New functionality

Ctrl-Up/Down skips whole entries
Alt-Left/Right moves the division line
Enter confirms the entry for overwriting

The modified arrow keys aren't going to work everywhere,
e.g. the Linux terminal doesn't support them.
This commit is contained in:
Přemysl Eric Janouch 2013-05-16 23:56:01 +02:00
parent d07f80c051
commit 5cb6a2e506
1 changed files with 136 additions and 5 deletions

View File

@ -45,7 +45,21 @@
#define KEY_VT 11 /**< Ctrl-K */ #define KEY_VT 11 /**< Ctrl-K */
#define KEY_NAK 21 /**< Ctrl-U */ #define KEY_NAK 21 /**< Ctrl-U */
#define KEY_ETB 23 /**< Ctrl-W */ #define KEY_ETB 23 /**< Ctrl-W */
#define KEY_ESCAPE 27 /**< Curses doesn't define this. */
#define KEY_RETURN 13 /**< Enter */
#define KEY_ESCAPE 27 /**< Esc */
// These codes may or may not work, depending on the terminal
// They lie above KEY_MAX, originally discovered on gnome-terminal
#define KEY_CTRL_UP 565
#define KEY_CTRL_DOWN 524
#define KEY_CTRL_LEFT 544
#define KEY_CTRL_RIGHT 559
#define KEY_ALT_UP 563
#define KEY_ALT_DOWN 522
#define KEY_ALT_LEFT 542
#define KEY_ALT_RIGHT 557
#define _(x) x /**< Fake gettext, for now. */ #define _(x) x /**< Fake gettext, for now. */
@ -99,6 +113,9 @@ struct application
GArray *input; //!< The current search input GArray *input; //!< The current search input
guint input_pos; //!< Cursor position within input guint input_pos; //!< Cursor position within input
gboolean input_confirmed; //!< Input has been confirmed
gfloat division; //!< Position of the division column
}; };
@ -220,6 +237,9 @@ app_init (Application *self, const gchar *filename)
self->input = g_array_new (TRUE, FALSE, sizeof (gunichar)); self->input = g_array_new (TRUE, FALSE, sizeof (gunichar));
self->input_pos = 0; self->input_pos = 0;
self->input_confirmed = FALSE;
self->division = 0.5;
self->wchar_to_utf8 = g_iconv_open ("utf-8//translit", "wchar_t"); self->wchar_to_utf8 = g_iconv_open ("utf-8//translit", "wchar_t");
self->utf8_to_wchar = g_iconv_open ("wchar_t//translit", "utf-8"); self->utf8_to_wchar = g_iconv_open ("wchar_t//translit", "utf-8");
@ -277,6 +297,8 @@ app_redraw_top (Application *self)
((gunichar *) self->input->data, -1, NULL, NULL, NULL); ((gunichar *) self->input->data, -1, NULL, NULL, NULL);
g_return_if_fail (input_utf8 != NULL); g_return_if_fail (input_utf8 != NULL);
if (self->input_confirmed)
attron (A_BOLD);
add_padded_string (self, input_utf8, COLS - x); add_padded_string (self, input_utf8, COLS - x);
g_free (input_utf8); g_free (input_utf8);
@ -284,6 +306,18 @@ app_redraw_top (Application *self)
refresh (); refresh ();
} }
/** Computes width for the left column. */
static guint
app_get_left_column_width (Application *self)
{
gint width = COLS * self->division + 0.5;
if (width < 1)
width = 1;
else if (width > COLS - 2)
width = COLS - 2;
return width;
}
/** Redraw the dictionary view. */ /** Redraw the dictionary view. */
static void static void
app_redraw_view (Application *self) app_redraw_view (Application *self)
@ -301,9 +335,10 @@ app_redraw_view (Application *self)
if (k + 1 == ve->definitions_length) attrs |= A_UNDERLINE; if (k + 1 == ve->definitions_length) attrs |= A_UNDERLINE;
attrset (attrs); attrset (attrs);
add_padded_string (self, ve->word, COLS / 2); guint left_width = app_get_left_column_width (self);
add_padded_string (self, ve->word, left_width);
addwstr (L" "); addwstr (L" ");
add_padded_string (self, ve->definitions[k], COLS - COLS / 2 - 1); add_padded_string (self, ve->definitions[k], COLS - left_width - 1);
if ((gint) ++shown == LINES - 1) if ((gint) ++shown == LINES - 1)
goto done; goto done;
@ -444,6 +479,69 @@ app_scroll_down (Application *self, guint n)
return success; return success;
} }
/** Moves the selection one entry up. */
static gboolean
app_one_entry_up (Application *self)
{
if (self->selected == 0 && self->top_offset == 0)
{
if (self->top_position == 0)
return FALSE;
prepend_entry (self, --self->top_position);
}
// Find the last entry that starts above the selection
gint first = -self->top_offset;
guint i;
for (i = 0; i < self->entries->len; i++)
{
ViewEntry *ve = g_ptr_array_index (self->entries, i);
gint new_first = first + ve->definitions_length;
if (new_first >= (gint) self->selected)
break;
first = new_first;
}
if (first < 0)
{
self->selected = 0;
app_scroll_up (self, -first);
}
else
{
self->selected = first;
app_redraw_view (self);
}
return TRUE;
}
/** Moves the selection one entry down. */
static void
app_one_entry_down (Application *self)
{
// Find the first entry that starts below the selection
gint first = -self->top_offset;
guint i;
for (i = 0; i < self->entries->len; i++)
{
ViewEntry *ve = g_ptr_array_index (self->entries, i);
first += ve->definitions_length;
if (first > (gint) self->selected)
break;
}
if (first > LINES - 2)
{
self->selected = LINES - 2;
app_scroll_down (self, first - (LINES - 2));
}
else
{
self->selected = first;
app_redraw_view (self);
}
}
/** Redraw everything. */ /** Redraw everything. */
static void static void
app_redraw (Application *self) app_redraw (Application *self)
@ -496,6 +594,26 @@ app_process_nonchar_code (Application *self, CursesEvent *event)
} }
break; break;
case KEY_CTRL_UP:
app_one_entry_up (self);
app_redraw_top (self); // FIXME just focus
break;
case KEY_CTRL_DOWN:
app_one_entry_down (self);
app_redraw_top (self); // FIXME just focus
break;
case KEY_ALT_LEFT:
self->division = (app_get_left_column_width (self) - 1.) / COLS;
app_redraw_view (self);
app_redraw_top (self); // FIXME just focus
break;
case KEY_ALT_RIGHT:
self->division = (app_get_left_column_width (self) + 1.) / COLS;
app_redraw_view (self);
app_redraw_top (self); // FIXME just focus
break;
case KEY_UP: case KEY_UP:
if (self->selected > 0) if (self->selected > 0)
{ {
@ -519,11 +637,11 @@ app_process_nonchar_code (Application *self, CursesEvent *event)
break; break;
case KEY_PPAGE: case KEY_PPAGE:
app_scroll_up (self, LINES - 1); app_scroll_up (self, LINES - 1);
app_redraw_top (self); // FIXME just focus, selection app_redraw_top (self); // FIXME just focus
break; break;
case KEY_NPAGE: case KEY_NPAGE:
app_scroll_down (self, LINES - 1); app_scroll_down (self, LINES - 1);
app_redraw_top (self); // FIXME just focus, selection app_redraw_top (self); // FIXME just focus
break; break;
case KEY_HOME: case KEY_HOME:
@ -579,6 +697,11 @@ app_process_curses_event (Application *self, CursesEvent *event)
{ {
case KEY_ESCAPE: case KEY_ESCAPE:
return FALSE; return FALSE;
case KEY_RETURN:
self->input_confirmed = TRUE;
app_redraw_top (self);
break;
case KEY_SOH: // Ctrl-A -- move to the start of line case KEY_SOH: // Ctrl-A -- move to the start of line
self->input_pos = 0; self->input_pos = 0;
app_redraw_top (self); app_redraw_top (self);
@ -637,6 +760,14 @@ app_process_curses_event (Application *self, CursesEvent *event)
gunichar c = g_utf8_get_char (letter); gunichar c = g_utf8_get_char (letter);
if (g_unichar_isprint (c)) if (g_unichar_isprint (c))
{ {
if (self->input_confirmed)
{
if (self->input->len != 0)
g_array_remove_range (self->input, 0, self->input->len);
self->input_pos = 0;
self->input_confirmed = FALSE;
}
g_array_insert_val (self->input, self->input_pos++, c); g_array_insert_val (self->input, self->input_pos++, c);
app_search_for_entry (self); app_search_for_entry (self);
app_redraw_top (self); app_redraw_top (self);