+# -*- coding: iso-8859-1 -*-
#----------------------------------------------------------------------
-# Name: wxPython.lib.analogclock
+# Name: wx.lib.analogclock
# Purpose: A simple analog clock window
#
# Author: several folks on wxPython-users
# o Updated for wx namespace
# o Tested with updated demo and with builtin test.
#
+# 15-February-2004 - E. A. Tacao
+#
+# o Many ehnacements
+#
+
+"""
+`AnalogClockWindow` is a simple analog clock class.
+"""
+
+import math
+import sys
+import string
+import time
+
+import wx
-import math
-import string
-import sys
-import time
+from analogclockopts import ACCustomizationFrame
-import wx
-class AnalogClockWindow(wx.Window):
- """A simple analog clock window"""
+# 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
- TICKS_NONE = 0
- TICKS_SQUARE = 1
- TICKS_CIRCLE = 2
+# 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...
- wx.Window.__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(1, 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
+
+ size = wx.Size(*size)
+ bestSize = self.GetBestSize()
+ size.x = max(size.x, bestSize.x)
+ size.y = max(size.y, bestSize.y)
+ self.SetSize(size)
+
# Make an initial bitmap for the face, it will be updated and
# painted at the first EVT_SIZE event.
W, H = size
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
self.timer = wx.Timer(self)
self.timer.Start(500)
- # 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)
+ def DoGetBestSize(self):
+ return wx.Size(25,25)
- 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 OnPaint(self, event):
+ dc = wx.BufferedPaintDC(self)
+ if hasattr(self, 'coords'):
+ 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
+ def OnTimerExpire(self, event):
+ size = self.GetClientSize()
+ dc = wx.BufferedDC(wx.ClientDC(self), size)
+ self._doDrawHands(dc, True)
- SetTickMarkColour = SetTickMarkColours
+ def OnQuit(self, event):
+ self.timer.Stop()
+ del self.timer
- def SetHandsColour(self, c):
- """An alias for SetForegroundColour"""
- self.SetForegroundColour(c) # the hands just use the foreground colour
+
+ def OnRightDown(self, event):
+ self.x = event.GetX()
+ self.y = event.GetY()
+ event.Skip()
- # 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 = wx.EmptyBitmap(size.width, size.height)
- self.DrawFace()
+ 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()
- def OnPaint(self, event):
- self.DrawHands(wx.PaintDC(self))
+ sm.Append(self.popupID1, "Customize...")
+ sm.Append(self.popupID2, "About...")
+ # 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 OnQuit(self, event):
- self.timer.Stop()
- del self.timer
+ def OnPopupOne(self, event):
+ self.prefs_open=True
+ frame = ACCustomizationFrame(self, -1, "AnalogClock Preferences")
+ frame.Show(True)
- def OnTimerExpire(self, event):
- self.DrawHands(wx.ClientDC(self))
+ 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()
- def DrawHands(self, drawDC):
- # Start by drawing the face bitmap
- drawDC.DrawBitmap(self.faceBitmap, (0,0))
- currentTime = time.localtime(time.time())
- hour, minutes, seconds = currentTime[3:6]
+ 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()
+ if size.x < 1 or size.y < 1:
+ return
+
+ self.faceBitmap = wx.EmptyBitmap(size.width, size.height)
+
+ # Update drawing coordinates...
+ new_dim = size.Get()
+ if not hasattr(self,"dim"):
+ self.dim = new_dim
+
+ 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
- W,H = self.faceBitmap.GetWidth(), self.faceBitmap.GetHeight()
- centerX = W / 2
- centerY = H / 2
+ self.shadowDistance = 2 * self.scale
- 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.radius_watch = min(self.centerX, self.centerY)
- # Draw the hour hand...
- drawDC.SetPen(wx.Pen(self.GetForegroundColour(), 5, wx.SOLID))
- drawDC.DrawLine((centerX, centerY), (hourX, hourY))
+ self._doDrawFace()
+
- # Draw the minutes hand...
- drawDC.SetPen(wx.Pen(self.GetForegroundColour(), 3, wx.SOLID))
- drawDC.DrawLine((centerX, centerY), (minutesX, minutesY))
- # Draw the seconds hand...
- drawDC.SetPen(wx.Pen(self.GetForegroundColour(), 1, wx.SOLID))
- drawDC.DrawLine((centerX, centerY), (secondsX, secondsY))
+ def _doDrawHands(self, drawDC, force=0):
+ currentTime = list(time.localtime(time.time())[3:6])
+ if not (self.handsStyle & SHOW_SECONDS_HAND):
+ currentTime[2]=-1
- # Draw the specified set of line marks inside the clock face for the
- # hours or minutes...
- def DrawFace(self):
+ 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)
+
+
+ # 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.DrawLine(self.centerX + self.shadowDistance,
+ self.centerY + self.shadowDistance,
+ x + self.shadowDistance,
+ 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.DrawLine(self.centerX + self.shadowDistance,
+ self.centerY + self.shadowDistance,
+ x + self.shadowDistance,
+ 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.DrawLine(self.centerX + self.shadowDistance,
+ self.centerY + self.shadowDistance,
+ x + self.shadowDistance,
+ 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.DrawLine(self.centerX, self.centerY, x, 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.DrawLine(self.centerX, self.centerY, x, 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.DrawLine(self.centerX, self.centerY, x, y)
+
+
+
+ def _doDrawFace(self):
backgroundBrush = wx.Brush(self.GetBackgroundColour(), wx.SOLID)
drawDC = wx.MemoryDC()
drawDC.SelectObject(self.faceBitmap)
drawDC.SetBackground(backgroundBrush)
drawDC.Clear()
- W,H = self.faceBitmap.GetWidth(), self.faceBitmap.GetHeight()
- centerX = W / 2
- centerY = H / 2
+ 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))
+
+ 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 watch...
+ self._drawWatch(drawDC)
# Draw the marks for hours and minutes...
- self.DrawTimeMarks(drawDC, self.minuteMarks, centerX, centerY, 4)
- self.DrawTimeMarks(drawDC, self.hourMarks, centerX, centerY, 9)
+ 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, size, size)
+
+ elif style & TICKS_SQUARE:
+ x, y = self._center2corner(x, y, tipo)
+ drawDC.DrawRectangle(x, y, size, 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, {}]}
+
+ radiansPerDegree = math.pi / 180
+ 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]]
- 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
+ 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.
+ """
- drawDC.SetBrush(wx.Brush(self.tickMarksBrushC, wx.SOLID))
- drawDC.SetPen(wx.Pen(self.tickMarksPenC, 1, wx.SOLID))
+ if not tsm:
+ tsm=tsh
- 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))
+ self.tickShapeHours = tsh
+ self.tickShapeMinutes = tsm
- 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 wx.Point(pointX, pointY)
+ def SetHandWeights(self, h=None, m=None, s=None):
+ """
+ h, m, s: value
+
+ 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 these 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__":
+ print wx.VERSION_STRING
class App(wx.App):
def OnInit(self):
- frame = wx.Frame(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(wx.BOTH)
frame.Show(True)
theApp.MainLoop()
-
+#
+##
+### eof