171 lines
6 KiB
Vala
171 lines
6 KiB
Vala
/* Copyright 2016 Software Freedom Conservancy Inc.
|
|
*
|
|
* This software is licensed under the GNU Lesser General Public License
|
|
* (version 2.1 or later). See the COPYING file in this distribution.
|
|
*/
|
|
|
|
/**
|
|
* Interface for creating a Nautilus-style "pill" toolbar. Use only as directed.
|
|
*
|
|
* Subclasses should inherit from some Gtk.Container and provide pack_start() and
|
|
* pack_end() methods with the correct signature. They also need to have action_group
|
|
* and size properties and call initialize() in their constructors.
|
|
*/
|
|
public interface PillBar : Gtk.Container {
|
|
protected abstract Gtk.ActionGroup action_group { get; set; }
|
|
protected abstract Gtk.SizeGroup size { get; set; }
|
|
|
|
public abstract void pack_start(Gtk.Widget widget);
|
|
public abstract void pack_end(Gtk.Widget widget);
|
|
|
|
protected virtual void initialize(Gtk.ActionGroup toolbar_action_group) {
|
|
action_group = toolbar_action_group;
|
|
size = new Gtk.SizeGroup(Gtk.SizeGroupMode.VERTICAL);
|
|
}
|
|
|
|
public virtual void add_start(Gtk.Widget widget) {
|
|
pack_start(widget);
|
|
size.add_widget(widget);
|
|
}
|
|
|
|
public virtual void add_end(Gtk.Widget widget) {
|
|
pack_end(widget);
|
|
size.add_widget(widget);
|
|
}
|
|
|
|
public virtual void setup_button(Gtk.Button b, string? icon_name, string action_name,
|
|
bool show_label = false) {
|
|
b.related_action = action_group.get_action(action_name);
|
|
b.tooltip_text = b.related_action.tooltip;
|
|
b.related_action.notify["tooltip"].connect(() => { b.tooltip_text = b.related_action.tooltip; });
|
|
|
|
// Load icon by name with this fallback order: specified icon name, the action's icon name,
|
|
// the action's stock ID ... although stock IDs are being deprecated, that's how we specify
|
|
// the icon in the GtkActionEntry (also being deprecated) and GTK+ 3.14 doesn't support that
|
|
// any longer
|
|
string? icon_to_load = icon_name ?? b.related_action.icon_name;
|
|
if (icon_to_load == null)
|
|
icon_to_load = b.related_action.stock_id;
|
|
|
|
// set pixel size to force GTK+ to load our images from our installed directory, not the theme
|
|
// directory
|
|
if (icon_to_load != null) {
|
|
Gtk.Image image = new Gtk.Image.from_icon_name(icon_to_load, Gtk.IconSize.MENU);
|
|
image.set_pixel_size(16);
|
|
b.image = image;
|
|
}
|
|
|
|
// Unity buttons are a bit tight
|
|
if (GearyApplication.instance.is_running_unity && b.image != null)
|
|
b.image.margin = b.image.margin + 4;
|
|
|
|
b.always_show_image = true;
|
|
|
|
if (!show_label)
|
|
b.label = null;
|
|
}
|
|
|
|
/**
|
|
* Given an icon and action, creates a button that triggers the action.
|
|
*/
|
|
public virtual Gtk.Button create_toolbar_button(string? icon_name, string action_name, bool show_label = false) {
|
|
Gtk.Button b = new Gtk.Button();
|
|
setup_button(b, icon_name, action_name, show_label);
|
|
|
|
return b;
|
|
}
|
|
|
|
/**
|
|
* Given an icon and action, creates a toggle button that triggers the action.
|
|
*/
|
|
public virtual Gtk.Button create_toggle_button(string? icon_name, string action_name) {
|
|
Gtk.ToggleButton b = new Gtk.ToggleButton();
|
|
setup_button(b, icon_name, action_name);
|
|
|
|
return b;
|
|
}
|
|
|
|
/**
|
|
* Given an icon, menu, and action, creates a button that triggers the menu and the action.
|
|
*/
|
|
public virtual Gtk.MenuButton create_menu_button(string? icon_name, Gtk.Menu? menu, string action_name) {
|
|
Gtk.MenuButton b = new Gtk.MenuButton();
|
|
setup_button(b, icon_name, action_name);
|
|
b.popup = menu;
|
|
|
|
return b;
|
|
}
|
|
|
|
/**
|
|
* Given a list of buttons, creates a "pill-style" tool item that can be appended to this
|
|
* toolbar. Optionally adds spacers "before" and "after" the buttons (those terms depending
|
|
* on Gtk.TextDirection)
|
|
*/
|
|
public virtual Gtk.Box create_pill_buttons(Gee.Collection<Gtk.Button> buttons,
|
|
bool before_spacer = true, bool after_spacer = false) {
|
|
Gtk.Box box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0);
|
|
box.valign = Gtk.Align.CENTER;
|
|
box.halign = Gtk.Align.CENTER;
|
|
|
|
if (buttons.size > 1) {
|
|
box.get_style_context().add_class(Gtk.STYLE_CLASS_RAISED);
|
|
box.get_style_context().add_class(Gtk.STYLE_CLASS_LINKED);
|
|
}
|
|
|
|
foreach(Gtk.Button button in buttons)
|
|
box.add(button);
|
|
|
|
return box;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A pill-style header bar.
|
|
*/
|
|
public class PillHeaderbar : Gtk.HeaderBar, PillBar {
|
|
protected Gtk.ActionGroup action_group { get; set; }
|
|
protected Gtk.SizeGroup size { get; set; }
|
|
|
|
public PillHeaderbar(Gtk.ActionGroup toolbar_action_group) {
|
|
initialize(toolbar_action_group);
|
|
}
|
|
|
|
public bool close_button_at_end() {
|
|
string layout;
|
|
bool at_end = false;
|
|
#if GTK_3_12
|
|
layout = Gtk.Settings.get_default().gtk_decoration_layout;
|
|
#else
|
|
get_toplevel().style_get("decoration-button-layout", out layout);
|
|
#endif
|
|
// Based on logic of close_button_at_end in gtkheaderbar.c: Close button appears
|
|
// at end iff "close" follows a colon in the layout string.
|
|
if (layout != null) {
|
|
int colon_ind = layout.index_of(":");
|
|
at_end = (colon_ind >= 0 && layout.index_of("close", colon_ind) >= 0);
|
|
}
|
|
return at_end;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A pill-style toolbar.
|
|
*/
|
|
public class PillToolbar : Gtk.Box, PillBar {
|
|
protected Gtk.ActionGroup action_group { get; set; }
|
|
protected Gtk.SizeGroup size { get; set; }
|
|
|
|
public PillToolbar(Gtk.ActionGroup toolbar_action_group) {
|
|
Object(orientation: Gtk.Orientation.HORIZONTAL, spacing: 6);
|
|
initialize(toolbar_action_group);
|
|
}
|
|
|
|
public new void pack_start(Gtk.Widget widget) {
|
|
base.pack_start(widget, false, false, 0);
|
|
}
|
|
|
|
public new void pack_end(Gtk.Widget widget) {
|
|
base.pack_end(widget, false, false, 0);
|
|
}
|
|
}
|
|
|