A primitive menu system for touchscreen on the RA8875. This menu is not "finger friendly" and reminds one of the 90's using a Palm.

Dependents:   FRDM_RA8875_mPaint PUB_RA8875_mPaint

menu.cpp

Committer:
WiredHome
Date:
2015-01-03
Revision:
3:b59d6f7c1e68
Parent:
1:d7a34c7f775b

File content as of revision 3:b59d6f7c1e68:


#include "menu.h"

//#define DEBUG "menu"
// ...
// INFO("Stuff to show %d", var); // new-line is automatically appended
//
#if (defined(DEBUG) && !defined(TARGET_LPC11U24))
#define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
#define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
#define ERR(x, ...)  std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
#else
#define INFO(x, ...)
#define WARN(x, ...)
#define ERR(x, ...)
#define HexDump(a, b, c)
#endif

Menu::~Menu()
{
}

Menu::Menu(RA8875 & _lcd, menu_item_t * _menu, color_t fg, color_t bg, color_t hl) 
    : lcd(_lcd), pTopMenu(_menu), pExpanded(0), isShowing(false), 
    menuForeground(fg), menuBackground(bg), menuHighlight(hl)
{
}

void Menu::init()
{
    lcd.SetLayerMode(RA8875::TransparentMode);
    lcd.SetLayerTransparency(0, 7);
    Show();
}

void Menu::SetColors(color_t fg, color_t bg, color_t hl)
{
    menuForeground = fg;
    menuBackground = bg;
    menuHighlight = hl;
}

bool Menu::_isTouched(menu_item_t * pMenu, rect_t r, point_t p, menu_item_t ** menuTouched)
{
    while (pMenu->menuText) {
        r.p2.x += lcd.fontwidth() * (strlen(pMenu->menuText) + strlen("  "));
        INFO("Is (%3d,%3d) in (%3d,%3d)-(%3d,%3d) %s", p.x, p.y, r.p1.x, r.p1.y, r.p2.x, r.p2.y, pMenu->menuText);
        if (lcd.Intersect(r, p)) {
            *menuTouched = pMenu;
            return true;
        }
//        if (!isShowing)   // Activating this traps the menu activation to the first entry only.
//            break;        // Disabling this permits anything on the top-line
        if (isShowing && pMenu->child && pExpanded == pMenu) {
            rect_t rectChild = r;
            INFO("    to child %s", pExpanded->child->menuText);
            rectChild.p1.x += lcd.fontwidth();
            rectChild.p1.y += lcd.fontheight();
            rectChild.p2.x = rectChild.p1.x;
            rectChild.p2.y = rectChild.p1.y + lcd.fontheight();
            if(_isTouched(pMenu->child, rectChild, p, menuTouched)) // walk the child items
                return true;
        }
        r.p1.x = r.p2.x;
        pMenu++;
    }
    return false;
}

bool Menu::HandledTouch(point_t p, TouchCode_t touchcode)
{
    rect_t r;
    menu_item_t * pTouchedMenu = NULL;
    bool handled = false;
    
    r.p1.x = r.p1.y = r.p2.x = 0;
    r.p2.y = lcd.fontheight();
    
    if (_isTouched(pTopMenu, r, p, &pTouchedMenu)) {
        INFO("Touched %s. touchcode:%d", pTouchedMenu->menuText, touchcode);
        if (!isShowing && touchcode == touch) {
            Show();
        }
        post_fnc_action_t action = no_action;
        switch (touchcode) {
            case touch:
                if (pTouchedMenu->fncPress) {
                    action = pTouchedMenu->fncPress(pTouchedMenu->param);
                }
                if (pTouchedMenu->child) {
                    Expand(pTouchedMenu);
                }
                break;
            case held:
                if (pTouchedMenu->fncHeld) {
                    action = pTouchedMenu->fncHeld(pTouchedMenu->param);
                }
                break;
            case release:
                if (pTouchedMenu->fncRelease) {
                    action = pTouchedMenu->fncRelease(pTouchedMenu->param);
                }
                break;
            default:
                break;
        }
        if (action == close_menu) {
            INFO("Hide it");
            Hide();
        }
        handled = true;
    }
    return handled;
}

