Merge remote-tracking branch 'cnjinhao/hotfix-1.5.4' into hotfix-1.5.4

This commit is contained in:
qPCR4vir 2017-09-04 22:09:05 +02:00
commit 85824a8caf
17 changed files with 569 additions and 373 deletions

View File

@ -58,7 +58,7 @@ matrix:
before_install:
- git clone --depth=1 --branch=develop https://github.com/qPCR4vir/nana-demo.git ../nana-demo
- export PATH="$HOME/bin:$PATH"
- mkdir ~/bin
#- mkdir ~/bin #it seemd that a bin already exists from 20170901
- wget --no-check-certificate --no-clobber -O /tmp/tools/cmake https://cmake.org/files/v3.4/cmake-3.4.0-rc3-Linux-x86_64.sh || true
- chmod -R +x /tmp/tools

View File

@ -91,9 +91,10 @@ namespace detail
void manage_form_loader(core_window_t*, bool insert_or_remove);
public:
bool emit(event_code, core_window_t*, const event_arg&, bool ask_update, thread_context*);
// if 'bForce__EmitInternal', then ONLY internal (widget's) events are processed (even through explicit filtering)
bool emit(event_code, core_window_t*, const event_arg&, bool ask_update, thread_context*, const bool bForce__EmitInternal = false);
private:
void _m_emit_core(event_code, core_window_t*, bool draw_only, const event_arg&);
void _m_emit_core(event_code, core_window_t*, bool draw_only, const event_arg&, const bool bForce__EmitInternal);
void _m_event_filter(event_code, core_window_t*, thread_context*);
private:
static bedrock bedrock_object;

View File

