Skip to content

Commit

Permalink
Designer stability improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
ObaraEmmanuel committed Sep 25, 2023
1 parent 7a05b26 commit f05c7ac
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 28 deletions.
61 changes: 46 additions & 15 deletions studio/feature/design.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,14 @@ def _move(self, widget, bounds):
def add_widget(self, widget, bounds=None, **kwargs):
super(PlaceLayoutStrategy, self).add_widget(widget, bounds=bounds, **kwargs)
super(PlaceLayoutStrategy, self).remove_widget(widget)
if bounds is None:
if bounds:
self.move_widget(widget, bounds)
else:
x = kwargs.get("x", 10)
y = kwargs.get("y", 10)
width = kwargs.get("width", 20)
height = kwargs.get("height", 20)
self.container.place_child(widget, x=x, y=y, width=width, height=height)
else:
x1, y1, x2, y2 = self.container.canvas_bounds(bounds)
self.container.place_child(widget, x=x1, y=y1, width=x2 - x1, height=y2 - y1)
self._insert(widget, widget.prev_stack_index if widget.layout == self.container else None)

def remove_widget(self, widget):
Expand Down Expand Up @@ -182,6 +181,9 @@ def __init__(self, master, studio):
"designer::frame_skip",
self._update_throttling
)
self._sorted_containers = []
self._realtime_layout_update = False
self._handle_active_data = None

def clear_studio_bindings(self):
for binding in self._studio_bindings:
Expand Down Expand Up @@ -385,19 +387,40 @@ def on_motion(self, event):
self._frame.canvasy(event.y)
)

def _on_handle_active_start(self, widget, direction):
self._handle_active_data = widget, direction

def _on_handle_active(self, widget, direction):
if direction == "all":
self._move_selection = self.studio.selection.siblings(widget)
self.current_container = self._move_selection[0].layout
self.current_container.show_highlight()
self._sorted_containers = sorted(
filter(lambda x: isinstance(x, Container) and x not in self._move_selection, self.objects),
key=lambda x: -x.level
)
self._all_bound = geometry.overall_bounds([w.get_bounds() for w in self._move_selection])
self._realtime_layout_update = True
for obj in self._move_selection:
obj.layout.change_start(obj)
# disable realtime layout update if any widget's layout doesn't support it
if not obj.layout.layout_strategy.realtime_support:
self._realtime_layout_update = False
else:
for obj in self._selected:
if not obj.layout.allow_resize:
continue
obj.layout.change_start(obj)

if all(w.layout.layout_strategy.realtime_support for w in self._selected):
self._realtime_layout_update = True

def _on_handle_inactive(self, widget, direction):
if self._handle_active_data is not None:
# no movement occurred so we can skip the post-processing
self._handle_active_data = None
return

layouts_changed = []
if direction == "all":
if not self.current_container:
Expand Down Expand Up @@ -427,9 +450,14 @@ def _on_handle_inactive(self, widget, direction):

self.create_restore(layouts_changed)
self.studio.widgets_layout_changed(layouts_changed)
self._realtime_layout_update = False
self._skip_var = 0

def _on_handle_resize(self, widget, direction, delta):
if self._handle_active_data is not None:
self._on_handle_active(*self._handle_active_data)
self._handle_active_data = None

if self._skip_var < self._skip_max:
self._skip_var += 1
self._surge_delta = (self._surge_delta[0] + delta[0], self._surge_delta[1] + delta[1])
Expand All @@ -443,14 +471,12 @@ def _on_handle_resize(self, widget, direction, delta):
for obj in self._selected:
if obj.layout.allow_resize:
obj.layout.resize_widget(obj, direction, delta)
if self._realtime_layout_update:
self.studio.widgets_layout_changed(self._selected)
else:
# move
self._on_handle_move(widget, delta)

# TODO handle realtime layout changes
# if obj.layout.layout_strategy.realtime_support:
# self.studio.widgets_layout_changed(obj)

def _on_handle_move(self, _, delta):
dx, dy = delta
objs = self._move_selection
Expand Down Expand Up @@ -478,28 +504,33 @@ def _on_handle_move(self, _, delta):
x1, y1, x2, y2 = w.get_bounds()
current.move_widget(w, [x1 + dx, y1 + dy, x2 + dx, y2 + dy])

if self.current_container.layout_strategy.realtime_support:
self.studio.widgets_layout_changed(objs)

def set_active_container(self, container):
if self.current_container is not None:
self.current_container.clear_highlight()
self.current_container = container

def layout_at(self, bounds):
for container in sorted(filter(lambda x: isinstance(x, Container) and x not in self._selected, self.objects),
key=lambda x: len(self.objects) - x.level):
if isinstance(self.current_obj, Container) and self.current_obj.level < container.level:
continue
candidate = None
for container in self._sorted_containers:
if geometry.is_within(geometry.bounds(container), bounds):
return container
candidate = container
break
if self.current_container and geometry.compute_overlap(geometry.bounds(self.current_container), bounds):
if candidate and candidate.level > self.current_container.level:
return candidate
return self.current_container
return self

