PatchworkOS
Loading...
Searching...
No Matches
element.c
Go to the documentation of this file.
1#include "internal.h"
2
3#include <stdlib.h>
4#include <string.h>
5
7{
8 event_t event = {.target = elem->win->surface, .type = LEVENT_INIT};
9 if (elem->proc(elem->win, elem, &event) == ERR)
10 {
11 return ERR;
12 }
13
14 element_redraw(elem, false);
15 return 0;
16}
17
18static element_t* element_new_raw(element_id_t id, const rect_t* rect, const char* text, element_flags_t flags,
19 procedure_t procedure, void* private)
20{
21 element_t* elem = malloc(sizeof(element_t));
22 if (elem == NULL)
23 {
24 return NULL;
25 }
26 list_entry_init(&elem->entry);
27 list_init(&elem->children);
28 elem->parent = NULL;
29 elem->id = id;
30 elem->proc = procedure;
31 elem->win = NULL;
32 elem->private = private;
33 elem->rect = *rect;
34 elem->flags = flags;
35 elem->text = strdup(text);
36 if (elem->text == NULL)
37 {
38 free(elem);
39 return NULL;
40 }
41 elem->image = NULL;
42 elem->imageProps = (image_props_t){.xAlign = ALIGN_CENTER, .yAlign = ALIGN_CENTER, .srcOffset = (point_t){0}};
43 elem->textProps = (text_props_t){.xAlign = ALIGN_CENTER, .yAlign = ALIGN_CENTER, .font = NULL};
44 elem->theme = *theme_global_get();
45 return elem;
46}
47
48element_t* element_new(element_t* parent, element_id_t id, const rect_t* rect, const char* text, element_flags_t flags,
49 procedure_t procedure, void* private)
50{
51 if (parent == NULL || rect == NULL || text == NULL || procedure == NULL)
52 {
53 errno = EINVAL;
54 return NULL;
55 }
56
57 element_t* elem = element_new_raw(id, rect, text, flags, procedure, private);
58 if (elem == NULL)
59 {
60 errno = ENOMEM;
61 return NULL;
62 }
63
64 elem->parent = parent;
65 elem->win = parent->win;
66 list_push(&parent->children, &elem->entry);
67
68 if (element_send_init(elem) == ERR)
69 {
70 element_free(elem);
71 return NULL;
72 }
73 return elem;
74}
75
76element_t* element_new_root(window_t* win, element_id_t id, const rect_t* rect, const char* text, element_flags_t flags,
77 procedure_t procedure, void* private)
78{
79 if (win == NULL || rect == NULL || text == NULL || procedure == NULL)
80 {
81 errno = EINVAL;
82 return NULL;
83 }
84
85 element_t* elem = element_new_raw(id, rect, text, flags, procedure, private);
86 if (elem == NULL)
87 {
88 errno = ENOMEM;
89 return NULL;
90 }
91
92 elem->win = win;
93
94 if (element_send_init(elem) == ERR)
95 {
96 element_free(elem);
97 return NULL;
98 }
99 return elem;
100}
101
103{
104 element_t* child;
105 element_t* temp;
106 LIST_FOR_EACH_SAFE(child, temp, &elem->children, entry)
107 {
108 list_remove(&elem->children, &child->entry);
109 element_free(child);
110 }
111}
112
114{
115 if (elem == NULL)
116 {
117 return;
118 }
119
120 event_t event = {.target = elem->win->surface, .type = LEVENT_DEINIT};
121 elem->proc(elem->win, elem, &event);
122
123 if (elem->parent != NULL)
124 {
125 list_remove(&elem->parent->children, &elem->entry);
126 elem->parent = NULL;
127 }
128
130 free(elem->text);
131 free(elem);
132}
133
135{
136 if (elem == NULL)
137 {
138 return NULL;
139 }
140
141 if (elem->id == id)
142 {
143 return elem;
144 }
145
146 element_t* child;
147 LIST_FOR_EACH(child, &elem->children, entry)
148 {
149 if (child->id == id)
150 {
151 return child;
152 }
153 element_t* grandChild = element_find(child, id);
154 if (grandChild != NULL)
155 {
156 return grandChild;
157 }
158 }
159
160 return NULL;
161}
162
163void element_set_private(element_t* elem, void* private)
164{
165 if (elem == NULL)
166 {
167 return;
168 }
169
170 elem->private = private;
171}
172
174{
175 if (elem == NULL)
176 {
177 return NULL;
178 }
179
180 return elem->private;
181}
182
184{
185 if (elem == NULL)
186 {
187 return ELEMENT_ID_NONE;
188 }
189
190 return elem->id;
191}
192
193void element_move(element_t* elem, const rect_t* rect)
194{
195 if (elem == NULL || rect == NULL)
196 {
197 return;
198 }
199
200 elem->rect = *rect;
201}
202
204{
205 if (elem == NULL)
206 {
207 return (rect_t){0};
208 }
209
210 return elem->rect;
211}
212
214{
215 if (elem == NULL)
216 {
217 return (rect_t){0};
218 }
219
220 return RECT_INIT_DIM(0, 0, RECT_WIDTH(&elem->rect), RECT_HEIGHT(&elem->rect));
221}
222
224{
225 if (elem == NULL)
226 {
227 return (rect_t){0};
228 }
229
230 point_t point = element_get_window_point(elem);
231 return RECT_INIT_DIM(point.x, point.y, RECT_WIDTH(&elem->rect), RECT_HEIGHT(&elem->rect));
232}
233
235{
236 if (elem == NULL)
237 {
238 return (point_t){0};
239 }
240
241 point_t offset = {.x = elem->rect.left, .y = elem->rect.top};
242 element_t* parent = elem->parent;
243 while (parent != NULL)
244 {
245 offset.x += parent->rect.left;
246 offset.y += parent->rect.top;
247 parent = parent->parent;
248 }
249
250 return offset;
251}
252
254{
255 if (elem == NULL || src == NULL)
256 {
257 return (rect_t){0};
258 }
259
260 point_t point = element_get_window_point(elem);
261 return (rect_t){
262 .left = point.x + src->left,
263 .top = point.y + src->top,
264 .right = point.x + src->right,
265 .bottom = point.y + src->bottom,
266 };
267}
268
270{
271 if (elem == NULL || src == NULL)
272 {
273 return (point_t){0};
274 }
275
276 point_t point = element_get_window_point(elem);
277 return (point_t){
278 .x = point.x + src->x,
279 .y = point.y + src->y,
280 };
281}
282
284{
285 if (elem == NULL || src == NULL)
286 {
287 return (rect_t){0};
288 }
289
290 point_t point = element_get_window_point(elem);
291 return (rect_t){
292 .left = src->left - point.x,
293 .top = src->top - point.y,
294 .right = src->right - point.x,
295 .bottom = src->bottom - point.y,
296 };
297}
298
300{
301 if (elem == NULL || src == NULL)
302 {
303 return (point_t){0};
304 }
305
306 point_t point = element_get_window_point(elem);
307 return (point_t){
308 .x = src->x - point.x,
309 .y = src->y - point.y,
310 };
311}
312
314{
315 if (elem == NULL)
316 {
317 return ELEMENT_NONE;
318 }
319
320 return elem->flags;
321}
322
324{
325 if (elem == NULL)
326 {
327 return;
328 }
329
330 elem->flags = flags;
331}
332
333const char* element_text_get(element_t* elem)
334{
335 if (elem == NULL)
336 {
337 return NULL;
338 }
339
340 return elem->text;
341}
342
343uint64_t element_set_text(element_t* elem, const char* text)
344{
345 if (elem == NULL || text == NULL)
346 {
347 return ERR;
348 }
349
350 char* newText = strdup(text);
351 if (newText == NULL)
352 {
353 return ERR;
354 }
355 free(elem->text);
356 elem->text = newText;
357
358 return 0;
359}
360
362{
363 if (elem == NULL)
364 {
365 return NULL;
366 }
367
368 return &elem->textProps;
369}
370
372{
373 if (elem == NULL)
374 {
375 return NULL;
376 }
377
378 return elem->image;
379}
380
382{
383 if (elem == NULL)
384 {
385 return;
386 }
387
388 elem->image = image;
389}
390
392{
393 if (elem == NULL)
394 {
395 return NULL;
396 }
397
398 return &elem->imageProps;
399}
400
402{
403 if (elem == NULL)
404 {
405 return NULL;
406 }
407
408 return &elem->theme;
409}
410
412{
413 if (elem == NULL || draw == NULL)
414 {
415 return;
416 }
417
418 rect_t globalRect = element_get_window_rect(elem);
419
420 draw->disp = elem->win->disp;
421 draw->stride = RECT_WIDTH(&elem->win->rect);
422 draw->buffer = &elem->win->buffer[globalRect.left + globalRect.top * draw->stride];
423 draw->contentRect = RECT_INIT(0, 0, RECT_WIDTH(&elem->rect), RECT_HEIGHT(&elem->rect));
424 draw->invalidRect = (rect_t){0};
425}
426
428{
429 if (elem == NULL || draw == NULL)
430 {
431 return;
432 }
433
434 rect_t globalInvalid = element_rect_to_window(elem, &draw->invalidRect);
435 window_invalidate(elem->win, &globalInvalid);
436
437 if (RECT_AREA(&draw->invalidRect) != 0)
438 {
439 element_t* child;
440 LIST_FOR_EACH(child, &elem->children, entry)
441 {
442 if (RECT_OVERLAP(&draw->invalidRect, &child->rect))
443 {
444 element_redraw(child, false);
445 }
446 }
447 }
448}
449
450void element_redraw(element_t* elem, bool shouldPropagate)
451{
452 if (elem == NULL)
453 {
454 return;
455 }
456
457 levent_redraw_t event;
458 event.id = elem->id;
459 event.shouldPropagate = shouldPropagate;
460 display_push(elem->win->disp, elem->win->surface, LEVENT_REDRAW, &event, sizeof(levent_redraw_t));
461}
462
464{
465 if (elem == NULL)
466 {
467 return;
468 }
469
471 event.dest = elem->id;
472 event.action = action;
473 display_push(elem->win->disp, elem->win->surface, LEVENT_FORCE_ACTION, &event, sizeof(levent_force_action_t));
474}
475
477{
478 if (elem == NULL || event == NULL)
479 {
480 errno = EINVAL;
481 return ERR;
482 }
483
484 switch (event->type)
485 {
486 case LEVENT_INIT:
487 {
488 if (elem->proc(elem->win, elem, event) == ERR)
489 {
490 return ERR;
491 }
492 }
493 break;
494 case LEVENT_REDRAW:
495 {
496 if (elem->proc(elem->win, elem, event) == ERR)
497 {
498 return ERR;
499 }
500
501 if (event->lRedraw.shouldPropagate)
502 {
503 element_t* child;
504 LIST_FOR_EACH(child, &elem->children, entry)
505 {
506 element_emit(child, event->type, event->raw, EVENT_MAX_DATA);
507 }
508 }
509 }
510 break;
511 case EVENT_MOUSE:
512 {
513 // Move mouse pos to be centered around elements origin.
514 event_t movedEvent = *event;
515 movedEvent.mouse.pos.x -= elem->rect.left;
516 movedEvent.mouse.pos.y -= elem->rect.top;
517
518 if (elem->proc(elem->win, elem, &movedEvent) == ERR)
519 {
520 return ERR;
521 }
522
523 element_t* child;
524 LIST_FOR_EACH(child, &elem->children, entry)
525 {
526 if (element_dispatch(child, &movedEvent) == ERR)
527 {
528 return ERR;
529 }
530 }
531 }
532 break;
533 default:
534 {
535 if (elem->proc(elem->win, elem, event) == ERR)
536 {
537 return ERR;
538 }
539
540 element_t* child;
541 LIST_FOR_EACH(child, &elem->children, entry)
542 {
543 if (element_dispatch(child, event) == ERR)
544 {
545 return ERR;
546 }
547 }
548 }
549 break;
550 }
551
552 return 0;
553}
554
556{
557 if (elem == NULL || (data == NULL && size > 0) || size > EVENT_MAX_DATA)
558 {
559 errno = EINVAL;
560 return ERR;
561 }
562
563 event_t event = {
564 .target = elem->win->surface,
565 .type = type,
566 };
567 memcpy(event.raw, data, MIN(EVENT_MAX_DATA, size));
568 return element_dispatch(elem, &event);
569}
static char id[MAX_NAME]
Definition dwm.c:20
static fd_t data
Definition dwm.c:21
image_t * element_image_get(element_t *elem)
Definition element.c:371
const char * element_text_get(element_t *elem)
Definition element.c:333
static uint64_t element_send_init(element_t *elem)
Definition element.c:6
static void element_free_children(element_t *elem)
Definition element.c:102
static element_t * element_new_raw(element_id_t id, const rect_t *rect, const char *text, element_flags_t flags, procedure_t procedure, void *private)
Definition element.c:18
element_flags_t element_flags_get(element_t *elem)
Definition element.c:313
element_t * element_new_root(window_t *win, element_id_t id, const rect_t *rect, const char *text, element_flags_t flags, procedure_t procedure, void *private)
Definition element.c:76
image_props_t * element_image_props_get(element_t *elem)
Definition element.c:391
void display_push(display_t *disp, surface_id_t target, event_type_t type, void *data, uint64_t size)
Push an event to the display's internal event queue.
Definition display.c:349
@ ALIGN_CENTER
Definition drawable.h:49
text_props_t * element_get_text_props(element_t *elem)
Get the text properties of an element.
Definition element.c:361
void element_set_image(element_t *elem, image_t *image)
Set the image of an element.
Definition element.c:381
void element_set_flags(element_t *elem, element_flags_t flags)
Set the flags of an element.
Definition element.c:323
void element_set_private(element_t *elem, void *private)
Set private data for an element.
Definition element.c:163
element_t * element_find(element_t *elem, element_id_t id)
Find a child element by its ID.
Definition element.c:134
#define ELEMENT_ID_NONE
Element ID indicating no element.
Definition element_id.h:28
uint64_t element_emit(element_t *elem, event_type_t type, const void *data, uint64_t size)
Emit an event to an element.
Definition element.c:555
theme_t * element_get_theme(element_t *elem)
Get the theme of an element.
Definition element.c:401
point_t element_point_to_window(element_t *elem, const point_t *src)
Convert a point from element coordinates to window coordinates.
Definition element.c:269
rect_t element_window_to_rect(element_t *elem, const rect_t *src)
Convert a rectangle from window coordinates to element coordinates.
Definition element.c:283
uint64_t element_dispatch(element_t *elem, const event_t *event)
Dispatch an event to an element.
Definition element.c:476
void element_draw_end(element_t *elem, drawable_t *draw)
End drawing to an element.
Definition element.c:427
element_t * element_new(element_t *parent, element_id_t id, const rect_t *rect, const char *text, element_flags_t flags, procedure_t procedure, void *private)
Allocate and initialize a new element.
Definition element.c:48
#define ELEMENT_NONE
Definition element.h:43
rect_t element_get_content_rect(element_t *elem)
Get the element's rectangle in local coordinates.
Definition element.c:213
uint64_t element_flags_t
Element flags type.
Definition element.h:41
void element_draw_begin(element_t *elem, drawable_t *draw)
Begin drawing to an element.
Definition element.c:411
rect_t element_rect_to_window(element_t *elem, const rect_t *src)
Convert a rectangle from element coordinates to window coordinates.
Definition element.c:253
uint64_t element_id_t
Element identifier type.
Definition element_id.h:23
rect_t element_get_window_rect(element_t *elem)
Get the rectangle of an element in window coordinates.
Definition element.c:223
void element_free(element_t *elem)
Deinitialize and free an element and all its children.
Definition element.c:113
point_t element_get_window_point(element_t *elem)
Get the top-left point of an element in window coordinates.
Definition element.c:234
void element_redraw(element_t *elem, bool shouldPropagate)
Redraw an element.
Definition element.c:450
element_id_t element_get_id(element_t *elem)
Get the ID of an element.
Definition element.c:183
uint64_t element_set_text(element_t *elem, const char *text)
Set the text of an element.
Definition element.c:343
rect_t element_get_rect(element_t *elem)
Get the rectangle of an element in its parent's coordinate space.
Definition element.c:203
point_t element_window_to_point(element_t *elem, const point_t *src)
Convert a point from window coordinates to element coordinates.
Definition element.c:299
void element_move(element_t *elem, const rect_t *rect)
Move an element to a new rectangle in its parent's coordinate space.
Definition element.c:193
void element_force_action(element_t *elem, action_type_t action)
Force an action on an element.
Definition element.c:463
void * element_get_private(element_t *elem)
Get private data for an element.
Definition element.c:173
#define LEVENT_FORCE_ACTION
Definition event.h:104
#define EVENT_MOUSE
Definition event.h:85
#define LEVENT_DEINIT
Definition event.h:100
#define EVENT_MAX_DATA
Maximum size of event data.
Definition event.h:263
#define LEVENT_REDRAW
Definition event.h:101
#define LEVENT_INIT
Definition event.h:99
action_type_t
Action type.
Definition event.h:48
uint16_t event_type_t
Event type.
Definition event.h:72
theme_t * theme_global_get(void)
Get the global theme.
Definition theme.c:97
void window_invalidate(window_t *win, const rect_t *rect)
Invalidate a rectangle of the window.
Definition window.c:553
#define EINVAL
Invalid argument.
Definition errno.h:142
#define ENOMEM
Out of memory.
Definition errno.h:92
#define errno
Error number variable.
Definition errno.h:27
#define LIST_FOR_EACH(elem, list, member)
Iterates over a list.
Definition list.h:65
#define LIST_FOR_EACH_SAFE(elem, temp, list, member)
Safely iterates over a list, allowing for element removal during iteration.
Definition list.h:81
static void list_remove(list_t *list, list_entry_t *entry)
Removes a list entry from its current list.
Definition list.h:317
static void list_push(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:345
static void list_entry_init(list_entry_t *entry)
Initializes a list entry.
Definition list.h:184
static void list_init(list_t *list)
Initializes a list.
Definition list.h:198
#define MIN(x, y)
Definition math.h:16
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
uint64_t(* procedure_t)(window_t *, element_t *, const event_t *)
Definition procedure.h:15
static uint64_t procedure(window_t *win, element_t *elem, const event_t *event)
Definition main.c:46
static image_t * image
Definition main.c:5
#define RECT_OVERLAP(rect, other)
Definition rect.h:65
#define RECT_AREA(rect)
Definition rect.h:40
#define RECT_INIT_DIM(x, y, width, height)
Definition rect.h:32
#define RECT_INIT(left, top, right, bottom)
Definition rect.h:26
#define RECT_HEIGHT(rect)
Definition rect.h:39
#define RECT_WIDTH(rect)
Definition rect.h:38
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
_PUBLIC void * malloc(size_t size)
Definition malloc.c:5
_PUBLIC void free(void *ptr)
Definition free.c:11
char * strdup(const char *src)
Definition strdup.c:5
_PUBLIC void * memcpy(void *_RESTRICT s1, const void *_RESTRICT s2, size_t n)
Definition memcpy.c:4
Drawable structure.
Definition drawable.h:35
pixel_t * buffer
Definition drawable.h:38
uint32_t stride
Definition drawable.h:37
rect_t contentRect
Definition drawable.h:39
display_t * disp
Definition drawable.h:36
rect_t invalidRect
Definition drawable.h:40
Opaque element structure.
Definition internal.h:23
procedure_t proc
Definition internal.h:28
element_id_t id
Definition internal.h:27
image_props_t imageProps
Definition internal.h:36
rect_t rect
Definition internal.h:31
image_t * image
Definition internal.h:35
list_t children
Definition internal.h:25
void * private
Definition internal.h:30
element_flags_t flags
Definition internal.h:32
theme_t theme
Definition internal.h:37
struct element * parent
Definition internal.h:26
list_entry_t entry
Definition internal.h:24
window_t * win
Definition internal.h:29
char * text
Definition internal.h:33
text_props_t textProps
Definition internal.h:34
point_t pos
Definition event.h:155
Event structure.
Definition event.h:271
surface_id_t target
Definition event.h:273
event_type_t type
Definition event.h:272
uint8_t raw[EVENT_MAX_DATA]
Definition event.h:290
event_mouse_t mouse
Definition event.h:278
levent_redraw_t lRedraw
Definition event.h:287
Element image properties structure.
Definition element.h:77
align_t xAlign
Definition element.h:78
Library Force Action event.
Definition event.h:255
element_id_t dest
Definition event.h:256
Library Redraw event.
Definition event.h:233
element_id_t id
Definition event.h:234
bool shouldPropagate
Whether the redraw event should be propagated to child elements.
Definition event.h:235
int64_t y
Definition point.h:14
int64_t x
Definition point.h:13
Definition rect.h:13
int32_t bottom
Definition rect.h:17
int32_t top
Definition rect.h:15
int32_t right
Definition rect.h:16
int32_t left
Definition rect.h:14
Element text properties structure.
Definition element.h:63
align_t xAlign
Definition element.h:64
Theme structure.
Definition theme.h:71
Opaque window structure.
Definition internal.h:44
rect_t rect
Definition internal.h:48
pixel_t * buffer
Definition internal.h:53
surface_id_t surface
Definition internal.h:52
display_t * disp
Definition internal.h:46