/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 *
 * Copyright (C) 2004 Pengxuan Liu (Isaac)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/

/*
   00 01    21 22 23    43 44 45    65 66 67    87 88 89    109110111
00 |-----------|-----------|-----------|-----------|-----------|
01 |           |           |           |           |           |
   |***********|***********|***********|***********|***********|
   |***********|***********|***********|***********|***********|
11 |           |           |           |           |           |
12 |-----------|-----------|-----------|-----------|-----------|
13 |-----------|-----------|-----------|-----------|-----------| y1
14 |           |           |           |           |           |
   |           |           |           |           |           |
22 |           |           |           |           |           |
23 |-----------|-----------|-----------|-----------|-----------| y2
24 |           |           |           |           |           |
   |           |           |           |           |           |
32 |           |           |           |           |           |
33 |-----------|-----------|-----------|-----------|-----------| y3
34 |           |           |           |           |           |
   |           |           |           |           |           |
42 |           |           |           |           |           |
43 |-----------|-----------|-----------|-----------|-----------| y4
44 |           |           |           |           |           |
   |           |           |           |           |           |
52 |           |           |           |           |           |
53 |-----------|-----------|-----------|-----------|-----------| y5
54 |           |           |           |           |           |
   |           |           |           |           |           |
62 |           |           |           |           |           |
63 |-----------|-----------|-----------|-----------|-----------| y6
   x0          x1          x2          x3          x4          x5
*/

/*---------------------------------------------------------------------------
Features:
- Scientific number format core code.  Support range 10^-999 ~ 10^999
- Number of significant figures up to 10

Limitations:
- Right now, only accept "num, operator (+,-,*,/), num, =" input sequence.
  Input "3, +, 5, -, 2, =", the calculator will only do 5-2 and result = 3
  You have to input "3, +, 5, =, -, 2, =" to get 3+5-2 = 6

- "*,/" have no priority.  Actually you can't input 3+5*2 yet.

User Instructions:
use arrow button to move cursor, "play" button to select, "off" button to exit
F1: if typing numbers, it's equal to "Del"; otherwise, equal to "C"
F2: circle input "+, -, *, /"
F3: equal to "="

"MR"  :  load temp memory
"M+"  :  add currently display to temp memory
"C"   :  reset calculator
---------------------------------------------------------------------------*/

#include "plugin.h"

#include "math.h"




#define M_TWOPI         (M_PI * 2.0)

#define BUTTON_ROWS 5
#define BUTTON_COLS 5

#define REC_HEIGHT (int)(LCD_HEIGHT / (BUTTON_ROWS + 1))
#define REC_WIDTH (int)(LCD_WIDTH / BUTTON_COLS)

#define Y_6_POS (LCD_HEIGHT)       /* Leave room for the border */
#define Y_5_POS (Y_6_POS - REC_HEIGHT) /* y5 = 53 */
#define Y_4_POS (Y_5_POS - REC_HEIGHT) /* y4 = 43 */
#define Y_3_POS (Y_4_POS - REC_HEIGHT) /* y3 = 33 */
#define Y_2_POS (Y_3_POS - REC_HEIGHT) /* y2 = 23 */
#define Y_1_POS (Y_2_POS - REC_HEIGHT) /* y1 = 13 */
#define Y_0_POS 0                      /* y0 = 0  */

#define X_0_POS 0                      /* x0 = 0  */
#define X_1_POS (X_0_POS + REC_WIDTH)  /* x1 = 22 */
#define X_2_POS (X_1_POS + REC_WIDTH)  /* x2 = 44 */
#define X_3_POS (X_2_POS + REC_WIDTH)  /* x3 = 66 */
#define X_4_POS (X_3_POS + REC_WIDTH)  /* x4 = 88 */
#define X_5_POS (X_4_POS + REC_WIDTH)  /* x5 = 110, column 111 left blank */

#define SIGN(x) ((x)<0?-1:1)
#ifndef ABS
#define ABS(a) (((a) < 0) ? -(a) : (a))
#endif

/* variable button definitions */
#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
    (CONFIG_KEYPAD == IRIVER_H300_PAD)
#define CALCULATOR_LEFT BUTTON_LEFT
#define CALCULATOR_RIGHT BUTTON_RIGHT
#define CALCULATOR_UP   BUTTON_UP
#define CALCULATOR_DOWN BUTTON_DOWN
#define CALCULATOR_QUIT BUTTON_OFF
#define CALCULATOR_INPUT BUTTON_SELECT
#define CALCULATOR_CALC BUTTON_ON
#define CALCULATOR_OPERATORS BUTTON_MODE
#define CALCULATOR_CLEAR BUTTON_REC

#define CALCULATOR_RC_QUIT BUTTON_RC_STOP

#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
      (CONFIG_KEYPAD == IPOD_3G_PAD) || \
      (CONFIG_KEYPAD == IPOD_1G2G_PAD)

#define CALCULATOR_LEFT BUTTON_LEFT
#define CALCULATOR_RIGHT        BUTTON_RIGHT
#define CALCULATOR_UP_W_SHIFT   BUTTON_SCROLL_BACK
#define CALCULATOR_DOWN_W_SHIFT BUTTON_SCROLL_FWD
#define CALCULATOR_QUIT         BUTTON_MENU
#define CALCULATOR_INPUT        BUTTON_SELECT
#define CALCULATOR_CALC         BUTTON_PLAY

#elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)

#define CALCULATOR_LEFT  BUTTON_LEFT
#define CALCULATOR_RIGHT BUTTON_RIGHT
#define CALCULATOR_UP    BUTTON_UP
#define CALCULATOR_DOWN  BUTTON_DOWN
#define CALCULATOR_QUIT  BUTTON_POWER
#define CALCULATOR_INPUT BUTTON_SELECT
#define CALCULATOR_CALC  BUTTON_PLAY
#define CALCULATOR_CLEAR BUTTON_REC

#elif (CONFIG_KEYPAD == GIGABEAT_PAD)

#define CALCULATOR_LEFT BUTTON_LEFT
#define CALCULATOR_RIGHT BUTTON_RIGHT
#define CALCULATOR_UP   BUTTON_UP
#define CALCULATOR_DOWN BUTTON_DOWN
#define CALCULATOR_QUIT BUTTON_POWER
#define CALCULATOR_INPUT BUTTON_SELECT
#define CALCULATOR_CALC BUTTON_MENU
#define CALCULATOR_CLEAR BUTTON_A

#elif (CONFIG_KEYPAD == SANSA_E200_PAD)
#define CALCULATOR_LEFT      BUTTON_LEFT
#define CALCULATOR_RIGHT     BUTTON_RIGHT
#define CALCULATOR_UP        BUTTON_UP
#define CALCULATOR_DOWN      BUTTON_DOWN
#define CALCULATOR_UP_W_SHIFT   BUTTON_SCROLL_BACK
#define CALCULATOR_DOWN_W_SHIFT BUTTON_SCROLL_FWD
#define CALCULATOR_QUIT      BUTTON_POWER
#define CALCULATOR_INPUT_CALC_PRE BUTTON_SELECT
#define CALCULATOR_INPUT     (BUTTON_SELECT|BUTTON_REL)
#define CALCULATOR_CALC      (BUTTON_SELECT|BUTTON_REPEAT)
#define CALCULATOR_CLEAR     BUTTON_REC

#elif (CONFIG_KEYPAD == SANSA_C200_PAD)
#define CALCULATOR_LEFT      BUTTON_LEFT
#define CALCULATOR_RIGHT     BUTTON_RIGHT
#define CALCULATOR_UP        BUTTON_UP
#define CALCULATOR_DOWN      BUTTON_DOWN
#define CALCULATOR_QUIT      BUTTON_POWER
#define CALCULATOR_INPUT_CALC_PRE BUTTON_SELECT
#define CALCULATOR_INPUT     (BUTTON_SELECT|BUTTON_REL)
#define CALCULATOR_CALC      (BUTTON_SELECT|BUTTON_REPEAT)

#elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
#define CALCULATOR_LEFT      BUTTON_LEFT
#define CALCULATOR_RIGHT     BUTTON_RIGHT
#define CALCULATOR_UP        BUTTON_UP
#define CALCULATOR_DOWN      BUTTON_DOWN
#define CALCULATOR_UP_W_SHIFT   BUTTON_SCROLL_BACK
#define CALCULATOR_DOWN_W_SHIFT BUTTON_SCROLL_FWD
#define CALCULATOR_QUIT      (BUTTON_HOME|BUTTON_REPEAT)
#define CALCULATOR_INPUT_CALC_PRE BUTTON_SELECT
#define CALCULATOR_INPUT     (BUTTON_SELECT|BUTTON_REL)
#define CALCULATOR_CALC      (BUTTON_SELECT|BUTTON_REPEAT)
#define CALCULATOR_CLEAR     BUTTON_HOME


#elif (CONFIG_KEYPAD == SANSA_CLIP_PAD)
#define CALCULATOR_LEFT      BUTTON_LEFT
#define CALCULATOR_RIGHT     BUTTON_RIGHT
#define CALCULATOR_UP        BUTTON_UP
#define CALCULATOR_DOWN      BUTTON_DOWN
#define CALCULATOR_QUIT      BUTTON_POWER
#define CALCULATOR_INPUT_CALC_PRE BUTTON_SELECT
#define CALCULATOR_INPUT     (BUTTON_SELECT|BUTTON_REL)
#define CALCULATOR_CALC      (BUTTON_SELECT|BUTTON_REPEAT)
#define CALCULATOR_CLEAR     BUTTON_HOME

#elif (CONFIG_KEYPAD == SANSA_M200_PAD)
#define CALCULATOR_LEFT      BUTTON_LEFT
#define CALCULATOR_RIGHT     BUTTON_RIGHT
#define CALCULATOR_UP        BUTTON_UP
#define CALCULATOR_DOWN      BUTTON_DOWN
#define CALCULATOR_QUIT      BUTTON_POWER
#define CALCULATOR_INPUT_CALC_PRE BUTTON_SELECT
#define CALCULATOR_INPUT     (BUTTON_SELECT|BUTTON_REL)
#define CALCULATOR_CALC      (BUTTON_SELECT|BUTTON_REPEAT)
#define CALCULATOR_CLEAR     (BUTTON_SELECT|BUTTON_UP)

#elif (CONFIG_KEYPAD == IRIVER_H10_PAD)

