yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
canvas_interaction_handler.cc
Go to the documentation of this file.
2
3#include <cmath>
4
6#include "imgui/imgui.h"
7
8namespace yaze {
9namespace gui {
10
11namespace {
12
13// Helper function to align position to grid (local version)
14ImVec2 AlignToGridLocal(ImVec2 pos, float grid_step) {
15 return ImVec2(std::floor(pos.x / grid_step) * grid_step,
16 std::floor(pos.y / grid_step) * grid_step);
17}
18
19} // namespace
20
21void CanvasInteractionHandler::Initialize(const std::string& canvas_id) {
22 canvas_id_ = canvas_id;
23 ClearState();
24}
25
27 hover_points_.clear();
28 selected_points_.clear();
29 selected_tiles_.clear();
30 drawn_tile_pos_ = ImVec2(-1, -1);
31 mouse_pos_in_canvas_ = ImVec2(0, 0);
32 selected_tile_pos_ = ImVec2(-1, -1);
33 rect_select_active_ = false;
34}
35
37 ImVec2 canvas_p0, ImVec2 scrolling, float /*global_scale*/,
38 float /*tile_size*/, ImVec2 /*canvas_size*/, bool is_hovered) {
40
41 if (!is_hovered) {
42 hover_points_.clear();
43 return result;
44 }
45
46 const ImGuiIO& imgui_io = ImGui::GetIO();
47 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y);
49 ImVec2(imgui_io.MousePos.x - origin.x, imgui_io.MousePos.y - origin.y);
50
51 // Update based on current mode - each mode is handled by its specific Draw
52 // method This method exists for future state updates if needed
53 (void)current_mode_; // Suppress unused warning
54
55 return result;
56}
57
59 const gfx::Bitmap& bitmap, ImDrawList* draw_list, ImVec2 canvas_p0,
60 ImVec2 scrolling, float global_scale, float tile_size, bool is_hovered) {
61 const ImGuiIO& imgui_io = ImGui::GetIO();
62 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y);
63 const ImVec2 mouse_pos(imgui_io.MousePos.x - origin.x,
64 imgui_io.MousePos.y - origin.y);
65 const auto scaled_size = tile_size * global_scale;
66
67 // Clear hover when not hovering
68 if (!is_hovered) {
69 hover_points_.clear();
70 return false;
71 }
72
73 // Reset previous hover
74 hover_points_.clear();
75
76 // Calculate grid-aligned paint position
77 ImVec2 paint_pos = AlignToGridLocal(mouse_pos, scaled_size);
78 mouse_pos_in_canvas_ = paint_pos;
79 auto paint_pos_end =
80 ImVec2(paint_pos.x + scaled_size, paint_pos.y + scaled_size);
81
82 hover_points_.push_back(paint_pos);
83 hover_points_.push_back(paint_pos_end);
84
85 // Draw preview of tile at hover position
86 if (bitmap.is_active() && draw_list) {
87 draw_list->AddImage(reinterpret_cast<ImTextureID>(bitmap.texture()),
88 ImVec2(origin.x + paint_pos.x, origin.y + paint_pos.y),
89 ImVec2(origin.x + paint_pos.x + scaled_size,
90 origin.y + paint_pos.y + scaled_size),
91 ImVec2(0, 0), ImVec2(1, 1),
92 ImGui::GetColorU32(ImVec4(1, 1, 1, 1)));
93 }
94
95 // Check for paint action
96 if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) &&
97 ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
98 drawn_tile_pos_ = paint_pos;
99 return true;
100 }
101
102 return false;
103}
104
106 gfx::Tilemap& tilemap, int current_tile, ImDrawList* draw_list,
107 ImVec2 canvas_p0, ImVec2 scrolling, float global_scale, bool is_hovered) {
108 const ImGuiIO& imgui_io = ImGui::GetIO();
109 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y);
110 const ImVec2 mouse_pos(imgui_io.MousePos.x - origin.x,
111 imgui_io.MousePos.y - origin.y);
112
113 // Safety check
114 if (!tilemap.atlas.is_active() || tilemap.tile_size.x <= 0) {
115 return false;
116 }
117
118 const auto scaled_size = tilemap.tile_size.x * global_scale;
119
120 if (!is_hovered) {
121 hover_points_.clear();
122 return false;
123 }
124
125 hover_points_.clear();
126
127 ImVec2 paint_pos = AlignToGrid(mouse_pos, scaled_size);
128 mouse_pos_in_canvas_ = paint_pos;
129
130 hover_points_.push_back(paint_pos);
131 hover_points_.push_back(
132 ImVec2(paint_pos.x + scaled_size, paint_pos.y + scaled_size));
133
134 // Draw tile preview from atlas
135 if (tilemap.atlas.is_active() && tilemap.atlas.texture() && draw_list) {
136 int tiles_per_row = tilemap.atlas.width() / tilemap.tile_size.x;
137 if (tiles_per_row > 0) {
138 int tile_x = (current_tile % tiles_per_row) * tilemap.tile_size.x;
139 int tile_y = (current_tile / tiles_per_row) * tilemap.tile_size.y;
140
141 if (tile_x >= 0 && tile_x < tilemap.atlas.width() && tile_y >= 0 &&
142 tile_y < tilemap.atlas.height()) {
143 ImVec2 uv0 =
144 ImVec2(static_cast<float>(tile_x) / tilemap.atlas.width(),
145 static_cast<float>(tile_y) / tilemap.atlas.height());
146 ImVec2 uv1 = ImVec2(static_cast<float>(tile_x + tilemap.tile_size.x) /
147 tilemap.atlas.width(),
148 static_cast<float>(tile_y + tilemap.tile_size.y) /
149 tilemap.atlas.height());
150
151 draw_list->AddImage(
152 reinterpret_cast<ImTextureID>(tilemap.atlas.texture()),
153 ImVec2(origin.x + paint_pos.x, origin.y + paint_pos.y),
154 ImVec2(origin.x + paint_pos.x + scaled_size,
155 origin.y + paint_pos.y + scaled_size),
156 uv0, uv1, ImGui::GetColorU32(ImVec4(1, 1, 1, 1)));
157 }
158 }
159 }
160
161 if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) ||
162 ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
163 drawn_tile_pos_ = paint_pos;
164 return true;
165 }
166
167 return false;
168}
169
171 const ImVec4& color, ImDrawList* draw_list, ImVec2 canvas_p0,
172 ImVec2 scrolling, float global_scale, float tile_size, bool is_hovered) {
173 const ImGuiIO& imgui_io = ImGui::GetIO();
174 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y);
175 const ImVec2 mouse_pos(imgui_io.MousePos.x - origin.x,
176 imgui_io.MousePos.y - origin.y);
177 auto scaled_tile_size = tile_size * global_scale;
178 static bool is_dragging = false;
179 static ImVec2 start_drag_pos;
180
181 if (!is_hovered) {
182 hover_points_.clear();
183 return false;
184 }
185
186 hover_points_.clear();
187
188 ImVec2 paint_pos = AlignToGrid(mouse_pos, scaled_tile_size);
189 mouse_pos_in_canvas_ = paint_pos;
190
191 // Clamp to canvas bounds (assuming canvas_size from Update)
192 // For now, skip clamping as we don't have canvas_size here
193
194 hover_points_.push_back(paint_pos);
195 hover_points_.push_back(
196 ImVec2(paint_pos.x + scaled_tile_size, paint_pos.y + scaled_tile_size));
197
198 if (draw_list) {
199 draw_list->AddRectFilled(
200 ImVec2(origin.x + paint_pos.x + 1, origin.y + paint_pos.y + 1),
201 ImVec2(origin.x + paint_pos.x + scaled_tile_size,
202 origin.y + paint_pos.y + scaled_tile_size),
203 IM_COL32(color.x * 255, color.y * 255, color.z * 255, 255));
204 }
205
206 if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
207 is_dragging = true;
208 start_drag_pos = paint_pos;
209 }
210
211 if (is_dragging && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) {
212 is_dragging = false;
213 drawn_tile_pos_ = start_drag_pos;
214 return true;
215 }
216
217 return false;
218}
219
220bool CanvasInteractionHandler::DrawTileSelector(ImDrawList* /*draw_list*/,
221 ImVec2 canvas_p0,
222 ImVec2 scrolling,
223 float tile_size,
224 bool is_hovered) {
225 const ImGuiIO& imgui_io = ImGui::GetIO();
226 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y);
227 const ImVec2 mouse_pos(imgui_io.MousePos.x - origin.x,
228 imgui_io.MousePos.y - origin.y);
229
230 if (is_hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
231 hover_points_.clear();
232 ImVec2 painter_pos = AlignToGridLocal(mouse_pos, tile_size);
233
234 hover_points_.push_back(painter_pos);
235 hover_points_.push_back(
236 ImVec2(painter_pos.x + tile_size, painter_pos.y + tile_size));
237 mouse_pos_in_canvas_ = painter_pos;
238 }
239
240 if (is_hovered && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
241 return true;
242 }
243
244 return false;
245}
246
248 int current_map, ImDrawList* draw_list, ImVec2 canvas_p0, ImVec2 scrolling,
249 float global_scale, float tile_size, bool is_hovered) {
250 if (!is_hovered) {
251 return false;
252 }
253
254 // Create CanvasGeometry from parameters
255 CanvasGeometry geometry;
256 geometry.canvas_p0 = canvas_p0;
257 geometry.scrolling = scrolling;
258 geometry.scaled_size =
259 ImVec2(tile_size * global_scale, tile_size * global_scale);
260 geometry.canvas_sz =
261 ImVec2(tile_size, tile_size); // Will be updated if needed
262
263 // Call new event-based function
265 geometry, current_map, tile_size, draw_list, ImGuiMouseButton_Right);
266
267 // Update internal state for backward compatibility
268 if (event.is_complete) {
269 selected_tiles_ = event.selected_tiles;
270 selected_points_.clear();
271 selected_points_.push_back(event.start_pos);
272 selected_points_.push_back(event.end_pos);
273 rect_select_active_ = true;
274 return true;
275 }
276
277 if (!event.selected_tiles.empty() && !event.is_complete) {
278 // Single tile selection
279 selected_tile_pos_ = event.selected_tiles[0];
280 selected_points_.clear();
281 rect_select_active_ = false;
282 }
283
284 rect_select_active_ = event.is_active;
285
286 return false;
287}
288
289// Helper methods - these are thin wrappers that could be static but kept as
290// instance methods for potential future state access
291ImVec2 CanvasInteractionHandler::AlignPosToGrid(ImVec2 pos, float grid_step) {
292 return AlignToGridLocal(pos, grid_step);
293}
294
296 ImVec2 scrolling) {
297 const ImGuiIO& imgui_io = ImGui::GetIO();
298 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y);
299 return ImVec2(imgui_io.MousePos.x - origin.x, imgui_io.MousePos.y - origin.y);
300}
301
302bool CanvasInteractionHandler::IsMouseClicked(ImGuiMouseButton button) {
303 return ImGui::IsMouseClicked(button);
304}
305
307 return ImGui::IsMouseDoubleClicked(button);
308}
309
310bool CanvasInteractionHandler::IsMouseDragging(ImGuiMouseButton button) {
311 return ImGui::IsMouseDragging(button);
312}
313
314bool CanvasInteractionHandler::IsMouseReleased(ImGuiMouseButton button) {
315 return ImGui::IsMouseReleased(button);
316}
317
318} // namespace gui
319} // namespace yaze
Free functions for canvas interaction handling.
Represents a bitmap image optimized for SNES ROM hacking.
Definition bitmap.h:70
TextureHandle texture() const
Definition bitmap.h:410
bool is_active() const
Definition bitmap.h:414
int height() const
Definition bitmap.h:399
int width() const
Definition bitmap.h:398
bool DrawSelectRect(int current_map, ImDrawList *draw_list, ImVec2 canvas_p0, ImVec2 scrolling, float global_scale, float tile_size, bool is_hovered)
Draw rectangle selector (multi-tile selection)
void ClearState()
Clear all interaction state.
bool DrawTilemapPainter(gfx::Tilemap &tilemap, int current_tile, ImDrawList *draw_list, ImVec2 canvas_p0, ImVec2 scrolling, float global_scale, bool is_hovered)
Draw tilemap painter (preview + interaction)
ImVec2 AlignPosToGrid(ImVec2 pos, float grid_step)
TileInteractionResult Update(ImVec2 canvas_p0, ImVec2 scrolling, float global_scale, float tile_size, ImVec2 canvas_size, bool is_hovered)
Update interaction state (call once per frame)
bool DrawTileSelector(ImDrawList *draw_list, ImVec2 canvas_p0, ImVec2 scrolling, float tile_size, bool is_hovered)
Draw tile selector (single tile selection)
bool DrawSolidTilePainter(const ImVec4 &color, ImDrawList *draw_list, ImVec2 canvas_p0, ImVec2 scrolling, float global_scale, float tile_size, bool is_hovered)
Draw solid color painter.
bool IsMouseDoubleClicked(ImGuiMouseButton button)
bool DrawTilePainter(const gfx::Bitmap &bitmap, ImDrawList *draw_list, ImVec2 canvas_p0, ImVec2 scrolling, float global_scale, float tile_size, bool is_hovered)
Draw tile painter (preview + interaction)
ImVec2 GetMousePosition(ImVec2 canvas_p0, ImVec2 scrolling)
void Initialize(const std::string &canvas_id)
Initialize the interaction handler.
ImVec2 AlignToGrid(ImVec2 pos, float grid_step)
Align position to grid.
RectSelectionEvent HandleRectangleSelection(const CanvasGeometry &geometry, int current_map, float tile_size, ImDrawList *draw_list, ImGuiMouseButton mouse_button)
Handle rectangle selection interaction.
int y
Y coordinate or height.
Definition tilemap.h:21
int x
X coordinate or width.
Definition tilemap.h:20
Tilemap structure for SNES tile-based graphics management.
Definition tilemap.h:118
Pair tile_size
Size of individual tiles (8x8 or 16x16)
Definition tilemap.h:123
Bitmap atlas
Master bitmap containing all tiles.
Definition tilemap.h:119
Canvas geometry calculated per-frame.
Event payload for rectangle selection operations.
Result of a tile interaction operation.