]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/wx/lib/analogclock.py
Fix or add some DoGetBestSize's
[wxWidgets.git] / wxPython / wx / lib / analogclock.py
index e53bcf228376b92c79471a295a94b34df00c9ef2..5d1b91f3e364c4fa56a3c65465548ec5ebd6e996 100644 (file)
@@ -1,5 +1,6 @@
+# -*- coding: iso-8859-1 -*-
 #----------------------------------------------------------------------
-# Name:        wxPython.lib.analogclock
+# Name:        wx.lib.analogclock
 # Purpose:     A simple analog clock window
 #
 # Author:      several folks on wxPython-users
 # Copyright:   (c) 2003 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 and with builtin test.
+# 
+# 15-February-2004 - E. A. Tacao
+#
+# o Many ehnacements
+#
+
 
-import math, sys, string, time
-from wxPython.wx import *
+import math
+import sys
+import string
+import time
 
+import wx
 
+from analogclockopts import ACCustomizationFrame
 
-class AnalogClockWindow(wxWindow):
-    """A simple analog clock window"""
 
-    TICKS_NONE   = 0
-    TICKS_SQUARE = 1
-    TICKS_CIRCLE = 2
+# self.clockStyle:
+SHOW_QUARTERS_TICKS = 1
+SHOW_HOURS_TICKS    = 2
+SHOW_MINUTES_TICKS  = 4
+ROTATE_TICKS        = 8
+SHOW_HOURS_HAND     = 16
+SHOW_MINUTES_HAND   = 32
+SHOW_SECONDS_HAND   = 64
+SHOW_SHADOWS        = 128
+OVERLAP_TICKS       = 256
 
-    def __init__(self, parent, ID=-1, pos=wxDefaultPosition, size=wxDefaultSize,
+# self.tickMarkHoursStyle and self.tickMarkMinutesStyle:
+TICKS_NONE          = 1
+TICKS_SQUARE        = 2
+TICKS_CIRCLE        = 4
+TICKS_POLY          = 8
+TICKS_DECIMAL       = 16
+TICKS_ROMAN         = 32
+
+
+class AnalogClockWindow(wx.PyWindow):
+    """An analog clock window"""
+
+    def __init__(self, parent, ID=-1, pos=wx.DefaultPosition, size=wx.DefaultSize,
                  style=0, name="clock"):
+        
         # Initialize the wxWindow...
-        wxWindow.__init__(self, parent, ID, pos, size, style, name)
+        wx.PyWindow.__init__(self, parent, ID, pos, size, style, name)
+
+        # Initialize some variables and defaults...
+        self.clockStep = 1
+        self.prefs_open = False
+
+        self.tickShapeHours = self.tickShapeMinutes= [[0,0],
+                                                      [1,-1],
+                                                      [2,0],
+                                                      [1,4]]
+        self.handHoursThickness = 5
+        self.handHoursColour = (0, 0, 0)
+
+        self.handMinutesThickness = 3
+        self.handMinutesColour = (0, 0, 0)
+
+        self.handSecondsThickness = 1
+        self.handSecondsColour = (0, 0, 0)
+
+        self.tickMarkHoursPen = wx.Pen((0, 0, 0), 1, wx.SOLID)
+        self.tickMarkHoursBrush = wx.Brush((0, 0, 0), wx.SOLID)
+        self.markSizeHour = 10
+        self.tickMarkHoursFont = wx.Font(0, wx.SWISS, wx.NORMAL, wx.BOLD)
+        self.tickMarkHoursFont.SetPointSize(self.markSizeHour)
+
+        self.tickMarkMinutesPen = wx.Pen((0, 0, 0), 1, wx.SOLID)
+        self.tickMarkMinutesBrush = wx.Brush((0, 0, 0), wx.SOLID)
+        self.markSizeMin = 6
+        self.tickMarkMinutesFont = wx.Font(self.markSizeMin, wx.SWISS, wx.NORMAL, wx.BOLD)
+
+        self.offM = 0
+
+        self.shadowPenColour = self.shadowBrushColour = (128,128,128)
+
+        self.watchPen = None
+        self.watchBrush = None
 
-        # Initialize the default clock settings...
-        self.minuteMarks = 60
-        self.hourMarks = 12
-        self.tickMarksBrushC = self.GetForegroundColour()
-        self.tickMarksPenC   = self.GetForegroundColour()
-        self.tickMarkStyle = self.TICKS_SQUARE
+        self.clockStyle = SHOW_HOURS_TICKS | SHOW_MINUTES_TICKS | SHOW_SHADOWS | ROTATE_TICKS
+        self.handsStyle = SHOW_SECONDS_HAND
+
+        self.tickMarkHoursStyle = TICKS_POLY
+        self.tickMarkMinutesStyle = TICKS_CIRCLE
+
+        self.currentTime=None
 
         # Make an initial bitmap for the face, it will be updated and
         # painted at the first EVT_SIZE event.
         W, H = size
-        self.faceBitmap = wxEmptyBitmap(max(W,1), max(H,1))
+        self.faceBitmap = wx.EmptyBitmap(max(W,1), max(H,1))
+
+        # Set event handlers...
+        self.Bind(wx.EVT_PAINT, self.OnPaint)
+        self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: None)
+        self.Bind(wx.EVT_SIZE, self.OnSize)
+        self.Bind(wx.EVT_TIMER, self.OnTimerExpire)
+        self.Bind(wx.EVT_WINDOW_DESTROY, self.OnQuit)
+        self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
+        self.Bind(wx.EVT_RIGHT_UP, self.OnRightClick)         
+
 
         # Initialize the timer that drives the update of the clock
         # face.  Update every half second to ensure that there is at
         # least one true update during each realtime second.
