mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-11-10 00:15:43 +01:00
alsamixer: added mouse support
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>
This commit is contained in:
parent
6e9e84ba60
commit
ba1c5357a1
12 changed files with 377 additions and 59 deletions
|
@ -10,6 +10,8 @@ alsamixer_SOURCES = card_select.c card_select.h \
|
||||||
die.c die.h \
|
die.c die.h \
|
||||||
mainloop.c mainloop.h \
|
mainloop.c mainloop.h \
|
||||||
mem.c mem.h \
|
mem.c mem.h \
|
||||||
|
menu_widget.c menu_widget.h \
|
||||||
|
mixer_clickable.c mixer_clickable.h \
|
||||||
mixer_controls.c mixer_controls.h \
|
mixer_controls.c mixer_controls.h \
|
||||||
mixer_display.c mixer_display.h \
|
mixer_display.c mixer_display.h \
|
||||||
mixer_widget.c mixer_widget.h \
|
mixer_widget.c mixer_widget.h \
|
||||||
|
|
|
@ -51,7 +51,12 @@ enum mixer_command {
|
||||||
CMD_MIXER_TOGGLE_MUTE,
|
CMD_MIXER_TOGGLE_MUTE,
|
||||||
CMD_MIXER_TOGGLE_CAPTURE,
|
CMD_MIXER_TOGGLE_CAPTURE,
|
||||||
CMD_MIXER_BALANCE_CONTROL,
|
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 {
|
enum textbox_command {
|
||||||
|
|
|
@ -28,10 +28,10 @@
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "colors.h"
|
#include "colors.h"
|
||||||
#include "widget.h"
|
#include "widget.h"
|
||||||
|
#include "menu_widget.h"
|
||||||
#include "mixer_widget.h"
|
#include "mixer_widget.h"
|
||||||
#include "device_name.h"
|
#include "device_name.h"
|
||||||
#include "card_select.h"
|
#include "card_select.h"
|
||||||
#include "bindings.h"
|
|
||||||
|
|
||||||
struct card {
|
struct card {
|
||||||
struct card *next;
|
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)
|
static void on_handle_key(int key)
|
||||||
{
|
{
|
||||||
switch (key) {
|
switch (menu_widget_handle_key(menu, key)) {
|
||||||
case 27:
|
case KEY_ENTER:
|
||||||
case KEY_CANCEL:
|
on_key_enter();
|
||||||
case 'q':
|
break;
|
||||||
case 'Q':
|
case KEY_CANCEL:
|
||||||
list_widget.close();
|
list_widget.close();
|
||||||
break;
|
break;
|
||||||
case 10:
|
|
||||||
case 13:
|
|
||||||
case KEY_ENTER:
|
|
||||||
on_key_enter();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
on_menu_key(key);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@ void initialize_curses(bool use_color)
|
||||||
#endif
|
#endif
|
||||||
window_size_changed(); /* update screen_lines/cols */
|
window_size_changed(); /* update screen_lines/cols */
|
||||||
init_colors(use_color);
|
init_colors(use_color);
|
||||||
|
mousemask(ALL_MOUSE_EVENTS, NULL);
|
||||||
snd_lib_error_set_handler(black_hole_error_handler);
|
snd_lib_error_set_handler(black_hole_error_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
63
alsamixer/menu_widget.c
Normal file
63
alsamixer/menu_widget.c
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
9
alsamixer/menu_widget.h
Normal file
9
alsamixer/menu_widget.h
Normal file
|
@ -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
|
136
alsamixer/mixer_clickable.c
Normal file
136
alsamixer/mixer_clickable.c
Normal file
|
@ -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;
|
||||||
|
}
|
21
alsamixer/mixer_clickable.h
Normal file
21
alsamixer/mixer_clickable.h
Normal file
|
@ -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
|
|
@ -34,6 +34,7 @@
|
||||||
#include "mixer_widget.h"
|
#include "mixer_widget.h"
|
||||||
#include "mixer_controls.h"
|
#include "mixer_controls.h"
|
||||||
#include "mixer_display.h"
|
#include "mixer_display.h"
|
||||||
|
#include "mixer_clickable.h"
|
||||||
|
|
||||||
enum align {
|
enum align {
|
||||||
ALIGN_LEFT,
|
ALIGN_LEFT,
|
||||||
|
@ -109,6 +110,7 @@ void init_mixer_layout(void)
|
||||||
unsigned int label_width_left, label_width_right;
|
unsigned int label_width_left, label_width_right;
|
||||||
unsigned int right_x, i;
|
unsigned int right_x, i;
|
||||||
|
|
||||||
|
clickable_clear(0, 0, -1, -1);
|
||||||
screen_too_small = screen_lines < 14 || screen_cols < 12;
|
screen_too_small = screen_lines < 14 || screen_cols < 12;
|
||||||
has_info_items = screen_lines >= 6;
|
has_info_items = screen_lines >= 6;
|
||||||
if (!has_info_items)
|
if (!has_info_items)
|
||||||
|
@ -135,9 +137,12 @@ void init_mixer_layout(void)
|
||||||
display_string_in_field(1 + i, 2, labels_left[i],
|
display_string_in_field(1 + i, 2, labels_left[i],
|
||||||
label_width_left, ALIGN_RIGHT);
|
label_width_left, ALIGN_RIGHT);
|
||||||
if (label_width_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],
|
display_string_in_field(1 + i, right_x, labels_right[i],
|
||||||
label_width_right, ALIGN_LEFT);
|
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)
|
void display_card_info(void)
|
||||||
|
@ -197,6 +202,7 @@ void display_view_mode(void)
|
||||||
bool has_view_mode;
|
bool has_view_mode;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
clickable_clear(3, 0, 3, 30);
|
||||||
if (!has_info_items)
|
if (!has_info_items)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -204,10 +210,10 @@ void display_view_mode(void)
|
||||||
for (i = 0; i < 3; ++i)
|
for (i = 0; i < 3; ++i)
|
||||||
widths[i] = get_mbs_width(modes[i]);
|
widths[i] = get_mbs_width(modes[i]);
|
||||||
if (4 + widths[0] + 6 + widths[1] + 6 + widths[2] + 1 <= info_items_width) {
|
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);
|
wattrset(mixer_widget.window, attr_mixer_text);
|
||||||
for (i = 0; i < 3; ++i) {
|
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) {
|
if (has_view_mode && (int)view_mode == i) {
|
||||||
wattrset(mixer_widget.window, attr_mixer_active);
|
wattrset(mixer_widget.window, attr_mixer_active);
|
||||||
wprintw(mixer_widget.window, "[%s]", modes[i]);
|
wprintw(mixer_widget.window, "[%s]", modes[i]);
|
||||||
|
@ -215,8 +221,8 @@ void display_view_mode(void)
|
||||||
} else {
|
} else {
|
||||||
wprintw(mixer_widget.window, " %s ", modes[i]);
|
wprintw(mixer_widget.window, " %s ", modes[i]);
|
||||||
}
|
}
|
||||||
if (i < 2)
|
clickable_set_relative(mixer_widget.window, 0, -(widths[i] + 5), 0, -1,
|
||||||
waddch(mixer_widget.window, ' ');
|
CMD_WITH_ARG(CMD_MIXER_SET_VIEW_MODE, i), -1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
wattrset(mixer_widget.window, attr_mixer_active);
|
wattrset(mixer_widget.window, attr_mixer_active);
|
||||||
|
@ -322,6 +328,7 @@ static void clear_controls_display(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
clickable_clear(5, 0, -1, -1);
|
||||||
wattrset(mixer_widget.window, attr_mixer_frame);
|
wattrset(mixer_widget.window, attr_mixer_frame);
|
||||||
for (i = 5; i < screen_lines - 1; ++i)
|
for (i = 5; i < screen_lines - 1; ++i)
|
||||||
mvwprintw(mixer_widget.window, i, 1, "%*s", screen_cols - 2, "");
|
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);
|
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)
|
if (control->flags & IS_ACTIVE)
|
||||||
wattrset(mixer_widget.window, attr_mixer_active);
|
wattrset(mixer_widget.window, attr_mixer_active);
|
||||||
if (!(control->flags & HAS_VOLUME_1)) {
|
if (!(control->flags & HAS_VOLUME_1)) {
|
||||||
|
@ -520,6 +529,8 @@ static void display_control(unsigned int control_index)
|
||||||
switches[1]
|
switches[1]
|
||||||
? _("O")[0] | (control->flags & IS_ACTIVE ? attr_ctl_nomute : 0)
|
? _("O")[0] | (control->flags & IS_ACTIVE ? attr_ctl_nomute : 0)
|
||||||
: _("M")[0] | (control->flags & IS_ACTIVE ? attr_ctl_mute : 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) {
|
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);
|
wattrset(mixer_widget.window, switches[0] ? attr_ctl_capture : attr_ctl_nocapture);
|
||||||
/* TRANSLATORS: "left"; no more than two characters */
|
/* TRANSLATORS: "left"; no more than two characters */
|
||||||
display_string_in_field(cswitch_y - 1, frame_left - 2, switches[0] ? _("L") : "", 2, ALIGN_RIGHT);
|
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)
|
if (control->flags & IS_ACTIVE)
|
||||||
wattrset(mixer_widget.window, switches[1] ? attr_ctl_capture : attr_ctl_nocapture);
|
wattrset(mixer_widget.window, switches[1] ? attr_ctl_capture : attr_ctl_nocapture);
|
||||||
/* TRANSLATORS: "right"; no more than two characters */
|
/* TRANSLATORS: "right"; no more than two characters */
|
||||||
display_string_in_field(cswitch_y - 1, frame_left + 4, switches[1] ? _("R") : "", 2, ALIGN_LEFT);
|
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 */
|
/* TRANSLATORS: no more than eight characters */
|
||||||
s = _("CAPTURE");
|
s = _("CAPTURE");
|
||||||
if (switches[0] || switches[1]) {
|
if (switches[0] || switches[1]) {
|
||||||
|
@ -554,6 +569,8 @@ static void display_control(unsigned int control_index)
|
||||||
wattrset(mixer_widget.window, attr_ctl_nocapture);
|
wattrset(mixer_widget.window, attr_ctl_nocapture);
|
||||||
display_string_in_field(cswitch_y, frame_left - 2, buf, 8, ALIGN_CENTER);
|
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) {
|
if (control->flags & TYPE_ENUM) {
|
||||||
|
@ -566,6 +583,8 @@ static void display_control(unsigned int control_index)
|
||||||
if (control->flags & IS_ACTIVE)
|
if (control->flags & IS_ACTIVE)
|
||||||
wattrset(mixer_widget.window, attr_mixer_active);
|
wattrset(mixer_widget.window, attr_mixer_active);
|
||||||
display_string_centered_in_control(base_y, col, buf, control_width);
|
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) {
|
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);
|
wattrset(mixer_widget.window, attr_ctl_label_inactive);
|
||||||
}
|
}
|
||||||
display_string_centered_in_control(name_y, col, control->name, control_name_width);
|
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 (channel_name_y > name_y) {
|
||||||
if (control->flags & IS_MULTICH) {
|
if (control->flags & IS_MULTICH) {
|
||||||
switch (control->flags & MULTICH_MASK) {
|
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, 0, left);
|
||||||
mvwaddch(mixer_widget.window, y, screen_cols - 1, right);
|
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)
|
void display_controls(void)
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "proc_files.h"
|
#include "proc_files.h"
|
||||||
#include "card_select.h"
|
#include "card_select.h"
|
||||||
#include "volume_mapping.h"
|
#include "volume_mapping.h"
|
||||||
|
#include "mixer_clickable.h"
|
||||||
#include "mixer_controls.h"
|
#include "mixer_controls.h"
|
||||||
#include "mixer_display.h"
|
#include "mixer_display.h"
|
||||||
#include "mixer_widget.h"
|
#include "mixer_widget.h"
|
||||||
|
@ -54,6 +55,9 @@ unsigned int current_control_flags;
|
||||||
bool control_values_changed;
|
bool control_values_changed;
|
||||||
bool controls_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)
|
static int elem_callback(snd_mixer_elem_t *elem, unsigned int mask)
|
||||||
{
|
{
|
||||||
if (mask == SND_CTL_EVENT_MASK_REMOVE) {
|
if (mask == SND_CTL_EVENT_MASK_REMOVE) {
|
||||||
|
@ -462,12 +466,95 @@ static void balance_volumes(void)
|
||||||
display_controls();
|
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)
|
static void on_handle_key(int key)
|
||||||
{
|
{
|
||||||
int arg;
|
int arg;
|
||||||
command_enum cmd;
|
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];
|
cmd = mixer_bindings[key];
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -32,6 +32,9 @@ extern unsigned int current_control_flags;
|
||||||
extern bool control_values_changed;
|
extern bool control_values_changed;
|
||||||
extern bool controls_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_object(struct snd_mixer_selem_regopt *selem_regopt);
|
||||||
void create_mixer_widget(void);
|
void create_mixer_widget(void);
|
||||||
void mixer_shutdown(void);
|
void mixer_shutdown(void);
|
||||||
|
|
|
@ -28,42 +28,26 @@
|
||||||
#include "widget.h"
|
#include "widget.h"
|
||||||
#include "textbox.h"
|
#include "textbox.h"
|
||||||
#include "proc_files.h"
|
#include "proc_files.h"
|
||||||
#include "bindings.h"
|
#include "menu_widget.h"
|
||||||
|
|
||||||
static struct widget proc_widget;
|
static struct widget proc_widget;
|
||||||
static ITEM *items[7];
|
static ITEM *items[7];
|
||||||
static unsigned int items_count;
|
static unsigned int items_count;
|
||||||
static MENU *menu;
|
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)
|
static void on_handle_key(int key)
|
||||||
{
|
{
|
||||||
ITEM *item;
|
ITEM *item;
|
||||||
|
|
||||||
switch (key) {
|
switch (menu_widget_handle_key(menu, key)) {
|
||||||
case 27:
|
case KEY_ENTER:
|
||||||
case KEY_CANCEL:
|
item = current_item(menu);
|
||||||
proc_widget.close();
|
if (item)
|
||||||
break;
|
show_textfile(item_name(item));
|
||||||
case 10:
|
break;
|
||||||
case 13:
|
case KEY_CANCEL:
|
||||||
case KEY_ENTER:
|
proc_widget.close();
|
||||||
item = current_item(menu);
|
break;
|
||||||
if (item)
|
|
||||||
show_textfile(item_name(item));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
on_menu_key(key);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue