12#include "absl/strings/str_format.h"
27#include "imgui/imgui.h"
28#include "imgui/imgui_internal.h"
61 "Switch to standalone panel workflow";
63 "Visit another room to build room history.";
67 float button_size = 0.0f;
77 bool entrance =
false;
78 bool pane_toggles =
true;
79 bool recent_rooms =
true;
80 bool stitched_rooms =
true;
82 bool apply_room =
false;
83 bool dungeon_map =
false;
84 bool view_options =
false;
86 bool save_content =
false;
87 bool panel_mode =
false;
88 bool overflow =
false;
93 layout.
width = toolbar_width;
94 layout.
spacing = ImGui::GetStyle().ItemSpacing.x;
101bool DrawToolbarActionButton(
const char*
id,
const char* label,
102 const ImVec2& size,
const char* tooltip,
103 bool active =
false);
106 int current_room,
int previous_room,
107 const std::function<
const std::deque<int>&()>& get_recent_rooms) {
108 if (previous_room >= 0 && previous_room != current_room) {
109 return {
true, previous_room};
111 if (get_recent_rooms) {
112 const auto& mru = get_recent_rooms();
113 for (
int rid : mru) {
114 if (rid != current_room) {
123 bool* value,
float btn_size,
const char* tooltip_on,
124 const char* tooltip_off) {
129 const float btn = btn_size;
132 const bool active = *value;
134 const ImVec4 col_btn = ImGui::GetStyleColorVec4(ImGuiCol_Button);
135 const ImVec4 col_active = ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive);
139 active ? col_active : col_btn);
141 ImGui::Button(active ? icon_on : icon_off, ImVec2(btn_w, btn));
143 if (ImGui::IsItemHovered()) {
144 ImGui::SetTooltip(
"%s", active ? tooltip_on : tooltip_off);
175 "Canvas view options")) {
191 "Choose which edited room content is saved")) {
215 "Edit the current room",
226 "Dungeon overview: click a room preview to edit it",
234 const ImVec2& size,
const char* tooltip,
243 if (tooltip && *tooltip && ImGui::IsItemHovered()) {
244 ImGui::SetTooltip(
"%s", tooltip);
252 ImGui::TextUnformatted(tr(
"Compare with room"));
264 if (ImGui::Button(tr(
"End compare"))) {
266 ImGui::CloseCurrentPopup();
268 if (ImGui::Button(tr(
"Swap rooms"))) {
279 const bool search_available =
281 ImGui::SetNextItemWidth(-1);
282 if (search_available)
286 std::transform(filter.begin(), filter.end(), filter.begin(),
287 [](
unsigned char c) { return std::tolower(c); });
293 const std::string label = absl::StrFormat(
297 std::string lower = label;
298 std::transform(lower.begin(), lower.end(), lower.begin(),
299 [](
unsigned char c) { return std::tolower(c); });
300 if (lower.find(filter) == std::string::npos)
303 if (ImGui::Selectable(label.c_str(),
308 ImGui::CloseCurrentPopup();
317 ImGuiCond_Appearing);
351 ImGui::TextDisabled(tr(
"Recent Rooms"));
358 std::vector<int> recent_ids;
361 recent_ids.assign(recent.begin(), recent.end());
363 std::vector<int> to_forget;
365 for (
int room_id : recent_ids) {
366 ImGui::PushID(room_id);
368 const bool room_dirty =
371 const auto room_name =
373 char item_label[160];
374 snprintf(item_label,
sizeof(item_label),
"[%03X]%s %s##RecentRoom", room_id,
375 room_dirty ?
"*" :
"", room_name.c_str());
377 if (ImGui::Selectable(item_label, is_current) && !is_current) {
384 if (ImGui::IsItemHovered()) {
385 ImGui::SetTooltip(
"Click to open; right-click for actions%s",
386 room_dirty ?
"\nPending room changes" :
"");
390 std::vector<gui::MenuItemSpec> items;
392 items.emplace_back(
"Open as Panel", ICON_MD_OPEN_IN_NEW,
393 [&p, room_id]() { p.on_open_room_panel(room_id); });
397 p.layout->show_connected_canvas_view = false;
400 *p.split_view_enabled = true;
403 *p.compare_room_id = room_id;
406 items.back().separator_after =
true;
408 "Copy Room ID", absl::StrFormat(
"0x%03X", room_id)));
410 items.back().separator_after =
true;
413 [&to_forget, room_id]() { to_forget.push_back(room_id); });
420 for (
int room_id : to_forget) {
421 p.forget_recent_room(room_id);
432 ImGui::BeginDisabled();
439 ImGui::EndDisabled();
456 auto append = [&](
float item_width) {
467 if (visibility.
tools) {
488 float left_width = 0.0f;
489 auto append_left = [&](
float item_width,
float gap) {
490 if (left_width > 0.0f) {
493 left_width += item_width;
505 const float navigation_width =
506 4.0f * ImGui::GetFrameHeight() + 4.0f * ImGui::GetStyle().ItemSpacing.x +
507 ImGui::CalcTextSize(
"00000").x + ImGui::GetStyle().FramePadding.x * 2.0f;
557 constexpr float kSafetyMargin = 4.0f;
566 auto collapse = [&](
bool& item) {
587 if (collapse(visibility.
compare))
593 if (collapse(visibility.
layers))
595 if (collapse(visibility.
tools))
606 const float button_width =
610 "More dungeon actions")) {
614 bool request_panel_mode =
false;
616 return request_panel_mode;
630 if (ImGui::MenuItem(
ICON_MD_LIST " Room Browser",
nullptr,
642 const bool has_history =
649 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
655 "Room view",
nullptr,
660 if (ImGui::MenuItem(
"Dungeon overview",
nullptr,
670 const bool has_hidden_room_action =
674 if (has_hidden_room_action) {
688 if (ImGui::BeginMenu(
"Display")) {
703 request_panel_mode =
true;
705 if (ImGui::IsItemHovered()) {
711 return request_panel_mode;
716bool DungeonWorkbenchToolbar::ShouldShowInlineRoomNav(
float toolbar_width) {
724 ImGui::TextDisabled(tr(
"Workbench toolbar not wired"));
728 const ToolbarLayout layout =
729 ResolveToolbarLayout(std::max(ImGui::GetContentRegionAvail().x, 1.0f));
730 bool request_panel_mode =
false;
734 const ImVec2 frame_pad = ImGui::GetStyle().FramePadding;
736 ImGuiStyleVar_FramePadding, ImVec2(std::max(4.0f, frame_pad.x - 1.0f),
737 std::max(3.0f, frame_pad.y - 1.0f)));
739 ImGuiStyleVar_ItemSpacing,
740 ImVec2(std::max(layout.spacing, 4.0f),
741 std::max(3.0f, ImGui::GetStyle().ItemSpacing.y - 1.0f)));
742 const ToolbarVisibility visibility = ResolveToolbarVisibility(p, layout);
743 const float right_actions_width =
744 ToolbarRightActionsWidth(p, layout, visibility);
756 if (visibility.pane_toggles) {
759 "Hide room browser",
"Show room browser");
760 ImGui::SameLine(0.0f, kToolbarActionGap);
763 "Hide inspector",
"Show inspector");
764 ImGui::SameLine(0.0f, kToolbarClusterGap);
768 if (visibility.stitched_rooms) {
769 ImGui::SameLine(0.0f, kToolbarClusterGap);
770 DrawCanvasModeSelector(p, layout);
773 if (visibility.entrance) {
774 ImGui::SameLine(0.0f, kToolbarClusterGap);
777 if (visibility.layers) {
778 ImGui::SameLine(0.0f, kToolbarClusterGap);
783 if (visibility.recent_rooms) {
784 ImGui::SameLine(0.0f, kToolbarActionGap);
785 DrawRecentRoomsMenu(p, layout);
788 if (visibility.apply_room) {
789 ImGui::SameLine(0.0f, kToolbarActionGap);
790 if (workbench::DrawHeaderIconAction(
792 "Apply this room into the loaded ROM buffer "
793 "(File > Save ROM persists to disk)")) {
797 if (visibility.dungeon_map) {
798 ImGui::SameLine(0.0f, kToolbarActionGap);
799 if (workbench::DrawHeaderIconAction(
"DungeonMapToolbar",
ICON_MD_MAP,
801 "Open the Dungeon Map popup")) {
806 if (visibility.compare) {
807 ImGui::SameLine(0.0f, kToolbarClusterGap);
808 DrawCompareMenu(p, layout);
811 if (right_actions_width > 0.0f) {
812 const float last_left_edge =
813 ImGui::GetItemRectMax().x - ImGui::GetWindowPos().x;
814 const float right_start =
815 std::max(last_left_edge + kToolbarActionGap,
816 ImGui::GetWindowContentRegionMax().x - right_actions_width);
817 ImGui::SameLine(right_start, 0.0f);
819 bool drew_right_action =
false;
820 if (visibility.view_options) {
821 DrawViewOptionsButton(p, layout);
822 drew_right_action =
true;
824 if (visibility.tools) {
825 if (drew_right_action) {
826 ImGui::SameLine(0.0f, kToolbarActionGap);
829 drew_right_action =
true;
831 if (visibility.save_content) {
832 if (drew_right_action) {
833 ImGui::SameLine(0.0f, kToolbarActionGap);
835 DrawSaveContentButton(p, layout);
836 drew_right_action =
true;
838 if (visibility.panel_mode) {
839 if (drew_right_action) {
840 ImGui::SameLine(0.0f, kToolbarActionGap);
844 kToolbarPanelWorkflowTooltip)) {
845 request_panel_mode =
true;
847 drew_right_action =
true;
849 if (visibility.overflow) {
850 if (drew_right_action) {
851 ImGui::SameLine(0.0f, kToolbarActionGap);
853 request_panel_mode |= DrawToolbarOverflowMenu(p, layout, visibility);
856 return request_panel_mode;
DungeonRoomStore * rooms() const
void SetConnectedControlsInline(bool inline_controls)
const project::YazeProject * project() const
zelda3::Room * GetIfMaterialized(int room_id)
static float GetStandardWidgetHeight()
RAII guard for ImGui style colors.
RAII guard for ImGui style vars.
bool HasUnsavedChanges() const
#define ICON_MD_VIEW_QUILT
#define ICON_MD_COMPARE_ARROWS
#define ICON_MD_MORE_HORIZ
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)
Editors are the view controllers for the application.
void DrawDungeonOverlayControls(DungeonCanvasViewer &viewer)
void DrawDungeonLayerControls(DungeonCanvasViewer &viewer, int room_id, float height)
float DungeonLayerControlsWidth()
void AutoRegisterLastItem(const std::string &widget_type, const std::string &explicit_label, const std::string &description)
Automatically register the last ImGui item.
bool ToggleButton(const char *label, bool active, const ImVec2 &size)
bool ItemContextMenu(const char *id, const std::function< std::vector< MenuItemSpec >()> &build, ImGuiPopupFlags flags)
Right-click menu for the last submitted ImGui item.
MenuItemSpec CopyToClipboardItem(const std::string &label, const std::string &text)
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.