ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ListView.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 const int NO_SELECTION = -1;
24 static int g_next_list_box_id = 1;
25 static const int g_min_visible_items = 3;
26 } // namespace
27 
29  std::string imgui_id_;
30  std::vector<std::string> items_;
31  int selected_index_ = NO_SELECTION;
33  std::function<void(const char *, bool)> on_value_changed_;
34 };
35 
36 ListView::ListView() : impl_(new ListView::Impl()) {
37  impl_->imgui_id_ = "##listview_" + std::to_string(g_next_list_box_id++);
38 }
39 
41 
42 void ListView::SetItems(const std::vector<std::string> &items) {
43  impl_->items_ = items;
44  impl_->selected_index_ = NO_SELECTION;
45 }
46 
47 int ListView::GetSelectedIndex() const { return impl_->selected_index_; }
48 
49 const char *ListView::GetSelectedValue() const {
50  if (impl_->selected_index_ < 0 ||
51  impl_->selected_index_ >= int(impl_->items_.size())) {
52  return "";
53  } else {
54  return impl_->items_[impl_->selected_index_].c_str();
55  }
56 }
57 
58 void ListView::SetSelectedIndex(int index) {
59  impl_->selected_index_ = std::min(int(impl_->items_.size() - 1), index);
60 }
61 
63  if (num > 0) {
64  impl_->max_visible_item_ = std::max(g_min_visible_items, num);
65  } else {
66  // unlimited, will make height be DIM_GROW
67  impl_->max_visible_item_ = -1;
68  }
69 }
70 
72  std::function<void(const char *, bool)> on_value_changed) {
73  impl_->on_value_changed_ = on_value_changed;
74 }
75 
77  const Constraints &constraints) const {
78  auto padding = ImGui::GetStyle().FramePadding;
79  auto fh = ImGui::GetFrameHeight();
80  auto *font = ImGui::GetFont();
81  ImVec2 size(0, 0);
82 
83  for (auto &item : impl_->items_) {
84  auto item_size = font->CalcTextSizeA(float(context.theme.font_size),
85  float(constraints.width), 0.0,
86  item.c_str());
87  size.x = std::max(size.x, item_size.x);
88  size.y += fh;
89  }
90  auto h = Widget::DIM_GROW;
91  if (impl_->max_visible_item_ > 0) {
92  // make sure show at least g_min_visible_items items, and
93  // at most max_visible_item_ items.
94  h = std::max((int)impl_->items_.size(), g_min_visible_items);
95  h = std::min(h, impl_->max_visible_item_);
96  h = int(std::ceil((float)h * fh));
97  }
98  return Size{int(std::ceil(size.x + 2.0f * padding.x)), h};
99 }
100 
102  return Size(0, g_min_visible_items * context.theme.font_size);
103 }
104 
106  auto &frame = GetFrame();
107  ImGui::SetCursorScreenPos(
108  ImVec2(float(frame.x), float(frame.y) + ImGui::GetScrollY()));
109  ImGui::PushItemWidth(float(frame.width));
110 
111  ImGui::PushStyleColor(ImGuiCol_FrameBg,
112  colorToImgui(context.theme.list_background_color));
113  ImGui::PushStyleColor(ImGuiCol_Header, // selection color
114  colorToImgui(context.theme.list_selected_color));
115  ImGui::PushStyleColor(ImGuiCol_HeaderHovered, // hover color
116  colorToImgui(Color(0, 0, 0, 0)));
117  ImGui::PushStyleColor(ImGuiCol_HeaderActive, // click-hold color
118  colorToImgui(context.theme.list_selected_color));
119 
120  int height_in_items =
121  int(std::floor(frame.height / ImGui::GetFrameHeight()));
122 
124  auto new_selected_idx = impl_->selected_index_;
125  bool is_double_click = false;
127  if (ImGui::ListBoxHeader(impl_->imgui_id_.c_str(),
128  int(impl_->items_.size()), height_in_items)) {
129  for (size_t i = 0; i < impl_->items_.size(); ++i) {
130  bool is_selected = (int(i) == impl_->selected_index_);
131  // ImGUI's list wants to hover over items, which is not done by
132  // any major OS, is pretty unnecessary (you can see the cursor
133  // right over the row), and acts really weird. Worse, the hover
134  // is drawn instead of the selection color. So to get rid of it
135  // we need hover to be the selected color iff this item is
136  // selected, otherwise we want it to be transparent.
137  if (is_selected) {
138  ImGui::PushStyleColor(
139  ImGuiCol_HeaderHovered,
140  colorToImgui(context.theme.list_selected_color));
141  } else {
142  ImGui::PushStyleColor(ImGuiCol_HeaderHovered,
143  colorToImgui(Color(0, 0, 0, 0)));
144  }
145  if (ImGui::Selectable(impl_->items_[i].c_str(), &is_selected,
146  ImGuiSelectableFlags_AllowDoubleClick)) {
147  if (is_selected) {
148  new_selected_idx = int(i);
149  }
150  // Dear ImGUI seems to have a bug where it registers a
151  // double-click as long as you haven't moved the mouse,
152  // no matter how long the time between clicks was.
153  if (ImGui::IsMouseDoubleClicked(0)) {
154  is_double_click = true;
155  }
156  }
157  ImGui::PopStyleColor();
158  }
159  ImGui::ListBoxFooter();
160 
161  if (new_selected_idx != impl_->selected_index_ || is_double_click) {
162  impl_->selected_index_ = new_selected_idx;
163  if (impl_->on_value_changed_) {
164  impl_->on_value_changed_(GetSelectedValue(), is_double_click);
165  }
167  }
168  }
170 
171  ImGui::PopStyleColor(4);
172 
173  ImGui::PopItemWidth();
174  return result;
175 }
176 
177 } // namespace gui
178 } // namespace visualization
179 } // namespace cloudViewer
Rect frame
int size
core::Tensor result
Definition: VtkUtils.cpp:76
DrawResult Draw(const DrawContext &context) override
Definition: ListView.cpp:105
void SetOnValueChanged(std::function< void(const char *, bool)> on_value_changed)
Definition: ListView.cpp:71
const char * GetSelectedValue() const
Returns the value of the currently selected item in the list.
Definition: ListView.cpp:49
int GetSelectedIndex() const
Returns the currently selected item in the list.
Definition: ListView.cpp:47
Size CalcPreferredSize(const LayoutContext &context, const Constraints &constraints) const override
Definition: ListView.cpp:76
Size CalcMinimumSize(const LayoutContext &context) const override
Definition: ListView.cpp:101
void SetItems(const std::vector< std::string > &items)
Definition: ListView.cpp:42
void SetSelectedIndex(int index)
Selects the indicated row of the list. Does not call onValueChanged.
Definition: ListView.cpp:58
virtual const Rect & GetFrame() const
Returns the frame size in pixels.
Definition: Widget.cpp:51
static constexpr int DIM_GROW
Definition: Widget.h:83
int min(int a, int b)
Definition: cutil_math.h:53
int max(int a, int b)
Definition: cutil_math.h:48
ImGuiContext * context
Definition: Window.cpp:76
MiniVec< float, N > floor(const MiniVec< float, N > &a)
Definition: MiniVec.h:75
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 *, bool)> on_value_changed_
Definition: ListView.cpp:33