-        self.timer = wxTimer(self)
+        self.timer = wx.Timer(self)
         self.timer.Start(500)
 
-        # Set event handlers...
-        EVT_PAINT(self, self.OnPaint)
-        EVT_ERASE_BACKGROUND(self, lambda x: None)
-        EVT_SIZE(self, self.OnSize)
-        EVT_TIMER(self, -1, self.OnTimerExpire)
-        EVT_WINDOW_DESTROY(self, self.OnQuit)
+    def DoGetBestSize(self):
+        return wx.Size(25,25)
 
+    def OnPaint(self, event):
+        self._doDrawHands(wx.BufferedPaintDC(self), True)
 
-    def SetTickMarkStyle(self, style):
-        """
-        Set the style of the marks around the edge of the clock.
-        Options are TICKS_NONE, TICKS_SQUARE, and TICKS_CIRCLE
-        """
-        self.tickMarkStyle = style
 
+    def OnTimerExpire(self, event):
+        size = self.GetClientSize()
+        dc = wx.BufferedDC(wx.ClientDC(self), size)
+        self._doDrawHands(dc, True)
 
-    def SetTickMarkColours(self, brushC, penC="BLACK"):
-        """
-        Set the brush colour and optionally the pen colour of
-        the marks around the edge of the clock.
-        """
-        self.tickMarksBrushC = brushC
-        self.tickMarksPenC   = penC
 
-    SetTickMarkColour = SetTickMarkColours
+    def OnQuit(self, event):
+        self.timer.Stop()
+        del self.timer
+
+        
+    def OnRightDown(self, event):
+        self.x = event.GetX()
+        self.y = event.GetY()
+        event.Skip()
+
+
+    def OnRightClick(self, event):
+        # only do this part the first time so the events are only bound once
+        if not hasattr(self, "popupID1"):
+            self.popupID1 = wx.NewId()
+            self.popupID2 = wx.NewId()
+            self.Bind(wx.EVT_MENU, self.OnPopupOne, id=self.popupID1)
+            self.Bind(wx.EVT_MENU, self.OnPopupTwo, id=self.popupID2)
+
+        # make a menu
+        sm = wx.Menu()
 
+        sm.Append(self.popupID1, "Customize...")
+        sm.Append(self.popupID2, "About...")
 
-    def SetHandsColour(self, c):
-        """An alias for SetForegroundColour"""
-        self.SetForegroundColour(c)  # the hands just use the foreground colour
+        # If there already a setup window open, we must not appear...
+        if not self.prefs_open:
+            # Popup the menu.  If an item is selected then its handler
+            # will be called before PopupMenu returns.
+            self.PopupMenu(sm, (self.x,self.y))
+        sm.Destroy()
 
 
+    def OnPopupOne(self, event):
+        self.prefs_open=True
+        frame = ACCustomizationFrame(self, -1, "AnalogClock Preferences")
+        frame.Show(True)
+
+
+    def OnPopupTwo(self, event):
+        dlg = wx.MessageDialog(self, "AnalogClockWindow\n\nby Several folks on wxPython-users\nwith enhancements from E. A. Tacão",
+                          'About', wx.OK | wx.ICON_INFORMATION)
+        dlg.ShowModal()
+        dlg.Destroy()
+
 
-    # Using the current settings, render the points and line endings for the
-    # circle inside the specified device context.  In this case, the DC is
-    # a memory based device context that will be blitted to the actual
-    # display DC inside the OnPaint() event handler.
     def OnSize(self, event):
         # The faceBitmap init is done here, to make sure the buffer is always
         # the same size as the Window
         size  = self.GetClientSize()
