Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/sugar
diff options
context:
space:
mode:
authorBenjamin Berg <benjamin@sipsolutions.net>2007-08-10 16:29:28 (GMT)
committer Benjamin Berg <benjamin@sipsolutions.net>2007-08-10 16:29:28 (GMT)
commit6573e8c5e6ed9ec8c9e7af10c6ad34acb10bcd67 (patch)
tree8c4df4ab62207e5a4dd075344844a8c1cd89be39 /sugar
parent6aeb95aa467c30c878ba29c66461d9254c7a7392 (diff)
Draw an invoker rectangle that looks connected to the main palette.
There is one catch though, the menu placement inside the palette seems broken. (Probably was already broken before.) Not sure what is going on there.
Diffstat (limited to 'sugar')
-rw-r--r--sugar/graphics/palette.py119
-rw-r--r--sugar/graphics/radiotoolbutton.py18
-rw-r--r--sugar/graphics/toggletoolbutton.py18
-rw-r--r--sugar/graphics/toolbutton.py17
4 files changed, 171 insertions, 1 deletions
diff --git a/sugar/graphics/palette.py b/sugar/graphics/palette.py
index e853202..b251ca7 100644
--- a/sugar/graphics/palette.py
+++ b/sugar/graphics/palette.py
@@ -36,6 +36,39 @@ _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
+ # adjacent to each other.
+ gap = True
+
+ if a.y + a.height == b.y:
+ gap_side = gtk.POS_BOTTOM
+ elif a.x + a.width == b.x:
+ gap_side = gtk.POS_RIGHT
+ elif a.x == b.x + b.width:
+ gap_side = gtk.POS_LEFT
+ elif a.y == b.y + b.height:
+ gap_side = gtk.POS_TOP
+ else:
+ gap = False
+
+ if gap:
+ if gap_side == gtk.POS_BOTTOM or gap_side == gtk.POS_TOP:
+ gap_start = min(a.width, max(0, b.x - b.x))
+ gap_size = max(0, min(a.width,
+ (b.x + b.width) - a.x) - gap_start)
+ elif gap_side == gtk.POS_RIGHT or gap_side == gtk.POS_LEFT:
+ 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
+
class Palette(gtk.Window):
DEFAULT = 0
AT_CURSOR = 1
@@ -54,7 +87,9 @@ class Palette(gtk.Window):
'invoker' : (object, None, None,
gobject.PARAM_READWRITE),
'position' : (gobject.TYPE_INT, None, None, 0, 6,
- 0, gobject.PARAM_READWRITE)
+ 0, gobject.PARAM_READWRITE),
+ 'draw-gap' : (bool, None, None, False,
+ gobject.PARAM_READWRITE)
}
__gsignals__ = {
@@ -79,6 +114,7 @@ class Palette(gtk.Window):
self._group_id = None
self._up = False
self._position = self.DEFAULT
+ self._draw_gap = False
self._palette_popup_sid = None
self._popup_anim = animator.Animator(0.3, 10)
@@ -131,6 +167,17 @@ class Palette(gtk.Window):
def is_up(self):
return self._up
+ def get_rect(self):
+ win_x, win_y = self.window.get_origin()
+ rectangle = self.get_allocation()
+
+ x = win_x + rectangle.x
+ y = win_y + rectangle.y
+ width = rectangle.width
+ height = rectangle.height
+
+ return gtk.gdk.Rectangle(x, y, width, height)
+
def set_primary_text(self, label, accel_path=None):
self._label.set_text(label)
self._label.show()
@@ -160,6 +207,9 @@ class Palette(gtk.Window):
self._invoker.connect('mouse-leave', self._invoker_mouse_leave_cb)
elif pspec.name == 'position':
self._position = value
+ elif pspec.name == 'draw-gap':
+ self._draw_gap = value
+ self.queue_draw()
else:
raise AssertionError
@@ -168,9 +218,39 @@ class Palette(gtk.Window):
return self._invoker
elif pspec.name == 'position':
return self._position
+ elif pspec.name == 'draw-gap':
+ return self._draw_gap
else:
raise AssertionError
+ def do_expose_event(self, event):
+ # We want to draw a border with a beautiful gap
+ if self._draw_gap:
+ invoker = self._invoker.get_rect()
+ palette = self.get_rect()
+
+ gap = _calculate_gap(palette, invoker)
+ else:
+ gap = False
+
+ if gap:
+ self.style.paint_box_gap(event.window, gtk.STATE_PRELIGHT,
+ gtk.SHADOW_IN, event.area, self, "palette",
+ 0, 0,
+ self.allocation.width,
+ self.allocation.height,
+ gap[0], gap[1], gap[2])
+ else:
+ self.style.paint_box(event.window, gtk.STATE_PRELIGHT,
+ gtk.SHADOW_IN, event.area, self, "palette",
+ 0, 0,
+ self.allocation.width,
+ self.allocation.height)
+
+ # Fall trough to the container expose handler.
+ # (Leaving out the window expose handler which redraws everything)
+ gtk.Bin.do_expose_event(self, event)
+
def _update_separator(self):
visible = len(self.menu.get_children()) > 0 or \
len(self._content.get_children()) > 0
@@ -396,6 +476,12 @@ class _Menu(_sugaruiext.Menu):
_sugaruiext.Menu.do_insert(self, item, position)
self._palette._update_separator()
+ def do_expose_event(self, event):
+ # Ignore the Menu expose, just do the MenuShell expose to prevent any
+ # border from being drawn here. A border is drawn by the palette object
+ # around everything.
+ gtk.MenuShell.do_expose_event(self, event)
+
def do_deactivate(self):
self._palette._hide()
@@ -467,6 +553,37 @@ class WidgetInvoker(Invoker):
return gtk.gdk.Rectangle(x, y, width, height)
+ def draw_invoker_rect(self, event, palette):
+ style = self._widget.style
+ if palette.is_up():
+ gap = _calculate_gap(self.get_rect(), palette.get_rect())
+
+ if gap:
+ style.paint_box_gap(event.window, gtk.STATE_PRELIGHT,
+ gtk.SHADOW_IN, event.area, self._widget,
+ "palette-invoker",
+ self._widget.allocation.x,
+ self._widget.allocation.y,
+ self._widget.allocation.width,
+ self._widget.allocation.height,
+ gap[0], gap[1], gap[2])
+ else:
+ style.paint_box(event.window, gtk.STATE_PRELIGHT,
+ gtk.SHADOW_IN, event.area, self._widget,
+ "palette-invoker",
+ self._widget.allocation.x,
+ self._widget.allocation.y,
+ self._widget.allocation.width,
+ self._widget.allocation.height)
+ else:
+ style.paint_box(event.window, gtk.STATE_PRELIGHT,
+ gtk.SHADOW_NONE, event.area, self._widget,
+ "palette-invoker",
+ self._widget.allocation.x,
+ self._widget.allocation.y,
+ self._widget.allocation.width,
+ self._widget.allocation.height)
+
def _enter_notify_event_cb(self, widget, event):
self.emit('mouse-enter')
diff --git a/sugar/graphics/radiotoolbutton.py b/sugar/graphics/radiotoolbutton.py
index 94ff6ba..52fe61c 100644
--- a/sugar/graphics/radiotoolbutton.py
+++ b/sugar/graphics/radiotoolbutton.py
@@ -22,6 +22,8 @@ from sugar.graphics.icon import Icon
from sugar.graphics.palette import Palette, WidgetInvoker
class RadioToolButton(gtk.RadioToolButton):
+ __gtype_name__ = "SugarRadioToolButton"
+
def __init__(self, named_icon=None, group=None):
gtk.RadioToolButton.__init__(self, group=group)
self._palette = None
@@ -38,9 +40,25 @@ class RadioToolButton(gtk.RadioToolButton):
def set_palette(self, palette):
self._palette = palette
self._palette.props.invoker = WidgetInvoker(self.child)
+ self._palette.props.draw_gap = True
+
+ self._palette.connect("popup", self._palette_changed)
+ self._palette.connect("popdown", self._palette_changed)
def set_tooltip(self, text):
self._palette = Palette(text)
self._palette.props.invoker = WidgetInvoker(self.child)
+
+ def do_expose_event(self, event):
+ if self._palette:
+ if self._palette.is_up() or self.child.state == gtk.STATE_PRELIGHT:
+ invoker = self._palette.props.invoker
+ invoker.draw_invoker_rect(event, self._palette)
+
+ gtk.RadioToolButton.do_expose_event(self, event)
+
+ def _palette_changed(self, palette):
+ # Force a redraw to update the invoker rectangle
+ self.queue_draw()
palette = property(get_palette, set_palette)
diff --git a/sugar/graphics/toggletoolbutton.py b/sugar/graphics/toggletoolbutton.py
index 3684e9c..975e78a 100644
--- a/sugar/graphics/toggletoolbutton.py
+++ b/sugar/graphics/toggletoolbutton.py
@@ -21,6 +21,8 @@ from sugar.graphics.icon import Icon
from sugar.graphics.palette import Palette, WidgetInvoker
class ToggleToolButton(gtk.ToggleToolButton):
+ __gtype_name__ = "SugarToggleToolButton"
+
def __init__(self, named_icon=None):
gtk.ToggleToolButton.__init__(self)
self._palette = None
@@ -37,9 +39,25 @@ class ToggleToolButton(gtk.ToggleToolButton):
def set_palette(self, palette):
self._palette = palette
self._palette.props.invoker = WidgetInvoker(self.child)
+ self._palette.props.draw_gap = True
+
+ self._palette.connect("popup", self._palette_changed)
+ self._palette.connect("popdown", self._palette_changed)
def set_tooltip(self, text):
self._palette = Palette(text)
self._palette.props.invoker = WidgetInvoker(self.child)
+ def do_expose_event(self, event):
+ if self._palette:
+ if self._palette.is_up() or self.child.state == gtk.STATE_PRELIGHT:
+ invoker = self._palette.props.invoker
+ invoker.draw_invoker_rect(event, self._palette)
+
+ gtk.ToggleToolButton.do_expose_event(self, event)
+
+ def _palette_changed(self, palette):
+ # Force a redraw to update the invoker rectangle
+ self.queue_draw()
+
palette = property(get_palette, set_palette)
diff --git a/sugar/graphics/toolbutton.py b/sugar/graphics/toolbutton.py
index e5d90ab..c447b3c 100644
--- a/sugar/graphics/toolbutton.py
+++ b/sugar/graphics/toolbutton.py
@@ -23,6 +23,7 @@ from sugar.graphics.icon import Icon
from sugar.graphics.palette import Palette, WidgetInvoker
class ToolButton(gtk.ToolButton):
+ __gtype_name__ = "SugarToolButton"
def __init__(self, icon_name=None):
gtk.ToolButton.__init__(self)
@@ -41,12 +42,28 @@ class ToolButton(gtk.ToolButton):
def set_palette(self, palette):
self._palette = palette
self._palette.props.invoker = WidgetInvoker(self.child)
+ self._palette.props.draw_gap = True
+
+ self._palette.connect("popup", self._palette_changed)
+ self._palette.connect("popdown", self._palette_changed)
def set_tooltip(self, text):
self.set_palette(Palette(text))
+ def do_expose_event(self, event):
+ if self._palette:
+ if self._palette.is_up() or self.child.state == gtk.STATE_PRELIGHT:
+ invoker = self._palette.props.invoker
+ invoker.draw_invoker_rect(event, self._palette)
+
+ gtk.ToolButton.do_expose_event(self, event)
+
def _button_clicked_cb(self, widget):
if self._palette:
self._palette.popdown(True)
+ def _palette_changed(self, palette):
+ # Force a redraw to update the invoker rectangle
+ self.queue_draw()
+
palette = property(get_palette, set_palette)