#define CALCULATOR_LEFT BUTTON_LEFT
#define CALCULATOR_RIGHT          BUTTON_RIGHT
#define CALCULATOR_UP             BUTTON_SCROLL_UP
#define CALCULATOR_DOWN           BUTTON_SCROLL_DOWN
#define CALCULATOR_QUIT           BUTTON_POWER
#define CALCULATOR_INPUT_CALC_PRE BUTTON_PLAY
#define CALCULATOR_INPUT          (BUTTON_PLAY | BUTTON_REL)
#define CALCULATOR_CALC           (BUTTON_PLAY | BUTTON_REPEAT)
#define CALCULATOR_CLEAR          BUTTON_REW

#elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)

#define CALCULATOR_LEFT  BUTTON_LEFT
#define CALCULATOR_RIGHT BUTTON_RIGHT
#define CALCULATOR_UP    BUTTON_UP
#define CALCULATOR_DOWN  BUTTON_DOWN
#define CALCULATOR_QUIT  BUTTON_BACK
#define CALCULATOR_INPUT BUTTON_SELECT
#define CALCULATOR_CALC  BUTTON_MENU
#define CALCULATOR_CLEAR BUTTON_PLAY

#elif (CONFIG_KEYPAD == MROBE100_PAD)

#define CALCULATOR_LEFT BUTTON_LEFT
#define CALCULATOR_RIGHT BUTTON_RIGHT
#define CALCULATOR_UP   BUTTON_UP
#define CALCULATOR_DOWN BUTTON_DOWN
#define CALCULATOR_QUIT BUTTON_POWER
#define CALCULATOR_INPUT BUTTON_SELECT
#define CALCULATOR_CALC BUTTON_MENU
#define CALCULATOR_CLEAR BUTTON_DISPLAY

#elif CONFIG_KEYPAD == IAUDIO_M3_PAD

#define CALCULATOR_LEFT BUTTON_RC_REW
#define CALCULATOR_RIGHT BUTTON_RC_FF
#define CALCULATOR_UP   BUTTON_RC_VOL_UP
#define CALCULATOR_DOWN BUTTON_RC_VOL_DOWN
#define CALCULATOR_QUIT BUTTON_RC_REC
#define CALCULATOR_INPUT BUTTON_RC_PLAY
#define CALCULATOR_CALC BUTTON_RC_MODE
#define CALCULATOR_CLEAR BUTTON_RC_MENU

#define CALCULATOR_RC_QUIT BUTTON_REC

#elif (CONFIG_KEYPAD == COWON_D2_PAD)

#define CALCULATOR_QUIT           BUTTON_POWER
#define CALCULATOR_CLEAR          BUTTON_MENU

#elif CONFIG_KEYPAD == CREATIVE_ZENXFI3_PAD

#define CALCULATOR_LEFT  (BUTTON_BACK|BUTTON_REL)
#define CALCULATOR_RIGHT BUTTON_MENU
#define CALCULATOR_UP    BUTTON_UP
#define CALCULATOR_DOWN  BUTTON_DOWN
#define CALCULATOR_QUIT  BUTTON_POWER
#define CALCULATOR_INPUT (BUTTON_PLAY|BUTTON_REL)
#define CALCULATOR_CALC  (BUTTON_PLAY|BUTTON_REPEAT)
#define CALCULATOR_CLEAR (BUTTON_BACK|BUTTON_REPEAT)

#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD

#define CALCULATOR_LEFT  BUTTON_LEFT
#define CALCULATOR_RIGHT BUTTON_RIGHT
#define CALCULATOR_UP    BUTTON_UP
#define CALCULATOR_DOWN  BUTTON_DOWN
#define CALCULATOR_QUIT  BUTTON_POWER
#define CALCULATOR_INPUT BUTTON_SELECT
#define CALCULATOR_CALC  BUTTON_MENU
#define CALCULATOR_CLEAR BUTTON_VIEW

#elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD

#define CALCULATOR_LEFT  BUTTON_PREV
#define CALCULATOR_RIGHT BUTTON_NEXT
#define CALCULATOR_UP    BUTTON_UP
#define CALCULATOR_DOWN  BUTTON_DOWN
#define CALCULATOR_QUIT  BUTTON_POWER
#define CALCULATOR_INPUT BUTTON_PLAY
#define CALCULATOR_CALC  BUTTON_MENU
#define CALCULATOR_CLEAR BUTTON_RIGHT

#elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD

#define CALCULATOR_LEFT  BUTTON_PREV
#define CALCULATOR_RIGHT BUTTON_NEXT
#define CALCULATOR_UP    BUTTON_UP
#define CALCULATOR_DOWN  BUTTON_DOWN
#define CALCULATOR_QUIT  BUTTON_POWER
#define CALCULATOR_INPUT BUTTON_PLAY
#define CALCULATOR_CALC  BUTTON_MENU
#define CALCULATOR_CLEAR BUTTON_RIGHT

#elif (CONFIG_KEYPAD == ONDAVX747_PAD)

#define CALCULATOR_QUIT           BUTTON_POWER
#define CALCULATOR_CLEAR          BUTTON_MENU

#elif (CONFIG_KEYPAD == ONDAVX777_PAD)
#define CALCULATOR_QUIT           BUTTON_POWER

#elif CONFIG_KEYPAD == MROBE500_PAD
#define CALCULATOR_QUIT           BUTTON_POWER

#elif CONFIG_KEYPAD == SAMSUNG_YH820_PAD

#define CALCULATOR_LEFT  BUTTON_LEFT
#define CALCULATOR_RIGHT BUTTON_RIGHT
#define CALCULATOR_UP    BUTTON_UP
#define CALCULATOR_DOWN  BUTTON_DOWN
#define CALCULATOR_QUIT  (BUTTON_REW|BUTTON_REPEAT)
#define CALCULATOR_INPUT BUTTON_PLAY
#define CALCULATOR_CALC  BUTTON_FFWD
#define CALCULATOR_CLEAR (BUTTON_REW|BUTTON_REL)
#define CALCULATOR_OPERATORS BUTTON_REC

#elif CONFIG_KEYPAD == SAMSUNG_YH92X_PAD

#define CALCULATOR_LEFT  BUTTON_LEFT
#define CALCULATOR_RIGHT BUTTON_RIGHT
#define CALCULATOR_UP    BUTTON_UP
#define CALCULATOR_DOWN  BUTTON_DOWN
#define CALCULATOR_QUIT  (BUTTON_REW|BUTTON_REPEAT)
#define CALCULATOR_INPUT BUTTON_PLAY
#define CALCULATOR_CALC  BUTTON_FFWD
#define CALCULATOR_CLEAR (BUTTON_REW|BUTTON_REL)

#elif CONFIG_KEYPAD == PBELL_VIBE500_PAD

#define CALCULATOR_LEFT  BUTTON_PREV
#define CALCULATOR_RIGHT BUTTON_NEXT
#define CALCULATOR_UP    BUTTON_UP
#define CALCULATOR_DOWN  BUTTON_DOWN
#define CALCULATOR_QUIT  BUTTON_REC
#define CALCULATOR_INPUT BUTTON_OK
#define CALCULATOR_CALC  BUTTON_PLAY
#define CALCULATOR_CLEAR BUTTON_CANCEL

#elif CONFIG_KEYPAD == MPIO_HD200_PAD
#define CALCULATOR_LEFT  BUTTON_REW
#define CALCULATOR_RIGHT BUTTON_FF
#define CALCULATOR_QUIT  (BUTTON_REC|BUTTON_PLAY)
#define CALCULATOR_INPUT BUTTON_FUNC
#define CALCULATOR_CALC  BUTTON_PLAY
#define CALCULATOR_CLEAR BUTTON_REC

#elif CONFIG_KEYPAD == MPIO_HD300_PAD
#define CALCULATOR_LEFT  BUTTON_REW
#define CALCULATOR_RIGHT BUTTON_FF
#define CALCULATOR_UP    BUTTON_UP
#define CALCULATOR_DOWN  BUTTON_DOWN
#define CALCULATOR_QUIT  (BUTTON_MENU|BUTTON_REPEAT)
#define CALCULATOR_INPUT BUTTON_ENTER
#define CALCULATOR_CALC  BUTTON_PLAY
#define CALCULATOR_CLEAR BUTTON_MENU

#elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
#define CALCULATOR_LEFT  BUTTON_LEFT
#define CALCULATOR_RIGHT BUTTON_RIGHT
#define CALCULATOR_UP    BUTTON_UP
#define CALCULATOR_DOWN  BUTTON_DOWN
#define CALCULATOR_QUIT  (BUTTON_BACK|BUTTON_REPEAT)
#define CALCULATOR_INPUT BUTTON_SELECT
#define CALCULATOR_CALC  BUTTON_PLAYPAUSE
#define CALCULATOR_CLEAR  (BUTTON_BACK|BUTTON_REL)

#elif (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
#define CALCULATOR_LEFT      BUTTON_LEFT
#define CALCULATOR_RIGHT     BUTTON_RIGHT
#define CALCULATOR_UP        BUTTON_UP
#define CALCULATOR_DOWN      BUTTON_DOWN
#define CALCULATOR_UP_W_SHIFT   BUTTON_SCROLL_BACK
#define CALCULATOR_DOWN_W_SHIFT BUTTON_SCROLL_FWD
#define CALCULATOR_QUIT      BUTTON_POWER
#define CALCULATOR_INPUT_CALC_PRE BUTTON_SELECT
#define CALCULATOR_INPUT     (BUTTON_SELECT|BUTTON_REL)
#define CALCULATOR_CALC      BUTTON_NEXT
#define CALCULATOR_CLEAR     BUTTON_PREV

#elif (CONFIG_KEYPAD == SAMSUNG_YPR0_PAD)

#define CALCULATOR_LEFT  BUTTON_LEFT
#define CALCULATOR_RIGHT BUTTON_RIGHT
#define CALCULATOR_UP    BUTTON_UP
#define CALCULATOR_DOWN  BUTTON_DOWN
#define CALCULATOR_QUIT  BUTTON_BACK
#define CALCULATOR_INPUT BUTTON_SELECT
#define CALCULATOR_CALC  BUTTON_MENU
#define CALCULATOR_CLEAR BUTTON_USER

#elif (CONFIG_KEYPAD == HM60X_PAD)

#define CALCULATOR_LEFT  BUTTON_LEFT
#define CALCULATOR_RIGHT BUTTON_RIGHT
#define CALCULATOR_UP    BUTTON_UP
#define CALCULATOR_DOWN  BUTTON_DOWN
#define CALCULATOR_QUIT  BUTTON_POWER
#define CALCULATOR_INPUT BUTTON_SELECT
#define CALCULATOR_CALC  (BUTTON_UP|BUTTON_POWER)
#define CALCULATOR_CLEAR (BUTTON_DOWN|BUTTON_POWER)

