Nana C++ Library  
An open-source C++ framework project
The Nana Programmer's Guide 
nana::gui::menu

Description

A menu widget is a list of items that specify options or group of options for an application.

Model of

Widget Window 

Public base classes

class widget_object<root_tag, DrawerTrigger>: public widget

Typedefs

item_proxy It a proxy used for a parameter in a callback.
event_fn_t  A callback function object type, the prototype is
void(item_proxy&);
enum check_t{check_none, check_option, check_highlight} It defines the check styles. CheckNone, CheckOption, CheckHighlight
renderer_interface The interface of user-defined renderer. (See Note 5)


Members

menu() The default constructor.
~menu() The destructor.
void answerer(std::size_t n, const event_fn_t&) Modify answerer of the specified item.
void append(const nana::string& text, const event_fn_t &answerer = event_fn_t()) Appends an item to the menu. answerer is a callback functor.
void append_splitter() Appends a splitter to the menu.
void clear() Erases all of the items.
void close() Closes the menu. It does not destroy the menu, just close the window for the menu.
void check_style(std::size_t n, check_t style) Sets the check style for the n'th item.
void checked(std::size_t n, bool check) Sets the check state of an item.
bool checked(std::size_t n) const Returns the check state of an item.
menu *create_sub_menu(std::size_t n) Creates a sub menu for the n'th item.
void enabled(std::size_t n, bool) Enables or disables the mouse or keyboard input for the n'th item.
bool enabled(std::size_t n) const Returns true if the n'th item is enabled.
void erase(std::size_t n) Removes n'th item.
void exit_submenu() Closes the current window of the sub menu.
void gaps(const nana::point &) Sets the gap between a menu and its sub menus. (See Note 4)
void goto_next(bool forward) Moves the focus to the next item or previous item.
bool goto_submenu() Popup the sub menu of the current item if it has a sub menu. It returns true if it succeeds.
void image(std::size_t n, const nana::paint::image&) Sets a icon image for a specified menu item.
menu & item_pixels(unsigned pixels) Sets the height in pixel for the items.
unsigned item_pixels() const Returns the height in pixels for the itmes.
bool link(std::size_t n, menu& menu) Link a menu as a sub menu for the n'th item.
menu* link(std::size_t n) Retrieves a linked sub menu by the n'th index.
menu& max_pixels(unsigned px) Sets the max pixels of the menu width.
unsigned max_pixels() const Gets the max pixels of the menu width.
void popup(window owner, int x, int y, bool owner_menubar) Popup the menu at the owner window. the last parameter specifies whether it is for menubar, always be false.
template<typename Renderer>
void renderer(const Renderer&)
Sets a user-defined renderer. (See Note 5)
void renderer(const nana::pat::cloneable<renderer_interface>&) Ditto.
const nana::pat::cloneable<renderer_interface>& renderer() const Returns a user-defined renderer. (See Note 5)
int send_shortkey(nana::char_t key) Sents a key to the menu.
std::size_t size() const Return the number of items.

C++03 Member
void destroy_answer(const nana::functor<void()>&) Sets an answerer for the callback while the menu window is closing.

C++11 Member
void destroy_answer(const std::function<void()>&) Ditto.

File

nana/gui/widgets/menu.hpp

Notes

1. The widget sets the shortkey that is a character behind the first of &-character in text for the item. e.g. "File(&F)" or "&File".

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
2. The type item_proxy is used for a callbacking, a programmer should not take care about the object of item_proxy, it is created and destroyed by menu. The definition is

class item_proxy: nana::noncopyable
{
public:
    implementation-specified constructor
    void enabled(bool);  //Sets the enable state of the item.
    bool enabled() const; //Gets the enable state of the item.
    std::size_t index() const; //Gets the index of the item.
private:
    //Private data members...
};


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
3. There is a helper for automatically popuping a menu.

class menu_popuper
{
public:
    //C++03
    menu_popuper(menu&, mouse::t = mouse::right_button);
    menu_popuper(menu&, window owner,
const point& pos, mouse::t = mouse::right_button);

    //C++11
    menu_popuper(menu&, mouse = mouse::right_button);
    menu_popuper(menu&, window owner,
const point& pos, mouse = mouse::right_button);
   
    void operator()(const eventinfo&);
private:
    //Implemented-Specified private members
};

Now let's use it. There is a button, it popups the menu when it is clicked.

#include <nana/gui/wvl.hpp>
#include <nana/gui/widgets/button.hpp>
#include <nana/gui/widgets/menu.hpp>

void on_menu_item(nana::gui::menu::item_proxy& ip)
{
    std::size_t index = ip.index(); //Get the index of the clicking item.
}

