]> git.alsa-project.org Git - alsa-utils.git/commitdiff
alsamixer: added mouse support
authorbraph <braph93@gmx.de>
Thu, 26 Sep 2019 23:25:56 +0000 (01:25 +0200)
committerJaroslav Kysela <perex@perex.cz>
Wed, 1 Jul 2020 14:10:35 +0000 (16:10 +0200)
Mouse support has been added for mixer_widget.c, card_select.c and
proc_files.c.

In the mixer widget the mouse is handled as follows:
- After an element has been printed in mixer_display.c, a call to
  clickable_set() will store the coordinates of the drawn area plus the
  command enum that should be executed on click. An optional argument
  holds an index which points to the selected mixer control.
- on_mouse_click() searches for a matching rectangle, focuses the mixer
  control and returns the command enum.

In the menu widgets, the menu_driver() function handles mouse input.

Signed-off-by: Benjamin Abendroth <braph93@gmx.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
12 files changed:
alsamixer/Makefile.am
alsamixer/bindings.h
alsamixer/card_select.c
alsamixer/mainloop.c
alsamixer/menu_widget.c [new file with mode: 0644]
alsamixer/menu_widget.h [new file with mode: 0644]
alsamixer/mixer_clickable.c [new file with mode: 0644]
alsamixer/mixer_clickable.h [new file with mode: 0644]
alsamixer/mixer_display.c
alsamixer/mixer_widget.c
alsamixer/mixer_widget.h
alsamixer/proc_files.c

index 3fe7a740bc67aff8d1266f3cfe638ab4ba455bc2..d1021f9e5eb543abb673bdf98c090f528b2b3c02 100644 (file)
@@ -10,6 +10,8 @@ alsamixer_SOURCES = card_select.c card_select.h \
                die.c die.h \
                mainloop.c mainloop.h \
                mem.c mem.h \
+               menu_widget.c menu_widget.h \
+               mixer_clickable.c mixer_clickable.h \
                mixer_controls.c mixer_controls.h \
                mixer_display.c mixer_display.h \
                mixer_widget.c mixer_widget.h \
index 1e9dd6db4f60ff7dec8fd67e8434ae401e469a41..fa2e8d3c4a2c005ed49e1eb0a1cde0651820cd8c 100644 (file)
@@ -51,7 +51,12 @@ enum mixer_command {
        CMD_MIXER_TOGGLE_MUTE,
        CMD_MIXER_TOGGLE_CAPTURE,
        CMD_MIXER_BALANCE_CONTROL,
-       CMD_MIXER_REFRESH
+       CMD_MIXER_REFRESH,
+
+       // Mouse
+       CMD_MIXER_MOUSE_CLICK_MUTE,
+       CMD_MIXER_MOUSE_CLICK_VOLUME_BAR,
+       CMD_MIXER_MOUSE_CLICK_CONTROL_ENUM,
 };
 
 enum textbox_command {
index e97020380716a562c468e520ef73651b496860bf..6762ecde395cb165ff0843d108170171a9430d38 100644 (file)
 #include "utils.h"
 #include "colors.h"
 #include "widget.h"
+#include "menu_widget.h"
 #include "mixer_widget.h"
 #include "device_name.h"
 #include "card_select.h"
-#include "bindings.h"
 
 struct card {
        struct card *next;
@@ -60,33 +60,15 @@ static void on_key_enter(void)
        }
 }
 
-static void on_menu_key(int key)
-{
-       if (key < ARRAY_SIZE(textbox_bindings)) {
-               key = textbox_bindings[key];
-               if (key >= CMD_TEXTBOX___MIN_MENU_COMMAND &&
-                               key <= CMD_TEXTBOX___MAX_MENU_COMMAND)
-                       menu_driver(menu, key + KEY_MAX);
-       }
-}
-
 static void on_handle_key(int key)
 {
-       switch (key) {
-       case 27:
-       case KEY_CANCEL:
-       case 'q':
-       case 'Q':
-               list_widget.close();
-               break;
-       case 10:
-       case 13:
-       case KEY_ENTER:
-               on_key_enter();
-               break;
-       default:
-               on_menu_key(key);
-               break;
+       switch (menu_widget_handle_key(menu, key)) {
+               case KEY_ENTER:
+                       on_key_enter();
+                       break;
+               case KEY_CANCEL:
+                       list_widget.close();
+                       break;
        }
 }
 
index a50109baea27dcc7a7504b94e73e9c2a5cd26ea9..e80f23275b8ac208cb77688d6f739700253725cc 100644 (file)
@@ -50,6 +50,7 @@ void initialize_curses(bool use_color)
 #endif
        window_size_changed(); /* update screen_lines/cols */
        init_colors(use_color);
+       mousemask(ALL_MOUSE_EVENTS, NULL);
        snd_lib_error_set_handler(black_hole_error_handler);
 }
 