#elif (CONFIG_KEYPAD == HM801_PAD)

#define CALCULATOR_LEFT  BUTTON_LEFT
#define CALCULATOR_RIGHT BUTTON_RIGHT
#define CALCULATOR_UP    BUTTON_UP
#define CALCULATOR_DOWN  BUTTON_DOWN
#define CALCULATOR_QUIT  BUTTON_POWER
#define CALCULATOR_INPUT BUTTON_SELECT
#define CALCULATOR_CALC  BUTTON_PLAY
#define CALCULATOR_CLEAR BUTTON_PREV

#elif CONFIG_KEYPAD == SONY_NWZ_PAD
#define CALCULATOR_LEFT    BUTTON_LEFT
#define CALCULATOR_RIGHT   BUTTON_RIGHT
#define CALCULATOR_UP      BUTTON_UP
#define CALCULATOR_DOWN    BUTTON_DOWN
#define CALCULATOR_QUIT    (BUTTON_BACK|BUTTON_REPEAT)
#define CALCULATOR_INPUT   BUTTON_PLAY
#define CALCULATOR_CALC    BUTTON_POWER
#define CALCULATOR_CLEAR   BUTTON_BACK

#elif CONFIG_KEYPAD == CREATIVE_ZEN_PAD
#define CALCULATOR_LEFT    BUTTON_LEFT
#define CALCULATOR_RIGHT   BUTTON_RIGHT
#define CALCULATOR_UP      BUTTON_UP
#define CALCULATOR_DOWN    BUTTON_DOWN
#define CALCULATOR_QUIT    BUTTON_BACK
#define CALCULATOR_INPUT   BUTTON_SELECT
#define CALCULATOR_CALC    BUTTON_PLAYPAUSE
#define CALCULATOR_CLEAR   BUTTON_SHORTCUT

#elif CONFIG_KEYPAD == DX50_PAD
#define CALCULATOR_QUIT    BUTTON_POWER

#elif CONFIG_KEYPAD == CREATIVE_ZENXFI2_PAD
#define CALCULATOR_QUIT     BUTTON_POWER
#define CALCULATOR_INPUT    BUTTON_MENU

#elif CONFIG_KEYPAD == AGPTEK_ROCKER_PAD
#define CALCULATOR_LEFT    BUTTON_LEFT
#define CALCULATOR_RIGHT   BUTTON_RIGHT
#define CALCULATOR_UP      BUTTON_UP
#define CALCULATOR_DOWN    BUTTON_DOWN
#define CALCULATOR_QUIT    BUTTON_POWER
#define CALCULATOR_INPUT   BUTTON_SELECT
#define CALCULATOR_CALC    BUTTON_VOLUP
#define CALCULATOR_CLEAR   (BUTTON_SELECT|BUTTON_REPEAT)

#elif CONFIG_KEYPAD == XDUOO_X3_PAD || CONFIG_KEYPAD == XDUOO_X3II_PAD || CONFIG_KEYPAD == XDUOO_X20_PAD
#define CALCULATOR_LEFT      BUTTON_PREV
#define CALCULATOR_RIGHT     BUTTON_NEXT
#define CALCULATOR_UP        BUTTON_HOME
#define CALCULATOR_DOWN      BUTTON_OPTION
#define CALCULATOR_QUIT      BUTTON_POWER
#define CALCULATOR_INPUT_CALC_PRE (BUTTON_OPTION|BUTTON_REPEAT)
#define CALCULATOR_INPUT     (BUTTON_PLAY|BUTTON_REL)
#define CALCULATOR_CALC      (BUTTON_PLAY|BUTTON_REPEAT)
#define CALCULATOR_CLEAR     (BUTTON_POWER|BUTTON_REPEAT)

#elif CONFIG_KEYPAD == FIIO_M3K_LINUX_PAD
#define CALCULATOR_LEFT      BUTTON_PREV
#define CALCULATOR_RIGHT     BUTTON_NEXT
#define CALCULATOR_UP        BUTTON_HOME
#define CALCULATOR_DOWN      BUTTON_OPTION
#define CALCULATOR_QUIT      BUTTON_POWER
#define CALCULATOR_INPUT_CALC_PRE (BUTTON_OPTION|BUTTON_REPEAT)
#define CALCULATOR_INPUT     (BUTTON_PLAY|BUTTON_REL)
#define CALCULATOR_CALC      (BUTTON_PLAY|BUTTON_REPEAT)
#define CALCULATOR_CLEAR     (BUTTON_POWER|BUTTON_REPEAT)

#elif CONFIG_KEYPAD == IHIFI_770_PAD || CONFIG_KEYPAD == IHIFI_800_PAD
#define CALCULATOR_LEFT      BUTTON_HOME
#define CALCULATOR_RIGHT     BUTTON_VOL_DOWN
#define CALCULATOR_UP        BUTTON_PREV
#define CALCULATOR_DOWN      BUTTON_NEXT
#define CALCULATOR_QUIT      BUTTON_POWER
#define CALCULATOR_INPUT_CALC_PRE (BUTTON_HOME|BUTTON_REPEAT)
#define CALCULATOR_INPUT     (BUTTON_PLAY|BUTTON_REL)
#define CALCULATOR_CALC      (BUTTON_PLAY|BUTTON_REPEAT)
#define CALCULATOR_CLEAR     (BUTTON_POWER|BUTTON_REPEAT)

#elif CONFIG_KEYPAD == EROSQ_PAD
#define CALCULATOR_LEFT    BUTTON_SCROLL_BACK
#define CALCULATOR_RIGHT   BUTTON_SCROLL_FWD
#define CALCULATOR_UP      BUTTON_PREV
#define CALCULATOR_DOWN    BUTTON_NEXT
#define CALCULATOR_QUIT    BUTTON_POWER
#define CALCULATOR_INPUT   BUTTON_PLAY
#define CALCULATOR_CALC    BUTTON_MENU
#define CALCULATOR_CLEAR   BUTTON_BACK

#elif CONFIG_KEYPAD == FIIO_M3K_PAD
#define CALCULATOR_LEFT     BUTTON_LEFT
#define CALCULATOR_RIGHT    BUTTON_RIGHT
#define CALCULATOR_UP       BUTTON_UP
#define CALCULATOR_DOWN     BUTTON_DOWN
#define CALCULATOR_QUIT     BUTTON_POWER
#define CALCULATOR_INPUT    BUTTON_PLAY
#define CALCULATOR_INPUT2  (BUTTON_SELECT|BUTTON_REL)
#define CALCULATOR_CALC     BUTTON_MENU
#define CALCULATOR_CLEAR    BUTTON_BACK

#elif CONFIG_KEYPAD == SHANLING_Q1_PAD || CONFIG_KEYPAD == HIBY_R3PROII_PAD
#define CALCULATOR_QUIT     BUTTON_POWER

#elif CONFIG_KEYPAD == MA_PAD
#define CALCULATOR_LEFT     BUTTON_LEFT
#define CALCULATOR_RIGHT    BUTTON_RIGHT
#define CALCULATOR_UP       BUTTON_UP
#define CALCULATOR_DOWN     BUTTON_DOWN
#define CALCULATOR_QUIT     (BUTTON_BACK|BUTTON_REPEAT)
#define CALCULATOR_INPUT    BUTTON_PLAY
#define CALCULATOR_CALC     BUTTON_MENU
#define CALCULATOR_CLEAR    BUTTON_BACK

#elif CONFIG_KEYPAD == RG_NANO_PAD

#define CALCULATOR_LEFT     BUTTON_LEFT
#define CALCULATOR_RIGHT    BUTTON_RIGHT
#define CALCULATOR_UP       BUTTON_UP
#define CALCULATOR_DOWN     BUTTON_DOWN
#define CALCULATOR_QUIT     BUTTON_START
#define CALCULATOR_INPUT    BUTTON_A
#define CALCULATOR_CALC     BUTTON_X
#define CALCULATOR_CLEAR    BUTTON_B

#elif CONFIG_KEYPAD == CTRU_PAD

#define CALCULATOR_LEFT  BUTTON_LEFT
#define CALCULATOR_RIGHT BUTTON_RIGHT
#define CALCULATOR_UP    BUTTON_UP
#define CALCULATOR_DOWN  BUTTON_DOWN
#define CALCULATOR_QUIT  BUTTON_BACK
#define CALCULATOR_INPUT BUTTON_SELECT
#define CALCULATOR_CALC  BUTTON_MENU
#define CALCULATOR_CLEAR BUTTON_USER

#else
#error No keymap defined!
#endif

#ifdef HAVE_TOUCHSCREEN
#ifndef CALCULATOR_LEFT
#define CALCULATOR_LEFT           BUTTON_MIDLEFT
#endif
#ifndef CALCULATOR_RIGHT
#define CALCULATOR_RIGHT          BUTTON_MIDRIGHT
#endif
#ifndef CALCULATOR_UP
#define CALCULATOR_UP             BUTTON_TOPMIDDLE
#endif
#ifndef CALCULATOR_DOWN
#define CALCULATOR_DOWN           BUTTON_BOTTOMMIDDLE
#endif
#ifndef CALCULATOR_CALC
#define CALCULATOR_CALC           BUTTON_BOTTOMRIGHT
#endif
#ifndef CALCULATOR_INPUT
#define CALCULATOR_INPUT          BUTTON_CENTER
#endif
#ifndef CALCULATOR_CLEAR
#define CALCULATOR_CLEAR          BUTTON_TOPRIGHT
#endif

#include "lib/pluginlib_touchscreen.h"
static struct ts_raster calc_raster = { X_0_POS, Y_1_POS,
    BUTTON_COLS*REC_WIDTH, BUTTON_ROWS*REC_HEIGHT, REC_WIDTH, REC_HEIGHT };
#endif

enum {
    basicButtons,
    sciButtons
} buttonGroup;

unsigned char* buttonChar[2][5][5] = {
    { { "MR" , "M+" , "2nd" , "CE"   , "C"   },
      { "7"  , "8"  , "9"   , "/"    , "sqr" },
      { "4"  , "5"  , "6"   , "*"    , "x^2" },
      { "1"  , "2"  , "3"   , "-"    , "1/x" },
      { "0"  , "+/-", "."   , "+"    , "="   }  },

    { { "n!" , "PI" , "1st" , "sin"  , "asi" },
      { "7"  , "8"  , "9"   , "cos"  , "aco" },
      { "4"  , "5"  , "6"   , "tan"  , "ata" },
      { "1"  , "2"  , "3"   , "ln"   , "e^x" },
      { "0"  , "+/-", "."   , "log"  , "x^y" }  }
};

