Skip to content

Commit

Permalink
Group drag handles only adjust positions, shift to size also
Browse files Browse the repository at this point in the history
  • Loading branch information
mikee47 committed Feb 5, 2024
1 parent 9d1d929 commit 2f5251e
Showing 1 changed file with 74 additions and 39 deletions.
113 changes: 74 additions & 39 deletions Tools/ged/ged.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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('<Control-1>', self.canvas_multi_select)
c.bind('<Motion>', self.canvas_move)
c.bind('<B1-Motion>', self.canvas_drag)
c.bind('<ButtonRelease-1>', self.canvas_end_move)
Expand Down Expand Up @@ -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:
Expand All @@ -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
Expand Down Expand Up @@ -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():
Expand Down

0 comments on commit 2f5251e

Please sign in to comment.