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()