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 // Pane headers use at least four pixels of horizontal frame padding.
31 const float frame_padding = std::max(4.0f, style.FramePadding.x);
32 const float padding = std::max(2.0f, frame_padding);
33 const float needed_width =
34 std::ceil(text_width + (frame_padding * 2.0f) + padding);
35 return std::max(button_height, needed_width);
36}
37
38inline float CalcIconToggleButtonWidth(const char* icon_on,
39 const char* icon_off,
40 float button_height) {
41 return std::max(CalcIconButtonWidth(icon_on, button_height),
42 CalcIconButtonWidth(icon_off, button_height));
43}
44
45inline float CalcPaneSegmentHeight(float button_size) {
46 return std::max(button_size + 2.0f,
48}
49
50inline bool ShouldStackSegments(float available_width, int item_count,
51 float min_item_width) {
52 if (item_count <= 1) {
53 return false;
54 }
55 const float spacing = ImGui::GetStyle().ItemSpacing.x;
56 const float required_width =
57 (min_item_width * static_cast<float>(item_count)) +
58 (spacing * static_cast<float>(item_count - 1));
59 return available_width < required_width;
60}
61
62inline void DrawPaneTitle(const char* icon, const char* title,
63 const char* compact_title, bool compact,
64 const char* subtitle = nullptr) {
65 ImGui::BeginGroup();
66 if (icon && *icon) {
68 ImGui::SameLine(0.0f, 4.0f);
69 }
70
71 ImGui::BeginGroup();
72 ImGui::AlignTextToFramePadding();
73 ImGui::TextUnformatted(
74 (compact && compact_title && *compact_title) ? compact_title : title);
75 if (subtitle && *subtitle) {
76 ImGui::TextDisabled("%s", subtitle);
77 }
78 ImGui::EndGroup();
79 ImGui::EndGroup();
80}
81
82inline void DrawSectionLabel(const char* icon, const char* label,
83 const char* tooltip = nullptr) {
84 ImGui::BeginGroup();
85 if (icon && *icon) {
87 ImGui::SameLine(0.0f, 6.0f);
88 }
89 ImGui::TextUnformatted(label);
90 if (tooltip && ImGui::IsItemHovered()) {
91 ImGui::SetTooltip("%s", tooltip);
92 }
93 ImGui::EndGroup();
94}
95
96inline bool DrawHeaderIconAction(const char* id, const char* icon,
97 float button_size, const char* tooltip,
98 bool active = false) {
99 ImGui::PushID(id);
100 const bool pressed = gui::TransparentIconButton(
101 icon, ImVec2(CalcIconButtonWidth(icon, button_size), button_size),
102 tooltip, active, ImVec4(0, 0, 0, 0), "dungeon_workbench", id);
103 ImGui::PopID();
104 return pressed;
105}
106
107inline void DrawPaneHeader(const char* table_id, const char* icon,
108 const char* title, const char* compact_title,
109 const char* subtitle, bool compact,
110 float action_width,
111 const std::function<void()>& draw_actions) {
112 // Pane header rows use action-cluster SameLine(0, spacing) calls for the
113 // right column; the table itself owns title-vs-actions layout. So the
114 // header guard only needs gentle vertical breathing room — don't shrink
115 // ItemSpacing.x below the theme default.
116 gui::StyleVarGuard frame_padding_guard(
117 ImGuiStyleVar_FramePadding,
118 ImVec2(std::max(4.0f, ImGui::GetStyle().FramePadding.x),
119 std::max(3.0f, ImGui::GetStyle().FramePadding.y)));
120 gui::StyleVarGuard item_spacing_guard(
121 ImGuiStyleVar_ItemSpacing,
122 ImVec2(std::max(ImGui::GetStyle().ItemSpacing.x, 4.0f),
123 std::max(3.0f, ImGui::GetStyle().ItemSpacing.y - 1.0f)));
124
125 constexpr ImGuiTableFlags kPaneHeaderTableFlags =
126 ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_NoPadInnerX |
127 ImGuiTableFlags_NoPadOuterX;
128
129 if (!ImGui::BeginTable(table_id, 2, kPaneHeaderTableFlags)) {
130 return;
131 }
132
133 ImGui::TableSetupColumn("Title", ImGuiTableColumnFlags_WidthStretch);
134 ImGui::TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthFixed,
135 action_width + 4.0f);
136 ImGui::TableNextRow();
137
138 ImGui::TableNextColumn();
139 DrawPaneTitle(icon, title, compact_title, compact, subtitle);
140
141 ImGui::TableNextColumn();
142 if (draw_actions) {
143 draw_actions();
144 }
145 ImGui::EndTable();
146}
147
148inline void DrawSegmentedControls(const char* id,
149 std::span<const SegmentSpec> segments,
150 int selected_index, float height,
151 float min_item_width,
152 const std::function<void(int)>& on_select,
153 bool force_stack = false) {
154 if (segments.empty()) {
155 return;
156 }
157
158 const float available_width =
159 std::max(ImGui::GetContentRegionAvail().x, 1.0f);
160 const bool stack =
161 force_stack ||
162 ShouldStackSegments(available_width, static_cast<int>(segments.size()),
163 min_item_width);
164 const float spacing = ImGui::GetStyle().ItemSpacing.x;
165 const float inline_width =
166 stack ? -1.0f
167 : std::max(min_item_width,
168 (available_width -
169 (spacing * static_cast<float>(segments.size() - 1))) /
170 static_cast<float>(segments.size()));
171
172 gui::StyleVarGuard text_align_guard(ImGuiStyleVar_ButtonTextAlign,
173 ImVec2(0.5f, 0.5f));
174
175 ImGui::PushID(id);
176 for (size_t i = 0; i < segments.size(); ++i) {
177 const bool selected = selected_index == static_cast<int>(i);
178 if (gui::ToggleButton(segments[i].label, selected,
179 ImVec2(inline_width, height))) {
180 if (on_select) {
181 on_select(static_cast<int>(i));
182 }
183 }
184 if (segments[i].tooltip && ImGui::IsItemHovered()) {
185 ImGui::SetTooltip("%s", segments[i].tooltip);
186 }
187 if (!stack && i + 1 < segments.size()) {
188 ImGui::SameLine(0.0f, spacing);
189 }
190 }
191 ImGui::PopID();
192}
193
194} // namespace yaze::editor::workbench
195
196#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)