diff --git a/alsamixer/menu_widget.c b/alsamixer/menu_widget.c
new file mode 100644 (file)
index 0000000..30940a7
--- /dev/null
@@ -0,0 +1,63 @@
+#include "menu_widget.h"
+#include "colors.h"
+#include "utils.h"
+#include "bindings.h"
+
+/* Returns
+ * - KEY_CANCEL: close is requested
+ * - KEY_ENTER: item is selected
+ * - -1: no action
+ */
+int menu_widget_handle_key(MENU *menu, int key)
+{
+       MEVENT m;
+
+       switch (key) {
+       case 27:
+       case KEY_CANCEL:
+       case 'q':
+       case 'Q':
+               return KEY_CANCEL;
+       case '\n':
+       case '\r':
+       case KEY_ENTER:
+               return KEY_ENTER;
+
+       case KEY_MOUSE:
+               switch (menu_driver(menu, KEY_MOUSE)) {
+                       case E_UNKNOWN_COMMAND:
+                               /* If you double-click an item a REQ_TOGGLE_ITEM is generated
+                                * and E_UNKNOWN_COMMAND is returned. (man menu_driver) */
+                               return KEY_ENTER;
+                       case E_REQUEST_DENIED:
+                               /* If menu did not handle KEY_MOUSE is has to be removed from
+                                * input queue to prevent an infinite loop. */
+                               key = wgetch(menu_win(menu));
+                               if (key == KEY_MOUSE) {
+                                       if (getmouse(&m) == ERR)
+                                               return -1;
+                                       if (m.bstate & (BUTTON4_PRESSED|BUTTON4_CLICKED))
+                                               menu_driver(menu, REQ_UP_ITEM);
+#if NCURSES_MOUSE_VERSION > 1
+                                       else if (m.bstate & (BUTTON5_PRESSED|BUTTON5_CLICKED))
+                                               menu_driver(menu, REQ_DOWN_ITEM);
+#endif
+                                       else
+                                               return KEY_CANCEL;
+                               }
+                               else if (key > 0)
+                                       ungetch(key);
+               }
+               return -1;
+
+       default:
+               if (key < ARRAY_SIZE(textbox_bindings)) {
+                       key = textbox_bindings[key];
+                       if (key >= CMD_TEXTBOX___MIN_MENU_COMMAND &&
+                                       key <= CMD_TEXTBOX___MAX_MENU_COMMAND)
+                               menu_driver(menu, key + KEY_MAX);
+               }
+
+               return -1;
+       }
+}
diff --git a/alsamixer/menu_widget.h b/alsamixer/menu_widget.h
new file mode 100644 (file)
index 0000000..ad3ed0e
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef MENU_WIDGET_H_INCLUDED
+#define MENU_WIDGET_H_INCLUDED
+
+#include "widget.h"
+#include <menu.h>
+
+int menu_widget_handle_key(MENU *menu, int key);
+
+#endif
diff --git a/alsamixer/mixer_clickable.c b/alsamixer/mixer_clickable.c
new file mode 100644 (file)
index 0000000..c772f37
--- /dev/null
@@ -0,0 +1,136 @@
+#include <stdlib.h>
+#include <string.h>
+#include "mixer_clickable.h"
+
+extern int screen_cols;
+extern int screen_lines;
+
+static struct clickable_rect *clickable_rects = NULL;
+static unsigned int clickable_rects_count = 0;
+static unsigned int last_rect = 0;
+
+/* Using 0 instead of -1 for marking free rectangles allows us to use
+ * memset for `freeing` all rectangles at once.
+ * Zero is actually a valid coordinate in ncurses, but since we don't have
+ * any clickables in the top line this is fine. */
+#define FREE_MARKER 0
+#define RECT_IS_FREE(RECT) ((RECT).y1 == FREE_MARKER)
+#define RECT_FREE(RECT) ((RECT).y1 = FREE_MARKER)
+
+void clickable_set(int y1, int x1, int y2, int x2, command_enum command, int arg1) {
+       struct clickable_rect* tmp;
+       unsigned int i;
+
+       for (i = last_rect; i < clickable_rects_count; ++i) {
+               if (RECT_IS_FREE(clickable_rects[i])) {
+                       last_rect = i;
+                       goto SET_CLICKABLE_DATA;
+               }
+       }
+
+       for (i = 0; i < last_rect; ++i) {
+               if (RECT_IS_FREE(clickable_rects[i])) {
+                       last_rect = i;
+                       goto SET_CLICKABLE_DATA;
+               }
+       }
+
+       last_rect = clickable_rects_count;
+       tmp = realloc(clickable_rects, (clickable_rects_count + 8) * sizeof(*clickable_rects));
+       if (!tmp) {
+               free(clickable_rects);
+               clickable_rects = NULL;
+               clickable_rects_count = 0;
+               last_rect = 0;
+               return;
+       }
+       clickable_rects = tmp;
+#if FREE_MARKER == 0
+       memset(clickable_rects + clickable_rects_count, 0, 8 * sizeof(*clickable_rects));
+#else
+       for (i = clickable_rects_count; i < clickable_rects_count + 8; ++i)
+               RECT_FREE(clickable_rects[i]);
+#endif
+       clickable_rects_count += 8;
+
+SET_CLICKABLE_DATA:
+       clickable_rects[last_rect] = (struct clickable_rect) {
+               .y1 = y1,
+               .x1 = x1,
+               .x2 = x2,
+               .y2 = y2,
+               .command = command,
+               .arg1 = arg1
+       };
+}
+
+void clickable_set_relative(WINDOW *win, int y1, int x1, int y2, int x2, command_enum command, int arg1) {
+       int y, x;
+       getyx(win, y, x);
+       y1 = y + y1;
+       x1 = x + x1;
+       y2 = y + y2;
+       x2 = x + x2;
+       clickable_set(y1, x1, y2, x2, command, arg1);
+}
+
+void clickable_clear(int y1, int x1, int y2, int x2) {
+#define IS_IN_RECT(Y, X) (Y >= y1 && Y <= y2 && X >= x1 && X <= x2)
+       unsigned int i;
+
+       if (x1 == 0 && x2 == -1 && y2 == -1) {
+               if (y1 == 0) {
+                       // Optimize case: clear all
+#if FREE_MARKER == 0
+                       if (clickable_rects)
+                               memset(clickable_rects, 0,
+                                               clickable_rects_count * sizeof(*clickable_rects));
+#else
+                       for (i = 0; i < clickable_rects_count; ++i)
+                               RECT_FREE(clickable_rects[i]);
+#endif
+               }
+               else {
+                       // Optimize case: clear all lines beyond y1
+                       for (i = 0; i < clickable_rects_count; ++i) {
+                               if (clickable_rects[i].y2 >= y1)
+                                       RECT_FREE(clickable_rects[i]);
+                       }
+               }
+               return;
+       }
+
+       if (y2 < 0)
+               y2 = screen_lines + y2 + 1;
+       if (x2 < 0)
+               x2 = screen_cols + x2 + 1;
+
+       for (i = 0; i < clickable_rects_count; ++i) {
+               if (!RECT_IS_FREE(clickable_rects[i]) && (
+                               IS_IN_RECT(clickable_rects[i].y1, clickable_rects[i].x1) ||
+                               IS_IN_RECT(clickable_rects[i].y2, clickable_rects[i].x2)
+                       ))
+               {
+                       RECT_FREE(clickable_rects[i]);
+               }
+       }
+}
+
+struct clickable_rect* clickable_find(int y, int x) {
+       unsigned int i;
+
+       for (i = 0; i < clickable_rects_count; ++i) {
+               if (
+                               !RECT_IS_FREE(clickable_rects[i]) &&
+                               y >= clickable_rects[i].y1 &&
+                               x >= clickable_rects[i].x1 &&
+                               y <= clickable_rects[i].y2 &&
+                               x <= clickable_rects[i].x2
+                       )
+               {
+                       return &clickable_rects[i];
+               }
+       }
+
+       return NULL;
+}
diff --git a/alsamixer/mixer_clickable.h b/alsamixer/mixer_clickable.h
new file mode 100644 (file)
index 0000000..792c711
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef MIXER_CLICKABLE_H
+#define MIXER_CLICKABLE_H
+
+#include CURSESINC
+#include "bindings.h"
+
+struct clickable_rect {
+       short y1;
+       short x1;
+       short y2;
+       short x2;
+       command_enum command;
+       int arg1;
+};
+
+void clickable_set(int y1, int x1, int y2, int x2, command_enum command, int arg1);
+void clickable_set_relative(WINDOW *win, int y1, int x1, int y2, int x2, command_enum command, int arg1);
+void clickable_clear(int y1, int x1, int y2, int x2);
+struct clickable_rect* clickable_find(int y, int x);
+
+#endif
index b1f79d06522157c80d438b8429648ebe5bb269f0..2f45ab36f55ae3ff7ba570a7fabd9c4f93f94b45 100644 (file)
@@ -34,6 +34,7 @@
 #include "mixer_widget.h"
 #include "mixer_controls.h"
 #include "mixer_display.h"
