00001
00039 #include <led.h>
00040 #include <board.h>
00041 #include <string.h>
00042
00043 #include <gfx/gfx.h>
00044 #include <gfx/win.h>
00045 #include <gfx/wtk.h>
00046 #include <gfx/sysfont.h>
00047 #include <membag.h>
00048 #include <debug.h>
00049 #include <stream.h>
00050 #include <mainloop.h>
00051
00052 #include "app_desktop.h"
00053 #include "app_calc.h"
00054
00067
00068 #define POS_X 10
00069
00070 #define POS_Y 50
00071
00072 #define SIZE_X 45
00073
00074 #define SIZE_Y 35
00075
00076 #define SPACE_X (SIZE_X + 10)
00077
00078 #define SPACE_Y (SIZE_Y + 10)
00079
00080 #define KEYS_PR_ROW 4
00081
00083
00090
00091 #define MAX_VALUE 999999
00092
00093 #define MAX_DIGITS (10+1)
00094
00096
00106 enum command_id {
00108 RADIO_DEC_ID = 123,
00110 RADIO_HEX_ID,
00112 BUTTON_EXIT_ID,
00113 };
00114
00116 enum calc_mode {
00118 CALC_DEC,
00120 CALC_HEX,
00121 };
00122
00124 struct calc_context {
00126 struct wtk_basic_frame *frame;
00128 struct wtk_label *display_lbl;
00130 struct font old_sysfont;
00132 struct gfx_bitmap background;
00134 struct gfx_bitmap label_background;
00135
00137 char text[MAX_DIGITS];
00139 int32_t stack_value;
00141 int32_t disp_value;
00143 char operator;
00145 enum calc_mode mode;
00146 };
00147
00156 static void calc_update_display(struct calc_context *calc)
00157 {
00158 assert(calc);
00159
00160
00161 switch (calc->mode) {
00162 case CALC_HEX:
00163 snprintf(calc->text, MAX_DIGITS, "0x%lx", calc->disp_value);
00164 break;
00165 default:
00166 snprintf(calc->text, MAX_DIGITS, "%ld", calc->disp_value);
00167 break;
00168 }
00169
00170 wtk_label_change(calc->display_lbl, calc->text);
00171 }
00172
00184 static bool calc_frame_command_handler(struct wtk_basic_frame *frame,
00185 win_command_t command_data)
00186 {
00187 struct calc_context *calc;
00188 char command;
00189
00190 calc = wtk_basic_frame_get_custom_data(frame);
00191
00192 command = (char)(uintptr_t)command_data;
00193 switch (command) {
00194
00195 case '0':
00196 case '1':
00197 case '2':
00198 case '3':
00199 case '4':
00200 case '5':
00201 case '6':
00202 case '7':
00203 case '8':
00204 case '9':
00205 if (calc->disp_value < MAX_VALUE) {
00206 calc->disp_value *= 10;
00207 calc->disp_value += command - '0';
00208 calc_update_display(calc);
00209 }
00210
00211 break;
00212
00213
00214 case '+':
00215 case '-':
00216 case '/':
00217 case '*':
00218 if (calc->disp_value) {
00219 calc->stack_value = calc->disp_value;
00220 calc->disp_value = 0;
00221 calc->operator = command;
00222
00223 calc_update_display(calc);
00224 }
00225 break;
00226
00227
00228 case '=':
00229 switch (calc->operator) {
00230 case '+':
00231 calc->disp_value = calc->stack_value + calc->disp_value;
00232 break;
00233
00234 case '-':
00235 calc->disp_value = calc->stack_value - calc->disp_value;
00236 break;
00237
00238 case '*':
00239 calc->disp_value = calc->stack_value * calc->disp_value;
00240 break;
00241
00242 case '/':
00243 if (calc->disp_value != 0) {
00244 calc->disp_value = calc->stack_value / calc->disp_value;
00245 }
00246 break;
00247
00248 default:
00249 break;
00250 }
00251 calc->operator = 0;
00252
00253 if (calc->disp_value > 0 ) {
00254 calc->disp_value = min_s(MAX_VALUE, calc->disp_value);
00255 } else {
00256 calc->disp_value = max_s(-MAX_VALUE, calc->disp_value);
00257 }
00258 calc_update_display(calc);
00259 break;
00260
00261
00262 case 'C':
00263 calc->disp_value = 0;
00264 calc->stack_value = 0;
00265 calc_update_display(calc);
00266 break;
00267
00268
00269 case RADIO_DEC_ID:
00270 calc->mode = CALC_DEC;
00271 calc_update_display(calc);
00272 break;
00273
00274
00275 case RADIO_HEX_ID:
00276 calc->mode = CALC_HEX;
00277 calc_update_display(calc);
00278 break;
00279
00280
00281 case BUTTON_EXIT_ID:
00282
00283 memcpy(&sysfont, &calc->old_sysfont, sizeof(struct font));
00284
00285 app_desktop_restart();
00286
00287 membag_free(calc);
00288
00289 return true;
00290 }
00291
00292 return false;
00293 }
00294
00308 void app_calc_launch(struct workqueue_task *task)
00309 {
00310 struct wtk_radio_group *rg;
00311 struct wtk_radio_button *rb;
00312 struct wtk_basic_frame *lframe;
00313 struct win_window *parent;
00314 struct win_area area;
00315 struct wtk_button *btn;
00316 struct calc_context *calc;
00317 uint8_t i;
00318 char caption[2] = "0";
00319 char keys[] = {
00320 '7','8','9','+',
00321 '4','5','6','-',
00322 '3','2','1','*',
00323 '0','C','=','/',
00324 };
00325
00326 calc = membag_alloc(sizeof(struct calc_context));
00327 if (!calc) {
00328 goto error_ctx;
00329 }
00330
00331
00332 memcpy(&calc->old_sysfont, &sysfont, sizeof(struct font));
00333 sysfont.scale = 2;
00334
00335 calc->mode = CALC_DEC;
00336 calc->disp_value = 0;
00337 calc->stack_value = 0;
00338
00339
00340 calc->background.type = BITMAP_SOLID;
00341 calc->background.data.color = GFX_COLOR(0, 0, 0);
00342
00343 area.pos.x = 0;
00344 area.pos.y = 0;
00345 area.size.x = gfx_get_width();
00346 area.size.y = gfx_get_height();
00347
00348 calc->frame = wtk_basic_frame_create(win_get_root(), &area,
00349 &calc->background, NULL, calc_frame_command_handler,
00350 calc);
00351 if (!calc->frame) {
00352 goto error_frame;
00353 }
00354
00355 parent = wtk_basic_frame_as_child(calc->frame);
00356 win_show(parent);
00357
00358
00359 calc->label_background.type = BITMAP_SOLID;
00360 calc->label_background.data.color = WTK_BUTTON_BACKGROUND_COLOR;
00361
00362 area.pos.x = POS_X;
00363 area.pos.y = 10;
00364 area.size.x = SPACE_X * KEYS_PR_ROW - 10;
00365 area.size.y = 30;
00366
00367 lframe = wtk_basic_frame_create(parent, &area, &calc->label_background,
00368 NULL, NULL, NULL);
00369 if (!lframe) {
00370 goto error_widget;
00371 }
00372 win_show(wtk_basic_frame_as_child(lframe));
00373
00374
00375 area.pos.x = 5;
00376 area.pos.y = 10;
00377 area.size.x -= area.pos.x + 20;
00378 area.size.x -= area.pos.y;
00379 calc->display_lbl = wtk_label_create(wtk_basic_frame_as_child(lframe),
00380 &area, "0", true);
00381 if (!calc->display_lbl) {
00382 goto error_widget;
00383 }
00384 win_show(wtk_label_as_child(calc->display_lbl));
00385
00386
00387 area.pos.x = POS_X;
00388 area.pos.y = POS_Y;
00389 area.size.x = SIZE_X;
00390 area.size.y = SIZE_Y;
00391 for (i = 0; i < ARRAY_LEN(keys); i++) {
00392 caption[0] = keys[i];
00393 btn = wtk_button_create(parent, &area, caption,
00394 (win_command_t)(uintptr_t)caption[0]);
00395 if (!btn) {
00396 goto error_widget;
00397 }
00398 win_show(wtk_button_as_child(btn));
00399
00400 if (((i + 1) % KEYS_PR_ROW) == 0) {
00401 area.pos.x = POS_X;
00402 area.pos.y += SPACE_Y;
00403 } else {
00404 area.pos.x += SPACE_X;
00405 }
00406 }
00407
00408
00409 rg = wtk_radio_group_create();
00410
00411 area.pos.x = SPACE_X * KEYS_PR_ROW + 10;
00412 area.pos.y = POS_Y + 20;
00413 area.size.x = 60;
00414 area.size.y = 30;
00415
00416 rb = wtk_radio_button_create(parent, &area, "Dec", true, rg,
00417 (win_command_t)RADIO_DEC_ID);
00418 if (!rb) {
00419 goto error_widget;
00420 }
00421 win_show(wtk_radio_button_as_child(rb));
00422
00423 area.pos.y += area.size.y + 10;
00424 rb = wtk_radio_button_create(parent, &area, "Hex", false, rg,
00425 (win_command_t)RADIO_HEX_ID);
00426 if (!rb) {
00427 goto error_widget;
00428 }
00429 win_show(wtk_radio_button_as_child(rb));
00430
00431
00432 area.size.x = APP_EXIT_BUTTON_SIZE_X;
00433 area.size.y = APP_EXIT_BUTTON_SIZE_Y;
00434 area.pos.x = APP_EXIT_BUTTON_POS_X;
00435 area.pos.y = APP_EXIT_BUTTON_POS_Y;
00436
00437 btn = wtk_button_create(parent, &area, APP_EXIT_BUTTON_TEXT,
00438 (win_command_t)BUTTON_EXIT_ID);
00439 if (!btn) {
00440 goto error_widget;
00441 }
00442 win_show(wtk_button_as_child(btn));
00443
00444 return;
00445
00446 error_widget:
00447 win_destroy(wtk_basic_frame_as_child(calc->frame));
00448 error_frame:
00449 memcpy(&sysfont, &calc->old_sysfont, sizeof(struct font));
00450 membag_free(calc);
00451 error_ctx:
00452 app_desktop_restart();
00453 }
00454