bool Menu::_GetMenuRect(menu_item_t * pMenu, menu_item_t * needle, rect_t * pRect)
{
    rect_t r;
    
    if (needle->menuText == NULL)
        return false;
    r.p1.x = r.p1.y = r.p2.x = 0;
    r.p2.y = lcd.fontheight();
    while (pMenu->menuText) {
        r.p2.x += lcd.fontwidth() * (strlen(pMenu->menuText) + strlen("  "));
        if (pMenu == needle) {
            *pRect = r;
            return true;
        }
        r.p1.x = r.p2.x;
        pMenu++;
    }
    return false;
}

void Menu::_Rect(rect_t r, color_t c, fill_t fill)
{
    r.p2.x--;
    r.p2.y--;
    lcd.rect(r, c, fill);
}


void Menu::Expand(menu_item_t * thisMenu)
{
    rect_t r;
    bool same = (pExpanded == thisMenu) ? true : false;
    INFO("Expand(%s)", thisMenu->menuText);
    if (pExpanded) { // need to hide this one first
        INFO("  Hiding children of %s. this=%s, same=%d", pExpanded->menuText, thisMenu->menuText, same);
        _GetMenuRect(pTopMenu, pExpanded, &r);
        _Rect(r, menuForeground);
        r.p1.x += lcd.fontwidth();
        r.p1.y += lcd.fontheight();
        r.p2.x = r.p1.x;
        r.p2.y = r.p1.y + lcd.fontheight();
        _ShowMenu_Helper(pExpanded->child, r, false);
        pExpanded = NULL;
    }
    if (!same && _GetMenuRect(pTopMenu, thisMenu, &r)) {
        INFO("  Expanding to children of %s.", thisMenu->menuText);
        _Rect(r, menuHighlight);
        // index in a little, then down a row
        r.p1.x += lcd.fontwidth();
        r.p1.y += lcd.fontheight();
        r.p2.x = r.p1.x;
        r.p2.y = r.p1.y + lcd.fontheight();
        _ShowMenu_Helper(thisMenu->child, r);
        pExpanded = thisMenu;
    }
}

void Menu::Show()
{
    rect_t r;
    INFO("Show()");
    lcd.SelectDrawingLayer(MENUS);
    lcd.SetLayerTransparency(7, 0);     // emphasize the menu
    lcd.SetTextCursor(0,0);
    r.p1.x = r.p1.y = r.p2.x = 0;
    r.p2.y = lcd.fontheight();
    menu_item_t * pMenu = pTopMenu;
    _ShowMenu_Helper(pMenu, r);
    isShowing = true;
}

void Menu::_ShowMenu_Helper(menu_item_t * pMenu, rect_t r, bool show)
{
    while (pMenu->menuText) {
        lcd.SetTextCursor(r.p1.x, r.p1.y);
        r.p2.x += lcd.fontwidth() * (strlen(pMenu->menuText) + strlen("  "));
        if (show) {
            INFO("(%3d,%3d)-(%3d,%3d) %s", r.p1.x, r.p1.y, r.p2.x, r.p2.y, pMenu->menuText);
            lcd.foreground(menuForeground);
            lcd.printf(" %s ", pMenu->menuText);
            _Rect(r, menuForeground);
        } else {
            INFO("HIDE (%3d,%3d)-(%3d,%3d) %s", r.p1.x, r.p1.y, r.p2.x, r.p2.y, pMenu->menuText);
            _Rect(r, menuBackground, FILL);
        }
        r.p1.x = r.p2.x;
        pMenu++;
    }
    isShowing = true;
}

void Menu::Hide()
{
    INFO("Hide()");
    if (pExpanded)
        Expand(pExpanded); // hides this menu
    lcd.SelectDrawingLayer(CANVAS);
    isShowing = false;
    lcd.SetLayerTransparency(0, 7);     // emphasize the canvas
}