class WebcamWindow(Window): def __init__(self, tui): super().__init__(tui) self.body.contents.append((Text("Available Webcams"), ('pack', None))) self.body.contents.append((Divider(), ('pack', None))) self.walker = SimpleFocusListWalker([]) listbox = ListBox(self.walker) self.body.contents.append((listbox, ('weight', 1))) self.body.focus_position = 2 self.add_hotkey('U', self.update, "update") self.update() def update(self): def camlist_cb(json_msg): self.walker.clear() def button_cb(locator, url, button): webbrowser.open_new(url) self.tui.pop_window() self.display_errors(json_msg) webcams = json_msg.get('webcams', None) if not webcams: return for locator, webcam in webcams.items(): name = webcam["name"] url = webcam["url"] button = Button(name) urwid.connect_signal(button, 'click', button_cb, user_args=[locator, url]) self.walker.append(AttrMap(button, None, focus_map='selected')) self.tui.controller.get_camlist(camlist_cb)
class ChatMessages(ListBox): """ Show the last couple of chat messages as a scrolling list """ def __init__(self, chat): self.chat = chat self.walker = SimpleFocusListWalker([]) super(ChatMessages, self).__init__(self.walker) def add(self, message): self.walker.append(Text(message)) self.set_focus(len(self.walker)-1)
class ChatMessages(ListBox): """ Show the last couple of chat messages as a scrolling list """ def __init__(self, chat): self.chat = chat self.walker = SimpleFocusListWalker([]) super(ChatMessages, self).__init__(self.walker) def add(self, message): self.walker.append(Text(message)) self.set_focus(len(self.walker) - 1)
class ProgressView(BaseView): def __init__(self, controller): self.controller = controller self.listwalker = SimpleFocusListWalker([]) self.listbox = ListBox(self.listwalker) self.linebox = MyLineBox(self.listbox) body = [ ('pack', Text("")), ('weight', 1, Padding.center_79(self.linebox)), ('pack', Text("")), ] self.pile = Pile(body) super().__init__(self.pile) def add_log_tail(self, text): at_end = len( self.listwalker) == 0 or self.listbox.focus_position == len( self.listwalker) - 1 for line in text.splitlines(): self.listwalker.append(Text(line)) if at_end: self.listbox.set_focus(len(self.listwalker) - 1) self.listbox.set_focus_valign('bottom') def clear_log_tail(self): self.listwalker[:] = [] def set_status(self, text): self.linebox.set_title(text) def show_complete(self, include_exit=False): buttons = [ ok_btn(_("Reboot Now"), on_press=self.reboot), ] if include_exit: buttons.append(cancel_btn(_("Exit To Shell"), on_press=self.quit)) buttons = button_pile(buttons) new_pile = Pile([ ('pack', Text("")), buttons, ('pack', Text("")), ]) self.pile.contents[-1] = (new_pile, self.pile.options('pack')) self.pile.focus_position = len(self.pile.contents) - 1 def reboot(self, btn): self.controller.reboot() def quit(self, btn): self.controller.quit()
class LogWindow(Window): def __init__(self, tui): super().__init__(tui) description = Text( "NOTICE. The log displayed here is a copy of the " "daemon log. Keeping the the loglevel at debug impacts " "performance. When done, run ':loglevel warning'") self.body.contents.append((description, ('pack', None))) self.walker = SimpleFocusListWalker([]) self.listbox = ScrollingListBox(self.walker) self.body.contents.append((self.listbox, ('weight', 1))) #self.add_hotkey('-', self.update, "increase") #self.add_hotkey('+', self.update, "decrease") #c e w i d def wrap(self, line): if line.startswith('CRITICAL'): focusmap = 'critical' elif line.startswith('ERROR'): focusmap = 'error' elif line.startswith('WARNING'): focusmap = 'warning' elif line.startswith('INFO'): focusmap = 'info' else: focusmap = 'default' txt = Text(line.strip()) return AttrMap(txt, focusmap) def start(self): self.walker.append(Text("---- START LOGGING ----", align='center')) def log_cb(json_msg): line = json_msg.get('log', None) if not line: return self.walker.append(self.wrap(line)) self.tui.controller.start_logs(log_cb) def stop(self): self.tui.controller.stop_logs()
class DeviceListWindow(Window): def __init__(self, tui): super().__init__(tui) self.body.contents.append( (Text("Available CNC Devices"), ('pack', None))) self.body.contents.append((Divider(), ('pack', None))) self.walker = SimpleFocusListWalker([]) listbox = ListBox(self.walker) self.body.contents.append((listbox, ('weight', 1))) self.body.focus_position = 2 self.add_hotkey('U', self.update, "update") self.add_hotkey('w', self.webcams, "webcams") self.add_hotkey('a', self.actions, "actions") self.update() def update(self): def devlist_cb(json_msg): self.walker.clear() def button_cb(locator, device, button): window = DeviceWindow(self.tui, locator, device) self.tui.push_window(window) self.display_errors(json_msg) devices = json_msg.get('devices') if not devices: return for locator, device in devices.items(): button = Button(device) urwid.connect_signal(button, 'click', button_cb, user_args=[locator, device]) self.walker.append(AttrMap(button, None, focus_map='selected')) self.tui.controller.get_devlist(devlist_cb)
class ActionWindow(Window): def __init__(self, tui): super().__init__(tui) self.body.contents.append((Text("Available Actions"), ('pack', None))) self.body.contents.append((Divider(), ('pack', None))) self.walker = SimpleFocusListWalker([]) listbox = ListBox(self.walker) self.body.contents.append((listbox, ('weight', 1))) self.body.focus_position = 2 self.add_hotkey('U', self.update, "update") self.update() def update(self): def action_cb(json_msg): self.walker.clear() def button_cb(cmd, button): self.tui.controller.action(cmd, None) self.tui.pop_window() self.display_errors(json_msg) actions = json_msg.get('actions', None) if not actions: return for action in actions: cmd = action['command'] label = action['short'] description = action['long'] button = Button("[{}] - {}".format(label, description)) urwid.connect_signal(button, 'click', button_cb, user_args=[cmd]) self.walker.append(AttrMap(button, None, focus_map='selected')) self.tui.controller.get_actions(action_cb)
class ProgressView(BaseView): def __init__(self, controller): self.controller = controller self.spinner = Spinner(controller.loop) self.event_listwalker = SimpleFocusListWalker([]) self.event_listbox = ListBox(self.event_listwalker) self.event_linebox = MyLineBox(self.event_listbox) self.event_buttons = button_pile([other_btn("View full log", on_press=self.view_log)]) event_body = [ ('pack', Text("")), ('weight', 1, Padding.center_79(self.event_linebox)), ('pack', Text("")), ('pack', self.event_buttons), ('pack', Text("")), ] self.event_pile = Pile(event_body) self.log_listwalker = SimpleFocusListWalker([]) self.log_listbox = ListBox(self.log_listwalker) log_linebox = MyLineBox(self.log_listbox, _("Full installer output")) log_body = [ ('weight', 1, log_linebox), ('pack', button_pile([other_btn(_("Close"), on_press=self.close_log)])), ] self.log_pile = Pile(log_body) super().__init__(self.event_pile) def add_event(self, text): at_end = len(self.event_listwalker) == 0 or self.event_listbox.focus_position == len(self.event_listwalker) - 1 if len(self.event_listwalker) > 0: self.event_listwalker[-1] = self.event_listwalker[-1][0] self.event_listwalker.append(Columns([('pack', Text(text)), ('pack', self.spinner)], dividechars=1)) if at_end: self.event_listbox.set_focus(len(self.event_listwalker) - 1) self.event_listbox.set_focus_valign('bottom') def add_log_line(self, text): at_end = len(self.log_listwalker) == 0 or self.log_listbox.focus_position == len(self.log_listwalker) - 1 self.log_listwalker.append(Text(text)) if at_end: self.log_listbox.set_focus(len(self.log_listwalker) - 1) self.log_listbox.set_focus_valign('bottom') def set_status(self, text): self.event_linebox.set_title(text) def show_complete(self, include_exit=False): p = self.event_buttons.original_widget p.contents.append( (ok_btn(_("Reboot Now"), on_press=self.reboot), p.options('pack'))) if include_exit: p.contents.append( (cancel_btn(_("Exit To Shell"), on_press=self.quit), p.options('pack'))) w = 0 for b, o in p.contents: w = max(len(b.base_widget.label), w) self.event_buttons.width = self.event_buttons.min_width = w + 4 self.event_pile.focus_position = 3 p.focus_position = 1 def reboot(self, btn): self.controller.reboot() def quit(self, btn): self.controller.quit() def view_log(self, btn): self._w = self.log_pile def close_log(self, btn): self._w = self.event_pile
class GUI(object): def __init__(self): self.screen = Screen() self.screen.set_input_timeouts(max_wait=0) self.steps = GridFlow([], 20, 2, 1, 'left') self.progress = SimpleFocusListWalker([]) self.log = SimpleFocusListWalker([]) self.widget = AttrMap( LineBox(Pile([ ('fixed', 6, AttrMap(Filler(self.steps), 'default')), ('fixed', 1, Filler(Divider('\u2500'))), ('fixed', 3, ListBox(self.progress)), AttrMap(LineBox(ListBox(self.log), title='Message log'), 'default') ]), title='Indico 1.2 -> 2.0 migration'), 'global_frame') self.screen.register_palette( [('green', 'light green', ''), ('white', 'white', ''), ('red', 'dark red', ''), ('yellow', 'yellow', ''), ('progress_empty', 'black', 'light gray'), ('progress_progress', 'light cyan', 'light gray'), ('progress_done', 'black', 'light cyan'), ('box', 'white', 'dark gray'), ('step_done', 'light green', ''), ('step_working', 'dark gray', ''), ('global_frame', 'light cyan', ''), ('fill', 'light cyan', 'dark cyan'), ('done', 'white', 'dark green'), ('eta', 'yellow', 'dark gray')] + generate_urwid_palette(PALETTE)) def print_log(self, icon, message, prefix='', event_id=''): self.log.append( Text([ color_segments(icon), ' ', color_segments(prefix), ' ' if prefix else '', color_segments( '%[cyan][%[cyan!]{}%[cyan]]%[reset]'.format(event_id)) if event_id else '', ' ' if event_id else '', color_segments(message) ])) self.log.set_focus(len(self.log) - 1) self.redraw() def start(self): # don't let Python warnings ruin the GUI warnings.filterwarnings('ignore') self.screen.start() self.redraw() def stop(self): self.screen.stop() warnings.filterwarnings('default') def create_progress_bar(self, description): if self.progress: del self.progress[:] return StepProgressBar(self, description) def set_success(self): if self.progress: del self.progress[:] self.progress.append( AttrMap(Text('Migration finished!', align='center'), 'done')) self.progress.append( AttrMap(Text('Please press any key...', align='center'), 'done')) self.redraw() self.wait_for_input() def wait_for_input(self): self.screen._getch(None) def set_step_banner(self, msg): if self.progress: del self.progress[:] self.progress.append(BoxAdapter(AttrMap(SolidFill('#'), 'fill'), 3)) def redraw(self): screen_size = self.screen.get_cols_rows() canvas = self.widget.render(screen_size, focus=True) self.screen.get_input() self.screen.draw_screen(screen_size, canvas)
class ScrollingListBox(ListBox): def __init__(self, rolling_packet_buffer=None): """ Args: rolling_packet_buffer (int, optional): Max packets to keep in the rolling buffer at a time. Defaults to unlimited. """ self.walker = SimpleFocusListWalker([]) self.packets = scapy.plist.PacketList() self.rolling_packet_buffer = rolling_packet_buffer super(ScrollingListBox, self).__init__(self.walker) def add(self, message, packet): """ Args: message (str): Text message that will appear packet (Scapy packet): Packet that corresponds to this entry. """ txt = AttrMap(Text(message), 'frame', 'selected') self.walker.append(txt) self.packets.append(packet) if self.rolling_packet_buffer is not None and len( self.walker) > self.rolling_packet_buffer: self.packets.pop(0) self.walker.pop(0) currently_selected = self.get_focus() if isinstance(currently_selected, (list, tuple)): currently_selected = currently_selected[0] # This ensures auto scrolling only engages if our selected item is the bottom one if len(self.walker) <= 1 or currently_selected is self.walker[-2]: self.set_focus(len(self.walker) - 1) def get_packet(self, message): """ Given message, return the corresponding packet. """ return self.packets[self.walker.index(message)] def _keypress_up(self, size): # TODO: Not sure why key up is failing like this... Really need to figure out root cause #out = super(ScrollingListBox, self)._keypress_up(size) try: self.set_focus(self.walker.prev_position(self.walker.focus)) return None # No more handling needed except IndexError: # IndexError is expected when we're at the top of the list return True def _keypress_down(self, size): # TODO: Not sure why key up is failing like this... Really need to figure out root cause (jumping down a page before incrementing down) try: self.set_focus(self.walker.next_position(self.walker.focus)) return None # No more handling needed except IndexError: # IndexError is expected when we're at the top of the list return True
class TableBox(WidgetWrap): headers = False dividechars = 0 min_width = 1 zebra = False odd = (None, 'darker gray') even = (None, None) row_factory = TableRow listbox = None def __init__(self, rows, columns, title=None, headers=False, zebra=False, dividechars=1, padding=None, row_factory=None): self.columns = columns self.headers = headers self.zebra = zebra self.dividechars = dividechars if row_factory is not None: self.row_factory = row_factory _rows = [] if self.headers: header = Columns([],dividechars=self.dividechars, min_width=self.min_width) for k in columns: head = columns[k].get('header', k) size = TableRow.size_options(*columns[k]['size']) if 'size' in columns[k] else TableRow.size_options() header.contents.append( (Text(head), size) ) header = AttrMap(header, 'table_header') for i, row in enumerate(rows): r = self.build_row(row, i) _rows.append(r) self.listwalker = SimpleFocusListWalker(_rows) self.listbox = ListBox(self.listwalker) self.frame = Frame(self.listbox) widget = self.frame if padding is not None: widget = Padding(self.frame, left=padding[0], right=padding[1]) if self.headers: self.set_title(header) elif title: self.set_title(title) self.__super.__init__(widget) def set_title(self, txt): if not isinstance(txt, Widget): txt = Text(txt) self.frame.header = txt self.title = txt def build_row(self, data, i): tablerow = data if not isinstance(tablerow, Widget): color = None if self.zebra: color = self.even if (i+1) % 2 == 0 else self.odd tablerow = self.row_factory(tablerow, parent=self, color=color, dividechars=self.dividechars, min_width=self.min_width) if self.zebra: tablerow = AttrMap(tablerow, B16(*color)) return tablerow def __getitem__(self, idx): if hasattr(self.listwalker[idx], 'original_widget'): return self.listwalker[idx].original_widget else: return self.listwalker[idx] def __setitem__(self, idx, value): self.listwalker[idx] = self.build_row(value, idx) def __delitem__(self, idx): del self.listwalker[idx] def __len__(self): return len(self.listwalker) def __iter__(self): return iter(self.listwalker) def insert(self, idx, value): self.listwalker.insert(idx, self.build_row(value, idx)) def append(self, value): idx = len(self.listwalker) self.listwalker.append(self.build_row(value, idx))
class DeviceWindow(Window): def __init__(self, tui, locator, device): super().__init__(tui) self.body.contents.append( (Text("Selected device \"{}\"".format(device)), ('pack', None))) fn = self.tui.controller.get_filename(locator) self.filename_txt = Text("Selected file \"{}\"".format(fn)) self.body.contents.append((self.filename_txt, ('pack', None))) self.body.contents.append((Divider(), ('pack', None))) self.statuswidget = Pile([]) self.body.contents.append((self.statuswidget, ('pack', None))) self.body.contents.append((Divider(), ('pack', None))) self.locator = locator self.device = device self.walker = SimpleFocusListWalker([]) listbox = ListBox(self.walker) self.body.contents.append((listbox, ('weight', 1))) self.body.focus_position = 5 self.add_hotkey('U', self.update, "update") self.add_hotkey('w', self.webcams, "webcams") self.add_hotkey('a', self.actions, "actions") self.status = defaultdict(str) self.update() def start(self): self.update() self.tui.controller.subscribe( partial(self.update_status_cb, self.statuswidget), self.locator) def stop(self): self.tui.controller.unsubscribe(None, self.locator) def update_status_cb(self, container, json_msg): self.display_errors(json_msg) ## TODO filter error from loop below. The results should be in a known ## section like 'i3' data = json_msg.get(self.locator, {}) for key, value in data.items(): self.status[key] = value def parse_time(status, container, ignore): try: tstart = float(status['starttime']) tstop = float(status['stoptime']) offset = self.tui.controller.time_offset if tstop == -1: d = time.time() - tstart - offset else: d = tstop - tstart t = time.asctime(time.localtime(tstart + offset)) txt = "Started at {} ({}h{}m)".format(t, int(d / 3600), int(d % 3600) // 60) attr = 'Flabel' w = AttrMap(Text(txt), attr, attr) container.contents.append((w, container.options('pack'))) except ValueError: pass finally: ignore.append('starttime') #ignore.append('stoptime') ## leave for debugging for now def parse_progress(status, container, ignore): try: fsize = int(status['filesize']) fprog = int(status['progress']) tstart = float(status['starttime']) tstop = float(status['stoptime']) cz = float(status['current_z']) fz = float(status['final_z']) ce = float(status['current_e']) fe = float(status['final_e']) offset = self.tui.controller.time_offset if tstop == -1: d = time.time() - tstart - offset else: d = tstop - tstart rate = fprog / fsize attr = 'Flabel' def div(a, b): if b == 0: return 0 return a / b label = "File: {:0.0f}/{:0.0f} Kb ({:0.2f}%)".format( fprog / 1024, fsize / 1024, rate * 100) bar = NamedProgressBar(label, 'progress_normal', 'progress_complete', fprog, fsize, 'status') container.contents.append((bar, container.options('pack'))) label = "Z Travel: {:0.2f}/{:0.2f} mm ({:0.2f}%)".format( cz, fz, div(cz, fz) * 100) bar = NamedProgressBar(label, 'progress_normal', 'progress_complete', cz, fz, 'status') container.contents.append((bar, container.options('pack'))) label = "Extruded: {:0.0f}/{:0.0f} mm ({:0.2f}%)".format( ce, fe, div(ce, fe) * 100) bar = NamedProgressBar(label, 'progress_normal', 'progress_complete', ce, fe, 'status') container.contents.append((bar, container.options('pack'))) except: pass finally: ignore.append('filesize') ignore.append('progress') ignore.append('current_z') ignore.append('final_z') ignore.append('current_e') ignore.append('final_e') def parse_status(status, container, ignore): stat_cols = Columns([], 0) w = make_w(stat_cols, 'connected', 'connected', 'disconnected') w = make_w(stat_cols, 'idle', 'active', 'idle', reverse=True) w = make_w(stat_cols, 'paused', 'paused', 'operating') container.contents.append((stat_cols, container.options('pack'))) ignore.append('connected') ignore.append('idle') ignore.append('paused') def make_w(container, key, Tlabel, Flabel, reverse=False): if (self.status[key] == True) ^ reverse: label = "[{}]".format(Tlabel) attr = 'Tlabel' else: label = "[{}]".format(Flabel) attr = 'Flabel' w = AttrMap(Text(label), attr, attr) container.contents.append((w, container.options('pack'))) ignore = ['last_temp_request'] # We really got to properly parse this to some struct first container.contents.clear() ## progress parse_status(self.status, container, ignore) parse_progress(self.status, container, ignore) parse_time(self.status, container, ignore) for key, value in sorted(self.status.items()): if key in ignore: continue attr = 'Flabel' w = AttrMap(Text("{}: {}".format(key, value)), attr, attr) container.contents.append((w, container.options('pack'))) def update_status(self): self.tui.controller.get_data( partial(self.update_status_cb, self.statuswidget), self.locator) def update(self): self.update_status() self.walker.clear() locator = self.locator def cmd_cb(json_msg): self.display_errors(json_msg) self.update_status() fn = self.tui.controller.get_filename(locator) self.filename_txt.set_text("Selected file \"{}\"".format(fn)) button = Button("[c] Connect") def button_cb(button, locator): self.tui.controller.connect(cmd_cb, locator) urwid.connect_signal(button, 'click', button_cb, locator) self.walker.append(AttrMap(button, None, focus_map='selected')) self.add_hotkey('c', partial(button_cb, button, locator), "connect", omit_header=True) button = Button("[D] Disconnect") def button_cb(button, locator): self.tui.controller.disconnect(cmd_cb, locator) urwid.connect_signal(button, 'click', button_cb, locator) self.walker.append(AttrMap(button, None, focus_map='selected')) self.add_hotkey('D', partial(button_cb, button, locator), "disconnect", omit_header=True) button = Button("[s] Start") def button_cb(button, locator): fn = self.tui.controller.get_filename(locator) if not fn: self.footer.set_text("Please Select a file first") return self.tui.controller.start( cmd_cb, locator, self.tui.controller.get_filename(locator)) urwid.connect_signal(button, 'click', button_cb, locator) self.walker.append(AttrMap(button, None, focus_map='selected')) self.add_hotkey('s', partial(button_cb, button, locator), "start", omit_header=True) button = Button("[S] Stop (ask nicely to stop)") def button_cb(button, locator): self.tui.controller.stop(cmd_cb, locator) urwid.connect_signal(button, 'click', button_cb, locator) self.walker.append(AttrMap(button, None, focus_map='selected')) self.add_hotkey('S', partial(button_cb, button, locator), "stop", omit_header=True) button = Button("[!] Abort (Interrupt then disconnect)") def button_cb(button, locator): self.tui.controller.abort(cmd_cb, locator) urwid.connect_signal(button, 'click', button_cb, locator) self.walker.append(AttrMap(button, None, focus_map='selected')) self.add_hotkey('!', partial(button_cb, button, locator), "abort", omit_header=True) button = Button("[p] Pause") def button_cb(button, locator): self.tui.controller.pause(cmd_cb, locator) urwid.connect_signal(button, 'click', button_cb, locator) self.walker.append(AttrMap(button, None, focus_map='selected')) self.add_hotkey('p', partial(button_cb, button, locator), "pause", omit_header=True) button = Button("[r] Resume") def button_cb(button, locator): self.tui.controller.resume(cmd_cb, locator) urwid.connect_signal(button, 'click', button_cb, locator) self.walker.append(AttrMap(button, None, focus_map='selected')) self.add_hotkey('r', partial(button_cb, button, locator), "resume", omit_header=True) button = Button("[l] Load File") def button_cb(button, locator): window = FileListWindow(self.tui, locator, self.device) self.tui.push_window(window) urwid.connect_signal(button, 'click', button_cb, locator) self.walker.append(AttrMap(button, None, focus_map='selected')) self.add_hotkey('l', partial(button_cb, button, locator), "load", omit_header=True) button = Button("[m] Manual Control") def button_cb(button, locator): window = ManualControlWindow(self.tui, locator, self.device) self.tui.push_window(window) urwid.connect_signal(button, 'click', button_cb, locator) self.walker.append(AttrMap(button, None, focus_map='selected')) self.add_hotkey('m', partial(button_cb, button, locator), "manual", omit_header=True)
class ManualControlWindow(Window): def __init__(self, tui, locator, device): super().__init__(tui) self.locator = locator self.device = device self.add_hotkey('U', self.update, "update") self.add_hotkey('w', self.webcams, "webcams") self.add_hotkey('a', self.actions, "actions") self.body.contents.append( (Text("Selected device \"{}\"".format(device)), ('pack', None))) self.body.contents.append((Divider(), ('pack', None))) self.walker = SimpleFocusListWalker([]) listbox = ListBox(self.walker) self.body.contents.append((listbox, ('weight', 1))) self.body.focus_position = 2 self.update() def update(self): self.walker.clear() locator = self.locator def cmd_cb(json_msg): self.display_errors(json_msg) button = Button("[h] Home (G28 W)") def button_cb(button, locator): self.tui.controller.action("gcode {} 'G28 W'".format(locator), cmd_cb) urwid.connect_signal(button, 'click', button_cb, locator) self.walker.append(AttrMap(button, None, focus_map='selected')) self.add_hotkey('h', partial(button_cb, button, locator), "home", omit_header=True) def edit_cb(txt): self.tui.controller.action("gcode {} 'G90'".format(locator), cmd_cb) self.tui.controller.action( "gcode {} 'G1 X{}'".format(locator, txt), cmd_cb) edit = CB_Edit("Move to ABS X (mm): ", "0", None, edit_cb, NUMERICALS) self.walker.append(AttrMap(edit, None, focus_map='selected')) def edit_cb(txt): self.tui.controller.action("gcode {} 'G90'".format(locator), cmd_cb) self.tui.controller.action( "gcode {} 'G1 Y{}'".format(locator, txt), cmd_cb) edit = CB_Edit("Move to ABS Y (mm): ", "0", None, edit_cb, NUMERICALS) self.walker.append(AttrMap(edit, None, focus_map='selected')) def edit_cb(txt): self.tui.controller.action("gcode {} 'G90'".format(locator), cmd_cb) self.tui.controller.action( "gcode {} 'G1 Z{}'".format(locator, txt), cmd_cb) edit = CB_Edit("Move to ABS Z (mm): ", "0", None, edit_cb, NUMERICALS) self.walker.append(AttrMap(edit, None, focus_map='selected')) def edit_cb(txt): self.tui.controller.action( "gcode {} 'G1 F{}'".format(locator, txt), cmd_cb) edit = CB_Edit("Set Feedrate mm/min: ", "", None, edit_cb, NUMERICALS) self.walker.append(AttrMap(edit, None, focus_map='selected')) def edit_cb(txt): self.tui.controller.action( "gcode {} 'M104 S{}'".format(locator, txt), cmd_cb) edit = CB_Edit("Set Extruder Temperature °C: ", "0", None, edit_cb, NUMERICALS) self.walker.append(AttrMap(edit, None, focus_map='selected')) def edit_cb(txt): self.tui.controller.action( "gcode {} 'M140 S{}'".format(locator, txt), cmd_cb) edit = CB_Edit("Set Bed Temperature °C: ", "0", None, edit_cb, NUMERICALS) self.walker.append(AttrMap(edit, None, focus_map='selected')) button = Button("[L] Load filament (G1 E100 F300)") def button_cb(button, locator): self.tui.controller.action("gcode {} 'M83'".format(locator), cmd_cb) self.tui.controller.action( "gcode {} 'G1 E100 F300'".format(locator), cmd_cb) urwid.connect_signal(button, 'click', button_cb, locator) self.walker.append(AttrMap(button, None, focus_map='selected')) self.add_hotkey('L', partial(button_cb, button, locator), "load", omit_header=True) button = Button("[U] Unload filament (G1 E-100 F2000)") def button_cb(button, locator): self.tui.controller.action("gcode {} 'M83'".format(locator), cmd_cb) self.tui.controller.action( "gcode {} 'G1 E-100 F2000'".format(locator), cmd_cb) urwid.connect_signal(button, 'click', button_cb, locator) self.walker.append(AttrMap(button, None, focus_map='selected')) self.add_hotkey('U', partial(button_cb, button, locator), "unload", omit_header=True) button = Button("[r] Release steppers (M18)") def button_cb(button, locator): self.tui.controller.action("gcode {} 'M18'".format(locator), cmd_cb) urwid.connect_signal(button, 'click', button_cb, locator) self.walker.append(AttrMap(button, None, focus_map='selected')) self.add_hotkey('r', partial(button_cb, button, locator), "release", omit_header=True) self.walker.append(Divider()) def enter_cb(edit, txt): if edit.hjkl_active: edit.hjkl_active = False edit.set_edit_text("[enter] to activate / deactivate") else: edit.hjkl_active = True edit.set_edit_text("") self.footer.set_text("Use keys 'hjklaz' to move printer.") def edit_cb(edit, txt): if not edit.hjkl_active: return key = txt[-1] m = {'h': "X-", 'l': "X", 'j': "Y-", 'k': "Y", 'a': "Z", 'z': "Z-"} if key not in m: self.footer.set_text( "key '{}' not handled. Please use keys 'hjklaz' to move printer." .format(key)) return edit.set_edit_text("{}".format(m[key])) increment = 10 c = "gcode {} 'G1 ".format(locator) + m[key] + "{}'".format( increment) self.tui.controller.action("gcode {} 'G91'".format(locator), cmd_cb) self.tui.controller.action(c, cmd_cb) #self.tui.controller.action("gcode {} 'G1 F{}'".format(locator, txt), cmd_cb) edit = CB_Edit("VI Move: ", "[enter] to activate", edit_cb, enter_cb, [i for i in "hjklaz"]) edit.type_cb = partial(edit_cb, edit) ##hack to solve cyclic dependency edit.enter_cb = partial(enter_cb, edit) ##hack to solve cyclic dependency edit.hjkl_active = False self.walker.append(AttrMap(edit, None, focus_map='selected'))
class FileListWindow(Window): def __init__(self, tui, locator, device): super().__init__(tui) self.body.contents.append( (Text("Select file to load on \"{}\"".format(device)), ('pack', None))) self.body.contents.append((Divider(), ('pack', None))) self.device = device self.locator = locator self.device = device self.all_files = [] def limit(regexp): self.regexp = regexp self.populate_list() def enter(edit_text): if len(self.walker) < 1: self.tui.pop_window() return button = self.walker[0] button.keypress(1, 'enter') editbox = CB_Edit("Limit (regexp): ", "", limit, enter) self.body.contents.append((editbox, ('pack', 1))) self.body.contents.append((Divider(), ('pack', 1))) self.walker = SimpleFocusListWalker([]) listbox = ListBox(self.walker) self.body.contents.append((listbox, ('weight', 1))) self.body.focus_position = 2 self.update() self.regexp = ".*" def populate_list(self): try: p = re.compile(self.regexp, re.IGNORECASE) except re.error: filtered_files = self.all_files else: filtered_files = filter(p.search, self.all_files) def button_cb(locator, filename, button): self.filename = filename self.tui.controller.set_filename(locator, filename) self.tui.pop_window() self.walker.clear() for line in filtered_files: filename = line.strip() button = Button(filename) urwid.connect_signal(button, 'click', button_cb, user_args=[self.locator, filename]) self.walker.append(AttrMap(button, None, focus_map='selected')) def update(self): def filelist_cb(json_msg): self.display_errors(json_msg) self.all_files = json_msg.get('files', []) self.populate_list() self.tui.controller.get_filelist(filelist_cb, self.locator)