@ -17,6 +17,7 @@
#include "general_events.hpp"
#include <nana/paint/graphics.hpp>
#include <functional>
#include <vector>
namespace nana
{
@ -27,6 +28,25 @@ namespace nana
class drawer;
}
class drawer_trigger;
class event_filter_status
{
public:
event_filter_status();
event_filter_status(const event_filter_status& rOther);
event_filter_status(const unsigned evt_disabled_);
const event_filter_status& operator=(const event_filter_status& rOther);
const event_filter_status& operator=(const unsigned evt_disabled_);
bool operator[](const nana::event_code evt_code) const;
bool operator==(const event_filter_status& rOther) const;
bool operator!=(const event_filter_status& rOther) const;
private:
unsigned evt_disabled_;
friend class drawer_trigger;
};
class drawer_trigger
{
friend class detail::drawer;
@ -70,11 +90,19 @@ namespace nana
virtual void key_release(graph_reference, const arg_keyboard&);
virtual void shortkey(graph_reference, const arg_keyboard&);
void filter_event(const event_code evt_code, const bool bDisabled);
void filter_event(const std::vector<event_code> evt_codes, const bool bDisabled);
void filter_event(const event_filter_status& evt_all_states);
bool filter_event(const event_code evt_code);
event_filter_status filter_event();
void clear_filter();
private:
void _m_reset_overrided();
bool _m_overrided(event_code) const;
private:
unsigned overrided_{ 0xFFFFFFFF };
unsigned evt_disabled_{ 0 }; // bit set if event is filtered
};
namespace detail
@ -99,23 +127,23 @@ namespace nana
void bind(basic_window*);
void typeface_changed();
void click(const arg_click&);
void dbl_click(const arg_mouse&);
void mouse_enter(const arg_mouse&);
void mouse_move(const arg_mouse&);
void mouse_leave(const arg_mouse&);
void mouse_down(const arg_mouse&);
void mouse_up(const arg_mouse&);
void mouse_wheel(const arg_wheel&);
void mouse_dropfiles(const arg_dropfiles&);
void resizing(const arg_resizing&);
void resized(const arg_resized&);
void move(const arg_move&);
void focus(const arg_focus&);
void key_press(const arg_keyboard&);
void key_char(const arg_keyboard&);
void key_release(const arg_keyboard&);
void shortkey(const arg_keyboard&);
void click(const arg_click&, const bool);
void dbl_click(const arg_mouse&, const bool);
void mouse_enter(const arg_mouse&, const bool);
void mouse_move(const arg_mouse&, const bool);
void mouse_leave(const arg_mouse&, const bool);
void mouse_down(const arg_mouse&, const bool);
void mouse_up(const arg_mouse&, const bool);
void mouse_wheel(const arg_wheel&, const bool);
void mouse_dropfiles(const arg_dropfiles&, const bool);
void resizing(const arg_resizing&, const bool);
void resized(const arg_resized&, const bool);
void move(const arg_move&, const bool);
void focus(const arg_focus&, const bool);
void key_press(const arg_keyboard&, const bool);
void key_char(const arg_keyboard&, const bool);
void key_release(const arg_keyboard&, const bool);
void shortkey(const arg_keyboard&, const bool);
void map(window, bool forced, const rectangle* update_area = nullptr); //Copy the root buffer to screen
void refresh();
drawer_trigger* realizer() const;
@ -130,7 +158,7 @@ namespace nana
method_state& _m_mth_state(int pos);
template<typename Arg, typename Mfptr>
void _m_emit(event_code evt_code, const Arg& arg, Mfptr mfptr)
void _m_emit(event_code evt_code, const Arg& arg, Mfptr mfptr, const bool bForce__EmitInternal)
{
const int pos = static_cast<int>(evt_code);
@ -139,17 +167,22 @@ namespace nana
if (realizer && (method_state::not_overrided != mth_state))
{
const bool bFiltered = !bForce__EmitInternal && realizer->filter_event(evt_code);
if (method_state::pending == mth_state)
{
(realizer->*mfptr)(graphics, arg);
if (!bFiltered)
(realizer->*mfptr)(graphics, arg);
//Check realizer, when the window is closed in that event handler, the drawer will be
//detached and realizer will be a nullptr
if (realizer)
mth_state = (realizer->_m_overrided(evt_code) ? method_state::overrided : method_state::not_overrided);
}
else
(realizer->*mfptr)(graphics, arg);
{
if (!bFiltered)
(realizer->*mfptr)(graphics, arg);
}
_m_effect_bground_subsequent();
}

View File

@ -120,8 +120,13 @@ namespace API
namespace detail
{
general_events* get_general_events(window);
// emits both internal and external event (internal event can be filtered)
bool emit_event(event_code, window, const ::nana::event_arg&);
// explicitly emits internal event (internal event not to be filtered)
bool emit_internal_event(event_code, window, const ::nana::event_arg&);
class enum_widgets_function_base
{
public:
@ -255,6 +260,12 @@ namespace API
return detail::emit_event(evt_code, wd, arg);
}
template<typename EventArg, typename std::enable_if<std::is_base_of< ::nana::event_arg, EventArg>::value>::type* = nullptr>
bool emit_internal_event(event_code evt_code, window wd, const EventArg& arg)
{
return detail::emit_internal_event(evt_code, wd, arg);
}
void umake_event(event_handle);
template<typename Widget = ::nana::widget>

View File

@ -181,6 +181,11 @@ namespace nana
void renderer(const pat::cloneable<renderer_interface>&); ///< Sets a user-defined renderer.
const pat::cloneable<renderer_interface>& renderer() const;
/// Returns the handle of menu window
/**
* @return handle of menu window, nullptr if the menu hasn't been popped up.
*/
window handle() const;
private:
void _m_popup(window, const point& position, bool called_by_menubar);
private:

View File

@ -1,7 +1,7 @@
/*
* A Menubar implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2009-2014 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2009-2017 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -58,12 +58,12 @@ namespace nana
: public drawer_trigger
{
class itembase;
struct essence;
public:
trigger();
~trigger();
nana::menu* push_back(const std::string&);
nana::menu* at(size_t) const;
std::size_t size() const;
essence& ess() const;
private:
void attached(widget_reference, graph_reference) override;
void refresh(graph_reference) override;
@ -76,38 +76,9 @@ namespace nana
void key_release(graph_reference, const arg_keyboard&) override;
void shortkey(graph_reference, const arg_keyboard&) override;
private:
void _m_move(bool to_left);
bool _m_popup_menu();
void _m_total_close();
bool _m_close_menu();
std::size_t _m_item_by_pos(const ::nana::point&);
bool _m_track_mouse(const ::nana::point&);
void _m_move(graph_reference, bool to_left);
private:
widget *widget_;
paint::graphics *graph_;
itembase* items_;
struct state_type
{
enum behavior_t
{
behavior_none, behavior_focus, behavior_menu,
};
state_type();
std::size_t active;
behavior_t behavior;
bool menu_active;
bool passive_close;
bool nullify_mouse;
nana::menu *menu;
nana::point mouse_pos;
}state_;
essence * const ess_;
};
}//end namespace menubar
}//end namespace drawerbase
@ -126,6 +97,16 @@ namespace nana
menu& push_back(const std::string&); ///< Appends a new (empty) menu.
menu& at(size_t index) const; ///< Gets the menu specified by index.
std::size_t length() const; ///< Number of menus.
/// Deselects the menu
/**
* If a menu is popped up, the menu deselects the item and close the popuped menu.
* @return true if an item is deselected, false otherwise.
*/
bool cancel();
/// Determines the mouse is hovered on the menubar or its popped menu.
bool hovered() const;
private:
::nana::event_handle evt_resized_{nullptr};
};//end class menubar

View File

@ -206,7 +206,7 @@ namespace nana
API::dev::attach_drawer(*this, trigger_);
if(visible)
API::show_window(handle_, true);
this->_m_complete_creation();
}
return (this->empty() == false);
@ -227,6 +227,39 @@ namespace nana
{
return *scheme_;
}
// disables or re-enables internal handling of event within base-widget
void filter_event(const event_code evt_code, const bool bDisabled)
{
trigger_.filter_event(evt_code, bDisabled);
}
void filter_event(const std::vector<event_code> evt_codes, const bool bDisabled)
{
trigger_.filter_event(evt_codes, bDisabled);
}
void filter_event(const event_filter_status& evt_all_states)
{
trigger_.filter_event(evt_all_states);
}
void clear_filter()
{
trigger_.clear_filter();
}
// reads status of if event is filtered
bool filter_event(const event_code evt_code)
{
return trigger_.filter_event(evt_code);
}
event_filter_status filter_event()
{
return trigger_.filter_event();
}
protected:
DrawerTrigger& get_drawer_trigger()
{

View File

@ -379,11 +379,13 @@ namespace nana
return pi_data_->scheme;
}
void bedrock::_m_emit_core(event_code evt_code, core_window_t* wd, bool draw_only, const ::nana::event_arg& event_arg)
void bedrock::_m_emit_core(event_code evt_code, core_window_t* wd, bool draw_only, const ::nana::event_arg& event_arg, const bool bForce__EmitInternal)
{
auto retain = wd->annex.events_ptr;
auto evts_ptr = retain.get();
// if 'bForce__EmitInternal', omit user defined events
const bool bProcess__External_event = !draw_only && !bForce__EmitInternal;
switch (evt_code)
{
case event_code::click:
@ -394,9 +396,9 @@ namespace nana
{
//enable refreshing flag, this is a RAII class for exception-safe
flag_guard fguard(this, wd);
wd->drawer.click(*arg);
wd->drawer.click(*arg, bForce__EmitInternal);
}
if (!draw_only)
if (bProcess__External_event)
evts_ptr->click.emit(*arg, reinterpret_cast<window>(wd));
}
}
@ -412,7 +414,7 @@ namespace nana
if (nullptr == arg)
return;
void(::nana::detail::drawer::*drawer_event_fn)(const arg_mouse&);
void(::nana::detail::drawer::*drawer_event_fn)(const arg_mouse&, const bool);
::nana::basic_event<arg_mouse>* evt_addr;
switch (evt_code)
@ -448,10 +450,10 @@ namespace nana
{
//enable refreshing flag, this is a RAII class for exception-safe
flag_guard fguard(this, wd);
(wd->drawer.*drawer_event_fn)(*arg);
(wd->drawer.*drawer_event_fn)(*arg, bForce__EmitInternal);
}
if (!draw_only)
if (bProcess__External_event)
evt_addr->emit(*arg, reinterpret_cast<window>(wd));
break;
}
@ -463,10 +465,10 @@ namespace nana
{
//enable refreshing flag, this is a RAII class for exception-safe
flag_guard fguard(this, wd);
wd->drawer.mouse_wheel(*arg);
wd->drawer.mouse_wheel(*arg, bForce__EmitInternal);
}
if (!draw_only)
if (bProcess__External_event)
evts_ptr->mouse_wheel.emit(*arg, reinterpret_cast<window>(wd));
}
break;
@ -480,7 +482,7 @@ namespace nana
if (nullptr == arg)
return;
void(::nana::detail::drawer::*drawer_event_fn)(const arg_keyboard&);
void(::nana::detail::drawer::*drawer_event_fn)(const arg_keyboard&, const bool);
::nana::basic_event<arg_keyboard>* evt_addr;
switch (evt_code)
@ -507,15 +509,15 @@ namespace nana
{
//enable refreshing flag, this is a RAII class for exception-safe
flag_guard fguard(this, wd);
(wd->drawer.*drawer_event_fn)(*arg);
(wd->drawer.*drawer_event_fn)(*arg, bForce__EmitInternal);
}
if (!draw_only)
if (bProcess__External_event)
evt_addr->emit(*arg, reinterpret_cast<window>(wd));
break;
}
case event_code::expose:
if (!draw_only)
if (bProcess__External_event)
{
auto arg = dynamic_cast<const arg_expose*>(&event_arg);
if (arg)
@ -530,9 +532,9 @@ namespace nana
{
//enable refreshing flag, this is a RAII class for exception-safe
flag_guard fguard(this, wd);
wd->drawer.focus(*arg);
wd->drawer.focus(*arg, bForce__EmitInternal);
}
if (!draw_only)
if (bProcess__External_event)
evts_ptr->focus.emit(*arg, reinterpret_cast<window>(wd));
}
break;
@ -545,9 +547,9 @@ namespace nana
{
//enable refreshing flag, this is a RAII class for exception-safe
flag_guard fguard(this, wd);
wd->drawer.move(*arg);
wd->drawer.move(*arg, bForce__EmitInternal);
}
if (!draw_only)
if (bProcess__External_event)
evts_ptr->move.emit(*arg, reinterpret_cast<window>(wd));
}
break;
@ -560,9 +562,9 @@ namespace nana
{
//enable refreshing flag, this is a RAII class for exception-safe
flag_guard fguard(this, wd);
wd->drawer.resizing(*arg);
wd->drawer.resizing(*arg, bForce__EmitInternal);
}
if (!draw_only)
if (bProcess__External_event)
evts_ptr->resizing.emit(*arg, reinterpret_cast<window>(wd));
}
break;
@ -575,15 +577,15 @@ namespace nana
{
//enable refreshing flag, this is a RAII class for exception-safe
flag_guard fguard(this, wd);
wd->drawer.resized(*arg);
wd->drawer.resized(*arg, bForce__EmitInternal);
}
if (!draw_only)
if (bProcess__External_event)
evts_ptr->resized.emit(*arg, reinterpret_cast<window>(wd));
}
break;
}
case event_code::unload:
if (!draw_only)
if (bProcess__External_event)
{
auto arg = dynamic_cast<const arg_unload*>(&event_arg);
if (arg && (wd->other.category == category::flags::root))
@ -595,7 +597,7 @@ namespace nana
}
break;
case event_code::destroy:
if (!draw_only)
if (bProcess__External_event)
{
auto arg = dynamic_cast<const arg_destroy*>(&event_arg);
if (arg)

View File

@ -232,7 +232,7 @@ namespace detail
//No implementation for Linux
}
bool bedrock::emit(event_code evt_code, core_window_t* wd, const ::nana::event_arg& arg, bool ask_update, thread_context* thrd)
bool bedrock::emit(event_code evt_code, core_window_t* wd, const ::nana::event_arg& arg, bool ask_update, thread_context* thrd, const bool bForce__EmitInternal)
{
if(wd_manager().available(wd) == false)
return false;
@ -248,7 +248,7 @@ namespace detail
if(wd->other.upd_state == core_window_t::update_state::none)
wd->other.upd_state = core_window_t::update_state::lazy;
_m_emit_core(evt_code, wd, false, arg);
_m_emit_core(evt_code, wd, false, arg, bForce__EmitInternal);
//A child of wd may not be drawn if it was out of wd's range before wd resized,
//so refresh all children of wd when a resized occurs.
@ -396,7 +396,7 @@ namespace detail
}
template<typename Arg>
void draw_invoker(void(::nana::detail::drawer::*event_ptr)(const Arg&), basic_window* wd, const Arg& arg, bedrock::thread_context* thrd)
void draw_invoker(void(::nana::detail::drawer::*event_ptr)(const Arg&, const bool), basic_window* wd, const Arg& arg, bedrock::thread_context* thrd)
{
if(bedrock::instance().wd_manager().available(wd) == false)
return;
@ -410,7 +410,7 @@ namespace detail
if(wd->other.upd_state == basic_window::update_state::none)
wd->other.upd_state = basic_window::update_state::lazy;
(wd->drawer.*event_ptr)(arg);
(wd->drawer.*event_ptr)(arg, false);
if(thrd) thrd->event_window = pre_wd;
}

