[gtk/new-style-menu] popover bar: Add arrow keynav



commit 457eac1669d64f326513c0eae824ee8272a26f8c
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Jun 8 17:48:29 2019 +0000

    popover bar: Add arrow keynav
    
    Make left/right cycle the active item
    among the bars children. Separate the styling
    for the active item from :hover, since it is
    a separate state, and only mixed up in menus
    for historical reasons.

 gtk/gtkpopoverbar.c            | 130 ++++++++++++++++++++++++++++++++---------
 gtk/theme/Adwaita/_common.scss |  26 +++++++++
 2 files changed, 128 insertions(+), 28 deletions(-)
---
diff --git a/gtk/gtkpopoverbar.c b/gtk/gtkpopoverbar.c
index 69c86df8ce..f702abf6e6 100644
--- a/gtk/gtkpopoverbar.c
+++ b/gtk/gtkpopoverbar.c
@@ -45,6 +45,8 @@
 
 GType gtk_popover_bar_item_get_type (void) G_GNUC_CONST;
 
+typedef struct _GtkPopoverBarItem GtkPopoverBarItem;
+
 struct _GtkPopoverBar
 {
   GtkWidget parent;
@@ -52,7 +54,8 @@ struct _GtkPopoverBar
   GMenuModel *model;
   GtkMenuTracker *tracker;
   GtkWidget *box;
-  GtkWidget *open_popover;
+
+  GtkPopoverBarItem *active_item;
 };
 
 typedef struct _GtkPopoverBarClass GtkPopoverBarClass;
@@ -61,13 +64,12 @@ struct _GtkPopoverBarClass
   GtkWidgetClass parent_class;
 };
 
-typedef struct _GtkPopoverBarItem GtkPopoverBarItem;
 struct _GtkPopoverBarItem
 {
   GtkWidget parent;
 
   GtkWidget *label;
-  GtkWidget *popover;
+  GtkPopover *popover;
 };
 
 typedef struct _GtkPopoverBarItemClass GtkPopoverBarItemClass;
@@ -80,6 +82,52 @@ struct _GtkPopoverBarItemClass
 
 G_DEFINE_TYPE (GtkPopoverBarItem, gtk_popover_bar_item, GTK_TYPE_WIDGET)
 
+static void
+set_active_item (GtkPopoverBar     *bar,
+                 GtkPopoverBarItem *item,
+                 gboolean           popup)
+{
+  gboolean changed;
+  gboolean was_popup;
+
+  changed = item != bar->active_item;
+
+  if (bar->active_item)
+    was_popup = gtk_widget_get_mapped (GTK_WIDGET (bar->active_item->popover));
+  else
+    was_popup = FALSE;
+
+  if (was_popup && changed)
+    gtk_popover_popdown (bar->active_item->popover);
+
+  if (changed)
+    {
+      GtkStyleContext *context;
+
+      if (bar->active_item)
+        {
+          context = gtk_widget_get_style_context (GTK_WIDGET (bar->active_item));
+          gtk_style_context_remove_class (context, "active");
+        }
+
+      bar->active_item = item;
+
+      if (bar->active_item)
+        {
+          context = gtk_widget_get_style_context (GTK_WIDGET (bar->active_item));
+          gtk_style_context_add_class (context, "active");
+        }
+    }
+
+  if (bar->active_item)
+    {
+      if (popup || (was_popup && changed))
+        gtk_popover_popup (bar->active_item->popover);
+      else
+        gtk_widget_grab_focus (GTK_WIDGET (bar->active_item));
+    }
+}
+
 static void
 clicked_cb (GtkGesture *gesture,
             int         n,
@@ -88,20 +136,12 @@ clicked_cb (GtkGesture *gesture,
             gpointer    data)
 {
   GtkWidget *target;
-  GtkPopoverBarItem *item;
   GtkPopoverBar *bar;
 
   target = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
   bar = GTK_POPOVER_BAR (gtk_widget_get_ancestor (target, GTK_TYPE_POPOVER_BAR));
-  item = GTK_POPOVER_BAR_ITEM (target);
 
-  if (item->popover && item->popover != bar->open_popover)
-    {
-      if (bar->open_popover)
-        gtk_popover_popdown (GTK_POPOVER (bar->open_popover));
-      bar->open_popover = item->popover;
-      gtk_popover_popup (GTK_POPOVER (bar->open_popover));
-    }
+  set_active_item (bar, GTK_POPOVER_BAR_ITEM (target), TRUE);
 }
 
 static void
@@ -113,21 +153,48 @@ enter_cb (GtkEventController *controller,
           gpointer            data)
 {
   GtkWidget *target;
-  GtkPopoverBarItem *item;
   GtkPopoverBar *bar;
 
   target = gtk_event_controller_get_widget (controller);
 
   bar = GTK_POPOVER_BAR (gtk_widget_get_ancestor (target, GTK_TYPE_POPOVER_BAR));
-  item = GTK_POPOVER_BAR_ITEM (target);
 
-  if (item->popover && bar->open_popover &&
-      item->popover != bar->open_popover)
+  set_active_item (bar, GTK_POPOVER_BAR_ITEM (target), FALSE);
+}
+
+static gboolean
+key_pressed_cb (GtkEventController *controller,
+                guint keyval,
+                guint keycode,
+                GdkModifierType state,
+                gpointer data)
+{
+  GtkWidget *target;
+  GtkPopoverBar *bar;
+  GtkWidget *next;
+
+  target = gtk_event_controller_get_widget (controller);
+
+  bar = GTK_POPOVER_BAR (gtk_widget_get_ancestor (target, GTK_TYPE_POPOVER_BAR));
+
+  if (keyval == GDK_KEY_Left)
+    {
+      next = gtk_widget_get_prev_sibling (target);
+      if (next == NULL)
+        next = gtk_widget_get_last_child (GTK_WIDGET (bar->box));
+    }
+  else if (keyval == GDK_KEY_Right)
     {
-      gtk_popover_popdown (GTK_POPOVER (bar->open_popover));
-      bar->open_popover = item->popover;
-      gtk_popover_popup (GTK_POPOVER (bar->open_popover));
+      next = gtk_widget_get_next_sibling (target);
+      if (next == NULL)
+        next = gtk_widget_get_first_child (GTK_WIDGET (bar->box));
     }
+  else
+    return FALSE;
+
+  set_active_item (bar, GTK_POPOVER_BAR_ITEM (next), FALSE);
+
+  return TRUE;
 }
 
 static void
@@ -135,6 +202,8 @@ gtk_popover_bar_item_init (GtkPopoverBarItem *item)
 {
   GtkEventController *controller;
 
+  gtk_widget_set_can_focus (GTK_WIDGET (item), TRUE);
+
   item->label = g_object_new (GTK_TYPE_LABEL,
                               "use-underline", TRUE,
                               NULL);
@@ -148,6 +217,11 @@ gtk_popover_bar_item_init (GtkPopoverBarItem *item)
   gtk_event_controller_set_propagation_limit (controller, GTK_LIMIT_NONE);
   g_signal_connect (controller, "enter", G_CALLBACK (enter_cb), NULL);
   gtk_widget_add_controller (GTK_WIDGET (item), controller);
+
+  controller = gtk_event_controller_key_new ();
+  gtk_event_controller_set_propagation_limit (controller, GTK_LIMIT_NONE);
+  g_signal_connect (controller, "key-pressed", G_CALLBACK (key_pressed_cb), NULL);
+  gtk_widget_add_controller (GTK_WIDGET (item), controller);
 }
 
 static void
@@ -226,7 +300,7 @@ gtk_popover_bar_item_class_init (GtkPopoverBarItemClass *klass)
                   NULL,
                   G_TYPE_NONE, 0);
 
