Coverage for paintmaskanimator/document.py: 100%
21 statements
« prev ^ index » next coverage.py v7.17.0, created at 2026-11-02 04:50 +0000
« prev ^ index » next coverage.py v7.17.0, created at 2026-11-02 04:50 +0000
1"""Qt-independent document model.
3Owns the *what* of a project — the list of frames, which frame is current,
4and which layer is active — independent of any widget, event loop, or
5rendering. The PaintCanvas widget delegates its state to a Document instance
6so that this core model can be reasoned about and tested without a GUI.
8Frames/Layers still carry QImage payloads (a Qt data type, not a widget); the
9constraint here is *UI independence*, not total Qt independence.
10"""
11from . import constants
12from .models import make_frame
15class Document:
16 """Holds project state: frames + the current frame / active layer cursor."""
18 def __init__(self):
19 self.frames = [make_frame()]
20 self.current_frame = 0
21 self.active_layer_index = 0
23 @property
24 def layers(self):
25 """Layers of the current frame."""
26 return self.frames[self.current_frame].layers
28 @property
29 def active_layer(self):
30 return self.layers[self.active_layer_index]
32 def snapshot(self):
33 """Deep copy of the whole document state (used by undo/redo)."""
34 return (
35 [f.clone() for f in self.frames],
36 self.current_frame,
37 self.active_layer_index,
38 constants.CANVAS_WIDTH,
39 constants.CANVAS_HEIGHT,
40 )
42 def restore(self, snap):
43 """Restore state produced by :meth:`snapshot`.
45 Returns the (width, height) recorded in the snapshot so the caller can
46 apply any canvas-size side effects it owns.
47 """
48 frames, current_frame, active_layer_index, width, height = snap
49 self.frames = [f.clone() for f in frames]
50 self.current_frame = current_frame
51 self.active_layer_index = active_layer_index
52 return width, height