fix issue of menu item_proxy

This commit is contained in:
Jinhao 2016-10-31 04:33:42 +08:00
parent e7ce506f5a
commit 445f0ed6de
3 changed files with 157 additions and 175 deletions

View File

@ -13,10 +13,7 @@
#ifndef NANA_GUI_WIDGETS_MENU_HPP #ifndef NANA_GUI_WIDGETS_MENU_HPP
#define NANA_GUI_WIDGETS_MENU_HPP #define NANA_GUI_WIDGETS_MENU_HPP
#include "widget.hpp" #include "widget.hpp"
#include <vector>
#include <nana/gui/timer.hpp>
#include <nana/pat/cloneable.hpp> #include <nana/pat/cloneable.hpp>
#include <nana/push_ignore_diagnostic> #include <nana/push_ignore_diagnostic>
namespace nana namespace nana
@ -71,25 +68,12 @@ namespace nana
menu_type *sub_menu{nullptr}; menu_type *sub_menu{nullptr};
std::string text; std::string text;
event_fn_t functor; event_fn_t event_handler;
checks style{checks::none}; checks style{checks::none};
paint::image image; paint::image image;
mutable wchar_t hotkey{0}; mutable wchar_t hotkey{0};
}; };
struct menu_type
{
typedef std::vector<menu_item_type> item_container;
typedef item_container::iterator iterator;
typedef item_container::const_iterator const_iterator;
std::vector<menu_type*> owner;
std::vector<menu_item_type> items;
unsigned max_pixels;
unsigned item_pixels;
nana::point gaps;
};
class renderer_interface class renderer_interface
{ {
public: public:
@ -156,7 +140,7 @@ namespace nana
void popup(window owner, int x, int y); ///< Popup the menu at the owner window. void popup(window owner, int x, int y); ///< Popup the menu at the owner window.
void popup_await(window owner, int x, int y); void popup_await(window owner, int x, int y);
void answerer(std::size_t index, const event_fn_t&); ///< Modify answerer of the specified item. void answerer(std::size_t index, const event_fn_t&); ///< Modify answerer of the specified item.
void destroy_answer(const std::function<void()>&); ///< Sets an answerer for the callback while the menu window is closing. void destroy_answer(std::function<void()>); ///< Sets an answerer for the callback while the menu window is closing.
void gaps(const nana::point&); ///< Sets the gap between a menu and its sub menus.(\See Note4) void gaps(const nana::point&); ///< Sets the gap between a menu and its sub menus.(\See Note4)
void goto_next(bool forward); ///< Moves the focus to the next or previous item. void goto_next(bool forward); ///< Moves the focus to the next or previous item.
bool goto_submen();///< Popup the submenu of the current item if it has a sub menu. Returns true if succeeds. bool goto_submen();///< Popup the submenu of the current item if it has a sub menu. Returns true if succeeds.
@ -175,7 +159,7 @@ namespace nana
const pat::cloneable<renderer_interface>& renderer() const; const pat::cloneable<renderer_interface>& renderer() const;
private: private:
void _m_popup(window, int x, int y, bool called_by_menubar); void _m_popup(window, const point& position, bool called_by_menubar);
private: private:
implement * impl_; implement * impl_;
}; };

View File