-        self.faceBitmap = wxEmptyBitmap(size.width, size.height)
-        self.DrawFace()
+        self.faceBitmap = wx.EmptyBitmap(size.width, size.height)
 
+        # Update drawing coordinates...
+        new_dim = size.Get()
+        if not hasattr(self,"dim"):
+            self.dim = new_dim
 
-    def OnPaint(self, event):
-        self.DrawHands(wxPaintDC(self))
+        x,y=[0,1]
+        self.scale = min([float(new_dim[x]) / self.dim[x],
+                          float(new_dim[y]) / self.dim[y]])
 
+        self.centerX = self.faceBitmap.GetWidth() / 2
+        self.centerY = self.faceBitmap.GetHeight() / 2
 
-    def OnQuit(self, event):
-        self.timer.Stop()
-        del self.timer
+        self.shadowDistance = 2 * self.scale
 
+        self.radius_watch = min(self.centerX, self.centerY)
 
-    def OnTimerExpire(self, event):
-        self.DrawHands(wxClientDC(self))
+        self._doDrawFace()
+        
 
 
-    def DrawHands(self, drawDC):
+    def _doDrawHands(self, drawDC, force=0):
+        currentTime = list(time.localtime(time.time())[3:6])
+
+        if not (self.handsStyle & SHOW_SECONDS_HAND):
+            currentTime[2]=-1
+
+        if not (force or currentTime != self.currentTime):
+            return
+        self.currentTime = currentTime
+        hour, minutes, seconds = currentTime
+
         # Start by drawing the face bitmap
         drawDC.DrawBitmap(self.faceBitmap, (0,0))
 
-        currentTime = time.localtime(time.time())
-        hour, minutes, seconds = currentTime[3:6]
 
-        W,H = self.faceBitmap.GetWidth(), self.faceBitmap.GetHeight()
-        centerX = W / 2
-        centerY = H / 2
+        # NOTE:  All this hand drawing code below should be refactored into a helper function.
+
+        
+        # Draw hours hand shadow
+        mStep = 6 * self.clockStep
+        angle = hour * 30
+        if angle > 360:
+            angle = angle - 360
+        angle = angle + round(minutes/(mStep*2)) * mStep
+
+        x,y,f = self._getCoords("hand_hours", angle)
+
+        if f and self.clockStyle & SHOW_SHADOWS:
+            drawDC.SetPen(wx.Pen(self.shadowPenColour,
+                                 int(self.handHoursThickness * self.scale),
+                                 wx.SOLID))
+            drawDC.DrawLineXY(int(self.centerX + self.shadowDistance),
+                              int(self.centerY + self.shadowDistance),
+                              int(x + self.shadowDistance),
+                              int(y + self.shadowDistance))
+
+        # Draw minutes hand shadow
+        angle = minutes * 6
+        x,y,f = self._getCoords("hand_minutes", angle)
+
+        if f and self.clockStyle & SHOW_SHADOWS:
+            drawDC.SetPen(wx.Pen(self.shadowPenColour,
+                                 int(self.handMinutesThickness * self.scale),
+                                 wx.SOLID))
+            drawDC.DrawLineXY(int(self.centerX + self.shadowDistance),
+                              int(self.centerY + self.shadowDistance),
+                              int(x + self.shadowDistance),
+                              int(y + self.shadowDistance))
+
+        # Draw seconds hand shadow if required
+        if seconds >= 0:
+            angle = seconds * 6
+            x,y,f = self._getCoords("hand_seconds", angle)
+            
+            if f and self.clockStyle & SHOW_SHADOWS:
+                drawDC.SetPen(wx.Pen(self.shadowPenColour,
+                                     int(self.handSecondsThickness * self.scale),
+                                     wx.SOLID))
+                drawDC.DrawLineXY(int(self.centerX + self.shadowDistance),
+                                  int(self.centerY + self.shadowDistance),
+                                  int(x + self.shadowDistance),
+                                  int(y + self.shadowDistance))
+
+
+        # Draw hours hand
+        angle = hour * 30
+        if angle > 360:
+            angle = angle - 360
+        angle = angle + round(minutes/(mStep*2)) * mStep
+        
+        x,y,f = self._getCoords("hand_hours", angle)
+
+        if f:
+            drawDC.SetPen(wx.Pen(self.handHoursColour,
+                                 int(self.handHoursThickness * self.scale),
+                                 wx.SOLID))
+            drawDC.DrawLineXY(int(self.centerX), int(self.centerY), int(x), int(y))
+
+        # Draw minutes hand
+        angle = minutes * 6
+        x,y,f = self._getCoords("hand_minutes", angle)
+
+        if f:
+            drawDC.SetPen(wx.Pen(self.handMinutesColour,
+                                 int(self.handMinutesThickness * self.scale),
+                                 wx.SOLID))
+            drawDC.DrawLineXY(int(self.centerX), int(self.centerY), int(x), int(y))
+
+        # Draw seconds hand if required
+        if seconds >= 0:
+            angle = seconds * 6
+            x,y,f = self._getCoords("hand_seconds", angle)
+            if f:
+                drawDC.SetPen(wx.Pen(self.handSecondsColour,
+                                     int(self.handSecondsThickness * self.scale),
+                                     wx.SOLID))
+                drawDC.DrawLineXY(int(self.centerX), int(self.centerY), int(x), int(y))
+
+
+
+    def _doDrawFace(self):
+        backgroundBrush = wx.Brush(self.GetBackgroundColour(), wx.SOLID)
+        drawDC = wx.MemoryDC()
+        drawDC.SelectObject(self.faceBitmap)
+        drawDC.SetBackground(backgroundBrush)
+        drawDC.Clear()
 
