yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
dungeon_workbench_chrome.h
Go to the documentation of this file.
1#ifndef YAZE_APP_EDITOR_DUNGEON_UI_WORKBENCH_DUNGEON_WORKBENCH_CHROME_H
2#define YAZE_APP_EDITOR_DUNGEON_UI_WORKBENCH_DUNGEON_WORKBENCH_CHROME_H
3
4#include <algorithm>
5#include <cmath>
6#include <functional>
7#include <span>
8
14#include "imgui/imgui.h"
15
17
19 const char* label = "";
20 const char* tooltip = nullptr;
21};
22
23inline float CalcIconButtonWidth(const char* icon, float button_height) {
24 if (!icon || !*icon) {
25 return button_height;
26 }
27
28 const ImGuiStyle& style = ImGui::GetStyle();
29 const float text_width = ImGui::CalcTextSize(icon).x;
30 const float padding = std::max(2.0f, style.FramePadding.x);
31 const float needed_width =
32 std::ceil(text_width + (style.FramePadding.x * 2.0f) + padding);
33 return std::max(button_height, needed_width);
34}
35
36inline float CalcIconToggleButtonWidth(const char* icon_on,
37 const char* icon_off,
38 float button_height) {
39 return std::max(CalcIconButtonWidth(icon_on, button_height),
40 CalcIconButtonWidth(icon_off, button_height));
41}
42
43inline float CalcPaneSegmentHeight(float button_size) {
44 return std::max(button_size + 2.0f,
46}
47
48inline bool ShouldStackSegments(float available_width, int item_count,
49 float min_item_width) {
50 if (item_count <= 1) {
51 return false;
52 }
53 const float spacing = ImGui::GetStyle().ItemSpacing.x;
54 const float required_width =
55 (min_item_width * static_cast<float>(item_count)) +
56 (spacing * static_cast<float>(item_count - 1));
57 return available_width < required_width;
58}
59
60inline void DrawPaneTitle(const char* icon, const char* title,
61 const char* compact_title, bool compact,
62 const char* subtitle = nullptr) {
63 ImGui::BeginGroup();
64 if (icon && *icon) {
66 ImGui::SameLine(0.0f, 4.0f);
67 }
68
69 ImGui::BeginGroup();
70 ImGui::AlignTextToFramePadding();
71 ImGui::TextUnformatted(
72 (compact && compact_title && *compact_title) ? compact_title : title);
73 if (subtitle && *subtitle) {
74 ImGui::TextDisabled("%s", subtitle);
75 }
76 ImGui::EndGroup();
77 ImGui::EndGroup();
78}
79
80inline void DrawSectionLabel(const char* icon, const char* label,
81 const char* tooltip = nullptr) {
82 ImGui::BeginGroup();
83 if (icon && *icon) {
85 ImGui::SameLine(0.0f, 6.0f);
86 }
87 ImGui::TextUnformatted(label);
88 if (tooltip && ImGui::IsItemHovered()) {
89 ImGui::SetTooltip("%s", tooltip);
90 }
91 ImGui::EndGroup();
92}
93
94inline bool DrawHeaderIconAction(const char* id, const char* icon,
95 float button_size, const char* tooltip,
96 bool active = false) {
97 ImGui::PushID(id);
98 const bool pressed = gui::TransparentIconButton(
99 icon, ImVec2(button_size, button_size), tooltip, active,
100 ImVec4(0, 0, 0, 0), "dungeon_workbench", id);
101 ImGui::PopID();
102 return pressed;
103}
104
105inline void DrawPaneHeader(const char* table_id, const char* icon,
106 const char* title, const char* compact_title,
107 const char* subtitle, bool compact,
108 float action_width,
109 const std::function<void()>& draw_actions) {
110 // Pane header rows use action-cluster SameLine(0, spacing) calls for the
111 // right column; the table itself owns title-vs-actions layout. So the
112 // header guard only needs gentle vertical breathing room — don't shrink
113 // ItemSpacing.x below the theme default.
114 gui::StyleVarGuard frame_padding_guard(
115 ImGuiStyleVar_FramePadding,
116 ImVec2(std::max(4.0f, ImGui::GetStyle().FramePadding.x),
117 std::max(3.0f, ImGui::GetStyle().FramePadding.y)));
118 gui::StyleVarGuard item_spacing_guard(
119 ImGuiStyleVar_ItemSpacing,
120 ImVec2(std::max(ImGui::GetStyle().ItemSpacing.x, 4.0f),
121 std::max(3.0f, ImGui::GetStyle().ItemSpacing.y - 1.0f)));
122
123 constexpr ImGuiTableFlags kPaneHeaderTableFlags =
124 ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_NoPadInnerX |
125 ImGuiTableFlags_NoPadOuterX;
126
127 if (!ImGui::BeginTable(table_id, 2, kPaneHeaderTableFlags)) {
128 return;
129 }
130
131 ImGui::TableSetupColumn("Title", ImGuiTableColumnFlags_WidthStretch);
132 ImGui::TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthFixed,
133 action_width + 4.0f);
134 ImGui::TableNextRow();
135
136 ImGui::TableNextColumn();
137 DrawPaneTitle(icon, title, compact_title, compact, subtitle);
138
139 ImGui::TableNextColumn();
140 if (draw_actions) {
141 draw_actions();
142 }
143 ImGui::EndTable();
144}
145
146inline void DrawSegmentedControls(const char* id,
147 std::span<const SegmentSpec> segments,
148 int selected_index, float height,
149 float min_item_width,
150 const std::function<void(int)>& on_select,
151 bool force_stack = false) {
152 if (segments.empty()) {
153 return;
154 }
155
156 const float available_width =
157 std::max(ImGui::GetContentRegionAvail().x, 1.0f);
158 const bool stack =
159 force_stack ||
160 ShouldStackSegments(available_width, static_cast<int>(segments.size()),
161 min_item_width);
162 const float spacing = ImGui::GetStyle().ItemSpacing.x;
163 const float inline_width =
164 stack ? -1.0f
165 : std::max(min_item_width,
166 (available_width -
167 (spacing * static_cast<float>(segments.size() - 1))) /
168 static_cast<float>(segments.size()));
169
170 gui::StyleVarGuard text_align_guard(ImGuiStyleVar_ButtonTextAlign,
171 ImVec2(0.5f, 0.5f));
172
173 ImGui::PushID(id);
174 for (size_t i = 0; i < segments.size(); ++i) {
175 const bool selected = selected_index == static_cast<int>(i);
176 if (gui::ToggleButton(segments[i].label, selected,
177 ImVec2(inline_width, height))) {
178 if (on_select) {
179 on_select(static_cast<int>(i));
180 }
181 }
182 if (segments[i].tooltip && ImGui::IsItemHovered()) {
183 ImGui::SetTooltip("%s", segments[i].tooltip);
184 }
185 if (!stack && i + 1 < segments.size()) {
186 ImGui::SameLine(0.0f, spacing);
187 }
188 }
189 ImGui::PopID();
190}
191
192} // namespace yaze::editor::workbench
193
194#endif // YAZE_APP_EDITOR_DUNGEON_UI_WORKBENCH_DUNGEON_WORKBENCH_CHROME_H
static float GetTouchSafeWidgetHeight()
RAII guard for ImGui style vars.
Definition style_guard.h:68
bool ShouldStackSegments(float available_width, int item_count, float min_item_width)
float CalcPaneSegmentHeight(float button_size)
void DrawSectionLabel(const char *icon, const char *label, const char *tooltip=nullptr)
void DrawSegmentedControls(const char *id, std::span< const SegmentSpec > segments, int selected_index, float height, float min_item_width, const std::function< void(int)> &on_select, bool force_stack=false)
void DrawPaneHeader(const char *table_id, const char *icon, const char *title, const char *compact_title, const char *subtitle, bool compact, float action_width, const std::function< void()> &draw_actions)
float CalcIconButtonWidth(const char *icon, float button_height)
void DrawPaneTitle(const char *icon, const char *title, const char *compact_title, bool compact, const char *subtitle=nullptr)
float CalcIconToggleButtonWidth(const char *icon_on, const char *icon_off, float button_height)
bool DrawHeaderIconAction(const char *id, const char *icon, float button_size, const char *tooltip, bool active=false)
bool TransparentIconButton(const char *icon, const ImVec2 &size, const char *tooltip, bool is_active, const ImVec4 &active_color, const char *panel_id, const char *anim_id)
Draw a transparent icon button (hover effect only).
void ColoredText(const char *text, const ImVec4 &color)
ImVec4 GetPrimaryVec4()
bool ToggleButton(const char *label, bool active, const ImVec2 &size)