refactor functions

This commit is contained in:
Jinhao 2015-05-01 16:45:05 +08:00
parent 4154c8e132
commit 99564a9161
7 changed files with 253 additions and 268 deletions

View File

@ -1,7 +1,7 @@
/*
* Implementations of Inner Forward Declaration
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -19,7 +19,6 @@
#include "../../paint/graphics.hpp"
#include <map>
#include <algorithm>
namespace nana{
namespace detail
@ -62,12 +61,15 @@ namespace nana{
void umake(window wd)
{
if (wd == nullptr) return;
auto i = std::find_if(keybase_.begin(), keybase_.end(), [wd](const item_type& m){
return (m.handle == wd);
});
if (i != keybase_.end())
keybase_.erase(i);
for (auto i = keybase_.begin(), end = keybase_.end(); i != end; ++i)
{
if (i->handle == wd)
{
keybase_.erase(i);
break;
}
}
}
std::vector<unsigned long> keys(window wd) const

View File

@ -139,16 +139,16 @@ namespace nana
void clear(); ///< Erases all of the items.
/// Closes the menu. It does not destroy the menu; just close the window for the menu.
void close();
void image(std::size_t index, const paint::image& icon);
void check_style(std::size_t index, checks);
void checked(std::size_t index, bool);
bool checked(std::size_t index) const;
void enabled(std::size_t index, bool);///< Enables or disables the mouse or keyboard input for the item.
bool enabled(std::size_t index) const;
void erase(std::size_t index); ///< Removes the item
bool link(std::size_t index, menu& menu_obj);///< Link a menu to the item as a sub menu.
menu * link(std::size_t index); ///< Retrieves a linked sub menu of the item.
menu *create_sub_menu(std::size_t index);
void image(std::size_t pos, const paint::image& icon);
void check_style(std::size_t pos, checks);
void checked(std::size_t pos, bool);
bool checked(std::size_t pos) const;
void enabled(std::size_t pos, bool);///< Enables or disables the mouse or keyboard input for the item.
bool enabled(std::size_t pos) const;
void erase(std::size_t pos); ///< Removes the item
bool link(std::size_t pos, menu& menu_obj);///< Link a menu to the item as a sub menu.
menu * link(std::size_t pos); ///< Retrieves a linked sub menu of the item.
menu *create_sub_menu(std::size_t pos);
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 answerer(std::size_t index, const event_fn_t&); ///< Modify answerer of the specified item.
@ -171,7 +171,6 @@ namespace nana
const pat::cloneable<renderer_interface>& renderer() const;
private:
void _m_destroy_menu_window();
void _m_popup(window, int x, int y, bool called_by_menubar);
private:
implement * impl_;

View File

@ -21,8 +21,6 @@
#include <nana/detail/linux_X11/platform_spec.hpp>
#endif
#include <algorithm>
namespace nana
{
typedef detail::edge_nimbus_renderer<detail::bedrock::core_window_t> edge_nimbus_renderer_t;
@ -351,12 +349,13 @@ namespace nana
{
if(p)
{
auto i = std::find(dynamic_drawing_objects_.begin(), dynamic_drawing_objects_.end(), p);
if (i != dynamic_drawing_objects_.end())
{
delete (*i);
dynamic_drawing_objects_.erase(i);
}
for (auto i = dynamic_drawing_objects_.begin(); i != dynamic_drawing_objects_.end(); ++i)
if (*i == p)
{
delete (*i);
dynamic_drawing_objects_.erase(i);
break;
}
}
}

View File

@ -556,6 +556,7 @@ namespace nana{
{
::EnableWindow(native_wd, true);
::SetActiveWindow(native_wd);
::SetForegroundWindow(native_wd);
}
else
::PostMessage(native_wd, nana::detail::messages::async_activate, 0, 0);

View File

@ -1,7 +1,7 @@
/**
* An Implementation of Place for Layout
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -21,6 +21,7 @@
#include <memory>
#include <limits>
#include <algorithm>
namespace nana
{

View File

@ -16,7 +16,6 @@
#include <nana/system/platform.hpp>
#include <nana/gui/detail/native_window_interface.hpp>
#include <nana/gui/widgets/widget.hpp>
#include <algorithm>
namespace nana
{
@ -54,7 +53,7 @@ namespace API
if (!restrict::window_manager.available(reinterpret_cast<restrict::core_window_t*>(wd)))
return nullptr;
return reinterpret_cast<restrict::core_window_t*>(wd)->together.attached_events;
return reinterpret_cast<restrict::core_window_t*>(wd)->together.events_ptr.get();
}
}//end namespace detail
@ -265,8 +264,20 @@ namespace API
if((wd->thread_id == tid) && (wd->root != root))
{
root = wd->root;
if(roots.cend() == std::find(roots.cbegin(), roots.cend(), root))
for (auto i = roots.cbegin(); i != roots.cend(); ++i)
{
if (*i == root)
{
root = nullptr;
break;
}
}
if (!root)
{
root = wd->root;
roots.push_back(root);
}
}
}

View File

@ -106,7 +106,7 @@ namespace nana
sz.width -= 30;
sz.height -= 2;
graph.rectangle(false, colors::gray_border);
graph.rectangle({ 1, 1, 28, sz.height }, true, { 0xf6, 0xf6, 0xf6 });
graph.rectangle({ 1, 1, 28, sz.height }, true, static_cast<color_rgb>(0xf6f6f6));
graph.rectangle({ 29, 1, sz.width, sz.height }, true, colors::white);
}
@ -122,17 +122,17 @@ namespace nana
nana::point(r.x + r.width - 1, r.y + r.height - 1)
};
graph.set_color({0xc0, 0xdd, 0xfc});
graph.set_color(static_cast<color_rgb>(0xc0ddfc));
for(int i = 0; i < 4; ++i)
graph.set_pixel(points[i].x, points[i].y);
if(at.enabled)
graph.gradual_rectangle(nana::rectangle(r).pare_off(1), { 0xE8, 0xF0, 0xF4 }, { 0xDB,0xEC,0xF4 }, true);
graph.gradual_rectangle(nana::rectangle(r).pare_off(1), static_cast<color_rgb>(0xE8F0F4), static_cast<color_rgb>(0xDBECF4), true);
}
if(at.checked && (checks::none != at.check_style))
{
graph.rectangle(r, false, { 0xCD, 0xD3, 0xE6 });
graph.rectangle(r, false, static_cast<color_rgb>(0xCDD3E6));
::nana::color clr(0xE6, 0xEF, 0xF4);
graph.rectangle(nana::rectangle(r).pare_off(1), true, clr);
@ -363,59 +363,58 @@ namespace nana
bool goto_next(bool forword)
{
state_.nullify_mouse = true;
if(menu_->items.size())
{
std::size_t index = state_.active;
if (menu_->items.empty())
return false;
bool end = false;
while(true)
auto pos = state_.active;
const auto lastpos = menu_->items.size() - 1;
bool end = false;
while(true)
{
if(forword)
{
if(forword)
if(pos == lastpos)
{
if(index == menu_->items.size() - 1)
if (end)
{
if(end == false)
{
end = true;
index = 0;
}
else
{
index = npos;
break;
}
pos = npos;
break;
}
else
++index;
end = true;
pos = 0;
}
else
{
if(index == 0 || index == npos)
{
if(end == false)
{
end = true;
index = menu_->items.size() - 1;
}
else
break;
}
else
--index;
}
if(menu_->items.at(index).flags.splitter == false)
break;
++pos;
}
if(index != npos && index != state_.active)
else
{
state_.active = index;
state_.sub_window = false;
draw();
return true;
if(pos == 0 || pos == npos)
{
if (end)
break;
end = true;
pos = lastpos;
}
else
--pos;
}
if(! menu_->items.at(pos).flags.splitter)
break;
}
if(pos != npos && pos != state_.active)
{
state_.active = pos;
state_.sub_window = false;
draw();
return true;
}
return false;
}
@ -486,30 +485,32 @@ namespace nana
std::size_t index = 0;
for(auto & m : menu_->items)
{
if(std::tolower(m.hotkey) == key)
if (std::tolower(m.hotkey) != key)
{
if(!m.flags.splitter)
{
if(m.sub_menu)
{
state_.active = index;
state_.active_timestamp = nana::system::timestamp();
draw();
API::update_window(*widget_);
return 2;
}
else if(m.flags.enabled)
{
std::move(fn_close_tree_)();
item_proxy ip(index, m);
m.functor.operator()(ip);
return 1;
}
}
break;
++index;
continue;
}
++index;
if(!m.flags.splitter)
{
if(m.sub_menu)
{
state_.active = index;
state_.active_timestamp = nana::system::timestamp();
draw();
API::update_window(*widget_);
return 2;
}
else if(m.flags.enabled)
{
std::move(fn_close_tree_)();
item_proxy ip(index, m);
m.functor.operator()(ip);
return 1;
}
}
break;
}
return 0;
}
@ -529,53 +530,53 @@ namespace nana
int text_top_off = (item_h_px - graph_->text_extent_size(STR("jh({[")).height) / 2;
std::size_t index = 0;
std::size_t pos = 0;
for(auto & m : menu_->items)
{
if(false == m.flags.splitter)
{
renderer_interface::attr attr = _m_make_renderer_attr(index == state_.active, m);
//Draw item background
renderer->item(*graph_, item_r, attr);
//Draw text, the text is transformed from orignal for hotkey character
nana::char_t hotkey;
nana::string::size_type hotkey_pos;
nana::string text = API::transform_shortkey_text(m.text, hotkey, &hotkey_pos);
if(m.image.empty() == false)
renderer->item_image(*graph_, nana::point(item_r.x + 5, item_r.y + (item_h_px - m.image.size().height) / 2), m.image);
renderer->item_text(*graph_, nana::point(item_r.x + 40, item_r.y + text_top_off), text, strpixels, attr);
if(hotkey)
{
m.hotkey = hotkey;
if(m.flags.enabled)
{
unsigned off_w = (hotkey_pos ? graph_->text_extent_size(text, static_cast<unsigned>(hotkey_pos)).width : 0);
nana::size hotkey_size = graph_->text_extent_size(text.c_str() + hotkey_pos, 1);
int x = item_r.x + 40 + off_w;
int y = item_r.y + text_top_off + hotkey_size.height;
graph_->set_color(colors::black);
graph_->line({ x, y }, { x + static_cast<int>(hotkey_size.width) - 1, y });
}
}
if(m.sub_menu)
renderer->sub_arrow(*graph_, nana::point(graph_->width() - 20, item_r.y), item_h_px, attr);
item_r.y += item_r.height + 1;
}
else
if(m.flags.splitter)
{
graph_->set_color(colors::gray_border);
graph_->line({ item_r.x + 40, item_r.y }, { static_cast<int>(graph_->width()) - 1, item_r.y });
item_r.y += 2;
++pos;
continue;
}
renderer_interface::attr attr = _m_make_renderer_attr(pos == state_.active, m);
//Draw item background
renderer->item(*graph_, item_r, attr);
//Draw text, the text is transformed from orignal for hotkey character
nana::char_t hotkey;
nana::string::size_type hotkey_pos;
nana::string text = API::transform_shortkey_text(m.text, hotkey, &hotkey_pos);
if(m.image.empty() == false)
renderer->item_image(*graph_, nana::point(item_r.x + 5, item_r.y + (item_h_px - m.image.size().height) / 2), m.image);
renderer->item_text(*graph_, nana::point(item_r.x + 40, item_r.y + text_top_off), text, strpixels, attr);
if(hotkey)
{
m.hotkey = hotkey;
if(m.flags.enabled)
{
unsigned off_w = (hotkey_pos ? graph_->text_extent_size(text, static_cast<unsigned>(hotkey_pos)).width : 0);
nana::size hotkey_size = graph_->text_extent_size(text.c_str() + hotkey_pos, 1);
int x = item_r.x + 40 + off_w;
int y = item_r.y + text_top_off + hotkey_size.height;
graph_->set_color(colors::black);
graph_->line({ x, y }, { x + static_cast<int>(hotkey_size.width) - 1, y });
}
}
++index;
if(m.sub_menu)
renderer->sub_arrow(*graph_, nana::point(graph_->width() - 20, item_r.y), item_h_px, attr);
item_r.y += item_r.height + 1;
++pos;
}
}
private:
@ -592,9 +593,9 @@ namespace nana
std::size_t _m_get_index_by_pos(int x, int y) const
{
if( (x < static_cast<int>(detail_.border.x)) ||
(x > static_cast<int>(graph_->width() - detail_.border.x)) ||
(x > static_cast<int>(graph_->width()) - static_cast<int>(detail_.border.x)) ||
(y < static_cast<int>(detail_.border.y)) ||
(y > static_cast<int>(graph_->height() - detail_.border.y)))
(y > static_cast<int>(graph_->height()) - static_cast<int>(detail_.border.y)))
return npos;
int pos = detail_.border.y;
@ -662,11 +663,11 @@ namespace nana
auto scr_area = screen().from_point(detail_.monitor_pos).workarea();
if(pos.x + static_cast<int>(size.width) > scr_area.right())
pos.x = static_cast<int>(scr_area.x + scr_area.width - size.width);
pos.x = scr_area.right() - static_cast<int>(size.width);
if(pos.x < scr_area.x) pos.x = scr_area.x;
if(pos.y + static_cast<int>(size.height) > scr_area.bottom())
pos.y = static_cast<int>(scr_area.y + scr_area.height - size.height);
pos.y = scr_area.bottom() - static_cast<int>(size.height);
if(pos.y < scr_area.y) pos.y = scr_area.y;
auto owner = API::get_owner_window(*widget_);
@ -705,7 +706,7 @@ namespace nana
menu_window(window wd, const point& pos, renderer_interface * rdptr)
: base_type(wd, false, rectangle(pos, nana::size(2, 2)), appear::bald<appear::floating>()),
want_focus_(nullptr == wd),
want_focus_(nullptr == wd || (API::focus_window() != wd)),
event_focus_(nullptr)
{
caption(STR("nana menu window"));
@ -729,11 +730,6 @@ namespace nana
API::activate_window(this->parent());
API::take_active(this->handle(), false, nullptr);
}
else
{
activate();
focus();
}
if(submenu_.parent == nullptr)
{
@ -753,14 +749,6 @@ namespace nana
pick();
});
if (want_focus_)
{
event_focus_ = events().focus.connect_unignorable([this](const arg_focus& arg)
{
_m_focus_changed(arg);
});
}
timer_.interval(100);
timer_.elapse([this]{
this->_m_check_repeatly();
@ -768,6 +756,30 @@ namespace nana
timer_.start();
show();
if (want_focus_)
{
event_focus_ = events().focus.connect_unignorable([this](const arg_focus& arg)
{
//when the focus of the menu window is losing, close the menu.
//But here is not every menu window may have focus event installed,
//It is only installed when the owner of window is the desktop window.
if (false == arg.getting && (arg.receiver != API::root(*this)))
{
for (auto child = submenu_.child; child; child = child->submenu_.child)
{
if (API::root(child->handle()) == arg.receiver)
return;
}
_m_close_all();
}
});
focus();
activate();
}
}
void goto_next(bool forward)
@ -783,39 +795,33 @@ namespace nana
API::update_window(object->handle());
}
bool goto_submenu()
bool submenu(bool enter)
{
menu_window * object = this;
while(object->submenu_.child)
while (object->submenu_.child)
object = object->submenu_.child;
state_.auto_popup_submenu = false;
if (enter)
{
if (object->submenu_.parent)
{
auto & sub = object->submenu_.parent->submenu_;
sub.child = nullptr;
sub.object = nullptr;
object->close();
return true;
}
return false;
}
nana::point pos;
menu_type * sbm = object->get_drawer_trigger().retrive_sub_menu(pos, 0);
return object->_m_show_submenu(sbm, pos, true);
}
bool exit_submenu()
{
menu_window * object =this;
while(object->submenu_.child)
object = object->submenu_.child;
state_.auto_popup_submenu = false;
if (object->submenu_.parent)
{
auto & sub = object->submenu_.parent->submenu_;
sub.child = nullptr;
sub.object = nullptr;
object->close();
return true;
}
return false;
}
int send_shortkey(nana::char_t key)
{
menu_window * object = this;
@ -832,62 +838,52 @@ namespace nana
object = object->submenu_.child;
auto active = object->get_drawer_trigger().active();
if (active != npos)
auto * menu = object->get_drawer_trigger().data();
if ((npos == active) || !menu)
return;
menu_item_type & item = menu->items.at(active);
if (item.flags.splitter == false && item.sub_menu == nullptr)
{
auto * menu = object->get_drawer_trigger().data();
if (menu)
//There is a situation that menu will not call functor if the item style is check_option
//and it is checked before clicking.
bool call_functor = true;
if (checks::highlight == item.style)
{
menu_item_type & item = menu->items.at(active);
if (item.flags.splitter == false && item.sub_menu == nullptr)
item.flags.checked = !item.flags.checked;
}
else if (checks::option == item.style)
{
//Forward Looks for a splitter
auto pos = active;
while (pos)
{
//There is a situation that menu will not call functor if the item style is check_option
//and it is checked before clicking.
bool call_functor = true;
if (checks::highlight == item.style)
{
item.flags.checked = !item.flags.checked;
}
else if (checks::option == item.style)
{
if (active > 0)
{
//clear the checked state in front of active if it is check_option.
auto i = active;
do
{
--i;
menu_item_type & im = menu->items.at(i);
if (im.flags.splitter) break;
if (checks::option == im.style && im.flags.checked)
im.flags.checked = false;
} while (i);
}
for (auto i = active + 1; i < menu->items.size(); ++i)
{
menu_item_type & im = menu->items.at(i);
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;
//The deleting operation has moved here, because item.functor.operator()(ip)
//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!
if (call_functor && item.flags.enabled && item.functor)
{
item_type::item_proxy ip(active, item);
item.functor.operator()(ip);
}
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;
//The deleting operation has moved here, because item.functor.operator()(ip)
//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!
if (call_functor && item.flags.enabled && item.functor)
{
item_type::item_proxy ip(active, item);
item.functor.operator()(ip);
}
}
}
@ -943,50 +939,29 @@ namespace nana
}
}
//when the focus of the menu window is losing, close the menu.
//But here is not every menu window may have focus event installed,
//It is only installed when the owner of window is the desktop window.
void _m_focus_changed(const arg_focus& arg)
{
if (false == arg.getting)
{
for (auto child = submenu_.child; child; child = child->submenu_.child)
{
if (API::root(child->handle()) == arg.receiver)
return;
}
_m_close_all();
}
}
void _m_key_down(const arg_keyboard& arg)
{
switch(arg.key)
{
case keyboard::os_arrow_up:
this->goto_next(false);
break;
case keyboard::os_arrow_down:
this->goto_next(true);
this->goto_next(keyboard::os_arrow_down == arg.key);
break;
case keyboard::os_arrow_left:
this->exit_submenu();
break;
case keyboard::os_arrow_right:
this->goto_submenu();
this->submenu(keyboard::os_arrow_right == arg.key);
break;
case keyboard::enter:
this->pick();
break;
default:
if(2 != send_shortkey(arg.key))
if (2 != send_shortkey(arg.key))
{
if(API::empty_window(*this) == false)
if (API::empty_window(*this) == false)
close();
}
else
goto_submenu();
this->submenu(true);
}
}
@ -1165,7 +1140,7 @@ namespace nana
{
if(impl_->mbuilder.set_sub_menu(index, menu_obj.impl_->mbuilder.data()))
{
implement::info& minfo = impl_->sub_container[index];
auto& minfo = impl_->sub_container[index];
minfo.handle = &menu_obj;
minfo.kill = false;
return true;
@ -1184,9 +1159,10 @@ namespace nana
menu *menu::create_sub_menu(std::size_t index)
{
menu * sub = new menu;
if(link(index, *sub))
if (this->link(index, *sub))
{
implement::info& minfo = impl_->sub_container[index];
auto& minfo = impl_->sub_container[index];
minfo.handle = sub;
minfo.kill = true;
return sub;
@ -1255,12 +1231,12 @@ namespace nana
bool menu::goto_submen()
{
return (impl_->uiobj ? impl_->uiobj->goto_submenu() : false);
return (impl_->uiobj ? impl_->uiobj->submenu(true) : false);
}
bool menu::exit_submenu()
{
return (impl_->uiobj ? impl_->uiobj->exit_submenu() : false);
return (impl_->uiobj ? impl_->uiobj->submenu(false) : false);
}
std::size_t menu::size() const
@ -1311,21 +1287,17 @@ namespace nana
impl_->mbuilder.renderer(rd);
}
void menu::_m_destroy_menu_window()
{
impl_->uiobj = nullptr;
if(impl_->destroy_answer)
impl_->destroy_answer();
}
void menu::_m_popup(window wd, int x, int y, bool called_by_menubar)
{
if (impl_->mbuilder.data().items.size())
{
close();
impl_->uiobj = &(form_loader<drawerbase::menu::menu_window, false>()(wd, point(x, y), &(*impl_->mbuilder.renderer())));
impl_->uiobj->events().destroy.connect_unignorable([this]{
_m_destroy_menu_window();
impl_->uiobj = nullptr;
if (impl_->destroy_answer)
impl_->destroy_answer();
});
impl_->uiobj->popup(impl_->mbuilder.data(), called_by_menubar);
}