9#include "imgui/imgui.h"
16 std::shared_ptr<zelda3::DungeonObjectEditor> object_editor)
17 : object_editor_(std::move(object_editor)) {}
58 auto& interaction = viewer->object_interaction();
65 auto indices = interaction.GetSelectedObjectIndices();
67 for (
size_t idx : indices) {
80 ImGui::TextDisabled(
"Object editor unavailable");
90 }
else if (viewer->object_interaction().HasEntitySelection()) {
93 "An entity is selected. Use the matching editor for entity-specific "
98 "Select one or more room objects to edit their properties here.");
112 const auto& interaction = viewer->object_interaction();
113 const size_t selection_count = interaction.GetSelectionCount();
115 if (selection_count == 0) {
116 ImGui::TextColored(theme.text_secondary_gray,
118 " Click room objects to edit them here.");
126 if (selection_count == 1) {
127 ImGui::TextColored(theme.status_success,
130 ImGui::TextColored(theme.status_success,
143 if (ImGui::BeginTable(
"##ObjectEditorActions", 5,
144 ImGuiTableFlags_SizingStretchSame |
145 ImGuiTableFlags_NoPadOuterX)) {
146 ImGui::TableNextRow();
148 ImGui::TableNextColumn();
153 ImGui::TableNextColumn();
158 ImGui::TableNextColumn();
163 ImGui::TableNextColumn();
168 ImGui::TableNextColumn();
170 ImVec2(0.08f, 0.5f));
184 if (!viewer || !viewer->HasRooms()) {
188 auto& interaction = viewer->object_interaction();
189 auto selected = interaction.GetSelectedObjectIndices();
190 if (selected.empty()) {
194 if (selected.size() == 1) {
196 if (selected[0] < objects.size()) {
197 const auto& obj = objects[selected[0]];
199 ImGui::TextColored(theme.status_success,
201 " Selected object #%zu ยท 0x%03X %s",
202 selected[0], obj.id_,
204 ImGui::TextColored(theme.text_secondary_gray,
205 "Position (%d, %d) Size 0x%02X Layer %s Draws %s",
206 obj.x_, obj.y_, obj.size_,
212 semantics.effective_bg_layer));
220 ImGui::TextColored(theme.text_secondary_gray,
221 "Use Ctrl+D to duplicate, Delete to remove, or Arrow Keys "
222 "to nudge the selection.");
231 ImGui::SetNextWindowSize(ImVec2(340, 0), ImGuiCond_Appearing);
233 ImGuiWindowFlags_NoCollapse)) {
235 auto shortcut_row = [&](
const char* keys,
const char* desc) {
236 ImGui::TextColored(theme.status_warning,
"%-18s", keys);
238 ImGui::TextUnformatted(desc);
243 shortcut_row(
"Ctrl+A",
"Select all objects");
244 shortcut_row(
"Ctrl+Shift+A",
"Deselect all");
245 shortcut_row(
"Tab / Shift+Tab",
"Cycle selection");
246 shortcut_row(
"Escape",
"Clear selection");
249 ImGui::TextColored(theme.status_success,
ICON_MD_EDIT " Editing");
251 shortcut_row(
"Delete",
"Remove selected");
252 shortcut_row(
"Ctrl+D",
"Duplicate selected");
253 shortcut_row(
"Ctrl+C",
"Copy selected");
254 shortcut_row(
"Ctrl+V",
"Paste");
255 shortcut_row(
"Ctrl+Z",
"Undo");
256 shortcut_row(
"Ctrl+Shift+Z",
"Redo");
261 shortcut_row(
"Arrow Keys",
"Nudge selected (1px)");
267 if (!ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows)) {
271 const ImGuiIO& io = ImGui::GetIO();
273 if (ImGui::IsKeyPressed(ImGuiKey_A) && io.KeyCtrl && !io.KeyShift) {
276 if (ImGui::IsKeyPressed(ImGuiKey_A) && io.KeyCtrl && io.KeyShift) {
279 if (ImGui::IsKeyPressed(ImGuiKey_Delete)) {
282 if (ImGui::IsKeyPressed(ImGuiKey_D) && io.KeyCtrl) {
285 if (ImGui::IsKeyPressed(ImGuiKey_C) && io.KeyCtrl) {
288 if (ImGui::IsKeyPressed(ImGuiKey_V) && io.KeyCtrl) {
291 if (ImGui::IsKeyPressed(ImGuiKey_Z) && io.KeyCtrl && !io.KeyShift) {
294 if ((ImGui::IsKeyPressed(ImGuiKey_Z) && io.KeyCtrl && io.KeyShift) ||
295 (ImGui::IsKeyPressed(ImGuiKey_Y) && io.KeyCtrl)) {
302 if (ImGui::IsKeyPressed(ImGuiKey_LeftArrow)) {
305 if (ImGui::IsKeyPressed(ImGuiKey_RightArrow)) {
308 if (ImGui::IsKeyPressed(ImGuiKey_UpArrow)) {
311 if (ImGui::IsKeyPressed(ImGuiKey_DownArrow)) {
314 if (dx != 0 || dy != 0) {
319 if (ImGui::IsKeyPressed(ImGuiKey_Tab) && !io.KeyCtrl) {
323 if (ImGui::IsKeyPressed(ImGuiKey_Escape)) {
327 if (ImGui::IsKeyPressed(ImGuiKey_Slash) && io.KeyShift) {
339 std::vector<size_t> all_indices;
340 all_indices.reserve(objects.size());
341 for (
size_t i = 0; i < objects.size(); ++i) {
342 all_indices.push_back(i);
361 if (selected.empty()) {
365 std::vector<size_t> sorted_indices(selected.begin(), selected.end());
366 std::sort(sorted_indices.rbegin(), sorted_indices.rend());
367 for (
size_t idx : sorted_indices) {
370 interaction.ClearSelection();
380 if (selected.empty()) {
384 std::vector<size_t> new_indices;
385 for (
size_t idx : selected) {
387 if (new_idx.has_value()) {
388 new_indices.push_back(*new_idx);
391 interaction.SetSelectedObjects(new_indices);
408 if (!new_indices.empty()) {
418 const auto& selected =
420 if (selected.empty()) {
424 for (
size_t idx : selected) {
437 const size_t total_objects = objects.size();
438 if (total_objects == 0) {
442 const size_t current_idx = selected.empty() ? 0 : selected.front();
443 const size_t next_idx =
444 (current_idx + direction + total_objects) % total_objects;
445 interaction.SetSelectedObjects({next_idx});
455 if (index >= objects.size()) {
459 const auto& obj = objects[index];
DungeonObjectInteraction & object_interaction()
void ScrollToTile(int tile_x, int tile_y)
void SetSelectedObjects(const std::vector< size_t > &indices)
std::vector< size_t > GetSelectedObjectIndices() const
void SetSelectionChangeCallback(std::function< void()> callback)
void Draw(bool *p_open) override
Draw the panel content.
DungeonCanvasViewer * ResolveCanvasViewer()
void HandleKeyboardShortcuts()
std::function< DungeonCanvasViewer *()> canvas_viewer_provider_
void DuplicateSelectedObjects()
void DeselectAllObjects()
void DrawSelectionActions()
void CycleObjectSelection(int direction)
void DrawKeyboardShortcutHelp()
void NudgeSelectedObjects(int dx, int dy)
ObjectEditorContent(std::shared_ptr< zelda3::DungeonObjectEditor > object_editor=nullptr)
void DrawSelectionSummary()
void ScrollToObject(size_t index)
void SetCanvasViewer(DungeonCanvasViewer *viewer)
size_t cached_selection_count_
DungeonCanvasViewer * canvas_viewer_
bool selection_callbacks_setup_
void SetupSelectionCallbacks()
void OnSelectionChanged()
void DeleteSelectedObjects()
void CopySelectedObjects()
std::shared_ptr< zelda3::DungeonObjectEditor > object_editor_
void DrawSelectedObjectInfo()
RAII guard for ImGui style vars.
#define ICON_MD_OPEN_WITH
#define ICON_MD_FILTER_NONE
#define ICON_MD_CONTENT_PASTE
#define ICON_MD_CHECK_CIRCLE
#define ICON_MD_HELP_OUTLINE
#define ICON_MD_SELECT_ALL
#define ICON_MD_CONTENT_COPY
const AgentUITheme & GetTheme()
Editors are the view controllers for the application.
void SectionHeader(const char *icon, const char *label, const ImVec4 &color)
ObjectLayerSemantics GetObjectLayerSemantics(const RoomObject &object)
std::string GetObjectName(int object_id)
const char * EffectiveBgLayerLabel(EffectiveBgLayer layer)