-        radius = min(centerX, centerY)
-        hour += minutes / 60.0 # added so the hour hand moves continuously
-        x, y = self.point(hour, 12, (radius * .65))
-        hourX, hourY = (x + centerX), (centerY - y)
-        x, y = self.point(minutes, 60, (radius * .85))
-        minutesX, minutesY = (x + centerX), (centerY - y)
-        x, y = self.point(seconds, 60, (radius * .85))
-        secondsX, secondsY = (x + centerX), (centerY - y)
+        self.handHoursLength = 0.65 * (self.radius_watch - self._getMarkMaxSize("ticks_hours", drawDC))
+        self.handMinutesLength = 0.85 * (self.radius_watch - self._getMarkMaxSize("ticks_hours", drawDC))
+        self.handSecondsLength = 0.85 * (self.radius_watch - self._getMarkMaxSize("ticks_hours", drawDC))
 
-        # Draw the hour hand...
-        drawDC.SetPen(wxPen(self.GetForegroundColour(), 5, wxSOLID))
-        drawDC.DrawLine((centerX, centerY), (hourX, hourY))
+        self.radius_ticks_hours = self.radius_watch - self.shadowDistance - self._getMarkMaxSize("ticks_hours", drawDC)
+        self.radius_ticks_minutes = self.radius_ticks_hours
+        
+        self._calcSteps()
 
-        # Draw the minutes hand...
-        drawDC.SetPen(wxPen(self.GetForegroundColour(), 3, wxSOLID))
-        drawDC.DrawLine((centerX, centerY), (minutesX, minutesY))
+        # Draw the watch...
+        self._drawWatch(drawDC)
 
