yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
minecart_track_editor_panel.h
Go to the documentation of this file.
1#ifndef YAZE_APP_EDITOR_DUNGEON_PANELS_MINECART_TRACK_EDITOR_PANEL_H
2#define YAZE_APP_EDITOR_DUNGEON_PANELS_MINECART_TRACK_EDITOR_PANEL_H
3
4#include <array>
5#include <cstdint>
6#include <filesystem>
7#include <functional>
8#include <optional>
9#include <string>
10#include <unordered_map>
11#include <utility>
12#include <vector>
13
14#include "absl/status/status.h"
15#include "absl/status/statusor.h"
21#include "app/gui/core/icons.h"
22#include "core/project.h"
23#include "imgui/imgui.h"
24#include "zelda3/dungeon/room.h"
26
27namespace yaze::editor {
28
30 public:
32 std::function<absl::Status(const project::DungeonOverlaySettings&)>;
33 using ProjectDraftChangedCallback = std::function<absl::Status()>;
34 using ProjectSaveCallback = std::function<absl::Status()>;
35 using CollisionBatchApplyCallback = std::function<absl::Status(
36 const std::vector<zelda3::TrackCollisionResult>&,
38
40
41 // WindowContent overrides
42 std::string GetId() const override { return "dungeon.minecart_tracks"; }
43 std::string GetWorkflowGroup() const override { return "Editors"; }
44 std::string GetDisplayName() const override { return "Minecart Tracks"; }
45 std::string GetIcon() const override { return ICON_MD_TRAIN; }
46 std::string GetEditorCategory() const override { return "Dungeon"; }
47
48 void Draw(bool* p_open) override;
49
50 // Custom methods
52 if (rooms_ != rooms) {
53 collision_preview_.clear();
55 }
56 rooms_ = rooms;
57 audit_dirty_ = true;
59 }
60 absl::Status SetProject(project::YazeProject* project);
61 // Reapply project-backed panel state even when the stable session project
62 // pointer and descriptor path did not change.
63 absl::Status RebindProjectContext(project::YazeProject* project);
64 absl::Status SaveTracks();
65 absl::Status ReloadTracks();
66 absl::Status DiscardUnpublishedChanges();
67 bool HasUnpublishedChanges() const;
68 absl::StatusOr<std::filesystem::path> ResolveTrackSourcePath() const;
69 absl::Status UpdateTrack(size_t track_index, const MinecartTrack& track);
71 absl::Status PrepareProjectSave();
72
73 using TrackEditCallback = std::function<absl::Status(
74 const MinecartTrack&, const MinecartTrack&, bool)>;
76 track_edit_callback_ = std::move(callback);
77 }
78 absl::Status MoveCartStart(const MinecartTrack& before,
79 const MinecartTrack& after);
80 // Undo replay only; validates source generation and expected record first.
81 absl::Status RestoreTrackDraft(uint64_t generation,
82 const MinecartTrack& expected,
83 const MinecartTrack& replacement);
84 uint64_t track_generation() const { return track_generation_; }
85 // Reload cancels an unfinished gesture even when Undo's source is unchanged.
86 uint64_t canvas_revision() const { return canvas_revision_; }
89 bool canvas_editing() const { return canvas_editing_; }
90 void set_canvas_editing(bool enabled);
91 int selected_track() const { return selected_track_; }
92 void SelectTrack(int id) { selected_track_ = id; }
93 void SetActiveRoom(int room) {
94 if (active_room_ != room) {
95 placement_brush_.reset();
96 }
97 active_room_ = room;
98 }
100
101 void SetRailPaletteCallback(std::function<bool()> draw) {
102 draw_rail_palette_ = std::move(draw);
103 }
111 void set_collision_stamping(bool enabled) {
112 collision_stamping_ = enabled;
113 if (enabled) {
115 set_canvas_editing(false);
116 }
117 }
119 int collision_stamp_size() const { return collision_stamp_large_ ? 2 : 1; }
120 void DrawRailTools();
121 void DrawNodeTools();
123 std::function<absl::Status(int, int, int, const MinecartNodeBrush&)>;
125 place_node_ = std::move(callback);
126 }
130 const std::optional<MinecartToolPayload>& placement_brush() const {
131 return placement_brush_;
132 }
135 set_canvas_editing(false);
136 collision_stamping_ = false;
137 placement_brush_ = brush;
138 placement_brush_->owner = this;
141 }
142 // Invalidate only an active payload owned by this panel. Repeated cleanup
143 // cannot renew or repeatedly age a canceled gesture. A viewer filter avoids
144 // canceling another editable canvas when a compare view becomes read only.
145 void CancelNodeDrag(const void* source_viewer = nullptr) {
146 if (!ImGui::GetCurrentContext())
147 return;
148 const auto* payload = ImGui::GetDragDropPayload();
149 if (!payload || !payload->IsDataType(kMinecartNodeDragPayload) ||
150 payload->DataSize != sizeof(MinecartToolPayload))
151 return;
152 const auto* token = static_cast<const MinecartToolPayload*>(payload->Data);
153 if (token->owner == this && token->revision == canvas_revision_ &&
154 (!source_viewer || token->source_viewer == source_viewer)) {
156 }
157 }
160 placement_brush_.reset();
161 }
162 void ReportToolStatus(const absl::Status& status) {
163 status_message_ = status.ok() ? "" : std::string(status.message());
164 show_success_ = status.ok();
165 }
167 void set_automatic_rail_collision(bool enabled) {
169 }
170
171 // Advanced Pick uses the same paired move operation as marker dragging.
172 bool IsPickingCoordinates() const { return picking_mode_; }
174 const std::vector<MinecartTrack>& GetTracks();
175
176 // Callback to navigate to a specific room for coordinate picking
177 using RoomNavigationCallback = std::function<void(int room_id)>;
179 room_navigation_callback_ = std::move(callback);
180 }
182 project_changed_callback_ = std::move(callback);
183 }
188 project_save_callback_ = std::move(callback);
189 }
217
218 private:
220
221 absl::Status LoadTracks();
222 absl::Status ValidateLoadedManifestIdentity() const;
223 absl::Status RefreshProjectBinding();
224 void ResetTrackSession();
225 void StartCoordinatePicking(int track_index);
227 void RebuildAuditCache(bool include_unmaterialized = false);
228 absl::Status BuildCollisionPreview(const std::vector<int>& room_ids);
230 absl::Status ApplyCollisionPreview();
232 absl::StatusOr<zelda3::GeneratorOptions> ResolveGeneratorOptions() const;
233 bool IsDefaultTrack(const MinecartTrack& track) const;
234 void DrawOverlaySettings();
236 void ClearOverlayInputs();
237
239 std::vector<uint16_t> project::DungeonOverlaySettings::*;
240 bool UpdateOverlayList(const char* label, std::string& input,
241 OverlayListMember member);
242 absl::StatusOr<bool> CommitOverlayList(std::string& input,
243 OverlayListMember member);
244 absl::StatusOr<bool> CommitOverlayInputsForSave();
245 absl::StatusOr<bool> ResetOverlaySettings();
246 absl::Status NotifyProjectChanged(
247 const project::DungeonOverlaySettings& overlay);
248 absl::Status NotifyProjectDraftChanged();
249 absl::Status SaveProjectSettings();
250
254 bool has_stop_tiles = false;
257 std::vector<int> track_subtypes;
258 std::vector<int> route_slots;
259 };
260
261 std::function<bool()> draw_rail_palette_;
265 std::optional<MinecartToolPayload> placement_brush_;
267 int node_id_ = 0;
274 uint64_t track_generation_ = 0;
275 uint64_t canvas_revision_ = 0;
277 int active_room_ = -1;
278 bool canvas_editing_ = false;
280 std::vector<MinecartTrack> tracks_;
281 std::vector<MinecartTrack> loaded_tracks_;
282 std::optional<MinecartTrackSourceDocument> source_document_;
283 std::optional<core::MinecartTrackLayout::Source> loaded_source_identity_;
284 std::filesystem::path loaded_source_path_;
287 std::optional<core::MinecartTrackLayout::Source> bound_source_identity_;
290 std::unordered_map<int, RoomTrackAudit> room_audit_;
291 std::unordered_map<int, std::vector<int>> route_usage_rooms_;
292 std::vector<bool> route_slot_used_;
293 std::vector<zelda3::TrackCollisionResult> collision_preview_;
295 bool audit_dirty_ = true;
297 bool load_attempted_ = false;
298 bool loaded_ = false;
299 std::string status_message_;
300 bool show_success_ = false;
301 float success_timer_ = 0.0f;
302
303 // Coordinate picking state
304 bool picking_mode_ = false;
306
312
313 // Overlay config input state
315 std::optional<project::DungeonOverlaySettings> overlay_inputs_model_;
321};
322
323} // namespace yaze::editor
324
325#endif
std::string GetWorkflowGroup() const override
Optional workflow group for hack-centric actions.
bool IsDefaultTrack(const MinecartTrack &track) const
absl::Status RestoreTrackDraft(uint64_t generation, const MinecartTrack &expected, const MinecartTrack &replacement)
std::string GetId() const override
Unique identifier for this panel.
std::string GetIcon() const override
Material Design icon for this panel.
absl::StatusOr< zelda3::GeneratorOptions > ResolveGeneratorOptions() const
std::string GetEditorCategory() const override
Editor category this panel belongs to.
std::optional< core::MinecartTrackLayout::Source > bound_source_identity_
void SetNodePlacementCallback(NodePlacementCallback callback)
const MinecartCollisionApply & collision_stamp_callback() const
void SetProjectChangedCallback(ProjectChangedCallback callback)
bool UpdateOverlayList(const char *label, std::string &input, OverlayListMember member)
void Draw(bool *p_open) override
Draw the panel content.
const std::vector< MinecartTrack > & GetTracks()
ProjectDraftChangedCallback project_draft_changed_callback_
std::vector< uint16_t > project::DungeonOverlaySettings::* OverlayListMember
std::unordered_map< int, RoomTrackAudit > room_audit_
std::function< void(int room_id)> RoomNavigationCallback
void SetRailPaletteCallback(std::function< bool()> draw)
std::function< absl::Status( const std::vector< zelda3::TrackCollisionResult > &, const zelda3::GeneratorOptions &)> CollisionBatchApplyCallback
CollisionBatchApplyCallback collision_batch_apply_callback_
const NodePlacementCallback & node_placement_callback() const
void SetRoomNavigationCallback(RoomNavigationCallback callback)
absl::Status NotifyProjectChanged(const project::DungeonOverlaySettings &overlay)
std::vector< zelda3::TrackCollisionResult > collision_preview_
std::optional< MinecartTrackSourceDocument > source_document_
void CancelNodeDrag(const void *source_viewer=nullptr)
const std::optional< MinecartToolPayload > & placement_brush() const
absl::StatusOr< bool > CommitOverlayList(std::string &input, OverlayListMember member)
absl::Status UpdateTrack(size_t track_index, const MinecartTrack &track)
absl::Status RebindProjectContext(project::YazeProject *project)
void SetTrackEditCallback(TrackEditCallback callback)
absl::StatusOr< std::filesystem::path > ResolveTrackSourcePath() const
absl::Status MoveCartStart(const MinecartTrack &before, const MinecartTrack &after)
absl::Status BuildCollisionPreview(const std::vector< int > &room_ids)
absl::Status SetProject(project::YazeProject *project)
std::optional< core::MinecartTrackLayout::Source > loaded_source_identity_
std::function< absl::Status(const project::DungeonOverlaySettings &)> ProjectChangedCallback
std::function< absl::Status()> ProjectSaveCallback
std::unordered_map< int, std::vector< int > > route_usage_rooms_
std::function< absl::Status(int, int, int, const MinecartNodeBrush &)> NodePlacementCallback
void SetCollisionBatchApplyCallback(CollisionBatchApplyCallback callback)
void RebuildAuditCache(bool include_unmaterialized=false)
void SetProjectDraftChangedCallback(ProjectDraftChangedCallback callback)
std::function< absl::Status()> ProjectDraftChangedCallback
void SetProjectSaveCallback(ProjectSaveCallback callback)
std::function< absl::Status( const MinecartTrack &, const MinecartTrack &, bool)> TrackEditCallback
std::string GetDisplayName() const override
Human-readable name shown in menus and title bars.
std::optional< MinecartToolPayload > placement_brush_
void SetPlacementBrush(const MinecartToolPayload &brush)
void SetCollisionStampCallback(MinecartCollisionApply apply)
void ReportToolStatus(const absl::Status &status)
std::optional< project::DungeonOverlaySettings > overlay_inputs_model_
Base interface for all logical window content components.
#define ICON_MD_TRAIN
Definition icons.h:2005
Editors are the view controllers for the application.
std::function< absl::Status( int, const zelda3::CustomCollisionMap &, const MinecartCollisionStamp &)> MinecartCollisionApply
constexpr const char * kMinecartNodeDragPayload
Dungeon overlay configuration (per-project).
Definition project.h:97
Modern project structure with comprehensive settings consolidation.
Definition project.h:290