mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-12-22 19:56:31 +01:00
137 lines
3.3 KiB
C
137 lines
3.3 KiB
C
|
#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;
|
||
|
}
|