ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
Widget.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 
8 #include "Widget.h"
9 
10 #include <imgui.h>
11 #include <imgui_internal.h>
12 
15 
16 namespace cloudViewer {
17 namespace visualization {
18 namespace gui {
19 
20 // This should not be Color(0, 0, 0, 0), since transparent is a valid and
21 // common background color to want.
22 static const Color DEFAULT_BGCOLOR(0.001f, 0.001f, 0.001f, 0.0f);
23 
24 struct Widget::Impl {
27  std::vector<std::shared_ptr<Widget>> children_;
28  std::string tooltip_;
29  bool is_visible_ = true;
30  bool is_enabled_ = true;
32 };
33 
34 Widget::Widget() : impl_(new Widget::Impl()) {}
35 
36 Widget::Widget(const std::vector<std::shared_ptr<Widget>>& children)
37  : impl_(new Widget::Impl()) {
38  impl_->children_ = children;
39 }
40 
42 
43 void Widget::AddChild(std::shared_ptr<Widget> child) {
44  impl_->children_.push_back(child);
45 }
46 
47 const std::vector<std::shared_ptr<Widget>> Widget::GetChildren() const {
48  return impl_->children_;
49 }
50 
51 const Rect& Widget::GetFrame() const { return impl_->frame_; }
52 
53 void Widget::SetFrame(const Rect& f) { impl_->frame_ = f; }
54 
55 const Color& Widget::GetBackgroundColor() const { return impl_->bg_color_; }
56 
58  return (impl_->bg_color_ == DEFAULT_BGCOLOR);
59 }
60 
62  impl_->bg_color_ = color;
63 }
64 
65 bool Widget::IsVisible() const { return impl_->is_visible_; }
66 
67 void Widget::SetVisible(bool vis) { impl_->is_visible_ = vis; }
68 
69 bool Widget::IsEnabled() const { return impl_->is_enabled_; }
70 
71 void Widget::SetEnabled(bool enabled) { impl_->is_enabled_ = enabled; }
72 
73 void Widget::SetTooltip(const char* text) { impl_->tooltip_ = text; }
74 
75 const char* Widget::GetTooltip() const { return impl_->tooltip_.c_str(); }
76 
78  const Constraints& constraints) const {
79  return Size(DIM_GROW, DIM_GROW);
80 }
81 
83  return Size(0, 0);
84 }
85 
87  for (auto& child : impl_->children_) {
88  child->Layout(context);
89  }
90 }
91 
93  if (!impl_->is_visible_) {
94  return DrawResult::NONE;
95  }
96 
98  for (auto& child : impl_->children_) {
99  if (child->IsVisible()) {
100  auto r = child->Draw(context);
101  // The mouse can only be over one item, so there should never
102  // be multiple items returning non-NONE.
103  if (r > result) {
104  result = r;
105  }
106  }
107  }
108  return result;
109 }
110 
112  if (!IsEnabled()) {
113  ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
114  ImGui::PushStyleVar(ImGuiStyleVar_Alpha,
115  ImGui::GetStyle().Alpha * 0.5f);
116  }
117  // As an immediate mode GUI, responses to UI events can happen
118  // during a draw. Store what the disabled flag was at the
119  // beginning of the draw, so we know how many things to pop
120  // to clean up. (An example of when this is needed is a reset
121  // button: after clicking it, it will probably disable itself
122  // since there is nothing to reset now)
123  impl_->pop_disabled_flags_at_end_of_draw_ = !IsEnabled();
124 }
125 
127  if (impl_->pop_disabled_flags_at_end_of_draw_) {
128  ImGui::PopStyleVar();
129  ImGui::PopItemFlag();
130  }
131 }
132 
134  if (!impl_->tooltip_.empty() && IsEnabled() &&
135  (ImGui::IsItemActive() || ImGui::IsItemHovered())) {
136  // The default margins of the tooltips are 0 and rather ugly. It turns
137  // out that tooltips are implemented as ImGui Windows, so we need to
138  // push WindowPadding, not FramePadding as you might expect.
139  // Note: using Push/PopStyleVar() causes problems because we might
140  // already done a Push of the WindowPadding above, and the pushes
141  // seem to get coalesced, so when we pop here, it effectively pops
142  // in calling code, which then crashes because there are too many
143  // pops.
144  float border_radius = std::round(0.2f * ImGui::GetFont()->FontSize);
145  float margin = 0.25f * ImGui::GetFont()->FontSize;
146  float old_radius = ImGui::GetStyle().WindowRounding;
147  ImVec2 old_padding = ImGui::GetStyle().WindowPadding;
148  ImGui::GetStyle().WindowPadding = ImVec2(2.0f * margin, margin);
149  ImGui::GetStyle().WindowRounding = border_radius;
150 
151  ImGui::BeginTooltip();
152  ImGui::Text("%s", impl_->tooltip_.c_str());
153  ImGui::EndTooltip();
154 
155  // Pop
156  ImGui::GetStyle().WindowPadding = old_padding;
157  ImGui::GetStyle().WindowRounding = old_radius;
158  }
159 }
160 
162  if (!impl_->is_visible_) {
163  return EventResult::IGNORED;
164  }
165 
166  // Iterate backwards so that we send mouse events from the top down.
167  for (auto it = impl_->children_.rbegin(); it != impl_->children_.rend();
168  ++it) {
169  if ((*it)->GetFrame().Contains(e.x, e.y)) {
170  auto result = (*it)->Mouse(e);
171  if (result != EventResult::IGNORED) {
172  return result;
173  }
174  }
175  }
176 
177  // If we get here then this event is either for an ImGUI widget,
178  // in which case we should not process this event further (ImGUI will
179  // do it later), or this is an empty widget like a panel or something,
180  // which eats events (it doesn't handle the event [e.g. button down]
181  // and nor should anything else).
182  return EventResult::DISCARD;
183 }
184 
186  return EventResult::DISCARD;
187 }
188 
190  auto result = DrawResult::NONE;
191  for (auto child : impl_->children_) {
192  if (child->Tick(e) == DrawResult::REDRAW) {
194  }
195  }
196  return result;
197 }
198 
199 } // namespace gui
200 } // namespace visualization
201 } // namespace cloudViewer
math::float4 color
core::Tensor result
Definition: VtkUtils.cpp:76
virtual const Color & GetBackgroundColor() const
Definition: Widget.cpp:55
virtual DrawResult Draw(const DrawContext &context)
Definition: Widget.cpp:92
virtual void SetTooltip(const char *text)
Definition: Widget.cpp:73
virtual Size CalcPreferredSize(const LayoutContext &context, const Constraints &constraints) const
Definition: Widget.cpp:77
virtual const std::vector< std::shared_ptr< Widget > > GetChildren() const
Definition: Widget.cpp:47
virtual bool IsEnabled() const
Definition: Widget.cpp:69
virtual void Layout(const LayoutContext &context)
Definition: Widget.cpp:86
virtual void SetFrame(const Rect &f)
Definition: Widget.cpp:53
virtual const Rect & GetFrame() const
Returns the frame size in pixels.
Definition: Widget.cpp:51
virtual void SetBackgroundColor(const Color &color)
Definition: Widget.cpp:61
virtual void AddChild(std::shared_ptr< Widget > child)
Definition: Widget.cpp:43
virtual const char * GetTooltip() const
Definition: Widget.cpp:75
virtual bool IsDefaultBackgroundColor() const
Definition: Widget.cpp:57
static constexpr int DIM_GROW
Definition: Widget.h:83
virtual void SetVisible(bool vis)
Definition: Widget.cpp:67
virtual Size CalcMinimumSize(const LayoutContext &context) const
Definition: Widget.cpp:82
virtual EventResult Mouse(const MouseEvent &e)
Definition: Widget.cpp:161
virtual DrawResult Tick(const TickEvent &e)
Definition: Widget.cpp:189
virtual bool IsVisible() const
Definition: Widget.cpp:65
virtual void SetEnabled(bool enabled)
Definition: Widget.cpp:71
virtual EventResult Key(const KeyEvent &e)
Definition: Widget.cpp:185
ImGuiContext * context
Definition: Window.cpp:76
static const Color DEFAULT_BGCOLOR(0.001f, 0.001f, 0.001f, 0.0f)
Generic file read and write utility for python interface.
std::vector< std::shared_ptr< Widget > > children_
Definition: Widget.cpp:27