Handle Enter/Escape keys in message dialog.
[helenos.git] / uspace / app / taskbar-cfg / startmenu.c
blob451a972a1a316af675dac68007142c5522293434
1 /*
2 * Copyright (c) 2024 Jiri Svoboda
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
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.
29 /** @addtogroup taskbar-cfg
30 * @{
32 /** @file Start menu configuration tab
35 #include <gfx/coord.h>
36 #include <loc.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <str.h>
40 #include <tbarcfg/tbarcfg.h>
41 #include <ui/control.h>
42 #include <ui/label.h>
43 #include <ui/list.h>
44 #include <ui/pbutton.h>
45 #include <ui/resource.h>
46 #include <ui/tab.h>
47 #include <ui/window.h>
48 #include "smeedit.h"
49 #include "startmenu.h"
50 #include "taskbar-cfg.h"
52 static void startmenu_entry_selected(ui_list_entry_t *, void *);
53 static void startmenu_new_entry_clicked(ui_pbutton_t *, void *);
54 static void startmenu_delete_entry_clicked(ui_pbutton_t *, void *);
55 static void startmenu_edit_entry_clicked(ui_pbutton_t *, void *);
56 static void startmenu_sep_entry_clicked(ui_pbutton_t *, void *);
57 static void startmenu_up_entry_clicked(ui_pbutton_t *, void *);
58 static void startmenu_down_entry_clicked(ui_pbutton_t *, void *);
60 /** Entry list callbacks */
61 ui_list_cb_t startmenu_entry_list_cb = {
62 .selected = startmenu_entry_selected
65 /** New entry button callbacks */
66 ui_pbutton_cb_t startmenu_new_entry_button_cb = {
67 .clicked = startmenu_new_entry_clicked
70 /** Delete entry button callbacks */
71 ui_pbutton_cb_t startmenu_delete_entry_button_cb = {
72 .clicked = startmenu_delete_entry_clicked
75 /** Edit entry button callbacks */
76 ui_pbutton_cb_t startmenu_edit_entry_button_cb = {
77 .clicked = startmenu_edit_entry_clicked
80 /** Separator entry button callbacks */
81 ui_pbutton_cb_t startmenu_sep_entry_button_cb = {
82 .clicked = startmenu_sep_entry_clicked
85 /** Move entry up button callbacks */
86 ui_pbutton_cb_t startmenu_up_entry_button_cb = {
87 .clicked = startmenu_up_entry_clicked
90 /** Move entry down button callbacks */
91 ui_pbutton_cb_t startmenu_down_entry_button_cb = {
92 .clicked = startmenu_down_entry_clicked
95 /** Create start menu configuration tab
97 * @param tbcfg Taskbar configuration dialog
98 * @param rsmenu Place to store pointer to new start menu configuration tab
99 * @return EOK on success or an error code
101 errno_t startmenu_create(taskbar_cfg_t *tbcfg, startmenu_t **rsmenu)
103 ui_resource_t *ui_res;
104 startmenu_t *smenu;
105 gfx_rect_t rect;
106 errno_t rc;
108 ui_res = ui_window_get_res(tbcfg->window);
110 smenu = calloc(1, sizeof(startmenu_t));
111 if (smenu == NULL) {
112 printf("Out of memory.\n");
113 return ENOMEM;
116 smenu->tbarcfg = tbcfg;
118 /* 'Start Menu' tab */
120 rc = ui_tab_create(tbcfg->tabset, "Start Menu", &smenu->tab);
121 if (rc != EOK)
122 goto error;
124 rc = ui_fixed_create(&smenu->fixed);
125 if (rc != EOK) {
126 printf("Error creating fixed layout.\n");
127 goto error;
130 /* 'Start menu entries:' label */
132 rc = ui_label_create(ui_res, "Start menu entries:",
133 &smenu->entries_label);
134 if (rc != EOK) {
135 printf("Error creating label.\n");
136 goto error;
139 if (ui_resource_is_textmode(ui_res)) {
140 rect.p0.x = 4;
141 rect.p0.y = 4;
142 rect.p1.x = 36;
143 rect.p1.y = 5;
144 } else {
145 rect.p0.x = 20;
146 rect.p0.y = 60;
147 rect.p1.x = 360;
148 rect.p1.y = 80;
151 ui_label_set_rect(smenu->entries_label, &rect);
153 rc = ui_fixed_add(smenu->fixed, ui_label_ctl(smenu->entries_label));
154 if (rc != EOK) {
155 printf("Error adding control to layout.\n");
156 goto error;
159 /* List of entries */
161 rc = ui_list_create(tbcfg->window, false, &smenu->entries_list);
162 if (rc != EOK) {
163 printf("Error creating list.\n");
164 goto error;
167 if (ui_resource_is_textmode(ui_res)) {
168 rect.p0.x = 4;
169 rect.p0.y = 5;
170 rect.p1.x = 56;
171 rect.p1.y = 20;
172 } else {
173 rect.p0.x = 20;
174 rect.p0.y = 80;
175 rect.p1.x = 360;
176 rect.p1.y = 330;
179 ui_list_set_rect(smenu->entries_list, &rect);
181 rc = ui_fixed_add(smenu->fixed, ui_list_ctl(smenu->entries_list));
182 if (rc != EOK) {
183 printf("Error adding control to layout.\n");
184 goto error;
187 ui_list_set_cb(smenu->entries_list, &startmenu_entry_list_cb,
188 (void *)smenu);
190 /* New entry button */
192 rc = ui_pbutton_create(ui_res, "New...", &smenu->new_entry);
193 if (rc != EOK) {
194 printf("Error creating button.\n");
195 goto error;
198 if (ui_resource_is_textmode(ui_res)) {
199 rect.p0.x = 58;
200 rect.p0.y = 5;
201 rect.p1.x = 68;
202 rect.p1.y = 6;
203 } else {
204 rect.p0.x = 370;
205 rect.p0.y = 80;
206 rect.p1.x = 450;
207 rect.p1.y = 105;
210 ui_pbutton_set_rect(smenu->new_entry, &rect);
212 rc = ui_fixed_add(smenu->fixed, ui_pbutton_ctl(smenu->new_entry));
213 if (rc != EOK) {
214 printf("Error adding control to layout.\n");
215 goto error;
218 ui_pbutton_set_cb(smenu->new_entry, &startmenu_new_entry_button_cb,
219 (void *)smenu);
221 /* Delete entry button */
223 rc = ui_pbutton_create(ui_res, "Delete", &smenu->delete_entry);
224 if (rc != EOK) {
225 printf("Error creating button.\n");
226 goto error;
229 if (ui_resource_is_textmode(ui_res)) {
230 rect.p0.x = 58;
231 rect.p0.y = 7;
232 rect.p1.x = 68;
233 rect.p1.y = 8;
234 } else {
235 rect.p0.x = 370;
236 rect.p0.y = 110;
237 rect.p1.x = 450;
238 rect.p1.y = 135;
241 ui_pbutton_set_rect(smenu->delete_entry, &rect);
243 rc = ui_fixed_add(smenu->fixed, ui_pbutton_ctl(smenu->delete_entry));
244 if (rc != EOK) {
245 printf("Error adding control to layout.\n");
246 goto error;
249 ui_pbutton_set_cb(smenu->delete_entry,
250 &startmenu_delete_entry_button_cb, (void *)smenu);
252 /* Edit entry button */
254 rc = ui_pbutton_create(ui_res, "Edit...", &smenu->edit_entry);
255 if (rc != EOK) {
256 printf("Error creating button.\n");
257 goto error;
260 if (ui_resource_is_textmode(ui_res)) {
261 rect.p0.x = 58;
262 rect.p0.y = 9;
263 rect.p1.x = 68;
264 rect.p1.y = 10;
265 } else {
266 rect.p0.x = 370;
267 rect.p0.y = 140;
268 rect.p1.x = 450;
269 rect.p1.y = 165;
272 ui_pbutton_set_rect(smenu->edit_entry, &rect);
274 rc = ui_fixed_add(smenu->fixed, ui_pbutton_ctl(smenu->edit_entry));
275 if (rc != EOK) {
276 printf("Error adding control to layout.\n");
277 goto error;
280 ui_pbutton_set_cb(smenu->edit_entry,
281 &startmenu_edit_entry_button_cb, (void *)smenu);
283 /* Separator entry button */
285 rc = ui_pbutton_create(ui_res, "Separator", &smenu->sep_entry);
286 if (rc != EOK) {
287 printf("Error creating button.\n");
288 goto error;
291 if (ui_resource_is_textmode(ui_res)) {
292 rect.p0.x = 58;
293 rect.p0.y = 11;
294 rect.p1.x = 68;
295 rect.p1.y = 12;
296 } else {
297 rect.p0.x = 370;
298 rect.p0.y = 170;
299 rect.p1.x = 450;
300 rect.p1.y = 195;
303 ui_pbutton_set_rect(smenu->sep_entry, &rect);
305 rc = ui_fixed_add(smenu->fixed, ui_pbutton_ctl(smenu->sep_entry));
306 if (rc != EOK) {
307 printf("Error adding control to layout.\n");
308 goto error;
311 ui_pbutton_set_cb(smenu->sep_entry,
312 &startmenu_sep_entry_button_cb, (void *)smenu);
314 /* Move entry up button */
316 rc = ui_pbutton_create(ui_res, "Up", &smenu->up_entry);
317 if (rc != EOK) {
318 printf("Error creating button.\n");
319 goto error;
322 if (ui_resource_is_textmode(ui_res)) {
323 rect.p0.x = 58;
324 rect.p0.y = 13;
325 rect.p1.x = 68;
326 rect.p1.y = 14;
327 } else {
328 rect.p0.x = 370;
329 rect.p0.y = 220;
330 rect.p1.x = 450;
331 rect.p1.y = 245;
334 ui_pbutton_set_rect(smenu->up_entry, &rect);
336 rc = ui_fixed_add(smenu->fixed, ui_pbutton_ctl(smenu->up_entry));
337 if (rc != EOK) {
338 printf("Error adding control to layout.\n");
339 goto error;
342 ui_pbutton_set_cb(smenu->up_entry,
343 &startmenu_up_entry_button_cb, (void *)smenu);
345 /* Move entry down button */
347 rc = ui_pbutton_create(ui_res, "Down", &smenu->down_entry);
348 if (rc != EOK) {
349 printf("Error creating button.\n");
350 goto error;
353 if (ui_resource_is_textmode(ui_res)) {
354 rect.p0.x = 58;
355 rect.p0.y = 15;
356 rect.p1.x = 68;
357 rect.p1.y = 16;
358 } else {
359 rect.p0.x = 370;
360 rect.p0.y = 250;
361 rect.p1.x = 450;
362 rect.p1.y = 275;
365 ui_pbutton_set_rect(smenu->down_entry, &rect);
367 rc = ui_fixed_add(smenu->fixed, ui_pbutton_ctl(smenu->down_entry));
368 if (rc != EOK) {
369 printf("Error adding control to layout.\n");
370 goto error;
373 ui_pbutton_set_cb(smenu->down_entry,
374 &startmenu_down_entry_button_cb, (void *)smenu);
376 ui_tab_add(smenu->tab, ui_fixed_ctl(smenu->fixed));
378 *rsmenu = smenu;
379 return EOK;
380 error:
381 if (smenu->down_entry != NULL)
382 ui_pbutton_destroy(smenu->down_entry);
383 if (smenu->up_entry != NULL)
384 ui_pbutton_destroy(smenu->up_entry);
385 if (smenu->delete_entry != NULL)
386 ui_pbutton_destroy(smenu->delete_entry);
387 if (smenu->new_entry != NULL)
388 ui_pbutton_destroy(smenu->new_entry);
389 if (smenu->entries_label != NULL)
390 ui_label_destroy(smenu->entries_label);
391 if (smenu->entries_list != NULL)
392 ui_list_destroy(smenu->entries_list);
393 if (smenu->fixed != NULL)
394 ui_fixed_destroy(smenu->fixed);
395 free(smenu);
396 return rc;
399 /** Populate start menu tab with start menu configuration data
401 * @param smenu Start menu configuration tab
402 * @param tbarcfg Taskbar configuration
403 * @return EOK on success or an error code
405 errno_t startmenu_populate(startmenu_t *smenu, tbarcfg_t *tbarcfg)
407 smenu_entry_t *entry;
408 startmenu_entry_t *smentry;
409 errno_t rc;
411 entry = tbarcfg_smenu_first(tbarcfg);
412 while (entry != NULL) {
413 rc = startmenu_insert(smenu, entry, &smentry);
414 if (rc != EOK)
415 return rc;
417 entry = tbarcfg_smenu_next(entry);
420 return EOK;
423 /** Destroy start menu configuration tab.
425 * @param smenu Start menu configuration tab
427 void startmenu_destroy(startmenu_t *smenu)
429 ui_list_entry_t *lentry;
430 startmenu_entry_t *entry;
432 lentry = ui_list_first(smenu->entries_list);
433 while (lentry != NULL) {
434 entry = (startmenu_entry_t *)ui_list_entry_get_arg(lentry);
435 free(entry);
436 ui_list_entry_delete(lentry);
437 lentry = ui_list_first(smenu->entries_list);
440 /* This will automatically destroy all controls in the tab */
441 ui_tab_destroy(smenu->tab);
442 free(smenu);
445 /** Insert new entry into entries list.
447 * @param smenu Start menu configuration tab
448 * @param entry Backing entry
449 * @param rsmentry Place to store pointer to new entry or NULL
450 * @return EOK on success or an error code
452 errno_t startmenu_insert(startmenu_t *smenu, smenu_entry_t *entry,
453 startmenu_entry_t **rsmentry)
455 startmenu_entry_t *smentry;
456 ui_list_entry_attr_t attr;
457 bool separator;
458 errno_t rc;
460 smentry = calloc(1, sizeof(startmenu_entry_t));
461 if (smentry == NULL)
462 return ENOMEM;
464 smentry->startmenu = smenu;
465 smentry->entry = entry;
467 ui_list_entry_attr_init(&attr);
468 separator = smenu_entry_get_separator(entry);
469 if (separator)
470 attr.caption = "-- Separator --";
471 else
472 attr.caption = smenu_entry_get_caption(entry);
474 attr.arg = (void *)smentry;
476 rc = ui_list_entry_append(smenu->entries_list, &attr, &smentry->lentry);
477 if (rc != EOK) {
478 free(smentry);
479 return rc;
482 if (rsmentry != NULL)
483 *rsmentry = smentry;
484 return EOK;
487 /** Get selected start menu entry.
489 * @param smenu Start menu
490 * @return Selected entry or @c NULL if no entry is selected
492 startmenu_entry_t *startmenu_get_selected(startmenu_t *smenu)
494 ui_list_entry_t *entry;
496 entry = ui_list_get_cursor(smenu->entries_list);
497 if (entry == NULL)
498 return NULL;
500 return (startmenu_entry_t *)ui_list_entry_get_arg(entry);
503 /** Create new menu entry.
505 * @param smenu Start menu
507 void startmenu_new_entry(startmenu_t *smenu)
509 smeedit_t *smee;
510 errno_t rc;
512 rc = smeedit_create(smenu, NULL, &smee);
513 if (rc != EOK)
514 return;
516 (void)smee;
517 (void)tbarcfg_sync(smenu->tbarcfg->tbarcfg);
518 (void)tbarcfg_notify(TBARCFG_NOTIFY_DEFAULT);
521 /** Create new separator menu entry.
523 * @param smenu Start menu
525 void startmenu_sep_entry(startmenu_t *smenu)
527 startmenu_entry_t *smentry = NULL;
528 smenu_entry_t *entry;
529 errno_t rc;
531 rc = smenu_entry_sep_create(smenu->tbarcfg->tbarcfg, &entry);
532 if (rc != EOK)
533 return;
535 (void)startmenu_insert(smenu, entry, &smentry);
536 (void)ui_control_paint(ui_list_ctl(smenu->entries_list));
537 (void)tbarcfg_sync(smenu->tbarcfg->tbarcfg);
538 (void)tbarcfg_notify(TBARCFG_NOTIFY_DEFAULT);
541 /** Edit selected menu entry.
543 * @param smenu Start menu
545 void startmenu_edit(startmenu_t *smenu)
547 smeedit_t *smee;
548 startmenu_entry_t *smentry;
549 errno_t rc;
551 smentry = startmenu_get_selected(smenu);
552 if (smentry == NULL)
553 return;
555 /* Do not edit separator entries */
556 if (smenu_entry_get_separator(smentry->entry))
557 return;
559 rc = smeedit_create(smenu, smentry, &smee);
560 if (rc != EOK)
561 return;
563 (void)smee;
566 /** Update start menu entry caption.
568 * When editing an entry the entry's label might change. We need
569 * to update the list entry caption to reflect that.
571 * @param entry Start menu entry
573 errno_t startmenu_entry_update(startmenu_entry_t *entry)
575 return ui_list_entry_set_caption(entry->lentry,
576 smenu_entry_get_caption(entry->entry));
579 /** Repaint start menu entry list.
581 * When editing an entry the entry's label might change. We need
582 * to update the list entry caption to reflect that.
584 * @param smenu Start menu
586 void startmenu_repaint(startmenu_t *smenu)
588 (void) ui_control_paint(ui_list_ctl(smenu->entries_list));
591 /** Entry in entry list is selected.
593 * @param lentry UI list entry
594 * @param arg Argument (dcfg_seats_entry_t *)
596 static void startmenu_entry_selected(ui_list_entry_t *lentry, void *arg)
598 (void)lentry;
599 (void)arg;
602 /** New entry button clicked.
604 * @param pbutton Push button
605 * @param arg Argument (startmenu_t *)
607 static void startmenu_new_entry_clicked(ui_pbutton_t *pbutton, void *arg)
609 startmenu_t *smenu = (startmenu_t *)arg;
611 (void)pbutton;
612 startmenu_new_entry(smenu);
615 /** Delete entry button clicked.
617 * @param pbutton Push button
618 * @param arg Argument (startmenu_t *)
620 static void startmenu_delete_entry_clicked(ui_pbutton_t *pbutton, void *arg)
622 startmenu_t *smenu = (startmenu_t *)arg;
623 startmenu_entry_t *smentry;
625 (void)pbutton;
627 smentry = startmenu_get_selected(smenu);
628 if (smentry == NULL)
629 return;
631 smenu_entry_destroy(smentry->entry);
632 ui_list_entry_delete(smentry->lentry);
633 free(smentry);
635 (void)ui_control_paint(ui_list_ctl(smenu->entries_list));
636 (void)tbarcfg_sync(smenu->tbarcfg->tbarcfg);
637 (void)tbarcfg_notify(TBARCFG_NOTIFY_DEFAULT);
640 /** Edit entry button clicked.
642 * @param pbutton Push button
643 * @param arg Argument (startmenu_t *)
645 static void startmenu_edit_entry_clicked(ui_pbutton_t *pbutton, void *arg)
647 startmenu_t *smenu = (startmenu_t *)arg;
649 (void)pbutton;
650 startmenu_edit(smenu);
653 /** Separator entry button clicked.
655 * @param pbutton Push button
656 * @param arg Argument (startmenu_t *)
658 static void startmenu_sep_entry_clicked(ui_pbutton_t *pbutton, void *arg)
660 startmenu_t *smenu = (startmenu_t *)arg;
662 (void)pbutton;
663 startmenu_sep_entry(smenu);
666 /** Up entry button clicked.
668 * @param pbutton Push button
669 * @param arg Argument (startmenu_t *)
671 static void startmenu_up_entry_clicked(ui_pbutton_t *pbutton, void *arg)
673 startmenu_t *smenu = (startmenu_t *)arg;
674 startmenu_entry_t *smentry;
676 (void)pbutton;
678 smentry = startmenu_get_selected(smenu);
679 if (smentry == NULL)
680 return;
682 smenu_entry_move_up(smentry->entry);
683 ui_list_entry_move_up(smentry->lentry);
685 (void)ui_control_paint(ui_list_ctl(smenu->entries_list));
686 (void)tbarcfg_sync(smenu->tbarcfg->tbarcfg);
687 (void)tbarcfg_notify(TBARCFG_NOTIFY_DEFAULT);
690 /** Down entry button clicked.
692 * @param pbutton Push button
693 * @param arg Argument (startmenu_t *)
695 static void startmenu_down_entry_clicked(ui_pbutton_t *pbutton, void *arg)
697 startmenu_t *smenu = (startmenu_t *)arg;
698 startmenu_entry_t *smentry;
700 (void)pbutton;
702 smentry = startmenu_get_selected(smenu);
703 if (smentry == NULL)
704 return;
706 smenu_entry_move_down(smentry->entry);
707 ui_list_entry_move_down(smentry->lentry);
709 (void)ui_control_paint(ui_list_ctl(smenu->entries_list));
710 (void)tbarcfg_sync(smenu->tbarcfg->tbarcfg);
711 (void)tbarcfg_notify(TBARCFG_NOTIFY_DEFAULT);
714 /** @}