comparison examples/example-ui/main.c @ 209:23a844fdc911

examples: move all into subdirectories, closes #2513
author David Demelier <markand@malikania.fr>
date Wed, 11 Nov 2020 17:10:40 +0100
parents examples/example-ui.c@133926e08d6e
children 76afe639fd72
comparison
equal deleted inserted replaced
208:c0e0d4accae8 209:23a844fdc911
1 /*
2 * example-action.c -- example on how to use automatic actions
3 *
4 * Copyright (c) 2020 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 <core/action.h>
20 #include <core/core.h>
21 #include <core/event.h>
22 #include <core/game.h>
23 #include <core/maths.h>
24 #include <core/panic.h>
25 #include <core/painter.h>
26 #include <core/state.h>
27 #include <core/sys.h>
28 #include <core/util.h>
29 #include <core/window.h>
30
31 #include <ui/align.h>
32 #include <ui/button.h>
33 #include <ui/checkbox.h>
34 #include <ui/frame.h>
35 #include <ui/label.h>
36 #include <ui/theme.h>
37 #include <ui/ui.h>
38
39 #define W (1280)
40 #define H (720)
41
42 #define FRAME_ORIGIN_X (10)
43 #define FRAME_ORIGIN_Y (10)
44 #define FRAME_WIDTH (400)
45 #define FRAME_HEIGHT (200)
46
47 #define HEADER_HEIGHT (32)
48
49 #define ELEMENT_HEIGHT (20)
50
51 /*
52 * We design a basic UI like this.
53 *
54 * FRAME_WIDTH
55 * +---------------------------------------------+--
56 * | Title | | HEADER_HEIGHT
57 * +---------------------------------------------+--
58 * | [x] Auto save |
59 * | |
60 * | |
61 * | [ Quit ] |
62 * +---------------------------------------------+
63 */
64 static struct {
65 struct action_stack st;
66
67 struct {
68 bool active;
69 int x;
70 int y;
71 } motion;
72
73 struct {
74 struct frame frame;
75 struct action act;
76 } panel;
77
78 struct {
79 struct label label;
80 struct action act;
81 } header;
82
83 struct {
84 struct checkbox cb;
85 struct action cb_act;
86 struct label label;
87 struct action label_act;
88 } autosave;
89
90 struct {
91 struct button button;
92 struct action act;
93 } quit;
94 } ui = {
95 .panel = {
96 .frame = {
97 .x = FRAME_ORIGIN_X,
98 .y = FRAME_ORIGIN_Y,
99 .w = FRAME_WIDTH,
100 .h = FRAME_HEIGHT
101 }
102 },
103 .header = {
104 .label = {
105 .text = "Preferences",
106 .x = FRAME_ORIGIN_X,
107 .y = FRAME_ORIGIN_Y,
108 .flags = LABEL_FLAGS_SHADOW,
109 }
110 },
111 .autosave = {
112 .cb = {
113 .w = ELEMENT_HEIGHT,
114 .h = ELEMENT_HEIGHT
115 },
116 .label = {
117 .text = "Auto save game",
118 .flags = LABEL_FLAGS_SHADOW,
119 }
120 },
121 .quit = {
122 .button = {
123 .text = "Quit",
124 .h = ELEMENT_HEIGHT
125 }
126 }
127 };
128
129 static void
130 init(void)
131 {
132 if (!core_init() || !ui_init())
133 panic();
134 if (!window_open("Example - UI", W, H))
135 panic();
136 }
137
138 static void
139 resize_header(void)
140 {
141 struct frame *f = &ui.panel.frame;
142 struct label *l = &ui.header.label;
143 unsigned int w, h;
144
145 /* Header. */
146 label_query(l, &w, &h);
147 align(ALIGN_LEFT, &l->x, &l->y, w, h, f->x, f->y, f->w, HEADER_HEIGHT);
148
149 l->x += theme_default()->padding;
150 }
151
152 static void
153 resize_autosave(void)
154 {
155 unsigned int padding = theme_default()->padding;
156 struct frame *f = &ui.panel.frame;
157 struct checkbox *c = &ui.autosave.cb;
158 struct label *l = &ui.autosave.label;
159
160 c->x = f->x + padding;
161 c->y = f->y + HEADER_HEIGHT + padding;
162
163 l->x = c->x + c->w + padding;
164 l->y = c->y;
165 }
166
167 static void
168 resize_button(void)
169 {
170 unsigned int padding = theme_default()->padding;
171 struct frame *f = &ui.panel.frame;
172 struct button *b = &ui.quit.button;
173
174 /* Button. */
175 b->w = f->w / 4;
176
177 align(ALIGN_BOTTOM_RIGHT, &b->x, &b->y, b->w, b->h,
178 f->x, f->y, f->w, f->h);
179
180 b->x -= padding;
181 b->y -= padding;
182 }
183
184 static void
185 resize(void)
186 {
187 resize_header();
188 resize_autosave();
189 resize_button();
190 }
191
192 static void
193 prepare(void)
194 {
195 /* Frame. */
196 frame_action(&ui.panel.frame, &ui.panel.act);
197
198 /* Header title. */
199 label_action(&ui.header.label, &ui.header.act);
200
201 /* Button quit. */
202 button_action(&ui.quit.button, &ui.quit.act);
203
204 /* Autosave. */
205 checkbox_action(&ui.autosave.cb, &ui.autosave.cb_act);
206 label_action(&ui.autosave.label, &ui.autosave.label_act);
207
208 /* Add all UI elements. */
209 action_stack_add(&ui.st, &ui.panel.act);
210 action_stack_add(&ui.st, &ui.header.act);
211 action_stack_add(&ui.st, &ui.autosave.cb_act);
212 action_stack_add(&ui.st, &ui.autosave.label_act);
213 action_stack_add(&ui.st, &ui.quit.act);
214 }
215
216 static bool
217 headerclick(int x, int y)
218 {
219 return maths_is_boxed(
220 ui.panel.frame.x,
221 ui.panel.frame.y,
222 ui.panel.frame.w,
223 HEADER_HEIGHT,
224 x,
225 y
226 );
227 }
228
229 static void
230 handle(struct state *st, const union event *ev)
231 {
232 (void)st;
233
234 switch (ev->type) {
235 case EVENT_QUIT:
236 game_quit();
237 break;
238 case EVENT_MOUSE:
239 if (ui.motion.active) {
240 ui.panel.frame.x += ev->mouse.x - ui.motion.x;
241 ui.panel.frame.y += ev->mouse.y - ui.motion.y;
242 ui.motion.x = ev->mouse.x;
243 ui.motion.y = ev->mouse.y;
244 resize();
245 }
246 break;
247 case EVENT_CLICKDOWN:
248 if (headerclick(ev->click.x, ev->click.y)) {
249 ui.motion.active = true;
250 ui.motion.x = ev->click.x;
251 ui.motion.y = ev->click.y;
252 window_set_cursor(WINDOW_CURSOR_SIZE);
253 }
254 else
255 action_stack_handle(&ui.st, ev);
256 break;
257 case EVENT_CLICKUP:
258 ui.motion.active = false;
259 window_set_cursor(WINDOW_CURSOR_ARROW);
260 /* Fallthrough. */
261 default:
262 action_stack_handle(&ui.st, ev);
263 break;
264 }
265 }
266
267 static void
268 update(struct state *st, unsigned int ticks)
269 {
270 (void)st;
271
272 if (ui.quit.button.state == BUTTON_STATE_ACTIVATED)
273 game_quit();
274 else
275 action_stack_update(&ui.st, ticks);
276 }
277
278 static void
279 draw(struct state *st)
280 {
281 (void)st;
282
283 painter_set_color(0xffffffff);
284 painter_clear();
285 action_stack_draw(&ui.st);
286 painter_present();
287 }
288
289 static void
290 run(void)
291 {
292 struct state state = {
293 .handle = handle,
294 .update = update,
295 .draw = draw
296 };
297
298 prepare();
299 resize();
300
301 game_switch(&state, true);
302 game_loop();
303 }
304
305 static void
306 quit(void)
307 {
308 window_finish();
309 ui_finish();
310 core_finish();
311 }
312
313 int
314 main(int argc, char **argv)
315 {
316 (void)argc;
317 (void)argv;
318
319 init();
320 run();
321 quit();
322
323 return 0;
324 }