blob: 7a34b3a480cef2c001c5744e06ad256bf7344c2e [file] [log] [blame]
Parker Schuh19b93b12018-03-02 23:26:58 -08001import gi
2gi.require_version('Gtk', '3.0')
3from gi.repository import Gtk
4from gi.repository import GLib
5from gi.repository import Gdk
6from gi.repository import GdkX11
Tabitha Jarvis1007a132018-12-12 21:47:54 -08007from color import Color, palette
Parker Schuh19b93b12018-03-02 23:26:58 -08008import cairo
9
10identity = cairo.Matrix()
11
Parker Schuhdc682952018-03-03 18:24:01 -080012
Parker Schuh19b93b12018-03-02 23:26:58 -080013# Override the matrix of a cairo context.
14class OverrideMatrix(object):
Parker Schuhdc682952018-03-03 18:24:01 -080015 def __init__(self, cr, matrix):
16 self.cr = cr
17 self.matrix = matrix
Parker Schuh19b93b12018-03-02 23:26:58 -080018
Parker Schuhdc682952018-03-03 18:24:01 -080019 def __enter__(self):
20 self.cr.save()
21 self.cr.set_matrix(self.matrix)
22
23 def __exit__(self, type, value, traceback):
24 self.cr.restore()
25
Parker Schuh19b93b12018-03-02 23:26:58 -080026
27mainloop = GLib.MainLoop()
28
Tabitha Jarvis1007a132018-12-12 21:47:54 -080029def set_color(cr, color):
30 if color.a == 1.0:
31 cr.set_source_rgb(color.r, color.g, color.b)
32 else:
33 cr.set_source_rgba(color.r, color.g, color.b, color.a)
Parker Schuhdc682952018-03-03 18:24:01 -080034
Parker Schuh19b93b12018-03-02 23:26:58 -080035def quit_main_loop(*args):
Parker Schuhdc682952018-03-03 18:24:01 -080036 mainloop.quit()
37
Parker Schuh19b93b12018-03-02 23:26:58 -080038
39def RunApp():
Parker Schuhdc682952018-03-03 18:24:01 -080040 try:
41 mainloop.run()
42 except KeyboardInterrupt:
43 print('\nCtrl+C hit, quitting')
44 mainloop.quit()
45
Parker Schuh19b93b12018-03-02 23:26:58 -080046
47# Create a GTK+ widget on which we will draw using Cairo
48class BaseWindow(Gtk.DrawingArea):
Parker Schuhdc682952018-03-03 18:24:01 -080049 def method_connect(self, event, cb):
50 def handler(obj, *args):
51 cb(*args)
Parker Schuh19b93b12018-03-02 23:26:58 -080052
Parker Schuhdc682952018-03-03 18:24:01 -080053 self.window.connect(event, handler)
Parker Schuh19b93b12018-03-02 23:26:58 -080054
Parker Schuhdc682952018-03-03 18:24:01 -080055 # Draw in response to an expose-event
56 def __init__(self):
57 super(BaseWindow, self).__init__()
58 self.window = Gtk.Window()
59 self.window.set_title("DrawingArea")
60 self.window.connect("destroy", quit_main_loop)
61 self.window.set_events(Gdk.EventMask.BUTTON_PRESS_MASK
62 | Gdk.EventMask.BUTTON_RELEASE_MASK
63 | Gdk.EventMask.POINTER_MOTION_MASK
64 | Gdk.EventMask.SCROLL_MASK
65 | Gdk.EventMask.KEY_PRESS_MASK)
66 self.method_connect("key-press-event", self.do_key_press)
67 self.method_connect("button-press-event",
68 self._do_button_press_internal)
69 self.method_connect("configure-event", self._do_configure)
Parker Schuh19b93b12018-03-02 23:26:58 -080070
Parker Schuhdc682952018-03-03 18:24:01 -080071 self.set_size_request(640, 400)
72 self.window.add(self)
73 self.window.show_all()
74 self.center = (0, 0)
75 self.shape = (640, 400)
76 self.needs_redraw = False
Parker Schuh19b93b12018-03-02 23:26:58 -080077
Parker Schuhdc682952018-03-03 18:24:01 -080078 def get_current_scale(self):
79 w_w, w_h = self.window_shape
80 w, h = self.shape
81 return min((w_w / w), (w_h / h))
Parker Schuh19b93b12018-03-02 23:26:58 -080082
Parker Schuhdc682952018-03-03 18:24:01 -080083 def init_extents(self, center, shape):
84 self.center = center
85 self.shape = shape
Parker Schuh19b93b12018-03-02 23:26:58 -080086
Parker Schuhdc682952018-03-03 18:24:01 -080087 # The gtk system creates cr which is a cairo_context_t (in the c docs), and then it
88 # passes it as a function argument to the "draw" event. do_draw is the default name.
89 def do_draw(self, cr):
90 cr.save()
91 cr.set_font_size(20)
92 cr.translate(self.window_shape[0] / 2, self.window_shape[1] / 2)
93 scale = self.get_current_scale()
94 cr.scale(scale, -scale)
95 cr.translate(-self.center[0], -self.center[1])
96 self.needs_redraw = False
97 self.handle_draw(cr)
98 cr.restore()
Parker Schuh19b93b12018-03-02 23:26:58 -080099
Parker Schuhdc682952018-03-03 18:24:01 -0800100 # Handle the expose-event by drawing
101 def handle_draw(self, cr):
102 pass
Parker Schuh19b93b12018-03-02 23:26:58 -0800103
Parker Schuhdc682952018-03-03 18:24:01 -0800104 def do_key_press(self, event):
105 pass
Parker Schuh19b93b12018-03-02 23:26:58 -0800106
Parker Schuhdc682952018-03-03 18:24:01 -0800107 def _do_button_press_internal(self, event):
108 o_x = event.x
109 o_y = event.y
110 x = event.x - self.window_shape[0] / 2
111 y = self.window_shape[1] / 2 - event.y
112 scale = self.get_current_scale()
113 event.x = x / scale + self.center[0]
114 event.y = y / scale + self.center[1]
115 self.do_button_press(event)
116 event.x = o_x
117 event.y = o_y
Parker Schuh19b93b12018-03-02 23:26:58 -0800118
Parker Schuhdc682952018-03-03 18:24:01 -0800119 def do_button_press(self, event):
120 pass
Parker Schuh19b93b12018-03-02 23:26:58 -0800121
Parker Schuhdc682952018-03-03 18:24:01 -0800122 def _do_configure(self, event):
123 self.window_shape = (event.width, event.height)
124
125 def redraw(self):
126 if not self.needs_redraw:
127 self.needs_redraw = True
128 self.window.queue_draw()