- commit
- 823ac74c2b02aeea19c4248cba14d5779c018258
- parent
- eb8440f4cd777f76eea1935b3a143213fd7d5b38
- author
- Dami <dami.etoile@gmail.com>
| M | nonogram/ | 39 | +++++++++++++++++++++--------- |
| M | nonogram/ | 15 | +++++++++++- |
@@ -41,6 +41,10 @@ type Model struct {
4141 // Screen geometry for mouse hit-testing.4242 termWidth, termHeight int4343 44+ // Cached grid origin for mouse hit-testing (recomputed on resize/solve).45+ originX, originY int46+ originValid bool47+4448 // Debug: last mouse event info.4549 lastMouseX, lastMouseY int4650 lastMouseBtn string@@ -90,28 +94,32 @@ func (m Model) Update(msg tea.Msg) (game.Gamer, tea.Cmd) {
9094 case tea.WindowSizeMsg:9195 m.termWidth = msg.Width9296 m.termHeight = msg.Height97+ m.originValid = false9398 9499 case tea.KeyPressMsg:95- if m.solved {96- break97- }98100 switch {99101 case key.Matches(msg, m.keys.FillTile):100- m.updateTile(filledTile)101- if m.supportsKeyRelease {102- m.paintBrush = filledTile102+ if !m.solved {103+ m.updateTile(filledTile)104+ if m.supportsKeyRelease {105+ m.paintBrush = filledTile106+ }103107 }104108 case key.Matches(msg, m.keys.MarkTile):105- m.updateTile(markedTile)106- if m.supportsKeyRelease {107- m.paintBrush = markedTile109+ if !m.solved {110+ m.updateTile(markedTile)111+ if m.supportsKeyRelease {112+ m.paintBrush = markedTile113+ }108114 }109115 case key.Matches(msg, m.keys.ClearTile):110- m.updateTile(emptyTile)111- m.paintBrush = 0116+ if !m.solved {117+ m.updateTile(emptyTile)118+ m.paintBrush = 0119+ }112120 default:113121 moved := m.cursor.Move(m.keys.CursorKeyMap, msg, m.width-1, m.height-1)114- if moved && m.paintBrush != 0 {122+ if moved && m.paintBrush != 0 && !m.solved {115123 m.updateTile(m.paintBrush)116124 }117125 }@@ -261,13 +269,20 @@ func (m Model) Reset() game.Gamer {
261269 m.currentHints = curr262270 m.solved = false263271 m.cursor = game.Cursor{}272+ m.paintBrush = 0273+ m.dragging = 0274+ m.originValid = false264275 return m265276 }266277 267278 func (m *Model) updateTile(r rune) {268279 m.grid[m.cursor.Y][m.cursor.X] = r269280 m.currentHints = generateTomography(m.grid)281+ wasSolved := m.solved270282 m.solved = m.currentHints.rows.equal(m.rowHints) && m.currentHints.cols.equal(m.colHints)283+ if m.solved != wasSolved {284+ m.originValid = false285+ }271286 }272287 273288 // toggleTile toggles a cell between the given target state and empty.@@ -11,7 +11,7 @@ import (
1111 // Returns (col, row, ok) where ok is false if the click landed outside the grid1212 // or on a separator.1313 func (m *Model) screenToGrid(screenX, screenY int) (col, row int, ok bool) {14- ox, oy := m.gridOrigin()14+ ox, oy := m.cachedGridOrigin()1515 lx := screenX - ox1616 ly := screenY - oy1717 if lx < 0 || ly < 0 {@@ -69,6 +69,19 @@ func localToCell(pos, count, unitWidth int) int {
6969 return cell7070 }7171 72+// cachedGridOrigin returns the screen position of the top-left corner of73+// cell (0,0), using a cached value when available. The cache is invalidated74+// on terminal resize and solve-state changes.75+func (m *Model) cachedGridOrigin() (x, y int) {76+ if m.originValid {77+ return m.originX, m.originY78+ }79+ x, y = m.gridOrigin()80+ m.originX, m.originY = x, y81+ m.originValid = true82+ return x, y83+}84+7285 // gridOrigin computes the screen position of the top-left corner of the7386 // first grid cell. Mouse coordinates are terminal-absolute, so we need to7487 // account for how the root model centers the game's View() output.