popover menu: Unify hover and focus

Menus traditionally don't have separate
hover and focus locations. Make the same
change here that we already did for
popover menubars: Track the active item
and set its selected state. Both keynav
and mouse change the active item.
This commit is contained in:
Matthias Clasen 2019-06-13 00:13:21 +00:00
parent a7e121384c
commit cbc0a8447d
3 changed files with 131 additions and 1 deletions

View File

@ -31,7 +31,7 @@
#include "gtkstylecontext.h" #include "gtkstylecontext.h"
#include "gtktypebuiltins.h" #include "gtktypebuiltins.h"
#include "gtkstack.h" #include "gtkstack.h"
#include "gtkpopover.h" #include "gtkpopovermenuprivate.h"
#include "gtkintl.h" #include "gtkintl.h"
#include "gtkcssnodeprivate.h" #include "gtkcssnodeprivate.h"
#include "gtkcsstypesprivate.h" #include "gtkcsstypesprivate.h"
@ -41,6 +41,8 @@
#include "gtksizegroup.h" #include "gtksizegroup.h"
#include "gtkaccellabelprivate.h" #include "gtkaccellabelprivate.h"
#include "gtkactionable.h" #include "gtkactionable.h"
#include "gtkeventcontrollermotion.h"
#include "gtkeventcontrollerkey.h"
/** /**
* SECTION:gtkmodelbutton * SECTION:gtkmodelbutton
@ -1127,9 +1129,75 @@ gtk_model_button_class_init (GtkModelButtonClass *class)
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), I_("modelbutton")); gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), I_("modelbutton"));
} }
static void
enter_cb (GtkEventController *controller,
double x,
double y,
GdkCrossingMode mode,
GdkNotifyType type,
gpointer data)
{
GtkWidget *target;
GtkWidget *popover;
gboolean is;
gboolean contains;
target = gtk_event_controller_get_widget (controller);
popover = gtk_widget_get_ancestor (target, GTK_TYPE_POPOVER_MENU);
g_object_get (controller,
"is-pointer-focus", &is,
"contains-pointer-focus", &contains,
NULL);
if (popover && (is || contains))
gtk_popover_menu_set_active_item (GTK_POPOVER_MENU (popover), target);
}
static void
leave_cb (GtkEventController *controller,
GdkCrossingMode mode,
GdkNotifyType type,
gpointer data)
{
GtkWidget *target;
GtkWidget *popover;
gboolean is;
gboolean contains;
target = gtk_event_controller_get_widget (controller);
popover = gtk_widget_get_ancestor (target, GTK_TYPE_POPOVER_MENU);
g_object_get (controller,
"is-pointer-focus", &is,
"contains-pointer-focus", &contains,
NULL);
if (popover && !(is || contains))
gtk_popover_menu_set_active_item (GTK_POPOVER_MENU (popover), NULL);
}
static void
focus_in_cb (GtkEventController *controller,
GdkCrossingMode mode,
GdkNotifyType type,
gpointer data)
{
GtkWidget *target;
GtkWidget *popover;
target = gtk_event_controller_get_widget (controller);
popover = gtk_widget_get_ancestor (target, GTK_TYPE_POPOVER_MENU);
if (popover)
gtk_popover_menu_set_active_item (GTK_POPOVER_MENU (popover), target);
}
static void static void
gtk_model_button_init (GtkModelButton *button) gtk_model_button_init (GtkModelButton *button)
{ {
GtkEventController *controller;
button->role = GTK_BUTTON_ROLE_NORMAL; button->role = GTK_BUTTON_ROLE_NORMAL;
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
button->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); button->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
@ -1161,6 +1229,15 @@ gtk_model_button_init (GtkModelButton *button)
gtk_widget_hide (button->start_indicator); gtk_widget_hide (button->start_indicator);
gtk_widget_hide (button->end_indicator); gtk_widget_hide (button->end_indicator);
update_node_ordering (button); update_node_ordering (button);
controller = gtk_event_controller_motion_new ();
g_signal_connect (controller, "enter", G_CALLBACK (enter_cb), NULL);
g_signal_connect (controller, "leave", G_CALLBACK (leave_cb), NULL);
gtk_widget_add_controller (GTK_WIDGET (button), controller);
controller = gtk_event_controller_key_new ();
g_signal_connect (controller, "focus-in", G_CALLBACK (focus_in_cb), NULL);
gtk_widget_add_controller (GTK_WIDGET (button), controller);
} }
/** /**

View File

@ -17,6 +17,8 @@
#include "config.h" #include "config.h"
#include "gtkpopovermenu.h" #include "gtkpopovermenu.h"
#include "gtkpopovermenuprivate.h"
#include "gtkstack.h" #include "gtkstack.h"
#include "gtkstylecontext.h" #include "gtkstylecontext.h"
#include "gtkintl.h" #include "gtkintl.h"
@ -120,6 +122,8 @@ typedef struct _GtkPopoverMenuClass GtkPopoverMenuClass;
struct _GtkPopoverMenu struct _GtkPopoverMenu
{ {
GtkPopover parent_instance; GtkPopover parent_instance;
GtkWidget *active_item;
}; };
struct _GtkPopoverMenuClass struct _GtkPopoverMenuClass
@ -133,6 +137,25 @@ enum {
G_DEFINE_TYPE (GtkPopoverMenu, gtk_popover_menu, GTK_TYPE_POPOVER) G_DEFINE_TYPE (GtkPopoverMenu, gtk_popover_menu, GTK_TYPE_POPOVER)
void
gtk_popover_menu_set_active_item (GtkPopoverMenu *menu,
GtkWidget *item)
{
if (menu->active_item != item)
{
if (menu->active_item)
gtk_widget_unset_state_flags (menu->active_item, GTK_STATE_FLAG_SELECTED);
menu->active_item = item;
if (menu->active_item)
{
gtk_widget_set_state_flags (menu->active_item, GTK_STATE_FLAG_SELECTED, FALSE);
gtk_widget_grab_focus (menu->active_item);
}
}
}
static void static void
visible_submenu_changed (GObject *object, visible_submenu_changed (GObject *object,
GParamSpec *pspec, GParamSpec *pspec,

View File

@ -0,0 +1,30 @@
/* GTK - The GIMP Toolkit
* Copyright © 2019 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GTK_POPOVER_MENU_PRIVATE_H__
#define __GTK_POPOVER_MENU_PRIVATE_H__
#include "gtkpopovermenu.h"
G_BEGIN_DECLS
void gtk_popover_menu_set_active_item (GtkPopoverMenu *popover,
GtkWidget *item);
G_END_DECLS
#endif /* __GTK_POPOVER_PRIVATE_H__ */