source: mainline/uspace/app/calculator/calculator.c

Last change on this file was 46bd63c9, checked in by Jiri Svoboda <jiri@…>, 23 months ago

Split drop-down menu into two classes: drop-down and menu

Naming is clearly the hardest problem in computer science.

  • Property mode set to 100644
File size: 21.8 KB
Line 
1/*
2 * Copyright (c) 2023 Jiri Svoboda
3 * Copyright (c) 2016 Martin Decky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
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.
17 *
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.
28 */
29
30/** @addtogroup calculator
31 * @{
32 */
33/** @file
34 *
35 * Inspired by the code released at https://github.com/osgroup/HelenOSProject
36 *
37 */
38
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>
55
56#define NAME "calculator"
57
58#define NULL_DISPLAY "0"
59
60#define SYNTAX_ERROR_DISPLAY "Syntax error"
61#define NUMERIC_ERROR_DISPLAY "Numerical error"
62#define UNKNOWN_ERROR_DISPLAY "Unknown error"
63
64#define EXPR_MAX_LEN 22
65
66typedef enum {
67 STATE_INITIAL = 0,
68 STATE_FINISH,
69 STATE_ERROR,
70 STATE_DIGIT,
71 STATE_VALUE
72} parser_state_t;
73
74typedef enum {
75 ERROR_SYNTAX = 0,
76 ERROR_NUMERIC
77} error_type_t;
78
79typedef enum {
80 OPERATOR_NONE = 0,
81 OPERATOR_ADD,
82 OPERATOR_SUB,
83 OPERATOR_MUL,
84 OPERATOR_DIV
85} operator_t;
86
87typedef enum {
88 ITEM_VALUE = 0,
89 ITEM_OPERATOR
90} stack_item_type_t;
91
92typedef struct {
93 link_t link;
94
95 stack_item_type_t type;
96 union {
97 int64_t value;
98 operator_t operator;
99 } data;
100} stack_item_t;
101
102/** Dimensions. Most of this should not be needed with auto layout */
103typedef 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;
110
111typedef 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;
133
134static void display_update(void);
135
136static void calc_file_exit(ui_menu_entry_t *, void *);
137static void calc_edit_copy(ui_menu_entry_t *, void *);
138static void calc_edit_paste(ui_menu_entry_t *, void *);
139
140static void calc_pb_clicked(ui_pbutton_t *, void *);
141static void calc_eval_clicked(ui_pbutton_t *, void *);
142static void calc_clear_clicked(ui_pbutton_t *, void *);
143
144static ui_pbutton_cb_t calc_pbutton_cb = {
145 .clicked = calc_pb_clicked
146};
147
148static ui_pbutton_cb_t calc_clear_cb = {
149 .clicked = calc_clear_clicked
150};
151
152static ui_pbutton_cb_t calc_eval_cb = {
153 .clicked = calc_eval_clicked
154};
155
156static void wnd_close(ui_window_t *, void *);
157static void wnd_kbd_event(ui_window_t *, void *, kbd_event_t *);
158
159static ui_window_cb_t window_cb = {
160 .close = wnd_close,
161 .kbd = wnd_kbd_event
162};
163
164static char *expr = NULL;
165static ui_entry_t *display;
166
167/** Window close request
168 *
169 * @param window Window
170 * @param arg Argument (calc_t *)
171 */
172static void wnd_close(ui_window_t *window, void *arg)
173{
174 calc_t *calc = (calc_t *) arg;
175
176 ui_quit(calc->ui);
177}
178
179/** Window keyboard event
180 *
181 * @param window Window
182 * @param arg Argument (calc_t *)
183 * @param event Keyboard event
184 */
185static void wnd_kbd_event(ui_window_t *window, void *arg, kbd_event_t *event)
186{
187 calc_t *calc = (calc_t *) arg;
188
189 if (ui_window_def_kbd(window, event) == ui_claimed)
190 return;
191
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;
202 }
203 }
204
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);
295 }
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;
305 }
306}
307
308/** File / Exit menu entry selected.
309 *
310 * @param mentry Menu entry
311 * @param arg Argument (calc_t *)
312 */
313static void calc_file_exit(ui_menu_entry_t *mentry, void *arg)
314{
315 calc_t *calc = (calc_t *) arg;
316
317 ui_quit(calc->ui);
318}
319
320/** Edit / Copy menu entry selected.
321 *
322 * @param mentry Menu entry
323 * @param arg Argument (calc_t *)
324 */
325static void calc_edit_copy(ui_menu_entry_t *mentry, void *arg)
326{
327 const char *str;
328
329 (void) arg;
330 str = (expr != NULL) ? expr : NULL_DISPLAY;
331
332 (void) clipboard_put_str(str);
333}
334
335/** Edit / Paste menu entry selected.
336 *
337 * @param mentry Menu entry
338 * @param arg Argument (calc_t *)
339 */
340static void calc_edit_paste(ui_menu_entry_t *mentry, void *arg)
341{
342 char *str;
343 char *old;
344 char *cp;
345 errno_t rc;
346
347 (void) arg;
348
349 rc = clipboard_get_str(&str);
350 if (rc != EOK)
351 return;
352
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;
360 }
361
362 /* Update expression */
363 old = expr;
364 expr = str;
365 free(old);
366
367 display_update();
368}
369
370static bool is_digit(char c)
371{
372 return ((c >= '0') && (c <= '9'));
373}
374
375static int get_digit(char c)
376{
377 assert(is_digit(c));
378
379 return (c - '0');
380}
381
382static bool is_plus(char c)
383{
384 return (c == '+');
385}
386
387static bool is_minus(char c)
388{
389 return (c == '-');
390}
391
392static bool is_finish(char c)
393{
394 return (c == 0);
395}
396
397static operator_t get_operator(char c)
398{
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;
410 }
411}
412
413static bool is_operator(char c)
414{
415 return (get_operator(c) != OPERATOR_NONE);
416}
417
418static bool stack_push_value(list_t *stack, int64_t value, bool value_neg)
419{
420 stack_item_t *item = malloc(sizeof(stack_item_t));
421 if (!item)
422 return false;
423
424 link_initialize(&item->link);
425 item->type = ITEM_VALUE;
426
427 if (value_neg)
428 item->data.value = -value;
429 else
430 item->data.value = value;
431
432 list_prepend(&item->link, stack);
433
434 return true;
435}
436
437static bool stack_push_operator(list_t *stack, operator_t operator)
438{
439 stack_item_t *item = malloc(sizeof(stack_item_t));
440 if (!item)
441 return false;
442
443 link_initialize(&item->link);
444 item->type = ITEM_OPERATOR;
445 item->data.operator = operator;
446 list_prepend(&item->link, stack);
447
448 return true;
449}
450
451static bool stack_pop_value(list_t *stack, int64_t *value)
452{
453 link_t *link = list_first(stack);
454 if (!link)
455 return false;
456
457 stack_item_t *item = list_get_instance(link, stack_item_t, link);
458 if (item->type != ITEM_VALUE)
459 return false;
460
461 *value = item->data.value;
462
463 list_remove(link);
464 free(item);
465
466 return true;
467}
468
469static bool stack_pop_operator(list_t *stack, operator_t *operator)
470{
471 link_t *link = list_first(stack);
472 if (!link)
473 return false;
474
475 stack_item_t *item = list_get_instance(link, stack_item_t, link);
476 if (item->type != ITEM_OPERATOR)
477 return false;
478
479 *operator = item->data.operator;
480
481 list_remove(link);
482 free(item);
483
484 return true;
485}
486
487static void stack_cleanup(list_t *stack)
488{
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);
494
495 list_remove(link);
496 free(item);
497 }
498 }
499}
500
501static bool compute(int64_t a, operator_t operator, int64_t b, int64_t *value)
502{
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;
516
517 *value = a / b;
518 break;
519 default:
520 return false;
521 }
522
523 return true;
524}
525
526static unsigned int get_priority(operator_t operator)
527{
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;
539 }
540}
541
542static void evaluate(list_t *stack, int64_t *value, parser_state_t *state,
543 error_type_t *error_type)
544{
545 while (!list_empty(stack)) {
546 if (!stack_pop_value(stack, value)) {
547 *state = STATE_ERROR;
548 *error_type = ERROR_SYNTAX;
549 break;
550 }
551
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;
558 }
559
560 int64_t value_a;
561 if (!stack_pop_value(stack, &value_a)) {
562 *state = STATE_ERROR;
563 *error_type = ERROR_SYNTAX;
564 break;
565 }
566
567 if (!compute(value_a, operator, *value, value)) {
568 *state = STATE_ERROR;
569 *error_type = ERROR_NUMERIC;
570 break;
571 }
572
573 if (!stack_push_value(stack, *value, false)) {
574 *state = STATE_ERROR;
575 *error_type = ERROR_SYNTAX;
576 break;
577 }
578 }
579 }
580}
581
582static void display_update(void)
583{
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);
588
589 ui_entry_paint(display);
590}
591
592static void display_error(error_type_t error_type)
593{
594 if (expr != NULL) {
595 free(expr);
596 expr = NULL;
597 }
598
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;
612 }
613
614 ui_entry_paint(display);
615}
616
617static void calc_pb_clicked(ui_pbutton_t *pbutton, void *arg)
618{
619 const char *subexpr = (const char *) arg;
620
621 if (expr != NULL) {
622 char *new_expr;
623
624 if (str_length(expr) < EXPR_MAX_LEN) {
625 asprintf(&new_expr, "%s%s", expr, subexpr);
626 free(expr);
627 expr = new_expr;
628 }
629 } else {
630 expr = str_dup(subexpr);
631 }
632
633 display_update();
634}
635
636static void calc_clear_clicked(ui_pbutton_t *pbutton, void *arg)
637{
638 if (expr != NULL) {
639 free(expr);
640 expr = NULL;
641 }
642
643 display_update();
644}
645
646static void calc_eval_clicked(ui_pbutton_t *pbutton, void *arg)
647{
648 if (expr == NULL)
649 return;
650
651 list_t stack;
652 list_initialize(&stack);
653
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;
660
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;
679
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;
688
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;
698 }
699
700 value = 0;
701 value_neg = false;
702
703 operator_t operator = get_operator(expr[i]);
704
705 if (get_priority(operator) <= get_priority(last_operator)) {
706 evaluate(&stack, &value, &state, &error_type);
707 if (state == STATE_ERROR)
708 break;
709
710 if (!stack_push_value(&stack, value, value_neg)) {
711 state = STATE_ERROR;
712 break;
713 }
714 }
715
716 if (!stack_push_operator(&stack, operator)) {
717 state = STATE_ERROR;
718 break;
719 }
720
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;
728 }
729
730 state = STATE_FINISH;
731 } else
732 state = STATE_ERROR;
733 break;
734
735 default:
736 state = STATE_ERROR;
737 }
738 }
739
740 evaluate(&stack, &value, &state, &error_type);
741 stack_cleanup(&stack);
742
743 if (state == STATE_ERROR) {
744 display_error(error_type);
745 return;
746 }
747
748 free(expr);
749 asprintf(&expr, "%" PRId64, value);
750 display_update();
751}
752
753static 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)
756{
757 ui_pbutton_t *pb;
758 gfx_rect_t rect;
759 errno_t rc;
760
761 rc = ui_pbutton_create(calc->ui_res, text, &pb);
762 if (rc != EOK) {
763 printf("Error creating button.\n");
764 return rc;
765 }
766
767 ui_pbutton_set_cb(pb, cb, arg);
768
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);
774
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;
779 }
780
781 if (rbutton != NULL)
782 *rbutton = pb;
783 return EOK;
784}
785
786static void print_syntax(void)
787{
788 printf("Syntax: %s [-d <display-spec>]\n", NAME);
789}
790
791int main(int argc, char *argv[])
792{
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;
807
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;
816 }
817
818 display_spec = argv[i++];
819 } else {
820 printf("Invalid option '%s'.\n", argv[i]);
821 print_syntax();
822 return 1;
823 }
824 }
825
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;
830 }
831
832 ui_wnd_params_init(&params);
833 params.caption = "Calculator";
834 params.rect.p0.x = 0;
835 params.rect.p0.y = 0;
836
837 if (ui_is_textmode(ui)) {
838 params.rect.p1.x = 38;
839 params.rect.p1.y = 18;
840
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;
858
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;
873 }
874
875 rc = ui_window_create(ui, &params, &window);
876 if (rc != EOK) {
877 printf("Error creating window.\n");
878 return rc;
879 }
880
881 ui_window_set_cb(window, &window_cb, (void *) &calc);
882 calc.ui = ui;
883
884 ui_res = ui_window_get_res(window);
885 calc.ui_res = ui_res;
886
887 rc = ui_fixed_create(&fixed);
888 if (rc != EOK) {
889 printf("Error creating fixed layout.\n");
890 return rc;
891 }
892
893 rc = ui_menu_bar_create(ui, window, &calc.menubar);
894 if (rc != EOK) {
895 printf("Error creating menu bar.\n");
896 return rc;
897 }
898
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;
903 }
904
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;
909 }
910
911 ui_menu_entry_set_cb(mexit, calc_file_exit, (void *) &calc);
912
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;
917 }
918
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;
923 }
924
925 ui_menu_entry_set_cb(mcopy, calc_edit_copy, (void *) &calc);
926
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;
931 }
932
933 ui_menu_entry_set_cb(mpaste, calc_edit_paste, (void *) &calc);
934
935 ui_menu_bar_set_rect(calc.menubar, &calc.geom.menubar_rect);
936
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;
941 }
942
943 rc = ui_entry_create(window, NULL_DISPLAY, &display);
944 if (rc != EOK) {
945 printf("Error creating text lentry.\n");
946 return rc;
947 }
948
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);
952
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;
957 }
958
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;
963
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;
968
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;
973
974 rc = calc_button_create(&calc, fixed, 3, 0, "/", &calc_pbutton_cb,
975 (void *) "/", &calc.btn_div);
976 if (rc != EOK)
977 return rc;
978
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;
983
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;
988
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;
993
994 rc = calc_button_create(&calc, fixed, 3, 1, "*", &calc_pbutton_cb,
995 (void *) "*", &calc.btn_mul);
996 if (rc != EOK)
997 return rc;
998
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;
1003
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;
1008
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;
1013
1014 rc = calc_button_create(&calc, fixed, 3, 2, "-", &calc_pbutton_cb,
1015 (void *) "-", &calc.btn_sub);
1016 if (rc != EOK)
1017 return rc;
1018
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;
1023
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;
1028
1029 rc = calc_button_create(&calc, fixed, 2, 3, "=", &calc_eval_cb,
1030 (void *) "=", &calc.btn_eval);
1031 if (rc != EOK)
1032 return rc;
1033
1034 rc = calc_button_create(&calc, fixed, 3, 3, "+", &calc_pbutton_cb,
1035 (void *) "+", &calc.btn_add);
1036 if (rc != EOK)
1037 return rc;
1038
1039 ui_pbutton_set_default(calc.btn_eval, true);
1040
1041 ui_window_add(window, ui_fixed_ctl(fixed));
1042
1043 rc = ui_window_paint(window);
1044 if (rc != EOK) {
1045 printf("Error painting window.\n");
1046 return rc;
1047 }
1048
1049 ui_run(ui);
1050 ui_window_destroy(window);
1051 ui_destroy(ui);
1052
1053 return 0;
1054}
Note: See TracBrowser for help on using the repository browser.