class LeafletWidget(flx.Widget): """ A widget that shows a slippy/tile-map using Leaflet. """ layers = flx.ListProp([], doc=""" List of tilemap layer tuples: (url, 'Layer'). """) zoom = flx.IntProp(8, settable=True, doc=""" Zoom level for the map. """) min_zoom = flx.IntProp(0, settable=True, doc=""" self zoom level for the map. """) max_zoom = flx.IntProp(18, settable=True, doc=""" Maximum zoom level for the map. """) center = flx.FloatPairProp((5.2, 5.5), settable=True, doc=""" The center of the map. """) show_layers = flx.BoolProp(False, settable=True, doc=""" Whether to show layers-icon on the top-right of the map. """) show_scale = flx.BoolProp(False, settable=True, doc=""" Whether to show scale at bottom-left of map. """) @flx.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) @flx.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.pointer_event(e.type, latlng, xy) @flx.emitter def pointer_event(self, event, latlng, xy): return {'event': event, 'latlng': latlng, 'xy': xy} @flx.reaction def __handle_zoom(self): self.map.setZoom(self.zoom) @flx.reaction def __handle_min_zoom(self): self.map.setMinZoom(self.min_zoom) @flx.reaction def __handle_max_zoom(self): self.map.setMaxZoom(self.max_zoom) @flx.reaction def __handle_center(self): self.map.panTo(self.center) @flx.reaction def __handle_show_layers(self): if self.show_layers: self.map.addControl(self.layer_control) else: self.map.removeControl(self.layer_control) @flx.reaction def __handle_show_scale(self): if self.show_scale: self.map.addControl(self.scale) else: self.map.removeControl(self.scale) @flx.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() @flx.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)
class IGraph(flx.PyComponent): CSS = """ .flx-main-widget{ overflow:scroll; } .configure{ overflow:scroll; } """ graph = flx.AnyProp(None, settable=True) graph_options = { # "height": "90%", } graph_list = flx.ListProp([]) current_graph = flx.IntProp(0, settable=True) def init(self): with ui.VSplit(): with ui.HFix(flex=0): self.previous = ui.Button(text="<-", disabled=True, flex=1) self.content = ui.Label(flex=0) self.next = ui.Button(text="->", disabled=True, flex=1) with ui.HSplit(flex=1, spacing=20): self.configure = flx.Widget(css_class="configure", flex=0) with ui.HFix(flex=1): self.visjs = VisJS( style="background-color: #dddddd;", flex=1, ) self.refresh() @event.reaction("graph") def update_viz(self, *events): ev = events[-1] graph = ev["new_value"] old_graph = ev["old_value"] if old_graph is None: self.visjs.load_viz(graph) else: def find_by_id(id, iterable): try: return [elem for elem in iterable if elem["id"] == id][0] except IndexError: return None self.visjs.update_viz({ "nodes": { "add": [ node for node in graph["nodes"] if not find_by_id(node["id"], old_graph["nodes"]) ], "remove": [ node["id"] for node in old_graph["nodes"] if not find_by_id(node["id"], graph["nodes"]) ], "update": [ node for node in graph["nodes"] if find_by_id(node["id"], old_graph["nodes"]) and find_by_id(node["id"], old_graph["nodes"]) != node ] }, "edges": { "add": [ edge for edge in graph["edges"] if not find_by_id(edge["id"], old_graph["edges"]) ], "remove": [ edge["id"] for edge in old_graph["edges"] if not find_by_id(edge["id"], graph["edges"]) ], "update": [ edge for edge in graph["edges"] if find_by_id(edge["id"], old_graph["edges"]) and find_by_id(edge["id"], old_graph["edges"]) != edge ], }, "options": graph["options"], }) @flx.action def refresh(self): try: graph = nx.nx_agraph.read_dot(self.file) except ImportError: try: graph = nx.nx_pydot.read_dot(self.file) except TypeError: print("TypeError") asyncio.get_event_loop().call_later(0.1, self.refresh) return def uniq_id(): i = 0 while True: yield i i = i + 1 genid = uniq_id() for src in graph.nodes: for dst in graph[src]: for number in graph[src][dst]: if "smooth.type" not in graph[src][dst][number]: graph[src][dst][number]["smooth.type"] = "curvedCW" if "smooth.roundness" not in graph[src][dst][number]: graph[src][dst][number]["smooth.roundness"] = float( number) / 5. graph_desc = { "nodes": [{ "id": node_id, "label": graph.nodes[node_id].get("label", node_id), **dotted_dict_to_nested_dict({ k: cast_it(v) for k, v in graph.nodes[node_id].items() }), } for node_id in graph.nodes], "edges": [{ "id": next(genid), "arrows": "to", "from": src, "to": dst, "number": number, **dotted_dict_to_nested_dict({ k: cast_it(v) for k, v in graph[src][dst][number].items() }), } for src in graph.nodes for dst in graph[src] for number in graph[src][dst]], "options": dotted_dict_to_nested_dict({ **self.graph_options, **dict_cast(graph.graph.get("graph", {})), }) } gl = len(self.graph_list) cg = self.current_graph last_graph = (gl != 0 and self.graph_list[-1]) or None if graph_desc != last_graph: self._mutate_graph_list([graph_desc], 'insert', gl) if cg == (gl - 1): self.set_current_graph(cg + 1) asyncio.get_event_loop().call_later(0.1, self.refresh) @flx.reaction("graph_list", "current_graph") def _update_buttons(self, *evs): self.previous.set_disabled( len(self.graph_list) == 1 or self.current_graph == 0) self.previous.set_text( "{} <-".format(self.current_graph - 1) if self.current_graph else "|") self.content.set_text("{}".format(self.current_graph)) self.next.set_disabled(self.current_graph == len(self.graph_list) - 1) self.next.set_text("-> {}".format( self.current_graph + 1) if self.current_graph < len(self.graph_list) - 1 else "|") @flx.reaction("current_graph") def _update_graph(self, *evs): self.set_graph(self.graph_list[self.current_graph]) @event.reaction("previous.pointer_click") def _previous(self, *evs): self.set_current_graph(self.current_graph - 1) @event.reaction("next.pointer_click") def _next(self, *evs): self.set_current_graph(self.current_graph + 1)
class NetworkVisualiser(flx.CanvasWidget): _current_node = flx.Property(None, settable=True) inputs = flx.ListProp(settable=True) neurons = flx.ListProp(settable=True) def init(self): self.ctx = self.node.getContext('2d') self.xx = [0.3, 0.3, 0.70, 0.60, 0.50, 0.40, 0.10]#, 0.23, 0.61, 0.88] self.yy = [0.33, 0.66, 0.90, 0.60, 0.90, 0.70, 0.55]#, 0.19, 0.11, 0.38] self.names = [] self.node_width = 25 i = [True, False] self._mutate_inputs(i) self._mutate_neurons(i) self.buttonlabel= flx.Label(text='dgfhdfgh') @flx.reaction('pointer_down') def _on_pointer_down(self, *events): for ev in events: w, h = self.size # Get closest point closest, dist = -1, 999999 for i in range(len(self.xx)): x, y = self.xx[i] * w, self.yy[i] * h d = ((x - ev.pos[0]) ** 2 + (y - ev.pos[1]) ** 2) ** 0.5 if d < dist: closest, dist = i, d # Did we touch it or not if dist < self.node_width: i = closest self._set_current_node(i) @flx.reaction('pointer_up') def _on_pointer_up(self, *events): self._set_current_node(None) @flx.reaction('pointer_move') def _on_pointer_move(self, *events): ev = events[-1] if self._current_node is not None: i = self._current_node w, h = self.size self.xx[i] = ev.pos[0] / w self.yy[i] = ev.pos[1] / h self.update() @flx.emitter def key_down(self, e): return self._create_key_event(e) @flx.reaction('size', '_current_node', 'inputs', 'neurons') def update(self, *events): self.draw() @flx.action def update_inputs(self, i): self.set_inputs(i) @flx.action def update_neurons(self, i): self.set_neurons(i) @flx.action def draw(self, inputs, Net): ctx = self.ctx w, h = self.size ctx.fillStyle = "white"#"0d053b" #ctx.strokeStyle = "black" ctx.fillRect(0, 0, w, h) ctx.fillStyle = "red" ctx.strokeStyle = "red" #Draw rectangles for input signals for i in range(len(self.inputs)): if(self.inputs[i]): ctx.fillStyle = "yellow" else: ctx.fillStyle = "blue" posx = w * 0.1 posy = (h/(len(self.inputs) + 1)) * (i + 1) ctx.fillRect(posx, posy, 25, 45) #print(self.inputs[i]) # Get coordinates xx = [x * w for x in self.xx] yy = [y * h for y in self.yy] # Draw nodes ctx.strokeStyle = '#000' ctx.lineWidth = 2 for i in range(0, len(self.neurons)): if(self.neurons[i][0]): ctx.fillStyle = 'yellow' else: ctx.fillStyle = '#acf' ctx.beginPath() ctx.arc(xx[i], yy[i], self.node_width, 0, 6.2831) ctx.fill() ctx.stroke() ctx.strokeStyle = "black" ctx.font = '25px Calibri'; ctx.strokeText(self.neurons[i][1], xx[i], yy[i]); # Draw lines #for i in range(1, len(xx)-2): # ctx.lineCap = "round" # ctx.lineWidth = 3 # ctx.strokeStyle = '#008' # # ctx.beginPath() # lineto = ctx.lineTo.bind(ctx) # # lineto(xx[i+0], yy[i+0]) # lineto(xx[i+1], yy[i+1]) # ctx.stroke()
class PanelRxView(flx.Widget): CSS = """ .detail { boarder: solid green 3px; font-size:small; word-wrap:break-word; overflow: auto; } .packet_list { overflow: auto; } .flx-TreeWidget { border: gray solid 1px; font-size: small; } .flx-TreeItem { border-top: white solid 1px; text-overflow:ellipse; white-space:nowrap; } .flx-TreeItem:hover { background-color: #EEEEEE; } .flx-TreeItem.selected-true { background: blue; color: white; } .flx-TreeWidget .flx-TreeItem > .text.hastitle { width: 95%; } .flx-TreeItem > .title { background: white; color: gray; } """ labels = flx.ListProp(settable=True) label_idx = flx.IntProp(settable=True) packets = flx.ListProp(settable=True) def init(self): with flx.HSplit(): with flx.VBox(flex=1): self.summary = flx.TreeWidget(flex=1, max_selected=1) with flx.VSplit(flex=1): with flx.GroupWidget(css_class="list", flex=6, title="Detail"): self.detail = flx.Label(flex=1, css_class="detail") self.detail.set_wrap(2) with flx.GroupWidget(css_class="list", flex=4, title="hexdump"): self.hexdump = flx.Label(flex=1, css_class="detail") self.hexdump.set_wrap(1) @flx.action def add_pkt(self, info): self.packets.append( dict(summary=info['pkt_summary'], detail=info['pkt_detail'], hex=info['pkt_hex'])) self.add_one_label(info['pkt_summary']) @flx.action def update_info(self, info): if info['packets']: self.add_labels(info['packets']) if info['hexdump_txt']: line = '<pre><code>' + info['hexdump_txt'] + '</ code></ pre>' self.hexdump.set_html(line) if info['detail_txt']: line = '<pre><code>' + info['detail_txt'] + '</ code></ pre>' self.detail.set_html(line) @flx.action def add_labels(self, msg): with self.summary: for l in msg.splitlines(): self.add_one_label(l) @flx.action def add_one_label(self, msg): with self.summary: l = flx.TreeItem(text=msg, title=str(self.label_idx), checked=None) self._mutate_labels([l], 'insert', len(self.labels)) self._mutate_label_idx(self.label_idx + 1) @flx.action def clear_labels(self): for l in self.labels: l.dispose() self.labels.clear() self._mutate_label_idx(0) self.hexdump.set_text('') self.detail.set_text('') @flx.action def clear_info(self): self.set_packets([]) self.clear_labels() @flx.reaction('summary.children**.checked', 'summary.children**.selected') def _update_detail(self, *events): e = events[-1] id = int(e.source.title) self.show_detail(self.packets[id]['detail']) self.show_hexdump(self.packets[id]['hex']) def show_detail(self, msg): msg = '<pre><code>' + msg + '</code></pre>' self.detail.set_html(msg) def show_hexdump(self, msg): msg = '<pre><code>' + msg + '</code></pre>' self.hexdump.set_html(msg)
class MyPrompt(MyWidget): options = flx.ListProp([]) n_options = flx.IntProp(5) ref = flx.StringProp('MyID') def init(self): super().init() self.label = {} with flx.VBox() as self.wmain: self.label['above'] = flx.Label(text='Text above', flex=1) with flx.HBox(): self.winput = MyLineEdit(flex=1) with flx.VBox(): self.dots_above = MyDots(text='···') with flx.VBox() as self.woptions_box: pass self.dots_below = MyDots(text='···') self.woptions = [] self.show_more = 0 self.index = 0 self.shift = 0 self.focus_element = self.winput @flx.emitter def emit_option(self, option): return dict(value=option, ref=self.ref, text=self.winput.text) @flx.emitter def emit_text(self, text): return dict(value=text, ref=self.ref) @flx.emitter def emit_escape(self): return dict(ref=self.ref) @flx.emitter def emit_interrupt(self): return dict(ref=self.ref) @flx.action def set_focus(self): self._set_focus() async def _set_focus(self): elem = self.focus_element while elem.node.offsetParent == None: await self.sleep(50) elem.node.focus() return async def select_text(self): await self.sleep(50) self.winput.node.select() return @flx.action def set_properties(self, kwargs): if 'prefill' in kwargs: self.winput.set_text(kwargs.pop('prefill')) self.select_text() if 'placeholder' in kwargs: self.winput.set_placeholder_text(kwargs.pop('placeholder')) for key in ['above']: if key in kwargs: value = kwargs.pop(key) elem = self.label[key] if value is None: elem.set_text('hidden') elem.node.hidden = True else: elem.node.hidden = False elem.set_text(value) if 'ref' in kwargs: self._mutate_ref(kwargs['ref']) keys = ['options', 'n_options'] if any([key in kwargs for key in keys]): kw = kwargs kw['options'] = kw.get('options', self.options) kw['n_options'] = kw.get('n_options', self.n_options) self.set_options(kw.pop('options'), kw.pop('n_options')) for key, val in kwargs.items(): print(f'Error: unhandled key={key}, val={val}') return @flx.action def set_options(self, options, n_options=None): if n_options == None: n_options = 5 if not self.winput: return self._mutate_options(options) self._mutate_n_options(n_options) self.pre_match = {} for s in self.options: self.pre_match[s] = self.my_grams(s) self.filtered = self.options self.index = 0 self.shift = 0 self.redraw_options() @flx.reaction('woptions_box.children*.pointer_click') def _listen_clicks(self, *events): for ev in events: self.listen_click(ev.source.text) def listen_click(self, option): self.winput.node.select() # Select text self.emit_option(option) self.options.remove(option) self.options.insert(0, option) self.index = 0 self.shift = 0 self.redraw_options() return @flx.reaction('key_down') def listen_keys(self, *events): for ev in events: if ev.modifiers == 'Ctrl' and ev.key == 'c' and self.winput.text == '': self.emit_interrupt() elif ev.modifiers: continue elif ev.key == 'Escape': self.emit_escape() elif ev.key == 'Enter': if len(self.woptions): option = self.woptions[self.index].text self.listen_click(option) else: self.emit_text(self.winput.text) elif ev.key == 'ArrowDown': if self.index + 1 < len(self.woptions): self.index += 1 elif self.shift + self.n_options < len(self.filtered): self.shift += 1 self.redraw_options() elif ev.key == 'ArrowUp': redraw = True if self.index > 0: self.index -= 1 elif self.shift: self.shift -= 1 else: redraw = False if redraw: self.redraw_options() return @flx.reaction('winput.text') def listen_winput(self, *events): if self.winput.text == '': self.filtered = self.options else: score = self.fuzzy_scores(self.winput.text) thr = max(max(score.values()) / 2, 1 / 3) self.filtered = sorted( [s for s in self.options if score[s] > thr], key=lambda s: -score[s], ) self.index = 0 self.shift = 0 self.redraw_options() return def redraw_options(self): to_show = self.filtered[self.shift:self.shift + self.n_options] with self.woptions_box: while len(self.woptions) < len(to_show): self.woptions.append(flx.Button()) while len(self.woptions) > len(to_show): self.woptions.pop().dispose() for i in range(len(to_show)): self.woptions[i].set_text(to_show[i]) style = 'background:#ccc' if i == self.index else 'background:#eee' self.woptions[i].node.style = style if len(self.options) == 1: self.winput.node.hidden = True self.focus_element = self.woptions[0] else: self.winput.node.hidden = False self.focus_element = self.winput self.dots_above.set_visible(self.shift > 0) self.dots_below.set_visible( len(self.filtered) - self.shift > self.n_options) return def my_grams(self, s): n = len(s) s = s.lower() g = {} for i in range(n): g[s[i]] = (g[s[i]] or 0) + 1 if i + 1 < n: g[s[i] + s[i + 1]] = (g[s[i] + s[i + 1]] or 0) + 1 if i + 2 < n: g[s[i] + s[i + 2]] = (g[s[i] + s[i + 1]] or 0) + 1 return g def fuzzy_scores(self, text): x = self.my_grams(text) score = {} for key, y in self.pre_match.items(): hits = total = 0 z = y.copy() for k, v in x.items(): z[k] = (z[k] or 0) - x[k] hits += z[k] >= 0 total += 1 score[key] = hits / total return score