Source

rk48 / rk48 / calculator.py

Full commit
from enthought.traits.api import Bool, Enum, HasTraits, Instance, Property, Str

from rk48.keys import hp48keys, code_to_hp48key, main_to_hp48key
from rk48.rpn_stack import RPNStack
from rk48.math_funcs import calc_funcs


add_to_command_keys = set('1234567890., ')
start_command_keys = add_to_command_keys | set(['EEX'])

class Calculator(HasTraits):
    """ Emulate a calculator.
    """

    # The RPN stack.
    stack = Instance(RPNStack, args=())

    # The input mode.
    input_mode = Enum('main', 'command')

    # The shift mode.
    shift_mode = Enum('none', 'leftshift', 'rightshift')
    shift_on = Property(Bool)

    # The alpha status.
    alpha_mode = Enum('none', 'alpha_once', 'alpha_lock')
    alpha_on = Property(Bool)

    # The current input.
    input = Str()


    def process_key(self, key):
        """ Process a single keystroke.
        """
        print 'process_key(%r)' % (key,)
        if key.main in ('leftshift', 'rightshift'):
            self.process_shift(key)
        elif key.main == 'alpha':
            if self.shift_on:
                name = self.get_shifted(key)
                self.shifted_command(name)
                self.shift_mode = 'none'
            else:
                self.process_alpha(key)
        else:
            name = '%s_key' % self.input_mode
            meth = getattr(self, name)
            meth(key)
            if self.shift_on:
                self.shift_mode = 'none'

    def main_key(self, key):
        if key.main == 'bkspc':
            self.stack.parse_input('DROP')
        elif key.main in start_command_keys:
            self.input_mode = 'command'
            self.process_key(key)
        else:
            name = self.get_shifted(key)
            self.shifted_command(name)

    def command_key(self, key, no_alpha=False):
        if key.main == 'ENTER':
            self.push_current_input()
        elif self.alpha_on and not no_alpha:
            if key.alpha is not None:
                self.input += key.alpha
            else:
                self.command_key(key, no_alpha=True)
        else:
            name = self.get_shifted(key)
            self.shifted_command(name)

    def push_current_input(self):
        parsed = self.parse_input()
        self.input = ''
        for part in parsed:
            self.stack.parse_input(part)

    def shifted_command(self, name):
        if name in add_to_command_keys:
            self.input += name
        elif name == 'EEX':
            if self.input[-1:] in '0123456789.':
                self.input += 'E'
            else:
                self.input += '1E'
        else:
            self.push_current_input()
            self.stack.parse_input(name)

    def parse_input(self):
        """ Simplistic parsing of input.
        """
        return self.input.split()

    def process_alpha(self, key):
        if self.alpha_mode == 'none':
            self.alpha_mode = 'alpha_once'
        elif self.alpha_mode == 'alpha_once':
            self.alpha_mode = 'alpha_lock'
        else:
            self.alpha_mode = 'none'

    def process_shift(self, key):
        if key.main == self.shift_mode:
            self.shift_mode = 'none'
        else:
            self.shift_mode = key.main

    def get_shifted(self, key):
        """ Get the shifted version of the key.
        """
        if self.shift_mode == 'none':
            attr = 'main'
        else:
            attr = self.shift_mode
        return getattr(key, attr)

    def _get_shift_on(self):
        return self.shift_mode != 'none'

    def _get_alpha_on(self):
        return self.alpha_mode != 'none'