Skip to content

Commit

Permalink
Merge pull request #24 from ObaraEmmanuel/feature-multiselect
Browse files Browse the repository at this point in the history
Add multiselect support
  • Loading branch information
ObaraEmmanuel authored Nov 25, 2023
2 parents 00f1f81 + c4daa23 commit 5e355cb
Show file tree
Hide file tree
Showing 25 changed files with 1,645 additions and 947 deletions.
2 changes: 1 addition & 1 deletion hoverset/ui/dialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,12 @@ def __init__(self, master, render_routine=None, **kw):
"SHOW_PROGRESS": self._show_progress,
"BUILDER": self._builder # Allows building custom dialogs
}
self.enable_centering()
if render_routine in routines:
# Completely custom dialogs
routines[render_routine](**kw) # noqa
elif render_routine is not None:
render_routine(self)
self.enable_centering()
self.value = None
# quirk that prevents explicit window centering on linux for best results
add = "+" if platform_is(WINDOWS, MAC) else None
Expand Down
14 changes: 8 additions & 6 deletions hoverset/ui/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -2558,6 +2558,10 @@ def _load_images(self):
cls.BLANK = get_icon_image("blank", 14, 14)
cls.__icons_loaded = True

@property
def selected(self):
return self._selected

@property
def depth(self):
return self._depth
Expand Down Expand Up @@ -2710,16 +2714,15 @@ def remove(self, node=None):
self.collapse()
self.nodes.remove(node)
node.pack_forget()
if was_expanded:
if was_expanded and len(self.nodes) > 0:
# If the parent was expanded when we began removal we expand it again
self.expand()
if len(self.nodes) == 0:
if not self.nodes:
# remove the expansion icon
self._set_expander(self.BLANK)

def expand(self):
if len(self.nodes) == 0:
# There is nothing to expand
if self._expanded:
return
self.pack_propagate(True)
for node in filter(lambda n: n._visible, self.nodes):
Expand All @@ -2728,8 +2731,7 @@ def expand(self):
self._expanded = True

def collapse(self):
if len(self.nodes) == 0:
# There is nothing to collapse
if not self._expanded:
return
for node in self.nodes:
node.pack_forget()
Expand Down
32 changes: 15 additions & 17 deletions studio/feature/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,28 +118,26 @@ def set_pref(cls, short_path, value):
def get_instance(cls):
return cls._instance

def on_select(self, widget):
def on_widgets_change(self, widgets):
"""
Called when a widget is selected in the designer
:param widget: selected widget
:return:None
Called when the widgets in the designer are changed
:param widgets: list of widgets
:return: None
"""
pass

def on_widget_change(self, old_widget, new_widget=None):
def on_widgets_layout_change(self, widgets):
"""
Called when a widget is fundamentally altered
:param old_widget: Altered widget
:param new_widget: The new widget taking the older widgets place
Called when layout options of a widgets are changed
:param widgets: Widgets with altered layout options
:return: None
"""
pass

def on_widget_layout_change(self, widget):
def on_widgets_reorder(self, indices):
"""
Called when layout options of a widget are changed
:param widget: Widget with altered layout options
:return: None
Called when the widgets in the designer are reordered within their parent.
Used to change stacking order of widgets
"""
pass

