fix issue of menu item_proxy
This commit is contained in:
parent
e7ce506f5a
commit
445f0ed6de
@ -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_;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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 = ⊂
|
item.sub_menu = ⊂
|
||||||
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
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user