class MyObject(event.Component): att = event.Attribute() # Props to test basic stuff foo = event.AnyProp(6, settable=True, doc='can be anything') bar = event.StringProp('xx') # not settable # Props to test array mutations eggs = event.ListProp([], settable=True) eggs2 = event.ListProp(settable=True) eggs3 = event.ListProp([3, 4]) # All kinds of props, defaults anyprop = event.AnyProp(doc='can be anything', settable=True) boolprop = event.BoolProp(settable=True) tristateprop = event.TriStateProp(settable=True) intprop = event.IntProp(settable=True) floatprop = event.FloatProp(settable=True) stringprop = event.StringProp(settable=True) tupleprop = event.TupleProp(settable=True) listprop = event.ListProp(settable=True) dictprop = event.DictProp(settable=True) componentprop = event.ComponentProp(settable=True) # can be None # nullprop = event.NullProp(None, settable=True) # eitherprop = event.EitherProp(event.IntProp, event.NoneProp) _privateprop = event.IntProp(settable=True)
class ScaleImageWidget(flx.Widget): """ Display an image from a url. The ``node`` of this widget is an `<img> <https://developer.mozilla.org/docs/Web/HTML/Element/img>`_ wrapped in a `<div> <https://developer.mozilla.org/docs/Web/HTML/Element/div>`_ (the ``outernode``) to handle sizing. """ DEFAULT_MIN_SIZE = 16, 16 _sequence = 0 source = event.StringProp('', settable=True, doc=""" The source of the image, This can be anything that an HTML img element supports. """) stretch = event.BoolProp(False, settable=True, doc=""" Whether the image should stretch to fill all available space, or maintain its aspect ratio (default). """) def _create_dom(self): global window outer = window.document.createElement('div') inner = window.document.createElement('img') outer.appendChild(inner) return outer, inner @event.reaction def __resize_image(self): size = self.size if self.stretch: self.node.style.maxWidth = None self.node.style.maxHeight = None self.node.style.width = size[0] + 'px' self.node.style.height = size[1] + 'px' else: self.node.style.backgroundColor = None self.node.style.marginLeft = "5%" self.node.style.marginTop = "5%" self.node.style.maxWidth = "90%" self.node.style.maxWidth = "auto" self.node.style.width = "90%" self.node.style.height = "auto" @event.reaction def __source_changed(self): self.node.src = self.source
class MyDefaults(event.Component): # Custom defaults anyprop2 = event.AnyProp(7, doc='can be anything') boolprop2 = event.BoolProp(True) intprop2 = event.IntProp(-9) floatprop2 = event.FloatProp(800.45) stringprop2 = event.StringProp('heya') tupleprop2 = event.TupleProp((2, 'xx')) listprop2 = event.ListProp([3, 'yy']) dictprop2 = event.DictProp({'foo':3, 'bar': 4}) componentprop2 = event.ComponentProp(None)
class LeafletWidget(ui.Widget): """ A widget that shows a slippy/tile-map using Leaflet. """ layers = event.ListProp([], doc=""" List of tilemap layer tuples: (url, 'Layer'). """) zoom = event.IntProp(8, settable=True, doc=""" Zoom level for the map. """) min_zoom = event.IntProp(0, settable=True, doc=""" self zoom level for the map. """) max_zoom = event.IntProp(18, settable=True, doc=""" Maximum zoom level for the map. """) center = event.FloatPairProp((5.2, 5.5), settable=True, doc=""" The center of the map. """) show_layers = event.BoolProp(False, settable=True, doc=""" Whether to show layers-icon on the top-right of the map. """) show_scale = event.BoolProp(False, settable=True, doc=""" Whether to show scale at bottom-left of map. """) @event.action def add_layer(self, url, name=None): """ Add a layer to the map. """ # Avoid duplicates self.remove_layer(url) if name: self.remove_layer(name) # Add layer layers = self.layers + [(url, name or 'Layer')] self._mutate_layers(layers) @event.action def remove_layer(self, url_or_name): """ Remove a layer from the map by url or name. """ layers = list(self.layers) for i in reversed(range(len(layers))): if url_or_name in layers[i]: layers.pop(i) self._mutate_layers(layers) def _create_dom(self): global L, document node = document.createElement('div') self.mapnode = document.createElement('div') node.appendChild(self.mapnode) self.mapnode.id = 'maproot' self.mapnode.style.position = 'absolute' self.mapnode.style.top = '0px' self.mapnode.style.left = '0px' self.map = L.map(self.mapnode) self.map.on('zoomend', self.map_handle_zoom) self.map.on('moveend', self.map_handle_move) self.map.on('click', self.map_handle_mouse) self.map.on('dblclick', self.map_handle_mouse) # Container to keep track of leaflet layer objects self.layer_container = [] self.layer_control = L.control.layers() self.scale = L.control.scale({'imperial': False, 'maxWidth': 200}) # Set the path for icon images L.Icon.Default.prototype.options.imagePath = '_data/shared/' return node def map_handle_zoom(self, e): global isNaN zoom = self.map.getZoom() if isNaN(zoom): return if zoom != self.zoom: self.set_zoom(zoom) def map_handle_move(self, e): center_coord = self.map.getCenter() center = center_coord.lat, center_coord.lng if center != self.center: self.set_center(center) def map_handle_mouse(self, e): latlng = [e.latlng.lat, e.latlng.lng] xy = [e.layerPoint.x, e.layerPoint.y] self.mouse_event(e.type, latlng, xy) @event.emitter def mouse_event(self, event, latlng, xy): return {'event': event, 'latlng': latlng, 'xy': xy} @event.reaction def __handle_zoom(self): self.map.setZoom(self.zoom) @event.reaction def __handle_min_zoom(self): self.map.setMinZoom(self.min_zoom) @event.reaction def __handle_max_zoom(self): self.map.setMaxZoom(self.max_zoom) @event.reaction def __handle_center(self): self.map.panTo(self.center) @event.reaction def __handle_show_layers(self): if self.show_layers: self.map.addControl(self.layer_control) else: self.map.removeControl(self.layer_control) @event.reaction def __handle_show_scale(self): if self.show_scale: self.map.addControl(self.scale) else: self.map.removeControl(self.scale) @event.reaction def __size_changed(self): size = self.size if size[0] or size[1]: self.mapnode.style.width = size[0] + 'px' self.mapnode.style.height = size[1] + 'px' # Notify the map that it's container's size changed self.map.invalidateSize() @event.reaction def __layers_changed(self): global L for layer in self.layer_container: self.layer_control.removeLayer(layer) if self.map.hasLayer(layer): self.map.removeLayer(layer) for layer_url, layer_name in self.layers: if not layer_url.endswith('.png'): if not layer_url.endswith('/'): layer_url += '/' layer_url += '{z}/{x}/{y}.png' new_layer = L.tileLayer(layer_url) self.layer_container.append(new_layer) self.map.addLayer(new_layer) self.layer_control.addOverlay(new_layer, layer_name)