source: mainline/uspace/app/calculator/calculator.c@ 1eaead4

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

Menu entry accelerators

  • Property mode set to 100644
File size: 21.8 KB
RevLine 
[bdfdc51c]1/*
[96c6a00]2 * Copyright (c) 2022 Jiri Svoboda
[bdfdc51c]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
[6dca10f]30/** @addtogroup calculator
[bdfdc51c]31 * @{
32 */
33/** @file
34 *
35 * Inspired by the code released at https://github.com/osgroup/HelenOSProject
36 *
37 */
38
[1746ede]39#include <clipboard.h>
[b41564c]40#include <ctype.h>
[d942ca4]41#include <io/kbd_event.h>
[bdfdc51c]42#include <stdbool.h>
43#include <stdio.h>
[38d150e]44#include <stdlib.h>
[bdfdc51c]45#include <str.h>
[03145ee]46#include <ui/entry.h>
[b41564c]47#include <ui/fixed.h>
[1746ede]48#include <ui/menubar.h>
49#include <ui/menu.h>
50#include <ui/menuentry.h>
[b41564c]51#include <ui/pbutton.h>
52#include <ui/ui.h>
53#include <ui/window.h>
[bdfdc51c]54
[6dca10f]55#define NAME "calculator"
[bdfdc51c]56
[b41564c]57#define NULL_DISPLAY "0"
[bdfdc51c]58
[b41564c]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
[bdfdc51c]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;
[a35b458]93
[bdfdc51c]94 stack_item_type_t type;
95 union {
96 int64_t value;
97 operator_t operator;
98 } data;
99} stack_item_t;
100
[9c7dc8e]101/** Dimensions. Most of this should not be needed with auto layout */
102typedef struct {
[1746ede]103 gfx_rect_t menubar_rect;
[9c7dc8e]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
[b41564c]110typedef struct {
111 ui_t *ui;
[9c7dc8e]112 ui_resource_t *ui_res;
[d942ca4]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;
[1746ede]129 ui_menu_bar_t *menubar;
[9c7dc8e]130 calc_geom_t geom;
[b41564c]131} calc_t;
132
[1746ede]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
[b41564c]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 *);
[d942ca4]156static void wnd_kbd_event(ui_window_t *, void *, kbd_event_t *);
[b41564c]157
158static ui_window_cb_t window_cb = {
[d942ca4]159 .close = wnd_close,
160 .kbd = wnd_kbd_event
[b41564c]161};
162
[1746ede]163static char *expr = NULL;
164static ui_entry_t *display;
165
[d942ca4]166/** Window close request
[b41564c]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
[d942ca4]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
[5de852c]188 if (ui_window_def_kbd(window, event) == ui_claimed)
189 return;
190
[1746ede]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
[d942ca4]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
[1746ede]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}
[bdfdc51c]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));
[a35b458]377
[bdfdc51c]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;
[a35b458]422
[bdfdc51c]423 link_initialize(&item->link);
424 item->type = ITEM_VALUE;
[a35b458]425
[bdfdc51c]426 if (value_neg)
427 item->data.value = -value;
428 else
429 item->data.value = value;
[a35b458]430
[bdfdc51c]431 list_prepend(&item->link, stack);
[a35b458]432
[bdfdc51c]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;
[a35b458]441
[bdfdc51c]442 link_initialize(&item->link);
443 item->type = ITEM_OPERATOR;
444 item->data.operator = operator;
445 list_prepend(&item->link, stack);
[a35b458]446
[bdfdc51c]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;
[a35b458]455
[bdfdc51c]456 stack_item_t *item = list_get_instance(link, stack_item_t, link);
457 if (item->type != ITEM_VALUE)
458 return false;
[a35b458]459
[bdfdc51c]460 *value = item->data.value;
[a35b458]461
[bdfdc51c]462 list_remove(link);
463 free(item);
[a35b458]464
[bdfdc51c]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;
[a35b458]473
[bdfdc51c]474 stack_item_t *item = list_get_instance(link, stack_item_t, link);
475 if (item->type != ITEM_OPERATOR)
476 return false;
[a35b458]477
[bdfdc51c]478 *operator = item->data.operator;
[a35b458]479
[bdfdc51c]480 list_remove(link);
481 free(item);
[a35b458]482
[bdfdc51c]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);
[a35b458]493
[bdfdc51c]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;
[a35b458]515
[bdfdc51c]516 *value = a / b;
517 break;
518 default:
519 return false;
520 }
[a35b458]521
[bdfdc51c]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 }
[a35b458]550
[bdfdc51c]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 }
[a35b458]558
[bdfdc51c]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 }
[a35b458]565
[bdfdc51c]566 if (!compute(value_a, operator, *value, value)) {
567 *state = STATE_ERROR;
568 *error_type = ERROR_NUMERIC;
569 break;
570 }
[a35b458]571
[bdfdc51c]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)
[03145ee]584 (void) ui_entry_set_text(display, (void *) expr);
[bdfdc51c]585 else
[03145ee]586 (void) ui_entry_set_text(display, (void *) NULL_DISPLAY);
[b41564c]587
[03145ee]588 ui_entry_paint(display);
[bdfdc51c]589}
590
591static void display_error(error_type_t error_type)
592{
593 if (expr != NULL) {
594 free(expr);
595 expr = NULL;
596 }
[a35b458]597
[bdfdc51c]598 switch (error_type) {
599 case ERROR_SYNTAX:
[03145ee]600 (void) ui_entry_set_text(display,
[b41564c]601 (void *) SYNTAX_ERROR_DISPLAY);
[bdfdc51c]602 break;
603 case ERROR_NUMERIC:
[03145ee]604 (void) ui_entry_set_text(display,
[b41564c]605 (void *) NUMERIC_ERROR_DISPLAY);
[bdfdc51c]606 break;
607 default:
[03145ee]608 (void) ui_entry_set_text(display,
[b41564c]609 (void *) UNKNOWN_ERROR_DISPLAY);
610 break;
[bdfdc51c]611 }
[b41564c]612
[03145ee]613 ui_entry_paint(display);
[bdfdc51c]614}
615
[b41564c]616static void calc_pb_clicked(ui_pbutton_t *pbutton, void *arg)
[bdfdc51c]617{
[b41564c]618 const char *subexpr = (const char *) arg;
[a35b458]619
[bdfdc51c]620 if (expr != NULL) {
621 char *new_expr;
[a35b458]622
[b41564c]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 {
[bdfdc51c]629 expr = str_dup(subexpr);
[b41564c]630 }
[a35b458]631
[bdfdc51c]632 display_update();
633}
634
[b41564c]635static void calc_clear_clicked(ui_pbutton_t *pbutton, void *arg)
[bdfdc51c]636{
637 if (expr != NULL) {
638 free(expr);
639 expr = NULL;
640 }
[a35b458]641
[bdfdc51c]642 display_update();
643}
644
[b41564c]645static void calc_eval_clicked(ui_pbutton_t *pbutton, void *arg)
[bdfdc51c]646{
647 if (expr == NULL)
648 return;
[a35b458]649
[bdfdc51c]650 list_t stack;
651 list_initialize(&stack);
[a35b458]652
[bdfdc51c]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;
[a35b458]659
[bdfdc51c]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;
[a35b458]678
[bdfdc51c]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;
[a35b458]687
[bdfdc51c]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 }
[a35b458]698
[bdfdc51c]699 value = 0;
700 value_neg = false;
[a35b458]701
[bdfdc51c]702 operator_t operator = get_operator(expr[i]);
[a35b458]703
[bdfdc51c]704 if (get_priority(operator) <= get_priority(last_operator)) {
705 evaluate(&stack, &value, &state, &error_type);
706 if (state == STATE_ERROR)
707 break;
[a35b458]708
[bdfdc51c]709 if (!stack_push_value(&stack, value, value_neg)) {
710 state = STATE_ERROR;
711 break;
712 }
713 }
[a35b458]714
[bdfdc51c]715 if (!stack_push_operator(&stack, operator)) {
716 state = STATE_ERROR;
717 break;
718 }
[a35b458]719
[bdfdc51c]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 }
[a35b458]728
[bdfdc51c]729 state = STATE_FINISH;
730 } else
731 state = STATE_ERROR;
732 break;
[a35b458]733
[bdfdc51c]734 default:
735 state = STATE_ERROR;
736 }
737 }
[a35b458]738
[bdfdc51c]739 evaluate(&stack, &value, &state, &error_type);
740 stack_cleanup(&stack);
[a35b458]741
[bdfdc51c]742 if (state == STATE_ERROR) {
743 display_error(error_type);
744 return;
745 }
[a35b458]746
[bdfdc51c]747 free(expr);
748 asprintf(&expr, "%" PRId64, value);
749 display_update();
750}
751
[9c7dc8e]752static errno_t calc_button_create(calc_t *calc, ui_fixed_t *fixed,
[b41564c]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
[9c7dc8e]760 rc = ui_pbutton_create(calc->ui_res, text, &pb);
[b41564c]761 if (rc != EOK) {
762 printf("Error creating button.\n");
763 return rc;
764 }
765
766 ui_pbutton_set_cb(pb, cb, arg);
767
[9c7dc8e]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;
[b41564c]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
[fd11144]785static void print_syntax(void)
786{
[b41564c]787 printf("Syntax: %s [-d <display-spec>]\n", NAME);
[fd11144]788}
789
[bdfdc51c]790int main(int argc, char *argv[])
791{
[552b69f]792 const char *display_spec = UI_ANY_DEFAULT;
[b41564c]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;
[1746ede]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;
[b41564c]803 calc_t calc;
804 errno_t rc;
[fd11144]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
[b41564c]817 display_spec = argv[i++];
[fd11144]818 } else {
819 printf("Invalid option '%s'.\n", argv[i]);
820 print_syntax();
821 return 1;
822 }
[bdfdc51c]823 }
[a35b458]824
[b41564c]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
[9c7dc8e]836 if (ui_is_textmode(ui)) {
[cd74fa8]837 params.rect.p1.x = 38;
[45004f3]838 params.rect.p1.y = 18;
[cd74fa8]839
[1746ede]840 calc.geom.menubar_rect.p0.x = 1;
[45004f3]841 calc.geom.menubar_rect.p0.y = 1;
[1746ede]842 calc.geom.menubar_rect.p1.x = params.rect.p1.x - 1;
[45004f3]843 calc.geom.menubar_rect.p1.y = 2;
[9c7dc8e]844 calc.geom.entry_rect.p0.x = 4;
[45004f3]845 calc.geom.entry_rect.p0.y = 3;
[cd74fa8]846 calc.geom.entry_rect.p1.x = 34;
[45004f3]847 calc.geom.entry_rect.p1.y = 4;
[9c7dc8e]848 calc.geom.btn_orig.x = 4;
[45004f3]849 calc.geom.btn_orig.y = 5;
[cd74fa8]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;
[9c7dc8e]854 } else {
[cd74fa8]855 params.rect.p1.x = 250;
856 params.rect.p1.y = 270;
857
[1746ede]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;
[d65accb]863 calc.geom.entry_rect.p0.y = 51;
[1746ede]864 calc.geom.entry_rect.p1.x = 240;
[d65accb]865 calc.geom.entry_rect.p1.y = 76;
[9c7dc8e]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
[b41564c]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);
[9c7dc8e]884 calc.ui_res = ui_res;
[b41564c]885
886 rc = ui_fixed_create(&fixed);
887 if (rc != EOK) {
888 printf("Error creating fixed layout.\n");
889 return rc;
890 }
891
[c68c18b9]892 rc = ui_menu_bar_create(ui, window, &calc.menubar);
[1746ede]893 if (rc != EOK) {
894 printf("Error creating menu bar.\n");
895 return rc;
896 }
897
[96c6a00]898 rc = ui_menu_create(calc.menubar, "~F~ile", &mfile);
[1746ede]899 if (rc != EOK) {
900 printf("Error creating menu.\n");
901 return rc;
902 }
903
[c88d7f99]904 rc = ui_menu_entry_create(mfile, "E~x~it", "Alt-F4", &mexit);
[1746ede]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
[96c6a00]912 rc = ui_menu_create(calc.menubar, "~E~dit", &medit);
[1746ede]913 if (rc != EOK) {
914 printf("Error creating menu.\n");
915 return rc;
916 }
917
[c88d7f99]918 rc = ui_menu_entry_create(medit, "~C~opy", "Ctrl-C", &mcopy);
[1746ede]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
[c88d7f99]926 rc = ui_menu_entry_create(medit, "~P~aste", "Ctrl-V", &mpaste);
[1746ede]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
[db3895d]942 rc = ui_entry_create(window, NULL_DISPLAY, &display);
[b41564c]943 if (rc != EOK) {
[03145ee]944 printf("Error creating text lentry.\n");
[b41564c]945 return rc;
946 }
947
[9c7dc8e]948 ui_entry_set_rect(display, &calc.geom.entry_rect);
[03145ee]949 ui_entry_set_halign(display, gfx_halign_right);
[7481ee19]950 ui_entry_set_read_only(display, true);
[b41564c]951
[03145ee]952 rc = ui_fixed_add(fixed, ui_entry_ctl(display));
[b41564c]953 if (rc != EOK) {
954 printf("Error adding control to layout.\n");
955 return rc;
[bdfdc51c]956 }
[a35b458]957
[9c7dc8e]958 rc = calc_button_create(&calc, fixed, 0, 0, "7", &calc_pbutton_cb,
[d942ca4]959 (void *) "7", &calc.btn_7);
[b41564c]960 if (rc != EOK)
961 return rc;
962
[9c7dc8e]963 rc = calc_button_create(&calc, fixed, 1, 0, "8", &calc_pbutton_cb,
[d942ca4]964 (void *) "8", &calc.btn_8);
[b41564c]965 if (rc != EOK)
966 return rc;
967
[9c7dc8e]968 rc = calc_button_create(&calc, fixed, 2, 0, "9", &calc_pbutton_cb,
[d942ca4]969 (void *) "9", &calc.btn_9);
[b41564c]970 if (rc != EOK)
971 return rc;
972
[9c7dc8e]973 rc = calc_button_create(&calc, fixed, 3, 0, "/", &calc_pbutton_cb,
[d942ca4]974 (void *) "/", &calc.btn_div);
[b41564c]975 if (rc != EOK)
976 return rc;
977
[9c7dc8e]978 rc = calc_button_create(&calc, fixed, 0, 1, "4", &calc_pbutton_cb,
[d942ca4]979 (void *) "4", &calc.btn_4);
[b41564c]980 if (rc != EOK)
981 return rc;
982
[9c7dc8e]983 rc = calc_button_create(&calc, fixed, 1, 1, "5", &calc_pbutton_cb,
[d942ca4]984 (void *) "5", &calc.btn_5);
[b41564c]985 if (rc != EOK)
986 return rc;
987
[9c7dc8e]988 rc = calc_button_create(&calc, fixed, 2, 1, "6", &calc_pbutton_cb,
[d942ca4]989 (void *) "6", &calc.btn_6);
[b41564c]990 if (rc != EOK)
991 return rc;
992
[9c7dc8e]993 rc = calc_button_create(&calc, fixed, 3, 1, "*", &calc_pbutton_cb,
[d942ca4]994 (void *) "*", &calc.btn_mul);
[b41564c]995 if (rc != EOK)
996 return rc;
997
[9c7dc8e]998 rc = calc_button_create(&calc, fixed, 0, 2, "1", &calc_pbutton_cb,
[d942ca4]999 (void *) "1", &calc.btn_1);
[b41564c]1000 if (rc != EOK)
1001 return rc;
1002
[9c7dc8e]1003 rc = calc_button_create(&calc, fixed, 1, 2, "2", &calc_pbutton_cb,
[d942ca4]1004 (void *) "2", &calc.btn_2);
[b41564c]1005 if (rc != EOK)
1006 return rc;
1007
[9c7dc8e]1008 rc = calc_button_create(&calc, fixed, 2, 2, "3", &calc_pbutton_cb,
[d942ca4]1009 (void *) "3", &calc.btn_3);
[b41564c]1010 if (rc != EOK)
1011 return rc;
1012
[9c7dc8e]1013 rc = calc_button_create(&calc, fixed, 3, 2, "-", &calc_pbutton_cb,
[d942ca4]1014 (void *) "-", &calc.btn_sub);
[b41564c]1015 if (rc != EOK)
1016 return rc;
1017
[9c7dc8e]1018 rc = calc_button_create(&calc, fixed, 0, 3, "0", &calc_pbutton_cb,
[d942ca4]1019 (void *) "0", &calc.btn_0);
[b41564c]1020 if (rc != EOK)
1021 return rc;
1022
[9c7dc8e]1023 rc = calc_button_create(&calc, fixed, 1, 3, "C", &calc_clear_cb,
[d942ca4]1024 (void *) "C", &calc.btn_clear);
[b41564c]1025 if (rc != EOK)
1026 return rc;
1027
[9c7dc8e]1028 rc = calc_button_create(&calc, fixed, 2, 3, "=", &calc_eval_cb,
[d942ca4]1029 (void *) "=", &calc.btn_eval);
[b41564c]1030 if (rc != EOK)
1031 return rc;
1032
[9c7dc8e]1033 rc = calc_button_create(&calc, fixed, 3, 3, "+", &calc_pbutton_cb,
[d942ca4]1034 (void *) "+", &calc.btn_add);
[b41564c]1035 if (rc != EOK)
1036 return rc;
1037
[d942ca4]1038 ui_pbutton_set_default(calc.btn_eval, true);
[b41564c]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;
[bdfdc51c]1046 }
[a35b458]1047
[b41564c]1048 ui_run(ui);
1049 ui_window_destroy(window);
1050 ui_destroy(ui);
[a35b458]1051
[bdfdc51c]1052 return 0;
1053}
Note: See TracBrowser for help on using the repository browser.