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())
23 return false;
24
26 PlaceItemAtPosition(canvas_x, canvas_y);
27 return true;
28 }
29
30 // Try to select item at position
31 auto item_index = GetEntityAtPosition(canvas_x, canvas_y);
32 if (item_index.has_value()) {
33 SelectItem(*item_index);
34 is_dragging_ = true;
36 ImVec2(static_cast<float>(canvas_x), static_cast<float>(canvas_y));
38 return true;
39 }
40
42 return false;
43}
44
45void ItemInteractionHandler::HandleDrag(ImVec2 current_pos, ImVec2 delta) {
46 if (!is_dragging_ || !selected_item_index_.has_value())
47 return;
48 drag_current_pos_ = current_pos;
49}
50
52 if (!is_dragging_ || !selected_item_index_.has_value()) {
53 is_dragging_ = false;
54 return;
55 }
56
57 auto* room = GetCurrentRoom();
58 if (!room) {
59 is_dragging_ = false;
60 return;
61 }
62
63 float scale = GetCanvasScale();
64
65 // Convert to pixel coordinates
66 int pixel_x = static_cast<int>(drag_current_pos_.x / scale);
67 int pixel_y = static_cast<int>(drag_current_pos_.y / scale);
68
69 // PotItem position encoding:
70 // high byte * 16 = Y, low byte * 4 = X
71 int encoded_x = pixel_x / 4;
72 int encoded_y = pixel_y / 16;
73
74 // Clamp to valid range
75 encoded_x = std::clamp(encoded_x, 0, 255);
76 encoded_y = std::clamp(encoded_y, 0, 255);
77
78 auto& pot_items = room->GetPotItems();
79 if (*selected_item_index_ < pot_items.size()) {
81
82 pot_items[*selected_item_index_].position =
83 static_cast<uint16_t>((encoded_y << 8) | encoded_x);
84
86 }
87
88 is_dragging_ = false;
89}
90
93 return;
94
95 auto* canvas = ctx_->canvas;
96 if (!canvas->IsMouseHovering())
97 return;
98
99 const ImGuiIO& io = ImGui::GetIO();
100 ImVec2 canvas_pos = canvas->zero_point();
101 float scale = GetCanvasScale();
102
103 // Convert to room coordinates (items use 8-pixel grid for fine positioning)
104 int canvas_x = static_cast<int>((io.MousePos.x - canvas_pos.x) / scale);
105 int canvas_y = static_cast<int>((io.MousePos.y - canvas_pos.y) / scale);
106
107 // Snap to 8-pixel grid
108 int snapped_x =
110 int snapped_y =
112
113 // Draw ghost rectangle for item preview
114 ImVec2 rect_min(canvas_pos.x + snapped_x * scale,
115 canvas_pos.y + snapped_y * scale);
116 ImVec2 rect_max(rect_min.x + 16 * scale, rect_min.y + 16 * scale);
117
118 // Semi-transparent yellow for items
119 ImU32 fill_color = IM_COL32(200, 200, 50, 100);
120 ImU32 outline_color = IM_COL32(255, 255, 50, 200);
121
122 canvas->draw_list()->AddRectFilled(rect_min, rect_max, fill_color);
123 canvas->draw_list()->AddRect(rect_min, rect_max, outline_color, 0.0f, 0,
124 2.0f);
125
126 // Draw item ID label
127 std::string label = absl::StrFormat("%02X", preview_item_id_);
128 canvas->draw_list()->AddText(rect_min, IM_COL32(255, 255, 255, 255),
129 label.c_str());
130}
131
133 if (!selected_item_index_.has_value() || !HasValidContext())
134 return;
135
136 auto* room = GetCurrentRoom();
137 if (!room)
138 return;
139
140 const auto& pot_items = room->GetPotItems();
141 if (*selected_item_index_ >= pot_items.size())
142 return;
143
144 const auto& pot_item = pot_items[*selected_item_index_];
145 int pixel_x = pot_item.GetPixelX();
146 int pixel_y = pot_item.GetPixelY();
147
148 // If dragging, use current drag position
149 if (is_dragging_) {
150 float scale = GetCanvasScale();
151 pixel_x = static_cast<int>(drag_current_pos_.x / scale);
152 pixel_y = static_cast<int>(drag_current_pos_.y / scale);
153 // Snap to 8-pixel grid
156 }
157
158 ImDrawList* draw_list = ImGui::GetWindowDrawList();
159 ImVec2 canvas_pos = GetCanvasZeroPoint();
160 float scale = GetCanvasScale();
161
162 ImVec2 pos(canvas_pos.x + pixel_x * scale, canvas_pos.y + pixel_y * scale);
163 ImVec2 size(16 * scale, 16 * scale);
164
165 // Animated selection
166 static float pulse = 0.0f;
167 pulse += ImGui::GetIO().DeltaTime * 3.0f;
168 float alpha = 0.5f + 0.3f * sinf(pulse);
169
170 ImU32 color = IM_COL32(255, 255, 0, 180); // Yellow
171 ImU32 fill_color =
172 (color & 0x00FFFFFF) | (static_cast<ImU32>(alpha * 100) << 24);
173
174 draw_list->AddRectFilled(pos, ImVec2(pos.x + size.x, pos.y + size.y),
175 fill_color);
176 draw_list->AddRect(pos, ImVec2(pos.x + size.x, pos.y + size.y), color, 0.0f,
177 0, 2.0f);
178
179 // Draw label
180 ImVec2 text_pos(pos.x, pos.y - 14 * scale);
181 draw_list->AddText(text_pos, IM_COL32(255, 255, 255, 220), "Item");
182}
183
185 int canvas_x, int canvas_y) const {
186 if (!HasValidContext())
187 return std::nullopt;
188
189 auto* room = ctx_->GetCurrentRoomConst();
190 if (!room)
191 return std::nullopt;
192
193 // Convert screen coordinates to room coordinates
194 float scale = GetCanvasScale();
195 int room_x = static_cast<int>(canvas_x / scale);
196 int room_y = static_cast<int>(canvas_y / scale);
197
198 // Check pot items
199 const auto& pot_items = room->GetPotItems();
200 for (size_t i = 0; i < pot_items.size(); ++i) {
201 const auto& pot_item = pot_items[i];
202
203 int item_x = pot_item.GetPixelX();
204 int item_y = pot_item.GetPixelY();
205
206 // 16x16 hitbox
207 if (room_x >= item_x && room_x < item_x + 16 && room_y >= item_y &&
208 room_y < item_y + 16) {
209 return i;
210 }
211 }
212
213 return std::nullopt;
214}
215
220
222 selected_item_index_ = std::nullopt;
223 is_dragging_ = false;
224}
225
227 if (!selected_item_index_.has_value() || !HasValidContext())
228 return;
229
230 auto* room = GetCurrentRoom();
231 if (!room)
232 return;
233
234 auto& pot_items = room->GetPotItems();
235 if (*selected_item_index_ >= pot_items.size())
236 return;
237
239 pot_items.erase(pot_items.begin() +
240 static_cast<ptrdiff_t>(*selected_item_index_));
243}
244
245void ItemInteractionHandler::PlaceItemAtPosition(int canvas_x, int canvas_y) {
246 if (!HasValidContext())
247 return;
248
249 auto* room = GetCurrentRoom();
250 if (!room)
251 return;
252
253 float scale = GetCanvasScale();
254
255 // Convert to pixel coordinates
256 int pixel_x = static_cast<int>(canvas_x / scale);
257 int pixel_y = static_cast<int>(canvas_y / scale);
258
259 // PotItem position encoding:
260 // high byte * 16 = Y, low byte * 4 = X
261 int encoded_x = pixel_x / 4;
262 int encoded_y = pixel_y / 16;
263
264 // Clamp to valid range
265 encoded_x = std::clamp(encoded_x, 0, 255);
266 encoded_y = std::clamp(encoded_y, 0, 255);
267
269
270 // Create the pot item
271 zelda3::PotItem new_item;
272 new_item.position = static_cast<uint16_t>((encoded_y << 8) | encoded_x);
273 new_item.item = preview_item_id_;
274
275 // Add item to room
276 room->GetPotItems().push_back(new_item);
277
279}
280
281} // 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.
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