diff --git a/include/nana/gui/detail/basic_window.hpp b/include/nana/gui/detail/basic_window.hpp index 207f7e3b..ed2e1db4 100644 --- a/include/nana/gui/detail/basic_window.hpp +++ b/include/nana/gui/detail/basic_window.hpp @@ -1,7 +1,7 @@ /* * A Basic Window Widget Definition * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -167,7 +167,8 @@ namespace detail bool make_bground_declared : 1; //explicitly make bground for bground effects bool ignore_menubar_focus : 1; //A flag indicates whether the menubar sets the focus. bool ignore_mouse_focus : 1; //A flag indicates whether the widget accepts focus when clicking on it - unsigned Reserved :19; + bool space_click_enabled : 1; //A flag indicates whether enable mouse_down/click/mouse_up when pressing and releasing whitespace key. + unsigned Reserved :18; unsigned char tab; //indicate a window that can receive the keyboard TAB mouse_action action; }flags; diff --git a/include/nana/gui/detail/inner_fwd_implement.hpp b/include/nana/gui/detail/inner_fwd_implement.hpp index e420c554..90589d3c 100644 --- a/include/nana/gui/detail/inner_fwd_implement.hpp +++ b/include/nana/gui/detail/inner_fwd_implement.hpp @@ -119,8 +119,9 @@ namespace nana{ struct condition_tag { - core_window_t* pressed{nullptr}; //The handle to a window which is being pressed - core_window_t* hovered{nullptr}; //the latest window that mouse moved + core_window_t* pressed{nullptr}; //The handle to a window which has been pressed by pressing left button of mouse. + core_window_t* pressed_by_space{ nullptr }; //The handle to a window which has been pressed by pressing spacebar. + core_window_t* hovered{nullptr}; //the latest window that mouse moved }condition; root_misc(core_window_t * wd, unsigned width, unsigned height) diff --git a/include/nana/gui/programming_interface.hpp b/include/nana/gui/programming_interface.hpp index 4585ed0c..8adfd2eb 100644 --- a/include/nana/gui/programming_interface.hpp +++ b/include/nana/gui/programming_interface.hpp @@ -1,7 +1,7 @@ /* * Nana GUI Programming Interface Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -86,6 +86,8 @@ namespace API void register_menu_window(window, bool has_keyboard); void set_menubar(window wd, bool attach); + + void enable_space_click(window, bool enable); }//end namespace dev diff --git a/include/nana/gui/widgets/button.hpp b/include/nana/gui/widgets/button.hpp index abf78616..bddeca77 100644 --- a/include/nana/gui/widgets/button.hpp +++ b/include/nana/gui/widgets/button.hpp @@ -43,9 +43,7 @@ namespace nana{ void mouse_leave(graph_reference, const arg_mouse&) override; void mouse_down(graph_reference, const arg_mouse&) override; void mouse_up(graph_reference, const arg_mouse&) override; - void key_char(graph_reference, const arg_keyboard&) override; void key_press(graph_reference, const arg_keyboard&) override; - void key_release(graph_reference, const arg_keyboard&) override; void focus(graph_reference, const arg_focus&) override; private: void _m_draw_title(graph_reference, bool enabled); diff --git a/include/nana/gui/widgets/label.hpp b/include/nana/gui/widgets/label.hpp index fef3b661..6b71bd88 100644 --- a/include/nana/gui/widgets/label.hpp +++ b/include/nana/gui/widgets/label.hpp @@ -65,7 +65,8 @@ namespace nana label& format(bool); ///< Switches the format mode of the widget. label& add_format_listener(std::function); - label& click_for(window associated_window) throw(); // as same as the "for" attribute of a label + /// as same as the HTML "for" attribute of a label + label& click_for(window associated_window) throw(); /// Returns the size of the text. If *allowed_width_in_pixel* is not zero, returns a /// "corrected" size that changes lines to fit the text into the specified width diff --git a/source/gui/detail/basic_window.cpp b/source/gui/detail/basic_window.cpp index 6c7146eb..9c1a5ae0 100644 --- a/source/gui/detail/basic_window.cpp +++ b/source/gui/detail/basic_window.cpp @@ -1,3 +1,15 @@ +/* +* A Basic Window Widget Definition +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt or copy at +* http://www.boost.org/LICENSE_1_0.txt) +* +* @file: nana/gui/detail/basic_window.cpp +*/ + #include #include @@ -384,6 +396,7 @@ namespace nana flags.make_bground_declared = false; flags.ignore_menubar_focus = false; flags.ignore_mouse_focus = false; + flags.space_click_enabled = false; visible = false; diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index 1e383e61..a8f78c37 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -233,7 +233,7 @@ namespace detail { if(wd) { - internal_scope_guard isg; + internal_scope_guard lock; if(wd_manager().available(wd)) return wd->other.category; } @@ -656,12 +656,17 @@ namespace detail auto pre_event_window = context.event_window; auto pressed_wd = root_runtime->condition.pressed; + auto pressed_wd_space = root_runtime->condition.pressed_by_space; auto hovered_wd = root_runtime->condition.hovered; const int message = xevent.type; switch(xevent.type) { case EnterNotify: + //Ignore mouse events when a window has been pressed by pressing spacebar. + if(pressed_wd_space) + break; + msgwnd = brock.wd_manager().find_window(native_window, xevent.xcrossing.x, xevent.xcrossing.y); if(msgwnd) { @@ -733,6 +738,10 @@ namespace detail } break; case ButtonPress: + //Ignore mouse events when a window has been pressed by pressing spacebar + if(pressed_wd_space) + break; + if(xevent.xbutton.button == Button4 || xevent.xbutton.button == Button5) break; @@ -788,6 +797,10 @@ namespace detail } break; case ButtonRelease: + //Ignore mouse events when a window has been pressed by pressing spacebar + if(pressed_wd_space) + break; + if(xevent.xbutton.button == Button4 || xevent.xbutton.button == Button5) { //The hovered window receives the message, unlike in Windows, no redirection is required. @@ -898,6 +911,10 @@ namespace detail else break; + //Ignore mouse events when a window has been pressed by pressing spacebar + if(pressed_wd_space) + break; + msgwnd = brock.wd_manager().find_window(native_window, xevent.xmotion.x, xevent.xmotion.y); if (brock.wd_manager().available(hovered_wd) && (msgwnd != hovered_wd)) { @@ -1018,6 +1035,7 @@ namespace detail keybuf[len] = 0; wchar_t os_code = 0; + auto & wd_manager = brock.wd_manager(); switch(status) { case XLookupKeySym: @@ -1027,11 +1045,37 @@ namespace detail { arg_keyboard argkey; brock.get_key_state(argkey); - auto tstop_wd = brock.wd_manager().tabstop(msgwnd, !argkey.shift); + auto tstop_wd = wd_manager.tabstop(msgwnd, !argkey.shift); if (tstop_wd) { - brock.wd_manager().set_focus(tstop_wd, false); - brock.wd_manager().do_lazy_refresh(tstop_wd, true); + wd_manager.set_focus(tstop_wd, false); + wd_manager.do_lazy_refresh(msgwnd, false); + wd_manager.do_lazy_refresh(tstop_wd, true); + } + } + else if((keyboard::space == os_code) && msgwnd->flags.space_click_enabled) + { + //Clicked by spacebar + if((nullptr == pressed_wd) && (nullptr == pressed_wd_space)) + { + arg_mouse arg; + arg.alt = false; + arg.button = ::nana::mouse::left_button; + arg.ctrl = false; + arg.evt_code = event_code::mouse_down; + arg.left_button = true; + arg.mid_button = false; + arg.pos.x = 0; + arg.pos.y = 0; + arg.window_handle = reinterpret_cast(msgwnd); + + msgwnd->flags.action = mouse_action::pressed; + + pressed_wd_space = msgwnd; + auto retain = msgwnd->together.events_ptr; + + emit_drawer(&drawer::mouse_down, msgwnd, arg, &context); + wd_manager.do_lazy_refresh(msgwnd, false); } } else if(keyboard::alt == os_code) @@ -1081,7 +1125,7 @@ namespace detail if(XLookupKeySym == status) { - brock.wd_manager().do_lazy_refresh(msgwnd, false); + wd_manager.do_lazy_refresh(msgwnd, false); break; } case XLookupChars: @@ -1109,7 +1153,7 @@ namespace detail arg.ctrl = arg.shift = false; arg.evt_code = event_code::shortkey; brock.set_keyboard_shortkey(true); - auto shr_wd = brock.wd_manager().find_shortkey(native_window, arg.key); + auto shr_wd = wd_manager.find_shortkey(native_window, arg.key); if(shr_wd) { arg.window_handle = reinterpret_cast(shr_wd); @@ -1121,7 +1165,7 @@ namespace detail arg.window_handle = reinterpret_cast(msgwnd); brock.get_key_state(arg); msgwnd->together.events_ptr->key_char.emit(arg); - if(arg.ignore == false && brock.wd_manager().available(msgwnd)) + if(arg.ignore == false && wd_manager.available(msgwnd)) brock.emit_drawer(event_code::key_char, msgwnd, arg, &context); } @@ -1131,7 +1175,7 @@ namespace detail break; } - brock.wd_manager().do_lazy_refresh(msgwnd, false); + wd_manager.do_lazy_refresh(msgwnd, false); if(keybuf != fixbuf) delete [] keybuf; } @@ -1149,13 +1193,43 @@ namespace detail msgwnd = brock.focus(); if(msgwnd) { - arg_keyboard arg; - arg.evt_code = event_code::key_release; - arg.window_handle = reinterpret_cast(msgwnd); - arg.ignore = false; - arg.key = os_code; - brock.get_key_state(arg); - brock.emit(event_code::key_release, msgwnd, arg, true, &context); + if(msgwnd == pressed_wd_space) + { + msgwnd->flags.action = mouse_action::normal; + + arg_click click_arg; + click_arg.mouse_args = nullptr; + click_arg.window_handle = reinterpret_cast(msgwnd); + + auto retain = msgwnd->together.events_ptr; + if (brock.emit(event_code::click, msgwnd, click_arg, true, &context)) + { + arg_mouse arg; + arg.alt = false; + arg.button = ::nana::mouse::left_button; + arg.ctrl = false; + arg.evt_code = event_code::mouse_up; + arg.left_button = true; + arg.mid_button = false; + arg.pos.x = 0; + arg.pos.y = 0; + arg.window_handle = reinterpret_cast(msgwnd); + + emit_drawer(&drawer::mouse_up, msgwnd, arg, &context); + brock.wd_manager().do_lazy_refresh(msgwnd, false); + } + pressed_wd_space = nullptr; + } + else + { + arg_keyboard arg; + arg.evt_code = event_code::key_release; + arg.window_handle = reinterpret_cast(msgwnd); + arg.ignore = false; + arg.key = os_code; + brock.get_key_state(arg); + brock.emit(event_code::key_release, msgwnd, arg, true, &context); + } } if(os_code < keyboard::os_arrow_left || keyboard::os_arrow_down < os_code) @@ -1216,6 +1290,7 @@ namespace detail context.event_window = pre_event_window; root_runtime->condition.pressed = pressed_wd; root_runtime->condition.hovered = hovered_wd; + root_runtime->condition.pressed_by_space = pressed_wd_space; } else { diff --git a/source/gui/detail/bedrock_windows.cpp b/source/gui/detail/bedrock_windows.cpp index 0b85b644..2915ec1c 100644 --- a/source/gui/detail/bedrock_windows.cpp +++ b/source/gui/detail/bedrock_windows.cpp @@ -1,7 +1,7 @@ /* * A Bedrock Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -795,6 +795,7 @@ namespace detail auto& context = *brock.get_thread_context(); auto pressed_wd = root_runtime->condition.pressed; + auto pressed_wd_space = root_runtime->condition.pressed_by_space; auto hovered_wd = root_runtime->condition.hovered; parameter_decoder pmdec; @@ -913,6 +914,10 @@ namespace detail def_window_proc = true; break; case WM_LBUTTONDBLCLK: case WM_MBUTTONDBLCLK: case WM_RBUTTONDBLCLK: + //Ignore mouse events when a window has been pressed by pressing spacebar + if (pressed_wd_space) + break; + pressed_wd = nullptr; msgwnd = brock.wd_manager().find_window(native_window, pmdec.mouse.x, pmdec.mouse.y); if(msgwnd && msgwnd->flags.enabled) @@ -938,8 +943,13 @@ namespace detail def_window_proc = true; break; case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN: + //Ignore mouse events when a window has been pressed by pressing spacebar + if (pressed_wd_space) + break; + msgwnd = brock.wd_manager().find_window(native_window, pmdec.mouse.x, pmdec.mouse.y); - if(nullptr == msgwnd) break; + if ((nullptr == msgwnd) || (pressed_wd && (msgwnd != pressed_wd))) + 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)) @@ -994,7 +1004,11 @@ namespace detail case WM_LBUTTONUP: case WM_MBUTTONUP: case WM_RBUTTONUP: - msgwnd = brock.wd_manager().find_window(native_window, pmdec.mouse.x, pmdec.mouse.y); + //Ignore mouse events when a window has been pressed by pressing spacebar + if (pressed_wd_space) + break; + + msgwnd = brock.wd_manager().find_window(native_window, pmdec.mouse.x, pmdec.mouse.y); if(nullptr == msgwnd) break; @@ -1015,7 +1029,7 @@ namespace detail if (msgwnd->dimension.is_hit(arg.pos)) { msgwnd->flags.action = mouse_action::over; - if (::nana::mouse::left_button == arg.button) + if ((::nana::mouse::left_button == arg.button) && (pressed_wd == msgwnd)) { click_arg.window_handle = reinterpret_cast(msgwnd); emit_drawer(&drawer::click, msgwnd, click_arg, &context); @@ -1045,6 +1059,10 @@ namespace detail pressed_wd = nullptr; break; case WM_MOUSEMOVE: + //Ignore mouse events when a window has been pressed by pressing spacebar + if (pressed_wd_space) + break; + msgwnd = brock.wd_manager().find_window(native_window, pmdec.mouse.x, pmdec.mouse.y); if (brock.wd_manager().available(hovered_wd) && (msgwnd != hovered_wd)) { @@ -1397,16 +1415,42 @@ namespace detail if(msgwnd) { - if((wParam == 9) && (!msgwnd->visible || (false == (msgwnd->flags.tab & tab_type::eating)))) //Tab + auto & wd_manager = brock.wd_manager(); + if((VK_TAB == wParam) && (!msgwnd->visible || (false == (msgwnd->flags.tab & tab_type::eating)))) //Tab { bool is_forward = (::GetKeyState(VK_SHIFT) >= 0); - auto tstop_wd = brock.wd_manager().tabstop(msgwnd, is_forward); + auto tstop_wd = wd_manager.tabstop(msgwnd, is_forward); if (tstop_wd) { - brock.wd_manager().set_focus(tstop_wd, false); - brock.wd_manager().do_lazy_refresh(msgwnd, false); - brock.wd_manager().do_lazy_refresh(tstop_wd, true); + wd_manager.set_focus(tstop_wd, false); + wd_manager.do_lazy_refresh(msgwnd, false); + wd_manager.do_lazy_refresh(tstop_wd, true); + } + } + else if ((VK_SPACE == wParam) && msgwnd->flags.space_click_enabled) + { + //Clicked by spacebar + if (nullptr == pressed_wd && nullptr == pressed_wd_space) + { + arg_mouse arg; + arg.alt = false; + arg.button = ::nana::mouse::left_button; + arg.ctrl = false; + arg.evt_code = event_code::mouse_down; + arg.left_button = true; + arg.mid_button = false; + arg.pos.x = 0; + arg.pos.y = 0; + arg.window_handle = reinterpret_cast(msgwnd); + + msgwnd->flags.action = mouse_action::pressed; + + pressed_wd_space = msgwnd; + auto retain = msgwnd->together.events_ptr; + + emit_drawer(&drawer::mouse_down, msgwnd, arg, &context); + wd_manager.do_lazy_refresh(msgwnd, false); } } else @@ -1456,18 +1500,48 @@ namespace detail } return 0; case WM_KEYUP: - if(wParam != 18) //MUST NOT BE AN ALT + if(wParam != VK_MENU) //MUST NOT BE AN ALT { msgwnd = brock.focus(); if(msgwnd) { - arg_keyboard arg; - arg.evt_code = event_code::key_release; - arg.window_handle = reinterpret_cast(msgwnd); - arg.key = static_cast(wParam); - brock.get_key_state(arg); - arg.ignore = false; - brock.emit(event_code::key_release, msgwnd, arg, true, &context); + if (msgwnd == pressed_wd_space) + { + msgwnd->flags.action = mouse_action::normal; + + arg_click click_arg; + click_arg.mouse_args = nullptr; + click_arg.window_handle = reinterpret_cast(msgwnd); + + auto retain = msgwnd->together.events_ptr; + if (brock.emit(event_code::click, msgwnd, click_arg, true, &context)) + { + arg_mouse arg; + arg.alt = false; + arg.button = ::nana::mouse::left_button; + arg.ctrl = false; + arg.evt_code = event_code::mouse_up; + arg.left_button = true; + arg.mid_button = false; + arg.pos.x = 0; + arg.pos.y = 0; + arg.window_handle = reinterpret_cast(msgwnd); + + emit_drawer(&drawer::mouse_up, msgwnd, arg, &context); + brock.wd_manager().do_lazy_refresh(msgwnd, false); + } + pressed_wd_space = nullptr; + } + else + { + arg_keyboard arg; + arg.evt_code = event_code::key_release; + arg.window_handle = reinterpret_cast(msgwnd); + arg.key = static_cast(wParam); + brock.get_key_state(arg); + arg.ignore = false; + brock.emit(event_code::key_release, msgwnd, arg, true, &context); + } } } else @@ -1521,6 +1595,7 @@ namespace detail { root_runtime->condition.pressed = pressed_wd; root_runtime->condition.hovered = hovered_wd; + root_runtime->condition.pressed_by_space = pressed_wd_space; } if (!def_window_proc) diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index df81e737..a5f96e98 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -1,7 +1,7 @@ /* * Nana GUI Programming Interface Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -307,6 +307,14 @@ namespace API } } } + + void enable_space_click(window wd, bool enable) + { + auto iwd = reinterpret_cast(wd); + internal_scope_guard lock; + if (restrict::wd_manager().available(iwd)) + iwd->flags.space_click_enabled = enable; + } }//end namespace dev diff --git a/source/gui/widgets/button.cpp b/source/gui/widgets/button.cpp index 895c4900..301c07c7 100644 --- a/source/gui/widgets/button.cpp +++ b/source/gui/widgets/button.cpp @@ -40,6 +40,7 @@ namespace nana{ namespace drawerbase wdg_ = &widget; window wd = widget; + API::dev::enable_space_click(widget, true); API::tabstop(wd); API::effects_edge_nimbus(wd, effects::edge_nimbus::active); API::effects_edge_nimbus(wd, effects::edge_nimbus::over); @@ -162,19 +163,8 @@ namespace nana{ namespace drawerbase _m_press(graph, false); } - void trigger::key_char(graph_reference, const arg_keyboard& arg) - { - if (static_cast(keyboard::enter) == arg.key) - emit_click(); - } - void trigger::key_press(graph_reference graph, const arg_keyboard& arg) { - if (keyboard::space == static_cast(arg.key)) - { - _m_press(graph, true); - return; - } bool ch_tabstop_next; switch(arg.key) { @@ -191,18 +181,6 @@ namespace nana{ namespace drawerbase API::move_tabstop(*wdg_, ch_tabstop_next); } - void trigger::key_release(graph_reference graph, const arg_keyboard& arg) - { - if (arg.key != static_cast(keyboard::space)) - return; - - emit_click(); - - //Check the widget, because it may be deleted by click event - if (API::is_window(*wdg_)) - _m_press(graph, false); - } - void trigger::focus(graph_reference graph, const arg_focus& arg) { attr_.focused = arg.getting; diff --git a/source/gui/widgets/checkbox.cpp b/source/gui/widgets/checkbox.cpp index 31ef7146..4a14a7fc 100644 --- a/source/gui/widgets/checkbox.cpp +++ b/source/gui/widgets/checkbox.cpp @@ -47,6 +47,7 @@ namespace nana{ namespace drawerbase void drawer::attached(widget_reference widget, graph_reference) { impl_->widget_ptr = &widget; + API::dev::enable_space_click(widget, true); } void drawer::refresh(graph_reference graph)