From 17643e9cd15aefdaddf704eb9946080b2a4ef8ff Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Fri, 27 Oct 2017 17:21:59 -0700 Subject: [PATCH] Port the LEDNumberCtrl from wxCode/gizmos in Classic --- demo/LEDNumberCtrl.py | 8 +- demo/demodata.py | 2 +- src/gizmos.py | 14 ++ wscript | 5 +- wx/lib/gizmos/__init__.py | 16 +++ wx/lib/gizmos/ledctrl.py | 267 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 307 insertions(+), 5 deletions(-) create mode 100644 src/gizmos.py create mode 100644 wx/lib/gizmos/__init__.py create mode 100644 wx/lib/gizmos/ledctrl.py diff --git a/demo/LEDNumberCtrl.py b/demo/LEDNumberCtrl.py index 13b5d70d..2d3708e8 100644 --- a/demo/LEDNumberCtrl.py +++ b/demo/LEDNumberCtrl.py @@ -13,15 +13,19 @@ class TestPanel(wx.Panel): self.log = log led = gizmos.LEDNumberCtrl(self, -1, (25,25), (280, 50)) - led.SetValue("01234") + led.SetValue("012.34") led = gizmos.LEDNumberCtrl(self, -1, (25,100), (280, 50)) led.SetValue("56789") led.SetAlignment(gizmos.LED_ALIGN_RIGHT) led.SetDrawFaded(False) + led.SetForegroundColour('yellow') led = gizmos.LEDNumberCtrl(self, -1, (25,175), (280, 50), gizmos.LED_ALIGN_CENTER)# | gizmos.LED_DRAW_FADED) + led.SetForegroundColour('black') + led.SetBackgroundColour('white') + self.clock = led self.OnTimer(None) @@ -32,7 +36,7 @@ class TestPanel(wx.Panel): def OnTimer(self, evt): t = time.localtime(time.time()) - st = time.strftime("%I-%M-%S", t) + st = time.strftime("%H:%M:%S", t) self.clock.SetValue(st) diff --git a/demo/demodata.py b/demo/demodata.py index 83884150..37295349 100644 --- a/demo/demodata.py +++ b/demo/demodata.py @@ -144,7 +144,7 @@ _treeList = [ 'GenericButtons', 'GenericDirCtrl', 'ItemsPicker', - #'LEDNumberCtrl', # TODO + 'LEDNumberCtrl', 'MultiSash', 'PlateButton', 'PopupControl', diff --git a/src/gizmos.py b/src/gizmos.py new file mode 100644 index 00000000..5fd6e65a --- /dev/null +++ b/src/gizmos.py @@ -0,0 +1,14 @@ +#--------------------------------------------------------------------------- +# Name: wx/gizmos.py +# Author: Robin Dunn +# +# Created: 27-Oct-2017 +# Copyright: (c) 2017 by Total Control Software +# License: wxWindows License +#--------------------------------------------------------------------------- + +# This is just a compatibility shim to make the gizmos classes usable from +# wx.gizmos like in Classic. They're actually in wx.lib.gizmos now. + +from wx.lib.gizmos import * + diff --git a/wscript b/wscript index 192c1b2b..efbe7580 100644 --- a/wscript +++ b/wscript @@ -500,8 +500,9 @@ def build(bld): # copy the wx locale message catalogs to the package dir cfg.build_locale_dir(opj(cfg.PKGDIR, 'locale')) - # copy __init__.py - copy_file('src/__init__.py', cfg.PKGDIR, update=1, verbose=1) + # copy .py files that need to go into the root wx package dir + for name in ['src/__init__.py', 'src/gizmos.py',]: + copy_file(name, cfg.PKGDIR, update=1, verbose=1) # Create the build tasks for each of our extension modules. diff --git a/wx/lib/gizmos/__init__.py b/wx/lib/gizmos/__init__.py new file mode 100644 index 00000000..24ea2969 --- /dev/null +++ b/wx/lib/gizmos/__init__.py @@ -0,0 +1,16 @@ +#---------------------------------------------------------------------- +# Name: wx.lib.gizmos +# Purpose: Python ports of some of the wrapped C++ classes in the +# wx.gizmos module in Classic wxPython +# +# Author: Robin Dunn +# +# Created: 26-Oct-2017 +# Copyright: (c) 2017 by Total Control Software +# Licence: wxWindows license +# Tags: +#---------------------------------------------------------------------- + + +from .ledctrl import * + diff --git a/wx/lib/gizmos/ledctrl.py b/wx/lib/gizmos/ledctrl.py new file mode 100644 index 00000000..77f91273 --- /dev/null +++ b/wx/lib/gizmos/ledctrl.py @@ -0,0 +1,267 @@ +#---------------------------------------------------------------------- +# Name: wx.lib.gizmos.ledctrl +# Purpose: +# +# Author: Robin Dunn +# +# Created: 26-Oct-2017 +# Copyright: (c) 2017 by Total Control Software +# Licence: wxWindows license +# Tags: +#---------------------------------------------------------------------- + +import wx + +LED_ALIGN_LEFT = 0x01 +LED_ALIGN_RIGHT = 0x02 +LED_ALIGN_CENTER = 0x04 +LED_ALIGN_MASK = 0x07 + +LED_DRAW_FADED = 0x08 + + +class LEDNumberCtrl(wx.Control): + """ + """ + + # constants used internally + class const: + LINE1 = 1 + LINE2 = 2 + LINE3 = 4 + LINE4 = 8 + LINE5 = 16 + LINE6 = 32 + LINE7 = 64 + DECIMALSIGN = 128 + COLON = 256 + + DIGITS = { + '0': LINE1 | LINE2 | LINE3 | LINE4 | LINE5 | LINE6, + '1': LINE2 | LINE3, + '2': LINE1 | LINE2 | LINE4 | LINE5 | LINE7, + '3': LINE1 | LINE2 | LINE3 | LINE4 | LINE7, + '4': LINE2 | LINE3 | LINE6 | LINE7, + '5': LINE1 | LINE3 | LINE4 | LINE6 | LINE7, + '6': LINE1 | LINE3 | LINE4 | LINE5 | LINE6 | LINE7, + '7': LINE1 | LINE2 | LINE3, + '8': LINE1 | LINE2 | LINE3 | LINE4 | LINE5 | LINE6 | LINE7, + '9': LINE1 | LINE2 | LINE3 | LINE6 | LINE7, + '-': LINE7, + ':': COLON, + } + DIGITALL = 0xFFFF + + + + def __init__(self, parent, id=wx.ID_ANY, + pos=wx.DefaultPosition, size=wx.DefaultSize, + style=LED_ALIGN_LEFT|LED_DRAW_FADED, name='ledctrl'): + super(LEDNumberCtrl, self).__init__(parent, id, pos, size, style, name=name) + + # defaults + self._alignment = LED_ALIGN_LEFT + self._lineMargin = -1 + self._digitMargin = -1 + self._lineLength = -1 + self._lineWidth = -1 + self._drawFaded = False + self._leftStartPos = -1 + self._value = '' + + self.SetBackgroundColour(wx.BLACK) + self.SetForegroundColour(wx.GREEN) + self.SetBackgroundStyle(wx.BG_STYLE_PAINT) + + # flags + if style & LED_DRAW_FADED: + self.SetDrawFaded(True) + if style & LED_ALIGN_MASK: + self.SetAlignment(style & LED_ALIGN_MASK) + + # event bindings + self.Bind(wx.EVT_ERASE_BACKGROUND, lambda evt: None) + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_SIZE, self.OnSize) + + + + def GetAlignment(self): + """ + """ + return self._alignment + + + def GetDrawFaded(self): + """ + """ + return self._drawFaded + + + def GetValue(self): + """ + """ + return self._value + + + def SetAlignment(self, alignment, redraw=True): + """ + """ + if alignment != self._alignment: + self._alignment = alignment + self._recalcInternals(self.GetClientSize()) + + if redraw: + self.Refresh(False) + + + def SetDrawFaded(self, drawFaded, redraw=True): + """ + """ + if drawFaded != self._drawFaded: + self._drawFaded = drawFaded + + if redraw: + self.Refresh(False) + + + def SetValue(self, value, redraw=True): + """ + """ + if value != self._value: + for c in value: + assert c in '0123456789-.: ', "LEDNumberCtrl can only display numeric string values." + + self._value = value + self._recalcInternals(self.GetClientSize()) + + if redraw: + self.Refresh(False) + + + Alignment = property(GetAlignment, SetAlignment) + DrawFaded = property(GetDrawFaded, SetDrawFaded) + Value = property(GetValue, SetValue) + + + def OnSize(self, evt): + self._recalcInternals(evt.GetSize()) + evt.Skip() + + + def OnPaint(self, evt): + c = self.const + dc = wx.AutoBufferedPaintDC(self) + + # Draw the background + dc.SetBrush(wx.Brush(self.GetBackgroundColour(), wx.BRUSHSTYLE_SOLID)) + dc.DrawRectangle(wx.Rect((0, 0), self.GetClientSize())) + + # Iterate the digits and draw each + offset = 0 + for i, ch in enumerate(self._value): + i -= offset + # Draw faded lines if wanted. + if self._drawFaded and ch != '.': + self._drawDigit(dc, c.DIGITALL, i); + + if ch == '.': + # draw the decimal point in the previous segment + self._drawDigit(dc, c.DECIMALSIGN, i-1) + offset += 1 + elif ch == ' ': + # skip spaces + continue + else: + self._drawDigit(dc, c.DIGITS[ch], i) + + + def _recalcInternals(self, size): + height = size.Height + + if (height * 0.075) < 1: + self._lineMargin = 1 + else: + self._lineMargin = int(height * 0.075) + + if (height * 0.275) < 1: + self._lineLength = 1 + else: + self._lineLength = int(height * 0.275) + + self._lineWidth = self._lineMargin + self._digitMargin = self._lineMargin * 4 + + # Count the number of characters in the string; '.' characters are not + # included because they do not take up space in the display + count = 0; + for ch in self._value: + if ch != '.': + count += 1 + + valueWidth = (self._lineLength + self._digitMargin) * count + clientWidth = size.Width + + if self._alignment == LED_ALIGN_LEFT: + self._leftStartPos = self._lineMargin + elif self._alignment == LED_ALIGN_RIGHT: + self._leftStartPos = clientWidth - valueWidth - self._lineMargin + elif self._alignment == LED_ALIGN_CENTER: + self._leftStartPos = int((clientWidth - valueWidth) / 2) + else: + raise AssertionError("Unknown alignment value for LEDNumberCtrl.") + + + def _drawDigit(self, dc, digit, column): + lineColor = self.GetForegroundColour() + c = self.const + + if digit == c.DIGITALL: + R = int(lineColor.Red() / 8) + G = int(lineColor.Green() / 8) + B = int(lineColor.Blue() / 8) + lineColor.Set(R, G, B) + + XPos = self._leftStartPos + column * (self._lineLength + self._digitMargin) + + # Create a pen and draw the lines. + dc.SetPen(wx.Pen(lineColor, self._lineWidth)) + + if digit & c.LINE1: + dc.DrawLine(XPos + self._lineMargin*2, self._lineMargin, + XPos + self._lineLength + self._lineMargin*2, self._lineMargin) + + if digit & c.LINE2: + dc.DrawLine(XPos + self._lineLength + self._lineMargin*3, self._lineMargin*2, + XPos + self._lineLength + self._lineMargin*3, self._lineLength + (self._lineMargin*2)) + + if digit & c.LINE3: + dc.DrawLine(XPos + self._lineLength + self._lineMargin*3, self._lineLength + (self._lineMargin*4), + XPos + self._lineLength + self._lineMargin*3, self._lineLength*2 + (self._lineMargin*4)) + + if digit & c.LINE4: + dc.DrawLine(XPos + self._lineMargin*2, self._lineLength*2 + (self._lineMargin*5), + XPos + self._lineLength + self._lineMargin*2, self._lineLength*2 + (self._lineMargin*5)) + + if digit & c.LINE5: + dc.DrawLine(XPos + self._lineMargin, self._lineLength + (self._lineMargin*4), + XPos + self._lineMargin, self._lineLength*2 + (self._lineMargin*4)) + + if digit & c.LINE6: + dc.DrawLine(XPos + self._lineMargin, self._lineMargin*2, + XPos + self._lineMargin, self._lineLength + (self._lineMargin*2)) + + if digit & c.LINE7: + dc.DrawLine(XPos + self._lineMargin*2, self._lineLength + (self._lineMargin*3), + XPos + self._lineMargin*2 + self._lineLength, self._lineLength + (self._lineMargin*3)) + + if digit & c.DECIMALSIGN: + dc.DrawLine(XPos + self._lineLength + self._lineMargin*4, self._lineLength*2 + (self._lineMargin*5), + XPos + self._lineLength + self._lineMargin*4, self._lineLength*2 + (self._lineMargin*5)) + + if digit & c.COLON: + dc.SetBrush(wx.Brush(lineColor)) + centerX = XPos + (self._lineLength + self._digitMargin)/2 + radius = self._lineWidth / 2 + dc.DrawCircle(centerX, (self._lineLength + (self._lineMargin*3))/2, radius) + dc.DrawCircle(centerX, (self._lineLength*2 + (self._lineMargin*5))*3/4, radius)