dabo Commit
Revision 2252
Date: 2006-07-13 09:41:37 -0700 (Thu, 13 Jul 2006)
Author: ed
Changed:
U trunk/dabo/ui/uiwx/__init__.py
U trunk/dabo/ui/uiwx/dKeys.py
U trunk/dabo/ui/uiwx/dPemMixin.py
U trunk/dabo/ui/uiwx/dSplitter.py
Log:
Added the drawGradient() method. This will draw a gradient that varies between
the two colors specified in either the horizontal or vertical direction,
depending on the orientation of the gradient.
There are still some problems with getting the drawing to stay 'behind' the
other elements, which are sometimes drawn before the gradient, but perhaps some
enterprising soul will figure out how to deal with this. The code to draw the
gradients is taken from Andrea Gavana's FoldPanelBar class, where he uses it to
draw the gradients on the caption bars.
Diff:
Modified: trunk/dabo/ui/uiwx/__init__.py
===================================================================
--- trunk/dabo/ui/uiwx/__init__.py 2006-07-13 03:10:20 UTC (rev 2251)
+++ trunk/dabo/ui/uiwx/__init__.py 2006-07-13 16:41:37 UTC (rev 2252)
@@ -291,7 +291,7 @@
if isinstance(wxEvt, (wx.KeyEvent, wx.MouseEvent, wx.TreeEvent,
wx.CommandEvent, wx.CloseEvent, wx.grid.GridEvent,
- wx.grid.GridSizeEvent) ):
+ wx.grid.GridSizeEvent, wx.SplitterEvent) ):
if dabo.allNativeEventInfo:
# Cycle through all the attributes of the wx events,
and evaluate them
@@ -313,6 +313,12 @@
except:
pass
+ if isinstance(wxEvt, (wx.SplitterEvent,) ):
+ try:
+ ed["mousePosition"] = (wxEvt.GetX(), wxEvt.GetY())
+ except:
+ ed["mousePosition"] = wx.GetMousePosition()
+
if isinstance(wxEvt, (wx.KeyEvent, wx.MouseEvent) ):
ed["mousePosition"] = wxEvt.GetPositionTuple()
ed["altDown"] = wxEvt.AltDown()
@@ -382,6 +388,15 @@
except:
pass
+ if isinstance(wxEvt, wx.SplitterEvent):
+ if hasattr(wxEvt, "GetSashPosition"):
+ ed["sashPosition"] = wxEvt.GetSashPosition()
+ if hasattr(wxEvt, "GetWindowBeingRemoved"):
+ try:
+ ed["windowRemoved"] =
wxEvt.GetWindowBeingRemoved()
+ except:
+ ed["windowRemoved"] = None
+
if hasattr(wxEvt, "GetId"):
ed["id"] = wxEvt.GetId()
Modified: trunk/dabo/ui/uiwx/dKeys.py
===================================================================
--- trunk/dabo/ui/uiwx/dKeys.py 2006-07-13 03:10:20 UTC (rev 2251)
+++ trunk/dabo/ui/uiwx/dKeys.py 2006-07-13 16:41:37 UTC (rev 2252)
@@ -174,4 +174,41 @@
"f12": key_F12,
"numlock": key_Numlock,
"scroll": key_Scroll,
+ "numpad_0": key_Numpad0,
+ "numpad_1": key_Numpad1,
+ "numpad_2": key_Numpad2,
+ "numpad_3": key_Numpad3,
+ "numpad_4": key_Numpad4,
+ "numpad_5": key_Numpad5,
+ "numpad_6": key_Numpad6,
+ "numpad_7": key_Numpad7,
+ "numpad_8": key_Numpad8,
+ "numpad_9": key_Numpad9,
+ "numpad_space": key_Numpad_space,
+ "numpad_tab": key_Numpad_tab,
+ "numpad_enter": key_Numpad_enter,
+ "numpad_f1": key_Numpad_f1,
+ "numpad_f2": key_Numpad_f2,
+ "numpad_f3": key_Numpad_f3,
+ "numpad_f4": key_Numpad_f4,
+ "numpad_home": key_Numpad_home,
+ "numpad_left": key_Numpad_left,
+ "numpad_up": key_Numpad_up,
+ "numpad_right": key_Numpad_right,
+ "numpad_down": key_Numpad_down,
+ "numpad_prior": key_Numpad_prior,
+ "numpad_pageup": key_Numpad_pageup,
+ "numpad_next": key_Numpad_next,
+ "numpad_pagedown": key_Numpad_pagedown,
+ "numpad_end": key_Numpad_end,
+ "numpad_begin": key_Numpad_begin,
+ "numpad_insert": key_Numpad_insert,
+ "numpad_delete": key_Numpad_delete,
+ "numpad_equal": key_Numpad_equal,
+ "numpad_multiply": key_Numpad_multiply,
+ "numpad_add": key_Numpad_add,
+ "numpad_separator": key_Numpad_separator,
+ "numpad_subtract": key_Numpad_subtract,
+ "numpad_decimal": key_Numpad_decimal,
+ "numpad_divide": key_Numpad_divide,
}
Modified: trunk/dabo/ui/uiwx/dPemMixin.py
===================================================================
--- trunk/dabo/ui/uiwx/dPemMixin.py 2006-07-13 03:10:20 UTC (rev 2251)
+++ trunk/dabo/ui/uiwx/dPemMixin.py 2006-07-13 16:41:37 UTC (rev 2252)
@@ -237,7 +237,7 @@
def _preInitUI(self, kwargs):
"""Subclass hook, for internal Dabo use.
- Some wx objects (RadioBox) need certain props forced if they
hadn't been
+ Some wx objects (RadioBox) need certain props forced if they
hadn't been
set by the user either as a parm or in beforeInit().
"""
return kwargs
@@ -670,7 +670,7 @@
This can significantly improve performance when many items are
being
updated at once.
- IMPORTANT: you must call unlockDisplay() when you are done,
or your
+ IMPORTANT: you must call unlockDisplay() when you are done, or
your
object will never draw.
Note that lockDisplay currently doesn't do anything on GTK.
@@ -685,8 +685,8 @@
that would result in lengthy screen updates.
"""
self.Thaw()
-
-
+
+
def addObject(self, classRef, Name=None, *args, **kwargs):
""" Instantiate object as a child of self.
@@ -808,7 +808,7 @@
def getPositionInSizer(self):
""" Returns the current position of this control in its
containing sizer.
- This is useful for when a control needs to be re-created in
place. If the
+ This is useful for when a control needs to be re-created in
place. If the
containing sizer is a box sizer, the integer position will be
returned.
If it is a grid sizer, a row,col tuple will be returned. If the
object is
not contained in a sizer, None will be returned.
@@ -845,8 +845,8 @@
If 'recurse' is True, setAll() will be called on each child as
well.
If 'filt' is not empty, only children that match the expression
in 'filt'
- will be affected. The expression will be evaluated assuming
the child
- object is prefixed to the expression. For example, if you
want to only
+ will be affected. The expression will be evaluated assuming the
child
+ object is prefixed to the expression. For example, if you want
to only
affect objects that are instances of dButton, you'd call:
form.setAll("FontBold", True, filt="BaseClass ==
dabo.ui.dButton")
@@ -931,7 +931,7 @@
def __onUpdate(self, evt):
- """Update any dynamic properties, and then call the refresh()
hook."""
+ """Update any dynamic properties, and then call the refresh()
hook."""
if isinstance(self, dabo.ui.deadObject):
return
self.update()
@@ -1133,9 +1133,23 @@
# Add it to the list of drawing objects
obj = self._addToDrawnObjects(obj, persist)
return obj
+
+
+ def drawGradient(self, orientation, x=0, y=0, width=None, height=None,
+ color1=None, color2=None, persist=True):
+ """Draws a horizontal or vertical gradient on the control.
Default
+ is to cover the entire control, although you can specify
positions.
+ The gradient is drawn with 'color1' as the top/left color, and
'color2'
+ as the bottom/right color.
+ """
+ obj = DrawObject(self, Shape="gradient",
Orientation=orientation,
+ Xpos=x, Ypos=y, Width=width, Height=height,
+ GradientColor1=color1, GradientColor2=color2)
+ # Add it to the list of drawing objects
+ obj = self._addToDrawnObjects(obj, persist)
+ return obj
-
def _addToDrawnObjects(self, obj, persist):
self._drawnObjects.append(obj)
self._redraw()
@@ -2011,7 +2025,7 @@
This property is write-only at runtime.""") )
- Parent = property(_getParent, _setParent, None,
+ Parent = property(_getParent, _setParent, None,
_("The containing object. (obj)") )
Position = property(_getPosition, _setPosition, None,
@@ -2039,8 +2053,8 @@
_("The top position of the object. (int)") )
Visible = property(_getVisible, _setVisible, None,
- _("Specifies whether the object is visible at runtime.
(bool)") )
-
+ _("Specifies whether the object is visible at runtime.
(bool)") )
+
Width = property(_getWidth, _setWidth, None,
_("The width of the object. (int)") )
@@ -2109,6 +2123,9 @@
self._backColor = None
self._text = None
self._angle = 0
+ self._gradientColor1 = None
+ self._gradientColor2 = None
+ self._orientation = None
self._transparent = True
super(DrawObject, self).__init__(*args, **kwargs)
self._inInit = False
@@ -2176,6 +2193,8 @@
x1, y1 = self.Points[0]
x2, y2 = self.Points[1]
dc.DrawLine(x1, y1, x2, y2)
+ elif self.Shape == "gradient":
+ self._drawGradient(dc)
elif self.Shape == "text":
txt = self._text
if not txt:
@@ -2209,6 +2228,63 @@
dc.DrawRotatedText(txt, self.Xpos, self.Ypos,
self._angle)
+ def _drawGradient(self, dc):
+ if self.GradientColor1 is None or self.GradientColor2 is None:
+ return
+ if self.Orientation is None:
+ return
+ if self.Width is None:
+ wd = self.Parent.Width
+ else:
+ wd = self.Width
+ if self.Xpos is None:
+ x1 = 0
+ x2 = wd
+ else:
+ x1 = self.Xpos
+ x2 = x1 + wd
+ if self.Height is None:
+ ht = self.Parent.Height
+ else:
+ ht = self.Height
+ if self.Ypos is None:
+ y1 = 0
+ y2 = ht
+ else:
+ y1 = self.Ypos
+ y2 = y1 + ht
+
+ dc.SetPen(wx.TRANSPARENT_PEN)
+ r1, g1, b1 = self.GradientColor1
+ r2, g2, b2 = self.GradientColor2
+
+ if self.Orientation == "h":
+ flrect = float(wd)
+ else:
+ flrect = float(ht)
+ rstep = float((r2 - r1)) / flrect
+ gstep = float((g2 - g1)) / flrect
+ bstep = float((b2 - b1)) / flrect
+
+ rf, gf, bf = 0, 0, 0
+ if self.Orientation == "h":
+ for x in range(x1, x1 + wd):
+ currRow = (r1 + rf, g1 + gf, b1 + bf)
+ dc.SetBrush(wx.Brush(currRow, wx.SOLID))
+ dc.DrawRectangle(x1 + (x - x1), y1, 1, ht)
+ rf = rf + rstep
+ gf = gf + gstep
+ bf = bf + bstep
+ else:
+ for y in range(y1, y1 + ht):
+ currCol = (r1 + rf, g1 + gf, b1 + bf)
+ dc.SetBrush(wx.Brush(currCol, wx.SOLID))
+ dc.DrawRectangle(x1, y1 + (y - y1), wd, ht)
+ rf = rf + rstep
+ gf = gf + gstep
+ bf = bf + bstep
+
+
def bringToFront(self):
self.Parent._bringDrawObjectToFront(self)
@@ -2316,6 +2392,28 @@
self.update()
+ def _getGradientColor1(self):
+ return self._gradientColor1
+
+ def _setGradientColor1(self, val):
+ if isinstance(val, basestring):
+ val = dColors.colorTupleFromName(val)
+ if self._gradientColor1 != val:
+ self._gradientColor1 = val
+ self.update()
+
+
+ def _getGradientColor2(self):
+ return self._gradientColor2
+
+ def _setGradientColor2(self, val):
+ if isinstance(val, basestring):
+ val = dColors.colorTupleFromName(val)
+ if self._gradientColor2 != val:
+ self._gradientColor2 = val
+ self.update()
+
+
def _getHeight(self):
return self._height
@@ -2336,6 +2434,16 @@
self.update()
+ def _getOrientation(self):
+ return self._orientation
+
+ def _setOrientation(self, val):
+ val = val[0].lower()
+ if self._orientation != val:
+ self._orientation = val
+ self.update()
+
+
def _getParent(self):
return self._parent
@@ -2451,9 +2559,6 @@
FontBold = property(_getFontBold, _setFontBold, None,
_("Bold setting for text objects (bool)"))
- ForeColor = property(_getForeColor, _setForeColor, None,
- _("Color of text when using text objects (str or
tuple)"))
-
FontFace = property(_getFontFace, _setFontFace, None,
_("Face of the font used for text objects (str)"))
@@ -2466,11 +2571,23 @@
FontUnderline = property(_getFontUnderline, _setFontUnderline, None,
_("Underline setting for text objects (bool)"))
+ ForeColor = property(_getForeColor, _setForeColor, None,
+ _("Color of text when using text objects (str or
tuple)"))
+
+ GradientColor1 = property(_getGradientColor1, _setGradientColor1, None,
+ _("Top/Left color for the gradient (color: str or
tuple)"))
+
+ GradientColor2 = property(_getGradientColor2, _setGradientColor2, None,
+ _("Bottom/Right color for the gradient (color: str or
tuple)"))
+
Height = property(_getHeight, _setHeight, None,
_("For rectangles, the height of the shape (int)"))
LineStyle = property(_getLineStyle, _setLineStyle, None,
_("Line style (solid, dash, dot) drawn (str)"))
+
+ Orientation = property(_getOrientation, _setOrientation, None,
+ _("Direction of the drawn gradient ('v' or 'h')
(str)"))
Parent = property(_getParent, _setParent, None,
_("Reference to the object being drawn upon.
(object)"))
Modified: trunk/dabo/ui/uiwx/dSplitter.py
===================================================================
--- trunk/dabo/ui/uiwx/dSplitter.py 2006-07-13 03:10:20 UTC (rev 2251)
+++ trunk/dabo/ui/uiwx/dSplitter.py 2006-07-13 16:41:37 UTC (rev 2252)
@@ -10,15 +10,13 @@
from dabo.ui import makeDynamicProperty
-class SplitterPanel(dabo.ui.dPanel):
- def __init__(self, parent):
- self._showSplitMenu = True
- super(SplitterPanel, self).__init__(parent)
+class SplitterPanelMixin:
+ def __init__(self, *args, **kwargs):
if self.ShowSplitMenu:
- self.bindEvent(dEvents.ContextMenu, self._onContextMenu)
+ self.bindEvent(dEvents.ContextMenu,
self._onMixinContextMenu)
- def _onContextMenu(self, evt):
+ def _onMixinContextMenu(self, evt):
evt.stop()
sm = dabo.ui.dMenu(self)
sm.append("Split this pane", bindfunc=self.onSplit)
@@ -76,7 +74,11 @@
# Property definitions start here
def _getShowSplitMenu(self):
- return self._showSplitMenu
+ try:
+ ret = self._showSplitMenu
+ except AttributeError:
+ ret = self._showSplitMenu = True
+ return ret
def _setShowSplitMenu(self, val):
if self._constructed():
@@ -97,7 +99,7 @@
class dSplitter(wx.SplitterWindow, cm.dControlMixin):
""" Main class for handling split windows. It will contain two
- panels (subclass of SplitterPanel), each of which can further
+ panels (subclass of SplitterPanelMixin), each of which can further
split itself in two.
"""
def __init__(self, parent, properties=None, *args, **kwargs):
@@ -106,13 +108,16 @@
style = self._extractKey((kwargs, properties), "style", 0)
self._createPanes = self._extractKey((kwargs, properties),
"createPanes", False)
self._splitOnInit = self._extractKey((kwargs, properties),
"splitOnInit", True)
+ self._p1 = self._p2 = None
+ # Default to a decent minimum panel size if none is specified
+ mp = self._extractKey((kwargs, properties), "MinimumPanelSize",
20)
+ kwargs["MinimumPanelSize"] = mp
# Default to vertical split
self._orientation = "v"
self._sashPos = 100
- self._minPanelSize = 0
# Default to showing the context menus on the panels
- self._showPanelSplitMenu = None
+ self._showPanelSplitMenu = True
preClass = wx.PreSplitterWindow
cm.dControlMixin.__init__(self, preClass, parent, properties,
@@ -126,8 +131,8 @@
def _afterInit(self):
- self.__p1 = None
- self.__p2 = None
+ self._p1 = None
+ self._p2 = None
# Create the panes
if self._createPanes:
self.createPanes()
@@ -135,10 +140,33 @@
self.split()
super(dSplitter, self)._afterInit()
-
- def createPanes(self):
- self.__p1 = self.PanelClass(self)
- self.__p2 = self.PanelClass(self)
+
+ def _makeSplitterPanelClass(self, cls):
+ # See if the class already is mixed in with the
SplitterPanelMixin
+ if isinstance(cls, SplitterPanelMixin):
+ ret = cls
+ else:
+ class MixedSplitterPanel(cls, SplitterPanelMixin):
+ def __init__(self, parent, *args, **kwargs):
+ cls.__init__(self, parent, *args,
**kwargs)
+ SplitterPanelMixin.__init__(self,
*args, **kwargs)
+ ret = MixedSplitterPanel
+ return ret
+
+
+ def createPanes(self, cls=None, pane=None):
+ if cls is None:
+ cls = self.PanelClass
+ spCls = self._makeSplitterPanelClass(cls)
+ if pane is None:
+ p1 = p2 = True
+ else:
+ p1 = (pane == 1)
+ p2 = (pane == 2)
+ if p1 and self.Panel1 is None:
+ self.Panel1 = spCls(self)
+ if p2 and self.Panel2 is None:
+ self.Panel2 = spCls(self)
if self.IsSplit():
self.unsplit()
self.split()
@@ -165,6 +193,7 @@
def _onSashPos(self, evt):
"""Fires when the sash position is changed."""
+ evt.Skip()
# Update the internal sash position attribute.
self._getSashPosition()
# Raise a dEvent for other code to bind to,
@@ -175,8 +204,8 @@
if self.IsSplit():
return
if self.Panel1 is None or self.Panel2 is None:
- # No panels, so we can't split
- return
+ # No panels, so we can't split! Create them.
+ self.createPanes()
if dir_:
self.Orientation = dir_
@@ -216,9 +245,9 @@
if self.IsSplit():
self.unsplit(pnl)
else:
- # If the parent of this is a SplitterPanel, tell it to
hide
+ # If the parent of this is a SplitterPanelMixin, tell
it to hide
prnt = self.Parent
- if isinstance(prnt, SplitterPanel):
+ if isinstance(prnt, SplitterPanelMixin):
prnt.remove()
else:
self.Destroy()
@@ -252,12 +281,17 @@
if self._constructed():
orient = val.lower()[0]
if orient in ("h", "v"):
- self._orientation = orient
+ self._orientation = {"h": "Horizontal", "v":
"Vertical"}[orient]
if self.IsSplit():
self.lockDisplay()
self.unsplit()
self.split()
self.unlockDisplay()
+ else:
+ self.lockDisplay()
+ self.split()
+ self.unsplit()
+ self.unlockDisplay()
else:
raise ValueError, "Orientation can only be
'Horizontal' or 'Vertical'"
else:
@@ -265,16 +299,17 @@
def _getPanel1(self):
- return self.__p1
+ return self._p1
def _setPanel1(self, pnl):
if self._constructed():
splt = self.IsSplit()
if splt:
- self.unsplit(self.__p1)
- if self.__p1:
- self.__p1.Destroy()
- self.__p1 = pnl
+ self.unsplit(self._p1)
+ if self._p1:
+ self.ReplaceWindow(self._p1, pnl)
+ self._p1.Destroy()
+ self._p1 = pnl
if splt:
self.split()
else:
@@ -282,16 +317,18 @@
def _getPanel2(self):
- return self.__p2
+ return self._p2
def _setPanel2(self, pnl):
if self._constructed():
splt = self.IsSplit()
if splt:
- self.unsplit(self.__p2)
- if self.__p2:
- self.__p2.Destroy()
- self.__p2 = pnl
+ self.unsplit(self._p2)
+ if self._p2:
+ self.split()
+ self.ReplaceWindow(self._p2, pnl)
+ self._p2.Destroy()
+ self._p2 = pnl
if splt:
self.split()
else:
@@ -302,7 +339,7 @@
try:
ret = self._panelClass
except:
- ret = self._panelClass = SplitterPanel
+ ret = self._panelClass = dabo.ui.dPanel
return ret
def _setPanelClass(self, val):
@@ -358,9 +395,11 @@
_("Returns the Bottom/Right panel. (dPanel)"))
PanelClass = property(_getPanelClass, _setPanelClass, None,
- _("""Class used for creating panels. This must be set
before the panels are
- created; setting it afterward has no effect unless you
destroy the panels
- and re-create them. Default=SplitterPanel
(dPanel)"""))
+ _("""Class used for creating panels. If the class does
not descend from
+ SplitterPanelMixin, that class will be mixed-into the
class specified here.
+ This must be set before the panels are created; setting
it afterward has
+ no effect unless you destroy the panels and re-create
them.
+ Default=dPanel (dPanel)"""))
SashPosition = property(_getSashPosition, _setSashPosition, None,
_("Position of the sash when the window is split.
(int)"))
_______________________________________________
Post Messages to: [email protected]
Subscription Maintenance: http://leafe.com/mailman/listinfo/dabo-dev