-        # Draw the seconds hand...
-        drawDC.SetPen(wxPen(self.GetForegroundColour(), 1, wxSOLID))
-        drawDC.DrawLine((centerX, centerY), (secondsX, secondsY))
+        # Draw the marks for hours and minutes...
+        circle = 360
+        mStep = 6 * self.clockStep
+
+        if self.clockStyle & SHOW_SHADOWS:
+            for i in range(0, circle, mStep):
+                for t in self.coords.keys():
+                    if t.find("ticks") > -1:
+                        x,y,f = self._getCoords(t, i)
+                        if f:
+                            self._doDrawTickMark(i, drawDC, t,
+                                                 x + self.shadowDistance,
+                                                 y + self.shadowDistance,
+                                                 True)
+
+        for i in range(0, circle, mStep):
+            for t in self.coords.keys():
+                if t.find("ticks") > -1:
+                    x,y,f = self._getCoords(t, i)
+                    if f:
+                        self._doDrawTickMark(i, drawDC, t, x, y)
+
+
+
+    def _doDrawTickMark(self, angle, drawDC, tipo, x, y, is_a_shadow=None):
+        opts = {"ticks_hours":    [self.tickMarkHoursPen, self.tickMarkHoursBrush, self.markSizeHour, self.tickMarkHoursStyle],
+                "ticks_quarters": [self.tickMarkHoursPen, self.tickMarkHoursBrush, self.markSizeHour, self.tickMarkHoursStyle],
+                "ticks_minutes":  [self.tickMarkMinutesPen, self.tickMarkMinutesBrush, self.markSizeMin, self.tickMarkMinutesStyle]}
+
+        pen, brush, size, style = opts[tipo];
+        size = size * self.scale
+
+        if is_a_shadow:
+            drawDC.SetPen(wx.Pen(self.shadowPenColour, 1, wx.SOLID))
+            drawDC.SetBrush(wx.Brush(self.shadowBrushColour, wx.SOLID))
+            drawDC.SetTextForeground(self.shadowBrushColour)
+        else:
+            drawDC.SetPen(pen)
+            drawDC.SetBrush(brush)
+            drawDC.SetTextForeground(brush.GetColour())
+
+        if style & TICKS_CIRCLE:
+            x, y = self._center2corner(x, y, tipo)
+            drawDC.DrawEllipse((x, y), (int(size), int(size)))
+
+        elif style & TICKS_SQUARE:
+            x, y = self._center2corner(x, y, tipo)
+            drawDC.DrawRectangle((x, y), (int(size), int(size)))
+
+        elif (style & TICKS_DECIMAL) or (style & TICKS_ROMAN):
+            self._draw_rotate_text(drawDC, x, y, tipo, angle)
+
+        elif style & TICKS_POLY:
+             self._draw_rotate_polygon(drawDC, x, y, tipo, angle)
+
+
+    def _draw_rotate_text(self, drawDC, x, y, tipo, angle):
+        text = self._build_text(angle, tipo)
+        lX, lY = self._center2corner(x, y, tipo, drawDC)
+        lX = lX * len(text)
+        angle = 360 - angle
+
+        if self.clockStyle & ROTATE_TICKS:
+            radiansPerDegree = math.pi / 180
+            x = int(x - 
+                    ((math.cos((angle) * radiansPerDegree)*lX) + 
+                     (math.sin((angle) * radiansPerDegree)*lY)))
+            y = int(y - 
+                    ((math.cos((angle) * radiansPerDegree)*lY) - 
+                     (math.sin((angle) * radiansPerDegree)*lX)))
+            drawDC.DrawRotatedText(text, (x,y), angle)
+
+        else:
+            x = x - lX
+            y = y - lY
+            drawDC.DrawText(text, (x, y))
+
+
+    def _draw_rotate_polygon(self, drawDC, x, y, tipo, angle):
+        if tipo=="ticks_quarters":
+            tipo="ticks_hours"
+            
+        # Add to empty list to prevent system-wide hard freezes under XP...
+        points = {"ticks_hours":self.tickShapeHours+[], "ticks_minutes":self.tickShapeMinutes+[]}[tipo]
+        size = self.scale * {"ticks_hours":self.markSizeHour, "ticks_minutes":self.markSizeMin}[tipo]
+
+        maxX = max(map(lambda x:x[0],points))
+        minX = min(map(lambda x:x[0],points))
+        maxY = max(map(lambda x:x[0],points))
+        minY = min(map(lambda x:x[0],points))
+
+        maxB = abs(max(maxX, maxY));
+        f = size / maxB
+
+        orgX = (maxX - minX) / 2.
+        orgY = (maxY - minY) / 2.
 
