]> git.deb.at Git - pkg/abook.git/commitdiff
Add basic mouse support
authorThorsten Wißmann <edu@thorsten-wissmann.de>
Sun, 8 Apr 2012 11:08:13 +0000 (13:08 +0200)
committerRaphaël Droz <raphael.droz+floss@gmail.com>
Sat, 5 May 2012 16:33:53 +0000 (18:33 +0200)
This adds the following optional mouse features:

  * Select items in the main view by clicking and scrolling
  * Go to the edit-form by double-clicking
  * Edit fields by clicking on them
  * Select tabs by clicking on them
  * Return to main view/quit abook by clicking on the first row

abookrc.5
edit.c
list.c
list.h
options.c
options.h
ui.c
ui.h

index fef99d69480323491fac095fd9dd4fcc67d9ad1d..8c13366622dce574a1ae5530c12350e3a55ad69f 100644 (file)
--- a/abookrc.5
+++ b/abookrc.5
@@ -146,6 +146,10 @@ Defines the field to be used by the "sort by field" command. Default is "nick" (
 \fBshow_cursor\fP=[true|false]
 Defines if the cursor is visible in main display. Default is false.
 
+.TP
+\fBuse_mouse\fP=[true|false]
+Defines if navigation via the mouse is activated. Default is false.
+
 .TP
 \fBuse_colors\fP=[true|false]
 Defines if the output of abook is colorized. Default is false.
diff --git a/edit.c b/edit.c
index 81da8895d1d6879451f11c1274e14aca7eaf3f58..9a76c8a8970aadda843bd1b7ab7638f3e2c84ec1 100644 (file)
--- a/edit.c
+++ b/edit.c
@@ -588,13 +588,14 @@ key_to_field_number(char c)
 static void
 edit_field(int tab, char c, int item_number)
 {
+       ui_enable_mouse(FALSE);
        int i = 0, number, idx;
        char *msg;
        abook_field_list *f;
        list_item item;
 
        if((number = key_to_field_number(c)) < 0)
-               return;
+               goto detachfield;
 
        edit_undo(item_number, BACKUP_ITEM);
 
@@ -602,7 +603,7 @@ edit_field(int tab, char c, int item_number)
 
        while(1) {
                if(!f)
-                       return;
+                       goto detachfield;
 
                if(i == number)
                        break;
@@ -631,10 +632,14 @@ edit_field(int tab, char c, int item_number)
                        break;
                case FIELD_DATE:
                        edit_date(item_number, idx);
-                       return;
+                       goto detachfield;
                default:
                        assert(0);
        }
+
+ detachfield:
+       if(opt_get_bool(BOOL_USE_MOUSE))
+         ui_enable_mouse(TRUE);
 }
 
 static int
@@ -668,6 +673,53 @@ edit_loop(int item)
 
                return item;
        }
+       if(c == KEY_MOUSE) {
+               MEVENT event;
+               if(getmouse(&event) == OK) {
+                       if(event.bstate & BUTTON1_CLICKED
+                          || event.bstate & BUTTON1_DOUBLE_CLICKED) {
+                               int window_y, window_x;
+                               getbegyx(editw, window_y, window_x);
+                               if(event.y == 0) {
+                                       /* if first row is selected, then go back to list */
+                                       return -1;
+                               } else if(event.y == window_y + TABLINE
+                                  || event.y == window_y + TABLINE + 1) {
+                                       char* tab_name;
+                                       int mouse_x = event.x;
+                                       int xpos = 2 + 1; /* look at editor_tab() and try out */
+                                       int clicked_tab = 0;
+                                       while(clicked_tab < views_count) {
+                                               view_info(clicked_tab, &tab_name, NULL);
+                                               xpos += strwidth(tab_name) + 5;
+                                               /* fprintf(stderr, "trying tab %d\n", clicked_tab); */
+                                               if(xpos >= mouse_x) {
+                                                       break; /* clicked tab was found */
+                                               } else {
+                                                       /* try next tab */
+                                                       clicked_tab++;
+                                               }
+                                       }
+                                       if(clicked_tab < views_count) {
+                                               tab = clicked_tab;
+                                       }
+                               } else if(event.y >= window_y + FIELDS_START_Y) {
+                                       /* is mouse in field area? */
+                                       int j = 1 + event.y - window_y - FIELDS_START_Y;
+                                       /* field numbers start with 1, but if j='0', then char='0' */
+                                       /* so fix this, by adding 1 to j */
+                                       int field_char = (j < 10) ? '0' + j : 'A' + j - 10;
+                                       edit_field(tab, field_char, item);
+                               }
+                       } else if(event.bstate & BUTTON4_PRESSED) {
+                               tab = tab == 0 ? views_count - 1 : tab - 1;
+                       }
+                       else if(event.bstate & BUTTON5_PRESSED) {
+                               tab = tab == views_count - 1 ? 0 : tab + 1;
+                       }
+                       return item;
+               }
+       }
 
        /* No uppercase nor numeric key should be used in this menu,
         * as they are reserved for field selection */
