Merge lp:~vikoadi/switchboard/keyboard-navigation into lp:~elementary-pantheon/switchboard/switchboard

Proposed by Viko Adi Rahmawan
Status: Merged
Approved by: Danielle Foré
Approved revision: 539
Merged at revision: 547
Proposed branch: lp:~vikoadi/switchboard/keyboard-navigation
Merge into: lp:~elementary-pantheon/switchboard/switchboard
Diff against target: 288 lines (+193/-10)
2 files modified
src/CategoryView.vala (+165/-8)
src/Switchboard.vala (+28/-2)
To merge this branch: bzr merge lp:~vikoadi/switchboard/keyboard-navigation
Reviewer Review Type Date Requested Status
Danielle Foré ux Approve
Artem Anufrij (community) code style Needs Fixing
David Gomes (community) Needs Fixing
elementary UX ux Pending
Review via email: mp+241757@code.launchpad.net

Commit message

Keyboard navigation throughout switchboard
- using arrow key will move selection
- using Return key to activate selection
- Alt+left key will bring back to CategoryView
- typing other key will start search
- press enter from startbar will activate first result

Description of the change

Keyboard navigation throughout switchboard
- using arrow key will move selection
- using Return key to activate selection
- Alt+left key will bring back to CategoryView
- typing other key will start search
- press enter from startbar will activate first result

please note that current elementary theme doesnt have focus style so either use Adwaita or comment

GtkIconView.view.cell:selected,
GtkIconView.view.cell:selected:focus {
    background-color: @base_color;
    color: @text_color;
}

in gtk-widgets.css theme file

To post a comment you must log in.
533. By Viko Adi Rahmawan

remove debug printing

534. By Viko Adi Rahmawan

remove TODO note

Revision history for this message
David Gomes (davidgomes) wrote :

"c", "d", "sel" and "dist" aren't really good variable names.

Also, this needs design input I'm pretty sure.

review: Needs Fixing
535. By Viko Adi Rahmawan

remove trailing whitespace, rename bad variable

Revision history for this message
Viko Adi Rahmawan (vikoadi) wrote :

variable renamed,
Ux team assigned

536. By Viko Adi Rahmawan

add space arround =>

Revision history for this message
Artem Anufrij (artem-anufrij) wrote :

see line comments

review: Needs Fixing (code style)
Revision history for this message
Danielle Foré (danrabbit) wrote :

Merge conflicts. Needs fixing.

review: Needs Fixing
537. By Viko Adi Rahmawan

merge trunk

538. By Viko Adi Rahmawan

clean code

539. By Viko Adi Rahmawan

clean code

Revision history for this message
Viko Adi Rahmawan (vikoadi) wrote :

merge trunk

Revision history for this message
Cody Garver (codygarver) wrote :

When I down arrow (⬇), the search field loses focus but I don't see where the "cursor" is. I can't see what is selected.

Revision history for this message
Viko Adi Rahmawan (vikoadi) wrote :

Have you try using adwaita theme?
read my note in Description of the Change above.

Revision history for this message
Danielle Foré (danrabbit) wrote :

Hm, just added some stuff to make a style for switchboard. For some reason GtkIconView in Switchboard won't accept a background color.

Revision history for this message
Danielle Foré (danrabbit) wrote :

It all appears to work correctly here :)

review: Approve (ux)
Revision history for this message
Cody Garver (codygarver) wrote :

Backspace key should close plug and return to categoryview

Revision history for this message
Danielle Foré (danrabbit) wrote :

