source: mainline/uspace/lib/ui/src/msgdialog.c@ afb4025

Last change on this file since afb4025 was 12dd36c, checked in by Jiri Svoboda <jiri@…>, 8 months ago

Handle Enter/Escape keys in message dialog.

  • Property mode set to 100644
File size: 8.0 KB
Line 
1/*
2 * Copyright (c) 2024 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libui
30 * @{
31 */
32/**
33 * @file Message dialog
34 */
35
36#include <errno.h>
37#include <mem.h>
38#include <stdlib.h>
39#include <ui/fixed.h>
40#include <ui/label.h>
41#include <ui/msgdialog.h>
42#include <ui/pbutton.h>
43#include <ui/resource.h>
44#include <ui/ui.h>
45#include <ui/window.h>
46#include "../private/msgdialog.h"
47
48static void ui_msg_dialog_wnd_close(ui_window_t *, void *);
49static void ui_msg_dialog_wnd_kbd(ui_window_t *, void *, kbd_event_t *);
50
51ui_window_cb_t ui_msg_dialog_wnd_cb = {
52 .close = ui_msg_dialog_wnd_close,
53 .kbd = ui_msg_dialog_wnd_kbd
54};
55
56static void ui_msg_dialog_btn_clicked(ui_pbutton_t *, void *);
57
58ui_pbutton_cb_t ui_msg_dialog_btn_cb = {
59 .clicked = ui_msg_dialog_btn_clicked
60};
61
62static const char *ui_msg_dialog_captions[][ui_msg_dialog_maxbtn + 1] = {
63 [umdc_ok] = { "OK", NULL },
64 [umdc_ok_cancel] = { "OK", "Cancel", NULL }
65};
66
67/** Initialize message dialog parameters structure.
68 *
69 * Message dialog parameters structure must always be initialized using
70 * this function first.
71 *
72 * @param params Message dialog parameters structure
73 */
74void ui_msg_dialog_params_init(ui_msg_dialog_params_t *params)
75{
76 memset(params, 0, sizeof(ui_msg_dialog_params_t));
77}
78
79/** Create new message dialog.
80 *
81 * @param ui User interface
82 * @param params Message dialog parameters
83 * @param rdialog Place to store pointer to new dialog
84 * @return EOK on success or an error code
85 */
86errno_t ui_msg_dialog_create(ui_t *ui, ui_msg_dialog_params_t *params,
87 ui_msg_dialog_t **rdialog)
88{
89 errno_t rc;
90 ui_msg_dialog_t *dialog;
91 ui_window_t *window = NULL;
92 ui_wnd_params_t wparams;
93 ui_fixed_t *fixed = NULL;
94 ui_label_t *label = NULL;
95 ui_pbutton_t *btn[ui_msg_dialog_maxbtn];
96 const char **cp;
97 unsigned i, nb;
98 gfx_rect_t rect;
99 gfx_coord_t bw, bpad, btnsw, bp0x;
100 ui_resource_t *ui_res;
101
102 for (i = 0; i < ui_msg_dialog_maxbtn; i++)
103 btn[i] = NULL;
104
105 dialog = calloc(1, sizeof(ui_msg_dialog_t));
106 if (dialog == NULL) {
107 rc = ENOMEM;
108 goto error;
109 }
110
111 ui_wnd_params_init(&wparams);
112 wparams.caption = params->caption;
113
114 /* FIXME: Auto layout */
115 if (ui_is_textmode(ui)) {
116 wparams.rect.p0.x = 0;
117 wparams.rect.p0.y = 0;
118 wparams.rect.p1.x = 60;
119 wparams.rect.p1.y = 7;
120 } else {
121 wparams.rect.p0.x = 0;
122 wparams.rect.p0.y = 0;
123 wparams.rect.p1.x = 400;
124 wparams.rect.p1.y = 110;
125 }
126
127 rc = ui_window_create(ui, &wparams, &window);
128 if (rc != EOK)
129 goto error;
130
131 ui_window_set_cb(window, &ui_msg_dialog_wnd_cb, dialog);
132
133 ui_res = ui_window_get_res(window);
134
135 rc = ui_fixed_create(&fixed);
136 if (rc != EOK)
137 goto error;
138
139 rc = ui_label_create(ui_res, params->text, &label);
140 if (rc != EOK)
141 goto error;
142
143 /* FIXME: Auto layout */
144 if (ui_is_textmode(ui)) {
145 rect.p0.x = 3;
146 rect.p0.y = 2;
147 rect.p1.x = 57;
148 rect.p1.y = 3;
149 } else {
150 rect.p0.x = 10;
151 rect.p0.y = 35;
152 rect.p1.x = 390;
153 rect.p1.y = 50;
154 }
155
156 ui_label_set_rect(label, &rect);
157 ui_label_set_halign(label, gfx_halign_center);
158
159 rc = ui_fixed_add(fixed, ui_label_ctl(label));
160 if (rc != EOK)
161 goto error;
162
163 label = NULL;
164
165 i = 0;
166 assert(params->choice == umdc_ok || params->choice == umdc_ok_cancel);
167 cp = ui_msg_dialog_captions[params->choice];
168
169 while (*cp != NULL) {
170 rc = ui_pbutton_create(ui_res, *cp, &btn[i]);
171 if (rc != EOK)
172 goto error;
173
174 ui_pbutton_set_cb(btn[i], &ui_msg_dialog_btn_cb, dialog);
175 ++cp;
176 ++i;
177 }
178
179 nb = i;
180
181 if (ui_is_textmode(ui)) {
182 bw = 12;
183 bpad = 2;
184 } else {
185 bw = 90;
186 bpad = 10;
187 }
188
189 btnsw = (nb - 1) * (bw + bpad) + bw;
190 bp0x = (wparams.rect.p0.x + wparams.rect.p1.x - btnsw) / 2;
191
192 for (i = 0; i < nb; i++) {
193 /* FIXME: Auto layout */
194 if (ui_is_textmode(ui)) {
195 rect.p0.x = bp0x + i * (bw + bpad);
196 rect.p0.y = 4;
197 rect.p1.x = bp0x + bw + i * (bw + bpad);
198 rect.p1.y = 5;
199 } else {
200 rect.p0.x = bp0x + i * (bw + bpad);
201 rect.p0.y = 60;
202 rect.p1.x = bp0x + bw + i * (bw + bpad);
203 rect.p1.y = 88;
204 }
205
206 ui_pbutton_set_rect(btn[i], &rect);
207
208 rc = ui_fixed_add(fixed, ui_pbutton_ctl(btn[i]));
209 if (rc != EOK)
210 goto error;
211 }
212
213 ui_pbutton_set_default(btn[0], true);
214
215 for (i = 0; i < ui_msg_dialog_maxbtn; i++) {
216 dialog->btn[i] = btn[i];
217 btn[i] = NULL;
218 }
219
220 ui_window_add(window, ui_fixed_ctl(fixed));
221 fixed = NULL;
222
223 rc = ui_window_paint(window);
224 if (rc != EOK)
225 goto error;
226
227 dialog->window = window;
228 *rdialog = dialog;
229 return EOK;
230error:
231 for (i = 0; i < ui_msg_dialog_maxbtn; i++) {
232 if (btn[i] != NULL)
233 ui_pbutton_destroy(btn[i]);
234 }
235 if (label != NULL)
236 ui_label_destroy(label);
237 if (fixed != NULL)
238 ui_fixed_destroy(fixed);
239 if (window != NULL)
240 ui_window_destroy(window);
241 if (dialog != NULL)
242 free(dialog);
243 return rc;
244}
245
246/** Destroy message dialog.
247 *
248 * @param dialog Message dialog or @c NULL
249 */
250void ui_msg_dialog_destroy(ui_msg_dialog_t *dialog)
251{
252 if (dialog == NULL)
253 return;
254
255 ui_window_destroy(dialog->window);
256 free(dialog);
257}
258
259/** Set mesage dialog callback.
260 *
261 * @param dialog Message dialog
262 * @param cb Message dialog callbacks
263 * @param arg Callback argument
264 */
265void ui_msg_dialog_set_cb(ui_msg_dialog_t *dialog, ui_msg_dialog_cb_t *cb,
266 void *arg)
267{
268 dialog->cb = cb;
269 dialog->arg = arg;
270}
271
272/** Message dialog window close handler.
273 *
274 * @param window Window
275 * @param arg Argument (ui_msg_dialog_t *)
276 */
277static void ui_msg_dialog_wnd_close(ui_window_t *window, void *arg)
278{
279 ui_msg_dialog_t *dialog = (ui_msg_dialog_t *) arg;
280
281 if (dialog->cb != NULL && dialog->cb->close != NULL)
282 dialog->cb->close(dialog, dialog->arg);
283}
284
285/** Message dialog window keyboard event handler.
286 *
287 * @param window Window
288 * @param arg Argument (ui_msg_dialog_t *)
289 * @param event Keyboard event
290 */
291static void ui_msg_dialog_wnd_kbd(ui_window_t *window, void *arg,
292 kbd_event_t *event)
293{
294 ui_msg_dialog_t *dialog = (ui_msg_dialog_t *) arg;
295 ui_evclaim_t claim;
296
297 claim = ui_window_def_kbd(window, event);
298 if (claim == ui_claimed)
299 return;
300
301 if (event->type == KEY_PRESS &&
302 (event->mods & (KM_CTRL | KM_SHIFT | KM_ALT)) == 0) {
303 if (event->key == KC_ENTER) {
304 /* OK / default button */
305 if (dialog->cb != NULL && dialog->cb->button != NULL) {
306 dialog->cb->button(dialog, dialog->arg, 0);
307 return;
308 }
309 } else if (event->key == KC_ESCAPE) {
310 /* Cancel */
311 if (dialog->cb != NULL && dialog->cb->close != NULL) {
312 dialog->cb->close(dialog, dialog->arg);
313 return;
314 }
315 }
316 }
317
318}
319
320/** Message dialog button click handler.
321 *
322 * @param pbutton Push button
323 * @param arg Argument (ui_msg_dialog_t *)
324 */
325static void ui_msg_dialog_btn_clicked(ui_pbutton_t *pbutton, void *arg)
326{
327 ui_msg_dialog_t *dialog = (ui_msg_dialog_t *) arg;
328 unsigned i;
329
330 if (dialog->cb != NULL && dialog->cb->button != NULL) {
331 for (i = 0; i < ui_msg_dialog_maxbtn; i++) {
332 if (dialog->btn[i] == pbutton)
333 dialog->cb->button(dialog, dialog->arg, i);
334 }
335 }
336}
337
338/** @}
339 */
Note: See TracBrowser for help on using the repository browser.