• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <stdlib.h>
2 #include <string.h>
3 #include "mixer_clickable.h"
4 
5 extern int screen_cols;
6 extern int screen_lines;
7 
8 static struct clickable_rect *clickable_rects = NULL;
9 static unsigned int clickable_rects_count = 0;
10 static unsigned int last_rect = 0;
11 
12 /* Using 0 instead of -1 for marking free rectangles allows us to use
13  * memset for `freeing` all rectangles at once.
14  * Zero is actually a valid coordinate in ncurses, but since we don't have
15  * any clickables in the top line this is fine. */
16 #define FREE_MARKER 0
17 #define RECT_IS_FREE(RECT) ((RECT).y1 == FREE_MARKER)
18 #define RECT_FREE(RECT) ((RECT).y1 = FREE_MARKER)
19 
clickable_set(int y1,int x1,int y2,int x2,command_enum command,int arg1)20 void clickable_set(int y1, int x1, int y2, int x2, command_enum command, int arg1) {
21 	struct clickable_rect* tmp;
22 	unsigned int i;
23 
24 	for (i = last_rect; i < clickable_rects_count; ++i) {
25 		if (RECT_IS_FREE(clickable_rects[i])) {
26 			last_rect = i;
27 			goto SET_CLICKABLE_DATA;
28 		}
29 	}
30 
31 	for (i = 0; i < last_rect; ++i) {
32 		if (RECT_IS_FREE(clickable_rects[i])) {
33 			last_rect = i;
34 			goto SET_CLICKABLE_DATA;
35 		}
36 	}
37 
38 	last_rect = clickable_rects_count;
39 	tmp = realloc(clickable_rects, (clickable_rects_count + 8) * sizeof(*clickable_rects));
40 	if (!tmp) {
41 		free(clickable_rects);
42 		clickable_rects = NULL;
43 		clickable_rects_count = 0;
44 		last_rect = 0;
45 		return;
46 	}
47 	clickable_rects = tmp;
48 #if FREE_MARKER == 0
49 	memset(clickable_rects + clickable_rects_count, 0, 8 * sizeof(*clickable_rects));
50 #else
51 	for (i = clickable_rects_count; i < clickable_rects_count + 8; ++i)
52 		RECT_FREE(clickable_rects[i]);
53 #endif
54 	clickable_rects_count += 8;
55 
56 SET_CLICKABLE_DATA:
57 	clickable_rects[last_rect] = (struct clickable_rect) {
58 		.y1 = y1,
59 		.x1 = x1,
60 		.x2 = x2,
61 		.y2 = y2,
62 		.command = command,
63 		.arg1 = arg1
64 	};
65 }
66 
clickable_set_relative(WINDOW * win,int y1,int x1,int y2,int x2,command_enum command,int arg1)67 void clickable_set_relative(WINDOW *win, int y1, int x1, int y2, int x2, command_enum command, int arg1) {
68 	int y, x;
69 	getyx(win, y, x);
70 	y1 = y + y1;
71 	x1 = x + x1;
72 	y2 = y + y2;
73 	x2 = x + x2;
74 	clickable_set(y1, x1, y2, x2, command, arg1);
75 }
76 
clickable_clear(int y1,int x1,int y2,int x2)77 void clickable_clear(int y1, int x1, int y2, int x2) {
78 #define IS_IN_RECT(Y, X) (Y >= y1 && Y <= y2 && X >= x1 && X <= x2)
79 	unsigned int i;
80 
81 	if (x1 == 0 && x2 == -1 && y2 == -1) {
82 		if (y1 == 0) {
83 			// Optimize case: clear all
84 #if FREE_MARKER == 0
85 			if (clickable_rects)
86 				memset(clickable_rects, 0,
87 						clickable_rects_count * sizeof(*clickable_rects));
88 #else
89 			for (i = 0; i < clickable_rects_count; ++i)
90 				RECT_FREE(clickable_rects[i]);
91 #endif
92 		}
93 		else {
94 			// Optimize case: clear all lines beyond y1
95 			for (i = 0; i < clickable_rects_count; ++i) {
96 				if (clickable_rects[i].y2 >= y1)
97 					RECT_FREE(clickable_rects[i]);
98 			}
99 		}
100 		return;
101 	}
102 
103 	if (y2 < 0)
104 		y2 = screen_lines + y2 + 1;
105 	if (x2 < 0)
106 		x2 = screen_cols + x2 + 1;
107 
108 	for (i = 0; i < clickable_rects_count; ++i) {
109 		if (!RECT_IS_FREE(clickable_rects[i]) && (
110 				IS_IN_RECT(clickable_rects[i].y1, clickable_rects[i].x1) ||
111 				IS_IN_RECT(clickable_rects[i].y2, clickable_rects[i].x2)
112 			))
113 		{
114 			RECT_FREE(clickable_rects[i]);
115 		}
116 	}
117 }
118 
clickable_find(int y,int x)119 struct clickable_rect* clickable_find(int y, int x) {
120 	unsigned int i;
121 
122 	for (i = 0; i < clickable_rects_count; ++i) {
123 		if (
124 				!RECT_IS_FREE(clickable_rects[i]) &&
125 				y >= clickable_rects[i].y1 &&
126 				x >= clickable_rects[i].x1 &&
127 				y <= clickable_rects[i].y2 &&
128 				x <= clickable_rects[i].x2
129 			)
130 		{
131 			return &clickable_rects[i];
132 		}
133 	}
134 
135 	return NULL;
136 }
137