From 72a833ece98ae4bb7919b32c88262aadffdcd7c9 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Mon, 29 Mar 2021 12:35:35 +0200 Subject: [PATCH 1/3] Factor out NamedListLike baseclass --- panel/layout/base.py | 147 ++++++++++++++++++++++++++----------------- 1 file changed, 90 insertions(+), 57 deletions(-) diff --git a/panel/layout/base.py b/panel/layout/base.py index a107d1004f..7999c022ed 100644 --- a/panel/layout/base.py +++ b/panel/layout/base.py @@ -142,7 +142,6 @@ def select(self, selector=None): return objects - class ListLike(param.Parameterized): objects = param.List(default=[], doc=""" @@ -331,62 +330,11 @@ def reverse(self): new_objects.reverse() self.objects = new_objects - - -class ListPanel(ListLike, Panel): - """ - An abstract baseclass for Panel objects with list-like children. - """ - - margin = param.Parameter(default=0, doc=""" - Allows to create additional space around the component. May - be specified as a two-tuple of the form (vertical, horizontal) - or a four-tuple (top, right, bottom, left).""") - - scroll = param.Boolean(default=False, doc=""" - Whether to add scrollbars if the content overflows the size - of the container.""") - _source_transforms = {'scroll': None} - - __abstract = True - - def __init__(self, *objects, **params): - from ..pane import panel - if objects: - if 'objects' in params: - raise ValueError("A %s's objects should be supplied either " - "as positional arguments or as a keyword, " - "not both." % type(self).__name__) - params['objects'] = [panel(pane) for pane in objects] - elif 'objects' in params: - params['objects'] = [panel(pane) for pane in params['objects']] - super(Panel, self).__init__(**params) - - def _process_param_change(self, params): - scroll = params.pop('scroll', None) - css_classes = self.css_classes or [] - if scroll: - params['css_classes'] = css_classes + ['scrollable'] - elif scroll == False: - params['css_classes'] = css_classes - return super()._process_param_change(params) - - def _cleanup(self, root): - if root.ref['id'] in state._fake_roots: - state._fake_roots.remove(root.ref['id']) - super()._cleanup(root) - for p in self.objects: - p._cleanup(root) - - -class NamedListPanel(ListPanel): - - active = param.Integer(default=0, bounds=(0, None), doc=""" - Index of the currently displayed objects.""") +class NamedListLike(param.Parameterized): objects = param.List(default=[], doc=""" - The list of child objects that make up the tabs.""") + The list of child objects that make up the layout.""") def __init__(self, *items, **params): if 'objects' in params: @@ -394,9 +342,9 @@ def __init__(self, *items, **params): raise ValueError('%s objects should be supplied either ' 'as positional arguments or as a keyword, ' 'not both.' % type(self).__name__) - items = params['objects'] - objects, self._names = self._to_objects_and_names(items) - super().__init__(*objects, **params) + items = params.pop('objects') + params['objects'], self._names = self._to_objects_and_names(items) + super().__init__(**params) self._panels = defaultdict(dict) self.param.watch(self._update_names, 'objects') # ALERT: Ensure that name update happens first, should be @@ -441,6 +389,10 @@ def _update_active(self, *events): # Public API #---------------------------------------------------------------- + def __iter__(self): + for obj in self.objects: + yield obj + def __add__(self, other): if isinstance(other, NamedListPanel): other = list(zip(other._names, other.objects)) @@ -621,6 +573,87 @@ def reverse(self): self.objects = new_objects +class ListPanel(ListLike, Panel): + """ + An abstract baseclass for Panel objects with list-like children. + """ + + margin = param.Parameter(default=0, doc=""" + Allows to create additional space around the component. May + be specified as a two-tuple of the form (vertical, horizontal) + or a four-tuple (top, right, bottom, left).""") + + scroll = param.Boolean(default=False, doc=""" + Whether to add scrollbars if the content overflows the size + of the container.""") + + _source_transforms = {'scroll': None} + + __abstract = True + + def __init__(self, *objects, **params): + from ..pane import panel + if objects: + if 'objects' in params: + raise ValueError("A %s's objects should be supplied either " + "as positional arguments or as a keyword, " + "not both." % type(self).__name__) + params['objects'] = [panel(pane) for pane in objects] + elif 'objects' in params: + params['objects'] = [panel(pane) for pane in params['objects']] + super(Panel, self).__init__(**params) + + def _process_param_change(self, params): + scroll = params.pop('scroll', None) + css_classes = self.css_classes or [] + if scroll: + params['css_classes'] = css_classes + ['scrollable'] + elif scroll == False: + params['css_classes'] = css_classes + return super()._process_param_change(params) + + def _cleanup(self, root): + if root.ref['id'] in state._fake_roots: + state._fake_roots.remove(root.ref['id']) + super()._cleanup(root) + for p in self.objects: + p._cleanup(root) + + +class NamedListPanel(NamedListLike, Panel): + + active = param.Integer(default=0, bounds=(0, None), doc=""" + Index of the currently displayed objects.""") + + margin = param.Parameter(default=0, doc=""" + Allows to create additional space around the component. May + be specified as a two-tuple of the form (vertical, horizontal) + or a four-tuple (top, right, bottom, left).""") + + scroll = param.Boolean(default=False, doc=""" + Whether to add scrollbars if the content overflows the size + of the container.""") + + _source_transforms = {'scroll': None} + + __abstract = True + + def _process_param_change(self, params): + scroll = params.pop('scroll', None) + css_classes = self.css_classes or [] + if scroll: + params['css_classes'] = css_classes + ['scrollable'] + elif scroll == False: + params['css_classes'] = css_classes + return super()._process_param_change(params) + + def _cleanup(self, root): + if root.ref['id'] in state._fake_roots: + state._fake_roots.remove(root.ref['id']) + super()._cleanup(root) + for p in self.objects: + p._cleanup(root) + class Row(ListPanel): """ From 0e07361c29beab70dc2cd1f2e3ee05c3b0a18392 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Mon, 29 Mar 2021 12:49:30 +0200 Subject: [PATCH 2/3] Add missing methods --- panel/layout/base.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/panel/layout/base.py b/panel/layout/base.py index 7999c022ed..16fd7eae7a 100644 --- a/panel/layout/base.py +++ b/panel/layout/base.py @@ -389,10 +389,17 @@ def _update_active(self, *events): # Public API #---------------------------------------------------------------- + def __len__(self): + return len(self.objects) + def __iter__(self): for obj in self.objects: yield obj + def __iadd__(self, other): + self.extend(other) + return self + def __add__(self, other): if isinstance(other, NamedListPanel): other = list(zip(other._names, other.objects)) From 692b2bed578f8141107b48a3d557eaf741df32fb Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Mon, 29 Mar 2021 14:32:34 +0200 Subject: [PATCH 3/3] Add missing getitem --- panel/layout/base.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/panel/layout/base.py b/panel/layout/base.py index 16fd7eae7a..74820de11b 100644 --- a/panel/layout/base.py +++ b/panel/layout/base.py @@ -389,6 +389,9 @@ def _update_active(self, *events): # Public API #---------------------------------------------------------------- + def __getitem__(self, index): + return self.objects[index] + def __len__(self): return len(self.objects)