+#include "mixer_clickable.h"
 
 enum align {
        ALIGN_LEFT,
@@ -109,6 +110,7 @@ void init_mixer_layout(void)
        unsigned int label_width_left, label_width_right;
        unsigned int right_x, i;
 
+       clickable_clear(0, 0, -1, -1);
        screen_too_small = screen_lines < 14 || screen_cols < 12;
        has_info_items = screen_lines >= 6;
        if (!has_info_items)
@@ -135,9 +137,12 @@ void init_mixer_layout(void)
                        display_string_in_field(1 + i, 2, labels_left[i],
                                                label_width_left, ALIGN_RIGHT);
        if (label_width_right)
-               for (i = 0; i < 4; ++i)
+               for (i = 0; i < 4; ++i) {
                        display_string_in_field(1 + i, right_x, labels_right[i],
                                                label_width_right, ALIGN_LEFT);
+                       clickable_set(1 + i, right_x, 1 + i, right_x + label_width_right - 1,
+                                               CMD_MIXER_HELP + i, -1);
+               }
 }
 
 void display_card_info(void)
@@ -197,6 +202,7 @@ void display_view_mode(void)
        bool has_view_mode;
        int i;
 
+       clickable_clear(3, 0, 3, 30);
        if (!has_info_items)
                return;
 
