comparison libmlk-ui/mlk/ui/notify.c @ 433:862b15c3a3ae

ui: cleanup hierarchy
author David Demelier <markand@malikania.fr>
date Sat, 15 Oct 2022 21:19:25 +0200
parents src/libmlk-ui/ui/notify.c@8f59201dc76b
children 773a082f0b91
comparison
equal deleted inserted replaced
432:38cf60f5a1c4 433:862b15c3a3ae
1 /*
2 * notify.c -- in game notifications
3 *
4 * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <assert.h>
20 #include <stddef.h>
21 #include <string.h>
22
23 #include <mlk/core/font.h>
24 #include <mlk/core/texture.h>
25 #include <mlk/core/trace.h>
26 #include <mlk/core/window.h>
27
28 #include "align.h"
29 #include "frame.h"
30 #include "label.h"
31 #include "notify.h"
32 #include "theme.h"
33
34 #define WIDTH (window.w / 3)
35 #define HEIGHT (window.h / 10)
36
37 struct geo {
38 const struct theme *theme;
39 int frame_x;
40 int frame_y;
41 unsigned int frame_w;
42 unsigned int frame_h;
43 int icon_x;
44 int icon_y;
45 int title_x;
46 int title_y;
47 int body_x;
48 int body_y;
49 };
50
51 static void draw(const struct notify *, size_t);
52
53 static const struct notify_system default_system = {
54 .draw = draw
55 };
56 static const struct notify_system *system = &default_system;
57 static struct notify stack[NOTIFY_MAX];
58 static size_t stacksz;
59
60 static void
61 geometry(struct geo *geo, const struct notify *n, size_t index)
62 {
63 int x, y;
64
65 /* Determine theme. */
66 geo->theme = system->theme ? system->theme : theme_default();
67
68 /* Determine notification position. */
69 x = window.w - geo->theme->padding;
70 x -= WIDTH;
71
72 y = geo->theme->padding * (index + 1);;
73 y += HEIGHT * index;
74
75 /* Content frame. */
76 geo->frame_x = x;
77 geo->frame_y = y;
78 geo->frame_w = WIDTH;
79 geo->frame_h = HEIGHT;
80
81 /* Align icon at the left center. */
82 if (n->icon->h >= HEIGHT) {
83 tracef("notification icon is too large: %u > %u", n->icon->h, HEIGHT);
84 geo->icon_x = x + geo->theme->padding;
85 geo->icon_y = y + geo->theme->padding;
86 } else {
87 align(ALIGN_LEFT, &geo->icon_x, &geo->icon_y, n->icon->w, n->icon->h, x, y, WIDTH, HEIGHT);
88 geo->icon_x += geo->icon_y - y;
89 }
90
91 /* Align title to the right of the icon at the same y coordinate. */
92 geo->title_x = geo->icon_x + n->icon->w + geo->theme->padding;
93 geo->title_y = geo->icon_y;
94 geo->title_y -= font_height(geo->theme->fonts[THEME_FONT_IMPORTANT]) / 2;
95
96 /* Align body so it ends at the end of the icon. */
97 geo->body_x = geo->title_x;
98 geo->body_y = geo->icon_y + n->icon->h;
99 geo->body_y -= font_height(geo->theme->fonts[THEME_FONT_INTERFACE]) / 2;
100 }
101
102 static void
103 draw_frame(const struct geo *geo)
104 {
105 const struct frame f = {
106 .x = geo->frame_x,
107 .y = geo->frame_y,
108 .w = geo->frame_w,
109 .h = geo->frame_h
110 };
111
112 frame_draw(&f);
113 }
114
115 static void
116 draw_icon(const struct geo *geo, const struct notify *n)
117 {
118 texture_draw(n->icon, geo->icon_x, geo->icon_y);
119 }
120
121 #include <stdio.h>
122
123 static void
124 draw_title(const struct geo *geo, const struct notify *n)
125 {
126 const struct label l = {
127 .x = geo->title_x,
128 .y = geo->title_y,
129 .text = n->title,
130 .flags = LABEL_FLAGS_SHADOW | LABEL_FLAGS_IMPORTANT
131 };
132
133 label_draw(&l);
134 }
135
136 static void
137 draw_body(const struct geo *geo, const struct notify *n)
138 {
139 const struct label l = {
140 .x = geo->body_x,
141 .y = geo->body_y,
142 .text = n->body,
143 .flags = LABEL_FLAGS_SHADOW
144 };
145
146 label_draw(&l);
147 }
148
149 static void
150 draw(const struct notify *n, size_t index)
151 {
152 struct geo geo;
153
154 /* Compute notification size and widgets. */
155 geometry(&geo, n, index);
156
157 draw_frame(&geo);
158 draw_icon(&geo, n);
159 draw_title(&geo, n);
160 draw_body(&geo, n);
161 }
162
163 void
164 notify(const struct texture *icon, const char *title, const char *body)
165 {
166 assert(icon);
167 assert(title);
168 assert(body);
169
170 struct notify *n;
171
172 if (stacksz >= NOTIFY_MAX) {
173 memmove(&stack[0], &stack[1], sizeof (stack[0]) - NOTIFY_MAX - 1);
174 n = &stack[NOTIFY_MAX - 1];
175 } else
176 n = &stack[stacksz++];
177
178 memset(n, 0, sizeof (*n));
179 n->icon = icon;
180 n->title = title;
181 n->body = body;
182 }
183
184 void
185 notify_update(unsigned int ticks)
186 {
187 struct notify *n;
188
189 for (size_t i = 0; i < stacksz; ++i) {
190 n = &stack[i];
191 n->elapsed += ticks;
192
193 if (n->elapsed >= NOTIFY_TIMEOUT_DEFAULT)
194 memmove(n, n + 1, sizeof (*n) * (--stacksz - i));
195 }
196 }
197
198 void
199 notify_draw(void)
200 {
201 for (size_t i = 0; i < stacksz; ++i)
202 system->draw(&stack[i], i);
203 }
204
205 void
206 notify_set_system(const struct notify_system *sys)
207 {
208 system = sys ? sys : &default_system;
209 }