diff --git a/Tools/ged/ged.py b/Tools/ged/ged.py index 6dc0c5c4..b095a068 100644 --- a/Tools/ged/ged.py +++ b/Tools/ged/ged.py @@ -12,6 +12,13 @@ GRID_ALIGNMENT = 8 +# Event state modifier masks +EVS_SHIFT = 0x0001 +EVS_CONTROL = 0x0004 +EVS_ALTLEFT = 0x0008 +EVS_ALTRIGHT = 0x0080 + + def align(value): a = GRID_ALIGNMENT if a <= 1: @@ -206,7 +213,6 @@ def __init__(self, tk_root, size): c = self.canvas = tk.Canvas(tk_root, width=size[0], height=size[1], background='black') c.pack(side=tk.TOP) c.bind('<1>', self.canvas_select) - c.bind('', self.canvas_multi_select) c.bind('', self.canvas_move) c.bind('', self.canvas_drag) c.bind('', self.canvas_end_move) @@ -254,7 +260,7 @@ def get_current(self): return elem, item def draw_handles(self): - hr = self.handle_rect = self.sel_items[0].get_bounds() + hr = self.sel_items[0].get_bounds() for item in self.sel_items[1:]: hr = union(hr, item) for e in Element: @@ -263,36 +269,29 @@ def draw_handles(self): r = hr.element_rect(e).tk_bounds() tags = ('handle', str(e)) self.canvas.create_rectangle(r[0], r[1], r[2], r[3], outline='white', width=1, tags=tags) + return hr def remove_handles(self): self.canvas.delete('handle') def canvas_select(self, evt): + self.sel_pos = (evt.x, evt.y) + is_multi = (evt.state & EVS_CONTROL) != 0 elem, item = self.get_current() if not elem: - if self.sel_items: + if not is_multi and self.sel_items: self.remove_handles() self.sel_items = [] return - self.sel_pos = (evt.x, evt.y) self.sel_elem = elem if item and not item in self.sel_items: self.remove_handles() - self.sel_items = [item] - self.draw_handles() - self.orig_bounds = [x.get_bounds() for x in self.sel_items] - - def canvas_multi_select(self, evt): - elem, item = self.get_current() - if not elem: - return - self.sel_pos = (evt.x, evt.y) - self.sel_elem = elem - if item and item not in self.sel_items: - self.remove_handles() - self.sel_items.append(item) - self.draw_handles() + if is_multi: + self.sel_items.append(item) + else: + self.sel_items = [item] + self.sel_bounds = self.draw_handles() self.orig_bounds = [x.get_bounds() for x in self.sel_items] @staticmethod @@ -320,37 +319,73 @@ def canvas_move(self, evt): def canvas_drag(self, evt): if not self.sel_items: return + self.remove_handles() if self.state != State.DRAGGING: - self.remove_handles() self.state = State.DRAGGING + self.orig_bounds = [x.get_bounds() for x in self.sel_items] elem = self.sel_elem - for item, orig in zip(self.sel_items, self.orig_bounds): - r = item.get_bounds() - off = evt.x - self.sel_pos[0], evt.y - self.sel_pos[1] - if elem == Element.ITEM: + off = evt.x - self.sel_pos[0], evt.y - self.sel_pos[1] + + if elem == Element.ITEM: + for item, orig in zip(self.sel_items, self.orig_bounds): + r = item.get_bounds() r.x, r.y = align((orig.x + off[0], orig.y + off[1])) - else: - if elem & DIR_N: - r.y = align(orig.y + off[1]) - r.h = orig.y + orig.h - r.y - if elem & DIR_E: - r.w = align(orig.w + off[0]) - if elem & DIR_S: - r.h = align(orig.h + off[1]) - if elem & DIR_W: - r.x = align(orig.x + off[0]) - r.w = orig.x + orig.w - r.x - min_size = item.get_min_size() - if r.w < min_size[0] or r.h < min_size[1]: - return - item.resize(self.canvas, r) + item.resize(self.canvas, r) + elif len(self.sel_items) == 1: + item, orig = self.sel_items[0], self.orig_bounds[0] + r = item.get_bounds() + if elem & DIR_N: + r.y = align(orig.y + off[1]) + r.h = orig.y + orig.h - r.y + if elem & DIR_E: + r.w = align(orig.w + off[0]) + if elem & DIR_S: + r.h = align(orig.h + off[1]) + if elem & DIR_W: + r.x = align(orig.x + off[0]) + r.w = orig.x + orig.w - r.x + min_size = item.get_min_size() + if r.w >= min_size[0] and r.h >= min_size[1]: + item.resize(self.canvas, r) + else: + # Scale the bounding rectangle + orig = orig_bounds = self.sel_bounds + r = copy.copy(orig) + if elem & DIR_N: + r.y = orig.y + off[1] + r.h = orig.y + orig.h - r.y + elif elem & DIR_S: + r.h = orig.h + off[1] + if elem & DIR_E: + r.w = orig.w + off[0] + elif elem & DIR_W: + r.x = orig.x + off[0] + r.w = orig.x + orig.w - r.x + if r.w > 0 and r.h > 0: + cur_bounds = r + # Now use scaled rectangle to move/resize items + do_size = (evt.state & EVS_SHIFT) != 0 + for item, orig in zip(self.sel_items, self.orig_bounds): + r = copy.copy(orig) + r.x = align(cur_bounds.x + (orig.x - orig_bounds.x) * cur_bounds.w // orig_bounds.w) + r.y = align(cur_bounds.y + (orig.y - orig_bounds.y) * cur_bounds.h // orig_bounds.h) + if do_size: + r.w = align(orig.w * cur_bounds.w // orig_bounds.w) + r.h = align(orig.h * cur_bounds.h // orig_bounds.h) + min_size = item.get_min_size() + if r.w < min_size[0] or r.h < min_size[1]: + continue + item.resize(self.canvas, r) + + self.draw_handles() + def canvas_end_move(self, evt): if self.state != State.DRAGGING: return self.state = State.IDLE self.remove_handles() - self.draw_handles() + self.sel_bounds = self.draw_handles() def run():