8#include "absl/strings/str_format.h"
9#include "absl/strings/str_join.h"
13#include "imgui/imgui_internal.h"
24 a_camera.dirty = b_camera.dirty =
false;
25 return a_camera == b_camera &&
36 a_camera.dirty = b_camera.dirty =
false;
46template <
typename Record>
53 std::shared_ptr<const int> gesture,
54 uint64_t save_generation)
55 : slot_index_(slot_index),
58 apply_(std::move(apply)),
59 gesture_(std::move(gesture)),
60 save_generation_(save_generation) {}
62 absl::Status
Undo()
override {
return apply_(before_); }
63 absl::Status
Redo()
override {
return apply_(after_); }
65 return absl::StrFormat(
"Edit entrance properties 0x%02X", slot_index_);
68 return sizeof(*this) + Description().size();
75 return prev && gesture_ && gesture_ == prev->
gesture_ &&
76 save_generation_ == prev->save_generation_ &&
77 slot_index_ == prev->slot_index_ &&
78 before_.dirty() == prev->after_.dirty() &&
103 : slot_index_(slot_index),
104 before_(std::move(before)),
105 after_(std::move(after)),
106 apply_(std::move(apply)) {}
108 absl::Status
Undo()
override {
return apply_(before_); }
109 absl::Status
Redo()
override {
return apply_(after_); }
111 return absl::StrFormat(
"Repair entrance camera 0x%02X", slot_index_);
114 return sizeof(*this) + Description().size();
127 const ImGuiID active_id = ImGui::GetActiveID();
131 active_id != 0 ? std::make_shared<const int>(0) :
nullptr;
136 const char* widget_label) {
139 ImGui::PushID(field_label);
140 const ImGuiID input_id = ImGui::GetID(
"");
142 const auto& item = ImGui::GetCurrentContext()->LastItemData;
144 metadata.
label = widget_label;
145 metadata.
visible = ImGui::IsItemVisible();
146 metadata.
enabled = (item.ItemFlags & ImGuiItemFlags_Disabled) == 0;
148 item.Rect.Min.x, item.Rect.Min.y, item.Rect.Max.x, item.Rect.Max.y,
true};
150 "Dungeon/Entrances/input:" +
152 "input", input_id,
"", metadata);
179 SameProperties(before, after)) {
185 std::make_unique<DungeonEntrancePropertiesAction<zelda3::RoomEntrance>>(
186 slot_index, before, after,
196 std::shared_ptr<const int> gesture) {
199 SameProperties(before, after)) {
206 DungeonEntrancePropertiesAction<zelda3::DungeonSpawnPoint>>(
207 slot_index, before, after,
217 return absl::OutOfRangeError(
"Dungeon entrance slot is out of range");
222 return absl::FailedPreconditionError(
"Dungeon entrance is mismatched");
227 return absl::OkStatus();
233 return absl::OutOfRangeError(
"Dungeon spawn slot is out of range");
237 return absl::FailedPreconditionError(
"Dungeon spawn point is unavailable");
242 return absl::OkStatus();
252 if (saved.ok() && SameProperties(spawn, *saved)) {
263 if (saved.
load_status().ok() && SameProperties(entrance, saved)) {
264 entrance.ClearDirty();
268 entrance.MarkDirty();
272std::optional<DungeonEntranceCameraState>
274 if (slot_index < 0 || slot_index >=
static_cast<int>(
entrances_.size())) {
284 const auto& entrance =
entrances_[slot_index];
293 if (slot_index < 0 || slot_index >=
static_cast<int>(
entrances_.size())) {
294 return absl::OutOfRangeError(
"Dungeon entrance slot is out of range");
300 return absl::FailedPreconditionError(
301 "Dungeon spawn point is unavailable or mismatched");
308 return absl::FailedPreconditionError(
309 "Dungeon entrance is unavailable or mismatched");
315 return absl::OkStatus();
320 [
this](
int room_id, std::unique_ptr<DungeonCanvasViewer>& viewer) {
334 if (!before.has_value()) {
335 return absl::FailedPreconditionError(
336 "Dungeon entrance camera data is unavailable");
339 if (!validation.repair_source_valid) {
340 return absl::InvalidArgumentError(absl::StrJoin(validation.errors,
" "));
342 if (validation.matches_derived()) {
343 return absl::FailedPreconditionError(
344 "Camera data already matches the derived values");
350 comparison.
dirty = before->dirty;
351 if (comparison == *before) {
352 return absl::FailedPreconditionError(
353 "No safely repairable camera fields differ");
360 slot_index, *before, after,
364 return absl::OkStatus();
absl::Status RepairEntranceCamera(int slot_index)
absl::Status RestoreEntranceCameraState(int slot_index, const DungeonEntranceCameraState &state)
void RefreshEntranceDirtyState(int slot_index)
uint64_t entrance_property_save_generation_
util::LruCache< int, std::unique_ptr< DungeonCanvasViewer > > room_viewers_
std::array< zelda3::RoomEntrance, zelda3::kNumDungeonEntranceSlots > entrances_
void FinalizePendingUndoActions()
std::optional< DungeonEntranceCameraState > GetEntranceCameraState(int slot_index) const
absl::Status RestoreEntranceProperties(int slot_index, const zelda3::RoomEntrance &entrance)
void ConfigureEntrancePropertyEditCallbacks(DungeonEntrancesPanel *panel)
void RefreshEntranceCameraOverlays()
std::unique_ptr< DungeonCanvasViewer > workbench_compare_viewer_
void RecordEntrancePropertyEdit(int slot_index, const zelda3::RoomEntrance &before, const zelda3::RoomEntrance &after, std::shared_ptr< const int > gesture)
std::array< zelda3::DungeonSpawnPoint, zelda3::kNumDungeonSpawnPoints > spawn_points_
void ConfigureViewerRenderContext(DungeonCanvasViewer *viewer, int room_id)
std::unique_ptr< DungeonCanvasViewer > workbench_viewer_
void RecordSpawnPropertyEdit(int slot_index, const zelda3::DungeonSpawnPoint &before, const zelda3::DungeonSpawnPoint &after, std::shared_ptr< const int > gesture)
absl::Status RestoreSpawnProperties(int slot_index, const zelda3::DungeonSpawnPoint &spawn)
WindowContent for displaying and editing dungeon entrances.
ImGuiID property_edit_active_id_
void SetPropertyEditCallbacks(EntrancePropertyEditCallback entrance_callback, SpawnPropertyEditCallback spawn_callback)
void SetCameraTools(CameraStateProvider state_provider, CameraRepairCallback repair_callback, std::function< void()> data_changed_callback={})
void RegisterPropertyInput(const char *field_label, const char *widget_label)
std::shared_ptr< const int > property_edit_gesture() const
void ObservePropertyEditGesture()
std::shared_ptr< const int > property_edit_gesture_
UndoManager undo_manager_
Abstract base for all undoable actions (Command pattern)
void Push(std::unique_ptr< UndoAction > action)
DungeonEntranceCameraState after_
absl::Status Undo() override
DungeonEntranceCameraRepairAction(int slot_index, DungeonEntranceCameraState before, DungeonEntranceCameraState after, ApplyCallback apply)
std::function< absl::Status(const DungeonEntranceCameraState &)> ApplyCallback
absl::Status Redo() override
std::string Description() const override
Human-readable description (e.g., "Paint 12 tiles on map 5")
DungeonEntranceCameraState before_
size_t MemoryUsage() const override
Approximate memory footprint for budget enforcement.
absl::Status Redo() override
size_t MemoryUsage() const override
Approximate memory footprint for budget enforcement.
uint64_t save_generation_
bool CanMergeWith(const UndoAction &previous) const override
std::function< absl::Status(const Record &)> ApplyCallback
std::shared_ptr< const int > gesture_
std::string Description() const override
Human-readable description (e.g., "Paint 12 tiles on map 5")
void MergeWith(UndoAction &previous) override
absl::Status Undo() override
DungeonEntrancePropertiesAction(int slot_index, const Record &before, const Record &after, ApplyCallback apply, std::shared_ptr< const int > gesture, uint64_t save_generation)
uint8_t camera_scroll_controller
uint16_t overworld_door_tilemap
static absl::StatusOr< DungeonSpawnPoint > Load(const Rom &rom, int spawn_id)
Dungeon Room Entrance or Spawn Point.
const absl::Status & load_status() const
bool SameProperties(const zelda3::RoomEntrance &a, const zelda3::RoomEntrance &b)
Editors are the view controllers for the application.
DungeonEntranceCameraState CaptureDungeonSpawnCamera(const zelda3::DungeonSpawnPoint &spawn)
bool CanEditDungeonEntrance(int slot_index, const zelda3::RoomEntrance &entrance)
DungeonEntranceCameraState BuildRepairedDungeonEntranceCamera(const DungeonEntranceCameraState &state)
bool CanEditDungeonSpawnPoint(int slot_index, const zelda3::DungeonSpawnPoint &spawn)
void ApplyDungeonSpawnCameraState(const DungeonEntranceCameraState &state, zelda3::DungeonSpawnPoint *spawn)
DungeonEntranceCameraValidation ValidateDungeonEntranceCamera(const DungeonEntranceCameraState &state)
DungeonEntranceCameraState CaptureDungeonEntranceCamera(const zelda3::RoomEntrance &entrance)
void ApplyDungeonEntranceCameraState(const DungeonEntranceCameraState &state, zelda3::RoomEntrance *entrance)
constexpr int kNumDungeonSpawnPoints
#define RETURN_IF_ERROR(expr)
DungeonEntranceRecordKind kind