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
):
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 onto the faceBitmap."""
190 dc
= wx
.BufferedDC(None, self
.faceBitmap
)
191 dc
.SetBackground(wx
.Brush(self
.GetBackgroundColour(), wx
.SOLID
))
196 def _drawHands(self
, dc
):
198 Draws the face bitmap, created on the last DrawBox call, and
201 dc
.DrawBitmap(self
.faceBitmap
, 0, 0)
205 # Public methods --------------------------------------------------
207 def GetHandSize(self
, target
=ALL
):
208 """Gets thickness of hands."""
210 return self
.Hands
.GetSize(target
)
213 def GetHandFillColour(self
, target
=ALL
):
214 """Gets fill colours of hands."""
216 return self
.Hands
.GetFillColour(target
)
219 def GetHandBorderColour(self
, target
=ALL
):
220 """Gets border colours of hands."""
222 return self
.Hands
.GetBorderColour(target
)
225 def GetHandBorderWidth(self
, target
=ALL
):
226 """Gets border widths of hands."""
228 return self
.Hands
.GetBorderWidth(target
)
231 def GetTickSize(self
, target
=ALL
):
232 """Gets sizes of ticks."""
234 return self
.Box
.GetTickSize(target
)
238 def GetTickFillColour(self
, target
=ALL
):
239 """Gets fill colours of ticks."""
241 return self
.Box
.GetTickFillColour(target
)
245 def GetTickBorderColour(self
, target
=ALL
):
246 """Gets border colours of ticks."""
248 return self
.Box
.GetTickBorderColour(target
)
252 def GetTickBorderWidth(self
, target
=ALL
):
253 """Gets border widths of ticks."""
255 return self
.Box
.GetTickBorderWidth(target
)
259 def GetTickPolygon(self
, target
=ALL
):
261 Gets lists of points to be used as polygon shapes
262 when using the TICKS_POLY style.
265 return self
.Box
.GetTickPolygon(target
)
269 def GetTickFont(self
, target
=ALL
):
271 Gets fonts for tick marks when using TICKS_DECIMAL or
275 return self
.Box
.GetTickFont(target
)
279 def GetTickOffset(self
, target
=ALL
):
280 """Gets the distance of tick marks for hours from border."""
282 return self
.Box
.GetTickOffset(target
)
286 def GetFaceFillColour(self
):
287 """Gets fill colours of watch."""
289 return self
.Box
.Face
.GetFillColour()
293 def GetFaceBorderColour(self
):
294 """Gets border colours of watch."""
296 return self
.Box
.Face
.GetBorderColour()
300 def GetFaceBorderWidth(self
):
301 """Gets border width of watch."""
303 return self
.Box
.Face
.GetBorderWidth()
307 def GetShadowColour(self
):
308 """Gets the colour to be used to draw shadows."""
310 a_clock_part
= self
.Box
311 return a_clock_part
.GetShadowColour()
315 def GetClockStyle(self
):
316 """Returns the current clock style."""
318 return self
.clockStyle
321 def GetTickStyle(self
, target
=ALL
):
322 """Gets the tick style(s)."""
324 return self
.Box
.GetTickStyle(target
)
329 Forces an immediate recalculation and redraw of all clock
332 size
= self
.GetClientSize()
333 if size
.x
< 1 or size
.y
< 1:
335 self
.RecalcCoords(size
)
340 def SetHandSize(self
, size
, target
=ALL
):
341 """Sets thickness of hands."""
343 self
.Hands
.SetSize(size
, target
)
346 def SetHandFillColour(self
, colour
, target
=ALL
):
347 """Sets fill colours of hands."""
349 self
.Hands
.SetFillColour(colour
, target
)
352 def SetHandBorderColour(self
, colour
, target
=ALL
):
353 """Sets border colours of hands."""
355 self
.Hands
.SetBorderColour(colour
, target
)
358 def SetHandBorderWidth(self
, width
, target
=ALL
):
359 """Sets border widths of hands."""
361 self
.Hands
.SetBorderWidth(width
, target
)
364 def SetTickSize(self
, size
, target
=ALL
):
365 """Sets sizes of ticks."""
367 self
.Box
.SetTickSize(size
, target
)
371 def SetTickFillColour(self
, colour
, target
=ALL
):
372 """Sets fill colours of ticks."""
374 self
.Box
.SetTickFillColour(colour
, target
)
378 def SetTickBorderColour(self
, colour
, target
=ALL
):
379 """Sets border colours of ticks."""
381 self
.Box
.SetTickBorderColour(colour
, target
)
385 def SetTickBorderWidth(self
, width
, target
=ALL
):
386 """Sets border widths of ticks."""
388 self
.Box
.SetTickBorderWidth(width
, target
)
392 def SetTickPolygon(self
, polygon
, target
=ALL
):
394 Sets lists of points to be used as polygon shapes
395 when using the TICKS_POLY style.
398 self
.Box
.SetTickPolygon(polygon
, target
)
402 def SetTickFont(self
, font
, target
=ALL
):
404 Sets fonts for tick marks when using text-based tick styles
405 such as TICKS_DECIMAL or TICKS_ROMAN.
408 self
.Box
.SetTickFont(font
, target
)
412 def SetTickOffset(self
, offset
, target
=ALL
):
413 """Sets the distance of tick marks for hours from border."""
415 self
.Box
.SetTickOffset(offset
, target
)
419 def SetFaceFillColour(self
, colour
):
420 """Sets fill colours of watch."""
422 self
.Box
.Face
.SetFillColour(colour
)
426 def SetFaceBorderColour(self
, colour
):
427 """Sets border colours of watch."""
429 self
.Box
.Face
.SetBorderColour(colour
)
433 def SetFaceBorderWidth(self
, width
):
434 """Sets border width of watch."""
436 self
.Box
.Face
.SetBorderWidth(width
)
440 def SetShadowColour(self
, colour
):
441 """Sets the colour to be used to draw shadows."""
443 self
.Hands
.SetShadowColour(colour
)
444 self
.Box
.SetShadowColour(colour
)
448 def SetClockStyle(self
, style
):
450 Set the clock style, according to the options below.
452 ==================== ================================
453 SHOW_QUARTERS_TICKS Show marks for hours 3, 6, 9, 12
454 SHOW_HOURS_TICKS Show marks for all hours
455 SHOW_MINUTES_TICKS Show marks for minutes
457 SHOW_HOURS_HAND Show hours hand
458 SHOW_MINUTES_HAND Show minutes hand
459 SHOW_SECONDS_HAND Show seconds hand
461 SHOW_SHADOWS Show hands and marks shadows
463 ROTATE_TICKS Align tick marks to watch
464 OVERLAP_TICKS Draw tick marks for minutes even
465 when they match the hours marks.
466 ==================== ================================
469 self
.clockStyle
= style
470 self
.Box
.SetIsRotated(style
& ROTATE_TICKS
)
474 def SetTickStyle(self
, style
, target
=ALL
):
476 Set the tick style, according to the options below.
478 ================= ======================================
479 TICKS_NONE Don't show tick marks.
480 TICKS_SQUARE Use squares as tick marks.
481 TICKS_CIRCLE Use circles as tick marks.
482 TICKS_POLY Use a polygon as tick marks. A
483 polygon can be passed using
484 SetTickPolygon, otherwise the default
485 polygon will be used.
486 TICKS_DECIMAL Use decimal numbers as tick marks.
487 TICKS_ROMAN Use Roman numbers as tick marks.
488 TICKS_BINARY Use binary numbers as tick marks.
489 TICKS_HEX Use hexadecimal numbers as tick marks.
490 ================= ======================================
493 self
.Box
.SetTickStyle(style
, target
)
497 def SetBackgroundColour(self
, colour
):
498 """Overriden base wx.Window method."""
500 wx
.Window
.SetBackgroundColour(self
, colour
)
504 def SetForegroundColour(self
, colour
):
506 Overriden base wx.Window method. This method sets a colour for
507 all hands and ticks at once.
510 wx
.Window
.SetForegroundColour(self
, colour
)
511 self
.SetHandFillColour(colour
)
512 self
.SetHandBorderColour(colour
)
513 self
.SetTickFillColour(colour
)
514 self
.SetTickBorderColour(colour
)
518 def SetWindowStyle(self
, *args
, **kwargs
):
519 """Overriden base wx.Window method."""
521 size
= self
.GetSize()
523 wx
.Window
.SetWindowStyle(self
, *args
, **kwargs
)
524 self
.SetSize((10, 10))
529 def SetWindowStyleFlag(self
, *args
, **kwargs
):
530 """Overriden base wx.Window method."""
532 self
.SetWindowStyle(*args
, **kwargs
)
535 # For backwards compatibility -----------------------------------------
537 class AnalogClockWindow(AnalogClock
):
539 A simple derived class that provides some backwards compatibility
540 with the old analogclock module.
542 def SetTickShapes(self
, tsh
, tsm
=None):
543 self
.SetTickPolygon(tsh
)
545 def SetHandWeights(self
, h
=None, m
=None, s
=None):
547 self
.SetHandSize(h
, HOUR
)
549 self
.SetHandSize(m
, MINUTE
)
551 self
.SetHandSize(s
, SECOND
)
553 def SetHandColours(self
, h
=None, m
=None, s
=None):
554 if h
and not m
and not s
:
558 self
.SetHandBorderColour(h
, HOUR
)
559 self
.SetHandFillColour(h
, HOUR
)
561 self
.SetHandBorderColour(m
, MINUTE
)
562 self
.SetHandFillColour(m
, MINUTE
)
564 self
.SetHandBorderColour(s
, SECOND
)
565 self
.SetHandFillColour(s
, SECOND
)
567 def SetTickColours(self
, h
=None, m
=None):
571 self
.SetTickBorderColour(h
, HOUR
)
572 self
.SetTickFillColour(h
, HOUR
)
574 self
.SetTickBorderColour(m
, MINUTE
)
575 self
.SetTickFillColour(m
, MINUTE
)
577 def SetTickSizes(self
, h
=None, m
=None):
579 self
.SetTickSize(h
, HOUR
)
581 self
.SetTickSize(m
, MINUTE
)
583 def SetTickFontss(self
, h
=None, m
=None):
585 self
.SetTickFont(h
, HOUR
)
587 self
.SetTickFont(m
, MINUTE
)
590 def SetMinutesOffset(self
, o
):
593 def SetShadowColour(self
, s
):
596 def SetWatchPenBrush(self
, p
=None, b
=None):
598 self
.SetFaceBorderColour(p
.GetColour())
599 self
.SetFaceBorderWidth(p
.GetWidth())
601 self
.SetFaceFillColour(b
.GetColour())
603 def SetClockStyle(self
, style
):
604 style |
= SHOW_HOURS_HAND|SHOW_MINUTES_HAND|SHOW_SECONDS_HAND
605 AnalogClock
.SetClockStyle(self
, style
)
607 def SetTickStyles(self
, h
=None, m
=None):
609 self
.SetTickStyle(h
, HOUR
)
611 self
.SetTickStyle(h
, MINUTE
)
614 # Test stuff ----------------------------------------------------------
616 if __name__
== "__main__":
617 print wx
.VERSION_STRING
619 class AcDemoApp(wx
.App
):
621 frame
= wx
.Frame(None, -1, "AnalogClock", size
=(375, 375))
622 clock
= AnalogClock(frame
)
623 frame
.CentreOnScreen()