@ -1,7 +1,7 @@
/* /*
* A Menu implementation * A Menu implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2009-2015 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2009-2016 Jinhao(cnjinhao@hotmail.com)
* *
* Distributed under the Boost Software License, Version 1.0. * Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at * (See accompanying file LICENSE_1_0.txt or copy at
@ -13,12 +13,15 @@
*/ */
#include <nana/gui/widgets/menu.hpp> #include <nana/gui/widgets/menu.hpp>
#include <nana/gui/timer.hpp>
#include <nana/system/platform.hpp> #include <nana/system/platform.hpp>
#include <nana/gui/element.hpp> #include <nana/gui/element.hpp>
#include <nana/gui/wvl.hpp> #include <nana/gui/wvl.hpp>
#include <nana/paint/text_renderer.hpp> #include <nana/paint/text_renderer.hpp>
#include <cctype> //introduces tolower #include <cctype> //introduces tolower
#include <map> #include <map>
#include <vector>
namespace nana namespace nana
{ {
@ -26,6 +29,20 @@ namespace nana
{ {
namespace menu namespace menu
{ {
struct menu_type
{
using item_type = menu_item_type;
using item_container = std::vector<std::unique_ptr<item_type>>;
using iterator = item_container::iterator;
std::vector<menu_type*> owner;
item_container items;
unsigned max_pixels;
unsigned item_pixels;
nana::point gaps;
};
//A helper function to check the style parameter //A helper function to check the style parameter
inline bool good_checks(checks s) inline bool good_checks(checks s)
{ {
@ -82,8 +99,8 @@ namespace nana
flags.checked = false; flags.checked = false;
} }
menu_item_type::menu_item_type(std::string text, const event_fn_t& f) menu_item_type::menu_item_type(std::string text, const event_fn_t& fn)
: text(std::move(text)), functor(f) : text(std::move(text)), event_handler(fn)
{ {
flags.enabled = true; flags.enabled = true;
flags.splitter = false; flags.splitter = false;
@ -152,10 +169,10 @@ namespace nana
//Stretchs menu icon only when it doesn't fit, center it otherwise. //Stretchs menu icon only when it doesn't fit, center it otherwise.
//Contributed by kmribti(pr#102) //Contributed by kmribti(pr#102)
nana::point ipos = pos; img.paste(graph, {
ipos.x += (image_px - img.size().width ) / 2; pos.x + static_cast<int>(image_px - img.size().width) / 2,
ipos.y += (image_px - img.size().height) / 2; pos.y + static_cast<int>(image_px - img.size().height) / 2
img.paste(graph, ipos); });
} }
void item_text(graph_reference graph, const nana::point& pos, const std::string& text, unsigned text_pixels, const attr& at) void item_text(graph_reference graph, const nana::point& pos, const std::string& text, unsigned text_pixels, const attr& at)
@ -182,11 +199,9 @@ namespace nana
: noncopyable : noncopyable
{ {
public: public:
typedef menu_item_type item_type; using item_type = menu_item_type;
using event_fn_t = item_type::event_fn_t;
typedef menu_type::item_container::value_type::event_fn_t event_fn_t; using iterator = menu_type::item_container::iterator;
typedef menu_type::item_container::iterator iterator;
typedef menu_type::item_container::const_iterator const_iterator;
menu_builder() menu_builder()
{ {
@ -205,40 +220,42 @@ namespace nana
if(good_checks(s)) if(good_checks(s))
{ {
if(root_.items.size() > index) if(root_.items.size() > index)
root_.items[index].style = s; root_.items[index]->style = s;
} }
} }
void checked(std::size_t index, bool check) void checked(std::size_t pos, bool check)
{ {
if (root_.items.size() <= index) if (root_.items.size() <= pos)
return; return;
item_type & m = root_.items[index]; item_type & m = *(root_.items[pos]);
if(check && (checks::option == m.style)) if(check && (checks::option == m.style))
{ {
if(index) //find a splitter in front of pos
if (pos > 0)
{ {
std::size_t i = index;
do do
{ {
item_type& el = root_.items[--i]; if (root_.items[--pos]->flags.splitter)
if(el.flags.splitter) break;
if(checks::option == el.style)
el.flags.checked = false;
}while(i);
}
for(std::size_t i = index + 1; i < root_.items.size(); ++i)
{ {
item_type & el = root_.items[i]; ++pos;
break;
}
}while(pos > 0);
}
while (pos < root_.items.size())
{
item_type & el = *(root_.items[pos++]);
if(el.flags.splitter) break; if(el.flags.splitter) break;
if(checks::option == el.style) if(checks::option == el.style)
el.flags.checked = false; el.flags.checked = false;
} }
} }
m.flags.checked = check; m.flags.checked = check;
} }
@ -247,25 +264,12 @@ namespace nana
return root_; return root_;
} }
const menu_type& data() const
{
return root_;
}
void insert(std::size_t pos, std::string&& text, const event_fn_t& fn)
{
if(pos < root_.items.size())
root_.items.emplace(root_.items.begin() + pos, std::move(text), std::ref(fn));
else
root_.items.emplace_back(std::move(text), std::ref(fn));
}
bool set_sub_menu(std::size_t pos, menu_type &sub) bool set_sub_menu(std::size_t pos, menu_type &sub)
{ {
if(root_.items.size() > pos) if(root_.items.size() > pos)
{ {
menu_item_type & item = root_.items[pos]; auto & item = *(root_.items[pos]);
if(item.sub_menu == nullptr) if(!item.sub_menu)
{ {
item.sub_menu = &sub; item.sub_menu = &sub;
sub.owner.emplace_back(&root_); sub.owner.emplace_back(&root_);
@ -280,17 +284,17 @@ namespace nana
for(auto i : root_.owner) for(auto i : root_.owner)
for(auto & m : i->items) for(auto & m : i->items)
{ {
if(m.sub_menu == &root_) if(m->sub_menu == &root_)
m.sub_menu = nullptr; m->sub_menu = nullptr;
} }
for(auto & m : root_.items) for(auto & m : root_.items)
{ {
if(m.sub_menu) if(m->sub_menu)
for(auto i = m.sub_menu->owner.begin(); i != m.sub_menu->owner.end();) for(auto i = m->sub_menu->owner.begin(); i != m->sub_menu->owner.end();)
{ {
if((*i) == &root_) if((*i) == &root_)
i = m.sub_menu->owner.erase(i); i = m->sub_menu->owner.erase(i);
else else
++i; ++i;
} }
@ -317,8 +321,6 @@ namespace nana
public: public:
using item_proxy = menu_item_type::item_proxy; using item_proxy = menu_item_type::item_proxy;
renderer_interface * renderer;
menu_drawer() menu_drawer()
{ {
state_.active = npos; state_.active = npos;
@ -328,9 +330,16 @@ namespace nana
detail_.border.x = detail_.border.y = 2; detail_.border.x = detail_.border.y = 2;
} }
void close_menu_tree(std::function<void()> && fn) void set_run(menu_builder& mbuilder, menu_type& menu, std::function<void()> && menu_tree_destroyer)
{ {
fn_close_tree_ = std::move(fn); mbuilder_ = &mbuilder;
menu_ = &menu;
fn_close_tree_ = std::move(menu_tree_destroyer);
}
menu_builder& mbuilder()
{
return *mbuilder_;
} }
void attached(widget_reference widget, graph_reference graph) void attached(widget_reference widget, graph_reference graph)
@ -363,10 +372,12 @@ namespace nana
void refresh(graph_reference graph) void refresh(graph_reference graph)
{ {
if (nullptr == menu_) return; if (!(mbuilder_ && menu_))
return;
_m_adjust_window_size(); _m_adjust_window_size();
auto renderer = mbuilder_->renderer().get();
renderer->background(graph, *widget_); renderer->background(graph, *widget_);
const unsigned item_h_px = _m_item_height(); const unsigned item_h_px = _m_item_height();
@ -375,12 +386,13 @@ namespace nana
unsigned strpixels = item_r.width - 60; unsigned strpixels = item_r.width - 60;
int text_top_off = (item_h_px - graph.text_extent_size(L"jh({[").height) / 2; int text_top_off = static_cast<int>(item_h_px - graph.text_extent_size(L"jh({[").height) / 2;
std::size_t pos = 0; std::size_t pos = 0;
for (auto & m : menu_->items) for (auto & m : menu_->items)
{ {
if (m.flags.splitter) auto item_ptr = m.get();
if (item_ptr->flags.splitter)
{ {
graph_->line({ item_r.x + 40, item_r.y }, { static_cast<int>(graph.width()) - 1, item_r.y }, colors::gray_border); graph_->line({ item_r.x + 40, item_r.y }, { static_cast<int>(graph.width()) - 1, item_r.y }, colors::gray_border);
item_r.y += 2; item_r.y += 2;
@ -388,24 +400,24 @@ namespace nana
continue; continue;
} }
renderer_interface::attr attr = _m_make_renderer_attr(pos == state_.active, m); renderer_interface::attr attr = _m_make_renderer_attr(pos == state_.active, *item_ptr);
//Draw item background //Draw item background
renderer->item(*graph_, item_r, attr); renderer->item(*graph_, item_r, attr);
//Draw text, the text is transformed from orignal for hotkey character //Draw text, the text is transformed from orignal for hotkey character
wchar_t hotkey; wchar_t hotkey;
std::string::size_type hotkey_pos; std::string::size_type hotkey_pos;
auto text = API::transform_shortkey_text(m.text, hotkey, &hotkey_pos); auto text = API::transform_shortkey_text(item_ptr->text, hotkey, &hotkey_pos);
if (m.image.empty() == false) if (item_ptr->image.empty() == false)
renderer->item_image(graph, nana::point(item_r.x + 5, item_r.y + static_cast<int>(item_h_px - image_px) / 2 - 1), image_px, m.image); renderer->item_image(graph, nana::point(item_r.x + 5, item_r.y + static_cast<int>(item_h_px - image_px) / 2 - 1), image_px, item_ptr->image);
renderer->item_text(graph, nana::point(item_r.x + 40, item_r.y + text_top_off), text, strpixels, attr); renderer->item_text(graph, nana::point(item_r.x + 40, item_r.y + text_top_off), text, strpixels, attr);
if (hotkey) if (hotkey)
{ {
m.hotkey = hotkey; item_ptr->hotkey = hotkey;
if (m.flags.enabled) if (item_ptr->flags.enabled)
{ {
auto off_px = (hotkey_pos ? graph.text_extent_size(text.c_str(), hotkey_pos).width : 0); auto off_px = (hotkey_pos ? graph.text_extent_size(text.c_str(), hotkey_pos).width : 0);
auto hotkey_px = graph.text_extent_size(text.c_str() + hotkey_pos, 1).width; auto hotkey_px = graph.text_extent_size(text.c_str() + hotkey_pos, 1).width;
@ -420,7 +432,7 @@ namespace nana
} }
} }
if (m.sub_menu) if (item_ptr->sub_menu)
renderer->sub_arrow(graph, nana::point(graph_->width() - 20, item_r.y), item_h_px, attr); renderer->sub_arrow(graph, nana::point(graph_->width() - 20, item_r.y), item_h_px, attr);
item_r.y += item_r.height + 1; item_r.y += item_r.height + 1;
@ -437,11 +449,14 @@ namespace nana
bool goto_next(bool forword) bool goto_next(bool forword)
{ {
state_.nullify_mouse = true; state_.nullify_mouse = true;
if (menu_->items.empty())
auto & items = menu_->items;
if (items.empty())
return false; return false;
auto pos = state_.active; auto pos = state_.active;
const auto lastpos = menu_->items.size() - 1; const auto lastpos = items.size() - 1;
bool end = false; bool end = false;
while(true) while(true)
@ -476,7 +491,8 @@ namespace nana
--pos; --pos;
} }
if(! menu_->items.at(pos).flags.splitter && menu_->items.at(pos).flags.enabled) auto item_ptr = items.at(pos).get();
if (!item_ptr->flags.splitter && item_ptr->flags.enabled)
break; break;
} }
@ -496,13 +512,14 @@ namespace nana
{ {
if (!state_.nullify_mouse) if (!state_.nullify_mouse)
{ {
auto & items = menu_->items;
std::size_t index = _m_get_index_by_pos(pos.x, pos.y); std::size_t index = _m_get_index_by_pos(pos.x, pos.y);
if (index != state_.active) if (index != state_.active)
{ {
if ((index == npos) && menu_->items.at(state_.active).sub_menu && state_.sub_window) if ((index == npos) && items.at(state_.active)->sub_menu && state_.sub_window)
return false; return false;
state_.active = (index != npos && menu_->items.at(index).flags.splitter) ? npos : index; state_.active = (index != npos && items.at(index)->flags.splitter) ? npos : index;
state_.active_timestamp = nana::system::timestamp(); state_.active_timestamp = nana::system::timestamp();
return true; return true;
} }
@ -511,11 +528,6 @@ namespace nana
return false; return false;
} }
void data(menu_type & menu)
{
menu_ = & menu;
}
menu_type* data() const menu_type* data() const
{ {
return menu_; return menu_;
@ -531,19 +543,20 @@ namespace nana
if (npos == state_.active) if (npos == state_.active)
return nullptr; return nullptr;
auto sub = menu_->items.at(state_.active).sub_menu; auto & items = menu_->items;
auto sub = items.at(state_.active)->sub_menu;
if (sub) if (sub)
{ {
pos.x = static_cast<int>(graph_->width()) - 2; pos.x = static_cast<int>(graph_->width()) - 2;
pos.y = 2; pos.y = 2;
auto index = state_.active; auto index = state_.active;
for (auto & m : menu_->items) for (auto & m : items)
{ {
if (0 == index--) if (0 == index--)
break; break;
if (m.flags.splitter) if (m->flags.splitter)
{ {
pos.y += 2; pos.y += 2;
continue; continue;
@ -565,15 +578,16 @@ namespace nana
std::size_t index = 0; std::size_t index = 0;
for(auto & m : menu_->items) for(auto & m : menu_->items)
{ {
if (std::tolower(m.hotkey) != key) auto item_ptr = m.get();
if (std::tolower(m->hotkey) != key)
{ {
++index; ++index;
continue; continue;
} }
if(!m.flags.splitter) if (!item_ptr->flags.splitter)
{ {
if(m.sub_menu) if (item_ptr->sub_menu)
{ {
state_.active = index; state_.active = index;
state_.active_timestamp = nana::system::timestamp(); state_.active_timestamp = nana::system::timestamp();
@ -581,13 +595,13 @@ namespace nana
API::refresh_window(*widget_); API::refresh_window(*widget_);
return 2; return 2;
} }
else if(m.flags.enabled) else if (item_ptr->flags.enabled)
{ {
fn_close_tree_(); fn_close_tree_();
if (m.functor) if (item_ptr->event_handler)
{ {
item_proxy ip(index, m); item_proxy ip(index, *item_ptr);
m.functor.operator()(ip); item_ptr->event_handler.operator()(ip);
} }
return 1; return 1;
} }
@ -619,7 +633,7 @@ namespace nana
std::size_t index = 0; std::size_t index = 0;
for (auto & m : menu_->items) for (auto & m : menu_->items)
{ {
unsigned h = (m.flags.splitter ? 1 : _m_item_height()); unsigned h = (m->flags.splitter ? 1 : _m_item_height());
if(pos <= y && y < static_cast<int>(pos + h)) if(pos <= y && y < static_cast<int>(pos + h))
return index; return index;
else if(y < pos) else if(y < pos)
@ -644,9 +658,9 @@ namespace nana
{ {
for (auto & m : menu_->items) for (auto & m : menu_->items)
{ {
if(false == m.flags.splitter) if(false == m->flags.splitter)
{ {
nana::size item_size = graph_->text_extent_size(m.text); nana::size item_size = graph_->text_extent_size(m->text);
if(size.width < item_size.width) if(size.width < item_size.width)
size.width = item_size.width; size.width = item_size.width;
} }
@ -687,13 +701,14 @@ namespace nana
pos.y = scr_area.bottom() - static_cast<int>(size.height); pos.y = scr_area.bottom() - static_cast<int>(size.height);
if(pos.y < scr_area.y) pos.y = scr_area.y; if(pos.y < scr_area.y) pos.y = scr_area.y;
auto owner = API::get_owner_window(*widget_); API::calc_window_point(API::get_owner_window(*widget_), pos);
API::calc_window_point(owner, pos);
widget_->move(pos.x, pos.y); widget_->move(pos.x, pos.y);
} }
private: private:
widget *widget_{nullptr}; widget *widget_{nullptr};
paint::graphics *graph_{nullptr}; paint::graphics *graph_{nullptr};
menu_builder* mbuilder_{ nullptr };
menu_type* menu_{ nullptr }; menu_type* menu_{ nullptr };
std::function<void()> fn_close_tree_; std::function<void()> fn_close_tree_;
@ -722,7 +737,7 @@ namespace nana
using item_type = menu_builder::item_type; using item_type = menu_builder::item_type;
menu_window(window wd, bool is_wd_parent_menu, const point& pos, renderer_interface * rdptr) menu_window(window wd, bool is_wd_parent_menu, const point& pos, menu_builder& mbuilder, menu_type& menu_data)
//add a is_wd_parent_menu to determine whether the menu wants the focus. //add a is_wd_parent_menu to determine whether the menu wants the focus.
//if a submenu gets the focus, the program may cause a crash error when the submenu is being destroyed //if a submenu gets the focus, the program may cause a crash error when the submenu is being destroyed
: base_type(wd, false, rectangle(pos, nana::size(2, 2)), appear::bald<appear::floating>()), : base_type(wd, false, rectangle(pos, nana::size(2, 2)), appear::bald<appear::floating>()),
@ -730,8 +745,8 @@ namespace nana
event_focus_{ nullptr } event_focus_{ nullptr }
{ {
caption("nana menu window"); caption("nana menu window");
get_drawer_trigger().close_menu_tree([this]{ this->_m_close_all(); }); get_drawer_trigger().set_run(mbuilder, menu_data, [this]{ this->_m_close_all(); });
get_drawer_trigger().renderer = rdptr;
state_.owner_menubar = state_.self_submenu = false; state_.owner_menubar = state_.self_submenu = false;
state_.auto_popup_submenu = true; state_.auto_popup_submenu = true;
@ -739,7 +754,7 @@ namespace nana
submenu_.object = nullptr; submenu_.object = nullptr;
state_.mouse_pos = API::cursor_position(); state_.mouse_pos = API::cursor_position();
events().mouse_move.connect_unignorable([this]{ events().mouse_move.connect_unignorable([this](const arg_mouse&){
nana::point pos = API::cursor_position(); nana::point pos = API::cursor_position();
if (pos != state_.mouse_pos) if (pos != state_.mouse_pos)
{ {
@ -753,10 +768,8 @@ namespace nana
}); });
} }
void popup(menu_type& menu, bool owner_menubar) void popup(bool owner_menubar)
{ {
get_drawer_trigger().data(menu);
if (!want_focus_) if (!want_focus_)
{ {
API::activate_window(this->parent()); API::activate_window(this->parent());
@ -770,7 +783,7 @@ namespace nana
} }
auto & events = this->events(); auto & events = this->events();
events.destroy.connect_unignorable([this]{ events.destroy.connect_unignorable([this](const arg_destroy&){
_m_destroy(); _m_destroy();
}); });
@ -880,7 +893,7 @@ namespace nana
if ((npos == active) || !menu) if ((npos == active) || !menu)
return; return;
menu_item_type & item = menu->items.at(active); menu_item_type & item = *(menu->items.at(active));
if ((!item.flags.enabled) || item.flags.splitter || item.sub_menu) if ((!item.flags.enabled) || item.flags.splitter || item.sub_menu)
return; return;
@ -891,35 +904,18 @@ namespace nana
} }
else if (checks::option == item.style) else if (checks::option == item.style)
{ {
//Forward Looks for a splitter get_drawer_trigger().mbuilder().checked(active, true);
auto pos = active;
while (pos)
{
if (menu->items.at(--pos).flags.splitter)
break;
}
for (; pos < menu->items.size(); ++pos)
{
menu_item_type & im = menu->items.at(pos);
if (im.flags.splitter) break;
if ((checks::option == im.style) && im.flags.checked)
im.flags.checked = false;
}
item.flags.checked = true;
} }
this->_m_close_all(); //means deleting this; this->_m_close_all(); //means deleting this;
//The deleting operation has moved here, because item.functor.operator()(ip) //The deleting operation has moved here, because item.event_handler.operator()(ip)
//may create a window, which make a killing focus for menu window, if so the close_all //may create a window, which make a killing focus for menu window, if so the close_all
//operation preformences after item.functor.operator()(ip), that would be deleting this object twice! //operation preformences after item.event_handler.operator()(ip), that would be deleting this object twice!
if (item.functor) if (item.event_handler)
{ {
item_type::item_proxy ip(active, item); item_type::item_proxy ip(active, item);
item.functor.operator()(ip); item.event_handler.operator()(ip);
} }
} }
private: private:
@ -1034,7 +1030,7 @@ namespace nana
menu_ptr->gaps = drawer.data()->gaps; menu_ptr->gaps = drawer.data()->gaps;
pos += menu_ptr->gaps; pos += menu_ptr->gaps;
menu_window & mwnd = form_loader<menu_window, false>()(handle(), true, pos, drawer.renderer); menu_window & mwnd = form_loader<menu_window, false>()(handle(), true, pos, drawer.mbuilder(), *menu_ptr);
mwnd.state_.self_submenu = true; mwnd.state_.self_submenu = true;
submenu_.child = &mwnd; submenu_.child = &mwnd;
submenu_.child->submenu_.parent = this; submenu_.child->submenu_.parent = this;
@ -1042,7 +1038,7 @@ namespace nana
API::set_window_z_order(handle(), mwnd.handle(), z_order_action::none); API::set_window_z_order(handle(), mwnd.handle(), z_order_action::none);
mwnd.popup(*menu_ptr, state_.owner_menubar); mwnd.popup(state_.owner_menubar);
drawer.set_sub_window(true); drawer.set_sub_window(true);
if (forced) if (forced)
mwnd.goto_next(true); mwnd.goto_next(true);
@ -1099,7 +1095,7 @@ namespace nana
}; };
drawerbase::menu::menu_builder mbuilder; drawerbase::menu::menu_builder mbuilder;
drawerbase::menu::menu_window * uiobj; drawerbase::menu::menu_window * window_ptr;
std::function<void()> destroy_answer; std::function<void()> destroy_answer;
std::map<std::size_t, info> sub_container; std::map<std::size_t, info> sub_container;
}; };
@ -1107,7 +1103,7 @@ namespace nana
menu::menu() menu::menu()
:impl_(new implement) :impl_(new implement)
{ {
impl_->uiobj = nullptr; impl_->window_ptr = nullptr;
} }
menu::~menu() menu::~menu()
@ -1120,34 +1116,36 @@ namespace nana
delete impl_; delete impl_;
} }
auto menu::append(const std::string& text, const menu::event_fn_t& f) -> item_proxy auto menu::append(const std::string& text, const event_fn_t& callback) -> item_proxy
{ {
impl_->mbuilder.data().items.emplace_back(text, f); impl_->mbuilder.data().items.emplace_back(new item_type(text, callback));
return item_proxy(size() - 1, impl_->mbuilder.data().items.back()); return item_proxy(size() - 1, *impl_->mbuilder.data().items.back());
} }
void menu::append_splitter() void menu::append_splitter()
{ {
impl_->mbuilder.data().items.emplace_back(); impl_->mbuilder.data().items.emplace_back(new item_type);
} }
void menu::clear() void menu::clear()
{ {
internal_scope_guard lock;
impl_->mbuilder.data().items.clear(); impl_->mbuilder.data().items.clear();
} }
void menu::enabled(std::size_t index, bool enable) void menu::enabled(std::size_t index, bool enable)
{ {
impl_->mbuilder.data().items.at(index).flags.enabled = enable; impl_->mbuilder.data().items.at(index)->flags.enabled = enable;
} }
bool menu::enabled(std::size_t index) const bool menu::enabled(std::size_t index) const
{ {
return impl_->mbuilder.data().items.at(index).flags.enabled; return impl_->mbuilder.data().items.at(index)->flags.enabled;
} }
void menu::erase(std::size_t index) void menu::erase(std::size_t index)
{ {
internal_scope_guard lock;
auto & items = impl_->mbuilder.data().items; auto & items = impl_->mbuilder.data().items;
if(index < items.size()) if(index < items.size())
items.erase(items.begin() + index); items.erase(items.begin() + index);
@ -1155,7 +1153,7 @@ namespace nana
void menu::image(std::size_t index, const paint::image& img) void menu::image(std::size_t index, const paint::image& img)
{ {
impl_->mbuilder.data().items.at(index).image = img; impl_->mbuilder.data().items.at(index)->image = img;
} }
bool menu::link(std::size_t index, menu& menu_obj) bool menu::link(std::size_t index, menu& menu_obj)
@ -1196,22 +1194,22 @@ namespace nana
void menu::popup(window wd, int x, int y) void menu::popup(window wd, int x, int y)
{ {
_m_popup(wd, x, y, false); _m_popup(wd, { x, y }, false);
} }
void menu::popup_await(window wd, int x, int y) void menu::popup_await(window wd, int x, int y)
{ {
_m_popup(wd, x, y, false); _m_popup(wd, { x, y }, false);
if (impl_->uiobj) if (impl_->window_ptr)
API::wait_for(impl_->uiobj->handle()); API::wait_for(impl_->window_ptr->handle());
} }
void menu::close() void menu::close()
{ {
if(impl_->uiobj) if (impl_->window_ptr)
{ {
impl_->uiobj->close(); impl_->window_ptr->close();
impl_->uiobj = nullptr; impl_->window_ptr = nullptr;
} }
} }
@ -1227,17 +1225,17 @@ namespace nana
bool menu::checked(std::size_t index) const bool menu::checked(std::size_t index) const
{ {
return impl_->mbuilder.data().items.at(index).flags.checked; return impl_->mbuilder.data().items.at(index)->flags.checked;
} }
void menu::answerer(std::size_t index, const event_fn_t& fn) void menu::answerer(std::size_t index, const event_fn_t& fn)
{ {
impl_->mbuilder.data().items.at(index).functor = fn; impl_->mbuilder.data().items.at(index)->event_handler = fn;
} }
void menu::destroy_answer(const std::function<void()>& fn) void menu::destroy_answer(std::function<void()> fn)
{ {
impl_->destroy_answer = fn; impl_->destroy_answer = std::move(fn);
} }
void menu::gaps(const nana::point& pos) void menu::gaps(const nana::point& pos)
@ -1247,18 +1245,18 @@ namespace nana
void menu::goto_next(bool forward) void menu::goto_next(bool forward)
{ {
if(impl_->uiobj) if (impl_->window_ptr)
impl_->uiobj->goto_next(forward); impl_->window_ptr->goto_next(forward);
} }
bool menu::goto_submen() bool menu::goto_submen()
{ {
return (impl_->uiobj ? impl_->uiobj->submenu(true) : false); return (impl_->window_ptr ? impl_->window_ptr->submenu(true) : false);
} }
bool menu::exit_submenu() bool menu::exit_submenu()
{ {
return (impl_->uiobj ? impl_->uiobj->submenu(false) : false); return (impl_->window_ptr ? impl_->window_ptr->submenu(false) : false);
} }
std::size_t menu::size() const std::size_t menu::size() const
@ -1268,13 +1266,13 @@ namespace nana
int menu::send_shortkey(wchar_t key) int menu::send_shortkey(wchar_t key)
{ {
return (impl_->uiobj ? impl_->uiobj->send_shortkey(key) : 0); return (impl_->window_ptr ? impl_->window_ptr->send_shortkey(key) : 0);
} }
void menu::pick() void menu::pick()
{ {
if (impl_->uiobj) if (impl_->window_ptr)
impl_->uiobj->pick(); impl_->window_ptr->pick();
} }
menu& menu::max_pixels(unsigned px) menu& menu::max_pixels(unsigned px)
@ -1309,19 +1307,19 @@ namespace nana
impl_->mbuilder.renderer(rd); impl_->mbuilder.renderer(rd);
} }
void menu::_m_popup(window wd, int x, int y, bool called_by_menubar) void menu::_m_popup(window wd, const point& pos, bool called_by_menubar)
{ {
if (impl_->mbuilder.data().items.size()) if (impl_->mbuilder.data().items.size())
{ {
close(); close();
impl_->uiobj = &(form_loader<drawerbase::menu::menu_window, false>()(wd, false, point(x, y), &(*impl_->mbuilder.renderer()))); impl_->window_ptr = &(form_loader<drawerbase::menu::menu_window, false>()(wd, false, pos, impl_->mbuilder, impl_->mbuilder.data()));
impl_->uiobj->events().destroy.connect_unignorable([this]{ impl_->window_ptr->events().destroy.connect_unignorable([this](const arg_destroy&){
impl_->uiobj = nullptr; impl_->window_ptr = nullptr;
if (impl_->destroy_answer) if (impl_->destroy_answer)
impl_->destroy_answer(); impl_->destroy_answer();
}); });
impl_->uiobj->popup(impl_->mbuilder.data(), called_by_menubar); impl_->window_ptr->popup(called_by_menubar);
} }
} }
//end class menu //end class menu

View File

@ -20,7 +20,7 @@ namespace nana
public: public:
static void popup(menu& m, window wd, int x, int y) static void popup(menu& m, window wd, int x, int y)
{ {
m._m_popup(wd, x, y, true); m._m_popup(wd, { x, y }, true);
} }
}; };