More palette positioning improvements.
This commit is contained in:
		
							parent
							
								
									bd9bd2d020
								
							
						
					
					
						commit
						8a3c2a5843
					
				@ -35,18 +35,12 @@ class FrameWidgetInvoker(WidgetInvoker):
 | 
			
		||||
    def __init__(self, widget):
 | 
			
		||||
        WidgetInvoker.__init__(self, widget)
 | 
			
		||||
 | 
			
		||||
    def get_default_position(self):
 | 
			
		||||
        return Palette.AROUND
 | 
			
		||||
 | 
			
		||||
    def get_screen_area(self):
 | 
			
		||||
        return _get_screen_area()
 | 
			
		||||
        self._position_hint = self.ANCHORED
 | 
			
		||||
        self._screen_area = _get_screen_area()
 | 
			
		||||
 | 
			
		||||
class FrameCanvasInvoker(CanvasInvoker):
 | 
			
		||||
    def __init__(self, item):
 | 
			
		||||
        CanvasInvoker.__init__(self, item)
 | 
			
		||||
 | 
			
		||||
    def get_default_position(self):
 | 
			
		||||
        return Palette.AROUND
 | 
			
		||||
 | 
			
		||||
    def get_screen_area(self):
 | 
			
		||||
        return _get_screen_area()
 | 
			
		||||
        self._position_hint = self.ANCHORED
 | 
			
		||||
        self._screen_area = _get_screen_area()
 | 
			
		||||
 | 
			
		||||
@ -27,16 +27,6 @@ from sugar.graphics import animator
 | 
			
		||||
from sugar.graphics import style
 | 
			
		||||
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
 | 
			
		||||
def _calculate_gap(a, b):
 | 
			
		||||
    # Test for each side if the palette and invoker are
 | 
			
		||||
@ -70,10 +60,6 @@ def _calculate_gap(a, b):
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
class Palette(gtk.Window):
 | 
			
		||||
    DEFAULT   = 0
 | 
			
		||||
    AT_CURSOR = 1
 | 
			
		||||
    AROUND    = 2
 | 
			
		||||
 | 
			
		||||
    PRIMARY = 0
 | 
			
		||||
    SECONDARY = 1
 | 
			
		||||
 | 
			
		||||
@ -102,7 +88,7 @@ class Palette(gtk.Window):
 | 
			
		||||
 | 
			
		||||
        self.palette_state = self.PRIMARY
 | 
			
		||||
 | 
			
		||||
        self._current_alignment = None
 | 
			
		||||
        self._alignment = None
 | 
			
		||||
        self._old_alloc = None
 | 
			
		||||
        self._full_request = [0, 0]
 | 
			
		||||
        self._cursor_x = 0
 | 
			
		||||
@ -110,7 +96,6 @@ class Palette(gtk.Window):
 | 
			
		||||
        self._invoker = None
 | 
			
		||||
        self._group_id = None
 | 
			
		||||
        self._up = False
 | 
			
		||||
        self._position = self.DEFAULT
 | 
			
		||||
        self._palette_popup_sid = None
 | 
			
		||||
 | 
			
		||||
        self._popup_anim = animator.Animator(0.3, 10)
 | 
			
		||||
@ -203,16 +188,12 @@ class Palette(gtk.Window):
 | 
			
		||||
            self._invoker = value
 | 
			
		||||
            self._invoker.connect('mouse-enter', self._invoker_mouse_enter_cb)
 | 
			
		||||
            self._invoker.connect('mouse-leave', self._invoker_mouse_leave_cb)
 | 
			
		||||
        elif pspec.name == 'position':
 | 
			
		||||
            self._position = value
 | 
			
		||||
        else:
 | 
			
		||||
            raise AssertionError
 | 
			
		||||
 | 
			
		||||
    def do_get_property(self, pspec):
 | 
			
		||||
        if pspec.name == 'invoker':
 | 
			
		||||
            return self._invoker
 | 
			
		||||
        elif pspec.name == 'position':
 | 
			
		||||
            return self._position
 | 
			
		||||
        else:
 | 
			
		||||
            raise AssertionError
 | 
			
		||||
 | 
			
		||||
@ -275,52 +256,6 @@ class Palette(gtk.Window):
 | 
			
		||||
        self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
 | 
			
		||||
        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):
 | 
			
		||||
        state = self.palette_state
 | 
			
		||||
 | 
			
		||||
