diff --git a/CMakeLists.txt b/CMakeLists.txt index 2cdeb93d..c66f18a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -131,7 +131,7 @@ endif(APPLE) if(UNIX) list(APPEND NANA_LINKS -lX11) - find_package(Freetype) + include(FindFreetype) if (FREETYPE_FOUND) include_directories( ${FREETYPE_INCLUDE_DIRS}) list(APPEND NANA_LINKS -lXft) diff --git a/include/nana/c++defines.hpp b/include/nana/c++defines.hpp index 04b5113f..ff4cf176 100644 --- a/include/nana/c++defines.hpp +++ b/include/nana/c++defines.hpp @@ -1,7 +1,7 @@ /** * Predefined Symbols for C++ * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2016-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2016-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -171,9 +171,9 @@ #endif #endif -//Assume the std::thread is not implement on MinGW +//Assume the std::thread is not implemented on MinGW, +//unless it was compiled with POSIX threading support. //But some toolchains may implement std::thread. -// it seems that MinGW 6.3 and 7.1 have std::thread #ifdef NANA_MINGW # ifndef STD_THREAD_NOT_SUPPORTED # define STD_THREAD_NOT_SUPPORTED @@ -221,8 +221,11 @@ # if __has_include() # undef STD_FILESYSTEM_NOT_SUPPORTED # endif -# if __has_include() -# undef STD_THREAD_NOT_SUPPORTED +# if __has_include() +# if !(defined(NANA_MINGW) && !defined(_GLIBCXX_HAS_GTHREADS)) +//See the comment above regarding MinGW's threading support +# undef STD_THREAD_NOT_SUPPORTED +# endif # endif #endif diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index ab90a584..b67a00ef 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -1,7 +1,7 @@ /** * A ISO C++ filesystem Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -72,13 +72,12 @@ namespace boost // begin() and end() are only used by a range-based for statement in the context of // auto - thus the top-level const is stripped - so returning const is harmless and // emphasizes begin() is just a pass through. - inline - const directory_iterator& begin(const directory_iterator& iter) BOOST_NOEXCEPT + inline const directory_iterator& begin(const directory_iterator& iter) BOOST_NOEXCEPT { return iter; } - inline - directory_iterator end(const directory_iterator&) BOOST_NOEXCEPT + + inline directory_iterator end(const directory_iterator&) BOOST_NOEXCEPT { return directory_iterator(); } diff --git a/include/nana/filesystem/filesystem_ext.hpp b/include/nana/filesystem/filesystem_ext.hpp index 50f82f82..959b8e33 100644 --- a/include/nana/filesystem/filesystem_ext.hpp +++ b/include/nana/filesystem/filesystem_ext.hpp @@ -1,6 +1,6 @@ /** * Nana C++ Library(http://www.nanapro.org) -* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) +* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -18,7 +18,6 @@ #include #include - namespace nana { namespace filesystem_ext diff --git a/include/nana/gui/basis.hpp b/include/nana/gui/basis.hpp index 2cc656ca..cc31f862 100644 --- a/include/nana/gui/basis.hpp +++ b/include/nana/gui/basis.hpp @@ -4,7 +4,7 @@ * * Basis Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -30,6 +30,15 @@ namespace nana struct native_drawable_impl{}; } + struct accel_key + { + char key; + bool case_sensitive{ false }; + bool alt{ false }; + bool ctrl{ false }; + bool shift{ false }; + }; + enum class checkstate { unchecked, checked, partial diff --git a/include/nana/gui/detail/bedrock.hpp b/include/nana/gui/detail/bedrock.hpp index 0db691b3..f0d3f63c 100644 --- a/include/nana/gui/detail/bedrock.hpp +++ b/include/nana/gui/detail/bedrock.hpp @@ -1,7 +1,7 @@ /** * A Bedrock Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -27,6 +27,7 @@ namespace detail struct basic_window; class window_manager; + struct window_platform_assoc; /// @brief fundamental core component, it provides an abstraction to the OS platform and some basic functions. class bedrock @@ -73,6 +74,11 @@ namespace detail //Closes the windows which are associated with the specified thread. If the given thread_id is 0, it closes all windows void close_thread_window(unsigned thread_id); + + public: + //Platform-dependent functions + static void delete_platform_assoc(window_platform_assoc*); + void keyboard_accelerator(native_window_type, const accel_key&, const std::function&); public: void event_expose(core_window_t *, bool exposed); void event_move(core_window_t*, int x, int y); diff --git a/include/nana/gui/detail/effects_renderer.hpp b/include/nana/gui/detail/effects_renderer.hpp index 3727933a..3a980caa 100644 --- a/include/nana/gui/detail/effects_renderer.hpp +++ b/include/nana/gui/detail/effects_renderer.hpp @@ -1,3 +1,15 @@ +/* +* Effects Renderer +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2018 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/effects_renderer.cpp +*/ + #ifndef NANA_GUI_DETAIL_EFFECTS_RENDERER_HPP #define NANA_GUI_DETAIL_EFFECTS_RENDERER_HPP #include @@ -76,7 +88,7 @@ namespace nana{ nana::rectangle r; for(auto & action : nimbus) { - if(_m_edge_nimbus(focused, action.window) && window_layer::read_visual_rectangle(action.window, r)) + if(_m_edge_nimbus(action.window, focused) && window_layer::read_visual_rectangle(action.window, r)) { if (action.window == wd) { @@ -140,12 +152,17 @@ namespace nana{ } } private: - static bool _m_edge_nimbus(core_window_t * focused_wd, core_window_t * wd) + /// Determines whether the effect will be rendered for the given window. + static bool _m_edge_nimbus(core_window_t * const wd, core_window_t * const focused_wd) { - if((focused_wd == wd) && (static_cast(wd->effect.edge_nimbus) & static_cast(effects::edge_nimbus::active))) - return true; - else if((static_cast(wd->effect.edge_nimbus) & static_cast(effects::edge_nimbus::over)) && (wd->flags.action == mouse_action::hovered)) - return true; + // Don't render the effect if the window is disabled. + if (wd->flags.enabled) + { + if ((focused_wd == wd) && (static_cast(wd->effect.edge_nimbus) & static_cast(effects::edge_nimbus::active))) + return true; + else if ((static_cast(wd->effect.edge_nimbus) & static_cast(effects::edge_nimbus::over)) && (wd->flags.action == mouse_action::hovered)) + return true; + } return false; } diff --git a/include/nana/gui/detail/general_events.hpp b/include/nana/gui/detail/general_events.hpp index 5992f1a0..72b4cbf3 100644 --- a/include/nana/gui/detail/general_events.hpp +++ b/include/nana/gui/detail/general_events.hpp @@ -1,7 +1,7 @@ /** * Definition of General Events * Nana C++ Library(http://www.nanapro.org) -* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) +* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -460,8 +460,9 @@ namespace nana ::nana::window window_handle; ///< A handle to the event window mutable wchar_t key; ///< the key corresponding to the key pressed mutable bool ignore; ///< this member is only available for key_char event, set 'true' to ignore the input. - bool ctrl; ///< keyboard Ctrl is pressed? - bool shift; ///< keyboard Shift is pressed + bool alt; ///< it is set to indicate the modifier key Alt just prior to the event. + bool ctrl; ///< it is set to indicate the modifier key Ctrl just prior to the event. + bool shift; ///< it is set to indicate the modifier key Shift just prior to the event. }; struct arg_move : public event_arg diff --git a/include/nana/gui/programming_interface.hpp b/include/nana/gui/programming_interface.hpp index 8c0d85fe..814a98b7 100644 --- a/include/nana/gui/programming_interface.hpp +++ b/include/nana/gui/programming_interface.hpp @@ -301,6 +301,8 @@ namespace API void window_size(window, const size&); size window_outline_size(window); void window_outline_size(window, const size&); + + nana::optional window_rectangle(window); bool get_window_rectangle(window, rectangle&); bool track_window_size(window, const size&, bool true_for_max); ///< Sets the minimum or maximum tracking size of a window. void window_enabled(window, bool); diff --git a/include/nana/gui/widgets/form.hpp b/include/nana/gui/widgets/form.hpp index 77972a8b..6053a1d7 100644 --- a/include/nana/gui/widgets/form.hpp +++ b/include/nana/gui/widgets/form.hpp @@ -1,7 +1,7 @@ /** * A Form Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -68,6 +68,8 @@ namespace nana void modality() const; void wait_for_this(); + + void keyboard_accelerator(const accel_key&, const std::function& fn); }; class nested_form diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 0b408c00..adbd4e14 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -1,7 +1,7 @@ /** * A List Box Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/nana/gui/widgets/scroll.hpp b/include/nana/gui/widgets/scroll.hpp index c4e39981..f06ef8e0 100644 --- a/include/nana/gui/widgets/scroll.hpp +++ b/include/nana/gui/widgets/scroll.hpp @@ -1,7 +1,7 @@ /** * A Scroll Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -147,7 +147,7 @@ namespace nana void step(size_type s) { - metrics_.step = s; + metrics_.step = (s ? s : 1); } bool make_step(bool forward, unsigned multiple) @@ -398,7 +398,7 @@ namespace nana /// \brief The construct that creates a widget. /// @param wd A handle to the parent window of the widget being created. /// @param visible specify the visibility after creation. - scroll(window wd, bool visible) + scroll(window wd, bool visible = true) { this->create(wd, rectangle(), visible); // add a widget scheme? and take some colors from these wd? } @@ -501,7 +501,8 @@ namespace nana /// @return true if the vlaue is changed. bool make_page_scroll(bool forward) { - return this->make_step(forward, static_cast(range() - 1)); + auto const count = range() / step(); + return this->make_step(forward, (count > 2 ? count - 1 : 1)); } };//end class scroll }//end namespace nana diff --git a/include/nana/gui/widgets/tabbar.hpp b/include/nana/gui/widgets/tabbar.hpp index 0e2e2e9c..a24cce4a 100644 --- a/include/nana/gui/widgets/tabbar.hpp +++ b/include/nana/gui/widgets/tabbar.hpp @@ -1,7 +1,7 @@ /** * A Tabbar implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -42,9 +42,8 @@ namespace nana : arg_tabbar({wdg, v}) {} - bool remove = true; ///< determines whether to remove the item - bool close_attach_window = true; ///< determines whether to close the attached window. It is ignored if remove is false - + mutable bool remove = true; ///< determines whether to remove the item + mutable bool close_attach_window = true; ///< determines whether to close the attached window. It is ignored if remove is false }; namespace drawerbase @@ -293,7 +292,7 @@ namespace nana if (pos > length()) throw std::out_of_range("tabbar::insert invalid position"); - this->get_drawer_trigger().insert(pos, to_nstring(text), std::move(value)); + this->get_drawer_trigger().insert(pos, to_nstring(std::move(text)), std::move(value)); API::update_window(*this); } diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index 5f4fa1fa..b8edb34c 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -1,7 +1,7 @@ /* * A Bedrock Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -15,10 +15,10 @@ #include #include #include -#include #include #include #include +#include "inner_fwd_implement.hpp" #include #include @@ -104,6 +104,42 @@ namespace detail void window_proc_for_packet(Display *, nana::detail::msg_packet_tag&); void window_proc_for_xevent(Display*, XEvent&); + class accel_key_comparer + { + public: + bool operator()(const accel_key& a, const accel_key& b) const + { + auto va = a.case_sensitive ? a.key : std::tolower(a.key); + auto vb = b.case_sensitive ? b.key : std::tolower(b.key); + + if(va < vb) + return true; + else if(va > vb) + return false; + + if (a.case_sensitive != b.case_sensitive) + return b.case_sensitive; + + if (a.alt != b.alt) + return b.alt; + + if (a.ctrl != b.ctrl) + return b.ctrl; + + return ((a.shift != b.shift) && b.shift); + } + }; + + struct accel_key_value + { + std::function command; + }; + + struct window_platform_assoc + { + std::map accel_commands; + }; + //class bedrock defines a static object itself to implement a static singleton //here is the definition of this object bedrock bedrock::bedrock_object; @@ -218,10 +254,28 @@ namespace detail { XKeyEvent xkey; nana::detail::platform_spec::instance().read_keystate(xkey); + arg.alt = (xkey.state & Mod1Mask); arg.ctrl = (xkey.state & ControlMask); arg.shift = (xkey.state & ShiftMask); } + void bedrock::delete_platform_assoc(window_platform_assoc* passoc) + { + delete passoc; + } + + void bedrock::keyboard_accelerator(native_window_type wd, const accel_key& ackey, const std::function& fn) + { + auto misc = wd_manager().root_runtime(wd); + if (nullptr == misc) + return; + + if (!misc->wpassoc) + misc->wpassoc = new window_platform_assoc; + + misc->wpassoc->accel_commands[ackey].command = fn; + } + element_store& bedrock::get_element_store() const { return impl_->estore; @@ -490,6 +544,34 @@ namespace detail return wchar_t(keysym); } + bool translate_keyboard_accelerator(root_misc* misc, char os_code, const arg_keyboard& modifiers) + { + if(!misc->wpassoc) + return false; + + auto lower_oc = std::tolower(os_code); + + std::function command; + + for(auto & accel : misc->wpassoc->accel_commands) + { + if(accel.first.key != (accel.first.case_sensitive ? os_code : lower_oc)) + continue; + + if(accel.first.alt == modifiers.alt && accel.first.ctrl == modifiers.ctrl && accel.first.shift == modifiers.shift) + { + command = accel.second.command; + break; + } + } + + if(!command) + return false; + + command(); + return true; + } + void window_proc_for_xevent(Display* /*display*/, XEvent& xevent) { typedef detail::bedrock::core_window_t core_window_t; @@ -849,6 +931,9 @@ namespace detail if(msgwnd) { + arg_keyboard modifiers_status; + brock.get_key_state(modifiers_status); + KeySym keysym; Status status; char fixbuf[33]; @@ -883,16 +968,20 @@ namespace detail keybuf[len] = 0; wchar_t os_code = 0; + bool accel_translated = false; + switch(status) { case XLookupKeySym: case XLookupBoth: os_code = os_code_from_keysym(keysym); + accel_translated = translate_keyboard_accelerator(root_runtime, os_code, modifiers_status); + if(accel_translated) + break; + if(os_code == keyboard::tab && (false == (msgwnd->flags.tab & detail::tab_type::eating))) //Tab { - arg_keyboard argkey; - brock.get_key_state(argkey); - auto tstop_wd = wd_manager.tabstop(msgwnd, !argkey.shift); + auto tstop_wd = wd_manager.tabstop(msgwnd, !modifiers_status.shift); if (tstop_wd) { root_runtime->condition.ignore_tab = true; @@ -907,9 +996,9 @@ namespace detail if((nullptr == pressed_wd) && (nullptr == pressed_wd_space)) { arg_mouse arg; - arg.alt = false; + arg.alt = modifiers_status.alt; arg.button = ::nana::mouse::left_button; - arg.ctrl = false; + arg.ctrl = modifiers_status.ctrl; arg.evt_code = event_code::mouse_down; arg.left_button = true; arg.mid_button = false; @@ -955,11 +1044,10 @@ namespace detail if(keyboard::os_ctrl == os_code) context.is_ctrl_pressed = true; - arg_keyboard arg; + arg_keyboard arg = modifiers_status; arg.ignore = false; arg.key = os_code; arg.evt_code = event_code::key_press; - brock.get_key_state(arg); arg.window_handle = reinterpret_cast(msgwnd); brock.emit(event_code::key_press, msgwnd, arg, true, &context); @@ -988,7 +1076,7 @@ namespace detail for(int i = 0; i < len; ++i) { - arg_keyboard arg; + arg_keyboard arg = modifiers_status; arg.ignore = false; arg.key = charbuf[i]; @@ -1011,7 +1099,6 @@ namespace detail } arg.evt_code = event_code::key_char; arg.window_handle = reinterpret_cast(msgwnd); - brock.get_key_state(arg); msgwnd->annex.events_ptr->key_char.emit(arg, reinterpret_cast(msgwnd)); if(arg.ignore == false && wd_manager.available(msgwnd)) draw_invoker(&drawer::key_char, msgwnd, arg, &context); diff --git a/source/gui/detail/bedrock_windows.cpp b/source/gui/detail/bedrock_windows.cpp index 2d75e7d4..ac1626ef 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-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -20,11 +20,11 @@ #include #include #include -#include #include #include #include #include +#include "inner_fwd_implement.hpp" #include //use std::cerr @@ -182,6 +182,12 @@ namespace detail }cache; }; + struct window_platform_assoc + { + HACCEL accel{ nullptr }; ///< A handle to a Windows keyboard accelerator object. + std::map> accel_commands; + }; + //class bedrock defines a static object itself to implement a static singleton //here is the definition of this object bedrock bedrock::bedrock_object; @@ -345,6 +351,25 @@ namespace detail } } + void process_msg(bedrock* brock, MSG& msg) + { + if (WM_KEYFIRST <= msg.message && msg.message <= WM_KEYLAST) + { + auto misc = brock->wd_manager().root_runtime(reinterpret_cast(msg.hwnd)); + if (misc && misc->wpassoc && misc->wpassoc->accel) + { + if (::TranslateAccelerator(msg.hwnd, misc->wpassoc->accel, &msg)) + return; + } + } + + auto menu_wd = brock->get_menu(reinterpret_cast(msg.hwnd), true); + if (menu_wd) interior_helper_for_menu(msg, menu_wd); + + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + void bedrock::pump_event(window condition_wd, bool is_modal) { const unsigned tid = ::GetCurrentThreadId(); @@ -383,11 +408,15 @@ namespace detail if (msg.message == WM_QUIT) break; if ((WM_KEYFIRST <= msg.message && msg.message <= WM_KEYLAST) || !::IsDialogMessage(native_handle, &msg)) { +#if 0 auto menu_wd = get_menu(reinterpret_cast(msg.hwnd), true); if (menu_wd) interior_helper_for_menu(msg, menu_wd); - ::TranslateMessage(&msg); + ::TranslateMessage(&msg); //deprecated ::DispatchMessage(&msg); +#else + process_msg(this, msg); +#endif wd_manager().remove_trash_handle(tid); } @@ -400,11 +429,15 @@ namespace detail { if (-1 != ::GetMessage(&msg, 0, 0, 0)) { +#if 0 auto menu_wd = get_menu(reinterpret_cast(msg.hwnd), true); if (menu_wd) interior_helper_for_menu(msg, menu_wd); ::TranslateMessage(&msg); ::DispatchMessage(&msg); +#else + process_msg(this, msg); +#endif } wd_manager().call_safe_place(tid); @@ -420,11 +453,15 @@ namespace detail { if(-1 != ::GetMessage(&msg, 0, 0, 0)) { +#if 0 auto menu_wd = get_menu(reinterpret_cast(msg.hwnd), true); if(menu_wd) interior_helper_for_menu(msg, menu_wd); ::TranslateMessage(&msg); ::DispatchMessage(&msg); +#else + process_msg(this, msg); +#endif } wd_manager().call_safe_place(tid); @@ -635,6 +672,7 @@ namespace detail switch(msg) { + case WM_COMMAND: case WM_DESTROY: case WM_SHOWWINDOW: case WM_SIZING: @@ -786,6 +824,17 @@ namespace detail switch (message) { + case WM_COMMAND: + if ((1 == HIWORD(wParam)) && root_runtime->wpassoc) + { + auto i = root_runtime->wpassoc->accel_commands.find(LOWORD(wParam)); + if (i != root_runtime->wpassoc->accel_commands.end()) + { + auto fn = i->second; + fn(); + } + } + break; case WM_IME_STARTCOMPOSITION: if (msgwnd->other.attribute.root->ime_enabled) { @@ -1578,10 +1627,58 @@ namespace detail void bedrock::get_key_state(arg_keyboard& kb) { + kb.alt = (0 != (::GetKeyState(VK_MENU) & 0x80)); kb.ctrl = (0 != (::GetKeyState(VK_CONTROL) & 0x80)); kb.shift = (0 != (::GetKeyState(VK_SHIFT) & 0x80)); } + void bedrock::delete_platform_assoc(window_platform_assoc* passoc) + { + delete passoc; + } + + //Generates an identitifer for an accel key. + std::pair id_accel_key(const accel_key& key) + { + std::pair ret; + + //Use virt-key for non-case sensitive + if (!key.case_sensitive) + ret.second = static_cast(std::tolower(key.key) - 'a' + 0x41); + + ret.first = ret.second | int(key.case_sensitive ? (1 << 8) : 0) | int(key.alt ? (1 << 9) : 0) | int(key.ctrl ? (1 << 10) : 0) | int(key.shift ? (1 << 11) : 0); + return ret; + } + + void bedrock::keyboard_accelerator(native_window_type wd, const accel_key& key, const std::function& fn) + { + auto misc = wd_manager().root_runtime(wd); + if (nullptr == misc) + return; + + if (!misc->wpassoc) + misc->wpassoc = new window_platform_assoc; + + auto idkey = id_accel_key(key); + + misc->wpassoc->accel_commands[idkey.first] = fn; + + auto accel_size = ::CopyAcceleratorTable(misc->wpassoc->accel, nullptr, 0); + + std::unique_ptr accels(new ACCEL[accel_size + 1]); + + if (accel_size) + ::CopyAcceleratorTable(misc->wpassoc->accel, accels.get(), accel_size); + + auto p = accels.get() + accel_size; + p->cmd = idkey.first; + p->fVirt = (key.case_sensitive ? 0 : FVIRTKEY) | (key.alt ? FALT : 0) | (key.ctrl ? FCONTROL : 0) | (key.shift ? FSHIFT : 0); + p->key = idkey.second; + + ::DestroyAcceleratorTable(misc->wpassoc->accel); + misc->wpassoc->accel = ::CreateAcceleratorTable(accels.get(), accel_size + 1); + } + element_store& bedrock::get_element_store() const { return impl_->estore; diff --git a/include/nana/gui/detail/inner_fwd_implement.hpp b/source/gui/detail/inner_fwd_implement.hpp similarity index 86% rename from include/nana/gui/detail/inner_fwd_implement.hpp rename to source/gui/detail/inner_fwd_implement.hpp index 68937148..ed8ef73d 100644 --- a/include/nana/gui/detail/inner_fwd_implement.hpp +++ b/source/gui/detail/inner_fwd_implement.hpp @@ -1,7 +1,7 @@ /* * Implementations of Inner Forward Declaration * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -15,9 +15,9 @@ #define NANA_GUI_INNER_FWD_IMPLEMENT_HPP #include -#include "inner_fwd.hpp" -#include "basic_window.hpp" -#include "../../paint/graphics.hpp" +#include +#include +#include #include @@ -54,10 +54,13 @@ namespace nana{ implementation * impl_; }; + struct window_platform_assoc; struct root_misc { basic_window * window; + window_platform_assoc * wpassoc{ nullptr }; + nana::paint::graphics root_graph; shortkey_container shortkeys; @@ -71,6 +74,10 @@ namespace nana{ root_misc(root_misc&&); root_misc(basic_window * wd, unsigned width, unsigned height); + ~root_misc(); + private: + root_misc(const root_misc&) = delete; + root_misc& operator=(const root_misc&) = delete; };//end struct root_misc diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp index 27357217..45764b81 100644 --- a/source/gui/detail/window_layout.cpp +++ b/source/gui/detail/window_layout.cpp @@ -1,7 +1,7 @@ /* * Window Layout Implementation * Nana C++ Library(http://www.nanapro.org) -* Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) +* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -106,43 +106,46 @@ namespace nana visual = rectangle{ wd->pos_root, wd->dimension }; - if (wd->root_widget != wd) + if (category::flags::root != wd->other.category) { //Test if the root widget is overlapped the specified widget //the pos of root widget is (0, 0) if (overlapped(visual, rectangle{ wd->root_widget->pos_owner, wd->root_widget->dimension }) == false) return false; - } - for (auto parent = wd->parent; parent; parent = parent->parent) - { - if (category::flags::root == parent->other.category) + for (auto parent = wd->parent; parent; parent = parent->parent) { - //visual rectangle of wd's parent - rectangle vrt_parent{parent->pos_root, parent->dimension}; - - point pos_root; - while (parent->parent) + if (category::flags::root == parent->other.category) { - pos_root -= native_interface::window_position(parent->root); - - if (!overlap(rectangle{ pos_root, parent->parent->root_widget->dimension }, vrt_parent, vrt_parent)) - return false; - - parent = parent->parent->root_widget; + wd = parent; + break; } - if (!overlap(vrt_parent, visual, visual)) + if (!overlap(rectangle{ parent->pos_root, parent->dimension }, visual, visual)) return false; - - return true; } - - if (!overlap(rectangle{ parent->pos_root, parent->dimension }, visual, visual)) - return false; } - return true; + //Now, wd actually is the root widget of original parameter wd + if (nullptr == wd->parent) + return true; + + auto parent_rw = wd->parent->root_widget; + //visual rectangle of wd's parent + rectangle vrt_parent{ parent_rw->pos_root, parent_rw->dimension }; + + point pos_root; + while (parent_rw->parent) + { + pos_root -= native_interface::window_position(parent_rw->root); + + if (!overlap(rectangle{ pos_root, parent_rw->parent->root_widget->dimension }, vrt_parent, vrt_parent)) + return false; + + parent_rw = parent_rw->parent->root_widget; + } + + return overlap(vrt_parent, visual, visual); } //read_overlaps @@ -386,6 +389,13 @@ namespace nana nana::rectangle r_of_sigwd(sigwd->pos_root, sigwd->dimension); for (auto wd : data_sect.effects_bground_windows) { + //Don't notify the window if both native root windows are not same(e.g. wd and sigwd have + //a some parent). Otherwise, _m_paint_glass_window() recursively paints sigwd to make stack overflow. + //On the other hand, a nested root window is always floating on its parent's child widgets, it's unnecessary to + //notify the wd if they haven't a same native root window. + if (sigwd->root != wd->root) + continue; + if (wd == sigwd || !wd->displayed() || (false == overlapped(nana::rectangle{ wd->pos_root, wd->dimension }, r_of_sigwd))) continue; diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index 4bfd1900..38add16a 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -1,7 +1,7 @@ /* * Window Manager Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -16,11 +16,11 @@ #include #include #include -#include "window_register.hpp" #include -#include #include #include +#include "window_register.hpp" +#include "inner_fwd_implement.hpp" #include #include @@ -140,10 +140,12 @@ namespace nana //struct root_misc root_misc::root_misc(root_misc&& other): window(other.window), + wpassoc(other.wpassoc), root_graph(std::move(other.root_graph)), shortkeys(std::move(other.shortkeys)), condition(std::move(other.condition)) { + other.wpassoc = nullptr; //moved-from } root_misc::root_misc(basic_window * wd, unsigned width, unsigned height) @@ -155,6 +157,11 @@ namespace nana condition.pressed_by_space = nullptr; condition.hovered = nullptr; } + + root_misc::~root_misc() + { + bedrock::delete_platform_assoc(wpassoc); + } //end struct root_misc //class root_register diff --git a/source/gui/filebox.cpp b/source/gui/filebox.cpp index b31653cc..ff58039d 100644 --- a/source/gui/filebox.cpp +++ b/source/gui/filebox.cpp @@ -1041,7 +1041,8 @@ namespace nana bool filebox::show() const { #if defined(NANA_WINDOWS) - std::wstring wfile; + auto winitfile = to_wstring(impl_->file); + std::wstring wfile(winitfile); wfile.resize(520); OPENFILENAME ofn; diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index 22e22cac..626803d3 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -821,6 +821,15 @@ namespace API } } + nana::optional window_rectangle(window wd) + { + auto iwd = reinterpret_cast(wd); + internal_scope_guard lock; + if (restrict::wd_manager().available(iwd)) + return rectangle(iwd->pos_owner, iwd->dimension); + return{}; + } + bool get_window_rectangle(window wd, rectangle& r) { auto iwd = reinterpret_cast(wd); diff --git a/source/gui/widgets/button.cpp b/source/gui/widgets/button.cpp index a01d001b..fe6f19c7 100644 --- a/source/gui/widgets/button.cpp +++ b/source/gui/widgets/button.cpp @@ -379,7 +379,7 @@ namespace nana{ namespace drawerbase }//end namespace drawerbase //button - //@brief: Defaine a button widget and it provides the interfaces to be operational + //@brief: Define a button widget and it provides the interfaces to be operational button::button(){} button::button(window wd, bool visible) diff --git a/source/gui/widgets/form.cpp b/source/gui/widgets/form.cpp index 7f8247ff..9414a07b 100644 --- a/source/gui/widgets/form.cpp +++ b/source/gui/widgets/form.cpp @@ -1,6 +1,6 @@ /* * A Form Implementation - * Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -10,6 +10,7 @@ */ #include +#include namespace nana { @@ -94,6 +95,11 @@ namespace nana { API::wait_for(handle()); } + + void form::keyboard_accelerator(const accel_key& key, const std::function& fn) + { + nana::detail::bedrock::instance().keyboard_accelerator(this->native_handle(), key, fn); + } //end class form //class nested_form diff --git a/source/gui/widgets/group.cpp b/source/gui/widgets/group.cpp index ab8e9e73..87d2ebc6 100644 --- a/source/gui/widgets/group.cpp +++ b/source/gui/widgets/group.cpp @@ -208,8 +208,8 @@ namespace nana{ outter[field_title] << impl_->caption; outter.collocate(); + impl_->caption.transparent(true); color pbg = API::bgcolor(this->parent()); - impl_->caption.bgcolor(pbg.blend(colors::black, 0.025)); this->bgcolor(pbg.blend(colors::black, 0.05)); @@ -222,10 +222,27 @@ namespace nana{ auto gap_px = impl_->gap - 1; graph.rectangle(true, API::bgcolor(this->parent())); - graph.round_rectangle(rectangle(point(gap_px, impl_->caption_dimension.height / 2), - nana::size(graph.width() - 2 * gap_px, graph.height() - impl_->caption_dimension.height / 2 - gap_px) + + auto const top_round_line = static_cast(impl_->caption_dimension.height) / 2; + + graph.round_rectangle(rectangle(point(gap_px, top_round_line), + nana::size(graph.width() - 2 * gap_px, graph.height() - top_round_line - gap_px) ), 3, 3, colors::gray_border, true, this->bgcolor()); + + auto opt_r = API::window_rectangle(impl_->caption); + if (opt_r) + { + rectangle grad_r{ opt_r->position(), nana::size{ opt_r->width, static_cast(top_round_line - opt_r->y) } }; + + grad_r.y += top_round_line*2 / 3; + grad_r.x -= 2; + grad_r.width += 4; + + graph.gradual_rectangle(grad_r, + API::bgcolor(this->parent()), this->bgcolor(), true + ); + } }); } diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index e473a080..c2d75048 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -1,7 +1,7 @@ /* * A List Box Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -1273,6 +1273,7 @@ namespace nana } //Backward + n = -n; dpos = pos; if (good(dpos.cat)) { @@ -1519,8 +1520,6 @@ namespace nana template std::vector> select_display_range_if(const index_pair& fr_abs, index_pair to_dpl, bool deselect_others, Pred pred) { - const index_pairs already_selected = (deselect_others ? this->pick_items(true) : index_pairs{}); - if (to_dpl.empty()) { if (fr_abs.empty()) @@ -1533,6 +1532,11 @@ namespace nana if (fr_dpl > to_dpl) std::swap(fr_dpl, to_dpl); + if (to_dpl.is_category() && this->size_item(to_dpl.cat) > 0) + to_dpl.item = this->size_item(to_dpl.cat) - 1; + + const index_pairs already_selected = (deselect_others ? this->pick_items(true) : index_pairs{}); + const auto begin = fr_dpl; const auto last = to_dpl; @@ -1586,7 +1590,7 @@ namespace nana return pairs; } - bool select_for_all(bool sel, const index_pair& except = index_pair{npos, npos}) + bool select_for_all(bool sel, const index_pair& except_abs = index_pair{npos, npos}) { bool changed = false; index_pair pos; @@ -1595,7 +1599,7 @@ namespace nana pos.item = 0; for(auto & m : cat.items) { - if (except != pos) + if (except_abs != pos) { if (m.flags.selected != sel) { @@ -1618,7 +1622,7 @@ namespace nana } /// return absolute positions, no relative to display - index_pairs pick_items(bool for_selection) const + index_pairs pick_items(bool for_selection, bool find_first = false) const { index_pairs results; index_pair id; @@ -1629,7 +1633,11 @@ namespace nana for (auto & m : cat.items) { if (for_selection ? m.flags.selected : m.flags.checked) + { results.push_back(id); // absolute positions, no relative to display + if (find_first) + return results; + } ++id.item; } ++id.cat; @@ -1978,6 +1986,15 @@ namespace nana }; } + bool cs_status(index_pair abs_pos, bool for_selection) const + { + if (abs_pos.is_category()) + return lister.cat_status(abs_pos.cat, for_selection); + + auto & flags = lister.get(abs_pos.cat)->items.at(abs_pos.item).flags; + return (for_selection ? flags.selected : flags.checked); + } + void resize_disp_area() { auto head_px = this->header_visible_px(); @@ -3416,6 +3433,8 @@ namespace nana rect.y - static_cast(origin.y % item_height_px) }; + essence_->inline_buffered_table.swap(essence_->inline_table); + // The first display is empty when the listbox is empty. if (!first_disp.empty()) { @@ -3438,8 +3457,6 @@ namespace nana auto idx = first_disp; - essence_->inline_buffered_table.swap(essence_->inline_table); - for (auto & cat : lister.cat_container()) for (auto & ind : cat.indicators) { @@ -3509,10 +3526,10 @@ namespace nana ++idx.item; } } - - essence_->inline_buffered_table.clear(); } + essence_->inline_buffered_table.clear(); + if (item_coord.y < rect.bottom()) { rectangle bground_r{ rect.x, item_coord.y, rect.width, static_cast(rect.bottom() - item_coord.y) }; @@ -4117,17 +4134,16 @@ namespace nana essence_->content_view->sync(false); } - bool sel = true; + bool new_selected_status = true; - //no single selected - if (!lister.single_status(true)) + if (!lister.single_status(true)) //multiply selection enabled { if (arg.shift) { //Set the first item as the begin of selected item if there //is not a latest selected item.(#154 reported by RenaudAlpes) - if (lister.latest_selected_abs.empty() || lister.latest_selected_abs.is_category()) - lister.latest_selected_abs.set_both(0); + if (lister.latest_selected_abs.empty()) + lister.latest_selected_abs = lister.first(); auto before = lister.latest_selected_abs; @@ -4141,7 +4157,7 @@ namespace nana else if (arg.ctrl) { essence_->mouse_selection.reverse_selection = true; - sel = !item_proxy(essence_, abs_item_pos).selected(); + new_selected_status = !essence_->cs_status(abs_item_pos, true); } else { @@ -4150,12 +4166,12 @@ namespace nana //Unselects all selected items if the current item is not selected before selecting. auto selected = lister.pick_items(true); if (selected.cend() == std::find(selected.cbegin(), selected.cend(), item_pos)) - lister.select_for_all(false, item_pos); + lister.select_for_all(false, abs_item_pos); } else { //Unselects all selected items except current item if right button clicked. - lister.select_for_all(false, item_pos); //cancel all selections + lister.select_for_all(false, abs_item_pos); //cancel all selections } } } @@ -4164,14 +4180,14 @@ namespace nana //Clicking on a category is ignored when single selection is enabled. //Fixed by Greentwip(issue #121) if (item_ptr) - sel = !item_proxy(essence_, abs_item_pos).selected(); + new_selected_status = !item_proxy(essence_, abs_item_pos).selected(); } if(item_ptr) { - if (item_ptr->flags.selected != sel) + if (item_ptr->flags.selected != new_selected_status) { - if (sel) + if (new_selected_status) { //Deselects the previously selected item. lister.cancel_others_if_single_enabled(true, abs_item_pos); @@ -4180,13 +4196,15 @@ namespace nana else if (essence_->lister.latest_selected_abs == abs_item_pos) essence_->lister.latest_selected_abs.set_both(npos); - item_ptr->flags.selected = sel; + item_ptr->flags.selected = new_selected_status; lister.emit_cs(abs_item_pos, true); } } else { - lister.cat_status(item_pos.cat, true, true); + //A category was clicked. Sets all child items to be selected only if multiply selection is enabled. + if(!lister.single_status(true)) + lister.cat_status(item_pos.cat, true, true); } } else @@ -4336,8 +4354,9 @@ namespace nana void trigger::key_press(graph_reference graph, const arg_keyboard& arg) { + auto & list = essence_->lister; // Exit if list is empty - if (essence_->lister.first().empty()) + if (list.first().empty()) return; bool upward = false; @@ -4347,12 +4366,12 @@ namespace nana case keyboard::os_arrow_up: upward = true; case keyboard::os_arrow_down: - essence_->lister.move_select(upward, !arg.shift, true); + list.move_select(upward, !arg.shift, true); break; case L' ': { index_pairs s; - bool ck = ! essence_->lister.item_selected_all_checked(s); + bool ck = ! list.item_selected_all_checked(s); for(auto i : s) item_proxy(essence_, i).check(ck); } @@ -4361,30 +4380,69 @@ namespace nana upward = true; case keyboard::os_pagedown: { - //Turns page, then returns if no change occurs - if (!essence_->content_view->turn_page(!upward, false)) - return; + auto const item_px = essence_->item_height(); + auto picked_items = list.pick_items(true, true); + index_pair init_idx = (picked_items.empty() ? list.first() : picked_items[0]); essence_->lister.select_for_all(false); - auto idx = essence_->first_display(); + //Get the pixels between the init item and top edge or bottom edge + auto logic_top = static_cast(list.distance(list.first(), init_idx) * item_px); - if (!upward) - idx = essence_->lister.advance(idx, static_cast(essence_->count_of_exposed(false)) - 1); + auto const screen_top = essence_->content_view->origin().y; + auto const screen_bottom = screen_top + essence_->content_view->view_area().height; + index_pair target_idx; - if (!idx.is_category()) - item_proxy::from_display(essence_, idx).select(true); - else if (!essence_->lister.single_status(true)) //not selected - essence_->lister.cat_status(idx.cat, true, true); + //Check if it scrolls in current screen window + //condition: top of target item is not less than top edge of content view and + //the bottom of target item is not greater than bottom edge of content view. + if ((screen_top + item_px <= logic_top) && (logic_top + item_px + item_px <= screen_bottom)) + { + int offset = (static_cast(upward ? screen_top : screen_bottom - item_px) - logic_top) / static_cast(item_px); + target_idx = list.advance(init_idx, offset); + } + else + { + //turn page + auto page_item_count = (std::max)(1, static_cast(essence_->count_of_exposed(false))); - break; + auto origin = essence_->content_view->origin(); + if (upward) + { + target_idx = list.advance(init_idx, -page_item_count); + if (target_idx.empty()) + target_idx = list.first(); + + origin.y = list.distance(list.first(), target_idx) * item_px; + } + else + { + target_idx = list.advance(init_idx, page_item_count); + if (target_idx.empty()) + target_idx = list.last(); + + origin.y = list.distance(list.first(), target_idx) * item_px + item_px; + if (origin.y >= (screen_bottom - screen_top)) + origin.y -= (screen_bottom - screen_top); + else + origin.y = 0; + } + + essence_->content_view->move_origin(origin - essence_->content_view->origin()); + } + + if (!target_idx.is_category()) + item_proxy::from_display(essence_, target_idx).select(true); + else if (!list.single_status(true)) //not selected + list.cat_status(target_idx.cat, true, true); } + break; case keyboard::os_home: case keyboard::os_end: { - essence_->lister.select_for_all(false); + list.select_for_all(false); - auto pos = (keyboard::os_home == arg.key ? essence_->lister.first() : essence_->lister.last()); + auto pos = (keyboard::os_home == arg.key ? list.first() : list.last()); if (!pos.empty()) { //When the pos indicates an empty category, then search forwards/backwards(depending on arg.key whether it is Home or End) for a non empty category. @@ -4393,9 +4451,9 @@ namespace nana { if (keyboard::os_home == arg.key) { - while (0 == essence_->lister.size_item(pos.cat)) + while (0 == list.size_item(pos.cat)) { - if (++pos.cat >= essence_->lister.cat_container().size()) + if (++pos.cat >= list.cat_container().size()) { pos = index_pair{ npos, npos }; break; @@ -4404,7 +4462,7 @@ namespace nana } else { - while (0 == essence_->lister.size_item(pos.cat)) + while (0 == list.size_item(pos.cat)) { if (pos.cat-- == 0) { @@ -4416,7 +4474,7 @@ namespace nana if (!pos.empty()) { - if (essence_->lister.expand(pos.cat)) + if (list.expand(pos.cat)) pos.item = 0; } } @@ -4425,8 +4483,8 @@ namespace nana { if (pos.is_category()) { - if (!essence_->lister.single_status(true)) //multiple selection is not enabled - essence_->lister.cat_status(pos.cat, true, true); + if (!list.single_status(true)) //multiple selection is not enabled + list.cat_status(pos.cat, true, true); } else item_proxy::from_display(essence_, pos).select(true); @@ -4662,12 +4720,12 @@ namespace nana bool item_proxy::operator==(const std::string& s) const { - return (text(pos_.item) == s); + return (text(0) == s); } bool item_proxy::operator==(const std::wstring& s) const { - return (text(pos_.item) == to_utf8(s)); + return (text(0) == to_utf8(s)); } item_proxy & item_proxy::operator=(const item_proxy& rhs) @@ -5158,7 +5216,8 @@ namespace nana cat_->make_sort_order(); ess_->lister.sort(); - ess_->update(true); + //Don't ignore the auto-draw flag for performance enhancement. + ess_->update(); } } //end class cat_proxy diff --git a/source/gui/widgets/progress.cpp b/source/gui/widgets/progress.cpp index 2c498f7c..8a679c4c 100644 --- a/source/gui/widgets/progress.cpp +++ b/source/gui/widgets/progress.cpp @@ -1,6 +1,6 @@ /* * A Progress Indicator Implementation - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -96,7 +96,11 @@ namespace nana { if (widget_) { - auto value_px = (widget_->size().width - border_px * 2) * value_ / max_; + auto value_px = (widget_->size().width - border_px * 2); + + //avoid overflow + if (value_ < max_) + value_px = static_cast(value_px * (double(value_) / double(max_))); if (value_px != value_px_) { diff --git a/source/gui/widgets/scroll.cpp b/source/gui/widgets/scroll.cpp index b59e4721..acc2c8b6 100644 --- a/source/gui/widgets/scroll.cpp +++ b/source/gui/widgets/scroll.cpp @@ -1,7 +1,7 @@ /* * A Scroll Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -20,9 +20,15 @@ namespace nana namespace scroll { //struct metrics_type - metrics_type::metrics_type() - :peak(1), range(1), step(1), value(0), - what(buttons::none), pressed(false), scroll_length(0), scroll_pos(0) + metrics_type::metrics_type(): + peak(1), + range(1), + step(1), + value(0), + what(buttons::none), + pressed(false), + scroll_length(0), + scroll_pos(0) {} //end struct metrics_type diff --git a/source/paint/detail/image_jpeg.hpp b/source/paint/detail/image_jpeg.hpp index 1f19373b..d63a2c1d 100644 --- a/source/paint/detail/image_jpeg.hpp +++ b/source/paint/detail/image_jpeg.hpp @@ -91,7 +91,7 @@ namespace nana { ::jpeg_create_decompress(&jdstru); - ::jpeg_mem_src(&jdstru, const_cast(reinterpret_cast(data)), bytes); + ::jpeg_mem_src(&jdstru, const_cast(reinterpret_cast(data)), static_cast(bytes)); _m_read_jpg(jdstru); jpeg_finish_decompress(&jdstru);