Merge remote-tracking branch 'nana_jinhao/hotfixes-1.0.1' into hotfixes-1.0.1

This commit is contained in:
qPCR4vir 2015-04-21 17:28:53 +02:00
commit 356ee07884
16 changed files with 315 additions and 249 deletions

View File

@ -166,7 +166,8 @@ namespace detail
bool fullscreen :1; //When the window is maximizing whether it fit for fullscreen. bool fullscreen :1; //When the window is maximizing whether it fit for fullscreen.
bool borderless :1; bool borderless :1;
bool make_bground_declared : 1; //explicitly make bground for bground effects bool make_bground_declared : 1; //explicitly make bground for bground effects
unsigned Reserved :21; bool ignore_menubar_focus : 1; //A flag indicates whether the menubar sets the focus.
unsigned Reserved :20;
unsigned char tab; //indicate a window that can receive the keyboard TAB unsigned char tab; //indicate a window that can receive the keyboard TAB
mouse_action action; mouse_action action;
}flags; }flags;

View File

@ -54,13 +54,14 @@ namespace detail
native_window_type root(core_window_t*); native_window_type root(core_window_t*);
void set_menubar_taken(core_window_t*); void set_menubar_taken(core_window_t*);
core_window_t* get_menubar_taken();
//Delay Restores focus when a menu which attached to menubar is closed
void delay_restore(int);
bool close_menu_if_focus_other_window(native_window_type focus); bool close_menu_if_focus_other_window(native_window_type focus);
void set_menu(native_window_type menu_window, bool is_keyboard_condition); void set_menu(native_window_type menu_window, bool is_keyboard_condition);
native_window_type get_menu(native_window_type owner, bool is_keyboard_condition); native_window_type get_menu(native_window_type owner, bool is_keyboard_condition);
native_window_type get_menu(); native_window_type get_menu();
void remove_menu(); void erase_menu(bool try_destroy);
void empty_menu();
void get_key_state(arg_keyboard&); void get_key_state(arg_keyboard&);
bool set_keyboard_shortkey(bool yes); bool set_keyboard_shortkey(bool yes);

View File

@ -77,6 +77,8 @@ namespace API
window create_frame(window, const rectangle&, widget* attached); window create_frame(window, const rectangle&, widget* attached);
paint::graphics* window_graphics(window); paint::graphics* window_graphics(window);
void delay_restore(bool);
}//end namespace dev }//end namespace dev
@ -290,7 +292,6 @@ namespace API
void register_menu_window(window, bool has_keyboard); void register_menu_window(window, bool has_keyboard);
bool attach_menubar(window menubar); bool attach_menubar(window menubar);
void detach_menubar(window menubar); void detach_menubar(window menubar);
void restore_menubar_taken_window();
bool is_window_zoomed(window, bool ask_for_max); ///<Tests a window whether it is maximized or minimized. bool is_window_zoomed(window, bool ask_for_max); ///<Tests a window whether it is maximized or minimized.

View File

@ -24,12 +24,16 @@ namespace nana
class item_renderer class item_renderer
{ {
public: public:
enum state_t{state_normal, state_highlight, state_selected}; enum class state
typedef nana::paint::graphics& graph_reference; {
normal, highlighted, selected
};
using graph_reference = paint::graphics&;
item_renderer(window, graph_reference); item_renderer(window, graph_reference);
virtual void background(const nana::point& pos, const nana::size& size, state_t); virtual void background(const point&, const ::nana::size&, state);
virtual void caption(int x, int y, const nana::string& text); virtual void caption(const point&, const ::nana::string&);
private: private:
window handle_; window handle_;
graph_reference graph_; graph_reference graph_;
@ -59,9 +63,8 @@ namespace nana
private: private:
void _m_move(bool to_left); void _m_move(bool to_left);
bool _m_popup_menu(); bool _m_popup_menu();
void _m_total_close(bool try_restore); void _m_total_close();
bool _m_close_menu(); bool _m_close_menu();
void _m_unload_menu_window();
std::size_t _m_item_by_pos(const ::nana::point&); std::size_t _m_item_by_pos(const ::nana::point&);
bool _m_track_mouse(const ::nana::point&); bool _m_track_mouse(const ::nana::point&);
void _m_draw(); void _m_draw();
@ -90,11 +93,6 @@ namespace nana
nana::menu *menu; nana::menu *menu;
nana::point mouse_pos; nana::point mouse_pos;
//The menu will restore the focus of taken window. But the restoring during
//key_press and key_release resets the focus to the taken window, it causes
//the taken window to receive a key_char which should be received by menubar.
bool delay_restore;
}state_; }state_;
}; };
}//end namespace menubar }//end namespace menubar

View File