diff --git a/list.c b/list.c
index 9eb4edeb83add05ea4b7257437afd25b482ab7eb..ca4892baea2e4f7bd495b225c0649c14f3052ac6 100644 (file)
--- a/list.c
+++ b/list.c
@@ -498,6 +498,12 @@ list_get_curitem()
        return curitem;
 }
 
+int
+list_get_firstitem()
+{
+       return first_list_item;
+}
+
 void
 list_set_curitem(int i)
 {
diff --git a/list.h b/list.h
index 45b00f832dc1be61435508c75a5425e350a175b1..0cc31137916c461bf92ef0bc4b3a2c755e0bca5c 100644 (file)
--- a/list.h
+++ b/list.h
@@ -47,6 +47,7 @@ int           selected_items();
 void           invert_selection();
 int            list_is_empty();
 int            list_get_curitem();
+int            list_get_firstitem();
 void           list_set_curitem(int i);
 int            duplicate_item();
 
index 57cb3342b0d25d731338a2ebbf6bfa1c5263e288..2c1303c5b3e5baacee895709a13bc2b4a87496eb 100644 (file)
--- a/options.c
+++ b/options.c
@@ -67,6 +67,7 @@ static struct option abook_vars[] = {
        { "preserve_fields", OT_STR, STR_PRESERVE_FIELDS, UL "standard" },
        { "sort_field", OT_STR, STR_SORT_FIELD, UL "nick" },
        { "show_cursor", OT_BOOL, BOOL_SHOW_CURSOR, FALSE },
+       { "use_mouse", OT_BOOL, BOOL_USE_MOUSE, FALSE },
        { "use_colors", OT_BOOL, BOOL_USE_COLORS, FALSE },
        { "color_header_fg", OT_STR, STR_COLOR_HEADER_FG, UL "blue" },
        { "color_header_fg", OT_STR, STR_COLOR_HEADER_FG, UL "blue" },
index 2dbadc322b985248aa8dbf263867e5ac130e8f6b..d2cc8c0b73b49e7e778395707bfb2716faa182c6 100644 (file)
--- a/options.h
+++ b/options.h
@@ -27,6 +27,7 @@ enum bool_opts {
        BOOL_ADD_EMAIL_PREVENT_DUPLICATES,
        BOOL_SHOW_CURSOR,
        BOOL_USE_COLORS,
+       BOOL_USE_MOUSE,
        BOOL_MAX
 };
 
diff --git a/ui.c b/ui.c
index 69fb71d3de3154329951b23ced1d24a390023899..9ef3ee6ac3b850119db2b9435f1072276286fb16 100644 (file)
--- a/ui.c
+++ b/ui.c
@@ -26,6 +26,7 @@
 #include "filter.h"
 #include "xmalloc.h"
 #include "color.h"
+#include <sys/time.h>
 #ifdef HAVE_CONFIG_H
 #      include "config.h"
 #endif
@@ -51,6 +52,8 @@ static bool ui_initialized = FALSE;
 
 static bool should_resize = FALSE;
 static bool can_resize = FALSE;
+static struct timeval last_click_time;
+static int double_click_interval = 200; /* maximum time in milliseconds */
 
 static WINDOW *top = NULL, *bottom = NULL;
 
@@ -130,6 +133,11 @@ ui_init_curses()
        noecho();
        nonl();
        intrflush(stdscr, FALSE);
+       if(opt_get_bool(BOOL_USE_MOUSE)) {
+               mouseinterval(0);
+               timerclear(&last_click_time);
+               ui_enable_mouse(TRUE);
+       }
        keypad(stdscr, TRUE);
        if(opt_get_bool(BOOL_USE_COLORS)) {
                start_color();
@@ -138,6 +146,35 @@ ui_init_curses()
        }
 }
 
+void
+ui_enable_mouse(bool enabled)
+{
+       mmask_t mask;
+       if(enabled) {
+               mask = BUTTON1_CLICKED | BUTTON4_PRESSED;
+#if NCURSES_MOUSE_VERSION == 2
+               mask |= BUTTON5_PRESSED;
+#endif
+       } else {
+               mask = 0;
+       }
+       mousemask(mask, NULL);
+}
+
+/** Check the time elapsed since last click and tell if it should be
+ * interpreted as a double click
+ */
+static bool
+was_double_click() {
+       struct timeval click_time, click_diff, maxdiff;
+       maxdiff.tv_sec = double_click_interval / 1000;
+       maxdiff.tv_usec = (double_click_interval % 1000)*1000;
+       gettimeofday(&click_time, NULL);
+
+       timersub(&click_time, &last_click_time, &click_diff);
+       last_click_time = click_time;
+       return !timercmp(&click_diff, &maxdiff, >);
+}
 
 #define CHECK_COLOR_NAME(value, name, DEFNAME) \
        if(!strcmp((name), (value))){ \
@@ -503,6 +540,28 @@ get_commands()
                if(!opt_get_bool(BOOL_SHOW_CURSOR))
                        show_cursor();
                can_resize = FALSE; /* it's not safe to resize anymore */
+               if(ch == KEY_MOUSE) {
+                       MEVENT event;
+                       bool double_clicked = was_double_click();
+                       if(getmouse(&event) == OK) {
+                               if(event.bstate & BUTTON1_CLICKED
+                                  || event.bstate & BUTTON1_DOUBLE_CLICKED) {
+                                       if(event.y == 0) {
+                                               return;
+                                       }
+                                       list_set_curitem(event.y + list_get_firstitem() - LIST_TOP);
+                                       if(double_clicked) {
+                                               edit_item(-1);
+                                       } else {
+                                               refresh_list();
+                                       }
+                               } else if(event.bstate & BUTTON4_PRESSED) {
+                                       scroll_up();
+                               } else if(event.bstate & BUTTON5_PRESSED) {
+                                       scroll_down();
+                               }
+                       }
+               }
                switch(ch) {
                        case 'q': return;
                        case 'Q': quit_abook(QUIT_DONTSAVE);    break;
diff --git a/ui.h b/ui.h
index 3e7483b2c06d497f5bcf1b0b1c18ae10fa9ee41e..fd7670e6fbed3beb91bae4fc89bf94ae2f8c121b 100644 (file)
--- a/ui.h
+++ b/ui.h
@@ -11,6 +11,7 @@ enum {
 int            is_ui_initialized();
 void           ui_init_curses();
 void           ui_init_color_pairs_user();
+void           ui_enable_mouse(bool enabled);
 int            init_ui();
 void           close_ui();
 void           headerline(const char *str);
@@ -36,6 +37,9 @@ char          *get_surname(char *s);
 void           ui_print_database();
 void           ui_open_datafile();
 
+#if NCURSES_MOUSE_VERSION != 2
+#define BUTTON5_PRESSED (0x80 | 0x8000000)
+#endif
 
 #include "options.h" /* needed for options_get_bool */