yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
item_interaction_handler.cc
Go to the documentation of this file.
1// Related header
3
4// C++ standard library
5#include <algorithm>
6
7// Third-party library headers
8#include "absl/strings/str_format.h"
9#include "imgui/imgui.h"
10
11// Project headers
13
14namespace yaze::editor {
15
20
21bool ItemInteractionHandler::HandleClick(int canvas_x, int canvas_y) {
22 if (!HasValidContext()) return false;
23
25 PlaceItemAtPosition(canvas_x, canvas_y);
26 return true;
27 }
28
29 // Try to select item at position
30 auto item_index = GetEntityAtPosition(canvas_x, canvas_y);
31 if (item_index.has_value()) {
32 SelectItem(*item_index);
33 is_dragging_ = true;
34 drag_start_pos_ = ImVec2(static_cast<float>(canvas_x),
35 static_cast<float>(canvas_y));
37 return true;
38 }
39
41 return false;
42}
43
44void ItemInteractionHandler::HandleDrag(ImVec2 current_pos, ImVec2 delta) {
45 if (!is_dragging_ || !selected_item_index_.has_value()) return;
46 drag_current_pos_ = current_pos;
47}
48
50 if (!is_dragging_ || !selected_item_index_.has_value()) {
51 is_dragging_ = false;
52 return;
53 }
54
55 auto* room = GetCurrentRoom();
56 if (!room) {
57 is_dragging_ = false;
58 return;
59 }
60
61 float scale = GetCanvasScale();
62
63 // Convert to pixel coordinates
64 int pixel_x = static_cast<int>(drag_current_pos_.x / scale);
65 int pixel_y = static_cast<int>(drag_current_pos_.y / scale);
66
67 // PotItem position encoding:
68 // high byte * 16 = Y, low byte * 4 = X
69 int encoded_x = pixel_x / 4;
70 int encoded_y = pixel_y / 16;
71
72 // Clamp to valid range
73 encoded_x = std::clamp(encoded_x, 0, 255);
74 encoded_y = std::clamp(encoded_y, 0, 255);
75
76 auto& pot_items = room->GetPotItems();
77 if (*selected_item_index_ < pot_items.size()) {
79
80 pot_items[*selected_item_index_].position =
81 static_cast<uint16_t>((encoded_y << 8) | encoded_x);
82
84 }
85
86 is_dragging_ = false;
87}
88
90 if (!item_placement_mode_ || !HasValidContext()) return;
91
92 auto* canvas = ctx_->canvas;
93 if (!canvas->IsMouseHovering()) return;
94
95 const ImGuiIO& io = ImGui::GetIO();
96 ImVec2 canvas_pos = canvas->zero_point();
97 float scale = GetCanvasScale();
98
99 // Convert to room coordinates (items use 8-pixel grid for fine positioning)
100 int canvas_x = static_cast<int>((io.MousePos.x - canvas_pos.x) / scale);
101 int canvas_y = static_cast<int>((io.MousePos.y - canvas_pos.y) / scale);
102
103 // Snap to 8-pixel grid
104 int snapped_x = (canvas_x / dungeon_coords::kTileSize) *
106 int snapped_y = (canvas_y / dungeon_coords::kTileSize) *
108
109 // Draw ghost rectangle for item preview
110 ImVec2 rect_min(canvas_pos.x + snapped_x * scale,
111 canvas_pos.y + snapped_y * scale);
112 ImVec2 rect_max(rect_min.x + 16 * scale, rect_min.y + 16 * scale);
113
114 // Semi-transparent yellow for items
115 ImU32 fill_color = IM_COL32(200, 200, 50, 100);
116 ImU32 outline_color = IM_COL32(255, 255, 50, 200);
117
118 canvas->draw_list()->AddRectFilled(rect_min, rect_max, fill_color);
119 canvas->draw_list()->AddRect(rect_min, rect_max, outline_color, 0.0f, 0,
120 2.0f);
121
122 // Draw item ID label
123 std::string label = absl::StrFormat("%02X", preview_item_id_);
124 canvas->draw_list()->AddText(rect_min, IM_COL32(255, 255, 255, 255),
125 label.c_str());
126}
127
129 if (!selected_item_index_.has_value() || !HasValidContext()) return;
130
131 auto* room = GetCurrentRoom();
132 if (!room) return;
133
134 const auto& pot_items = room->GetPotItems();
135 if (*selected_item_index_ >= pot_items.size()) return;
136
137 const auto& pot_item = pot_items[*selected_item_index_];
138 int pixel_x = pot_item.GetPixelX();
139 int pixel_y = pot_item.GetPixelY();
140
141 // If dragging, use current drag position
142 if (is_dragging_) {
143 float scale = GetCanvasScale();
144 pixel_x = static_cast<int>(drag_current_pos_.x / scale);
145 pixel_y = static_cast<int>(drag_current_pos_.y / scale);
146 // Snap to 8-pixel grid
149 }
150
151 ImDrawList* draw_list = ImGui::GetWindowDrawList();
152 ImVec2 canvas_pos = GetCanvasZeroPoint();
153 float scale = GetCanvasScale();
154
155 ImVec2 pos(canvas_pos.x + pixel_x * scale, canvas_pos.y + pixel_y * scale);
156 ImVec2 size(16 * scale, 16 * scale);
157
158 // Animated selection
159 static float pulse = 0.0f;
160 pulse += ImGui::GetIO().DeltaTime * 3.0f;
161 float alpha = 0.5f + 0.3f * sinf(pulse);
162
163 ImU32 color = IM_COL32(255, 255, 0, 180); // Yellow
164 ImU32 fill_color =
165 (color & 0x00FFFFFF) | (static_cast<ImU32>(alpha * 100) << 24);
166
167 draw_list->AddRectFilled(pos, ImVec2(pos.x + size.x, pos.y + size.y),
168 fill_color);
169 draw_list->AddRect(pos, ImVec2(pos.x + size.x, pos.y + size.y), color, 0.0f,
170 0, 2.0f);
171
172 // Draw label
173 ImVec2 text_pos(pos.x, pos.y - 14 * scale);
174 draw_list->AddText(text_pos, IM_COL32(255, 255, 255, 220), "Item");
175}
176
178 int canvas_x, int canvas_y) const {
179 if (!HasValidContext()) return std::nullopt;
180
181 auto* room = ctx_->GetCurrentRoomConst();
182 if (!room) return std::nullopt;
183
184 // Convert screen coordinates to room coordinates
185 float scale = GetCanvasScale();
186 int room_x = static_cast<int>(canvas_x / scale);
187 int room_y = static_cast<int>(canvas_y / scale);
188
189 // Check pot items
190 const auto& pot_items = room->GetPotItems();
191 for (size_t i = 0; i < pot_items.size(); ++i) {
192 const auto& pot_item = pot_items[i];
193
194 int item_x = pot_item.GetPixelX();
195 int item_y = pot_item.GetPixelY();
196
197 // 16x16 hitbox
198 if (room_x >= item_x && room_x < item_x + 16 && room_y >= item_y &&
199 room_y < item_y + 16) {
200 return i;
201 }
202 }
203
204 return std::nullopt;
205}
206
211
213 selected_item_index_ = std::nullopt;
214 is_dragging_ = false;
215}
216
218 if (!selected_item_index_.has_value() || !HasValidContext()) return;
219
220 auto* room = GetCurrentRoom();
221 if (!room) return;
222
223 auto& pot_items = room->GetPotItems();
224 if (*selected_item_index_ >= pot_items.size()) return;
225
227 pot_items.erase(pot_items.begin() +
228 static_cast<ptrdiff_t>(*selected_item_index_));
231}
232
233void ItemInteractionHandler::PlaceItemAtPosition(int canvas_x, int canvas_y) {
234 if (!HasValidContext()) return;
235
236 auto* room = GetCurrentRoom();
237 if (!room) return;
238
239 float scale = GetCanvasScale();
240
241 // Convert to pixel coordinates
242 int pixel_x = static_cast<int>(canvas_x / scale);
243 int pixel_y = static_cast<int>(canvas_y / scale);
244
245 // PotItem position encoding:
246 // high byte * 16 = Y, low byte * 4 = X
247 int encoded_x = pixel_x / 4;
248 int encoded_y = pixel_y / 16;
249
250 // Clamp to valid range
251 encoded_x = std::clamp(encoded_x, 0, 255);
252 encoded_y = std::clamp(encoded_y, 0, 255);
253
255
256 // Create the pot item
257 zelda3::PotItem new_item;
258 new_item.position = static_cast<uint16_t>((encoded_y << 8) | encoded_x);
259 new_item.item = preview_item_id_;
260
261 // Add item to room
262 room->GetPotItems().push_back(new_item);
263
265}
266
267} // namespace yaze::editor
float GetCanvasScale() const
Get canvas global scale.
zelda3::Room * GetCurrentRoom() const
Get current room (convenience method)
bool HasValidContext() const
Check if context is valid.
ImVec2 GetCanvasZeroPoint() const
Get canvas zero point (for screen coordinate conversion)
void DrawSelectionHighlight() override
Draw selection highlight for selected entities.
bool HandleClick(int canvas_x, int canvas_y) override
Handle mouse click at canvas position.
void DrawGhostPreview() override
Draw ghost preview during placement.
void BeginPlacement() override
Begin placement mode.
void PlaceItemAtPosition(int canvas_x, int canvas_y)
Place item at position.
void HandleDrag(ImVec2 current_pos, ImVec2 delta) override
Handle mouse drag.
std::optional< size_t > GetEntityAtPosition(int canvas_x, int canvas_y) const override
Get entity at canvas position.
void HandleRelease() override
Handle mouse release.
void SelectItem(size_t index)
Select item at index.
Editors are the view controllers for the application.
Definition agent_chat.cc:23
const zelda3::Room * GetCurrentRoomConst() const
Get const pointer to current room.
void NotifyEntityChanged() const
Notify that entity has changed.
void NotifyInvalidateCache() const
Notify that cache invalidation is needed.
void NotifyMutation() const
Notify that a mutation is about to happen.
uint16_t position
Definition room.h:136