Fix FS#9296 by catching repeat events for wheel targets too, moved a bit of code...
[kugel-rb.git] / apps / plugins / calculator.c
bloba5c427752892e9bdaa3b263a517c24594311a310
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2004 Pengxuan Liu (Isaac)
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 00 01 21 22 23 43 44 45 65 66 67 87 88 89 109110111
24 00 |-----------|-----------|-----------|-----------|-----------|
25 01 | | | | | |
26 |***********|***********|***********|***********|***********|
27 |***********|***********|***********|***********|***********|
28 11 | | | | | |
29 12 |-----------|-----------|-----------|-----------|-----------|
30 13 |-----------|-----------|-----------|-----------|-----------| y1
31 14 | | | | | |
32 | | | | | |
33 22 | | | | | |
34 23 |-----------|-----------|-----------|-----------|-----------| y2
35 24 | | | | | |
36 | | | | | |
37 32 | | | | | |
38 33 |-----------|-----------|-----------|-----------|-----------| y3
39 34 | | | | | |
40 | | | | | |
41 42 | | | | | |
42 43 |-----------|-----------|-----------|-----------|-----------| y4
43 44 | | | | | |
44 | | | | | |
45 52 | | | | | |
46 53 |-----------|-----------|-----------|-----------|-----------| y5
47 54 | | | | | |
48 | | | | | |
49 62 | | | | | |
50 63 |-----------|-----------|-----------|-----------|-----------| y6
51 x0 x1 x2 x3 x4 x5
54 /*---------------------------------------------------------------------------
55 Features:
56 - Scientific number format core code. Support range 10^-999 ~ 10^999
57 - Number of significant figures up to 10
59 Limitations:
60 - Right now, only accept "num, operator (+,-,*,/), num, =" input sequence.
61 Input "3, +, 5, -, 2, =", the calculator will only do 5-2 and result = 3
62 You have to input "3, +, 5, =, -, 2, =" to get 3+5-2 = 6
64 - "*,/" have no priority. Actually you can't input 3+5*2 yet.
66 User Instructions:
67 use arrow button to move cursor, "play" button to select, "off" button to exit
68 F1: if typing numbers, it's equal to "Del"; otherwise, equal to "C"
69 F2: circle input "+, -, *, /"
70 F3: equal to "="
72 "MR" : load temp memory
73 "M+" : add currently display to temp memory
74 "C" : reset calculator
75 ---------------------------------------------------------------------------*/
77 #include "plugin.h"
78 #ifdef HAVE_LCD_BITMAP
79 #include "math.h"
81 PLUGIN_HEADER
83 #define BUTTON_ROWS 5
84 #define BUTTON_COLS 5
86 #define REC_HEIGHT (int)(LCD_HEIGHT / (BUTTON_ROWS + 1))
87 #define REC_WIDTH (int)(LCD_WIDTH / BUTTON_COLS)
89 #define Y_6_POS (LCD_HEIGHT) /* Leave room for the border */
90 #define Y_5_POS (Y_6_POS - REC_HEIGHT) /* y5 = 53 */
91 #define Y_4_POS (Y_5_POS - REC_HEIGHT) /* y4 = 43 */
92 #define Y_3_POS (Y_4_POS - REC_HEIGHT) /* y3 = 33 */
93 #define Y_2_POS (Y_3_POS - REC_HEIGHT) /* y2 = 23 */
94 #define Y_1_POS (Y_2_POS - REC_HEIGHT) /* y1 = 13 */
95 #define Y_0_POS 0 /* y0 = 0 */
97 #define X_0_POS 0 /* x0 = 0 */
98 #define X_1_POS (X_0_POS + REC_WIDTH) /* x1 = 22 */
99 #define X_2_POS (X_1_POS + REC_WIDTH) /* x2 = 44 */
100 #define X_3_POS (X_2_POS + REC_WIDTH) /* x3 = 66 */
101 #define X_4_POS (X_3_POS + REC_WIDTH) /* x4 = 88 */
102 #define X_5_POS (X_4_POS + REC_WIDTH) /* x5 = 110, column 111 left blank */
104 #define TEXT_1_POS (Y_1_POS-10) /* y1 = 2 */ /* blank height = 12 */
105 #define TEXT_2_POS (Y_2_POS-8) /* y2 = 15 */ /* blank height = 9 */
106 #define TEXT_3_POS (Y_3_POS-8) /* y3 = 25 */
107 #define TEXT_4_POS (Y_4_POS-8) /* y4 = 35 */
108 #define TEXT_5_POS (Y_5_POS-8) /* y5 = 45 */
109 #define TEXT_6_POS (Y_6_POS-8) /* y6 = 55 */
111 #define SIGN(x) ((x)<0?-1:1)
112 #define ABS(x) ((x)<0?-(x):(x))
114 /* variable button definitions */
115 #if CONFIG_KEYPAD == RECORDER_PAD
116 #define CALCULATOR_LEFT BUTTON_LEFT
117 #define CALCULATOR_RIGHT BUTTON_RIGHT
118 #define CALCULATOR_UP BUTTON_UP
119 #define CALCULATOR_DOWN BUTTON_DOWN
120 #define CALCULATOR_QUIT BUTTON_OFF
121 #define CALCULATOR_INPUT BUTTON_PLAY
122 #define CALCULATOR_CALC BUTTON_F3
123 #define CALCULATOR_OPERATORS BUTTON_F2
124 #define CALCULATOR_CLEAR BUTTON_F1
126 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
127 #define CALCULATOR_LEFT BUTTON_LEFT
128 #define CALCULATOR_RIGHT BUTTON_RIGHT
129 #define CALCULATOR_UP BUTTON_UP
130 #define CALCULATOR_DOWN BUTTON_DOWN
131 #define CALCULATOR_QUIT BUTTON_OFF
132 #define CALCULATOR_INPUT BUTTON_SELECT
133 #define CALCULATOR_CALC BUTTON_F3
134 #define CALCULATOR_OPERATORS BUTTON_F2
135 #define CALCULATOR_CLEAR BUTTON_F1
137 #elif CONFIG_KEYPAD == ONDIO_PAD
138 #define CALCULATOR_LEFT BUTTON_LEFT
139 #define CALCULATOR_RIGHT BUTTON_RIGHT
140 #define CALCULATOR_UP BUTTON_UP
141 #define CALCULATOR_DOWN BUTTON_DOWN
142 #define CALCULATOR_QUIT BUTTON_OFF
143 #define CALCULATOR_INPUT_CALC_PRE BUTTON_MENU
144 #define CALCULATOR_INPUT (BUTTON_MENU | BUTTON_REL)
145 #define CALCULATOR_CALC (BUTTON_MENU | BUTTON_REPEAT)
147 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
148 (CONFIG_KEYPAD == IRIVER_H300_PAD)
149 #define CALCULATOR_LEFT BUTTON_LEFT
150 #define CALCULATOR_RIGHT BUTTON_RIGHT
151 #define CALCULATOR_UP BUTTON_UP
152 #define CALCULATOR_DOWN BUTTON_DOWN
153 #define CALCULATOR_QUIT BUTTON_OFF
154 #define CALCULATOR_INPUT BUTTON_SELECT
155 #define CALCULATOR_CALC BUTTON_ON
156 #define CALCULATOR_OPERATORS BUTTON_MODE
157 #define CALCULATOR_CLEAR BUTTON_REC
159 #define CALCULATOR_RC_QUIT BUTTON_RC_STOP
161 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
162 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
163 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
165 #define CALCULATOR_LEFT BUTTON_LEFT
166 #define CALCULATOR_RIGHT BUTTON_RIGHT
167 #define CALCULATOR_UP_W_SHIFT BUTTON_SCROLL_BACK
168 #define CALCULATOR_DOWN_W_SHIFT BUTTON_SCROLL_FWD
169 #define CALCULATOR_QUIT BUTTON_MENU
170 #define CALCULATOR_INPUT BUTTON_SELECT
171 #define CALCULATOR_CALC BUTTON_PLAY
173 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
175 #define CALCULATOR_LEFT BUTTON_LEFT
176 #define CALCULATOR_RIGHT BUTTON_RIGHT
177 #define CALCULATOR_UP BUTTON_UP
178 #define CALCULATOR_DOWN BUTTON_DOWN
179 #define CALCULATOR_QUIT BUTTON_POWER
180 #define CALCULATOR_INPUT BUTTON_SELECT
181 #define CALCULATOR_CALC BUTTON_PLAY
182 #define CALCULATOR_CLEAR BUTTON_REC
184 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
186 #define CALCULATOR_LEFT BUTTON_LEFT
187 #define CALCULATOR_RIGHT BUTTON_RIGHT
188 #define CALCULATOR_UP BUTTON_UP
189 #define CALCULATOR_DOWN BUTTON_DOWN
190 #define CALCULATOR_QUIT BUTTON_POWER
191 #define CALCULATOR_INPUT BUTTON_SELECT
192 #define CALCULATOR_CALC BUTTON_MENU
193 #define CALCULATOR_CLEAR BUTTON_A
195 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
196 (CONFIG_KEYPAD == SANSA_C200_PAD)
197 #define CALCULATOR_LEFT BUTTON_LEFT
198 #define CALCULATOR_RIGHT BUTTON_RIGHT
199 #define CALCULATOR_UP BUTTON_UP
200 #define CALCULATOR_DOWN BUTTON_DOWN
201 #if CONFIG_KEYPAD == SANSA_E200_PAD
202 /* c200 does not have a scroll wheel */
203 #define CALCULATOR_UP_W_SHIFT BUTTON_SCROLL_BACK
204 #define CALCULATOR_DOWN_W_SHIFT BUTTON_SCROLL_FWD
205 #endif
206 #define CALCULATOR_QUIT BUTTON_POWER
207 #define CALCULATOR_INPUT_CALC_PRE BUTTON_SELECT
208 #define CALCULATOR_INPUT (BUTTON_SELECT|BUTTON_REL)
209 #define CALCULATOR_CALC (BUTTON_SELECT|BUTTON_REPEAT)
210 #define CALCULATOR_CLEAR BUTTON_REC
212 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
214 #define CALCULATOR_LEFT BUTTON_LEFT
215 #define CALCULATOR_RIGHT BUTTON_RIGHT
216 #define CALCULATOR_UP BUTTON_SCROLL_UP
217 #define CALCULATOR_DOWN BUTTON_SCROLL_DOWN
218 #define CALCULATOR_QUIT BUTTON_POWER
219 #define CALCULATOR_INPUT_CALC_PRE BUTTON_PLAY
220 #define CALCULATOR_INPUT (BUTTON_PLAY | BUTTON_REL)
221 #define CALCULATOR_CALC (BUTTON_PLAY | BUTTON_REPEAT)
222 #define CALCULATOR_CLEAR BUTTON_REW
224 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
226 #define CALCULATOR_LEFT BUTTON_LEFT
227 #define CALCULATOR_RIGHT BUTTON_RIGHT
228 #define CALCULATOR_UP BUTTON_UP
229 #define CALCULATOR_DOWN BUTTON_DOWN
230 #define CALCULATOR_QUIT BUTTON_BACK
231 #define CALCULATOR_INPUT BUTTON_SELECT
232 #define CALCULATOR_CALC BUTTON_MENU
233 #define CALCULATOR_CLEAR BUTTON_PLAY
235 #elif (CONFIG_KEYPAD == MROBE100_PAD)
237 #define CALCULATOR_LEFT BUTTON_LEFT
238 #define CALCULATOR_RIGHT BUTTON_RIGHT
239 #define CALCULATOR_UP BUTTON_UP
240 #define CALCULATOR_DOWN BUTTON_DOWN
241 #define CALCULATOR_QUIT BUTTON_POWER
242 #define CALCULATOR_INPUT BUTTON_SELECT
243 #define CALCULATOR_CALC BUTTON_MENU
244 #define CALCULATOR_CLEAR BUTTON_DISPLAY
246 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
248 #define CALCULATOR_LEFT BUTTON_RC_REW
249 #define CALCULATOR_RIGHT BUTTON_RC_FF
250 #define CALCULATOR_UP BUTTON_RC_VOL_UP
251 #define CALCULATOR_DOWN BUTTON_RC_VOL_DOWN
252 #define CALCULATOR_QUIT BUTTON_RC_REC
253 #define CALCULATOR_INPUT BUTTON_RC_PLAY
254 #define CALCULATOR_CALC BUTTON_RC_MODE
255 #define CALCULATOR_CLEAR BUTTON_RC_MENU
257 #define CALCULATOR_RC_QUIT BUTTON_REC
259 #elif (CONFIG_KEYPAD == COWOND2_PAD)
261 #define CALCULATOR_QUIT BUTTON_POWER
262 #define CALCULATOR_CLEAR BUTTON_MENU
264 #else
265 #error No keymap defined!
266 #endif
268 #ifdef HAVE_TOUCHSCREEN
269 #ifndef CALCULATOR_LEFT
270 #define CALCULATOR_LEFT BUTTON_MIDLEFT
271 #endif
272 #ifndef CALCULATOR_RIGHT
273 #define CALCULATOR_RIGHT BUTTON_MIDRIGHT
274 #endif
275 #ifndef CALCULATOR_UP
276 #define CALCULATOR_UP BUTTON_TOPMIDDLE
277 #endif
278 #ifndef CALCULATOR_DOWN
279 #define CALCULATOR_DOWN BUTTON_BOTTOMMIDDLE
280 #endif
281 #ifndef CALCULATOR_CALC
282 #define CALCULATOR_CALC BUTTON_BOTTOMRIGHT
283 #endif
284 #ifndef CALCULATOR_INPUT
285 #define CALCULATOR_INPUT BUTTON_CENTER
286 #endif
287 #ifndef CALCULATOR_CLEAR
288 #define CALCULATOR_CLEAR BUTTON_TOPRIGHT
289 #endif
291 #include "lib/touchscreen.h"
292 static struct ts_raster calc_raster = { X_0_POS, Y_1_POS, BUTTON_COLS*REC_WIDTH, BUTTON_ROWS*REC_HEIGHT, REC_WIDTH, REC_HEIGHT };
293 #endif
295 static const struct plugin_api* rb;
296 MEM_FUNCTION_WRAPPERS(rb);
298 enum {
299 basicButtons,
300 sciButtons
301 } buttonGroup;
303 unsigned char* buttonChar[2][5][5] = {
304 { { "MR" , "M+" , "2nd" , "CE" , "C" },
305 { "7" , "8" , "9" , "/" , "sqr" },
306 { "4" , "5" , "6" , "*" , "x^2" },
307 { "1" , "2" , "3" , "-" , "1/x" },
308 { "0" , "+/-", "." , "+" , "=" } },
310 { { "n!" , "PI" , "1st" , "sin" , "asi" },
311 { "7" , "8" , "9" , "cos" , "aco" },
312 { "4" , "5" , "6" , "tan" , "ata" },
313 { "1" , "2" , "3" , "ln" , "e^x" },
314 { "0" , "+/-", "." , "log" , "x^y" } }
317 enum { btn_MR , btn_M , btn_bas , btn_CE , btn_C ,
318 btn_7 , btn_8 , btn_9 , btn_div , btn_sqr ,
319 btn_4 , btn_5 , btn_6 , btn_time , btn_square ,
320 btn_1 , btn_2 , btn_3 , btn_minus , btn_rec ,
321 btn_0 , btn_sign , btn_dot , btn_add , btn_equal
324 enum { sci_fac, sci_pi , sci_sci , sci_sin , sci_asin ,
325 sci_7 , sci_8 , sci_9 , sci_cos , sci_acos ,
326 sci_4 , sci_5 , sci_6 , sci_tan , sci_atan ,
327 sci_1 , sci_2 , sci_3 , sci_ln , sci_exp ,
328 sci_0 , sci_sign , sci_dot , sci_log , sci_xy
331 #define MINIMUM 0.000000000001 /* e-12 */
332 /* ^ ^ ^ ^ */
333 /* 123456789abcdef */
335 #define DIGITLEN 10 /* must <= 10 */
336 #define SCIENTIFIC_FORMAT ( power < -(DIGITLEN-3) || power > (DIGITLEN))
337 /* 0.000 00000 0001 */
338 /* ^ ^ ^ ^ ^ ^ */
339 /* DIGITLEN 12345 6789a bcdef */
340 /* power 12 34567 89abc def */
341 /* 10^- 123 45678 9abcd ef */
343 unsigned char buf[19];/* 18 bytes of output line,
344 buf[0] is operator
345 buf[1] = 'M' if memTemp is not 0
346 buf[2] = ' '
348 if SCIENTIFIC_FORMAT
349 buf[2]-buf[12] or buf[3]-buf[13] = result;
350 format X.XXXXXXXX
351 buf[13] or buf[14] -buf[17] = power;
352 format eXXX or e-XXX
353 else
354 buf[3]-buf[6] = ' ';
355 buf[7]-buf[17] = result;
357 buf[18] = '\0' */
359 unsigned char typingbuf[DIGITLEN+2];/* byte 0 is sign or ' ',
360 byte 1~DIGITLEN are num and '.'
361 byte (DIGITLEN+1) is '\0' */
362 unsigned char* typingbufPointer = typingbuf;
364 double result = 0; /* main operand, format 0.xxxxx */
365 int power = 0; /* 10^power */
366 double modifier = 0.1; /* position of next input */
367 double operand = 0; /* second operand, format 0.xxxxx */
368 int operandPower = 0; /* 10^power of second operand */
369 char oper = ' '; /* operators: + - * / */
370 bool operInputted = false; /* false: do calculation first and
371 replace current oper
372 true: just replace current oper */
374 double memTemp = 0; /* temp memory */
375 int memTempPower = 0; /* 10^^power of memTemp */
377 int btn_row, btn_col; /* current position index for button */
378 int prev_btn_row, prev_btn_col; /* previous cursor position */
379 #define CAL_BUTTON (btn_row*5+btn_col)
381 int btn = BUTTON_NONE;
382 int lastbtn = BUTTON_NONE;
384 /* Status of calculator */
385 enum {cal_normal, /* 0, normal status, display result */
386 cal_typing, /* 1, currently typing, dot hasn't been typed */
387 cal_dotted, /* 2, currently typing, dot already has been typed. */
388 cal_error,
389 cal_exit,
390 cal_toDo
391 } calStatus;
393 /* constant table for CORDIC algorithm */
394 double cordicTable[51][2]= {
395 /* pow(2,0) - pow(2,-50) atan(pow(2,0) - atan(pow(2,-50) */
396 {1e+00, 7.853981633974483e-01},
397 {5e-01, 4.636476090008061e-01},
398 {2.5e-01, 2.449786631268641e-01},
399 {1.25e-01, 1.243549945467614e-01},
400 {6.25e-02, 6.241880999595735e-02},
401 {3.125e-02, 3.123983343026828e-02},
402 {1.5625e-02, 1.562372862047683e-02},
403 {7.8125e-03, 7.812341060101111e-03},
404 {3.90625e-03, 3.906230131966972e-03},
405 {1.953125e-03, 1.953122516478819e-03},
406 {9.765625e-04, 9.765621895593195e-04},
407 {4.8828125e-04, 4.882812111948983e-04},
408 {2.44140625e-04, 2.441406201493618e-04},
409 {1.220703125e-04, 1.220703118936702e-04},
410 {6.103515625e-05, 6.103515617420877e-05},
411 {3.0517578125e-05, 3.051757811552610e-05},
412 {1.52587890625e-05, 1.525878906131576e-05},
413 {7.62939453125e-06, 7.629394531101970e-06},
414 {3.814697265625e-06, 3.814697265606496e-06},
415 {1.9073486328125e-06, 1.907348632810187e-06},
416 {9.5367431640625e-07, 9.536743164059608e-07},
417 {4.76837158203125e-07, 4.768371582030888e-07},
418 {2.384185791015625e-07, 2.384185791015580e-07},
419 {1.1920928955078125e-07, 1.192092895507807e-07},
420 {5.9604644775390625e-08, 5.960464477539055e-08},
421 {2.98023223876953125e-08, 2.980232238769530e-08},
422 {1.490116119384765625e-08, 1.490116119384765e-08},
423 {7.450580596923828125e-09, 7.450580596923828e-09},
424 {3.7252902984619140625e-09, 3.725290298461914e-09},
425 {1.86264514923095703125e-09, 1.862645149230957e-09},
426 {9.31322574615478515625e-10, 9.313225746154785e-10},
427 {4.656612873077392578125e-10, 4.656612873077393e-10},
428 {2.3283064365386962890625e-10, 2.328306436538696e-10},
429 {1.16415321826934814453125e-10, 1.164153218269348e-10},
430 {5.82076609134674072265625e-11, 5.820766091346741e-11},
431 {2.910383045673370361328125e-11, 2.910383045673370e-11},
432 {1.4551915228366851806640625e-11, 1.455191522836685e-11},
433 {7.2759576141834259033203125e-12, 7.275957614183426e-12},
434 {3.63797880709171295166015625e-12, 3.637978807091713e-12},
435 {1.818989403545856475830078125e-12, 1.818989403545856e-12},
436 {9.094947017729282379150390625e-13, 9.094947017729282e-13},
437 {4.5474735088646411895751953125e-13, 4.547473508864641e-13},
438 {2.27373675443232059478759765625e-13, 2.273736754432321e-13},
439 {1.136868377216160297393798828125e-13, 1.136868377216160e-13},
440 {5.684341886080801486968994140625e-14, 5.684341886080801e-14},
441 {2.8421709430404007434844970703125e-14, 2.842170943040401e-14},
442 {1.42108547152020037174224853515625e-14, 1.421085471520200e-14},
443 {7.10542735760100185871124267578125e-15, 7.105427357601002e-15},
444 {3.552713678800500929355621337890625e-15, 3.552713678800501e-15},
445 {1.7763568394002504646778106689453125e-15, 1.776356839400250e-15},
446 {8.8817841970012523233890533447265625e-16, 8.881784197001252e-16}
449 void doMultiple(double* operandOne, int* powerOne,
450 double operandTwo, int powerTwo);
451 void doAdd (double* operandOne, int* powerOne,
452 double operandTwo, int powerTwo);
453 void printResult(void);
454 void formatResult(void);
455 void oneOperand(void);
457 void drawLines(void);
458 void drawButtons(int group);
460 /* -----------------------------------------------------------------------
461 Handy funtions
462 ----------------------------------------------------------------------- */
463 void cleartypingbuf(void)
465 int k;
466 for( k=1; k<=(DIGITLEN+1); k++)
467 typingbuf[k] = 0;
468 typingbuf[0] = ' ';
469 typingbufPointer = typingbuf+1;
471 void clearbuf(void)
473 int k;
474 for(k=0;k<18;k++)
475 buf[k]=' ';
476 buf[18] = 0;
478 void clearResult(void)
480 result = 0;
481 power = 0;
482 modifier = 0.1;
485 void clearInput(void)
487 calStatus = cal_normal;
488 clearResult();
489 cleartypingbuf();
490 rb->lcd_clear_display();
491 drawButtons(buttonGroup);
492 drawLines();
495 void clearOperand(void)
497 operand = 0;
498 operandPower = 0;
501 void clearMemTemp(void)
503 memTemp = 0;
504 memTempPower = 0;
507 void clearOper(void)
509 oper = ' ';
510 operInputted = false;
513 void clearMem(void)
515 clearInput();
516 clearMemTemp();
517 clearOperand();
518 clearOper();
519 btn = BUTTON_NONE;
522 void switchOperands(void)
524 double tempr = operand;
525 int tempp = operandPower;
526 operand = result;
527 operandPower = power;
528 result = tempr;
529 power = tempp;
532 void drawLines(void)
534 int i;
535 rb->lcd_hline(0, LCD_WIDTH, Y_1_POS-1);
536 for (i = 0; i < 5 ; i++)
537 rb->lcd_hline(0, LCD_WIDTH, Y_1_POS+i*REC_HEIGHT);
538 for (i = 0; i < 4 ; i++)
539 rb->lcd_vline(X_1_POS+i*REC_WIDTH, Y_1_POS, LCD_HEIGHT);
542 void drawButtons(int group)
544 int i, j, w, h;
545 for (i = 0; i <= 4; i++){
546 for (j = 0; j <= 4; j++){
547 rb->lcd_getstringsize( buttonChar[group][i][j],&w,&h);
548 if (i == btn_row && j == btn_col) /* selected item */
549 rb->lcd_set_drawmode(DRMODE_SOLID);
550 else
551 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
552 rb->lcd_fillrect( X_0_POS + j*REC_WIDTH,
553 Y_1_POS + i*REC_HEIGHT,
554 REC_WIDTH, REC_HEIGHT+1);
555 if (i == btn_row && j == btn_col) /* selected item */
556 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
557 else
558 rb->lcd_set_drawmode(DRMODE_SOLID);
559 rb->lcd_putsxy( X_0_POS + j*REC_WIDTH + (REC_WIDTH - w)/2,
560 Y_1_POS + i*REC_HEIGHT + (REC_HEIGHT - h)/2 + 1,
561 buttonChar[group][i][j] );
564 rb->lcd_set_drawmode(DRMODE_SOLID);
567 /* -----------------------------------------------------------------------
568 Initiate calculator
569 ----------------------------------------------------------------------- */
570 void cal_initial (void)
572 int w,h;
574 rb->lcd_getstringsize("A",&w,&h);
575 if (h >= REC_HEIGHT)
576 rb->lcd_setfont(FONT_SYSFIXED);
578 rb->lcd_clear_display();
580 #ifdef CALCULATOR_OPERATORS
581 /* basic operators are available through separate button */
582 buttonGroup = sciButtons;
583 #else
584 buttonGroup = basicButtons;
585 #endif
587 /* initially, invert button "5" */
588 btn_row = 2;
589 btn_col = 1;
590 prev_btn_row = btn_row;
591 prev_btn_col = btn_col;
592 drawButtons(buttonGroup);
593 drawLines();
594 rb->lcd_update();
596 /* initial mem and output display*/
597 clearMem();
598 printResult();
600 /* clear button queue */
601 rb->button_clear_queue();
604 /* -----------------------------------------------------------------------
605 mySqrt uses Heron's algorithm, which is the Newtone-Raphson algorhitm
606 in it's private case for sqrt.
607 Thanks BlueChip for his intro text and Dave Straayer for the actual name.
608 ----------------------------------------------------------------------- */
609 double mySqrt(double square)
611 int k = 0;
612 double temp = 0;
613 double root= ABS(square+1)/2;
615 while( ABS(root - temp) > MINIMUM ){
616 temp = root;
617 root = (square/temp + temp)/2;
618 k++;
619 if (k>10000) return 0;
622 return root;
624 /* -----------------------------------------------------------------------
625 transcendFunc uses CORDIC (COordinate Rotation DIgital Computer) method
626 transcendFunc can do sin,cos,log,exp
627 input parameter is angle
628 ----------------------------------------------------------------------- */
629 void transcendFunc(char* func, double* tt, int* ttPower)
631 double t = (*tt)*M_PI/180; int tPower = *ttPower;
632 int sign = 1;
633 int n = 50; /* n <=50, tables are all <= 50 */
634 int j;
635 double x,y,z,xt,yt,zt;
637 if (tPower < -998) {
638 calStatus = cal_normal;
639 return;
641 if (tPower > 8) {
642 calStatus = cal_error;
643 return;
645 *ttPower = 0;
646 calStatus = cal_normal;
648 if( func[0] =='s' || func[0] =='S'|| func[0] =='t' || func[0] =='T')
649 sign = SIGN(t);
650 else {
651 /* if( func[0] =='c' || func[0] =='C') */
652 sign = 1;
654 t = ABS(t);
656 while (tPower > 0){
657 t *= 10;
658 tPower--;
660 while (tPower < 0) {
661 t /= 10;
662 tPower++;
664 j = 0;
665 while (t > j*M_TWOPI) {j++;}
666 t -= (j-1)*M_TWOPI;
667 if (M_PI_2 < t && t < 3*M_PI_2){
668 t = M_PI - t;
669 if (func[0] =='c' || func[0] =='C')
670 sign = -1;
671 else if (func[0] =='t' || func[0] =='T')
672 t*=-1;
674 else if ( 3*M_PI_2 <= t && t <= M_TWOPI)
675 t -= M_TWOPI;
677 x = 0.60725293500888; y = 0; z = t;
678 for (j=1;j<n+2;j++){
679 xt = x - SIGN(z) * y*cordicTable[j-1][0];
680 yt = y + SIGN(z) * x*cordicTable[j-1][0];
681 zt = z - SIGN(z) * cordicTable[j-1][1];
682 x = xt;
683 y=yt;
684 z=zt;
686 if( func[0] =='s' || func[0] =='S') {
687 *tt = sign*y;
688 return;
690 else if( func[0] =='c' || func[0] =='C') {
691 *tt = sign*x;
692 return;
694 else /*if( func[0] =='t' || func[0] =='T')*/ {
695 if(t==M_PI_2||t==-M_PI_2){
696 calStatus = cal_error;
697 return;
699 else{
700 *tt = sign*(y/x);
701 return;
706 /* -----------------------------------------------------------------------
707 add in scientific number format
708 ----------------------------------------------------------------------- */
709 void doAdd (double* operandOne, int* powerOne,
710 double operandTwo, int powerTwo)
712 if ( *powerOne >= powerTwo ){
713 if (*powerOne - powerTwo <= DIGITLEN+1){
714 while (powerTwo < *powerOne){
715 operandTwo /=10;
716 powerTwo++;
718 *operandOne += operandTwo;
720 /*do nothing if operandTwo is too small*/
722 else{
723 if (powerTwo - *powerOne <= DIGITLEN+1){
724 while(powerTwo > *powerOne){
725 *operandOne /=10;
726 (*powerOne)++;
728 (*operandOne) += operandTwo;
730 else{/* simply copy operandTwo if operandOne is too small */
731 *operandOne = operandTwo;
732 *powerOne = powerTwo;
736 /* -----------------------------------------------------------------------
737 multiple in scientific number format
738 ----------------------------------------------------------------------- */
739 void doMultiple(double* operandOne, int* powerOne,
740 double operandTwo, int powerTwo)
742 (*operandOne) *= operandTwo;
743 (*powerOne) += powerTwo;
746 /* -----------------------------------------------------------------------
747 Handles all one operand calculations
748 ----------------------------------------------------------------------- */
749 void oneOperand(void)
751 int k = 0;
752 if (buttonGroup == basicButtons){
753 switch(CAL_BUTTON){
754 case btn_sqr:
755 if (result<0)
756 calStatus = cal_error;
757 else{
758 if (power%2 == 1){
759 result = (mySqrt(result*10))/10;
760 power = (power+1) / 2;
762 else{
763 result = mySqrt(result);
764 power = power / 2;
766 calStatus = cal_normal;
768 break;
769 case btn_square:
770 power *= 2;
771 result *= result;
772 calStatus = cal_normal;
773 break;
775 case btn_rec:
776 if (result==0)
777 calStatus = cal_error;
778 else{
779 power = -power;
780 result = 1/result;
781 calStatus = cal_normal;
783 break;
784 default:
785 calStatus = cal_toDo;
786 break; /* just for the safety */
789 else{ /* sciButtons */
790 switch(CAL_BUTTON){
791 case sci_sin:
792 transcendFunc("sin", &result, &power);
793 break;
794 case sci_cos:
795 transcendFunc("cos", &result, &power);
796 break;
797 case sci_tan:
798 transcendFunc("tan", &result, &power);
799 break;
800 case sci_fac:
801 if (power<0 || power>8 || result<0 )
802 calStatus = cal_error;
803 else if(result == 0) {
804 result = 1;
805 power = 0;
807 else{
808 while(power > 0) {
809 result *= 10;
810 power--;
812 if ( ( result - (int)result) > MINIMUM )
813 calStatus = cal_error;
814 else {
815 k = result; result = 1;
816 while (k > 1){
817 doMultiple(&result, &power, k, 0);
818 formatResult();
819 k--;
821 calStatus = cal_normal;
824 break;
825 default:
826 calStatus = cal_toDo;
827 break; /* just for the safety */
833 /* -----------------------------------------------------------------------
834 Handles all two operands calculations
835 ----------------------------------------------------------------------- */
836 void twoOperands(void)
838 switch(oper){
839 case '-':
840 doAdd(&operand, &operandPower, -result, power);
841 break;
842 case '+':
843 doAdd(&operand, &operandPower, result, power);
844 break;
845 case '*':
846 doMultiple(&operand, &operandPower, result, power);
847 break;
848 case '/':
849 if ( ABS(result) > MINIMUM ){
850 doMultiple(&operand, &operandPower, 1/result, -power);
852 else
853 calStatus = cal_error;
854 break;
855 default: /* ' ' */
856 switchOperands(); /* counter switchOperands() below */
857 break;
858 } /* switch(oper) */
859 switchOperands();
860 clearOper();
863 /* First, increases *dimen1 by dimen1_delta modulo dimen1_modulo.
864 If dimen1 wraps, increases *dimen2 by dimen2_delta modulo dimen2_modulo.
866 static void move_with_wrap_and_shift(
867 int *dimen1, int dimen1_delta, int dimen1_modulo,
868 int *dimen2, int dimen2_delta, int dimen2_modulo)
870 bool wrapped = false;
872 *dimen1 += dimen1_delta;
873 if (*dimen1 < 0)
875 *dimen1 = dimen1_modulo - 1;
876 wrapped = true;
878 else if (*dimen1 >= dimen1_modulo)
880 *dimen1 = 0;
881 wrapped = true;
884 if (wrapped)
886 /* Make the dividend always positive to be sure about the result.
887 Adding dimen2_modulo does not change it since we do it modulo. */
888 *dimen2 = (*dimen2 + dimen2_modulo + dimen2_delta) % dimen2_modulo;
892 /* -----------------------------------------------------------------------
893 Print buttons when switching 1st and 2nd
894 int group = {basicButtons, sciButtons}
895 ----------------------------------------------------------------------- */
896 void printButtonGroups(int group)
898 drawButtons(group);
899 drawLines();
900 rb->lcd_update();
902 /* -----------------------------------------------------------------------
903 flash the currently marked button
904 ----------------------------------------------------------------------- */
905 void flashButton(void)
907 int k, w, h;
908 for (k=2;k>0;k--)
910 rb->lcd_getstringsize( buttonChar[buttonGroup][btn_row][btn_col],&w,&h);
911 rb->lcd_set_drawmode(DRMODE_SOLID|(k==1) ? 0 : DRMODE_INVERSEVID);
912 rb->lcd_fillrect( X_0_POS + btn_col*REC_WIDTH + 1,
913 Y_1_POS + btn_row*REC_HEIGHT + 1,
914 REC_WIDTH - 1, REC_HEIGHT - 1);
915 rb->lcd_putsxy( X_0_POS + btn_col*REC_WIDTH + (REC_WIDTH - w)/2,
916 Y_1_POS + btn_row*REC_HEIGHT + (REC_HEIGHT - h)/2 +1,
917 buttonChar[buttonGroup][btn_row][btn_col] );
918 rb->lcd_update_rect( X_0_POS + btn_col*REC_WIDTH + 1,
919 Y_1_POS + btn_row*REC_HEIGHT + 1,
920 REC_WIDTH - 1, REC_HEIGHT - 1);
922 if (k!= 1)
923 rb->sleep(HZ/22);
928 /* -----------------------------------------------------------------------
929 pos is the position that needs animation. pos = [1~18]
930 ----------------------------------------------------------------------- */
931 void deleteAnimation(int pos)
933 int k;
934 if (pos<1 || pos >18)
935 return;
936 pos--;
937 rb->lcd_fillrect(1+pos*6, TEXT_1_POS, 6, 8);
938 rb->lcd_update_rect(1+pos*6, TEXT_1_POS, 6, 8);
940 for (k=1;k<=4;k++){
941 rb->sleep(HZ/32);
942 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
943 rb->lcd_fillrect(1+pos*6, TEXT_1_POS, 6, 8);
944 rb->lcd_set_drawmode(DRMODE_SOLID);
945 rb->lcd_fillrect(1+pos*6+1+k, TEXT_1_POS+k,
946 (5-2*k)>0?(5-2*k):1, (7-2*k)>0?(7-2*k):1 );
947 rb->lcd_update_rect(1+pos*6, TEXT_1_POS, 6, 8);
952 /* -----------------------------------------------------------------------
953 result may be one of these formats:
955 xxxx.xxxx
956 0.xxxx
957 0.0000xxxx
959 formatResult() change result to standard format: 0.xxxx
960 if result is close to 0, let it be 0;
961 if result is close to 1, let it be 0.1 and power++;
962 ----------------------------------------------------------------------- */
963 void formatResult(void)
965 int resultsign = SIGN(result);
966 result = ABS(result);
967 if(result > MINIMUM ){ /* doesn't check power, might have problem
968 input wouldn't,
969 + - * / of two formatted number wouldn't.
970 only a calculation that makes a formatted
971 number (0.xxxx) less than MINIMUM in only
972 one operation */
974 if (result<1){
975 while( (int)(result*10) == 0 ){
976 result *= 10;
977 power--;
978 modifier *= 10;
981 else{ /* result >= 1 */
982 while( (int)result != 0 ){
983 result /= 10;
984 power++;
985 modifier /= 10;
987 } /* if result<1 */
989 if (result > (1-MINIMUM)){
990 result = 0.1;
991 power++;
992 modifier /= 10;
994 result *= resultsign;
996 else {
997 result = 0;
998 power = 0;
999 modifier = 0.1;
1003 /* -----------------------------------------------------------------------
1004 result2typingbuf() outputs standard format result to typingbuf.
1005 case SCIENTIFIC_FORMAT, let temppower = 1;
1006 case temppower > 0: print '.' in the middle
1007 case temppower <= 0: print '.' in the begining
1008 ----------------------------------------------------------------------- */
1009 void result2typingbuf(void)
1011 bool haveDot = false;
1012 char tempchar = 0;
1013 int k;
1014 double tempresult = ABS(result); /* positive num makes things simple */
1016 int temppower;
1017 double tempmodifier = 1;
1018 int count;
1020 if(SCIENTIFIC_FORMAT)
1021 temppower = 1; /* output x.xxxx format */
1022 else
1023 temppower = power;
1025 cleartypingbuf();
1027 if(tempresult < MINIMUM){ /* if 0,faster display and avoid complication*/
1028 typingbuf[0] = ' ';
1029 typingbuf[1] = '0';
1031 else{ /* tempresult > 0 */
1032 typingbuf[0] = (SIGN(result)<0)?'-':' ';
1034 typingbufPointer = typingbuf;
1035 if(temppower > 0){
1036 for (k = 0; k<DIGITLEN+1 ; k++){
1037 typingbufPointer++;
1038 if(temppower || *(typingbufPointer-1) == '.'){
1039 count = 0;
1040 tempmodifier = tempmodifier/10;
1041 while( (tempresult-tempmodifier*count) >
1042 (tempmodifier-MINIMUM)){
1043 count++;
1045 tempresult -= tempmodifier*count;
1046 tempresult = ABS(tempresult);
1047 temppower-- ;
1048 *typingbufPointer = count + '0';
1050 else{ /* temppower == 0 */
1051 *typingbufPointer = '.';
1052 haveDot = true;
1054 } /* for */
1056 else{
1057 haveDot = true;
1058 typingbufPointer++; *typingbufPointer = '0';
1059 typingbufPointer++; *typingbufPointer = '.';
1060 for (k = 2; k<DIGITLEN+1 ; k++){
1061 typingbufPointer++;
1062 count = 0;
1063 if ( (-temppower) < (k-1)){
1064 tempmodifier = tempmodifier/10;
1065 while((tempresult-tempmodifier*count)>(tempmodifier-MINIMUM)){
1066 count++;
1069 tempresult -= tempmodifier*count;
1070 tempresult = ABS(tempresult);
1071 temppower-- ;
1073 *typingbufPointer = count + '0';
1076 /* now, typingbufPointer = typingbuf + 16 */
1077 /* backward strip off 0 and '.' */
1078 if (haveDot){
1079 while( (*typingbufPointer == '0') || (*typingbufPointer == '.')){
1080 tempchar = *typingbufPointer;
1081 *typingbufPointer = 0;
1082 typingbufPointer--;
1083 if (tempchar == '.') break;
1086 typingbuf[DIGITLEN+1] = 0;
1087 } /* else tempresult > 0 */
1090 /* -----------------------------------------------------------------------
1091 printResult() generates LCD display.
1092 ----------------------------------------------------------------------- */
1093 void printResult(void)
1095 int k, w, h;
1097 char operbuf[3] = {0, 0, 0};
1099 switch_Status:
1100 switch(calStatus){
1101 case cal_exit:
1102 rb->lcd_clear_display();
1103 rb->splash(HZ/3, "Bye now!");
1104 break;
1105 case cal_error:
1106 clearbuf();
1107 rb->snprintf(buf, 19, "%18s","Error");
1108 break;
1109 case cal_toDo:
1110 clearbuf();
1111 rb->snprintf(buf, 19, "%18s","Coming soon ^_* ");
1112 break;
1114 case cal_normal:
1115 formatResult();
1117 if( power > 1000 ){ /* power -1 > 999 */
1118 calStatus = cal_error;
1119 goto switch_Status;
1121 if (power < -998 ) /* power -1 < -999 */
1122 clearResult(); /* too small, let it be 0 */
1124 result2typingbuf();
1125 clearbuf();
1127 operbuf[0] = oper;
1128 operbuf[1] = ( ABS(memTemp) > MINIMUM )?'M':' ';
1129 operbuf[2] = '\0';
1131 if(SCIENTIFIC_FORMAT){
1132 /* output format: X.XXXX eXXX */
1133 if(power > -98){ /* power-1 >= -99, eXXX or e-XX */
1134 rb->snprintf(buf, 12, "%11s",typingbuf);
1135 for(k=11;k<=14;k++) buf[k] = ' ';
1136 cleartypingbuf();
1137 rb->snprintf(typingbuf, 5, "e%d",power-1);
1138 rb->snprintf(buf+11, 5, "%4s",typingbuf);
1140 else{ /* power-1 <= -100, e-XXX */
1141 rb->snprintf(buf, 12, "%11s",typingbuf);
1142 rb->snprintf(buf+11, 6, "e%d",power-1);
1145 else{
1146 rb->snprintf(buf, 12, "%11s",typingbuf);
1147 } /* if SCIENTIFIC_FORMAT */
1148 break;
1149 case cal_typing:
1150 case cal_dotted:
1151 clearbuf();
1152 operbuf[0] = oper;
1153 operbuf[1] = ( ABS(memTemp) > MINIMUM )?'M':' ';
1154 rb->snprintf(buf, 12, "%11s",typingbuf);
1155 break;
1159 rb->lcd_getstringsize(buf, &w, &h);
1160 rb->screen_clear_area(rb->screens[0], 0, 0, LCD_WIDTH, REC_HEIGHT-1);
1161 rb->lcd_putsxy(4, Y_1_POS - h -1, operbuf);
1162 rb->lcd_putsxy(LCD_WIDTH - w - 4, Y_1_POS - h -1, buf);
1163 rb->lcd_update_rect(0, 1, LCD_WIDTH, Y_1_POS);
1166 /* -----------------------------------------------------------------------
1167 Process typing buttons: 1-9, '.', sign
1168 main operand "result" and typingbuf are processed seperately here.
1169 ----------------------------------------------------------------------- */
1170 void typingProcess(void){
1171 switch( CAL_BUTTON ){
1172 case btn_sign:
1173 if (calStatus == cal_typing ||
1174 calStatus == cal_dotted)
1175 typingbuf[0] = (typingbuf[0]=='-')?' ':'-';
1176 result = -result;
1177 break;
1178 case btn_dot:
1179 operInputted = false;
1180 switch(calStatus){
1181 case cal_normal:
1182 clearInput();
1183 *typingbufPointer = '0';
1184 typingbufPointer++;
1185 case cal_typing:
1186 calStatus = cal_dotted;
1187 *typingbufPointer = '.';
1188 if (typingbufPointer != typingbuf+DIGITLEN+1)
1189 typingbufPointer++;
1190 break;
1191 default: /* cal_dotted */
1192 break;
1194 break;
1195 default: /* 0-9 */
1196 operInputted = false;
1197 /* normal,0; normal,1-9; typing,0; typing,1-9 */
1198 switch(calStatus){
1199 case cal_normal:
1200 if(CAL_BUTTON == btn_0 )
1201 break; /* first input is 0, ignore */
1202 clearInput();
1203 /*no operator means start a new calculation*/
1204 if (oper ==' ')
1205 clearOperand();
1206 calStatus = cal_typing;
1207 /* go on typing, no break */
1208 case cal_typing:
1209 case cal_dotted:
1210 switch(CAL_BUTTON){
1211 case btn_0:
1212 *typingbufPointer = '0';
1213 break;
1214 default:
1215 *typingbufPointer=(7+btn_col-3*(btn_row-1))+ '0';
1216 break;
1218 if (typingbufPointer!=typingbuf+DIGITLEN+1){
1219 typingbufPointer++;
1221 {/* result processing */
1222 if (calStatus == cal_typing) power++;
1223 if (CAL_BUTTON != btn_0)
1224 result= result +
1225 SIGN(result)*
1226 (7+btn_col-3*(btn_row-1))*modifier;
1227 modifier /= 10;
1230 else /* last byte always '\0' */
1231 *typingbufPointer = 0;
1232 break;
1233 default: /* cal_error, cal_exit */
1234 break;
1236 break; /* default, 0-9 */
1237 } /* switch( CAL_BUTTON ) */
1240 /* -----------------------------------------------------------------------
1241 Handle delete operation
1242 main operand "result" and typingbuf are processed seperately here.
1243 ----------------------------------------------------------------------- */
1244 void doDelete(void){
1245 deleteAnimation(18);
1246 switch(calStatus){
1247 case cal_dotted:
1248 if (*(typingbufPointer-1) == '.'){
1249 /* if dotted and deleting '.',
1250 change status and delete '.' below */
1251 calStatus = cal_typing;
1253 else{ /* if dotted and not deleting '.',
1254 power stays */
1255 power++; /* counter "power--;" below */
1257 case cal_typing:
1258 typingbufPointer--;
1260 {/* result processing */ /* 0-9, '.' */
1261 /* if deleting '.', do nothing */
1262 if ( *typingbufPointer != '.'){
1263 power--;
1264 modifier *= 10;
1265 result = result - SIGN(result)*
1266 ((*typingbufPointer)- '0')*modifier;
1270 *typingbufPointer = 0;
1272 /* if (only one digit left and it's 0)
1273 or no digit left, change status*/
1274 if ( typingbufPointer == typingbuf+1 ||
1275 ( typingbufPointer == typingbuf+2 &&
1276 *(typingbufPointer-1) == '0' ))
1277 calStatus = cal_normal;
1278 break;
1279 default: /* normal, error, exit */
1280 break;
1283 /* -----------------------------------------------------------------------
1284 Handle buttons on basic screen
1285 ----------------------------------------------------------------------- */
1286 void basicButtonsProcess(void){
1287 switch (btn) {
1288 case CALCULATOR_INPUT:
1289 if (calStatus == cal_error && (CAL_BUTTON != btn_C) ) break;
1290 flashButton();
1291 switch( CAL_BUTTON ){
1292 case btn_MR:
1293 operInputted = false;
1294 result = memTemp; power = memTempPower;
1295 calStatus = cal_normal;
1296 break;
1297 case btn_M:
1298 formatResult();
1299 if (memTemp > MINIMUM)
1300 doAdd(&memTemp, &memTempPower, result, power);
1301 else {
1302 /* if result is too small and memTemp = 0,
1303 doAdd will not add */
1304 memTemp = result;
1305 memTempPower = power;
1307 calStatus = cal_normal;
1308 break;
1310 case btn_C: clearMem(); break;
1311 case btn_CE: clearInput(); break;
1313 case btn_bas:
1314 buttonGroup = sciButtons;
1315 printButtonGroups(buttonGroup);
1316 break;
1318 /* one operand calculation, may be changed to
1319 like sin, cos, log, etc */
1320 case btn_sqr:
1321 case btn_square:
1322 case btn_rec:
1323 formatResult(); /* not necessary, just for safty */
1324 oneOperand();
1325 break;
1327 case_btn_equal: /* F3 shortkey entrance */
1328 case btn_equal:
1329 formatResult();
1330 calStatus = cal_normal;
1331 operInputted = false;
1332 if (oper != ' ') twoOperands();
1333 break;
1335 case btn_div:
1336 case btn_time:
1337 case btn_minus:
1338 case btn_add:
1339 if(!operInputted) {twoOperands(); operInputted = true;}
1340 oper = buttonChar[basicButtons][btn_row][btn_col][0];
1341 #ifdef CALCULATOR_OPERATORS
1342 case_cycle_operators: /* F2 shortkey entrance */
1343 #endif
1344 calStatus = cal_normal;
1345 formatResult();
1346 operand = result;
1347 operandPower = power;
1349 break;
1351 case btn_sign:
1352 case btn_dot:
1353 default: /* 0-9 */
1354 typingProcess();
1355 break;
1356 } /* switch (CAL_BUTTON) */
1357 break;
1359 #ifdef CALCULATOR_OPERATORS
1360 case CALCULATOR_OPERATORS:
1361 if (calStatus == cal_error) break;
1362 if (!operInputted) {twoOperands(); operInputted = true;}
1363 switch (oper){
1364 case ' ':
1365 case '/': oper = '+'; flashButton(); break;
1366 case '+': oper = '-'; flashButton(); break;
1367 case '-': oper = '*'; flashButton(); break;
1368 case '*': oper = '/'; flashButton(); break;
1370 goto case_cycle_operators;
1371 break;
1372 #endif
1374 case CALCULATOR_CALC:
1375 if (calStatus == cal_error) break;
1376 flashButton();
1377 goto case_btn_equal;
1378 break;
1379 default: break;
1381 printResult();
1384 /* -----------------------------------------------------------------------
1385 Handle buttons on scientific screen
1386 ----------------------------------------------------------------------- */
1387 void sciButtonsProcess(void){
1388 switch (btn) {
1389 case CALCULATOR_INPUT:
1390 if (calStatus == cal_error && (CAL_BUTTON != sci_sci) ) break;
1391 flashButton();
1392 switch( CAL_BUTTON ){
1394 case sci_pi:
1395 result = M_PI; power = 0;
1396 calStatus = cal_normal;
1397 break;
1399 case sci_xy: break;
1401 case sci_sci:
1402 buttonGroup = basicButtons;
1403 printButtonGroups(basicButtons);
1404 break;
1406 case sci_fac:
1407 case sci_sin:
1408 case sci_asin:
1409 case sci_cos:
1410 case sci_acos:
1411 case sci_tan:
1412 case sci_atan:
1413 case sci_ln:
1414 case sci_exp:
1415 case sci_log:
1416 formatResult(); /* not necessary, just for safty */
1417 oneOperand();
1418 break;
1420 case btn_sign:
1421 case btn_dot:
1422 default: /* 0-9 */
1423 typingProcess();
1424 break;
1425 } /* switch (CAL_BUTTON) */
1426 break;
1428 #ifdef CALCULATOR_OPERATORS
1429 case CALCULATOR_OPERATORS:
1430 if (calStatus == cal_error) break;
1431 if (!operInputted) {twoOperands(); operInputted = true;}
1432 switch (oper){
1433 case ' ': oper = '+'; break;
1434 case '/': oper = '+'; deleteAnimation(1); break;
1435 case '+': oper = '-'; deleteAnimation(1); break;
1436 case '-': oper = '*'; deleteAnimation(1); break;
1437 case '*': oper = '/'; deleteAnimation(1); break;
1439 calStatus = cal_normal;
1440 formatResult();
1441 operand = result;
1442 operandPower = power;
1443 break;
1444 #endif
1446 case CALCULATOR_CALC:
1447 if (calStatus == cal_error) break;
1448 formatResult();
1449 calStatus = cal_normal;
1450 operInputted = false;
1451 if (oper != ' ') twoOperands();
1452 break;
1453 default: break;
1455 printResult();
1458 /* -----------------------------------------------------------------------
1459 move button index
1460 Invert display new button, invert back previous button
1461 ----------------------------------------------------------------------- */
1462 int handleButton(int button){
1463 switch(button)
1465 case CALCULATOR_INPUT:
1466 case CALCULATOR_CALC:
1467 #ifdef CALCULATOR_INPUT_CALC_PRE
1468 if (lastbtn != CALCULATOR_INPUT_CALC_PRE)
1469 break;
1470 /* no unconditional break; here! */
1471 #endif
1472 #ifdef CALCULATOR_OPERATORS
1473 case CALCULATOR_OPERATORS:
1474 #endif
1475 switch(buttonGroup){
1476 case basicButtons:
1477 basicButtonsProcess();
1478 break;
1479 case sciButtons:
1480 sciButtonsProcess();
1481 break;
1483 break;
1485 #ifdef CALCULATOR_CLEAR
1486 case CALCULATOR_CLEAR:
1487 switch(calStatus){
1488 case cal_typing:
1489 case cal_dotted:
1490 doDelete();
1491 break;
1492 default: /* cal_normal, cal_error, cal_exit */
1493 clearMem();
1494 break;
1496 printResult();
1497 break;
1498 #endif
1499 case CALCULATOR_LEFT:
1500 case CALCULATOR_LEFT | BUTTON_REPEAT:
1501 move_with_wrap_and_shift(
1502 &btn_col, -1, BUTTON_COLS,
1503 &btn_row, 0, BUTTON_ROWS);
1504 break;
1506 case CALCULATOR_RIGHT:
1507 case CALCULATOR_RIGHT | BUTTON_REPEAT:
1508 move_with_wrap_and_shift(
1509 &btn_col, 1, BUTTON_COLS,
1510 &btn_row, 0, BUTTON_ROWS);
1511 break;
1513 #ifdef CALCULATOR_UP
1514 case CALCULATOR_UP:
1515 case CALCULATOR_UP | BUTTON_REPEAT:
1516 move_with_wrap_and_shift(
1517 &btn_row, -1, BUTTON_ROWS,
1518 &btn_col, 0, BUTTON_COLS);
1519 break;
1520 #endif
1521 #ifdef CALCULATOR_DOWN
1522 case CALCULATOR_DOWN:
1523 case CALCULATOR_DOWN | BUTTON_REPEAT:
1524 move_with_wrap_and_shift(
1525 &btn_row, 1, BUTTON_ROWS,
1526 &btn_col, 0, BUTTON_COLS);
1527 break;
1528 #endif
1530 #ifdef CALCULATOR_UP_W_SHIFT
1531 case CALCULATOR_UP_W_SHIFT:
1532 case CALCULATOR_UP_W_SHIFT | BUTTON_REPEAT:
1533 move_with_wrap_and_shift(
1534 &btn_row, -1, BUTTON_ROWS,
1535 &btn_col, -1, BUTTON_COLS);
1536 break;
1537 #endif
1538 #ifdef CALCULATOR_DOWN_W_SHIFT
1539 case CALCULATOR_DOWN_W_SHIFT:
1540 case CALCULATOR_DOWN_W_SHIFT | BUTTON_REPEAT:
1541 move_with_wrap_and_shift(
1542 &btn_row, 1, BUTTON_ROWS,
1543 &btn_col, 1, BUTTON_COLS);
1544 break;
1545 #endif
1546 #ifdef CALCULATOR_LEFT_W_SHIFT
1547 case CALCULATOR_LEFT_W_SHIFT:
1548 case CALCULATOR_LEFT_W_SHIFT | BUTTON_REPEAT:
1549 move_with_wrap_and_shift(
1550 &btn_col, -1, BUTTON_COLS,
1551 &btn_row, -1, BUTTON_ROWS);
1552 break;
1553 #endif
1554 #ifdef CALCULATOR_RIGHT_W_SHIFT
1555 case CALCULATOR_RIGHT_W_SHIFT:
1556 case CALCULATOR_RIGHT_W_SHIFT | BUTTON_REPEAT:
1557 move_with_wrap_and_shift(
1558 &btn_col, 1, BUTTON_COLS,
1559 &btn_row, 1, BUTTON_ROWS);
1560 break;
1561 #endif
1562 #ifdef CALCULATOR_RC_QUIT
1563 case CALCULATOR_RC_QUIT:
1564 #endif
1565 case CALCULATOR_QUIT:
1566 return -1;
1569 return 0;
1571 prev_btn_row = btn_row;
1572 prev_btn_col = btn_col;
1575 /* -----------------------------------------------------------------------
1576 Main();
1577 ----------------------------------------------------------------------- */
1578 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
1580 (void)parameter;
1581 rb = api;
1583 /* now go ahead and have fun! */
1585 cal_initial();
1587 while (calStatus != cal_exit ) {
1588 btn = rb->button_get_w_tmo(HZ/2);
1589 #ifdef HAVE_TOUCHSCREEN
1590 if(btn & BUTTON_TOUCHSCREEN)
1592 struct ts_raster_result res;
1593 if(touchscreen_map_raster(&calc_raster, rb->button_get_data() >> 16,
1594 rb->button_get_data() & 0xffff, &res) == 1)
1596 btn_row = res.y;
1597 btn_col = res.x;
1598 drawButtons(buttonGroup);
1599 drawLines();
1601 rb->lcd_update();
1603 prev_btn_row = btn_row;
1604 prev_btn_col = btn_col;
1605 if(btn & BUTTON_REL)
1607 btn = CALCULATOR_INPUT;
1608 switch(buttonGroup){
1609 case basicButtons:
1610 basicButtonsProcess();
1611 break;
1612 case sciButtons:
1613 sciButtonsProcess();
1614 break;
1616 btn = BUTTON_TOUCHSCREEN;
1620 #endif
1621 if (handleButton(btn) == -1)
1623 calStatus = cal_exit;
1624 printResult();
1626 else
1628 drawButtons(buttonGroup);
1629 drawLines();
1632 rb->lcd_update();
1634 if(rb->default_event_handler(btn) == SYS_USB_CONNECTED)
1635 return PLUGIN_USB_CONNECTED;
1637 if (btn != BUTTON_NONE)
1638 lastbtn = btn;
1639 } /* while (calStatus != cal_exit ) */
1641 rb->button_clear_queue();
1642 return PLUGIN_OK;
1645 #endif /* #ifdef HAVE_LCD_BITMAP */