Coverage for paintmaskanimator/document.py: 100%

21 statements  

« prev     ^ index     » next       coverage.py v7.17.0, created at 2026-11-02 04:50 +0000

1"""Qt-independent document model. 

2 

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. 

7 

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 

13 

14 

15class Document: 

16 """Holds project state: frames + the current frame / active layer cursor.""" 

17 

18 def __init__(self): 

19 self.frames = [make_frame()] 

20 self.current_frame = 0 

21 self.active_layer_index = 0 

22 

23 @property 

24 def layers(self): 

25 """Layers of the current frame.""" 

26 return self.frames[self.current_frame].layers 

27 

28 @property 

29 def active_layer(self): 

30 return self.layers[self.active_layer_index] 

31 

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 ) 

41 

42 def restore(self, snap): 

43 """Restore state produced by :meth:`snapshot`. 

44 

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