ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
Combobox.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 
12 #include <algorithm>
13 #include <cmath>
14 
16 #include "visualization/gui/Util.h"
17 
18 namespace cloudViewer {
19 namespace visualization {
20 namespace gui {
21 
22 namespace {
23 static int g_next_combobox_id = 1;
24 
25 int CalcItemHeight(const Theme& theme) {
26  auto em = ImGui::GetTextLineHeight();
27  auto padding = ImGui::GetStyle().FramePadding.y;
28  return int(std::ceil(em + 2.0 * padding));
29 }
30 
31 } // namespace
33  std::string imgui_id_;
34  std::vector<std::string> items_;
35  int current_index_ = 0;
36  std::function<void(const char*, int)> on_value_changed_;
37 };
38 
39 Combobox::Combobox() : impl_(new Combobox::Impl()) {
40  impl_->imgui_id_ = "##combobox_" + std::to_string(g_next_combobox_id++);
41 }
42 
43 Combobox::Combobox(const std::vector<const char*>& items) : Combobox() {
44  for (auto& item : items) {
45  AddItem(item);
46  }
47 }
48 
50 
52  impl_->items_.clear();
53  impl_->current_index_ = 0;
54 }
55 
56 int Combobox::AddItem(const char* name) {
57  impl_->items_.push_back(name);
58  return int(impl_->items_.size()) - 1;
59 }
60 
61 void Combobox::ChangeItem(int index, const char* new_name) {
62  impl_->items_[index] = new_name;
63 }
64 
65 void Combobox::ChangeItem(const char* orig_name, const char* new_name) {
66  for (size_t i = 0; i < impl_->items_.size(); ++i) {
67  if (impl_->items_[i] == orig_name) {
68  impl_->items_[i] = new_name;
69  break;
70  }
71  }
72 }
73 
74 void Combobox::RemoveItem(const char* name) {
75  for (size_t i = 0; i < impl_->items_.size(); ++i) {
76  if (impl_->items_[i] == name) {
77  RemoveItem(int(i));
78  break;
79  }
80  }
81 }
82 
83 void Combobox::RemoveItem(int index) {
84  if (index >= 0 && index < int(impl_->items_.size())) {
85  impl_->items_.erase(impl_->items_.begin() + index);
86  if (impl_->current_index_ >= int(impl_->items_.size())) {
87  impl_->current_index_ = int(impl_->items_.size()) - 1;
88  }
89  }
90 }
91 
93  return static_cast<int>(impl_->items_.size());
94 }
95 
96 const char* Combobox::GetItem(int index) const {
97  return impl_->items_[index].c_str();
98 }
99 
100 int Combobox::GetSelectedIndex() const { return impl_->current_index_; }
101 
102 const char* Combobox::GetSelectedValue() const {
103  if (impl_->current_index_ >= 0 &&
104  impl_->current_index_ < int(impl_->items_.size())) {
105  return impl_->items_[impl_->current_index_].c_str();
106  } else {
107  return "";
108  }
109 }
110 
111 void Combobox::SetSelectedIndex(int index) {
112  if (index >= 0 && index < int(impl_->items_.size())) {
113  impl_->current_index_ = index;
114  }
115 }
116 
117 bool Combobox::SetSelectedValue(const char* value) {
118  std::string svalue = value;
119  for (size_t i = 0; i < impl_->items_.size(); ++i) {
120  if (impl_->items_[i] == svalue) {
121  SetSelectedIndex(int(i));
122  return true;
123  }
124  }
125  return false;
126 }
127 
129  std::function<void(const char*, int)> on_value_changed) {
130  impl_->on_value_changed_ = on_value_changed;
131 }
132 
134  const Constraints& constraints) const {
135  auto button_width = ImGui::GetFrameHeight(); // button is square
136  auto padding = ImGui::GetStyle().FramePadding;
137  int width = 0;
138  for (auto& item : impl_->items_) {
139  auto size = ImGui::GetFont()->CalcTextSizeA(
140  float(context.theme.font_size), float(constraints.width),
141  10000.0f, item.c_str());
142  width = std::max(width, int(std::ceil(size.x)));
143  }
144  return Size(width + int(std::round(button_width + 2.0 * padding.x)),
145  CalcItemHeight(context.theme));
146 }
147 
149  bool value_changed = false;
150 
151  auto& frame = GetFrame();
152  ImGui::SetCursorScreenPos(
153  ImVec2(float(frame.x), float(frame.y) - ImGui::GetScrollY()));
154 
155  ImGui::PushStyleColor(
156  ImGuiCol_Button,
157  colorToImgui(context.theme.combobox_arrow_background_color));
158  ImGui::PushStyleColor(
159  ImGuiCol_ButtonHovered,
160  colorToImgui(context.theme.combobox_arrow_background_color));
161  ImGui::PushStyleColor(
162  ImGuiCol_ButtonActive,
163  colorToImgui(context.theme.combobox_arrow_background_color));
164 
166  ImGui::PushItemWidth(float(frame.width));
167 
168  if (ImGui::BeginCombo(impl_->imgui_id_.c_str(), GetSelectedValue())) {
169  for (size_t i = 0; i < impl_->items_.size(); ++i) {
170  bool isSelected = false;
171  if (ImGui::Selectable(impl_->items_[i].c_str(), &isSelected, 0)) {
172  impl_->current_index_ = int(i);
173  value_changed = true;
174  if (impl_->on_value_changed_) {
175  impl_->on_value_changed_(GetSelectedValue(), int(i));
176  }
177  }
178  if (isSelected) {
179  ImGui::SetItemDefaultFocus(); // keyboard focus
180  }
181  }
182  ImGui::EndCombo();
183  }
184 
185  ImGui::PopItemWidth();
187 
188  ImGui::PopStyleColor(3);
189 
190  return value_changed ? Widget::DrawResult::REDRAW
192 }
193 
194 } // namespace gui
195 } // namespace visualization
196 } // namespace cloudViewer
Rect frame
int width
int size
std::string name
void RemoveItem(const char *name)
Removes the first item matching the given text.
Definition: Combobox.cpp:74
const char * GetSelectedValue() const
Returns the text of the selected value, or "" if nothing is selected.
Definition: Combobox.cpp:102
Size CalcPreferredSize(const LayoutContext &context, const Constraints &constraints) const override
Definition: Combobox.cpp:133
DrawResult Draw(const DrawContext &context) override
Definition: Combobox.cpp:148
bool SetSelectedValue(const char *value)
Definition: Combobox.cpp:117
void ChangeItem(int index, const char *name)
Definition: Combobox.cpp:61
const char * GetItem(int index) const
Definition: Combobox.cpp:96
void SetOnValueChanged(std::function< void(const char *, int)> on_value_changed)
Definition: Combobox.cpp:128
virtual const Rect & GetFrame() const
Returns the frame size in pixels.
Definition: Widget.cpp:51
int max(int a, int b)
Definition: cutil_math.h:48
ImGuiContext * context
Definition: Window.cpp:76
const Theme * theme
Definition: Window.cpp:74
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
std::function< void(const char *, int)> on_value_changed_
Definition: Combobox.cpp:36