comparison librpg/rpg/message.c @ 148:c577c15df07f

misc: split libraries, closes #2496
author David Demelier <markand@malikania.fr>
date Thu, 15 Oct 2020 10:32:18 +0200
parents libcore/core/message.c@7d7ea7a9cf50
children 9733d379be89
comparison
equal deleted inserted replaced
147:b386d25832c8 148:c577c15df07f
1 /*
2 * message.c -- message dialog
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 <assert.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <core/action.h>
24 #include <core/event.h>
25 #include <core/font.h>
26 #include <core/maths.h>
27 #include <core/painter.h>
28 #include <core/panic.h>
29 #include <core/sprite.h>
30 #include <core/trace.h>
31 #include <core/util.h>
32
33 #include <ui/frame.h>
34 #include <ui/label.h>
35 #include <ui/theme.h>
36
37 #include "message.h"
38
39 #define THEME(msg) (msg->theme ? msg->theme : theme_default())
40
41 static void
42 handle(struct action *action, const union event *ev)
43 {
44 assert(action);
45 assert(ev);
46
47 message_handle(action->data, ev);
48 }
49
50 static bool
51 update(struct action *action, unsigned int ticks)
52 {
53 assert(action);
54
55 return message_update(action->data, ticks);
56 }
57
58 static void
59 draw(struct action *action)
60 {
61 assert(action);
62
63 message_draw(action->data);
64 }
65
66 static void
67 draw_frame(const struct message *msg)
68 {
69 assert(msg);
70
71 struct frame frame = {
72 .w = msg->w,
73 .h = msg->h,
74 .theme = msg->theme
75 };
76
77 frame_draw(&frame);
78 }
79
80 static void
81 draw_lines(const struct message *msg)
82 {
83 struct theme theme;
84 unsigned int lineh;
85
86 /* Shallow copy theme to modify colors. */
87 theme_shallow(&theme, msg->theme);
88
89 /* Compute text size for list alignment. */
90 lineh = font_height(theme.fonts[THEME_FONT_INTERFACE]);
91
92 for (int i = 0; i < 6; ++i) {
93 if (!msg->text[i])
94 continue;
95
96 struct label label = {
97 .y = i * lineh,
98 .w = msg->w,
99 .h = msg->h,
100 .theme = &theme,
101 .text = msg->text[i],
102 .align = LABEL_ALIGN_TOP_LEFT,
103 .flags = LABEL_FLAGS_SHADOW
104 };
105
106 /*
107 * The function label_draw will use THEME_COLOR_NORMAL to draw
108 * text and THEME_COLOR_SHADOW so if we have selected a line
109 * we need to cheat the normal color.
110 */
111 if (msg->flags & MESSAGE_FLAGS_QUESTION && msg->index == (unsigned int)i)
112 theme.colors[THEME_COLOR_NORMAL] = THEME(msg)->colors[THEME_COLOR_SELECTED];
113 else
114 theme.colors[THEME_COLOR_NORMAL] = THEME(msg)->colors[THEME_COLOR_NORMAL];
115
116 label_draw(&label);
117 }
118 }
119
120 void
121 message_start(struct message *msg)
122 {
123 assert(msg);
124
125 if (msg->flags & (MESSAGE_FLAGS_FADEIN|MESSAGE_FLAGS_FADEOUT))
126 assert(msg->delay > 0);
127
128 msg->elapsed = 0;
129 msg->scale = msg->flags & MESSAGE_FLAGS_FADEIN ? 0.0 : 1.0;
130 msg->state = msg->flags & MESSAGE_FLAGS_FADEIN
131 ? MESSAGE_STATE_OPENING
132 : MESSAGE_STATE_SHOWING;
133
134 if (msg->flags & MESSAGE_FLAGS_AUTOMATIC && msg->timeout == 0)
135 trace("message is automatic but has zero timeout");
136 }
137
138 void
139 message_handle(struct message *msg, const union event *ev)
140 {
141 assert(msg);
142 assert(ev);
143
144 /* Skip if the message animation hasn't complete. */
145 if (msg->state != MESSAGE_STATE_SHOWING)
146 return;
147
148 /* Only keyboard event are valid. */
149 if (ev->type != EVENT_KEYDOWN || msg->state == MESSAGE_STATE_NONE)
150 return;
151
152 switch (ev->key.key) {
153 case KEY_UP:
154 if (msg->index > 0)
155 msg->index--;
156 break;
157 case KEY_DOWN:
158 if (msg->index < 5 && msg->text[msg->index + 1])
159 msg->index++;
160 break;
161 case KEY_ENTER:
162 msg->state = msg->flags & MESSAGE_FLAGS_FADEOUT
163 ? MESSAGE_STATE_HIDING
164 : MESSAGE_STATE_NONE;
165 msg->elapsed = 0;
166 break;
167 default:
168 break;
169 }
170 }
171
172 bool
173 message_update(struct message *msg, unsigned int ticks)
174 {
175 assert(msg);
176
177 msg->elapsed += ticks;
178
179 switch (msg->state) {
180 case MESSAGE_STATE_OPENING:
181 msg->scale = (double)msg->elapsed / (double)msg->delay;
182
183 if (msg->scale > 1)
184 msg->scale = 1;
185
186 if (msg->elapsed >= msg->delay) {
187 msg->state = MESSAGE_STATE_SHOWING;
188 msg->elapsed = 0;
189 }
190
191 break;
192 case MESSAGE_STATE_SHOWING:
193 /* Do automatically switch state if requested by the user. */
194 if (msg->flags & MESSAGE_FLAGS_AUTOMATIC && msg->elapsed >= msg->timeout) {
195 msg->state = msg->flags & MESSAGE_FLAGS_FADEOUT
196 ? MESSAGE_STATE_HIDING
197 : MESSAGE_STATE_NONE;
198 msg->elapsed = 0;
199 }
200
201 break;
202 case MESSAGE_STATE_HIDING:
203 msg->scale = 1 - (double)msg->elapsed / (double)msg->delay;
204
205 if (msg->scale < 0)
206 msg->scale = 0;
207 if (msg->elapsed >= msg->delay) {
208 msg->state = MESSAGE_STATE_NONE;
209 msg->elapsed = 0;
210 }
211
212 break;
213 default:
214 break;
215 }
216
217 return msg->state == MESSAGE_STATE_NONE;
218 }
219
220 void
221 message_draw(struct message *msg)
222 {
223 assert(msg);
224
225 struct texture tex;
226 int x, y;
227 unsigned int w, h;
228
229 if (!texture_new(&tex, msg->w, msg->h))
230 panic();
231
232 PAINTER_BEGIN(&tex);
233 draw_frame(msg);
234 draw_lines(msg);
235 PAINTER_END();
236
237 /* Compute scaling. */
238 w = msg->w * msg->scale;
239 h = msg->h * msg->scale;
240
241 /* Centerize within its drawing area. */
242 maths_centerize(&x, &y, w, h, msg->x, msg->y, msg->w, msg->h);
243
244 /* Draw and clear. */
245 texture_scale(&tex, 0, 0, msg->w, msg->h, x, y, w, h, 0);
246 texture_finish(&tex);
247 }
248
249 void
250 message_hide(struct message *msg)
251 {
252 assert(msg);
253
254 msg->state = MESSAGE_STATE_HIDING;
255 msg->elapsed = 0;
256 }
257
258 void
259 message_action(struct message *msg, struct action *action)
260 {
261 assert(msg);
262 assert(action);
263
264 memset(action, 0, sizeof (struct action));
265 action->data = msg;
266 action->handle = handle;
267 action->update = update;
268 action->draw = draw;
269
270 message_start(msg);
271 }