diff --git a/include/nana/gui/detail/basic_window.hpp b/include/nana/gui/detail/basic_window.hpp index 2834c870..8016836c 100644 --- a/include/nana/gui/detail/basic_window.hpp +++ b/include/nana/gui/detail/basic_window.hpp @@ -166,7 +166,8 @@ namespace detail bool fullscreen :1; //When the window is maximizing whether it fit for fullscreen. bool borderless :1; 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 mouse_action action; }flags; diff --git a/include/nana/gui/detail/bedrock.hpp b/include/nana/gui/detail/bedrock.hpp index 71a52149..1ae2a41d 100644 --- a/include/nana/gui/detail/bedrock.hpp +++ b/include/nana/gui/detail/bedrock.hpp @@ -54,13 +54,14 @@ namespace detail native_window_type root(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); 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(); - void remove_menu(); - void empty_menu(); + void erase_menu(bool try_destroy); void get_key_state(arg_keyboard&); bool set_keyboard_shortkey(bool yes); diff --git a/include/nana/gui/programming_interface.hpp b/include/nana/gui/programming_interface.hpp index 7caf038b..09bb1c84 100644 --- a/include/nana/gui/programming_interface.hpp +++ b/include/nana/gui/programming_interface.hpp @@ -77,6 +77,8 @@ namespace API window create_frame(window, const rectangle&, widget* attached); paint::graphics* window_graphics(window); + + void delay_restore(bool); }//end namespace dev @@ -290,7 +292,6 @@ namespace API void register_menu_window(window, bool has_keyboard); bool attach_menubar(window menubar); void detach_menubar(window menubar); - void restore_menubar_taken_window(); bool is_window_zoomed(window, bool ask_for_max); ///input_context_event_mask) == addr->input_context_event_mask) { 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(wd), CWEventMask, &new_attr); } } diff --git a/source/gui/detail/basic_window.cpp b/source/gui/detail/basic_window.cpp index f1bd3c95..4cb500bf 100644 --- a/source/gui/detail/basic_window.cpp +++ b/source/gui/detail/basic_window.cpp @@ -347,6 +347,7 @@ namespace nana flags.destroying = false; flags.borderless = false; flags.make_bground_declared = false; + flags.ignore_menubar_focus = false; visible = false; diff --git a/source/gui/detail/bedrock_selector.cpp b/source/gui/detail/bedrock_selector.cpp index 62ca3673..3d10fd7b 100644 --- a/source/gui/detail/bedrock_selector.cpp +++ b/source/gui/detail/bedrock_selector.cpp @@ -1,7 +1,7 @@ /* * Bedrock Selector * 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. * (See accompanying file LICENSE_1_0.txt or copy at diff --git a/source/gui/detail/linux_X11/bedrock.cpp b/source/gui/detail/linux_X11/bedrock.cpp index 886f1493..94f35223 100644 --- a/source/gui/detail/linux_X11/bedrock.cpp +++ b/source/gui/detail/linux_X11/bedrock.cpp @@ -102,27 +102,18 @@ namespace detail { struct thread_context_cache { - unsigned tid; - thread_context *object; + unsigned tid{ 0 }; + thread_context *object{ nullptr }; }tcontext; - - cache_type() - { - tcontext.tid = 0; - tcontext.object = nullptr; - } }cache; struct menu_tag { - menu_tag() - :taken_window(nullptr), window(nullptr), owner(nullptr), has_keyboard(false) - {} - - core_window_t* taken_window; - native_window_type window; - native_window_type owner; - bool has_keyboard; + core_window_t* taken_window{ nullptr }; + bool delay_restore{ false }; + native_window_type window{ nullptr }; + native_window_type owner{ nullptr }; + bool has_keyboard{ false }; }menu; struct keyboard_tracking_state_tag @@ -282,14 +273,39 @@ namespace detail void bedrock::set_menubar_taken(core_window_t* wd) { + auto pre = impl_->menu.taken_window; 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; - impl_->menu.taken_window = nullptr; - return wd; + switch (state) + { + 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) @@ -304,7 +320,7 @@ namespace detail else return false; } - remove_menu(); + erase_menu(true); return true; } return false; @@ -314,7 +330,7 @@ namespace detail { if(menu_window && impl_->menu.window != menu_window) { - remove_menu(); + erase_menu(true); impl_->menu.window = menu_window; impl_->menu.owner = native_interface::get_owner_window(menu_window); impl_->menu.has_keyboard = has_keyboard; @@ -338,21 +354,13 @@ namespace detail 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; - impl_->menu.window = impl_->menu.owner = nullptr; - impl_->menu.has_keyboard = false; - native_interface::close_window(delwin); - } - } + if (try_destroy) + native_interface::close_window(impl_->menu.window); - void bedrock::empty_menu() - { - if(impl_->menu.window) - { impl_->menu.window = impl_->menu.owner = nullptr; impl_->menu.has_keyboard = false; } @@ -372,6 +380,11 @@ namespace detail return ret; } + bool bedrock::whether_keyboard_shortkey() const + { + return impl_->keyboard_tracking_state.has_shortkey_occured; + } + element_store& bedrock::get_element_store() const { return impl_->estore; @@ -700,8 +713,8 @@ namespace detail msgwnd = brock.wd_manager.find_window(native_window, xevent.xbutton.x, xevent.xbutton.y); if(nullptr == msgwnd) break; - if((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true)) - brock.remove_menu(); + if ((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true)) + brock.erase_menu(true); else brock.close_menu_if_focus_other_window(msgwnd->root); @@ -719,7 +732,7 @@ namespace detail if(kill_focus != new_focus) 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; context.event_window = msgwnd; @@ -773,7 +786,7 @@ namespace detail msgwnd->flags.action = mouse_action::normal; if(msgwnd->flags.enabled) { - auto retain = msgwnd->together.event_ptr; + auto retain = msgwnd->together.events_ptr; arg_mouse arg; assign_arg(arg, msgwnd, message, xevent); @@ -829,8 +842,11 @@ namespace detail if(brock.wd_manager.available(msgwnd)) { //The msgwnd may be destroyed if the window is destroyed by calling native interface of close_window(). - if(msgwnd->root == brock.get_menu()) - brock.empty_menu(); + if (msgwnd->root == brock.get_menu()) + { + brock.erase_menu(false); + brock.delay_restore(3); //Restores if delay_restore not decleared + } spec.remove(native_window); brock.wd_manager.destroy(msgwnd); @@ -929,6 +945,9 @@ namespace detail nana::detail::platform_spec::instance().write_keystate(xevent.xkey); if(msgwnd->flags.enabled) { + if (brock.get_menu()) + brock.delay_restore(0); //Enable delay restore + if(msgwnd->root != brock.get_menu()) msgwnd = brock.focus(); @@ -1011,12 +1030,31 @@ namespace detail else if(keyboard::alt == keychar) { 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(msgwnd); + arg.ignore = false; + arg.key = static_cast(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.ignore = false; - arg.key = keychar; + arg.key = keychar ? keychar : xevent.xkey.keycode; arg.evt_code = event_code::key_press; brock.get_key_state(arg); arg.window_handle = reinterpret_cast(msgwnd); @@ -1093,11 +1131,35 @@ namespace detail brock.get_key_state(arg); brock.emit(event_code::key_release, msgwnd, arg, true, &context); } + brock.delay_restore(2); //Restores while key release } else { 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(msgwnd); + arg.ignore = false; + arg.key = static_cast(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; default: diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp index 0ad45b61..a01d80b8 100644 --- a/source/gui/detail/native_window_interface.cpp +++ b/source/gui/detail/native_window_interface.cpp @@ -580,27 +580,30 @@ namespace nana{ //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 //works should be handled before calling XDestroyWindow. - auto & bedrock = bedrock::instance(); - if(wd == bedrock.get_menu()) - bedrock.empty_menu(); + auto & brock = bedrock::instance(); + if(wd == brock.get_menu()) + { + brock.erase_menu(false); + brock.delay_restore(3); //Restores if delay_restore is not decleard + } Display* disp = restrict::spec.open_display(); restrict::spec.remove(wd); - auto iwd = bedrock.wd_manager.root(wd); + auto iwd = brock.wd_manager.root(wd); if(iwd) { { //Before calling window_manager::destroy, make sure the window is invisible. //It is a behavior like Windows. - nana::detail::platform_scope_guard psg; + nana::detail::platform_scope_guard lock; restrict::spec.set_error_handler(); ::XUnmapWindow(disp, reinterpret_cast(wd)); ::XFlush(disp); restrict::spec.rev_error_handler(); } - bedrock.wd_manager.destroy(iwd); - bedrock.rt_manager.remove_if_exists(iwd); - bedrock.wd_manager.destroy_handle(iwd); + brock.wd_manager.destroy(iwd); + brock.rt_manager.remove_if_exists(iwd); + brock.wd_manager.destroy_handle(iwd); } nana::detail::platform_scope_guard psg; diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp index 94e90e23..38740d97 100644 --- a/source/gui/detail/win32/bedrock.cpp +++ b/source/gui/detail/win32/bedrock.cpp @@ -185,17 +185,18 @@ namespace detail { struct thread_context_cache { - unsigned tid = 0; - thread_context *object = nullptr; + unsigned tid{ 0 }; + thread_context *object{ nullptr }; }tcontext; }cache; struct menu_tag { - core_window_t* taken_window = nullptr; - native_window_type window = nullptr; - native_window_type owner = nullptr; - bool has_keyboard = false; + core_window_t* taken_window{ nullptr }; + bool delay_restore{ false }; + native_window_type window{ nullptr }; + native_window_type owner{ nullptr }; + bool has_keyboard{false}; }menu; struct keyboard_tracking_state_tag @@ -921,8 +922,8 @@ namespace detail if(nullptr == msgwnd) break; //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)) - brock.remove_menu(); + if ((msgwnd == msgwnd->root_widget->other.attribute.root->menubar) && brock.get_menu(msgwnd->root, true)) + brock.erase_menu(true); else brock.close_menu_if_focus_other_window(msgwnd->root); @@ -1322,13 +1323,12 @@ namespace detail def_window_proc = true; break; case WM_SYSKEYDOWN: - if(brock.whether_keyboard_shortkey() == false) + if (brock.whether_keyboard_shortkey() == false) { 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.evt_code = event_code::key_press; arg.window_handle = reinterpret_cast(msgwnd); @@ -1336,9 +1336,11 @@ namespace detail arg.key = static_cast(wParam); 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 if(brock.get_menu()) - brock.remove_menu(); + else + brock.erase_menu(true); } def_window_proc = true; break; @@ -1348,6 +1350,10 @@ namespace detail 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(msgwnd); @@ -1355,6 +1361,12 @@ namespace detail arg.key = static_cast(wParam); 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; + } } } def_window_proc = true; @@ -1362,6 +1374,9 @@ namespace detail case WM_KEYDOWN: if(msgwnd->flags.enabled) { + if (brock.get_menu()) + brock.delay_restore(0); //Enable delay restore + if(msgwnd->root != brock.get_menu()) msgwnd = brock.focus(); @@ -1431,6 +1446,8 @@ namespace detail } else brock.set_keyboard_shortkey(false); + + brock.delay_restore(2); //Restores while key release break; case WM_CLOSE: { @@ -1448,8 +1465,12 @@ namespace detail break; } case WM_DESTROY: - if(msgwnd->root == brock.get_menu()) - brock.empty_menu(); + if (msgwnd->root == brock.get_menu()) + { + brock.erase_menu(false); + brock.delay_restore(3); //Restores if delay_restore not decleared + } + brock.wd_manager.destroy(msgwnd); 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) { + auto pre = impl_->menu.taken_window; 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; - impl_->menu.taken_window = nullptr; - return wd; + switch (state) + { + 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) @@ -1534,7 +1580,7 @@ namespace detail else return false; } - remove_menu(); + erase_menu(true); return true; } return false; @@ -1544,7 +1590,7 @@ namespace detail { if(menu_wd && impl_->menu.window != menu_wd) { - remove_menu(); + erase_menu(true); impl_->menu.window = menu_wd; impl_->menu.owner = native_interface::get_owner_window(menu_wd); @@ -1568,21 +1614,13 @@ namespace detail return impl_->menu.window; } - void bedrock::remove_menu() + void bedrock::erase_menu(bool try_destroy) { - if(impl_->menu.window) - { - auto delwin = impl_->menu.window; - impl_->menu.window = impl_->menu.owner = nullptr; - impl_->menu.has_keyboard = false; - native_interface::close_window(delwin); - } - } - - void bedrock::empty_menu() - { - if(impl_->menu.window) + if (impl_->menu.window) { + if (try_destroy) + native_interface::close_window(impl_->menu.window); + impl_->menu.window = impl_->menu.owner = nullptr; impl_->menu.has_keyboard = false; } diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index fb0d0491..93186a57 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -884,7 +884,8 @@ namespace detail if (wd == wd->root_widget->other.attribute.root->menubar) 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; } diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index 6af6945d..c2db60b8 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -240,6 +240,11 @@ namespace API return &reinterpret_cast(wd)->drawer.graphics; return nullptr; } + + void delay_restore(bool enable) + { + restrict::bedrock.delay_restore(enable ? 0 : 1); + } }//end namespace dev //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) { auto const iwd = reinterpret_cast(wd); diff --git a/source/gui/widgets/float_listbox.cpp b/source/gui/widgets/float_listbox.cpp index 3f569aee..8af19e43 100644 --- a/source/gui/widgets/float_listbox.cpp +++ b/source/gui/widgets/float_listbox.cpp @@ -37,21 +37,25 @@ namespace nana ::nana::color clr{ 0xaf, 0xc7, 0xe3 }; graph.rectangle(r, false, clr); + auto right = r.right() - 1; + auto bottom = r.bottom() - 1; graph.set_color(colors::white); graph.set_pixel(r.x, r.y); - graph.set_pixel(r.x + r.width - 1, r.y); - graph.set_pixel(r.x, r.y + r.height - 1); - graph.set_pixel(r.x + r.width - 1, r.y + r.height - 1); + graph.set_pixel(right, r.y); + graph.set_pixel(r.x, bottom); + graph.set_pixel(right, bottom); + --right; + --bottom; graph.set_color(clr); graph.set_pixel(r.x + 1, r.y + 1); - graph.set_pixel(r.x + r.width - 2, r.y + 1); - graph.set_pixel(r.x + 1, r.y + r.height - 2); - graph.set_pixel(r.x + r.width - 2, r.y + r.height - 2); + graph.set_pixel(right, r.y + 1); + graph.set_pixel(r.x + 1, bottom); + graph.set_pixel(right, bottom); nana::rectangle po_r(r); - graph.rectangle(po_r.pare_off(1), false, { 0xEB, 0xF4, 0xFB }); - graph.gradual_rectangle(po_r.pare_off(1), { 0xDD, 0xEC, 0xFD }, { 0xC2, 0xDC, 0xFD }, true); + graph.rectangle(po_r.pare_off(1), false, static_cast(0xEBF4FB)); + graph.gradual_rectangle(po_r.pare_off(1), static_cast(0xDDECFD), static_cast(0xC2DCFD), true); } else graph.rectangle(r, true, colors::white); @@ -113,13 +117,8 @@ namespace nana class drawer_impl { public: - typedef widget& widget_reference; - typedef nana::paint::graphics& graph_reference; - - drawer_impl() - : widget_(nullptr), graph_(nullptr), image_pixels_(16), - ignore_first_mouseup_(true), module_(nullptr) - {} + using widget_reference = widget&; + using graph_reference = paint::graphics&; void clear_state() { @@ -151,25 +150,19 @@ namespace nana { if(scrollbar_.empty()) return; - bool update = false; + const auto before_change = state_.offset_y; if(upwards) { - if(state_.offset_y) - { + if (before_change) --(state_.offset_y); - update = true; - } } else { - if((state_.offset_y + module_->max_items) < module_->items.size()) - { + if ((before_change + module_->max_items) < module_->items.size()) ++(state_.offset_y); - update = true; - } } - if(update) + if(before_change != state_.offset_y) { draw(); scrollbar_.value(state_.offset_y); @@ -323,8 +316,7 @@ namespace nana state_.renderer->image(_m_image_enabled(), image_pixels_); for(std::size_t i = state_.offset_y; i < items; ++i) { - item_renderer::state_t state = item_renderer::StateNone; - if(i == state_.index) state = item_renderer::StateHighlighted; + auto state = (i != state_.index ? item_renderer::StateNone : item_renderer::StateHighlighted); state_.renderer->render(*widget_, *graph_, item_r, module_->items[i].get(), state); item_r.y += item_pixels; @@ -384,20 +376,20 @@ namespace nana scrollbar_.close(); } private: - widget * widget_; - nana::paint::graphics * graph_; - unsigned image_pixels_; //Define the width pixels of the image area + widget * widget_{nullptr}; + nana::paint::graphics * graph_{nullptr}; + unsigned image_pixels_{16}; //Define the width pixels of the image area - bool ignore_first_mouseup_; + bool ignore_first_mouseup_{true}; struct state_type { - std::size_t offset_y; - std::size_t index; //The index of the selected item. + std::size_t offset_y{0}; + std::size_t index{npos}; //The index of the selected item. item_renderer * const orig_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() { delete orig_renderer; @@ -405,7 +397,7 @@ namespace nana }state_; nana::scroll scrollbar_; - const module_def* module_; + const module_def* module_{nullptr}; }; //class drawer_impl; diff --git a/source/gui/widgets/label.cpp b/source/gui/widgets/label.cpp index ab40bda8..66e76027 100644 --- a/source/gui/widgets/label.cpp +++ b/source/gui/widgets/label.cpp @@ -588,8 +588,6 @@ namespace nana std::pair _m_locate(dstream::linecontainer::iterator& i, std::size_t pos) { - //std::pair r; //deprecated - std::size_t n = i->data_ptr->text().length(); while(pos >= n) { diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index d8445c0d..c8c8fa03 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -1,7 +1,7 @@ /* * A Menu implementation * 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. * (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) { - 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); tr.render(pos, text.c_str(), text.length(), text_pixels, true); } diff --git a/source/gui/widgets/menubar.cpp b/source/gui/widgets/menubar.cpp index 8a19b321..63401c0f 100644 --- a/source/gui/widgets/menubar.cpp +++ b/source/gui/widgets/menubar.cpp @@ -58,16 +58,6 @@ namespace nana 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 { if(shortkey) @@ -98,19 +88,19 @@ namespace nana :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_); ::nana::color border, body, corner; - switch(state) + switch (item_state) { - case item_renderer::state_highlight: + case state::highlighted: border = colors::highlight; body.from_rgb(0xC0, 0xDD, 0xFC); corner = body.blend(bground, 0.5); break; - case item_renderer::state_selected: + case state::selected: border = colors::dark_border; body = colors::white; corner = body.blend(bground, 0.5); @@ -132,9 +122,9 @@ namespace nana 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 @@ -150,22 +140,26 @@ namespace nana 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); if(shkey) API::register_shortkey(widget_->handle(), shkey); - auto i = items_->cont().size(); + auto pos = items_->cont().size(); items_->append(text, shkey); _m_draw(); 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 @@ -222,22 +216,17 @@ namespace nana void trigger::mouse_down(graph_reference graph, const arg_mouse& arg) { state_.nullify_mouse = false; - 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; - _m_popup_menu(); - } - else - _m_total_close(true); - } - else if(npos == state_.active) - _m_total_close(true); - else + _m_popup_menu(); + } + else + _m_total_close(); _m_draw(); API::lazy_refresh(); @@ -255,11 +244,10 @@ namespace nana else { state_.behavior = state_.behavior_none; - _m_total_close(true); + _m_total_close(); _m_draw(); API::lazy_refresh(); } - } void trigger::focus(graph_reference, const arg_focus& arg) @@ -284,10 +272,10 @@ namespace nana switch(arg.key) { case keyboard::os_arrow_down: - state_.menu->goto_next(true); break; case keyboard::backspace: 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: if(state_.menu->goto_submen() == false) _m_move(false); @@ -305,19 +293,14 @@ namespace nana } break; case keyboard::enter: - state_.delay_restore = true; state_.menu->pick(); break; default: - if(2 != state_.menu->send_shortkey(arg.key)) + if (2 != state_.menu->send_shortkey(arg.key)) { - if (state_.active != npos) - { - state_.delay_restore = true; - _m_total_close(false); - if (arg.key == 18) //ALT - state_.behavior = state_.behavior_focus; - } + _m_total_close(); + if (arg.key == 18) //ALT + state_.behavior = state_.behavior_focus; } else state_.menu->goto_submen(); @@ -328,18 +311,15 @@ namespace nana switch(arg.key) { case keyboard::os_arrow_right: - _m_move(false); - break; case keyboard::backspace: case keyboard::os_arrow_left: - _m_move(true); + _m_move(keyboard::os_arrow_right != arg.key); break; case keyboard::escape: if(state_.behavior == state_.behavior_focus) { state_.active= npos; state_.behavior = state_.behavior_none; - API::restore_menubar_taken_window(); } } } @@ -369,12 +349,6 @@ namespace nana _m_draw(); 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) @@ -430,33 +404,44 @@ namespace nana bool trigger::_m_popup_menu() { - if(state_.menu_active && (state_.menu != items_->get_menu(state_.active))) - { - std::size_t index = state_.active; - _m_close_menu(); - state_.active = index; + auto& items = items_->cont(); - state_.menu = items_->get_menu(state_.active); - if(state_.menu) + 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] { - const item_type &m = items_->at(state_.active); - state_.menu->destroy_answer(std::bind(&trigger::_m_unload_menu_window, this)); - menu_accessor::popup(*state_.menu, widget_->handle(), m.pos.x, m.pos.y + m.size.height); - return true; - } + state_.menu = nullptr; + if (state_.passive_close) + { + _m_total_close(); + + _m_draw(); + API::update_window(widget_->handle()); + } + }); + menu_accessor::popup(*state_.menu, *widget_, m->pos.x, m->pos.y + static_cast(m->size.height)); + return true; } return false; } - void trigger::_m_total_close(bool try_restore) + void trigger::_m_total_close() { _m_close_menu(); state_.menu_active = false; state_.behavior = state_.behavior_none; - if (try_restore) - API::restore_menubar_taken_window(); - auto pos = API::cursor_position(); API::calc_window_point(widget_->handle(), pos); state_.active = _m_item_by_pos(pos); @@ -475,18 +460,6 @@ namespace nana 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) { if((2 <= pos.x) && (2 <= pos.y) && (pos.y < 25)) @@ -534,9 +507,9 @@ namespace nana for(auto i : items_->cont()) { //Transform the text if it contains the hotkey character - nana::string::value_type hotkey; - nana::string::size_type hotkey_pos; - nana::string text = API::transform_shortkey_text(i->text, hotkey, &hotkey_pos); + ::nana::char_t hotkey; + ::nana::string::size_type hotkey_pos; + auto text = API::transform_shortkey_text(i->text, hotkey, &hotkey_pos); nana::size text_s = graph_->text_extent_size(text); @@ -545,10 +518,11 @@ namespace nana i->pos = item_pos; i->size = item_s; - item_renderer::state_t state = (index != state_.active ? ird.state_normal : (state_.menu_active ? ird.state_selected : ird.state_highlight)); - ird.background(item_pos, item_s, state); + using state = item_renderer::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 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 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) { @@ -584,8 +558,7 @@ namespace nana menu_active(false), passive_close(true), nullify_mouse(false), - menu(nullptr), - delay_restore(false) + menu(nullptr) {} //end struct state_type //end class trigger