##// END OF EJS Templates
Better respect for abstraction barriers
Better respect for abstraction barriers

File last commit:

r18173:d980e07d merge
r18207:e27b7a97
Show More
widget.py
446 lines | 16.4 KiB | text/x-python | PythonLexer
Jonathan Frederic
Dev meeting widget review day 1
r14586 """Base Widget class. Allows user to create widgets in the back-end that render
in the IPython notebook front-end.
Jonathan Frederic
Cleaned up Python widget code.
r14283 """
#-----------------------------------------------------------------------------
# Copyright (c) 2013, the IPython Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
Jonathan Frederic
Implement a context manager as a property locking mechanism in Widget.
r14579 from contextlib import contextmanager
Jason Grout
Add a new context manager, Widget.hold_sync(), which holds any syncing until the manager exits...
r17621 import collections
Jonathan Frederic
Added widget.py
r14223
MinRK
show traceback in widget handlers...
r15192 from IPython.core.getipython import get_ipython
Jonathan Frederic
Basic display logic...
r14229 from IPython.kernel.comm import Comm
from IPython.config import LoggingConfigurable
Jonathan Frederic
Partial implementation of styles
r17723 from IPython.utils.traitlets import Unicode, Dict, Instance, Bool, List, \
CaselessStrEnum, Tuple, CUnicode, Int, Set
Jonathan Frederic
Updates to widget.py...
r14232 from IPython.utils.py3compat import string_types
Jonathan Frederic
Cleaned up Python widget code.
r14283 #-----------------------------------------------------------------------------
# Classes
#-----------------------------------------------------------------------------
Jonathan Frederic
Added new CallbackDispatcher class
r14658 class CallbackDispatcher(LoggingConfigurable):
MinRK
review pass on Python-side of widgets...
r14793 """A structure for registering and running callbacks"""
callbacks = List()
def __call__(self, *args, **kwargs):
"""Call all of the registered callbacks."""
Jonathan Frederic
Callback dispatcher return callback value....
r14721 value = None
MinRK
review pass on Python-side of widgets...
r14793 for callback in self.callbacks:
try:
local_value = callback(*args, **kwargs)
except Exception as e:
MinRK
show traceback in widget handlers...
r15192 ip = get_ipython()
if ip is None:
self.log.warn("Exception in callback %s: %s", callback, e, exc_info=True)
else:
ip.showtraceback()
MinRK
review pass on Python-side of widgets...
r14793 else:
Jonathan Frederic
Callback dispatcher return callback value....
r14721 value = local_value if local_value is not None else value
return value
Jonathan Frederic
Added new CallbackDispatcher class
r14658
def register_callback(self, callback, remove=False):
"""(Un)Register a callback
Parameters
----------
callback: method handle
MinRK
review pass on Python-side of widgets...
r14793 Method to be registered or unregistered.
Jonathan Frederic
Added new CallbackDispatcher class
r14658 remove=False: bool
MinRK
review pass on Python-side of widgets...
r14793 Whether to unregister the callback."""
Jonathan Frederic
Added new CallbackDispatcher class
r14658 # (Un)Register the callback.
MinRK
review pass on Python-side of widgets...
r14793 if remove and callback in self.callbacks:
self.callbacks.remove(callback)
elif not remove and callback not in self.callbacks:
self.callbacks.append(callback)
Jonathan Frederic
Added widget.py
r14223
MinRK
show traceback in widget handlers...
r15192 def _show_traceback(method):
"""decorator for showing tracebacks in IPython"""
def m(self, *args, **kwargs):
try:
return(method(self, *args, **kwargs))
except Exception as e:
ip = get_ipython()
if ip is None:
self.log.warn("Exception in widget method %s: %s", method, e, exc_info=True)
else:
ip.showtraceback()
return m
Jonathan Frederic
Added new CallbackDispatcher class
r14658
class Widget(LoggingConfigurable):
Jonathan Frederic
Reorganized attrs in widget.py
r14653 #-------------------------------------------------------------------------
# Class attributes
#-------------------------------------------------------------------------
MinRK
review pass on Python-side of widgets...
r14793 _widget_construction_callback = None
Jonathan Frederic
Dev meeting widget review day 1
r14586 widgets = {}
Jonathan Frederic
Added event for widget construction
r14478
MinRK
review pass on Python-side of widgets...
r14793 @staticmethod
Jonathan Frederic
Added event for widget construction
r14478 def on_widget_constructed(callback):
MinRK
review pass on Python-side of widgets...
r14793 """Registers a callback to be called when a widget is constructed.
Jonathan Frederic
More PEP8 changes
r14607
The callback must have the following signature:
Jonathan Frederic
Added event for widget construction
r14478 callback(widget)"""
MinRK
review pass on Python-side of widgets...
r14793 Widget._widget_construction_callback = callback
Jonathan Frederic
Added event for widget construction
r14478
MinRK
review pass on Python-side of widgets...
r14793 @staticmethod
Jonathan Frederic
s/_handle_widget_constructed/_call_widget_constructed
r14542 def _call_widget_constructed(widget):
MinRK
review pass on Python-side of widgets...
r14793 """Static method, called when a widget is constructed."""
if Widget._widget_construction_callback is not None and callable(Widget._widget_construction_callback):
Widget._widget_construction_callback(widget)
Jonathan Frederic
Added event for widget construction
r14478
Jonathan Frederic
Reorganized attrs in widget.py
r14653 #-------------------------------------------------------------------------
# Traits
#-------------------------------------------------------------------------
Jonathan Frederic
s/model_name/_model_name
r14896 _model_name = Unicode('WidgetModel', help="""Name of the backbone model
Jonathan Frederic
Dev meeting widget review day 1
r14586 registered in the front-end to create and sync this widget with.""")
Sylvain Corlay
Set default view to None and never display widget with no view
r17989 _view_name = Unicode(None, allow_none=True, help="""Default view registered in the front-end
Jonathan Frederic
sync=True isntead of a keys list
r14588 to use to represent the widget.""", sync=True)
Jason Grout
Make the widget comm attribute more straigtforward...
r17615 comm = Instance('IPython.kernel.comm.Comm')
MinRK
review pass on Python-side of widgets...
r14793
Jonathan Frederic
Added msg_throttle sync=True widget traitlet
r15368 msg_throttle = Int(3, sync=True, help="""Maximum number of msgs the
front-end can send before receiving an idle msg from the back-end.""")
MinRK
review pass on Python-side of widgets...
r14793
keys = List()
def _keys_default(self):
return [name for name in self.traits(sync=True)]
_property_lock = Tuple((None, None))
Jason Grout
Add a new context manager, Widget.hold_sync(), which holds any syncing until the manager exits...
r17621 _send_state_lock = Int(0)
_states_to_send = Set(allow_none=False)
MinRK
review pass on Python-side of widgets...
r14793 _display_callbacks = Instance(CallbackDispatcher, ())
_msg_callbacks = Instance(CallbackDispatcher, ())
Jonathan Frederic
Reorganized attrs in widget.py
r14653 #-------------------------------------------------------------------------
# (Con/de)structor
MinRK
review pass on Python-side of widgets...
r14793 #-------------------------------------------------------------------------
Jonathan Frederic
Allow parent to be set after construction......
r14310 def __init__(self, **kwargs):
Jonathan Frederic
More PEP8 changes
r14607 """Public constructor"""
Sylvain Corlay
allowing widet id to be set externally
r17616 self._model_id = kwargs.pop('model_id', None)
Jonathan Frederic
s/Widget/DOMWidget s/BaseWidget/Widget
r14540 super(Widget, self).__init__(**kwargs)
Jonathan Frederic
Added event for widget construction
r14478
Jonathan Frederic
s/_handle_widget_constructed/_call_widget_constructed
r14542 Widget._call_widget_constructed(self)
Jason Grout
Automatically open a comm on creation of widgets...
r17612 self.open()
Jason Grout
Separate the display from the models on the python side, creating a BaseWidget class....
r14485
Jonathan Frederic
Added widget.py
r14223 def __del__(self):
Jonathan Frederic
Cleaned up Python widget code.
r14283 """Object disposal"""
Jonathan Frederic
Added widget.py
r14223 self.close()
Jason Grout
Separate the display from the models on the python side, creating a BaseWidget class....
r14485
Jonathan Frederic
Reorganized attrs in widget.py
r14653 #-------------------------------------------------------------------------
# Properties
MinRK
review pass on Python-side of widgets...
r14793 #-------------------------------------------------------------------------
Jonathan Frederic
Dev meeting widget review day 1
r14586
Jason Grout
Automatically open a comm on creation of widgets...
r17612 def open(self):
"""Open a comm to the frontend if one isn't already open."""
Jason Grout
Make the widget comm attribute more straigtforward...
r17615 if self.comm is None:
Sylvain Corlay
allowing widet id to be set externally
r17616 if self._model_id is None:
self.comm = Comm(target_name=self._model_name)
self._model_id = self.model_id
else:
self.comm = Comm(target_name=self._model_name, comm_id=self._model_id)
Jason Grout
Make the widget comm attribute more straigtforward...
r17615 self.comm.on_msg(self._handle_msg)
Jonathan Frederic
Dev meeting widget review day 1
r14586 Widget.widgets[self.model_id] = self
# first update
self.send_state()
Jason Grout
Automatically open a comm on creation of widgets...
r17612
Jonathan Frederic
Re-decoupled comm_id from widget models
r14512 @property
def model_id(self):
Jonathan Frederic
Added doc strings to properties in widget.py
r14654 """Gets the model id of this widget.
If a Comm doesn't exist yet, a Comm will be created automagically."""
Jonathan Frederic
Fixed typo in model_id property
r14527 return self.comm.comm_id
Jason Grout
Separate the display from the models on the python side, creating a BaseWidget class....
r14485
Jonathan Frederic
Reorganized attrs in widget.py
r14653 #-------------------------------------------------------------------------
# Methods
MinRK
review pass on Python-side of widgets...
r14793 #-------------------------------------------------------------------------
Jonathan Frederic
Reorganized attrs in widget.py
r14653 def close(self):
MinRK
review pass on Python-side of widgets...
r14793 """Close method.
Jonathan Frederic
Updates to widget.py...
r14232
sylvain.corlay
decoupling the comm lifetime from the widget lifetime
r17405 Closes the underlying comm.
Jonathan Frederic
Reorganized attrs in widget.py
r14653 When the comm is closed, all of the widget views are automatically
removed from the front-end."""
Jason Grout
Make the widget comm attribute more straigtforward...
r17615 if self.comm is not None:
MinRK
avoid unregistering widget model twice...
r17540 Widget.widgets.pop(self.model_id, None)
Jason Grout
Make the widget comm attribute more straigtforward...
r17615 self.comm.close()
self.comm = None
Sylvain Corlay
del Widget.widgets[seld.model_id] in close rather than in __del__
r17465
Jonathan Frederic
Cleaned up Python widget code.
r14283 def send_state(self, key=None):
Jonathan Frederic
Dev meeting widget review day 1
r14586 """Sends the widget state, or a piece of it, to the front-end.
Jonathan Frederic
Cleaned up Python widget code.
r14283
Parameters
----------
Jason Grout
Add a new context manager, Widget.hold_sync(), which holds any syncing until the manager exits...
r17621 key : unicode, or iterable (optional)
A single property's name or iterable of property names to sync with the front-end.
Jonathan Frederic
Cleaned up Python widget code.
r14283 """
Jonathan Frederic
Halign dict colons
r14610 self._send({
"method" : "update",
Jason Grout
Add a new context manager, Widget.hold_sync(), which holds any syncing until the manager exits...
r17621 "state" : self.get_state(key=key)
Jonathan Frederic
Halign dict colons
r14610 })
Jonathan Frederic
Cleaned up Python widget code.
r14283
Jason Grout
Intermediate changes to javascript side of backbone widgets
r14486 def get_state(self, key=None):
Jason Grout
Separate the display from the models on the python side, creating a BaseWidget class....
r14485 """Gets the widget state, or a piece of it.
Jonathan Frederic
Cleaned up Python widget code.
r14283
Parameters
----------
Jason Grout
Add a new context manager, Widget.hold_sync(), which holds any syncing until the manager exits...
r17621 key : unicode or iterable (optional)
A single property's name or iterable of property names to get.
Jonathan Frederic
Cleaned up Python widget code.
r14283 """
Jason Grout
Add a new context manager, Widget.hold_sync(), which holds any syncing until the manager exits...
r17621 if key is None:
keys = self.keys
elif isinstance(key, string_types):
keys = [key]
elif isinstance(key, collections.Iterable):
keys = key
else:
raise ValueError("key must be a string, an iterable of keys, or None")
Jason Grout
Update widget serializer/unserializer to allow custom serialization on a trait-by-trait basis....
r17237 state = {}
for k in keys:
Jason Grout
Make the widget property_lock store the JSON state, not the original object...
r17674 f = self.trait_metadata(k, 'to_json', self._trait_to_json)
Jason Grout
Simplify the code for picking json serialization functions to expose the logic better
r17294 value = getattr(self, k)
state[k] = f(value)
Jason Grout
Update widget serializer/unserializer to allow custom serialization on a trait-by-trait basis....
r17237 return state
Jonathan Frederic
s/long thing/set_state
r18070
def set_state(self, sync_data):
"""Called when a state is received from the front-end."""
for name in self.keys:
if name in sync_data:
json_value = sync_data[name]
from_json = self.trait_metadata(name, 'from_json', self._trait_from_json)
with self._lock_property(name, json_value):
setattr(self, name, from_json(json_value))
Jason Grout
Update widget serializer/unserializer to allow custom serialization on a trait-by-trait basis....
r17237
Jonathan Frederic
Added support for custom widget msgs
r14387 def send(self, content):
"""Sends a custom msg to the widget model in the front-end.
Parameters
----------
content : dict
Content of the message to send.
"""
Jonathan Frederic
s/custom_content/content
r14655 self._send({"method": "custom", "content": content})
Jonathan Frederic
Added support for custom widget msgs
r14387
Jonathan Frederic
Dev meeting widget review day 1
r14586 def on_msg(self, callback, remove=False):
MinRK
review pass on Python-side of widgets...
r14793 """(Un)Register a custom msg receive callback.
Jonathan Frederic
Added support for custom widget msgs
r14387
Parameters
----------
MinRK
review pass on Python-side of widgets...
r14793 callback: callable
Thomas Kluyver
Fix some formatting in widget docstrings
r14915 callback will be passed two arguments when a message arrives::
MinRK
review pass on Python-side of widgets...
r14793 callback(widget, content)
Thomas Kluyver
Fix some formatting in widget docstrings
r14915
Jonathan Frederic
Added support for custom widget msgs
r14387 remove: bool
True if the callback should be unregistered."""
Jonathan Frederic
Added new CallbackDispatcher class
r14658 self._msg_callbacks.register_callback(callback, remove=remove)
Jonathan Frederic
Added support for custom widget msgs
r14387
Jonathan Frederic
Added on_display callback
r14330 def on_displayed(self, callback, remove=False):
Jonathan Frederic
More PEP8 changes
r14607 """(Un)Register a widget displayed callback.
Jonathan Frederic
Added on_display callback
r14330
Jonathan Frederic
Fixed doc string comments, removed extra space
r14332 Parameters
----------
Jonathan Frederic
Added on_display callback
r14330 callback: method handler
Thomas Kluyver
Fix some formatting in widget docstrings
r14915 Must have a signature of::
MinRK
review pass on Python-side of widgets...
r14793 callback(widget, **kwargs)
Thomas Kluyver
Fix some formatting in widget docstrings
r14915
MinRK
review pass on Python-side of widgets...
r14793 kwargs from display are passed through without modification.
Jonathan Frederic
Added on_display callback
r14330 remove: bool
True if the callback should be unregistered."""
Jonathan Frederic
Added new CallbackDispatcher class
r14658 self._display_callbacks.register_callback(callback, remove=remove)
Jonathan Frederic
Added on_display callback
r14330
Jonathan Frederic
Reorganized attrs in widget.py
r14653 #-------------------------------------------------------------------------
Jonathan Frederic
Cleaned up Python widget code.
r14283 # Support methods
Jonathan Frederic
Reorganized attrs in widget.py
r14653 #-------------------------------------------------------------------------
@contextmanager
Jonathan Frederic
Fixed name conflict with _property_lock
r14659 def _lock_property(self, key, value):
Jonathan Frederic
Reorganized attrs in widget.py
r14653 """Lock a property-value pair.
Jason Grout
Make the widget property_lock store the JSON state, not the original object...
r17674 The value should be the JSON state of the property.
Jonathan Frederic
Reorganized attrs in widget.py
r14653 NOTE: This, in addition to the single lock for all state changes, is
flawed. In the future we may want to look into buffering state changes
back to the front-end."""
self._property_lock = (key, value)
try:
yield
finally:
self._property_lock = (None, None)
Jason Grout
Add a new context manager, Widget.hold_sync(), which holds any syncing until the manager exits...
r17621 @contextmanager
def hold_sync(self):
"""Hold syncing any state until the context manager is released"""
# We increment a value so that this can be nested. Syncing will happen when
# all levels have been released.
self._send_state_lock += 1
try:
yield
finally:
self._send_state_lock -=1
if self._send_state_lock == 0:
self.send_state(self._states_to_send)
self._states_to_send.clear()
Jonathan Frederic
Reorganized attrs in widget.py
r14653 def _should_send_property(self, key, value):
"""Check the property lock (property_lock)"""
Jason Grout
Make the widget property_lock store the JSON state, not the original object...
r17674 to_json = self.trait_metadata(key, 'to_json', self._trait_to_json)
if (key == self._property_lock[0]
and to_json(value) == self._property_lock[1]):
Jason Grout
Before syncing a widget's state, check first for the property lock, then for the widget state lock
r17623 return False
elif self._send_state_lock > 0:
Jason Grout
Add a new context manager, Widget.hold_sync(), which holds any syncing until the manager exits...
r17621 self._states_to_send.add(key)
return False
Jason Grout
Before syncing a widget's state, check first for the property lock, then for the widget state lock
r17623 else:
return True
Jonathan Frederic
Reorganized attrs in widget.py
r14653
# Event handlers
MinRK
show traceback in widget handlers...
r15192 @_show_traceback
Jonathan Frederic
Reorganized attrs in widget.py
r14653 def _handle_msg(self, msg):
"""Called when a msg is received from the front-end"""
data = msg['content']['data']
method = data['method']
if not method in ['backbone', 'custom']:
self.log.error('Unknown front-end to back-end widget msg with method "%s"' % method)
# Handle backbone sync methods CREATE, PATCH, and UPDATE all in one.
if method == 'backbone' and 'sync_data' in data:
sync_data = data['sync_data']
Jonathan Frederic
s/long thing/set_state
r18070 self.set_state(sync_data) # handles all methods
Jonathan Frederic
Reorganized attrs in widget.py
r14653
# Handle a custom msg from the front-end
elif method == 'custom':
Jonathan Frederic
s/custom_content/content
r14655 if 'content' in data:
self._handle_custom_msg(data['content'])
Jonathan Frederic
Reorganized attrs in widget.py
r14653
def _handle_custom_msg(self, content):
"""Called when a custom msg is received."""
MinRK
review pass on Python-side of widgets...
r14793 self._msg_callbacks(self, content)
Jonathan Frederic
Fix infinite loop typo
r17967
def _notify_trait(self, name, old_value, new_value):
Jonathan Frederic
Reorganized attrs in widget.py
r14653 """Called when a property has been changed."""
Jonathan Frederic
Fix infinite loop typo
r17967 # Trigger default traitlet callback machinery. This allows any user
# registered validation to be processed prior to allowing the widget
# machinery to handle the state.
Jonathan Frederic
Fix notify_trait getting called too early.
r17994 LoggingConfigurable._notify_trait(self, name, old_value, new_value)
Jonathan Frederic
Fix infinite loop typo
r17967
# Send the state after the user registered callbacks for trait changes
# have all fired (allows for user to validate values).
Jonathan Frederic
Fix notify_trait getting called too early.
r17994 if self.comm is not None and name in self.keys:
Jonathan Frederic
Fix infinite loop typo
r17967 # Make sure this isn't information that the front-end just sent us.
if self._should_send_property(name, new_value):
# Send new state to front-end
self.send_state(key=name)
Jonathan Frederic
Reorganized attrs in widget.py
r14653
def _handle_displayed(self, **kwargs):
"""Called when a view has been displayed for this widget instance"""
MinRK
review pass on Python-side of widgets...
r14793 self._display_callbacks(self, **kwargs)
Jonathan Frederic
Reorganized attrs in widget.py
r14653
Jason Grout
Change serialize/deserialize to to_json/from_json
r17328 def _trait_to_json(self, x):
"""Convert a trait value to json
Jonathan Frederic
Reorganized attrs in widget.py
r14653
Jason Grout
Update widget serializer/unserializer to allow custom serialization on a trait-by-trait basis....
r17237 Traverse lists/tuples and dicts and serialize their values as well.
Replace any widgets with their model_id
"""
Jonathan Frederic
ict comprehension and list comprehension in pack/unpack widgets
r14656 if isinstance(x, dict):
Jason Grout
Change serialize/deserialize to to_json/from_json
r17328 return {k: self._trait_to_json(v) for k, v in x.items()}
Jonathan Frederic
Changed children list to CTuple....
r15465 elif isinstance(x, (list, tuple)):
Jason Grout
Change serialize/deserialize to to_json/from_json
r17328 return [self._trait_to_json(v) for v in x]
Jonathan Frederic
ict comprehension and list comprehension in pack/unpack widgets
r14656 elif isinstance(x, Widget):
Jason Grout
Prepend a sentinel value to model ids to distinguish them from normal UUIDs (from Sylvain Corlay).
r17262 return "IPY_MODEL_" + x.model_id
Jonathan Frederic
Reorganized attrs in widget.py
r14653 else:
Jonathan Frederic
Document in widget packing that vaues must be JSON-able.
r14657 return x # Value must be JSON-able
Jonathan Frederic
Reorganized attrs in widget.py
r14653
Jason Grout
Change serialize/deserialize to to_json/from_json
r17328 def _trait_from_json(self, x):
Jason Grout
Update widget serializer/unserializer to allow custom serialization on a trait-by-trait basis....
r17237 """Convert json values to objects
Jonathan Frederic
Reorganized attrs in widget.py
r14653
Jason Grout
Change serialize/deserialize to to_json/from_json
r17328 Replace any strings representing valid model id values to Widget references.
Jason Grout
Update widget serializer/unserializer to allow custom serialization on a trait-by-trait basis....
r17237 """
Jonathan Frederic
ict comprehension and list comprehension in pack/unpack widgets
r14656 if isinstance(x, dict):
Jason Grout
Change serialize/deserialize to to_json/from_json
r17328 return {k: self._trait_from_json(v) for k, v in x.items()}
Jonathan Frederic
Changed children list to CTuple....
r15465 elif isinstance(x, (list, tuple)):
Jason Grout
Change serialize/deserialize to to_json/from_json
r17328 return [self._trait_from_json(v) for v in x]
Jason Grout
Prepend a sentinel value to model ids to distinguish them from normal UUIDs (from Sylvain Corlay).
r17262 elif isinstance(x, string_types) and x.startswith('IPY_MODEL_') and x[10:] in Widget.widgets:
Jason Grout
Update widget serializer/unserializer to allow custom serialization on a trait-by-trait basis....
r17237 # we want to support having child widgets at any level in a hierarchy
# trusting that a widget UUID will not appear out in the wild
Jason Grout
Strip the IPY_MODEL_ prefix from widget IDs before referencing them.
r17733 return Widget.widgets[x[10:]]
Jonathan Frederic
Reorganized attrs in widget.py
r14653 else:
Jonathan Frederic
ict comprehension and list comprehension in pack/unpack widgets
r14656 return x
Jonathan Frederic
Reorganized attrs in widget.py
r14653
Jonathan Frederic
Dev meeting widget review day 1
r14586 def _ipython_display_(self, **kwargs):
Jonathan Frederic
More PEP8 changes
r14607 """Called when `IPython.display.display` is called on the widget."""
Sylvain Corlay
Set default view to None and never display widget with no view
r17989 # Show view.
if self._view_name is not None:
self._send({"method": "display"})
self._handle_displayed(**kwargs)
Jonathan Frederic
Decoupled Python Widget from Comm...
r14479
def _send(self, msg):
Jonathan Frederic
More PEP8 changes
r14607 """Sends a message to the model in the front-end."""
Jonathan Frederic
Fixed _send so it can open a comm if needed....
r14548 self.comm.send(msg)
Jonathan Frederic
Moved view widget into widget.py
r14516
Jonathan Frederic
s/Widget/DOMWidget s/BaseWidget/Widget
r14540 class DOMWidget(Widget):
MinRK
review pass on Python-side of widgets...
r14793 visible = Bool(True, help="Whether the widget is visible.", sync=True)
Jonathan Frederic
Partial implementation of styles
r17723 _css = Tuple(sync=True, help="CSS property list: (selector, key, value)")
_dom_classes = Tuple(sync=True, help="DOM classes applied to widget.$el.")
Jonathan Frederic
Initial crack at using specific traits for styling.
r17722
width = CUnicode(sync=True)
height = CUnicode(sync=True)
Jonathan Frederic
Fix some bugs found by the widget examples,...
r17727 padding = CUnicode(sync=True)
margin = CUnicode(sync=True)
Jonathan Frederic
Initial crack at using specific traits for styling.
r17722
Jonathan Frederic
s/fore_color/color...
r17860 color = Unicode(sync=True)
background_color = Unicode(sync=True)
Jonathan Frederic
Initial crack at using specific traits for styling.
r17722 border_color = Unicode(sync=True)
border_width = CUnicode(sync=True)
Jonathan Frederic
Address problems found in in-person review
r17947 border_radius = CUnicode(sync=True)
Jonathan Frederic
Initial crack at using specific traits for styling.
r17722 border_style = CaselessStrEnum(values=[ # http://www.w3schools.com/cssref/pr_border-style.asp
'none',
'hidden',
'dotted',
'dashed',
'solid',
'double',
'groove',
'ridge',
'inset',
'outset',
'initial',
'inherit', ''],
default_value='', sync=True)
font_style = CaselessStrEnum(values=[ # http://www.w3schools.com/cssref/pr_font_font-style.asp
'normal',
'italic',
'oblique',
'initial',
'inherit', ''],
default_value='', sync=True)
font_weight = CaselessStrEnum(values=[ # http://www.w3schools.com/cssref/pr_font_weight.asp
'normal',
'bold',
'bolder',
'lighter',
'initial',
'inherit', ''] + [str(100 * (i+1)) for i in range(9)],
default_value='', sync=True)
font_size = CUnicode(sync=True)
font_family = Unicode(sync=True)
Jonathan Frederic
Address problems found in in-person review
r17947
def __init__(self, *pargs, **kwargs):
super(DOMWidget, self).__init__(*pargs, **kwargs)
def _validate_border(name, old, new):
if new is not None and new != '':
if name != 'border_width' and not self.border_width:
self.border_width = 1
if name != 'border_style' and self.border_style == '':
self.border_style = 'solid'
self.on_trait_change(_validate_border, ['border_width', 'border_style', 'border_color'])