@@ -204,10 +210,10 @@ void display_view_mode(void)
        for (i = 0; i < 3; ++i)
                widths[i] = get_mbs_width(modes[i]);
        if (4 + widths[0] + 6 + widths[1] + 6 + widths[2] + 1 <= info_items_width) {
-               wmove(mixer_widget.window, 3, info_items_left);
+               wmove(mixer_widget.window, 3, info_items_left - 1);
                wattrset(mixer_widget.window, attr_mixer_text);
                for (i = 0; i < 3; ++i) {
-                       wprintw(mixer_widget.window, "F%c:", '3' + i);
+                       wprintw(mixer_widget.window, " F%c:", '3' + i);
                        if (has_view_mode && (int)view_mode == i) {
                                wattrset(mixer_widget.window, attr_mixer_active);
                                wprintw(mixer_widget.window, "[%s]", modes[i]);
@@ -215,8 +221,8 @@ void display_view_mode(void)
                        } else {
                                wprintw(mixer_widget.window, " %s ", modes[i]);
                        }
-                       if (i < 2)
-                               waddch(mixer_widget.window, ' ');
+                       clickable_set_relative(mixer_widget.window, 0, -(widths[i] + 5), 0, -1,
+                                       CMD_WITH_ARG(CMD_MIXER_SET_VIEW_MODE, i), -1);
                }
        } else {
                wattrset(mixer_widget.window, attr_mixer_active);
@@ -322,6 +328,7 @@ static void clear_controls_display(void)
 {
        int i;
 
+       clickable_clear(5, 0, -1, -1);
        wattrset(mixer_widget.window, attr_mixer_frame);
        for (i = 5; i < screen_lines - 1; ++i)
                mvwprintw(mixer_widget.window, i, 1, "%*s", screen_cols - 2, "");
@@ -483,6 +490,8 @@ static void display_control(unsigned int control_index)
                                         frame_left + c + 1, ch);
                        }
                }