-  gtk_widget_class_set_css_name (widget_class, I_("menuitem"));
+  gtk_widget_class_set_css_name (widget_class, I_("item"));
 }
 enum
 {
@@ -260,11 +334,11 @@ tracker_remove (gint     position,
 }
 
 static void
-popover_unmap (GtkWidget     *popover,
+popover_unmap (GtkPopover    *popover,
                GtkPopoverBar *bar)
 {
-  if (popover == bar->open_popover)
-    bar->open_popover = NULL;
+  if (bar->active_item && bar->active_item->popover == popover)
+    set_active_item (bar, NULL, FALSE);
 }
 
 static void
@@ -280,7 +354,7 @@ tracker_insert (GtkMenuTrackerItem *item,
       GMenuModel *model;
       GtkWidget *sibling;
       GtkWidget *child;
-      GtkWidget *popover;
+      GtkPopover *popover;
       int i;
 
       widget = g_object_new (GTK_TYPE_POPOVER_BAR_ITEM, NULL);
@@ -289,10 +363,10 @@ tracker_insert (GtkMenuTrackerItem *item,
                               G_BINDING_SYNC_CREATE);
 
       model = _gtk_menu_tracker_item_get_link (item, G_MENU_LINK_SUBMENU);
-      popover = gtk_popover_menu_new_from_model (GTK_WIDGET (widget), model);
-      gtk_popover_set_position (GTK_POPOVER (popover), GTK_POS_BOTTOM);
-      gtk_popover_set_has_arrow (GTK_POPOVER (popover), FALSE);
-      gtk_widget_set_halign (popover, GTK_ALIGN_START);
+      popover = GTK_POPOVER (gtk_popover_menu_new_from_model (GTK_WIDGET (widget), model));
+      gtk_popover_set_position (popover, GTK_POS_BOTTOM);
+      gtk_popover_set_has_arrow (popover, FALSE);
+      gtk_widget_set_halign (GTK_WIDGET (popover), GTK_ALIGN_START);
 
       g_signal_connect (popover, "unmap", G_CALLBACK (popover_unmap), bar);
 
diff --git a/gtk/theme/Adwaita/_common.scss b/gtk/theme/Adwaita/_common.scss
index 3c0759b135..1c239e9f6b 100644
--- a/gtk/theme/Adwaita/_common.scss
+++ b/gtk/theme/Adwaita/_common.scss
@@ -2053,6 +2053,32 @@ menubar,
   .csd.popup decoration {border-radius:0;}
 }
 
+// popover menu bar
+
+menubar {
+  padding: 0px;
+  box-shadow: inset 0 -1px transparentize(black, 0.9);
+
+  &:backdrop { background-color: $backdrop_bg_color; }
+
+  > box > item {
+    min-height: 16px;
+    padding: 4px 8px;
+
+    &.active { //Seems like it :hover even with keyboard focus
+      box-shadow: inset 0 -3px $selected_bg_color;
+      color: $link_color;
+    }
+
+    &:disabled {
+      color: $insensitive_fg_color;
+      box-shadow: none;
+    }
+  }
+  // remove padding and rounding from menubar submenu decoration
+  .csd.popup decoration { border-radius:0; }
+}
+
 // Needed to make the border-radius of menus work
 // otherwise the background bleeds out of the menu edges
 .background.popup { background-color: transparent; }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]