Onscreen QWERTY keypad for RA8857 based display. Uses the resistive touch panel.

Dependents:   RA8875_KeyPadDemo PUB_RA8875_Keypad IAC_Final_Monil_copy

Keypad.cpp

Committer:
WiredHome
Date:
2016-11-13
Revision:
6:4da6fa0fe51b
Parent:
5:7ccb8f7386fa

File content as of revision 6:4da6fa0fe51b:

#include "Keypad.h"

// byte pairs: size, symbol [,size, symbol [, size, symbol [...]]]
// size is a scale factor where 10 = "normal calculated size" based on the keyboard width and the # of keys, 5 is 1/2 width, etc.
// symbol is either the ASCII character to show, when leveraging the RA8875 internal fonts, or it is a special
//    character [normally non-printable] that is intercepted to perform an operation (e.g. <bs>, <shift>, etc.)
//    \x01: special no-key value, to leave whitespace before the next key.
const char kpd_shiftkeys[] = {
    5,'\x01', 8,'\x15',10,'~',10,'!',10,'@',10,'#',10,'$',10,'%',10,'^',10,'&',10,'*',10,'(',10,')',10,'_',   10,'+',10,'\x1B',0,0,
    5,'\x01',12,'\x1A',10,'Q',10,'W',10,'E',10,'R',10,'T',10,'Y',10,'U',10,'I',10,'O',10,'P',10,'{',   10,'}',10,'|',0,0,
    5,'\x01',15,' ',10,'A',10,'S',10,'D',10,'F',10,'G',10,'H',10,'J',10,'K',10,'L',10,':',10,'"',   17,'\x1C',0,0,
    5,'\x01',21,'\x18',10,'Z',10,'X',10,'C',10,'V',10,'B',10,'N',10,'M',10,'<',10,'>',10,'?',21,'\x18',0,0,
    5,'\x01',40,'\x01',55,' ',0,0,
    0,0
};
const char kpd_unshiftkeys[] = {
    5,'\x01', 8,'\x15',10,'`',10,'1',10,'2',10,'3',10,'4',10,'5',10,'6',10,'7',10,'8',10,'9',10,'0',10,'-',   10,'=',10,'\x1B',0,0,
    5,'\x01',12,'\x1A',10,'q',10,'w',10,'e',10,'r',10,'t',10,'y',10,'u',10,'i',10,'o',10,'p',10,'[',   10,']',10,'\\',0,0,
    5,'\x01',15,' ',10,'a',10,'s',10,'d',10,'f',10,'g',10,'h',10,'j',10,'k',10,'l',10,';',10,'\'',  17,'\x1C',0,0,
    5,'\x01',21,'\x18',10,'z',10,'x',10,'c',10,'v',10,'b',10,'n',10,'m',10,',',10,'.',10,'/',21,'\x18',0,0,
    5,'\x01',40,'\x01',55,' ',0,0,
    0,0
};

const Keypad::keyboard_t internalkbd = {
    0,-1,   // x,y: 0; start at left edge, -1; top is calculated from # rows
         //      -1 is size calculated
    0,      // wi,h: width is calculated
    0,      //      bottom of screen justified
    5,      // 5 rows
    15,     // columns in the <esc>`1234...-=<bs> row
    kpd_unshiftkeys,
    kpd_shiftkeys
};



Keypad::Keypad(RA8875 & _ra, color_t _fore, color_t _back) : ra(_ra), fore(_fore), back(_back) {
    shift = false;
    enter_key = KYBD_SYM_ENTER;
    esc_key   = KYBD_SYM_ESCAPE;
    user_font = NULL;
    user_font_scale = 0;
}

Keypad::~Keypad() {
}

bool Keypad::SetKeyboard(const keyboard_t * _kbd, char _enter_key, char _esc_key) {
    if (_kbd)
        kbd = _kbd;
    else
        kbd = &internalkbd;
    enter_key = _enter_key;
    esc_key   = _esc_key;
    return true;
}

bool Keypad::SetKeyboardFont(const uint8_t * _font, int _fontscale) {
    if (_font)
        user_font = _font;
    else
        user_font_scale = _fontscale;
    return true;
}