+               clickable_set(base_y - volume_height, frame_left + 1, base_y, frame_left + 2,
+                               CMD_MIXER_MOUSE_CLICK_VOLUME_BAR, control_index);
                if (control->flags & IS_ACTIVE)
                        wattrset(mixer_widget.window, attr_mixer_active);
                if (!(control->flags & HAS_VOLUME_1)) {
@@ -520,6 +529,8 @@ static void display_control(unsigned int control_index)
                       switches[1]
                       ? _("O")[0] | (control->flags & IS_ACTIVE ? attr_ctl_nomute : 0)
                       : _("M")[0] | (control->flags & IS_ACTIVE ? attr_ctl_mute : 0));
+               clickable_set(base_y + 1, frame_left + 1, base_y + 1, frame_left + 2,
+                               CMD_MIXER_MOUSE_CLICK_MUTE, control_index);
        }
 
        if (control->flags & TYPE_CSWITCH) {
@@ -534,10 +545,14 @@ static void display_control(unsigned int control_index)
                        wattrset(mixer_widget.window, switches[0] ? attr_ctl_capture : attr_ctl_nocapture);
                /* TRANSLATORS: "left"; no more than two characters */
                display_string_in_field(cswitch_y - 1, frame_left - 2, switches[0] ? _("L") : "", 2, ALIGN_RIGHT);
+               clickable_set(cswitch_y - 1, frame_left - 2, cswitch_y - 1, frame_left - 1,
+                               CMD_WITH_ARG(CMD_MIXER_TOGGLE_CAPTURE, LEFT), control_index);
                if (control->flags & IS_ACTIVE)
                        wattrset(mixer_widget.window, switches[1] ? attr_ctl_capture : attr_ctl_nocapture);
                /* TRANSLATORS: "right"; no more than two characters */
                display_string_in_field(cswitch_y - 1, frame_left + 4, switches[1] ? _("R") : "", 2, ALIGN_LEFT);
+               clickable_set(cswitch_y - 1, frame_left + 4, cswitch_y - 1, frame_left + 5,
+                               CMD_WITH_ARG(CMD_MIXER_TOGGLE_CAPTURE, RIGHT), control_index);
                /* TRANSLATORS: no more than eight characters */
                s = _("CAPTURE");
                if (switches[0] || switches[1]) {
@@ -554,6 +569,8 @@ static void display_control(unsigned int control_index)
                                wattrset(mixer_widget.window, attr_ctl_nocapture);
                        display_string_in_field(cswitch_y, frame_left - 2, buf, 8, ALIGN_CENTER);
                }
+               clickable_set(cswitch_y, frame_left - 2, cswitch_y, frame_left - 2 + 8,
+                               CMD_WITH_ARG(CMD_MIXER_TOGGLE_CAPTURE, LEFT|RIGHT), control_index);
        }
 
        if (control->flags & TYPE_ENUM) {
@@ -566,6 +583,8 @@ static void display_control(unsigned int control_index)
                if (control->flags & IS_ACTIVE)
                        wattrset(mixer_widget.window, attr_mixer_active);
                display_string_centered_in_control(base_y, col, buf, control_width);
+               clickable_set_relative(mixer_widget.window, 0, -control_name_width, 0, -2,
+                               CMD_MIXER_MOUSE_CLICK_CONTROL_ENUM, control_index);
        }
 
        if (control_index == focus_control_index) {
@@ -584,6 +603,8 @@ static void display_control(unsigned int control_index)
                        wattrset(mixer_widget.window, attr_ctl_label_inactive);
        }
        display_string_centered_in_control(name_y, col, control->name, control_name_width);