int main()
{
    using namespace nana::gui;
    form fm;
   
    //We need a menu object
    menu mobj;
    mobj.append(STR("Item 0"), &on_menu_item);
    mobj.append_splitter();
    mobj.append(STR("Item 1"), &on_menu_item);

    //Now we need a button.
    button btn(fm, nana::rectangle(nana::point(10, 10), nana::size(100, 25)));
    btn.caption(STR("Popup Menu"));

    //Popup the menu when right clicking the button.
    btn.make_event<events::click>(menu_popuper(mobj));

    //Or popuping the menu with a specified coordinate when any mouse button is clicked.
    //btn.make_event<events::click>(menu_popuper(mobj, btn, nana::point(0, 26), mouse::any_button);

    fm.show();
    exec();
}


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
4. The gap of menu is used to specify the interval pixels between the menu and its sub menus. It affects all sub menus and all sub menus of its sub menus.

Gap of Menu

int main()
{
    using namespace nana::gui;

    menu mobj;
    mobj.append(STR("Item 0"));
    mobj.append(STR("Item 1"));

    mobj.gaps(nana::point(3, -2)); //Remove this statement for default gaps.

    menu * sub = mobj.create_sub_menu(0);
    sub->append(STR("Item 0"));
    sub->append(STR("Item 1"));

    sub = sub->create_sub_menu(0);
    sub->append(STR("A sub's sub menu item"));

    form fm;
    fm.make_event<events::click>(menu_popuper(mobj));
    fm.show();
    exec();
}


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
5, When a renderer is set for a menu, it affects all sub menus of the menu and all sub menus of its all sub menus.
An example of a user-defined renderer.

The definition of class renderer_interface

class renderer_interface
{
public:
    typedef nana::paint::graphics & graph_reference;

    //C++03
    struct state
    {
        enum t{ normal, active};
    };


    //C++11
    enum class state
    {
        normal, active
    };


    struct attr
    {
        //C++03
        state::t item_state;
        //C++11
        state item_state;

        bool enabled;
        bool checked;
        int check_style;
    };

    virtual ~renderer_interface() = 0;
    virtual void background(graph_reference, window) = 0;
    virtual void item(graph_reference, const nana::rectangle&, const attr&) = 0;
    virtual void item_image(graph_reference, const nana::point&, const nana::paint::image&) = 0;
    virtual void item_text(graph_reference, const nana::point&, const nana::string&, unsigned pixles, const attr&) = 0;
    virtual void sub_arrow(graph_reference, const nana::point&, unsigned pixels, const attr&) = 0;
  
};


The implementation of the user-defined renderer. In this example, the renderer only provides the drawing of background and drawing of item, so that we have to employ the existing renderer of a menu for other drawing methods.

Renderer of Menu

using namespace nana::gui;

class renderer: public menu::renderer_interface
{
public:
    //My renderer employs the existing renderer of a menu.
    renderer(const nana::pat::cloneable_interface<renderer_interface> * rd)
        : rdptr_(rd->clone())
    {}

    //The renderer is copy-constructable, therefore a deep-copy is required.
    renderer(const renderer & rd)
        : rdptr_(rd.rdptr_->clone())
    {}

    ~renderer()
    {
        rdptr_->self_delete();
    }
private:
    void background(graph_reference graph, window wd)
    {
        graph.rectangle(0xFFFFFF, true);
        graph.rectangle(0x5DC1AC, false);

        //Makes the menu transparent, it only works under Windows with #include <windows.h>
        HWND native = reinterpret_cast(API::root(wd));
        DWORD ex_style = ::GetWindowLong(native, GWL_EXSTYLE);
        ::SetWindowLong(native, GWL_EXSTYLE, ex_style | 0x00080000 /*WS_EX_LAYERED*/);
        typedef         BOOL (WINAPI *slwa_t)(HWND hwnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags);
        slwa_t slwa = reinterpret_cast(::GetProcAddress(::GetModuleHandleA("User32.DLL"), "SetLayeredWindowAttributes"));
        if        (slwa)
            slwa(native, 0, 220, 0x00000002/*LWA_ALPHA*/);
    }

    void         item(graph_reference graph, const nana::rectangle& r, const attr & atr)
    {
        if            (state::active == atr.item_state)
            graph.rectangle(r, 0x9ADCCA, true);
    }

    void         item_image(graph_reference graph, const nana::point& pos, const nana::paint::image& img)
    {
            rdptr_->refer().item_image(graph, pos, img);
    }

    void         item_text(graph_reference graph, const nana::point& pos, const nana::string& text, unsigned pixels, const attr& atr)
    {
            rdptr_->refer().item_text(graph, pos, text, pixels, atr);
    }

    void         sub_arrow(graph_reference graph, const nana::point& pos, unsigned pixels, const attr & atr)
    {
            rdptr_->refer().sub_arrow(graph, pos, pixels, atr);
    }
   
private:
            nana::pat::cloneable_interface<renderer_interface> * rdptr_;
};

int main()
{
    menu mobj;
    mobj.append(STR("Item 0"));
    mobj.append(STR("Item 1"));
                mobj.create_sub_menu(1)->append(STR("A sub menu item"));

    mobj.renderer(renderer(mobj.renderer()));
    mobj.item_pixels(20);

    form fm;
    fm.make_event<events::click>(menu_popuper(mobj));
    fm.show();
    exec();
}

               

See also

menubar.


Move to The Nana Programmer's Guide Main Page