diff --git a/src/fenigma/grid_widget.py b/src/fenigma/grid_widget.py index fafdf99..3ae1774 100644 --- a/src/fenigma/grid_widget.py +++ b/src/fenigma/grid_widget.py @@ -117,6 +117,12 @@ class GridCanvas(Gtk.DrawingArea): self.on_right_click = None # callback(Coord, x, y), fired on right-click (unless placing) self.hide_dead_from_map = False # off by default; toggled from the firing panel toolbar + # Which large cell the cursor is currently over, (col, row) both + # floored, or None off the map/off the widget entirely. Redrawn + # only when this actually changes cell (not on every pixel of + # motion within the same one), see _draw_hover_subgrid(). + self._hover_cell: tuple[int, int] | None = None + # Placement mode: while armed, the next left-click calls # placement_callback(Coord) instead of doing the normal # select/hit-test, and (if placement_preview_radius_km is set) a @@ -423,6 +429,12 @@ class GridCanvas(Gtk.DrawingArea): if self.on_cursor_move is not None: self.on_cursor_move(cursor_km) + col, row = cursor_km + new_cell = (int(col), int(row)) if (0 <= col < COLS and 0 <= row < ROWS) else None + if new_cell != self._hover_cell: + self._hover_cell = new_cell + self.queue_draw() + if self.placement_callback is not None: self._placement_cursor_km = cursor_km self.queue_draw() @@ -440,6 +452,9 @@ class GridCanvas(Gtk.DrawingArea): self._last_pointer_px = None if self.on_cursor_move is not None: self.on_cursor_move(None) + if self._hover_cell is not None: + self._hover_cell = None + self.queue_draw() if self.placement_callback is not None: self._placement_cursor_km = None self.queue_draw() @@ -552,6 +567,7 @@ class GridCanvas(Gtk.DrawingArea): cr.rectangle(MARGIN_LEFT + view.pad_x, MARGIN_TOP + view.pad_y, view.grid_w, view.grid_h) cr.clip() + self._draw_hover_subgrid(cr, view) self._draw_geo_overlays(cr, view) self._draw_firing_arrows(cr, view) self._draw_blast_radius(cr, view) @@ -600,6 +616,29 @@ class GridCanvas(Gtk.DrawingArea): cr.restore() + def _draw_hover_subgrid(self, cr, view) -> None: + """The fine 10x10 x:y subdivision lines for whichever large + cell the cursor is currently over, for precise sub-cell + targeting, most useful once zoomed in enough that a single + large cell actually has room to show them meaningfully.""" + if self._hover_cell is None: + return + cell_col, cell_row = self._hover_cell + r, g, b, a = GRID_LINE + cr.set_source_rgba(r, g, b, a * 0.6) # fainter than the plain grid lines, not louder + cr.set_line_width(1) + x0, y0 = self._km_to_px(view, (cell_col, cell_row)) + x1, y1 = self._km_to_px(view, (cell_col + 1, cell_row + 1)) + for i in range(1, 10): + x, _ = self._km_to_px(view, (cell_col + i / 10, cell_row)) + cr.move_to(x, y0) + cr.line_to(x, y1) + for i in range(1, 10): + _, y = self._km_to_px(view, (cell_col, cell_row + i / 10)) + cr.move_to(x0, y) + cr.line_to(x1, y) + cr.stroke() + def _draw_marker(self, cr, view, point_km, color, label, canvas_width, canvas_height, *, hollow=False, dim=False, selected=False, coord=None, extra_line=None, icon_surface=None) -> None: