17#include "imgui/imgui.h"
18#include "imgui/imgui_internal.h"
30 context_ = ImGui::GetCurrentContext();
31 if (context_ !=
nullptr) {
32 style_stack_before_ = context_->StyleVarStack.Size;
33 color_stack_before_ = context_->ColorStack.Size;
34 window_stack_before_ = context_->CurrentWindowStack.Size;
37 const auto& theme = gui::LayoutHelpers::GetTheme();
38 ImGui::PushStyleColor(ImGuiCol_ChildBg,
39 gui::ConvertColorToImVec4(theme.menu_bar_bg));
40 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding,
41 ImVec2(gui::LayoutHelpers::GetButtonPadding(),
42 gui::LayoutHelpers::GetButtonPadding()));
45 const float min_height =
46 (gui::LayoutHelpers::GetTouchSafeWidgetHeight() + 6.0f) +
47 (gui::LayoutHelpers::GetButtonPadding() * 2.0f) + 2.0f;
49 std::max(gui::LayoutHelpers::GetToolbarHeight(), min_height);
51 label, ImVec2(0, height),
true,
52 ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
58 context_ !=
nullptr ? context_ : ImGui::GetCurrentContext();
59 const bool has_child_window =
60 ctx !=
nullptr && ctx->CurrentWindow !=
nullptr &&
61 ctx->CurrentWindowStack.Size > window_stack_before_ &&
62 ((ctx->CurrentWindow->Flags & ImGuiWindowFlags_ChildWindow) != 0);
63 if (began_child_ && has_child_window) {
66 if (ctx !=
nullptr && ctx->StyleVarStack.Size > style_stack_before_) {
67 ImGui::PopStyleVar(1);
69 if (ctx !=
nullptr && ctx->ColorStack.Size > color_stack_before_) {
70 ImGui::PopStyleColor(1);
75 ImGuiContext* context_ =
nullptr;
76 int style_stack_before_ = 0;
77 int color_stack_before_ = 0;
78 int window_stack_before_ = 0;
79 bool began_child_ =
false;
83 if (!icon || !*icon) {
87 const ImGuiStyle& style = ImGui::GetStyle();
90 const float text_w = ImGui::CalcTextSize(icon).x;
91 const float fudge = std::max(2.0f, style.FramePadding.x);
92 const float needed_w =
93 std::ceil(text_w + (style.FramePadding.x * 2.0f) + fudge);
94 return std::max(btn_height, needed_w);
109 int current_room,
int previous_room,
110 const std::function<
const std::deque<int>&()>& get_recent_rooms) {
111 if (previous_room >= 0 && previous_room != current_room) {
112 return {
true, previous_room};
114 if (get_recent_rooms) {
115 const auto& mru = get_recent_rooms();
116 for (
int rid : mru) {
117 if (rid != current_room) {
126 bool* value,
float btn_size,
const char* tooltip_on,
127 const char* tooltip_off) {
132 const float btn = btn_size;
134 const bool active = *value;
136 const ImVec4 col_btn = ImGui::GetStyleColorVec4(ImGuiCol_Button);
137 const ImVec4 col_active = ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive);
141 active ? col_active : col_btn);
143 ImGui::Button(active ? icon_on : icon_off, ImVec2(btn_w, btn));
145 if (ImGui::IsItemHovered()) {
146 ImGui::SetTooltip(
"%s", active ? tooltip_on : tooltip_off);
156 const char* tooltip) {
157 const float btn = btn_size;
160 const bool pressed = ImGui::Button(icon, ImVec2(btn_w, btn));
162 if (ImGui::IsItemHovered() && tooltip && *tooltip) {
163 ImGui::SetTooltip(
"%s", tooltip);
169 int current_room_id,
int* compare_room_id,
170 const std::function<
const std::deque<int>&()>& get_recent_rooms,
171 char* search_buf,
size_t search_buf_size) {
172 if (!compare_room_id || *compare_room_id < 0) {
175 const bool can_search = search_buf !=
nullptr && search_buf_size > 1;
176 const char* filter = can_search ? search_buf :
"";
180 snprintf(preview,
sizeof(preview),
"[%03X] %s", *compare_room_id,
183 auto to_lower = [](
unsigned char c) {
184 return static_cast<char>(std::tolower(c));
186 auto icontains = [&](
const std::string& haystack,
187 const char* needle) ->
bool {
188 if (!needle || *needle ==
'\0') {
191 const size_t nlen = std::strlen(needle);
192 for (
size_t i = 0; i + nlen <= haystack.size(); ++i) {
194 for (
size_t j = 0; j < nlen; ++j) {
195 if (to_lower(
static_cast<unsigned char>(haystack[i + j])) !=
196 to_lower(
static_cast<unsigned char>(needle[j]))) {
208 ImGui::SetNextItemWidth(
209 std::clamp(ImGui::GetContentRegionAvail().x, 180.0f, 420.0f));
210 if (ImGui::BeginCombo(
"##CompareRoomPicker", preview,
211 ImGuiComboFlags_HeightLarge)) {
213 if (get_recent_rooms) {
214 const auto& mru = get_recent_rooms();
215 for (
int rid : mru) {
216 if (rid == current_room_id) {
221 snprintf(item,
sizeof(item),
"[%03X] %s", rid, rid_label.c_str());
222 const bool is_selected = (rid == *compare_room_id);
223 if (ImGui::Selectable(item, is_selected)) {
224 *compare_room_id = rid;
231 ImGui::SetNextItemWidth(-1.0f);
233 ImGui::InputTextWithHint(
"##CompareSearch",
"Type to filter rooms...",
234 search_buf, search_buf_size);
236 ImGui::TextDisabled(
"Search unavailable");
240 ImGui::BeginChild(
"##CompareSearchList", ImVec2(0, 220),
true);
241 ImGuiListClipper clipper;
242 clipper.Begin(0x128);
243 while (clipper.Step()) {
244 for (
int rid = clipper.DisplayStart; rid < clipper.DisplayEnd; ++rid) {
245 if (rid == current_room_id) {
250 snprintf(hex_buf,
sizeof(hex_buf),
"%03X", rid);
251 if (!icontains(rid_label, filter) && !icontains(hex_buf, filter)) {
255 snprintf(item,
sizeof(item),
"[%03X] %s", rid, rid_label.c_str());
256 const bool is_selected = (rid == *compare_room_id);
257 if (ImGui::Selectable(item, is_selected)) {
258 *compare_room_id = rid;
266 if (ImGui::IsItemHovered()) {
267 ImGui::SetTooltip(
"Pick a room to compare");
276 ImGui::TextDisabled(
"Workbench toolbar not wired");
282 ScopedWorkbenchToolbar toolbar_scope(
"##DungeonWorkbenchToolbar");
283 bool request_panel_mode =
false;
288 const float spacing = ImGui::GetStyle().ItemSpacing.x;
293 const ImVec2 frame_pad = ImGui::GetStyle().FramePadding;
295 ImGuiStyleVar_FramePadding,
296 ImVec2(frame_pad.x, std::max(frame_pad.y, 4.0f)));
298 constexpr ImGuiTableFlags kFlags = ImGuiTableFlags_NoBordersInBody |
299 ImGuiTableFlags_NoPadInnerX |
300 ImGuiTableFlags_NoPadOuterX;
301 if (ImGui::BeginTable(
"##DungeonWorkbenchToolbarTable", 3, kFlags)) {
307 const float right_cluster_w =
308 w_grid + w_bounds + w_coords + w_camera + (spacing * 3.0f);
309 const float right_w = right_cluster_w + 6.0f;
310 ImGui::TableSetupColumn(
"Left", ImGuiTableColumnFlags_WidthStretch);
311 ImGui::TableSetupColumn(
"Middle", ImGuiTableColumnFlags_WidthStretch);
312 ImGui::TableSetupColumn(
"Right", ImGuiTableColumnFlags_WidthFixed,
314 ImGui::TableNextRow();
317 ImGui::TableNextColumn();
320 "Hide room browser",
"Show room browser");
324 "Hide inspector",
"Show inspector");
328 "Switch to standalone panel workflow")) {
329 request_panel_mode =
true;
340 snprintf(title,
sizeof(title),
"[%03X] %s", rid, room_label.c_str());
341 ImGui::AlignTextToFramePadding();
342 ImGui::TextUnformatted(title);
343 if (ImGui::IsItemHovered()) {
344 ImGui::SetTooltip(
"%s", title);
348 ImGui::TableNextColumn();
352 "Enable split view (compare)")) {
353 const CompareDefaultResult def = PickDefaultCompareRoom(
363 ImGui::AlignTextToFramePadding();
367 const float avail = ImGui::GetContentRegionAvail().x;
368 const bool stacked = avail < kTightCompareStackThreshold;
385 if (ImGui::IsItemHovered()) {
386 ImGui::SetTooltip(
"Compare room ID");
391 "Swap active and compare rooms")) {
405 "Unsync compare view",
406 "Sync compare view to active")) {
412 "Disable split view")) {
419 ImGui::TableNextColumn();
422 const float total_w = right_cluster_w;
423 const float start_x =
424 ImGui::GetCursorPosX() +
425 std::max(0.0f, ImGui::GetContentRegionAvail().x - total_w);
426 ImGui::SetCursorPosX(start_x);
429 if (SquareIconButton(
"##GridToggle",
431 v ?
"Hide grid" :
"Show grid")) {
438 v ?
"Hide object bounds" :
"Show object bounds")) {
444 if (SquareIconButton(
446 v ?
"Hide hover coordinates" :
"Show hover coordinates")) {
452 if (SquareIconButton(
454 v ?
"Hide camera quadrants" :
"Show camera quadrants")) {
463 return request_panel_mode;
bool show_object_bounds() const
bool show_coordinate_overlay() const
bool show_camera_quadrant_overlay() const
void set_show_object_bounds(bool show)
void set_show_coordinate_overlay(bool show)
void set_show_camera_quadrant_overlay(bool show)
void set_show_grid(bool show)
static float GetTouchSafeWidgetHeight()
static float GetStandardWidgetHeight()
RAII guard for ImGui style colors.
RAII guard for ImGui style vars.
#define ICON_MD_GRID_VIEW
#define ICON_MD_MY_LOCATION
#define ICON_MD_VIEW_QUILT
#define ICON_MD_SWAP_HORIZ
#define ICON_MD_COMPARE_ARROWS
#define ICON_MD_CROP_SQUARE
Editors are the view controllers for the application.
InputHexResult InputHexWordEx(const char *label, uint16_t *data, float input_width, bool no_step)
std::string GetRoomLabel(int id)
Convenience function to get a room label.
bool show_right_inspector