View File

@ -755,7 +755,7 @@ namespace detail
}
template<typename Arg>
void draw_invoker(void (::nana::detail::drawer::*event_ptr)(const Arg&), basic_window* wd, const Arg& arg, bedrock::thread_context* thrd)
void draw_invoker(void (::nana::detail::drawer::*event_ptr)(const Arg&, const bool), basic_window* wd, const Arg& arg, bedrock::thread_context* thrd)
{
if (bedrock::instance().wd_manager().available(wd) == false)
return;
@ -770,7 +770,7 @@ namespace detail
if (wd->other.upd_state == basic_window::update_state::none)
wd->other.upd_state = basic_window::update_state::lazy;
(wd->drawer.*event_ptr)(arg);
(wd->drawer.*event_ptr)(arg, false);
if (thrd) thrd->event_window = prev_event_wd;
}
@ -1626,7 +1626,7 @@ namespace detail
}
}
bool bedrock::emit(event_code evt_code, core_window_t* wd, const ::nana::event_arg& arg, bool ask_update, thread_context* thrd)
bool bedrock::emit(event_code evt_code, core_window_t* wd, const ::nana::event_arg& arg, bool ask_update, thread_context* thrd, const bool bForce__EmitInternal)
{
if (wd_manager().available(wd) == false)
return false;
@ -1642,7 +1642,7 @@ namespace detail
if (wd->other.upd_state == core_window_t::update_state::none)
wd->other.upd_state = core_window_t::update_state::lazy;
_m_emit_core(evt_code, wd, false, arg);
_m_emit_core(evt_code, wd, false, arg, bForce__EmitInternal);
bool good_wd = false;
if (wd_manager().available(wd))

View File

@ -128,8 +128,88 @@ namespace nana
return 0 != (overrided_ & (1 << static_cast<int>(evt_code)));
}
void drawer_trigger::filter_event(const event_code evt_code, const bool bDisabled)
{
if (bDisabled)
evt_disabled_ |= 1 << static_cast<int>(evt_code); // set
else
evt_disabled_ &= ~(1 << static_cast<int>(evt_code)); // clear
}
void drawer_trigger::filter_event(const std::vector<event_code> evt_codes, const bool bDisabled)
{
const auto it_end = evt_codes.end();
for (auto it = evt_codes.begin(); it != it_end; it++)
filter_event(*it, bDisabled);
}
void drawer_trigger::filter_event(const event_filter_status& evt_all_states)
{
evt_disabled_ = evt_all_states.evt_disabled_;
}
bool drawer_trigger::filter_event(const event_code evt_code)
{
return static_cast<bool>((evt_disabled_ >> static_cast<int>(evt_code)) & 1);
}
event_filter_status drawer_trigger::filter_event()
{
return event_filter_status(evt_disabled_);
}
void drawer_trigger::clear_filter()
{
for (int i = 0; i < static_cast<int>(nana::event_code::end); i++)
filter_event(static_cast<nana::event_code>(i), false);
}
//end class drawer_trigger
//class event_filter_status
event_filter_status::event_filter_status()
{
evt_disabled_ = 0;
}
event_filter_status::event_filter_status(const event_filter_status& rOther)
{
this->evt_disabled_ = rOther.evt_disabled_;
}
event_filter_status::event_filter_status(const unsigned evt_disabled_)
{
this->evt_disabled_ = evt_disabled_;
}
bool event_filter_status::operator[](const nana::event_code evt_code) const
{
return static_cast<bool>((evt_disabled_ >> static_cast<int>(evt_code)) & 1);
}
bool event_filter_status::operator==(const event_filter_status& rOther) const
{
return evt_disabled_ == rOther.evt_disabled_;
}
bool event_filter_status::operator!=(const event_filter_status& rOther) const
{
return evt_disabled_ != rOther.evt_disabled_;
}
const event_filter_status& event_filter_status::operator=(const event_filter_status& rOther)
{
evt_disabled_ = rOther.evt_disabled_;
return *this;
}
const event_filter_status& event_filter_status::operator=(const unsigned evt_disabled_)
{
this->evt_disabled_ = evt_disabled_;
return *this;
}
//end of class event_filter_status
namespace detail
{
typedef bedrock bedrock_type;
@ -174,89 +254,89 @@ namespace nana
data_impl_->realizer->typeface_changed(graphics);
}
void drawer::click(const arg_click& arg)
void drawer::click(const arg_click& arg, const bool bForce__EmitInternal)
{
_m_emit(event_code::click, arg, &drawer_trigger::click);
_m_emit(event_code::click, arg, &drawer_trigger::click, bForce__EmitInternal);
}
void drawer::dbl_click(const arg_mouse& arg)
void drawer::dbl_click(const arg_mouse& arg, const bool bForce__EmitInternal)
{
_m_emit(event_code::dbl_click, arg, &drawer_trigger::dbl_click);
_m_emit(event_code::dbl_click, arg, &drawer_trigger::dbl_click, bForce__EmitInternal);
}
void drawer::mouse_enter(const arg_mouse& arg)
void drawer::mouse_enter(const arg_mouse& arg, const bool bForce__EmitInternal)
{
_m_emit(event_code::mouse_enter, arg, &drawer_trigger::mouse_enter);
_m_emit(event_code::mouse_enter, arg, &drawer_trigger::mouse_enter, bForce__EmitInternal);
}
void drawer::mouse_move(const arg_mouse& arg)
void drawer::mouse_move(const arg_mouse& arg, const bool bForce__EmitInternal)
{
_m_emit(event_code::mouse_move, arg, &drawer_trigger::mouse_move);
_m_emit(event_code::mouse_move, arg, &drawer_trigger::mouse_move, bForce__EmitInternal);
}
void drawer::mouse_leave(const arg_mouse& arg)
void drawer::mouse_leave(const arg_mouse& arg, const bool bForce__EmitInternal)
{
_m_emit(event_code::mouse_leave, arg, &drawer_trigger::mouse_leave);
_m_emit(event_code::mouse_leave, arg, &drawer_trigger::mouse_leave, bForce__EmitInternal);
}
void drawer::mouse_down(const arg_mouse& arg)
void drawer::mouse_down(const arg_mouse& arg, const bool bForce__EmitInternal)
{
_m_emit(event_code::mouse_down, arg, &drawer_trigger::mouse_down);
_m_emit(event_code::mouse_down, arg, &drawer_trigger::mouse_down, bForce__EmitInternal);
}
void drawer::mouse_up(const arg_mouse& arg)
void drawer::mouse_up(const arg_mouse& arg, const bool bForce__EmitInternal)
{
_m_emit(event_code::mouse_up, arg, &drawer_trigger::mouse_up);
_m_emit(event_code::mouse_up, arg, &drawer_trigger::mouse_up, bForce__EmitInternal);
}
void drawer::mouse_wheel(const arg_wheel& arg)
void drawer::mouse_wheel(const arg_wheel& arg, const bool bForce__EmitInternal)
{
_m_emit(event_code::mouse_wheel, arg, &drawer_trigger::mouse_wheel);
_m_emit(event_code::mouse_wheel, arg, &drawer_trigger::mouse_wheel, bForce__EmitInternal);
}
void drawer::mouse_dropfiles(const arg_dropfiles& arg)
void drawer::mouse_dropfiles(const arg_dropfiles& arg, const bool bForce__EmitInternal)
{
_m_emit(event_code::mouse_drop, arg, &drawer_trigger::mouse_dropfiles);
_m_emit(event_code::mouse_drop, arg, &drawer_trigger::mouse_dropfiles, bForce__EmitInternal);
}
void drawer::resizing(const arg_resizing& arg)
void drawer::resizing(const arg_resizing& arg, const bool bForce__EmitInternal)
{
_m_emit(event_code::resizing, arg, &drawer_trigger::resizing);
_m_emit(event_code::resizing, arg, &drawer_trigger::resizing, bForce__EmitInternal);
}
void drawer::resized(const arg_resized& arg)
void drawer::resized(const arg_resized& arg, const bool bForce__EmitInternal)
{
_m_emit(event_code::resized, arg, &drawer_trigger::resized);
_m_emit(event_code::resized, arg, &drawer_trigger::resized, bForce__EmitInternal);
}
void drawer::move(const arg_move& arg)
void drawer::move(const arg_move& arg, const bool bForce__EmitInternal)
{
_m_emit(event_code::move, arg, &drawer_trigger::move);
_m_emit(event_code::move, arg, &drawer_trigger::move, bForce__EmitInternal);
}
void drawer::focus(const arg_focus& arg)
void drawer::focus(const arg_focus& arg, const bool bForce__EmitInternal)
{
_m_emit(event_code::focus, arg, &drawer_trigger::focus);
_m_emit(event_code::focus, arg, &drawer_trigger::focus, bForce__EmitInternal);
}
void drawer::key_press(const arg_keyboard& arg)
void drawer::key_press(const arg_keyboard& arg, const bool bForce__EmitInternal)
{
_m_emit(event_code::key_press, arg, &drawer_trigger::key_press);
_m_emit(event_code::key_press, arg, &drawer_trigger::key_press, bForce__EmitInternal);
}
void drawer::key_char(const arg_keyboard& arg)
void drawer::key_char(const arg_keyboard& arg, const bool bForce__EmitInternal)
{
_m_emit(event_code::key_char, arg, &drawer_trigger::key_char);
_m_emit(event_code::key_char, arg, &drawer_trigger::key_char, bForce__EmitInternal);
}
void drawer::key_release(const arg_keyboard& arg)
void drawer::key_release(const arg_keyboard& arg, const bool bForce__EmitInternal)
{
_m_emit(event_code::key_release, arg, &drawer_trigger::key_release);
_m_emit(event_code::key_release, arg, &drawer_trigger::key_release, bForce__EmitInternal);
}
void drawer::shortkey(const arg_keyboard& arg)
void drawer::shortkey(const arg_keyboard& arg, const bool bForce__EmitInternal)
{
_m_emit(event_code::shortkey, arg, &drawer_trigger::shortkey);
_m_emit(event_code::shortkey, arg, &drawer_trigger::shortkey, bForce__EmitInternal);
}
void drawer::map(window wd, bool forced, const rectangle* update_area) //Copy the root buffer to screen

