elementaryart team mailing list archive
-
elementaryart team
-
Mailing list archive
-
Message #01896
[Merge] lp:~victored/granite/tool-button-with-menu-fixes into lp:granite
Victor Eduardo has proposed merging lp:~victored/granite/tool-button-with-menu-fixes into lp:granite.
Requested reviews:
xapantu (xapantu)
For more details, see:
https://code.launchpad.net/~victored/granite/tool-button-with-menu-fixes/+merge/90152
--
https://code.launchpad.net/~victored/granite/tool-button-with-menu-fixes/+merge/90152
Your team elementaryart (old) is subscribed to branch lp:granite.
=== modified file 'lib/Widgets/ToolButtonWithMenu.vala'
--- lib/Widgets/ToolButtonWithMenu.vala 2012-01-15 21:04:11 +0000
+++ lib/Widgets/ToolButtonWithMenu.vala 2012-01-25 16:53:27 +0000
@@ -22,11 +22,12 @@
*
*/
-/*
- * ToolButtonWithMenu
+/*
+ * ToolButtonWithMenu
* - support long click / right click with depressed button states
* - activate a GtkAction if any or popup a menu.
- * (used in history navigation buttons next/prev, appmenu)
+ * (used in history navigation buttons next/prev, appmenu)
+ *
*/
using Gdk;
@@ -34,124 +35,120 @@
namespace Granite.Widgets {
- public class ToolButtonWithMenu : ToggleToolButton
- {
+ public class ToolButtonWithMenu : Gtk.ToggleToolButton {
+
+ public signal void right_click (Gdk.EventButton ev);
+
+ /**
+ * MenuPosition:
+ * CENTER: Center-align the menu relative to the button's position.
+ * LEFT: Left-align the menu relative to the button's position.
+ * RIGHT: Right-align the menu relative to the button's position.
+ * INSIDE_WINDOW: Keep the menu inside the GtkWindow. Center-align when possible.
+ **/
+ public enum MenuPosition {
+ CENTER,
+ LEFT,
+ RIGHT,
+ INSIDE_WINDOW
+ }
+
public Gtk.Action? myaction;
-
- /* delegate function used to populate menu */
- public delegate Gtk.Menu MenuFetcher();
-
- private int long_press_time = Gtk.Settings.get_default().gtk_double_click_time * 2;
- private Button button;
public ulong toggled_sig_id;
+ public MenuPosition menu_position;
+
+ /* Delegate function used to populate menu */
+ public delegate Gtk.Menu MenuFetcher ();
+
+ public MenuFetcher fetcher {
+ set {
+ _fetcher = value;
+ has_fetcher = true;
+ }
+ get {
+ return _fetcher;
+ }
+ }
+
+ public Gtk.Menu menu {
+ get {
+ return _menu;
+ }
+ set {
+ if (has_fetcher) {
+ warning ("Don't set the menu property on a ToolMenuButton when there is already a menu fetcher");
+ }
+ else {
+ _menu = value;
+ update_menu_properties ();
+ }
+ }
+ }
+
+ private int LONG_PRESS_TIME = Gtk.Settings.get_default ().gtk_double_click_time * 2;
private int timeout = -1;
private uint last_click_time = -1;
-
- private PositionType _menu_orientation;
- public PositionType menu_orientation{
- set{
- var orientation = value;
- switch(orientation){
- case(PositionType.TOP):
- case(PositionType.BOTTOM):
- orientation = PositionType.LEFT;
- break;
- }
- _menu_orientation = orientation;
- }
- get{
- return _menu_orientation;
- }
- }
-
- public signal void right_click (Gdk.EventButton ev);
-
private bool has_fetcher = false;
+
private unowned MenuFetcher _fetcher;
- public MenuFetcher fetcher{
- set{
- _fetcher = value;
- has_fetcher = true;
- }
- get{
- return _fetcher;
- }
- }
-
private Gtk.Menu _menu;
- public Gtk.Menu menu {
- get {
- return _menu;
- }
- set {
- if(has_fetcher)
- warning ("Don't set the menu property on a ToolMenuButton when there is allready a menu fetcher");
- else{
- _menu = value;
- update_menu_properties();
- }
- }
- }
-
- public ToolButtonWithMenu.from_action (Gtk.Action action)
- {
- this.from_stock(action.stock_id, IconSize.MENU, action.label, new Gtk.Menu());
-
+ private Gtk.Button button;
+
+ public ToolButtonWithMenu.from_action (Gtk.Action action) {
+ this.from_stock (action.stock_id, IconSize.MENU, action.label, new Gtk.Menu ());
use_action_appearance = true;
-
- set_related_action(action);
-
- action.connect_proxy(this);
+ set_related_action (action);
+ action.connect_proxy (this);
myaction = action;
}
- public ToolButtonWithMenu.from_stock (string stock_image, IconSize size, string label, Gtk.Menu menu)
- {
- Image image = new Image.from_stock(stock_image, size);
-
- this(image, label, menu);
+ public ToolButtonWithMenu.from_stock (string stock_image, IconSize size, string label, Gtk.Menu menu) {
+ Image image = new Image.from_stock (stock_image, size);
+ this (image, label, menu);
}
- private void update_menu_properties()
- {
+ private void update_menu_properties () {
menu.attach_to_widget (this, null);
- menu.deactivate.connect(() => {
+ menu.deactivate.connect ( () => {
deactivate_menu ();
});
- menu.deactivate.connect(popdown_menu);
+ menu.deactivate.connect (popdown_menu);
}
- public ToolButtonWithMenu (Image image, string label, Gtk.Menu _menu, PositionType _menu_orientation = Gtk.PositionType.LEFT)
+ public ToolButtonWithMenu (Image image, string label, Gtk.Menu _menu,
+ MenuPosition menu_position = MenuPosition.CENTER)
{
- this.menu_orientation = _menu_orientation;
+ this.menu_position = menu_position;
icon_widget = image;
- label_widget = new Label (label);
- ((Label) label_widget).use_underline = true;
+ label_widget = new Gtk.Label (label);
+ (label_widget as Gtk.Label).use_underline = true;
can_focus = true;
set_tooltip_text (label);
menu = _menu;
- mnemonic_activate.connect(on_mnemonic_activate);
+ mnemonic_activate.connect (on_mnemonic_activate);
- button = (Button) get_child();
+ button = get_child () as Gtk.Button;
button.events |= EventMask.BUTTON_PRESS_MASK
| EventMask.BUTTON_RELEASE_MASK;
- button.button_press_event.connect(on_button_press_event);
- button.button_release_event.connect(on_button_release_event);
+ button.button_press_event.connect (on_button_press_event);
+ button.button_release_event.connect (on_button_release_event);
}
- public override void show_all(){
- menu.show_all();
- base.show_all();
+ public override void show_all () {
+ menu.show_all ();
+ base.show_all ();
}
private void deactivate_menu () {
if (myaction != null)
myaction.block_activate ();
+
active = false;
+
if (myaction != null)
myaction.unblock_activate ();
}
@@ -159,56 +156,59 @@
private void popup_menu_and_depress_button (Gdk.EventButton ev) {
if (myaction != null)
myaction.block_activate ();
+
active = true;
+
if (myaction != null)
myaction.unblock_activate ();
- popup_menu(ev);
+
+ popup_menu (ev);
}
- private bool on_button_release_event (Gdk.EventButton ev)
- {
- if (ev.time - last_click_time < long_press_time) {
+ private bool on_button_release_event (Gdk.EventButton ev) {
+ if (ev.time - last_click_time < LONG_PRESS_TIME) {
if (myaction != null) {
myaction.activate ();
} else {
active = true;
- popup_menu(ev);
+ popup_menu (ev);
}
}
- if(timeout != -1){
- Source.remove((uint) timeout);
+ if (timeout != -1) {
+ Source.remove ((uint) timeout);
timeout = -1;
}
return true;
}
- private bool on_button_press_event (Gdk.EventButton ev)
- {
- if(timeout == -1 && ev.button == 1) {
+ private bool on_button_press_event (Gdk.EventButton ev) {
+ // If the button is kept pressed, don't make the user wait when there's no action
+ int max_press_time = (myaction != null)? LONG_PRESS_TIME : 0;
+
+ if (timeout == -1 && ev.button == 1) {
last_click_time = ev.time;
- timeout = (int) Timeout.add(long_press_time, () => {
- /* long click */
+ timeout = (int) Timeout.add(max_press_time, () => {
+ // long click
timeout = -1;
popup_menu_and_depress_button (ev);
return false;
});
}
- if(ev.button == 3){
- /* right_click */
- right_click(ev);
+ if (ev.button == 3) {
+ // right_click
+ right_click (ev);
+
if (myaction != null)
- popup_menu_and_depress_button (ev);
+ popup_menu_and_depress_button (ev);
}
return true;
}
- private bool on_mnemonic_activate (bool group_cycling)
- {
- //stdout.printf ("on mnemonic activate\n");
+ private bool on_mnemonic_activate (bool group_cycling) {
// ToggleButton always grabs focus away from the editor,
// so reimplement Widget's version, which only grabs the
// focus if we are group cycling.
@@ -221,46 +221,43 @@
return true;
}
- protected new void popup_menu(Gdk.EventButton? ev = null)
- {
- if(has_fetcher) fetch_menu();
-
- /* FIXME select_first works ok but some gtk_return_fail make some nasty verbose lines in the terminal, origin gtk_device_grab_add gtk+-3 */
+ protected new void popup_menu (Gdk.EventButton? ev = null) {
+ if (has_fetcher)
+ fetch_menu ();
try {
menu.popup (null,
null,
get_menu_position,
(ev == null) ? 0 : ev.button,
- (ev == null) ? get_current_event_time() : ev.time);
+ (ev == null) ? get_current_event_time () : ev.time);
} finally {
// Highlight the parent
if (menu.attach_widget != null)
- menu.attach_widget.set_state(StateType.SELECTED);
- menu.select_first (true);
+ menu.attach_widget.set_state_flags (StateFlags.SELECTED, true);
+
+ menu.select_first (false);
}
}
- protected void popdown_menu ()
- {
+ protected void popdown_menu () {
menu.popdown ();
// Unhighlight the parent
if (menu.attach_widget != null)
- menu.attach_widget.set_state(Gtk.StateType.NORMAL);
- }
-
- private void fetch_menu(){
- _menu = fetcher();
- update_menu_properties();
- }
-
- private void get_menu_position (Gtk.Menu menu, out int x, out int y, out bool push_in)
- {
+ menu.attach_widget.set_state_flags (StateFlags.NORMAL, true);
+ }
+
+ private void fetch_menu () {
+ _menu = fetcher ();
+ update_menu_properties ();
+ }
+
+ private void get_menu_position (Gtk.Menu menu, out int x, out int y, out bool push_in) {
Allocation menu_allocation;
menu.get_allocation (out menu_allocation);
if (menu.attach_widget == null ||
- menu.attach_widget.get_window() == null) {
+ menu.attach_widget.get_window () == null) {
// Prevent null exception in weird cases
x = 0;
y = 0;
@@ -268,19 +265,60 @@
return;
}
- menu.attach_widget.get_window().get_origin (out x, out y);
+ menu.attach_widget.get_window ().get_origin (out x, out y);
Allocation allocation;
- menu.attach_widget.get_allocation(out allocation);
-
- x += allocation.x;
- x -= menu_allocation.width/2;
- x += allocation.width/2;
+ menu.attach_widget.get_allocation (out allocation);
+
+ if (menu_position == MenuPosition.RIGHT) {
+ x += allocation.x;
+ x -= menu_allocation.width;
+ x += allocation.width;
+ }
+ else if (menu_position != MenuPosition.LEFT) {
+ /* Centered menu */
+ x += allocation.x;
+ x -= menu_allocation.width / 2;
+ x += allocation.width / 2;
+ }
+
+ int width, height;
+ menu.get_size_request (out width, out height);
+
+ if (menu_position == MenuPosition.INSIDE_WINDOW) {
+ /* Get window geometry */
+ Gtk.Widget? parent_widget = get_parent ();
+ Gtk.Widget? next_parent = parent_widget.get_parent ();
+
+ while (true) {
+ if (parent_widget != null && next_parent != null) {
+ parent_widget = parent_widget.get_parent();
+ next_parent = parent_widget.get_parent();
+ }
+
+ if (parent_widget == null || next_parent == null)
+ break;
+ }
+
+ Allocation window_allocation;
+ parent_widget.get_allocation (out window_allocation);
+
+ parent_widget.get_window ().get_origin (out x, out y);
+ int parent_window_x0 = x;
+ int parent_window_xf = parent_window_x0 + window_allocation.width;
+
+ // Now check if the menu is outside the window and un-center it
+ // if that's the case
+
+ if (x + menu_allocation.width > parent_window_xf)
+ x = parent_window_xf - menu_allocation.width; // Move to left
+
+ if (x < parent_window_x0)
+ x = parent_window_x0; // Move to right
+ }
+
y += allocation.y;
- int width, height;
- menu.get_size_request(out width, out height);
-
- if (y + height >= menu.attach_widget.get_screen().get_height())
+ if (y + height >= menu.attach_widget.get_screen ().get_height ())
y -= height;
else
y += allocation.height;
Follow ups