+        radiansPerDegree = math.pi / 180
+        scaledX = x
+        scaledY = y
+
+        for z in range(0, len(points)):
+            x,y = points[z]
+            x = x * f - orgX * f
+            y = y * f - orgY * f
+            if self.clockStyle & ROTATE_TICKS:
+                m,t = self._rect2pol(x,y)
+                t = t + angle
+                x,y = self._pol2rect(m,t)
+            x = x + scaledX
+            y = y + scaledY
+            points[z] = [int(x), int(y)]
+
+        drawDC.DrawPolygon(points)
+
+
+    def _pol2rect(self, r, w, deg=1):          # radian if deg=0; degree if deg=1
+        if deg:
+            w = math.pi * w / 180.0
+        return r * math.cos(w), r * math.sin(w)
+
+
+    def _rect2pol(self, x, y, deg=1):          # radian if deg=0; degree if deg=1
+        if deg:
+           return math.hypot(x, y), 180.0 * math.atan2(y, x) / math.pi
+        else:
+           return math.hypot(x, y), math.atan2(y, x)
+
+
+    def _center2corner(self, x, y, tipo, drawDC=None):
+        if tipo == "ticks_quarters":
+            tipo = "ticks_hours"
+
+        style = {"ticks_hours":self.tickMarkHoursStyle, "ticks_minutes":self.tickMarkMinutesStyle}[tipo]
+        size = self.scale * {"ticks_hours":self.markSizeHour, "ticks_minutes":self.markSizeMin}[tipo]
+
+        if style & TICKS_DECIMAL or style & TICKS_ROMAN:
+            font = {"ticks_hours":self.tickMarkHoursFont, "ticks_minutes":self.tickMarkMinutesFont}[tipo]
+            font.SetPointSize(int(size));
+            drawDC.SetFont(font)
+            lX = drawDC.GetCharWidth() / 2.
+            lY = drawDC.GetCharHeight() / 2.
+            x = lX
+            y = lY
+        else:
+            size = self.scale * {"ticks_hours":self.markSizeHour, "ticks_minutes":self.markSizeMin}[tipo]
+            x=x-size/2.;y=y-size/2.
+        return x, y
+
+
+    def _build_text(self, angle, tipo):
+        if tipo == "ticks_quarters":
+            tipo = "ticks_hours"
+        a = angle
+        if a <= 0:
+            a = a + 360
+        divider = {"ticks_hours":30,"ticks_minutes":6}[tipo]
+        a = int(a / divider)
+
+        style = {"ticks_hours":self.tickMarkHoursStyle," ticks_minutes":self.tickMarkMinutesStyle}[tipo]
+        if style & TICKS_ROMAN:
+            text=["I","II","III","IV","V","VI","VII","VIII","IX","X", \
+                  "XI","XII","XIII","XIV","XV","XVI","XVII","XVIII","XIX","XX", \
+                  "XXI","XXII","XXIII","XXIV","XXV","XXVI","XXVII","XXVIII","XXIX","XXX", \
+                  "XXXI","XXXII","XXXIII","XXXIV","XXXV","XXXVI","XXXVII","XXXVIII","XXXIX","XL", \
+                  "XLI","XLII","XLIII","XLIV","XLV","XLVI","XLVII","XLVIII","XLIX","L", \
+                  "LI","LII","LIII","LIV","LV","LVI","LVII","LVIII","LIX","LX"][a-1]
+        else:
+            text = "%s" % a
+
+        return text
+
+
+    def _getMarkMaxSize(self, tipo, drawDC=None):
+        if tipo == "ticks_quarters":
+            tipo = "ticks_hours"
+
+        style = {"ticks_hours":self.tickMarkHoursStyle, "ticks_minutes":self.tickMarkMinutesStyle}[tipo]
+        size = self.scale * {"ticks_hours":self.markSizeHour, "ticks_minutes":self.markSizeMin}[tipo]
+
+        if style & TICKS_DECIMAL or style & TICKS_ROMAN:
+            lX = 2 * drawDC.GetCharWidth()
+            lY = drawDC.GetCharHeight()
+            size = math.sqrt(lX**2 + lY**2) * self.scale
+        else:
+            size=math.sqrt(2) * size
+
+        return size
+
+
+    def _drawWatch(self, drawDC):
+        # Draw the watch...
+        if self.watchPen or self.watchBrush:
+            if self.watchPen:
+                drawDC.SetPen(self.watchPen)
+            if self.watchBrush:
+                drawDC.SetBrush(self.watchBrush)
+            else:
+                drawDC.SetBrush(wx.Brush(self.GetBackgroundColour(), wx.SOLID))
+            drawDC.DrawCircle((self.centerX, self.centerY), self.radius_watch)
+
+
+    def _calcSteps(self):
+        # Calcule todos os pontos para:
+        #  - marcas de horas
+        #  - marcas de minutos
+        #  - ponteiro de horas
+        #  - ponteiro de minutos
+        #  - ponteiro de segundos
+
+        circle = 360
+        mStep = 6 * self.clockStep # Step in degrees...
+
+        vq = 90 * (self.clockStyle & SHOW_QUARTERS_TICKS) / SHOW_QUARTERS_TICKS
+        vh = 30 * (self.clockStyle & SHOW_HOURS_TICKS) / SHOW_HOURS_TICKS
+        vm = 1  * (self.clockStyle & SHOW_MINUTES_TICKS) / SHOW_MINUTES_TICKS
+
+        coords = {"ticks_quarters": [self.radius_ticks_hours,  60,vq,{}],
+                  "ticks_hours":    [self.radius_ticks_hours,  60,vh,{}],
+                  "ticks_minutes":  [self.radius_ticks_minutes,60,vm,{}],
+                  "hand_hours":     [self.handHoursLength,     60,1, {}],
+                  "hand_minutes":   [self.handMinutesLength,   60,1, {}],
+                  "hand_seconds":   [self.handSecondsLength,   60,1, {}]}
 
-    # Draw the specified set of line marks inside the clock face for the
-    # hours or minutes...
-    def DrawFace(self):
-        backgroundBrush = wxBrush(self.GetBackgroundColour(), wxSOLID)
-        drawDC = wxMemoryDC()
-        drawDC.SelectObject(self.faceBitmap)
-        drawDC.SetBackground(backgroundBrush)
-        drawDC.Clear()
+        radiansPerDegree = math.pi / 180
 
