def make_action_menu_row(cells, menu, attr_map='menu_button', focus_map='menu_button focus', cursor_x=2): row = TableRow(cells) if not isinstance(attr_map, dict): attr_map = {None: attr_map} if not isinstance(focus_map, dict): focus_map = {None: focus_map} am = AttrMap(CursorOverride(row, cursor_x=cursor_x), attr_map, focus_map) connect_signal(menu, 'open', lambda menu: am.set_attr_map(focus_map)) connect_signal(menu, 'close', lambda menu: am.set_attr_map(attr_map)) return am
def add_menu_row_focus_behaviour(menu, row, attr_map, focus_map, cursor_x=0): """Configure focus behaviour of row (which contains menu) The desired behaviour is that: 1) The cursor appears at the left of the row rather than where the menu is. 2) The row is highlighted when focused and retains that focus even when the popup is open. """ if not isinstance(attr_map, dict): attr_map = {None: attr_map} if not isinstance(focus_map, dict): focus_map = {None: focus_map} am = AttrMap(CursorOverride(row, cursor_x=cursor_x), attr_map, focus_map) connect_signal(menu, 'open', lambda menu: am.set_attr_map(focus_map)) connect_signal(menu, 'close', lambda menu: am.set_attr_map(attr_map)) return am
class TaskTag(urwid.PopUpLauncher): signals = ['delete'] size = None def __init__(self, tag_index, tag_text, new=False): self.new_tag = new op_char = tag_text[0] if op_char == 'o': self.strikethrough = False elif op_char == 'x': self.strikethrough = True tag_text = tag_text.lstrip(op_char) self.tag_index = tag_index self.tag_text = tag_text # Default color specs self.index_attr = AttrSpec('h11', '') self.index_STRIKE = AttrSpec('h11, strikethrough', '') self.text_attr = AttrSpec('', '') self.text_STRIKE = AttrSpec(', strikethrough', '') self.focus_attr = AttrSpec(', bold', '') self.focus_STRIKE = AttrSpec(', bold, strikethrough', '') # Build widget stack self.edit = Edit( caption=self.build_caption(), edit_text=self.tag_text, multiline=False, wrap ='clip') if not self.strikethrough: self.tag_map = AttrMap( self.edit, attr_map=self.text_attr, focus_map=self.focus_attr) else: self.tag_map = AttrMap( self.edit, attr_map=self.text_STRIKE, focus_map=self.focus_STRIKE) self.tag_fill = Filler(self.tag_map, 'top') super().__init__(self.tag_map) def build_caption(self, expan=False): trailing_space = ' ' if not expan else '*' caption_tag = '' if not self.strikethrough: caption_tag = str(self.tag_index) else: caption_tag = 'X' leading_space = ' ' if len(caption_tag) < 2 else '' if not self.strikethrough: caption = (self.index_attr, leading_space + caption_tag + trailing_space) else: caption = (self.index_STRIKE, leading_space + caption_tag + trailing_space) return caption def get_text(self): return self.edit.edit_text def move_cursor(self, translation): self.edit.edit_pos += translation def prompt_delete(self): self.open_pop_up() def toggle_strike(self): if self.strikethrough: self.strikethrough = False caption = self.build_caption() self.edit.set_caption(caption) self.tag_map.set_attr_map({None: self.text_attr}) self.tag_map.set_focus_map({None: self.focus_attr}) else: self.strikethrough = True caption = self.build_caption() self.edit.set_caption(caption) self.tag_map.set_attr_map({None: self.text_STRIKE}) self.tag_map.set_focus_map({None: self.focus_STRIKE}) def create_pop_up(self): prompt = ConfPrompt('line') urwid.connect_signal(prompt, 'close', self.confirm_delete) return prompt def confirm_delete(self, obj): response = obj.response if response == 'yes': self.close_pop_up() self._emit('delete') else: self.close_pop_up() def get_pop_up_parameters(self): width = len(self.edit.text)-3 if len(self.edit.text)-3 > 21 else 21 if width > self.size[0]-3: width = self.size[0]-3 return {'left': 3, 'top': 1, 'overlay_width': width, 'overlay_height': 1} def keypress(self, size, key): if self.new_tag: if self.edit.valid_char(key) or key == 'backspace': self.edit.set_edit_text('') self.new_tag = False super().keypress(size, key) def render(self, size, focus=False): self.size = size return super().render(size, focus)
class _Expan(urwid.PopUpLauncher): signals = ['delete'] 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 toggle_strike(self): if self.strikethrough: self.strikethrough = False attr = self.text_attr attr_focus = self.focus_attr self.map.set_attr_map({None: attr}) self.map.set_focus_map({None: attr_focus}) self.edit.set_caption(self.leading_space + self.leading_char) else: self.strikethrough = True caption = self.leading_space + self.leading_STRIKE attr = self.text_STRIKE attr_focus = self.focus_STRIKE self.map.set_attr_map({None: attr}) self.map.set_focus_map({None: attr_focus}) self.edit.set_caption(self.leading_space + self.leading_STRIKE) def create_pop_up(self): prompt = ConfPrompt('line') urwid.connect_signal(prompt, 'close', self.confirm_delete) return prompt def confirm_delete(self, obj): response = obj.response if response == 'yes': self.close_pop_up() self._emit('delete') else: self.close_pop_up() def get_pop_up_parameters(self): width = len(self.edit.text)-5 if len(self.edit.text)-5 > 21 else 21 return {'left': 5, 'top': 1, 'overlay_width': width, 'overlay_height': 1} def keypress(self, size, key): if self.new_expan: if self.edit.valid_char(key) or key == 'backspace': self.edit.set_edit_text('') self.new_expan= False super().keypress(size, key)