Commit b7a99d42 authored by Jacek Sowiński's avatar Jacek Sowiński

Add widget showing current keystate

It's purpose is to show entered keystrokes during entering key-combos.
It's positioned at the bottom-right corner (similarly as in vim). Many
thanks to @bram85 for the idea.

Also fixed one nasty bug resulting in getting stuck in keystate. It
occured only when keystate had also corresponding pending action and
user typed something other than expected by the keypress(). Now any
non-sensical input will result in resetting keystate.
parent ed719b62
# Topydo - A todo.txt client written in Python.
# Copyright (C) 2015 Bram Schoenmakers <me@bramschoenmakers.nl>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import urwid
class KeystateWidget(urwid.Text):
def __init__(self):
super().__init__('', align='right')
def selectable(self):
return False
...@@ -22,6 +22,7 @@ from topydo.cli.CLIApplicationBase import CLIApplicationBase ...@@ -22,6 +22,7 @@ from topydo.cli.CLIApplicationBase import CLIApplicationBase
from topydo.Commands import get_subcommand from topydo.Commands import get_subcommand
from topydo.ui.CommandLineWidget import CommandLineWidget from topydo.ui.CommandLineWidget import CommandLineWidget
from topydo.ui.ConsoleWidget import ConsoleWidget from topydo.ui.ConsoleWidget import ConsoleWidget
from topydo.ui.KeystateWidget import KeystateWidget
from topydo.ui.TodoListWidget import TodoListWidget from topydo.ui.TodoListWidget import TodoListWidget
from topydo.ui.ViewWidget import ViewWidget from topydo.ui.ViewWidget import ViewWidget
from topydo.ui.ColumnLayout import columns from topydo.ui.ColumnLayout import columns
...@@ -35,6 +36,7 @@ from topydo.lib import TodoList ...@@ -35,6 +36,7 @@ from topydo.lib import TodoList
COLUMN_WIDTH = 40 COLUMN_WIDTH = 40
class UIView(View): class UIView(View):
""" """
A subclass of view holding user input data that constructed the view (i.e. A subclass of view holding user input data that constructed the view (i.e.
...@@ -49,6 +51,7 @@ _EDIT_COLUMN = 2 ...@@ -49,6 +51,7 @@ _EDIT_COLUMN = 2
_COPY_COLUMN = 3 _COPY_COLUMN = 3
_INSERT_COLUMN = 4 _INSERT_COLUMN = 4
class MainPile(urwid.Pile): class MainPile(urwid.Pile):
""" """
This subclass of Pile doesn't change focus on cursor up/down / mouse press This subclass of Pile doesn't change focus on cursor up/down / mouse press
...@@ -80,6 +83,7 @@ class MainPile(urwid.Pile): ...@@ -80,6 +83,7 @@ class MainPile(urwid.Pile):
if self._command_map[key] not in ('cursor up', 'cursor down'): if self._command_map[key] not in ('cursor up', 'cursor down'):
return key return key
class UIApplication(CLIApplicationBase): class UIApplication(CLIApplicationBase):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
...@@ -91,6 +95,10 @@ class UIApplication(CLIApplicationBase): ...@@ -91,6 +95,10 @@ class UIApplication(CLIApplicationBase):
self.columns = urwid.Columns([], dividechars=0, min_width=COLUMN_WIDTH) self.columns = urwid.Columns([], dividechars=0, min_width=COLUMN_WIDTH)
self.commandline = CommandLineWidget('topydo> ') self.commandline = CommandLineWidget('topydo> ')
self.keystate_widget = KeystateWidget()
self.status_line = urwid.Columns([
('weight', 1, urwid.Filler(self.commandline)),
])
self.keymap = config().column_keymap() self.keymap = config().column_keymap()
self._alarm = None self._alarm = None
...@@ -123,7 +131,7 @@ class UIApplication(CLIApplicationBase): ...@@ -123,7 +131,7 @@ class UIApplication(CLIApplicationBase):
self.mainwindow = MainPile([ self.mainwindow = MainPile([
('weight', 1, self.columns), ('weight', 1, self.columns),
(1, urwid.Filler(self.commandline)), (1, self.status_line),
]) ])
urwid.connect_signal(self.mainwindow, 'blur_console', hide_console) urwid.connect_signal(self.mainwindow, 'blur_console', hide_console)
...@@ -307,6 +315,7 @@ class UIApplication(CLIApplicationBase): ...@@ -307,6 +315,7 @@ class UIApplication(CLIApplicationBase):
urwid.connect_signal(todolist, 'add_pending_action', self._set_alarm) urwid.connect_signal(todolist, 'add_pending_action', self._set_alarm)
urwid.connect_signal(todolist, 'remove_pending_action', self._remove_alarm) urwid.connect_signal(todolist, 'remove_pending_action', self._remove_alarm)
urwid.connect_signal(todolist, 'column_action', self._column_action_handler) urwid.connect_signal(todolist, 'column_action', self._column_action_handler)
urwid.connect_signal(todolist, 'show_keystate', self._print_keystate)
options = self.columns.options( options = self.columns.options(
width_type='given', width_type='given',
...@@ -324,6 +333,10 @@ class UIApplication(CLIApplicationBase): ...@@ -324,6 +333,10 @@ class UIApplication(CLIApplicationBase):
self.columns.focus_position = p_pos self.columns.focus_position = p_pos
self._blur_commandline() self._blur_commandline()
def _print_keystate(self, p_keystate):
self.keystate_widget.set_text(p_keystate)
self._keystate_visible = len(p_keystate) > 0
def _set_alarm(self, p_callback): def _set_alarm(self, p_callback):
""" Sets alarm to execute p_action specified in 0.5 sec. """ """ Sets alarm to execute p_action specified in 0.5 sec. """
self._alarm = self.mainloop.set_alarm_in(0.5, p_callback) self._alarm = self.mainloop.set_alarm_in(0.5, p_callback)
...@@ -364,6 +377,22 @@ class UIApplication(CLIApplicationBase): ...@@ -364,6 +377,22 @@ class UIApplication(CLIApplicationBase):
del contents[2] del contents[2]
self.mainwindow.focus_position = 0 self.mainwindow.focus_position = 0
@property
def _keystate_visible(self):
contents = self.status_line.contents
return len(contents) == 2 and isinstance(contents[1][0].original_widget,
KeystateWidget)
@_keystate_visible.setter
def _keystate_visible(self, p_enabled):
contents = self.status_line.contents
if p_enabled and len(contents) == 1:
contents.append((urwid.Filler(self.keystate_widget),
('weight', 1, True)))
elif not p_enabled and self._keystate_visible:
del contents[1]
@property @property
def _viewwidget_visible(self): def _viewwidget_visible(self):
contents = self.mainwindow.contents contents = self.mainwindow.contents
......
...@@ -61,6 +61,7 @@ class TodoListWidget(urwid.LineBox): ...@@ -61,6 +61,7 @@ class TodoListWidget(urwid.LineBox):
'add_pending_action', 'add_pending_action',
'remove_pending_action', 'remove_pending_action',
'column_action', 'column_action',
'show_keystate',
]) ])
@property @property
...@@ -118,6 +119,16 @@ class TodoListWidget(urwid.LineBox): ...@@ -118,6 +119,16 @@ class TodoListWidget(urwid.LineBox):
# deals with pending focus changes. # deals with pending focus changes.
self.listbox.calculate_visible(p_size) self.listbox.calculate_visible(p_size)
@property
def keystate(self):
return self._keystate
@keystate.setter
def keystate(self, p_keystate):
self._keystate = p_keystate
keystate_to_show = p_keystate if p_keystate else ''
urwid.emit_signal(self, 'show_keystate', keystate_to_show)
def keypress(self, p_size, p_key): def keypress(self, p_size, p_key):
urwid.emit_signal(self, 'remove_pending_action') urwid.emit_signal(self, 'remove_pending_action')
requires_further_input = ['postpone', 'postpone_s', 'pri'] requires_further_input = ['postpone', 'postpone_s', 'pri']
...@@ -156,6 +167,11 @@ class TodoListWidget(urwid.LineBox): ...@@ -156,6 +167,11 @@ class TodoListWidget(urwid.LineBox):
if mode in ['postpone', 'postpone_s']: if mode in ['postpone', 'postpone_s']:
if self._postpone_selected(p_key, mode) is not None: if self._postpone_selected(p_key, mode) is not None:
self.keystate = None self.keystate = None
else:
urwid.emit_signal(self, 'show_keystate',
self.keystate + self._pp_offset)
else:
self.keystate = None
return return
except KeyError: except KeyError:
if not self.keystate: if not self.keystate:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment