add Mode, LineMode, and CircleMode classes

This commit is contained in:
Josh Holtrop 2011-09-08 15:58:07 -04:00
parent 701b7db7ba
commit 05c8627395

View File

@ -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'