ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
Button.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 <cmath>
13 #include <string>
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_button_id = 1;
24 } // namespace
25 
26 struct Button::Impl {
27  std::string id_;
28  std::string title_;
29  std::shared_ptr<UIImage> image_;
30  float padding_horizontal_em_ = 0.5f;
31  float padding_vertical_em_ = 0.5f;
32  bool is_toggleable_ = false;
33  bool is_on_ = false;
34  std::function<void()> on_clicked_;
35 };
36 
37 Button::Button(const char* title) : impl_(new Button::Impl()) {
38  impl_->id_ = std::string("##button") + std::to_string(g_next_button_id++);
39  impl_->title_ = title;
40 }
41 
42 Button::Button(std::shared_ptr<UIImage> image) : impl_(new Button::Impl()) {
43  impl_->image_ = image;
44 }
45 
47 
48 const char* Button::GetText() const { return impl_->title_.c_str(); }
49 
50 void Button::SetText(const char* text) { impl_->title_ = text; }
51 
53  return impl_->padding_horizontal_em_;
54 }
55 
57  return impl_->padding_vertical_em_;
58 }
59 
60 void Button::SetPaddingEm(float horiz_ems, float vert_ems) {
61  impl_->padding_horizontal_em_ = horiz_ems;
62  impl_->padding_vertical_em_ = vert_ems;
63 }
64 
65 bool Button::GetIsToggleable() const { return impl_->is_toggleable_; }
66 
67 void Button::SetToggleable(bool toggles) { impl_->is_toggleable_ = toggles; }
68 
69 bool Button::GetIsOn() const { return impl_->is_on_; }
70 
71 void Button::SetOn(bool is_on) {
72  if (impl_->is_toggleable_) {
73  impl_->is_on_ = is_on;
74  }
75 }
76 
77 void Button::SetOnClicked(std::function<void()> on_clicked) {
78  impl_->on_clicked_ = on_clicked;
79 }
80 
82  const Constraints& constraints) const {
83  auto em = float(context.theme.font_size);
84  auto padding_horiz = int(std::ceil(impl_->padding_horizontal_em_ * em));
85  auto padding_vert = int(std::ceil(impl_->padding_vertical_em_ * em));
86  if (impl_->image_) {
87  auto size = impl_->image_->CalcPreferredSize(context, constraints);
88  return Size(size.width + 2 * padding_horiz,
89  size.height + 2 * padding_vert);
90  } else {
91  auto font = ImGui::GetFont();
92  auto imguiVertPadding = ImGui::GetTextLineHeightWithSpacing() -
93  ImGui::GetTextLineHeight();
94  auto size = font->CalcTextSizeA(float(context.theme.font_size),
95  float(constraints.width), 10000,
96  impl_->title_.c_str());
97  // When ImGUI draws text, it draws text in a box of height
98  // font_size + spacing. The padding on the bottom is essentially the
99  // descender height, and the box height ends up giving a visual padding
100  // of descender_height on the top and bottom. So while we only need to
101  // 1 * imguiVertPadding on the bottom, we need to add 2x on the sides.
102  // Note that padding of 0 doesn't actually produce a padding of zero,
103  // because that would look horrible. (And also because if we do that,
104  // ImGUI will position the text so that the descender is cut off,
105  // because it is assuming that it gets a little extra on the bottom.
106  // This looks really bad...)
107  return Size(
108  int(std::ceil(size.x + 2.0f + imguiVertPadding)) +
109  2 * padding_horiz,
110  int(std::ceil(ImGui::GetTextLineHeight() + imguiVertPadding)) +
111  2 * padding_vert);
112  }
113 }
114 
116  auto& frame = GetFrame();
118 
119  ImGui::SetCursorScreenPos(
120  ImVec2(float(frame.x), float(frame.y) - ImGui::GetScrollY()));
121 
122  bool was_on = impl_->is_on_;
123  if (was_on) {
124  ImGui::PushStyleColor(ImGuiCol_Text,
125  colorToImgui(context.theme.button_on_text_color));
126  ImGui::PushStyleColor(ImGuiCol_Button,
127  colorToImgui(context.theme.button_on_color));
128  ImGui::PushStyleColor(
129  ImGuiCol_ButtonHovered,
130  colorToImgui(context.theme.button_on_hover_color));
131  ImGui::PushStyleColor(
132  ImGuiCol_ButtonActive,
133  colorToImgui(context.theme.button_on_active_color));
134  }
136  bool pressed = false;
137  if (impl_->image_) {
138  auto params = impl_->image_->CalcDrawParams(context.renderer, frame);
139  ImTextureID image_id =
140  reinterpret_cast<ImTextureID>(params.texture.GetId());
141  pressed = ImGui::ImageButton(
142  image_id, ImVec2(params.width, params.height),
143  ImVec2(params.u0, params.v0), ImVec2(params.u1, params.v1));
144  } else {
145  pressed = ImGui::Button(
146  (impl_->title_ + impl_->id_).c_str(),
147  ImVec2(float(GetFrame().width), float(GetFrame().height)));
148  }
149  if (pressed) {
150  if (impl_->is_toggleable_) {
151  impl_->is_on_ = !impl_->is_on_;
152  }
153  if (impl_->on_clicked_) {
154  impl_->on_clicked_();
155  }
157  }
160  if (was_on) {
161  ImGui::PopStyleColor(4);
162  }
163 
164  return result;
165 }
166 
167 } // namespace gui
168 } // namespace visualization
169 } // namespace cloudViewer
Rect frame
std::shared_ptr< core::Tensor > image
int width
int size
int height
cmdLineReadable * params[]
core::Tensor result
Definition: VtkUtils.cpp:76
void SetOnClicked(std::function< void()> on_clicked)
Definition: Button.cpp:77
void SetText(const char *text)
Sets the text of the button. Do not call if this is an image button.
Definition: Button.cpp:50
float GetHorizontalPaddingEm() const
Returns the padding, in units of ems.
Definition: Button.cpp:52
Size CalcPreferredSize(const LayoutContext &context, const Constraints &constraints) const override
Definition: Button.cpp:81
void SetPaddingEm(float horiz_ems, float vert_ems)
Definition: Button.cpp:60
DrawResult Draw(const DrawContext &context) override
Definition: Button.cpp:115
virtual const Rect & GetFrame() const
Returns the frame size in pixels.
Definition: Widget.cpp:51
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
std::shared_ptr< UIImage > image_
Definition: Button.cpp:29