Skip to content

Commit

Permalink
Implement multiselect in components and event pane
Browse files Browse the repository at this point in the history
  • Loading branch information
ObaraEmmanuel committed Aug 19, 2023
1 parent f4e59cd commit ae62678
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 31 deletions.
4 changes: 2 additions & 2 deletions studio/feature/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
ComponentPane,
ComponentTree,
StylePane,
#EventPane,
#VariablePane,
EventPane,
VariablePane,
)


7 changes: 3 additions & 4 deletions studio/feature/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,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 @@ -439,7 +439,7 @@ def render_groups(self):

def render_extern_groups(self):
for group in self._extern_groups:
if group.supports(self._widget):
if all(group.supports(w) for w in self.studio.widgets):
self.add_selector(group.selector)
else:
self.remove_selector(group.selector)
Expand Down Expand Up @@ -481,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
85 changes: 60 additions & 25 deletions studio/feature/eventspane.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Label, CompoundList, Entry, Frame, Checkbutton, Button
)
from studio.feature._base import BaseFeature
from studio.lib.events import EventBinding, make_event
from studio.lib.events import EventBinding, make_event, event_equal


class BindingsTable(CompoundList):
Expand Down Expand Up @@ -33,13 +33,10 @@ def _delete_entry(self, *_):

def render(self):
self.config(height=40)
seq_frame = Frame(self, **self.style.highlight)
seq_frame.grid(row=0, column=0, sticky="nsew")
seq_frame.pack_propagate(False)
self.sequence = Entry(seq_frame, **self.style.input)
self.sequence.place(x=0, y=0, relwidth=1, relheight=1, width=-40)
self.sequence = Entry(self, **self.style.input)
self.sequence.grid(row=0, column=0, sticky="nsew")
self.sequence.set(self.value.sequence)
self.sequence.configure(**self.style.no_highlight)
self.sequence.configure(**self.style.highlight)
self.sequence.focus_set()
self.handler = Entry(self, **self.style.input)
self.handler.grid(row=0, column=1, sticky="ew")
Expand All @@ -56,7 +53,7 @@ def render(self):
del_btn.bind("<Button-1>", self._delete_entry)
# set the first two columns to expand evenly
for column in range(2):
self.grid_columnconfigure(column, weight=1, uniform=1)
self.grid_columnconfigure(column, weight=1)

for widget in (self.sequence, self.handler):
widget.on_change(self._on_value_change)
Expand Down Expand Up @@ -174,6 +171,8 @@ def __init__(self, master, studio, **cnf):
self.bindings.on_item_delete(self.delete_item)
self.bindings.pack(fill="both", expand=True)

self._multimap = {}

self._add = Button(
self._header, **self.style.button, width=25, height=25,
image=get_icon_image("add", 15, 15)
Expand All @@ -192,45 +191,81 @@ def __init__(self, master, studio, **cnf):
self._empty_frame = Label(self.bindings, **self.style.text_passive)
self._show_empty(self.NO_SELECTION_MSG)

self.studio.bind("<<SelectionChanged>>", self._on_select, "+")
self._suppress_change = False

def _show_empty(self, message):
self._empty_frame.place(x=0, y=0, relwidth=1, relheight=1)
self._empty_frame["text"] = message

def _remove_empty(self):
self._empty_frame.place_forget()

def _enforce_event_map(self, widget):
if not hasattr(widget, "_event_map_"):
setattr(widget, "_event_map_", {})

def add_new(self, *_):
if self.studio.selected is None:
if not self.studio.selection:
return
self._remove_empty()

target_widget = self.studio.selection[0]
new_binding = make_event("<>", "", False)
widget = self.studio.selected
if not hasattr(widget, "_event_map_"):
setattr(widget, "_event_map_", {})
widget._event_map_[new_binding.id] = new_binding
target_widget._event_map_[new_binding.id] = new_binding
self._multimap[new_binding.id] = [(new_binding.id, target_widget)]

for widget in self.studio.selection[1:]:
self._enforce_event_map(widget)
binding = make_event("<>", "", False)
widget._event_map_[binding.id] = binding
self._multimap[new_binding.id].append((binding.id, widget))
self.bindings.add(new_binding)

def delete_item(self, item):
widget = self.studio.selected
if widget is None:
return
widget._event_map_.pop(item.id)
for ev_id, widget in self._multimap[item.id]:
widget._event_map_.pop(ev_id)
self._multimap.pop(item.id)
self.bindings.remove(item.id)

def modify_item(self, value: EventBinding):
widget = self.studio.selected
widget._event_map_[value.id] = value
if self._suppress_change:
return
for ev_id, widget in self._multimap[value.id]:
widget._event_map_[ev_id] = EventBinding(ev_id, value.sequence, value.handler, value.add)

def on_select(self, widget):
if widget is None:
def _on_select(self, _):
if not self.studio.selection:
self._show_empty(self.NO_SELECTION_MSG)
return
self._remove_empty()
bindings = getattr(widget, "_event_map_", {})
values = bindings.values()
bindings = []
self._multimap.clear()
target_widget = self.studio.selection[0]
self._enforce_event_map(target_widget)

for binding in target_widget._event_map_.values():
is_common = True
ids = []
for widget in self.studio.selection[1:]:
self._enforce_event_map(widget)
for b in widget._event_map_.values():
if event_equal(binding, b):
ids.append((b.id, widget))
break
else:
is_common = False
break
if is_common:
bindings.append(binding)
ids.append((binding.id, target_widget))
self._multimap[binding.id] = ids

self.bindings.clear()
self.bindings.add(*values)
if not values:
self._suppress_change = True
self.bindings.add(*bindings)
self._suppress_change = False
if not bindings:
self._show_empty(self.NO_EVENT_MSG)

def start_search(self, *_):
Expand Down
4 changes: 4 additions & 0 deletions studio/lib/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
EventBinding = namedtuple("EventBinding", ["id", "sequence", "handler", "add"])


def event_equal(event1, event2):
return event1.sequence == event2.sequence and event1.handler == event2.handler and event1.add == event2.add


def make_event(*args, **kwargs):
return EventBinding(generate_id(), *args, **kwargs)

Expand Down

0 comments on commit ae62678

Please sign in to comment.