enum { btn_MR , btn_M    , btn_bas , btn_CE    , btn_C      ,
       btn_7  , btn_8    , btn_9   , btn_div   , btn_sqr    ,
       btn_4  , btn_5    , btn_6   , btn_time  , btn_square ,
       btn_1  , btn_2    , btn_3   , btn_minus , btn_rec    ,
       btn_0  , btn_sign , btn_dot , btn_add   , btn_equal
     };

enum { sci_fac, sci_pi   , sci_sci , sci_sin   , sci_asin   ,
       sci_7  , sci_8    , sci_9   , sci_cos   , sci_acos    ,
       sci_4  , sci_5    , sci_6   , sci_tan   , sci_atan    ,
       sci_1  , sci_2    , sci_3   , sci_ln    , sci_exp    ,
       sci_0  , sci_sign , sci_dot , sci_log   , sci_xy
     };

#define MINIMUM 0.000000000001   /* e-12 */
              /*  ^   ^    ^    ^       */
              /*  123456789abcdef       */

#define DIGITLEN 10  /* must <= 10 */
#define SCIENTIFIC_FORMAT ( power < -(DIGITLEN-3) || power > (DIGITLEN))
           /*          0.000 00000 0001         */
           /*          ^   ^ ^   ^ ^   ^        */
           /* DIGITLEN 12345 6789a bcdef        */
           /* power       12 34567 89abc def    */
           /* 10^-       123 45678 9abcd ef     */

unsigned char buf[19];/* 18 bytes of output line,
                         buf[0] is operator
                         buf[1] = 'M' if memTemp is not 0
                         buf[2] = ' '

                         if SCIENTIFIC_FORMAT
                             buf[2]-buf[12] or buf[3]-buf[13] = result;
                             format X.XXXXXXXX
                             buf[13] or buf[14] -buf[17] = power;
                             format eXXX or e-XXX
                         else
                             buf[3]-buf[6] = ' ';
                             buf[7]-buf[17] = result;

                         buf[18] = '\0'                    */

unsigned char typingbuf[DIGITLEN+2];/* byte 0 is sign or ' ',
                                       byte 1~DIGITLEN are num and '.'
                                       byte (DIGITLEN+1) is '\0' */
unsigned char* typingbufPointer = typingbuf;

double result = 0;          /*  main operand, format 0.xxxxx     */
int power = 0;              /*  10^power                         */
double modifier = 0.1;      /*  position of next input           */
double operand = 0;         /*  second operand, format 0.xxxxx   */
int operandPower = 0;       /*  10^power of second operand       */
char oper = ' ';            /*  operators: + - * /               */
bool operInputted = false;  /*  false: do calculation first and
                                       replace current oper
                                true:  just replace current oper */

double memTemp = 0;         /* temp memory                       */
int memTempPower = 0;       /* 10^^power of memTemp              */

int btn_row, btn_col;       /* current position index for button */
int prev_btn_row, prev_btn_col; /* previous cursor position      */
#define CAL_BUTTON (btn_row*5+btn_col)

int btn = BUTTON_NONE;
int lastbtn = BUTTON_NONE;

/* Status of calculator */
enum {cal_normal,  /* 0, normal status, display result */
      cal_typing,  /* 1, currently typing, dot hasn't been typed */
      cal_dotted,  /* 2, currently typing, dot already has been typed. */
      cal_error,
      cal_exit,
      cal_toDo
} calStatus;

/* constant table for CORDIC algorithm */
static const double cordicTable[51][2]= {
 /* pow(2,0) - pow(2,-50)             atan(pow(2,0) - atan(pow(2,-50) */
    {1e+00,                                    7.853981633974483e-01},
    {5e-01,                                    4.636476090008061e-01},
    {2.5e-01,                                  2.449786631268641e-01},
    {1.25e-01,                                 1.243549945467614e-01},
    {6.25e-02,                                 6.241880999595735e-02},
    {3.125e-02,                                3.123983343026828e-02},
    {1.5625e-02,                               1.562372862047683e-02},
    {7.8125e-03,                               7.812341060101111e-03},
    {3.90625e-03,                              3.906230131966972e-03},
    {1.953125e-03,                             1.953122516478819e-03},
    {9.765625e-04,                             9.765621895593195e-04},
    {4.8828125e-04,                            4.882812111948983e-04},
    {2.44140625e-04,                           2.441406201493618e-04},
    {1.220703125e-04,                          1.220703118936702e-04},
    {6.103515625e-05,                          6.103515617420877e-05},
    {3.0517578125e-05,                         3.051757811552610e-05},
    {1.52587890625e-05,                        1.525878906131576e-05},
    {7.62939453125e-06,                        7.629394531101970e-06},
    {3.814697265625e-06,                       3.814697265606496e-06},
    {1.9073486328125e-06,                      1.907348632810187e-06},
    {9.5367431640625e-07,                      9.536743164059608e-07},
    {4.76837158203125e-07,                     4.768371582030888e-07},
    {2.384185791015625e-07,                    2.384185791015580e-07},
    {1.1920928955078125e-07,                   1.192092895507807e-07},
    {5.9604644775390625e-08,                   5.960464477539055e-08},
    {2.98023223876953125e-08,                  2.980232238769530e-08},
    {1.490116119384765625e-08,                 1.490116119384765e-08},
    {7.450580596923828125e-09,                 7.450580596923828e-09},
    {3.7252902984619140625e-09,                3.725290298461914e-09},
    {1.86264514923095703125e-09,               1.862645149230957e-09},
    {9.31322574615478515625e-10,               9.313225746154785e-10},
    {4.656612873077392578125e-10,              4.656612873077393e-10},
    {2.3283064365386962890625e-10,             2.328306436538696e-10},
    {1.16415321826934814453125e-10,            1.164153218269348e-10},
    {5.82076609134674072265625e-11,            5.820766091346741e-11},
    {2.910383045673370361328125e-11,           2.910383045673370e-11},
    {1.4551915228366851806640625e-11,          1.455191522836685e-11},
    {7.2759576141834259033203125e-12,          7.275957614183426e-12},
    {3.63797880709171295166015625e-12,         3.637978807091713e-12},
    {1.818989403545856475830078125e-12,        1.818989403545856e-12},
    {9.094947017729282379150390625e-13,        9.094947017729282e-13},
    {4.5474735088646411895751953125e-13,       4.547473508864641e-13},
    {2.27373675443232059478759765625e-13,      2.273736754432321e-13},
    {1.136868377216160297393798828125e-13,     1.136868377216160e-13},
    {5.684341886080801486968994140625e-14,     5.684341886080801e-14},
    {2.8421709430404007434844970703125e-14,    2.842170943040401e-14},
    {1.42108547152020037174224853515625e-14,   1.421085471520200e-14},
    {7.10542735760100185871124267578125e-15,   7.105427357601002e-15},
    {3.552713678800500929355621337890625e-15,  3.552713678800501e-15},
    {1.7763568394002504646778106689453125e-15, 1.776356839400250e-15},
    {8.8817841970012523233890533447265625e-16, 8.881784197001252e-16}
};

static void doMultiple(double* operandOne, int* powerOne,
                       double  operandTwo, int  powerTwo);
static void doAdd (double* operandOne, int* powerOne,
                   double  operandTwo, int  powerTwo);
static void doExponent(double* operandOne, int* powerOne,
                       double  operandTwo, int  powerTwo);
static void printResult(void);
static void formatResult(void);
static void oneOperand(void);

static void drawLines(void);
static void drawButtons(int group);

#ifndef _WIN32
double      strtod(const char *nptr, char **endptr);
#endif
long long atoll(const char *nptr);

/* -----------------------------------------------------------------------
Standard library function
----------------------------------------------------------------------- */
#ifndef _WIN32
double strtod(const char *nptr, char **endptr)
{
    double out;
    long mantissa;
    int length=0, end=0;
    mantissa=atoll(nptr);
    while(!end)
    {
        switch(*nptr)
        {
            case '\0':
              end=1;
              break;
            case ',':
            case '.':
            case '\'':
              end=1;
              /* fallthrough */
            default:
              nptr++;
        }
    }
    out=atoll(nptr);
    while( (*nptr == '0')||(*nptr == '1')||(*nptr == '2')||(*nptr == '3')||(*nptr == '4')||
        (*nptr == '5')||(*nptr == '6')||(*nptr == '7')||(*nptr == '8')||(*nptr == '9') )
    {
        nptr++;
        length++;
    }
    for(;length;length--)
        out /= 10;
    out += mantissa;
    if(endptr != NULL)
        *endptr=(char *) nptr;
    return out;
}
#endif

// WARNING Unsafe: Use strtoll instead
long long atoll(const char *nptr)
{
    long long result=0;
    char negative=0;
    while( (*nptr == ' ') || (*nptr == '\f') || (*nptr == '\n')||
      (*nptr == '\r') || (*nptr == '\t') || (*nptr == '\v') )
        nptr++;
    if(*nptr == '+')
        nptr++;
    if(*nptr == '-')
    {
        negative++;
        nptr++;
    }
    while (*nptr)
    {
        if( (*nptr < '0') || (*nptr > '9') )
            break;
        result *=10;
        result+= (*(nptr++) -'0');
    }
    if(negative)
        result = 0 - result;
    return result;
}

/* -----------------------------------------------------------------------
Handy functions
----------------------------------------------------------------------- */
static void cleartypingbuf(void)
{
    int k;
    for( k=1; k<=(DIGITLEN+1); k++)
        typingbuf[k] = 0;
    typingbuf[0] = ' ';
    typingbufPointer = typingbuf+1;
}
static void clearbuf(void)
{
    int k;
    for(k=0;k<18;k++)
        buf[k]=' ';
    buf[18] = 0;
}
static void clearResult(void)
{
    result = 0;
    power = 0;
    modifier = 0.1;
}

static void clearInput(void)
{
    calStatus = cal_normal;
    clearResult();
    cleartypingbuf();
    rb->lcd_clear_display();
    drawButtons(buttonGroup);
    drawLines();
}

static void clearOperand(void)
{
    operand = 0;
    operandPower = 0;
}

static void clearMemTemp(void)
{
    memTemp = 0;
    memTempPower = 0;
}

static void clearOper(void)
{
    oper = ' ';
    operInputted = false;
}

static void clearMem(void)
{
    clearInput();
    clearMemTemp();
    clearOperand();
    clearOper();
    btn = BUTTON_NONE;
}

static void switchOperands(void)
{
    double tempr = operand;
    int tempp = operandPower;
    operand = result;
    operandPower = power;
    result = tempr;
    power = tempp;
}

