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.h

Committer:
WiredHome
Date:
2015-01-03
Revision:
3:b59d6f7c1e68
Parent:
2:944069915001

File content as of revision 3:b59d6f7c1e68:


#ifndef MENU_H
#define MENU_H

#include "RA8875.h"

#define CANVAS  0
#define MENUS   1

/// A very simple menu system, for use with the RA8875 display library.
///
/// This will seem like a "throwback" to the 90's. As designed, it is 
/// not for "finger" but for stylus, since menu picks are the size of 
/// the selected font. The user could change the font size, and the
/// menu should resize accordingly.
///
/// The user defines some simple arrays of structures which define
/// menu picks.
///
/// The menu is created horizontally on the screen, starting in the top-
/// left.
///
/// Submenus, of which only 1 submenu level is supported, are also
/// shown horizontally starting directly beneath the top-level (and 
/// 1 char to the right). Care should be taken if it may cause wordwrap,
/// as this is not supported (and the behavior has not been tested).
///
/// @note When using this menu system, it uses the two-layer mode of the 
/// RA8875 display, which limits the display to those with not more
/// than 480x272 pixels in size.
///
/// @code
/// // +----------------------------------------------------+
/// // | File | Pen | Tools                                 |
/// // +----------------------------------------------------+ fontheight()
/// // |                                                    |
/// // |                                                    |
/// // |                                                    |
/// // |                                                    |
/// // |                                                    |
/// // |                                                    |
/// // |                                                    |
/// // |                                                    |
/// // |                                                    |
/// // |                                                    |
/// // |                                                    |
/// // +----------------------------------------------------+ 
///
/// // +----------------------------------------------------+
/// // | File | Pen | Tools                                 |
/// // +----------------------------------------------------+
/// // || New... | Save... | Save all | Calibrate | Reset | |
/// // |                                                    |
///
/// // +----------------------------------------------------+
/// // | File | Pen | Tools                                 |
/// // +----------------------------------------------------+
/// // |       | 1 pix | 2 pix | 4 pix | ...                |
/// //
/// @endcode
///
class Menu
{
public:
    /// When menu functions are called, they can return a command
    /// to the menu system to determine what it should do - if
    /// anything.
    ///
    typedef enum 
    {
        no_action,          ///< take no action on return.
        close_menu,         ///< close the menu immediately.
    } post_fnc_action_t;
    
    /// Each menu item is a structure as defined here. An array
    /// of these create multple entries on that menu level.
    /// The array must be terminated by a NULL entry.
    ///
    typedef struct menu_item_t
    {
        char * menuText;                            ///< text to show (keep it brief!)
        post_fnc_action_t (* fncPress)(uint32_t);   ///< function to call "on touch", or NULL
        post_fnc_action_t (* fncHeld)(uint32_t);    ///< function to call "on held", or NULL
        post_fnc_action_t (* fncRelease)(uint32_t); ///< function to call "on release", or NULL
        uint32_t param;                             ///< parameter to pass to the function.
        menu_item_t * child;                        ///< child menu, if this is an upper menu.
    } menu_item_t;

    /// The constructor for the menu class.
    ///
    /// This creates the instance of the menu. The initialization is done
    /// later.
    ///
    /// @code
    /// #include "menu.h"
    /// ...
    /// Menu::menu_item_t menudata[] = {
    ///     // Text    touch held  release  param childmenu
    ///     { "File",  File, NULL, NULL,     0, file_menu },
    ///     { "Pen",   NULL, NULL, NULL,     0, pen_menu },
    ///     { "Tools", NULL, NULL, NULL,     0, tools_menu },
    ///     { "Hide",  NULL, NULL, HideMenu, 0, NULL },
    ///     { NULL,    NULL, NULL, NULL,     0, NULL }, // NULL terminator
    /// };
    ///
    /// Menu menu(lcd, menudata);
    ///
    /// void main() {
    ///    menu.init();
    ///    for (;;) {
    ///        point_t p;
    ///        TouchCode_t touchcode = lcd.TouchPanelReadable(&p);
    ///
    ///        if (touchcode != no_touch) {
    ///            bool menuHandledIt = menu.HandledTouch(p, touchcode);
    ///            if (menuHandledIt) {
    ///                // menu handled it
    ///            } else {
    ///                // user code here for touch in non-menu areas.
    ///            }
    ///        }
    ///    }
    /// }
    /// @endcode
    ///
    /// @param lcd is a reference to the RA8875 display object. @see RA8875.
    /// @param menu is a pointer to the top-level menu list. @see menu_item_t.
    /// @param fg is the foreground color for the menu.
    /// @param bg is the background color for the menu.
    /// @param hl is the highlight color for the menu.
    ///
    Menu(RA8875 & lcd, menu_item_t * menu, color_t fg = BrightBlue, color_t bg = Black, color_t hl = Red);
    
    /// Destructure for the menu class.
    ~Menu();
    
    /// initialize the menu system to get it started.
    ///
    /// This sets up the RA8875 display and layering for the menu system.
    ///
    void init(void);
    
    /// This is the main "run-time" entry point. 
    ///
    /// Every touch should call this and pass in the point and touchcode.
    /// If the menu can handle this event, it will indicate so the
    /// return code.
    ///
    /// @param p is the point provided to this method indicating where
    ///         the last touch was detected.
    /// @param touchcode indicates the type of touch, and permits easy
    ///         handling of touch, held, release events.
    /// @returns true if the touch was handled by the menu system.
    /// 
    bool HandledTouch(point_t p, TouchCode_t touchcode);
    
    /// Force show the menu.
    ///
    void Show();
    
    /// Force hide the menu.
    ///
    void Hide();
    
    /// Indicates if the menu is currently visible.
    ///
    /// @returns true if the menu is visible.
    ///
    bool isVisible() { return isShowing; }

private:
    /// This method expands a top-level menu to show the lower.
    /// 
    /// It also will first high any previously open submenu.
    ///
    /// @param menu is a pointer to the menu to expand if it has child menus.
    ///
    void Expand(menu_item_t * menu);
    void SetColors(color_t fg, color_t bg, color_t hl);
    bool _isTouched(menu_item_t * pTraverse, rect_t r, point_t p, menu_item_t ** menuTouched);
    bool _GetMenuRect(menu_item_t * pMenu, menu_item_t * needle, rect_t * pRect);
    void _ShowMenu_Helper(menu_item_t * pMenu, rect_t r, bool show = true);
    void _Rect(rect_t r, color_t c, fill_t fill = NOFILL);
    RA8875 & lcd;
    menu_item_t * pTopMenu;
    menu_item_t * pExpanded;    // points to an expanded menu
    bool isShowing;
    color_t menuForeground;
    color_t menuBackground;
    color_t menuHighlight;
};

#endif // MENU_H