# Crossword State
**Status**: Deprecated Jan, 2024

## Changes
:::{important}
There have been some substantial updates to this struct
since this was authored. Most of the information included is not
wrong, but it's insufficient to describe this object. In particular:

* `XwordState` has now been renamed to `GridState` to more closely
  align with what it is.
* We capture more than just the cursor position in the struct, as
  selection and quirks have been added to the state.
* For the editor, more state is needed to be stored. This is kept in
  the `EditState` object (which itself contains multiple `GridStates`).
* The `load_state()` / `update_state()` pair has been simplified with
  just a single `update()` method.
:::

## Original Doc

Our goal with this game is to keep the playing board (and Crossword
Editor) as stateless as possible. To implement this, we have the
following invariants we adhere to:

* We encapsulate the current state completely in `XwordState`. This is
  enough to turn any widget to a known state, independent of path
  taken to get there.
* All `Play*` widgets and `Edit*` widgets should be able to recreate
  their state completely.
* Only the toplevels (`PlayXword` and `EditWindow` ) keeps a copy of
  that puzzle. Nothing else does.
* After loading the puzzle, we load a separate `IpuzSaved` grid from
  saved file, or the puzzle file itself if it exists. Otherwise, a new
  one is created. This is used to store any guesses the user makes.

* Each `Play*` widget has `_load_state()` and `_update_state()` functions that
will take a `PuzzleState` boxed and update its visual state based on it. They
will pass it on to their children.
 * `_load_state()` is called once the puzzle is loaded and sets up widgets
 based on the puzzle. `_update_state()` is called multiple times.
 * `_update_state()` should queue_redraws where appropriate.
* No `Play*` widget should cache a `PuzzleState` or IpuzCrossword. It copies
any appropriate identifying information directly into its widgets. `PlayCells`
will keep their coordinates; `PlayClueRows` will keep a copy of their
`IpuzClues`.
* Each `Play*` widget will emit a signal indicating if any change in the state
has occurred. Current valid signals are :
 * **`"PlayGrid::guess"`** – Text changed in a PlayCell
 * **`"PlayGrid::focus-changed"`** – A potential move of the focus (from an
 arrow key or Tab)
 * **`"PlayGrid::cell-selected"`** – A click on a cell
 * **`"PlayClues::clue-selected"`** – A click on a clue
* When those changes occur, they bubble up to the `PlayWindow`. The `PlayWindow`
is solely responsible for forwarding changes to the state as appropriate. Once
updated, it will call `_update_state()` again to propagate down.


### Invariants
* The only code that updates the board lives in `XwordState`.
* PlayWindow is responsible for forwarding events to the `XwordState`
* The XwordState keeps a copy of both the clue and the current cell for
convenience. The cell must be in the clue's cell extents.

### Focus

One result of this is we are completely replacing GTK's focus handling with
our own. It's close to correct, but not good enough and it will fight with the
state handling.

Only `PlayCell`s can have focus right now (along with the menu). The Clues
cannot. We will have to confirm this works with Accessibility.

As a result, PlayCell captures all focus keybindings and propagates that up
to the top. `XwordState` figures out the new focused widget.

A new `PlayCell` calls `grab_focus()` every time we set the state, which will
pull focus away from any other theoretical other widget. Time will tell if this
becomes a problem.
