Fix toolbar problems with Adwaita: Closes #5567
Complete refactoring of dropdown menu toolbar buttons. This uses a better approach toward using customized widgets for the toggle buttons and a more centralized approach toward maintaining the dropdown menu. In additional, Geary.FolderPath is now a Comparable, and should be used as such in the future. It's believed this patch will also fix ticket #5831.
This commit is contained in:
parent
a969b44ad2
commit
403ae6dc69
9 changed files with 291 additions and 165 deletions
|
|
@ -237,8 +237,8 @@ client/util/util-date.vala
|
|||
client/util/util-email.vala
|
||||
client/util/util-files.vala
|
||||
client/util/util-gravatar.vala
|
||||
client/util/util-gtk.vala
|
||||
client/util/util-keyring.vala
|
||||
client/util/util-menu.vala
|
||||
client/util/util-webkit.vala
|
||||
|
||||
client/views/formatted-conversation-data.vala
|
||||
|
|
|
|||
|
|
@ -724,7 +724,7 @@ public class ComposerWindow : Gtk.Window {
|
|||
return;
|
||||
|
||||
font_menu.show_all();
|
||||
font_menu.popup(null, null, menu_popup_relative, 0, 0);
|
||||
font_menu.popup(null, null, GtkUtil.menu_popup_relative, 0, 0);
|
||||
}
|
||||
|
||||
private void on_deactivate_font_menu() {
|
||||
|
|
@ -736,7 +736,7 @@ public class ComposerWindow : Gtk.Window {
|
|||
return;
|
||||
|
||||
font_size_menu.show_all();
|
||||
font_size_menu.popup(null, null, menu_popup_relative, 0, 0);
|
||||
font_size_menu.popup(null, null, GtkUtil.menu_popup_relative, 0, 0);
|
||||
}
|
||||
|
||||
private void on_deactivate_font_size_menu() {
|
||||
|
|
|
|||
|
|
@ -194,13 +194,11 @@ public class GearyController {
|
|||
mark_unstarred.label = _("U_nstar");
|
||||
entries += mark_unstarred;
|
||||
|
||||
Gtk.ActionEntry copy_menu = { ACTION_COPY_MENU, null, TRANSLATABLE, "L", null,
|
||||
on_show_copy_menu };
|
||||
Gtk.ActionEntry copy_menu = { ACTION_COPY_MENU, null, TRANSLATABLE, "L", null, null };
|
||||
copy_menu.label = _("_Label");
|
||||
entries += copy_menu;
|
||||
|
||||
Gtk.ActionEntry move_menu = { ACTION_MOVE_MENU, null, TRANSLATABLE, "M", null,
|
||||
on_show_move_menu };
|
||||
Gtk.ActionEntry move_menu = { ACTION_MOVE_MENU, null, TRANSLATABLE, "M", null, null };
|
||||
move_menu.label = _("_Move");
|
||||
entries += move_menu;
|
||||
|
||||
|
|
@ -891,15 +889,7 @@ public class GearyController {
|
|||
private void on_mark_complete() {
|
||||
set_busy(false);
|
||||
}
|
||||
|
||||
private void on_show_copy_menu() {
|
||||
main_window.main_toolbar.copy_folder_menu.show();
|
||||
}
|
||||
|
||||
private void on_show_move_menu() {
|
||||
main_window.main_toolbar.move_folder_menu.show();
|
||||
}
|
||||
|
||||
|
||||
private void on_copy_conversation(Geary.Folder destination) {
|
||||
// Nothing to do if nothing selected.
|
||||
if (selected_conversations == null || selected_conversations.size == 0)
|
||||
|
|
@ -1227,7 +1217,7 @@ public class GearyController {
|
|||
}
|
||||
|
||||
// Disables all single-message buttons and enables all multi-message buttons.
|
||||
public void enable_multiple_message_buttons(){
|
||||
public void enable_multiple_message_buttons() {
|
||||
// Single message only buttons.
|
||||
GearyApplication.instance.actions.get_action(ACTION_REPLY_TO_MESSAGE).sensitive = false;
|
||||
GearyApplication.instance.actions.get_action(ACTION_REPLY_ALL_MESSAGE).sensitive = false;
|
||||
|
|
|
|||
|
|
@ -4,33 +4,20 @@
|
|||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
public class FolderMenu {
|
||||
private Gtk.Menu? menu = null;
|
||||
private Gtk.Menu proxy_menu;
|
||||
private Gtk.ToggleToolButton button;
|
||||
public class FolderMenu : GtkUtil.ToggleToolbarDropdown {
|
||||
private Gee.List<Geary.Folder> folder_list = new Gee.ArrayList<Geary.Folder>();
|
||||
|
||||
public signal void folder_selected(Geary.Folder folder);
|
||||
|
||||
public FolderMenu(Gtk.ToggleToolButton button, Icon? icon, string? label) {
|
||||
this.button = button;
|
||||
public FolderMenu(Icon icon, Gtk.IconSize icon_size, Gtk.Menu? supplied_menu,
|
||||
Gtk.Menu? supplied_proxy_menu) {
|
||||
base (icon, icon_size, supplied_menu, supplied_proxy_menu);
|
||||
|
||||
// TODO Add fancy filter option.
|
||||
// TODO Make the menu items checkboxes instead of buttons.
|
||||
// TODO Merge the move/copy menus and just have a move/copy buttons at bottom of this menu.
|
||||
|
||||
menu = new Gtk.Menu();
|
||||
attach_menu(button, menu);
|
||||
menu.deactivate.connect(on_menu_deactivate);
|
||||
menu.show_all();
|
||||
|
||||
proxy_menu = new Gtk.Menu();
|
||||
add_proxy_menu(button, label, proxy_menu);
|
||||
|
||||
// only use label for proxy, not the toolbar
|
||||
make_menu_dropdown_button(button, icon, null);
|
||||
}
|
||||
|
||||
|
||||
public void add_folder(Geary.Folder folder) {
|
||||
folder_list.add(folder);
|
||||
folder_list.sort((CompareFunc) folder_sort);
|
||||
|
|
@ -56,39 +43,17 @@ public class FolderMenu {
|
|||
proxy_menu.show_all();
|
||||
}
|
||||
|
||||
public void show() {
|
||||
if (!button.active)
|
||||
return;
|
||||
|
||||
menu.popup(null, null, menu_popup_relative, 0, 0);
|
||||
menu.select_first(true);
|
||||
}
|
||||
|
||||
private Gtk.MenuItem build_menu_item(Geary.Folder folder) {
|
||||
Gtk.MenuItem menu_item = new Gtk.MenuItem.with_label(folder.get_path().to_string());
|
||||
menu_item.activate.connect(() => {
|
||||
on_menu_item_activated(folder);
|
||||
folder_selected(folder);
|
||||
});
|
||||
|
||||
return menu_item;
|
||||
}
|
||||
|
||||
private void attach_menu(Gtk.ToggleToolButton button, Gtk.Menu menu) {
|
||||
menu.attach_to_widget(button, null);
|
||||
menu.deactivate.connect(() => button.active = false);
|
||||
button.clicked.connect(show);
|
||||
}
|
||||
|
||||
private void on_menu_deactivate() {
|
||||
button.active = false;
|
||||
}
|
||||
|
||||
private void on_menu_item_activated(Geary.Folder folder) {
|
||||
folder_selected(folder);
|
||||
}
|
||||
|
||||
private static int folder_sort(Geary.Folder a, Geary.Folder b) {
|
||||
return a.get_path().to_string().casefold().collate(b.get_path().to_string().casefold());
|
||||
return a.get_path().compare(b.get_path());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,18 +53,23 @@ public class IconFactory {
|
|||
unstarred = load("non-starred-grey", STAR_ICON_SIZE);
|
||||
}
|
||||
|
||||
public Icon get_custom_icon(string name, Gtk.IconSize size) {
|
||||
int pixels;
|
||||
switch (size) {
|
||||
private int icon_size_to_pixels(Gtk.IconSize icon_size) {
|
||||
switch (icon_size) {
|
||||
case ICON_SIDEBAR:
|
||||
pixels = 16;
|
||||
break;
|
||||
return 16;
|
||||
|
||||
case ICON_TOOLBAR:
|
||||
default:
|
||||
pixels = 24;
|
||||
break;
|
||||
return 24;
|
||||
}
|
||||
}
|
||||
|
||||
public Icon get_theme_icon(string name) {
|
||||
return new ThemedIcon(name);
|
||||
}
|
||||
|
||||
public Icon get_custom_icon(string name, Gtk.IconSize size) {
|
||||
int pixels = icon_size_to_pixels(size);
|
||||
|
||||
return new FileIcon(icons_dir.get_child("%dx%d".printf(pixels, pixels)).get_child("%s.svg".printf(name)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,10 @@ public class MainToolbar : Gtk.Box {
|
|||
private Gtk.Toolbar toolbar;
|
||||
public FolderMenu copy_folder_menu { get; private set; }
|
||||
public FolderMenu move_folder_menu { get; private set; }
|
||||
|
||||
|
||||
private GtkUtil.ToggleToolbarDropdown mark_menu_dropdown;
|
||||
private GtkUtil.ToggleToolbarDropdown app_menu_dropdown;
|
||||
|
||||
public MainToolbar() {
|
||||
Object(orientation: Gtk.Orientation.VERTICAL, spacing: 0);
|
||||
|
||||
|
|
@ -24,58 +27,52 @@ public class MainToolbar : Gtk.Box {
|
|||
set_toolbutton_action(builder, GearyController.ACTION_DELETE_MESSAGE);
|
||||
|
||||
// Setup the folder menus (move/copy).
|
||||
Gtk.ToggleToolButton copy_menu_button = set_toolbutton_action(builder,
|
||||
|
||||
Gtk.ToggleToolButton copy_toggle_button = set_toolbutton_action(builder,
|
||||
GearyController.ACTION_COPY_MENU) as Gtk.ToggleToolButton;
|
||||
copy_folder_menu = new FolderMenu(copy_menu_button,
|
||||
IconFactory.instance.get_custom_icon("tag-new", IconFactory.ICON_TOOLBAR), _("Label as"));
|
||||
|
||||
Gtk.ToggleToolButton move_menu_button = set_toolbutton_action(builder,
|
||||
copy_folder_menu = new FolderMenu(
|
||||
IconFactory.instance.get_custom_icon("tag-new", IconFactory.ICON_TOOLBAR),
|
||||
Gtk.IconSize.LARGE_TOOLBAR, null, null);
|
||||
copy_folder_menu.attach(copy_toggle_button);
|
||||
|
||||
Gtk.ToggleToolButton move_toggle_button = set_toolbutton_action(builder,
|
||||
GearyController.ACTION_MOVE_MENU) as Gtk.ToggleToolButton;
|
||||
move_folder_menu = new FolderMenu(move_menu_button,
|
||||
IconFactory.instance.get_custom_icon("mail-move", IconFactory.ICON_TOOLBAR), _("Move to"));
|
||||
|
||||
move_folder_menu = new FolderMenu(
|
||||
IconFactory.instance.get_custom_icon("mail-move", IconFactory.ICON_TOOLBAR),
|
||||
Gtk.IconSize.LARGE_TOOLBAR, null, null);
|
||||
move_folder_menu.attach(move_toggle_button);
|
||||
|
||||
// Assemble mark menu button.
|
||||
GearyApplication.instance.load_ui_file("toolbar_mark_menu.ui");
|
||||
Gtk.Menu mark_menu = GearyApplication.instance.ui_manager.get_widget("/ui/ToolbarMarkMenu")
|
||||
as Gtk.Menu;
|
||||
Gtk.ToggleToolButton mark_menu_button = set_toolbutton_action(builder,
|
||||
GearyController.ACTION_MARK_AS_MENU) as Gtk.ToggleToolButton;
|
||||
attach_menu(mark_menu, mark_menu_button);
|
||||
make_menu_dropdown_button(mark_menu_button,
|
||||
IconFactory.instance.get_custom_icon("edit-mark", IconFactory.ICON_TOOLBAR), null);
|
||||
Gtk.Menu mark_proxy_menu = (Gtk.Menu) GearyApplication.instance.ui_manager
|
||||
.get_widget("/ui/ToolbarMarkMenuProxy");
|
||||
add_proxy_menu(mark_menu_button, _("Mark"), mark_proxy_menu);
|
||||
|
||||
Gtk.ToggleToolButton mark_menu_button = set_toolbutton_action(builder,
|
||||
GearyController.ACTION_MARK_AS_MENU) as Gtk.ToggleToolButton;
|
||||
mark_menu_dropdown = new GtkUtil.ToggleToolbarDropdown(
|
||||
IconFactory.instance.get_custom_icon("edit-mark", IconFactory.ICON_TOOLBAR),
|
||||
Gtk.IconSize.LARGE_TOOLBAR, mark_menu, mark_proxy_menu);
|
||||
mark_menu_dropdown.attach(mark_menu_button);
|
||||
|
||||
// Setup the application menu.
|
||||
GearyApplication.instance.load_ui_file("toolbar_menu.ui");
|
||||
Gtk.Menu menu = GearyApplication.instance.ui_manager.get_widget("/ui/ToolbarMenu") as Gtk.Menu;
|
||||
Gtk.ToggleToolButton application_menu_button = (Gtk.ToggleToolButton) builder.get_object("menu_button");
|
||||
attach_menu(menu, application_menu_button);
|
||||
Gtk.Menu application_proxy_menu = (Gtk.Menu) GearyApplication.instance.ui_manager
|
||||
.get_widget("/ui/ToolbarMenuProxy");
|
||||
add_proxy_menu(application_menu_button, application_menu_button.label, application_proxy_menu);
|
||||
|
||||
Gtk.Menu application_menu = GearyApplication.instance.ui_manager.get_widget("/ui/ToolbarMenu")
|
||||
as Gtk.Menu;
|
||||
Gtk.Menu application_proxy_menu = GearyApplication.instance.ui_manager.get_widget("/ui/ToolbarMenuProxy")
|
||||
as Gtk.Menu;
|
||||
Gtk.ToggleToolButton app_menu_button = (Gtk.ToggleToolButton) builder.get_object("menu_button");
|
||||
app_menu_dropdown = new GtkUtil.ToggleToolbarDropdown(
|
||||
IconFactory.instance.get_theme_icon("application-menu"), Gtk.IconSize.LARGE_TOOLBAR,
|
||||
application_menu, application_proxy_menu);
|
||||
app_menu_dropdown.show_arrow = false;
|
||||
app_menu_dropdown.attach(app_menu_button);
|
||||
|
||||
toolbar.get_style_context().add_class("primary-toolbar");
|
||||
|
||||
add(toolbar);
|
||||
}
|
||||
|
||||
private void attach_menu(Gtk.Menu menu, Gtk.ToggleToolButton button) {
|
||||
menu.attach_to_widget(button, null);
|
||||
menu.deactivate.connect(() => {
|
||||
button.active = false;
|
||||
});
|
||||
button.clicked.connect(() => {
|
||||
// Prevent loops.
|
||||
if (!button.active) {
|
||||
return;
|
||||
}
|
||||
|
||||
menu.popup(null, null, menu_popup_relative, 0, 0);
|
||||
});
|
||||
}
|
||||
|
||||
private Gtk.ToolButton set_toolbutton_action(Gtk.Builder builder, string action) {
|
||||
Gtk.ToolButton button = builder.get_object(action) as Gtk.ToolButton;
|
||||
button.set_related_action(GearyApplication.instance.actions.get_action(action));
|
||||
|
|
|
|||
196
src/client/util/util-gtk.vala
Normal file
196
src/client/util/util-gtk.vala
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
/* Copyright 2012 Yorba Foundation
|
||||
*
|
||||
* This software is licensed under the GNU Lesser General Public License
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
namespace GtkUtil {
|
||||
|
||||
// The reason GtkUtil.ToggleToolbarDropdown exists (rather than using Gtk.MenuToolButton) is that
|
||||
// the latter creates two separate buttons, one for the icon (which activates the "default" action)
|
||||
// and one for the arrow (which presents the dropdown menu). We need a single button that shows
|
||||
// the dropdown menu only, hence this version.
|
||||
//
|
||||
// In order to use this, create a Gtk.ToggleToolButton and call attach().
|
||||
//
|
||||
// TODO: An better solution would be for this to subclass Gtk.ToggleToolButton and register class
|
||||
// with Gtk.Builder and Glade.
|
||||
//
|
||||
// TODO: Would be better to get the icon from the ToggleToolbarButton (could do this even without
|
||||
// above improvement), but unlike the label, that's not so straightforward due to the number of
|
||||
// ways of representing an icon in GTK.
|
||||
|
||||
public class ToggleToolbarDropdown : Object {
|
||||
public const int DEFAULT_PADDING = 2;
|
||||
|
||||
public bool show_arrow { get; set; default = true; }
|
||||
public Gtk.Menu menu { get; private set; }
|
||||
public Gtk.Menu proxy_menu { get; private set; }
|
||||
|
||||
private int padding;
|
||||
private Gtk.Image icon;
|
||||
private Gtk.Label label = new Gtk.Label(null);
|
||||
private Gtk.Arrow icon_arrow = new Gtk.Arrow(Gtk.ArrowType.DOWN, Gtk.ShadowType.NONE);
|
||||
private Gtk.Box icon_box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0);
|
||||
private Gtk.Arrow label_arrow = new Gtk.Arrow(Gtk.ArrowType.DOWN, Gtk.ShadowType.NONE);
|
||||
private Gtk.Box label_box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0);
|
||||
private Gtk.ToggleToolButton? owner = null;
|
||||
|
||||
public ToggleToolbarDropdown(Icon icon, Gtk.IconSize icon_size, Gtk.Menu? supplied_menu,
|
||||
Gtk.Menu? supplied_proxy_menu, int padding = DEFAULT_PADDING) {
|
||||
this.padding = padding;
|
||||
this.icon = new Gtk.Image.from_gicon(icon, icon_size);
|
||||
menu = supplied_menu ?? new Gtk.Menu();
|
||||
proxy_menu = supplied_proxy_menu ?? new Gtk.Menu();
|
||||
|
||||
// icon widget
|
||||
icon_box.pack_start(this.icon, true, true, padding);
|
||||
icon_box.pack_end(icon_arrow, true, true, padding);
|
||||
icon_box.no_show_all = true;
|
||||
|
||||
// label widget
|
||||
label_box.pack_start(this.label, true, true, padding);
|
||||
label_box.pack_end(label_arrow, true, true, padding);
|
||||
label_box.no_show_all = true;
|
||||
|
||||
this.icon.visible = true;
|
||||
this.icon_arrow.visible = show_arrow;
|
||||
icon_box.visible = true;
|
||||
|
||||
this.label.visible = true;
|
||||
this.label_arrow.visible = show_arrow;
|
||||
label_box.visible = true;
|
||||
|
||||
notify["show-arrow"].connect(on_refresh_now);
|
||||
}
|
||||
|
||||
~ToggleToolbarDropdown() {
|
||||
detach();
|
||||
}
|
||||
|
||||
public void attach(Gtk.ToggleToolButton owner) {
|
||||
if (this.owner != null) {
|
||||
debug("ToggleToolbarDropdown already attached");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.owner = owner;
|
||||
|
||||
owner.set_icon_widget(icon_box);
|
||||
owner.set_label_widget(label_box);
|
||||
|
||||
menu.attach_to_widget(owner, null);
|
||||
menu.deactivate.connect(on_menu_deactivated);
|
||||
|
||||
add_proxy_menu(owner, owner.label, proxy_menu);
|
||||
|
||||
owner.clicked.connect(on_clicked);
|
||||
owner.notify["label"].connect(on_refresh_now);
|
||||
owner.notify["active"].connect(on_refresh_now);
|
||||
owner.notify["is-important"].connect(on_refresh_now);
|
||||
owner.notify["sensitive"].connect(on_refresh_now);
|
||||
owner.toolbar_reconfigured.connect(on_refresh_now);
|
||||
|
||||
on_refresh_now();
|
||||
}
|
||||
|
||||
public void detach() {
|
||||
if (owner == null)
|
||||
return;
|
||||
|
||||
owner.clicked.disconnect(on_clicked);
|
||||
owner.notify["label"].disconnect(on_refresh_now);
|
||||
owner.notify["active"].disconnect(on_refresh_now);
|
||||
owner.notify["is-important"].disconnect(on_refresh_now);
|
||||
owner.notify["sensitive"].disconnect(on_refresh_now);
|
||||
owner.toolbar_reconfigured.disconnect(on_refresh_now);
|
||||
|
||||
this.owner = null;
|
||||
}
|
||||
|
||||
private void on_menu_deactivated() {
|
||||
if (owner != null)
|
||||
owner.active = false;
|
||||
}
|
||||
|
||||
private void on_clicked() {
|
||||
if (owner != null && owner.active)
|
||||
menu.popup(null, null, menu_popup_relative, 0, 0);
|
||||
}
|
||||
|
||||
private void on_refresh_now() {
|
||||
if (owner == null)
|
||||
return;
|
||||
|
||||
label.set_label(owner.label);
|
||||
|
||||
icon.sensitive = owner.sensitive;
|
||||
icon_arrow.sensitive = owner.sensitive;
|
||||
label.sensitive = owner.sensitive;
|
||||
label_arrow.sensitive = owner.sensitive;
|
||||
|
||||
switch (owner.get_toolbar_style()) {
|
||||
case Gtk.ToolbarStyle.BOTH:
|
||||
icon.visible = true;
|
||||
icon_arrow.visible = show_arrow;
|
||||
label.visible = true;
|
||||
label_arrow.visible = false;
|
||||
break;
|
||||
|
||||
case Gtk.ToolbarStyle.ICONS:
|
||||
icon.visible = true;
|
||||
icon_arrow.visible = show_arrow;
|
||||
label.visible = false;
|
||||
label.visible = false;
|
||||
break;
|
||||
|
||||
case Gtk.ToolbarStyle.TEXT:
|
||||
icon.visible = false;
|
||||
icon_arrow.visible = false;
|
||||
label.visible = true;
|
||||
label_arrow.visible = show_arrow;
|
||||
break;
|
||||
|
||||
case Gtk.ToolbarStyle.BOTH_HORIZ:
|
||||
default:
|
||||
icon.visible = true;
|
||||
icon_arrow.visible = !owner.is_important && show_arrow;
|
||||
label.visible = owner.is_important;
|
||||
label_arrow.visible = owner.is_important && show_arrow;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use this MenuPositionFunc to position a popup menu relative to a widget
|
||||
// with Gtk.Menu.popup().
|
||||
//
|
||||
// You *must* attach the button widget with Gtk.Menu.attach_to_widget() before
|
||||
// this function can be used.
|
||||
public void menu_popup_relative(Gtk.Menu menu, out int x, out int y, out bool push_in) {
|
||||
menu.realize();
|
||||
|
||||
int rx, ry;
|
||||
menu.get_attach_widget().get_window().get_origin(out rx, out ry);
|
||||
|
||||
Gtk.Allocation menu_button_allocation;
|
||||
menu.get_attach_widget().get_allocation(out menu_button_allocation);
|
||||
|
||||
x = rx + menu_button_allocation.x;
|
||||
y = ry + menu_button_allocation.y + menu_button_allocation.height;
|
||||
|
||||
push_in = false;
|
||||
}
|
||||
|
||||
public void add_proxy_menu(Gtk.ToolItem tool_item, string label, Gtk.Menu proxy_menu) {
|
||||
Gtk.MenuItem proxy_menu_item = new Gtk.MenuItem.with_label(label);
|
||||
proxy_menu_item.submenu = proxy_menu;
|
||||
tool_item.create_menu_proxy.connect((sender) => {
|
||||
sender.set_proxy_menu_item("proxy", proxy_menu_item);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
/* Copyright 2011-2012 Yorba Foundation
|
||||
*
|
||||
* This software is licensed under the GNU Lesser General Public License
|
||||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
// Use this MenuPositionFunc to position a popup menu relative to a widget
|
||||
// with Gtk.Menu.popup().
|
||||
//
|
||||
// You *must* attach the button widget with Gtk.Menu.attach_to_widget() before
|
||||
// this function can be used.
|
||||
public void menu_popup_relative(Gtk.Menu menu, out int x, out int y, out bool push_in) {
|
||||
menu.realize();
|
||||
|
||||
int rx, ry;
|
||||
menu.get_attach_widget().get_window().get_origin(out rx, out ry);
|
||||
|
||||
Gtk.Allocation menu_button_allocation;
|
||||
menu.get_attach_widget().get_allocation(out menu_button_allocation);
|
||||
|
||||
x = rx + menu_button_allocation.x;
|
||||
y = ry + menu_button_allocation.y + menu_button_allocation.height;
|
||||
|
||||
push_in = false;
|
||||
}
|
||||
|
||||
// This method must be called AFTER the button is added to the toolbar.
|
||||
public void make_menu_dropdown_button(Gtk.ToggleToolButton toggle_tool_button, Icon? icon, string? label) {
|
||||
Gtk.ToggleButton? toggle_button = toggle_tool_button.get_child() as Gtk.ToggleButton;
|
||||
if (toggle_button == null) {
|
||||
debug("Problem making dropdown button: ToggleToolButton's child is not a ToggleButton");
|
||||
return;
|
||||
}
|
||||
|
||||
Gtk.Widget? child = toggle_button.get_child();
|
||||
if (child != null)
|
||||
toggle_button.remove(child);
|
||||
|
||||
Gtk.Box box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0);
|
||||
box.set_homogeneous(false);
|
||||
|
||||
if (icon != null)
|
||||
box.pack_start(new Gtk.Image.from_gicon(icon, Gtk.IconSize.LARGE_TOOLBAR));
|
||||
|
||||
if (label != null)
|
||||
box.pack_start(new Gtk.Label(label));
|
||||
|
||||
box.pack_end(new Gtk.Image.from_icon_name("menu-down", Gtk.IconSize.LARGE_TOOLBAR));
|
||||
|
||||
toggle_button.add(box);
|
||||
}
|
||||
|
||||
public void add_proxy_menu(Gtk.ToolItem tool_item, string label, Gtk.Menu proxy_menu) {
|
||||
Gtk.MenuItem proxy_menu_item = new Gtk.MenuItem.with_label(label);
|
||||
proxy_menu_item.submenu = proxy_menu;
|
||||
tool_item.create_menu_proxy.connect((sender) => {
|
||||
sender.set_proxy_menu_item("proxy", proxy_menu_item);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
* (version 2.1 or later). See the COPYING file in this distribution.
|
||||
*/
|
||||
|
||||
public class Geary.FolderPath : Object, Hashable, Equalable {
|
||||
public class Geary.FolderPath : Object, Hashable, Equalable, Comparable {
|
||||
public string basename { get; private set; }
|
||||
|
||||
private Gee.List<Geary.FolderPath>? path = null;
|
||||
|
|
@ -116,6 +116,39 @@ public class Geary.FolderPath : Object, Hashable, Equalable {
|
|||
return cs ? str_hash(basename) : str_hash(basename.down());
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparisons for Geary.FolderPath is defined as (a) empty paths are less-than non-empty paths
|
||||
* and (b) each element is compared to the corresponding path element of the other FolderPath
|
||||
* following collation rules for casefolded (case-insensitive) compared, and (c) shorter paths
|
||||
* are less-than longer paths, assuming the path elements are equal up to the shorter path's
|
||||
* length.
|
||||
*/
|
||||
public int compare(Comparable o) {
|
||||
FolderPath? other = o as FolderPath;
|
||||
if (other == null)
|
||||
return -1;
|
||||
|
||||
if (this == other)
|
||||
return 0;
|
||||
|
||||
// walk elements using as_list() as that includes the basename (whereas path does not),
|
||||
// avoids the null problem, and makes comparisons straightforward
|
||||
Gee.List<string> this_list = as_list();
|
||||
Gee.List<string> other_list = other.as_list();
|
||||
|
||||
// if paths exist, do comparison of each parent in order
|
||||
int min = int.min(this_list.size, other_list.size);
|
||||
for (int ctr = 0; ctr < min; ctr++) {
|
||||
int result = this_list[ctr].casefold().collate(other_list[ctr].casefold());
|
||||
if (result != 0)
|
||||
return result;
|
||||
}
|
||||
|
||||
// paths up to the min element count are equal, shortest path is less-than, otherwise
|
||||
// equal paths
|
||||
return this_list.size - other_list.size;
|
||||
}
|
||||
|
||||
public uint to_hash() {
|
||||
if (hash != uint.MAX)
|
||||
return hash;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue