2009-08-01 16:15:01 +02:00
|
|
|
# Copyright (C) 2007, Eduardo Silva <edsiper@gmail.com>
|
|
|
|
# Copyright (C) 2008, One Laptop Per Child
|
|
|
|
# Copyright (C) 2009, Tomeu Vizoso
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
# Copyright (C) 2011, Benjamin Berg <benjamin@sipsolutions.net>
|
|
|
|
# Copyright (C) 2011, Marco Pesenti Gritti <marco@marcopg.org>
|
2009-08-01 16:15:01 +02:00
|
|
|
#
|
|
|
|
# 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, write to the
|
|
|
|
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
# Boston, MA 02111-1307, USA.
|
|
|
|
|
|
|
|
"""
|
|
|
|
STABLE.
|
|
|
|
"""
|
|
|
|
|
|
|
|
import logging
|
2012-11-15 18:09:00 +01:00
|
|
|
import math
|
2009-08-01 16:15:01 +02:00
|
|
|
|
2011-11-15 19:29:07 +01:00
|
|
|
from gi.repository import Gdk
|
|
|
|
from gi.repository import Gtk
|
|
|
|
from gi.repository import GObject
|
2013-05-06 18:18:10 +02:00
|
|
|
from gi.repository import GLib
|
2009-08-01 16:15:01 +02:00
|
|
|
|
2012-10-25 11:42:00 +02:00
|
|
|
from gi.repository import SugarGestures
|
2011-10-29 10:44:18 +02:00
|
|
|
from sugar3.graphics import palettegroup
|
|
|
|
from sugar3.graphics import animator
|
|
|
|
from sugar3.graphics import style
|
2014-11-28 12:45:22 +01:00
|
|
|
from sugar3.graphics.icon import CellRendererIcon
|
2009-08-01 16:15:01 +02:00
|
|
|
|
2009-08-25 21:12:40 +02:00
|
|
|
|
2009-08-01 16:15:01 +02:00
|
|
|
def _calculate_gap(a, b):
|
2009-08-25 21:12:40 +02:00
|
|
|
"""Helper function to find the gap position and size of widget a"""
|
2009-08-01 16:15:01 +02:00
|
|
|
# Test for each side if the palette and invoker are
|
|
|
|
# adjacent to each other.
|
|
|
|
gap = True
|
|
|
|
|
|
|
|
if a.y + a.height == b.y:
|
2011-11-15 19:29:07 +01:00
|
|
|
gap_side = Gtk.PositionType.BOTTOM
|
2009-08-01 16:15:01 +02:00
|
|
|
elif a.x + a.width == b.x:
|
2011-11-15 19:29:07 +01:00
|
|
|
gap_side = Gtk.PositionType.RIGHT
|
2009-08-01 16:15:01 +02:00
|
|
|
elif a.x == b.x + b.width:
|
2011-11-15 19:29:07 +01:00
|
|
|
gap_side = Gtk.PositionType.LEFT
|
2009-08-01 16:15:01 +02:00
|
|
|
elif a.y == b.y + b.height:
|
2011-11-15 19:29:07 +01:00
|
|
|
gap_side = Gtk.PositionType.TOP
|
2009-08-01 16:15:01 +02:00
|
|
|
else:
|
|
|
|
gap = False
|
2009-08-25 19:55:48 +02:00
|
|
|
|
2009-08-01 16:15:01 +02:00
|
|
|
if gap:
|
2013-05-18 04:27:04 +02:00
|
|
|
if gap_side == Gtk.PositionType.BOTTOM or \
|
|
|
|
gap_side == Gtk.PositionType.TOP:
|
2009-08-01 16:15:01 +02:00
|
|
|
gap_start = min(a.width, max(0, b.x - a.x))
|
|
|
|
gap_size = max(0, min(a.width,
|
|
|
|
(b.x + b.width) - a.x) - gap_start)
|
2013-05-18 04:27:04 +02:00
|
|
|
elif gap_side == Gtk.PositionType.RIGHT or \
|
|
|
|
gap_side == Gtk.PositionType.LEFT:
|
2009-08-01 16:15:01 +02:00
|
|
|
gap_start = min(a.height, max(0, b.y - a.y))
|
|
|
|
gap_size = max(0, min(a.height,
|
|
|
|
(b.y + b.height) - a.y) - gap_start)
|
|
|
|
|
|
|
|
if gap and gap_size > 0:
|
|
|
|
return (gap_side, gap_start, gap_size)
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
2009-08-25 21:12:40 +02:00
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
class _PaletteMenuWidget(Gtk.Menu):
|
|
|
|
|
|
|
|
__gtype_name__ = "SugarPaletteMenuWidget"
|
|
|
|
|
|
|
|
__gsignals__ = {
|
|
|
|
'enter-notify': (GObject.SignalFlags.RUN_FIRST, None, ([])),
|
|
|
|
'leave-notify': (GObject.SignalFlags.RUN_FIRST, None, ([])),
|
|
|
|
}
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
Gtk.Menu.__init__(self)
|
|
|
|
|
|
|
|
accel_group = Gtk.AccelGroup()
|
2012-06-06 12:57:00 +02:00
|
|
|
self.sugar_accel_group = accel_group
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
self.get_toplevel().add_accel_group(accel_group)
|
|
|
|
|
|
|
|
self._popup_position = (0, 0)
|
|
|
|
self._entered = False
|
|
|
|
self._mouse_in_palette = False
|
|
|
|
self._mouse_in_invoker = False
|
|
|
|
self._up = False
|
|
|
|
self._invoker = None
|
|
|
|
self._menus = []
|
|
|
|
|
|
|
|
def set_accept_focus(self, focus):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def get_origin(self):
|
|
|
|
res_, x, y = self.get_toplevel().get_window().get_origin()
|
|
|
|
return x, y
|
|
|
|
|
|
|
|
def move(self, x, y):
|
|
|
|
self._popup_position = (x, y)
|
|
|
|
|
|
|
|
def set_transient_for(self, window):
|
|
|
|
pass
|
|
|
|
|
2012-03-15 17:56:16 +01:00
|
|
|
def set_invoker(self, invoker):
|
|
|
|
pass
|
|
|
|
|
2015-05-17 10:22:19 +02:00
|
|
|
def _position(self, widget, *data):
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
return self._popup_position[0], self._popup_position[1], False
|
|
|
|
|
|
|
|
def popup(self, invoker):
|
|
|
|
if self._up:
|
|
|
|
return
|
|
|
|
|
|
|
|
# We need to track certain mouse events in order to close the palette
|
|
|
|
# when the mouse leaves the palette and the invoker widget, but
|
|
|
|
# GtkMenu makes our lives hard here.
|
|
|
|
#
|
|
|
|
# GtkMenu takes a grab on the root window, meaning that normal
|
|
|
|
# enter/leave events are not sent to the relevant widgets.
|
|
|
|
# However, connecting enter-notify and leave-notify events in this
|
|
|
|
# GtkMenu subclass mean that we get to see the events being grabbed.
|
|
|
|
# With certain filtering in place (see _enter_notify_cb and
|
|
|
|
# _leave_notify_cb) we are able to accurately determine when the
|
|
|
|
# mouse leaves/enters the palette menu. Some spurious events are
|
|
|
|
# generated but the important thing is that the last event generated
|
|
|
|
# in response to a user action is always reliable (i.e. we will
|
|
|
|
# always get a leave event last if the user left the menu,
|
|
|
|
# even if we get some strange enter events leading up to it).
|
|
|
|
#
|
|
|
|
# This is complicated with submenus; in this case the submenu takes
|
|
|
|
# the grab, so we must also listen for events on any submenus of
|
|
|
|
# the palette and apply the same considerations.
|
|
|
|
#
|
|
|
|
# The remaining challenge is tracking when the mouse enters or leaves
|
|
|
|
# the invoker area. While the appropriate GtkMenu grab is active,
|
|
|
|
# we do get informed of such events, however these events will only
|
|
|
|
# arrive if the user has entered the menu. If the user hovers over
|
|
|
|
# the invoker and then leaves the invoker without entering the palette,
|
|
|
|
# we get no enter/leave event.
|
|
|
|
# We work around this by tracking mouse motion events. When the mouse
|
|
|
|
# moves, we compare the mouse coordinates to the region occupied by the
|
|
|
|
# invoker, and this lets us track enter/leave for the invoker widget.
|
|
|
|
|
|
|
|
self._invoker = invoker
|
|
|
|
self._find_all_menus(self)
|
2013-01-17 13:29:51 +01:00
|
|
|
self.realize()
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
for menu in self._menus:
|
|
|
|
if self._invoker:
|
|
|
|
menu.connect('motion-notify-event', self._motion_notify_cb)
|
|
|
|
menu.connect('enter-notify-event', self._enter_notify_cb)
|
|
|
|
menu.connect('leave-notify-event', self._leave_notify_cb)
|
2012-11-01 19:05:54 +01:00
|
|
|
menu.connect('button-release-event', self._button_release_event_cb)
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
self._entered = False
|
|
|
|
self._mouse_in_palette = False
|
|
|
|
self._mouse_in_invoker = False
|
|
|
|
Gtk.Menu.popup(self, None, None, self._position, None, 0, 0)
|
|
|
|
self._up = True
|
|
|
|
|
|
|
|
def popdown(self):
|
|
|
|
if not self._up:
|
|
|
|
return
|
|
|
|
Gtk.Menu.popdown(self)
|
|
|
|
|
|
|
|
for menu in self._menus:
|
|
|
|
menu.disconnect_by_func(self._motion_notify_cb)
|
|
|
|
menu.disconnect_by_func(self._enter_notify_cb)
|
|
|
|
menu.disconnect_by_func(self._leave_notify_cb)
|
|
|
|
|
|
|
|
self._up = False
|
|
|
|
self._menus = []
|
|
|
|
self._invoker = None
|
|
|
|
|
|
|
|
def _find_all_menus(self, menu):
|
|
|
|
"""
|
|
|
|
Recursively find all submenus of menu, adding them to self._menus.
|
|
|
|
"""
|
|
|
|
self._menus.append(menu)
|
|
|
|
for child in menu.get_children():
|
|
|
|
if not isinstance(child, Gtk.MenuItem):
|
|
|
|
continue
|
|
|
|
submenu = child.get_submenu()
|
|
|
|
if submenu and isinstance(submenu, Gtk.Menu):
|
|
|
|
self._find_all_menus(submenu)
|
|
|
|
|
|
|
|
def _enter_notify_cb(self, widget, event):
|
|
|
|
if event.mode in (Gdk.CrossingMode.GRAB, Gdk.CrossingMode.GTK_GRAB):
|
|
|
|
return False
|
2012-11-01 19:05:54 +01:00
|
|
|
if event.get_source_device().get_source() == \
|
|
|
|
Gdk.InputSource.TOUCHSCREEN:
|
|
|
|
return False
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
if Gtk.get_event_widget(event) not in self._menus:
|
|
|
|
return False
|
|
|
|
|
|
|
|
self._mouse_in_palette = True
|
|
|
|
self._reevaluate_state()
|
|
|
|
return False
|
|
|
|
|
|
|
|
def _leave_notify_cb(self, widget, event):
|
|
|
|
if event.mode in (Gdk.CrossingMode.GRAB, Gdk.CrossingMode.GTK_GRAB):
|
|
|
|
return False
|
2012-11-01 19:05:54 +01:00
|
|
|
if event.get_source_device().get_source() == \
|
|
|
|
Gdk.InputSource.TOUCHSCREEN:
|
|
|
|
return False
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
if Gtk.get_event_widget(event) not in self._menus:
|
|
|
|
return False
|
|
|
|
|
|
|
|
self._mouse_in_palette = False
|
|
|
|
self._reevaluate_state()
|
|
|
|
return False
|
|
|
|
|
|
|
|
def _motion_notify_cb(self, widget, event):
|
2012-11-01 19:05:54 +01:00
|
|
|
if event.get_source_device().get_source() == \
|
|
|
|
Gdk.InputSource.TOUCHSCREEN:
|
|
|
|
return False
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
x = event.x_root
|
|
|
|
y = event.y_root
|
2012-10-30 09:30:31 +01:00
|
|
|
|
2014-11-28 12:45:22 +01:00
|
|
|
rect = self._invoker.get_rect()
|
|
|
|
in_invoker = x >= rect.x and x < (rect.x + rect.width) \
|
|
|
|
and y >= rect.y and y < (rect.y + rect.height)
|
2012-10-30 09:30:31 +01:00
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
if in_invoker != self._mouse_in_invoker:
|
|
|
|
self._mouse_in_invoker = in_invoker
|
|
|
|
self._reevaluate_state()
|
|
|
|
|
2012-11-01 19:05:54 +01:00
|
|
|
def _button_release_event_cb(self, widget, event):
|
|
|
|
x = event.x_root
|
|
|
|
y = event.y_root
|
|
|
|
|
2014-11-28 12:45:22 +01:00
|
|
|
rect = self._invoker.get_rect()
|
|
|
|
in_invoker = x >= rect.x and x < (rect.x + rect.width) \
|
|
|
|
and y >= rect.y and y < (rect.y + rect.height)
|
2012-11-01 19:05:54 +01:00
|
|
|
|
|
|
|
if in_invoker:
|
|
|
|
return True
|
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
def _reevaluate_state(self):
|
|
|
|
if self._entered:
|
|
|
|
# If we previously advised that the mouse was inside, but now the
|
|
|
|
# mouse is outside both the invoker and the palette, notify that
|
|
|
|
# the mouse has left.
|
|
|
|
if not self._mouse_in_palette and not self._mouse_in_invoker:
|
|
|
|
self._entered = False
|
|
|
|
self.emit('leave-notify')
|
|
|
|
else:
|
|
|
|
# If we previously advised that the mouse had left, but now the
|
|
|
|
# mouse is inside either the palette or the invoker, notify that
|
|
|
|
# the mouse has entered.
|
|
|
|
if self._mouse_in_palette or self._mouse_in_invoker:
|
|
|
|
self._entered = True
|
|
|
|
self.emit('enter-notify')
|
|
|
|
|
|
|
|
|
|
|
|
class _PaletteWindowWidget(Gtk.Window):
|
|
|
|
|
|
|
|
__gtype_name__ = 'SugarPaletteWindowWidget'
|
|
|
|
|
|
|
|
__gsignals__ = {
|
|
|
|
'enter-notify': (GObject.SignalFlags.RUN_FIRST, None, ([])),
|
|
|
|
'leave-notify': (GObject.SignalFlags.RUN_FIRST, None, ([])),
|
|
|
|
}
|
|
|
|
|
2012-04-18 22:29:15 +02:00
|
|
|
def __init__(self, palette=None):
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
Gtk.Window.__init__(self)
|
|
|
|
|
2012-04-18 22:29:15 +02:00
|
|
|
self._palette = palette
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
self.set_decorated(False)
|
|
|
|
self.set_resizable(False)
|
|
|
|
self.set_position(Gtk.WindowPosition.NONE)
|
|
|
|
|
2012-12-14 18:51:06 +01:00
|
|
|
context = self.get_style_context()
|
|
|
|
# Just assume all borders are the same
|
|
|
|
border = context.get_border(Gtk.StateFlags.ACTIVE).right
|
|
|
|
self.set_border_width(border)
|
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
accel_group = Gtk.AccelGroup()
|
2012-06-06 12:57:00 +02:00
|
|
|
self.sugar_accel_group = accel_group
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
self.add_accel_group(accel_group)
|
|
|
|
|
|
|
|
self._old_alloc = None
|
2012-03-15 17:56:16 +01:00
|
|
|
self._invoker = None
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
self._should_accept_focus = True
|
|
|
|
|
|
|
|
def set_accept_focus(self, focus):
|
|
|
|
self._should_accept_focus = focus
|
2013-05-18 04:27:04 +02:00
|
|
|
if self.get_window() is not None:
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
self.get_window().set_accept_focus(focus)
|
|
|
|
|
|
|
|
def get_origin(self):
|
|
|
|
res_, x, y = self.get_window().get_origin()
|
|
|
|
return x, y
|
|
|
|
|
|
|
|
def do_realize(self):
|
|
|
|
Gtk.Window.do_realize(self)
|
|
|
|
|
|
|
|
self.get_window().set_accept_focus(self._should_accept_focus)
|
|
|
|
self.set_type_hint(Gdk.WindowTypeHint.DIALOG)
|
|
|
|
|
2012-03-15 17:56:16 +01:00
|
|
|
def do_get_preferred_width(self):
|
2012-04-18 22:29:15 +02:00
|
|
|
minimum, natural = Gtk.Window.do_get_preferred_width(self)
|
|
|
|
label_width = 0
|
|
|
|
if self._palette is not None:
|
|
|
|
label_width = self._palette.get_label_width()
|
|
|
|
size = max(natural, label_width + 2 * self.get_border_width(),
|
Set correct padding and size for the palette, window implementation - SL #4144
A new API is provided: PaletteMenuBox is a container to be used in
Palette.set_content(). This is to hide the implementation details and
set the corresponding paddings and sizes.
Usage:
box = PaletteMenuBox()
palette.set_content(box)
Then we can append items to it, like:
item = PaletteMenuItem(text_label, icon, xo_color=xo_color)
box.append_child(item)
separator = PaletteMenuItemSeparator()
box.append_child(item)
We can also append any widget, and the box will handle the paddings:
box.append_child(widget)
style.DEFAULT_PADDING for horizontal and vertical padding is the
default. But can be overriden:
box.append_child(widget, horizontal_padding=0, vertical_padding=0)
Details:
- move palettemenuitem.py to palettemenu.py
- Width of palette: make it a minimun size of 3 Sugar grid cells.
- Padding of content, secondary box: we need top and bottom padding,
which can be set when packing the items container inside the
secondary box.
- Padding of menu items: needs to be just for left and right, so move
the padding to a new horizontal box.
- Padding of separators: unlike GtkSeparatorMenuItem, GtkSeparator
doesn't support padding. But we can wrap it in a GtkEventBox and
force the height of the widget there.
Signed-off-by: Manuel Quiñones <manuq@laptop.org>
Acked-by: Simon Schampijer <simon@laptop.org>
2012-11-01 21:45:37 +01:00
|
|
|
style.GRID_CELL_SIZE * 3)
|
2012-03-15 17:56:16 +01:00
|
|
|
return size, size
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
|
|
|
|
def do_size_allocate(self, allocation):
|
|
|
|
Gtk.Window.do_size_allocate(self, allocation)
|
|
|
|
|
|
|
|
if self._old_alloc is None or \
|
|
|
|
self._old_alloc.x != allocation.x or \
|
|
|
|
self._old_alloc.y != allocation.y or \
|
|
|
|
self._old_alloc.width != allocation.width or \
|
|
|
|
self._old_alloc.height != allocation.height:
|
|
|
|
self.queue_draw()
|
|
|
|
|
|
|
|
# We need to store old allocation because when size_allocate
|
|
|
|
# is called widget.allocation is already updated.
|
|
|
|
# Gtk.Window resizing is different from normal containers:
|
|
|
|
# the X window is resized, widget.allocation is updated from
|
|
|
|
# the configure request handler and finally size_allocate is called.
|
|
|
|
self._old_alloc = allocation
|
|
|
|
|
2012-03-15 17:56:16 +01:00
|
|
|
def set_invoker(self, invoker):
|
|
|
|
self._invoker = invoker
|
|
|
|
|
|
|
|
def get_rect(self):
|
|
|
|
win_x, win_y = self.get_origin()
|
|
|
|
rectangle = self.get_allocation()
|
|
|
|
|
|
|
|
x = win_x + rectangle.x
|
|
|
|
y = win_y + rectangle.y
|
|
|
|
minimum, natural = self.get_preferred_size()
|
|
|
|
rect = Gdk.Rectangle()
|
|
|
|
rect.x = x
|
|
|
|
rect.y = y
|
|
|
|
rect.width = minimum.width
|
|
|
|
rect.height = natural.height
|
|
|
|
|
|
|
|
return rect
|
|
|
|
|
|
|
|
def do_draw(self, cr):
|
|
|
|
# Fall trough to the container expose handler.
|
|
|
|
# (Leaving out the window expose handler which redraws everything)
|
|
|
|
Gtk.Window.do_draw(self, cr)
|
|
|
|
|
|
|
|
if self._invoker is not None and self._invoker.has_rectangle_gap():
|
|
|
|
invoker = self._invoker.get_rect()
|
|
|
|
palette = self.get_rect()
|
|
|
|
gap = _calculate_gap(palette, invoker)
|
|
|
|
else:
|
|
|
|
gap = False
|
|
|
|
|
|
|
|
allocation = self.get_allocation()
|
|
|
|
context = self.get_style_context()
|
|
|
|
context.add_class('toolitem')
|
|
|
|
if gap:
|
2014-05-30 00:29:24 +02:00
|
|
|
cr.save()
|
|
|
|
cr.set_source_rgb(0, 0, 0)
|
|
|
|
cr.rectangle(0, 0, allocation.width, allocation.height)
|
|
|
|
cr.set_line_width(4)
|
|
|
|
cr.stroke()
|
|
|
|
cr.restore()
|
2013-05-18 04:27:04 +02:00
|
|
|
Gtk.render_frame_gap(
|
|
|
|
context, cr, 0, 0, allocation.width, allocation.height,
|
|
|
|
gap[0], gap[1], gap[1] + gap[2])
|
2012-03-15 17:56:16 +01:00
|
|
|
else:
|
2013-05-18 04:27:04 +02:00
|
|
|
Gtk.render_frame(
|
|
|
|
context, cr, 0, 0, allocation.width, allocation.height)
|
2012-03-15 17:56:16 +01:00
|
|
|
return False
|
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
def __enter_notify_event_cb(self, widget, event):
|
|
|
|
if event.mode == Gdk.CrossingMode.NORMAL and \
|
|
|
|
event.detail != Gdk.NotifyType.INFERIOR:
|
|
|
|
self.emit('enter-notify')
|
|
|
|
return False
|
|
|
|
|
|
|
|
def __leave_notify_event_cb(self, widget, event):
|
|
|
|
if event.mode != Gdk.CrossingMode.NORMAL:
|
|
|
|
return False
|
|
|
|
|
|
|
|
if event.detail != Gdk.NotifyType.INFERIOR:
|
|
|
|
self.emit('leave-notify')
|
|
|
|
|
|
|
|
def popup(self, invoker):
|
|
|
|
if self.get_visible():
|
2014-11-28 12:45:22 +01:00
|
|
|
logging.error('PaletteWindowWidget popup get_visible True')
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
return
|
|
|
|
self.connect('enter-notify-event', self.__enter_notify_event_cb)
|
|
|
|
self.connect('leave-notify-event', self.__leave_notify_event_cb)
|
|
|
|
self.show()
|
|
|
|
|
|
|
|
def popdown(self):
|
|
|
|
if not self.get_visible():
|
|
|
|
return
|
|
|
|
self.disconnect_by_func(self.__enter_notify_event_cb)
|
|
|
|
self.disconnect_by_func(self.__leave_notify_event_cb)
|
|
|
|
self.hide()
|
|
|
|
|
|
|
|
|
2011-11-15 19:29:07 +01:00
|
|
|
class MouseSpeedDetector(GObject.GObject):
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
__gsignals__ = {
|
2011-11-15 19:29:07 +01:00
|
|
|
'motion-slow': (GObject.SignalFlags.RUN_FIRST, None, ([])),
|
|
|
|
'motion-fast': (GObject.SignalFlags.RUN_FIRST, None, ([])),
|
2009-08-01 16:15:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
_MOTION_SLOW = 1
|
|
|
|
_MOTION_FAST = 2
|
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
def __init__(self, delay, thresh):
|
2009-08-01 16:15:01 +02:00
|
|
|
"""Create MouseSpeedDetector object,
|
|
|
|
delay in msec
|
|
|
|
threshold in pixels (per tick of 'delay' msec)"""
|
|
|
|
|
2011-11-15 19:29:07 +01:00
|
|
|
GObject.GObject.__init__(self)
|
2009-08-01 16:15:01 +02:00
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
self.parent = None
|
2009-08-01 16:15:01 +02:00
|
|
|
self._threshold = thresh
|
|
|
|
self._delay = delay
|
|
|
|
self._state = None
|
|
|
|
self._timeout_hid = None
|
|
|
|
self._mouse_pos = None
|
|
|
|
|
|
|
|
def start(self):
|
|
|
|
self.stop()
|
|
|
|
|
|
|
|
self._mouse_pos = self._get_mouse_position()
|
2013-05-06 18:18:10 +02:00
|
|
|
self._timeout_hid = GLib.timeout_add(self._delay, self._timer_cb)
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
def stop(self):
|
|
|
|
if self._timeout_hid is not None:
|
2011-11-15 19:29:07 +01:00
|
|
|
GObject.source_remove(self._timeout_hid)
|
2015-07-24 20:07:09 +02:00
|
|
|
self._timeout_hid = None
|
2009-08-01 16:15:01 +02:00
|
|
|
self._state = None
|
|
|
|
|
|
|
|
def _get_mouse_position(self):
|
2012-09-12 11:21:42 +02:00
|
|
|
if hasattr(self.parent, 'get_display'):
|
|
|
|
display = self.parent.get_display()
|
|
|
|
else:
|
|
|
|
display = Gdk.Display.get_default()
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
manager = display.get_device_manager()
|
|
|
|
pointer_device = manager.get_client_pointer()
|
|
|
|
screen, x, y = pointer_device.get_position()
|
2009-08-01 16:15:01 +02:00
|
|
|
return (x, y)
|
|
|
|
|
|
|
|
def _detect_motion(self):
|
|
|
|
oldx, oldy = self._mouse_pos
|
|
|
|
(x, y) = self._get_mouse_position()
|
|
|
|
self._mouse_pos = (x, y)
|
|
|
|
|
2010-10-15 20:23:34 +02:00
|
|
|
dist2 = (oldx - x) ** 2 + (oldy - y) ** 2
|
|
|
|
if dist2 > self._threshold ** 2:
|
2009-08-01 16:15:01 +02:00
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
|
|
|
def _timer_cb(self):
|
|
|
|
motion = self._detect_motion()
|
|
|
|
if motion and self._state != self._MOTION_FAST:
|
|
|
|
self.emit('motion-fast')
|
|
|
|
self._state = self._MOTION_FAST
|
|
|
|
elif not motion and self._state != self._MOTION_SLOW:
|
|
|
|
self.emit('motion-slow')
|
|
|
|
self._state = self._MOTION_SLOW
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
2009-08-25 21:12:40 +02:00
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
class PaletteWindow(GObject.GObject):
|
|
|
|
"""
|
|
|
|
Base class for _ToolbarPalette and Palette.
|
2009-08-01 16:15:01 +02:00
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
Provides basic management of child widget, invoker, and animation.
|
|
|
|
"""
|
2009-08-01 16:15:01 +02:00
|
|
|
|
2012-10-22 19:04:36 +02:00
|
|
|
PRIMARY = 0
|
|
|
|
SECONDARY = 1
|
|
|
|
|
2009-08-01 16:15:01 +02:00
|
|
|
__gsignals__ = {
|
2011-11-15 19:29:07 +01:00
|
|
|
'popup': (GObject.SignalFlags.RUN_FIRST, None, ([])),
|
|
|
|
'popdown': (GObject.SignalFlags.RUN_FIRST, None, ([])),
|
2009-08-01 16:15:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
def __init__(self, **kwargs):
|
|
|
|
self._group_id = None
|
|
|
|
self._invoker = None
|
|
|
|
self._invoker_hids = []
|
|
|
|
self._cursor_x = 0
|
|
|
|
self._cursor_y = 0
|
|
|
|
self._alignment = None
|
|
|
|
self._up = False
|
2010-10-15 22:04:49 +02:00
|
|
|
self._palette_state = None
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
self._widget = None
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
self._popup_anim = animator.Animator(.5, 10)
|
|
|
|
self._popup_anim.add(_PopupAnimation(self))
|
|
|
|
|
|
|
|
self._popdown_anim = animator.Animator(0.6, 10)
|
|
|
|
self._popdown_anim.add(_PopdownAnimation(self))
|
|
|
|
|
2011-11-15 19:29:07 +01:00
|
|
|
GObject.GObject.__init__(self, **kwargs)
|
2009-08-01 16:15:01 +02:00
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
self.set_group_id('default')
|
2009-08-01 16:15:01 +02:00
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
self._mouse_detector = MouseSpeedDetector(200, 5)
|
2009-08-01 16:15:01 +02:00
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
def _setup_widget(self):
|
|
|
|
self._widget.connect('show', self.__show_cb)
|
|
|
|
self._widget.connect('hide', self.__hide_cb)
|
|
|
|
self._widget.connect('destroy', self.__destroy_cb)
|
|
|
|
self._widget.connect('enter-notify', self.__enter_notify_cb)
|
|
|
|
self._widget.connect('leave-notify', self.__leave_notify_cb)
|
2015-05-25 04:41:24 +02:00
|
|
|
self._widget.connect('key-press-event', self.__key_press_event_cb)
|
2009-08-01 16:15:01 +02:00
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
self._set_effective_group_id(self._group_id)
|
2012-03-15 17:56:16 +01:00
|
|
|
self._widget.set_invoker(self._invoker)
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
self._mouse_detector.connect('motion-slow', self._mouse_slow_cb)
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
self._mouse_detector.parent = self._widget
|
|
|
|
|
|
|
|
def _teardown_widget(self):
|
|
|
|
self._widget.disconnect_by_func(self.__show_cb)
|
|
|
|
self._widget.disconnect_by_func(self.__hide_cb)
|
|
|
|
self._widget.disconnect_by_func(self.__destroy_cb)
|
|
|
|
self._widget.disconnect_by_func(self.__enter_notify_cb)
|
|
|
|
self._widget.disconnect_by_func(self.__leave_notify_cb)
|
2015-05-25 04:41:24 +02:00
|
|
|
self._widget.disconnect_by_func(self.__key_press_event_cb)
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
self._set_effective_group_id(None)
|
|
|
|
|
|
|
|
def destroy(self):
|
|
|
|
if self._widget is not None:
|
|
|
|
self._widget.destroy()
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
def __destroy_cb(self, palette):
|
2010-10-11 11:25:49 +02:00
|
|
|
self._mouse_detector.disconnect_by_func(self._mouse_slow_cb)
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
def set_invoker(self, invoker):
|
2009-08-25 19:55:48 +02:00
|
|
|
for hid in self._invoker_hids[:]:
|
2009-08-01 16:15:01 +02:00
|
|
|
self._invoker.disconnect(hid)
|
|
|
|
self._invoker_hids.remove(hid)
|
|
|
|
|
|
|
|
self._invoker = invoker
|
2012-06-06 14:38:25 +02:00
|
|
|
if self._widget is not None:
|
|
|
|
self._widget.set_invoker(invoker)
|
2009-08-01 16:15:01 +02:00
|
|
|
if invoker is not None:
|
|
|
|
self._invoker_hids.append(self._invoker.connect(
|
|
|
|
'mouse-enter', self._invoker_mouse_enter_cb))
|
|
|
|
self._invoker_hids.append(self._invoker.connect(
|
|
|
|
'mouse-leave', self._invoker_mouse_leave_cb))
|
|
|
|
self._invoker_hids.append(self._invoker.connect(
|
|
|
|
'right-click', self._invoker_right_click_cb))
|
2012-10-22 18:42:30 +02:00
|
|
|
self._invoker_hids.append(self._invoker.connect(
|
|
|
|
'toggle-state', self._invoker_toggle_state_cb))
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
def get_invoker(self):
|
|
|
|
return self._invoker
|
|
|
|
|
2011-11-15 19:29:07 +01:00
|
|
|
invoker = GObject.property(type=object,
|
2009-08-01 16:15:01 +02:00
|
|
|
getter=get_invoker,
|
|
|
|
setter=set_invoker)
|
|
|
|
|
|
|
|
def _mouse_slow_cb(self, widget):
|
|
|
|
self._mouse_detector.stop()
|
|
|
|
self._palette_do_popup()
|
|
|
|
|
|
|
|
def _palette_do_popup(self):
|
|
|
|
immediate = False
|
|
|
|
|
|
|
|
if self.is_up():
|
2009-08-25 19:55:48 +02:00
|
|
|
self._popdown_anim.stop()
|
2009-08-01 16:15:01 +02:00
|
|
|
return
|
|
|
|
|
|
|
|
if self._group_id:
|
|
|
|
group = palettegroup.get_group(self._group_id)
|
|
|
|
if group and group.is_up():
|
|
|
|
immediate = True
|
|
|
|
group.popdown()
|
|
|
|
|
|
|
|
self.popup(immediate=immediate)
|
|
|
|
|
|
|
|
def is_up(self):
|
|
|
|
return self._up
|
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
def _set_effective_group_id(self, group_id):
|
2009-08-01 16:15:01 +02:00
|
|
|
if self._group_id:
|
|
|
|
group = palettegroup.get_group(self._group_id)
|
|
|
|
group.remove(self)
|
|
|
|
if group_id:
|
|
|
|
group = palettegroup.get_group(group_id)
|
|
|
|
group.add(self)
|
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
def set_group_id(self, group_id):
|
|
|
|
self._set_effective_group_id(group_id)
|
|
|
|
self._group_id = group_id
|
|
|
|
|
2009-08-01 16:15:01 +02:00
|
|
|
def get_group_id(self):
|
|
|
|
return self._group_id
|
|
|
|
|
2011-11-15 19:29:07 +01:00
|
|
|
group_id = GObject.property(type=str,
|
2009-08-01 16:15:01 +02:00
|
|
|
getter=get_group_id,
|
|
|
|
setter=set_group_id)
|
|
|
|
|
|
|
|
def update_position(self):
|
|
|
|
invoker = self._invoker
|
|
|
|
if invoker is None or self._alignment is None:
|
|
|
|
logging.error('Cannot update the palette position.')
|
|
|
|
return
|
|
|
|
|
2014-11-28 12:45:22 +01:00
|
|
|
if self._widget is None:
|
|
|
|
return
|
|
|
|
|
Show palettes at the screen bottom with the right size - Fixes #4673
On Gtk 3.10, Gtk.Menu at the bottom of the screen are resized
to avoid fall out of the screen, then report a wrong height.
We need calculate the size of the children and move the Menu up.
This problem is visible on the Clipboard icon palettes,
and in journal objects palettes at the bottom of the screen.
This patch also rename a variable 'rect' to 'req', because is
a Requisition (width, height) and not a Rectangle (x, y, width, height).
Finally, to avoid a error with the secondary text on the palette,
when copy text from the terminal, reove the '¬r' character.
Signed-off-by: Gonzalo Odiard <godiard@sugarlabs.org>
2014-05-28 15:00:05 +02:00
|
|
|
req = self._widget.size_request()
|
|
|
|
# on Gtk 3.10, menu at the bottom of the screen are resized
|
|
|
|
# to not fall out, and report a wrong size.
|
|
|
|
# measure the children and move the menu - SL #4673
|
|
|
|
total_height = 0
|
|
|
|
for child in self._widget.get_children():
|
|
|
|
child_req = child.size_request()
|
|
|
|
total_height += child_req.height
|
2014-05-30 20:13:45 +02:00
|
|
|
|
|
|
|
# need add the border line width as defined in sugar-artwork
|
|
|
|
line_width = 2
|
|
|
|
total_height += line_width * 2
|
Show palettes at the screen bottom with the right size - Fixes #4673
On Gtk 3.10, Gtk.Menu at the bottom of the screen are resized
to avoid fall out of the screen, then report a wrong height.
We need calculate the size of the children and move the Menu up.
This problem is visible on the Clipboard icon palettes,
and in journal objects palettes at the bottom of the screen.
This patch also rename a variable 'rect' to 'req', because is
a Requisition (width, height) and not a Rectangle (x, y, width, height).
Finally, to avoid a error with the secondary text on the palette,
when copy text from the terminal, reove the '¬r' character.
Signed-off-by: Gonzalo Odiard <godiard@sugarlabs.org>
2014-05-28 15:00:05 +02:00
|
|
|
req.height = total_height
|
|
|
|
|
|
|
|
position = invoker.get_position_for_alignment(self._alignment, req)
|
2009-08-01 16:15:01 +02:00
|
|
|
if position is None:
|
Show palettes at the screen bottom with the right size - Fixes #4673
On Gtk 3.10, Gtk.Menu at the bottom of the screen are resized
to avoid fall out of the screen, then report a wrong height.
We need calculate the size of the children and move the Menu up.
This problem is visible on the Clipboard icon palettes,
and in journal objects palettes at the bottom of the screen.
This patch also rename a variable 'rect' to 'req', because is
a Requisition (width, height) and not a Rectangle (x, y, width, height).
Finally, to avoid a error with the secondary text on the palette,
when copy text from the terminal, reove the '¬r' character.
Signed-off-by: Gonzalo Odiard <godiard@sugarlabs.org>
2014-05-28 15:00:05 +02:00
|
|
|
position = invoker.get_position(req)
|
2009-08-01 16:15:01 +02:00
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
self._widget.move(position.x, position.y)
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
def get_full_size_request(self):
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
return self._widget.size_request()
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
def popup(self, immediate=False):
|
2014-11-28 12:45:22 +01:00
|
|
|
if self._widget is None:
|
|
|
|
return
|
2009-08-01 16:15:01 +02:00
|
|
|
if self._invoker is not None:
|
|
|
|
full_size_request = self.get_full_size_request()
|
|
|
|
self._alignment = self._invoker.get_alignment(full_size_request)
|
|
|
|
|
|
|
|
self.update_position()
|
2013-03-14 12:00:22 +01:00
|
|
|
try:
|
|
|
|
self._widget.set_transient_for(self._invoker.get_toplevel())
|
|
|
|
except TypeError:
|
|
|
|
# the expected parent window did likely change e.g. SL #4221
|
|
|
|
# popdown the Palette
|
|
|
|
self.emit('popdown')
|
|
|
|
return
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
self._popdown_anim.stop()
|
|
|
|
|
|
|
|
if not immediate:
|
|
|
|
self._popup_anim.start()
|
|
|
|
else:
|
2009-09-09 14:41:37 +02:00
|
|
|
self._popup_anim.stop()
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
self._widget.popup(self._invoker)
|
2009-09-03 23:18:27 +02:00
|
|
|
# we have to invoke update_position() twice
|
|
|
|
# since WM could ignore first move() request
|
|
|
|
self.update_position()
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
def popdown(self, immediate=False):
|
2009-09-09 14:41:37 +02:00
|
|
|
self._popup_anim.stop()
|
2009-08-01 16:15:01 +02:00
|
|
|
self._mouse_detector.stop()
|
|
|
|
|
|
|
|
if not immediate:
|
|
|
|
self._popdown_anim.start()
|
|
|
|
else:
|
2009-09-09 14:41:37 +02:00
|
|
|
self._popdown_anim.stop()
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
if self._widget is not None:
|
|
|
|
self._widget.popdown()
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
def on_invoker_enter(self):
|
2009-09-09 20:47:07 +02:00
|
|
|
self._popdown_anim.stop()
|
2009-08-01 16:15:01 +02:00
|
|
|
self._mouse_detector.start()
|
|
|
|
|
|
|
|
def on_invoker_leave(self):
|
|
|
|
self._mouse_detector.stop()
|
|
|
|
self.popdown()
|
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
def on_enter(self):
|
2009-08-01 16:15:01 +02:00
|
|
|
self._popdown_anim.stop()
|
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
def on_leave(self):
|
2009-08-01 16:15:01 +02:00
|
|
|
self.popdown()
|
|
|
|
|
|
|
|
def _invoker_mouse_enter_cb(self, invoker):
|
2012-11-15 18:09:00 +01:00
|
|
|
if not self._invoker.locked:
|
|
|
|
self.on_invoker_enter()
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
def _invoker_mouse_leave_cb(self, invoker):
|
2012-11-15 18:09:00 +01:00
|
|
|
if not self._invoker.locked:
|
|
|
|
self.on_invoker_leave()
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
def _invoker_right_click_cb(self, invoker):
|
2014-06-24 16:18:57 +02:00
|
|
|
self.popup(immediate=True)
|
2012-10-22 18:42:30 +02:00
|
|
|
|
|
|
|
def _invoker_toggle_state_cb(self, invoker):
|
2014-06-24 16:18:57 +02:00
|
|
|
if self.is_up():
|
2012-10-22 18:42:30 +02:00
|
|
|
self.popdown(immediate=True)
|
|
|
|
else:
|
2014-06-24 16:18:57 +02:00
|
|
|
self.popup(immediate=True)
|
2009-08-01 16:15:01 +02:00
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
def __enter_notify_cb(self, widget):
|
2012-11-15 18:09:00 +01:00
|
|
|
if not self._invoker.locked:
|
|
|
|
self.on_enter()
|
2009-08-01 16:15:01 +02:00
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
def __leave_notify_cb(self, widget):
|
2012-11-15 18:09:00 +01:00
|
|
|
if not self._invoker.locked:
|
|
|
|
self.on_leave()
|
2009-08-01 16:15:01 +02:00
|
|
|
|
2015-05-25 04:41:24 +02:00
|
|
|
def __key_press_event_cb(self, window, event):
|
|
|
|
if event.keyval == Gdk.KEY_Escape:
|
|
|
|
self.popdown()
|
|
|
|
|
2009-08-01 16:15:01 +02:00
|
|
|
def __show_cb(self, widget):
|
2009-09-10 09:48:20 +02:00
|
|
|
if self._invoker is not None:
|
|
|
|
self._invoker.notify_popup()
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
self._up = True
|
|
|
|
self.emit('popup')
|
|
|
|
|
|
|
|
def __hide_cb(self, widget):
|
|
|
|
if self._invoker:
|
|
|
|
self._invoker.notify_popdown()
|
|
|
|
|
|
|
|
self._up = False
|
|
|
|
self.emit('popdown')
|
|
|
|
|
|
|
|
def get_rect(self):
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
win_x, win_y = self._widget.get_origin()
|
2012-03-15 17:56:16 +01:00
|
|
|
rectangle = self._widget.get_allocation()
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
x = win_x + rectangle.x
|
|
|
|
y = win_y + rectangle.y
|
2012-03-15 17:56:16 +01:00
|
|
|
minimum, natural_ = self._widget.get_preferred_size()
|
2009-08-01 16:15:01 +02:00
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
rect = Gdk.Rectangle()
|
|
|
|
rect.x = x
|
|
|
|
rect.y = y
|
2012-03-15 17:56:16 +01:00
|
|
|
rect.width = minimum.width
|
|
|
|
rect.height = minimum.height
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
|
|
|
|
return rect
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
def get_palette_state(self):
|
|
|
|
return self._palette_state
|
|
|
|
|
|
|
|
def _set_palette_state(self, state):
|
|
|
|
self._palette_state = state
|
|
|
|
|
|
|
|
def set_palette_state(self, state):
|
|
|
|
self._set_palette_state(state)
|
|
|
|
|
|
|
|
palette_state = property(get_palette_state)
|
|
|
|
|
2009-08-25 21:12:40 +02:00
|
|
|
|
2009-08-01 16:15:01 +02:00
|
|
|
class _PopupAnimation(animator.Animation):
|
2009-08-25 21:12:40 +02:00
|
|
|
|
2009-08-01 16:15:01 +02:00
|
|
|
def __init__(self, palette):
|
|
|
|
animator.Animation.__init__(self, 0.0, 1.0)
|
|
|
|
self._palette = palette
|
|
|
|
|
|
|
|
def next_frame(self, current):
|
|
|
|
if current == 1.0:
|
2009-09-04 12:05:16 +02:00
|
|
|
self._palette.popup(immediate=True)
|
2009-08-01 16:15:01 +02:00
|
|
|
|
2009-08-25 21:12:40 +02:00
|
|
|
|
2009-08-01 16:15:01 +02:00
|
|
|
class _PopdownAnimation(animator.Animation):
|
2009-08-25 21:12:40 +02:00
|
|
|
|
2009-08-01 16:15:01 +02:00
|
|
|
def __init__(self, palette):
|
|
|
|
animator.Animation.__init__(self, 0.0, 1.0)
|
|
|
|
self._palette = palette
|
|
|
|
|
|
|
|
def next_frame(self, current):
|
|
|
|
if current == 1.0:
|
2009-09-04 12:05:16 +02:00
|
|
|
self._palette.popdown(immediate=True)
|
2009-08-01 16:15:01 +02:00
|
|
|
|
2009-08-25 21:12:40 +02:00
|
|
|
|
2011-11-15 19:29:07 +01:00
|
|
|
class Invoker(GObject.GObject):
|
2009-08-25 21:12:40 +02:00
|
|
|
|
2009-08-01 16:15:01 +02:00
|
|
|
__gtype_name__ = 'SugarPaletteInvoker'
|
|
|
|
|
|
|
|
__gsignals__ = {
|
2011-11-15 19:29:07 +01:00
|
|
|
'mouse-enter': (GObject.SignalFlags.RUN_FIRST, None, ([])),
|
|
|
|
'mouse-leave': (GObject.SignalFlags.RUN_FIRST, None, ([])),
|
|
|
|
'right-click': (GObject.SignalFlags.RUN_FIRST, None, ([])),
|
2012-10-22 18:42:30 +02:00
|
|
|
'toggle-state': (GObject.SignalFlags.RUN_FIRST, None, ([])),
|
2011-11-15 19:29:07 +01:00
|
|
|
'focus-out': (GObject.SignalFlags.RUN_FIRST, None, ([])),
|
2009-08-01 16:15:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ANCHORED = 0
|
|
|
|
AT_CURSOR = 1
|
|
|
|
|
2009-08-25 21:12:40 +02:00
|
|
|
BOTTOM = [(0.0, 0.0, 0.0, 1.0), (-1.0, 0.0, 1.0, 1.0)]
|
|
|
|
RIGHT = [(0.0, 0.0, 1.0, 0.0), (0.0, -1.0, 1.0, 1.0)]
|
|
|
|
TOP = [(0.0, -1.0, 0.0, 0.0), (-1.0, -1.0, 1.0, 0.0)]
|
|
|
|
LEFT = [(-1.0, 0.0, 0.0, 0.0), (-1.0, -1.0, 0.0, 1.0)]
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
def __init__(self):
|
2011-11-15 19:29:07 +01:00
|
|
|
GObject.GObject.__init__(self)
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
self.parent = None
|
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
self._screen_area = Gdk.Rectangle()
|
|
|
|
self._screen_area.x = self._screen_area.y = 0
|
|
|
|
self._screen_area.width = Gdk.Screen.width()
|
|
|
|
self._screen_area.height = Gdk.Screen.height()
|
2009-08-01 16:15:01 +02:00
|
|
|
self._position_hint = self.ANCHORED
|
|
|
|
self._cursor_x = -1
|
|
|
|
self._cursor_y = -1
|
|
|
|
self._palette = None
|
2010-10-11 11:25:49 +02:00
|
|
|
self._cache_palette = True
|
2012-10-22 18:42:30 +02:00
|
|
|
self._toggle_palette = False
|
2012-11-15 18:09:00 +01:00
|
|
|
self._lock_palette = False
|
|
|
|
self.locked = False
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
def attach(self, parent):
|
|
|
|
self.parent = parent
|
|
|
|
|
|
|
|
def detach(self):
|
|
|
|
self.parent = None
|
|
|
|
if self._palette is not None:
|
|
|
|
self._palette.destroy()
|
|
|
|
self._palette = None
|
|
|
|
|
|
|
|
def _get_position_for_alignment(self, alignment, palette_dim):
|
|
|
|
palette_halign = alignment[0]
|
|
|
|
palette_valign = alignment[1]
|
|
|
|
invoker_halign = alignment[2]
|
|
|
|
invoker_valign = alignment[3]
|
|
|
|
|
|
|
|
if self._cursor_x == -1 or self._cursor_y == -1:
|
2012-09-12 11:21:42 +02:00
|
|
|
if hasattr(self.parent, 'get_display'):
|
|
|
|
display = self.parent.get_display()
|
|
|
|
else:
|
|
|
|
display = Gdk.Display.get_default()
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
manager = display.get_device_manager()
|
|
|
|
pointer_device = manager.get_client_pointer()
|
|
|
|
screen, x, y = pointer_device.get_position()
|
2009-08-01 16:15:01 +02:00
|
|
|
self._cursor_x = x
|
|
|
|
self._cursor_y = y
|
|
|
|
|
|
|
|
if self._position_hint is self.ANCHORED:
|
|
|
|
rect = self.get_rect()
|
|
|
|
else:
|
|
|
|
dist = style.PALETTE_CURSOR_DISTANCE
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
rect = Gdk.Rectangle()
|
|
|
|
rect.x = self._cursor_x - dist
|
|
|
|
rect.y = self._cursor_y - dist
|
|
|
|
rect.width = rect.height = dist * 2
|
2009-08-01 16:15:01 +02:00
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
palette_width, palette_height = palette_dim.width, palette_dim.height
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
x = rect.x + rect.width * invoker_halign + \
|
|
|
|
palette_width * palette_halign
|
|
|
|
|
|
|
|
y = rect.y + rect.height * invoker_valign + \
|
|
|
|
palette_height * palette_valign
|
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
rect = Gdk.Rectangle()
|
|
|
|
rect.x = int(x)
|
|
|
|
rect.y = int(y)
|
|
|
|
rect.width = palette_width
|
|
|
|
rect.height = palette_height
|
|
|
|
return rect
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
def _in_screen(self, rect):
|
|
|
|
return rect.x >= self._screen_area.x and \
|
2013-05-18 04:27:04 +02:00
|
|
|
rect.y >= self._screen_area.y and \
|
|
|
|
rect.x + rect.width <= self._screen_area.width and \
|
|
|
|
rect.y + rect.height <= self._screen_area.height
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
def _get_area_in_screen(self, rect):
|
|
|
|
"""Return area of rectangle visible in the screen"""
|
|
|
|
|
|
|
|
x1 = max(rect.x, self._screen_area.x)
|
|
|
|
y1 = max(rect.y, self._screen_area.y)
|
|
|
|
x2 = min(rect.x + rect.width,
|
2013-05-18 04:27:04 +02:00
|
|
|
self._screen_area.x + self._screen_area.width)
|
2009-08-01 16:15:01 +02:00
|
|
|
y2 = min(rect.y + rect.height,
|
2013-05-18 04:27:04 +02:00
|
|
|
self._screen_area.y + self._screen_area.height)
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
return (x2 - x1) * (y2 - y1)
|
|
|
|
|
|
|
|
def _get_alignments(self):
|
|
|
|
if self._position_hint is self.AT_CURSOR:
|
|
|
|
return [(0.0, 0.0, 1.0, 1.0),
|
|
|
|
(0.0, -1.0, 1.0, 0.0),
|
|
|
|
(-1.0, -1.0, 0.0, 0.0),
|
|
|
|
(-1.0, 0.0, 0.0, 1.0)]
|
|
|
|
else:
|
|
|
|
return self.BOTTOM + self.RIGHT + self.TOP + self.LEFT
|
|
|
|
|
|
|
|
def get_position_for_alignment(self, alignment, palette_dim):
|
|
|
|
rect = self._get_position_for_alignment(alignment, palette_dim)
|
|
|
|
if self._in_screen(rect):
|
|
|
|
return rect
|
|
|
|
else:
|
|
|
|
return None
|
|
|
|
|
|
|
|
def get_position(self, palette_dim):
|
|
|
|
alignment = self.get_alignment(palette_dim)
|
|
|
|
rect = self._get_position_for_alignment(alignment, palette_dim)
|
|
|
|
|
2009-08-25 21:12:40 +02:00
|
|
|
# In case our efforts to find an optimum place inside the screen
|
|
|
|
# failed, just make sure the palette fits inside the screen if at all
|
|
|
|
# possible.
|
2009-08-01 16:15:01 +02:00
|
|
|
rect.x = max(0, rect.x)
|
|
|
|
rect.y = max(0, rect.y)
|
|
|
|
|
|
|
|
rect.x = min(rect.x, self._screen_area.width - rect.width)
|
|
|
|
rect.y = min(rect.y, self._screen_area.height - rect.height)
|
|
|
|
|
|
|
|
return rect
|
|
|
|
|
|
|
|
def get_alignment(self, palette_dim):
|
|
|
|
best_alignment = None
|
|
|
|
best_area = -1
|
|
|
|
for alignment in self._get_alignments():
|
|
|
|
pos = self._get_position_for_alignment(alignment, palette_dim)
|
|
|
|
if self._in_screen(pos):
|
|
|
|
return alignment
|
|
|
|
|
|
|
|
area = self._get_area_in_screen(pos)
|
|
|
|
if area > best_area:
|
|
|
|
best_alignment = alignment
|
|
|
|
best_area = area
|
|
|
|
|
|
|
|
# Palette horiz/vert alignment
|
|
|
|
ph = best_alignment[0]
|
|
|
|
pv = best_alignment[1]
|
|
|
|
|
|
|
|
# Invoker horiz/vert alignment
|
|
|
|
ih = best_alignment[2]
|
|
|
|
iv = best_alignment[3]
|
|
|
|
|
|
|
|
rect = self.get_rect()
|
|
|
|
screen_area = self._screen_area
|
|
|
|
|
|
|
|
if best_alignment in self.LEFT or best_alignment in self.RIGHT:
|
|
|
|
dtop = rect.y - screen_area.y
|
|
|
|
dbottom = screen_area.y + screen_area.height - rect.y - rect.width
|
|
|
|
|
|
|
|
iv = 0
|
|
|
|
|
|
|
|
# Set palette_valign to align to screen on the top
|
|
|
|
if dtop > dbottom:
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
pv = -float(dtop) / palette_dim.height
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
# Set palette_valign to align to screen on the bottom
|
|
|
|
else:
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
pv = -float(palette_dim.height - dbottom - rect.height) \
|
2013-05-18 04:27:04 +02:00
|
|
|
/ palette_dim.height
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
elif best_alignment in self.TOP or best_alignment in self.BOTTOM:
|
|
|
|
dleft = rect.x - screen_area.x
|
|
|
|
dright = screen_area.x + screen_area.width - rect.x - rect.width
|
|
|
|
|
|
|
|
ih = 0
|
|
|
|
|
|
|
|
# Set palette_halign to align to screen on left
|
|
|
|
if dleft > dright:
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
ph = -float(dleft) / palette_dim.width
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
# Set palette_halign to align to screen on right
|
|
|
|
else:
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
ph = -float(palette_dim.width - dright - rect.width) \
|
2013-05-18 04:27:04 +02:00
|
|
|
/ palette_dim.width
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
return (ph, pv, ih, iv)
|
|
|
|
|
|
|
|
def has_rectangle_gap(self):
|
|
|
|
return False
|
|
|
|
|
|
|
|
def draw_rectangle(self, event, palette):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def notify_popup(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def notify_popdown(self):
|
|
|
|
self._cursor_x = -1
|
|
|
|
self._cursor_y = -1
|
|
|
|
|
|
|
|
def _ensure_palette_exists(self):
|
|
|
|
if self.parent and self.palette is None:
|
|
|
|
palette = self.parent.create_palette()
|
|
|
|
if palette is not None:
|
|
|
|
self.palette = palette
|
|
|
|
|
|
|
|
def notify_mouse_enter(self):
|
|
|
|
self._ensure_palette_exists()
|
|
|
|
self.emit('mouse-enter')
|
|
|
|
|
|
|
|
def notify_mouse_leave(self):
|
|
|
|
self.emit('mouse-leave')
|
|
|
|
|
|
|
|
def notify_right_click(self):
|
|
|
|
self._ensure_palette_exists()
|
|
|
|
self.emit('right-click')
|
|
|
|
|
2012-10-22 18:42:30 +02:00
|
|
|
def notify_toggle_state(self):
|
|
|
|
self._ensure_palette_exists()
|
|
|
|
self.emit('toggle-state')
|
|
|
|
|
2009-08-01 16:15:01 +02:00
|
|
|
def get_palette(self):
|
|
|
|
return self._palette
|
2009-08-25 19:55:48 +02:00
|
|
|
|
2009-08-01 16:15:01 +02:00
|
|
|
def set_palette(self, palette):
|
2009-09-08 09:14:22 +02:00
|
|
|
if self._palette is not None:
|
|
|
|
self._palette.popdown(immediate=True)
|
2009-08-01 16:15:01 +02:00
|
|
|
self._palette.props.invoker = None
|
2011-03-03 14:30:30 +01:00
|
|
|
# GTK pops down the palette before it invokes the actions on the
|
|
|
|
# menu item. We need to postpone destruction of the palette until
|
|
|
|
# after all signals have propagated from the menu item to the
|
|
|
|
# palette owner.
|
2013-05-06 05:14:57 +02:00
|
|
|
GLib.idle_add(lambda old_palette=self._palette:
|
|
|
|
old_palette.destroy(),
|
|
|
|
priority=GObject.PRIORITY_LOW)
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
self._palette = palette
|
|
|
|
|
2010-10-11 11:25:49 +02:00
|
|
|
if self._palette is not None:
|
2009-08-01 16:15:01 +02:00
|
|
|
self._palette.props.invoker = self
|
2010-10-11 11:25:49 +02:00
|
|
|
self._palette.connect('popdown', self.__palette_popdown_cb)
|
2009-08-01 16:15:01 +02:00
|
|
|
|
2011-11-15 19:29:07 +01:00
|
|
|
palette = GObject.property(
|
2009-08-01 16:15:01 +02:00
|
|
|
type=object, setter=set_palette, getter=get_palette)
|
|
|
|
|
2010-10-11 11:25:49 +02:00
|
|
|
def get_cache_palette(self):
|
|
|
|
return self._cache_palette
|
|
|
|
|
|
|
|
def set_cache_palette(self, cache_palette):
|
|
|
|
self._cache_palette = cache_palette
|
|
|
|
|
2011-11-15 19:29:07 +01:00
|
|
|
cache_palette = GObject.property(type=object, setter=set_cache_palette,
|
2010-10-11 11:25:49 +02:00
|
|
|
getter=get_cache_palette)
|
|
|
|
"""Whether the invoker will cache the palette after its creation. Defaults
|
|
|
|
to True.
|
|
|
|
"""
|
|
|
|
|
2012-10-22 18:42:30 +02:00
|
|
|
def get_toggle_palette(self):
|
|
|
|
return self._toggle_palette
|
|
|
|
|
|
|
|
def set_toggle_palette(self, toggle_palette):
|
|
|
|
self._toggle_palette = toggle_palette
|
|
|
|
|
|
|
|
toggle_palette = GObject.property(type=object, setter=set_toggle_palette,
|
|
|
|
getter=get_toggle_palette)
|
|
|
|
"""Whether the invoker will popup/popdown the Palette on
|
|
|
|
button left click/touch tap. Defaults to False.
|
|
|
|
"""
|
|
|
|
|
2012-11-15 18:09:00 +01:00
|
|
|
def get_lock_palette(self):
|
|
|
|
return self._lock_palette
|
|
|
|
|
|
|
|
def set_lock_palette(self, lock_palette):
|
|
|
|
self._lock_palette = lock_palette
|
|
|
|
|
|
|
|
lock_palette = GObject.property(type=object, setter=set_lock_palette,
|
2013-05-18 04:27:04 +02:00
|
|
|
getter=get_lock_palette)
|
2012-11-15 18:09:00 +01:00
|
|
|
"""Whether the invoker will lock the Palette and
|
|
|
|
ignore mouse events. Defaults to False.
|
|
|
|
"""
|
|
|
|
|
2010-10-11 11:25:49 +02:00
|
|
|
def __palette_popdown_cb(self, palette):
|
|
|
|
if not self.props.cache_palette:
|
|
|
|
self.set_palette(None)
|
2009-08-25 21:12:40 +02:00
|
|
|
|
2013-11-29 13:09:53 +01:00
|
|
|
def primary_text_clicked(self):
|
|
|
|
"""Implemented by invokers that can be clicked"""
|
|
|
|
pass
|
|
|
|
|
2010-10-15 19:53:25 +02:00
|
|
|
|
2009-08-01 16:15:01 +02:00
|
|
|
class WidgetInvoker(Invoker):
|
2009-08-25 21:12:40 +02:00
|
|
|
|
2009-08-01 16:15:01 +02:00
|
|
|
def __init__(self, parent=None, widget=None):
|
|
|
|
Invoker.__init__(self)
|
|
|
|
|
|
|
|
self._widget = None
|
2012-11-15 18:09:00 +01:00
|
|
|
self._expanded = False
|
2009-08-01 16:15:01 +02:00
|
|
|
self._enter_hid = None
|
|
|
|
self._leave_hid = None
|
|
|
|
self._release_hid = None
|
2012-11-01 13:35:16 +01:00
|
|
|
self._click_hid = None
|
|
|
|
self._touch_hid = None
|
2012-11-15 18:09:00 +01:00
|
|
|
self._draw_hid = None
|
2012-11-01 13:35:16 +01:00
|
|
|
self._long_pressed_recognized = False
|
|
|
|
self._long_pressed_hid = None
|
|
|
|
self._long_pressed_controller = SugarGestures.LongPressController()
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
if parent or widget:
|
|
|
|
self.attach_widget(parent, widget)
|
|
|
|
|
|
|
|
def attach_widget(self, parent, widget=None):
|
|
|
|
if widget:
|
|
|
|
self._widget = widget
|
|
|
|
else:
|
|
|
|
self._widget = parent
|
|
|
|
|
|
|
|
self.notify('widget')
|
|
|
|
|
|
|
|
self._enter_hid = self._widget.connect('enter-notify-event',
|
2013-05-18 04:27:04 +02:00
|
|
|
self.__enter_notify_event_cb)
|
2009-08-01 16:15:01 +02:00
|
|
|
self._leave_hid = self._widget.connect('leave-notify-event',
|
2013-05-18 04:27:04 +02:00
|
|
|
self.__leave_notify_event_cb)
|
2012-11-01 13:35:16 +01:00
|
|
|
if GObject.signal_lookup('clicked', self._widget) != 0:
|
|
|
|
self._click_hid = self._widget.connect('clicked',
|
2013-05-18 04:27:04 +02:00
|
|
|
self.__click_event_cb)
|
2012-11-01 13:35:16 +01:00
|
|
|
self._touch_hid = self._widget.connect('touch-event',
|
2013-05-18 04:27:04 +02:00
|
|
|
self.__touch_event_cb)
|
|
|
|
self._release_hid = \
|
|
|
|
self._widget.connect('button-release-event',
|
|
|
|
self.__button_release_event_cb)
|
2012-11-15 18:09:00 +01:00
|
|
|
self._draw_hid = self._widget.connect_after('draw', self.__drawing_cb)
|
2009-08-01 16:15:01 +02:00
|
|
|
|
2012-11-01 13:35:16 +01:00
|
|
|
self._long_pressed_hid = self._long_pressed_controller.connect(
|
|
|
|
'pressed', self.__long_pressed_event_cb, self._widget)
|
2013-05-18 04:27:04 +02:00
|
|
|
self._long_pressed_controller.attach(
|
|
|
|
self._widget,
|
2012-11-01 13:35:16 +01:00
|
|
|
SugarGestures.EventControllerFlags.NONE)
|
2012-11-15 18:09:00 +01:00
|
|
|
|
2009-08-01 16:15:01 +02:00
|
|
|
self.attach(parent)
|
|
|
|
|
|
|
|
def detach(self):
|
|
|
|
Invoker.detach(self)
|
|
|
|
self._widget.disconnect(self._enter_hid)
|
|
|
|
self._widget.disconnect(self._leave_hid)
|
|
|
|
self._widget.disconnect(self._release_hid)
|
2012-11-15 18:09:00 +01:00
|
|
|
self._widget.disconnect(self._draw_hid)
|
2012-11-01 13:35:16 +01:00
|
|
|
if self._click_hid:
|
|
|
|
self._widget.disconnect(self._click_hid)
|
|
|
|
self._widget.disconnect(self._touch_hid)
|
|
|
|
self._long_pressed_controller.detach(self._widget)
|
|
|
|
self._long_pressed_controller.disconnect(self._long_pressed_hid)
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
def get_rect(self):
|
|
|
|
allocation = self._widget.get_allocation()
|
2011-11-15 21:32:03 +01:00
|
|
|
window = self._widget.get_window()
|
|
|
|
if window is not None:
|
2012-09-12 12:44:20 +02:00
|
|
|
res_, x, y = window.get_origin()
|
2009-08-01 16:15:01 +02:00
|
|
|
else:
|
|
|
|
logging.warning(
|
|
|
|
"Trying to position palette with invoker that's not realized.")
|
|
|
|
x = 0
|
|
|
|
y = 0
|
|
|
|
|
2012-09-12 20:52:51 +02:00
|
|
|
if not self._widget.get_has_window():
|
|
|
|
x += allocation.x
|
|
|
|
y += allocation.y
|
|
|
|
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
rect = Gdk.Rectangle()
|
|
|
|
rect.x = x
|
|
|
|
rect.y = y
|
2012-09-12 12:44:20 +02:00
|
|
|
rect.width = allocation.width
|
|
|
|
rect.height = allocation.height
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
return rect
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
def has_rectangle_gap(self):
|
|
|
|
return True
|
|
|
|
|
2012-03-15 17:56:16 +01:00
|
|
|
def draw_rectangle(self, cr, palette):
|
|
|
|
allocation = self.parent.get_allocation()
|
2009-08-01 16:15:01 +02:00
|
|
|
|
2012-03-15 17:56:16 +01:00
|
|
|
context = self.parent.get_style_context()
|
|
|
|
context.add_class('toolitem')
|
2009-08-01 16:15:01 +02:00
|
|
|
|
2012-03-15 17:56:16 +01:00
|
|
|
gap = _calculate_gap(self.get_rect(), palette.get_rect())
|
2009-08-01 16:15:01 +02:00
|
|
|
if gap:
|
2012-03-15 17:56:16 +01:00
|
|
|
Gtk.render_frame_gap(context, cr, 0, 0,
|
|
|
|
allocation.width,
|
|
|
|
allocation.height,
|
2012-04-18 22:38:40 +02:00
|
|
|
gap[0], gap[1], gap[1] + gap[2])
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
def __enter_notify_event_cb(self, widget, event):
|
2012-10-25 11:42:00 +02:00
|
|
|
if event.mode == Gdk.CrossingMode.NORMAL:
|
|
|
|
self.notify_mouse_enter()
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
def __leave_notify_event_cb(self, widget, event):
|
Reimplement Palettes for GTK3
Moving from GTK2 to GTK3 has presented various challenges regarding
palettes.
In GTK2, we were able to access some internal API of the GtkMenu class
and use it to embed a GtkMenu in a regular window. As of GTK3, that API
has become private and we can no longer access it.
We still want to use GtkMenu for the advanced functionality it provides
(multiple-level menus, keyboard navigation, etc), but we are now limited
to popping it up with its own (internal) window, rather than being able
to pack it into one of our own.
Our palettes can historically be used either as a menu, or as a general
area where widgets can be added, or both. The new restrictions upon
GtkMenu force some changes here, but we work hard to stick to the old
API as far as possible.
A Palette instance now acts as a controller of either a "window widget"
(where any type of widget can be displayed as usual) or a "menu widget"
which just pops up a GtkMenu. A Palette defaults to the window mode, but
dynamically switches to menu mode if/when the user attempts to access
the menu element.
As a result of this, palettes can now pack either a user-defined collection
of widgets, or a menu, but types can no longer be mixed. This should
only affect a handful of palettes which will need to pick a single
approach and convert to it.
Some further challenges are presented by the fact that GtkMenu performs a
grab on the whole screen, meaning that all input events are delivered to
the GtkMenu widget. Through some careful event filtering and examination
of the mouse cursor position we are still able to determine when the mouse
has entered or left the invoker or menu areas.
This work is authored by Benjamin Berg, Marco Pesenti Gritti, Simon
Schampijer and Daniel Drake.
2011-12-15 02:53:48 +01:00
|
|
|
if event.mode == Gdk.CrossingMode.NORMAL:
|
|
|
|
self.notify_mouse_leave()
|
2009-08-01 16:15:01 +02:00
|
|
|
|
2012-11-01 13:35:16 +01:00
|
|
|
def __touch_event_cb(self, button, event):
|
|
|
|
if event.type == Gdk.EventType.TOUCH_END:
|
|
|
|
if self._long_pressed_recognized:
|
|
|
|
self._long_pressed_recognized = False
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def __click_event_cb(self, button):
|
2012-12-20 14:27:38 +01:00
|
|
|
event = Gtk.get_current_event()
|
|
|
|
if not event:
|
|
|
|
# not an event from a user interaction, this can be when
|
|
|
|
# the clicked event is emitted on a 'active' property
|
|
|
|
# change of ToggleToolButton for example
|
|
|
|
return
|
|
|
|
if event and button != Gtk.get_event_widget(event):
|
|
|
|
# another special case for the ToggleToolButton: this handles
|
|
|
|
# the case where we select an item and the active property
|
|
|
|
# of the other one changes to 'False'
|
|
|
|
return
|
|
|
|
|
2012-11-23 10:26:51 +01:00
|
|
|
if self.props.lock_palette and not self.locked:
|
|
|
|
self.locked = True
|
|
|
|
if hasattr(self.parent, 'set_expanded'):
|
2012-11-15 18:09:00 +01:00
|
|
|
self.parent.set_expanded(True)
|
|
|
|
|
2012-11-01 13:35:16 +01:00
|
|
|
if self.props.toggle_palette:
|
|
|
|
self.notify_toggle_state()
|
|
|
|
|
2009-08-01 16:15:01 +02:00
|
|
|
def __button_release_event_cb(self, widget, event):
|
2012-11-01 13:35:16 +01:00
|
|
|
if event.button == 1 and not self._click_hid:
|
2012-11-23 10:26:51 +01:00
|
|
|
if self.props.lock_palette and not self.locked:
|
|
|
|
self.locked = True
|
|
|
|
if hasattr(self.parent, 'set_expanded'):
|
|
|
|
self.parent.set_expanded(True)
|
|
|
|
|
2012-10-22 18:42:30 +02:00
|
|
|
if self.props.toggle_palette:
|
|
|
|
self.notify_toggle_state()
|
|
|
|
elif event.button == 3:
|
2009-08-01 16:15:01 +02:00
|
|
|
self.notify_right_click()
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
2012-11-01 13:35:16 +01:00
|
|
|
def __long_pressed_event_cb(self, controller, x, y, widget):
|
|
|
|
self._long_pressed_recognized = True
|
|
|
|
self.notify_right_click()
|
|
|
|
|
2009-08-01 16:15:01 +02:00
|
|
|
def get_toplevel(self):
|
|
|
|
return self._widget.get_toplevel()
|
|
|
|
|
|
|
|
def notify_popup(self):
|
|
|
|
Invoker.notify_popup(self)
|
|
|
|
self._widget.queue_draw()
|
|
|
|
|
|
|
|
def notify_popdown(self):
|
2012-11-15 18:09:00 +01:00
|
|
|
self.locked = False
|
2009-08-01 16:15:01 +02:00
|
|
|
Invoker.notify_popdown(self)
|
|
|
|
self._widget.queue_draw()
|
|
|
|
|
|
|
|
def _get_widget(self):
|
|
|
|
return self._widget
|
2011-11-15 19:29:07 +01:00
|
|
|
widget = GObject.property(type=object, getter=_get_widget, setter=None)
|
2009-08-01 16:15:01 +02:00
|
|
|
|
2012-11-15 18:09:00 +01:00
|
|
|
def __drawing_cb(self, widget, cr):
|
|
|
|
if not self.props.lock_palette:
|
|
|
|
return False
|
|
|
|
alloc = widget.get_allocation()
|
|
|
|
arrow_size = style.TOOLBAR_ARROW_SIZE / 2
|
|
|
|
y = alloc.height - arrow_size
|
|
|
|
x = (alloc.width - arrow_size) / 2
|
|
|
|
context = widget.get_style_context()
|
|
|
|
context.add_class('toolitem')
|
|
|
|
if self.locked:
|
|
|
|
Gtk.render_arrow(context, cr, 0, x, y, arrow_size)
|
|
|
|
else:
|
|
|
|
Gtk.render_arrow(context, cr, math.pi, x, y, arrow_size)
|
|
|
|
|
2009-08-25 21:12:40 +02:00
|
|
|
|
2011-12-15 00:47:11 +01:00
|
|
|
class CursorInvoker(Invoker):
|
|
|
|
|
|
|
|
def __init__(self, parent=None):
|
|
|
|
Invoker.__init__(self)
|
|
|
|
|
|
|
|
self._position_hint = self.AT_CURSOR
|
|
|
|
self._enter_hid = None
|
|
|
|
self._leave_hid = None
|
|
|
|
self._release_hid = None
|
|
|
|
self._item = None
|
2012-10-25 11:42:00 +02:00
|
|
|
self._long_pressed_recognized = False
|
|
|
|
self._long_pressed_hid = None
|
|
|
|
self._long_pressed_controller = SugarGestures.LongPressController()
|
2011-12-15 00:47:11 +01:00
|
|
|
|
|
|
|
if parent:
|
|
|
|
self.attach(parent)
|
|
|
|
|
|
|
|
def attach(self, parent):
|
|
|
|
Invoker.attach(self, parent)
|
|
|
|
|
|
|
|
self._item = parent
|
|
|
|
self._enter_hid = self._item.connect('enter-notify-event',
|
|
|
|
self.__enter_notify_event_cb)
|
|
|
|
self._leave_hid = self._item.connect('leave-notify-event',
|
|
|
|
self.__leave_notify_event_cb)
|
|
|
|
self._release_hid = self._item.connect('button-release-event',
|
|
|
|
self.__button_release_event_cb)
|
2013-05-18 04:27:04 +02:00
|
|
|
self._long_pressed_hid = self._long_pressed_controller.connect(
|
|
|
|
'pressed',
|
|
|
|
self.__long_pressed_event_cb, self._item)
|
|
|
|
self._long_pressed_controller.attach(
|
|
|
|
self._item,
|
|
|
|
SugarGestures.EventControllerFlags.NONE)
|
2011-12-15 00:47:11 +01:00
|
|
|
|
|
|
|
def detach(self):
|
|
|
|
Invoker.detach(self)
|
|
|
|
self._item.disconnect(self._enter_hid)
|
|
|
|
self._item.disconnect(self._leave_hid)
|
|
|
|
self._item.disconnect(self._release_hid)
|
2012-10-25 11:42:00 +02:00
|
|
|
self._long_pressed_controller.detach(self._item)
|
|
|
|
self._long_pressed_controller.disconnect(self._long_pressed_hid)
|
2011-12-15 00:47:11 +01:00
|
|
|
|
|
|
|
def get_default_position(self):
|
|
|
|
return self.AT_CURSOR
|
|
|
|
|
|
|
|
def get_rect(self):
|
|
|
|
window = self._item.get_window()
|
|
|
|
allocation = self._item.get_allocation()
|
|
|
|
rect = Gdk.Rectangle()
|
|
|
|
rect.x, rect.y = window.get_root_coords(allocation.x, allocation.y)
|
|
|
|
rect.width = allocation.width
|
|
|
|
rect.height = allocation.height
|
|
|
|
return rect
|
|
|
|
|
|
|
|
def __enter_notify_event_cb(self, button, event):
|
2012-10-25 11:42:00 +02:00
|
|
|
if event.mode == Gdk.CrossingMode.NORMAL:
|
|
|
|
self.notify_mouse_enter()
|
2011-12-15 00:47:11 +01:00
|
|
|
return False
|
|
|
|
|
|
|
|
def __leave_notify_event_cb(self, button, event):
|
2012-09-02 13:17:32 +02:00
|
|
|
if event.mode == Gdk.CrossingMode.NORMAL:
|
|
|
|
self.notify_mouse_leave()
|
2011-12-15 00:47:11 +01:00
|
|
|
return False
|
|
|
|
|
|
|
|
def __button_release_event_cb(self, button, event):
|
2015-07-24 17:00:02 +02:00
|
|
|
# check if the release is done outside of the parent widget
|
|
|
|
alloc = self._item.get_allocation()
|
|
|
|
if not (0 < event.x < alloc.width and 0 < event.y < alloc.height):
|
|
|
|
return False
|
|
|
|
|
2012-10-25 11:42:00 +02:00
|
|
|
if self._long_pressed_recognized:
|
|
|
|
self._long_pressed_recognized = False
|
|
|
|
return True
|
2012-10-22 18:42:30 +02:00
|
|
|
if event.button == 1:
|
|
|
|
if self.props.toggle_palette:
|
|
|
|
self.notify_toggle_state()
|
2011-12-15 00:47:11 +01:00
|
|
|
if event.button == 3:
|
|
|
|
self.notify_right_click()
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
2012-10-25 11:42:00 +02:00
|
|
|
def __long_pressed_event_cb(self, controller, x, y, widget):
|
|
|
|
self._long_pressed_recognized = True
|
|
|
|
self.notify_right_click()
|
|
|
|
|
2011-12-15 00:47:11 +01:00
|
|
|
def get_toplevel(self):
|
|
|
|
return self._item.get_toplevel()
|
|
|
|
|
|
|
|
|
2009-08-01 16:15:01 +02:00
|
|
|
class ToolInvoker(WidgetInvoker):
|
2009-08-25 21:12:40 +02:00
|
|
|
|
2009-08-01 16:15:01 +02:00
|
|
|
def __init__(self, parent=None):
|
|
|
|
WidgetInvoker.__init__(self)
|
|
|
|
|
|
|
|
if parent:
|
|
|
|
self.attach_tool(parent)
|
|
|
|
|
|
|
|
def attach_tool(self, widget):
|
2011-11-15 19:29:07 +01:00
|
|
|
self.attach_widget(widget, widget.get_child())
|
2009-08-01 16:15:01 +02:00
|
|
|
|
|
|
|
def _get_alignments(self):
|
|
|
|
parent = self._widget.get_parent()
|
|
|
|
if parent is None:
|
2010-10-15 22:06:25 +02:00
|
|
|
return WidgetInvoker._get_alignments(self)
|
2009-08-01 16:15:01 +02:00
|
|
|
|
2011-11-15 19:29:07 +01:00
|
|
|
if parent.get_orientation() is Gtk.Orientation.HORIZONTAL:
|
2009-08-01 16:15:01 +02:00
|
|
|
return self.BOTTOM + self.TOP
|
|
|
|
else:
|
|
|
|
return self.LEFT + self.RIGHT
|
|
|
|
|
2013-11-29 13:09:53 +01:00
|
|
|
def primary_text_clicked(self):
|
|
|
|
self._widget.emit('clicked')
|
|
|
|
|
2009-08-25 21:12:40 +02:00
|
|
|
|
2014-11-28 12:45:22 +01:00
|
|
|
class TreeViewInvoker(Invoker):
|
|
|
|
def __init__(self):
|
|
|
|
Invoker.__init__(self)
|
|
|
|
|
|
|
|
self._tree_view = None
|
|
|
|
self._motion_hid = None
|
|
|
|
self._leave_hid = None
|
|
|
|
self._release_hid = None
|
|
|
|
self._long_pressed_hid = None
|
|
|
|
self._position_hint = self.AT_CURSOR
|
|
|
|
|
|
|
|
self._long_pressed_controller = SugarGestures.LongPressController()
|
|
|
|
|
|
|
|
self._mouse_detector = MouseSpeedDetector(200, 5)
|
|
|
|
|
|
|
|
self._tree_view = None
|
|
|
|
self._path = None
|
|
|
|
self._column = None
|
|
|
|
|
|
|
|
self.palette = None
|
|
|
|
|
|
|
|
def attach_treeview(self, tree_view):
|
|
|
|
self._tree_view = tree_view
|
|
|
|
|
|
|
|
self._motion_hid = tree_view.connect('motion-notify-event',
|
|
|
|
self.__motion_notify_event_cb)
|
|
|
|
self._enter_hid = tree_view.connect('enter-notify-event',
|
|
|
|
self.__enter_notify_event_cb)
|
|
|
|
self._leave_hid = tree_view.connect('leave-notify-event',
|
|
|
|
self.__leave_notify_event_cb)
|
|
|
|
self._release_hid = tree_view.connect('button-release-event',
|
|
|
|
self.__button_release_event_cb)
|
|
|
|
self._long_pressed_hid = self._long_pressed_controller.connect(
|
|
|
|
'pressed', self.__long_pressed_event_cb, tree_view)
|
|
|
|
self._long_pressed_controller.attach(
|
|
|
|
tree_view,
|
|
|
|
SugarGestures.EventControllerFlags.NONE)
|
|
|
|
|
|
|
|
self._mouse_detector.connect('motion-slow', self.__mouse_slow_cb)
|
|
|
|
self._mouse_detector.parent = tree_view
|
|
|
|
Invoker.attach(self, tree_view)
|
|
|
|
|
|
|
|
def detach(self):
|
|
|
|
Invoker.detach(self)
|
|
|
|
self._tree_view.disconnect(self._motion_hid)
|
|
|
|
self._tree_view.disconnect(self._enter_hid)
|
|
|
|
self._tree_view.disconnect(self._leave_hid)
|
|
|
|
self._tree_view.disconnect(self._release_hid)
|
|
|
|
self._long_pressed_controller.detach(self._tree_view)
|
|
|
|
self._long_pressed_controller.disconnect(self._long_pressed_hid)
|
|
|
|
self._mouse_detector.disconnect_by_func(self.__mouse_slow_cb)
|
|
|
|
|
|
|
|
def get_rect(self):
|
|
|
|
return self._tree_view.get_background_area(self._path, self._column)
|
|
|
|
|
|
|
|
def get_toplevel(self):
|
|
|
|
return self._tree_view.get_toplevel()
|
|
|
|
|
|
|
|
def __motion_notify_event_cb(self, widget, event):
|
|
|
|
try:
|
|
|
|
path, column, x_, y_ = self._tree_view.get_path_at_pos(
|
|
|
|
int(event.x), int(event.y))
|
|
|
|
if path != self._path or column != self._column:
|
|
|
|
self._redraw_cell(self._path, self._column)
|
|
|
|
self._redraw_cell(path, column)
|
|
|
|
|
|
|
|
self._path = path
|
|
|
|
self._column = column
|
|
|
|
|
|
|
|
if self.palette is not None:
|
|
|
|
self.palette.popdown(immediate=True)
|
|
|
|
self.palette = None
|
|
|
|
|
|
|
|
self._mouse_detector.start()
|
|
|
|
except TypeError:
|
|
|
|
# tree_view.get_path_at_pos() fail if x,y poition is over
|
|
|
|
# a empty area
|
|
|
|
pass
|
|
|
|
|
|
|
|
def _redraw_cell(self, path, column):
|
|
|
|
area = self._tree_view.get_background_area(path, column)
|
|
|
|
x, y = \
|
|
|
|
self._tree_view.convert_bin_window_to_widget_coords(area.x, area.y)
|
|
|
|
self._tree_view.queue_draw_area(x, y, area.width, area.height)
|
|
|
|
|
|
|
|
def __enter_notify_event_cb(self, widget, event):
|
|
|
|
self._mouse_detector.start()
|
|
|
|
|
|
|
|
def __leave_notify_event_cb(self, widget, event):
|
|
|
|
self._mouse_detector.stop()
|
|
|
|
|
|
|
|
def __button_release_event_cb(self, widget, event):
|
|
|
|
x, y = int(event.x), int(event.y)
|
|
|
|
path, column, cell_x, cell_y = self._tree_view.get_path_at_pos(x, y)
|
|
|
|
self._path = path
|
|
|
|
self._column = column
|
|
|
|
if event.button == 1:
|
|
|
|
# left mouse button
|
|
|
|
if self.palette is not None:
|
|
|
|
self.palette.popdown(immediate=True)
|
|
|
|
# NOTE: we don't use columns with more than one cell
|
|
|
|
cellrenderer = column.get_cells()[0]
|
|
|
|
if cellrenderer is not None and \
|
|
|
|
isinstance(cellrenderer, CellRendererIcon):
|
|
|
|
cellrenderer.emit('clicked', path)
|
|
|
|
# So the treeview receives it and knows a drag isn't going on
|
|
|
|
return False
|
|
|
|
if event.button == 3:
|
|
|
|
# right mouse button
|
|
|
|
self._mouse_detector.stop()
|
|
|
|
self._change_palette()
|
|
|
|
self.notify_right_click()
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
|
|
|
def __long_pressed_event_cb(self, controller, x, y, widget):
|
|
|
|
path, column, x_, y_ = self._tree_view.get_path_at_pos(x, y)
|
|
|
|
self._path = path
|
|
|
|
self._column = column
|
|
|
|
self._change_palette()
|
|
|
|
self.notify_right_click()
|
|
|
|
|
|
|
|
def __mouse_slow_cb(self, widget):
|
|
|
|
self._mouse_detector.stop()
|
|
|
|
self._change_palette()
|
|
|
|
self.emit('mouse-enter')
|
|
|
|
|
|
|
|
def _change_palette(self):
|
|
|
|
if hasattr(self._tree_view, 'create_palette'):
|
|
|
|
self.palette = self._tree_view.create_palette(
|
|
|
|
self._path, self._column)
|
|
|
|
else:
|
|
|
|
self.palette = None
|
|
|
|
|
|
|
|
def notify_popdown(self):
|
|
|
|
Invoker.notify_popdown(self)
|
|
|
|
self.palette = None
|