23#include "imgui/imgui.h"
24#include "imgui/imgui_internal.h"
55 "Switch to standalone panel workflow (Ctrl+Shift+W)";
58 "Visit another room to seed compare history.";
60 "Visit another room first to seed compare history.";
64 float button_size = 0.0f;
74 layout.
width = toolbar_width;
75 layout.
spacing = ImGui::GetStyle().ItemSpacing.x;
82bool DrawToolbarActionButton(
const char*
id,
const char* label,
83 const ImVec2& size,
const char* tooltip,
87 int current_room,
int previous_room,
88 const std::function<
const std::deque<int>&()>& get_recent_rooms) {
89 if (previous_room >= 0 && previous_room != current_room) {
90 return {
true, previous_room};
92 if (get_recent_rooms) {
93 const auto& mru = get_recent_rooms();
95 if (rid != current_room) {
104 bool* value,
float btn_size,
const char* tooltip_on,
105 const char* tooltip_off) {
110 const float btn = btn_size;
113 const bool active = *value;
115 const ImVec4 col_btn = ImGui::GetStyleColorVec4(ImGuiCol_Button);
116 const ImVec4 col_active = ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive);
120 active ? col_active : col_btn);
122 ImGui::Button(active ? icon_on : icon_off, ImVec2(btn_w, btn));
124 if (ImGui::IsItemHovered()) {
125 ImGui::SetTooltip(
"%s", active ? tooltip_on : tooltip_off);
144 "Canvas view options")) {
150 ImGui::TextDisabled(tr(
"Canvas"));
152 if (ImGui::Checkbox(tr(
"Grid (8x8)"), &v)) {
156 if (ImGui::Checkbox(tr(
"Object Bounds"), &v)) {
160 if (ImGui::Checkbox(tr(
"Hover Coordinates"), &v)) {
164 if (ImGui::Checkbox(tr(
"Camera Quadrants"), &v)) {
172 ImGui::TextDisabled(tr(
"Authoring"));
174 if (ImGui::Checkbox(tr(
"Track Collision"), &v)) {
178 if (ImGui::Checkbox(tr(
"Custom Collision"), &v)) {
182 if (ImGui::Checkbox(tr(
"Water Fill (Oracle)"), &v)) {
186 if (ImGui::Checkbox(tr(
"Minecart Pathing"), &v)) {
190 if (ImGui::Checkbox(tr(
"Track Gaps"), &v)) {
194 if (ImGui::Checkbox(tr(
"Track Routes"), &v)) {
198 if (ImGui::Checkbox(tr(
"Custom Objects (Oracle)"), &v)) {
201 if (ImGui::IsItemHovered()) {
203 tr(
"Highlight custom-draw objects (IDs 0x31/0x32)\n"
204 "with a cyan overlay showing position and subtype."));
216 const float mode_height = toolbar_layout.
button_size;
217 const float connected_width =
220 ImVec2(connected_width, mode_height),
222 ?
"Return to single-room canvas"
223 :
"Stitched Rooms: browse the current room "
224 "and its neighbors as one canvas",
231 const ImVec2& size,
const char* tooltip,
236 if (tooltip && *tooltip && ImGui::IsItemHovered()) {
237 ImGui::SetTooltip(
"%s", tooltip);
243 int current_room_id,
int* compare_room_id,
244 const std::function<
const std::deque<int>&()>& get_recent_rooms,
245 char* search_buf,
size_t search_buf_size,
247 if (!compare_room_id || *compare_room_id < 0) {
250 const bool can_search = search_buf !=
nullptr && search_buf_size > 1;
251 const char* filter = can_search ? search_buf :
"";
256 snprintf(preview,
sizeof(preview),
"[%03X] %s", *compare_room_id,
259 auto to_lower = [](
unsigned char c) {
260 return static_cast<char>(std::tolower(c));
262 auto icontains = [&](
const std::string& haystack,
263 const char* needle) ->
bool {
264 if (!needle || *needle ==
'\0') {
267 const size_t nlen = std::strlen(needle);
268 for (
size_t i = 0; i + nlen <= haystack.size(); ++i) {
270 for (
size_t j = 0; j < nlen; ++j) {
271 if (to_lower(
static_cast<unsigned char>(haystack[i + j])) !=
272 to_lower(
static_cast<unsigned char>(needle[j]))) {
284 ImGui::SetNextItemWidth(std::clamp(ImGui::GetContentRegionAvail().x, 120.0f,
286 if (ImGui::BeginCombo(
"##CompareRoomPicker", preview,
287 ImGuiComboFlags_HeightLarge)) {
289 if (get_recent_rooms) {
290 const auto& mru = get_recent_rooms();
291 for (
int rid : mru) {
292 if (rid == current_room_id) {
296 const auto rid_label =
298 snprintf(item,
sizeof(item),
"[%03X] %s", rid, rid_label.c_str());
299 const bool is_selected = (rid == *compare_room_id);
300 if (ImGui::Selectable(item, is_selected)) {
301 *compare_room_id = rid;
308 ImGui::SetNextItemWidth(-1.0f);
311 search_buf, search_buf_size);
313 ImGui::TextDisabled(tr(
"Search unavailable"));
317 std::vector<int> filtered_rooms;
320 if (rid == current_room_id) {
325 snprintf(hex_buf,
sizeof(hex_buf),
"%03X", rid);
326 if (!icontains(rid_label, filter) && !icontains(hex_buf, filter)) {
329 filtered_rooms.push_back(rid);
334 ImGuiListClipper clipper;
335 clipper.Begin(
static_cast<int>(filtered_rooms.size()));
336 while (clipper.Step()) {
337 for (
int idx = clipper.DisplayStart; idx < clipper.DisplayEnd; ++idx) {
338 const int rid = filtered_rooms[idx];
339 const auto rid_label =
342 snprintf(item,
sizeof(item),
"[%03X] %s", rid, rid_label.c_str());
343 const bool is_selected = (rid == *compare_room_id);
344 if (ImGui::Selectable(item, is_selected)) {
345 *compare_room_id = rid;
353 if (ImGui::IsItemHovered()) {
370 const char* tooltip = compare_active ?
"Compare settings" :
"Start compare";
382 if (!compare_active) {
384 ImGui::TextDisabled(tr(
"No recent room to compare"));
388 ImGui::BeginDisabled();
390 if (ImGui::MenuItem(tr(
"Start Compare"))) {
396 ImGui::EndDisabled();
399 ImGui::TextDisabled(tr(
"Compare Room"));
404 uint16_t cmp =
static_cast<uint16_t
>(
411 if (ImGui::IsItemHovered()) {
417 if (ImGui::MenuItem(tr(
"Swap Rooms"))) {
430 if (ImGui::MenuItem(tr(
"End Compare"))) {
448 ImGui::TextDisabled(tr(
"Workbench toolbar not wired"));
452 const ToolbarLayout layout =
453 ResolveToolbarLayout(std::max(ImGui::GetContentRegionAvail().x, 1.0f));
454 bool request_panel_mode =
false;
458 const ImVec2 frame_pad = ImGui::GetStyle().FramePadding;
460 ImGuiStyleVar_FramePadding, ImVec2(std::max(4.0f, frame_pad.x - 1.0f),
461 std::max(3.0f, frame_pad.y - 1.0f)));
463 ImGuiStyleVar_ItemSpacing,
464 ImVec2(std::max(layout.spacing, 4.0f),
465 std::max(3.0f, ImGui::GetStyle().ItemSpacing.y - 1.0f)));
470 const float right_icon_width =
472 float right_actions_width = right_icon_width;
474 right_actions_width +=
479 const float room_matrix_chunk =
481 kToolbarRoomReviewLabel, layout.button_size);
482 if (show_room_matrix) {
483 right_actions_width += room_matrix_chunk;
491 const float toggle_w = layout.button_size;
496 const float nav_w = kToolbarClusterGap + 4.0f * layout.button_size +
497 3.0f * ImGui::GetStyle().ItemSpacing.x;
499 const float stitched_w =
501 kToolbarModeConnectedLabel, layout.button_size);
502 const float essential_left =
503 toggle_w + kToolbarActionGap + toggle_w + nav_w + stitched_w;
505 const float apply_room_chunk =
508 const float dungeon_map_chunk =
512 const float compare_chunk = kToolbarClusterGap + kCompactCompareButtonWidth;
514 constexpr float kSafetyMargin = 8.0f;
515 float remaining_for_optional =
516 layout.width - essential_left - right_actions_width - kSafetyMargin;
518 auto try_show = [&](
float chunk_w) ->
bool {
519 if (remaining_for_optional >= chunk_w) {
520 remaining_for_optional -= chunk_w;
528 const bool show_compare = try_show(compare_chunk);
529 const bool show_apply_room =
531 const bool show_dungeon_map =
533 if (show_room_matrix && remaining_for_optional < 0.0f) {
534 show_room_matrix =
false;
535 right_actions_width -= room_matrix_chunk;
550 "Hide room browser",
"Show room browser");
551 ImGui::SameLine(0.0f, kToolbarActionGap);
554 "Hide inspector",
"Show inspector");
556 ImGui::SameLine(0.0f, kToolbarClusterGap);
560 if (show_apply_room) {
561 ImGui::SameLine(0.0f, kToolbarActionGap);
564 "Apply this room into the loaded ROM buffer "
565 "(File > Save ROM persists to disk)")) {
569 if (show_dungeon_map) {
570 ImGui::SameLine(0.0f, kToolbarActionGap);
573 "Open the Dungeon Map popup")) {
578 ImGui::SameLine(0.0f, kToolbarClusterGap);
579 DrawCanvasModeSelector(p.
layout, layout);
582 ImGui::SameLine(0.0f, kToolbarClusterGap);
583 DrawCompareMenu(p, layout);
586 const float right_start =
587 std::max(ImGui::GetCursorPosX() + kToolbarActionGap,
588 ImGui::GetWindowContentRegionMax().x - right_actions_width);
589 ImGui::SameLine(right_start, 0.0f);
592 ImGui::SameLine(0.0f, kToolbarActionGap);
595 kToolbarPanelWorkflowTooltip)) {
596 request_panel_mode =
true;
599 if (show_room_matrix) {
600 ImGui::SameLine(0.0f, kToolbarActionGap);
602 kToolbarRoomReviewLabel, layout.button_size);
603 if (DrawToolbarActionButton(
"RoomMatrix", kToolbarRoomReviewLabel,
604 ImVec2(review_button_width, layout.button_size),
605 kToolbarRoomMatrixTooltip)) {
610 return request_panel_mode;
bool show_object_bounds() const
void set_show_water_fill_overlay(bool show)
void set_show_custom_collision_overlay(bool show)
void set_show_track_route_overlay(bool show)
void SetConnectedControlsInline(bool inline_controls)
bool show_track_gap_overlay() const
void set_show_custom_objects_overlay(bool show)
bool show_custom_objects_overlay() const
void set_show_track_collision_overlay(bool show)
void set_show_minecart_sprite_overlay(bool show)
bool show_coordinate_overlay() const
bool show_track_collision_overlay() const
bool show_minecart_sprite_overlay() const
bool show_water_fill_overlay() const
bool show_camera_quadrant_overlay() const
void set_show_object_bounds(bool show)
void set_show_coordinate_overlay(bool show)
const project::YazeProject * project() const
bool show_track_route_overlay() const
void set_show_track_gap_overlay(bool show)
void set_show_camera_quadrant_overlay(bool show)
bool show_custom_collision_overlay() const
void set_show_grid(bool show)
static float GetStandardWidgetHeight()
RAII guard for ImGui style colors.
RAII guard for ImGui style vars.
#define ICON_MD_GRID_VIEW
#define ICON_MD_VIEW_QUILT
#define ICON_MD_COMPARE_ARROWS
#define ICON_MD_VISIBILITY
std::string GetRoomLabel(const project::YazeProject *project, int room_id)
float CalcIconButtonWidth(const char *icon, float button_height)
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)
Editors are the view controllers for the application.
bool ToggleButton(const char *label, bool active, const ImVec2 &size)
InputHexResult InputHexWordEx(const char *label, uint16_t *data, float input_width, bool no_step)
bool show_connected_canvas_view
bool show_right_inspector
static constexpr float kIconButtonSmall
Modern project structure with comprehensive settings consolidation.