static void drawLines(void)
{
    int i;
    rb->lcd_hline(0, LCD_WIDTH, Y_1_POS-1);
    for (i = 0; i < 5 ; i++)
        rb->lcd_hline(0, LCD_WIDTH, Y_1_POS+i*REC_HEIGHT);
    for (i = 0; i < 4 ; i++)
        rb->lcd_vline(X_1_POS+i*REC_WIDTH, Y_1_POS, LCD_HEIGHT);
}

static void drawButtons(int group)
{
    int i, j, w, h;
    for (i = 0; i <= 4; i++){
        for (j = 0; j <= 4; j++){
            rb->lcd_getstringsize( buttonChar[group][i][j],&w,&h);
            if (i == btn_row && j == btn_col) /* selected item */
                rb->lcd_set_drawmode(DRMODE_SOLID);
            else
                rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
            rb->lcd_fillrect( X_0_POS + j*REC_WIDTH,
                              Y_1_POS + i*REC_HEIGHT,
                              REC_WIDTH, REC_HEIGHT+1);
            if (i == btn_row && j == btn_col) /* selected item */
                rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
            else
                rb->lcd_set_drawmode(DRMODE_SOLID);
            rb->lcd_putsxy( X_0_POS + j*REC_WIDTH + (REC_WIDTH - w)/2,
                            Y_1_POS + i*REC_HEIGHT + (REC_HEIGHT - h)/2 + 1,
                            buttonChar[group][i][j] );
        }
    }
    rb->lcd_set_drawmode(DRMODE_SOLID);
}

/* -----------------------------------------------------------------------
Initiate calculator
----------------------------------------------------------------------- */
static void cal_initial (void)
{
    int w,h;

    rb->lcd_getstringsize("2nd",&w,&h);
    if (w > REC_WIDTH || h > REC_HEIGHT)
        rb->lcd_setfont(FONT_SYSFIXED);

    rb->lcd_clear_display();

#ifdef CALCULATOR_OPERATORS
    /* basic operators are available through separate button */
    buttonGroup = sciButtons;
#else
    buttonGroup = basicButtons;
#endif

    /* initially, invert button "5" */
    btn_row = 2;
    btn_col = 1;
    prev_btn_row = btn_row;
    prev_btn_col = btn_col;
    drawButtons(buttonGroup);
    drawLines();
    rb->lcd_update();

    /* initial mem and output display*/
    clearMem();
    printResult();

    /* clear button queue */
    rb->button_clear_queue();
}

/* -----------------------------------------------------------------------
   mySqrt uses Heron's algorithm, which is the Newtone-Raphson algorhitm
   in it's private case for sqrt.
   Thanks BlueChip for his intro text and Dave Straayer for the actual name.
   ----------------------------------------------------------------------- */
static double mySqrt(double square)
{
    int k = 0;
    double temp = 0;
    double root= ABS(square+1)/2;

    while( ABS(root - temp) > MINIMUM ){
        temp = root;
        root = (square/temp + temp)/2;
        k++;
        if (k>10000) return 0;
    }

    return root;
}

/*Uses the sequence sum(x^k/k!) that tends to exp(x)*/
static double myExp (double x) {
    unsigned int k=0;
    double res=0, xPow=1,fact=1,toAdd;

    do {
        toAdd = xPow/fact;
        res += toAdd;
        xPow *= x; //xPow = x^k
        k++;
        fact*=k; //fact = k!
    } while (ABS(toAdd) > MINIMUM && xPow<1e302);
    return res;
}

/*myLn : uses the series ln⁡(a) = 2 * ∑(1/(2n+1) * ((a-1)/(a+1))^(2k+1) )*/
static double myLn (double a) {
    unsigned int k=1;
    double res=0,xPow,xSquare,fract=1,toAdd;

    xPow = (a-1)/(a+1);
    xSquare = xPow*xPow;

    do {
        toAdd = fract*xPow;
        res += toAdd;
        xPow *= xSquare; // ((a-1)/(a+1))^k
        k+=2;
        fract=1./k;
    } while (ABS(toAdd) > MINIMUM);
    return res * 2;
}


/* -----------------------------------------------------------------------
   transcendFunc uses CORDIC (COordinate Rotation DIgital Computer) method
   transcendFunc can do sin,cos,log,exp,asin,acos,atan
   input parameter is angle
----------------------------------------------------------------------- */
static void transcendFunc(char* func, double* tt, int* ttPower)
{
    double t = (*tt);
    int tPower = *ttPower;
    int sign = 1;
    int n = 50; /* n <=50, tables are all <= 50 */
    int j;
    double x,y,z,xt,yt,zt;

    if (tPower < -998) {
        calStatus = cal_normal;
        return;
    }
    if (tPower > 8) {
        calStatus = cal_error;
        return;
    }
    *ttPower = 0;
    calStatus = cal_normal;

    /* Powerscale */
    while (tPower > 0){
        t *= 10;
        tPower--;
    }
    while (tPower < 0) {
        t /= 10;
        tPower++;
    }

    /* Vectoring mode */
    if(func[0] == 'a' || func[0] == 'A') {
        if(func[1] == 's' || func[1] == 'S') { /* arcsin */
            /* arcsin input must be in [-1, 1] */
            if(t < -1.0 || t > 1.0) {
                calStatus = cal_error;
                return;
            }
            /* Avoid division by zero */
            if(t == 1.0) {
                *tt = 90.0;  /* arcsin(1) = 90° */
                return;
            }
            if(t == -1.0) {
                *tt = -90.0; /* arcsin(-1) = -90° */
                return;
            }
            
            /* Vectoring mode */
            /* Start with vector (sqrt(1-t^2), t) and find its angle */
            double magnitude = mySqrt(1.0 - t*t);
            x = magnitude;
            y = t;
            z = 0.0;
            
            /* Vectoring mode: drive y to 0 */
            for (j = 1; j < n + 2; j++) {
                if(y >= 0) {
                    /* Rotate clockwise (negative direction) */
                    xt = x + y * cordicTable[j-1][0];
                    yt = y - x * cordicTable[j-1][0];
                    zt = z - cordicTable[j-1][1];
                } else {
                    /* Rotate anticlockwise (positive direction) */
                    xt = x - y * cordicTable[j-1][0];
                    yt = y + x * cordicTable[j-1][0];
                    zt = z + cordicTable[j-1][1];
                }
                x = xt;
                y = yt;
                z = zt;
            }
            *tt = z * 180/M_PI * -1; /* Convert to degrees and invert sign */
            return;
        }
        else if(func[1] == 'c' || func[1] == 'C') { /* arccos */
            /* arccos input must be in [-1, 1] */
            if(t < -1.0 || t > 1.0) {
                calStatus = cal_error;
                return;
            }
            /* For arccos: use arcsin relationship: arccos(t) = π/2 - arcsin(t) */
            double arcsin_input = t;
            int arcsin_power = 0;
            
            /* Save current function context */
            char original_func[3];
            rb->strncpy(original_func, func, 3);
            
            transcendFunc("asin", &arcsin_input, &arcsin_power);
            
            if (calStatus == cal_error) {
                return;
            }
           
            /* arccos(t) = 90° - arcsin(t) */
            /* arcsin_input now contains arcsin(t) in degrees */
            double arccos_degrees = 90.0 - arcsin_input;
            *tt = arccos_degrees;
            return;
        }
        else if(func[1] == 't' || func[1] == 'T') { /* arctan */
            /* start with x=1, y=input, z=0 and drive y to 0 */
            x = 1.0;
            y = t;
            z = 0.0;
            
            /* Vectoring mode: drive y to 0 */
            for (j=1; j<n+2; j++){
                if(y < 0) {
                    /* Rotate anticlockwise */
                    xt = x - y*cordicTable[j-1][0];
                    yt = y + x*cordicTable[j-1][0];
                    zt = z + cordicTable[j-1][1];
                } else {
                    /* Rotate clockwise */
                    xt = x + y*cordicTable[j-1][0];
                    yt = y - x*cordicTable[j-1][0];
                    zt = z - cordicTable[j-1][1];
                }
                x = xt; y = yt; z = zt;
            }
            *tt = z * 180/M_PI * -1; /* Convert back to degrees and invert sign */
            return;
        }
    }

    if( func[0] =='s' || func[0] =='S'|| func[0] =='t' || func[0] =='T')
        sign = SIGN(t);
    else {
        /* if( func[0] =='c' || func[0] =='C') */
        sign = 1;
    }
    t = ABS(t);

    /* Jump to radians for rotation mode */
    t = t * M_PI / 180;

    while (tPower > 0){
        t *= 10;
        tPower--;
    }
    while (tPower < 0) {
        t /= 10;
        tPower++;
    }
    j = 0;
    while (t > j*M_TWOPI) {j++;}
    t -= (j-1)*M_TWOPI;
    if (M_PI_2 < t && t < 3*M_PI_2){
        t = M_PI - t;
        if (func[0] =='c' || func[0] =='C')
            sign = -1;
        else if (func[0] =='t' || func[0] =='T')
            t*=-1;
    }
    else if ( 3*M_PI_2 <= t && t <= M_TWOPI)
        t -= M_TWOPI;

    x = 0.60725293500888;  y = 0;  z = t;
    for (j=1;j<n+2;j++){
        xt = x - SIGN(z) * y*cordicTable[j-1][0];
        yt = y + SIGN(z) * x*cordicTable[j-1][0];
        zt = z - SIGN(z) * cordicTable[j-1][1];
        x = xt;
        y=yt;
        z=zt;
    }
    if( func[0] =='s' || func[0] =='S') {
        *tt = sign*y;
        return;
    }
    else if( func[0] =='c' || func[0] =='C') {
        *tt = sign*x;
        return;
    }
    else /*if( func[0] =='t' || func[0] =='T')*/ {
        if(t==M_PI_2||t==-M_PI_2){
            calStatus = cal_error;
            return;
        }
        else{
            *tt = sign*(y/x);
            return;
        }
    }

}
/* -----------------------------------------------------------------------
   add in scientific number format
----------------------------------------------------------------------- */
static void doAdd (double* operandOne, int* powerOne,
                   double  operandTwo, int  powerTwo)
{
    if ( *powerOne >= powerTwo ){
        if (*powerOne - powerTwo <= DIGITLEN+1){
            while (powerTwo < *powerOne){
                operandTwo /=10;
                powerTwo++;
            }
            *operandOne += operandTwo;
        }
        /*do nothing if operandTwo is too small*/
    }
    else{
        if (powerTwo - *powerOne <= DIGITLEN+1){
            while(powerTwo > *powerOne){
                *operandOne /=10;
                (*powerOne)++;
            }
            (*operandOne) += operandTwo;
        }
        else{/* simply copy operandTwo if operandOne is too small */
            *operandOne = operandTwo;
            *powerOne = powerTwo;
        }
    }
}
/* -----------------------------------------------------------------------
multiple in scientific number format
----------------------------------------------------------------------- */
static void doMultiple(double* operandOne, int* powerOne,
                       double  operandTwo, int  powerTwo)
{
    (*operandOne) *= operandTwo;
    (*powerOne) += powerTwo;
}

