Strange behaviour of GtkCheckMenuItem with submenus



I need a UI for letting the user limit a view of their data based on tags.
The user needs to be able to choose to a) show all items, b) show items
with certain tags, c) show items without certain tags.  So I made a menu
with 3 GtkRadioMenuItems and put submenus with GtkCheckMenuItems in them
for the two cases where the user has to select the tags.  It worked, but
the behaviour of the menus is odd.

When I activate the menu and move the cursor over the GtkRadioMenuItems and
the item under the cursor has a submenu, then the item under the cursor
becomes selected without any clicks. But if the
item under the cursor does not have a submenu, it does not become selected.

I think that's a problem because it's going to violate user expectations. A
user won't expect that scrolling through the menus without clicking
anything might cause a persistent state change.

What could be done about it?

1. disallow submenus on GtkRadioMenuItems
    I think this would be a bit extreme. I've presented one use case for
GtkCheckMenuItems with submenus and there are probably lots of others.

2. don't change which item is selected based on enter-events
    Sure, but that raises the question of how can the user select one of
these items. The obvious answer it that he can click on it. The issue there
is that currently clicking on an item with a submenu dismisses the submenu.
The behaviour would have to change in the case of GtkCheckMenuItems so that
a click on it would select it if it wasn't already selected.

3. make the check-mark box in the menu item separately clickable, so that
the user can click in the box to select the item.

The versions are: glib  2 .32.3, gtk 3.4.2

Here is code to reproduce the problem:

// Reproduces a problem with GtkCheckMenuItem with submenu
// To reproduce, run this, click on view, move mouse across entries, and
see the selected (i.e.
// checked) entry move between "show items with these tags" and "show items
without these tags".
// cc main.c -o main $(shell pkg-config --libs --cflags gtk+-3.0
gmodule-2.0)
// glib 2.32.3 gtk 3.4.2
#include <gtk/gtk.h>
main(int argc, char **argv) {
  printf("glib %d.%d.%d\n", glib_major_version, glib_minor_version,
glib_micro_version);
  printf("gtk %d.%d.%d\n", gtk_major_version, gtk_minor_version,
gtk_micro_version);
  gtk_init(&argc, &argv);

  // Make a window with a vbox and a menu bar
  GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_widget_set_size_request (window, 500, 400);
  GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
  gtk_container_add(GTK_CONTAINER(window), vbox);
  GtkWidget *menu_bar = gtk_menu_bar_new();
  gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 0);

  // add the view menu item and menu
  GtkWidget *view_menu_item = gtk_menu_item_new_with_label("view");
  gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), view_menu_item);
  GtkWidget *view_menu = gtk_menu_new();
  gtk_menu_item_set_submenu(GTK_MENU_ITEM(view_menu_item), view_menu);

  // add the show_all and show nothing menu items
  GtkWidget *show_all = gtk_radio_menu_item_new_with_label(NULL, "show
all");
  GtkWidget *show_nothing = gtk_radio_menu_item_new_with_label_from_widget(
      GTK_RADIO_MENU_ITEM(show_all), "don't show anything");
  gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), show_all);
  gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), show_nothing);

  // add the show_with_tags and show_without_tags menu items and menus.
  GtkWidget *show_with_tags =
gtk_radio_menu_item_new_with_label_from_widget(
      GTK_RADIO_MENU_ITEM(show_all), "show items with these tags");
  GtkWidget *show_without_tags =
gtk_radio_menu_item_new_with_label_from_widget(
      GTK_RADIO_MENU_ITEM(show_all), "show items without these tags");
  gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), show_with_tags);
  gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), show_without_tags);
  GtkWidget* show_with_tags_menu = gtk_menu_new();
  GtkWidget* show_without_tags_menu = gtk_menu_new();
  gtk_menu_item_set_submenu(GTK_MENU_ITEM(show_with_tags),
show_with_tags_menu);
  gtk_menu_item_set_submenu(GTK_MENU_ITEM(show_without_tags),
show_without_tags_menu);

  // Add the check menu items for tags to the show_with_tags_menu
  GtkWidget *show_red = gtk_check_menu_item_new_with_label("red");
  gtk_menu_shell_append(GTK_MENU_SHELL(show_with_tags_menu), show_red);
  GtkWidget *show_green = gtk_check_menu_item_new_with_label("green");
  gtk_menu_shell_append(GTK_MENU_SHELL(show_with_tags_menu), show_green);

  // Add the check menu items for tags to the show_without_tags_menu
  GtkWidget *dont_show_red = gtk_check_menu_item_new_with_label("red");
  gtk_menu_shell_append(GTK_MENU_SHELL(show_without_tags_menu),
dont_show_red);
  GtkWidget *dont_show_green = gtk_check_menu_item_new_with_label("green");
  gtk_menu_shell_append(GTK_MENU_SHELL(show_without_tags_menu),
dont_show_green);

  gtk_widget_show_all(window);
  gtk_main();
}



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