1
0
mirror of https://github.com/rzzzwilson/pymlac.git synced 2025-06-10 09:32:41 +00:00
2016-01-21 20:55:55 +07:00

209 lines
5.2 KiB
Python

#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
The Imlac display.
"""
import wx
from Globals import *
# if we don't have log.py, don't crash
try:
import log
log = log.Log('test.log', log.Log.DEBUG)
except ImportError:
def log(*args, **kwargs):
pass
# the widget version
__version__ = '0.0'
# type of events
DisplayStop = 1
######
# Base class for the widget canvas - buffered and flicker-free.
######
class _BufferedCanvas(wx.Panel):
"""Implements a buffered, flicker-free canvas widget.
This class is based on:
http://wiki.wxpython.org/index.cgi/BufferedCanvas
"""
# The backing buffer
buffer = None
# max coordinates of scaled display
ScaleMaxX = 2048
ScaleMaxY = 2048
# ScaleMaxX = 512
# ScaleMaxY = 512
def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.NO_FULL_REPAINT_ON_RESIZE):
"""Initialise the canvas.
parent reference to 'parent' widget
id the unique widget ID (NB: shadows builtin 'id')
pos canvas position
size canvas size
style wxPython style
"""
wx.Panel.__init__(self, parent, id, pos, size, style)
# Bind events
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_SIZE, self.OnSize)
# Disable background erasing (flicker-licious)
def disable_event(*args, **kwargs):
pass # the sauce, please
self.Bind(wx.EVT_ERASE_BACKGROUND, disable_event)
# set callback upon onSize event
self.onSizeCallback = None
self.dc = None
def Draw(self, dc):
"""Stub: called when the canvas needs to be re-drawn."""
# set display scale
scaleX = self.view_width*1.0 / self.ScaleMaxX
scaleY = self.view_height*1.0 / self.ScaleMaxY
dc.SetUserScale(min(scaleX,scaleY), min(scaleX,scaleY))
# don't REPLACE this method, EXTEND it!
def Update(self):
"""Causes the canvas to be updated."""
dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
dc.BeginDrawing()
dc.Clear() # because maybe view size > map size
self.Draw(dc)
dc.EndDrawing()
self.dc = dc
def OnPaint(self, event):
"""Paint the canvas to the screen."""
# Blit the front buffer to the screen
wx.BufferedPaintDC(self, self.buffer)
def OnSize(self, event=None):
"""Create a new off-screen buffer to hold drawn data."""
(width, height) = self.GetClientSizeTuple()
# keep widget square
minsize = min(width, height)
self.SetSize((minsize, minsize))
self.view_width = minsize
self.view_height = minsize
# new off-screen buffer
self.buffer = wx.EmptyBitmap(minsize, minsize)
# call onSize callback, if registered
if self.onSizeCallback:
self.onSizeCallback()
# Now update the screen
self.Update()
################################################################################
# The actual pymlc display widget.
################################################################################
class Display(_BufferedCanvas):
BackgroundColour = 'black'
DrawColour = '#ffff88'
SYNC_HZ = 40
SYNC_40HZ_CYCLE_COUNT = int(CYCLES_PER_SECOND / SYNC_HZ)
# max coordinates of pymlac display
# ScaleMaxX = 2048
# ScaleMaxY = 2048
ScaleMaxX = 1024
ScaleMaxY = 1024
def __init__(self, parent, **kwargs):
# create and initialise the base panel
_BufferedCanvas.__init__(self, parent=parent, **kwargs)
self.SetBackgroundColour(self.BackgroundColour)
# set internal state
self.running = 0
self.cycle_count = 0
self.Sync40hz = 1
self.drawlist = []
self.OnSize()
def draw(self, x1, y1, x2, y2, dotted=False):
"""Draw a line on the screen.
x1, y1 start coordinates
x2, y2 end coordinates
dotted True if dotted line, else False
"""
self.drawlist.append((x1, y1, x2, y2, dotted))
# log('Draw: x1,y1=%d,%d, x2,y2=%d,%d, dotted=%s' % (x1, y1, x2, y2, str(dotted)))
self.Update()
def clear(self):
"""Clear the display."""
self.drawlist = []
self.Update()
def Draw(self, dc):
"""Update the display on the widget screen."""
# there's some code in super.Draw() we need
super(Display, self).Draw(dc)
pen = wx.Pen(self.DrawColour)
for (x1, y1, x2, y2, dotted) in self.drawlist:
if not dotted:
pen.SetStyle(wx.SOLID)
pen.SetWidth(1)
else:
pen.SetStyle(wx.DOT)
pen.SetWidth(2)
dc.SetPen(pen)
dc.DrawLine(x1, self.ScaleMaxY - y1,
x2, self.ScaleMaxY - y2)
def syncclear(self):
self.Sync40hz = 0
self.cycle_count = self.SYNC_40HZ_CYCLE_COUNT
def ready(self):
return self.Sync40hz
def tick(self, cycles):
"""Advance the internal state by given cycles."""
self.cycle_count -= cycles
if self.cycle_count <= 0:
self.Sync40hz = 1
self.cycle_count = 0