/* -----------------------------------------------------------------------
exponentiate in scientific number format
----------------------------------------------------------------------- */
static void doExponent(double* operandOne, int* powerOne,
                       double  operandTwo, int  powerTwo)
{
    char negative=0;
    char *lastDigit;
    char negativeBuffer[25];
    if (*operandOne == 0)
    {
        if (operandTwo == 0)
        {
            calStatus=cal_error; // result is undefined
        }
        else{
            *powerOne = 0;
            *operandOne = 0;
        }
        return;
    }
    if (operandTwo == 0)
    {
        *powerOne = 1;
        *operandOne = 0.1;
        return;
    }
    if (operandTwo < 0)
    {
        negative+=2;
        operandTwo= ABS(operandTwo);
    }
    if (*operandOne < 0)
    {
#if MEMORYSIZE < 8
        (void)negativeBuffer;
        (void)lastDigit;
        calStatus=cal_error;
        return;
#else
        if(powerTwo < 0)
        {
            calStatus=cal_error; // result is imaginary
            return;
        }

        /*Truncate operandTwo to three places past the radix
        in order to eliminate floating point artifacts
        (function should set error if truncating a non-integer) */
        rb->snprintf(negativeBuffer, 25, "%.*f", powerTwo+3, operandTwo);
        operandTwo = strtod(negativeBuffer, NULL);

        /*Truncate operandTwo to powerTwo digits by way of string
        in order to confirm operandTwo *10^powerTwo is an integer*/
        rb->snprintf(negativeBuffer, 25, "%.*f", powerTwo, operandTwo);

        if(strtod(negativeBuffer, &lastDigit) != operandTwo)
        {
            calStatus=cal_error; // result is imaginary
            return;
        }
        if(rb->atoi(lastDigit-1) % 2)
            negative++;
#endif
    }
    (*operandOne) = myLn(ABS(*operandOne)) + (double) (*powerOne) * 2.302585092994046;
    (*powerOne) = 0;
    doMultiple(operandOne, powerOne, ABS(operandTwo), powerTwo);
   while(*powerOne)
    {
        if(*powerOne > 0)
        {
            (*operandOne) *= 10;
            (*powerOne) --;
        }
        else{
            (*operandOne) /= 10;
            (*powerOne) ++;
        }
    }
    (*operandOne) = myExp(*operandOne);
    if(negative & 2)
        (*operandOne) = 1/(*operandOne);
    if(negative & 1)
        *operandOne = -(*operandOne);
}

/* -----------------------------------------------------------------------
Handles all one operand calculations
----------------------------------------------------------------------- */
static void oneOperand(void)
{
    int k = 0;

    if (buttonGroup == basicButtons){
        switch(CAL_BUTTON){
            case btn_sqr:
                if (result<0)
                    calStatus = cal_error;
                else{
                    if (power%2 == 1){
                        result = (mySqrt(result*10))/10;
                        power = (power+1) / 2;
                    }
                    else{
                        result = mySqrt(result);
                        power = power / 2;
                    }
                    calStatus = cal_normal;
                }
                break;
            case btn_square:
                power *= 2;
                result *= result;
                calStatus = cal_normal;
                break;

            case btn_rec:
                if (result==0)
                    calStatus = cal_error;
                else{
                    power = -power;
                    result = 1/result;
                    calStatus = cal_normal;
                }
                break;
            default:
                calStatus = cal_toDo;
                break; /* just for the safety */
        }
    }
    else{ /* sciButtons */
        switch(CAL_BUTTON){
            case sci_sin:
                transcendFunc("sin", &result, &power);
                break;
            case sci_cos:
                transcendFunc("cos", &result, &power);
                break;
            case sci_tan:
                transcendFunc("tan", &result, &power);
                break;
            case sci_asin:
                transcendFunc("asin", &result, &power);
                break;
            case sci_acos:
                transcendFunc("acos", &result, &power);
                break;
            case sci_atan:
                transcendFunc("atan", &result, &power);
                break;
            case sci_fac:
                if (power<0 || power>8 || result<0 )
                    calStatus = cal_error;
                else if(result == 0) {
                    result = 1;
                    power = 0;
                }
                else{
                    while(power > 0) {
                        result *= 10;
                        power--;
                    }
                    if ( ( result - (int)result) > MINIMUM )
                        calStatus = cal_error;
                    else {
                        k = result; result = 1;
                        while (k > 1){
                            doMultiple(&result, &power, k, 0);
                            formatResult();
                            k--;
                        }
                        calStatus = cal_normal;
                    }
                }
                break;
            case sci_exp:
                /*Uses the sequence (1+a/n)^n -> exp(a) */
                if (power>3 || result > 1e3) calStatus = cal_error;
                else {
                    while(power < 0) {
                            result /= 10;
                            power++;
                    }
                    while (power > 0){
                        power--;
                        result*=10;
                    }
                    result = myExp(result);
                    calStatus = cal_normal;
                }
                break;
            case sci_ln:
                if (result<=0) calStatus = cal_error;
                else {
               //ln(a*10^n) = ln(a) + n*ln(10), with ln(10) ≈  2.30
                    result = myLn(result) + power * 2.302585092994046;
                    power=0;
                    calStatus = cal_normal;
                }
                break;
            case sci_log:
                if (result<=0) calStatus = cal_error;
                else {
               //log10(a+10^n) = ln(a)/ln(10) + n, with ln(10) ≈  2.30
                    result = myLn(result)/2.302585092994046 + power;
                    power=0;
                    calStatus = cal_normal;
                }
                break;
            default:
                calStatus = cal_toDo;
                break; /* just for the safety */
        }
    }
}


/* -----------------------------------------------------------------------
Handles all two operands calculations
----------------------------------------------------------------------- */
static void twoOperands(void)
{
    switch(oper){
        case '-':
            doAdd(&operand, &operandPower, -result, power);
            break;
        case '+':
            doAdd(&operand, &operandPower, result, power);
            break;
        case '*':
            doMultiple(&operand, &operandPower, result, power);
            break;
        case '/':
            if ( ABS(result) > MINIMUM ){
                doMultiple(&operand, &operandPower, 1/result, -power);
            }
            else
                calStatus = cal_error;
            break;
        case '^':
            doExponent(&operand, &operandPower, result, power);
            break;
        default: /* ' ' */
            switchOperands(); /* counter switchOperands() below */
            break;
    } /* switch(oper) */
    switchOperands();
    clearOper();
}

/* First, increases *dimen1 by dimen1_delta modulo dimen1_modulo.
   If dimen1 wraps, increases *dimen2 by dimen2_delta modulo dimen2_modulo.
*/
static void move_with_wrap_and_shift(
    int *dimen1, int dimen1_delta, int dimen1_modulo,
    int *dimen2, int dimen2_delta, int dimen2_modulo)
{
    bool wrapped = false;

    *dimen1 += dimen1_delta;
    if (*dimen1 < 0)
    {
        *dimen1 = dimen1_modulo - 1;
        wrapped = true;
    }
    else if (*dimen1 >= dimen1_modulo)
    {
        *dimen1 = 0;
        wrapped = true;
    }

    if (wrapped)
    {
        /* Make the dividend always positive to be sure about the result.
           Adding dimen2_modulo does not change it since we do it modulo. */
        *dimen2 = (*dimen2 + dimen2_modulo + dimen2_delta) % dimen2_modulo;
    }
}

/* -----------------------------------------------------------------------
Print buttons when switching 1st and 2nd
int group = {basicButtons, sciButtons}
----------------------------------------------------------------------- */
static void printButtonGroups(int group)
{
    drawButtons(group);
    drawLines();
    rb->lcd_update();
}
/* -----------------------------------------------------------------------
flash the currently marked button
----------------------------------------------------------------------- */
static void flashButton(void)
{
    int k, w, h;
    for (k=2;k>0;k--)
    {
        rb->lcd_getstringsize( buttonChar[buttonGroup][btn_row][btn_col],&w,&h);
        rb->lcd_set_drawmode(DRMODE_SOLID|(k==1) ? 0 : DRMODE_INVERSEVID);
        rb->lcd_fillrect( X_0_POS + btn_col*REC_WIDTH + 1,
                          Y_1_POS + btn_row*REC_HEIGHT + 1,
                          REC_WIDTH - 1, REC_HEIGHT - 1);
        rb->lcd_putsxy( X_0_POS + btn_col*REC_WIDTH + (REC_WIDTH - w)/2,
                        Y_1_POS + btn_row*REC_HEIGHT + (REC_HEIGHT - h)/2 +1,
                        buttonChar[buttonGroup][btn_row][btn_col] );
        rb->lcd_update_rect( X_0_POS + btn_col*REC_WIDTH + 1,
                            Y_1_POS + btn_row*REC_HEIGHT + 1,
                            REC_WIDTH - 1, REC_HEIGHT - 1);

        if (k!= 1)
            rb->sleep(HZ/22);

    }
}

/* -----------------------------------------------------------------------
pos is the position that needs animation. pos = [1~18]
----------------------------------------------------------------------- */
#if defined(CALCULATOR_CLEAR) || defined(CALCULATOR_OPERATORS)
static void deleteAnimation(int pos)
{
    int k, w, h, x;
    if (pos<1 || pos >18)
        return;

    rb->lcd_getstringsize("0", &w, &h);
    x = (pos==1? 4: LCD_WIDTH - 4 - w);

    for (k=0;k<4;k++){
        rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
        rb->lcd_fillrect(x, Y_1_POS - h -1, w, h);
        rb->lcd_set_drawmode(DRMODE_SOLID);
        rb->lcd_fillrect(x + (w*k)/8, Y_1_POS - h -1 + (h*k)/8,
                         (w*(4-k))/4, (h*(4-k))/4);
        rb->lcd_update_rect(x, Y_1_POS - h -1, w, h);
        rb->sleep(HZ/32);
    }
}
#endif

