More palette positioning improvements.
This commit is contained in:
parent
bd9bd2d020
commit
8a3c2a5843
@ -35,18 +35,12 @@ class FrameWidgetInvoker(WidgetInvoker):
|
|||||||
def __init__(self, widget):
|
def __init__(self, widget):
|
||||||
WidgetInvoker.__init__(self, widget)
|
WidgetInvoker.__init__(self, widget)
|
||||||
|
|
||||||
def get_default_position(self):
|
self._position_hint = self.ANCHORED
|
||||||
return Palette.AROUND
|
self._screen_area = _get_screen_area()
|
||||||
|
|
||||||
def get_screen_area(self):
|
|
||||||
return _get_screen_area()
|
|
||||||
|
|
||||||
class FrameCanvasInvoker(CanvasInvoker):
|
class FrameCanvasInvoker(CanvasInvoker):
|
||||||
def __init__(self, item):
|
def __init__(self, item):
|
||||||
CanvasInvoker.__init__(self, item)
|
CanvasInvoker.__init__(self, item)
|
||||||
|
|
||||||
def get_default_position(self):
|
self._position_hint = self.ANCHORED
|
||||||
return Palette.AROUND
|
self._screen_area = _get_screen_area()
|
||||||
|
|
||||||
def get_screen_area(self):
|
|
||||||
return _get_screen_area()
|
|
||||||
|
@ -27,16 +27,6 @@ from sugar.graphics import animator
|
|||||||
from sugar.graphics import style
|
from sugar.graphics import style
|
||||||
from sugar import _sugaruiext
|
from sugar import _sugaruiext
|
||||||
|
|
||||||
_BOTTOM_LEFT = 0
|
|
||||||
_BOTTOM_RIGHT = 1
|
|
||||||
_LEFT_BOTTOM = 2
|
|
||||||
_LEFT_TOP = 3
|
|
||||||
_RIGHT_BOTTOM = 4
|
|
||||||
_RIGHT_TOP = 5
|
|
||||||
_TOP_LEFT = 6
|
|
||||||
_TOP_RIGHT = 7
|
|
||||||
|
|
||||||
|
|
||||||
# Helper function to find the gap position and size of widget a
|
# Helper function to find the gap position and size of widget a
|
||||||
def _calculate_gap(a, b):
|
def _calculate_gap(a, b):
|
||||||
# Test for each side if the palette and invoker are
|
# Test for each side if the palette and invoker are
|
||||||
@ -70,10 +60,6 @@ def _calculate_gap(a, b):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
class Palette(gtk.Window):
|
class Palette(gtk.Window):
|
||||||
DEFAULT = 0
|
|
||||||
AT_CURSOR = 1
|
|
||||||
AROUND = 2
|
|
||||||
|
|
||||||
PRIMARY = 0
|
PRIMARY = 0
|
||||||
SECONDARY = 1
|
SECONDARY = 1
|
||||||
|
|
||||||
@ -102,7 +88,7 @@ class Palette(gtk.Window):
|
|||||||
|
|
||||||
self.palette_state = self.PRIMARY
|
self.palette_state = self.PRIMARY
|
||||||
|
|
||||||
self._current_alignment = None
|
self._alignment = None
|
||||||
self._old_alloc = None
|
self._old_alloc = None
|
||||||
self._full_request = [0, 0]
|
self._full_request = [0, 0]
|
||||||
self._cursor_x = 0
|
self._cursor_x = 0
|
||||||
@ -110,7 +96,6 @@ class Palette(gtk.Window):
|
|||||||
self._invoker = None
|
self._invoker = None
|
||||||
self._group_id = None
|
self._group_id = None
|
||||||
self._up = False
|
self._up = False
|
||||||
self._position = self.DEFAULT
|
|
||||||
self._palette_popup_sid = None
|
self._palette_popup_sid = None
|
||||||
|
|
||||||
self._popup_anim = animator.Animator(0.3, 10)
|
self._popup_anim = animator.Animator(0.3, 10)
|
||||||
@ -203,16 +188,12 @@ class Palette(gtk.Window):
|
|||||||
self._invoker = value
|
self._invoker = value
|
||||||
self._invoker.connect('mouse-enter', self._invoker_mouse_enter_cb)
|
self._invoker.connect('mouse-enter', self._invoker_mouse_enter_cb)
|
||||||
self._invoker.connect('mouse-leave', self._invoker_mouse_leave_cb)
|
self._invoker.connect('mouse-leave', self._invoker_mouse_leave_cb)
|
||||||
elif pspec.name == 'position':
|
|
||||||
self._position = value
|
|
||||||
else:
|
else:
|
||||||
raise AssertionError
|
raise AssertionError
|
||||||
|
|
||||||
def do_get_property(self, pspec):
|
def do_get_property(self, pspec):
|
||||||
if pspec.name == 'invoker':
|
if pspec.name == 'invoker':
|
||||||
return self._invoker
|
return self._invoker
|
||||||
elif pspec.name == 'position':
|
|
||||||
return self._position
|
|
||||||
else:
|
else:
|
||||||
raise AssertionError
|
raise AssertionError
|
||||||
|
|
||||||
@ -275,52 +256,6 @@ class Palette(gtk.Window):
|
|||||||
self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
|
self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
|
||||||
self._update_accept_focus()
|
self._update_accept_focus()
|
||||||
|
|
||||||
def _in_screen(self, rect):
|
|
||||||
screen_area = self._invoker.get_screen_area()
|
|
||||||
return rect.x >= screen_area.x and \
|
|
||||||
rect.y >= screen_area.y and \
|
|
||||||
rect.x + rect.width <= screen_area.width and \
|
|
||||||
rect.y + rect.height <= screen_area.height
|
|
||||||
|
|
||||||
def _get_rectangle(self, alignments, full=False, inv_rect=None):
|
|
||||||
palette_halign = alignments[0]
|
|
||||||
palette_valign = alignments[1]
|
|
||||||
invoker_halign = alignments[2]
|
|
||||||
invoker_valign = alignments[3]
|
|
||||||
|
|
||||||
if inv_rect == None:
|
|
||||||
inv_rect = self._invoker.get_rect()
|
|
||||||
|
|
||||||
if full:
|
|
||||||
palette_width, palette_height = self._full_request
|
|
||||||
else:
|
|
||||||
palette_width, palette_height = self.size_request()
|
|
||||||
|
|
||||||
x = inv_rect.x + inv_rect.width * invoker_halign + \
|
|
||||||
palette_width * palette_halign
|
|
||||||
|
|
||||||
y = inv_rect.y + inv_rect.height * invoker_valign + \
|
|
||||||
palette_height * palette_valign
|
|
||||||
|
|
||||||
return gtk.gdk.Rectangle(int(x), int(y),
|
|
||||||
palette_width, palette_height)
|
|
||||||
|
|
||||||
def _get_around_alignments(self):
|
|
||||||
return [(0.0, 0.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, 1.0, 1.0),
|
|
||||||
(0.0, -1.0, 0.0, 0.0),
|
|
||||||
(-1.0, -1.0, 1.0, 0.0),
|
|
||||||
(-1.0, 0.0, 0.0, 0.0),
|
|
||||||
(-1.0, -1.0, 0.0, 1.0)]
|
|
||||||
|
|
||||||
def _get_at_cursor_alignments(self, inv_rect=None):
|
|
||||||
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)]
|
|
||||||
|
|
||||||
def _update_full_request(self):
|
def _update_full_request(self):
|
||||||
state = self.palette_state
|
state = self.palette_state
|
||||||
|
|
||||||
@ -333,61 +268,35 @@ class Palette(gtk.Window):
|
|||||||
|
|
||||||
self._set_state(state)
|
self._set_state(state)
|
||||||
|
|
||||||
def _update_cursor_position(self):
|
|
||||||
display = gtk.gdk.display_get_default()
|
|
||||||
screen, x, y, mask = display.get_pointer()
|
|
||||||
self._cursor_x = x
|
|
||||||
self._cursor_y = y
|
|
||||||
|
|
||||||
def _update_position(self):
|
def _update_position(self):
|
||||||
x = y = 0
|
invoker = self._invoker
|
||||||
|
if invoker is None or self._alignment is None:
|
||||||
|
logging.error('Cannot update the palette position.')
|
||||||
|
return
|
||||||
|
|
||||||
if self._position == self.DEFAULT:
|
rect = self.size_request()
|
||||||
position = self._invoker.get_default_position()
|
position = invoker.get_position_for_alignment(self._alignment, rect)
|
||||||
else:
|
if position is None:
|
||||||
position = self._position
|
position = invoker.get_position(rect)
|
||||||
|
|
||||||
inv_rect = None
|
self.move(position.x, position.y)
|
||||||
if position == self.AT_CURSOR:
|
|
||||||
dist = style.PALETTE_CURSOR_DISTANCE
|
|
||||||
inv_rect = gtk.gdk.Rectangle(self._cursor_x - dist,
|
|
||||||
self._cursor_y - dist,
|
|
||||||
dist * 2, dist * 2)
|
|
||||||
|
|
||||||
alignments = self._get_around_alignments()[:]
|
|
||||||
if self._current_alignment is not None:
|
|
||||||
alignments.remove(self._current_alignment)
|
|
||||||
alignments.insert(0, self._current_alignment)
|
|
||||||
|
|
||||||
for align in alignments:
|
|
||||||
rect = self._get_rectangle(align, inv_rect=inv_rect)
|
|
||||||
if self._in_screen(rect):
|
|
||||||
break
|
|
||||||
|
|
||||||
self.move(rect.x, rect.y)
|
|
||||||
|
|
||||||
def _show(self):
|
def _show(self):
|
||||||
if self._up:
|
if self._up:
|
||||||
return
|
return
|
||||||
|
|
||||||
self._update_cursor_position()
|
|
||||||
self._update_full_request()
|
|
||||||
|
|
||||||
self._palette_popup_sid = _palette_observer.connect(
|
self._palette_popup_sid = _palette_observer.connect(
|
||||||
'popup', self._palette_observer_popup_cb)
|
'popup', self._palette_observer_popup_cb)
|
||||||
|
|
||||||
for align in self._get_around_alignments():
|
if self._invoker is not None:
|
||||||
rect = self._get_rectangle(align, full=True)
|
self._update_full_request()
|
||||||
if self._in_screen(rect):
|
self._alignment = self._invoker.get_alignment(self._full_request)
|
||||||
self._current_alignment = align
|
self._update_position()
|
||||||
break
|
|
||||||
|
|
||||||
self._update_position()
|
|
||||||
self.menu.set_active(True)
|
self.menu.set_active(True)
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
if self._invoker:
|
self._invoker.notify_popup()
|
||||||
self._invoker.notify_popup()
|
|
||||||
|
|
||||||
self._up = True
|
self._up = True
|
||||||
_palette_observer.emit('popup', self)
|
_palette_observer.emit('popup', self)
|
||||||
@ -541,28 +450,109 @@ class Invoker(gobject.GObject):
|
|||||||
'focus-out': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([]))
|
'focus-out': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ANCHORED = 0
|
||||||
|
AT_CURSOR = 1
|
||||||
|
|
||||||
|
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)]
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
gobject.GObject.__init__(self)
|
gobject.GObject.__init__(self)
|
||||||
|
|
||||||
|
self._screen_area = gtk.gdk.Rectangle(0, 0, gtk.gdk.screen_width(),
|
||||||
|
gtk.gdk.screen_height())
|
||||||
|
self._alignments = self.BOTTOM + self.RIGHT + self.TOP + self.LEFT
|
||||||
|
self._position_hint = self.ANCHORED
|
||||||
|
self._cursor_x = -1
|
||||||
|
self._cursor_y = -1
|
||||||
|
|
||||||
|
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:
|
||||||
|
display = gtk.gdk.display_get_default()
|
||||||
|
screen, x, y, mask = display.get_pointer()
|
||||||
|
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
|
||||||
|
rect = gtk.gdk.Rectangle(self._cursor_x - dist,
|
||||||
|
self._cursor_y - dist,
|
||||||
|
dist * 2, dist * 2)
|
||||||
|
|
||||||
|
palette_width, palette_height = palette_dim
|
||||||
|
|
||||||
|
x = rect.x + rect.width * invoker_halign + \
|
||||||
|
palette_width * palette_halign
|
||||||
|
|
||||||
|
y = rect.y + rect.height * invoker_valign + \
|
||||||
|
palette_height * palette_valign
|
||||||
|
|
||||||
|
return gtk.gdk.Rectangle(int(x), int(y),
|
||||||
|
palette_width, palette_height)
|
||||||
|
|
||||||
|
def _in_screen(self, rect):
|
||||||
|
return rect.x >= self._screen_area.x and \
|
||||||
|
rect.y >= self._screen_area.y and \
|
||||||
|
rect.x + rect.width <= self._screen_area.width and \
|
||||||
|
rect.y + rect.height <= self._screen_area.height
|
||||||
|
|
||||||
|
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._alignments
|
||||||
|
|
||||||
|
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):
|
||||||
|
for alignment in self._get_alignments():
|
||||||
|
rect = self._get_position_for_alignment(alignment, palette_dim)
|
||||||
|
if self._in_screen(rect):
|
||||||
|
break
|
||||||
|
|
||||||
|
return rect
|
||||||
|
|
||||||
|
def get_alignment(self, palette_dim):
|
||||||
|
for alignment in self._get_alignments():
|
||||||
|
rect = self._get_position_for_alignment(alignment, palette_dim)
|
||||||
|
if self._in_screen(rect):
|
||||||
|
break
|
||||||
|
|
||||||
|
return alignment
|
||||||
|
|
||||||
def has_rectangle_gap(self):
|
def has_rectangle_gap(self):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def draw_rectangle(self, event, palette):
|
def draw_rectangle(self, event, palette):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_default_position(self):
|
|
||||||
return Palette.AROUND
|
|
||||||
|
|
||||||
def get_screen_area(self):
|
|
||||||
width = gtk.gdk.screen_width()
|
|
||||||
height = gtk.gdk.screen_height()
|
|
||||||
return gtk.gdk.Rectangle(0, 0, width, height)
|
|
||||||
|
|
||||||
def notify_popup(self):
|
def notify_popup(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def notify_popdown(self):
|
def notify_popdown(self):
|
||||||
pass
|
self._cursor_x = -1
|
||||||
|
self._cursor_y = -1
|
||||||
|
|
||||||
class WidgetInvoker(Invoker):
|
class WidgetInvoker(Invoker):
|
||||||
def __init__(self, widget):
|
def __init__(self, widget):
|
||||||
@ -617,15 +607,19 @@ class WidgetInvoker(Invoker):
|
|||||||
return self._widget.get_toplevel()
|
return self._widget.get_toplevel()
|
||||||
|
|
||||||
def notify_popup(self):
|
def notify_popup(self):
|
||||||
|
Invoker.notify_popup(self)
|
||||||
self._widget.queue_draw()
|
self._widget.queue_draw()
|
||||||
|
|
||||||
def notify_popdown(self):
|
def notify_popdown(self):
|
||||||
|
Invoker.notify_popdown(self)
|
||||||
self._widget.queue_draw()
|
self._widget.queue_draw()
|
||||||
|
|
||||||
class CanvasInvoker(Invoker):
|
class CanvasInvoker(Invoker):
|
||||||
def __init__(self, item):
|
def __init__(self, item):
|
||||||
Invoker.__init__(self)
|
Invoker.__init__(self)
|
||||||
|
|
||||||
self._item = item
|
self._item = item
|
||||||
|
self._position_hint = self.AT_CURSOR
|
||||||
|
|
||||||
item.connect('motion-notify-event',
|
item.connect('motion-notify-event',
|
||||||
self._motion_notify_event_cb)
|
self._motion_notify_event_cb)
|
||||||
@ -644,6 +638,7 @@ class CanvasInvoker(Invoker):
|
|||||||
|
|
||||||
def _motion_notify_event_cb(self, button, event):
|
def _motion_notify_event_cb(self, button, event):
|
||||||
if event.detail == hippo.MOTION_DETAIL_ENTER:
|
if event.detail == hippo.MOTION_DETAIL_ENTER:
|
||||||
|
context = self._item.get_context()
|
||||||
self.emit('mouse-enter')
|
self.emit('mouse-enter')
|
||||||
elif event.detail == hippo.MOTION_DETAIL_LEAVE:
|
elif event.detail == hippo.MOTION_DETAIL_LEAVE:
|
||||||
self.emit('mouse-leave')
|
self.emit('mouse-leave')
|
||||||
|
Loading…
Reference in New Issue
Block a user