--- /dev/null
+# AnalogClock's main class
+# E. A. Tacao <e.a.tacao |at| estadao.com.br>
+# http://j.domaindlx.com/elements28/wxpython/
+# 15 Fev 2006, 22:00 GMT-03:00
+# Distributed under the wxWidgets license.
+#
+# For more info please see the __init__.py file.
+
+import wx
+
+from styles import *
+from helpers import Dyer, Face, Hand, HandSet, TickSet, Box
+from setup import Setup
+
+#----------------------------------------------------------------------
+
+class AnalogClock(wx.PyWindow):
+ """An analog clock."""
+
+ def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
+ size=wx.DefaultSize, style=wx.NO_BORDER, name="AnalogClock",
+ clockStyle=DEFAULT_CLOCK_STYLE,
+ minutesStyle=TICKS_CIRCLE, hoursStyle=TICKS_POLY):
+
+ wx.PyWindow.__init__(self, parent, id, pos, size, style, name)
+
+ # Base size for scale calc purposes.
+ self.basesize = wx.Size(348, 348)
+
+ # Store some references.
+ self.clockStyle = clockStyle
+ self.minutesStyle = minutesStyle
+ self.hoursStyle = hoursStyle
+
+ self.DrawHands = self._drawHands
+ self.DrawBox = self._drawBox
+ self.RecalcCoords = self._recalcCoords
+
+ self.shadowOffset = 3
+
+ self.allHandStyles = [SHOW_HOURS_HAND,
+ SHOW_MINUTES_HAND,
+ SHOW_SECONDS_HAND]
+
+ # Initialize clock face.
+ #
+ # By default we don't use colours or borders on the clock face.
+ bg = self.GetBackgroundColour()
+ face = Face(dyer=Dyer(bg, 0, bg))
+
+ # Initialize tick marks.
+ #
+ # TickSet is a set of tick marks; there's always two TickSets defined
+ # regardless whether they're being shown or not.
+ ticksM = TickSet(self, style=minutesStyle, size=5, kind="minutes")
+ ticksH = TickSet(self, style=hoursStyle, size=25, kind="hours",
+ rotate=clockStyle&ROTATE_TICKS)
+
+ # Box holds the clock face and tick marks.
+ self.Box = Box(self, face, ticksM, ticksH)
+
+ # Initialize hands.
+ #
+ # HandSet is the set of hands; there's always one HandSet defined
+ # regardless whether hands are being shown or not.
+ #
+ # A 'lenfac = 0.95', e.g., means that the lenght of that hand will
+ # be 95% of the maximum allowed hand lenght ('nice' maximum lenght).
+ handH = Hand(size=7, lenfac=0.7)
+ handM = Hand(size=5, lenfac=0.95)
+ handS = Hand(size=1, lenfac=0.95)
+ self.Hands = HandSet(self, handH, handM, handS)
+
+ # Create the customization dialog.
+ self.Setup = None
+
+ # Make a context menu.
+ popup1 = wx.NewId()
+ popup2 = wx.NewId()
+ cm = self.cm = wx.Menu()
+ cm.Append(popup1, "Customize...")
+ cm.Append(popup2, "About...")
+
+ # Set event handlers.
+ self.Bind(wx.EVT_SIZE, self._OnSize)
+ self.Bind(wx.EVT_PAINT, self._OnPaint)
+ self.Bind(wx.EVT_ERASE_BACKGROUND, lambda evt: None)
+ self.Bind(wx.EVT_TIMER, self._OnTimer)
+ self.Bind(wx.EVT_WINDOW_DESTROY, self._OnDestroyWindow)
+ self.Bind(wx.EVT_CONTEXT_MENU, self._OnContextMenu)
+ self.Bind(wx.EVT_MENU, self._OnShowSetup, id=popup1)
+ self.Bind(wx.EVT_MENU, self._OnShowAbout, id=popup2)
+
+ # Set initial size based on given size, or best size
+ self.SetBestFittingSize(size)
+
+ # Do initial drawing (in case there is not an initial size event)
+ self.RecalcCoords(self.GetSize())
+ self.DrawBox()
+
+ # 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 = wx.Timer(self)
+ self.timer.Start(500)
+
+
+ def DoGetBestSize(self):
+ # Just pull a number out of the air. If there is a way to
+ # calculate this then it should be done...
+ size = wx.Size(50,50)
+ self.CacheBestSize(size)
+ return size
+
+
+ def _OnSize(self, evt):
+ size = self.GetClientSize()
+ if size.x < 1 or size.y < 1:
+ return
+
+ self.RecalcCoords(size)
+ self.DrawBox()
+
+
+ def _OnPaint(self, evt):
+ dc = wx.BufferedPaintDC(self)
+ self.DrawHands(dc)
+
+
+ def _OnTimer(self, evt):
+ dc = wx.BufferedDC(wx.ClientDC(self), self.GetClientSize())
+ self.DrawHands(dc)
+
+
+ def _OnDestroyWindow(self, evt):
+ self.timer.Stop()
+ del self.timer
+
+
+ def _OnContextMenu(self, evt):
+ self.PopupMenu(self.cm)
+
+
+ def _OnShowSetup(self, evt):
+ if self.Setup is None:
+ self.Setup = Setup(self)
+ self.Setup.Show()
+ self.Setup.Raise()
+
+
+ def _OnShowAbout(self, evt):
+ msg = "AnalogClock\n\n" \
+ "by Several folks on wxPython-users\n" \
+ "with enhancements from E. A. Tacao."
+ title = "About..."
+ style = wx.OK|wx.ICON_INFORMATION
+
+ dlg = wx.MessageDialog(self, msg, title, style)
+ dlg.ShowModal()
+ dlg.Destroy()
+
+
+ def _recalcCoords(self, size):
+ """
+ Recalculates all coordinates/geometry and inits the faceBitmap
+ to make sure the buffer is always the same size as the window.
+ """
+
+ self.faceBitmap = wx.EmptyBitmap(*size.Get())
+
+ # Recalc all coords.
+ scale = min([float(size.width) / self.basesize.width,
+ float(size.height) / self.basesize.height])
+
+ centre = wx.Point(size.width / 2., size.height / 2.)
+
+ self.Box.RecalcCoords(size, centre, scale)
+ self.Hands.RecalcCoords(size, centre, scale)
+
+ # Try to find a 'nice' maximum length for the hands so that they won't
+ # overlap the tick marks. OTOH, if you do want to allow overlapping the
+ # lenfac value (defined on __init__ above) has to be set to
+ # something > 1.
+ niceradius = self.Box.GetNiceRadiusForHands(centre)
+ self.Hands.SetMaxRadius(niceradius)
+
+
+ def _drawBox(self):
+ """Draws clock face and tick marks."""
+
+ dc = wx.BufferedDC(wx.ClientDC(self), self.GetClientSize())
+ dc.BeginDrawing()
+ dc.SelectObject(self.faceBitmap)
+ dc.SetBackground(wx.Brush(self.GetBackgroundColour(), wx.SOLID))
+ dc.Clear()
+ self.Box.Draw(dc)
+ dc.EndDrawing()
+
+
+ def _drawHands(self, dc):
+ """
+ Draws the face bitmap, created on the last DrawBox call, and
+ clock hands.
+ """
+
+ dc.BeginDrawing()
+ dc.DrawBitmap(self.faceBitmap, 0, 0)
+ self.Hands.Draw(dc)
+ dc.EndDrawing()
+
+
+ # Public methods --------------------------------------------------
+
+ def GetHandSize(self, target=ALL):
+ """Gets thickness of hands."""
+
+ return self.Hands.GetSize(target)
+
+
+ def GetHandFillColour(self, target=ALL):
+ """Gets fill colours of hands."""
+
+ return self.Hands.GetFillColour(target)
+
+
+ def GetHandBorderColour(self, target=ALL):
+ """Gets border colours of hands."""
+
+ return self.Hands.GetBorderColour(target)
+
+
+ def GetHandBorderWidth(self, target=ALL):
+ """Gets border widths of hands."""
+
+ return self.Hands.GetBorderWidth(target)
+
+
+ def GetTickSize(self, target=ALL):
+ """Gets sizes of ticks."""
+
+ return self.Box.GetTickSize(target)
+
+
+
+ def GetTickFillColour(self, target=ALL):
+ """Gets fill colours of ticks."""
+
+ return self.Box.GetTickFillColour(target)
+
+
+
+ def GetTickBorderColour(self, target=ALL):
+ """Gets border colours of ticks."""
+
+ return self.Box.GetTickBorderColour(target)
+
+
+
+ def GetTickBorderWidth(self, target=ALL):
+ """Gets border widths of ticks."""
+
+ return self.Box.GetTickBorderWidth(target)
+
+
+
+ def GetTickPolygon(self, target=ALL):
+ """
+ Gets lists of points to be used as polygon shapes
+ when using the TICKS_POLY style.
+ """
+
+ return self.Box.GetTickPolygon(target)
+
+
+
+ def GetTickFont(self, target=ALL):
+ """
+ Gets fonts for tick marks when using TICKS_DECIMAL or
+ TICKS_ROMAN style.
+ """
+
+ return self.Box.GetTickFont(target)
+
+
+
+ def GetTickOffset(self, target=ALL):
+ """Gets the distance of tick marks for hours from border."""
+
+ return self.Box.GetTickOffset(target)
+
+
+
+ def GetFaceFillColour(self):
+ """Gets fill colours of watch."""
+
+ return self.Box.Face.GetFillColour()
+
+
+
+ def GetFaceBorderColour(self):
+ """Gets border colours of watch."""
+
+ return self.Box.Face.GetBorderColour()
+
+
+
+ def GetFaceBorderWidth(self):
+ """Gets border width of watch."""
+
+ return self.Box.Face.GetBorderWidth()
+
+
+
+ def GetShadowColour(self):
+ """Gets the colour to be used to draw shadows."""
+
+ a_clock_part = self.Box
+ return a_clock_part.GetShadowColour()
+
+
+
+ def GetClockStyle(self):
+ """Returns the current clock style."""
+
+ return self.clockStyle
+
+
+ def GetTickStyle(self, target=ALL):
+ """Gets the tick style(s)."""
+
+ return self.Box.GetTickStyle(target)
+
+
+ def Refresh(self):
+ """
+ Overriden base wx.Window method. Forces an immediate
+ recalculation and redraw of all clock elements.
+ """
+
+ size = self.GetClientSize()
+ if size.x < 1 or size.y < 1:
+ return
+ self.Freeze()
+ self.RecalcCoords(size)
+ self.DrawBox()
+ dc = wx.BufferedDC(wx.ClientDC(self), self.GetClientSize())
+ self.DrawHands(dc)
+ self.Thaw()
+
+
+ def SetHandSize(self, size, target=ALL):
+ """Sets thickness of hands."""
+
+ self.Hands.SetSize(size, target)
+
+
+ def SetHandFillColour(self, colour, target=ALL):
+ """Sets fill colours of hands."""
+
+ self.Hands.SetFillColour(colour, target)
+
+
+ def SetHandBorderColour(self, colour, target=ALL):
+ """Sets border colours of hands."""
+
+ self.Hands.SetBorderColour(colour, target)
+
+
+ def SetHandBorderWidth(self, width, target=ALL):
+ """Sets border widths of hands."""
+
+ self.Hands.SetBorderWidth(width, target)
+
+
+ def SetTickSize(self, size, target=ALL):
+ """Sets sizes of ticks."""
+
+ self.Box.SetTickSize(size, target)
+ self.Refresh()
+
+
+ def SetTickFillColour(self, colour, target=ALL):
+ """Sets fill colours of ticks."""
+
+ self.Box.SetTickFillColour(colour, target)
+ self.Refresh()
+
+
+ def SetTickBorderColour(self, colour, target=ALL):
+ """Sets border colours of ticks."""
+
+ self.Box.SetTickBorderColour(colour, target)
+ self.Refresh()
+
+
+ def SetTickBorderWidth(self, width, target=ALL):
+ """Sets border widths of ticks."""
+
+ self.Box.SetTickBorderWidth(width, target)
+ self.Refresh()
+
+
+ def SetTickPolygon(self, polygon, target=ALL):
+ """
+ Sets lists of points to be used as polygon shapes
+ when using the TICKS_POLY style.
+ """
+
+ self.Box.SetTickPolygon(polygon, target)
+ self.Refresh()
+
+
+ def SetTickFont(self, font, target=ALL):
+ """
+ Sets fonts for tick marks when using text-based tick styles
+ such as TICKS_DECIMAL or TICKS_ROMAN.
+ """
+
+ self.Box.SetTickFont(font, target)
+ self.Refresh()
+
+
+ def SetTickOffset(self, offset, target=ALL):
+ """Sets the distance of tick marks for hours from border."""
+
+ self.Box.SetTickOffset(offset, target)
+ self.Refresh()
+
+
+ def SetFaceFillColour(self, colour):
+ """Sets fill colours of watch."""
+
+ self.Box.Face.SetFillColour(colour)
+ self.Refresh()
+
+
+ def SetFaceBorderColour(self, colour):
+ """Sets border colours of watch."""
+
+ self.Box.Face.SetBorderColour(colour)
+ self.Refresh()
+
+
+ def SetFaceBorderWidth(self, width):
+ """Sets border width of watch."""
+
+ self.Box.Face.SetBorderWidth(width)
+ self.Refresh()
+
+
+ def SetShadowColour(self, colour):
+ """Sets the colour to be used to draw shadows."""
+
+ self.Hands.SetShadowColour(colour)
+ self.Box.SetShadowColour(colour)
+ self.Refresh()
+
+
+ def SetClockStyle(self, style):
+ """
+ Set the clock style, according to the options below.
+
+ ==================== ================================
+ 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
+ self.Box.SetIsRotated(style & ROTATE_TICKS)
+ self.Refresh()
+
+
+ def SetTickStyle(self, style, target=ALL):
+ """
+ Set the tick style, according 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. A
+ polygon can be passed using
+ SetTickPolygon, otherwise the default
+ polygon will be used.
+ TICKS_DECIMAL Use decimal numbers as tick marks.
+ TICKS_ROMAN Use Roman numbers as tick marks.
+ TICKS_BINARY Use binary numbers as tick marks.
+ TICKS_HEX Use hexadecimal numbers as tick marks.
+ ================= ======================================
+ """
+
+ self.Box.SetTickStyle(style, target)
+ self.Refresh()
+
+
+ def SetBackgroundColour(self, colour):
+ """Overriden base wx.Window method."""
+
+ wx.Window.SetBackgroundColour(self, colour)
+ self.Refresh()
+
+
+ def SetForegroundColour(self, colour):
+ """
+ Overriden base wx.Window method. This method sets a colour for
+ all hands and ticks at once.
+ """
+
+ wx.Window.SetForegroundColour(self, colour)
+ self.SetHandFillColour(colour)
+ self.SetHandBorderColour(colour)
+ self.SetTickFillColour(colour)
+ self.SetTickBorderColour(colour)
+ self.Refresh()
+
+
+ def SetWindowStyle(self, *args, **kwargs):
+ """Overriden base wx.Window method."""
+
+ size = self.GetSize()
+ self.Freeze()
+ wx.Window.SetWindowStyle(self, *args, **kwargs)
+ self.SetSize((10, 10))
+ self.SetSize(size)
+ self.Thaw()
+
+
+ def SetWindowStyleFlag(self, *args, **kwargs):
+ """Overriden base wx.Window method."""
+
+ self.SetWindowStyle(*args, **kwargs)
+
+
+# For backwards compatibility -----------------------------------------
+
+class AnalogClockWindow(AnalogClock):
+ """
+ A simple derived class that provides some backwards compatibility
+ with the old analogclock module.
+ """
+ def SetTickShapes(self, tsh, tsm=None):
+ self.SetTickPolygon(tsh)
+
+ def SetHandWeights(self, h=None, m=None, s=None):
+ if h:
+ self.SetHandSize(h, HOUR)
+ if m:
+ self.SetHandSize(m, MINUTE)
+ if s:
+ self.SetHandSize(h, SECOND)
+
+ def SetHandColours(self, h=None, m=None, s=None):
+ if h and not m and not s:
+ m=h
+ s=h
+ if h:
+ self.SetHandBorderColour(h, HOUR)
+ self.SetHandFillColour(h, HOUR)
+ if m:
+ self.SetHandBorderColour(m, MINUTE)
+ self.SetHandFillColour(m, MINUTE)
+ if s:
+ self.SetHandBorderColour(h, SECOND)
+ self.SetHandFillColour(h, SECOND)
+
+ def SetTickColours(self, h=None, m=None):
+ if not m:
+ m=h
+ if h:
+ self.SetTickBorderColour(h, HOUR)
+ self.SetTickFillColour(h, HOUR)
+ if m:
+ self.SetTickBorderColour(m, MINUTE)
+ self.SetTickFillColour(m, MINUTE)
+
+ def SetTickSizes(self, h=None, m=None):
+ if h:
+ self.SetTickSize(h, HOUR)
+ if m:
+ self.SetTickSize(h, MINUTE)
+
+ def SetTickFontss(self, h=None, m=None):
+ if h:
+ self.SetTickFont(h, HOUR)
+ if m:
+ self.SetTickFont(h, MINUTE)
+
+
+ def SetMinutesOffset(self, o):
+ pass
+
+ def SetShadowColour(self, s):
+ pass
+
+ def SetWatchPenBrush(self, p=None, b=None):
+ if p:
+ self.SetFaceBorderColour(p.GetColour())
+ self.SetFaceBorderWidth(p.GetWidth())
+ if b:
+ self.SetFaceFillColour(b.GetColour())
+
+ def SetClockStyle(self, style):
+ style |= SHOW_HOURS_HAND|SHOW_MINUTES_HAND|SHOW_SECONDS_HAND
+ AnalogClock.SetClockStyle(self, style)
+
+ def SetTickStyles(self, h=None, m=None):
+ if h:
+ self.SetTickStyle(h, HOUR)
+ if m:
+ self.SetTickStyle(h, MINUTE)
+
+
+# Test stuff ----------------------------------------------------------
+
+if __name__ == "__main__":
+ print wx.VERSION_STRING
+
+ class AcDemoApp(wx.App):
+ def OnInit(self):
+ frame = wx.Frame(None, -1, "AnalogClock", size=(375, 375))
+ clock = AnalogClock(frame)
+ frame.CentreOnScreen()
+ frame.Show()
+ return True
+
+ acApp = AcDemoApp(0)
+ acApp.MainLoop()
+
+
+#
+##
+### eof