class StringEditor(WidgetWrap): """ Edit input class Initializes and Edit object and attachs its result to the `value` accessor. """ def __init__(self, caption=None, default=None, **kwargs): if caption is None: caption = "" self._edit = Edit(caption=caption, **kwargs) if default is not None: self._edit.set_edit_text(default) self.error = None super().__init__(self._edit) def keypress(self, size, key): if self.error: self._edit.set_edit_text("") self.error = None return super().keypress(size, key) def set_error(self, msg): self.error = msg return self._edit.set_edit_text(msg) @property def value(self): if self._edit.get_edit_text() == "": return None return self._edit.get_edit_text() @value.setter # NOQA def value(self, value): self._edit.set_edit_text(value)
class AddTodo(ConnectedComponent): def render_component(self, props): self.edit = Edit(caption='Todo: ', edit_text='') self.button = Button('Add Todo') return Columns([ (1, Text('[')), self.edit, (1, Text(']')), (18, self.button), ]) def keypress(self, size, key): if key == 'enter': self.on_submit() return True return super(AddTodo, self).keypress(size, key) def on_submit(self): if not self.edit.get_edit_text().strip(): return self.store['dispatch'](add_todo(self.edit.get_edit_text())) self.edit.set_edit_text('') def on_click(self, *args): self.on_submit()
class NoteEditor(WidgetWrap): __metaclass__ = signals.MetaSignals signals = ['done'] def __init__(self, done_handler, note=None): self.modes = ['title', 'tags', 'text'] self.mode = self.modes[0] self.note = note if note is None: self.title = '' self.tags = '' self.text = '' else: self.title = note.title self.tags = note.formatted_tags() self.text = note.text self.editor = Edit(u'title :: ', self.title) connect_signal(self, 'done', done_handler) WidgetWrap.__init__(self, self.editor) def keypress(self, size, key): if key == 'enter': if self.mode == 'title': self.title = self.editor.get_edit_text() self.init_tags_mode() elif self.mode == 'tags': # Enforce lower case tags for consistency self.tags = self.editor.get_edit_text().lower() self.init_text_mode() elif key == 'esc': self.emit_done() return size = size, self.editor.keypress(size, key) def init_tags_mode(self): self.mode = self.modes[1] self.editor.set_caption('tags :: ') self.editor.set_edit_text(self.tags) def init_text_mode(self): self.mode = self.modes[2] editor = os.environ.get('EDITOR', 'vim') with tempfile.NamedTemporaryFile(prefix="aerende_tmp", suffix=".tmp") as temp: temp.write(self.text.encode('utf-8')) temp.flush() call([editor, temp.name]) temp.seek(0) self.text = temp.read().decode('utf-8').strip() os.system('clear') self.emit_done((self.title, self.tags, self.text)) def emit_done(self, note=None): emit_signal(self, 'done', note, self.note)
class StyledEdit(Padding): def __init__(self, content, default, tooltip, left_margin, source=None): """ General Edit Field Args: content: text of the editbox default: default value of the editbox tooltip: tooltip of the editbox left_margin: left_margin of the editbox source: there this item is from for value reference """ text = u" * " + content + u": " self.core = Edit(('editcp', ""), default) self.source = source self.widget = Pile([ Text(text), Padding(AttrWrap(self.core, 'editbx', 'editfc'), left=4), Padding(Text(tooltip), left=4) ]) super().__init__(self.widget, left=2 + left_margin - 4, right=2) def get_source(self): return self.source def get_core_value(self): return self.core.get_edit_text()
class TextEditor(WidgetWrap): """Editor for creating arbitrary text.""" __metaclass__ = signals.MetaSignals signals = ['done'] def __init__(self, prompt, content, done_signal_handler): if content: content += ' ' self.editor = Edit(u'%s (twice enter key to validate or esc) \n>> ' % prompt, content) widgets = [self.editor] w = AttrMap(Columns(widgets), 'editor') connect_signal(self, 'done', done_signal_handler) self.__super.__init__(w) def keypress(self, size, key): if key == 'enter' and self.last_key == 'enter': self.emit_done_signal(self.editor.get_edit_text()) return elif key == 'esc': self.emit_done_signal() return self.last_key = key size = size, self.editor.keypress(size, key) def emit_done_signal(self, content=None): emit_signal(self, 'done', content)
class TextEditor(WidgetWrap): """Editor for creating arbitrary text.""" __metaclass__ = signals.MetaSignals signals = ['done'] def __init__(self, prompt, content, done_signal_handler): if content: content += ' ' self.editor = Edit( u'%s (twice enter key to validate or esc) \n>> ' % prompt, content) widgets = [self.editor] w = AttrMap(Columns(widgets), 'editor') connect_signal(self, 'done', done_signal_handler) self.__super.__init__(w) def keypress(self, size, key): if key == 'enter' and self.last_key == 'enter': self.emit_done_signal(self.editor.get_edit_text()) return elif key == 'esc': self.emit_done_signal() return self.last_key = key size = size, self.editor.keypress(size, key) def emit_done_signal(self, content=None): emit_signal(self, 'done', content)
class LockScreen(Overlay): LOCKED = "The screen is locked. Please enter a password (this is the " \ "password you entered for OpenStack during installation). " INVALID = ("error", "Invalid password.") IOERROR = ("error", "Problem accessing {pwd}. Please make sure " "it contains exactly one line that is the lock " "password.".format(pwd=pegasus.PASSWORD_FILE)) def __init__(self, underlying, unlock): self.unlock = unlock self.password = Edit("Password: "******"") w = ListBox([Text(self.LOCKED), self.invalid, self.password]) w = LineBox(w) w = AttrWrap(w, "dialog") Overlay.__init__(self, w, underlying, 'center', 60, 'middle', 8) def keypress(self, size, key): if key == 'enter': if pegasus.OPENSTACK_PASSWORD is None: self.invalid.set_text(self.IOERROR) elif pegasus.OPENSTACK_PASSWORD == self.password.get_edit_text(): self.unlock() else: self.invalid.set_text(self.INVALID) self.password.set_edit_text("") else: return Overlay.keypress(self, size, key)
class BaseEditor(WidgetWrap): """Base class for editors.""" __metaclass__ = signals.MetaSignals signals = ["done"] def __init__(self, prompt, content, done_signal_handler, cursor_position=None): """ Initializes editor, connects 'done' signal. When pressing 'enter' twice the `submit` method is called, which by default calls `emit_done_signal` with the text that has been introduced. When pressing 'esc' the `cancel` method is called, which by default calls `emit_done_signal` with no arguments. The subclasses must call the `_wrap` method with the editor widgets and `BaseEditor` will wrap it in a `urwid.Colums` widget, calling to `urwid.WidgetWrap.__init__` with the wrapped widget. """ caption = _(u"%s (twice enter key to validate or esc) \n>> ") % prompt if content: content += " " self.content = content self.editor = Edit(caption=caption, edit_text=content, edit_pos=cursor_position) self.last_key = None connect_signal(self, "done", done_signal_handler) def _wrap(self, widgets): widgets = widgets if isinstance(widgets, list) else [widgets] composed_widget = Columns(widgets) widget = AttrMap(LineBox(composed_widget), "editor") WidgetWrap.__init__(self, widget) def keypress(self, size, key): if key == "enter" and self.last_key == "enter": self.submit() return elif key == "esc": self.cancel() return self.last_key = key size = (size,) self.editor.keypress(size, key) def submit(self): self.emit_done_signal(self.editor.get_edit_text()) def cancel(self): self.emit_done_signal() def emit_done_signal(self, content=None): emit_signal(self, "done", content)
class EditInput(WidgetWrap): """ Edit input class Initializes an Edit object and attaches its result to the `value` accessor. """ def __init__(self, caption, **kwargs): self._edit = Edit(caption=caption, **kwargs) super().__init__( Color.string_input(self._edit, focus_map="string_input focus")) @property def value(self): """ Returns text of input """ return self._edit.get_edit_text()
async def apply_cb(edit: urwid.Edit) -> None: text: str = edit.get_edit_text() # In case the text is empty if not text: return sha = await core.full_sha(text) for c in reversed(list(itertools.chain(self.new_commits, self.previous_commits))): if c.sha == sha: commit = c break else: raise RuntimeError(f"Couldn't find {sha}") await commit.apply(self)
class EditInput(WidgetWrap): """ Edit input class Initializes an Edit object and attaches its result to the `value` accessor. """ def __init__(self, caption, **kwargs): self._edit = Edit(caption=caption, **kwargs) super().__init__(self._edit) @property def value(self): """ Returns text of input """ return self._edit.get_edit_text()
class TweetEditor(WidgetWrap): """Editor for creating tweets.""" __metaclass__ = signals.MetaSignals signals = ['done'] def __init__(self, prompt, content, done_signal_handler): if content: content += ' ' self.editor = Edit(u'%s (twice enter key to validate or esc) \n>> ' % prompt, content) self.counter = len(content) self.counter_widget = Text(str(self.counter)) widgets = [('fixed', 4, self.counter_widget), self.editor] w = AttrMap(Columns(widgets), 'editor') connect_signal(self, 'done', done_signal_handler) connect_signal(self.editor, 'change', self.update_counter) self.__super.__init__(w) def update_counter(self, edit, new_edit_text): self.counter = len(new_edit_text) self.counter_widget.set_text(str(self.counter)) def keypress(self, size, key): if key == 'enter' and self.last_key == 'enter': if self.counter > TWEET_MAX_CHARS: return else: self.emit_done_signal(self.editor.get_edit_text()) elif key == 'esc': self.emit_done_signal() return self.last_key = key size = size, self.editor.keypress(size, key) def emit_done_signal(self, content=None): emit_signal(self, 'done', content)
class TweetEditor(WidgetWrap): """Editor for creating tweets.""" __metaclass__ = signals.MetaSignals signals = ['done'] def __init__(self, prompt, content, done_signal_handler): if content: content += ' ' self.editor = Edit( u'%s (twice enter key to validate or esc) \n>> ' % prompt, content) self.counter = len(content) self.counter_widget = Text(str(self.counter)) widgets = [('fixed', 4, self.counter_widget), self.editor] w = AttrMap(Columns(widgets), 'editor') connect_signal(self, 'done', done_signal_handler) connect_signal(self.editor, 'change', self.update_counter) self.__super.__init__(w) def update_counter(self, edit, new_edit_text): self.counter = len(new_edit_text) self.counter_widget.set_text(str(self.counter)) def keypress(self, size, key): if key == 'enter' and self.last_key == 'enter': if self.counter > TWEET_MAX_CHARS: return else: self.emit_done_signal(self.editor.get_edit_text()) elif key == 'esc': self.emit_done_signal() return self.last_key = key size = size, self.editor.keypress(size, key) def emit_done_signal(self, content=None): emit_signal(self, 'done', content)
class GazuaFrame(Frame): column_pos = 0 def __init__(self, *args, **kwargs): self.search_edit = Edit('Search: ') self.arrow_callback = kwargs['arrow_callback'] super(GazuaFrame, self).__init__(*args, header=AttrMap(self.search_edit, 'header')) def keypress(self, size, key): if len(key) == 1 and key.isalpha: if re.compile('^[a-zA-Z0-9]$').match(key): self.search_edit.insert_text(key) elif key == 'backspace': self.search_edit.set_edit_text( self.search_edit.get_edit_text()[0:-1]) elif key == 'left': if self.column_pos == 0: self.arrow_callback(None) elif self.column_pos == 1: self.column_pos -= 1 self.arrow_callback(0) else: self.column_pos -= 1 self.arrow_callback(1) elif key == 'right': if self.column_pos == 0: self.column_pos += 1 self.arrow_callback(1) elif self.column_pos == 1: self.column_pos += 1 self.arrow_callback(2) else: self.arrow_callback(None) return super(GazuaFrame, self).keypress(size, key)
class Client(Component): channel = "client" def init(self, host, port=6667, opts=None): self.host = host self.port = port self.opts = opts self.hostname = gethostname() self.nick = opts.nick self.ircchannel = opts.channel # Add TCPClient and IRC to the system. TCPClient(channel=self.channel).register(self) IRC(channel=self.channel).register(self) self.create_interface() def create_interface(self): self.screen = Screen() self.screen.start() self.screen.register_palette([ ("title", "white", "dark blue", "standout"), ("line", "light gray", "black"), ("help", "white", "dark blue")] ) self.body = ListBox(SimpleListWalker([])) self.lines = self.body.body self.title = Text(MAIN_TITLE) self.header = AttrWrap(self.title, "title") self.help = AttrWrap( Text(HELP_STRINGS["main"]), "help" ) self.input = Edit(caption="%s> " % self.ircchannel) self.footer = Pile([self.help, self.input]) self.top = Frame(self.body, self.header, self.footer) def ready(self, component): """Ready Event This event is triggered by the underlying ``TCPClient`` Component when it is ready to start making a new connection. """ self.fire(connect(self.host, self.port)) def connected(self, host, port): """connected Event This event is triggered by the underlying ``TCPClient`` Component when a successfully connection has been made. """ nick = self.nick hostname = self.hostname name = "%s on %s using circuits/%s" % (nick, hostname, systemVersion) self.fire(NICK(nick)) self.fire(USER(nick, hostname, host, name)) def numeric(self, source, numeric, *args): """Numeric Event This event is triggered by the ``IRC`` Protocol Component when we have received an IRC Numberic Event from server we are connected to. """ if numeric == ERR_NICKNAMEINUSE: self.fire(NICK("{0:s}_".format(args[0]))) elif numeric in (RPL_ENDOFMOTD, ERR_NOMOTD): self.fire(JOIN(self.ircchannel)) @handler("stopped", channel="*") def _on_stopped(self, component): self.screen.stop() @handler("generate_events") def _on_generate_events(self, event): event.reduce_time_left(0) size = self.screen.get_cols_rows() if not select( self.screen.get_input_descriptors(), [], [], 0.1)[0] == []: timeout, keys, raw = self.screen.get_input_nonblocking() for k in keys: if k == "window resize": size = self.screen.get_cols_rows() continue elif k == "enter": self.processCommand(self.input.get_edit_text()) self.input.set_edit_text("") continue self.top.keypress(size, k) self.input.set_edit_text(self.input.get_edit_text() + k) self.update_screen(size) def unknownCommand(self, command): self.lines.append(Text("Unknown command: %s" % command)) def syntaxError(self, command, args, expected): self.lines.append( Text("Syntax error ({0:s}): {1:s} Expected: {2:s}".format( command, args, expected) ) ) def processCommand(self, s): # noqa match = CMD_REGEX.match(s) if match is not None: command = match.groupdict()["command"] if not match.groupdict()["args"] == "": tokens = match.groupdict()["args"].split(" ") else: tokens = [] fn = "cmd" + command.upper() if hasattr(self, fn): f = getattr(self, fn) if callable(f): args, vargs, kwargs, default = getargspec(f) args.remove("self") if len(args) == len(tokens): if len(args) == 0: f() else: f(*tokens) else: if len(tokens) > len(args): if vargs is None: if len(args) > 0: factor = len(tokens) - len(args) + 1 f(*back_merge(tokens, factor)) else: self.syntaxError( command, " ".join(tokens), " ".join( x for x in args + [vargs] if x is not None ) ) else: f(*tokens) elif default is not None and \ len(args) == ( len(tokens) + len(default)): f(*(tokens + list(default))) else: self.syntaxError( command, " ".join(tokens), " ".join( x for x in args + [vargs] if x is not None ) ) else: if self.ircchannel is not None: self.lines.append(Text("<%s> %s" % (self.nick, s))) self.fire(PRIVMSG(self.ircchannel, s)) else: self.lines.append(Text( "No channel joined. Try /join #<channel>")) def cmdEXIT(self, message=""): self.fire(QUIT(message)) raise SystemExit(0) def cmdSERVER(self, host, port=6667): self.fire(connect(host, port)) def cmdSSLSERVER(self, host, port=6697): self.fire(connect(host, port, secure=True)) def cmdJOIN(self, channel): if self.ircchannel is not None: self.cmdPART(self.ircchannel, "Joining %s" % channel) self.fire(JOIN(channel)) self.ircchannel = channel def cmdPART(self, channel=None, message="Leaving"): if channel is None: channel = self.ircchannel if channel is not None: self.fire(PART(channel, message)) self.ircchannel = None def cmdQUOTE(self, message): self.fire(request(Message(message))) def cmdQUIT(self, message="Bye"): self.fire(QUIT(message)) def update_screen(self, size): canvas = self.top.render(size, focus=True) self.screen.draw_screen(size, canvas) @handler("notice", "privmsg") def _on_notice_or_privmsg(self, event, source, target, message): nick, ident, host = source if event.name == "notice": self.lines.append(Text("-%s- %s" % (nick, message))) else: self.lines.append(Text("<%s> %s" % (nick, message)))
class LoginWindow(WidgetWrap): signals = ['login', 'logout'] def __init__(self, app, extra=None, get_user=None, max_time=30): self.app = app self.extra = extra self.get_user = get_user self.max_time = max_time self._create_widgets() self._out_count = 0 self._evt_time = 0 self._parent = None self._key_sig_id = None self._timeout_sig_id = None self.__super.__init__(self.login_widget) def _create_widgets(self): self._create_login_widget() if self.extra: widget = Frame(LineBox(self.login_widget), footer=self.extra) else: widget = LineBox(self.login_widget) self.overlay = Overlay( widget, None, 'center', ('relative', 100), 'middle', ('relative', 100), ) def _create_login_widget(self): self.username_entry = Edit(align='right') self.username_entry.keypress = self._username_keypress self.password_entry = Password(align='right') self.password_entry.keypress = self._password_keypress username_row = Columns([ ('fixed', 10, Text("Usuario:", align='right')), ('fixed', 10, self.username_entry), ]) password_row = Columns([ ('fixed', 10, Text("Clave:", align='right')), ('fixed', 10, self.password_entry), ]) self.pile = Pile([ username_row, Divider(), password_row, ], focus_item=0) self.login_widget = Filler(Columns([Divider(), self.pile, Divider()])) def show(self): """Show login window""" #self.pile.set_focus(0) self.clear() loop = self.app.loop self.overlay.bottom_w = loop.widget loop.widget = self.overlay if loop.screen.started: loop.draw_screen() def hide(self): """Hide login window""" loop = self.app.loop loop.widget = self.overlay.bottom_w if loop.screen.started: loop.draw_screen() def login(self, user): """ Login the session, showing all content and hidding login window. """ # connect esc-esc signal to logout widget = self.overlay.bottom_w widget.orig_keypress = widget.keypress widget.keypress = self._wrapped_keypress self._last_key_time = time.time() self._timeout_sig_id = self.app.loop.set_alarm_in(self.max_time+1, self._check_logout) if hasattr(widget, 'set_user') and callable(widget.set_user): widget.set_user(user) self.hide() self._emit("login") def logout(self): """Logout the session, hidding all content and showing login window again. """ # disconnect esc-esc signal self.app.loop.widget.keypress = self.app.loop.widget.orig_keypress self.app.loop.remove_alarm(self._timeout_sig_id) self.show() self._emit("logout") def clear(self): self.username_entry.set_edit_text("") self.password_entry.set_edit_text("") self.pile.set_focus(0) def _wrapped_keypress(self, size, key): self._last_key_time = time.time() if key == 'esc': if self._out_count == 1 and (time.time() - self._evt_time) < 1: self._out_count = 0 self._evt_time = 0 self.logout() else: self._out_count = 1 self._evt_time = time.time() return None else: return self.app.loop.widget.orig_keypress(size, key) def _username_keypress(self, size, key): if key == 'enter': key = 'down' return self.username_entry.__class__.keypress(self.username_entry, size, key) def _password_keypress(self, size, key): if key == 'enter': password = self.password_entry.get_edit_text() username = self.username_entry.get_edit_text() self.password_entry.set_edit_text("") if password and username: user = self.get_user(username, password) if user: #self.username_entry.set_edit_text("") self.login(user) return return self.password_entry.__class__.keypress(self.password_entry, size, key) def _check_logout(self, main_loop, user_data=None): etime = int(time.time() - self._last_key_time) if etime >= self.max_time: self.logout() else: main_loop.remove_alarm(self._timeout_sig_id) self._timeout_sig_id = main_loop.set_alarm_in(self.max_time-etime, self._check_logout) return False
class BaseEditor(with_metaclass(signals.MetaSignals, WidgetWrap)): """Base class for editors.""" signals = ['done'] def __init__(self, prompt, content, done_signal_handler, cursor_position=None): """ Initializes editor, connects 'done' signal. When pressing 'enter' twice the `submit` method is called, which by default calls `emit_done_signal` with the text that has been introduced. When pressing 'esc' the `cancel` method is called, which by default calls `emit_done_signal` with no arguments. The subclasses must call the `_wrap` method with the editor widgets and `BaseEditor` will wrap it in a `urwid.Colums` widget, calling to `urwid.WidgetWrap.__init__` with the wrapped widget. """ caption = _(u'{0} (Enter key twice to validate, ' u'Esc or Ctrl-C to cancel) \n>> ').format(prompt) if content: content += ' ' self.content = content self.editor = Edit(caption=caption, edit_text=content, edit_pos=cursor_position) self.last_key = None connect_signal(self, 'done', done_signal_handler) def _wrap(self, widgets): widgets = widgets if isinstance(widgets, list) else [widgets] composed_widget = Columns(widgets) widget = AttrMap(LineBox(composed_widget), 'editor') super(BaseEditor, self).__init__(widget) def keypress(self, size, key): if key == 'enter' and self.last_key == 'enter': self.submit() return elif key == 'esc': self.cancel() return self.last_key = key size = size, self.editor.keypress(size, key) def submit(self): self.emit_done_signal(self.editor.get_edit_text()) def cancel(self): self.emit_done_signal() def emit_done_signal(self, content=None): emit_signal(self, 'done', content)
class BaseEditor(WidgetWrap, metaclass=signals.MetaSignals): """Base class for editors.""" signals = ['done'] def __init__(self, prompt, content, done_signal_handler, cursor_position=None): """ Initializes editor, connects 'done' signal. When pressing 'enter' twice the `submit` method is called, which by default calls `emit_done_signal` with the text that has been introduced. When pressing 'esc' the `cancel` method is called, which by default calls `emit_done_signal` with no arguments. The subclasses must call the `_wrap` method with the editor widgets and `BaseEditor` will wrap it in a `urwid.Colums` widget, calling to `urwid.WidgetWrap.__init__` with the wrapped widget. """ caption = _(u'{0} (Enter key twice to validate, ' u'Esc or Ctrl-C to cancel) \n>> ').format(prompt) if content: content += ' ' self.content = content self.editor = Edit(caption=caption, edit_text=content, edit_pos=cursor_position) self.last_key = None connect_signal(self, 'done', done_signal_handler) def _wrap(self, widgets): widgets = widgets if isinstance(widgets, list) else [widgets] composed_widget = Columns(widgets) widget = AttrMap(LineBox(composed_widget), 'editor') super(BaseEditor, self).__init__(widget) def keypress(self, size, key): if key == 'enter' and self.last_key == 'enter': self.submit() return elif key == 'esc': self.cancel() return self.last_key = key size = size, self.editor.keypress(size, key) def submit(self): self.emit_done_signal(self.editor.get_edit_text()) def cancel(self): self.emit_done_signal() def emit_done_signal(self, content=None): emit_signal(self, 'done', content)