-
Notifications
You must be signed in to change notification settings - Fork 110
Expand file tree
/
Copy pathturtlewidget.py
More file actions
111 lines (92 loc) · 3.7 KB
/
turtlewidget.py
File metadata and controls
111 lines (92 loc) · 3.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
"""
TurtleWidget is defined in this module, see its documentation.
"""
import misc.dumpqueue as dumpqueue
import wx
from misc.fromresourcefolder import from_resource_folder
from my_turtle import BITMAP_SIZE, Turtle, from_my_pos, from_my_angle
from vector import Vector
class TurtleWidget(wx.Panel):
"""
A wxPython widget to display the turtle and all the drawings that
it made.
"""
def __init__(self, parent, turtle_queue, *args, **kwargs):
wx.Panel.__init__(self, parent, style=wx.SUNKEN_BORDER,
*args, **kwargs)
self.BACKGROUND_COLOR = wx.Colour(212, 208, 200)
self.TURTLE_IMAGE = wx.Bitmap(from_resource_folder("turtle.png"))
self.turtle = Turtle()
# bitmap = self.bitmap = wx.EmptyBitmapRGBA(2000, 1200,
# BACKGROUND_COLOR[0],
# BACKGROUND_COLOR[1],
# BACKGROUND_COLOR[2], 255) # todo: Change to something smarter?
self.bitmap = wx.EmptyBitmap(*BITMAP_SIZE)
self.Bind(wx.EVT_PAINT, self.on_paint)
self.Bind(wx.EVT_SIZE, self.on_size)
self.Bind(wx.EVT_IDLE, self.on_idle)
self.turtle_queue = turtle_queue
self.idle_block = False
def on_paint(self, e=None):
"""
Paint event handler. Reads the turtle reports and draws graphics
accordingly.
"""
turtle_reports = dumpqueue.dump_queue(self.turtle_queue)
dc = wx.GCDC(wx.MemoryDC(self.bitmap))
for turtle_report in turtle_reports:
# print(turtle_report.__dict__)
if turtle_report.pen_down is True:
dc.SetPen(turtle_report.give_pen())
dc.DrawLinePoint(from_my_pos(self.turtle.pos),
from_my_pos(turtle_report.pos))
if turtle_report.clear is True:
brush = wx.Brush("black")
dc.SetBackground(brush)
dc.Clear()
self.turtle = turtle_report
del dc
if len(turtle_reports) > 0:
self.Refresh()
dc = wx.PaintDC(self)
widget_size = Vector(self.GetSize())
top_left_corner = (-BITMAP_SIZE + widget_size) / 2.0
# Draw the bitmap:
dc.DrawBitmap(self.bitmap, *top_left_corner)
# Draw the turtle:
if self.turtle.visible:
new_pos = top_left_corner + from_my_pos(self.turtle.pos)
draw_bitmap_to_dc_rotated(dc,
self.TURTLE_IMAGE,
from_my_angle(self.turtle.orientation),
new_pos)
dc.Destroy()
def on_idle(self, e=None):
"""
Idle event handler. Checks whether there are any
pending turtle reports, and if there are tells the widget
to process them.
"""
if self.idle_block is True:
return
if not self.turtle_queue.empty():
self.Refresh()
# TODO: should make the delay customizable?
wx.CallLater(30, self._clear_idle_block_and_do)
self.idle_block = True
def _clear_idle_block_and_do(self):
self.idle_block = False
event = wx.PyEvent()
event.SetEventType(wx.wxEVT_IDLE)
wx.PostEvent(self, event)
def on_size(self, e=None):
self.Refresh()
def draw_bitmap_to_dc_rotated(dc, bitmap, angle, point):
"""
Rotate a bitmap and write it to the supplied device context.
"""
img = bitmap.ConvertToImage()
img_centre = wx.Point(img.GetWidth() / 2.0, img.GetHeight() / 2.0)
img = img.Rotate(angle, img_centre, interpolating=True)
new_point = Vector(point) - Vector(img.GetSize()) / 2
dc.DrawBitmapPoint(img.ConvertToBitmap(), new_point, useMask=True)