caeac82e4d
E. A. Tacao. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@38120 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
645 lines
18 KiB
Python
645 lines
18 KiB
Python
# 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
|