ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
NumberEdit.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
9 
10 #include <imgui.h>
11 #include <string.h> // for snprintf
12 
13 #include <algorithm> // for min, max
14 #include <cmath>
15 #include <unordered_set>
16 
18 #include "visualization/gui/Util.h"
19 
20 namespace cloudViewer {
21 namespace visualization {
22 namespace gui {
23 
24 namespace {
25 static int g_next_number_edit_id = 1;
26 }
27 
29  std::string id_;
31  // Double has 53-bits of integer range, which is sufficient for the
32  // numbers that are reasonable for users to be entering. (Since JavaScript
33  // only uses doubles, apparently it works for a lot more situations, too.)
34  double value_;
35  double min_value_ = -2e9; // -2 billion, which is roughly -INT_MAX
36  double max_value_ = 2e9;
39  std::function<void(double)> on_changed_;
40 };
41 
43  impl_->type_ = type;
44  impl_->id_ = "##numedit" + std::to_string(g_next_number_edit_id++);
45 }
46 
48 
49 int NumberEdit::GetIntValue() const { return int(impl_->value_); }
50 
51 double NumberEdit::GetDoubleValue() const { return impl_->value_; }
52 
53 void NumberEdit::SetValue(double val) {
54  if (impl_->type_ == INT) {
55  impl_->value_ = std::round(val);
56  } else {
57  impl_->value_ = val;
58  }
59 }
60 
61 double NumberEdit::GetMinimumValue() const { return impl_->min_value_; }
62 
63 double NumberEdit::GetMaximumValue() const { return impl_->max_value_; }
64 
65 void NumberEdit::SetLimits(double min_value, double max_value) {
66  if (impl_->type_ == INT) {
67  impl_->min_value_ = std::round(min_value);
68  impl_->max_value_ = std::round(max_value);
69  } else {
70  impl_->min_value_ = min_value;
71  impl_->max_value_ = min_value;
72  }
73  impl_->value_ = std::min(max_value, std::max(min_value, impl_->value_));
74 }
75 
76 int NumberEdit::GetDecimalPrecision() { return impl_->num_decimal_digits_; }
77 
78 void NumberEdit::SetDecimalPrecision(int num_digits) {
79  impl_->num_decimal_digits_ = num_digits;
80 }
81 
83  impl_->preferred_width_ = width;
84 }
85 
86 void NumberEdit::SetOnValueChanged(std::function<void(double)> on_changed) {
87  impl_->on_changed_ = on_changed;
88 }
89 
91  const Constraints& constraints) const {
92  int num_min_digits =
93  int(std::ceil(std::log10(std::abs(impl_->min_value_))));
94  int num_max_digits =
95  int(std::ceil(std::log10(std::abs(impl_->max_value_))));
96  int num_digits = std::max(6, std::max(num_min_digits, num_max_digits));
97  if (impl_->min_value_ < 0) {
98  num_digits += 1;
99  }
100 
101  int height = int(std::round(ImGui::GetTextLineHeightWithSpacing()));
102  auto padding = height - int(std::round(ImGui::GetTextLineHeight()));
103  int incdec_width = 0;
104  if (impl_->type_ == INT) {
105  // padding is for the spacing between buttons and between text box
106  incdec_width = 2 * height + padding;
107  }
108 
109  int width =
110  (num_digits * context.theme.font_size) / 2 + padding + incdec_width;
111  if (impl_->preferred_width_ > 0) {
112  width = impl_->preferred_width_;
113  }
114  return Size(width, height);
115 }
116 
118  auto& frame = GetFrame();
119  ImGui::SetCursorScreenPos(
120  ImVec2(float(frame.x), float(frame.y) - ImGui::GetScrollY()));
121 
122  ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding,
123  0.0); // macOS doesn't round text edit borders
124 
125  ImGui::PushStyleColor(
126  ImGuiCol_FrameBg,
127  colorToImgui(context.theme.text_edit_background_color));
128  ImGui::PushStyleColor(
129  ImGuiCol_FrameBgHovered,
130  colorToImgui(context.theme.text_edit_background_color));
131  ImGui::PushStyleColor(
132  ImGuiCol_FrameBgActive,
133  colorToImgui(context.theme.text_edit_background_color));
134 
137  ImGui::PushItemWidth(float(GetFrame().width));
138  if (impl_->type_ == INT) {
139  int ivalue = int(impl_->value_);
140  if (ImGui::InputInt(impl_->id_.c_str(), &ivalue)) {
141  SetValue(ivalue);
143  }
144  } else {
145  std::string fmt;
146  if (impl_->num_decimal_digits_ >= 0) {
147  char buff[32];
148  snprintf(buff, 31, "%%.%df", impl_->num_decimal_digits_);
149  fmt = buff;
150  } else {
151  if (impl_->value_ < 10) {
152  fmt = "%.3f";
153  } else if (impl_->value_ < 100) {
154  fmt = "%.2f";
155  } else if (impl_->value_ < 1000) {
156  fmt = "%.1f";
157  } else {
158  fmt = "%.0f";
159  }
160  }
161  double dvalue = impl_->value_;
162  if (ImGui::InputDouble(impl_->id_.c_str(), &dvalue, 0.0, 0.0,
163  fmt.c_str())) {
164  SetValue(dvalue);
166  }
167  }
168  ImGui::PopItemWidth();
171 
172  ImGui::PopStyleColor(3);
173  ImGui::PopStyleVar();
174 
175  if (ImGui::IsItemDeactivatedAfterEdit()) {
176  if (impl_->on_changed_) {
177  impl_->on_changed_(impl_->value_);
178  }
180  }
181 
182  return result;
183 }
184 
185 } // namespace gui
186 } // namespace visualization
187 } // namespace cloudViewer
Rect frame
int width
int height
char type
core::Tensor result
Definition: VtkUtils.cpp:76
Size CalcPreferredSize(const LayoutContext &context, const Constraints &constraints) const override
Definition: NumberEdit.cpp:90
void SetLimits(double min_value, double max_value)
Definition: NumberEdit.cpp:65
Widget::DrawResult Draw(const DrawContext &context) override
Definition: NumberEdit.cpp:117
void SetOnValueChanged(std::function< void(double)> on_changed)
Definition: NumberEdit.cpp:86
virtual const Rect & GetFrame() const
Returns the frame size in pixels.
Definition: Widget.cpp:51
int min(int a, int b)
Definition: cutil_math.h:53
__host__ __device__ int2 abs(int2 v)
Definition: cutil_math.h:1267
int max(int a, int b)
Definition: cutil_math.h:48
ImGuiContext * context
Definition: Window.cpp:76
MiniVec< float, N > ceil(const MiniVec< float, N > &a)
Definition: MiniVec.h:89
ImVec4 colorToImgui(const Color &color)
Definition: Util.cpp:20
Generic file read and write utility for python interface.
std::string to_string(const T &n)
Definition: Common.h:20