Expand All @@ -152,21 +150,21 @@ def on_widget_add(self, widget, parent):
"""
pass

def on_widget_delete(self, widget, silently=False):
def on_widgets_delete(self, widgets, silently=False):
"""
Called when a widget is deleted from the designer
:param widget: deleted widget
Called when widgets are deleted from the designer
:param widgets: deleted widgets
:param silently: flag indicating whether the deletion should be treated implicitly
which is useful for instance when you don't want the deletion to be logged in the
undo stack
:return: None
"""
pass

def on_widget_restore(self, widget):
def on_widgets_restore(self, widgets):
"""
Called when a deleted widget is restored
:param widget: restored widget
:param widgets: widgets to be restored
:return: None
"""
pass
Expand Down
81 changes: 48 additions & 33 deletions studio/feature/component_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ def __init__(self, master, studio=None, **cnf):
self.body = Frame(self, **self.style.surface)
self.body.pack(side="top", fill="both", expand=True)
self._empty_label = Label(self.body, **self.style.text_passive)
self.studio.bind("<<SelectionChanged>>", self._select, "+")

self._selected = None
self._expanded = False
self._tree = None

Expand All @@ -92,6 +92,7 @@ def on_context_switch(self):
self._tree = self.studio.designer.node
else:
self._tree = ComponentTreeView(self.body)
self._tree.allow_multi_select(True)
self._tree.on_select(self._trigger_select)
self.studio.designer.node = self._tree
self._tree.pack(fill="both", expand=True)
Expand Down Expand Up @@ -142,38 +143,52 @@ def on_widget_add(self, widget: PseudoWidget, parent=None):
)

def _trigger_select(self):
if self._selected and self._selected.widget == self._tree.get().widget:
if self.studio.selection == self.selection():
return
self.studio.select(self._tree.get().widget, self)
self._selected = self._tree.get()

def select(self, widget):
if widget:
self.studio.selection.set(self.selection())

def _select(self, _):
if self.studio.selection == self.selection():
return

if not self._tree:
return
nodes = self.studio_selection()

for node in list(self._tree.get()):
if node not in nodes:
self._tree.deselect(node)

for node in nodes:
if not node.selected:
node.select(silently=True)

def selection(self):
if not self._tree:
return []
return [i.widget for i in self._tree.get()]

def studio_selection(self):
return [i.node for i in self.studio.selection]

def on_widgets_delete(self, widgets, silently=False):
for widget in widgets:
widget.node.remove()

def on_widgets_restore(self, widgets):
for widget in widgets:
widget.layout.node.add(widget.node)

def on_widgets_layout_change(self, widgets):
for widget in widgets:
node = widget.node
self._selected = node
node.select(None, True) # Select node silently to avoid triggering a duplicate selection event
elif widget is None:
if self._selected:
self._selected.deselect()
self._selected = None

def on_select(self, widget):
self.select(widget)

def on_widget_delete(self, widget, silently=False):
widget.node.remove()

def on_widget_restore(self, widget):
widget.layout.node.add(widget.node)

def on_widget_layout_change(self, widget):
node = widget.node
if widget.layout == self.studio.designer:
parent = self._tree
else:
parent = widget.layout.node
if node.parent_node != parent:
parent.insert(None, node)
if widget.layout == self.studio.designer:
parent = self._tree
else:
parent = widget.layout.node
if node.parent_node != parent:
parent.insert(None, node)

def on_context_close(self, context):
if hasattr(context, "designer"):
Expand All @@ -184,9 +199,9 @@ def on_context_close(self, context):
def on_session_clear(self):
self._tree.clear()

def on_widget_change(self, old_widget, new_widget=None):
new_widget = new_widget if new_widget else old_widget
new_widget.node.widget_modified(new_widget)
def on_widgets_change(self, widgets):
for widget in widgets:
widget.node.widget_modified(widget)

def on_search_query(self, query: str):
self._tree.search(query)
Expand Down
8 changes: 4 additions & 4 deletions studio/feature/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def on_drag_end(self, event):
widget = self.event_first(event, self, Container)
if isinstance(widget, Container):
widget.add_new(self.component, *self.window.drag_window.get_center())
widget.clear_highlight()


class SelectableComponent(Component):
Expand Down Expand Up @@ -274,12 +275,12 @@ def __init__(self, master, studio=None, **cnf):
self._selected = None
self._component_cache = None
self._extern_groups = []
self._widget = None
self.collect_groups(self.get_pref("widget_set"))
# add custom widgets config to settings
templates.update(_widget_pref_template)
self._custom_group = None
self._custom_widgets = []
self.studio.bind("<<SelectionChanged>>", self.on_widget_select, add='+')
Preferences.acquire().add_listener(self._custom_pref_path, self._init_custom)
self._reload_custom()

Expand Down Expand Up @@ -438,7 +439,7 @@ def render_groups(self):

def render_extern_groups(self):
for group in self._extern_groups:
if group.supports(self._widget):
if self.studio.selection and all(group.supports(w) for w in self.studio.selection):
self.add_selector(group.selector)
else:
self.remove_selector(group.selector)
Expand Down Expand Up @@ -480,8 +481,7 @@ def unregister_group(self, group):
self._extern_groups.remove(group)
self._auto_select()

def on_select(self, widget):
self._widget = widget
def on_widget_select(self, _):
self.render_extern_groups()

def start_search(self, *_):
Expand Down
Loading

0 comments on commit 5e355cb

Please sign in to comment.