source: mainline/uspace/app/taskbar-cfg/startmenu.c@ 384f081

Last change on this file since 384f081 was e63e74a, checked in by Jiri Svoboda <jiri@…>, 20 months ago

Start menu separator entry support

  • Property mode set to 100644
File size: 16.2 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 taskbar-cfg
30 * @{
31 */
32/** @file Start menu configuration tab
33 */
34
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"
51
52static void startmenu_entry_selected(ui_list_entry_t *, void *);
53static void startmenu_new_entry_clicked(ui_pbutton_t *, void *);
54static void startmenu_delete_entry_clicked(ui_pbutton_t *, void *);
55static void startmenu_edit_entry_clicked(ui_pbutton_t *, void *);
56static void startmenu_sep_entry_clicked(ui_pbutton_t *, void *);
57static void startmenu_up_entry_clicked(ui_pbutton_t *, void *);
58static void startmenu_down_entry_clicked(ui_pbutton_t *, void *);
59
60/** Entry list callbacks */
61ui_list_cb_t startmenu_entry_list_cb = {
62 .selected = startmenu_entry_selected
63};
64
65/** New entry button callbacks */
66ui_pbutton_cb_t startmenu_new_entry_button_cb = {
67 .clicked = startmenu_new_entry_clicked
68};
69
70/** Delete entry button callbacks */
71ui_pbutton_cb_t startmenu_delete_entry_button_cb = {
72 .clicked = startmenu_delete_entry_clicked
73};
74
75/** Edit entry button callbacks */
76ui_pbutton_cb_t startmenu_edit_entry_button_cb = {
77 .clicked = startmenu_edit_entry_clicked
78};
79
80/** Separator entry button callbacks */
81ui_pbutton_cb_t startmenu_sep_entry_button_cb = {
82 .clicked = startmenu_sep_entry_clicked
83};
84
85/** Move entry up button callbacks */
86ui_pbutton_cb_t startmenu_up_entry_button_cb = {
87 .clicked = startmenu_up_entry_clicked
88};
89
90/** Move entry down button callbacks */
91ui_pbutton_cb_t startmenu_down_entry_button_cb = {
92 .clicked = startmenu_down_entry_clicked
93};
94
95/** Create start menu configuration tab
96 *
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
100 */
101errno_t startmenu_create(taskbar_cfg_t *tbcfg, startmenu_t **rsmenu)
102{
103 ui_resource_t *ui_res;
104 startmenu_t *smenu;
105 gfx_rect_t rect;
106 errno_t rc;
107
108 ui_res = ui_window_get_res(tbcfg->window);
109
110 smenu = calloc(1, sizeof(startmenu_t));
111 if (smenu == NULL) {
112 printf("Out of memory.\n");
113 return ENOMEM;
114 }
115
116 smenu->tbarcfg = tbcfg;
117
118 /* 'Start Menu' tab */
119
120 rc = ui_tab_create(tbcfg->tabset, "Start Menu", &smenu->tab);
121 if (rc != EOK)
122 goto error;
123
124 rc = ui_fixed_create(&smenu->fixed);
125 if (rc != EOK) {
126 printf("Error creating fixed layout.\n");
127 goto error;
128 }
129
130 /* 'Start menu entries:' label */
131
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;
137 }
138
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;
149 }
150
151 ui_label_set_rect(smenu->entries_label, &rect);
152
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;
157 }
158
159 /* List of entries */
160
161 rc = ui_list_create(tbcfg->window, false, &smenu->entries_list);
162 if (rc != EOK) {
163 printf("Error creating list.\n");
164 goto error;
165 }
166
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;
177 }
178
179 ui_list_set_rect(smenu->entries_list, &rect);
180
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;
185 }
186
187 ui_list_set_cb(smenu->entries_list, &startmenu_entry_list_cb,
188 (void *)smenu);
189
190 /* New entry button */
191
192 rc = ui_pbutton_create(ui_res, "New...", &smenu->new_entry);
193 if (rc != EOK) {
194 printf("Error creating button.\n");
195 goto error;
196 }
197
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;
208 }
209
210 ui_pbutton_set_rect(smenu->new_entry, &rect);
211
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;
216 }
217
218 ui_pbutton_set_cb(smenu->new_entry, &startmenu_new_entry_button_cb,
219 (void *)smenu);
220
221 /* Delete entry button */
222
223 rc = ui_pbutton_create(ui_res, "Delete", &smenu->delete_entry);
224 if (rc != EOK) {
225 printf("Error creating button.\n");
226 goto error;
227 }
228
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;
239 }
240
241 ui_pbutton_set_rect(smenu->delete_entry, &rect);
242
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;
247 }
248
249 ui_pbutton_set_cb(smenu->delete_entry,
250 &startmenu_delete_entry_button_cb, (void *)smenu);
251
252 /* Edit entry button */
253
254 rc = ui_pbutton_create(ui_res, "Edit...", &smenu->edit_entry);
255 if (rc != EOK) {
256 printf("Error creating button.\n");
257 goto error;
258 }
259
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;
270 }
271
272 ui_pbutton_set_rect(smenu->edit_entry, &rect);
273
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;
278 }
279
280 ui_pbutton_set_cb(smenu->edit_entry,
281 &startmenu_edit_entry_button_cb, (void *)smenu);
282
283 /* Separator entry button */
284
285 rc = ui_pbutton_create(ui_res, "Separator", &smenu->sep_entry);
286 if (rc != EOK) {
287 printf("Error creating button.\n");
288 goto error;
289 }
290
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;
301 }
302
303 ui_pbutton_set_rect(smenu->sep_entry, &rect);
304
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;
309 }
310
311 ui_pbutton_set_cb(smenu->sep_entry,
312 &startmenu_sep_entry_button_cb, (void *)smenu);
313
314 /* Move entry up button */
315
316 rc = ui_pbutton_create(ui_res, "Up", &smenu->up_entry);
317 if (rc != EOK) {
318 printf("Error creating button.\n");
319 goto error;
320 }
321
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;
332 }
333
334 ui_pbutton_set_rect(smenu->up_entry, &rect);
335
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;
340 }
341
342 ui_pbutton_set_cb(smenu->up_entry,
343 &startmenu_up_entry_button_cb, (void *)smenu);
344
345 /* Move entry down button */
346
347 rc = ui_pbutton_create(ui_res, "Down", &smenu->down_entry);
348 if (rc != EOK) {
349 printf("Error creating button.\n");
350 goto error;
351 }
352
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;
363 }
364
365 ui_pbutton_set_rect(smenu->down_entry, &rect);
366
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;
371 }
372
373 ui_pbutton_set_cb(smenu->down_entry,
374 &startmenu_down_entry_button_cb, (void *)smenu);
375
376 ui_tab_add(smenu->tab, ui_fixed_ctl(smenu->fixed));
377
378 *rsmenu = smenu;
379 return EOK;
380error:
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;
397}
398
399/** Populate start menu tab with start menu configuration data
400 *
401 * @param smenu Start menu configuration tab
402 * @param tbarcfg Taskbar configuration
403 * @return EOK on success or an error code
404 */
405errno_t startmenu_populate(startmenu_t *smenu, tbarcfg_t *tbarcfg)
406{
407 smenu_entry_t *entry;
408 startmenu_entry_t *smentry;
409 errno_t rc;
410
411 entry = tbarcfg_smenu_first(tbarcfg);
412 while (entry != NULL) {
413 rc = startmenu_insert(smenu, entry, &smentry);
414 if (rc != EOK)
415 return rc;
416
417 entry = tbarcfg_smenu_next(entry);
418 }
419
420 return EOK;
421}
422
423/** Destroy start menu configuration tab.
424 *
425 * @param smenu Start menu configuration tab
426 */
427void startmenu_destroy(startmenu_t *smenu)
428{
429 ui_list_entry_t *lentry;
430 startmenu_entry_t *entry;
431
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);
438 }
439
440 /* This will automatically destroy all controls in the tab */
441 ui_tab_destroy(smenu->tab);
442 free(smenu);
443}
444
445/** Insert new entry into entries list.
446 *
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
451 */
452errno_t startmenu_insert(startmenu_t *smenu, smenu_entry_t *entry,
453 startmenu_entry_t **rsmentry)
454{
455 startmenu_entry_t *smentry;
456 ui_list_entry_attr_t attr;
457 bool separator;
458 errno_t rc;
459
460 smentry = calloc(1, sizeof(startmenu_entry_t));
461 if (smentry == NULL)
462 return ENOMEM;
463
464 smentry->startmenu = smenu;
465 smentry->entry = entry;
466
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);
473
474 attr.arg = (void *)smentry;
475
476 rc = ui_list_entry_append(smenu->entries_list, &attr, &smentry->lentry);
477 if (rc != EOK) {
478 free(smentry);
479 return rc;
480 }
481
482 if (rsmentry != NULL)
483 *rsmentry = smentry;
484 return EOK;
485}
486
487/** Get selected start menu entry.
488 *
489 * @param smenu Start menu
490 * @return Selected entry or @c NULL if no entry is selected
491 */
492startmenu_entry_t *startmenu_get_selected(startmenu_t *smenu)
493{
494 ui_list_entry_t *entry;
495
496 entry = ui_list_get_cursor(smenu->entries_list);
497 if (entry == NULL)
498 return NULL;
499
500 return (startmenu_entry_t *)ui_list_entry_get_arg(entry);
501}
502
503/** Create new menu entry.
504 *
505 * @param smenu Start menu
506 */
507void startmenu_new_entry(startmenu_t *smenu)
508{
509 smeedit_t *smee;
510 errno_t rc;
511
512 rc = smeedit_create(smenu, NULL, &smee);
513 if (rc != EOK)
514 return;
515
516 (void)smee;
517}
518
519/** Create new separator menu entry.
520 *
521 * @param smenu Start menu
522 */
523void startmenu_sep_entry(startmenu_t *smenu)
524{
525 startmenu_entry_t *smentry = NULL;
526 smenu_entry_t *entry;
527 errno_t rc;
528
529 rc = smenu_entry_sep_create(smenu->tbarcfg->tbarcfg, &entry);
530 if (rc != EOK)
531 return;
532
533 (void)startmenu_insert(smenu, entry, &smentry);
534 (void)ui_control_paint(ui_list_ctl(smenu->entries_list));
535}
536
537/** Edit selected menu entry.
538 *
539 * @param smenu Start menu
540 */
541void startmenu_edit(startmenu_t *smenu)
542{
543 smeedit_t *smee;
544 startmenu_entry_t *smentry;
545 errno_t rc;
546
547 smentry = startmenu_get_selected(smenu);
548 if (smentry == NULL)
549 return;
550
551 /* Do not edit separator entries */
552 if (smenu_entry_get_separator(smentry->entry))
553 return;
554
555 rc = smeedit_create(smenu, smentry, &smee);
556 if (rc != EOK)
557 return;
558
559 (void)smee;
560}
561
562/** Update start menu entry caption.
563 *
564 * When editing an entry the entry's label might change. We need
565 * to update the list entry caption to reflect that.
566 *
567 * @param entry Start menu entry
568 */
569errno_t startmenu_entry_update(startmenu_entry_t *entry)
570{
571 return ui_list_entry_set_caption(entry->lentry,
572 smenu_entry_get_caption(entry->entry));
573}
574
575/** Repaint start menu entry list.
576 *
577 * When editing an entry the entry's label might change. We need
578 * to update the list entry caption to reflect that.
579 *
580 * @param smenu Start menu
581 */
582void startmenu_repaint(startmenu_t *smenu)
583{
584 (void) ui_control_paint(ui_list_ctl(smenu->entries_list));
585}
586
587/** Entry in entry list is selected.
588 *
589 * @param lentry UI list entry
590 * @param arg Argument (dcfg_seats_entry_t *)
591 */
592static void startmenu_entry_selected(ui_list_entry_t *lentry, void *arg)
593{
594 (void)lentry;
595 (void)arg;
596}
597
598/** New entry button clicked.
599 *
600 * @param pbutton Push button
601 * @param arg Argument (startmenu_t *)
602 */
603static void startmenu_new_entry_clicked(ui_pbutton_t *pbutton, void *arg)
604{
605 startmenu_t *smenu = (startmenu_t *)arg;
606
607 (void)pbutton;
608 startmenu_new_entry(smenu);
609}
610
611/** Delete entry button clicked.
612 *
613 * @param pbutton Push button
614 * @param arg Argument (startmenu_t *)
615 */
616static void startmenu_delete_entry_clicked(ui_pbutton_t *pbutton, void *arg)
617{
618 startmenu_t *smenu = (startmenu_t *)arg;
619 startmenu_entry_t *smentry;
620 errno_t rc;
621
622 (void)pbutton;
623
624 smentry = startmenu_get_selected(smenu);
625 if (smentry == NULL)
626 return;
627
628 rc = smenu_entry_destroy(smentry->entry);
629 if (rc != EOK)
630 return;
631
632 ui_list_entry_delete(smentry->lentry);
633 free(smentry);
634 (void)ui_control_paint(ui_list_ctl(smenu->entries_list));
635}
636
637/** Edit entry button clicked.
638 *
639 * @param pbutton Push button
640 * @param arg Argument (startmenu_t *)
641 */
642static void startmenu_edit_entry_clicked(ui_pbutton_t *pbutton, void *arg)
643{
644 startmenu_t *smenu = (startmenu_t *)arg;
645
646 (void)pbutton;
647 startmenu_edit(smenu);
648}
649
650/** Separator entry button clicked.
651 *
652 * @param pbutton Push button
653 * @param arg Argument (startmenu_t *)
654 */
655static void startmenu_sep_entry_clicked(ui_pbutton_t *pbutton, void *arg)
656{
657 startmenu_t *smenu = (startmenu_t *)arg;
658
659 (void)pbutton;
660 startmenu_sep_entry(smenu);
661}
662
663/** Up entry button clicked.
664 *
665 * @param pbutton Push button
666 * @param arg Argument (startmenu_t *)
667 */
668static void startmenu_up_entry_clicked(ui_pbutton_t *pbutton, void *arg)
669{
670 startmenu_t *smenu = (startmenu_t *)arg;
671 startmenu_entry_t *smentry;
672 errno_t rc;
673
674 (void)pbutton;
675
676 smentry = startmenu_get_selected(smenu);
677 if (smentry == NULL)
678 return;
679
680 rc = smenu_entry_move_up(smentry->entry);
681 if (rc != EOK)
682 return;
683
684 ui_list_entry_move_up(smentry->lentry);
685
686 (void)ui_control_paint(ui_list_ctl(smenu->entries_list));
687}
688
689/** Down entry button clicked.
690 *
691 * @param pbutton Push button
692 * @param arg Argument (startmenu_t *)
693 */
694static void startmenu_down_entry_clicked(ui_pbutton_t *pbutton, void *arg)
695{
696 startmenu_t *smenu = (startmenu_t *)arg;
697 startmenu_entry_t *smentry;
698 errno_t rc;
699
700 (void)pbutton;
701
702 smentry = startmenu_get_selected(smenu);
703 if (smentry == NULL)
704 return;
705
706 rc = smenu_entry_move_up(smentry->entry);
707 if (rc != EOK)
708 return;
709
710 ui_list_entry_move_down(smentry->lentry);
711
712 (void)ui_control_paint(ui_list_ctl(smenu->entries_list));
713}
714
715/** @}
716 */
Note: See TracBrowser for help on using the repository browser.