1 # AnalogClock's main class
2 # E. A. Tacao <e.a.tacao |at| estadao.com.br>
3 # http://j.domaindlx.com/elements28/wxpython/
4 # 15 Fev 2006, 22:00 GMT-03:00
5 # Distributed under the wxWidgets license.
7 # For more info please see the __init__.py file.
12 from helpers
import Dyer
, Face
, Hand
, HandSet
, TickSet
, Box
13 from setup
import Setup
15 #----------------------------------------------------------------------
17 class AnalogClock(wx
.PyWindow
):
18 """An analog clock."""
20 def __init__(self
, parent
, id=wx
.ID_ANY
, pos
=wx
.DefaultPosition
,
21 size
=wx
.DefaultSize
, style
=wx
.NO_BORDER
, name
="AnalogClock",
22 clockStyle
=DEFAULT_CLOCK_STYLE
,
23 minutesStyle
=TICKS_CIRCLE
, hoursStyle
=TICKS_POLY
):
25 wx
.PyWindow
.__init
__(self
, parent
, id, pos
, size
, style
, name
)
27 # Base size for scale calc purposes.
28 self
.basesize
= wx
.Size(348, 348)
30 # Store some references.
31 self
.clockStyle
= clockStyle
32 self
.minutesStyle
= minutesStyle
33 self
.hoursStyle
= hoursStyle
35 self
.DrawHands
= self
._drawHands
36 self
.DrawBox
= self
._drawBox
37 self
.RecalcCoords
= self
._recalcCoords
41 self
.allHandStyles
= [SHOW_HOURS_HAND
,
45 # Initialize clock face.
47 # By default we don't use colours or borders on the clock face.
48 bg
= self
.GetBackgroundColour()
49 face
= Face(dyer
=Dyer(bg
, 0, bg
))
51 # Initialize tick marks.
53 # TickSet is a set of tick marks; there's always two TickSets defined
54 # regardless whether they're being shown or not.
55 ticksM
= TickSet(self
, style
=minutesStyle
, size
=5, kind
="minutes")
56 ticksH
= TickSet(self
, style
=hoursStyle
, size
=25, kind
="hours",
57 rotate
=clockStyle
&ROTATE_TICKS
)
59 # Box holds the clock face and tick marks.
60 self
.Box
= Box(self
, face
, ticksM
, ticksH
)
64 # HandSet is the set of hands; there's always one HandSet defined
65 # regardless whether hands are being shown or not.
67 # A 'lenfac = 0.95', e.g., means that the lenght of that hand will
68 # be 95% of the maximum allowed hand lenght ('nice' maximum lenght).
69 handH
= Hand(size
=7, lenfac
=0.7)
70 handM
= Hand(size
=5, lenfac
=0.95)
71 handS
= Hand(size
=1, lenfac
=0.95)
72 self
.Hands
= HandSet(self
, handH
, handM
, handS
)
74 # Create the customization dialog.
77 # Make a context menu.
80 cm
= self
.cm
= wx
.Menu()
81 cm
.Append(popup1
, "Customize...")
82 cm
.Append(popup2
, "About...")
85 self
.Bind(wx
.EVT_SIZE
, self
._OnSize
)
86 self
.Bind(wx
.EVT_PAINT
, self
._OnPaint
)
87 self
.Bind(wx
.EVT_ERASE_BACKGROUND
, lambda evt
: None)
88 self
.Bind(wx
.EVT_TIMER
, self
._OnTimer
)
89 self
.Bind(wx
.EVT_WINDOW_DESTROY
, self
._OnDestroyWindow
)
90 self
.Bind(wx
.EVT_CONTEXT_MENU
, self
._OnContextMenu
)
91 self
.Bind(wx
.EVT_MENU
, self
._OnShowSetup
, id=popup1
)
92 self
.Bind(wx
.EVT_MENU
, self
._OnShowAbout
, id=popup2
)
94 # Set initial size based on given size, or best size
95 self
.SetBestFittingSize(size
)
97 # Do initial drawing (in case there is not an initial size event)
98 self
.RecalcCoords(self
.GetSize())
101 # Initialize the timer that drives the update of the clock face.
102 # Update every half second to ensure that there is at least one true
103 # update during each realtime second.
104 self
.timer
= wx
.Timer(self
)
105 self
.timer
.Start(500)
108 def DoGetBestSize(self
):
109 # Just pull a number out of the air. If there is a way to
110 # calculate this then it should be done...
111 size
= wx
.Size(50,50)
112 self
.CacheBestSize(size
)
116 def _OnSize(self
, evt
):
117 size
= self
.GetClientSize()
118 if size
.x
< 1 or size
.y
< 1:
121 self
.RecalcCoords(size
)
125 def _OnPaint(self
, evt
):
126 dc
= wx
.BufferedPaintDC(self
)
130 def _OnTimer(self
, evt
):
131 dc
= wx
.BufferedDC(wx
.ClientDC(self
), self
.GetClientSize())
135 def _OnDestroyWindow(self
, evt
):
140 def _OnContextMenu(self
, evt
):
141 self
.PopupMenu(self
.cm
)
144 def _OnShowSetup(self
, evt
):
145 if self
.Setup
is None:
146 self
.Setup
= Setup(self
)
151 def _OnShowAbout(self
, evt
):
152 msg
= "AnalogClock\n\n" \
153 "by Several folks on wxPython-users\n" \
154 "with enhancements from E. A. Tacao."
156 style
= wx
.OK|wx
.ICON_INFORMATION
158 dlg
= wx
.MessageDialog(self
, msg
, title
, style
)
163 def _recalcCoords(self
, size
):
165 Recalculates all coordinates/geometry and inits the faceBitmap
166 to make sure the buffer is always the same size as the window.
169 self
.faceBitmap
= wx
.EmptyBitmap(*size
.Get())
172 scale
= min([float(size
.width
) / self
.basesize
.width
,
173 float(size
.height
) / self
.basesize
.height
])
175 centre
= wx
.Point(size
.width
/ 2., size
.height
/ 2.)
177 self
.Box
.RecalcCoords(size
, centre
, scale
)
178 self
.Hands
.RecalcCoords(size
, centre
, scale
)
180 # Try to find a 'nice' maximum length for the hands so that they won't
181 # overlap the tick marks. OTOH, if you do want to allow overlapping the
182 # lenfac value (defined on __init__ above) has to be set to
184 niceradius
= self
.Box
.GetNiceRadiusForHands(centre
)
185 self
.Hands
.SetMaxRadius(niceradius
)
189 """Draws clock face and tick marks."""
191 dc
= wx
.BufferedDC(wx
.ClientDC(self
), self
.GetClientSize())
193 dc
.SelectObject(self
.faceBitmap
)
194 dc
.SetBackground(wx
.Brush(self
.GetBackgroundColour(), wx
.SOLID
))
200 def _drawHands(self
, dc
):
202 Draws the face bitmap, created on the last DrawBox call, and
207 dc
.DrawBitmap(self
.faceBitmap
, 0, 0)
212 # Public methods --------------------------------------------------
214 def GetHandSize(self
, target
=ALL
):
215 """Gets thickness of hands."""
217 return self
.Hands
.GetSize(target
)
220 def GetHandFillColour(self
, target
=ALL
):
221 """Gets fill colours of hands."""
223 return self
.Hands
.GetFillColour(target
)
226 def GetHandBorderColour(self
, target
=ALL
):
227 """Gets border colours of hands."""
229 return self
.Hands
.GetBorderColour(target
)
232 def GetHandBorderWidth(self
, target
=ALL
):
233 """Gets border widths of hands."""
235 return self
.Hands
.GetBorderWidth(target
)
238 def GetTickSize(self
, target
=ALL
):
239 """Gets sizes of ticks."""
241 return self
.Box
.GetTickSize(target
)
245 def GetTickFillColour(self
, target
=ALL
):
246 """Gets fill colours of ticks."""
248 return self
.Box
.GetTickFillColour(target
)
252 def GetTickBorderColour(self
, target
=ALL
):
253 """Gets border colours of ticks."""
255 return self
.Box
.GetTickBorderColour(target
)
259 def GetTickBorderWidth(self
, target
=ALL
):
260 """Gets border widths of ticks."""
262 return self
.Box
.GetTickBorderWidth(target
)
266 def GetTickPolygon(self
, target
=ALL
):
268 Gets lists of points to be used as polygon shapes
269 when using the TICKS_POLY style.
272 return self
.Box
.GetTickPolygon(target
)
276 def GetTickFont(self
, target
=ALL
):
278 Gets fonts for tick marks when using TICKS_DECIMAL or
282 return self
.Box
.GetTickFont(target
)
286 def GetTickOffset(self
, target
=ALL
):
287 """Gets the distance of tick marks for hours from border."""
289 return self
.Box
.GetTickOffset(target
)
293 def GetFaceFillColour(self
):
294 """Gets fill colours of watch."""
296 return self
.Box
.Face
.GetFillColour()
300 def GetFaceBorderColour(self
):
301 """Gets border colours of watch."""
303 return self
.Box
.Face
.GetBorderColour()
307 def GetFaceBorderWidth(self
):
308 """Gets border width of watch."""
310 return self
.Box
.Face
.GetBorderWidth()
314 def GetShadowColour(self
):
315 """Gets the colour to be used to draw shadows."""
317 a_clock_part
= self
.Box
318 return a_clock_part
.GetShadowColour()
322 def GetClockStyle(self
):
323 """Returns the current clock style."""
325 return self
.clockStyle
328 def GetTickStyle(self
, target
=ALL
):
329 """Gets the tick style(s)."""
331 return self
.Box
.GetTickStyle(target
)
336 Overriden base wx.Window method. Forces an immediate
337 recalculation and redraw of all clock elements.
340 size
= self
.GetClientSize()
341 if size
.x
< 1 or size
.y
< 1:
344 self
.RecalcCoords(size
)
346 dc
= wx
.BufferedDC(wx
.ClientDC(self
), self
.GetClientSize())
351 def SetHandSize(self
, size
, target
=ALL
):
352 """Sets thickness of hands."""
354 self
.Hands
.SetSize(size
, target
)
357 def SetHandFillColour(self
, colour
, target
=ALL
):
358 """Sets fill colours of hands."""
360 self
.Hands
.SetFillColour(colour
, target
)
363 def SetHandBorderColour(self
, colour
, target
=ALL
):
364 """Sets border colours of hands."""
366 self
.Hands
.SetBorderColour(colour
, target
)
369 def SetHandBorderWidth(self
, width
, target
=ALL
):
370 """Sets border widths of hands."""
372 self
.Hands
.SetBorderWidth(width
, target
)
375 def SetTickSize(self
, size
, target
=ALL
):
376 """Sets sizes of ticks."""
378 self
.Box
.SetTickSize(size
, target
)
382 def SetTickFillColour(self
, colour
, target
=ALL
):
383 """Sets fill colours of ticks."""
385 self
.Box
.SetTickFillColour(colour
, target
)
389 def SetTickBorderColour(self
, colour
, target
=ALL
):
390 """Sets border colours of ticks."""
392 self
.Box
.SetTickBorderColour(colour
, target
)
396 def SetTickBorderWidth(self
, width
, target
=ALL
):
397 """Sets border widths of ticks."""
399 self
.Box
.SetTickBorderWidth(width
, target
)
403 def SetTickPolygon(self
, polygon
, target
=ALL
):
405 Sets lists of points to be used as polygon shapes
406 when using the TICKS_POLY style.
409 self
.Box
.SetTickPolygon(polygon
, target
)
413 def SetTickFont(self
, font
, target
=ALL
):
415 Sets fonts for tick marks when using text-based tick styles
416 such as TICKS_DECIMAL or TICKS_ROMAN.
419 self
.Box
.SetTickFont(font
, target
)
423 def SetTickOffset(self
, offset
, target
=ALL
):
424 """Sets the distance of tick marks for hours from border."""
426 self
.Box
.SetTickOffset(offset
, target
)
430 def SetFaceFillColour(self
, colour
):
431 """Sets fill colours of watch."""
433 self
.Box
.Face
.SetFillColour(colour
)
437 def SetFaceBorderColour(self
, colour
):
438 """Sets border colours of watch."""
440 self
.Box
.Face
.SetBorderColour(colour
)
444 def SetFaceBorderWidth(self
, width
):
445 """Sets border width of watch."""
447 self
.Box
.Face
.SetBorderWidth(width
)
451 def SetShadowColour(self
, colour
):
452 """Sets the colour to be used to draw shadows."""
454 self
.Hands
.SetShadowColour(colour
)
455 self
.Box
.SetShadowColour(colour
)
459 def SetClockStyle(self
, style
):
461 Set the clock style, according to the options below.
463 ==================== ================================
464 SHOW_QUARTERS_TICKS Show marks for hours 3, 6, 9, 12
465 SHOW_HOURS_TICKS Show marks for all hours
466 SHOW_MINUTES_TICKS Show marks for minutes
468 SHOW_HOURS_HAND Show hours hand
469 SHOW_MINUTES_HAND Show minutes hand
470 SHOW_SECONDS_HAND Show seconds hand
472 SHOW_SHADOWS Show hands and marks shadows
474 ROTATE_TICKS Align tick marks to watch
475 OVERLAP_TICKS Draw tick marks for minutes even
476 when they match the hours marks.
477 ==================== ================================
480 self
.clockStyle
= style
481 self
.Box
.SetIsRotated(style
& ROTATE_TICKS
)
485 def SetTickStyle(self
, style
, target
=ALL
):
487 Set the tick style, according to the options below.
489 ================= ======================================
490 TICKS_NONE Don't show tick marks.
491 TICKS_SQUARE Use squares as tick marks.
492 TICKS_CIRCLE Use circles as tick marks.
493 TICKS_POLY Use a polygon as tick marks. A
494 polygon can be passed using
495 SetTickPolygon, otherwise the default
496 polygon will be used.
497 TICKS_DECIMAL Use decimal numbers as tick marks.
498 TICKS_ROMAN Use Roman numbers as tick marks.
499 TICKS_BINARY Use binary numbers as tick marks.
500 TICKS_HEX Use hexadecimal numbers as tick marks.
501 ================= ======================================
504 self
.Box
.SetTickStyle(style
, target
)
508 def SetBackgroundColour(self
, colour
):
509 """Overriden base wx.Window method."""
511 wx
.Window
.SetBackgroundColour(self
, colour
)
515 def SetForegroundColour(self
, colour
):
517 Overriden base wx.Window method. This method sets a colour for
518 all hands and ticks at once.
521 wx
.Window
.SetForegroundColour(self
, colour
)
522 self
.SetHandFillColour(colour
)
523 self
.SetHandBorderColour(colour
)
524 self
.SetTickFillColour(colour
)
525 self
.SetTickBorderColour(colour
)
529 def SetWindowStyle(self
, *args
, **kwargs
):
530 """Overriden base wx.Window method."""
532 size
= self
.GetSize()
534 wx
.Window
.SetWindowStyle(self
, *args
, **kwargs
)
535 self
.SetSize((10, 10))
540 def SetWindowStyleFlag(self
, *args
, **kwargs
):
541 """Overriden base wx.Window method."""
543 self
.SetWindowStyle(*args
, **kwargs
)
546 # For backwards compatibility -----------------------------------------
548 class AnalogClockWindow(AnalogClock
):
550 A simple derived class that provides some backwards compatibility
551 with the old analogclock module.
553 def SetTickShapes(self
, tsh
, tsm
=None):
554 self
.SetTickPolygon(tsh
)
556 def SetHandWeights(self
, h
=None, m
=None, s
=None):
558 self
.SetHandSize(h
, HOUR
)
560 self
.SetHandSize(m
, MINUTE
)
562 self
.SetHandSize(h
, SECOND
)
564 def SetHandColours(self
, h
=None, m
=None, s
=None):
565 if h
and not m
and not s
:
569 self
.SetHandBorderColour(h
, HOUR
)
570 self
.SetHandFillColour(h
, HOUR
)
572 self
.SetHandBorderColour(m
, MINUTE
)
573 self
.SetHandFillColour(m
, MINUTE
)
575 self
.SetHandBorderColour(h
, SECOND
)
576 self
.SetHandFillColour(h
, SECOND
)
578 def SetTickColours(self
, h
=None, m
=None):
582 self
.SetTickBorderColour(h
, HOUR
)
583 self
.SetTickFillColour(h
, HOUR
)
585 self
.SetTickBorderColour(m
, MINUTE
)
586 self
.SetTickFillColour(m
, MINUTE
)
588 def SetTickSizes(self
, h
=None, m
=None):
590 self
.SetTickSize(h
, HOUR
)
592 self
.SetTickSize(h
, MINUTE
)
594 def SetTickFontss(self
, h
=None, m
=None):
596 self
.SetTickFont(h
, HOUR
)
598 self
.SetTickFont(h
, MINUTE
)
601 def SetMinutesOffset(self
, o
):
604 def SetShadowColour(self
, s
):
607 def SetWatchPenBrush(self
, p
=None, b
=None):
609 self
.SetFaceBorderColour(p
.GetColour())
610 self
.SetFaceBorderWidth(p
.GetWidth())
612 self
.SetFaceFillColour(b
.GetColour())
614 def SetClockStyle(self
, style
):
615 style |
= SHOW_HOURS_HAND|SHOW_MINUTES_HAND|SHOW_SECONDS_HAND
616 AnalogClock
.SetClockStyle(self
, style
)
618 def SetTickStyles(self
, h
=None, m
=None):
620 self
.SetTickStyle(h
, HOUR
)
622 self
.SetTickStyle(h
, MINUTE
)
625 # Test stuff ----------------------------------------------------------
627 if __name__
== "__main__":
628 print wx
.VERSION_STRING
630 class AcDemoApp(wx
.App
):
632 frame
= wx
.Frame(None, -1, "AnalogClock", size
=(375, 375))
633 clock
= AnalogClock(frame
)
634 frame
.CentreOnScreen()