]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/wx/lib/buttons.py
Using buffered drawing won't let the themed background show through,
[wxWidgets.git] / wxPython / wx / lib / buttons.py
index eaba907b327b3a9101bce787ebc9eb0f0068f20b..ea8fea98b5a49ae875e2ad72c6e694ebac0ed817 100644 (file)
 # Copyright:   (c) 1999 by Total Control Software
 # Licence:     wxWindows license
 #----------------------------------------------------------------------
+# 11/30/2003 - Jeff Grimmett (grimmtooth@softhome.net)
+#
+# o Updated for wx namespace
+# o Tested with updated demo
+# 
 
 """
 This module implements various forms of generic buttons, meaning that
-they are not built on native controls but are self-drawn.
-
-The GenButton is the base.  It acts like a normal button but you
-are able to better control how it looks, bevel width, colours, etc.
-
-GenBitmapButton is a button with one or more bitmaps that show
-the various states the button can be in.
-
-GenToggleButton stays depressed when clicked, until clicked again.
-
-GenBitmapToggleButton the same but with bitmaps.
-
+they are not built on native controls but are self-drawn.  They act
+like normal buttons but you are able to better control how they look,
+bevel width, colours, etc.
 """
 
 import wx
@@ -34,8 +30,9 @@ import imageutils
 #----------------------------------------------------------------------
 
 class GenButtonEvent(wx.PyCommandEvent):
-    def __init__(self, eventType, ID):
-        wx.PyCommandEvent.__init__(self, eventType, ID)
+    """Event sent from the generic buttons when the button is activated. """
+    def __init__(self, eventType, id):
+        wx.PyCommandEvent.__init__(self, eventType, id)
         self.isDown = False
         self.theButton = None
 
@@ -55,28 +52,32 @@ class GenButtonEvent(wx.PyCommandEvent):
 #----------------------------------------------------------------------
 
 class GenButton(wx.PyControl):
+    """A generic button, and base class for the other generic buttons."""
+
     labelDelta = 1
 
