Handle Enter/Escape keys in message dialog.
[helenos.git] / uspace / app / calculator / calculator.c
blob0d266a4d7e91edfd1383b4ac56fa5aeb756c643f
1 /*
2 * Copyright (c) 2023 Jiri Svoboda
3 * Copyright (c) 2016 Martin Decky
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 /** @addtogroup calculator
31 * @{
33 /** @file
35 * Inspired by the code released at https://github.com/osgroup/HelenOSProject
39 #include <clipboard.h>
40 #include <ctype.h>
41 #include <io/kbd_event.h>
42 #include <stdbool.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <str.h>
46 #include <ui/entry.h>
47 #include <ui/fixed.h>
48 #include <ui/menu.h>
49 #include <ui/menubar.h>
50 #include <ui/menudd.h>
51 #include <ui/menuentry.h>
52 #include <ui/pbutton.h>
53 #include <ui/ui.h>
54 #include <ui/window.h>
56 #define NAME "calculator"
58 #define NULL_DISPLAY "0"
60 #define SYNTAX_ERROR_DISPLAY "Syntax error"
61 #define NUMERIC_ERROR_DISPLAY "Numerical error"
62 #define UNKNOWN_ERROR_DISPLAY "Unknown error"
64 #define EXPR_MAX_LEN 22
66 typedef enum {
67 STATE_INITIAL = 0,
68 STATE_FINISH,
69 STATE_ERROR,
70 STATE_DIGIT,
71 STATE_VALUE
72 } parser_state_t;
74 typedef enum {
75 ERROR_SYNTAX = 0,
76 ERROR_NUMERIC
77 } error_type_t;
79 typedef enum {
80 OPERATOR_NONE = 0,
81 OPERATOR_ADD,
82 OPERATOR_SUB,
83 OPERATOR_MUL,
84 OPERATOR_DIV
85 } operator_t;
87 typedef enum {
88 ITEM_VALUE = 0,
89 ITEM_OPERATOR
90 } stack_item_type_t;
92 typedef struct {
93 link_t link;
95 stack_item_type_t type;
96 union {
97 int64_t value;
98 operator_t operator;
99 } data;
100 } stack_item_t;
102 /** Dimensions. Most of this should not be needed with auto layout */
103 typedef struct {
104 gfx_rect_t menubar_rect;
105 gfx_rect_t entry_rect;
106 gfx_coord2_t btn_orig;
107 gfx_coord2_t btn_stride;
108 gfx_coord2_t btn_dim;
109 } calc_geom_t;
111 typedef struct {
112 ui_t *ui;
113 ui_resource_t *ui_res;
114 ui_pbutton_t *btn_eval;
115 ui_pbutton_t *btn_clear;
116 ui_pbutton_t *btn_add;
117 ui_pbutton_t *btn_sub;
118 ui_pbutton_t *btn_mul;
119 ui_pbutton_t *btn_div;
120 ui_pbutton_t *btn_0;
121 ui_pbutton_t *btn_1;
122 ui_pbutton_t *btn_2;
123 ui_pbutton_t *btn_3;
124 ui_pbutton_t *btn_4;
125 ui_pbutton_t *btn_5;
126 ui_pbutton_t *btn_6;
127 ui_pbutton_t *btn_7;
128 ui_pbutton_t *btn_8;
129 ui_pbutton_t *btn_9;
130 ui_menu_bar_t *menubar;
131 calc_geom_t geom;
132 } calc_t;
134 static void display_update(void);
136 static void calc_file_exit(ui_menu_entry_t *, void *);
137 static void calc_edit_copy(ui_menu_entry_t *, void *);
138 static void calc_edit_paste(ui_menu_entry_t *, void *);
140 static void calc_pb_clicked(ui_pbutton_t *, void *);
141 static void calc_eval_clicked(ui_pbutton_t *, void *);
142 static void calc_clear_clicked(ui_pbutton_t *, void *);
144 static ui_pbutton_cb_t calc_pbutton_cb = {
145 .clicked = calc_pb_clicked
148 static ui_pbutton_cb_t calc_clear_cb = {
149 .clicked = calc_clear_clicked
152 static ui_pbutton_cb_t calc_eval_cb = {
153 .clicked = calc_eval_clicked
156 static void wnd_close(ui_window_t *, void *);
157 static void wnd_kbd_event(ui_window_t *, void *, kbd_event_t *);
159 static ui_window_cb_t window_cb = {
160 .close = wnd_close,
161 .kbd = wnd_kbd_event
164 static char *expr = NULL;
165 static ui_entry_t *display;
167 /** Window close request
169 * @param window Window
170 * @param arg Argument (calc_t *)
172 static void wnd_close(ui_window_t *window, void *arg)
174 calc_t *calc = (calc_t *) arg;
176 ui_quit(calc->ui);
179 /** Window keyboard event
181 * @param window Window
182 * @param arg Argument (calc_t *)
183 * @param event Keyboard event
185 static void wnd_kbd_event(ui_window_t *window, void *arg, kbd_event_t *event)
187 calc_t *calc = (calc_t *) arg;
189 if (ui_window_def_kbd(window, event) == ui_claimed)
190 return;
192 if (event->type == KEY_PRESS && (event->mods & KM_CTRL) != 0) {
193 switch (event->key) {
194 case KC_C:
195 calc_edit_copy(NULL, calc);
196 break;
197 case KC_V:
198 calc_edit_paste(NULL, calc);
199 break;
200 default:
201 break;
205 switch (event->key) {
206 case KC_ENTER:
207 if (event->type == KEY_PRESS)
208 ui_pbutton_press(calc->btn_eval);
209 else
210 ui_pbutton_release(calc->btn_eval);
211 break;
212 case KC_BACKSPACE:
213 if (event->type == KEY_PRESS)
214 ui_pbutton_press(calc->btn_clear);
215 else
216 ui_pbutton_release(calc->btn_clear);
217 break;
218 case KC_MINUS:
219 if (event->type == KEY_PRESS)
220 ui_pbutton_press(calc->btn_sub);
221 else
222 ui_pbutton_release(calc->btn_sub);
223 break;
224 case KC_EQUALS:
225 if (event->type == KEY_PRESS)
226 ui_pbutton_press(calc->btn_add);
227 else
228 ui_pbutton_release(calc->btn_add);
229 break;
230 case KC_SLASH:
231 if (event->type == KEY_PRESS)
232 ui_pbutton_press(calc->btn_div);
233 else
234 ui_pbutton_release(calc->btn_div);
235 break;
236 case KC_0:
237 if (event->type == KEY_PRESS)
238 ui_pbutton_press(calc->btn_0);
239 else
240 ui_pbutton_release(calc->btn_0);
241 break;
242 case KC_1:
243 if (event->type == KEY_PRESS)
244 ui_pbutton_press(calc->btn_1);
245 else
246 ui_pbutton_release(calc->btn_1);
247 break;
248 case KC_2:
249 if (event->type == KEY_PRESS)
250 ui_pbutton_press(calc->btn_2);
251 else
252 ui_pbutton_release(calc->btn_2);
253 break;
254 case KC_3:
255 if (event->type == KEY_PRESS)
256 ui_pbutton_press(calc->btn_3);
257 else
258 ui_pbutton_release(calc->btn_3);
259 break;
260 case KC_4:
261 if (event->type == KEY_PRESS)
262 ui_pbutton_press(calc->btn_4);
263 else
264 ui_pbutton_release(calc->btn_4);
265 break;
266 case KC_5:
267 if (event->type == KEY_PRESS)
268 ui_pbutton_press(calc->btn_5);
269 else
270 ui_pbutton_release(calc->btn_5);
271 break;
272 case KC_6:
273 if (event->type == KEY_PRESS)
274 ui_pbutton_press(calc->btn_6);
275 else
276 ui_pbutton_release(calc->btn_6);
277 break;
278 case KC_7:
279 if (event->type == KEY_PRESS)
280 ui_pbutton_press(calc->btn_7);
281 else
282 ui_pbutton_release(calc->btn_7);
283 break;
284 case KC_8:
285 if ((event->mods & KM_SHIFT) != 0) {
286 if (event->type == KEY_PRESS)
287 ui_pbutton_press(calc->btn_mul);
288 else
289 ui_pbutton_release(calc->btn_mul);
290 } else {
291 if (event->type == KEY_PRESS)
292 ui_pbutton_press(calc->btn_8);
293 else
294 ui_pbutton_release(calc->btn_8);
296 break;
297 case KC_9:
298 if (event->type == KEY_PRESS)
299 ui_pbutton_press(calc->btn_9);
300 else
301 ui_pbutton_release(calc->btn_9);
302 break;
303 default:
304 break;
308 /** File / Exit menu entry selected.
310 * @param mentry Menu entry
311 * @param arg Argument (calc_t *)
313 static void calc_file_exit(ui_menu_entry_t *mentry, void *arg)
315 calc_t *calc = (calc_t *) arg;
317 ui_quit(calc->ui);
320 /** Edit / Copy menu entry selected.
322 * @param mentry Menu entry
323 * @param arg Argument (calc_t *)
325 static void calc_edit_copy(ui_menu_entry_t *mentry, void *arg)
327 const char *str;
329 (void) arg;
330 str = (expr != NULL) ? expr : NULL_DISPLAY;
332 (void) clipboard_put_str(str);
335 /** Edit / Paste menu entry selected.
337 * @param mentry Menu entry
338 * @param arg Argument (calc_t *)
340 static void calc_edit_paste(ui_menu_entry_t *mentry, void *arg)
342 char *str;
343 char *old;
344 char *cp;
345 errno_t rc;
347 (void) arg;
349 rc = clipboard_get_str(&str);
350 if (rc != EOK)
351 return;
353 /* Make sure string only contains allowed characters */
354 cp = str;
355 while (*cp != '\0') {
356 if (!isdigit(*cp) && *cp != '+' && *cp != '-' &&
357 *cp != '*' && *cp != '/')
358 return;
359 ++cp;
362 /* Update expression */
363 old = expr;
364 expr = str;
365 free(old);
367 display_update();
370 static bool is_digit(char c)
372 return ((c >= '0') && (c <= '9'));
375 static int get_digit(char c)
377 assert(is_digit(c));
379 return (c - '0');
382 static bool is_plus(char c)
384 return (c == '+');
387 static bool is_minus(char c)
389 return (c == '-');
392 static bool is_finish(char c)
394 return (c == 0);
397 static operator_t get_operator(char c)
399 switch (c) {
400 case '+':
401 return OPERATOR_ADD;
402 case '-':
403 return OPERATOR_SUB;
404 case '*':
405 return OPERATOR_MUL;
406 case '/':
407 return OPERATOR_DIV;
408 default:
409 return OPERATOR_NONE;
413 static bool is_operator(char c)
415 return (get_operator(c) != OPERATOR_NONE);
418 static bool stack_push_value(list_t *stack, int64_t value, bool value_neg)
420 stack_item_t *item = malloc(sizeof(stack_item_t));
421 if (!item)
422 return false;
424 link_initialize(&item->link);
425 item->type = ITEM_VALUE;
427 if (value_neg)
428 item->data.value = -value;
429 else
430 item->data.value = value;
432 list_prepend(&item->link, stack);
434 return true;
437 static bool stack_push_operator(list_t *stack, operator_t operator)
439 stack_item_t *item = malloc(sizeof(stack_item_t));
440 if (!item)
441 return false;
443 link_initialize(&item->link);
444 item->type = ITEM_OPERATOR;
445 item->data.operator = operator;
446 list_prepend(&item->link, stack);
448 return true;
451 static bool stack_pop_value(list_t *stack, int64_t *value)
453 link_t *link = list_first(stack);
454 if (!link)
455 return false;
457 stack_item_t *item = list_get_instance(link, stack_item_t, link);
458 if (item->type != ITEM_VALUE)
459 return false;
461 *value = item->data.value;
463 list_remove(link);
464 free(item);
466 return true;
469 static bool stack_pop_operator(list_t *stack, operator_t *operator)
471 link_t *link = list_first(stack);
472 if (!link)
473 return false;
475 stack_item_t *item = list_get_instance(link, stack_item_t, link);
476 if (item->type != ITEM_OPERATOR)
477 return false;
479 *operator = item->data.operator;
481 list_remove(link);
482 free(item);
484 return true;
487 static void stack_cleanup(list_t *stack)
489 while (!list_empty(stack)) {
490 link_t *link = list_first(stack);
491 if (link) {
492 stack_item_t *item = list_get_instance(link, stack_item_t,
493 link);
495 list_remove(link);
496 free(item);
501 static bool compute(int64_t a, operator_t operator, int64_t b, int64_t *value)
503 switch (operator) {
504 case OPERATOR_ADD:
505 *value = a + b;
506 break;
507 case OPERATOR_SUB:
508 *value = a - b;
509 break;
510 case OPERATOR_MUL:
511 *value = a * b;
512 break;
513 case OPERATOR_DIV:
514 if (b == 0)
515 return false;
517 *value = a / b;
518 break;
519 default:
520 return false;
523 return true;
526 static unsigned int get_priority(operator_t operator)
528 switch (operator) {
529 case OPERATOR_ADD:
530 return 0;
531 case OPERATOR_SUB:
532 return 0;
533 case OPERATOR_MUL:
534 return 1;
535 case OPERATOR_DIV:
536 return 1;
537 default:
538 return 0;
542 static void evaluate(list_t *stack, int64_t *value, parser_state_t *state,
543 error_type_t *error_type)
545 while (!list_empty(stack)) {
546 if (!stack_pop_value(stack, value)) {
547 *state = STATE_ERROR;
548 *error_type = ERROR_SYNTAX;
549 break;
552 if (!list_empty(stack)) {
553 operator_t operator;
554 if (!stack_pop_operator(stack, &operator)) {
555 *state = STATE_ERROR;
556 *error_type = ERROR_SYNTAX;
557 break;
560 int64_t value_a;
561 if (!stack_pop_value(stack, &value_a)) {
562 *state = STATE_ERROR;
563 *error_type = ERROR_SYNTAX;
564 break;
567 if (!compute(value_a, operator, *value, value)) {
568 *state = STATE_ERROR;
569 *error_type = ERROR_NUMERIC;
570 break;
573 if (!stack_push_value(stack, *value, false)) {
574 *state = STATE_ERROR;
575 *error_type = ERROR_SYNTAX;
576 break;
582 static void display_update(void)
584 if (expr != NULL)
585 (void) ui_entry_set_text(display, (void *) expr);
586 else
587 (void) ui_entry_set_text(display, (void *) NULL_DISPLAY);
589 ui_entry_paint(display);
592 static void display_error(error_type_t error_type)
594 if (expr != NULL) {
595 free(expr);
596 expr = NULL;
599 switch (error_type) {
600 case ERROR_SYNTAX:
601 (void) ui_entry_set_text(display,
602 (void *) SYNTAX_ERROR_DISPLAY);
603 break;
604 case ERROR_NUMERIC:
605 (void) ui_entry_set_text(display,
606 (void *) NUMERIC_ERROR_DISPLAY);
607 break;
608 default:
609 (void) ui_entry_set_text(display,
610 (void *) UNKNOWN_ERROR_DISPLAY);
611 break;
614 ui_entry_paint(display);
617 static void calc_pb_clicked(ui_pbutton_t *pbutton, void *arg)
619 const char *subexpr = (const char *) arg;
621 if (expr != NULL) {
622 char *new_expr;
624 if (str_length(expr) < EXPR_MAX_LEN) {
625 asprintf(&new_expr, "%s%s", expr, subexpr);
626 free(expr);
627 expr = new_expr;
629 } else {
630 expr = str_dup(subexpr);
633 display_update();
636 static void calc_clear_clicked(ui_pbutton_t *pbutton, void *arg)
638 if (expr != NULL) {
639 free(expr);
640 expr = NULL;
643 display_update();
646 static void calc_eval_clicked(ui_pbutton_t *pbutton, void *arg)
648 if (expr == NULL)
649 return;
651 list_t stack;
652 list_initialize(&stack);
654 error_type_t error_type = ERROR_SYNTAX;
655 size_t i = 0;
656 parser_state_t state = STATE_INITIAL;
657 int64_t value = 0;
658 bool value_neg = false;
659 operator_t last_operator = OPERATOR_NONE;
661 while ((state != STATE_FINISH) && (state != STATE_ERROR)) {
662 switch (state) {
663 case STATE_INITIAL:
664 if (is_digit(expr[i])) {
665 value = get_digit(expr[i]);
666 i++;
667 state = STATE_VALUE;
668 } else if (is_plus(expr[i])) {
669 i++;
670 value_neg = false;
671 state = STATE_DIGIT;
672 } else if (is_minus(expr[i])) {
673 i++;
674 value_neg = true;
675 state = STATE_DIGIT;
676 } else
677 state = STATE_ERROR;
678 break;
680 case STATE_DIGIT:
681 if (is_digit(expr[i])) {
682 value = get_digit(expr[i]);
683 i++;
684 state = STATE_VALUE;
685 } else
686 state = STATE_ERROR;
687 break;
689 case STATE_VALUE:
690 if (is_digit(expr[i])) {
691 value *= 10;
692 value += get_digit(expr[i]);
693 i++;
694 } else if (is_operator(expr[i])) {
695 if (!stack_push_value(&stack, value, value_neg)) {
696 state = STATE_ERROR;
697 break;
700 value = 0;
701 value_neg = false;
703 operator_t operator = get_operator(expr[i]);
705 if (get_priority(operator) <= get_priority(last_operator)) {
706 evaluate(&stack, &value, &state, &error_type);
707 if (state == STATE_ERROR)
708 break;
710 if (!stack_push_value(&stack, value, value_neg)) {
711 state = STATE_ERROR;
712 break;
716 if (!stack_push_operator(&stack, operator)) {
717 state = STATE_ERROR;
718 break;
721 last_operator = operator;
722 i++;
723 state = STATE_DIGIT;
724 } else if (is_finish(expr[i])) {
725 if (!stack_push_value(&stack, value, value_neg)) {
726 state = STATE_ERROR;
727 break;
730 state = STATE_FINISH;
731 } else
732 state = STATE_ERROR;
733 break;
735 default:
736 state = STATE_ERROR;
740 evaluate(&stack, &value, &state, &error_type);
741 stack_cleanup(&stack);
743 if (state == STATE_ERROR) {
744 display_error(error_type);
745 return;
748 free(expr);
749 asprintf(&expr, "%" PRId64, value);
750 display_update();
753 static errno_t calc_button_create(calc_t *calc, ui_fixed_t *fixed,
754 int x, int y, const char *text, ui_pbutton_cb_t *cb, void *arg,
755 ui_pbutton_t **rbutton)
757 ui_pbutton_t *pb;
758 gfx_rect_t rect;
759 errno_t rc;
761 rc = ui_pbutton_create(calc->ui_res, text, &pb);
762 if (rc != EOK) {
763 printf("Error creating button.\n");
764 return rc;
767 ui_pbutton_set_cb(pb, cb, arg);
769 rect.p0.x = calc->geom.btn_orig.x + calc->geom.btn_stride.x * x;
770 rect.p0.y = calc->geom.btn_orig.y + calc->geom.btn_stride.y * y;
771 rect.p1.x = rect.p0.x + calc->geom.btn_dim.x;
772 rect.p1.y = rect.p0.y + calc->geom.btn_dim.y;
773 ui_pbutton_set_rect(pb, &rect);
775 rc = ui_fixed_add(fixed, ui_pbutton_ctl(pb));
776 if (rc != EOK) {
777 printf("Error adding control to layout.\n");
778 return rc;
781 if (rbutton != NULL)
782 *rbutton = pb;
783 return EOK;
786 static void print_syntax(void)
788 printf("Syntax: %s [-d <display-spec>]\n", NAME);
791 int main(int argc, char *argv[])
793 const char *display_spec = UI_ANY_DEFAULT;
794 ui_t *ui;
795 ui_resource_t *ui_res;
796 ui_fixed_t *fixed;
797 ui_wnd_params_t params;
798 ui_window_t *window;
799 ui_menu_t *mfile;
800 ui_menu_entry_t *mexit;
801 ui_menu_t *medit;
802 ui_menu_entry_t *mcopy;
803 ui_menu_entry_t *mpaste;
804 calc_t calc;
805 errno_t rc;
806 int i;
808 i = 1;
809 while (i < argc) {
810 if (str_cmp(argv[i], "-d") == 0) {
811 ++i;
812 if (i >= argc) {
813 printf("Argument missing.\n");
814 print_syntax();
815 return 1;
818 display_spec = argv[i++];
819 } else {
820 printf("Invalid option '%s'.\n", argv[i]);
821 print_syntax();
822 return 1;
826 rc = ui_create(display_spec, &ui);
827 if (rc != EOK) {
828 printf("Error creating UI on display %s.\n", display_spec);
829 return rc;
832 ui_wnd_params_init(&params);
833 params.caption = "Calculator";
834 params.rect.p0.x = 0;
835 params.rect.p0.y = 0;
837 if (ui_is_textmode(ui)) {
838 params.rect.p1.x = 38;
839 params.rect.p1.y = 18;
841 calc.geom.menubar_rect.p0.x = 1;
842 calc.geom.menubar_rect.p0.y = 1;
843 calc.geom.menubar_rect.p1.x = params.rect.p1.x - 1;
844 calc.geom.menubar_rect.p1.y = 2;
845 calc.geom.entry_rect.p0.x = 4;
846 calc.geom.entry_rect.p0.y = 3;
847 calc.geom.entry_rect.p1.x = 34;
848 calc.geom.entry_rect.p1.y = 4;
849 calc.geom.btn_orig.x = 4;
850 calc.geom.btn_orig.y = 5;
851 calc.geom.btn_dim.x = 6;
852 calc.geom.btn_dim.y = 2;
853 calc.geom.btn_stride.x = 8;
854 calc.geom.btn_stride.y = 3;
855 } else {
856 params.rect.p1.x = 250;
857 params.rect.p1.y = 270;
859 calc.geom.menubar_rect.p0.x = 4;
860 calc.geom.menubar_rect.p0.y = 30;
861 calc.geom.menubar_rect.p1.x = params.rect.p1.x - 4;
862 calc.geom.menubar_rect.p1.y = 52;
863 calc.geom.entry_rect.p0.x = 10;
864 calc.geom.entry_rect.p0.y = 51;
865 calc.geom.entry_rect.p1.x = 240;
866 calc.geom.entry_rect.p1.y = 76;
867 calc.geom.btn_orig.x = 10;
868 calc.geom.btn_orig.y = 90;
869 calc.geom.btn_dim.x = 50;
870 calc.geom.btn_dim.y = 35;
871 calc.geom.btn_stride.x = 60;
872 calc.geom.btn_stride.y = 45;
875 rc = ui_window_create(ui, &params, &window);
876 if (rc != EOK) {
877 printf("Error creating window.\n");
878 return rc;
881 ui_window_set_cb(window, &window_cb, (void *) &calc);
882 calc.ui = ui;
884 ui_res = ui_window_get_res(window);
885 calc.ui_res = ui_res;
887 rc = ui_fixed_create(&fixed);
888 if (rc != EOK) {
889 printf("Error creating fixed layout.\n");
890 return rc;
893 rc = ui_menu_bar_create(ui, window, &calc.menubar);
894 if (rc != EOK) {
895 printf("Error creating menu bar.\n");
896 return rc;
899 rc = ui_menu_dd_create(calc.menubar, "~F~ile", NULL, &mfile);
900 if (rc != EOK) {
901 printf("Error creating menu.\n");
902 return rc;
905 rc = ui_menu_entry_create(mfile, "E~x~it", "Alt-F4", &mexit);
906 if (rc != EOK) {
907 printf("Error creating menu.\n");
908 return rc;
911 ui_menu_entry_set_cb(mexit, calc_file_exit, (void *) &calc);
913 rc = ui_menu_dd_create(calc.menubar, "~E~dit", NULL, &medit);
914 if (rc != EOK) {
915 printf("Error creating menu.\n");
916 return rc;
919 rc = ui_menu_entry_create(medit, "~C~opy", "Ctrl-C", &mcopy);
920 if (rc != EOK) {
921 printf("Error creating menu.\n");
922 return rc;
925 ui_menu_entry_set_cb(mcopy, calc_edit_copy, (void *) &calc);
927 rc = ui_menu_entry_create(medit, "~P~aste", "Ctrl-V", &mpaste);
928 if (rc != EOK) {
929 printf("Error creating menu.\n");
930 return rc;
933 ui_menu_entry_set_cb(mpaste, calc_edit_paste, (void *) &calc);
935 ui_menu_bar_set_rect(calc.menubar, &calc.geom.menubar_rect);
937 rc = ui_fixed_add(fixed, ui_menu_bar_ctl(calc.menubar));
938 if (rc != EOK) {
939 printf("Error adding control to layout.\n");
940 return rc;
943 rc = ui_entry_create(window, NULL_DISPLAY, &display);
944 if (rc != EOK) {
945 printf("Error creating text lentry.\n");
946 return rc;
949 ui_entry_set_rect(display, &calc.geom.entry_rect);
950 ui_entry_set_halign(display, gfx_halign_right);
951 ui_entry_set_read_only(display, true);
953 rc = ui_fixed_add(fixed, ui_entry_ctl(display));
954 if (rc != EOK) {
955 printf("Error adding control to layout.\n");
956 return rc;
959 rc = calc_button_create(&calc, fixed, 0, 0, "7", &calc_pbutton_cb,
960 (void *) "7", &calc.btn_7);
961 if (rc != EOK)
962 return rc;
964 rc = calc_button_create(&calc, fixed, 1, 0, "8", &calc_pbutton_cb,
965 (void *) "8", &calc.btn_8);
966 if (rc != EOK)
967 return rc;
969 rc = calc_button_create(&calc, fixed, 2, 0, "9", &calc_pbutton_cb,
970 (void *) "9", &calc.btn_9);
971 if (rc != EOK)
972 return rc;
974 rc = calc_button_create(&calc, fixed, 3, 0, "/", &calc_pbutton_cb,
975 (void *) "/", &calc.btn_div);
976 if (rc != EOK)
977 return rc;
979 rc = calc_button_create(&calc, fixed, 0, 1, "4", &calc_pbutton_cb,
980 (void *) "4", &calc.btn_4);
981 if (rc != EOK)
982 return rc;
984 rc = calc_button_create(&calc, fixed, 1, 1, "5", &calc_pbutton_cb,
985 (void *) "5", &calc.btn_5);
986 if (rc != EOK)
987 return rc;
989 rc = calc_button_create(&calc, fixed, 2, 1, "6", &calc_pbutton_cb,
990 (void *) "6", &calc.btn_6);
991 if (rc != EOK)
992 return rc;
994 rc = calc_button_create(&calc, fixed, 3, 1, "*", &calc_pbutton_cb,
995 (void *) "*", &calc.btn_mul);
996 if (rc != EOK)
997 return rc;
999 rc = calc_button_create(&calc, fixed, 0, 2, "1", &calc_pbutton_cb,
1000 (void *) "1", &calc.btn_1);
1001 if (rc != EOK)
1002 return rc;
1004 rc = calc_button_create(&calc, fixed, 1, 2, "2", &calc_pbutton_cb,
1005 (void *) "2", &calc.btn_2);
1006 if (rc != EOK)
1007 return rc;
1009 rc = calc_button_create(&calc, fixed, 2, 2, "3", &calc_pbutton_cb,
1010 (void *) "3", &calc.btn_3);
1011 if (rc != EOK)
1012 return rc;
1014 rc = calc_button_create(&calc, fixed, 3, 2, "-", &calc_pbutton_cb,
1015 (void *) "-", &calc.btn_sub);
1016 if (rc != EOK)
1017 return rc;
1019 rc = calc_button_create(&calc, fixed, 0, 3, "0", &calc_pbutton_cb,
1020 (void *) "0", &calc.btn_0);
1021 if (rc != EOK)
1022 return rc;
1024 rc = calc_button_create(&calc, fixed, 1, 3, "C", &calc_clear_cb,
1025 (void *) "C", &calc.btn_clear);
1026 if (rc != EOK)
1027 return rc;
1029 rc = calc_button_create(&calc, fixed, 2, 3, "=", &calc_eval_cb,
1030 (void *) "=", &calc.btn_eval);
1031 if (rc != EOK)
1032 return rc;
1034 rc = calc_button_create(&calc, fixed, 3, 3, "+", &calc_pbutton_cb,
1035 (void *) "+", &calc.btn_add);
1036 if (rc != EOK)
1037 return rc;
1039 ui_pbutton_set_default(calc.btn_eval, true);
1041 ui_window_add(window, ui_fixed_ctl(fixed));
1043 rc = ui_window_paint(window);
1044 if (rc != EOK) {
1045 printf("Error painting window.\n");
1046 return rc;
1049 ui_run(ui);
1050 ui_window_destroy(window);
1051 ui_destroy(ui);
1053 return 0;