Beispiel #1
0
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)
Beispiel #2
0
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)
Beispiel #3
0
class TList(urwid.WidgetWrap):
    def __init__(self, list_data=None):

        self.is_editing = False
        self.tasks = []
        self.name = None
        self.group = None
        self.id = None

        if list_data:
            # Parse the data.
            self.parse_data(list_data)
        else:
            # Must be a new list
            self.name = 'untitled'
            self.group = 'none'
            self.id = uuid.uuid4().hex

        # AttrSpecs
        self.attr_spec = AttrSpec('', '')
        self.focus_nav = AttrSpec('h12', '')
        self.focus_ins = AttrSpec('h160', '')

        # Build widget stack
        self.title = TitleBar(self.name)
        self.group_foot = GroupFoot(self.group)
        self.body = urwid.SimpleFocusListWalker(self.tasks)
        self.list_box = ListBox(self.body)
        self.list_frame = Frame(self.list_box,
                                header=self.title,
                                footer=self.group_foot)
        self.line_box = LineBox(self.list_frame)
        self.line_attr = AttrMap(self.line_box, self.attr_spec, self.focus_nav)
        super().__init__(self.line_attr)

    def parse_data(self, list_data):
        self.name = list_data['name']
        self.group = list_data['group']
        self.id = list_data['id']
        task_data = list_data['tasks']

        index = 1
        for task_dict in task_data:
            task = Task(index, task_dict)
            urwid.connect_signal(task, 'delete', self.delete)
            index += 1
            self.tasks.append(task)

    def delete(self, obj):
        self.tasks.remove(obj)
        self.body.remove(obj)
        self.index_tasks()

    def move_task(self, trans):
        # FIX INDEX ERROR WHEN TRYING TO MOVE TO FAR DOWN OR UP
        focus_task = self.list_box.focus
        task_index = focus_task.tag.tag_index
        new_index = task_index + trans - 1
        self.delete(focus_task)
        if new_index < 0: new_index = 0
        elif new_index > len(self.tasks): new_index = len(self.tasks)
        self.tasks.insert(new_index, focus_task)
        self.body.insert(new_index, focus_task)
        self.list_box.focus_position = new_index
        self.index_tasks()

    def set_edit(self, editing):
        if editing:
            self.is_editing = True
            self.line_attr.set_focus_map({None: self.focus_ins})
        else:
            self.is_editing = False
            self.line_attr.set_focus_map({None: self.focus_nav})

    def export(self):
        data = {
            'name': self.title.get_title(),
            'group': self.group_foot.get_group(),
            'id': self.id,
            'tasks': []
        }
        for task in self.tasks:
            task_dict = {}
            task_dict['id'] = task.id
            if task.tag.strikethrough:
                task_dict['tag'] = 'x' + task.tag.get_text()
            else:
                task_dict['tag'] = 'o' + task.tag.get_text()
            task_dict['expan'] = task.expan.get_lines()
            data['tasks'].append(task_dict)

        return data

    def keypress(self, size, key):
        if not self.is_editing:
            return self.nav_keypress(size, key)
        else:
            return self.input_keypress(size, key)

    def nav_keypress(self, size, key):
        if key == 'i':
            self.set_edit(True)
        # Move focus up/down
        elif key == 'j':
            self.move_focus(1)
        elif key == 'k':
            self.move_focus(-1)
        # Move cursor left/right
        elif key == 'J':
            self.move_task(1)
        elif key == 'K':
            self.move_task(-1)
        elif key == 'h':
            try:
                self.list_box.focus.move_cursor(-1)
            except AttributeError:
                pass
        elif key == 'l':
            try:
                self.list_box.focus.move_cursor(1)
            except AttributeError:
                pass
        # Open/close expan list
        elif key == 'e':
            try:
                self.list_box.focus.toggle_expan()
            except AttributeError:
                pass
        elif key == 'E':
            try:
                if not self.list_box.focus.show_expan:
                    for task in self.tasks:
                        task.open_expan()
                else:
                    for task in self.tasks:
                        task.close_expan()
            except AttributeError:
                pass
        # Cross out a line
        elif key == 'x':
            try:
                self.list_box.focus.toggle_strike()
            except AttributeError:
                pass
        elif key == 'n':
            self.title.edit()
        elif key == 'g':
            self.group_foot.edit()
        elif key == 'D':
            if self.list_box.focus:
                self.list_box.focus.prompt_delete()
        elif key == 't':
            new_task = Task()
            urwid.connect_signal(new_task, 'delete', self.delete)
            if self.list_box.focus:
                self.tasks.insert(self.list_box.focus_position + 1, new_task)
                self.body.insert(self.list_box.focus_position + 1, new_task)
                self.list_box.focus_position += 1
            else:
                self.tasks.append(new_task)
                self.body.append(new_task)
            self.index_tasks()
            self.set_edit(True)
        elif key == 'T':
            if self.list_box.focus:
                focus = self.list_box.focus
                focus.new()
                self.set_edit(True)
        else:
            return key

    def input_keypress(self, size, key):
        if (key == 'esc' or key == 'enter'):
            self.set_edit(False)
            if self.list_frame.focus_position != 'body':
                self.name = self.title.edit.edit_text
                self.group = self.group_foot.edit.edit_text
                self.list_frame.focus_position = 'body'
        else:
            return super().keypress(size, key)

    def get_focus(self):
        task = self.list_box.focus
        return task

    def move_focus(self, trans):
        focus_task = self.list_box.focus
        if focus_task:
            sub_focus = focus_task.pile.focus
            if sub_focus == focus_task.expan:
                try:
                    sub_focus.expan_pile.focus_position += trans
                except IndexError:
                    try:
                        focus_task.pile.focus_position += trans
                    except IndexError:
                        try:
                            self.list_box.focus_position += trans
                        except IndexError:
                            pass
            else:
                try:
                    focus_task.pile.focus_position += trans
                except IndexError:
                    try:
                        self.list_box.focus_position += trans
                    except IndexError:
                        pass

    def index_tasks(self):
        index = 1
        for task in self.body:
            task.tag.tag_index = index
            task.tag.edit.set_caption(task.tag.build_caption())
            index += 1