View File

@ -3058,7 +3058,7 @@ namespace nana
throw std::runtime_error("place.bind: it has already bound to a window.");
impl_->window_handle = wd;
impl_->event_size_handle = API::events(wd).resized.connect([this](const arg_resized& arg)
impl_->event_size_handle = API::events(wd).resized.connect_unignorable([this](const arg_resized& arg)
{
if (impl_->root_division)
{

View File

@ -260,7 +260,7 @@ namespace nana
notifier_->request_close();
});
this->events().resized.connect([this](const arg_resized& arg)
this->events().resized.connect_unignorable([this](const arg_resized& arg)
{
rectangle r{ 0, 0, arg.width, 20 };
caption_.move(r);
@ -360,7 +360,7 @@ namespace nana
API::set_parent_window(handle(), container_->handle());
this->move({ 1, 1 });
container_->events().resized.connect([this](const arg_resized& arg)
container_->events().resized.connect_unignorable([this](const arg_resized& arg)
{
this->size({arg.width - 2, arg.height - 2});
});

View File

@ -62,7 +62,12 @@ namespace API
bool emit_event(event_code evt_code, window wd, const ::nana::event_arg& arg)
{
return restrict::bedrock.emit(evt_code, reinterpret_cast<::nana::detail::basic_window*>(wd), arg, true, restrict::bedrock.get_thread_context());
return restrict::bedrock.emit(evt_code, reinterpret_cast<::nana::detail::basic_window*>(wd), arg, true, restrict::bedrock.get_thread_context(), false);
}
bool emit_internal_event(event_code evt_code, window wd, const ::nana::event_arg& arg)
{
return restrict::bedrock.emit(evt_code, reinterpret_cast<::nana::detail::basic_window*>(wd), arg, true, restrict::bedrock.get_thread_context(), true);
}
void enum_widgets_function_base::enum_widgets(window wd, bool recursive)

View File

@ -433,8 +433,16 @@ namespace nana
{
check_range(pos, cont_.size());
//The order of cont_'s elements is the display order.
if (!disp_order)
pos = this->cast(pos, false);
{
/// It always match the item with pos, otherwise a bug occurs.
for (auto & m : cont_)
{
if (m.index == pos)
return m;
}
}
return cont_[pos];
}

View File

@ -1355,6 +1355,11 @@ namespace nana
impl_->mbuilder.renderer(rd);
}
window menu::handle() const
{
return (impl_->window_ptr ? impl_->window_ptr->handle() : nullptr);
}
void menu::_m_popup(window wd, const point& pos, bool called_by_menubar)
{
if (impl_->mbuilder.data().items.size())

View File

@ -30,7 +30,7 @@ namespace nana
{
struct item_type
{
item_type(const native_string_type text, unsigned long shortkey)
item_type(const native_string_type& text, unsigned long shortkey)
: text(text), shortkey(shortkey)
{}
@ -83,6 +83,131 @@ namespace nana
container cont_;
};
struct trigger::essence
{
widget *widget_ptr{ nullptr };
//paint::graphics *graph{ nullptr };
itembase items;
enum class behavior
{
none, focus, menu,
};
struct state_type
{
std::size_t active{ nana::npos };
behavior behave{ behavior::none };
bool menu_active{ false };
bool passive_close{ true };
bool nullify_mouse{ false };
nana::menu *menu{ nullptr };
nana::point mouse_pos;
}state;
//functions
nana::menu& push_back(const std::string& text)
{
wchar_t shortkey;
API::transform_shortkey_text(text, shortkey, nullptr);
if (shortkey)
API::register_shortkey(this->widget_ptr->handle(), shortkey);
this->items.append(to_nstring(text), shortkey);
API::refresh_window(this->widget_ptr->handle());
return this->items.cont()[this->items.cont().size() - 1]->menu_obj;
}
bool cancel()
{
if (nana::npos == state.active)
return false;
this->close_menu();
state.menu_active = false;
state.behave = behavior::none;
auto pos = API::cursor_position();
API::calc_window_point(widget_ptr->handle(), pos);
state.active = find(pos);
return true;
}
bool open_menu()
{
auto pos = state.active;
if (pos >= items.cont().size())
return false;
auto item_ptr = items.cont()[pos];
if (state.menu_active && (state.menu != &(item_ptr->menu_obj)))
{
API::dev::delay_restore(true);
this->close_menu();
API::dev::delay_restore(false);
state.active = pos;
state.menu = &(item_ptr->menu_obj);
state.menu->destroy_answer([this]
{
state.menu = nullptr;
if (state.passive_close)
{
cancel();
API::refresh_window(*widget_ptr);
}
});
if (API::focus_window() != this->widget_ptr->handle())
API::focus_window(widget_ptr->handle());
menu_accessor::popup(*state.menu, *widget_ptr, item_ptr->pos.x, item_ptr->pos.y + static_cast<int>(item_ptr->size.height));
return true;
}
return false;
}
bool close_menu()
{
if (state.menu)
{
state.passive_close = false;
state.menu->close();
state.passive_close = true;
state.menu = nullptr;
return true;
}
return false;
}
std::size_t find(const ::nana::point& pos)
{
if ((2 <= pos.x) && (2 <= pos.y) && (pos.y < 25))
{
int item_x = 2;
std::size_t index = 0;
for (auto i : items.cont())
{
if (item_x <= pos.x && pos.x < item_x + static_cast<int>(i->size.width))
return index;
item_x += i->size.width;
++index;
}
}
return npos;
}
};
//class item_renderer
item_renderer::item_renderer(window wd, graph_reference graph)
:graph_(graph), scheme_ptr_(static_cast<scheme*>(API::dev::get_scheme(wd)))
@ -91,19 +216,17 @@ namespace nana
void item_renderer::background(const nana::point& pos, const nana::size& size, state item_state)
{
auto bground = scheme_ptr_->text_fgcolor;
::nana::color border, body, corner;
::nana::color border, body;
switch (item_state)
{
case state::highlighted:
border = scheme_ptr_->border_highlight;
body = scheme_ptr_->body_highlight;
corner = body.blend(bground, 0.5);
break;
case state::selected:
border = scheme_ptr_->border_selected;
body = scheme_ptr_->body_selected;
corner = body.blend(bground, 0.5);
break;
default: //Don't process other states.
return;
@ -112,7 +235,7 @@ namespace nana
nana::rectangle r(pos, size);
graph_.rectangle(r, false, border);
graph_.palette(false, corner);
graph_.palette(false, body.blend(bground, 0.5));
paint::draw{ graph_ }.corner(r, 1);
graph_.rectangle(r.pare_off(1), true, body);
@ -127,77 +250,52 @@ namespace nana
//class trigger
trigger::trigger()
: widget_(nullptr)
, graph_(nullptr)
, items_(new itembase) {}
: ess_(new essence)
{}
trigger::~trigger()
{
delete items_;
delete ess_;
}
nana::menu* trigger::push_back(const std::string& text)
auto trigger::ess() const -> essence&
{
wchar_t shkey;
API::transform_shortkey_text(text, shkey, nullptr);
if(shkey)
API::register_shortkey(widget_->handle(), shkey);
auto pos = items_->cont().size();
items_->append(to_nstring(text), shkey);
refresh(*graph_);
API::update_window(*widget_);
return at(pos);
}
nana::menu* trigger::at(std::size_t pos) const
{
if (pos < items_->cont().size())
return &(items_->cont()[pos]->menu_obj);
return nullptr;
}
std::size_t trigger::size() const
{
return items_->cont().size();
return *ess_;
}
void trigger::attached(widget_reference widget, graph_reference graph)
{
graph_ = &graph;
widget_ = &widget;
ess_->widget_ptr = &widget;
}
void trigger::refresh(graph_reference graph)
{
auto bgcolor = API::bgcolor(*widget_);
graph_->rectangle(true, bgcolor);
auto bgcolor = API::bgcolor(*ess_->widget_ptr);
item_renderer ird(*widget_, graph);
graph.rectangle(true, bgcolor);
item_renderer ird{ *ess_->widget_ptr, graph };
nana::point item_pos(2, 2);
nana::size item_s(0, 23);
unsigned long index = 0;
for (auto i : items_->cont())
for (auto pm : ess_->items.cont())
{
//Transform the text if it contains the hotkey character
wchar_t hotkey;
::std::wstring::size_type hotkey_pos;
auto text = API::transform_shortkey_text(to_utf8(i->text), hotkey, &hotkey_pos);
auto text = API::transform_shortkey_text(to_utf8(pm->text), hotkey, &hotkey_pos);
nana::size text_s = graph.text_extent_size(text);
item_s.width = text_s.width + 16;
i->pos = item_pos;
i->size = item_s;
pm->pos = item_pos;
pm->size = item_s;
using state = item_renderer::state;
state item_state = (index != state_.active ? state::normal : (state_.menu_active ? state::selected : state::highlighted));
state item_state = (index != ess_->state.active ? state::normal : (ess_->state.menu_active ? state::selected : state::highlighted));
ird.background(item_pos, item_s, item_state);
if (state::selected == item_state)
@ -214,59 +312,67 @@ namespace nana
API::dev::draw_shortkey_underline(graph, text, hotkey, hotkey_pos, { item_pos.x + 8, item_pos.y + text_top_off }, ird.scheme_ptr()->text_fgcolor);
item_pos.x += i->size.width;
item_pos.x += pm->size.width;
++index;
}
}
void trigger::mouse_move(graph_reference graph, const arg_mouse& arg)
{
if (arg.pos != state_.mouse_pos)
state_.nullify_mouse = false;
if (arg.pos != ess_->state.mouse_pos)
ess_->state.nullify_mouse = false;
bool popup = false;
if(state_.behavior == state_type::behavior_focus)
if(essence::behavior::focus == ess_->state.behave)
{
auto index = _m_item_by_pos(arg.pos);
if(index != npos && state_.active != index)
auto index = ess_->find(arg.pos);
if(index != npos && ess_->state.active != index)
{
state_.active = index;
ess_->state.active = index;
popup = true;
}
}
else if (!ess_->state.nullify_mouse)
{
auto which = ess_->find(arg.pos);
if ((which != ess_->state.active) && (which != npos || (false == ess_->state.menu_active)))
{
ess_->state.active = which;
popup = true;
}
}
else
popup = _m_track_mouse(arg.pos);
if(popup)
{
_m_popup_menu();
ess_->open_menu();
refresh(graph);
API::dev::lazy_refresh();
}
state_.mouse_pos = arg.pos;
ess_->state.mouse_pos = arg.pos;
}
void trigger::mouse_leave(graph_reference graph, const arg_mouse& arg)
{
state_.nullify_mouse = false;
ess_->state.nullify_mouse = false;
mouse_move(graph, arg);
}
void trigger::mouse_down(graph_reference graph, const arg_mouse& arg)
{
state_.nullify_mouse = false;
state_.active = _m_item_by_pos(arg.pos);
ess_->state.nullify_mouse = false;
ess_->state.active = ess_->find(arg.pos);
if (npos != state_.active)
if (npos != ess_->state.active)
{
if (!state_.menu_active)
state_.menu_active = true;
if (!ess_->state.menu_active)
ess_->state.menu_active = true;
_m_popup_menu();
ess_->open_menu();
}
else
_m_total_close();
ess_->cancel();
refresh(graph);
API::dev::lazy_refresh();
@ -274,17 +380,17 @@ namespace nana
void trigger::mouse_up(graph_reference graph, const arg_mouse&)
{
state_.nullify_mouse = false;
ess_->state.nullify_mouse = false;
if(state_.behavior != state_.behavior_menu)
if(ess_->state.behave != essence::behavior::menu)
{
if(state_.menu_active)
state_.behavior = state_.behavior_menu;
if(ess_->state.menu_active)
ess_->state.behave = essence::behavior::menu;
}
else
{
state_.behavior = state_.behavior_none;
_m_total_close();
ess_->state.behave = essence::behavior::none;
ess_->cancel();
refresh(graph);
API::dev::lazy_refresh();
}
@ -292,13 +398,13 @@ namespace nana
void trigger::focus(graph_reference graph, const arg_focus& arg)
{
if((arg.getting == false) && (state_.active != npos))
if((arg.getting == false) && (ess_->state.active != npos))
{
state_.behavior = state_type::behavior_none;
state_.nullify_mouse = true;
state_.menu_active = false;
_m_close_menu();
state_.active = npos;
ess_->state.behave = essence::behavior::none;
ess_->state.nullify_mouse = true;
ess_->state.menu_active = false;
ess_->close_menu();
ess_->state.active = npos;
refresh(graph);
API::dev::lazy_refresh();
}
@ -306,53 +412,55 @@ namespace nana
void trigger::key_press(graph_reference graph, const arg_keyboard& arg)
{
state_.nullify_mouse = true;
if(state_.menu)
ess_->state.nullify_mouse = true;
auto & menu_ptr = ess_->state.menu;
if(ess_->state.menu)
{
switch(arg.key)
{
case keyboard::os_arrow_down:
case keyboard::backspace:
case keyboard::os_arrow_up:
state_.menu->goto_next(keyboard::os_arrow_down == arg.key);
menu_ptr->goto_next(keyboard::os_arrow_down == arg.key);
break;
case keyboard::os_arrow_right:
if(state_.menu->goto_submen() == false)
_m_move(false);
if(menu_ptr->goto_submen() == false)
_m_move(graph, false);
break;
case keyboard::os_arrow_left:
if(state_.menu->exit_submenu() == false)
_m_move(true);
if(menu_ptr->exit_submenu() == false)
_m_move(graph, true);
break;
case keyboard::escape:
if(state_.menu->exit_submenu() == false)
if(menu_ptr->exit_submenu() == false)
{
_m_close_menu();
state_.behavior = state_.behavior_focus;
state_.menu_active = false;
ess_->close_menu();
ess_->state.behave = essence::behavior::focus;
ess_->state.menu_active = false;
}
break;
case keyboard::enter:
state_.menu->pick();
menu_ptr->pick();
break;
default:
//Katsuhisa Yuasa: menubar key_press improvements
//send_shortkey has 3 states, 0 = UNKNOWN KEY, 1 = ITEM, 2 = GOTO SUBMENU
int sk_state = state_.menu->send_shortkey(arg.key);
int sk_state = menu_ptr->send_shortkey(arg.key);
switch(sk_state)
{
case 0: //UNKNOWN KEY
break;
case 1: //ITEM
if (state_.active != npos)
if (ess_->state.active != npos)
{
_m_total_close();
ess_->cancel();
if (arg.key == 18) //ALT
state_.behavior = state_.behavior_focus;
ess_->state.behave = essence::behavior::focus;
}
break;
case 2: //GOTO SUBMENU
state_.menu->goto_submen();
menu_ptr->goto_submen();
break;
default: break;
}
@ -366,30 +474,30 @@ namespace nana
case keyboard::os_arrow_right:
case keyboard::backspace:
case keyboard::os_arrow_left:
_m_move(keyboard::os_arrow_right != arg.key);
_m_move(graph, keyboard::os_arrow_right != arg.key);
break;
case keyboard::os_arrow_up:
case keyboard::os_arrow_down:
case keyboard::enter:
state_.menu_active = true;
if(_m_popup_menu())
state_.menu->goto_next(true);
ess_->state.menu_active = true;
if(ess_->open_menu())
menu_ptr->goto_next(true);
break;
case keyboard::escape:
if(state_.behavior == state_.behavior_focus)
if(essence::behavior::focus == ess_->state.behave)
{
state_.active= npos;
state_.behavior = state_.behavior_none;
ess_->state.active= npos;
ess_->state.behave = essence::behavior::none;
}
break;
default:
auto index = items_->find(arg.key);
auto index = ess_->items.find(arg.key);
if(index != npos)
{
state_.active = index;
state_.menu_active = true;
if(_m_popup_menu())
state_.menu->goto_next(true);
ess_->state.active = index;
ess_->state.menu_active = true;
if(ess_->open_menu())
menu_ptr->goto_next(true);
}
break;
}
@ -403,20 +511,20 @@ namespace nana
{
if(arg.key == 18)
{
if(state_.behavior == state_type::behavior_none)
if(essence::behavior::none == ess_->state.behave)
{
state_.behavior = state_type::behavior_focus;
state_.active = 0;
ess_->state.behave = essence::behavior::focus;
ess_->state.active = 0;
}
else
{
state_.behavior = state_type::behavior_none;
ess_->state.behave = essence::behavior::none;
auto pos = API::cursor_position();
API::calc_window_point(widget_->handle(), pos);
state_.active = _m_item_by_pos(pos);
API::calc_window_point(ess_->widget_ptr->handle(), pos);
ess_->state.active = ess_->find(pos);
}
state_.menu_active = false;
ess_->state.menu_active = false;
refresh(graph);
API::dev::lazy_refresh();
}
@ -424,31 +532,31 @@ namespace nana
void trigger::shortkey(graph_reference graph, const arg_keyboard& arg)
{
API::focus_window(widget_->handle());
API::focus_window(ess_->widget_ptr->handle());
auto index = items_->find(arg.key);
if(index != npos && (index != state_.active || nullptr == state_.menu))
auto index = ess_->items.find(arg.key);
if(index != npos && (index != ess_->state.active || nullptr == ess_->state.menu))
{
_m_close_menu();
state_.menu_active = true;
state_.nullify_mouse = true;
state_.active = index;
ess_->close_menu();
ess_->state.menu_active = true;
ess_->state.nullify_mouse = true;
ess_->state.active = index;
if(_m_popup_menu())
state_.menu->goto_next(true);
if(ess_->open_menu())
ess_->state.menu->goto_next(true);
refresh(graph);
API::dev::lazy_refresh();
state_.behavior = state_.behavior_menu;
ess_->state.behave = essence::behavior::menu;
}
}
void trigger::_m_move(bool to_left)
void trigger::_m_move(graph_reference graph, bool to_left)
{
if(items_->cont().empty()) return;
if(ess_->items.cont().empty()) return;
const std::size_t last_pos = items_->cont().size() - 1;
auto index = state_.active;
const std::size_t last_pos = ess_->items.cont().size() - 1;
auto index = ess_->state.active;
if(to_left)
{
--index;
@ -462,121 +570,16 @@ namespace nana
index = 0;
}
if(index != state_.active)
if(index != ess_->state.active)
{
state_.active = index;
refresh(*graph_);
ess_->state.active = index;
refresh(graph);
API::dev::lazy_refresh();
if(_m_popup_menu())
state_.menu->goto_next(true);
if(ess_->open_menu())
ess_->state.menu->goto_next(true);
}
}
bool trigger::_m_popup_menu()
{
auto& items = items_->cont();
auto pos = state_.active;
if (pos >= items.size())
return false;
if(state_.menu_active && (state_.menu != &(items[pos]->menu_obj)))
{
API::dev::delay_restore(true);
_m_close_menu();
API::dev::delay_restore(false);
state_.active = pos;
auto & m = items[pos];
state_.menu = &(m->menu_obj);
state_.menu->destroy_answer([this]
{
state_.menu = nullptr;
if (state_.passive_close)
{
_m_total_close();
refresh(*graph_);
API::update_window(widget_->handle());
}
});
if (API::focus_window() != this->widget_->handle())
API::focus_window(widget_->handle());
menu_accessor::popup(*state_.menu, *widget_, m->pos.x, m->pos.y + static_cast<int>(m->size.height));
return true;
}
return false;
}
void trigger::_m_total_close()
{
_m_close_menu();
state_.menu_active = false;
state_.behavior = state_.behavior_none;
auto pos = API::cursor_position();
API::calc_window_point(widget_->handle(), pos);
state_.active = _m_item_by_pos(pos);
}
bool trigger::_m_close_menu()
{
if(state_.menu)
{
state_.passive_close = false;
state_.menu->close();
state_.passive_close = true;
state_.menu = nullptr;
return true;
}
return false;
}
std::size_t trigger::_m_item_by_pos(const ::nana::point& pos)
{
if((2 <= pos.x) && (2 <= pos.y) && (pos.y < 25))
{
int item_x = 2;
std::size_t index = 0;
for(auto i : items_->cont())
{
if(item_x <= pos.x && pos.x < item_x + static_cast<int>(i->size.width))
return index;
item_x += i->size.width;
++index;
}
}
return npos;
}
bool trigger::_m_track_mouse(const ::nana::point& pos)
{
if(state_.nullify_mouse == false)
{
auto which = _m_item_by_pos(pos);
if((which != state_.active) && (which != npos || (false == state_.menu_active)))
{
state_.active = which;
return true;
}
}
return false;
}
//struct state_type
trigger::state_type::state_type()
: active(npos),
behavior(behavior_none),
menu_active(false),
passive_close(true),
nullify_mouse(false),
menu(nullptr)
{}
//end struct state_type
//end class trigger
}//end namespace menubar
}//end namespace drawerbase
@ -599,7 +602,7 @@ namespace nana
::create(wd, rectangle(nana::size(API::window_size(wd).width, 28)));
API::dev::set_menubar(handle(), true);
evt_resized_ = API::events(wd).resized.connect([this](const ::nana::arg_resized& arg)
evt_resized_ = API::events(wd).resized.connect_unignorable([this](const ::nana::arg_resized& arg)
{
auto sz = this->size();
sz.width = arg.width;
@ -609,20 +612,49 @@ namespace nana
menu& menubar::push_back(const std::string& text)
{
return *(get_drawer_trigger().push_back(text));
return get_drawer_trigger().ess().push_back(text);
}
menu& menubar::at(std::size_t index) const
menu& menubar::at(std::size_t pos) const
{
auto p = get_drawer_trigger().at(index);
if(nullptr == p)
throw std::out_of_range("menubar::at, out of range");
return *p;
return get_drawer_trigger().ess().items.cont().at(pos)->menu_obj;
}
std::size_t menubar::length() const
{
return get_drawer_trigger().size();
return get_drawer_trigger().ess().items.cont().size();
}
bool menubar::cancel()
{
return get_drawer_trigger().ess().cancel();
}
bool menubar::hovered() const
{
auto const native_handle = API::root(this->handle());
if (native_handle)
{
auto wd = API::find_window(API::cursor_position());
if (wd == this->handle())
return true;
auto & items = get_drawer_trigger().ess().items.cont();
while (wd)
{
auto owner = API::get_owner_window(wd);
if (API::root(owner) == native_handle)
{
for (auto p : items)
{
if (p->menu_obj.handle() == wd)
return true;
}
}
wd = owner;
}
}
return false;
}
//end class menubar
}//end namespace nana