void Keypad::DrawKey(rect_t r, char c, bool invert) {
    ra.fillroundrect(r, 2, 2, invert ? fore : back);
    ra.roundrect(r, 2, 2, invert ? back : fore);
    ra.SetTextCursor(r.p1.x+(r.p2.x-r.p1.x)/2-ra.fontwidth()/2, r.p1.y+2);
    if (invert) {
        ra.foreground(back);
        ra.background(fore);
        ra.SetTextCursorControl(RA8875::NOCURSOR);
    }
    ra.putc(c);
    if (invert) {
        ra.foreground(fore);
        ra.background(back);
    }
}

void Keypad::Erase(color_t c) {
    dim_t kH = ra.fontheight() + 4;
    rect_t r = ComputeKeypadRect();
    
    ra.fillrect(r, c);
    if (user_font)
        ra.SelectUserFont(restore_font);                   // restore
    else if (restore_hScale | restore_vScale)
        ra.SetTextFontSize(restore_hScale, restore_vScale);
    //printf("Restore: font: %p, scale: %d,%d\r\n", user_font, restore_hScale, restore_vScale);    
}

void Keypad::DrawInputPanel(const char * prompt) {
    rect_t r;
    
    if (user_font || user_font_scale) {
        restore_font = ra.GetUserFont();   // save to later restore
        ra.GetTextFontSize(&restore_hScale, &restore_vScale);
        //printf("Save   : font: %p, scale: %d,%d\r\n", user_font, restore_hScale, restore_vScale);
    }
    if (!user_font && user_font_scale) {
        ra.SetTextFontSize(user_font_scale);
    }
    r = ComputeKeypadRect();
    ra.fillrect(r, back);
    ra.foreground(fore);
    ra.background(back);
    ra.SetTextCursor(r.p1.x,r.p1.y+2);
    ra.puts(prompt); ra.puts(":");
    userText = ra.GetTextCursor();
    DrawKeypad();
}

rect_t Keypad::ComputeKeypadRect(void) {
    dim_t kH = ra.fontheight() + 4;
    rect_t r;
    
    if (kbd->x <= 0)
        r.p1.x = 0;
    else
        r.p1.x = kbd->x;
    if (kbd->y <= 0)
        r.p1.y = ra.height() - (kH * (kbd->rows+1)) - 1;
    else
        r.p1.y = kbd->y;
    if (kbd->width == 0)
        r.p2.x = ra.width() - 1;
    else
        r.p2.x = r.p1.x + kbd->width - 1;
    if (kbd->height == 0)
        r.p2.y = ra.height() - 1;   
    else
        r.p2.y = r.p1.y + kbd->height - 1;
    //printf("KeypadRect (%d,%d) - (%d,%d)\r\n", r.p1.x, r.p1.y, r.p2.x, r.p2.y);
    return r; 
}

void Keypad::DrawKeypad(void) {
    //dim_t fW;
    dim_t fH;
    dim_t kW;       // key width
    dim_t kH;       // key Height
    
    //fW = ra.fontwidth();
    fH = ra.fontheight();
    kH = fH + 4;
    
    const char * p = kbd->keydef1;
    rect_t r = ComputeKeypadRect();
    rect_t ref = r;
    kW = (ref.p2.x - ref.p1.x) / (kbd->cols+1);
    //printf("DrawKeypad kW=%d from (%d,%d) %d\r\n", kW, ref.p2.x, ref.p1.x, kbd->cols+1);
    r.p1.y += kH;
    if (shift)
        p = kbd->keydef2;
    while (*p || *(p+2)) {
        if (*p == 0) {
            r.p1.x = ref.p1.x;
            r.p1.y += kH;
        } else {
            const char * symbol = p + 1;
            if (*symbol >= 0x10) {
                r.p2.x = r.p1.x + (kW * *p)/10;
                r.p2.y = r.p1.y + kH;
                DrawKey(r,*symbol);
            }
            r.p1.x += (kW * *p)/10;
        }
        p+=2;
    }
}