+       clickable_set_relative(mixer_widget.window, -1, -control_name_width, 0, -2,
+                       CMD_WITH_ARG(CMD_MIXER_FOCUS_CONTROL, control_index), -1);
        if (channel_name_y > name_y) {
                if (control->flags & IS_MULTICH) {
                        switch (control->flags & MULTICH_MASK) {
@@ -630,6 +651,10 @@ static void display_scroll_indicators(void)
                mvwaddch(mixer_widget.window, y, 0, left);
                mvwaddch(mixer_widget.window, y, screen_cols - 1, right);
        }
+       clickable_set(y0, 0, y1, 0,
+                       CMD_WITH_ARG(CMD_MIXER_PREVIOUS, visible_controls), -1);
+       clickable_set(y0, screen_cols - 1, y1, screen_cols - 1,
+                       CMD_WITH_ARG(CMD_MIXER_NEXT, visible_controls), -1);
 }
 
 void display_controls(void)
index b1bd61e56f2b07443dd480932a0dd9064597c91d..160124f1688078b96a8a4512050cf0244ccb3ec1 100644 (file)
@@ -34,6 +34,7 @@
 #include "proc_files.h"
 #include "card_select.h"
 #include "volume_mapping.h"
+#include "mixer_clickable.h"
 #include "mixer_controls.h"
 #include "mixer_display.h"
 #include "mixer_widget.h"
@@ -54,6 +55,9 @@ unsigned int current_control_flags;
 bool control_values_changed;
 bool controls_changed;
 
+unsigned int mouse_wheel_step = 1;
+bool mouse_wheel_focuses_control = 1;
+
 static int elem_callback(snd_mixer_elem_t *elem, unsigned int mask)
 {
        if (mask == SND_CTL_EVENT_MASK_REMOVE) {
@@ -462,12 +466,95 @@ static void balance_volumes(void)
        display_controls();
 }
 
+static int on_mouse_key() {
+       MEVENT m;
+       command_enum cmd = 0;
+       unsigned int channels = LEFT | RIGHT;
+       unsigned int index;
+       struct control *control;
+       struct clickable_rect *rect;
+
+       if (getmouse(&m) == ERR)
+               return 0;
+
+       if (m.bstate & (
+                               BUTTON1_PRESSED|BUTTON1_RELEASED|
+                               BUTTON2_PRESSED|BUTTON2_RELEASED|
+                               BUTTON3_PRESSED|BUTTON3_RELEASED))
+               return 0;
+
+       rect = clickable_find(m.y, m.x);
+       if (rect)
+               cmd = rect->command;
+
+#if NCURSES_MOUSE_VERSION > 1
+       if (m.bstate & (BUTTON4_CLICKED|BUTTON4_PRESSED|BUTTON5_CLICKED|BUTTON5_PRESSED)) {
+               switch (cmd) {
+                       case CMD_MIXER_MOUSE_CLICK_CONTROL_ENUM:
+                               focus_control_index = rect->arg1;
+                               return CMD_WITH_ARG((
+                                                       m.bstate & (BUTTON4_CLICKED|BUTTON4_PRESSED)
+                                                       ? CMD_MIXER_CONTROL_UP
+                                                       : CMD_MIXER_CONTROL_DOWN
+                                               ), 1);
+
+                       case CMD_MIXER_MOUSE_CLICK_VOLUME_BAR:
+                               if (mouse_wheel_focuses_control)
+                                       focus_control_index = rect->arg1;
+
+                       default:
+                               return CMD_WITH_ARG((
+                                                       m.bstate & (BUTTON4_CLICKED|BUTTON4_PRESSED)
+                                                       ? CMD_MIXER_CONTROL_UP
+                                                       : CMD_MIXER_CONTROL_DOWN
+                                               ), mouse_wheel_step);
+               }
+       }
+#endif
+
+       /* If the rectangle has got an argument (value != -1) it is used for
+        * setting `focus_control_index` */
+       if (rect && rect->arg1 >= 0)
+               focus_control_index = rect->arg1;
+
+       switch (cmd) {
+       case CMD_MIXER_MOUSE_CLICK_VOLUME_BAR:
+               if (m.bstate & (BUTTON3_CLICKED|BUTTON3_DOUBLE_CLICKED|BUTTON3_TRIPLE_CLICKED))
+                       channels = m.x - rect->x1 + 1;
+               return CMD_WITH_ARG(CMD_MIXER_CONTROL_SET_PERCENT_LEFT + channels - 1,
+                       (100 * (rect->y2 - m.y) / (rect->y2 - rect->y1)) // volume
+               );
+
+       case CMD_MIXER_MOUSE_CLICK_MUTE:
+               if (m.bstate & (BUTTON3_CLICKED|BUTTON3_DOUBLE_CLICKED|BUTTON3_TRIPLE_CLICKED))
+                       channels = m.x - rect->x1 + 1;
+               return CMD_WITH_ARG(CMD_MIXER_TOGGLE_MUTE, channels);
+
+       case CMD_MIXER_MOUSE_CLICK_CONTROL_ENUM:
+               control = get_focus_control(TYPE_ENUM);
+               if (control &&
+                       (snd_mixer_selem_get_enum_item(control->elem, 0, &index) >= 0)) {
+                               return (index == 0
+                                       ? CMD_WITH_ARG(CMD_MIXER_CONTROL_UP, 100)
+                                       : CMD_WITH_ARG(CMD_MIXER_CONTROL_DOWN, 1));
+               }
+               break;
+
+       default:
+               return cmd; // non-mouse command
+       }
+
+       return 0; // failed mouse command
+}
+
 static void on_handle_key(int key)
 {
        int arg;
        command_enum cmd;
 
-       if (key < ARRAY_SIZE(mixer_bindings))
+       if (key == KEY_MOUSE)
+               cmd = on_mouse_key();
+       else if (key < ARRAY_SIZE(mixer_bindings))
                cmd = mixer_bindings[key];
        else
                return;
index 5b1cfcca386d183603bf6e790dd04c4342346148..3b6f474dfbc77b2524fa6ffb614dfec7c79ef998 100644 (file)
@@ -32,6 +32,9 @@ extern unsigned int current_control_flags;
 extern bool control_values_changed;
 extern bool controls_changed;
 
+extern unsigned int mouse_wheel_step;
+extern bool mouse_wheel_focuses_control;
+
 void create_mixer_object(struct snd_mixer_selem_regopt *selem_regopt);
 void create_mixer_widget(void);
 void mixer_shutdown(void);
index 9d3fe3f4426bcf99f5c28f08eab4030269414868..5ae7ae921c432e501e22e1b05817edf90f330260 100644 (file)
 #include "widget.h"
 #include "textbox.h"
 #include "proc_files.h"
-#include "bindings.h"
+#include "menu_widget.h"
 
 static struct widget proc_widget;
 static ITEM *items[7];
 static unsigned int items_count;
 static MENU *menu;
 
-static void on_menu_key(int key)
-{
-       if (key < ARRAY_SIZE(textbox_bindings)) {
-               key = textbox_bindings[key];
-               if (key >= CMD_TEXTBOX___MIN_MENU_COMMAND &&
-                               key <= CMD_TEXTBOX___MAX_MENU_COMMAND)
-                       menu_driver(menu, key + KEY_MAX);
-       }
-}
-
 static void on_handle_key(int key)
 {
        ITEM *item;
 
-       switch (key) {
-       case 27:
-       case KEY_CANCEL:
-               proc_widget.close();
-               break;
-       case 10:
-       case 13:
-       case KEY_ENTER:
-               item = current_item(menu);
-               if (item)
-                       show_textfile(item_name(item));
-               break;
-       default:
-               on_menu_key(key);
-               break;
+       switch (menu_widget_handle_key(menu, key)) {
+               case KEY_ENTER:
+                       item = current_item(menu);
+                       if (item)
+                               show_textfile(item_name(item));
+                       break;
+               case KEY_CANCEL:
+                       proc_widget.close();
+                       break;
        }
 }