More palette positioning improvements.

This commit is contained in:
Marco Pesenti Gritti 2007-09-01 11:59:16 +02:00
parent bd9bd2d020
commit 8a3c2a5843
2 changed files with 114 additions and 125 deletions

View File

@ -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()

View File

@ -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,60 +268,34 @@ 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
break
self._update_position() 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
@ -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')