/* -----------------------------------------------------------------------
result may be one of these formats:
0
xxxx.xxxx
0.xxxx
0.0000xxxx

formatResult() change result to standard format: 0.xxxx
if result is close to 0, let it be 0;
if result is close to 1, let it be 0.1 and power++;
----------------------------------------------------------------------- */
static void formatResult(void)
{
    int resultsign = SIGN(result);
    result = ABS(result);
    if(result > MINIMUM ){ /* doesn't check power, might have problem
                              input wouldn't,
                              + - * / of two formatted number wouldn't.
                              only a calculation that makes a formatted
                              number (0.xxxx) less than MINIMUM in only
                              one operation  */

        if (result<1){
            while( (int)(result*10) == 0 ){
                result *= 10;
                power--;
                modifier *= 10;
            }
        }
        else{ /* result >= 1 */
            while( (int)result != 0 ){
                result /= 10;
                power++;
                modifier /= 10;
            }
        } /* if result<1 */

        if (result > (1-MINIMUM)){
            result = 0.1;
            power++;
            modifier /= 10;
        }
        result *= resultsign;
    }
    else {
        result = 0;
        power = 0;
        modifier = 0.1;
    }
}

/* -----------------------------------------------------------------------
result2typingbuf() outputs standard format result to typingbuf.
case SCIENTIFIC_FORMAT, let temppower = 1;
case temppower >  0:  print '.' in the middle
case temppower <= 0:  print '.' in the begining
----------------------------------------------------------------------- */
static void result2typingbuf(void)
{
    bool haveDot = false;
    char tempchar = 0;
    int k;
    double tempresult = ABS(result); /* positive num makes things simple */

    int temppower;
    double tempmodifier = 1;
    int count;

    if(SCIENTIFIC_FORMAT)
        temppower = 1; /* output x.xxxx format */
    else
        temppower = power;

    cleartypingbuf();

    if(tempresult < MINIMUM){ /* if 0,faster display and avoid complication*/
        typingbuf[0] = ' ';
        typingbuf[1] = '0';
    }
    else{ /* tempresult > 0 */
        typingbuf[0] = (SIGN(result)<0)?'-':' ';

        typingbufPointer = typingbuf;
        if(temppower > 0){
            for (k = 0; k<DIGITLEN+1 ; k++){
                typingbufPointer++;
                if(temppower || *(typingbufPointer-1) == '.'){
                    count = 0;
                    tempmodifier = tempmodifier/10;
                    while( (tempresult-tempmodifier*count) >
                           (tempmodifier-MINIMUM)){
                        count++;
                    }
                    tempresult -= tempmodifier*count;
                    tempresult = ABS(tempresult);
                    temppower-- ;
                    *typingbufPointer = count + '0';
                }
                else{ /* temppower == 0 */
                    *typingbufPointer = '.';
                    haveDot = true;
                }
            } /* for */
        }
        else{
            haveDot = true;
            typingbufPointer++;  *typingbufPointer = '0';
            typingbufPointer++;  *typingbufPointer = '.';
            for (k = 2; k<DIGITLEN+1 ; k++){
                typingbufPointer++;
                count = 0;
                if ( (-temppower) < (k-1)){
                    tempmodifier = tempmodifier/10;
                    while((tempresult-tempmodifier*count)>(tempmodifier-MINIMUM)){
                        count++;

                    }
                    tempresult -= tempmodifier*count;
                    tempresult = ABS(tempresult);
                    temppower-- ;
                }
                *typingbufPointer = count + '0';
            }
        }
        /* now, typingbufPointer = typingbuf + 16 */
        /* backward strip off 0 and '.' */
        if (haveDot){
            while( (*typingbufPointer == '0') || (*typingbufPointer == '.')){
                tempchar = *typingbufPointer;
                *typingbufPointer = 0;
                typingbufPointer--;
                if (tempchar == '.') break;
            }
        }
        typingbuf[DIGITLEN+1] = 0;
    } /* else tempresult > 0 */
}

/* -----------------------------------------------------------------------
printResult() generates LCD display.
----------------------------------------------------------------------- */
static void printResult(void)
{
    int k, w, h;

    char operbuf[3] = {0, 0, 0};

    switch_Status:
    switch(calStatus){
        case cal_exit:
            return;
        case cal_error:
            clearbuf();
            rb->snprintf(buf, 19, "%18s","Error");
            break;
        case cal_toDo:
            clearbuf();
            rb->snprintf(buf, 19, "%18s","Coming soon ^_* ");
            break;

        case cal_normal:
            formatResult();

            if( power > 1000 ){  /* power -1 > 999  */
                calStatus = cal_error;
                goto switch_Status;
            }
            if (power < -998 )   /* power -1 < -999 */
                clearResult();   /* too small, let it be 0 */

            result2typingbuf();
            clearbuf();

            operbuf[0] = oper;
            operbuf[1] = ( ABS(memTemp) > MINIMUM )?'M':' ';
            operbuf[2] = '\0';

            if(SCIENTIFIC_FORMAT){
                /* output format: X.XXXX eXXX */
                if(power > -98){ /* power-1 >= -99, eXXX or e-XX */
                    rb->snprintf(buf, 12, "%11s",typingbuf);
                    for(k=11;k<=14;k++) buf[k] = ' ';
                    cleartypingbuf();
                    rb->snprintf(typingbuf, 5, "e%d",power-1);
                    rb->snprintf(buf+11, 5, "%4s",typingbuf);
                }
                else{  /* power-1 <= -100, e-XXX */
                    rb->snprintf(buf, 12, "%11s",typingbuf);
                    rb->snprintf(buf+11, 6, "e%d",power-1);
                }
            }
            else{
                rb->snprintf(buf, 12, "%11s",typingbuf);
            } /* if SCIENTIFIC_FORMAT */
            break;
        case cal_typing:
        case cal_dotted:
            clearbuf();
            operbuf[0] = oper;
            operbuf[1] = ( ABS(memTemp) > MINIMUM )?'M':' ';
            rb->snprintf(buf, 12, "%11s",typingbuf);
            break;

    }

    rb->lcd_getstringsize(buf, &w, &h);
    rb->screen_clear_area(rb->screens[0], 0, 0, LCD_WIDTH, Y_1_POS - 1);
    rb->lcd_putsxy(4, Y_1_POS - h -1, operbuf);
    rb->lcd_putsxy(LCD_WIDTH - w - 4, Y_1_POS - h -1, buf);
    rb->lcd_update_rect(0, 1, LCD_WIDTH, Y_1_POS);
}

/* -----------------------------------------------------------------------
Process typing buttons: 1-9, '.', sign
main operand "result" and typingbuf are processed seperately here.
----------------------------------------------------------------------- */
static void typingProcess(void){
    switch( CAL_BUTTON ){
        case btn_sign:
            if (calStatus == cal_typing ||
                calStatus == cal_dotted)
                typingbuf[0] = (typingbuf[0]=='-')?' ':'-';
            result = -result;
            break;
        case btn_dot:
            operInputted = false;
            switch(calStatus){
                case cal_normal:
                    clearInput();
                    *typingbufPointer = '0';
                    typingbufPointer++;
                    /* Fallthrough */
                case cal_typing:
                    calStatus = cal_dotted;
                    *typingbufPointer = '.';
                    if (typingbufPointer != typingbuf+DIGITLEN+1)
                        typingbufPointer++;
                    break;
                default:  /* cal_dotted */
                    break;
            }
            break;
        default:  /* 0-9 */
            operInputted = false;
            /* normal,0; normal,1-9; typing,0; typing,1-9 */
            switch(calStatus){
                case cal_normal:
                    if(CAL_BUTTON == btn_0 )
                        break;   /* first input is 0, ignore */
                    clearInput();
                    /*no operator means start a new calculation*/
                    if (oper ==' ')
                        clearOperand();
                    calStatus = cal_typing;
                    /* go on typing, no break */
                    /* Intentional fallthrough */
                case cal_typing:
                case cal_dotted:
                    switch(CAL_BUTTON){
                        case btn_0:
                            *typingbufPointer = '0';
                            break;
                        default:
                            *typingbufPointer=(7+btn_col-3*(btn_row-1))+ '0';
                            break;
                    }
                    if (typingbufPointer!=typingbuf+DIGITLEN+1){
                        typingbufPointer++;

                        {/* result processing */
                         if (calStatus == cal_typing) power++;
                         if (CAL_BUTTON != btn_0)
                             result= result +
                                     SIGN(result)*
                                     (7+btn_col-3*(btn_row-1))*modifier;
                         modifier /= 10;
                        }
                    }
                    else /* last byte always '\0' */
                        *typingbufPointer = 0;
                    break;
                default: /* cal_error, cal_exit */
                    break;
            }
            break; /* default, 0-9 */
    } /* switch( CAL_BUTTON ) */
}