return candidate or self

def _attach(self, obj):
# bind events for context menu and object selection
# all widget additions call this method so clear empty message
self._show_empty(False)
obj.on_handle_resize(self._on_handle_resize)
obj.on_handle_active(self._on_handle_active)
obj.on_handle_active(self._on_handle_active_start)
obj.on_handle_inactive(self._on_handle_inactive)

MenuUtils.bind_all_context(obj, lambda e: self.show_menu(e, obj), add='+')
Expand Down
27 changes: 15 additions & 12 deletions studio/lib/layouts.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
# Copyright (C) 2019 Hoverset Group. #
# ======================================================================= #
from collections import defaultdict
from copy import deepcopy

from studio.ui import geometry
from studio.ui.highlight import WidgetHighlighter, EdgeIndicator
Expand Down Expand Up @@ -84,12 +85,8 @@ def add_widget(self, widget, bounds=None, **kwargs):
self.container.clear_highlight()

def _insert(self, widget, index=None):
if index is None:
self.children.append(widget)
else:
self.children.insert(index, widget)
self._update_stacking()

# actual insert logic does not work, we'll stick with append for now
self.children.append(widget)
if widget.prev_stack_index is None:
widget.prev_stack_index = len(self.children) - 1

Expand All @@ -98,7 +95,7 @@ def _update_stacking(self):
if index > 0:
widget.lift(self.children[index - 1])
else:
widget.lift(self.container.body)
widget.lift(self.container)

def widget_released(self, widget):
pass
Expand Down Expand Up @@ -171,8 +168,8 @@ def get_def(self, widget):
# May be overridden to return dynamic definitions based on the widget
# Always use a copy to avoid messing with definition
if self.dimensions_in_px:
return dict(self.DEFINITION)
props = dict(self.DEFINITION)
return deepcopy(self.DEFINITION)
props = deepcopy(self.DEFINITION)
overrides = getattr(widget, 'DEF_OVERRIDES', {})
for key in ('width', 'height'):
if key in props and key in overrides:
Expand Down Expand Up @@ -772,6 +769,7 @@ def _location_analysis(self, bounds):
self._edge_indicator.update_idletasks()
bounds = geometry.relative_bounds(bounds, self.container.body)
x, y = bounds[0], bounds[1]
w, h = geometry.dimensions(bounds)
col, row = self.container.body.grid_location(x, y)
x, y = geometry.upscale_bounds(bounds, self.container.body)[:2]
slaves = self.container.body.grid_slaves(max(0, row), max(0, col))
Expand All @@ -781,6 +779,9 @@ def _location_analysis(self, bounds):
bounds = *bbox[:2], bbox[0] + bbox[2], bbox[1] + bbox[3]
# Make bounds relative to designer
bounds = geometry.upscale_bounds(bounds, self.container.body)
if geometry.dimensions(bounds) == (0, 0):
w, h = w or 50, h or 25
bounds = bounds[0], bounds[1], bounds[0] + w, bounds[1] + h
else:
bounds = geometry.bounds(slaves[0])
y_offset, x_offset = 10, 10 # 0.15*(bounds[3] - bounds[1]), 0.15*(bounds[2] - bounds[0])
Expand Down Expand Up @@ -812,7 +813,8 @@ def apply(self, prop, value, widget):
widget.grid_configure(**{prop: value})

def react_to_pos(self, x, y):
self._location_analysis((*geometry.resolve_position((x, y), self.container.parent), 0, 0))
x, y = geometry.resolve_position((x, y), self.container.parent)
self._location_analysis((x, y, x, y))

def info(self, widget):
info = widget.grid_info() or {}
Expand Down Expand Up @@ -1062,7 +1064,8 @@ def resize_widget(self, widget, direction, delta):
def add_widget(self, widget, bounds=None, **kwargs):
super().remove_widget(widget)
super().add_widget(widget, bounds, **kwargs)
self.container.body.add(widget)
if str(widget) not in self.container.body.panes():
self.container.body.add(widget)
self._config(widget, **kwargs)
self._insert(widget)

Expand Down Expand Up @@ -1117,7 +1120,7 @@ def apply(self, prop, value, widget):

def _config(self, widget, **kwargs):
if not kwargs:
return self.container.pane(widget)
return self.container.body.pane(widget)
self.container.body.pane(widget, **kwargs)

def copy_layout(self, widget, from_):
Expand Down
2 changes: 1 addition & 1 deletion studio/ui/highlight.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def top(self, bounds):
self.place(x=x, y=y, height=1.5, width=bounds[2] - bounds[0])

def right(self, bounds):
x, y = bounds[2], bounds[3]
x, y = bounds[2], bounds[1]
self.lift()
self.place(x=x, y=y, height=bounds[3] - bounds[1], width=1.5)

Expand Down

0 comments on commit f05c7ac

Please sign in to comment.