1
"""
2
Defines the Widget base class which provides bi-directional
3
communication between the rendered dashboard and the Widget
4
parameters.
5
"""
6 6
from __future__ import absolute_import, division, unicode_literals
7

8 6
from functools import partial
9

10 6
import param
11

12 6
from ..layout import Row
13 6
from ..io import push, state, unlocked
14 6
from ..reactive import Reactive
15 6
from ..viewable import Layoutable
16

17

18 6
class Widget(Reactive):
19
    """
20
    Widgets allow syncing changes in bokeh widget models with the
21
    parameters on the Widget instance.
22
    """
23

24 6
    disabled = param.Boolean(default=False, doc="""
25
       Whether the widget is disabled.""")
26

27 6
    name = param.String(default='')
28

29 6
    height = param.Integer(default=None, bounds=(0, None))
30

31 6
    width = param.Integer(default=None, bounds=(0, None))
32

33 6
    margin = param.Parameter(default=(5, 10), doc="""
34
        Allows to create additional space around the component. May
35
        be specified as a two-tuple of the form (vertical, horizontal)
36
        or a four-tuple (top, right, bottom, left).""")
37

38 6
    __abstract = True
39

40 6
    _widget_type = None
41

42
    # Whether the widget supports embedding
43 6
    _supports_embed = False
44

45
    # Any parameters that require manual updates handling for the models
46
    # e.g. parameters which affect some sub-model
47 6
    _manual_params = []
48

49 6
    _rename = {'name': 'title'}
50

51 6
    def __init__(self, **params):
52 6
        if 'name' not in params:
53 6
            params['name'] = ''
54 6
        if '_supports_embed' in params:
55 6
            self._supports_embed = params.pop('_supports_embed')
56 6
        if '_param_pane' in params:
57 0
            self._param_pane = params.pop('_param_pane')
58
        else:
59 6
            self._param_pane = None
60 6
        super(Widget, self).__init__(**params)
61 6
        self.param.watch(self._update_widget, self._manual_params)
62

63 6
    @classmethod
64 1
    def from_param(cls, parameter, **params):
65
        """
66
        Construct a widget from a Parameter and link the two
67
        bi-directionally.
68
        
69
        Parameters
70
        ----------
71
        parameter: param.Parameter
72
          A parameter to create the widget from.
73
        params: dict
74
          Keyword arguments to be passed to the widget constructor
75
        
76
        Returns
77
        -------
78
        Widget instance linked to the supplied parameter
79
        """
80 6
        from ..param import Param
81 6
        layout = Param(parameter, widgets={parameter.name: dict(type=cls, **params)})
82 6
        return layout[0]
83

84 6
    def _manual_update(self, events, model, doc, root, parent, comm):
85
        """
86
        Method for handling any manual update events, i.e. events triggered
87
        by changes in the manual params.
88
        """
89

90 6
    def _update_widget(self, *events):
91 6
        for ref, (model, parent) in self._models.items():
92 6
            if ref not in state._views or ref in state._fake_roots:
93 0
                continue
94 6
            viewable, root, doc, comm = state._views[ref]
95 6
            if comm or state._unblocked(doc):
96 6
                with unlocked():
97 6
                    self._manual_update(events, model, doc, root, parent, comm)
98 6
                if comm and 'embedded' not in root.tags:
99 6
                    push(doc, comm)
100
            else:
101 0
                cb = partial(self._manual_update, events, model, doc, root, parent, comm)
102 0
                if doc.session_context:
103 0
                    doc.add_next_tick_callback(cb)
104
                else:
105 0
                    cb()
106

107 6
    def _get_model(self, doc, root=None, parent=None, comm=None):
108 6
        model = self._widget_type(**self._process_param_change(self._init_properties()))
109 6
        if root is None:
110 6
            root = model
111
        # Link parameters and bokeh model
112 6
        values = dict(self.param.get_param_values())
113 6
        properties = self._filter_properties(list(self._process_param_change(values)))
114 6
        self._models[root.ref['id']] = (model, parent)
115 6
        self._link_props(model, properties, doc, root, comm)
116 6
        return model
117

118 6
    @property
119 1
    def _linkable_params(self):
120 6
        return [p for p in self._synced_params() if self._rename.get(p, False) is not None
121
                and self._source_transforms.get(p, False) is not None]
122

123 6
    def _synced_params(self):
124 6
        return [p for p in self.param if p not in self._manual_params]
125

126 6
    def _filter_properties(self, properties):
127 6
        return [p for p in properties if p not in Layoutable.param]
128

129 6
    def _get_embed_state(self, root, values=None, max_opts=3):
130
        """
131
        Returns the bokeh model and a discrete set of value states
132
        for the widget.
133

134
        Arguments
135
        ---------
136
        root: bokeh.model.Model
137
          The root model of the widget
138
        values: list (optional)
139
          An explicit list of value states to embed
140
        max_opts: int
141
          The maximum number of states the widget should return
142

143
        Returns
144
        -------
145
        widget: panel.widget.Widget
146
          The Panel widget instance to modify to effect state changes
147
        model: bokeh.model.Model
148
          The bokeh model to record the current value state on
149
        values: list
150
          A list of value states to explore.
151
        getter: callable
152
          A function that returns the state value given the model
153
        on_change: string
154
          The name of the widget property to attach a callback on
155
        js_getter: string
156
          JS snippet that returns the state value given the model
157
        """
158

159

160 6
class CompositeWidget(Widget):
161
    """
162
    A baseclass for widgets which are made up of two or more other
163
    widgets
164
    """
165

166 6
    __abstract = True
167

168 6
    _composite_type = Row
169

170 6
    def __init__(self, **params):
171 6
        super(CompositeWidget, self).__init__(**params)
172 6
        layout = {p: getattr(self, p) for p in Layoutable.param
173
                  if getattr(self, p) is not None}
174 6
        if layout.get('width', self.width) is None and not 'sizing_mode' in layout:
175 6
            layout['sizing_mode'] = 'stretch_width'
176 6
        self._composite = self._composite_type(**layout)
177 6
        self._models = self._composite._models
178 6
        self.param.watch(self._update_layout_params, list(Layoutable.param))
179

180 6
    def _update_layout_params(self, *events):
181 0
        updates = {event.name: event.new for event in events}
182 0
        self._composite.param.set_param(**updates)
183

184 6
    def select(self, selector=None):
185
        """
186
        Iterates over the Viewable and any potential children in the
187
        applying the Selector.
188

189
        Arguments
190
        ---------
191
        selector: type or callable or None
192
          The selector allows selecting a subset of Viewables by
193
          declaring a type or callable function to filter by.
194

195
        Returns
196
        -------
197
        viewables: list(Viewable)
198
        """
199 6
        objects = super(CompositeWidget, self).select(selector)
200 6
        for obj in self._composite.objects:
201 6
            objects += obj.select(selector)
202 6
        return objects
203

204 6
    def _cleanup(self, root):
205 6
        self._composite._cleanup(root)
206 6
        super(CompositeWidget, self)._cleanup(root)
207

208 6
    def _get_model(self, doc, root=None, parent=None, comm=None):
209 6
        model = self._composite._get_model(doc, root, parent, comm)
210 6
        if root is None:
211 6
            root = parent = model
212 6
        self._models[root.ref['id']] = (model, parent)
213 6
        return model
214

215 6
    def __contains__(self, object):
216 0
        return object in self._composite.objects
217

218 6
    def _synced_params(self):
219 6
        return []

Read our documentation on viewing source code .

Loading