55 * Authored by: Leonhard Kargl <[email protected] > 66 */
77
8- public interface Gala.Focusable : Clutter .Actor {
8+ public interface Gala.Focusable : Clutter .Actor {
99 public enum FocusDirection {
1010 UP ,
1111 DOWN ,
@@ -17,6 +17,23 @@ public interface Gala.Focusable : Clutter.Actor {
1717 public bool is_forward () {
1818 return this == DOWN || this == RIGHT || this == NEXT ;
1919 }
20+
21+ public static FocusDirection ? get_for_event (Clutter .Event event ) {
22+ switch (event. get_key_symbol ()) {
23+ case Clutter . Key . Up : return UP ;
24+ case Clutter . Key . Down : return DOWN ;
25+ case Clutter . Key . Left : return LEFT ;
26+ case Clutter . Key . Right : return RIGHT ;
27+ case Clutter . Key . Tab :
28+ if (SHIFT_MASK in event. get_state ()) {
29+ return PREVIOUS ;
30+ } else {
31+ return NEXT ;
32+ }
33+ }
34+
35+ return null ;
36+ }
2037 }
2138
2239 public bool focus (FocusDirection direction ) {
@@ -62,6 +79,46 @@ public interface Gala.Focusable : Clutter.Actor {
6279 }
6380
6481 protected virtual bool move_focus (FocusDirection direction ) {
82+ var children = get_focusable_children ();
83+
84+ filter_children_for_direction (children, direction);
85+
86+ switch (direction) {
87+ case NEXT :
88+ sort_children_for_direction (children, DOWN );
89+ sort_children_for_direction (children, RIGHT );
90+ break ;
91+
92+ case PREVIOUS :
93+ sort_children_for_direction (children, UP );
94+ sort_children_for_direction (children, LEFT );
95+ break ;
96+
97+ default:
98+ sort_children_for_direction (children, direction);
99+ break ;
100+ }
101+
102+ foreach (var child in children) {
103+ if (child. focus (direction)) {
104+ return true ;
105+ }
106+ }
107+
108+ return false ;
109+ }
110+
111+ private Gee .List<Focusable > get_focusable_children () {
112+ var focusable_children = new Gee .ArrayList<Focusable > ();
113+ for (var child = get_first_child (); child != null ; child = child. get_next_sibling ()) {
114+ if (child is Focusable ) {
115+ focusable_children. add ((Focusable ) child);
116+ }
117+ }
118+ return focusable_children;
119+ }
120+
121+ private void filter_children_for_direction (Gee .List<Focusable > children , FocusDirection direction ) {
65122 var focus_actor = get_stage (). get_key_focus ();
66123
67124 Focusable ? focus_child = null ;
@@ -74,9 +131,9 @@ public interface Gala.Focusable : Clutter.Actor {
74131 }
75132 }
76133
77- var possible_children = new Gee .ArrayList <Focusable > ();
78- possible_children . add_all_iterator (get_focusable_children () . filter ((c) = > {
79- if (focus_child == null || c == focus_child) {
134+ var to_retain = new Gee .LinkedList <Focusable > ();
135+ to_retain . add_all_iterator (children . filter ((c) = > {
136+ if (focus_child == null || c == focus_child || direction == NEXT || direction == PREVIOUS ) {
80137 return true ;
81138 }
82139
@@ -97,7 +154,15 @@ public interface Gala.Focusable : Clutter.Actor {
97154 );
98155 }));
99156
100- possible_children. sort ((a, b) = > {
157+ children. retain_all (to_retain);
158+ }
159+
160+ private inline Mtk .Rectangle get_allocation_rect (Clutter .Actor actor ) {
161+ return {(int ) actor. x, (int ) actor. y, (int ) actor. width, (int ) actor. height};
162+ }
163+
164+ private void sort_children_for_direction (Gee .List<Focusable > children , FocusDirection direction ) {
165+ children. sort ((a, b) = > {
101166 if (direction == UP && a. y + a. height > b. y + b. height ||
102167 direction == DOWN && a. y < b. y ||
103168 direction == LEFT && a. x + a. width > b. x + b. width ||
@@ -108,28 +173,6 @@ public interface Gala.Focusable : Clutter.Actor {
108173
109174 return 1 ;
110175 });
111-
112- foreach (var child in possible_children) {
113- if (child. focus (direction)) {
114- return true ;
115- }
116- }
117-
118- return false ;
119- }
120-
121- private Mtk .Rectangle get_allocation_rect (Clutter .Actor actor ) {
122- return {(int ) actor. x, (int ) actor. y, (int ) actor. width, (int ) actor. height};
123- }
124-
125- private Gee .List<Focusable > get_focusable_children () {
126- var focusable_children = new Gee .ArrayList<Focusable > ();
127- for (var child = get_first_child (); child != null ; child = child. get_next_sibling ()) {
128- if (child is Focusable ) {
129- focusable_children. add ((Focusable ) child);
130- }
131- }
132- return focusable_children;
133176 }
134177
135178 private bool grab_focus () {
@@ -138,6 +181,8 @@ public interface Gala.Focusable : Clutter.Actor {
138181 }
139182
140183 get_stage (). set_key_focus (this );
184+ notify_visible_focus_changed ();
185+ key_focus_out. connect (notify_visible_focus_changed);
141186
142187 return true ;
143188 }
@@ -146,37 +191,10 @@ public interface Gala.Focusable : Clutter.Actor {
146191 return false ;
147192 }
148193
149- public void mark_root (Clutter .Stage stage ) {
150- stage. key_press_event. connect (on_key_press_event);
194+ internal void notify_visible_focus_changed () {
195+ var stage = get_stage ();
196+ update_focus (stage? . get_key_focus () == this && FocusController . get_default (stage). focus_visible);
151197 }
152198
153- private bool on_key_press_event (Clutter .Event event ) {
154- if (! mapped) {
155- return Clutter . EVENT_PROPAGATE ;
156- }
157-
158- switch (event. get_key_symbol ()) {
159- case Clutter . Key . Tab :
160- if (SHIFT_MASK in event. get_state ()) {
161- focus (PREVIOUS );
162- } else {
163- focus (NEXT );
164- }
165- return Clutter . EVENT_STOP ;
166- case Clutter . Key . Up :
167- focus (UP );
168- return Clutter . EVENT_STOP ;
169- case Clutter . Key . Left :
170- focus (LEFT );
171- return Clutter . EVENT_STOP ;
172- case Clutter . Key . Down :
173- focus (DOWN );
174- return Clutter . EVENT_STOP ;
175- case Clutter . Key . Right :
176- focus (RIGHT );
177- return Clutter . EVENT_STOP ;
178- default:
179- return Clutter . EVENT_PROPAGATE ;
180- }
181- }
199+ protected virtual void update_focus (bool has_visible_focus ) { }
182200}
0 commit comments