char Keypad::isKeyTouched(point_t * point, rect_t * rectTouched) {
    dim_t kW;
    dim_t kH = ra.fontheight() + 4;
    
    const char * p = kbd->keydef1;
    rect_t r = ComputeKeypadRect();
    rect_t ref = r;
    kW = (ref.p2.x - ref.p1.x) / (kbd->cols+1);
    r.p1.y = r.p1.y + kH;    
    if (shift)
        p = kbd->keydef2;
    while (*p || *(p+2)) {
        if (*p == 0) {
            r.p1.x = ref.p1.x;
            r.p1.y += kH;
        } else {
            const char * symbol = p + 1;
            if (*symbol >= 0x10) {
                r.p2.x = r.p1.x + (kW * *p)/10;
                r.p2.y = r.p1.y + kH;
                if (ra.Intersect(r, *point)) {
                    if (rectTouched)
                        *rectTouched = r;
                    return (*symbol);
                }
            }
            r.p1.x += (kW * *p)/10;
        }
        p+=2;
    }
    return 0;
}

void Keypad::ShowBufferMetrics(void) {
    rect_t r = ComputeKeypadRect();
    ra.SetTextCursor(r.p2.x-1-ra.fontwidth()*5, r.p1.y+2);
    ra.printf("%02d/%02d", pNext - pStart, bufSize);            // "001/100"
    //ra.SetTextCursor(ra.width()-1-ra.fontwidth()*7, ra.height()-1-ra.fontheight());
    ra.SetTextCursor(userText.x, userText.y);
    ra.SetTextCursorControl(RA8875::UNDER);
}


bool Keypad::GetString(char * buffer, size_t size, const char * prompt, bool initFromBuffer, char mask, bool auto_close) {
    point_t point = {0, 0};
    bool success = false;
    
    pStart = pNext = buffer;
    bufSize = size;
    DrawInputPanel(prompt);
    if (initFromBuffer && strlen(buffer) < size) {
        ra.SetTextCursor(userText);
        ra.puts(buffer);
        userText = ra.GetTextCursor();
        pNext += strlen(buffer);
    }
    ShowBufferMetrics();
    while (1) {
        if (touch == ra.TouchPanelReadable(&point)) {
            rect_t touchRect;
            // find out if they touched a key;
            char key = isKeyTouched(&point, &touchRect);
            if (key) {
                DrawKey(touchRect, key, true);
                wait_ms(50);
                TouchCode_t is;
                do {
                    is = ra.TouchPanelReadable(NULL);
                    //printf("is: %d\r\n", is);
                } while (is != no_touch);
                DrawKey(touchRect, key);
            }
            //printf("Touch %02X at (%d,%d)\r\n", key, point.x, point.y);
            //printf("Touch %02X at (%d,%d)\r\n", key, point.x, point.y);
            if (key == enter_key) {
                *pNext = '\0';
                ra.SetTextCursorControl();
                success = true;
                break;
            } else if (key == esc_key) {
                *buffer = '\0';
                ra.SetTextCursorControl();
                success = false;
                break;
            } else if (key == KYBD_SYM_BS) {
                if (pNext > buffer) {
                    pNext--;
                    // blank the last char
                    userText.x -= ra.fontwidth();
                    ra.SetTextCursor(userText.x, userText.y);
                    ra.putc(' ');
                }
            } else if (key == KYBD_SYM_TAB) {
                *pNext++ = ' ';
                ra.SetTextCursor(userText.x, userText.y);
                ra.putc(' ');
                userText.x += ra.fontwidth();
            } else if (key == KYBD_SYM_SHIFT) {
                shift = !shift;
                DrawKeypad();
            } else if (key) {
                *pNext++ = key;
                ra.SetTextCursor(userText.x, userText.y);
                if (mask)
                    ra.putc(mask);
                else
                    ra.putc(key);
                userText.x += ra.fontwidth();
            }
            if ((pNext - buffer) >= (size - 1)) {
                *pNext = '\0';
                ra.SetTextCursorControl();
                success = true;
                break;
            }
            ShowBufferMetrics();
        }
    }
    if (auto_close)
        Erase(back);
    return success;
}