/* -----------------------------------------------------------------------
Handle delete operation
main operand "result" and typingbuf are processed seperately here.
----------------------------------------------------------------------- */
#ifdef CALCULATOR_CLEAR
static void doDelete(void){
    deleteAnimation(18);
    switch(calStatus){
        case cal_dotted:
            if (*(typingbufPointer-1) == '.'){
                /* if dotted and deleting '.',
                   change status and delete '.' below */
                calStatus = cal_typing;
            }
            else{ /* if dotted and not deleting '.',
                     power stays */
                power++; /* counter "power--;" below */
            }
        case cal_typing:
            typingbufPointer--;

            {/* result processing */   /* 0-9, '.' */
             /* if deleting '.', do nothing */
             if ( *typingbufPointer != '.'){
                power--;
                modifier *= 10;
                result = result - SIGN(result)*
                    ((*typingbufPointer)- '0')*modifier;
             }
            }

            *typingbufPointer = 0;

            /* if (only one digit left and it's 0)
               or  no digit left, change status*/
            if ( typingbufPointer == typingbuf+1 ||
                 ( typingbufPointer == typingbuf+2 &&
                   *(typingbufPointer-1) == '0' ))
                calStatus = cal_normal;
            break;
        default: /* normal, error, exit */
            break;
    }
}
#endif
/* -----------------------------------------------------------------------
Handle buttons on basic screen
----------------------------------------------------------------------- */
static void basicButtonsProcess(void){
    switch (btn) {
#ifdef CALCULATOR_INPUT2
        case CALCULATOR_INPUT2: /*fallthrough*/
#endif
        case CALCULATOR_INPUT:
            if (calStatus == cal_error && (CAL_BUTTON != btn_C) ) break;
            flashButton();
            switch( CAL_BUTTON ){
                case btn_MR:
                    operInputted = false;
                    result = memTemp; power = memTempPower;
                    calStatus = cal_normal;
                    break;
                case btn_M:
                    formatResult();
                    if (memTemp > MINIMUM)
                        doAdd(&memTemp, &memTempPower, result, power);
                    else {
                        /* if result is too small and memTemp = 0,
                           doAdd will not add */
                        memTemp = result;
                        memTempPower = power;
                    }
                    calStatus = cal_normal;
                    break;

                case btn_C:    clearMem();        break;
                case btn_CE:   clearInput();      break;

                case btn_bas:
                    buttonGroup = sciButtons;
                    printButtonGroups(buttonGroup);
                    break;

                /* one operand calculation, may be changed to
                   like sin, cos, log, etc */
                case btn_sqr:
                case btn_square:
                case btn_rec:
                    formatResult(); /* not necessary, just for safty */
                    oneOperand();
                    break;

                case_btn_equal:  /* F3 shortkey entrance */
                case btn_equal:
                    formatResult();
                    calStatus = cal_normal;
                    operInputted = false;
                    if (oper != ' ') twoOperands();
                    break;

                case btn_div:
                case btn_time:
                case btn_minus:
                case btn_add:
                    if(!operInputted) {twoOperands(); operInputted = true;}
                    oper = buttonChar[basicButtons][btn_row][btn_col][0];
#ifdef CALCULATOR_OPERATORS
                    case_cycle_operators:  /* F2 shortkey entrance */
#endif
                    if (calStatus == cal_typing ||
                        calStatus == cal_dotted)
                            calStatus = cal_normal;
                    formatResult();
                    operand = result;
                    operandPower = power;

                    break;

                case btn_sign:
                case btn_dot:
                default:  /* 0-9 */
                    typingProcess();
                    break;
            } /* switch (CAL_BUTTON) */
            break;

#ifdef CALCULATOR_OPERATORS
        case CALCULATOR_OPERATORS:
            if (calStatus == cal_error) break;
            if (!operInputted) {twoOperands(); operInputted = true;}
            switch (oper){
                case ' ':
                case '/':  oper = '+';  flashButton();    break;
                case '+':  oper = '-';  flashButton();  break;
                case '-':  oper = '*';  flashButton();   break;
                case '*':  oper = '/';  flashButton();    break;
            }
            goto case_cycle_operators;
            break;
#endif

        case CALCULATOR_CALC:
            if (calStatus == cal_error) break;
            flashButton();
            goto case_btn_equal;
            break;
        default: break;
    }
    printResult();
}

/* -----------------------------------------------------------------------
Handle buttons on scientific screen
----------------------------------------------------------------------- */
static void sciButtonsProcess(void){
    switch (btn) {
#ifdef CALCULATOR_INPUT2
        case CALCULATOR_INPUT2: /*fallthrough*/
#endif
        case CALCULATOR_INPUT:
            if (calStatus == cal_error && (CAL_BUTTON != sci_sci) ) break;
            flashButton();
            switch( CAL_BUTTON ){

                case sci_pi:
                    result = M_PI;  power = 0;
                    calStatus = cal_normal;
                    break;

                case sci_xy:
                    if(!operInputted) {twoOperands(); operInputted = true;}
                    oper = '^';
                    if (calStatus == cal_typing ||
                        calStatus == cal_dotted)
                            calStatus = cal_normal;
                    formatResult();
                    operand = result;
                    operandPower = power;
                    break;

                case sci_sci:
                    buttonGroup = basicButtons;
                    printButtonGroups(basicButtons);
                    break;

                case sci_fac:
                case sci_sin:
                case sci_asin:
                case sci_cos:
                case sci_acos:
                case sci_tan:
                case sci_atan:
                case sci_ln:
                case sci_exp:
                case sci_log:
                    formatResult(); /* not necessary, just for safty */
                    oneOperand();
                    break;

                case btn_sign:
                case btn_dot:
                default:  /* 0-9 */
                    typingProcess();
                    break;
            } /* switch (CAL_BUTTON) */
            break;

#ifdef CALCULATOR_OPERATORS
        case CALCULATOR_OPERATORS:
            if (calStatus == cal_error) break;
            if (!operInputted) {twoOperands(); operInputted = true;}
            switch (oper){
                case ' ':  oper = '+'; break;
                case '/':  oper = '+'; deleteAnimation(1);  break;
                case '+':  oper = '-'; deleteAnimation(1);  break;
                case '-':  oper = '*'; deleteAnimation(1);  break;
                case '*':  oper = '/'; deleteAnimation(1);  break;
            }
            calStatus = cal_normal;
            formatResult();
            operand = result;
            operandPower = power;
            break;
#endif

        case CALCULATOR_CALC:
            if (calStatus == cal_error) break;
            formatResult();
            calStatus = cal_normal;
            operInputted = false;
            if (oper != ' ') twoOperands();
            break;
        default: break;
    }
    printResult();
}

/* -----------------------------------------------------------------------
move button index
Invert display new button, invert back previous button
----------------------------------------------------------------------- */
static int handleButton(int button){
    switch(button)
    {
        case CALCULATOR_INPUT:
        case CALCULATOR_CALC:
#ifdef CALCULATOR_INPUT_CALC_PRE
            if (lastbtn != CALCULATOR_INPUT_CALC_PRE)
                break;
            /* no unconditional break; here! */
#endif
#ifdef CALCULATOR_INPUT2 /* bypass pre button */
        case CALCULATOR_INPUT2: /*fallthrough*/
#endif
#ifdef CALCULATOR_OPERATORS
        case CALCULATOR_OPERATORS:
#endif
            switch(buttonGroup){
                case basicButtons:
                    basicButtonsProcess();
                    break;
                case sciButtons:
                    sciButtonsProcess();
                    break;
            }
            break;

#ifdef CALCULATOR_CLEAR
        case CALCULATOR_CLEAR:
            switch(calStatus){
                case cal_typing:
                case cal_dotted:
                    doDelete();
                    break;
                default: /* cal_normal, cal_error, cal_exit */
                    clearMem();
                    break;
            }
            printResult();
            break;
#endif
        case CALCULATOR_LEFT:
        case CALCULATOR_LEFT | BUTTON_REPEAT:
            move_with_wrap_and_shift(
                &btn_col, -1, BUTTON_COLS,
                &btn_row,  0, BUTTON_ROWS);
            break;

        case CALCULATOR_RIGHT:
        case CALCULATOR_RIGHT | BUTTON_REPEAT:
            move_with_wrap_and_shift(
                &btn_col,  1, BUTTON_COLS,
                &btn_row,  0, BUTTON_ROWS);
            break;

#ifdef CALCULATOR_UP
        case CALCULATOR_UP:
        case CALCULATOR_UP | BUTTON_REPEAT:
            move_with_wrap_and_shift(
                &btn_row, -1, BUTTON_ROWS,
                &btn_col,  0, BUTTON_COLS);
            break;
#endif
#ifdef CALCULATOR_DOWN
        case CALCULATOR_DOWN:
        case CALCULATOR_DOWN | BUTTON_REPEAT:
            move_with_wrap_and_shift(
                &btn_row,  1, BUTTON_ROWS,
                &btn_col,  0, BUTTON_COLS);
            break;
#endif

#ifdef CALCULATOR_UP_W_SHIFT
        case CALCULATOR_UP_W_SHIFT:
        case CALCULATOR_UP_W_SHIFT | BUTTON_REPEAT:
            move_with_wrap_and_shift(
                &btn_row, -1, BUTTON_ROWS,
                &btn_col, -1, BUTTON_COLS);
            break;
#endif
#ifdef CALCULATOR_DOWN_W_SHIFT
        case CALCULATOR_DOWN_W_SHIFT:
        case CALCULATOR_DOWN_W_SHIFT | BUTTON_REPEAT:
            move_with_wrap_and_shift(
                &btn_row,  1, BUTTON_ROWS,
                &btn_col,  1, BUTTON_COLS);
            break;
#endif
#ifdef CALCULATOR_LEFT_W_SHIFT
        case CALCULATOR_LEFT_W_SHIFT:
        case CALCULATOR_LEFT_W_SHIFT | BUTTON_REPEAT:
            move_with_wrap_and_shift(
                &btn_col, -1, BUTTON_COLS,
                &btn_row, -1, BUTTON_ROWS);
            break;
#endif
#ifdef CALCULATOR_RIGHT_W_SHIFT
        case CALCULATOR_RIGHT_W_SHIFT:
        case CALCULATOR_RIGHT_W_SHIFT | BUTTON_REPEAT:
            move_with_wrap_and_shift(
                &btn_col,  1, BUTTON_COLS,
                &btn_row,  1, BUTTON_ROWS);
            break;
#endif
#ifdef CALCULATOR_RC_QUIT
        case CALCULATOR_RC_QUIT:
#endif
        case CALCULATOR_QUIT:
            return -1;
    }

    return 0;
}

/* -----------------------------------------------------------------------
Main();
----------------------------------------------------------------------- */
enum plugin_status plugin_start(const void* parameter)
{
    (void)parameter;

    /* now go ahead and have fun! */

#ifdef HAVE_TOUCHSCREEN
    rb->touchscreen_set_mode(TOUCHSCREEN_POINT);
#endif

    cal_initial();

    while (calStatus != cal_exit ) {
        btn = rb->button_get_w_tmo(HZ/2);
#ifdef HAVE_TOUCHSCREEN
        if(btn & BUTTON_TOUCHSCREEN)
        {
            struct ts_raster_result res;
            if(touchscreen_map_raster(&calc_raster, rb->button_get_data() >> 16,
                                      rb->button_get_data() & 0xffff, &res) == 1)
            {
                btn_row = res.y;
                btn_col = res.x;
                drawButtons(buttonGroup);
                drawLines();

                rb->lcd_update();

                prev_btn_row = btn_row;
                prev_btn_col = btn_col;
                if(btn & BUTTON_REL)
                {
                    btn = CALCULATOR_INPUT;
                    switch(buttonGroup){
                        case basicButtons:
                            basicButtonsProcess();
                            break;
                        case sciButtons:
                            sciButtonsProcess();
                            break;
                    }
                    btn = BUTTON_TOUCHSCREEN;
                }
            }
        }
#endif
        if (handleButton(btn) == -1)
        {
            calStatus = cal_exit;
            printResult();
        }
        else
        {
            drawButtons(buttonGroup);
            drawLines();
        }

        rb->lcd_update();

        if(rb->default_event_handler(btn) == SYS_USB_CONNECTED)
            return PLUGIN_USB_CONNECTED;

        if (btn != BUTTON_NONE)
            lastbtn = btn;
    } /* while (calStatus != cal_exit ) */

    rb->button_clear_queue();
    return PLUGIN_OK;
}
