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);
171 "Canvas view options")) {
187 "Choose which edited room content is saved")) {
211 "Edit the current room",
222 "Dungeon overview: click a room preview to edit it",
230 const ImVec2& size,
const char* tooltip,
239 if (tooltip && *tooltip && ImGui::IsItemHovered()) {
240 ImGui::SetTooltip(
"%s", tooltip);
248 ImGui::TextUnformatted(tr(
"Compare with room"));
260 if (ImGui::Button(tr(
"End compare"))) {
262 ImGui::CloseCurrentPopup();
264 if (ImGui::Button(tr(
"Swap rooms"))) {
275 const bool search_available =
277 ImGui::SetNextItemWidth(-1);
278 if (search_available)
282 std::transform(filter.begin(), filter.end(), filter.begin(),
283 [](
unsigned char c) { return std::tolower(c); });
289 const std::string label = absl::StrFormat(
293 std::string lower = label;
294 std::transform(lower.begin(), lower.end(), lower.begin(),
295 [](
unsigned char c) { return std::tolower(c); });
296 if (lower.find(filter) == std::string::npos)
299 if (ImGui::Selectable(label.c_str(),
304 ImGui::CloseCurrentPopup();
313 ImGuiCond_Appearing);
347 ImGui::TextDisabled(tr(
"Recent Rooms"));
354 std::vector<int> recent_ids;
357 recent_ids.assign(recent.begin(), recent.end());
359 std::vector<int> to_forget;
361 for (
int room_id : recent_ids) {
362 ImGui::PushID(room_id);
364 const bool room_dirty =
367 const auto room_name =
369 char item_label[160];
370 snprintf(item_label,
sizeof(item_label),
"[%03X]%s %s##RecentRoom", room_id,
371 room_dirty ?
"*" :
"", room_name.c_str());
373 if (ImGui::Selectable(item_label, is_current) && !is_current) {
380 if (ImGui::IsItemHovered()) {
381 ImGui::SetTooltip(
"Click to open; right-click for actions%s",
382 room_dirty ?
"\nPending room changes" :
"");
386 std::vector<gui::MenuItemSpec> items;
388 items.emplace_back(
"Open as Panel", ICON_MD_OPEN_IN_NEW,
389 [&p, room_id]() { p.on_open_room_panel(room_id); });
393 p.layout->show_connected_canvas_view = false;
396 *p.split_view_enabled = true;
399 *p.compare_room_id = room_id;
402 items.back().separator_after =
true;
404 "Copy Room ID", absl::StrFormat(
"0x%03X", room_id)));
406 items.back().separator_after =
true;
409 [&to_forget, room_id]() { to_forget.push_back(room_id); });
416 for (
int room_id : to_forget) {
417 p.forget_recent_room(room_id);
428 ImGui::BeginDisabled();
435 ImGui::EndDisabled();
452 auto append = [&](
float item_width) {
463 if (visibility.
tools) {
484 float left_width = 0.0f;
485 auto append_left = [&](
float item_width,
float gap) {
486 if (left_width > 0.0f) {
489 left_width += item_width;
501 const float navigation_width =
502 4.0f * ImGui::GetFrameHeight() + 4.0f * ImGui::GetStyle().ItemSpacing.x +
503 ImGui::CalcTextSize(
"00000").x + ImGui::GetStyle().FramePadding.x * 2.0f;
553 constexpr float kSafetyMargin = 4.0f;
562 auto collapse = [&](
bool& item) {
583 if (collapse(visibility.
compare))
589 if (collapse(visibility.
layers))
591 if (collapse(visibility.
tools))
602 const float button_width =
606 "More dungeon actions")) {
610 bool request_panel_mode =
false;
612 return request_panel_mode;
626 if (ImGui::MenuItem(
ICON_MD_LIST " Room Browser",
nullptr,
638 const bool has_history =
645 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
651 "Room view",
nullptr,
656 if (ImGui::MenuItem(
"Dungeon overview",
nullptr,
666 const bool has_hidden_room_action =
670 if (has_hidden_room_action) {
684 if (ImGui::BeginMenu(
"Display")) {
699 request_panel_mode =
true;
701 if (ImGui::IsItemHovered()) {
707 return request_panel_mode;
712bool DungeonWorkbenchToolbar::ShouldShowInlineRoomNav(
float toolbar_width) {
720 ImGui::TextDisabled(tr(
"Workbench toolbar not wired"));
724 const ToolbarLayout layout =
725 ResolveToolbarLayout(std::max(ImGui::GetContentRegionAvail().x, 1.0f));
726 bool request_panel_mode =
false;
730 const ImVec2 frame_pad = ImGui::GetStyle().FramePadding;
732 ImGuiStyleVar_FramePadding, ImVec2(std::max(4.0f, frame_pad.x - 1.0f),
733 std::max(3.0f, frame_pad.y - 1.0f)));
735 ImGuiStyleVar_ItemSpacing,
736 ImVec2(std::max(layout.spacing, 4.0f),
737 std::max(3.0f, ImGui::GetStyle().ItemSpacing.y - 1.0f)));
738 const ToolbarVisibility visibility = ResolveToolbarVisibility(p, layout);
739 const float right_actions_width =
740 ToolbarRightActionsWidth(p, layout, visibility);
752 if (visibility.pane_toggles) {
755 "Hide room browser",
"Show room browser");
756 ImGui::SameLine(0.0f, kToolbarActionGap);
759 "Hide inspector",
"Show inspector");
760 ImGui::SameLine(0.0f, kToolbarClusterGap);
764 if (visibility.stitched_rooms) {
765 ImGui::SameLine(0.0f, kToolbarClusterGap);
766 DrawCanvasModeSelector(p, layout);
769 if (visibility.entrance) {
770 ImGui::SameLine(0.0f, kToolbarClusterGap);
773 if (visibility.layers) {
774 ImGui::SameLine(0.0f, kToolbarClusterGap);
779 if (visibility.recent_rooms) {
780 ImGui::SameLine(0.0f, kToolbarActionGap);
781 DrawRecentRoomsMenu(p, layout);
784 if (visibility.apply_room) {
785 ImGui::SameLine(0.0f, kToolbarActionGap);
786 if (workbench::DrawHeaderIconAction(
788 "Apply this room into the loaded ROM buffer "
789 "(File > Save ROM persists to disk)")) {
793 if (visibility.dungeon_map) {
794 ImGui::SameLine(0.0f, kToolbarActionGap);
795 if (workbench::DrawHeaderIconAction(
"DungeonMapToolbar",
ICON_MD_MAP,
797 "Open the Dungeon Map popup")) {
802 if (visibility.compare) {
803 ImGui::SameLine(0.0f, kToolbarClusterGap);
804 DrawCompareMenu(p, layout);
807 if (right_actions_width > 0.0f) {
808 const float last_left_edge =
809 ImGui::GetItemRectMax().x - ImGui::GetWindowPos().x;
810 const float right_start =
811 std::max(last_left_edge + kToolbarActionGap,
812 ImGui::GetWindowContentRegionMax().x - right_actions_width);
813 ImGui::SameLine(right_start, 0.0f);
815 bool drew_right_action =
false;
816 if (visibility.view_options) {
817 DrawViewOptionsButton(p, layout);
818 drew_right_action =
true;
820 if (visibility.tools) {
821 if (drew_right_action) {
822 ImGui::SameLine(0.0f, kToolbarActionGap);
825 drew_right_action =
true;
827 if (visibility.save_content) {
828 if (drew_right_action) {
829 ImGui::SameLine(0.0f, kToolbarActionGap);
831 DrawSaveContentButton(p, layout);
832 drew_right_action =
true;
834 if (visibility.panel_mode) {
835 if (drew_right_action) {
836 ImGui::SameLine(0.0f, kToolbarActionGap);
840 kToolbarPanelWorkflowTooltip)) {
841 request_panel_mode =
true;
843 drew_right_action =
true;
845 if (visibility.overflow) {
846 if (drew_right_action) {
847 ImGui::SameLine(0.0f, kToolbarActionGap);
849 request_panel_mode |= DrawToolbarOverflowMenu(p, layout, visibility);
852 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.