1 module actions.find_focus_box_action;
2 
3 import fluid;
4 import optional;
5 
6 @safe:
7 
8 alias focusTracker = nodeBuilder!FocusTracker;
9 
10 /// Runs the focus box action
11 class FocusTracker : Space {
12 
13     FocusIO focusIO;
14     FindFocusBoxAction findFocusBoxAction;
15 
16     this(Node[] nodes...) {
17         super(nodes);
18         this.findFocusBoxAction = new FindFocusBoxAction;
19     }
20 
21     Optional!Rectangle focusBox() const {
22 
23         return findFocusBoxAction.focusBox;
24 
25     }
26 
27     override void resizeImpl(Vector2 space) {
28 
29         require(focusIO);
30         findFocusBoxAction.focusIO = focusIO;
31 
32         super.resizeImpl(space);
33 
34     }
35 
36     override void drawImpl(Rectangle outer, Rectangle inner) {
37 
38         // Start the action before drawing nodes
39         auto frame = startBranchAction(findFocusBoxAction);
40         super.drawImpl(outer, inner);
41 
42     }
43 
44 }
45 
46 alias presetFocusBox = nodeBuilder!PresetFocusBox;
47 
48 /// Always returns the focus box in the same position, regardless of where the node itself
49 /// is on on the screen
50 class PresetFocusBox : InputNode!Node {
51 
52     Rectangle focusBox;
53 
54     this(Rectangle focusBox = Rectangle(10, 10, 10, 10)) {
55         this.focusBox = focusBox;
56     }
57 
58     override void resizeImpl(Vector2 space) {
59         super.resizeImpl(space);
60         minSize = Vector2();
61     }
62 
63     override void drawImpl(Rectangle, Rectangle) {
64 
65     }
66 
67     override Rectangle focusBoxImpl(Rectangle) const {
68         return focusBox;
69     }
70 
71 }
72 
73 @("FindFocusBoxAction will report the current focus box")
74 unittest {
75 
76     PresetFocusBox[2] box;
77 
78     auto root = focusChain(
79         vspace(
80             box[0] = presetFocusBox(Rectangle(2, 2, 2, 2)),
81             box[1] = presetFocusBox(Rectangle(4, 4, 6, 6)),
82         ),
83     );
84 
85     // Frame 0: no focus
86     root.findFocusBox()
87         .then(rect => assert(rect.empty))
88         .runWhileDrawing(root);
89 
90     // Frame 1: first box has focus
91     box[0].focus();
92     assert(root.isFocused(box[0]));
93     root.findFocusBox()
94         .then(rect => assert(rect == box[0].focusBox))
95         .runWhileDrawing(root);
96 
97     // Frame 2: second box has focus
98     box[1].focus();
99     assert(root.isFocused(box[1]));
100     root.findFocusBox()
101         .then(rect => assert(rect == box[1].focusBox))
102         .runWhileDrawing(root);
103 
104 }
105 
106 @("FindFocusBoxAction can be used as a branch action")
107 unittest {
108 
109     PresetFocusBox[2] box;
110     FocusTracker tracker;
111 
112     auto root = focusChain(
113         tracker = focusTracker(
114             box[0] = presetFocusBox(Rectangle(2, 2, 2, 2)),
115             box[1] = presetFocusBox(Rectangle(4, 4, 6, 6)),
116         )
117     );
118 
119     root.draw();
120     assert(tracker.focusBox.empty);
121 
122     box[0].focus();
123     root.draw();
124     assert(tracker.focusBox == box[0].focusBox);
125     assert(tracker.focusBox != box[1].focusBox);
126 
127     box[1].focus();
128     root.draw();
129     assert(tracker.focusBox == box[1].focusBox);
130     assert(tracker.focusBox != box[0].focusBox);
131 
132 }