-        W,H = self.faceBitmap.GetWidth(), self.faceBitmap.GetHeight()
-        centerX = W / 2
-        centerY = H / 2
+        for t in coords.keys():
+            for i in range(0, circle+mStep, mStep):
+                radius = coords[t][0]
+                if t == "ticks_minutes":
+                    radius = radius - self.offM
+                step_angle = 360. / coords[t][1]
+                pre = coords[t][2]
+                x = self.centerX + radius * math.sin(i * radiansPerDegree)
+                y = self.centerY + radius * math.cos(i * radiansPerDegree)
+                f = (pre and (i/step_angle == int(i/step_angle)) and (float(i)/pre == int(i/pre)))
+                coords[t][3][i] = [x,y,f]
+
+        if not self.clockStyle & OVERLAP_TICKS:
+            for i in range(0, circle + mStep, mStep):
+                f=coords["ticks_minutes"][3][i][2]
+                if f and \
+                   (coords["ticks_hours"][3].get(i,[0,0,0])[2] or coords["ticks_quarters"][3].get(i,[0,0,0])[2]):
+                    f=False
+                coords["ticks_minutes"][3][i][2]=f
+
+        self.coords=coords
+
+
+    def _getCoords(self, tipo, angle):
+        # Returns coords and 'use flag' based on current angle...
+        k = 360 - (angle + 180)
+        if k <= 0:
+            k = k + 360
+        return self.coords[tipo][3][k]
+
+
+# -----------------------------------------------------
+#
+    def SetTickShapes(self, tsh, tsm=None):
+        """
+        tsh, tsm: [[x0,y0], [x1,y1], ... [xn,yn]]
 
-        # Draw the marks for hours and minutes...
-        self.DrawTimeMarks(drawDC, self.minuteMarks, centerX, centerY, 4)
-        self.DrawTimeMarks(drawDC, self.hourMarks, centerX, centerY, 9)
+        Sets lists of lists of points to be used as polygon shapes
+        when using the TICKS_POLY style. If tsm is ommitted,
+        we'll use tsh for both shapes.
+        """
 
+        if not tsm:
+            tsm=tsh
 
-    def DrawTimeMarks(self, drawDC, markCount, centerX, centerY, markSize):
-        for i in range(markCount):
-            x, y = self.point(i + 1, markCount, min(centerX,centerY) - 16)
-            scaledX = x + centerX - markSize/2
-            scaledY = centerY - y - markSize/2
+        self.tickShapeHours = tsh
+        self.tickShapeMinutes = tsm
 
-            drawDC.SetBrush(wxBrush(self.tickMarksBrushC, wxSOLID))
-            drawDC.SetPen(wxPen(self.tickMarksPenC, 1, wxSOLID))
-            if self.tickMarkStyle != self.TICKS_NONE:
-                if self.tickMarkStyle == self.TICKS_CIRCLE:
-                    drawDC.DrawEllipse((scaledX - 2, scaledY), (markSize, markSize))
-                else:
-                    drawDC.DrawRectangle((scaledX - 3, scaledY), (markSize, markSize))
 
+    def SetHandWeights(self, h=None, m=None, s=None):
+        """
+        h, m, s: value
 
-    def point(self, tick, range, radius):
-        angle = tick * (360.0 / range)
-        radiansPerDegree = math.pi / 180
-        pointX = int(round(radius * math.sin(angle * radiansPerDegree)))
-        pointY = int(round(radius * math.cos(angle * radiansPerDegree)))
-        return wxPoint(pointX, pointY)
+        Sets thickness of hands.
+        """
 