@ -333,60 +268,34 @@ class Palette(gtk.Window):
 | 
			
		||||
 | 
			
		||||
        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):
 | 
			
		||||
        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:
 | 
			
		||||
            position = self._invoker.get_default_position()
 | 
			
		||||
        else:
 | 
			
		||||
            position = self._position
 | 
			
		||||
        rect = self.size_request()
 | 
			
		||||
        position = invoker.get_position_for_alignment(self._alignment, rect)
 | 
			
		||||
        if position is None:
 | 
			
		||||
            position = invoker.get_position(rect)
 | 
			
		||||
 | 
			
		||||
        inv_rect = None
 | 
			
		||||
        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)
 | 
			
		||||
        self.move(position.x, position.y)
 | 
			
		||||
 | 
			
		||||
    def _show(self):
 | 
			
		||||
        if self._up:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        self._update_cursor_position()        
 | 
			
		||||
        self._update_full_request()
 | 
			
		||||
 | 
			
		||||
        self._palette_popup_sid = _palette_observer.connect(
 | 
			
		||||
                                'popup', self._palette_observer_popup_cb)
 | 
			
		||||
 | 
			
		||||
        for align in self._get_around_alignments():
 | 
			
		||||
            rect = self._get_rectangle(align, full=True)
 | 
			
		||||
            if self._in_screen(rect):
 | 
			
		||||
                self._current_alignment = align
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
        if self._invoker is not None:
 | 
			
		||||
            self._update_full_request()
 | 
			
		||||
            self._alignment = self._invoker.get_alignment(self._full_request)
 | 
			
		||||
            self._update_position()
 | 
			
		||||
 | 
			
		||||
        self.menu.set_active(True)
 | 
			
		||||
        self.show()
 | 
			
		||||
 | 
			
		||||
        if self._invoker:
 | 
			
		||||
        self._invoker.notify_popup()
 | 
			
		||||
 | 
			
		||||
        self._up = True
 | 
			
		||||
@ -541,28 +450,109 @@ class Invoker(gobject.GObject):
 | 
			
		||||
        '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):
 | 
			
		||||
        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):
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    def draw_rectangle(self, event, palette):
 | 
			
		||||
        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):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def notify_popdown(self):
 | 
			
		||||
        pass
 | 
			
		||||
        self._cursor_x = -1
 | 
			
		||||
        self._cursor_y = -1
 | 
			
		||||
 | 
			
		||||
class WidgetInvoker(Invoker):
 | 
			
		||||
    def __init__(self, widget):
 | 
			
		||||
@ -617,15 +607,19 @@ class WidgetInvoker(Invoker):
 | 
			
		||||
        return self._widget.get_toplevel()
 | 
			
		||||
 | 
			
		||||
    def notify_popup(self):
 | 
			
		||||
        Invoker.notify_popup(self)
 | 
			
		||||
        self._widget.queue_draw()
 | 
			
		||||
 | 
			
		||||
    def notify_popdown(self):
 | 
			
		||||
        Invoker.notify_popdown(self)
 | 
			
		||||
        self._widget.queue_draw()
 | 
			
		||||
 | 
			
		||||
class CanvasInvoker(Invoker):
 | 
			
		||||
    def __init__(self, item):
 | 
			
		||||
        Invoker.__init__(self)
 | 
			
		||||
 | 
			
		||||
        self._item = item
 | 
			
		||||
        self._position_hint = self.AT_CURSOR
 | 
			
		||||
 | 
			
		||||
        item.connect('motion-notify-event',
 | 
			
		||||
                     self._motion_notify_event_cb)
 | 
			
		||||
@ -644,6 +638,7 @@ class CanvasInvoker(Invoker):
 | 
			
		||||
        
 | 
			
		||||
    def _motion_notify_event_cb(self, button, event):
 | 
			
		||||
        if event.detail == hippo.MOTION_DETAIL_ENTER:
 | 
			
		||||
            context = self._item.get_context()
 | 
			
		||||
            self.emit('mouse-enter')
 | 
			
		||||
        elif event.detail == hippo.MOTION_DETAIL_LEAVE:
 | 
			
		||||
            self.emit('mouse-leave')
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user