Ticket #3571: 3571-High-level-mouse-API.patch

File 3571-High-level-mouse-API.patch, 12.1 KB (added by mooffie, 8 years ago)
  • lib/widget/Makefile.am

    From 738bab54f4a9a64b788508ccc9a7bdc808ea1795 Mon Sep 17 00:00:00 2001
    From: Mooffie <mooffie@gmail.com>
    Date: Thu, 26 Nov 2015 00:28:08 +0200
    Subject: [PATCH] High-level mouse API.
    
    ---
     lib/widget/Makefile.am     |   1 +
     lib/widget/mouse.c         | 194 +++++++++++++++++++++++++++++++++++++++++++++
     lib/widget/mouse.h         |  66 +++++++++++++++
     lib/widget/widget-common.c |   2 +
     lib/widget/widget-common.h |  11 +++
     5 files changed, 274 insertions(+)
     create mode 100644 lib/widget/mouse.c
     create mode 100644 lib/widget/mouse.h
    
    diff --git a/lib/widget/Makefile.am b/lib/widget/Makefile.am
    index 40058c9..c918ec8 100644
    a b libmcwidget_la_SOURCES = \ 
    1717        listbox.c listbox.h \ 
    1818        label.c label.h \ 
    1919        menu.c menu.h \ 
     20        mouse.c mouse.h \ 
    2021        quick.c quick.h \ 
    2122        radio.c radio.h \ 
    2223        widget-common.c widget-common.h \ 
  • new file lib/widget/mouse.c

    diff --git a/lib/widget/mouse.c b/lib/widget/mouse.c
    new file mode 100644
    index 0000000..70b6676
    - +  
     1/* 
     2   Widgets for the Midnight Commander 
     3 
     4   Copyright (C) 1994-2015 
     5   Free Software Foundation, Inc. 
     6 
     7   Authors: 
     8   Human beings. 
     9 
     10   This file is part of the Midnight Commander. 
     11 
     12   The Midnight Commander is free software: you can redistribute it 
     13   and/or modify it under the terms of the GNU General Public License as 
     14   published by the Free Software Foundation, either version 3 of the License, 
     15   or (at your option) any later version. 
     16 
     17   The Midnight Commander is distributed in the hope that it will be useful, 
     18   but WITHOUT ANY WARRANTY; without even the implied warranty of 
     19   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     20   GNU General Public License for more details. 
     21 
     22   You should have received a copy of the GNU General Public License 
     23   along with this program.  If not, see <http://www.gnu.org/licenses/>. 
     24 */ 
     25 
     26/** \file mouse.c 
     27 *  \brief Header: High-level mouse API 
     28 */ 
     29 
     30#include <config.h> 
     31 
     32#include "lib/global.h" 
     33#include "lib/widget.h" 
     34 
     35/*** global variables ****************************************************************************/ 
     36 
     37/*** file scope macro definitions ****************************************************************/ 
     38 
     39/*** file scope type declarations ****************************************************************/ 
     40 
     41/*** file scope variables ************************************************************************/ 
     42 
     43static int last_buttons_down; 
     44 
     45/* --------------------------------------------------------------------------------------------- */ 
     46/*** file scope functions ************************************************************************/ 
     47/* --------------------------------------------------------------------------------------------- */ 
     48 
     49/* 
     50 * Constructs a mouse event structure. The is the high-level type used 
     51 * with "easy callbacks". 
     52 */ 
     53static void 
     54init_mouse_event (mouse_event_t * event, mouse_msg_t msg, const Gpm_Event * global_gpm, 
     55                  const Widget * w) 
     56{ 
     57    event->msg = msg; 
     58    event->x = global_gpm->x - w->x - 1;        /* '-1' because Gpm_Event is 1-based. */ 
     59    event->y = global_gpm->y - w->y - 1; 
     60    event->count = global_gpm->type & (GPM_SINGLE | GPM_DOUBLE | GPM_TRIPLE); 
     61    event->buttons = global_gpm->buttons; 
     62    event->result.abort = FALSE; 
     63    event->result.repeat = FALSE; 
     64} 
     65 
     66/* --------------------------------------------------------------------------------------------- */ 
     67 
     68/* 
     69 * This is the low-level mouse handler that's in use when you install 
     70 * an "easy callback". 
     71 * 
     72 * It receives a Gpm_Event event and translates it into a higher level 
     73 * protocol with which it feeds your "easy callback". 
     74 * 
     75 * Tip: for details on the C mouse API, see MC's lib/tty/mouse.h, 
     76 * or GPM's excellent 'info' manual: 
     77 * 
     78 *    http://www.fifi.org/cgi-bin/info2www?(gpm)Event+Types 
     79 */ 
     80static int 
     81easy_mouse_translator (Gpm_Event * event, void *data) 
     82{ 
     83    Widget *w = WIDGET (data); 
     84 
     85    gboolean in_widget; 
     86    gboolean run_click = FALSE; 
     87    mouse_msg_t msg = 0; 
     88 
     89    in_widget = mouse_global_in_widget (event, w); 
     90 
     91    /* 
     92     * Very special widgets may want to control area outside their bounds. 
     93     * For such widgets you will have to turn on the 'forced_capture' flag. 
     94     * You'll also need, in your mouse handler, to inform the system of 
     95     * events you want to pass on by setting 'event->result.abort' to TRUE. 
     96     */ 
     97    if (w->Mouse.forced_capture) 
     98        in_widget = TRUE; 
     99 
     100    if ((event->type & GPM_DOWN) != 0) 
     101    { 
     102        if (in_widget) 
     103        { 
     104            if ((event->buttons & GPM_B_UP) != 0) 
     105                msg = MSG_MOUSE_SCROLL_UP; 
     106            else if ((event->buttons & GPM_B_DOWN) != 0) 
     107                msg = MSG_MOUSE_SCROLL_DOWN; 
     108            else 
     109            { 
     110                /* Handle normal buttons: anything but the mouse wheel's. 
     111                 * 
     112                 * (Note that turning on capturing for the mouse wheel 
     113                 * buttons doesn't make sense as they don't generate a 
     114                 * mouse_up event, which means we'd never get uncaptured.) 
     115                 */ 
     116                w->Mouse.capture = TRUE; 
     117                msg = MSG_MOUSE_DOWN; 
     118 
     119                last_buttons_down = event->buttons; 
     120            } 
     121        } 
     122    } 
     123    else if ((event->type & GPM_UP) != 0) 
     124    { 
     125        /* We trigger the mouse_up event even when !in_widget. That's 
     126         * because, for example, a paint application should stop drawing 
     127         * lines when the button is released even outside the canvas. */ 
     128        if (w->Mouse.capture) 
     129        { 
     130            w->Mouse.capture = FALSE; 
     131            msg = MSG_MOUSE_UP; 
     132 
     133            if (in_widget) 
     134                run_click = TRUE; 
     135 
     136            /* 
     137             * When using xterm, event->buttons reports the buttons' state 
     138             * after the event occurred (meaning that event->buttons is zero, 
     139             * because the mouse button is now released). When using GPM, 
     140             * however, that field reports the button(s) that was released. 
     141             * 
     142             * The following makes xterm behave effectively like GPM: 
     143             */ 
     144            if (event->buttons == 0) 
     145                event->buttons = last_buttons_down; 
     146        } 
     147    } 
     148    else if ((event->type & GPM_DRAG) != 0) 
     149    { 
     150        if (w->Mouse.capture) 
     151            msg = MSG_MOUSE_DRAG; 
     152    } 
     153    else if ((event->type & GPM_MOVE) != 0) 
     154    { 
     155        if (in_widget) 
     156            msg = MSG_MOUSE_MOVE; 
     157    } 
     158 
     159    if (msg != 0) 
     160    { 
     161        mouse_event_t local; 
     162 
     163        init_mouse_event (&local, msg, event, w); 
     164 
     165        w->Mouse.callback (w, msg, &local); 
     166        if (run_click) 
     167            w->Mouse.callback (w, MSG_MOUSE_CLICK, &local); 
     168 
     169        if (!local.result.abort) 
     170            return local.result.repeat ? MOU_REPEAT : MOU_NORMAL; 
     171    } 
     172 
     173    return MOU_UNHANDLED; 
     174} 
     175 
     176/* --------------------------------------------------------------------------------------------- */ 
     177/*** public functions ****************************************************************************/ 
     178/* --------------------------------------------------------------------------------------------- */ 
     179 
     180/** 
     181 * Use this to install an "easy mouse callback". 
     182 * 
     183 * (The mouse callback widget_init() accepts is a low-level one; you can 
     184 * pass NULL to it. In the future we'll probably do the opposite: have 
     185 * widget_init() accept the "easy" callback.) 
     186 */ 
     187void 
     188set_easy_mouse_callback (Widget * w, easy_mouse_callback cb) 
     189{ 
     190    w->mouse = easy_mouse_translator; 
     191    w->Mouse.callback = cb; 
     192} 
     193 
     194/* --------------------------------------------------------------------------------------------- */ 
  • new file lib/widget/mouse.h

    diff --git a/lib/widget/mouse.h b/lib/widget/mouse.h
    new file mode 100644
    index 0000000..ba4c97e
    - +  
     1/** \file mouse.h 
     2 *  \brief Header: Hight-level mouse API. 
     3 * 
     4 * This is a thin layer over the low-level mouse protocol in lib/tty/mouse.h. 
     5 * The latter is oblivious to the regions on the screen and is therefore a 
     6 * bit hard to use in widgets. This layer translates the low level Gpm_Event 
     7 * into something that's easy to work with in widgets. 
     8 */ 
     9 
     10#ifndef MC__WIDGET_MOUSE_H 
     11#define MC__WIDGET_MOUSE_H 
     12 
     13/*** enums ***************************************************************************************/ 
     14 
     15/* Mouse messages */ 
     16typedef enum 
     17{ 
     18    /* 
     19     * Notes: 
     20     * (1) "anywhere" means "inside or outside the widget". 
     21     * (2) the mouse wheel is not considered "mouse button". 
     22     */ 
     23    MSG_MOUSE_DOWN = 1,         /* When mouse button is pressed down inside the widget. */ 
     24    MSG_MOUSE_UP,               /* When mouse button, previously pressed inside the widget, is released anywhere. */ 
     25    MSG_MOUSE_CLICK,            /* When mouse button, previously pressed inside the widget, is released inside the widget. */ 
     26    MSG_MOUSE_DRAG,             /* When a drag, initiated by button press inside the widget, occurs anywhere. */ 
     27    MSG_MOUSE_MOVE,             /* (Not currently implemented in MC.) */ 
     28    MSG_MOUSE_SCROLL_UP,        /* When mouse wheel is rotated away from the user. */ 
     29    MSG_MOUSE_SCROLL_DOWN       /* When mouse wheel is rotated towards the user. */ 
     30} mouse_msg_t; 
     31 
     32/*** structures declarations (and typedefs of structures)*****************************************/ 
     33 
     34/* Mouse event structure. */ 
     35typedef struct 
     36{ 
     37    mouse_msg_t msg; 
     38 
     39    int x, y;                   /* Local to the widget. */ 
     40    int buttons;                /* Bitwise-or of: GPM_B_LEFT, GPM_B_MIDDLE, GPM_B_RIGHT */ 
     41    int count;                  /* One of: GPM_SINGLE, GPM_DOUBLE, GPM_TRIPLE */ 
     42 
     43    /* A mechanism for the callback to report back: */ 
     44    struct 
     45    { 
     46        gboolean abort; 
     47        gboolean repeat; 
     48    } result; 
     49} mouse_event_t; 
     50 
     51/*** typedefs(not structures) and defined constants **********************************************/ 
     52 
     53/* A callback to respond to mouse events. 
     54 * Note: We embed "easy" in it to distinguish it from the old-style callbacks we still use. */ 
     55typedef void (*easy_mouse_callback) (Widget *, mouse_msg_t msg, mouse_event_t *); 
     56 
     57/*** global variables defined in .c file *********************************************************/ 
     58 
     59/*** declarations of public functions ************************************************************/ 
     60 
     61/* Installs an easy callback on a widget. */ 
     62void set_easy_mouse_callback (Widget * w, easy_mouse_callback cb); 
     63 
     64/*** inline functions ****************************************************************************/ 
     65 
     66#endif /* MC__WIDGET_MOUSE_H */ 
  • lib/widget/widget-common.c

    diff --git a/lib/widget/widget-common.c b/lib/widget/widget-common.c
    index 3571ed2..5499de8 100644
    a b widget_init (Widget * w, int y, int x, int lines, int cols, 
    149149    w->mouse = mouse_handler; 
    150150    w->set_options = widget_default_set_options_callback; 
    151151    w->owner = NULL; 
     152    w->Mouse.capture = FALSE; 
     153    w->Mouse.forced_capture = FALSE; 
    152154 
    153155    /* Almost all widgets want to put the cursor in a suitable place */ 
    154156    w->options = W_WANT_CURSOR; 
  • lib/widget/widget-common.h

    diff --git a/lib/widget/widget-common.h b/lib/widget/widget-common.h
    index 0398a1e..6072445 100644
    a b  
    77#define MC__WIDGET_INTERNAL_H 
    88 
    99#include "lib/tty/mouse.h" 
     10#include "lib/widget/mouse.h"   /* typedef easy_mouse_callback */ 
    1011 
    1112/*** typedefs(not structures) and defined constants **********************************************/ 
    1213 
    struct Widget 
    105106    mouse_h mouse; 
    106107    void (*set_options) (Widget * w, widget_options_t options, gboolean enable); 
    107108    struct WDialog *owner; 
     109 
     110    /* Mouse-related fields. */ 
     111    struct 
     112    { 
     113        easy_mouse_callback callback; 
     114        gboolean capture;       /* Whether the widget "owns" the mouse. */ 
     115        gboolean forced_capture;        /* Overrides the above. Set explicitly by the programmer. */ 
     116    } Mouse; 
     117    /* "Mouse" capitalized -- as we already have a lowercase "mouse" here. 
     118     * @FIXME: rename "mouse" to something else. */ 
    108119}; 
    109120 
    110121/* structure for label (caption) with hotkey, if original text does not contain