@ -1,7 +1,7 @@
/* /*
* Platform Specification Implementation * Platform Specification Implementation
* Nana C++ Library(http://www.nanapro.org) * 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 Nana Software License, Version 1.0. * Distributed under the Nana 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
@ -841,7 +841,10 @@ namespace detail
if((attr.your_event_mask & addr->input_context_event_mask) == addr->input_context_event_mask) if((attr.your_event_mask & addr->input_context_event_mask) == addr->input_context_event_mask)
{ {
XSetWindowAttributes new_attr; XSetWindowAttributes new_attr;
new_attr.event_mask = (attr.your_event_mask & ~addr->input_context_event_mask);
//Don't remove the KeyPress and KeyRelease mask(0x3), otherwise the window will not receive
//Keyboard events after destroying caret
new_attr.event_mask = (attr.your_event_mask & ~(addr->input_context_event_mask & (~0x3)));
::XChangeWindowAttributes(display_, reinterpret_cast<Window>(wd), CWEventMask, &new_attr); ::XChangeWindowAttributes(display_, reinterpret_cast<Window>(wd), CWEventMask, &new_attr);
} }
} }

View File

@ -347,6 +347,7 @@ namespace nana
flags.destroying = false; flags.destroying = false;
flags.borderless = false; flags.borderless = false;
flags.make_bground_declared = false; flags.make_bground_declared = false;
flags.ignore_menubar_focus = false;
visible = false; visible = false;

View File

@ -1,7 +1,7 @@
/* /*
* Bedrock Selector * Bedrock Selector
* Nana C++ Library(http://www.nanapro.org) * 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 Nana Software License, Version 1.0. * Distributed under the Nana 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

View File

@ -102,27 +102,18 @@ namespace detail
{ {
struct thread_context_cache struct thread_context_cache
{ {
unsigned tid; unsigned tid{ 0 };
thread_context *object; thread_context *object{ nullptr };
}tcontext; }tcontext;
cache_type()
{
tcontext.tid = 0;
tcontext.object = nullptr;
}
}cache; }cache;
struct menu_tag struct menu_tag
{ {
menu_tag() core_window_t* taken_window{ nullptr };
:taken_window(nullptr), window(nullptr), owner(nullptr), has_keyboard(false) bool delay_restore{ false };
{} native_window_type window{ nullptr };
native_window_type owner{ nullptr };
core_window_t* taken_window; bool has_keyboard{ false };
native_window_type window;
native_window_type owner;
bool has_keyboard;
}menu; }menu;
struct keyboard_tracking_state_tag struct keyboard_tracking_state_tag
@ -282,14 +273,39 @@ namespace detail
void bedrock::set_menubar_taken(core_window_t* wd) void bedrock::set_menubar_taken(core_window_t* wd)
{ {
auto pre = impl_->menu.taken_window;
impl_->menu.taken_window = wd; impl_->menu.taken_window = wd;
//assigning of a nullptr taken window is to restore the focus of pre taken
if ((!wd) && pre)
{
internal_scope_guard lock;
wd_manager.set_focus(pre, false);
wd_manager.update(pre, true, false);
}
} }
bedrock::core_window_t* bedrock::get_menubar_taken() //0:Enable delay, 1:Cancel, 2:Restores, 3: Restores when menu is destroying
void bedrock::delay_restore(int state)
{ {
core_window_t* wd = impl_->menu.taken_window; switch (state)
impl_->menu.taken_window = nullptr; {
return wd; case 0: //Enable
break;
case 1: //Cancel
break;
case 2: //Restore if key released
//restores the focus when menu is closed by pressing keyboard
if (!impl_->menu.window)
set_menubar_taken(nullptr);
break;
case 3: //Restores if destroying
//when the menu is destroying, restores the focus if delay restore is not declared
if (!impl_->menu.delay_restore)
set_menubar_taken(nullptr);
}
impl_->menu.delay_restore = (0 == state);
} }
bool bedrock::close_menu_if_focus_other_window(native_window_type wd) bool bedrock::close_menu_if_focus_other_window(native_window_type wd)
@ -304,7 +320,7 @@ namespace detail
else else
return false; return false;
} }
remove_menu(); erase_menu(true);
return true; return true;
} }
return false; return false;
@ -314,7 +330,7 @@ namespace detail
{ {
if(menu_window && impl_->menu.window != menu_window) if(menu_window && impl_->menu.window != menu_window)
{ {
remove_menu(); erase_menu(true);
impl_->menu.window = menu_window; impl_->menu.window = menu_window;
impl_->menu.owner = native_interface::get_owner_window(menu_window); impl_->menu.owner = native_interface::get_owner_window(menu_window);
impl_->menu.has_keyboard = has_keyboard; impl_->menu.has_keyboard = has_keyboard;
@ -338,21 +354,13 @@ namespace detail
return impl_->menu.window; return impl_->menu.window;
} }
void bedrock::remove_menu() void bedrock::erase_menu(bool try_destroy)
{ {
if(impl_->menu.window) if (impl_->menu.window)
{ {
native_window_type delwin = impl_->menu.window; if (try_destroy)
impl_->menu.window = impl_->menu.owner = nullptr; native_interface::close_window(impl_->menu.window);
impl_->menu.has_keyboard = false;
native_interface::close_window(delwin);
}
}
void bedrock::empty_menu()
{
if(impl_->menu.window)
{
impl_->menu.window = impl_->menu.owner = nullptr; impl_->menu.window = impl_->menu.owner = nullptr;
impl_->menu.has_keyboard = false; impl_->menu.has_keyboard = false;
} }
@ -372,6 +380,11 @@ namespace detail
return ret; return ret;
} }
bool bedrock::whether_keyboard_shortkey() const
{
return impl_->keyboard_tracking_state.has_shortkey_occured;
}
element_store& bedrock::get_element_store() const element_store& bedrock::get_element_store() const
{ {
return impl_->estore; return impl_->estore;
@ -700,8 +713,8 @@ namespace detail
msgwnd = brock.wd_manager.find_window(native_window, xevent.xbutton.x, xevent.xbutton.y); msgwnd = brock.wd_manager.find_window(native_window, xevent.xbutton.x, xevent.xbutton.y);
if(nullptr == msgwnd) break; if(nullptr == msgwnd) break;
if((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true)) if ((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true))
brock.remove_menu(); brock.erase_menu(true);
else else
brock.close_menu_if_focus_other_window(msgwnd->root); brock.close_menu_if_focus_other_window(msgwnd->root);
@ -719,7 +732,7 @@ namespace detail
if(kill_focus != new_focus) if(kill_focus != new_focus)
brock.wd_manager.do_lazy_refresh(kill_focus, false); brock.wd_manager.do_lazy_refresh(kill_focus, false);
} }
auto retain = msgwnd->together.event_ptr; auto retain = msgwnd->together.events_ptr;
msgwnd->root_widget->other.attribute.root->context.focus_changed = false; msgwnd->root_widget->other.attribute.root->context.focus_changed = false;
context.event_window = msgwnd; context.event_window = msgwnd;
@ -773,7 +786,7 @@ namespace detail
msgwnd->flags.action = mouse_action::normal; msgwnd->flags.action = mouse_action::normal;
if(msgwnd->flags.enabled) if(msgwnd->flags.enabled)
{ {
auto retain = msgwnd->together.event_ptr; auto retain = msgwnd->together.events_ptr;
arg_mouse arg; arg_mouse arg;
assign_arg(arg, msgwnd, message, xevent); assign_arg(arg, msgwnd, message, xevent);
@ -829,8 +842,11 @@ namespace detail
if(brock.wd_manager.available(msgwnd)) if(brock.wd_manager.available(msgwnd))
{ {
//The msgwnd may be destroyed if the window is destroyed by calling native interface of close_window(). //The msgwnd may be destroyed if the window is destroyed by calling native interface of close_window().
if(msgwnd->root == brock.get_menu()) if (msgwnd->root == brock.get_menu())
brock.empty_menu(); {
brock.erase_menu(false);
brock.delay_restore(3); //Restores if delay_restore not decleared
}
spec.remove(native_window); spec.remove(native_window);
brock.wd_manager.destroy(msgwnd); brock.wd_manager.destroy(msgwnd);
@ -929,6 +945,9 @@ namespace detail
nana::detail::platform_spec::instance().write_keystate(xevent.xkey); nana::detail::platform_spec::instance().write_keystate(xevent.xkey);
if(msgwnd->flags.enabled) if(msgwnd->flags.enabled)
{ {
if (brock.get_menu())
brock.delay_restore(0); //Enable delay restore
if(msgwnd->root != brock.get_menu()) if(msgwnd->root != brock.get_menu())
msgwnd = brock.focus(); msgwnd = brock.focus();
@ -1011,12 +1030,31 @@ namespace detail
else if(keyboard::alt == keychar) else if(keyboard::alt == keychar)
{ {
context.is_alt_pressed = true; context.is_alt_pressed = true;
if (brock.whether_keyboard_shortkey() == false)
{
msgwnd = msgwnd->root_widget->other.attribute.root->menubar;
if (msgwnd)
{
bool focused = (brock.focus() == msgwnd);
arg_keyboard arg;
arg.evt_code = event_code::key_press;
arg.window_handle = reinterpret_cast<window>(msgwnd);
arg.ignore = false;
arg.key = static_cast<nana::char_t>(keychar);
brock.get_key_state(arg);
brock.emit(event_code::key_press, msgwnd, arg, true, &context);
msgwnd->root_widget->flags.ignore_menubar_focus = (focused && (brock.focus() != msgwnd));
}
else
brock.erase_menu(true);
}
} }
else if(keychar) else
{ {
arg_keyboard arg; arg_keyboard arg;
arg.ignore = false; arg.ignore = false;
arg.key = keychar; arg.key = keychar ? keychar : xevent.xkey.keycode;
arg.evt_code = event_code::key_press; arg.evt_code = event_code::key_press;
brock.get_key_state(arg); brock.get_key_state(arg);
arg.window_handle = reinterpret_cast<window>(msgwnd); arg.window_handle = reinterpret_cast<window>(msgwnd);
@ -1093,11 +1131,35 @@ namespace detail
brock.get_key_state(arg); brock.get_key_state(arg);
brock.emit(event_code::key_release, msgwnd, arg, true, &context); brock.emit(event_code::key_release, msgwnd, arg, true, &context);
} }
brock.delay_restore(2); //Restores while key release
} }
else else
{ {
context.is_alt_pressed = false; context.is_alt_pressed = false;
brock.set_keyboard_shortkey(false); if (brock.set_keyboard_shortkey(false) == false)
{
msgwnd = msgwnd->root_widget->other.attribute.root->menubar;
if (msgwnd)
{
bool set_focus = (brock.focus() != msgwnd) && (!msgwnd->root_widget->flags.ignore_menubar_focus);
if (set_focus)
brock.wd_manager.set_focus(msgwnd, false);
arg_keyboard arg;
arg.evt_code = event_code::key_release;
arg.window_handle = reinterpret_cast<window>(msgwnd);
arg.ignore = false;
arg.key = static_cast<nana::char_t>(context.platform.keychar);
brock.get_key_state(arg);
brock.emit(event_code::key_release, msgwnd, arg, true, &context);
if (!set_focus)
{
brock.set_menubar_taken(nullptr);
msgwnd->root_widget->flags.ignore_menubar_focus = false;
}
}
}
} }
break; break;
default: default:

View File

@ -580,27 +580,30 @@ namespace nana{
//event, when the client receives the event, the specified window has been already //event, when the client receives the event, the specified window has been already
//destroyed. This is a feature which is different from Windows. So the following //destroyed. This is a feature which is different from Windows. So the following
//works should be handled before calling XDestroyWindow. //works should be handled before calling XDestroyWindow.
auto & bedrock = bedrock::instance(); auto & brock = bedrock::instance();
if(wd == bedrock.get_menu()) if(wd == brock.get_menu())
bedrock.empty_menu(); {
brock.erase_menu(false);
brock.delay_restore(3); //Restores if delay_restore is not decleard
}
Display* disp = restrict::spec.open_display(); Display* disp = restrict::spec.open_display();
restrict::spec.remove(wd); restrict::spec.remove(wd);
auto iwd = bedrock.wd_manager.root(wd); auto iwd = brock.wd_manager.root(wd);
if(iwd) if(iwd)
{ {
{ {
//Before calling window_manager::destroy, make sure the window is invisible. //Before calling window_manager::destroy, make sure the window is invisible.
//It is a behavior like Windows. //It is a behavior like Windows.
nana::detail::platform_scope_guard psg; nana::detail::platform_scope_guard lock;
restrict::spec.set_error_handler(); restrict::spec.set_error_handler();
::XUnmapWindow(disp, reinterpret_cast<Window>(wd)); ::XUnmapWindow(disp, reinterpret_cast<Window>(wd));
::XFlush(disp); ::XFlush(disp);
restrict::spec.rev_error_handler(); restrict::spec.rev_error_handler();
} }
bedrock.wd_manager.destroy(iwd); brock.wd_manager.destroy(iwd);
bedrock.rt_manager.remove_if_exists(iwd); brock.rt_manager.remove_if_exists(iwd);
bedrock.wd_manager.destroy_handle(iwd); brock.wd_manager.destroy_handle(iwd);
} }
nana::detail::platform_scope_guard psg; nana::detail::platform_scope_guard psg;

View File

@ -185,17 +185,18 @@ namespace detail
{ {
struct thread_context_cache struct thread_context_cache
{ {
unsigned tid = 0; unsigned tid{ 0 };
thread_context *object = nullptr; thread_context *object{ nullptr };
}tcontext; }tcontext;
}cache; }cache;
struct menu_tag struct menu_tag
{ {
core_window_t* taken_window = nullptr; core_window_t* taken_window{ nullptr };
native_window_type window = nullptr; bool delay_restore{ false };
native_window_type owner = nullptr; native_window_type window{ nullptr };
bool has_keyboard = false; native_window_type owner{ nullptr };
bool has_keyboard{false};
}menu; }menu;
struct keyboard_tracking_state_tag struct keyboard_tracking_state_tag
@ -921,8 +922,8 @@ namespace detail
if(nullptr == msgwnd) break; if(nullptr == msgwnd) break;
//if event on the menubar, just remove the menu if it is not associating with the menubar //if event on the menubar, just remove the menu if it is not associating with the menubar
if((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true)) if ((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true))
brock.remove_menu(); brock.erase_menu(true);
else else
brock.close_menu_if_focus_other_window(msgwnd->root); brock.close_menu_if_focus_other_window(msgwnd->root);
@ -1322,13 +1323,12 @@ namespace detail
def_window_proc = true; def_window_proc = true;
break; break;
case WM_SYSKEYDOWN: case WM_SYSKEYDOWN:
if(brock.whether_keyboard_shortkey() == false) if (brock.whether_keyboard_shortkey() == false)
{ {
msgwnd = msgwnd->root_widget->other.attribute.root->menubar; msgwnd = msgwnd->root_widget->other.attribute.root->menubar;
if(msgwnd) if (msgwnd)
{ {
brock.wd_manager.set_focus(msgwnd, false); bool focused = (brock.focus() == msgwnd);
arg_keyboard arg; arg_keyboard arg;
arg.evt_code = event_code::key_press; arg.evt_code = event_code::key_press;
arg.window_handle = reinterpret_cast<window>(msgwnd); arg.window_handle = reinterpret_cast<window>(msgwnd);
@ -1336,9 +1336,11 @@ namespace detail
arg.key = static_cast<nana::char_t>(wParam); arg.key = static_cast<nana::char_t>(wParam);
brock.get_key_state(arg); brock.get_key_state(arg);
brock.emit(event_code::key_press, msgwnd, arg, true, &context); brock.emit(event_code::key_press, msgwnd, arg, true, &context);
msgwnd->root_widget->flags.ignore_menubar_focus = (focused && (brock.focus() != msgwnd));
} }
else if(brock.get_menu()) else
brock.remove_menu(); brock.erase_menu(true);
} }
def_window_proc = true; def_window_proc = true;
break; break;
@ -1348,6 +1350,10 @@ namespace detail
msgwnd = msgwnd->root_widget->other.attribute.root->menubar; msgwnd = msgwnd->root_widget->other.attribute.root->menubar;
if(msgwnd) if(msgwnd)
{ {
bool set_focus = (brock.focus() != msgwnd) && (!msgwnd->root_widget->flags.ignore_menubar_focus);
if (set_focus)
brock.wd_manager.set_focus(msgwnd, false);
arg_keyboard arg; arg_keyboard arg;
arg.evt_code = event_code::key_release; arg.evt_code = event_code::key_release;
arg.window_handle = reinterpret_cast<window>(msgwnd); arg.window_handle = reinterpret_cast<window>(msgwnd);
@ -1355,6 +1361,12 @@ namespace detail
arg.key = static_cast<nana::char_t>(wParam); arg.key = static_cast<nana::char_t>(wParam);
brock.get_key_state(arg); brock.get_key_state(arg);
brock.emit(event_code::key_release, msgwnd, arg, true, &context); brock.emit(event_code::key_release, msgwnd, arg, true, &context);
if (!set_focus)
{
brock.set_menubar_taken(nullptr);
msgwnd->root_widget->flags.ignore_menubar_focus = false;
}
} }
} }
def_window_proc = true; def_window_proc = true;
@ -1362,6 +1374,9 @@ namespace detail
case WM_KEYDOWN: case WM_KEYDOWN:
if(msgwnd->flags.enabled) if(msgwnd->flags.enabled)
{ {
if (brock.get_menu())
brock.delay_restore(0); //Enable delay restore
if(msgwnd->root != brock.get_menu()) if(msgwnd->root != brock.get_menu())
msgwnd = brock.focus(); msgwnd = brock.focus();
@ -1431,6 +1446,8 @@ namespace detail
} }
else else
brock.set_keyboard_shortkey(false); brock.set_keyboard_shortkey(false);
brock.delay_restore(2); //Restores while key release
break; break;
case WM_CLOSE: case WM_CLOSE:
{ {
@ -1448,8 +1465,12 @@ namespace detail
break; break;
} }
case WM_DESTROY: case WM_DESTROY:
if(msgwnd->root == brock.get_menu()) if (msgwnd->root == brock.get_menu())
brock.empty_menu(); {
brock.erase_menu(false);
brock.delay_restore(3); //Restores if delay_restore not decleared
}
brock.wd_manager.destroy(msgwnd); brock.wd_manager.destroy(msgwnd);
nana::detail::platform_spec::instance().release_window_icon(msgwnd->root); nana::detail::platform_spec::instance().release_window_icon(msgwnd->root);
@ -1512,14 +1533,39 @@ namespace detail
void bedrock::set_menubar_taken(core_window_t* wd) void bedrock::set_menubar_taken(core_window_t* wd)
{ {
auto pre = impl_->menu.taken_window;
impl_->menu.taken_window = wd; impl_->menu.taken_window = wd;
//assigning of a nullptr taken window is to restore the focus of pre taken
if ((!wd) && pre)
{
internal_scope_guard lock;
wd_manager.set_focus(pre, false);
wd_manager.update(pre, true, false);
}
} }
bedrock::core_window_t* bedrock::get_menubar_taken() //0:Enable delay, 1:Cancel, 2:Restores, 3: Restores when menu is destroying
void bedrock::delay_restore(int state)
{ {
core_window_t* wd = impl_->menu.taken_window; switch (state)
impl_->menu.taken_window = nullptr; {
return wd; case 0: //Enable
break;
case 1: //Cancel
break;
case 2: //Restore if key released
//restores the focus when menu is closed by pressing keyboard
if (!impl_->menu.window)
set_menubar_taken(nullptr);
break;
case 3: //Restores if destroying
//when the menu is destroying, restores the focus if delay restore is not declared
if (!impl_->menu.delay_restore)
set_menubar_taken(nullptr);
}
impl_->menu.delay_restore = (0 == state);
} }
bool bedrock::close_menu_if_focus_other_window(native_window_type wd) bool bedrock::close_menu_if_focus_other_window(native_window_type wd)
@ -1534,7 +1580,7 @@ namespace detail
else else
return false; return false;
} }
remove_menu(); erase_menu(true);
return true; return true;
} }
return false; return false;
@ -1544,7 +1590,7 @@ namespace detail
{ {
if(menu_wd && impl_->menu.window != menu_wd) if(menu_wd && impl_->menu.window != menu_wd)
{ {
remove_menu(); erase_menu(true);
impl_->menu.window = menu_wd; impl_->menu.window = menu_wd;
impl_->menu.owner = native_interface::get_owner_window(menu_wd); impl_->menu.owner = native_interface::get_owner_window(menu_wd);
@ -1568,21 +1614,13 @@ namespace detail
return impl_->menu.window; return impl_->menu.window;
} }
void bedrock::remove_menu() void bedrock::erase_menu(bool try_destroy)
{ {
if(impl_->menu.window) if (impl_->menu.window)
{ {
auto delwin = impl_->menu.window; if (try_destroy)
impl_->menu.window = impl_->menu.owner = nullptr; native_interface::close_window(impl_->menu.window);
impl_->menu.has_keyboard = false;
native_interface::close_window(delwin);
}
}
void bedrock::empty_menu()
{
if(impl_->menu.window)
{
impl_->menu.window = impl_->menu.owner = nullptr; impl_->menu.window = impl_->menu.owner = nullptr;
impl_->menu.has_keyboard = false; impl_->menu.has_keyboard = false;
} }

View File

@ -884,7 +884,8 @@ namespace detail
if (wd == wd->root_widget->other.attribute.root->menubar) if (wd == wd->root_widget->other.attribute.root->menubar)
wd = prev_focus; wd = prev_focus;
brock.set_menubar_taken(wd); if (wd != wd->root_widget->other.attribute.root->menubar)
brock.set_menubar_taken(wd);
} }
return prev_focus; return prev_focus;
} }

View File

@ -240,6 +240,11 @@ namespace API
return &reinterpret_cast<restrict::core_window_t*>(wd)->drawer.graphics; return &reinterpret_cast<restrict::core_window_t*>(wd)->drawer.graphics;
return nullptr; return nullptr;
} }
void delay_restore(bool enable)
{
restrict::bedrock.delay_restore(enable ? 0 : 1);
}
}//end namespace dev }//end namespace dev
//exit //exit
@ -1203,17 +1208,6 @@ namespace API
} }
} }
void restore_menubar_taken_window()
{
auto wd = restrict::bedrock.get_menubar_taken();
if(wd)
{
internal_scope_guard lock;
restrict::window_manager.set_focus(wd, false);
restrict::window_manager.update(wd, true, false);
}
}
bool is_window_zoomed(window wd, bool ask_for_max) bool is_window_zoomed(window wd, bool ask_for_max)
{ {
auto const iwd = reinterpret_cast<restrict::core_window_t*>(wd); auto const iwd = reinterpret_cast<restrict::core_window_t*>(wd);

View File

@ -37,21 +37,25 @@ namespace nana
::nana::color clr{ 0xaf, 0xc7, 0xe3 }; ::nana::color clr{ 0xaf, 0xc7, 0xe3 };
graph.rectangle(r, false, clr); graph.rectangle(r, false, clr);
auto right = r.right() - 1;
auto bottom = r.bottom() - 1;
graph.set_color(colors::white); graph.set_color(colors::white);
graph.set_pixel(r.x, r.y); graph.set_pixel(r.x, r.y);
graph.set_pixel(r.x + r.width - 1, r.y); graph.set_pixel(right, r.y);
graph.set_pixel(r.x, r.y + r.height - 1); graph.set_pixel(r.x, bottom);
graph.set_pixel(r.x + r.width - 1, r.y + r.height - 1); graph.set_pixel(right, bottom);
--right;
--bottom;
graph.set_color(clr); graph.set_color(clr);
graph.set_pixel(r.x + 1, r.y + 1); graph.set_pixel(r.x + 1, r.y + 1);
graph.set_pixel(r.x + r.width - 2, r.y + 1); graph.set_pixel(right, r.y + 1);
graph.set_pixel(r.x + 1, r.y + r.height - 2); graph.set_pixel(r.x + 1, bottom);
graph.set_pixel(r.x + r.width - 2, r.y + r.height - 2); graph.set_pixel(right, bottom);
nana::rectangle po_r(r); nana::rectangle po_r(r);
graph.rectangle(po_r.pare_off(1), false, { 0xEB, 0xF4, 0xFB }); graph.rectangle(po_r.pare_off(1), false, static_cast<color_rgb>(0xEBF4FB));
graph.gradual_rectangle(po_r.pare_off(1), { 0xDD, 0xEC, 0xFD }, { 0xC2, 0xDC, 0xFD }, true); graph.gradual_rectangle(po_r.pare_off(1), static_cast<color_rgb>(0xDDECFD), static_cast<color_rgb>(0xC2DCFD), true);
} }
else else
graph.rectangle(r, true, colors::white); graph.rectangle(r, true, colors::white);
@ -113,13 +117,8 @@ namespace nana
class drawer_impl class drawer_impl
{ {
public: public:
typedef widget& widget_reference; using widget_reference = widget&;
typedef nana::paint::graphics& graph_reference; using graph_reference = paint::graphics&;
drawer_impl()
: widget_(nullptr), graph_(nullptr), image_pixels_(16),
ignore_first_mouseup_(true), module_(nullptr)
{}
void clear_state() void clear_state()
{ {
@ -151,25 +150,19 @@ namespace nana
{ {
if(scrollbar_.empty()) return; if(scrollbar_.empty()) return;
bool update = false; const auto before_change = state_.offset_y;
if(upwards) if(upwards)
{ {
if(state_.offset_y) if (before_change)
{
--(state_.offset_y); --(state_.offset_y);
update = true;
}
} }
else else
{ {
if((state_.offset_y + module_->max_items) < module_->items.size()) if ((before_change + module_->max_items) < module_->items.size())
{
++(state_.offset_y); ++(state_.offset_y);
update = true;
}
} }
if(update) if(before_change != state_.offset_y)
{ {
draw(); draw();
scrollbar_.value(state_.offset_y); scrollbar_.value(state_.offset_y);
@ -323,8 +316,7 @@ namespace nana
state_.renderer->image(_m_image_enabled(), image_pixels_); state_.renderer->image(_m_image_enabled(), image_pixels_);
for(std::size_t i = state_.offset_y; i < items; ++i) for(std::size_t i = state_.offset_y; i < items; ++i)
{ {
item_renderer::state_t state = item_renderer::StateNone; auto state = (i != state_.index ? item_renderer::StateNone : item_renderer::StateHighlighted);
if(i == state_.index) state = item_renderer::StateHighlighted;
state_.renderer->render(*widget_, *graph_, item_r, module_->items[i].get(), state); state_.renderer->render(*widget_, *graph_, item_r, module_->items[i].get(), state);
item_r.y += item_pixels; item_r.y += item_pixels;
@ -384,20 +376,20 @@ namespace nana
scrollbar_.close(); scrollbar_.close();
} }
private: private:
widget * widget_; widget * widget_{nullptr};
nana::paint::graphics * graph_; nana::paint::graphics * graph_{nullptr};
unsigned image_pixels_; //Define the width pixels of the image area unsigned image_pixels_{16}; //Define the width pixels of the image area
bool ignore_first_mouseup_; bool ignore_first_mouseup_{true};
struct state_type struct state_type
{ {
std::size_t offset_y; std::size_t offset_y{0};
std::size_t index; //The index of the selected item. std::size_t index{npos}; //The index of the selected item.
item_renderer * const orig_renderer; item_renderer * const orig_renderer;
item_renderer * renderer; item_renderer * renderer;
state_type(): offset_y(0), index(npos), orig_renderer(new def_item_renderer), renderer(orig_renderer){} state_type(): orig_renderer(new def_item_renderer), renderer(orig_renderer){}
~state_type() ~state_type()
{ {
delete orig_renderer; delete orig_renderer;
@ -405,7 +397,7 @@ namespace nana
}state_; }state_;
nana::scroll<true> scrollbar_; nana::scroll<true> scrollbar_;
const module_def* module_; const module_def* module_{nullptr};
}; };
//class drawer_impl; //class drawer_impl;

View File

@ -588,8 +588,6 @@ namespace nana
std::pair<std::size_t, std::size_t> _m_locate(dstream::linecontainer::iterator& i, std::size_t pos) std::pair<std::size_t, std::size_t> _m_locate(dstream::linecontainer::iterator& i, std::size_t pos)
{ {
//std::pair<std::size_t, std::size_t> r; //deprecated
std::size_t n = i->data_ptr->text().length(); std::size_t n = i->data_ptr->text().length();
while(pos >= n) while(pos >= n)
{ {

View File

@ -1,7 +1,7 @@
/* /*
* A Menu implementation * A Menu implementation
* Nana C++ Library(http://www.nanapro.org) * Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2009-2014 Jinhao(cnjinhao@hotmail.com) * Copyright(C) 2009-2015 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
@ -151,7 +151,7 @@ namespace nana
void item_text(graph_reference graph, const nana::point& pos, const nana::string& text, unsigned text_pixels, const attr& at) void item_text(graph_reference graph, const nana::point& pos, const nana::string& text, unsigned text_pixels, const attr& at)
{ {
graph.set_color(at.enabled ? colors::black : colors::gray_border); graph.set_text_color(at.enabled ? colors::black : colors::gray_border);
nana::paint::text_renderer tr(graph); nana::paint::text_renderer tr(graph);
tr.render(pos, text.c_str(), text.length(), text_pixels, true); tr.render(pos, text.c_str(), text.length(), text_pixels, true);
} }

View File

@ -58,16 +58,6 @@ namespace nana
cont_.push_back(new item_type(text, shortkey)); cont_.push_back(new item_type(text, shortkey));
} }
nana::menu* get_menu(std::size_t index) const
{
return (index < cont_.size() ? &(cont_[index]->menu_obj) : nullptr);
}
const item_type& at(std::size_t index) const
{
return *cont_.at(index);
}
std::size_t find(unsigned long shortkey) const std::size_t find(unsigned long shortkey) const
{ {
if(shortkey) if(shortkey)
@ -98,19 +88,19 @@ namespace nana
:handle_(wd), graph_(graph) :handle_(wd), graph_(graph)
{} {}
void item_renderer::background(const nana::point& pos, const nana::size& size, state_t state) void item_renderer::background(const nana::point& pos, const nana::size& size, state item_state)
{ {
auto bground = API::fgcolor(handle_); auto bground = API::fgcolor(handle_);
::nana::color border, body, corner; ::nana::color border, body, corner;
switch(state) switch (item_state)
{ {
case item_renderer::state_highlight: case state::highlighted:
border = colors::highlight; border = colors::highlight;
body.from_rgb(0xC0, 0xDD, 0xFC); body.from_rgb(0xC0, 0xDD, 0xFC);
corner = body.blend(bground, 0.5); corner = body.blend(bground, 0.5);
break; break;
case item_renderer::state_selected: case state::selected:
border = colors::dark_border; border = colors::dark_border;
body = colors::white; body = colors::white;
corner = body.blend(bground, 0.5); corner = body.blend(bground, 0.5);
@ -132,9 +122,9 @@ namespace nana
graph_.rectangle(r.pare_off(1), true, body); graph_.rectangle(r.pare_off(1), true, body);
} }
void item_renderer::caption(int x, int y, const nana::string& text) void item_renderer::caption(const point& pos, const nana::string& text)
{ {
graph_.string({ x, y }, text, colors::black); graph_.string(pos, text, colors::black);
} }
//end class item_renderer //end class item_renderer
@ -150,22 +140,26 @@ namespace nana
nana::menu* trigger::push_back(const ::nana::string& text) nana::menu* trigger::push_back(const ::nana::string& text)
{ {
::nana::string::value_type shkey; ::nana::char_t shkey;
API::transform_shortkey_text(text, shkey, nullptr); API::transform_shortkey_text(text, shkey, nullptr);
if(shkey) if(shkey)
API::register_shortkey(widget_->handle(), shkey); API::register_shortkey(widget_->handle(), shkey);
auto i = items_->cont().size(); auto pos = items_->cont().size();
items_->append(text, shkey); items_->append(text, shkey);
_m_draw(); _m_draw();
API::update_window(*widget_); API::update_window(*widget_);
return items_->get_menu(i);
return at(pos);
} }
nana::menu* trigger::at(std::size_t index) const nana::menu* trigger::at(std::size_t pos) const
{ {
return items_->get_menu(index); if (pos < items_->cont().size())
return &(items_->cont()[pos]->menu_obj);
return nullptr;
} }
std::size_t trigger::size() const std::size_t trigger::size() const
@ -222,22 +216,17 @@ namespace nana
void trigger::mouse_down(graph_reference graph, const arg_mouse& arg) void trigger::mouse_down(graph_reference graph, const arg_mouse& arg)
{ {
state_.nullify_mouse = false; state_.nullify_mouse = false;
state_.active = _m_item_by_pos(arg.pos); state_.active = _m_item_by_pos(arg.pos);
if(state_.menu_active == false)
if (npos != state_.active)
{ {
if(state_.active != npos) if (!state_.menu_active)
{
state_.menu_active = true; state_.menu_active = true;
_m_popup_menu();
}
else
_m_total_close(true);
}
else if(npos == state_.active)
_m_total_close(true);
else
_m_popup_menu(); _m_popup_menu();
}
else
_m_total_close();
_m_draw(); _m_draw();
API::lazy_refresh(); API::lazy_refresh();
@ -255,11 +244,10 @@ namespace nana
else else
{ {
state_.behavior = state_.behavior_none; state_.behavior = state_.behavior_none;
_m_total_close(true); _m_total_close();
_m_draw(); _m_draw();
API::lazy_refresh(); API::lazy_refresh();
} }
} }
void trigger::focus(graph_reference, const arg_focus& arg) void trigger::focus(graph_reference, const arg_focus& arg)
@ -284,10 +272,10 @@ namespace nana
switch(arg.key) switch(arg.key)
{ {
case keyboard::os_arrow_down: case keyboard::os_arrow_down:
state_.menu->goto_next(true); break;
case keyboard::backspace: case keyboard::backspace:
case keyboard::os_arrow_up: case keyboard::os_arrow_up:
state_.menu->goto_next(false); break; state_.menu->goto_next(keyboard::os_arrow_down == arg.key);
break;
case keyboard::os_arrow_right: case keyboard::os_arrow_right:
if(state_.menu->goto_submen() == false) if(state_.menu->goto_submen() == false)
_m_move(false); _m_move(false);
@ -305,19 +293,14 @@ namespace nana
} }
break; break;
case keyboard::enter: case keyboard::enter:
state_.delay_restore = true;
state_.menu->pick(); state_.menu->pick();
break; break;
default: default:
if(2 != state_.menu->send_shortkey(arg.key)) if (2 != state_.menu->send_shortkey(arg.key))
{ {
if (state_.active != npos) _m_total_close();
{ if (arg.key == 18) //ALT
state_.delay_restore = true; state_.behavior = state_.behavior_focus;
_m_total_close(false);
if (arg.key == 18) //ALT
state_.behavior = state_.behavior_focus;
}
} }
else else
state_.menu->goto_submen(); state_.menu->goto_submen();
@ -328,18 +311,15 @@ namespace nana
switch(arg.key) switch(arg.key)
{ {
case keyboard::os_arrow_right: case keyboard::os_arrow_right:
_m_move(false);
break;
case keyboard::backspace: case keyboard::backspace:
case keyboard::os_arrow_left: case keyboard::os_arrow_left:
_m_move(true); _m_move(keyboard::os_arrow_right != arg.key);
break; break;
case keyboard::escape: case keyboard::escape:
if(state_.behavior == state_.behavior_focus) if(state_.behavior == state_.behavior_focus)
{ {
state_.active= npos; state_.active= npos;
state_.behavior = state_.behavior_none; state_.behavior = state_.behavior_none;
API::restore_menubar_taken_window();
} }
} }
} }
@ -369,12 +349,6 @@ namespace nana
_m_draw(); _m_draw();
API::lazy_refresh(); API::lazy_refresh();
} }
if (state_.delay_restore)
{
API::restore_menubar_taken_window();
state_.delay_restore = false;
}
} }
void trigger::shortkey(graph_reference graph, const arg_keyboard& arg) void trigger::shortkey(graph_reference graph, const arg_keyboard& arg)
@ -430,33 +404,44 @@ namespace nana
bool trigger::_m_popup_menu() bool trigger::_m_popup_menu()
{ {
if(state_.menu_active && (state_.menu != items_->get_menu(state_.active))) auto& items = items_->cont();
{
std::size_t index = state_.active;
_m_close_menu();
state_.active = index;
state_.menu = items_->get_menu(state_.active); auto pos = state_.active;
if(state_.menu) 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]
{ {
const item_type &m = items_->at(state_.active); state_.menu = nullptr;
state_.menu->destroy_answer(std::bind(&trigger::_m_unload_menu_window, this)); if (state_.passive_close)
menu_accessor::popup(*state_.menu, widget_->handle(), m.pos.x, m.pos.y + m.size.height); {
return true; _m_total_close();
}
_m_draw();
API::update_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; return false;
} }
void trigger::_m_total_close(bool try_restore) void trigger::_m_total_close()
{ {
_m_close_menu(); _m_close_menu();
state_.menu_active = false; state_.menu_active = false;
state_.behavior = state_.behavior_none; state_.behavior = state_.behavior_none;
if (try_restore)
API::restore_menubar_taken_window();
auto pos = API::cursor_position(); auto pos = API::cursor_position();
API::calc_window_point(widget_->handle(), pos); API::calc_window_point(widget_->handle(), pos);
state_.active = _m_item_by_pos(pos); state_.active = _m_item_by_pos(pos);
@ -475,18 +460,6 @@ namespace nana
return false; return false;
} }
void trigger::_m_unload_menu_window()
{
state_.menu = nullptr;
if(state_.passive_close)
{
_m_total_close(false);
_m_draw();
API::update_window(widget_->handle());
}
}
std::size_t trigger::_m_item_by_pos(const ::nana::point& pos) std::size_t trigger::_m_item_by_pos(const ::nana::point& pos)
{ {
if((2 <= pos.x) && (2 <= pos.y) && (pos.y < 25)) if((2 <= pos.x) && (2 <= pos.y) && (pos.y < 25))
@ -534,9 +507,9 @@ namespace nana
for(auto i : items_->cont()) for(auto i : items_->cont())
{ {
//Transform the text if it contains the hotkey character //Transform the text if it contains the hotkey character
nana::string::value_type hotkey; ::nana::char_t hotkey;
nana::string::size_type hotkey_pos; ::nana::string::size_type hotkey_pos;
nana::string text = API::transform_shortkey_text(i->text, hotkey, &hotkey_pos); auto text = API::transform_shortkey_text(i->text, hotkey, &hotkey_pos);
nana::size text_s = graph_->text_extent_size(text); nana::size text_s = graph_->text_extent_size(text);
@ -545,10 +518,11 @@ namespace nana
i->pos = item_pos; i->pos = item_pos;
i->size = item_s; i->size = item_s;
item_renderer::state_t state = (index != state_.active ? ird.state_normal : (state_.menu_active ? ird.state_selected : ird.state_highlight)); using state = item_renderer::state;
ird.background(item_pos, item_s, state); state item_state = (index != state_.active ? state::normal : (state_.menu_active ? state::selected : state::highlighted));
ird.background(item_pos, item_s, item_state);
if(state == ird.state_selected) if (state::selected == item_state)
{ {
int x = item_pos.x + item_s.width; int x = item_pos.x + item_s.width;
int y1 = item_pos.y + 2, y2 = item_pos.y + item_s.height - 1; int y1 = item_pos.y + 2, y2 = item_pos.y + item_s.height - 1;
@ -558,7 +532,7 @@ namespace nana
//Draw text, the text is transformed from orignal for hotkey character //Draw text, the text is transformed from orignal for hotkey character
int text_top_off = (item_s.height - text_s.height) / 2; int text_top_off = (item_s.height - text_s.height) / 2;
ird.caption(item_pos.x + 8, item_pos.y + text_top_off, text); ird.caption({ item_pos.x + 8, item_pos.y + text_top_off }, text);
if(hotkey) if(hotkey)
{ {
@ -584,8 +558,7 @@ namespace nana
menu_active(false), menu_active(false),
passive_close(true), passive_close(true),
nullify_mouse(false), nullify_mouse(false),
menu(nullptr), menu(nullptr)
delay_restore(false)
{} {}
//end struct state_type //end struct state_type
//end class trigger //end class trigger