No, no backspace! We removed that before because it causes issues.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/CategoryView.vala'
--- src/CategoryView.vala 2014-08-07 09:48:26 +0000
+++ src/CategoryView.vala 2015-03-10 10:08:38 +0000
@@ -102,6 +102,76 @@
102 break;102 break;
103 }103 }
104104
105 category_plugs.focus_out_event.connect ((e) => {
106 category_plugs.unselect_all ();
107
108 return false;
109 });
110
111 category_plugs.focus_in_event.connect ((e) => {
112 Gtk.TreePath path;
113
114 if (!category_plugs.get_cursor (out path, null)) {
115 path = new Gtk.TreePath.from_indices (0, -1);
116 }
117 category_plugs.select_path (path);
118
119 return false;
120 });
121
122 category_plugs.keynav_failed.connect ((direction) => {
123 Gtk.IconView new_view = null;
124 Gtk.TreePath path = null;
125 Gtk.TreePath selected_path = null;
126 int smallest_distance = 1000;
127 Gtk.TreeIter iter;
128 int distance;
129
130 if (direction == Gtk.DirectionType.UP) {
131 new_view = get_prev_icon_view (category);
132 if (new_view != null && category_plugs.get_cursor (out path, null)) {
133 var current_column = category_plugs.get_item_column (path);
134 var model = new_view.get_model ();
135
136 model.get_iter_first (out iter);
137 do {
138 path = model.get_path (iter);
139 var next_column = new_view.get_item_column (path);
140 distance = (next_column - current_column).abs ();
141 if (distance <= smallest_distance) {
142 selected_path = path;
143 smallest_distance = distance;
144 }
145 } while (model.iter_next (ref iter));
146 }
147 } else if (direction == Gtk.DirectionType.DOWN) {
148 new_view = get_next_icon_view (category);
149 if (new_view != null && category_plugs.get_cursor (out path, null)) {
150 var current_column = category_plugs.get_item_column (path);
151 var model = new_view.get_model ();
152
153 model.get_iter_first (out iter);
154 do {
155 path = model.get_path (iter);
156 var next_column = new_view.get_item_column (path);
157 distance = (next_column - current_column).abs ();
158 if (distance < smallest_distance) {
159 selected_path = path;
160 smallest_distance = distance;
161 }
162 } while (model.iter_next (ref iter));
163 }
164 }
165
166 if (new_view != null) {
167 new_view.set_cursor (selected_path, null, false);
168 new_view.grab_focus ();
169 return true;
170 }
171
172 return false;
173 });
174
105 attach (grid, 0, i, 1, 1);175 attach (grid, 0, i, 1, 1);
106 }176 }
107177
@@ -123,9 +193,9 @@
123 return false;193 return false;
124 });194 });
125 }195 }
126 196
127 private Gtk.IconView setup_icon_view () {197 private Gtk.IconView setup_icon_view () {
128 var store = new Gtk.ListStore (Columns.N_COLUMNS, typeof (Gdk.Pixbuf), typeof (string), 198 var store = new Gtk.ListStore (Columns.N_COLUMNS, typeof (Gdk.Pixbuf), typeof (string),
129 typeof(string), typeof(bool), typeof(Switchboard.Plug));199 typeof(string), typeof(bool), typeof(Switchboard.Plug));
130 store.set_sort_column_id (1, Gtk.SortType.ASCENDING);200 store.set_sort_column_id (1, Gtk.SortType.ASCENDING);
131 store.set_sort_column_id (1, Gtk.SortType.ASCENDING);201 store.set_sort_column_id (1, Gtk.SortType.ASCENDING);
@@ -142,7 +212,7 @@
142 category_plugs.set_hexpand (true);212 category_plugs.set_hexpand (true);
143 category_plugs.set_selection_mode (Gtk.SelectionMode.SINGLE);213 category_plugs.set_selection_mode (Gtk.SelectionMode.SINGLE);
144 category_plugs.set_activate_on_single_click (true);214 category_plugs.set_activate_on_single_click (true);
145 215
146 category_plugs.item_activated.connect (on_item_activated);216 category_plugs.item_activated.connect (on_item_activated);
147 var cellrenderer = (Gtk.CellRendererText)category_plugs.get_cells ().nth_data (0);217 var cellrenderer = (Gtk.CellRendererText)category_plugs.get_cells ().nth_data (0);
148 cellrenderer.wrap_mode = Pango.WrapMode.WORD;218 cellrenderer.wrap_mode = Pango.WrapMode.WORD;
@@ -195,7 +265,7 @@
195 }265 }
196266
197 store.append (out root);267 store.append (out root);
198 store.set (root, Columns.ICON, icon_pixbuf, Columns.TEXT, plug.display_name, 268 store.set (root, Columns.ICON, icon_pixbuf, Columns.TEXT, plug.display_name,
199 Columns.DESCRIPTION, plug.description, Columns.VISIBLE, true, Columns.PLUG, plug);269 Columns.DESCRIPTION, plug.description, Columns.VISIBLE, true, Columns.PLUG, plug);
200 unowned SwitchboardApp app = (SwitchboardApp) GLib.Application.get_default ();270 unowned SwitchboardApp app = (SwitchboardApp) GLib.Application.get_default ();
201 app.search_box.sensitive = true;271 app.search_box.sensitive = true;
@@ -211,6 +281,43 @@
211 }281 }
212 }282 }
213283
284
285 // focus to first visible item
286 public void grab_focus_first_icon_view () {
287 Gtk.TreePath first_path = null;
288
289 if (get_first_visible_path (personal_iconview, out first_path)) {
290 personal_iconview.grab_focus ();
291 } else if (get_first_visible_path (hardware_iconview, out first_path)) {
292 hardware_iconview.grab_focus ();
293 } else if (get_first_visible_path (network_iconview, out first_path)) {
294 network_iconview.grab_focus ();
295 } else if (get_first_visible_path (system_iconview, out first_path)) {
296 system_iconview.grab_focus ();
297 }
298 }
299
300 // activate first visible item
301 public void activate_first_item () {
302 Gtk.TreePath first_path = null;
303
304 if (get_first_visible_path (personal_iconview, out first_path)) {
305 personal_iconview.item_activated (first_path);
306 } else if (get_first_visible_path (hardware_iconview, out first_path)){
307 hardware_iconview.item_activated (first_path);
308 } else if (get_first_visible_path (network_iconview, out first_path)){
309 network_iconview.item_activated (first_path);
310 } else if (get_first_visible_path (system_iconview, out first_path)){
311 system_iconview.item_activated (first_path);
312 }
313 }
314
315 private bool get_first_visible_path (Gtk.IconView iv, out Gtk.TreePath path) {
316 Gtk.TreePath end;
317
318 return (iv.get_visible_range (out path, out end));
319 }
320
214 public void filter_plugs (string filter) {321 public void filter_plugs (string filter) {
215322
216 var any_found = false;323 var any_found = false;
@@ -231,12 +338,12 @@
231 app.hide_alert ();338 app.hide_alert ();
232 }339 }
233 }340 }
234 341
235 private bool search_by_category (string filter, Plug.Category category) {342 private bool search_by_category (string filter, Plug.Category category) {
236 343
237 Gtk.TreeModelFilter model_filter;344 Gtk.TreeModelFilter model_filter;
238 Gtk.Widget grid;345 Gtk.Widget grid;
239 346
240 switch (category) {347 switch (category) {
241 case Switchboard.Plug.Category.PERSONAL:348 case Switchboard.Plug.Category.PERSONAL:
242 model_filter = (Gtk.TreeModelFilter)personal_iconview.get_model ();349 model_filter = (Gtk.TreeModelFilter)personal_iconview.get_model ();
@@ -274,7 +381,7 @@
274381
275 return false;382 return false;
276 });383 });
277 384
278 if (shown == 0) {385 if (shown == 0) {
279 grid.hide ();386 grid.hide ();
280 return false;387 return false;
@@ -322,5 +429,55 @@
322429
323 return null;430 return null;
324 }431 }
432
433 private Gtk.IconView? get_next_icon_view (Switchboard.Plug.Category category) {
434 if (category == Plug.Category.PERSONAL) {
435 if (hardware_iconview.is_visible ())
436 return hardware_iconview;
437 else
438 category = Plug.Category.HARDWARE;
439 }
440
441 if (category == Plug.Category.HARDWARE) {
442 if (network_iconview.is_visible ())
443 return network_iconview;
444 else
445 category = Plug.Category.NETWORK;
446 }
447
448 if (category == Plug.Category.NETWORK) {
449 if (system_iconview.is_visible ())
450 return system_iconview;
451 else
452 category = Plug.Category.SYSTEM;
453 }
454
455 return null;
456 }
457
458 private Gtk.IconView? get_prev_icon_view (Switchboard.Plug.Category category) {
459 if (category == Plug.Category.SYSTEM) {
460 if (network_iconview.is_visible ())
461 return network_iconview;
462 else
463 category = Plug.Category.NETWORK;
464 }
465
466 if (category == Plug.Category.NETWORK) {
467 if (hardware_iconview.is_visible ())
468 return hardware_iconview;
469 else
470 category = Plug.Category.HARDWARE;
471 }
472
473 if (category == Plug.Category.HARDWARE) {
474 if (personal_iconview.is_visible ())
475 return personal_iconview;
476 else
477 category = Plug.Category.SYSTEM;
478 }
479
480 return null;
481 }
325 }482 }
326}483}
327484
=== modified file 'src/Switchboard.vala'
--- src/Switchboard.vala 2015-02-22 15:30:10 +0000
+++ src/Switchboard.vala 2015-03-10 10:08:38 +0000
@@ -59,6 +59,13 @@
59 private static string? plug_to_open = null;59 private static string? plug_to_open = null;
60 private static bool opened_directly = false;60 private static bool opened_directly = false;
61 private static bool should_animate_next_transition = true;61 private static bool should_animate_next_transition = true;
62 private const uint[] NAVIGATION_KEYS = {
63 Gdk.Key.Up,
64 Gdk.Key.Down,
65 Gdk.Key.Left,
66 Gdk.Key.Right,
67 Gdk.Key.Return
68 };
6269
63 static const OptionEntry[] entries = {70 static const OptionEntry[] entries = {
64 { "open-plug", 'o', 0, OptionArg.STRING, ref plug_to_open, N_("Open a plug"), "PLUG_NAME" },71 { "open-plug", 'o', 0, OptionArg.STRING, ref plug_to_open, N_("Open a plug"), "PLUG_NAME" },
@@ -402,13 +409,32 @@
402 search_box.changed.connect(() => {409 search_box.changed.connect(() => {
403 category_view.filter_plugs(search_box.get_text ());410 category_view.filter_plugs(search_box.get_text ());
404 });411 });
412 search_box.key_press_event.connect ((event) => {
413 if (event.keyval == Gdk.Key.Return) {
414 category_view.activate_first_item ();
415 return true;
416 }
417
418 return false;
419 });
405420
406 // Focus typing to the search bar421 // Focus typing to the search bar
407 main_window.key_press_event.connect ((event) => {422 main_window.key_press_event.connect ((event) => {
408 // alt+left should go back to all settings423 // alt+left should go back to all settings
409 if (Gdk.ModifierType.MOD1_MASK in event.state && event.keyval == Gdk.Key.Left) {424 if ((event.state & Gdk.ModifierType.MOD1_MASK) != 0 && event.keyval == Gdk.Key.Left) {
410 navigation_button.clicked ();425 navigation_button.clicked ();
411 }426 return false;
427 }
428
429 // Down key from search_bar should move focus to CategoryVIew
430 if (search_box.has_focus && event.keyval == Gdk.Key.Down) {
431 category_view.grab_focus_first_icon_view ();
432 return false;
433 }
434
435 // arrow key is being used by CategoryView to navigate
436 if (event.keyval in NAVIGATION_KEYS)
437 return false;
412438
413 // Don't focus if it is a modifier or if search_box is already focused439 // Don't focus if it is a modifier or if search_box is already focused
414 if ((event.is_modifier == 0) && !search_box.has_focus)440 if ((event.is_modifier == 0) && !search_box.has_focus)

Subscribers

People subscribed via source and target branches