def build_unselected_widgets(self): cdict = juju.constraints_to_dict(self.md.get('constraints', '')) self.juju_machine_id_button = MenuSelectButton( '{:20s}'.format(self.juju_machine_id), self.show_pin_chooser) self.juju_machine_id_label = Text("{:20s}".format( self.juju_machine_id)) self.cores_field = IntEdit('', str(cdict.get('cores', ''))) connect_signal(self.cores_field, 'change', self.handle_cores_changed) memval = cdict.get('mem', '') if memval != '': memval = memval / 1024 self.mem_field = Edit('', str(memval)) connect_signal(self.mem_field, 'change', self.handle_mem_changed) diskval = cdict.get('root-disk', '') if diskval != '': diskval = diskval / 1024 self.disk_field = Edit('', str(diskval)) connect_signal(self.disk_field, 'change', self.handle_disk_changed) if self.show_pin: machine_id_w = self.juju_machine_id_button else: machine_id_w = self.juju_machine_id_label cols = [ machine_id_w, self.cores_field, self.mem_field, self.disk_field ] cols = [AttrMap(w, 'string_input', 'string_input_focus') for w in cols] cols.append(Text("placeholder")) self.unselected_columns = Columns(cols, dividechars=2) self.update_assignments() return self.unselected_columns
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)
def __init__(self): grading_directory = LineBox( Edit(("header", "Grading directory\n\n"), state.grading_directory)) subdirectories = LineBox( Edit(("header", "Subdirectories\n\n"), state.subdirectories)) assignment_type = RadioGroup("Assignment type", AssignmentType, state.assignment_type) deadline = LineBox(Edit(("header", "Deadline\n\n"), state.deadline)) assignment_sname = LineBox( Edit(("header", "Assignment short name\n\n"), state.assignment_sname)) assignment_lname = LineBox( Edit(("header", "Assignment long name\n\n"), state.assignment_lname)) grid_elements = [ { "grading_directory": grading_directory, "subdirectories": subdirectories }, { "assignment_type": assignment_type, "deadline": deadline }, { "assignment_sname": assignment_sname, "assignment_lname": assignment_lname }, ] super().__init__("Grade", grid_elements, grade)
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)
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)
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()
def __init__(self): # self.caption = AttrMap( # Text( # ('caption', self.caption_text), align='center' # ), # 'blackongrey' # ) self.caption = Text(('caption', self.caption_text), align='center') self.inputbox_a = Padding(AttrMap( Edit(multiline=False, mask=self.mask), 'inputfield'), align='center', width=24) self.divider = Padding(Divider(' '), align='center') self.inputbox_b = Padding(AttrMap( Edit(multiline=False, mask=self.mask), 'inputfield'), align='center', width=24) self.innerbox = AttrMap( LineBox(Pile([self.inputbox_a, self.divider, self.inputbox_b])), 'blackongrey') # scratchpad = Text('<enter>') self.button = Button('OK', on_press=self._ok_button) self.button_wrap = Padding(AttrMap(self.button, 'button.normal', 'button.focus'), align='center', width=15)
def __init__(self): sender = LineBox( Edit(("header", "Sender email\n\n"), state.sender_email)) recipient = LineBox( Edit(("header", "Recipient email\n\n"), state.recipient_email)) grading_directory = LineBox( Edit(("header", "Grading directory\n\n"), state.grading_directory)) subject = LineBox(Edit(("header", "Subject\n\n"), state.subject)) message = LineBox( Edit(("header", "Message\n\n"), state.message, multiline=True)) grid_elements = [ { "sender_email": sender, "recipient_email": recipient }, { "grading_directory": grading_directory, "subject": subject }, { "message": message }, ] super().__init__("Mail", grid_elements, mail)
def __init__(self, edit_text, strike=False, new=False): self.strikethrough = strike self.new_expan = new # Spacing strings self.leading_space = ' ' self.leading_char = '- ' self.leading_STRIKE = 'x ' # Default color specs self.text_attr = AttrSpec('h6', '') self.text_STRIKE = AttrSpec('h6, strikethrough', '') self.focus_attr = AttrSpec('h6, bold', '') self.focus_STRIKE = AttrSpec('h6, bold, strikethrough', '') if not self.strikethrough: caption = self.leading_space + self.leading_char attr = self.text_attr attr_focus = self.focus_attr else: caption = self.leading_space + self.leading_STRIKE attr = self.text_STRIKE attr_focus = self.focus_STRIKE self.edit = Edit(caption, edit_text, wrap='clip') self.map = AttrMap(self.edit, attr_map=attr, focus_map=attr_focus) self.fill = Filler(self.map) super().__init__(self.map)
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 build_unselected_widgets(self): cdict = juju.constraints_to_dict(self.md.get('constraints', '')) label = str(self.juju_machine_id) self.juju_machine_id_button = SecondaryButton(label, self.show_pin_chooser) self.juju_machine_id_label = Text(label) self.cores_field = IntEdit('', str(cdict.get('cores', ''))) connect_signal(self.cores_field, 'change', self.handle_cores_changed) memval = cdict.get('mem', '') if memval != '': memval = self._format_constraint(memval) / 1024 self.mem_field = Edit('', str(memval)) connect_signal(self.mem_field, 'change', self.handle_mem_changed) diskval = cdict.get('root-disk', '') if diskval != '': diskval = self._format_constraint(diskval) / 1024 self.disk_field = Edit('', str(diskval)) connect_signal(self.disk_field, 'change', self.handle_disk_changed) if self.show_pin: machine_id_w = self.juju_machine_id_button else: machine_id_w = self.juju_machine_id_label cols = [machine_id_w] for field in (self.cores_field, self.mem_field, self.disk_field): cols.append(AttrMap(field, 'string_input', 'string_input_focus')) cols.append(Text("placeholder")) self.unselected_columns = Columns(cols, dividechars=2) self.update_assignments() return self.unselected_columns
class FilterBox(WidgetWrap): def __init__(self, edit_changed_cb, label="", info_text=""): self.label = Text(label) self.info_text = Text(info_text) self.editbox = Edit(caption=('text', "Filter: ")) connect_signal(self.editbox, 'change', edit_changed_cb) w = Pile([Columns([AttrMap(self.editbox, 'filter', 'filter_focus')]) # self.info_text # -- WORKAROUND for issue #194 ]) super().__init__(w) def set_info(self, n_showing, n_total): m = ["Filter ", ('label', "({} of {} shown): ".format(n_showing, n_total))] self.editbox.set_caption(m) if False: # WORKAROUND for issue #194 t = '' else: t = ('label', " Filter on hostname or hardware info like 'cores:4'") self.info_text.set_text(t)
class FilterBox(ContainerWidgetWrap): def __init__(self, edit_changed_cb, label="", info_text=""): self.label = Text(label) self.info_text = Text(info_text) self.editbox = Edit(caption=('text', "Filter: ")) connect_signal(self.editbox, 'change', edit_changed_cb) w = Pile([ Columns( [AttrMap(self.editbox, 'string_input', 'string_input_focus')]) # self.info_text # -- WORKAROUND for issue #194 ]) super().__init__(w) def set_info(self, n_showing, n_total): m = [ "Filter ", ('label', "({} of {} shown): ".format(n_showing, n_total)) ] self.editbox.set_caption(m) if False: # WORKAROUND for issue #194 t = '' else: t = ('label', " Filter on hostname or hardware info like 'cores:4'") self.info_text.set_text(t)
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)
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)
def __init__(self, choice_callback=None, command_callback=None, help_callback=None): self.palette = [ ('brick', 'light red', 'black'), ('rubble', 'yellow', 'black'), ('wood', 'light green', 'black'), ('concrete', 'white', 'black'), ('stone', 'light cyan', 'black'), ('marble', 'light magenta', 'black'), ('jack', 'dark gray', 'white'), ('msg_info', 'white', 'black'), ('msg_err', 'light red', 'black'), ('msg_debug', 'light green', 'black'), ] self.choice_callback = choice_callback self.command_callback = command_callback self.help_callback = help_callback self.screen = None self.loop = None self.called_loop_stop = False self.reactor_stop_fired = False self.quit_flag = False self.edit_msg = "Make selection ('q' to quit): " self.roll_list = SimpleListWalker([]) self.game_log_list = SimpleListWalker([]) self.choices_list = SimpleListWalker([]) self.state_text = SimpleListWalker([Text('Connecting...')]) self.edit_widget = Edit(self.edit_msg) self.roll = ListBox(self.roll_list) self.game_log = ListBox(self.game_log_list) self.choices = ListBox(self.choices_list) self.state = ListBox(self.state_text) self.left_frame = Pile([ LineBox(self.state), (13, LineBox(self.choices)), ]) self.right_frame = Pile([LineBox(self.game_log), LineBox(self.roll)]) self.state.set_focus(len(self.state_text) - 1) self.columns = Columns([('weight', 0.75, self.left_frame), ('weight', 0.25, self.right_frame)]) self.frame_widget = Frame(footer=self.edit_widget, body=self.columns, focus_part='footer') self.exc_info = None
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), ])
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)
def __init__(self, edit_changed_cb, label="", info_text=""): self.label = Text(label) self.info_text = Text(info_text) self.editbox = Edit(caption=('text', "Filter: ")) connect_signal(self.editbox, 'change', edit_changed_cb) w = Pile([ Columns([AttrMap(self.editbox, 'filter', 'filter_focus')]) # self.info_text # -- WORKAROUND for issue #194 ]) super().__init__(w)
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 __init__(self, submit_cb, back_cb, error=None): self.submit_cb = submit_cb self.prev_screen = back_cb self.error = error self.email = Edit() self.password = Edit(mask='*') self.twofa = Edit() # can't use IntEdit because it precludes leading zeros self.twofa.valid_char = lambda ch: ch in '0123456789' super().__init__()
def _build_fields(self): self.email = Edit() self.password = Edit(mask='*') self.twofa = Edit() # can't use IntEdit because it precludes leading zeros self.twofa.valid_char = lambda ch: ch in '0123456789' return Pile([ Color.string_input(self.email), Padding.line_break(""), Color.string_input(self.password), Padding.line_break(""), Color.string_input(self.twofa) ])
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)
def __init__(self): grading_directory = LineBox( Edit(("header", "Grading directory\n\n"), state.grading_directory)) assignment_sname = LineBox( Edit(("header", "Assignment short name\n\n"), state.assignment_sname)) grid_elements = [ { "grading_directory": grading_directory, "assignment_sname": assignment_sname }, ] super().__init__("Push", grid_elements, push)
def __init__(self): grading_directory = LineBox(Edit(("header", "Grading directory\n\n"), state.grading_directory)) grader_name = LineBox(Edit(("header", "Grader's name\n\n"), state.grader_name)) group_number = LineBox(IntEdit(("header", "Group number\n\n"), state.group_number)) team_type = RadioGroup("Team type", TeamType, state.team_type) username = LineBox(Edit(("header", "Username\n\n"), "")) password = LineBox(Edit(("header", "Password\n\n"), "", mask="*")) grid_elements = [ {"grading_directory": grading_directory, "grader_name": grader_name}, {"group_number": group_number, "team_type": team_type}, {"username": username, "password": password}, ] super().__init__("Clone", grid_elements, clone)
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 __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)
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()
def __init__(self, choice_callback=None, command_callback=None, help_callback=None): self.palette = [ ('brick', 'light red', 'black'), ('rubble', 'yellow', 'black'), ('wood', 'light green', 'black'), ('concrete', 'white', 'black'), ('stone', 'light cyan', 'black'), ('marble', 'light magenta', 'black'), ('jack', 'dark gray', 'white'), ('msg_info', 'white', 'black'), ('msg_err', 'light red', 'black'), ('msg_debug', 'light green', 'black'), ] self.choice_callback = choice_callback self.command_callback = command_callback self.help_callback = help_callback self.screen = None self.loop = None self.called_loop_stop = False self.reactor_stop_fired = False self.quit_flag = False self.edit_msg = "Make selection ('q' to quit): " self.roll_list = SimpleListWalker([]) self.game_log_list = SimpleListWalker([]) self.choices_list = SimpleListWalker([]) self.state_text = SimpleListWalker([Text('Connecting...')]) self.edit_widget = Edit(self.edit_msg) self.roll = ListBox(self.roll_list) self.game_log = ListBox(self.game_log_list) self.choices = ListBox(self.choices_list) self.state = ListBox(self.state_text) self.left_frame = Pile([ LineBox(self.state), (13, LineBox(self.choices)), ]) self.right_frame = Pile([ LineBox(self.game_log), LineBox(self.roll) ]) self.state.set_focus(len(self.state_text)-1) self.columns = Columns([('weight', 0.75, self.left_frame), ('weight', 0.25, self.right_frame) ]) self.frame_widget = Frame(footer=self.edit_widget, body=self.columns, focus_part='footer') self.exc_info = None
def get_widget(self): if isinstance(self.value, str): return AttrMap(Edit('', self.value), 'editable') elif isinstance(self.value, bool): return CheckBox('', self.value) else: return Text("Unknown field for {}".format(str(type(self.value))))
def keypress(self, size, key): """ Handle editing keystrokes. Remove leading zeros. >>> e, size = NumEdit("0123456789", u"", "5002"), (10,) >>> e.keypress(size, 'home') >>> e.keypress(size, 'delete') >>> assert e.edit_text == "002" >>> e.keypress(size, 'end') >>> assert e.edit_text == "2" >>> # binary only >>> e, size = NumEdit("01", u"", ""), (10,) >>> assert e.edit_text == "" >>> e.keypress(size, '1') >>> e.keypress(size, '0') >>> e.keypress(size, '1') >>> assert e.edit_text == "101" """ (maxcol, ) = size unhandled = Edit.keypress(self, (maxcol, ), key) if not unhandled: if self.trimLeadingZeros: # trim leading zeros while self.edit_pos > 0 and self.edit_text[:1] == "0": self.set_edit_pos(self.edit_pos - 1) self.set_edit_text(self.edit_text[1:]) return unhandled
def build_widgets(self): self.editbox = Edit(caption=('text', "Search Charm Store: ")) connect_signal(self.editbox, 'change', self.handle_edit_changed) return Padding(AttrMap(self.editbox, 'filter', 'filter_focus'), left=2, right=2)
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)
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)
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)
def editable(self, yes): if self._editable == yes: return self._editable = yes if yes: self._content = Edit(caption="tags:", edit_text=self._content.get_text()[0]) self._update() self._root.focus_position = 1 else: self._content = Text(self._content.get_edit_text()) self._update()
def __init__(self, edit_changed_cb, label="", info_text=""): self.label = Text(label) self.info_text = Text(info_text) self.editbox = Edit(caption=('text', "Filter: ")) connect_signal(self.editbox, 'change', edit_changed_cb) w = Pile([Columns([AttrMap(self.editbox, 'filter', 'filter_focus')]) # self.info_text # -- WORKAROUND for issue #194 ]) super().__init__(w)
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)
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()
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 keypress(self, size, key): if key == 'enter': self._top[1]() self._done(self.get_edit_text()) elif key == 'esc': self._top[1]() elif key == 'tab' and self._tab: text = self.get_edit_text()[:self.edit_pos] text_len = len(text) match = None for entry in self._tab(text): if entry.startswith(text): entry = entry[text_len:] if match is None: match = entry else: while not entry.startswith(match): match = match[:-1] if match: self.insert_text(match) else: return Edit.keypress(self, size, key)
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 move_cursor_to_coords(self, size, x, y): if self._end: x = "right" self._end = False return Edit.move_cursor_to_coords(self, size, x, y)
def __init__(self, caption, **kwargs): self._edit = Edit(caption=caption, **kwargs) super().__init__(Color.string_input(self._edit, focus_map="string_input focus"))
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 CursesGUI(object): def __init__(self, choice_callback=None, command_callback=None, help_callback=None): self.palette = [ ('brick', 'light red', 'black'), ('rubble', 'yellow', 'black'), ('wood', 'light green', 'black'), ('concrete', 'white', 'black'), ('stone', 'light cyan', 'black'), ('marble', 'light magenta', 'black'), ('jack', 'dark gray', 'white'), ('msg_info', 'white', 'black'), ('msg_err', 'light red', 'black'), ('msg_debug', 'light green', 'black'), ] self.choice_callback = choice_callback self.command_callback = command_callback self.help_callback = help_callback self.screen = None self.loop = None self.called_loop_stop = False self.reactor_stop_fired = False self.quit_flag = False self.edit_msg = "Make selection ('q' to quit): " self.roll_list = SimpleListWalker([]) self.game_log_list = SimpleListWalker([]) self.choices_list = SimpleListWalker([]) self.state_text = SimpleListWalker([Text('Connecting...')]) self.edit_widget = Edit(self.edit_msg) self.roll = ListBox(self.roll_list) self.game_log = ListBox(self.game_log_list) self.choices = ListBox(self.choices_list) self.state = ListBox(self.state_text) self.left_frame = Pile([ LineBox(self.state), (13, LineBox(self.choices)), ]) self.right_frame = Pile([ LineBox(self.game_log), LineBox(self.roll) ]) self.state.set_focus(len(self.state_text)-1) self.columns = Columns([('weight', 0.75, self.left_frame), ('weight', 0.25, self.right_frame) ]) self.frame_widget = Frame(footer=self.edit_widget, body=self.columns, focus_part='footer') self.exc_info = None def register_loggers(self): """Gets the global loggers and sets up log handlers. """ self.game_logger_handler = RollLogHandler(self._roll_write) self.logger_handler = RollLogHandler(self._roll_write) self.game_logger = logging.getLogger('gtr.game') self.logger = logging.getLogger('gtr') self.logger.addHandler(self.logger_handler) self.game_logger.addHandler(self.game_logger_handler) #self.set_log_level(logging.INFO) def unregister_loggers(self): self.game_logger.removeHandler(self.game_logger_handler) self.logger.removeHandler(self.logger_handler) def fail_safely(f): """Wraps functions in this class to catch arbitrary exceptions, shut down the event loop and reset the terminal to a normal state. It then re-raises the exception. """ @wraps(f) def wrapper(self, *args, **kwargs): retval = None try: retval = f(self, *args, **kwargs) except urwid.ExitMainLoop: from twisted.internet import reactor if not self.reactor_stop_fired and reactor.running: # Make sure to call reactor.stop once reactor.stop() self.reactor_stop_fired = True except: #pdb.set_trace() from twisted.internet import reactor if not self.reactor_stop_fired and reactor.running: # Make sure to call reactor.stop once reactor.stop() self.reactor_stop_fired = True if not self.called_loop_stop: self.called_loop_stop = True self.loop.stop() # Save exception info for printing later outside the GUI. self.exc_info = sys.exc_info() raise return retval return wrapper def set_log_level(self, level): """Set the log level as per the standard library logging module. Default is logging.INFO. """ logging.getLogger('gtr.game').setLevel(level) logging.getLogger('gtr').setLevel(level) def run(self): loop = MainLoop(self.frame_widget, unhandled_input=self.handle_input) loop.run() def run_twisted(self): from twisted.internet import reactor evloop = urwid.TwistedEventLoop(reactor, manage_reactor=False) self.screen = urwid.raw_display.Screen() self.screen.register_palette(self.palette) self.loop = MainLoop(self.frame_widget, unhandled_input=self.handle_input, screen = self.screen, event_loop = evloop) self.loop.set_alarm_in(0.1, lambda loop, _: loop.draw_screen()) self.loop.start() # The loggers get a Handler that writes to the screen. We want this to only # happen if the screen exists, so de-register them after the reactor stops. reactor.addSystemEventTrigger('after','startup', self.register_loggers) reactor.addSystemEventTrigger('before','shutdown', self.unregister_loggers) reactor.run() # We might have stopped the screen already, and the stop() method # doesn't check for stopping twice. if self.called_loop_stop: self.logger.warn('Internal error!') else: self.loop.stop() self.called_loop_stop = True @fail_safely def handle_input(self, key): if key == 'enter': text = self.edit_widget.edit_text if text in ['q', 'Q']: self.handle_quit_request() else: self.quit_flag = False try: i = int(text) except ValueError: i = None self.handle_invalid_choice(text) if i is not None: self.handle_choice(i) self.edit_widget.set_edit_text('') def _roll_write(self, line, attr=None): """Add a line to the roll with palette attributes 'attr'. If no attr is specified, None is used. Default attr is plain text """ text = Text((attr, '* ' + line)) self.roll_list.append(text) self.roll_list.set_focus(len(self.roll_list)-1) self._modified() @fail_safely def update_state(self, state): """Sets the game state window via one large string. """ self.logger.debug('Drawing game state.') self.state_text[:] = [self.colorize(s) for s in state.split('\n')] self._modified() @fail_safely def update_game_log(self, log): """Sets the game log window via one large string. """ self.logger.debug('Drawing game log.') self.game_log_list[:] = [self.colorize(s) for s in log.split('\n')] self.game_log_list.set_focus(len(self.game_log_list)-1) self._modified() @fail_safely def update_choices(self, choices): """Update choices list. """ self.choices_list[:] = [self.colorize(str(c)) for c in choices] self._modified() length = len([c for c in choices if c[2] == '[']) i = randint(1,length) if length else 0 self.choices_list.append(self.colorize('\nPicking random choice: {0} in 1s'.format(i))) self._modified() #from twisted.internet import reactor #reactor.callLater(1, self.handle_choice, i) @fail_safely def update_prompt(self, prompt): """Set the prompt for the input field. """ self.edit_widget.set_caption(prompt) self._modified() def _modified(self): if self.loop: self.loop.draw_screen() @fail_safely def quit(self): """Quit the program. """ #import pdb; pdb.set_trace() #raise TypeError('Artificial TypeError') raise urwid.ExitMainLoop() def handle_invalid_choice(self, s): if len(s): text = 'Invalid choice: "' + s + '". Please enter an integer.' self.logger.warn(text) def handle_quit_request(self): if True or self.quit_flag: self.quit() else: self.quit_flag = True text = 'Are you sure you want to quit? Press Q again to confirm.' self.logger.warn(text) def handle_choice(self, i): if self.choice_callback: self.choice_callback(i) def colorize(self, s): """Applies color to roles found in a string. A string with attributes applied looks like Text([('attr1', 'some text'), 'some more text']) so we need to split into a list of tuples of text. """ regex_color_dict = { r'\b([Ll]egionaries|[Ll]egionary|[Ll]eg|LEGIONARIES|LEGIONARY|LEG)\b' : 'brick', r'\b([Ll]aborers?|[Ll]ab|LABORERS?|LAB)\b' : 'rubble', r'\b([Cc]raftsmen|[Cc]raftsman|[Cc]ra|CRAFTSMEN|CRAFTSMAN|CRA)\b' : 'wood', r'\b([Aa]rchitects?|[Aa]rc|ARCHITECTS?|ARC)\b' : 'concrete', r'\b([Mm]erchants?|[Mm]er|MERCHANTS?|MER)\b' : 'stone', r'\b([Pp]atrons?|[Pp]at|PATRONS?|PAT)\b' : 'marble', r'\b([Jj]acks?|JACKS?)\b' : 'jack', r'\b([Bb]ricks?|[Bb]ri|BRICKS?|BRI)\b' : 'brick', r'\b([Rr]ubble|[Rr]ub|RUBBLE|RUB)\b' : 'rubble', r'\b([Ww]ood|[Ww]oo|WOOD|WOO)\b' : 'wood', r'\b([Cc]oncrete|[Cc]on|CONCRETE|CON)\b' : 'concrete', r'\b([Ss]tone|[Ss]to|STONE|STO)\b' : 'stone', r'\b([Mm]arble|[Mm]ar|MARBLE|MAR)\b' : 'marble', } def _colorize(s, regex, attr): """s is a tuple of ('attr', 'text'). This splits based on the regex and adds attr to any matches. Returns a list of tuples [('attr1', 'text1'), ('attr2', 'text2'), ('attr3','text3')] with some attributes being None if they aren't colored. """ output = [] a, t = s # Make a list of all tokens, split by matches tokens = re.split(regex, t) for tok in tokens: m = re.match(regex, tok) if m: # matches get the new attributes output.append( (attr,tok) ) else: # non-matches keep the old ones output.append( (a, tok) ) return output output = [ (None, s) ] for k,v in regex_color_dict.items(): new_output = [] for token in output: new_output.extend(_colorize(token, k, v)) output[:] = new_output return Text(output)
def __init__(self, enter, leave): self._top = enter, leave Edit.__init__(self)
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)
def __init__(self, caption, **kwargs): self._edit = Edit(caption=caption, **kwargs) super().__init__(self._edit)
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)))