class FauxButton(urwid.Button): button_left = Text("") button_right = Text("") def __init__(self, label, on_press=None, user_data=None): self.user_data = user_data super(FauxButton, self).__init__(label, on_press, user_data)
def __init__(self, original_widget, title="", tlcorner=u'┌', tline=u'─', lline=u'│', trcorner=u'┐', blcorner=u'└', rline=u'│', bline=u'─', brcorner=u'┘'): """ Draw a line around original_widget. Use 'title' to set an initial title text with will be centered on top of the box. You can also override the widgets used for the lines/corners: tline: top line bline: bottom line lline: left line rline: right line tlcorner: top left corner trcorner: top right corner blcorner: bottom left corner brcorner: bottom right corner """ tline, bline = Divider(tline), Divider(bline) lline, rline = SolidFill(lline), SolidFill(rline) tlcorner, trcorner = Text(tlcorner), Text(trcorner) blcorner, brcorner = Text(blcorner), Text(brcorner) self.title_widget = Text(self.format_title(title)) self.tline_widget = Columns([ tline, ('flow', self.title_widget), tline, ]) top = Columns([('fixed', 1, tlcorner), self.tline_widget, ('fixed', 1, trcorner)]) middle = Columns([ ('fixed', 1, lline), original_widget, ('fixed', 1, rline), ], box_columns=[0, 2], focus_column=1) bottom = Columns([('fixed', 1, blcorner), bline, ('fixed', 1, brcorner)]) pile = Pile([('flow', top), middle, ('flow', bottom)], focus_item=1) WidgetDecoration.__init__(self, original_widget) WidgetWrap.__init__(self, pile)
def setup_popup(self, title): """ Overlays a dialog box on top of the working view using a Frame """ # Header if self.small_display: header = Padding(Text(title, align='center')) else: header = LineBox(Text(title), tline=None, rline=' ', lline=' ', trcorner=' ', tlcorner=' ', blcorner='', brcorner='') header = AttrWrap(header, 'header') # Body error_text = Text("", align='center') # register the Text widget with the application, so we can change it self._error = error_text error_text = AttrWrap(error_text, 'error') body = Pile([ Divider(), error_text, Divider(), LineBox(GridFlow([self.setup_button("Dismiss", self.close_popup)], 12, 2, 0, 'center'), bline=None, lline=None, rline=None, tlcorner='─', trcorner='─') ]) body = LineBox(body) body = AttrWrap(body, 'body') # on small displays let the popup fill the screen (horizontal) if self.small_display: body = Padding(Filler(body, 'middle'), 'center') else: body = Padding(Filler(body, 'middle'), 'center', ('relative', 50)) body = AttrWrap(body, 'bg') # Main dialog widget dialog = Frame(body, header=header, focus_part='body') return dialog
def __init__(self, label, on_press=None, user_data=None, delimiters=True): self._label = Text(label, align='center') if delimiters: cols = Columns([('fixed', 1, Text("<")), self._label, ('fixed', 1, Text(">"))], dividechars=1) else: cols = self._label self.__super.__init__(cols) if on_press: connect_signal(self, 'click', on_press, user_data)
def render(self, size, focus=False): """ Render the progress bar. """ (maxcol, ) = size txt = Text(self.get_text(), self.text_align, CLIP) c = txt.render((maxcol, )) cf = float(self.current) * maxcol / self.done ccol = int(cf) cs = 0 if self.satt is not None: cs = int((cf - ccol) * 8) if ccol < 0 or (ccol == 0 and cs == 0): c._attr = [[(self.normal, maxcol)]] elif ccol >= maxcol: c._attr = [[(self.complete, maxcol)]] elif cs and c._text[0][ccol] == " ": t = c._text[0] cenc = self.eighths[cs].encode("utf-8") c._text[0] = t[:ccol] + cenc + t[ccol + 1:] a = [] if ccol > 0: a.append((self.complete, ccol)) a.append((self.satt, len(cenc))) if maxcol - ccol - 1 > 0: a.append((self.normal, maxcol - ccol - 1)) c._attr = [a] c._cs = [[(None, len(c._text[0]))]] else: c._attr = [[(self.complete, ccol), (self.normal, maxcol - ccol)]] return c
def render(self, size, focus=False): """ Render BarGraph. """ (maxcol, maxrow) = size disp = self.calculate_display((maxcol, maxrow)) combinelist = [] for y_count, row in disp: l = [] for bar_type, width in row: if type(bar_type) == tuple: if len(bar_type) == 3: # vertical eighths fg, bg, k = bar_type a = self.satt[(fg, bg)] t = self.eighths[k] * width else: # horizontal lines bg, k = bar_type a = self.hatt[bg] t = self.hlines[k] * width else: a = self.attr[bar_type] t = self.char[bar_type] * width l.append((a, t)) c = Text(l).render((maxcol, )) assert c.rows() == 1, "Invalid characters in BarGraph!" combinelist += [(c, None, False)] * y_count canv = CanvasCombine(combinelist) return canv
def __init__(self): """ Create canvas containing an ASCII version of the Python Logo and store it. """ blu = AttrSpec('light blue', 'default') yel = AttrSpec('yellow', 'default') width = 17 self._canvas = Text([(blu, " ______\n"), (blu, " _|_o__ |"), (yel, "__\n"), (blu, " | _____|"), (yel, " |\n"), (blu, " |__| "), (yel, "______|\n"), (yel, " |____o_|")]).render((width, ))
def __init__(self, label, state=False, has_mixed=False, on_state_change=None, user_data=None, checked_symbol=None): """ :param label: markup for check box label :param state: False, True or "mixed" :param has_mixed: True if "mixed" is a state to cycle through :param on_state_change: shorthand for connect_signal() function call for a single callback :param user_data: user_data for on_state_change Signals supported: ``'change'``, ``"postchange"`` Register signal handler with:: urwid.connect_signal(check_box, 'change', callback, user_data) where callback is callback(check_box, new_state [,user_data]) Unregister signal handlers with:: urwid.disconnect_signal(check_box, 'change', callback, user_data) >>> CheckBox(u"Confirm") <CheckBox selectable flow widget 'Confirm' state=False> >>> CheckBox(u"Yogourt", "mixed", True) <CheckBox selectable flow widget 'Yogourt' state='mixed'> >>> cb = CheckBox(u"Extra onions", True) >>> cb <CheckBox selectable flow widget 'Extra onions' state=True> >>> cb.render((20,), focus=True).text # ... = b in Python 3 [...'[X] Extra onions '] """ self.__super.__init__(None) # self.w set by set_state below self._label = Text("") self.has_mixed = has_mixed self._state = None if checked_symbol: self.states[True] = SelectableIcon(u"[%s]" % checked_symbol, 1) # The old way of listening for a change was to pass the callback # in to the constructor. Just convert it to the new way: if on_state_change: connect_signal(self, 'change', on_state_change, user_data) self.set_label(label) self.set_state(state)
def set_scale(self, labels, top): """ set_scale( [(label1 position, label1 markup),...], top ) label position -- 0 < position < top for the y position label markup -- text markup for this label top -- top y position """ labels = labels[:] # shallow copy labels.sort() labels.reverse() self.pos = [] self.txt = [] for y, markup in labels: self.pos.append(y) self.txt.append(Text(markup)) self.top = top
def __init__(self, label, state=False, has_mixed=False, on_state_change=None, user_data=None): """ label -- markup for check box label state -- False, True or "mixed" has_mixed -- True if "mixed" is a state to cycle through on_state_change, user_data -- shorthand for connect_signal() function call for a single callback Signals supported: 'change' Register signal handler with: connect_signal(check_box, 'change', callback [,user_data]) where callback is callback(check_box, new_state [,user_data]) Unregister signal handlers with: disconnect_signal(check_box, 'change', callback [,user_data]) >>> CheckBox(u"Confirm") <CheckBox selectable widget 'Confirm' state=False> >>> CheckBox(u"Yogourt", "mixed", True) <CheckBox selectable widget 'Yogourt' state='mixed'> >>> cb = CheckBox(u"Extra onions", True) >>> cb <CheckBox selectable widget 'Extra onions' state=True> >>> cb.render((20,), focus=True).text # ... = b in Python 3 [...'[X] Extra onions '] """ self.__super.__init__(None) # self.w set by set_state below self._label = Text("") self.has_mixed = has_mixed self._state = None # The old way of listening for a change was to pass the callback # in to the constructor. Just convert it to the new way: if on_state_change: connect_signal(self, 'change', on_state_change, user_data) self.set_label(label) self.set_state(state)
def __init__(self, original_widget, title="", title_align="center", title_attr=None, tlcorner=u'┌', tline=u'─', lline=u'│', trcorner=u'┐', blcorner=u'└', rline=u'│', bline=u'─', brcorner=u'┘'): """ Draw a line around original_widget. Use 'title' to set an initial title text with will be centered on top of the box. Use `title_attr` to apply a specific attribute to the title text. Use `title_align` to align the title to the 'left', 'right', or 'center'. The default is 'center'. You can also override the widgets used for the lines/corners: tline: top line bline: bottom line lline: left line rline: right line tlcorner: top left corner trcorner: top right corner blcorner: bottom left corner brcorner: bottom right corner If empty string is specified for one of the lines/corners, then no character will be output there. This allows for seamless use of adjoining LineBoxes. """ if tline: tline = Divider(tline) if bline: bline = Divider(bline) if lline: lline = SolidFill(lline) if rline: rline = SolidFill(rline) tlcorner, trcorner = Text(tlcorner), Text(trcorner) blcorner, brcorner = Text(blcorner), Text(brcorner) if not tline and title: raise ValueError('Cannot have a title when tline is empty string') if title_attr: self.title_widget = Text((title_attr, self.format_title(title))) else: self.title_widget = Text(self.format_title(title)) if tline: if title_align not in ('left', 'center', 'right'): raise ValueError('title_align must be one of "left", "right", or "center"') if title_align == 'left': tline_widgets = [('flow', self.title_widget), tline] else: tline_widgets = [tline, ('flow', self.title_widget)] if title_align == 'center': tline_widgets.append(tline) self.tline_widget = Columns(tline_widgets) top = Columns([ ('fixed', 1, tlcorner), self.tline_widget, ('fixed', 1, trcorner) ]) else: self.tline_widget = None top = None middle_widgets = [] if lline: middle_widgets.append(('fixed', 1, lline)) else: # Note: We need to define a fixed first widget (even if it's 0 width) so that the other # widgets have something to anchor onto middle_widgets.append(('fixed', 0, SolidFill(u""))) middle_widgets.append(original_widget) focus_col = len(middle_widgets) - 1 if rline: middle_widgets.append(('fixed', 1, rline)) middle = Columns(middle_widgets, box_columns=[0, 2], focus_column=focus_col) if bline: bottom = Columns([ ('fixed', 1, blcorner), bline, ('fixed', 1, brcorner) ]) else: bottom = None pile_widgets = [] if top: pile_widgets.append(('flow', top)) pile_widgets.append(middle) focus_pos = len(pile_widgets) - 1 if bottom: pile_widgets.append(('flow', bottom)) pile = Pile(pile_widgets, focus_item=focus_pos) WidgetDecoration.__init__(self, original_widget) WidgetWrap.__init__(self, pile)
class Button(WidgetWrap): def sizing(self): return frozenset([FLOW]) button_left = Text("<") button_right = Text(">") signals = ["click"] def __init__(self, label, on_press=None, user_data=None): """ :param label: markup for button label :param on_press: shorthand for connect_signal() function call for a single callback :param user_data: user_data for on_press Signals supported: ``'click'`` Register signal handler with:: urwid.connect_signal(button, 'click', callback, user_data) where callback is callback(button [,user_data]) Unregister signal handlers with:: urwid.disconnect_signal(button, 'click', callback, user_data) >>> Button(u"Ok") <Button selectable flow widget 'Ok'> >>> b = Button("Cancel") >>> b.render((15,), focus=True).text # ... = b in Python 3 [...'< Cancel >'] """ self._label = SelectableIcon("", 0) cols = Columns([('fixed', 1, self.button_left), self._label, ('fixed', 1, self.button_right)], dividechars=1) self.__super.__init__(cols) # The old way of listening for a change was to pass the callback # in to the constructor. Just convert it to the new way: if on_press: connect_signal(self, 'click', on_press, user_data) self.set_label(label) def _repr_words(self): # include button.label in repr(button) return self.__super._repr_words() + [python3_repr(self.label)] def set_label(self, label): """ Change the button label. label -- markup for button label >>> b = Button("Ok") >>> b.set_label(u"Yup yup") >>> b <Button selectable flow widget 'Yup yup'> """ self._label.set_text(label) def get_label(self): """ Return label text. >>> b = Button(u"Ok") >>> print b.get_label() Ok >>> print b.label Ok """ return self._label.text label = property(get_label) def keypress(self, size, key): """ Send 'click' signal on 'activate' command. >>> assert Button._command_map[' '] == 'activate' >>> assert Button._command_map['enter'] == 'activate' >>> size = (15,) >>> b = Button(u"Cancel") >>> clicked_buttons = [] >>> def handle_click(button): ... clicked_buttons.append(button.label) >>> connect_signal(b, 'click', handle_click) >>> b.keypress(size, 'enter') >>> b.keypress(size, ' ') >>> clicked_buttons # ... = u in Python 2 [...'Cancel', ...'Cancel'] """ if self._command_map[key] != ACTIVATE: return key self._emit('click') def mouse_event(self, size, event, button, x, y, focus): """ Send 'click' signal on button 1 press. >>> size = (15,) >>> b = Button(u"Ok") >>> clicked_buttons = [] >>> def handle_click(button): ... clicked_buttons.append(button.label) >>> connect_signal(b, 'click', handle_click) >>> b.mouse_event(size, 'mouse press', 1, 4, 0, True) True >>> b.mouse_event(size, 'mouse press', 2, 4, 0, True) # ignored False >>> clicked_buttons # ... = u in Python 2 [...'Ok'] """ if button != 1 or not is_mouse_press(event): return False self._emit('click') return True
def __init__(self, original_widget, title="", title_align="center", tlcorner='┌', tline='─', lline='│', trcorner='┐', blcorner='└', rline='│', bline='─', brcorner='┘'): """ Draw a line around original_widget. Use 'title' to set an initial title text with will be centered on top of the box. Use `title_align` to align the title to the 'left', 'right', or 'center'. The default is 'center'. You can also override the widgets used for the lines/corners: tline: top line bline: bottom line lline: left line rline: right line tlcorner: top left corner trcorner: top right corner blcorner: bottom left corner brcorner: bottom right corner .. note:: This differs from the vanilla urwid LineBox by discarding the a line if the middle of the line is set to either None or the empty string. """ if tline: tline = Divider(tline) if bline: bline = Divider(bline) if lline: lline = SolidFill(lline) if rline: rline = SolidFill(rline) tlcorner, trcorner = Text(tlcorner), Text(trcorner) blcorner, brcorner = Text(blcorner), Text(brcorner) if not tline and title: raise ValueError('Cannot have a title when tline is unset') self.title_widget = Text(self.format_title(title)) if tline: if title_align not in ('left', 'center', 'right'): raise ValueError( 'title_align must be one of "left", "right", or "center"') if title_align == 'left': tline_widgets = [('flow', self.title_widget), tline] else: tline_widgets = [tline, ('flow', self.title_widget)] if title_align == 'center': tline_widgets.append(tline) self.tline_widget = Columns(tline_widgets) top = Columns([('fixed', 1, tlcorner), self.tline_widget, ('fixed', 1, trcorner)]) else: self.tline_widget = None top = None middle_widgets = [] if lline: middle_widgets.append(('fixed', 1, lline)) middle_widgets.append(original_widget) focus_col = len(middle_widgets) - 1 if rline: middle_widgets.append(('fixed', 1, rline)) middle = Columns(middle_widgets, box_columns=[0, 2], focus_column=focus_col) if bline: bottom = Columns([('fixed', 1, blcorner), bline, ('fixed', 1, brcorner)]) else: bottom = None pile_widgets = [] if top: pile_widgets.append(('flow', top)) pile_widgets.append(middle) focus_pos = len(pile_widgets) - 1 if bottom: pile_widgets.append(('flow', bottom)) pile = Pile(pile_widgets, focus_item=focus_pos) WidgetDecoration.__init__(self, original_widget) WidgetWrap.__init__(self, pile)
def setup_frame(self, title, input_title): """ Creates the main view, with a 3 horizontal pane container (Frame) """ self.keys = [] # List of keys added to the OSK self._shift = False # OSK Shift key state # title frame (header) uses a LineBox with just the bottom line enabled # if we're on a small display, use a simple Text with Padding if self.small_display: header = Padding(Text(title, align='center')) else: header = LineBox(Text(title), tline=None, rline=' ', lline=' ', trcorner=' ', tlcorner=' ', blcorner='', brcorner='') header = AttrWrap(header, 'header') # Body frame, containing the input and the OSK widget input = Text([('input text', ''), ('prompt', ASCII_BLOCK)]) self.input = input Key = self.add_osk_key # alias the key creation function osk = Pile([ # 1st keyboard row WrappableColumns([ (1, Text(" ")), (3, Key('`', shifted='~')), (3, Key('1', shifted='!')), (3, Key('2', shifted='@')), (3, Key('3', shifted='#')), (3, Key('4', shifted='$')), (3, Key('5', shifted='%')), (3, Key('6', shifted='^')), (3, Key('7', shifted='&')), (3, Key('8', shifted='*')), (3, Key('9', shifted='(')), (3, Key('0', shifted=')')), (3, Key('-', shifted='_')), (3, Key('=', shifted='+')), (1, Text(" ")), ], 0), Divider(), # 2nd keyboard row WrappableColumns([ (2, Text(" ")), (3, Key('q')), (3, Key('w')), (3, Key('e')), (3, Key('r')), (3, Key('t')), (3, Key('y')), (3, Key('u')), (3, Key('i')), (3, Key('o')), (3, Key('p')), (3, Key('[', shifted='{')), (3, Key(']', shifted='}')), (3, Key('\\', shifted='|')), ], 0), Divider(), # 3rd keyboard row WrappableColumns([ (3, Text(" ")), (3, Key('a')), (3, Key('s')), (3, Key('d')), (3, Key('f')), (3, Key('g')), (3, Key('h')), (3, Key('j')), (3, Key('k')), (3, Key('l')), (3, Key(';', shifted=':')), (3, Key('\'', shifted='"')), ], 0), Divider(), # 4th keyboard row WrappableColumns([(4, Text(" ")), (3, Key('z')), (3, Key('x')), (3, Key('c')), (3, Key('v')), (3, Key('b')), (3, Key('n')), (3, Key('m')), (3, Key(',', shifted='<')), (3, Key('.', shifted='>')), (3, Key('/', shifted='?'))], 0), Divider(), # 5th (last) keyboard row WrappableColumns([ (1, Text(" ")), (9, Key('↑ Shift', shifted='↑ SHIFT', callback=self.shift_key_press)), (2, Text(" ")), (15, Key('Space', value=' ', shifted=' ')), (2, Text(" ")), (10, Key('Delete ←', callback=self.bksp_key_press)), ], 0), Divider() ]) if self.small_display: # small displays: remove last divider line osk.contents.pop(len(osk.contents) - 1) osk = Padding(osk, 'center', 40) # setup the text input and the buttons input = AttrWrap(LineBox(input), 'input') input = Padding(AttrWrap(input, 'input text'), 'center', ('relative', 80), min_width=30) ok_btn = self.setup_button("OK", self.button_press, exitcode=0) cancel_btn = self.setup_button("Cancel", self.button_press, exitcode=1) # setup the main OSK area, depending on the screen size if self.small_display: body = Pile([ Text(f'Enter the {input_title}', align='center'), input, Divider(), osk, Divider(), GridFlow([ok_btn, cancel_btn], 10, 2, 0, 'center'), Divider() ]) else: body = Pile([ Divider(), input, Divider(), osk, LineBox(GridFlow([ok_btn, cancel_btn], 10, 2, 0, 'center'), bline=None, lline=None, rline=None, tlcorner='─', trcorner='─') ]) body = LineBox(body, f'Enter the {input_title}') body = AttrWrap(body, 'body') # Style the main OSK area # wrap and align the main OSK in the frame body = Padding(body, 'center', 55, min_width=42) body = Filler(body, 'middle') body = AttrWrap(body, 'bg') # Style the body containing the OSK frame = Frame(body, header=header, focus_part='body') return frame
def __init__(self, original_widget, title="", tlcorner=None, tline=None, lline=None, trcorner=None, blcorner=None, rline=None, bline=None, brcorner=None): """ Draw a line around original_widget. Use 'title' to set an initial title text with will be centered on top of the box. You can also override the widgets used for the lines/corners: tline: top line bline: bottom line lline: left line rline: right line tlcorner: top left corner trcorner: top right corner blcorner: bottom left corner brcorner: bottom right corner """ self.title_widget = Text(self.format_title(title)) def use_attr(a, t): if a is not None: t = AttrWrap(t, a) return t else: return t self.tline_widget = Columns([ Divider(self.ACS_HLINE), ('flow', self.title_widget), Divider(self.ACS_HLINE), ]) tline = use_attr(tline, self.tline_widget) bline = use_attr(bline, Divider(self.ACS_HLINE)) lline = use_attr(lline, SolidFill(self.ACS_VLINE)) rline = use_attr(rline, SolidFill(self.ACS_VLINE)) tlcorner = use_attr(tlcorner, Text(self.ACS_ULCORNER)) trcorner = use_attr(trcorner, Text(self.ACS_URCORNER)) blcorner = use_attr(blcorner, Text(self.ACS_LLCORNER)) brcorner = use_attr(brcorner, Text(self.ACS_LRCORNER)) top = Columns([('fixed', 1, tlcorner), tline, ('fixed', 1, trcorner)]) middle = Columns([('fixed', 1, lline), original_widget, ('fixed', 1, rline)], box_columns=[0, 2], focus_column=1) bottom = Columns([('fixed', 1, blcorner), bline, ('fixed', 1, brcorner)]) pile = Pile([('flow', top), middle, ('flow', bottom)], focus_item=1) WidgetDecoration.__init__(self, original_widget) WidgetWrap.__init__(self, pile)