source: mainline/uspace/lib/ui/src/filedialog.c

Last change on this file 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: 10.8 KB
RevLine 
[5e109e1]1/*
[12dd36c]2 * Copyright (c) 2024 Jiri Svoboda
[5e109e1]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 File dialog
34 */
35
36#include <errno.h>
37#include <mem.h>
38#include <stdlib.h>
39#include <ui/entry.h>
40#include <ui/fixed.h>
41#include <ui/label.h>
42#include <ui/filedialog.h>
[11662bd]43#include <ui/filelist.h>
[5e109e1]44#include <ui/pbutton.h>
45#include <ui/resource.h>
46#include <ui/ui.h>
47#include <ui/window.h>
48#include "../private/filedialog.h"
49
50static void ui_file_dialog_wnd_close(ui_window_t *, void *);
[6c0766b]51static void ui_file_dialog_wnd_kbd(ui_window_t *, void *, kbd_event_t *);
[5e109e1]52
53ui_window_cb_t ui_file_dialog_wnd_cb = {
[6c0766b]54 .close = ui_file_dialog_wnd_close,
55 .kbd = ui_file_dialog_wnd_kbd
[5e109e1]56};
57
[11662bd]58static void ui_file_dialog_flist_activate_req(ui_file_list_t *, void *);
59static void ui_file_dialog_flist_selected(ui_file_list_t *, void *,
60 const char *);
61
62ui_file_list_cb_t ui_file_dialog_flist_cb = {
63 .activate_req = ui_file_dialog_flist_activate_req,
64 .selected = ui_file_dialog_flist_selected
65};
66
[5e109e1]67static void ui_file_dialog_bok_clicked(ui_pbutton_t *, void *);
68static void ui_file_dialog_bcancel_clicked(ui_pbutton_t *, void *);
69
70ui_pbutton_cb_t ui_file_dialog_bok_cb = {
71 .clicked = ui_file_dialog_bok_clicked
72};
73
74ui_pbutton_cb_t ui_file_dialog_bcancel_cb = {
75 .clicked = ui_file_dialog_bcancel_clicked
76};
77
78/** Initialize file dialog parameters structure.
79 *
80 * File dialog parameters structure must always be initialized using
81 * this function first.
82 *
83 * @param params File dialog parameters structure
84 */
85void ui_file_dialog_params_init(ui_file_dialog_params_t *params)
86{
87 memset(params, 0, sizeof(ui_file_dialog_params_t));
[e0cf963]88 params->ifname = "";
[5e109e1]89}
90
91/** Create new file dialog.
92 *
93 * @param ui User interface
94 * @param params File dialog parameters
95 * @param rdialog Place to store pointer to new dialog
96 * @return EOK on success or an error code
97 */
98errno_t ui_file_dialog_create(ui_t *ui, ui_file_dialog_params_t *params,
99 ui_file_dialog_t **rdialog)
100{
101 errno_t rc;
102 ui_file_dialog_t *dialog;
103 ui_window_t *window = NULL;
104 ui_wnd_params_t wparams;
105 ui_fixed_t *fixed = NULL;
106 ui_label_t *label = NULL;
107 ui_entry_t *entry = NULL;
[11662bd]108 ui_file_list_t *flist = NULL;
[5e109e1]109 ui_pbutton_t *bok = NULL;
110 ui_pbutton_t *bcancel = NULL;
111 gfx_rect_t rect;
112 ui_resource_t *ui_res;
113
114 dialog = calloc(1, sizeof(ui_file_dialog_t));
115 if (dialog == NULL) {
116 rc = ENOMEM;
117 goto error;
118 }
119
120 ui_wnd_params_init(&wparams);
121 wparams.caption = params->caption;
122
123 /* FIXME: Auto layout */
124 if (ui_is_textmode(ui)) {
125 wparams.rect.p0.x = 0;
126 wparams.rect.p0.y = 0;
127 wparams.rect.p1.x = 40;
[11662bd]128 wparams.rect.p1.y = 20;
[5e109e1]129 } else {
130 wparams.rect.p0.x = 0;
131 wparams.rect.p0.y = 0;
132 wparams.rect.p1.x = 300;
[11662bd]133 wparams.rect.p1.y = 335;
[5e109e1]134 }
135
136 rc = ui_window_create(ui, &wparams, &window);
137 if (rc != EOK)
138 goto error;
139
140 ui_window_set_cb(window, &ui_file_dialog_wnd_cb, dialog);
141
142 ui_res = ui_window_get_res(window);
143
144 rc = ui_fixed_create(&fixed);
145 if (rc != EOK)
146 goto error;
147
148 rc = ui_label_create(ui_res, "File Name:", &label);
149 if (rc != EOK)
150 goto error;
151
152 /* FIXME: Auto layout */
153 if (ui_is_textmode(ui)) {
154 rect.p0.x = 3;
[45004f3]155 rect.p0.y = 2;
[5e109e1]156 rect.p1.x = 17;
[45004f3]157 rect.p1.y = 3;
[5e109e1]158 } else {
159 rect.p0.x = 10;
160 rect.p0.y = 35;
161 rect.p1.x = 190;
162 rect.p1.y = 50;
163 }
164
165 ui_label_set_rect(label, &rect);
166
167 rc = ui_fixed_add(fixed, ui_label_ctl(label));
168 if (rc != EOK)
169 goto error;
170
171 label = NULL;
172
[e0cf963]173 rc = ui_entry_create(window, params->ifname, &entry);
[5e109e1]174 if (rc != EOK)
175 goto error;
176
177 /* FIXME: Auto layout */
178 if (ui_is_textmode(ui)) {
179 rect.p0.x = 3;
[11662bd]180 rect.p0.y = 3;
[5e109e1]181 rect.p1.x = 37;
[11662bd]182 rect.p1.y = 4;
[5e109e1]183 } else {
184 rect.p0.x = 10;
185 rect.p0.y = 55;
186 rect.p1.x = 290;
187 rect.p1.y = 80;
188 }
189
190 ui_entry_set_rect(entry, &rect);
191
192 rc = ui_fixed_add(fixed, ui_entry_ctl(entry));
193 if (rc != EOK)
194 goto error;
195
[a7a8f599]196 ui_entry_activate(entry);
197
[e0cf963]198 /* Select all */
199 ui_entry_seek_start(entry, false);
200 ui_entry_seek_end(entry, true);
201
[5e109e1]202 dialog->ename = entry;
203 entry = NULL;
204
[11662bd]205 /* Files label */
206 rc = ui_label_create(ui_res, "Files:", &label);
207 if (rc != EOK)
208 goto error;
209
210 /* FIXME: Auto layout */
211 if (ui_is_textmode(ui)) {
212 rect.p0.x = 3;
213 rect.p0.y = 5;
214 rect.p1.x = 17;
215 rect.p1.y = 6;
216 } else {
217 rect.p0.x = 10;
218 rect.p0.y = 90;
219 rect.p1.x = 190;
220 rect.p1.y = 105;
221 }
222
223 ui_label_set_rect(label, &rect);
224
225 rc = ui_fixed_add(fixed, ui_label_ctl(label));
226 if (rc != EOK)
227 goto error;
228
229 label = NULL;
230
231 /* File list */
232
233 rc = ui_file_list_create(window, false, &flist);
234 if (rc != EOK)
235 goto error;
236
237 /* FIXME: Auto layout */
238 if (ui_is_textmode(ui)) {
239 rect.p0.x = 3;
240 rect.p0.y = 6;
241 rect.p1.x = 37;
242 rect.p1.y = 16;
243 } else {
244 rect.p0.x = 10;
245 rect.p0.y = 110;
246 rect.p1.x = 290;
247 rect.p1.y = 280;
248 }
249
250 ui_file_list_set_rect(flist, &rect);
251 ui_file_list_set_cb(flist, &ui_file_dialog_flist_cb, dialog);
252
253 rc = ui_fixed_add(fixed, ui_file_list_ctl(flist));
254 if (rc != EOK)
255 goto error;
256
257 dialog->flist = flist;
258 flist = NULL;
259
260 rc = ui_file_list_read_dir(dialog->flist, ".");
261 if (rc != EOK)
262 goto error;
263
264 /* OK button */
265
[5e109e1]266 rc = ui_pbutton_create(ui_res, "OK", &bok);
267 if (rc != EOK)
268 goto error;
269
270 ui_pbutton_set_cb(bok, &ui_file_dialog_bok_cb, dialog);
271
272 /* FIXME: Auto layout */
273 if (ui_is_textmode(ui)) {
274 rect.p0.x = 10;
[11662bd]275 rect.p0.y = 17;
[5e109e1]276 rect.p1.x = 20;
[11662bd]277 rect.p1.y = 18;
[5e109e1]278 } else {
279 rect.p0.x = 55;
[11662bd]280 rect.p0.y = 290;
[5e109e1]281 rect.p1.x = 145;
[11662bd]282 rect.p1.y = 318;
[5e109e1]283 }
284
285 ui_pbutton_set_rect(bok, &rect);
286
287 ui_pbutton_set_default(bok, true);
288
289 rc = ui_fixed_add(fixed, ui_pbutton_ctl(bok));
290 if (rc != EOK)
291 goto error;
292
293 dialog->bok = bok;
294 bok = NULL;
295
[11662bd]296 /* Cancel button */
297
[5e109e1]298 rc = ui_pbutton_create(ui_res, "Cancel", &bcancel);
299 if (rc != EOK)
300 goto error;
301
302 ui_pbutton_set_cb(bcancel, &ui_file_dialog_bcancel_cb, dialog);
303
304 /* FIXME: Auto layout */
305 if (ui_is_textmode(ui)) {
306 rect.p0.x = 22;
[11662bd]307 rect.p0.y = 17;
[5e109e1]308 rect.p1.x = 32;
[11662bd]309 rect.p1.y = 18;
[5e109e1]310 } else {
311 rect.p0.x = 155;
[11662bd]312 rect.p0.y = 290;
[5e109e1]313 rect.p1.x = 245;
[11662bd]314 rect.p1.y = 318;
[5e109e1]315 }
316
317 ui_pbutton_set_rect(bcancel, &rect);
318
319 rc = ui_fixed_add(fixed, ui_pbutton_ctl(bcancel));
320 if (rc != EOK)
321 goto error;
322
323 dialog->bcancel = bcancel;
324 bcancel = NULL;
325
326 ui_window_add(window, ui_fixed_ctl(fixed));
327 fixed = NULL;
328
329 rc = ui_window_paint(window);
330 if (rc != EOK)
331 goto error;
332
333 dialog->window = window;
334 *rdialog = dialog;
335 return EOK;
336error:
337 if (entry != NULL)
338 ui_entry_destroy(entry);
[11662bd]339 if (flist != NULL)
340 ui_file_list_destroy(flist);
[5e109e1]341 if (bok != NULL)
342 ui_pbutton_destroy(bok);
343 if (bcancel != NULL)
344 ui_pbutton_destroy(bcancel);
345 if (label != NULL)
346 ui_label_destroy(label);
347 if (fixed != NULL)
348 ui_fixed_destroy(fixed);
349 if (window != NULL)
350 ui_window_destroy(window);
351 if (dialog != NULL)
352 free(dialog);
353 return rc;
354}
355
356/** Destroy file dialog.
357 *
358 * @param dialog File dialog or @c NULL
359 */
360void ui_file_dialog_destroy(ui_file_dialog_t *dialog)
361{
362 if (dialog == NULL)
363 return;
364
365 ui_window_destroy(dialog->window);
366 free(dialog);
367}
368
369/** Set mesage dialog callback.
370 *
371 * @param dialog File dialog
372 * @param cb File dialog callbacks
373 * @param arg Callback argument
374 */
375void ui_file_dialog_set_cb(ui_file_dialog_t *dialog, ui_file_dialog_cb_t *cb,
376 void *arg)
377{
378 dialog->cb = cb;
379 dialog->arg = arg;
380}
381
382/** File dialog window close handler.
383 *
384 * @param window Window
385 * @param arg Argument (ui_file_dialog_t *)
386 */
387static void ui_file_dialog_wnd_close(ui_window_t *window, void *arg)
388{
389 ui_file_dialog_t *dialog = (ui_file_dialog_t *) arg;
390
391 if (dialog->cb != NULL && dialog->cb->close != NULL)
392 dialog->cb->close(dialog, dialog->arg);
393}
394
[6c0766b]395/** File dialog window keyboard event handler.
396 *
397 * @param window Window
[12dd36c]398 * @param arg Argument (ui_file_dialog_t *)
[6c0766b]399 * @param event Keyboard event
400 */
401static void ui_file_dialog_wnd_kbd(ui_window_t *window, void *arg,
402 kbd_event_t *event)
403{
404 ui_file_dialog_t *dialog = (ui_file_dialog_t *) arg;
405 const char *fname;
[11662bd]406 ui_evclaim_t claim;
407
408 claim = ui_window_def_kbd(window, event);
409 if (claim == ui_claimed)
410 return;
[6c0766b]411
412 if (event->type == KEY_PRESS &&
413 (event->mods & (KM_CTRL | KM_SHIFT | KM_ALT)) == 0) {
414 if (event->key == KC_ENTER) {
415 /* Confirm */
416 if (dialog->cb != NULL && dialog->cb->bok != NULL) {
417 fname = ui_entry_get_text(dialog->ename);
418 dialog->cb->bok(dialog, dialog->arg, fname);
419 return;
420 }
421 } else if (event->key == KC_ESCAPE) {
422 /* Cancel */
423 if (dialog->cb != NULL && dialog->cb->bcancel != NULL) {
424 dialog->cb->bcancel(dialog, dialog->arg);
425 return;
426 }
427 }
428 }
[11662bd]429}
430
431static void ui_file_dialog_flist_activate_req(ui_file_list_t *flist, void *arg)
432{
433 ui_file_dialog_t *dialog = (ui_file_dialog_t *) arg;
434
435 ui_file_list_activate(dialog->flist);
436 ui_entry_deactivate(dialog->ename);
437}
438
439static void ui_file_dialog_flist_selected(ui_file_list_t *flist, void *arg,
440 const char *fname)
441{
442 ui_file_dialog_t *dialog = (ui_file_dialog_t *) arg;
443
444 dialog->cb->bok(dialog, dialog->arg, fname);
[6c0766b]445}
446
[5e109e1]447/** File dialog OK button click handler.
448 *
449 * @param pbutton Push button
450 * @param arg Argument (ui_file_dialog_t *)
451 */
452static void ui_file_dialog_bok_clicked(ui_pbutton_t *pbutton, void *arg)
453{
454 ui_file_dialog_t *dialog = (ui_file_dialog_t *) arg;
455 const char *fname;
456
457 if (dialog->cb != NULL && dialog->cb->bok != NULL) {
458 fname = ui_entry_get_text(dialog->ename);
459 dialog->cb->bok(dialog, dialog->arg, fname);
460 }
461}
462
463/** File dialog cancel button click handler.
464 *
465 * @param pbutton Push button
466 * @param arg Argument (ui_file_dialog_t *)
467 */
468static void ui_file_dialog_bcancel_clicked(ui_pbutton_t *pbutton, void *arg)
469{
470 ui_file_dialog_t *dialog = (ui_file_dialog_t *) arg;
471
472 if (dialog->cb != NULL && dialog->cb->bcancel != NULL)
473 dialog->cb->bcancel(dialog, dialog->arg);
474}
475
476/** @}
477 */
Note: See TracBrowser for help on using the repository browser.