+        if h:
+           self.handHoursThickness = h
+        if m:
+           self.handMinutesThickness = m
+        if s:
+           self.handSecondsThickness = s
 
 
+    def SetHandColours(self, h=None, m=None, s=None):
+        """
+        h, m, s: wx.Colour
+
+        Sets colours of hands. If m and s are ommitted,
+        we'll use h for all.
+        """
+
+        if h and not m and not s:
+            m=h
+            s=h
+
+        if h:
+            self.handHoursColour = h
+        if m:
+            self.handMinutesColour = m
+        if s:
+            self.handSecondsColour = s
+
+
+    def SetTickColours(self, h=None, m=None):
+        """
+        h, m: wx.Colour
+
+        Sets colours of ticks. If m is ommitted,
+        we'll use h for both.
+        """
+
+        if not m:
+            m=h
+
+        if h:
+            self.tickMarkHoursPen = wx.Pen(h, 1, wx.SOLID)
+            self.tickMarkHoursBrush = wx.Brush(h, wx.SOLID)
+
+        if m:
+           self.tickMarkMinutesPen = wx.Pen(m, 1, wx.SOLID)
+           self.tickMarkMinutesBrush = wx.Brush(m, wx.SOLID)
+
+
+    def SetTickSizes(self, h=None, m=None):
+        """
+        h, m: value
+
+        Sizes for tick marks.
+        """
+
+        if h:
+            self.markSizeHour = h
+        if m:
+            self.markSizeMin = m
+
+
+    def SetTickFonts(self, h=None, m=None):
+        """
+        h, m: wx.Font
+
+        Fonts for tick marks when using TICKS_DECIMAL or TICKS_ROMAN style.
+        If m is ommitted, we'll use h for both.
+        """
+
+        if not m:
+            m=h
+
+        if h:
+            self.tickMarkHoursFont = h
+            self.tickMarkHoursFont.SetPointSize(self.markSizeHour)
+        if m:
+            self.tickMarkMinutesFont = m
+            self.tickMarkMinutesFont.SetPointSize(self.markSizeMin)
+
+
+    def SetMinutesOffset(self, o):
+        """
+        s = value
+
+        Sets the distance between tick marks for hours and minutes.
+        """
+        self.offM = o
+
+
+    def SetShadowColour(self, s):
+        """
+        s = wx.Colour or (r,g,b) tuple.
+
+        Sets the colour to be used to draw shadows.
+        """
+
+        self.shadowPenColour = self.shadowBrushColour = s
+
+
+    def SetWatchPenBrush(self, p=None, b=None):
+        """
+        p = wx.Pen; b = wx.Brush
+
+        Set the pen and brush for the watch.
+        """
+
+        if p:
+            self.watchPen = p
+        if b:
+            self.watchBrush = b
+
+
+    def SetClockStyle(self, style):
+        """
+        Set the clock style, acording to the options:
+
+            SHOW_QUARTERS_TICKS - Show marks for hours 3, 6, 9, 12
+            SHOW_HOURS_TICKS    - Show marks for all hours
+            SHOW_MINUTES_TICKS  - Show marks for minutes
+
+            SHOW_HOURS_HAND     - Show hours hand
+            SHOW_MINUTES_HAND   - Show minutes hand
+            SHOW_SECONDS_HAND   - Show seconds hand
+
+            SHOW_SHADOWS        - Show hands and marks shadows
+
+            ROTATE_TICKS        - Align tick marks to watch
+            OVERLAP_TICKS       - Draw tick marks for minutes even
+                                  when they match the hours marks.
+        """
+
+        self.clockStyle = style
+
+
+    def SetTickStyles(self, h=None, m=None):
+        """
+        Set the ticks styles, acording to the options below.
+
+            TICKS_NONE          = Don't show tick marks.
+            TICKS_SQUARE        = Use squares as tick marks.
+            TICKS_CIRCLE        = Use circles as tick marks.
+            TICKS_POLY          = Use a polygon as tick marks. The polygon
+                                  must be passed using SetTickShapes,
+                                  otherwise the default polygon will be used.
+            TICKS_DECIMAL       = Use decimal numbers.
+            TICKS_ROMAN         = Use Roman numbers.
+        """
+
+        if h:
+            self.tickMarkHoursStyle = h
+        if m:
+            self.tickMarkMinutesStyle = m
+#
+# -----------------------------------------------------
+
 
 if __name__ == "__main__":
-    class App(wxApp):
+    print wx.VERSION_STRING
+    class App(wx.App):
         def OnInit(self):
-            frame = wxFrame(None, -1, "AnalogClockWindow Test", size=(375,375))
+            frame = wx.Frame(None, -1, "AnalogClockWindow", size=(375,375))
 
             clock = AnalogClockWindow(frame)
-            clock.SetTickMarkColours("RED")
-            clock.SetHandsColour("WHITE")
-            clock.SetBackgroundColour("BLUE")
+            
+            # Settings below are used by default...
+            #clock.SetClockStyle(SHOW_HOURS_TICKS|SHOW_MINUTES_TICKS|SHOW_SHADOWS|ROTATE_TICKS)
+            #clock.SetTickStyles(TICKS_POLY, TICKS_CIRCLE)
 
-            frame.Centre(wxBOTH)
+            frame.Centre(wx.BOTH)
             frame.Show(True)
             self.SetTopWindow(frame)
-            return true
+            return True
 
     theApp = App(0)
     theApp.MainLoop()
 
 
-
+#
+##
+### eof