Blame alsamixer/mixer_clickable.c

Packit Service a9274b
#include <stdlib.h>
Packit Service a9274b
#include <string.h>
Packit Service a9274b
#include "mixer_clickable.h"
Packit Service a9274b
Packit Service a9274b
extern int screen_cols;
Packit Service a9274b
extern int screen_lines;
Packit Service a9274b
Packit Service a9274b
static struct clickable_rect *clickable_rects = NULL;
Packit Service a9274b
static unsigned int clickable_rects_count = 0;
Packit Service a9274b
static unsigned int last_rect = 0;
Packit Service a9274b
Packit Service a9274b
/* Using 0 instead of -1 for marking free rectangles allows us to use
Packit Service a9274b
 * memset for `freeing` all rectangles at once.
Packit Service a9274b
 * Zero is actually a valid coordinate in ncurses, but since we don't have
Packit Service a9274b
 * any clickables in the top line this is fine. */
Packit Service a9274b
#define FREE_MARKER 0
Packit Service a9274b
#define RECT_IS_FREE(RECT) ((RECT).y1 == FREE_MARKER)
Packit Service a9274b
#define RECT_FREE(RECT) ((RECT).y1 = FREE_MARKER)
Packit Service a9274b
Packit Service a9274b
void clickable_set(int y1, int x1, int y2, int x2, command_enum command, int arg1) {
Packit Service a9274b
	struct clickable_rect* tmp;
Packit Service a9274b
	unsigned int i;
Packit Service a9274b
Packit Service a9274b
	for (i = last_rect; i < clickable_rects_count; ++i) {
Packit Service a9274b
		if (RECT_IS_FREE(clickable_rects[i])) {
Packit Service a9274b
			last_rect = i;
Packit Service a9274b
			goto SET_CLICKABLE_DATA;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	for (i = 0; i < last_rect; ++i) {
Packit Service a9274b
		if (RECT_IS_FREE(clickable_rects[i])) {
Packit Service a9274b
			last_rect = i;
Packit Service a9274b
			goto SET_CLICKABLE_DATA;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	last_rect = clickable_rects_count;
Packit Service a9274b
	tmp = realloc(clickable_rects, (clickable_rects_count + 8) * sizeof(*clickable_rects));
Packit Service a9274b
	if (!tmp) {
Packit Service a9274b
		free(clickable_rects);
Packit Service a9274b
		clickable_rects = NULL;
Packit Service a9274b
		clickable_rects_count = 0;
Packit Service a9274b
		last_rect = 0;
Packit Service a9274b
		return;
Packit Service a9274b
	}
Packit Service a9274b
	clickable_rects = tmp;
Packit Service a9274b
#if FREE_MARKER == 0
Packit Service a9274b
	memset(clickable_rects + clickable_rects_count, 0, 8 * sizeof(*clickable_rects));
Packit Service a9274b
#else
Packit Service a9274b
	for (i = clickable_rects_count; i < clickable_rects_count + 8; ++i)
Packit Service a9274b
		RECT_FREE(clickable_rects[i]);
Packit Service a9274b
#endif
Packit Service a9274b
	clickable_rects_count += 8;
Packit Service a9274b
Packit Service a9274b
SET_CLICKABLE_DATA:
Packit Service a9274b
	clickable_rects[last_rect] = (struct clickable_rect) {
Packit Service a9274b
		.y1 = y1,
Packit Service a9274b
		.x1 = x1,
Packit Service a9274b
		.x2 = x2,
Packit Service a9274b
		.y2 = y2,
Packit Service a9274b
		.command = command,
Packit Service a9274b
		.arg1 = arg1
Packit Service a9274b
	};
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
void clickable_set_relative(WINDOW *win, int y1, int x1, int y2, int x2, command_enum command, int arg1) {
Packit Service a9274b
	int y, x;
Packit Service a9274b
	getyx(win, y, x);
Packit Service a9274b
	y1 = y + y1;
Packit Service a9274b
	x1 = x + x1;
Packit Service a9274b
	y2 = y + y2;
Packit Service a9274b
	x2 = x + x2;
Packit Service a9274b
	clickable_set(y1, x1, y2, x2, command, arg1);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
void clickable_clear(int y1, int x1, int y2, int x2) {
Packit Service a9274b
#define IS_IN_RECT(Y, X) (Y >= y1 && Y <= y2 && X >= x1 && X <= x2)
Packit Service a9274b
	unsigned int i;
Packit Service a9274b
Packit Service a9274b
	if (x1 == 0 && x2 == -1 && y2 == -1) {
Packit Service a9274b
		if (y1 == 0) {
Packit Service a9274b
			// Optimize case: clear all
Packit Service a9274b
#if FREE_MARKER == 0
Packit Service a9274b
			if (clickable_rects)
Packit Service a9274b
				memset(clickable_rects, 0,
Packit Service a9274b
						clickable_rects_count * sizeof(*clickable_rects));
Packit Service a9274b
#else
Packit Service a9274b
			for (i = 0; i < clickable_rects_count; ++i)
Packit Service a9274b
				RECT_FREE(clickable_rects[i]);
Packit Service a9274b
#endif
Packit Service a9274b
		}
Packit Service a9274b
		else {
Packit Service a9274b
			// Optimize case: clear all lines beyond y1
Packit Service a9274b
			for (i = 0; i < clickable_rects_count; ++i) {
Packit Service a9274b
				if (clickable_rects[i].y2 >= y1)
Packit Service a9274b
					RECT_FREE(clickable_rects[i]);
Packit Service a9274b
			}
Packit Service a9274b
		}
Packit Service a9274b
		return;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	if (y2 < 0)
Packit Service a9274b
		y2 = screen_lines + y2 + 1;
Packit Service a9274b
	if (x2 < 0)
Packit Service a9274b
		x2 = screen_cols + x2 + 1;
Packit Service a9274b
Packit Service a9274b
	for (i = 0; i < clickable_rects_count; ++i) {
Packit Service a9274b
		if (!RECT_IS_FREE(clickable_rects[i]) && (
Packit Service a9274b
				IS_IN_RECT(clickable_rects[i].y1, clickable_rects[i].x1) ||
Packit Service a9274b
				IS_IN_RECT(clickable_rects[i].y2, clickable_rects[i].x2)
Packit Service a9274b
			))
Packit Service a9274b
		{
Packit Service a9274b
			RECT_FREE(clickable_rects[i]);
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
struct clickable_rect* clickable_find(int y, int x) {
Packit Service a9274b
	unsigned int i;
Packit Service a9274b
Packit Service a9274b
	for (i = 0; i < clickable_rects_count; ++i) {
Packit Service a9274b
		if (
Packit Service a9274b
				!RECT_IS_FREE(clickable_rects[i]) &&
Packit Service a9274b
				y >= clickable_rects[i].y1 &&
Packit Service a9274b
				x >= clickable_rects[i].x1 &&
Packit Service a9274b
				y <= clickable_rects[i].y2 &&
Packit Service a9274b
				x <= clickable_rects[i].x2
Packit Service a9274b
			)
Packit Service a9274b
		{
Packit Service a9274b
			return &clickable_rects[i];
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	return NULL;
Packit Service a9274b
}