From 05c8627395c873fdae9be4333ef83d665a406e6d Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Thu, 8 Sep 2011 15:58:07 -0400 Subject: [PATCH] add Mode, LineMode, and CircleMode classes --- SketchWidget.py | 298 ++++++++++++++++++++++++++---------------------- 1 file changed, 161 insertions(+), 137 deletions(-) diff --git a/SketchWidget.py b/SketchWidget.py index dc0840c..0f1f45d 100644 --- a/SketchWidget.py +++ b/SketchWidget.py @@ -1,4 +1,5 @@ +import sys import math import gtk import gtk.gtkgl @@ -20,12 +21,19 @@ class SketchWidget(object): self.panning = False self.drawingShape = None self.drawingConstraints = {} - self.mode = '' + self.modes = { + 'select': SelectMode(), + 'line': LineMode(), + 'circle': CircleMode(), + } + self.mode_name = 'select' + self.mode = self.modes[self.mode_name] self.snap_ptrefs = {} # keyed on PointRef self.cursors = { 'arrow': gtk.gdk.Cursor(gtk.gdk.ARROW), 'crosshair': gtk.gdk.Cursor(gtk.gdk.CROSSHAIR), } + self.cursor = 'arrow' self.hover_snap_ptref = None self.solved = False @@ -238,18 +246,12 @@ class SketchWidget(object): def button_press_event(self, widget, event, data = None): if event.button == 1: - if self.mode == 'line': - self.do_line_left_click(event.x, event.y) - elif self.mode == 'circle': - self.do_circle_left_click(event.x, event.y) + self.mode.do_left_click(self, event.x, event.y) elif event.button == 2: self.panning = True self.panning_start = (event.x, self.size[1] - event.y) elif event.button == 3: - if self.mode == 'line': - self.do_line_right_click(event.x, event.y) - elif self.mode == 'circle': - self.do_circle_right_click(event.x, event.y) + self.mode.do_right_click(self, event.x, event.y) def button_release_event(self, widget, event, data = None): if event.button == 2: @@ -265,10 +267,7 @@ class SketchWidget(object): self.panning_start = (event.x, self.size[1] - event.y) self.queue_redraw() else: - if self.mode == 'line': - self.do_line_motion(event.x, event.y) - elif self.mode == 'circle': - self.do_circle_motion(event.x, event.y) + self.mode.do_motion(self, event.x, event.y) def scroll_event(self, widget, event, data = None): if event.direction == gtk.gdk.SCROLL_UP: @@ -363,133 +362,24 @@ class SketchWidget(object): glEnd() glPopAttrib() - def set_mode(self, mode): - if mode != self.mode: - if self.mode == 'line': - self.drawingShape = None - self.queue_redraw() - elif self.mode == 'circle': - self.drawingShape = None - self.queue_redraw() - if self.widget.window is not None: - if mode in ('line', 'circle'): - self.widget.window.set_cursor(self.cursors['crosshair']) - else: - self.widget.window.set_cursor(self.cursors['arrow']) - self.mode = mode + def set_mode(self, mode_name): + if mode_name not in self.modes: + sys.stderr.write(__name__ + + ':set_mode(): Unknown mode %s\n' % mode_name) + elif mode_name != self.mode_name: + self.mode.end_mode(self) + self.mode_name = mode_name + self.mode = self.modes[mode_name] self.cancel_drawing_shape() - - def do_line_left_click(self, x, y): - click_pt = self.screenPtToPt((x, self.size[1] - y)) - start = click_pt - start_pt_ref = None - if self.hover_snap_ptref is not None: - start = self.hover_snap_ptref.getPt() - start_pt_ref = self.hover_snap_ptref - if self.drawingShape is not None: - # end a currently drawing line - # add snap points for newly drawn line - self.add_snap_ptrefs_from_shape(self.drawingShape) - start = self.drawingShape.getPt(1) # start at last snap point - prev_line = self.drawingShape - if self.hover_snap_ptref is not None: - c = Connect(self.hover_snap_ptref.shape, - self.hover_snap_ptref.ptNum, - self.drawingShape, 1) - self.drawingConstraints['c2'] = c - pt = self.hover_snap_ptref.getPt() - self.drawingShape.setPt(1, pt) - # don't do a horizontal/vertical when snapping - self.drawingConstraints['hv'] = None - self.merge_in_drawing_shape() - start = prev_line.getPt(1) - start_pt_ref = PointRef(prev_line, 1) - # begin a new line - self.drawingShape = Line( - start[0], start[1], click_pt[0], click_pt[1]) - if start_pt_ref is not None: - c = Connect(start_pt_ref.shape, start_pt_ref.ptNum, - self.drawingShape, 0) - self.drawingConstraints['c1'] = c - self.queue_redraw() - - def do_line_right_click(self, x, y): - if self.drawingShape is not None: - self.cancel_drawing_shape() - self.queue_redraw() - else: - self.window.set_mode('') - - def do_line_motion(self, x, y): - self.update_hover_snap_point(x, y) - if self.drawingShape is not None: - this_pt = self.screenPtToPt((x, self.size[1] - y)) - if self.hover_snap_ptref is not None: - this_pt = self.hover_snap_ptref.getPt() - self.drawingConstraints['hv'] = None - else: - start = self.drawingShape.getPt(0) - angle = math.atan2(this_pt[1] - start[1], this_pt[0] - start[0]) - angle *= 180.0 / math.pi - def within(a, b, d): return abs(a - b) < d - def snaps_to(q): return within(angle, q, self.snap_angle) - hv_snap_dist = self.screenDistToDist(self.hv_snap_dist) - if ((snaps_to(-180) or snaps_to(180) or snaps_to(0)) - and within(start[1], this_pt[1], hv_snap_dist)): - this_pt = (this_pt[0], start[1]) - if not ('hv' in self.drawingConstraints - and isinstance(self.drawingConstraints['hv'], - Horizontal)): - c = Horizontal( - self.drawingShape, 0, self.drawingShape, 1) - self.drawingConstraints['hv'] = c - elif ((snaps_to(-90) or snaps_to(90)) - and within(start[0], this_pt[0], hv_snap_dist)): - this_pt = (start[0], this_pt[1]) - if not ('hv' in self.drawingConstraints - and isinstance(self.drawingConstraints['hv'], - Vertical)): - c = Vertical(self.drawingShape, 0, self.drawingShape, 1) - self.drawingConstraints['hv'] = c - else: - self.drawingConstraints['hv'] = None - self.drawingShape.setPt(1, this_pt) - self.queue_redraw() - - def do_circle_left_click(self, x, y): - pt = self.screenPtToPt((x, self.size[1] - y)) - if self.drawingShape is None: - hsp = self.hover_snap_ptref - if hsp is not None: - pt = hsp.getPt() - self.drawingShape = Circle(pt[0], pt[1], 0) - if hsp is not None: - c = Connect(hsp.shape, hsp.ptNum, self.drawingShape, 0) - self.drawingConstraints['c'] = c - else: - self.add_snap_ptrefs_from_shape(self.drawingShape) - self.merge_in_drawing_shape() - self.queue_redraw() - - def do_circle_right_click(self, x, y): - if self.drawingShape is not None: - self.cancel_drawing_shape() - self.queue_redraw() - else: - self.window.set_mode('') - - def do_circle_motion(self, x, y): - if self.drawingShape is not None: - pt = self.screenPtToPt((x, self.size[1] - y)) - r = self.dist_bw(self.drawingShape.getPt(0), pt) - self.drawingShape.setRadius(r) - self.queue_redraw() - self.set_hover_snap_point(None) - else: - self.update_hover_snap_point(x, y) + c = self.mode.get_cursor() + if c in self.cursors and c != self.cursor: + self.cursor = c + self.widget.window.set_cursor(self.cursors[c]) def cancel_drawing_shape(self): - self.drawingShape = None + if self.drawingShape is not None: + self.drawingShape = None + self.queue_redraw() self.drawingConstraints = {} self.hover_snap_ptref = None @@ -581,3 +471,137 @@ class SketchWidget(object): sys.stderr.write(__name__ + ':solve(): Unknown Sketch.solve() result\n') self.window.update_sketch_status(valid, text) + +class Mode(object): + def do_left_click(self, sw, x, y): + pass + def do_right_click(self, sw, x, y): + pass + def do_motion(self, sw, x, y): + pass + def begin_mode(self, sw): + pass + def end_mode(self, sw): + pass + def get_cursor(self): + return 'arrow' + +class SelectMode(Mode): + pass + +class LineMode(Mode): + def do_left_click(self, sw, x, y): + click_pt = sw.screenPtToPt((x, sw.size[1] - y)) + start = click_pt + start_pt_ref = None + if sw.hover_snap_ptref is not None: + start = sw.hover_snap_ptref.getPt() + start_pt_ref = sw.hover_snap_ptref + if sw.drawingShape is not None: + # end a currently drawing line + # add snap points for newly drawn line + sw.add_snap_ptrefs_from_shape(sw.drawingShape) + start = sw.drawingShape.getPt(1) # start at last snap point + prev_line = sw.drawingShape + if sw.hover_snap_ptref is not None: + c = Connect(sw.hover_snap_ptref.shape, + sw.hover_snap_ptref.ptNum, + sw.drawingShape, 1) + sw.drawingConstraints['c2'] = c + pt = sw.hover_snap_ptref.getPt() + sw.drawingShape.setPt(1, pt) + # don't do a horizontal/vertical when snapping + sw.drawingConstraints['hv'] = None + sw.merge_in_drawing_shape() + start = prev_line.getPt(1) + start_pt_ref = PointRef(prev_line, 1) + # begin a new line + sw.drawingShape = Line( + start[0], start[1], click_pt[0], click_pt[1]) + if start_pt_ref is not None: + c = Connect(start_pt_ref.shape, start_pt_ref.ptNum, + sw.drawingShape, 0) + sw.drawingConstraints['c1'] = c + sw.queue_redraw() + + def do_right_click(self, sw, x, y): + if sw.drawingShape is not None: + sw.cancel_drawing_shape() + sw.queue_redraw() + else: + sw.window.set_mode('') + + def do_motion(self, sw, x, y): + sw.update_hover_snap_point(x, y) + if sw.drawingShape is not None: + this_pt = sw.screenPtToPt((x, sw.size[1] - y)) + if sw.hover_snap_ptref is not None: + this_pt = sw.hover_snap_ptref.getPt() + sw.drawingConstraints['hv'] = None + else: + start = sw.drawingShape.getPt(0) + angle = math.atan2(this_pt[1] - start[1], this_pt[0] - start[0]) + angle *= 180.0 / math.pi + def within(a, b, d): return abs(a - b) < d + def snaps_to(q): return within(angle, q, sw.snap_angle) + hv_snap_dist = sw.screenDistToDist(sw.hv_snap_dist) + if ((snaps_to(-180) or snaps_to(180) or snaps_to(0)) + and within(start[1], this_pt[1], hv_snap_dist)): + this_pt = (this_pt[0], start[1]) + if not ('hv' in sw.drawingConstraints + and isinstance(sw.drawingConstraints['hv'], + Horizontal)): + c = Horizontal( + sw.drawingShape, 0, sw.drawingShape, 1) + sw.drawingConstraints['hv'] = c + elif ((snaps_to(-90) or snaps_to(90)) + and within(start[0], this_pt[0], hv_snap_dist)): + this_pt = (start[0], this_pt[1]) + if not ('hv' in sw.drawingConstraints + and isinstance(sw.drawingConstraints['hv'], + Vertical)): + c = Vertical(sw.drawingShape, 0, sw.drawingShape, 1) + sw.drawingConstraints['hv'] = c + else: + sw.drawingConstraints['hv'] = None + sw.drawingShape.setPt(1, this_pt) + sw.queue_redraw() + + def get_cursor(self): + return 'crosshair' + +class CircleMode(Mode): + def do_left_click(self, sw, x, y): + pt = sw.screenPtToPt((x, sw.size[1] - y)) + if sw.drawingShape is None: + hsp = sw.hover_snap_ptref + if hsp is not None: + pt = hsp.getPt() + sw.drawingShape = Circle(pt[0], pt[1], 0) + if hsp is not None: + c = Connect(hsp.shape, hsp.ptNum, sw.drawingShape, 0) + sw.drawingConstraints['c'] = c + else: + sw.add_snap_ptrefs_from_shape(sw.drawingShape) + sw.merge_in_drawing_shape() + sw.queue_redraw() + + def do_right_click(self, sw, x, y): + if sw.drawingShape is not None: + sw.cancel_drawing_shape() + sw.queue_redraw() + else: + sw.window.set_mode('') + + def do_motion(self, sw, x, y): + if sw.drawingShape is not None: + pt = sw.screenPtToPt((x, sw.size[1] - y)) + r = sw.dist_bw(sw.drawingShape.getPt(0), pt) + sw.drawingShape.setRadius(r) + sw.queue_redraw() + sw.set_hover_snap_point(None) + else: + sw.update_hover_snap_point(x, y) + + def get_cursor(self): + return 'crosshair'