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

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d8503fd was c88d7f99, checked in by Jiri Svoboda <jiri@…>, 3 years ago

Menu entry accelerators

  • Property mode set to 100644
File size: 21.8 KB
Line 
1/*
2 * Copyright (c) 2022 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/menubar.h>
49#include <ui/menu.h>
50#include <ui/menuentry.h>
51#include <ui/pbutton.h>
52#include <ui/ui.h>
53#include <ui/window.h>
54
55#define NAME "calculator"
56
57#define NULL_DISPLAY "0"
58
59#define SYNTAX_ERROR_DISPLAY "Syntax error"
60#define NUMERIC_ERROR_DISPLAY "Numerical error"
61#define UNKNOWN_ERROR_DISPLAY "Unknown error"
62
63#define EXPR_MAX_LEN 22
64
65typedef enum {
66 STATE_INITIAL = 0,
67 STATE_FINISH,
68 STATE_ERROR,
69 STATE_DIGIT,
70 STATE_VALUE
71} parser_state_t;
72
73typedef enum {
74 ERROR_SYNTAX = 0,
75 ERROR_NUMERIC
76} error_type_t;
77
78typedef enum {
79 OPERATOR_NONE = 0,
80 OPERATOR_ADD,
81 OPERATOR_SUB,
82 OPERATOR_MUL,
83 OPERATOR_DIV
84} operator_t;
85
86typedef enum {
87 ITEM_VALUE = 0,
88 ITEM_OPERATOR
89} stack_item_type_t;
90
91typedef struct {
92 link_t link;
93
94 stack_item_type_t type;
95 union {
96 int64_t value;
97 operator_t operator;
98 } data;
99} stack_item_t;
100
101/** Dimensions. Most of this should not be needed with auto layout */
102typedef struct {
103 gfx_rect_t menubar_rect;
104 gfx_rect_t entry_rect;
105 gfx_coord2_t btn_orig;
106 gfx_coord2_t btn_stride;
107 gfx_coord2_t btn_dim;
108} calc_geom_t;
109
110typedef struct {
111 ui_t *ui;
112 ui_resource_t *ui_res;
113 ui_pbutton_t *btn_eval;
114 ui_pbutton_t *btn_clear;
115 ui_pbutton_t *btn_add;
116 ui_pbutton_t *btn_sub;
117 ui_pbutton_t *btn_mul;
118 ui_pbutton_t *btn_div;
119 ui_pbutton_t *btn_0;
120 ui_pbutton_t *btn_1;
121 ui_pbutton_t *btn_2;
122 ui_pbutton_t *btn_3;
123 ui_pbutton_t *btn_4;
124 ui_pbutton_t *btn_5;
125 ui_pbutton_t *btn_6;
126 ui_pbutton_t *btn_7;
127 ui_pbutton_t *btn_8;
128 ui_pbutton_t *btn_9;
129 ui_menu_bar_t *menubar;
130 calc_geom_t geom;
131} calc_t;
132
133static void display_update(void);
134
135static void calc_file_exit(ui_menu_entry_t *, void *);
136static void calc_edit_copy(ui_menu_entry_t *, void *);
137static void calc_edit_paste(ui_menu_entry_t *, void *);
138
139static void calc_pb_clicked(ui_pbutton_t *, void *);
140static void calc_eval_clicked(ui_pbutton_t *, void *);
141static void calc_clear_clicked(ui_pbutton_t *, void *);
142
143static ui_pbutton_cb_t calc_pbutton_cb = {
144 .clicked = calc_pb_clicked
145};
146
147static ui_pbutton_cb_t calc_clear_cb = {
148 .clicked = calc_clear_clicked
149};
150
151static ui_pbutton_cb_t calc_eval_cb = {
152 .clicked = calc_eval_clicked
153};
154
155static void wnd_close(ui_window_t *, void *);
156static void wnd_kbd_event(ui_window_t *, void *, kbd_event_t *);
157
158static ui_window_cb_t window_cb = {
159 .close = wnd_close,
160 .kbd = wnd_kbd_event
161};
162
163static char *expr = NULL;
164static ui_entry_t *display;
165
166/** Window close request
167 *
168 * @param window Window
169 * @param arg Argument (calc_t *)
170 */
171static void wnd_close(ui_window_t *window, void *arg)
172{
173 calc_t *calc = (calc_t *) arg;
174
175 ui_quit(calc->ui);
176}
177
178/** Window keyboard event
179 *
180 * @param window Window
181 * @param arg Argument (calc_t *)
182 * @param event Keyboard event
183 */
184static void wnd_kbd_event(ui_window_t *window, void *arg, kbd_event_t *event)
185{
186 calc_t *calc = (calc_t *) arg;
187
188 if (ui_window_def_kbd(window, event) == ui_claimed)
189 return;
190
191 if (event->type == KEY_PRESS && (event->mods & KM_CTRL) != 0) {
192 switch (event->key) {
193 case KC_C:
194 calc_edit_copy(NULL, calc);
195 break;
196 case KC_V:
197 calc_edit_paste(NULL, calc);
198 break;
199 default:
200 break;
201 }
202 }
203
204 switch (event->key) {
205 case KC_ENTER:
206 if (event->type == KEY_PRESS)
207 ui_pbutton_press(calc->btn_eval);
208 else
209 ui_pbutton_release(calc->btn_eval);
210 break;
211 case KC_BACKSPACE:
212 if (event->type == KEY_PRESS)
213 ui_pbutton_press(calc->btn_clear);
214 else
215 ui_pbutton_release(calc->btn_clear);
216 break;
217 case KC_MINUS:
218 if (event->type == KEY_PRESS)
219 ui_pbutton_press(calc->btn_sub);
220 else
221 ui_pbutton_release(calc->btn_sub);
222 break;
223 case KC_EQUALS:
224 if (event->type == KEY_PRESS)
225 ui_pbutton_press(calc->btn_add);
226 else
227 ui_pbutton_release(calc->btn_add);
228 break;
229 case KC_SLASH:
230 if (event->type == KEY_PRESS)
231 ui_pbutton_press(calc->btn_div);
232 else
233 ui_pbutton_release(calc->btn_div);
234 break;
235 case KC_0:
236 if (event->type == KEY_PRESS)
237 ui_pbutton_press(calc->btn_0);
238 else
239 ui_pbutton_release(calc->btn_0);
240 break;
241 case KC_1:
242 if (event->type == KEY_PRESS)
243 ui_pbutton_press(calc->btn_1);
244 else
245 ui_pbutton_release(calc->btn_1);
246 break;
247 case KC_2:
248 if (event->type == KEY_PRESS)
249 ui_pbutton_press(calc->btn_2);
250 else
251 ui_pbutton_release(calc->btn_2);
252 break;
253 case KC_3:
254 if (event->type == KEY_PRESS)
255 ui_pbutton_press(calc->btn_3);
256 else
257 ui_pbutton_release(calc->btn_3);
258 break;
259 case KC_4:
260 if (event->type == KEY_PRESS)
261 ui_pbutton_press(calc->btn_4);
262 else
263 ui_pbutton_release(calc->btn_4);
264 break;
265 case KC_5:
266 if (event->type == KEY_PRESS)
267 ui_pbutton_press(calc->btn_5);
268 else
269 ui_pbutton_release(calc->btn_5);
270 break;
271 case KC_6:
272 if (event->type == KEY_PRESS)
273 ui_pbutton_press(calc->btn_6);
274 else
275 ui_pbutton_release(calc->btn_6);
276 break;
277 case KC_7:
278 if (event->type == KEY_PRESS)
279 ui_pbutton_press(calc->btn_7);
280 else
281 ui_pbutton_release(calc->btn_7);
282 break;
283 case KC_8:
284 if ((event->mods & KM_SHIFT) != 0) {
285 if (event->type == KEY_PRESS)
286 ui_pbutton_press(calc->btn_mul);
287 else
288 ui_pbutton_release(calc->btn_mul);
289 } else {
290 if (event->type == KEY_PRESS)
291 ui_pbutton_press(calc->btn_8);
292 else
293 ui_pbutton_release(calc->btn_8);
294 }
295 break;
296 case KC_9:
297 if (event->type == KEY_PRESS)
298 ui_pbutton_press(calc->btn_9);
299 else
300 ui_pbutton_release(calc->btn_9);
301 break;
302 default:
303 break;
304 }
305}
306
307/** File / Exit menu entry selected.
308 *
309 * @param mentry Menu entry
310 * @param arg Argument (calc_t *)
311 */
312static void calc_file_exit(ui_menu_entry_t *mentry, void *arg)
313{
314 calc_t *calc = (calc_t *) arg;
315
316 ui_quit(calc->ui);
317}
318
319/** Edit / Copy menu entry selected.
320 *
321 * @param mentry Menu entry
322 * @param arg Argument (calc_t *)
323 */
324static void calc_edit_copy(ui_menu_entry_t *mentry, void *arg)
325{
326 const char *str;
327
328 (void) arg;
329 str = (expr != NULL) ? expr : NULL_DISPLAY;
330
331 (void) clipboard_put_str(str);
332}
333
334/** Edit / Paste menu entry selected.
335 *
336 * @param mentry Menu entry
337 * @param arg Argument (calc_t *)
338 */
339static void calc_edit_paste(ui_menu_entry_t *mentry, void *arg)
340{
341 char *str;
342 char *old;
343 char *cp;
344 errno_t rc;
345
346 (void) arg;
347
348 rc = clipboard_get_str(&str);
349 if (rc != EOK)
350 return;
351
352 /* Make sure string only contains allowed characters */
353 cp = str;
354 while (*cp != '\0') {
355 if (!isdigit(*cp) && *cp != '+' && *cp != '-' &&
356 *cp != '*' && *cp != '/')
357 return;
358 ++cp;
359 }
360
361 /* Update expression */
362 old = expr;
363 expr = str;
364 free(old);
365
366 display_update();
367}
368
369static bool is_digit(char c)
370{
371 return ((c >= '0') && (c <= '9'));
372}
373
374static int get_digit(char c)
375{
376 assert(is_digit(c));
377
378 return (c - '0');
379}
380
381static bool is_plus(char c)
382{
383 return (c == '+');
384}
385
386static bool is_minus(char c)
387{
388 return (c == '-');
389}
390
391static bool is_finish(char c)
392{
393 return (c == 0);
394}
395
396static operator_t get_operator(char c)
397{
398 switch (c) {
399 case '+':
400 return OPERATOR_ADD;
401 case '-':
402 return OPERATOR_SUB;
403 case '*':
404 return OPERATOR_MUL;
405 case '/':
406 return OPERATOR_DIV;
407 default:
408 return OPERATOR_NONE;
409 }
410}
411
412static bool is_operator(char c)
413{
414 return (get_operator(c) != OPERATOR_NONE);
415}
416
417static bool stack_push_value(list_t *stack, int64_t value, bool value_neg)
418{
419 stack_item_t *item = malloc(sizeof(stack_item_t));
420 if (!item)
421 return false;
422
423 link_initialize(&item->link);
424 item->type = ITEM_VALUE;
425
426 if (value_neg)
427 item->data.value = -value;
428 else
429 item->data.value = value;
430
431 list_prepend(&item->link, stack);
432
433 return true;
434}
435
436static bool stack_push_operator(list_t *stack, operator_t operator)
437{
438 stack_item_t *item = malloc(sizeof(stack_item_t));
439 if (!item)
440 return false;
441
442 link_initialize(&item->link);
443 item->type = ITEM_OPERATOR;
444 item->data.operator = operator;
445 list_prepend(&item->link, stack);
446
447 return true;
448}
449
450static bool stack_pop_value(list_t *stack, int64_t *value)
451{
452 link_t *link = list_first(stack);
453 if (!link)
454 return false;
455
456 stack_item_t *item = list_get_instance(link, stack_item_t, link);
457 if (item->type != ITEM_VALUE)
458 return false;
459
460 *value = item->data.value;
461
462 list_remove(link);
463 free(item);
464
465 return true;
466}
467
468static bool stack_pop_operator(list_t *stack, operator_t *operator)
469{
470 link_t *link = list_first(stack);
471 if (!link)
472 return false;
473
474 stack_item_t *item = list_get_instance(link, stack_item_t, link);
475 if (item->type != ITEM_OPERATOR)
476 return false;
477
478 *operator = item->data.operator;
479
480 list_remove(link);
481 free(item);
482
483 return true;
484}
485
486static void stack_cleanup(list_t *stack)
487{
488 while (!list_empty(stack)) {
489 link_t *link = list_first(stack);
490 if (link) {
491 stack_item_t *item = list_get_instance(link, stack_item_t,
492 link);
493
494 list_remove(link);
495 free(item);
496 }
497 }
498}
499
500static bool compute(int64_t a, operator_t operator, int64_t b, int64_t *value)
501{
502 switch (operator) {
503 case OPERATOR_ADD:
504 *value = a + b;
505 break;
506 case OPERATOR_SUB:
507 *value = a - b;
508 break;
509 case OPERATOR_MUL:
510 *value = a * b;
511 break;
512 case OPERATOR_DIV:
513 if (b == 0)
514 return false;
515
516 *value = a / b;
517 break;
518 default:
519 return false;
520 }
521
522 return true;
523}
524
525static unsigned int get_priority(operator_t operator)
526{
527 switch (operator) {
528 case OPERATOR_ADD:
529 return 0;
530 case OPERATOR_SUB:
531 return 0;
532 case OPERATOR_MUL:
533 return 1;
534 case OPERATOR_DIV:
535 return 1;
536 default:
537 return 0;
538 }
539}
540
541static void evaluate(list_t *stack, int64_t *value, parser_state_t *state,
542 error_type_t *error_type)
543{
544 while (!list_empty(stack)) {
545 if (!stack_pop_value(stack, value)) {
546 *state = STATE_ERROR;
547 *error_type = ERROR_SYNTAX;
548 break;
549 }
550
551 if (!list_empty(stack)) {
552 operator_t operator;
553 if (!stack_pop_operator(stack, &operator)) {
554 *state = STATE_ERROR;
555 *error_type = ERROR_SYNTAX;
556 break;
557 }
558
559 int64_t value_a;
560 if (!stack_pop_value(stack, &value_a)) {
561 *state = STATE_ERROR;
562 *error_type = ERROR_SYNTAX;
563 break;
564 }
565
566 if (!compute(value_a, operator, *value, value)) {
567 *state = STATE_ERROR;
568 *error_type = ERROR_NUMERIC;
569 break;
570 }
571
572 if (!stack_push_value(stack, *value, false)) {
573 *state = STATE_ERROR;
574 *error_type = ERROR_SYNTAX;
575 break;
576 }
577 }
578 }
579}
580
581static void display_update(void)
582{
583 if (expr != NULL)
584 (void) ui_entry_set_text(display, (void *) expr);
585 else
586 (void) ui_entry_set_text(display, (void *) NULL_DISPLAY);
587
588 ui_entry_paint(display);
589}
590
591static void display_error(error_type_t error_type)
592{
593 if (expr != NULL) {
594 free(expr);
595 expr = NULL;
596 }
597
598 switch (error_type) {
599 case ERROR_SYNTAX:
600 (void) ui_entry_set_text(display,
601 (void *) SYNTAX_ERROR_DISPLAY);
602 break;
603 case ERROR_NUMERIC:
604 (void) ui_entry_set_text(display,
605 (void *) NUMERIC_ERROR_DISPLAY);
606 break;
607 default:
608 (void) ui_entry_set_text(display,
609 (void *) UNKNOWN_ERROR_DISPLAY);
610 break;
611 }
612
613 ui_entry_paint(display);
614}
615
616static void calc_pb_clicked(ui_pbutton_t *pbutton, void *arg)
617{
618 const char *subexpr = (const char *) arg;
619
620 if (expr != NULL) {
621 char *new_expr;
622
623 if (str_length(expr) < EXPR_MAX_LEN) {
624 asprintf(&new_expr, "%s%s", expr, subexpr);
625 free(expr);
626 expr = new_expr;
627 }
628 } else {
629 expr = str_dup(subexpr);
630 }
631
632 display_update();
633}
634
635static void calc_clear_clicked(ui_pbutton_t *pbutton, void *arg)
636{
637 if (expr != NULL) {
638 free(expr);
639 expr = NULL;
640 }
641
642 display_update();
643}
644
645static void calc_eval_clicked(ui_pbutton_t *pbutton, void *arg)
646{
647 if (expr == NULL)
648 return;
649
650 list_t stack;
651 list_initialize(&stack);
652
653 error_type_t error_type = ERROR_SYNTAX;
654 size_t i = 0;
655 parser_state_t state = STATE_INITIAL;
656 int64_t value = 0;
657 bool value_neg = false;
658 operator_t last_operator = OPERATOR_NONE;
659
660 while ((state != STATE_FINISH) && (state != STATE_ERROR)) {
661 switch (state) {
662 case STATE_INITIAL:
663 if (is_digit(expr[i])) {
664 value = get_digit(expr[i]);
665 i++;
666 state = STATE_VALUE;
667 } else if (is_plus(expr[i])) {
668 i++;
669 value_neg = false;
670 state = STATE_DIGIT;
671 } else if (is_minus(expr[i])) {
672 i++;
673 value_neg = true;
674 state = STATE_DIGIT;
675 } else
676 state = STATE_ERROR;
677 break;
678
679 case STATE_DIGIT:
680 if (is_digit(expr[i])) {
681 value = get_digit(expr[i]);
682 i++;
683 state = STATE_VALUE;
684 } else
685 state = STATE_ERROR;
686 break;
687
688 case STATE_VALUE:
689 if (is_digit(expr[i])) {
690 value *= 10;
691 value += get_digit(expr[i]);
692 i++;
693 } else if (is_operator(expr[i])) {
694 if (!stack_push_value(&stack, value, value_neg)) {
695 state = STATE_ERROR;
696 break;
697 }
698
699 value = 0;
700 value_neg = false;
701
702 operator_t operator = get_operator(expr[i]);
703
704 if (get_priority(operator) <= get_priority(last_operator)) {
705 evaluate(&stack, &value, &state, &error_type);
706 if (state == STATE_ERROR)
707 break;
708
709 if (!stack_push_value(&stack, value, value_neg)) {
710 state = STATE_ERROR;
711 break;
712 }
713 }
714
715 if (!stack_push_operator(&stack, operator)) {
716 state = STATE_ERROR;
717 break;
718 }
719
720 last_operator = operator;
721 i++;
722 state = STATE_DIGIT;
723 } else if (is_finish(expr[i])) {
724 if (!stack_push_value(&stack, value, value_neg)) {
725 state = STATE_ERROR;
726 break;
727 }
728
729 state = STATE_FINISH;
730 } else
731 state = STATE_ERROR;
732 break;
733
734 default:
735 state = STATE_ERROR;
736 }
737 }
738
739 evaluate(&stack, &value, &state, &error_type);
740 stack_cleanup(&stack);
741
742 if (state == STATE_ERROR) {
743 display_error(error_type);
744 return;
745 }
746
747 free(expr);
748 asprintf(&expr, "%" PRId64, value);
749 display_update();
750}
751
752static errno_t calc_button_create(calc_t *calc, ui_fixed_t *fixed,
753 int x, int y, const char *text, ui_pbutton_cb_t *cb, void *arg,
754 ui_pbutton_t **rbutton)
755{
756 ui_pbutton_t *pb;
757 gfx_rect_t rect;
758 errno_t rc;
759
760 rc = ui_pbutton_create(calc->ui_res, text, &pb);
761 if (rc != EOK) {
762 printf("Error creating button.\n");
763 return rc;
764 }
765
766 ui_pbutton_set_cb(pb, cb, arg);
767
768 rect.p0.x = calc->geom.btn_orig.x + calc->geom.btn_stride.x * x;
769 rect.p0.y = calc->geom.btn_orig.y + calc->geom.btn_stride.y * y;
770 rect.p1.x = rect.p0.x + calc->geom.btn_dim.x;
771 rect.p1.y = rect.p0.y + calc->geom.btn_dim.y;
772 ui_pbutton_set_rect(pb, &rect);
773
774 rc = ui_fixed_add(fixed, ui_pbutton_ctl(pb));
775 if (rc != EOK) {
776 printf("Error adding control to layout.\n");
777 return rc;
778 }
779
780 if (rbutton != NULL)
781 *rbutton = pb;
782 return EOK;
783}
784
785static void print_syntax(void)
786{
787 printf("Syntax: %s [-d <display-spec>]\n", NAME);
788}
789
790int main(int argc, char *argv[])
791{
792 const char *display_spec = UI_ANY_DEFAULT;
793 ui_t *ui;
794 ui_resource_t *ui_res;
795 ui_fixed_t *fixed;
796 ui_wnd_params_t params;
797 ui_window_t *window;
798 ui_menu_t *mfile;
799 ui_menu_entry_t *mexit;
800 ui_menu_t *medit;
801 ui_menu_entry_t *mcopy;
802 ui_menu_entry_t *mpaste;
803 calc_t calc;
804 errno_t rc;
805 int i;
806
807 i = 1;
808 while (i < argc) {
809 if (str_cmp(argv[i], "-d") == 0) {
810 ++i;
811 if (i >= argc) {
812 printf("Argument missing.\n");
813 print_syntax();
814 return 1;
815 }
816
817 display_spec = argv[i++];
818 } else {
819 printf("Invalid option '%s'.\n", argv[i]);
820 print_syntax();
821 return 1;
822 }
823 }
824
825 rc = ui_create(display_spec, &ui);
826 if (rc != EOK) {
827 printf("Error creating UI on display %s.\n", display_spec);
828 return rc;
829 }
830
831 ui_wnd_params_init(&params);
832 params.caption = "Calculator";
833 params.rect.p0.x = 0;
834 params.rect.p0.y = 0;
835
836 if (ui_is_textmode(ui)) {
837 params.rect.p1.x = 38;
838 params.rect.p1.y = 18;
839
840 calc.geom.menubar_rect.p0.x = 1;
841 calc.geom.menubar_rect.p0.y = 1;
842 calc.geom.menubar_rect.p1.x = params.rect.p1.x - 1;
843 calc.geom.menubar_rect.p1.y = 2;
844 calc.geom.entry_rect.p0.x = 4;
845 calc.geom.entry_rect.p0.y = 3;
846 calc.geom.entry_rect.p1.x = 34;
847 calc.geom.entry_rect.p1.y = 4;
848 calc.geom.btn_orig.x = 4;
849 calc.geom.btn_orig.y = 5;
850 calc.geom.btn_dim.x = 6;
851 calc.geom.btn_dim.y = 2;
852 calc.geom.btn_stride.x = 8;
853 calc.geom.btn_stride.y = 3;
854 } else {
855 params.rect.p1.x = 250;
856 params.rect.p1.y = 270;
857
858 calc.geom.menubar_rect.p0.x = 4;
859 calc.geom.menubar_rect.p0.y = 30;
860 calc.geom.menubar_rect.p1.x = params.rect.p1.x - 4;
861 calc.geom.menubar_rect.p1.y = 52;
862 calc.geom.entry_rect.p0.x = 10;
863 calc.geom.entry_rect.p0.y = 51;
864 calc.geom.entry_rect.p1.x = 240;
865 calc.geom.entry_rect.p1.y = 76;
866 calc.geom.btn_orig.x = 10;
867 calc.geom.btn_orig.y = 90;
868 calc.geom.btn_dim.x = 50;
869 calc.geom.btn_dim.y = 35;
870 calc.geom.btn_stride.x = 60;
871 calc.geom.btn_stride.y = 45;
872 }
873
874 rc = ui_window_create(ui, &params, &window);
875 if (rc != EOK) {
876 printf("Error creating window.\n");
877 return rc;
878 }
879
880 ui_window_set_cb(window, &window_cb, (void *) &calc);
881 calc.ui = ui;
882
883 ui_res = ui_window_get_res(window);
884 calc.ui_res = ui_res;
885
886 rc = ui_fixed_create(&fixed);
887 if (rc != EOK) {
888 printf("Error creating fixed layout.\n");
889 return rc;
890 }
891
892 rc = ui_menu_bar_create(ui, window, &calc.menubar);
893 if (rc != EOK) {
894 printf("Error creating menu bar.\n");
895 return rc;
896 }
897
898 rc = ui_menu_create(calc.menubar, "~F~ile", &mfile);
899 if (rc != EOK) {
900 printf("Error creating menu.\n");
901 return rc;
902 }
903
904 rc = ui_menu_entry_create(mfile, "E~x~it", "Alt-F4", &mexit);
905 if (rc != EOK) {
906 printf("Error creating menu.\n");
907 return rc;
908 }
909
910 ui_menu_entry_set_cb(mexit, calc_file_exit, (void *) &calc);
911
912 rc = ui_menu_create(calc.menubar, "~E~dit", &medit);
913 if (rc != EOK) {
914 printf("Error creating menu.\n");
915 return rc;
916 }
917
918 rc = ui_menu_entry_create(medit, "~C~opy", "Ctrl-C", &mcopy);
919 if (rc != EOK) {
920 printf("Error creating menu.\n");
921 return rc;
922 }
923
924 ui_menu_entry_set_cb(mcopy, calc_edit_copy, (void *) &calc);
925
926 rc = ui_menu_entry_create(medit, "~P~aste", "Ctrl-V", &mpaste);
927 if (rc != EOK) {
928 printf("Error creating menu.\n");
929 return rc;
930 }
931
932 ui_menu_entry_set_cb(mpaste, calc_edit_paste, (void *) &calc);
933
934 ui_menu_bar_set_rect(calc.menubar, &calc.geom.menubar_rect);
935
936 rc = ui_fixed_add(fixed, ui_menu_bar_ctl(calc.menubar));
937 if (rc != EOK) {
938 printf("Error adding control to layout.\n");
939 return rc;
940 }
941
942 rc = ui_entry_create(window, NULL_DISPLAY, &display);
943 if (rc != EOK) {
944 printf("Error creating text lentry.\n");
945 return rc;
946 }
947
948 ui_entry_set_rect(display, &calc.geom.entry_rect);
949 ui_entry_set_halign(display, gfx_halign_right);
950 ui_entry_set_read_only(display, true);
951
952 rc = ui_fixed_add(fixed, ui_entry_ctl(display));
953 if (rc != EOK) {
954 printf("Error adding control to layout.\n");
955 return rc;
956 }
957
958 rc = calc_button_create(&calc, fixed, 0, 0, "7", &calc_pbutton_cb,
959 (void *) "7", &calc.btn_7);
960 if (rc != EOK)
961 return rc;
962
963 rc = calc_button_create(&calc, fixed, 1, 0, "8", &calc_pbutton_cb,
964 (void *) "8", &calc.btn_8);
965 if (rc != EOK)
966 return rc;
967
968 rc = calc_button_create(&calc, fixed, 2, 0, "9", &calc_pbutton_cb,
969 (void *) "9", &calc.btn_9);
970 if (rc != EOK)
971 return rc;
972
973 rc = calc_button_create(&calc, fixed, 3, 0, "/", &calc_pbutton_cb,
974 (void *) "/", &calc.btn_div);
975 if (rc != EOK)
976 return rc;
977
978 rc = calc_button_create(&calc, fixed, 0, 1, "4", &calc_pbutton_cb,
979 (void *) "4", &calc.btn_4);
980 if (rc != EOK)
981 return rc;
982
983 rc = calc_button_create(&calc, fixed, 1, 1, "5", &calc_pbutton_cb,
984 (void *) "5", &calc.btn_5);
985 if (rc != EOK)
986 return rc;
987
988 rc = calc_button_create(&calc, fixed, 2, 1, "6", &calc_pbutton_cb,
989 (void *) "6", &calc.btn_6);
990 if (rc != EOK)
991 return rc;
992
993 rc = calc_button_create(&calc, fixed, 3, 1, "*", &calc_pbutton_cb,
994 (void *) "*", &calc.btn_mul);
995 if (rc != EOK)
996 return rc;
997
998 rc = calc_button_create(&calc, fixed, 0, 2, "1", &calc_pbutton_cb,
999 (void *) "1", &calc.btn_1);
1000 if (rc != EOK)
1001 return rc;
1002
1003 rc = calc_button_create(&calc, fixed, 1, 2, "2", &calc_pbutton_cb,
1004 (void *) "2", &calc.btn_2);
1005 if (rc != EOK)
1006 return rc;
1007
1008 rc = calc_button_create(&calc, fixed, 2, 2, "3", &calc_pbutton_cb,
1009 (void *) "3", &calc.btn_3);
1010 if (rc != EOK)
1011 return rc;
1012
1013 rc = calc_button_create(&calc, fixed, 3, 2, "-", &calc_pbutton_cb,
1014 (void *) "-", &calc.btn_sub);
1015 if (rc != EOK)
1016 return rc;
1017
1018 rc = calc_button_create(&calc, fixed, 0, 3, "0", &calc_pbutton_cb,
1019 (void *) "0", &calc.btn_0);
1020 if (rc != EOK)
1021 return rc;
1022
1023 rc = calc_button_create(&calc, fixed, 1, 3, "C", &calc_clear_cb,
1024 (void *) "C", &calc.btn_clear);
1025 if (rc != EOK)
1026 return rc;
1027
1028 rc = calc_button_create(&calc, fixed, 2, 3, "=", &calc_eval_cb,
1029 (void *) "=", &calc.btn_eval);
1030 if (rc != EOK)
1031 return rc;
1032
1033 rc = calc_button_create(&calc, fixed, 3, 3, "+", &calc_pbutton_cb,
1034 (void *) "+", &calc.btn_add);
1035 if (rc != EOK)
1036 return rc;
1037
1038 ui_pbutton_set_default(calc.btn_eval, true);
1039
1040 ui_window_add(window, ui_fixed_ctl(fixed));
1041
1042 rc = ui_window_paint(window);
1043 if (rc != EOK) {
1044 printf("Error painting window.\n");
1045 return rc;
1046 }
1047
1048 ui_run(ui);
1049 ui_window_destroy(window);
1050 ui_destroy(ui);
1051
1052 return 0;
1053}
Note: See TracBrowser for help on using the repository browser.