-    def __init__(self, parent, ID, label,
+    def __init__(self, parent, id=-1, label='',
                  pos = wx.DefaultPosition, size = wx.DefaultSize,
                  style = 0, validator = wx.DefaultValidator,
                  name = "genbutton"):
-        if style == 0:
-            style = wx.NO_BORDER
-        wx.PyControl.__init__(self, parent, ID, pos, size, style, validator, name)
+        cstyle = style
+        if cstyle == 0:
+            cstyle = wx.BORDER_NONE
+        wx.PyControl.__init__(self, parent, id, pos, size, cstyle, validator, name)
 
         self.up = True
-        self.bezelWidth = 2
         self.hasFocus = False
-        self.useFocusInd = True
+        self.style = style
+        if style & wx.BORDER_NONE:
+            self.bezelWidth = 0
+            self.useFocusInd = False
+        else:
+            self.bezelWidth = 2
+            self.useFocusInd = True
 
         self.SetLabel(label)
-        self.SetPosition(pos)
-        font = parent.GetFont()
-        if not font.Ok():
-            font = wx.SystemSettings.GetSystemFont(wx.SYS_DEFAULT_GUI_FONT)
-        self.SetFont(font)
-        self.SetBestSize(size)
+        self.InheritAttributes()
+        self.SetBestFittingSize(size)
         self.InitColours()
 
         self.Bind(wx.EVT_LEFT_DOWN,        self.OnLeftDown)
@@ -88,7 +89,6 @@ class GenButton(wx.PyControl):
         self.Bind(wx.EVT_KILL_FOCUS,       self.OnLoseFocus)
         self.Bind(wx.EVT_KEY_DOWN,         self.OnKeyDown)
         self.Bind(wx.EVT_KEY_UP,           self.OnKeyUp)
-        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
         self.Bind(wx.EVT_PAINT,            self.OnPaint)
 
 
@@ -98,23 +98,15 @@ class GenButton(wx.PyControl):
         and set a good size.
         """
         if size is None:
-            size = wx.Size(-1,-1)
-        if type(size) == type(()):
-            size = wx.Size(size[0], size[1])
-        size = wx.Size(size.width, size.height)  # make a copy
-
-        best = self.GetBestSize()
-        if size.width == -1:
-            size.width = best.width
-        if size.height == -1:
-            size.height = best.height
-
-        self.SetSize(size)
+            size = wx.DefaultSize            
+        wx.PyControl.SetBestFittingSize(self, size)
 
 
     def DoGetBestSize(self):
-        """Overridden base class virtual.  Determines the best size of the
-        button based on the label and bezel size."""
+        """
+        Overridden base class virtual.  Determines the best size of the
+        button based on the label and bezel size.
+        """
         w, h, useMin = self._GetLabelSize()
         defSize = wx.Button.GetDefaultSize()
         width = 12 + w
@@ -133,6 +125,22 @@ class GenButton(wx.PyControl):
         return self.IsShown() and self.IsEnabled()
 
 
+    def GetDefaultAttributes(self):
+        """
+        Overridden base class virtual.  By default we should use
+        the same font/colour attributes as the native Button.
+        """
+        return wx.Button.GetClassDefaultAttributes()
+
+
+    def ShouldInheritColours(self):
+        """
+        Overridden base class virtual.  Buttons usually don't inherit
+        the parent's colours.
+        """
+        return False
+    
+
     def Enable(self, enable=True):
         wx.PyControl.Enable(self, enable)
         self.Refresh()
@@ -156,41 +164,41 @@ class GenButton(wx.PyControl):
 
 
     def InitColours(self):
-        faceClr      = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE)
-        textClr      = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNTEXT)
-        self.faceDnClr = faceClr
-        self.SetBackgroundColour(faceClr)
-        self.SetForegroundColour(textClr)
-
-        shadowClr    = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNSHADOW)
-        highlightClr = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNHIGHLIGHT)
-        self.shadowPen    = wx.Pen(shadowClr, 1, wx.SOLID)
-        self.highlightPen = wx.Pen(highlightClr, 1, wx.SOLID)
+        """
+        Calculate a new set of highlight and shadow colours based on
+        the background colour.  Works okay if the colour is dark...
+        """
+        faceClr = self.GetBackgroundColour()
+        r, g, b = faceClr.Get()
+        fr, fg, fb = min(255,r+32), min(255,g+32), min(255,b+32)
+        self.faceDnClr = wx.Colour(fr, fg, fb)
+        sr, sg, sb = max(0,r-32), max(0,g-32), max(0,b-32)
+        self.shadowPen = wx.Pen(wx.Colour(sr,sg,sb), 1, wx.SOLID)
+        hr, hg, hb = min(255,r+64), min(255,g+64), min(255,b+64)
+        self.highlightPen = wx.Pen(wx.Colour(hr,hg,hb), 1, wx.SOLID)
+        self.focusClr = wx.Colour(hr, hg, hb)
+
+        textClr = self.GetForegroundColour()
         if wx.Platform == "__WXMAC__":
             self.focusIndPen = wx.Pen(textClr, 1, wx.SOLID)
         else:
             self.focusIndPen  = wx.Pen(textClr, 1, wx.USER_DASH)
             self.focusIndPen.SetDashes([1,1])
             self.focusIndPen.SetCap(wx.CAP_BUTT)
-        self.focusClr = highlightClr
-
-
+        
+        
     def SetBackgroundColour(self, colour):
         wx.PyControl.SetBackgroundColour(self, colour)
-        colour = self.GetBackgroundColour()
+        self.InitColours()
 
-        # Calculate a new set of highlight and shadow colours based on
-        # the new background colour.  Works okay if the colour is dark...
-        r, g, b = colour.Get()
-        fr, fg, fb = min(255,r+32), min(255,g+32), min(255,b+32)
-        self.faceDnClr = wx.Colour(fr, fg, fb)
-        sr, sg, sb = max(0,r-32), max(0,g-32), max(0,b-32)
-        self.shadowPen = wx.Pen(wx.Colour(sr,sg,sb), 1, wx.SOLID)
-        hr, hg, hb = min(255,r+64), min(255,g+64), min(255,b+64)
-        self.highlightPen = wx.Pen(wx.Colour(hr,hg,hb), 1, wx.SOLID)
-        self.focusClr = wx.Colour(hr, hg, hb)
 
+    def SetForegroundColour(self, colour):
+        wx.PyControl.SetForegroundColour(self, colour)
+        self.InitColours()
 
+    def SetDefault(self):
+        self.GetParent().SetDefaultItem(self)
+        
     def _GetLabelSize(self):
         """ used internally """
         w, h = self.GetTextExtent(self.GetLabel())
@@ -212,8 +220,8 @@ class GenButton(wx.PyControl):
         else:
             dc.SetPen(self.shadowPen)
         for i in range(self.bezelWidth):
-            dc.DrawLine((x1+i, y1), (x1+i, y2-i))
-            dc.DrawLine((x1, y1+i), (x2-i, y1+i))
+            dc.DrawLine(x1+i, y1, x1+i, y2-i)
+            dc.DrawLine(x1, y1+i, x2-i, y1+i)
 
         # draw the lower right sides
         if self.up:
@@ -221,8 +229,8 @@ class GenButton(wx.PyControl):
         else:
             dc.SetPen(self.highlightPen)
         for i in range(self.bezelWidth):
-            dc.DrawLine((x1+i, y2-i), (x2+1, y2-i))
-            dc.DrawLine((x2-i, y1+i), (x2-i, y2))
+            dc.DrawLine(x1+i, y2-i, x2+1, y2-i)
+            dc.DrawLine(x2-i, y1+i, x2-i, y2)
 
 
     def DrawLabel(self, dc, width, height, dw=0, dy=0):
@@ -235,21 +243,16 @@ class GenButton(wx.PyControl):
         tw, th = dc.GetTextExtent(label)
         if not self.up:
             dw = dy = self.labelDelta
-        dc.DrawText(label, ((width-tw)/2+dw, (height-th)/2+dy))
+        dc.DrawText(label, (width-tw)/2+dw, (height-th)/2+dy)
 
 
     def DrawFocusIndicator(self, dc, w, h):
         bw = self.bezelWidth
-##         if self.hasFocus:
-##             self.focusIndPen.SetColour(self.GetForegroundColour())
-##         else:
-##             #self.focusIndPen.SetColour(self.GetBackgroundColour())
-##             self.focusIndPen.SetColour(self.GetForegroundColour())
         self.focusIndPen.SetColour(self.focusClr)
         dc.SetLogicalFunction(wx.INVERT)
         dc.SetPen(self.focusIndPen)
         dc.SetBrush(wx.TRANSPARENT_BRUSH)
-        dc.DrawRectangle((bw+2,bw+2), (w-bw*2-4, h-bw*2-4))
+        dc.DrawRectangle(bw+2,bw+2,  w-bw*2-4, h-bw*2-4)
         dc.SetLogicalFunction(wx.COPY)
 
 
@@ -258,22 +261,39 @@ class GenButton(wx.PyControl):
         x1 = y1 = 0
         x2 = width-1
         y2 = height-1
-        dc = wx.BufferedPaintDC(self)
+        
+        dc = wx.PaintDC(self)
+        brush = None
+        
         if self.up:
-            dc.SetBackground(wx.Brush(self.GetBackgroundColour(), wx.SOLID))
+            colBg = self.GetBackgroundColour()
+            brush = wx.Brush(colBg, wx.SOLID)
+            if self.style & wx.BORDER_NONE:
+                myAttr = self.GetDefaultAttributes()
+                parAttr = self.GetParent().GetDefaultAttributes()
+                myDef = colBg == myAttr.colBg
+                parDef = self.GetParent().GetBackgroundColour() == parAttr.colBg
+                if myDef and parDef:
+                    if wx.Platform == "__WXMAC__":
+                        brush.MacSetTheme(1) # 1 == kThemeBrushDialogBackgroundActive
+                    elif wx.Platform == "__WXMSW__":
+                        if self.DoEraseBackground(dc):
+                            brush = None
+                elif myDef and not parDef:
+                    colBg = self.GetParent().GetBackgroundColour()
+                    brush = wx.Brush(colBg, wx.SOLID)
         else:
-            dc.SetBackground(wx.Brush(self.faceDnClr, wx.SOLID))
-        dc.Clear()
+            brush = wx.Brush(self.faceDnClr, wx.SOLID)
+        if brush is not None:
+            dc.SetBackground(brush)
+            dc.Clear()
+                    
         self.DrawBezel(dc, x1, y1, x2, y2)
         self.DrawLabel(dc, width, height)
         if self.hasFocus and self.useFocusInd:
             self.DrawFocusIndicator(dc, width, height)
 
 
-    def OnEraseBackground(self, event):
-        pass
-
-
     def OnLeftDown(self, event):
         if not self.IsEnabled():
             return
@@ -292,8 +312,9 @@ class GenButton(wx.PyControl):
             if not self.up:    # if the button was down when the mouse was released...
                 self.Notify()
             self.up = True
-            self.Refresh()
-            event.Skip()
+            if self:           # in case the button was destroyed in the eventhandler
+                self.Refresh()
+                event.Skip()
 
 
     def OnMotion(self, event):
@@ -315,18 +336,14 @@ class GenButton(wx.PyControl):
 
     def OnGainFocus(self, event):
         self.hasFocus = True
-        dc = wx.ClientDC(self)
-        w, h = self.GetClientSizeTuple()
-        if self.useFocusInd:
-            self.DrawFocusIndicator(dc, w, h)
+        self.Refresh()
+        self.Update()
 
 
     def OnLoseFocus(self, event):
         self.hasFocus = False
-        dc = wx.ClientDC(self)
-        w, h = self.GetClientSizeTuple()
-        if self.useFocusInd:
-            self.DrawFocusIndicator(dc, w, h)
+        self.Refresh()
+        self.Update()
 
 
     def OnKeyDown(self, event):
@@ -347,7 +364,9 @@ class GenButton(wx.PyControl):
 #----------------------------------------------------------------------
 
 class GenBitmapButton(GenButton):
-    def __init__(self, parent, ID, bitmap,
+    """A generic bitmap button."""
+
+    def __init__(self, parent, id=-1, bitmap=wx.NullBitmap,
                  pos = wx.DefaultPosition, size = wx.DefaultSize,
                  style = 0, validator = wx.DefaultValidator,
                  name = "genbutton"):
@@ -355,7 +374,7 @@ class GenBitmapButton(GenButton):
         self.bmpFocus = None
         self.bmpSelected = None
         self.SetBitmapLabel(bitmap)
-        GenButton.__init__(self, parent, ID, "", pos, size, style, validator, name)
+        GenButton.__init__(self, parent, id, "", pos, size, style, validator, name)
 
 
     def GetBitmapLabel(self):
@@ -414,18 +433,19 @@ class GenBitmapButton(GenButton):
         if not self.up:
             dw = dy = self.labelDelta
         hasMask = bmp.GetMask() != None
-        dc.DrawBitmap(bmp, ((width-bw)/2+dw, (height-bh)/2+dy), hasMask)
+        dc.DrawBitmap(bmp, (width-bw)/2+dw, (height-bh)/2+dy, hasMask)
 
 
 #----------------------------------------------------------------------
 
 
-class GenBitmapTextButton(GenBitmapButton):     # generic bitmapped button with Text Label
-    def __init__(self, parent, ID, bitmap, label,
+class GenBitmapTextButton(GenBitmapButton):
+    """A generic bitmapped button with text label"""
+    def __init__(self, parent, id=-1, bitmap=wx.NullBitmap, label='',
                  pos = wx.DefaultPosition, size = wx.DefaultSize,
                  style = 0, validator = wx.DefaultValidator,
                  name = "genbutton"):
-        GenBitmapButton.__init__(self, parent, ID, bitmap, pos, size, style, validator, name)
+        GenBitmapButton.__init__(self, parent, id, bitmap, pos, size, style, validator, name)
         self.SetLabel(label)
 
 
@@ -474,10 +494,10 @@ class GenBitmapTextButton(GenBitmapButton):     # generic bitmapped button with
 
         pos_x = (width-bw-tw)/2+dw      # adjust for bitmap and text to centre
         if bmp !=None:
-            dc.DrawBitmap(bmp, (pos_x, (height-bh)/2+dy), hasMask) # draw bitmap if available
+            dc.DrawBitmap(bmp, pos_x, (height-bh)/2+dy, hasMask) # draw bitmap if available
             pos_x = pos_x + 2   # extra spacing from bitmap
 
-        dc.DrawText(label, (pos_x + dw+bw, (height-th)/2+dy))      # draw the text
+        dc.DrawText(label, pos_x + dw+bw, (height-th)/2+dy)      # draw the text
 
 
 #----------------------------------------------------------------------
@@ -506,10 +526,10 @@ class __ToggleMixin:
         if not self.IsEnabled() or not self.HasCapture():
             return
         if self.HasCapture():
-            if self.up != self.saveUp:
-                self.Notify()
             self.ReleaseMouse()
             self.Refresh()
+            if self.up != self.saveUp:
+                self.Notify()
 
     def OnKeyDown(self, event):
         event.Skip()
@@ -541,12 +561,15 @@ class __ToggleMixin:
 
 
 class GenToggleButton(__ToggleMixin, GenButton):
+    """A generic toggle button"""
     pass
 
 class GenBitmapToggleButton(__ToggleMixin, GenBitmapButton):
+    """A generic toggle bitmap button"""
     pass
 
 class GenBitmapTextToggleButton(__ToggleMixin, GenBitmapTextButton):
+    """A generic toggle bitmap button with text label"""
     pass
 
 #----------------------------------------------------------------------