diff --git a/build/vc2019/nana.sln b/build/vc2019/nana.sln new file mode 100644 index 00000000..d01415ee --- /dev/null +++ b/build/vc2019/nana.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26228.4 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nana", "nana.vcxproj", "{42D0520F-EFA5-4831-84FE-2B9085301C5D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {42D0520F-EFA5-4831-84FE-2B9085301C5D}.Debug|x64.ActiveCfg = Debug|x64 + {42D0520F-EFA5-4831-84FE-2B9085301C5D}.Debug|x64.Build.0 = Debug|x64 + {42D0520F-EFA5-4831-84FE-2B9085301C5D}.Debug|x86.ActiveCfg = Debug|Win32 + {42D0520F-EFA5-4831-84FE-2B9085301C5D}.Debug|x86.Build.0 = Debug|Win32 + {42D0520F-EFA5-4831-84FE-2B9085301C5D}.Release|x64.ActiveCfg = Release|x64 + {42D0520F-EFA5-4831-84FE-2B9085301C5D}.Release|x64.Build.0 = Release|x64 + {42D0520F-EFA5-4831-84FE-2B9085301C5D}.Release|x86.ActiveCfg = Release|Win32 + {42D0520F-EFA5-4831-84FE-2B9085301C5D}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/build/vc2019/nana.vcxproj b/build/vc2019/nana.vcxproj new file mode 100644 index 00000000..34b0b29d --- /dev/null +++ b/build/vc2019/nana.vcxproj @@ -0,0 +1,316 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {42D0520F-EFA5-4831-84FE-2B9085301C5D} + Win32Proj + nana + + + + StaticLibrary + true + v142 + Unicode + + + StaticLibrary + false + v142 + true + Unicode + + + StaticLibrary + true + v142 + Unicode + + + StaticLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + ..\..\include;$(IncludePath) + ../bin/ + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + + + ..\..\include;$(IncludePath) + ../bin/ + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + + + ../bin/ + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + ..\..\include;$(IncludePath) + + + ../bin/ + ..\..\..\temp\$(ProjectName)\$(PlatformToolset)_$(Configuration)_$(PlatformShortName)\ + $(ProjectName)_$(PlatformToolset)_$(Configuration)_$(PlatformShortName) + ..\..\include;$(IncludePath) + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + true + stdcpplatest + + + Windows + + + + + + + Level3 + Disabled + _DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + true + stdcpplatest + + + Windows + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + true + stdcpplatest + + + Windows + true + true + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + true + stdcpplatest + + + Windows + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/vc2019/nana.vcxproj.filters b/build/vc2019/nana.vcxproj.filters new file mode 100644 index 00000000..4923833d --- /dev/null +++ b/build/vc2019/nana.vcxproj.filters @@ -0,0 +1,489 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {81850bad-7436-405a-beb5-357c5e34f039} + + + {44582b36-4575-4663-ac02-e80417f95d05} + + + {b7e3cdb7-99ac-473d-86c8-53dddce70480} + + + {02fa693c-edc1-4e04-bf1d-ec3c2a89182a} + + + {cffe7506-b96c-42aa-a747-41b5115d9580} + + + {b6b2c032-c6a4-4884-8c14-eca4aa69ef0c} + + + {58f2e0f8-4d63-40db-807d-d7adf71c4ebe} + + + {f288a25d-3ce8-4c2e-a86f-9aeda44bc557} + + + {90b2da01-605d-489b-b6c5-2af8d3c2d8a6} + + + {430feed0-e1d9-45cb-8d59-e1a48a04d19f} + + + {dcf62634-a658-453b-a58d-f1a96a12a8b8} + + + {c1cdf46a-519f-422a-947f-39e173045414} + + + {d68bd89c-170f-445f-b79f-aa03c881ab6b} + + + {a5d87649-2cd1-4a8f-a1f9-7151eaf6c772} + + + {0e6a58ab-652c-45d7-b9aa-8d9f2fa80ea1} + + + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources\audio\detail + + + Sources\audio\detail + + + Sources\audio\detail + + + Sources\audio + + + Sources\detail + + + Sources\filesystem + + + Sources\gui\detail + + + Sources\gui\detail + + + Sources\gui\detail + + + Sources\gui\detail + + + Sources\gui\detail + + + Sources\gui\detail + + + Sources\gui\detail + + + Sources\gui\detail + + + Sources\gui\detail + + + Sources\gui\detail + + + Sources\gui\widgets\skeletons + + + Sources\gui\widgets\skeletons + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\gui\widgets + + + Sources\paint\detail + + + Sources\paint\detail + + + Sources\paint + + + Sources\paint + + + Sources\paint + + + Sources\paint + + + Sources\paint + + + Sources\system + + + Sources\system + + + Sources\system + + + Sources\system + + + Sources\threads + + + Sources\detail + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + Sources\gui + + + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui\widgets + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include\gui + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include + + + Include\gui + + + + + Include + + + Include + + + \ No newline at end of file diff --git a/include/nana/deploy.hpp b/include/nana/deploy.hpp index 168358c5..e3091d23 100644 --- a/include/nana/deploy.hpp +++ b/include/nana/deploy.hpp @@ -118,7 +118,5 @@ namespace nana } } -#define NANA_RGB(a) (((DWORD)(a) & 0xFF)<<16) | ((DWORD)(a) & 0xFF00) | (((DWORD)(a) & 0xFF0000) >> 16 ) - #include #endif //NANA_DEPLOY_HPP diff --git a/include/nana/gui.hpp b/include/nana/gui.hpp index 70bcb077..09c2f7b9 100644 --- a/include/nana/gui.hpp +++ b/include/nana/gui.hpp @@ -1 +1,54 @@ -#include "gui/wvl.hpp" \ No newline at end of file +/** + * Nana GUI Header + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 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.hpp + * @description + * the header file contains the files required for running of Nana.GUI + */ + +#ifndef NANA_GUI_HPP +#define NANA_GUI_HPP + +#include "gui/compact.hpp" +#include "gui/screen.hpp" +#include "gui/widgets/form.hpp" +#include "gui/drawing.hpp" +#include "gui/msgbox.hpp" +#include "gui/place.hpp" + + +namespace nana +{ +#ifdef NANA_AUTOMATIC_GUI_TESTING + + /// @brief Take control of the GUI and optionally automatically tests it. + /// + /// @detail It transfers to nana the program flow control, which begin pumping messages + /// from the underlying OS, interpreting and sending it with suitable arguments + /// to the nana widgets that registered a response in the corresponding event. + /// It also accept arguments to be used in case of automatic GUI testing. + /// Other Way the arguments are ignored. + void exec( + unsigned wait = 1, ///< for the GUI to be constructed, in seconds + unsigned wait_end = 1, ///< for the GUI to be destructed, in seconds + std::function = {} ///< emit events to mimics user actions and may assert results + ); + + /// send a click message to this widget - useful in GUI testing + void click(widget& w); + + /// in seconds + void Wait(unsigned wait = 0); +#else + void exec(); +#endif + + +}//end namespace nana +#endif diff --git a/include/nana/gui/basis.hpp b/include/nana/gui/basis.hpp index b868a00a..e6ee771c 100644 --- a/include/nana/gui/basis.hpp +++ b/include/nana/gui/basis.hpp @@ -24,10 +24,11 @@ namespace nana { namespace detail { - struct native_window_handle_impl{}; - struct window_handle_impl{}; - struct event_handle_impl{}; - struct native_drawable_impl{}; + struct basic_window; + + struct native_window_handle_impl; + struct native_drawable_impl; + struct event_handle_impl; } struct accel_key @@ -87,10 +88,11 @@ namespace nana struct root_tag : public widget_tag{ static const flags value = flags::root; }; }// end namespace category - using native_window_type = detail::native_window_handle_impl*; - using window = detail::window_handle_impl*; ///< \see [What is window class ](https://sourceforge.net/p/nanapro/discussion/general/thread/bd0fabfb/) - using event_handle = detail::event_handle_impl*; - using native_drawable_type = detail::native_drawable_impl*; + using window = detail::basic_window*; ///< The window handle type representing nana window objects + using native_window_type = detail::native_window_handle_impl*; ///< The native window handle type representing system native windows. E.g, HWND in windows, Window in X11 + + using event_handle = detail::event_handle_impl*; ///< The event handle type representing nana window events + using native_drawable_type = detail::native_drawable_impl*; ///< The drawable handle type representing system native drawable objects. E.g. HDC in windows, Drawable in X11 struct keyboard diff --git a/include/nana/gui/compact.hpp b/include/nana/gui/compact.hpp new file mode 100644 index 00000000..c4a9789a --- /dev/null +++ b/include/nana/gui/compact.hpp @@ -0,0 +1,57 @@ +/** + * Nana GUI Library Definition + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 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/compact.hpp + * @description + * the header file contains the files required for running of Nana.GUI + */ + +#ifndef NANA_GUI_WVL_HPP +#define NANA_GUI_WVL_HPP + +#include "programming_interface.hpp" + +namespace nana +{ + namespace detail + { + struct form_loader_private + { + template friend class form_loader; + private: + static void insert_form(::nana::widget*); + }; + + template + class form_loader + { + public: + template + Form & operator()(Args &&... args) const + { + auto p = new Form(std::forward(args)...); + + if (p->empty()) + throw std::runtime_error("form_loader failed to create the form"); + + + detail::form_loader_private::insert_form(p); + if (IsVisible) + p->show(); + + return *p; + } + + }; + } + + template + using form_loader = detail::form_loader; +}//end namespace nana +#endif diff --git a/include/nana/gui/detail/bedrock.hpp b/include/nana/gui/detail/bedrock.hpp index db731e97..834431ac 100644 --- a/include/nana/gui/detail/bedrock.hpp +++ b/include/nana/gui/detail/bedrock.hpp @@ -37,8 +37,6 @@ namespace detail bedrock(const bedrock&) = delete; bedrock& operator=(const bedrock&) = delete; public: - using core_window_t = basic_window; - struct thread_context; class flag_guard; @@ -59,16 +57,16 @@ namespace detail ~bedrock(); void pump_event(window, bool is_modal); - void flush_surface(core_window_t*, bool forced, const rectangle* update_area = nullptr); + void flush_surface(basic_window*, bool forced, const rectangle* update_area = nullptr); static int inc_window(thread_t tid = 0); thread_context* open_thread_context(thread_t tid = 0); thread_context* get_thread_context(thread_t tid = 0); void remove_thread_context(thread_t tid = 0); static bedrock& instance(); - core_window_t* focus(); + basic_window* focus(); - void set_menubar_taken(core_window_t*); + void set_menubar_taken(basic_window*); //Delay Restores focus when a menu which attached to menubar is closed void delay_restore(int); @@ -84,7 +82,7 @@ namespace detail bool shortkey_occurred() const; element_store& get_element_store() const; - void map_through_widgets(core_window_t*, native_drawable_type); + void map_through_widgets(basic_window*, native_drawable_type); //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(thread_t thread_id); @@ -94,28 +92,28 @@ namespace detail 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); - bool event_msleave(core_window_t*); - void event_focus_changed(core_window_t* root_wd, native_window_type receiver, bool getting); - void thread_context_destroy(core_window_t*); + void event_expose(basic_window *, bool exposed); + void event_move(basic_window*, int x, int y); + bool event_msleave(basic_window*); + void event_focus_changed(basic_window* root_wd, native_window_type receiver, bool getting); + void thread_context_destroy(basic_window*); void thread_context_lazy_refresh(); - void update_cursor(core_window_t*); - void set_cursor(core_window_t*, nana::cursor, thread_context*); - void define_state_cursor(core_window_t*, nana::cursor, thread_context*); - void undefine_state_cursor(core_window_t*, thread_context*); + void update_cursor(basic_window*); + void set_cursor(basic_window*, nana::cursor, thread_context*); + void define_state_cursor(basic_window*, nana::cursor, thread_context*); + void undefine_state_cursor(basic_window*, thread_context*); color_schemes& scheme(); events_operation& evt_operation(); window_manager& wd_manager(); - void manage_form_loader(core_window_t*, bool insert_or_remove); + void manage_form_loader(basic_window*, bool insert_or_remove); public: // if 'bForce__EmitInternal', then ONLY internal (widget's) events are processed (even through explicit filtering) - bool emit(event_code, core_window_t*, const event_arg&, bool ask_update, thread_context*, const bool bForce__EmitInternal = false); + bool emit(event_code, basic_window*, const event_arg&, bool ask_update, thread_context*, const bool bForce__EmitInternal = false); private: - void _m_emit_core(event_code, core_window_t*, bool draw_only, const event_arg&, const bool bForce__EmitInternal); - void _m_event_filter(event_code, core_window_t*, thread_context*); + void _m_emit_core(event_code, basic_window*, bool draw_only, const event_arg&, const bool bForce__EmitInternal); + void _m_event_filter(event_code, basic_window*, thread_context*); private: static bedrock bedrock_object; diff --git a/include/nana/gui/detail/effects_renderer.hpp b/include/nana/gui/detail/effects_renderer.hpp deleted file mode 100644 index 3a980caa..00000000 --- a/include/nana/gui/detail/effects_renderer.hpp +++ /dev/null @@ -1,223 +0,0 @@ -/* -* 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 -#include -#include -#include -#include - -namespace nana{ - namespace detail - { - template - class edge_nimbus_renderer - { - edge_nimbus_renderer() = default; - public: - using core_window_t = CoreWindow; - using window_layer = ::nana::detail::window_layout; - using graph_reference = ::nana::paint::graphics&; - - static edge_nimbus_renderer& instance() - { - static edge_nimbus_renderer object; - return object; - } - - constexpr unsigned weight() const - { - return 2; - } - - void erase(core_window_t* wd) - { - if (effects::edge_nimbus::none == wd->effect.edge_nimbus) - return; - - core_window_t * root_wd = wd->root_widget; - auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus; - - for (auto i = nimbus.begin(); i != nimbus.end(); ++i) - { - if (i->window == wd) - { - auto pixels = weight(); - rectangle r{wd->pos_root, wd->dimension}; - r.x -= static_cast(pixels); - r.y -= static_cast(pixels); - r.width += static_cast(pixels << 1); - r.height += static_cast(pixels << 1); - - root_wd->root_graph->paste(root_wd->root, r, r.x, r.y); - - nimbus.erase(i); - break; - } - } - } - - void render(core_window_t * wd, bool forced, const rectangle* update_area = nullptr) - { - bool copy_separately = true; - std::vector> rd_set; - - if (wd->root_widget->other.attribute.root->effects_edge_nimbus.size()) - { - auto root_wd = wd->root_widget; - - auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus; - - auto focused = root_wd->other.attribute.root->focus; - - const unsigned pixels = weight(); - - auto graph = root_wd->root_graph; - - nana::rectangle r; - for(auto & action : nimbus) - { - if(_m_edge_nimbus(action.window, focused) && window_layer::read_visual_rectangle(action.window, r)) - { - if (action.window == wd) - { - if (update_area) - ::nana::overlap(*update_area, rectangle(r), r); - copy_separately = false; - } - - //Avoiding duplicated rendering. If the window is declared to lazy refresh, it should be rendered. - if ((forced && (action.window == wd)) || (focused == action.window) || !action.rendered || (action.window->other.upd_state == core_window_t::update_state::refreshed)) - { - rd_set.emplace_back(r, action.window); - action.rendered = true; - } - } - else if(action.rendered) - { - action.rendered = false; - - if (action.window == wd) - copy_separately = false; - - ::nana::rectangle erase_r( - action.window->pos_root.x - static_cast(pixels), - action.window->pos_root.y - static_cast(pixels), - static_cast(action.window->dimension.width + (pixels << 1)), - static_cast(action.window->dimension.height + (pixels << 1)) - ); - - graph->paste(root_wd->root, erase_r, erase_r.x, erase_r.y); - } - } - } - - if (copy_separately) - { - rectangle vr; - if (window_layer::read_visual_rectangle(wd, vr)) - { - if (update_area) - ::nana::overlap(*update_area, rectangle(vr), vr); - wd->root_graph->paste(wd->root, vr, vr.x, vr.y); - } - } - - rectangle wd_r{ wd->pos_root, wd->dimension }; - wd_r.pare_off(-static_cast(this->weight())); - //Render - for (auto & rd : rd_set) - { - auto other_wd = rd.second; - - if (other_wd != wd) - { - rectangle other_r{ other_wd->pos_root, other_wd->dimension }; - other_r.pare_off(-static_cast(this->weight())); - if (!overlapped(wd_r, other_r)) - continue; - } - _m_render_edge_nimbus(other_wd, rd.first); - } - } - private: - /// 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) - { - // 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; - } - - void _m_render_edge_nimbus(core_window_t* wd, const nana::rectangle & visual) - { - wd->flags.action_before = wd->flags.action; - - auto r = visual; - r.pare_off(-static_cast(weight())); - rectangle good_r; - if (overlap(r, rectangle{ wd->root_graph->size() }, good_r)) - { - if ((good_r.x < wd->pos_root.x) || (good_r.y < wd->pos_root.y) || - (good_r.right() > visual.right()) || (good_r.bottom() > visual.bottom())) - { - auto graph = wd->root_graph; - nana::paint::pixel_buffer pixbuf(graph->handle(), r); - - pixel_argb_t px0, px1, px2, px3; - - px0 = pixbuf.pixel(0, 0); - px1 = pixbuf.pixel(r.width - 1, 0); - px2 = pixbuf.pixel(0, r.height - 1); - px3 = pixbuf.pixel(r.width - 1, r.height - 1); - - good_r.x = good_r.y = 1; - good_r.width = r.width - 2; - good_r.height = r.height - 2; - pixbuf.rectangle(good_r, wd->annex.scheme->activated.get_color(), 0.95, false); - - good_r.x = good_r.y = 0; - good_r.width = r.width; - good_r.height = r.height; - pixbuf.rectangle(good_r, wd->annex.scheme->activated.get_color(), 0.4, false); - - pixbuf.pixel(0, 0, px0); - pixbuf.pixel(r.width - 1, 0, px1); - pixbuf.pixel(0, r.height - 1, px2); - pixbuf.pixel(r.width - 1, r.height - 1, px3); - - pixbuf.paste(wd->root, { r.x, r.y }); - - std::vector overlaps; - if(window_layer::read_overlaps(wd, visual, overlaps)) - { - for(auto & wdr : overlaps) - graph->paste(wd->root, wdr.r, wdr.r.x, wdr.r.y); - } - } - else - wd->root_graph->paste(wd->root, visual, visual.x, visual.y); - } - } - }; - } -}//end namespace nana - -#endif diff --git a/include/nana/gui/detail/general_events.hpp b/include/nana/gui/detail/general_events.hpp index 2171cb7a..f58f9680 100644 --- a/include/nana/gui/detail/general_events.hpp +++ b/include/nana/gui/detail/general_events.hpp @@ -24,9 +24,13 @@ namespace nana { + namespace API + { + bool is_window(window); ///< Determines whether a window is existing, equal to !empty_window. + } + namespace detail { - bool check_window(window); void events_operation_register(event_handle); class event_interface @@ -36,16 +40,16 @@ namespace nana virtual void remove(event_handle) = 0; }; - class docker_interface + class event_docker_interface { public: - virtual ~docker_interface() = default; + virtual ~event_docker_interface() = default; virtual event_interface* get_event() const = 0; }; struct docker_base - : public docker_interface + : public event_docker_interface { event_interface * const event_ptr; bool flag_deleted; @@ -78,11 +82,11 @@ namespace nana event_base * const evt_; }; - event_handle _m_emplace(detail::docker_interface*, bool in_front); + event_handle _m_emplace(detail::event_docker_interface*, bool in_front); protected: unsigned emitting_count_{ 0 }; bool deleted_flags_{ false }; - std::vector * dockers_{ nullptr }; + std::vector * dockers_{ nullptr }; }; }//end namespace detail @@ -228,7 +232,7 @@ namespace nana d->invoke(arg); - if (window_handle && (!detail::check_window(window_handle))) + if (window_handle && (!::nana::API::is_window(window_handle))) break; } } diff --git a/include/nana/gui/detail/window_layout.hpp b/include/nana/gui/detail/window_layout.hpp index 9d628946..01256ce6 100644 --- a/include/nana/gui/detail/window_layout.hpp +++ b/include/nana/gui/detail/window_layout.hpp @@ -35,11 +35,9 @@ namespace detail class window_layout { public: - typedef basic_window core_window_t; - struct wd_rectangle { - core_window_t * window; + basic_window * window; rectangle r; }; @@ -49,27 +47,27 @@ namespace detail try_refresh }; public: - static void paint(core_window_t*, paint_operation, bool request_refresh_children); + static void paint(basic_window*, paint_operation, bool request_refresh_children); - static bool maproot(core_window_t*, bool have_refreshed, bool request_refresh_children); + static bool maproot(basic_window*, bool have_refreshed, bool request_refresh_children); - static void paste_children_to_graphics(core_window_t*, nana::paint::graphics& graph); + static void paste_children_to_graphics(basic_window*, nana::paint::graphics& graph); //read_visual_rectangle //@brief: Reads the visual rectangle of a window, the visual rectangle's reference frame is to root widget, // the visual rectangle is a rectangular block that a window should be displayed on screen. // The result is a rectangle that is a visible area for its ancesters. - static bool read_visual_rectangle(core_window_t*, nana::rectangle& visual); + static bool read_visual_rectangle(basic_window*, nana::rectangle& visual); //read_overlaps // reads the overlaps that are overlapped a rectangular block - static bool read_overlaps(core_window_t*, const nana::rectangle& vis_rect, std::vector& blocks); + static bool read_overlaps(basic_window*, const nana::rectangle& vis_rect, std::vector& blocks); - static bool enable_effects_bground(core_window_t *, bool enabled); + static bool enable_effects_bground(basic_window *, bool enabled); //make_bground // update the glass buffer of a glass window. - static void make_bground(core_window_t* const); + static void make_bground(basic_window* const); private: /// _m_paste_children @@ -82,16 +80,16 @@ namespace detail * @param graph A graphics object to which the child windows are pasted. * @param graph_rpos The reference point to the graph. */ - static void _m_paste_children(core_window_t* window, bool has_refreshed, bool request_refresh_children, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos); + static void _m_paste_children(basic_window* window, bool has_refreshed, bool request_refresh_children, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos); - static void _m_paint_glass_window(core_window_t*, bool is_redraw, bool is_child_refreshed, bool called_by_notify, bool notify_other); + static void _m_paint_glass_window(basic_window*, bool is_redraw, bool is_child_refreshed, bool called_by_notify, bool notify_other); //Notify the windows which have brground to update their background buffer. - static void _m_notify_glasses(core_window_t* const sigwd); + static void _m_notify_glasses(basic_window* const sigwd); private: struct data_section { - std::vector effects_bground_windows; + std::vector effects_bground_windows; }; static data_section data_sect; };//end class window_layout diff --git a/include/nana/gui/detail/window_manager.hpp b/include/nana/gui/detail/window_manager.hpp index 1aa18fe2..8c4390d3 100644 --- a/include/nana/gui/detail/window_manager.hpp +++ b/include/nana/gui/detail/window_manager.hpp @@ -67,95 +67,93 @@ namespace detail using native_window = native_window_type; using mutex_type = revertible_mutex; - using core_window_t = basic_window; - window_manager(); ~window_manager(); - std::size_t number_of_core_window() const; + std::size_t window_count() const; mutex_type & internal_lock() const; - void all_handles(std::vector&) const; + void all_handles(std::vector&) const; - void event_filter(core_window_t*, bool is_make, event_code); + void event_filter(basic_window*, bool is_make, event_code); - bool available(core_window_t*); - bool available(core_window_t *, core_window_t*); + bool available(basic_window*); + bool available(basic_window *, basic_window*); - core_window_t* create_root(core_window_t*, bool nested, rectangle, const appearance&, widget*); - core_window_t* create_widget(core_window_t*, const rectangle&, bool is_lite, widget*); - void close(core_window_t*); + basic_window* create_root(basic_window*, bool nested, rectangle, const appearance&, widget*); + basic_window* create_widget(basic_window*, const rectangle&, bool is_lite, widget*); + void close(basic_window*); //destroy //@brief: Delete the window handle - void destroy(core_window_t*); + void destroy(basic_window*); //destroy_handle //@brief: Delete window handle, the handle type must be a root and a frame. // Deletes a window whose category type is a root type or a frame type. - void destroy_handle(core_window_t*); + void destroy_handle(basic_window*); - void icon(core_window_t*, const paint::image& small_icon, const paint::image& big_icon); + void icon(basic_window*, const paint::image& small_icon, const paint::image& big_icon); - bool show(core_window_t* wd, bool visible); + bool show(basic_window* wd, bool visible); //find a widget window at specified position //@param root A root window //@param pos Position //@param ignore_captured A flag indicates whether to ignore redirecting the result to its captured window. If this paramter is true, it returns the window at the position, if the parameter is false, it returns the captured window if the captured window don't ignore children. - core_window_t* find_window(native_window_type root, const point& pos, bool ignore_captured = false); + basic_window* find_window(native_window_type root, const point& pos, bool ignore_captured = false); //move the wnd and its all children window, x and y is a relatively coordinate for wnd's parent window - bool move(core_window_t*, int x, int y, bool passive); - bool move(core_window_t*, const rectangle&); + bool move(basic_window*, int x, int y, bool passive); + bool move(basic_window*, const rectangle&); - bool size(core_window_t*, nana::size, bool passive, bool ask_update); + bool size(basic_window*, nana::size, bool passive, bool ask_update); - core_window_t* root(native_window_type) const; + basic_window* root(native_window_type) const; //Copy the root buffer that wnd specified into DeviceContext - void map(core_window_t*, bool forced, const rectangle* update_area = nullptr); + void map(basic_window*, bool forced, const rectangle* update_area = nullptr); - bool update(core_window_t*, bool redraw, bool force, const rectangle* update_area = nullptr); - void update_requesters(core_window_t* root_wd); - void refresh_tree(core_window_t*); + bool update(basic_window*, bool redraw, bool force, const rectangle* update_area = nullptr); + void update_requesters(basic_window* root_wd); + void refresh_tree(basic_window*); - void do_lazy_refresh(core_window_t*, bool force_copy_to_screen, bool refresh_tree = false); + void do_lazy_refresh(basic_window*, bool force_copy_to_screen, bool refresh_tree = false); - bool set_parent(core_window_t* wd, core_window_t* new_parent); - core_window_t* set_focus(core_window_t*, bool root_has_been_focused, arg_focus::reason); + bool set_parent(basic_window* wd, basic_window* new_parent); + basic_window* set_focus(basic_window*, bool root_has_been_focused, arg_focus::reason); - core_window_t* capture_redirect(core_window_t*); + basic_window* capture_redirect(basic_window*); bool capture_window_entered(int root_x, int root_y, bool& prev); - core_window_t * capture_window() const; - void capture_window(core_window_t*, bool capture, bool ignore_children_if_captured); + basic_window * capture_window() const; + void capture_window(basic_window*, bool capture, bool ignore_children_if_captured); - void enable_tabstop(core_window_t*); - core_window_t* tabstop(core_window_t*, bool forward) const; //forward means move to next in logic. + void enable_tabstop(basic_window*); + basic_window* tabstop(basic_window*, bool forward) const; //forward means move to next in logic. void remove_trash_handle(thread_t tid); - bool enable_effects_bground(core_window_t*, bool); + bool enable_effects_bground(basic_window*, bool); - bool calc_window_point(core_window_t*, nana::point&); + bool calc_window_point(basic_window*, nana::point&); root_misc* root_runtime(native_window) const; - bool register_shortkey(core_window_t*, unsigned long key); - void unregister_shortkey(core_window_t*, bool with_children); + bool register_shortkey(basic_window*, unsigned long key); + void unregister_shortkey(basic_window*, bool with_children); - core_window_t* find_shortkey(native_window_type, unsigned long key); + basic_window* find_shortkey(native_window_type, unsigned long key); - void set_safe_place(core_window_t* wd, std::function&& fn); + void set_safe_place(basic_window* wd, std::function&& fn); void call_safe_place(thread_t thread_id); private: - void _m_disengage(core_window_t*, core_window_t* for_new); - void _m_destroy(core_window_t*); - void _m_move_core(core_window_t*, const point& delta); - void _m_shortkeys(core_window_t*, bool with_chlidren, std::vector>& keys) const; - core_window_t* _m_find(core_window_t*, const point&); - static bool _m_effective(core_window_t*, const point& root_pos); + void _m_disengage(basic_window*, basic_window* for_new); + void _m_destroy(basic_window*); + void _m_move_core(basic_window*, const point& delta); + void _m_shortkeys(basic_window*, bool with_chlidren, std::vector>& keys) const; + basic_window* _m_find(basic_window*, const point&); + static bool _m_effective(basic_window*, const point& root_pos); private: mutable mutex_type mutex_; @@ -166,10 +164,10 @@ namespace detail { struct captured { - core_window_t *window; + basic_window *window; bool inside; bool ignore_children; - std::vector > history; + std::vector > history; }capture; }attr_; diff --git a/include/nana/gui/notifier.hpp b/include/nana/gui/notifier.hpp index 31cf28f1..d0d87efa 100644 --- a/include/nana/gui/notifier.hpp +++ b/include/nana/gui/notifier.hpp @@ -59,11 +59,7 @@ namespace nana void text(const ::std::string&); void icon(const ::std::string& icon_file); void insert_icon(const ::std::string& icon_file); -#if 0 //deprecated - void period(unsigned millisecond); -#else void period(std::chrono::milliseconds time); -#endif detail::notifier_events& events(); window handle() const; private: diff --git a/include/nana/gui/timer.hpp b/include/nana/gui/timer.hpp index 699be103..c360884b 100644 --- a/include/nana/gui/timer.hpp +++ b/include/nana/gui/timer.hpp @@ -22,14 +22,16 @@ namespace nana { - /// Can repeatedly call a piece of code. + + class timer; struct arg_elapse : public event_arg { - long long id; //timer identifier; + timer* sender; //indicates which timer emitted this notification }; + /// Can repeatedly call a piece of code. class timer { struct implement; diff --git a/include/nana/gui/widgets/listbox.hpp b/include/nana/gui/widgets/listbox.hpp index 717d6d91..4827a227 100644 --- a/include/nana/gui/widgets/listbox.hpp +++ b/include/nana/gui/widgets/listbox.hpp @@ -1219,7 +1219,6 @@ namespace nana unsigned min_column_width{ 20 }; ///< def=20 . non counting suspension_width - unsigned suspension_width{ 8 }; ///< def= . the trigger will set this to the width if ("...") unsigned text_margin{ 5 }; ///< def= 5. Additional or extended with added (before) to the text width to determine the cell width. cell_w = text_w + ext_w +1 unsigned item_height_ex{ 6 }; ///< Set !=0 !!!! def=6. item_height = text_height + item_height_ex @@ -1603,6 +1602,8 @@ the nana::detail::basic_window member pointer scheme * It returns true to deselect the selected items. It returns false to cancel to deselect the selected items. */ void set_deselect(std::function predicate); + + unsigned suspension_width() const; private: drawerbase::listbox::essence & _m_ess() const; nana::any* _m_anyobj(size_type cat, size_type index, bool allocate_if_empty) const override; diff --git a/include/nana/gui/wvl.hpp b/include/nana/gui/wvl.hpp deleted file mode 100644 index c18be253..00000000 --- a/include/nana/gui/wvl.hpp +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Nana GUI Library Definition - * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2017 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/wvl.hpp - * @description - * the header file contains the files required for running of Nana.GUI - */ - -#ifndef NANA_GUI_WVL_HPP -#define NANA_GUI_WVL_HPP - -#include "programming_interface.hpp" -#include "screen.hpp" -#include "widgets/form.hpp" -#include "drawing.hpp" -#include "msgbox.hpp" -#include "place.hpp" - - -namespace nana -{ - namespace detail - { - struct form_loader_private - { - template friend class form_loader; - private: - static void insert_form(::nana::widget*); - }; - - template - class form_loader - { - public: - template - Form & operator()(Args &&... args) const - { - auto p = new Form(std::forward(args)...); - - if (p->empty()) - throw std::logic_error("form_loader failed to create the form"); - - detail::form_loader_private::insert_form(p); - if (IsVisible) - p->show(); - - return *p; - } - - }; - } - - template - using form_loader = detail::form_loader; - -#ifdef NANA_AUTOMATIC_GUI_TESTING - - /// @brief Take control of the GUI and optionally automatically tests it. - /// - /// @detail It transfers to nana the program flow control, which begin pumping messages - /// from the underlying OS, interpreting and sending it with suitable arguments - /// to the nana widgets that registered a response in the corresponding event. - /// It also accept arguments to be used in case of automatic GUI testing. - /// Other Way the arguments are ignored. - void exec( - unsigned wait = 1, ///< for the GUI to be constructed, in seconds - unsigned wait_end = 1, ///< for the GUI to be destructed, in seconds - std::function = {} ///< emit events to mimics user actions and may assert results - ); - - /// send a click message to this widget - useful in GUI testing - void click(widget& w); - - /// in seconds - void Wait(unsigned wait = 0); -#else - void exec(); -#endif - - -}//end namespace nana -#endif diff --git a/include/nana/paint/text_renderer.hpp b/include/nana/paint/text_renderer.hpp index 96fbbfdb..3510bb3d 100644 --- a/include/nana/paint/text_renderer.hpp +++ b/include/nana/paint/text_renderer.hpp @@ -10,14 +10,20 @@ namespace nana { public: using graph_reference = graphics &; + + enum class mode + { + truncate_with_ellipsis, + truncate_letter_with_ellipsis, + word_wrap + }; text_renderer(graph_reference graph, align = align::left); - nana::size extent_size(int x, int y, const wchar_t*, std::size_t len, unsigned restricted_pixels) const; + nana::size extent_size(int x, int y, const wchar_t*, std::size_t len, unsigned space_pixels) const; void render(const point&, const wchar_t*, std::size_t len); - void render(const point&, const wchar_t*, std::size_t len, unsigned restricted_pixels, bool omitted); - void render(const point&, const wchar_t*, std::size_t len, unsigned restricted_pixels); + void render(const point&, const wchar_t*, std::size_t len, unsigned space_pixels, mode); private: graph_reference graph_; align text_align_; diff --git a/source/datetime.cpp b/source/datetime.cpp index 8b024735..e6e8fa5b 100644 --- a/source/datetime.cpp +++ b/source/datetime.cpp @@ -14,29 +14,28 @@ #if defined(NANA_WINDOWS) #include #endif -#include #include namespace { std::tm localtime() { #if defined(NANA_WINDOWS) && !defined(NANA_MINGW) - time_t t; - ::time(&t); + std::time_t t = std::time(nullptr); std::tm tm; - if(localtime_s(&tm, &t) != 0) - assert(false); + if (localtime_s(&tm, &t) != 0) + throw std::runtime_error("invalid local time"); return tm; #else time_t t = std::time(nullptr); struct tm * tm_addr = std::localtime(&t); - assert(tm_addr); - + if(nullptr == tm_addr) + throw std::runtime_error("invalid local time"); + return *tm_addr; #endif } - + ::nana::date::value to_dateval(const std::tm& t) { return {static_cast(t.tm_year + 1900), static_cast(t.tm_mon + 1), static_cast(t.tm_mday)}; @@ -51,7 +50,7 @@ namespace { namespace nana { - //class date + //class date void date::set(const std::tm& t) { value_ = to_dateval(t); diff --git a/source/detail/mswin/platform_spec.hpp b/source/detail/mswin/platform_spec.hpp index 1a44ce8b..ae83562d 100644 --- a/source/detail/mswin/platform_spec.hpp +++ b/source/detail/mswin/platform_spec.hpp @@ -1,7 +1,7 @@ /** * Platform Specification Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -96,19 +96,19 @@ namespace detail unsigned whitespace_pixels; }string; + unsigned fgcolor_rgb{ 0xFFFFFFFF }; + unsigned bgcolor_rgb{ 0xFFFFFFFF }; + unsigned fgcolor_native{ 0xFFFFFFFF }; //Windows RGB format: 0xBBGGRR + unsigned bgcolor_native{ 0xFFFFFFFF }; //Windows RGB format + drawable_impl_type(const drawable_impl_type&) = delete; drawable_impl_type& operator=(const drawable_impl_type&) = delete; drawable_impl_type(); ~drawable_impl_type(); - unsigned get_color() const; - unsigned get_text_color() const; void set_color(const ::nana::color&); void set_text_color(const ::nana::color&); - private: - unsigned color_{ 0xffffffff }; - unsigned text_color_{0xffffffff}; }; class platform_spec diff --git a/source/detail/platform_spec_posix.cpp b/source/detail/platform_spec_posix.cpp index f7cbc9d6..8944468b 100644 --- a/source/detail/platform_spec_posix.cpp +++ b/source/detail/platform_spec_posix.cpp @@ -1,7 +1,7 @@ /* * Platform Specification Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Nana Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -35,6 +34,7 @@ #include #include "posix/msg_dispatcher.hpp" +#include "../gui/detail/basic_window.hpp" namespace nana { @@ -95,7 +95,7 @@ namespace detail return std::string(); } //end class conf - +#if 0 //class charset_conv charset_conv::charset_conv(const char* tocode, const char* fromcode) { @@ -140,6 +140,7 @@ namespace detail return rstr; } //end class charset_conv +#endif #endif //Caret implementation @@ -209,15 +210,15 @@ namespace detail class timer_runner { - typedef void (*timer_proc_t)(std::size_t id); + using handler_type = void(*)(const timer_core*); struct timer_tag { - std::size_t id; - thread_t tid; + const timer_core* handle; + thread_t thread_id; std::size_t interval; std::size_t timestamp; - timer_proc_t proc; + handler_type handler; }; //timer_group @@ -233,32 +234,32 @@ namespace detail struct timer_group { bool proc_entered{false}; //This flag indicates whether the timers are going to do event. - std::set timers; - std::vector delay_deleted; + std::set timers; + std::vector delay_deleted; }; public: timer_runner() : is_proc_handling_(false) {} - void set(std::size_t id, std::size_t interval, timer_proc_t proc) + void set(const timer_core* handle, std::size_t interval, handler_type handler) { - auto i = holder_.find(id); + auto i = holder_.find(handle); if(i != holder_.end()) { i->second.interval = interval; - i->second.proc = proc; + i->second.handler = handler; return; } auto tid = nana::system::this_thread_id(); - threadmap_[tid].timers.insert(id); + threadmap_[tid].timers.insert(handle); - timer_tag & tag = holder_[id]; - tag.id = id; - tag.tid = tid; + timer_tag & tag = holder_[handle]; + tag.handle = handle; + tag.thread_id = tid; tag.interval = interval; tag.timestamp = 0; - tag.proc = proc; + tag.handler = handler; } bool is_proc_handling() const @@ -266,12 +267,12 @@ namespace detail return is_proc_handling_; } - void kill(std::size_t id) + bool kill(const timer_core* handle) { - auto i = holder_.find(id); + auto i = holder_.find(handle); if(i != holder_.end()) { - auto tid = i->second.tid; + auto tid = i->second.thread_id; auto ig = threadmap_.find(tid); if(ig != threadmap_.end()) //Generally, the ig should not be the end of threadmap_ @@ -279,20 +280,16 @@ namespace detail auto & group = ig->second; if(!group.proc_entered) { - group.timers.erase(id); + group.timers.erase(handle); if(group.timers.empty()) threadmap_.erase(ig); } else - group.delay_deleted.push_back(id); + group.delay_deleted.push_back(handle); } holder_.erase(i); } - } - - bool empty() const - { - return (holder_.empty()); + return holder_.empty(); } void timer_proc(thread_t tid) @@ -314,7 +311,7 @@ namespace detail tag.timestamp = ticks; try { - tag.proc(tag.id); + tag.handler(tag.handle); }catch(...){} //nothrow } } @@ -330,7 +327,7 @@ namespace detail private: bool is_proc_handling_; std::map threadmap_; - std::map holder_; + std::map holder_; }; drawable_impl_type::drawable_impl_type() @@ -338,49 +335,28 @@ namespace detail string.tab_length = 4; string.tab_pixels = 0; string.whitespace_pixels = 0; -#if defined(NANA_USE_XFT) - conv_.handle = ::iconv_open("UTF-8", NANA_UNICODE); - conv_.code = NANA_UNICODE; -#endif - } - - drawable_impl_type::~drawable_impl_type() - { -#if defined(NANA_USE_XFT) - ::iconv_close(conv_.handle); -#endif - } - - unsigned drawable_impl_type::get_color() const - { - return color_; - } - - unsigned drawable_impl_type::get_text_color() const - { - return text_color_; } void drawable_impl_type::set_color(const ::nana::color& clr) { - color_ = (clr.px_color().value & 0xFFFFFF); + bgcolor_rgb = (clr.px_color().value & 0xFFFFFF); } void drawable_impl_type::set_text_color(const ::nana::color& clr) { - text_color_ = (clr.px_color().value & 0xFFFFFF); + fgcolor_rgb = (clr.px_color().value & 0xFFFFFF); update_text_color(); } void drawable_impl_type::update_color() { - if (color_ != current_color_) + if (bgcolor_rgb != current_color_) { auto & spec = nana::detail::platform_spec::instance(); platform_scope_guard lock; - current_color_ = color_; - auto col = color_; + current_color_ = bgcolor_rgb; + auto col = bgcolor_rgb; switch (spec.screen_depth()) { case 16: @@ -391,18 +367,32 @@ namespace detail } ::XSetForeground(spec.open_display(), context, col); ::XSetBackground(spec.open_display(), context, col); + +#if defined(NANA_USE_XFT) + //xft_fgcolor also needs to be assigned. + //assumes the xft_fgcolor is not assigned in update_color. There is a situation that causes a bug. + // + //update_text_color ( if fgcolor_rgb = A, then current_color = A and xft_fgcolor = A) + //update_color (if bgcolor_rgb = B, then current_color = B and xft_fgcolor is still A) + //update_text_color ( if fgcolor_rgb = B, then current_color = B, xft_fgcolor is still A) + + xft_fgcolor.color.red = ((0xFF0000 & col) >> 16) * 0x101; + xft_fgcolor.color.green = ((0xFF00 & col) >> 8) * 0x101; + xft_fgcolor.color.blue = (0xFF & col) * 0x101; + xft_fgcolor.color.alpha = 0xFFFF; +#endif } } void drawable_impl_type::update_text_color() { - if (text_color_ != current_color_) + if (fgcolor_rgb != current_color_) { auto & spec = nana::detail::platform_spec::instance(); platform_scope_guard lock; - current_color_ = text_color_; - auto col = text_color_; + current_color_ = fgcolor_rgb; + auto col = fgcolor_rgb; switch (spec.screen_depth()) { case 16: @@ -445,7 +435,7 @@ namespace detail } platform_spec::timer_runner_tag::timer_runner_tag() - : runner(0), delete_declared(false) + : runner(nullptr), delete_declared(false) {} platform_spec::platform_spec() @@ -987,30 +977,32 @@ namespace detail return r; } - void platform_spec::set_timer(std::size_t id, std::size_t interval, void (*timer_proc)(std::size_t)) + void platform_spec::set_timer(const timer_core* handle, std::size_t interval, void (*timer_proc)(const timer_core*)) { std::lock_guard lock(timer_.mutex); - if(0 == timer_.runner) + if(!timer_.runner) timer_.runner = new timer_runner; - timer_.runner->set(id, interval, timer_proc); + + timer_.runner->set(handle, interval, timer_proc); timer_.delete_declared = false; } - void platform_spec::kill_timer(std::size_t id) + void platform_spec::kill_timer(const timer_core* handle) { - if(timer_.runner == 0) return; - std::lock_guard lock(timer_.mutex); - timer_.runner->kill(id); - if(timer_.runner->empty()) + if(timer_.runner) { - if(timer_.runner->is_proc_handling() == false) + // Test if there is not a timer after killing + if(timer_.runner->kill(handle)) { - delete timer_.runner; - timer_.runner = 0; + if(timer_.runner->is_proc_handling() == false) + { + delete timer_.runner; + timer_.runner = nullptr; + } + else + timer_.delete_declared = true; } - else - timer_.delete_declared = true; } } @@ -1023,7 +1015,7 @@ namespace detail if(timer_.delete_declared) { delete timer_.runner; - timer_.runner = 0; + timer_.runner = nullptr; timer_.delete_declared = false; } } diff --git a/source/detail/platform_spec_windows.cpp b/source/detail/platform_spec_windows.cpp index 812c2ed0..0fc7d8bc 100644 --- a/source/detail/platform_spec_windows.cpp +++ b/source/detail/platform_spec_windows.cpp @@ -1,7 +1,7 @@ /** * Platform Specification Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -42,28 +42,22 @@ namespace detail ::DeleteObject(pixmap); } - unsigned drawable_impl_type::get_color() const - { - return color_; - } - - unsigned drawable_impl_type::get_text_color() const - { - return text_color_; - } +#define NANA_WINDOWS_RGB(a) (((DWORD)(a) & 0xFF)<<16) | ((DWORD)(a) & 0xFF00) | (((DWORD)(a) & 0xFF0000) >> 16 ) void drawable_impl_type::set_color(const ::nana::color& clr) { - color_ = (clr.px_color().value & 0xFFFFFF); + bgcolor_rgb = (clr.px_color().value & 0xFFFFFF); + bgcolor_native = NANA_WINDOWS_RGB(bgcolor_rgb); } void drawable_impl_type::set_text_color(const ::nana::color& clr) { auto rgb = (clr.px_color().value & 0xFFFFFF); - if (text_color_ != rgb) + if (fgcolor_rgb != rgb) { - ::SetTextColor(context, NANA_RGB(rgb)); - text_color_ = rgb; + fgcolor_rgb = rgb; + fgcolor_native = NANA_WINDOWS_RGB(rgb); + ::SetTextColor(context, fgcolor_native); } } diff --git a/source/detail/posix/platform_spec.hpp b/source/detail/posix/platform_spec.hpp index 84c1c24e..ff37717e 100644 --- a/source/detail/posix/platform_spec.hpp +++ b/source/detail/posix/platform_spec.hpp @@ -1,7 +1,7 @@ /* * Platform Specification Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -42,7 +42,6 @@ #if defined(NANA_USE_XFT) #include - #include #include #endif @@ -62,19 +61,6 @@ namespace detail private: std::ifstream ifs_; }; - - class charset_conv - { - charset_conv(const charset_conv&) = delete; - charset_conv& operator=(const charset_conv*) = delete; - public: - charset_conv(const char* tocode, const char* fromcode); - ~charset_conv(); - std::string charset(const std::string& str) const; - std::string charset(const char * buf, std::size_t len) const; - private: - iconv_t handle_; - }; #endif struct drawable_impl_type @@ -95,16 +81,15 @@ namespace detail unsigned whitespace_pixels; }string; + unsigned fgcolor_rgb{ 0xFFFFFFFF }; + unsigned bgcolor_rgb{ 0xFFFFFFFF }; + #if defined(NANA_USE_XFT) XftDraw * xftdraw{nullptr}; XftColor xft_fgcolor; - const std::string charset(const std::wstring& str, const std::string& strcode); #endif drawable_impl_type(); - ~drawable_impl_type(); - unsigned get_color() const; - unsigned get_text_color() const; void set_color(const ::nana::color&); void set_text_color(const ::nana::color&); @@ -115,16 +100,6 @@ namespace detail drawable_impl_type& operator=(const drawable_impl_type&) = delete; unsigned current_color_{ 0xFFFFFF }; - unsigned color_{ 0xFFFFFFFF }; - unsigned text_color_{ 0xFFFFFFFF }; - -#if defined(NANA_USE_XFT) - struct conv_tag - { - iconv_t handle; - std::string code; - }conv_; -#endif }; struct atombase_tag @@ -171,6 +146,13 @@ namespace detail //A forward declaration of caret data struct caret_rep; + /// class timer_core + /** + * Platform-spec only provides the declaration for intrducing a handle type, the definition + * of timer_core is given by gui/timer.cpp + */ + class timer_core; + class timer_runner; class platform_scope_guard @@ -251,8 +233,8 @@ namespace detail //when native_interface::show a window that is registered as a grab //window, the native_interface grabs the window. Window grab(Window); - void set_timer(std::size_t id, std::size_t interval, void (*timer_proc)(std::size_t id)); - void kill_timer(std::size_t id); + void set_timer(const timer_core*, std::size_t interval, void (*timer_proc)(const timer_core* tm)); + void kill_timer(const timer_core*); void timer_proc(thread_t tid); //Message dispatcher diff --git a/source/filesystem/filesystem.cpp b/source/filesystem/filesystem.cpp index 8be0cce9..9180f084 100644 --- a/source/filesystem/filesystem.cpp +++ b/source/filesystem/filesystem.cpp @@ -110,42 +110,6 @@ namespace nana return tm.str(); } return {}; - -/* - // Deprecated - //Windows stores file times using the FILETIME structure, which is a 64 bit value of 100ns intervals from January 1, 1601. - //What's worse is that this 1601 date is fairly common to see given that it's the all zeroes value, and it is far before the - //earliest date representable with time_t.std::filesystem can't change the reality of the underlying platform. - - - try { -#if NANA_USING_BOOST_FILESYSTEM - // The return type of boost::filesystem::last_write_time isn't - // the same as in nana and std implementations of this function - auto ftime = std::chrono::system_clock::from_time_t(fs::last_write_time(path)); -#else - auto ftime = fs::last_write_time(path); -#endif - - // crash: VS2015 will not read the time for some files (for example: C:/hiberfil.sys) - // and will return file_time_type(-1) without throwing - // https://msdn.microsoft.com/en-us/library/dn823784.aspx - - if (ftime == ((fs::file_time_type::min)())) return{}; - - //A workaround for VC2013 - using time_point = decltype(ftime); - auto cftime = time_point::clock::to_time_t(ftime); - - std::stringstream tm; - tm << std::put_time(std::localtime(&cftime), "%Y-%m-%d, %H:%M:%S"); - return tm.str(); - } - catch (...) { - return{}; - } -#endif -*/ } bool modified_file_time(const fs::path& p, struct tm& t) diff --git a/source/gui/detail/basic_window.cpp b/source/gui/detail/basic_window.cpp index 661e3619..bb585f49 100644 --- a/source/gui/detail/basic_window.cpp +++ b/source/gui/detail/basic_window.cpp @@ -10,7 +10,7 @@ * @file: nana/gui/detail/basic_window.cpp */ -#include +#include "basic_window.hpp" #include namespace nana diff --git a/include/nana/gui/detail/basic_window.hpp b/source/gui/detail/basic_window.hpp similarity index 96% rename from include/nana/gui/detail/basic_window.hpp rename to source/gui/detail/basic_window.hpp index bc0a116f..3d53eab5 100644 --- a/include/nana/gui/detail/basic_window.hpp +++ b/source/gui/detail/basic_window.hpp @@ -14,11 +14,11 @@ #ifndef NANA_GUI_DETAIL_BASIC_WINDOW_HPP #define NANA_GUI_DETAIL_BASIC_WINDOW_HPP #include -#include "drawer.hpp" -#include "events_holder.hpp" -#include "widget_geometrics.hpp" -#include "widget_content_measurer_interface.hpp" -#include "widget_notifier_interface.hpp" +#include +#include +#include +#include +#include #include #include #include diff --git a/source/gui/detail/bedrock_pi.cpp b/source/gui/detail/bedrock_pi.cpp index fdb1181b..5f31b3d2 100644 --- a/source/gui/detail/bedrock_pi.cpp +++ b/source/gui/detail/bedrock_pi.cpp @@ -11,16 +11,18 @@ */ #include "../../detail/platform_spec_selector.hpp" +#include "basic_window.hpp" #include "bedrock_types.hpp" +#include +#include #include #include -#include #include -#include -#include #include #include #include + +#include #include namespace nana @@ -64,11 +66,6 @@ namespace nana namespace detail { - bool check_window(window wd) - { - return bedrock::instance().wd_manager().available(reinterpret_cast(wd)); - } - void events_operation_register(event_handle evt) { bedrock::instance().evt_operation().register_evt(evt); @@ -77,7 +74,7 @@ namespace nana class bedrock::flag_guard { public: - flag_guard(bedrock* brock, core_window_t * wd) + flag_guard(bedrock* brock, basic_window * wd) : brock_{ brock }, wd_(wd) { wd_->flags.refreshing = true; @@ -90,7 +87,7 @@ namespace nana } private: bedrock *const brock_; - core_window_t *const wd_; + basic_window *const wd_; }; //class root_guard @@ -111,7 +108,7 @@ namespace nana } //end class root_guard - bedrock::core_window_t* bedrock::focus() + basic_window* bedrock::focus() { auto wd = wd_manager().root(native_interface::get_focus_window()); return (wd ? wd->other.attribute.root->focus : nullptr); @@ -127,7 +124,7 @@ namespace nana return pi_data_->wd_manager; } - void bedrock::manage_form_loader(core_window_t* wd, bool insert_or_remove) + void bedrock::manage_form_loader(basic_window* wd, bool insert_or_remove) { if (insert_or_remove) { @@ -144,7 +141,7 @@ namespace nana void bedrock::close_thread_window(thread_t thread_id) { - std::vector v; + std::vector v; wd_manager().all_handles(v); std::vector roots; @@ -163,7 +160,7 @@ namespace nana native_interface::close_window(i); } - void bedrock::event_expose(core_window_t * wd, bool exposed) + void bedrock::event_expose(basic_window * wd, bool exposed) { if (nullptr == wd) return; @@ -171,11 +168,11 @@ namespace nana arg_expose arg; arg.exposed = exposed; - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; if (emit(event_code::expose, wd, arg, false, get_thread_context())) { //Get the window who has the activated caret - const core_window_t * caret_wd = ((wd->annex.caret_ptr && wd->annex.caret_ptr->activated()) ? wd : wd->child_caret()); + auto const caret_wd = ((wd->annex.caret_ptr && wd->annex.caret_ptr->activated()) ? wd : wd->child_caret()); if (caret_wd) { if (exposed) @@ -198,19 +195,19 @@ namespace nana } } - void bedrock::event_move(core_window_t* wd, int x, int y) + void bedrock::event_move(basic_window* wd, int x, int y) { if (wd) { arg_move arg; - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; arg.x = x; arg.y = y; emit(event_code::move, wd, arg, true, get_thread_context()); } } - bool bedrock::event_msleave(core_window_t* hovered) + bool bedrock::event_msleave(basic_window* hovered) { if (wd_manager().available(hovered) && hovered->flags.enabled) { @@ -218,7 +215,7 @@ namespace nana arg_mouse arg; arg.evt_code = event_code::mouse_leave; - arg.window_handle = reinterpret_cast(hovered); + arg.window_handle = hovered; arg.pos.x = arg.pos.y = 0; arg.left_button = arg.right_button = arg.mid_button = false; arg.ctrl = arg.shift = false; @@ -229,12 +226,12 @@ namespace nana } //The wd must be a root window - void bedrock::event_focus_changed(core_window_t* root_wd, native_window_type receiver, bool getting) + void bedrock::event_focus_changed(basic_window* root_wd, native_window_type receiver, bool getting) { auto focused = root_wd->other.attribute.root->focus; arg_focus arg; - arg.window_handle = reinterpret_cast(focused); + arg.window_handle = focused; arg.getting = getting; arg.receiver = receiver; @@ -260,7 +257,7 @@ namespace nana } } - void bedrock::update_cursor(core_window_t * wd) + void bedrock::update_cursor(basic_window * wd) { internal_scope_guard isg; if (wd_manager().available(wd)) @@ -282,7 +279,7 @@ namespace nana } } - void bedrock::set_menubar_taken(core_window_t* wd) + void bedrock::set_menubar_taken(basic_window* wd) { auto pre = pi_data_->menu.taken_window; pi_data_->menu.taken_window = wd; @@ -396,7 +393,7 @@ namespace nana return pi_data_->scheme; } - void bedrock::_m_emit_core(event_code evt_code, core_window_t* wd, bool draw_only, const ::nana::event_arg& event_arg, const bool bForce__EmitInternal) + void bedrock::_m_emit_core(event_code evt_code, basic_window* wd, bool draw_only, const ::nana::event_arg& event_arg, const bool bForce__EmitInternal) { auto retain = wd->annex.events_ptr; auto evts_ptr = retain.get(); @@ -416,7 +413,7 @@ namespace nana wd->drawer.click(*arg, bForce__EmitInternal); } if (bProcess__External_event) - evts_ptr->click.emit(*arg, reinterpret_cast(wd)); + evts_ptr->click.emit(*arg, wd); } } break; @@ -471,7 +468,7 @@ namespace nana } if (bProcess__External_event) - evt_addr->emit(*arg, reinterpret_cast(wd)); + evt_addr->emit(*arg, wd); break; } case event_code::mouse_wheel: @@ -486,7 +483,7 @@ namespace nana } if (bProcess__External_event) - evts_ptr->mouse_wheel.emit(*arg, reinterpret_cast(wd)); + evts_ptr->mouse_wheel.emit(*arg, wd); } break; } @@ -530,7 +527,7 @@ namespace nana } if (bProcess__External_event) - evt_addr->emit(*arg, reinterpret_cast(wd)); + evt_addr->emit(*arg, wd); break; } case event_code::expose: @@ -538,7 +535,7 @@ namespace nana { auto arg = dynamic_cast(&event_arg); if (arg) - evts_ptr->expose.emit(*arg, reinterpret_cast(wd)); + evts_ptr->expose.emit(*arg, wd); } break; case event_code::focus: @@ -552,7 +549,7 @@ namespace nana wd->drawer.focus(*arg, bForce__EmitInternal); } if (bProcess__External_event) - evts_ptr->focus.emit(*arg, reinterpret_cast(wd)); + evts_ptr->focus.emit(*arg, wd); } break; } @@ -567,7 +564,7 @@ namespace nana wd->drawer.move(*arg, bForce__EmitInternal); } if (bProcess__External_event) - evts_ptr->move.emit(*arg, reinterpret_cast(wd)); + evts_ptr->move.emit(*arg, wd); } break; } @@ -582,7 +579,7 @@ namespace nana wd->drawer.resizing(*arg, bForce__EmitInternal); } if (bProcess__External_event) - evts_ptr->resizing.emit(*arg, reinterpret_cast(wd)); + evts_ptr->resizing.emit(*arg, wd); } break; } @@ -597,7 +594,7 @@ namespace nana wd->drawer.resized(*arg, bForce__EmitInternal); } if (bProcess__External_event) - evts_ptr->resized.emit(*arg, reinterpret_cast(wd)); + evts_ptr->resized.emit(*arg, wd); } break; } @@ -609,7 +606,7 @@ namespace nana { auto evt_root = dynamic_cast(evts_ptr); if (evt_root) - evt_root->unload.emit(*arg, reinterpret_cast(wd)); + evt_root->unload.emit(*arg, wd); } } break; @@ -618,7 +615,7 @@ namespace nana { auto arg = dynamic_cast(&event_arg); if (arg) - evts_ptr->destroy.emit(*arg, reinterpret_cast(wd)); + evts_ptr->destroy.emit(*arg, wd); } break; default: @@ -626,7 +623,7 @@ namespace nana } } - void bedrock::thread_context_destroy(core_window_t * wd) + void bedrock::thread_context_destroy(basic_window * wd) { auto ctx = get_thread_context(0); if(ctx && ctx->event_window == wd) @@ -637,15 +634,15 @@ namespace nana { auto ctx = get_thread_context(0); if(ctx && ctx->event_window) - ctx->event_window->other.upd_state = core_window_t::update_state::refreshed; + ctx->event_window->other.upd_state = basic_window::update_state::refreshed; } - bool bedrock::emit(event_code evt_code, core_window_t* wd, const ::nana::event_arg& arg, bool ask_update, thread_context* thrd, const bool bForce__EmitInternal) + bool bedrock::emit(event_code evt_code, basic_window* wd, const ::nana::event_arg& arg, bool ask_update, thread_context* thrd, const bool bForce__EmitInternal) { if(wd_manager().available(wd) == false) return false; - core_window_t * prev_wd = nullptr; + basic_window * prev_wd = nullptr; if(thrd) { prev_wd = thrd->event_window; @@ -680,7 +677,7 @@ namespace nana return good_wd; } - void bedrock::_m_event_filter(event_code event_id, core_window_t * wd, thread_context * thrd) + void bedrock::_m_event_filter(event_code event_id, basic_window * wd, thread_context * thrd) { auto not_state_cur = (wd->root_widget->other.attribute.root->state_cursor == nana::cursor::arrow); diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index 9b1160bf..b3ed3fb4 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -141,9 +141,9 @@ namespace detail delete impl_; } - void bedrock::flush_surface(core_window_t* wd, bool forced, const rectangle* update_area) + void bedrock::flush_surface(basic_window* wd, bool forced, const rectangle* update_area) { - wd->drawer.map(reinterpret_cast(wd), forced, update_area); + wd->drawer.map(wd, forced, update_area); } //inc_window @@ -248,14 +248,14 @@ namespace detail return impl_->estore; } - void bedrock::map_through_widgets(core_window_t*, native_drawable_type) + void bedrock::map_through_widgets(basic_window*, native_drawable_type) { //No implementation for Linux } void assign_arg(arg_mouse& arg, basic_window* wd, unsigned msg, const XEvent& evt) { - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; arg.button = ::nana::mouse::any_button; int mask_state = 0; @@ -308,7 +308,7 @@ namespace detail void assign_arg(arg_focus& arg, basic_window* wd, native_window_type recv, bool getting) { - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; arg.receiver = recv; arg.getting = getting; arg.focus_reason = arg_focus::reason::general; @@ -317,7 +317,7 @@ namespace detail void assign_arg(arg_wheel& arg, basic_window* wd, const XEvent& evt) { arg.evt_code = event_code::mouse_wheel; - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; if (ButtonRelease == evt.type && (evt.xbutton.button == Button4 || evt.xbutton.button == Button5)) { arg.evt_code = event_code::mouse_wheel; @@ -371,12 +371,12 @@ namespace detail if(msgwd) { arg_dropfiles arg; - arg.window_handle = reinterpret_cast(msgwd); + arg.window_handle = msgwd; arg.files.swap(*msg.u.mouse_drop.files); delete msg.u.mouse_drop.files; arg.pos.x = msg.u.mouse_drop.x - msgwd->pos_root.x; arg.pos.y = msg.u.mouse_drop.y - msgwd->pos_root.y; - msgwd->annex.events_ptr->mouse_dropfiles.emit(arg, reinterpret_cast(msgwd)); + msgwd->annex.events_ptr->mouse_dropfiles.emit(arg, msgwd); brock.wd_manager().do_lazy_refresh(msgwd, false); } break; @@ -512,11 +512,9 @@ namespace detail auto const native_window = rruntime->window->root; - - nana::detail::charset_conv charset(NANA_UNICODE, "UTF-8"); - const std::string& str = charset.charset(std::string(keybuf, keybuf + keybuf_len)); - auto const charbuf = reinterpret_cast(str.c_str()); - auto const len = str.size() / sizeof(wchar_t); + auto wstr = nana::to_wstring(std::string{keybuf, keybuf + keybuf_len}); + auto const charbuf = wstr.c_str(); + auto const len = wstr.length(); for(std::size_t i = 0; i < len; ++i) { @@ -539,15 +537,15 @@ namespace detail auto shr_wd = wd_manager.find_shortkey(native_window, arg.key); if(shr_wd) { - arg.window_handle = reinterpret_cast(shr_wd); + arg.window_handle = shr_wd; brock.emit(event_code::shortkey, shr_wd, arg, true, &context); } continue; } arg.evt_code = event_code::key_char; - arg.window_handle = reinterpret_cast(msgwd); - msgwd->annex.events_ptr->key_char.emit(arg, reinterpret_cast(msgwd)); + arg.window_handle = msgwd; + msgwd->annex.events_ptr->key_char.emit(arg, msgwd); if(arg.ignore == false && wd_manager.available(msgwd)) draw_invoker(&drawer::key_char, msgwd, arg, &context); } @@ -556,36 +554,11 @@ namespace detail context.is_alt_pressed = false; } -#if 0 - class window_proc_guard - { - public: - window_proc_guard(detail::basic_window* wd) : - root_wd_(wd) - { - root_wd_->other.attribute.root->lazy_update = true; - } - - ~window_proc_guard() - { - if (!bedrock::instance().wd_manager().available(root_wd_)) - return; - - root_wd_->other.attribute.root->lazy_update = false; - root_wd_->other.attribute.root->update_requesters.clear(); - } - private: - detail::basic_window* const root_wd_; - }; -#endif - void window_proc_for_xevent(Display* /*display*/, XEvent& xevent) { - typedef detail::bedrock::core_window_t core_window_t; - static auto& brock = detail::bedrock::instance(); static unsigned long last_mouse_down_time; - static core_window_t* last_mouse_down_window; + static basic_window* last_mouse_down_window; auto native_window = reinterpret_cast(event_window(xevent)); auto & wd_manager = brock.wd_manager(); @@ -789,7 +762,7 @@ namespace detail { msgwnd->set_action(mouse_action::hovered); - click_arg.window_handle = reinterpret_cast(msgwnd); + click_arg.window_handle = msgwnd; draw_invoker(&drawer::click, msgwnd, click_arg, &context); } } @@ -807,16 +780,16 @@ namespace detail draw_invoker(&drawer::mouse_up, msgwnd, arg, &context); if(click_arg.window_handle) - evt_ptr->click.emit(click_arg, reinterpret_cast(msgwnd)); + evt_ptr->click.emit(click_arg, msgwnd); if (wd_manager.available(msgwnd)) { arg.evt_code = event_code::mouse_up; - evt_ptr->mouse_up.emit(arg, reinterpret_cast(msgwnd)); + evt_ptr->mouse_up.emit(arg, msgwnd); } } else if(click_arg.window_handle) - msgwnd->annex.events_ptr->click.emit(click_arg, reinterpret_cast(msgwnd)); + msgwnd->annex.events_ptr->click.emit(click_arg, msgwnd); wd_manager.do_lazy_refresh(msgwnd, false); } @@ -940,7 +913,7 @@ namespace detail //Don't copy root_graph to the window directly, otherwise the edge nimbus effect will be missed. ::nana::rectangle update_area(xevent.xexpose.x, xevent.xexpose.y, xevent.xexpose.width, xevent.xexpose.height); if (!update_area.empty()) - msgwnd->drawer.map(reinterpret_cast(msgwnd), true, &update_area); + msgwnd->drawer.map(msgwnd, true, &update_area); } } break; @@ -1019,7 +992,7 @@ namespace detail else if((keyboard::space == os_code) && msgwnd->flags.space_click_enabled) { //Clicked by spacebar - if((nullptr == pressed_wd) && (nullptr == pressed_wd_space)) + if((nullptr == pressed_wd) && (nullptr == pressed_wd_space) && msgwnd->flags.enabled) { arg_mouse arg; arg.alt = modifiers_status.alt; @@ -1030,7 +1003,7 @@ namespace detail arg.mid_button = false; arg.pos.x = 0; arg.pos.y = 0; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; msgwnd->set_action(mouse_action::pressed); @@ -1052,7 +1025,7 @@ namespace detail bool focused = (brock.focus() == msgwnd); arg_keyboard arg; arg.evt_code = event_code::key_press; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; arg.ignore = false; arg.key = os_code; brock.get_key_state(arg); @@ -1074,7 +1047,7 @@ namespace detail arg.ignore = false; arg.key = os_code; arg.evt_code = event_code::key_press; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; brock.emit(event_code::key_press, msgwnd, arg, true, &context); @@ -1122,7 +1095,7 @@ namespace detail msgwnd = brock.focus(); if(msgwnd) { - if(msgwnd == pressed_wd_space) + if((msgwnd == pressed_wd_space) && msgwnd->flags.enabled) { msgwnd->set_action(mouse_action::normal); @@ -1130,7 +1103,7 @@ namespace detail arg_click click_arg; click_arg.mouse_args = nullptr; - click_arg.window_handle = reinterpret_cast(msgwnd); + click_arg.window_handle = msgwnd; arg_mouse arg; arg.alt = false; @@ -1141,7 +1114,7 @@ namespace detail arg.mid_button = false; arg.pos.x = 0; arg.pos.y = 0; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; draw_invoker(&drawer::mouse_up, msgwnd, arg, &context); @@ -1155,7 +1128,7 @@ namespace detail arg_keyboard arg; arg.evt_code = event_code::key_release; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; arg.ignore = false; arg.key = os_code; brock.get_key_state(arg); @@ -1181,7 +1154,7 @@ namespace detail arg_keyboard arg; arg.evt_code = event_code::key_release; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; arg.ignore = false; arg.key = os_code; brock.get_key_state(arg); @@ -1208,7 +1181,7 @@ namespace detail if(msgwnd->flags.enabled && (atoms.wm_delete_window == static_cast(xclient.data.l[0]))) { arg_unload arg; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; arg.cancel = false; brock.emit(event_code::unload, msgwnd, arg, true, &context); if(false == arg.cancel) @@ -1259,10 +1232,10 @@ namespace detail lock.revert(); native_window_type owner_native{}; - core_window_t * owner = 0; + basic_window * owner = nullptr; if(condition_wd && is_modal) { - native_window_type modal = reinterpret_cast(condition_wd)->root; + native_window_type modal = condition_wd->root; owner_native = native_interface::get_window(modal, window_relationship::owner); if(owner_native) { @@ -1273,7 +1246,7 @@ namespace detail } } - nana::detail::platform_spec::instance().msg_dispatch(condition_wd ? reinterpret_cast(condition_wd)->root : 0); + nana::detail::platform_spec::instance().msg_dispatch(condition_wd ? condition_wd->root : 0); if(owner_native) { @@ -1301,7 +1274,7 @@ namespace detail }//end bedrock::event_loop //Dynamically set a cursor for a window - void bedrock::set_cursor(core_window_t* wd, nana::cursor cur, thread_context* thrd) + void bedrock::set_cursor(basic_window* wd, nana::cursor cur, thread_context* thrd) { if (nullptr == thrd) thrd = get_thread_context(wd->thread_id); @@ -1344,14 +1317,14 @@ namespace detail } } - void bedrock::define_state_cursor(core_window_t* wd, nana::cursor cur, thread_context* thrd) + void bedrock::define_state_cursor(basic_window* wd, nana::cursor cur, thread_context* thrd) { wd->root_widget->other.attribute.root->state_cursor = cur; wd->root_widget->other.attribute.root->state_cursor_window = wd; set_cursor(wd, cur, thrd); } - void bedrock::undefine_state_cursor(core_window_t * wd, thread_context* thrd) + void bedrock::undefine_state_cursor(basic_window * wd, thread_context* thrd) { if (!wd_manager().available(wd)) return; diff --git a/source/gui/detail/bedrock_types.hpp b/source/gui/detail/bedrock_types.hpp index f3fb55bc..a95b0755 100644 --- a/source/gui/detail/bedrock_types.hpp +++ b/source/gui/detail/bedrock_types.hpp @@ -18,12 +18,12 @@ namespace nana color_schemes scheme; events_operation evt_operation; window_manager wd_manager; - std::set auto_form_set; + std::set auto_form_set; bool shortkey_occurred{ false }; struct menu_rep { - core_window_t* taken_window{ nullptr }; + basic_window* taken_window{ nullptr }; bool delay_restore{ false }; native_window_type window{ nullptr }; native_window_type owner{ nullptr }; @@ -37,7 +37,7 @@ namespace nana { unsigned event_pump_ref_count{0}; int window_count{0}; //The number of windows - core_window_t* event_window{nullptr}; + basic_window* event_window{nullptr}; struct platform_detail_tag { @@ -46,7 +46,7 @@ namespace nana struct cursor_tag { - core_window_t * window; + basic_window * window; native_window_type native_handle; nana::cursor predef_cursor; HCURSOR handle; @@ -66,7 +66,7 @@ namespace nana unsigned event_pump_ref_count{0}; int window_count{0}; //The number of windows - core_window_t* event_window{nullptr}; + basic_window* event_window{nullptr}; bool is_alt_pressed{false}; bool is_ctrl_pressed{false}; @@ -78,7 +78,7 @@ namespace nana struct cursor_tag { - core_window_t * window; + basic_window * window; native_window_type native_handle; nana::cursor predef_cursor; Cursor handle; diff --git a/source/gui/detail/bedrock_windows.cpp b/source/gui/detail/bedrock_windows.cpp index d549bedc..829c909a 100644 --- a/source/gui/detail/bedrock_windows.cpp +++ b/source/gui/detail/bedrock_windows.cpp @@ -18,7 +18,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -213,9 +214,9 @@ namespace detail bedrock::~bedrock() { - if(wd_manager().number_of_core_window()) + if(wd_manager().window_count()) { - std::string msg = "Nana.GUI detects a memory leaks in window_manager, " + std::to_string(wd_manager().number_of_core_window()) + " window(s) are not uninstalled."; + std::string msg = "Nana.GUI detects a memory leaks in window_manager, " + std::to_string(wd_manager().window_count()) + " window(s) are not uninstalled."; std::cerr << msg; /// \todo add list of cations of opening windows and if auto testing GUI do auto OK after 2 seconds. ::MessageBoxA(0, msg.c_str(), ("Nana C++ Library"), MB_OK); } @@ -290,7 +291,7 @@ namespace detail return bedrock_object; } - void bedrock::flush_surface(core_window_t* wd, bool forced, const rectangle* update_area) + void bedrock::flush_surface(basic_window* wd, bool forced, const rectangle* update_area) { if (nana::system::this_thread_id() != wd->thread_id) { @@ -311,7 +312,7 @@ namespace detail } } else - wd->drawer.map(reinterpret_cast(wd), forced, update_area); + wd->drawer.map(wd, forced, update_area); } void interior_helper_for_menu(MSG& msg, native_window_type menu_window) @@ -367,7 +368,7 @@ namespace detail MSG msg; if (condition_wd) { - HWND native_handle = reinterpret_cast(reinterpret_cast(condition_wd)->root); + HWND native_handle = reinterpret_cast(condition_wd->root); if (is_modal) { HWND owner = ::GetWindow(native_handle, GW_OWNER); @@ -466,7 +467,7 @@ namespace detail void assign_arg(nana::arg_mouse& arg, basic_window* wd, unsigned msg, const parameter_decoder& pmdec) { - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; bool set_key_state = true; switch (msg) @@ -530,7 +531,7 @@ namespace detail void assign_arg(arg_wheel& arg, basic_window* wd, const parameter_decoder& pmdec) { - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; arg.evt_code = event_code::mouse_wheel; POINT point = { pmdec.mouse.x, pmdec.mouse.y }; @@ -581,7 +582,7 @@ namespace detail case nana::detail::messages::remote_flush_surface: { auto stru = reinterpret_cast(lParam); - bedrock.wd_manager().map(reinterpret_cast(wParam), stru->forced, (stru->ignore_update_area ? nullptr : &stru->update_area)); + bedrock.wd_manager().map(reinterpret_cast(wParam), stru->forced, (stru->ignore_update_area ? nullptr : &stru->update_area)); ::UpdateWindow(wd); ::HeapFree(::GetProcessHeap(), 0, stru); } @@ -652,7 +653,7 @@ namespace detail return true; } - void adjust_sizing(bedrock::core_window_t* wd, ::RECT * const r, int edge, unsigned req_width, unsigned req_height) + void adjust_sizing(basic_window* wd, ::RECT * const r, int edge, unsigned req_width, unsigned req_height) { unsigned width = static_cast(r->right - r->left) - wd->extra_width; unsigned height = static_cast(r->bottom - r->top) - wd->extra_height; @@ -985,7 +986,7 @@ namespace detail msgwnd->set_action(mouse_action::hovered); if ((::nana::mouse::left_button == arg.button) && (pressed_wd == msgwnd)) { - click_arg.window_handle = reinterpret_cast(msgwnd); + click_arg.window_handle = msgwnd; draw_invoker(&drawer::click, msgwnd, click_arg, &context); } } @@ -997,16 +998,16 @@ namespace detail draw_invoker(&drawer::mouse_up, msgwnd, arg, &context); if (click_arg.window_handle) - retain->click.emit(click_arg, reinterpret_cast(msgwnd)); + retain->click.emit(click_arg, msgwnd); if (wd_manager.available(msgwnd)) { arg.evt_code = event_code::mouse_up; - retain->mouse_up.emit(arg, reinterpret_cast(msgwnd)); + retain->mouse_up.emit(arg, msgwnd); } } else if (click_arg.window_handle) - retain->click.emit(click_arg, reinterpret_cast(msgwnd)); + retain->click.emit(click_arg, msgwnd); wd_manager.do_lazy_refresh(msgwnd, false); } @@ -1176,9 +1177,9 @@ namespace detail dropfiles.pos = pos; wd_manager.calc_window_point(msgwnd, dropfiles.pos); - dropfiles.window_handle = reinterpret_cast(msgwnd); + dropfiles.window_handle = msgwnd; - msgwnd->annex.events_ptr->mouse_dropfiles.emit(dropfiles, reinterpret_cast(msgwnd)); + msgwnd->annex.events_ptr->mouse_dropfiles.emit(dropfiles, msgwnd); wd_manager.do_lazy_refresh(msgwnd, false); } } @@ -1232,7 +1233,7 @@ namespace detail static_cast(r->bottom - r->top - msgwnd->extra_height)); arg_resizing arg; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; arg.width = size_before.width; arg.height = size_before.height; @@ -1285,7 +1286,7 @@ namespace detail //Don't copy root_graph to the window directly, otherwise the edge nimbus effect will be missed. ::nana::rectangle update_area(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top); if (!update_area.empty()) - msgwnd->drawer.map(reinterpret_cast(msgwnd), true, &update_area); + msgwnd->drawer.map(msgwnd, true, &update_area); } ::EndPaint(root_window, &ps); } @@ -1300,7 +1301,7 @@ namespace detail arg.evt_code = event_code::shortkey; arg.key = static_cast(wParam < 0x61 ? wParam + 0x61 - 0x41 : wParam); arg.ctrl = arg.shift = false; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; arg.ignore = false; brock.emit(event_code::shortkey, msgwnd, arg, true, &context); def_window_proc = false; @@ -1316,7 +1317,7 @@ namespace detail bool focused = (brock.focus() == msgwnd); arg_keyboard arg; arg.evt_code = event_code::key_press; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; arg.ignore = false; arg.key = static_cast(wParam); brock.get_key_state(arg); @@ -1344,7 +1345,7 @@ namespace detail arg_keyboard arg; arg.evt_code = event_code::key_release; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; arg.ignore = false; arg.key = static_cast(wParam); brock.get_key_state(arg); @@ -1386,7 +1387,7 @@ namespace detail else if ((VK_SPACE == wParam) && msgwnd->flags.space_click_enabled) { //Clicked by spacebar - if (nullptr == pressed_wd && nullptr == pressed_wd_space) + if ((nullptr == pressed_wd) && (nullptr == pressed_wd_space) && msgwnd->flags.enabled) { arg_mouse arg; arg.alt = false; @@ -1397,7 +1398,7 @@ namespace detail arg.mid_button = false; arg.pos.x = 0; arg.pos.y = 0; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; msgwnd->set_action(mouse_action::pressed); @@ -1412,7 +1413,7 @@ namespace detail { arg_keyboard arg; arg.evt_code = event_code::key_press; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; arg.ignore = false; arg.key = translate_virtual_key(wParam); brock.get_key_state(arg); @@ -1443,12 +1444,12 @@ namespace detail { arg_keyboard arg; arg.evt_code = event_code::key_char; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; arg.key = static_cast(wParam); brock.get_key_state(arg); arg.ignore = false; - msgwnd->annex.events_ptr->key_char.emit(arg, reinterpret_cast(msgwnd)); + msgwnd->annex.events_ptr->key_char.emit(arg, msgwnd); if ((false == arg.ignore) && wd_manager.available(msgwnd)) draw_invoker(&drawer::key_char, msgwnd, arg, &context); @@ -1468,7 +1469,7 @@ namespace detail msgwnd = brock.focus(); if (msgwnd) { - if (msgwnd == pressed_wd_space) + if ((msgwnd == pressed_wd_space) && msgwnd->flags.enabled) { msgwnd->set_action(mouse_action::normal); @@ -1476,7 +1477,7 @@ namespace detail arg_click click_arg; click_arg.mouse_args = nullptr; - click_arg.window_handle = reinterpret_cast(msgwnd); + click_arg.window_handle = msgwnd; arg_mouse arg; arg.alt = false; @@ -1487,7 +1488,7 @@ namespace detail arg.mid_button = false; arg.pos.x = 0; arg.pos.y = 0; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; draw_invoker(&drawer::mouse_up, msgwnd, arg, &context); @@ -1500,7 +1501,7 @@ namespace detail { arg_keyboard keyboard_arg; keyboard_arg.evt_code = event_code::key_release; - keyboard_arg.window_handle = reinterpret_cast(msgwnd); + keyboard_arg.window_handle = msgwnd; keyboard_arg.key = translate_virtual_key(wParam); brock.get_key_state(keyboard_arg); keyboard_arg.ignore = false; @@ -1521,7 +1522,7 @@ namespace detail case WM_CLOSE: { arg_unload arg; - arg.window_handle = reinterpret_cast(msgwnd); + arg.window_handle = msgwnd; arg.cancel = false; brock.emit(event_code::unload, msgwnd, arg, true, &context); if (!arg.cancel) @@ -1638,7 +1639,7 @@ namespace detail return impl_->estore; } - void bedrock::map_through_widgets(core_window_t* wd, native_drawable_type drawable) + void bedrock::map_through_widgets(basic_window* wd, native_drawable_type drawable) { auto graph_context = reinterpret_cast(wd->root_graph->handle()->context); @@ -1685,7 +1686,7 @@ namespace detail } //Dynamically set a cursor for a window - void bedrock::set_cursor(core_window_t* wd, nana::cursor cur, thread_context* thrd) + void bedrock::set_cursor(basic_window* wd, nana::cursor cur, thread_context* thrd) { if (nullptr == thrd) thrd = get_thread_context(wd->thread_id); @@ -1730,7 +1731,7 @@ namespace detail } } - void bedrock::define_state_cursor(core_window_t* wd, nana::cursor cur, thread_context* thrd) + void bedrock::define_state_cursor(basic_window* wd, nana::cursor cur, thread_context* thrd) { wd->root_widget->other.attribute.root->state_cursor = cur; wd->root_widget->other.attribute.root->state_cursor_window = wd; @@ -1740,11 +1741,8 @@ namespace detail ::ShowCursor(TRUE); } - void bedrock::undefine_state_cursor(core_window_t * wd, thread_context* thrd) + void bedrock::undefine_state_cursor(basic_window * wd, thread_context* thrd) { - if (nullptr == thrd) - thrd = get_thread_context(wd->thread_id); - HCURSOR rev_handle = ::LoadCursor(nullptr, IDC_ARROW); if (!wd_manager().available(wd)) { @@ -1753,6 +1751,9 @@ namespace detail return; } + if (nullptr == thrd) + thrd = get_thread_context(wd->thread_id); + wd->root_widget->other.attribute.root->state_cursor = nana::cursor::arrow; wd->root_widget->other.attribute.root->state_cursor_window = nullptr; diff --git a/source/gui/detail/drawer.cpp b/source/gui/detail/drawer.cpp index da5b0091..5b21161b 100644 --- a/source/gui/detail/drawer.cpp +++ b/source/gui/detail/drawer.cpp @@ -1,7 +1,7 @@ /* * A Drawer Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -10,11 +10,11 @@ * @file: nana/gui/detail/drawer.cpp */ +#include "basic_window.hpp" +#include "effects_renderer.hpp" #include #include #include -#include -#include #include "dynamic_drawing_object.hpp" #if defined(NANA_X11) @@ -23,8 +23,6 @@ namespace nana { - typedef detail::edge_nimbus_renderer edge_nimbus_renderer_t; - //class drawer_trigger void drawer_trigger::attached(widget_reference, graph_reference){} void drawer_trigger::detached(){} //none-const @@ -344,8 +342,7 @@ namespace nana { if(wd) { - auto iwd = reinterpret_cast(wd); - bool owns_caret = (iwd->annex.caret_ptr) && (iwd->annex.caret_ptr->visible()); + bool owns_caret = (wd->annex.caret_ptr) && (wd->annex.caret_ptr->visible()); //The caret in X11 is implemented by Nana, it is different from Windows' //the caret in X11 is asynchronous, it is hard to hide and show the caret @@ -354,20 +351,20 @@ namespace nana if(owns_caret) { #ifndef NANA_X11 - iwd->annex.caret_ptr->visible(false); + wd->annex.caret_ptr->visible(false); #else - owns_caret = nana::detail::platform_spec::instance().caret_update(iwd->root, *iwd->root_graph, false); + owns_caret = nana::detail::platform_spec::instance().caret_update(wd->root, *wd->root_graph, false); #endif } - edge_nimbus_renderer_t::instance().render(iwd, forced, update_area); + edge_nimbus_renderer::instance().render(wd, forced, update_area); if(owns_caret) { #ifndef NANA_X11 - iwd->annex.caret_ptr->visible(true); + wd->annex.caret_ptr->visible(true); #else - nana::detail::platform_spec::instance().caret_update(iwd->root, *iwd->root_graph, true); + nana::detail::platform_spec::instance().caret_update(wd->root, *wd->root_graph, true); #endif } } @@ -475,4 +472,192 @@ namespace nana return data_impl_->mth_state[pos]; } }//end namespace detail + + namespace detail + { + //class edge_nimbus_renderer + edge_nimbus_renderer& edge_nimbus_renderer::instance() + { + static edge_nimbus_renderer object; + return object; + } + + void edge_nimbus_renderer::erase(basic_window* wd) + { + if (effects::edge_nimbus::none == wd->effect.edge_nimbus) + return; + + auto root_wd = wd->root_widget; + auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus; + + for (auto i = nimbus.begin(); i != nimbus.end(); ++i) + { + if (i->window == wd) + { + auto pixels = weight(); + rectangle r{ wd->pos_root, wd->dimension }; + r.x -= static_cast(pixels); + r.y -= static_cast(pixels); + r.width += static_cast(pixels << 1); + r.height += static_cast(pixels << 1); + + root_wd->root_graph->paste(root_wd->root, r, r.x, r.y); + + nimbus.erase(i); + break; + } + } + } + + void edge_nimbus_renderer::render(basic_window* wd, bool forced, const rectangle* update_area) + { + bool copy_separately = true; + std::vector> rd_set; + + if (wd->root_widget->other.attribute.root->effects_edge_nimbus.size()) + { + auto root_wd = wd->root_widget; + + auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus; + + auto focused = root_wd->other.attribute.root->focus; + + const unsigned pixels = weight(); + + auto graph = root_wd->root_graph; + + nana::rectangle r; + for (auto & action : nimbus) + { + if (_m_edge_nimbus(action.window, focused) && window_layer::read_visual_rectangle(action.window, r)) + { + if (action.window == wd) + { + if (update_area) + ::nana::overlap(*update_area, rectangle(r), r); + copy_separately = false; + } + + //Avoiding duplicated rendering. If the window is declared to lazy refresh, it should be rendered. + if ((forced && (action.window == wd)) || (focused == action.window) || !action.rendered || (action.window->other.upd_state == basic_window::update_state::refreshed)) + { + rd_set.emplace_back(r, action.window); + action.rendered = true; + } + } + else if (action.rendered) + { + action.rendered = false; + + if (action.window == wd) + copy_separately = false; + + ::nana::rectangle erase_r( + action.window->pos_root.x - static_cast(pixels), + action.window->pos_root.y - static_cast(pixels), + static_cast(action.window->dimension.width + (pixels << 1)), + static_cast(action.window->dimension.height + (pixels << 1)) + ); + + graph->paste(root_wd->root, erase_r, erase_r.x, erase_r.y); + } + } + } + + if (copy_separately) + { + rectangle vr; + if (window_layer::read_visual_rectangle(wd, vr)) + { + if (update_area) + ::nana::overlap(*update_area, rectangle(vr), vr); + wd->root_graph->paste(wd->root, vr, vr.x, vr.y); + } + } + + rectangle wd_r{ wd->pos_root, wd->dimension }; + wd_r.pare_off(-static_cast(this->weight())); + //Render + for (auto & rd : rd_set) + { + auto other_wd = rd.second; + + if (other_wd != wd) + { + rectangle other_r{ other_wd->pos_root, other_wd->dimension }; + other_r.pare_off(-static_cast(this->weight())); + if (!overlapped(wd_r, other_r)) + continue; + } + _m_render_edge_nimbus(other_wd, rd.first); + } + } + + /// Determines whether the effect will be rendered for the given window. + bool edge_nimbus_renderer::_m_edge_nimbus(basic_window * const wd, basic_window * const focused_wd) + { + // 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; + } + + void edge_nimbus_renderer::_m_render_edge_nimbus(basic_window* wd, const nana::rectangle & visual) + { + wd->flags.action_before = wd->flags.action; + + auto r = visual; + r.pare_off(-static_cast(weight())); + rectangle good_r; + if (overlap(r, rectangle{ wd->root_graph->size() }, good_r)) + { + if ((good_r.x < wd->pos_root.x) || (good_r.y < wd->pos_root.y) || + (good_r.right() > visual.right()) || (good_r.bottom() > visual.bottom())) + { + auto graph = wd->root_graph; + nana::paint::pixel_buffer pixbuf(graph->handle(), r); + + pixel_argb_t px0, px1, px2, px3; + + px0 = pixbuf.pixel(0, 0); + px1 = pixbuf.pixel(r.width - 1, 0); + px2 = pixbuf.pixel(0, r.height - 1); + px3 = pixbuf.pixel(r.width - 1, r.height - 1); + + good_r.x = good_r.y = 1; + good_r.width = r.width - 2; + good_r.height = r.height - 2; + pixbuf.rectangle(good_r, wd->annex.scheme->activated.get_color(), 0.95, false); + + good_r.x = good_r.y = 0; + good_r.width = r.width; + good_r.height = r.height; + pixbuf.rectangle(good_r, wd->annex.scheme->activated.get_color(), 0.4, false); + + pixbuf.pixel(0, 0, px0); + pixbuf.pixel(r.width - 1, 0, px1); + pixbuf.pixel(0, r.height - 1, px2); + pixbuf.pixel(r.width - 1, r.height - 1, px3); + + pixbuf.paste(wd->root, { r.x, r.y }); + + std::vector overlaps; + if (window_layer::read_overlaps(wd, visual, overlaps)) + { + for (auto & wdr : overlaps) + graph->paste(wd->root, wdr.r, wdr.r.x, wdr.r.y); + } + } + else + wd->root_graph->paste(wd->root, visual, visual.x, visual.y); + } + } + + //end class edge_nimbus_renderer + }//end namespace detail }//end namespace nana diff --git a/source/gui/detail/effects_renderer.hpp b/source/gui/detail/effects_renderer.hpp new file mode 100644 index 00000000..99fbf49c --- /dev/null +++ b/source/gui/detail/effects_renderer.hpp @@ -0,0 +1,52 @@ +/* +* Effects Renderer +* Nana C++ Library(http://www.nanapro.org) +* Copyright(C) 2003-2019 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 "basic_window.hpp" +#include +#include +#include +#include +#include + +namespace nana{ + namespace detail + { + /// Effect edige nimbus renderer + class edge_nimbus_renderer + { + edge_nimbus_renderer() = default; + public: + using window_layer = ::nana::detail::window_layout; + using graph_reference = ::nana::paint::graphics&; + + static edge_nimbus_renderer& instance(); + + constexpr unsigned weight() const + { + return 2; + } + + void erase(basic_window* wd); + + void render(basic_window* wd, bool forced, const rectangle* update_area = nullptr); + private: + /// Determines whether the effect will be rendered for the given window. + static bool _m_edge_nimbus(basic_window * const wd, basic_window * const focused_wd); + + void _m_render_edge_nimbus(basic_window* wd, const nana::rectangle & visual); + }; + } +}//end namespace nana + +#endif diff --git a/source/gui/detail/events_operation.cpp b/source/gui/detail/events_operation.cpp index a278bc96..9c7c12dc 100644 --- a/source/gui/detail/events_operation.cpp +++ b/source/gui/detail/events_operation.cpp @@ -26,9 +26,7 @@ namespace nana auto i = handles_.find(evt); if (i != handles_.end()) - { - reinterpret_cast(evt)->get_event()->remove(evt); - } + reinterpret_cast(evt)->get_event()->remove(evt); } //end namespace events_operation @@ -80,35 +78,33 @@ namespace nana void event_base::remove(event_handle evt) { internal_scope_guard lock; - if (dockers_) + + for (auto i = dockers_->begin(), end = dockers_->end(); i != end; ++i) { - for (auto i = dockers_->begin(), end = dockers_->end(); i != end; ++i) + if (reinterpret_cast(evt) == *i) { - if (reinterpret_cast(evt) == *i) + //Checks whether this event is working now. + if (emitting_count_) { - //Checks whether this event is working now. - if (emitting_count_) - { - static_cast(*i)->flag_deleted = true; - deleted_flags_ = true; - } - else - { - bedrock::instance().evt_operation().cancel(evt); - dockers_->erase(i); - delete reinterpret_cast(evt); - } - break; + static_cast(*i)->flag_deleted = true; + deleted_flags_ = true; } + else + { + bedrock::instance().evt_operation().cancel(evt); + dockers_->erase(i); + delete reinterpret_cast(evt); + } + return; } } } - event_handle event_base::_m_emplace(detail::docker_interface* docker_ptr, bool in_front) + event_handle event_base::_m_emplace(detail::event_docker_interface* docker_ptr, bool in_front) { internal_scope_guard lock; if (nullptr == dockers_) - dockers_ = new std::vector; + dockers_ = new std::vector; auto evt = reinterpret_cast(docker_ptr); diff --git a/source/gui/detail/inner_fwd_implement.hpp b/source/gui/detail/inner_fwd_implement.hpp index 5c66323c..af246905 100644 --- a/source/gui/detail/inner_fwd_implement.hpp +++ b/source/gui/detail/inner_fwd_implement.hpp @@ -15,8 +15,8 @@ #define NANA_GUI_INNER_FWD_IMPLEMENT_HPP #include +#include "basic_window.hpp" #include -#include #include #include diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp index b0187eec..c94f363c 100644 --- a/source/gui/detail/window_layout.cpp +++ b/source/gui/detail/window_layout.cpp @@ -11,8 +11,8 @@ * */ +#include "basic_window.hpp" #include -#include #include #include #include @@ -22,7 +22,7 @@ namespace nana namespace detail { //class window_layout - void window_layout::paint(core_window_t* wd, paint_operation operation, bool req_refresh_children) + void window_layout::paint(basic_window* wd, paint_operation operation, bool req_refresh_children) { if (wd->flags.refreshing && (paint_operation::try_refresh == operation)) return; @@ -41,7 +41,7 @@ namespace nana _m_paint_glass_window(wd, (paint_operation::try_refresh == operation), req_refresh_children, false, true); } - bool window_layout::maproot(core_window_t* wd, bool have_refreshed, bool req_refresh_children) + bool window_layout::maproot(basic_window* wd, bool have_refreshed, bool req_refresh_children) { auto check_opaque = wd->seek_non_lite_widget_ancestor(); if (check_opaque && check_opaque->flags.refreshing) @@ -80,7 +80,7 @@ namespace nana return false; } - void window_layout::paste_children_to_graphics(core_window_t* wd, nana::paint::graphics& graph) + void window_layout::paste_children_to_graphics(basic_window* wd, nana::paint::graphics& graph) { _m_paste_children(wd, false, false, rectangle{ wd->pos_root, wd->dimension }, graph, wd->pos_root); } @@ -89,7 +89,7 @@ namespace nana ///@brief Reads the visual rectangle of a window, the visual rectangle's reference frame is to root widget, /// the visual rectangle is a rectangular block that a window should be displayed on screen. /// The result is a rectangle that is a visible area for its ancestors. - bool window_layout::read_visual_rectangle(core_window_t* wd, nana::rectangle& visual) + bool window_layout::read_visual_rectangle(basic_window* wd, nana::rectangle& visual) { if (! wd->displayed()) return false; @@ -139,7 +139,7 @@ namespace nana //read_overlaps // reads the overlaps that are overlapped a rectangular block - bool window_layout::read_overlaps(core_window_t* wd, const nana::rectangle& vis_rect, std::vector& blocks) + bool window_layout::read_overlaps(basic_window* wd, const nana::rectangle& vis_rect, std::vector& blocks) { auto const is_wd_root = (category::flags::root == wd->other.category); wd_rectangle block; @@ -150,7 +150,7 @@ namespace nana { for (++i; i != wd->parent->children.cend(); ++i) { - core_window_t* cover = *i; + basic_window* cover = *i; if (!cover->visible) continue; @@ -182,7 +182,7 @@ namespace nana return (!blocks.empty()); } - bool window_layout::enable_effects_bground(core_window_t * wd, bool enabled) + bool window_layout::enable_effects_bground(basic_window * wd, bool enabled) { if (category::flags::widget != wd->other.category) return false; @@ -220,15 +220,15 @@ namespace nana //make_bground // update the glass buffer of a glass window. - void window_layout::make_bground(core_window_t* const wd) + void window_layout::make_bground(basic_window* const wd) { nana::point rpos{ wd->pos_root }; auto & glass_buffer = wd->other.glass_buffer; if (category::flags::lite_widget == wd->parent->other.category) { - std::vector layers; - core_window_t * beg = wd->parent; + std::vector layers; + auto beg = wd->parent; while (beg && (category::flags::lite_widget == beg->other.category)) { layers.push_back(beg); @@ -240,11 +240,11 @@ namespace nana nana::rectangle r(wd->pos_owner, wd->dimension); for (auto i = layers.rbegin(), layers_rend = layers.rend(); i != layers_rend; ++i) { - core_window_t * pre = *i; + auto pre = *i; if (false == pre->visible) continue; - core_window_t * term = ((i + 1 != layers_rend) ? *(i + 1) : wd); + auto term = ((i + 1 != layers_rend) ? *(i + 1) : wd); r.position(wd->pos_root - pre->pos_root); for (auto child : pre->children) @@ -286,10 +286,10 @@ namespace nana } if (wd->effect.bground) - wd->effect.bground->take_effect(reinterpret_cast(wd), glass_buffer); + wd->effect.bground->take_effect(wd, glass_buffer); } - void window_layout::_m_paste_children(core_window_t* wd, bool have_refreshed, bool req_refresh_children, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos) + void window_layout::_m_paste_children(basic_window* wd, bool have_refreshed, bool req_refresh_children, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos) { nana::rectangle rect; for (auto child : wd->children) @@ -333,7 +333,7 @@ namespace nana } } - void window_layout::_m_paint_glass_window(core_window_t* wd, bool is_redraw, bool is_child_refreshed, bool called_by_notify, bool notify_other) + void window_layout::_m_paint_glass_window(basic_window* wd, bool is_redraw, bool is_child_refreshed, bool called_by_notify, bool notify_other) { //A window which has an empty graphics(and lite-widget) does not notify //glass windows for updating their background. @@ -381,7 +381,7 @@ namespace nana /// Notify the glass windows that are overlapped with the specified visual rectangle. /// If a child window of sigwd is a glass window, it doesn't to be notified. - void window_layout::_m_notify_glasses(core_window_t* const sigwd) + void window_layout::_m_notify_glasses(basic_window* const sigwd) { nana::rectangle r_of_sigwd(sigwd->pos_root, sigwd->dimension); for (auto wd : data_sect.effects_bground_windows) @@ -420,7 +420,7 @@ namespace nana else { //test if sigwnd is a parent of glass window x, or a slibing of the glass window, or a child of the slibing of the glass window. - core_window_t *p = wd->parent, *signode = sigwd; + basic_window *p = wd->parent, *signode = sigwd; while (signode->parent && (signode->parent != p)) signode = signode->parent; diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index 9f854ee4..90624598 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -18,7 +18,8 @@ #include #include #include -#include + +#include "effects_renderer.hpp" #include "window_register.hpp" #include "inner_fwd_implement.hpp" @@ -281,7 +282,7 @@ namespace detail paint::image default_icon_big; paint::image default_icon_small; - lite_map>> safe_place; + lite_map>> safe_place; }; //end struct wdm_private_impl @@ -454,7 +455,7 @@ namespace detail delete impl_; } - std::size_t window_manager::number_of_core_window() const + std::size_t window_manager::window_count() const { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -467,14 +468,14 @@ namespace detail return mutex_; } - void window_manager::all_handles(std::vector &v) const + void window_manager::all_handles(std::vector &v) const { //Thread-Safe Required! std::lock_guard lock(mutex_); v = impl_->wd_register.queue(); } - void window_manager::event_filter(core_window_t* wd, bool is_make, event_code evtid) + void window_manager::event_filter(basic_window* wd, bool is_make, event_code evtid) { switch(evtid) { @@ -486,21 +487,21 @@ namespace detail } } - bool window_manager::available(core_window_t* wd) + bool window_manager::available(basic_window* wd) { //Thread-Safe Required! std::lock_guard lock(mutex_); return impl_->wd_register.available(wd); } - bool window_manager::available(core_window_t * a, core_window_t* b) + bool window_manager::available(basic_window * a, basic_window* b) { //Thread-Safe Required! std::lock_guard lock(mutex_); return (impl_->wd_register.available(a) && impl_->wd_register.available(b)); } - window_manager::core_window_t* window_manager::create_root(core_window_t* owner, bool nested, rectangle r, const appearance& app, widget* wdg) + basic_window* window_manager::create_root(basic_window* owner, bool nested, rectangle r, const appearance& app, widget* wdg) { native_window_type native = nullptr; if (owner) @@ -524,7 +525,7 @@ namespace detail auto result = native_interface::create_window(native, nested, r, app); if (result.native_handle) { - auto wd = new core_window_t(owner, widget_notifier_interface::get_notifier(wdg), (category::root_tag**)nullptr); + auto wd = new basic_window(owner, widget_notifier_interface::get_notifier(wdg), (category::root_tag**)nullptr); if (nested) { wd->owner = nullptr; @@ -552,7 +553,7 @@ namespace detail return nullptr; } - window_manager::core_window_t* window_manager::create_widget(core_window_t* parent, const rectangle& r, bool is_lite, widget* wdg) + basic_window* window_manager::create_widget(basic_window* parent, const rectangle& r, bool is_lite, widget* wdg) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -564,17 +565,17 @@ namespace detail auto wdg_notifier = widget_notifier_interface::get_notifier(wdg); - core_window_t * wd; + basic_window * wd; if (is_lite) - wd = new core_window_t(parent, std::move(wdg_notifier), r, (category::lite_widget_tag**)nullptr); + wd = new basic_window(parent, std::move(wdg_notifier), r, (category::lite_widget_tag**)nullptr); else - wd = new core_window_t(parent, std::move(wdg_notifier), r, (category::widget_tag**)nullptr); + wd = new basic_window(parent, std::move(wdg_notifier), r, (category::widget_tag**)nullptr); impl_->wd_register.insert(wd); return wd; } - void window_manager::close(core_window_t *wd) + void window_manager::close(basic_window *wd) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -587,7 +588,7 @@ namespace detail { auto &brock = bedrock::instance(); arg_unload arg; - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; arg.cancel = false; brock.emit(event_code::unload, wd, arg, true, brock.get_thread_context()); if (false == arg.cancel) @@ -616,7 +617,7 @@ namespace detail //destroy //@brief: Delete the window handle - void window_manager::destroy(core_window_t* wd) + void window_manager::destroy(basic_window* wd) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -640,7 +641,7 @@ namespace detail update(parent, false, false, &update_area); } - void window_manager::destroy_handle(core_window_t* wd) + void window_manager::destroy_handle(basic_window* wd) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -653,7 +654,7 @@ namespace detail } } - void window_manager::icon(core_window_t* wd, const paint::image& small_icon, const paint::image& big_icon) + void window_manager::icon(basic_window* wd, const paint::image& small_icon, const paint::image& big_icon) { if(!big_icon.empty() || !small_icon.empty()) { @@ -676,7 +677,7 @@ namespace detail //show //@brief: show or hide a window - bool window_manager::show(core_window_t* wd, bool visible) + bool window_manager::show(basic_window* wd, bool visible) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -701,7 +702,7 @@ namespace detail return true; } - window_manager::core_window_t* window_manager::find_window(native_window_type root, const point& pos, bool ignore_captured) + basic_window* window_manager::find_window(native_window_type root, const point& pos, bool ignore_captured) { if (nullptr == root) return nullptr; @@ -739,7 +740,7 @@ namespace detail } //move the wnd and its all children window, x and y is a relatively coordinate for wnd's parent window - bool window_manager::move(core_window_t* wd, int x, int y, bool passive) + bool window_manager::move(basic_window* wd, int x, int y, bool passive) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -758,7 +759,7 @@ namespace detail auto &brock = bedrock::instance(); arg_move arg; - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; arg.x = x; arg.y = y; @@ -788,7 +789,7 @@ namespace detail return false; } - bool window_manager::move(core_window_t* wd, const rectangle& r) + bool window_manager::move(basic_window* wd, const rectangle& r) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -812,7 +813,7 @@ namespace detail wd->other.upd_state = basic_window::update_state::request_refresh; arg_move arg; - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; arg.x = r.x; arg.y = r.y; brock.emit(event_code::move, wd, arg, true, brock.get_thread_context()); @@ -846,7 +847,7 @@ namespace detail native_interface::move_window(wd->root, root_r); arg_resized arg; - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; arg.width = root_r.width; arg.height = root_r.height; brock.emit(event_code::resized, wd, arg, true, brock.get_thread_context()); @@ -864,7 +865,7 @@ namespace detail // e.g, when the size of window is changed by OS/user, the function should not resize the // window again, otherwise, it causes an infinite loop, because when a root_widget is resized, // window_manager will call the function. - bool window_manager::size(core_window_t* wd, nana::size sz, bool passive, bool ask_update) + bool window_manager::size(basic_window* wd, nana::size sz, bool passive, bool ask_update) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -875,7 +876,7 @@ namespace detail if (sz != wd->dimension) { arg_resizing arg; - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; arg.border = window_border::none; arg.width = sz.width; arg.height = sz.height; @@ -902,7 +903,7 @@ namespace detail if (wd->dimension == sz) return false; - std::vector presence; + std::vector presence; if (wd->dimension.width < sz.width || wd->dimension.height < sz.height) { @@ -970,16 +971,16 @@ namespace detail } arg_resized arg; - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; arg.width = sz.width; arg.height = sz.height; brock.emit(event_code::resized, wd, arg, ask_update, brock.get_thread_context()); return true; } - window_manager::core_window_t* window_manager::root(native_window_type wd) const + basic_window* window_manager::root(native_window_type wd) const { - static std::pair cache; + static std::pair cache; if(cache.first == wd) return cache.second; //Thread-Safe Required! @@ -996,7 +997,7 @@ namespace detail } //Copy the root buffer that wnd specified into DeviceContext - void window_manager::map(core_window_t* wd, bool forced, const rectangle* update_area) + void window_manager::map(basic_window* wd, bool forced, const rectangle* update_area) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1008,7 +1009,7 @@ namespace detail //@brief: update is used for displaying the screen-off buffer. // Because of a good efficiency, if it is called in an event procedure and the event procedure window is the // same as update's, update would not map the screen-off buffer and just set the window for lazy refresh - bool window_manager::update(core_window_t* wd, bool redraw, bool forced, const rectangle* update_area) + bool window_manager::update(basic_window* wd, bool redraw, bool forced, const rectangle* update_area) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1045,13 +1046,13 @@ namespace detail else if (redraw) window_layer::paint(wd, paint_operation::try_refresh, false); - if (wd->other.upd_state == core_window_t::update_state::lazy) - wd->other.upd_state = core_window_t::update_state::refreshed; + if (wd->other.upd_state == basic_window::update_state::lazy) + wd->other.upd_state = basic_window::update_state::refreshed; } return true; } - void window_manager::update_requesters(core_window_t* root_wd) + void window_manager::update_requesters(basic_window* root_wd) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1074,7 +1075,7 @@ namespace detail } - void window_manager::refresh_tree(core_window_t* wd) + void window_manager::refresh_tree(basic_window* wd) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1086,7 +1087,7 @@ namespace detail //do_lazy_refresh //@brief: defined a behavior of flush the screen - void window_manager::do_lazy_refresh(core_window_t* wd, bool force_copy_to_screen, bool refresh_tree) + void window_manager::do_lazy_refresh(basic_window* wd, bool force_copy_to_screen, bool refresh_tree) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1100,11 +1101,11 @@ namespace detail using paint_operation = window_layer::paint_operation; if (wd->visible_parents()) { - if ((wd->other.upd_state == core_window_t::update_state::refreshed) || (wd->other.upd_state == core_window_t::update_state::request_refresh) || force_copy_to_screen) + if ((wd->other.upd_state == basic_window::update_state::refreshed) || (wd->other.upd_state == basic_window::update_state::request_refresh) || force_copy_to_screen) { - if (!wd->try_lazy_update(wd->other.upd_state == core_window_t::update_state::request_refresh)) + if (!wd->try_lazy_update(wd->other.upd_state == basic_window::update_state::request_refresh)) { - window_layer::paint(wd, (wd->other.upd_state == core_window_t::update_state::request_refresh ? paint_operation::try_refresh : paint_operation::have_refreshed), refresh_tree); + window_layer::paint(wd, (wd->other.upd_state == basic_window::update_state::request_refresh ? paint_operation::try_refresh : paint_operation::have_refreshed), refresh_tree); this->map(wd, force_copy_to_screen); } } @@ -1123,10 +1124,10 @@ namespace detail window_layer::paint(wd, paint_operation::try_refresh, refresh_tree); //only refreshing if it has an invisible parent } - wd->other.upd_state = core_window_t::update_state::none; + wd->other.upd_state = basic_window::update_state::none; } - bool window_manager::set_parent(core_window_t* wd, core_window_t* newpa) + bool window_manager::set_parent(basic_window* wd, basic_window* newpa) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1153,7 +1154,7 @@ namespace detail //set_focus //@brief: set a keyboard focus to a window. this may fire a focus event. - window_manager::core_window_t* window_manager::set_focus(core_window_t* wd, bool root_has_been_focused, arg_focus::reason reason) + basic_window* window_manager::set_focus(basic_window* wd, bool root_has_been_focused, arg_focus::reason reason) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1177,7 +1178,7 @@ namespace detail prev_focus->annex.caret_ptr->activate(false); arg.getting = false; - arg.window_handle = reinterpret_cast(prev_focus); + arg.window_handle = prev_focus; arg.receiver = wd->root; arg.focus_reason = arg_focus::reason::general; brock.emit(event_code::focus, prev_focus, arg, true, brock.get_thread_context()); @@ -1194,7 +1195,7 @@ namespace detail if(wd->annex.caret_ptr) wd->annex.caret_ptr->activate(true); - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; arg.getting = true; arg.receiver = wd->root; arg.focus_reason = reason; @@ -1217,7 +1218,7 @@ namespace detail return prev_focus; } - window_manager::core_window_t* window_manager::capture_redirect(core_window_t* wd) + basic_window* window_manager::capture_redirect(basic_window* wd) { if(attr_.capture.window && (attr_.capture.ignore_children == false) && (attr_.capture.window != wd)) { @@ -1244,12 +1245,12 @@ namespace detail return false; } - window_manager::core_window_t * window_manager::capture_window() const + basic_window * window_manager::capture_window() const { return attr_.capture.window; } - void window_manager::capture_window(core_window_t* wd, bool captured, bool ignore_children) + void window_manager::capture_window(basic_window* wd, bool captured, bool ignore_children) { if (!this->available(wd)) return; @@ -1285,7 +1286,7 @@ namespace detail wd->flags.captured = false; if(attr_cap.size()) { - std::pair last = attr_cap.back(); + std::pair last = attr_cap.back(); attr_cap.pop_back(); if (impl_->wd_register.available(last.first)) @@ -1320,7 +1321,7 @@ namespace detail // this method insert a window which catches an user TAB into a TAB window container // the TAB window container is held by a wd's root widget. Not every widget has a TAB window container, // the container is created while a first Tab Window is setting - void window_manager::enable_tabstop(core_window_t* wd) + void window_manager::enable_tabstop(basic_window* wd) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1332,7 +1333,7 @@ namespace detail } // preconditions of get_tabstop: tabstop is not empty and at least one window is visible - window_manager::core_window_t* get_tabstop(window_manager::core_window_t* wd, bool forward) + basic_window* get_tabstop(basic_window* wd, bool forward) { auto & tabs = wd->root_widget->other.attribute.root->tabstop; @@ -1347,7 +1348,7 @@ namespace detail if (i != end) { ++i; - window_manager::core_window_t* ts = (i != end ? (*i) : tabs.front()); + basic_window* ts = (i != end ? (*i) : tabs.front()); return (ts != wd ? ts : 0); } else @@ -1363,7 +1364,7 @@ namespace detail return nullptr; } - auto window_manager::tabstop(core_window_t* wd, bool forward) const -> core_window_t* + auto window_manager::tabstop(basic_window* wd, bool forward) const -> basic_window* { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1407,7 +1408,7 @@ namespace detail impl_->wd_register.delete_trash(tid); } - bool window_manager::enable_effects_bground(core_window_t* wd, bool enabled) + bool window_manager::enable_effects_bground(basic_window* wd, bool enabled) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1417,7 +1418,7 @@ namespace detail return false; } - bool window_manager::calc_window_point(core_window_t* wd, nana::point& pos) + bool window_manager::calc_window_point(basic_window* wd, nana::point& pos) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1437,19 +1438,19 @@ namespace detail return impl_->misc_register.find(native_wd); } - bool window_manager::register_shortkey(core_window_t* wd, unsigned long key) + bool window_manager::register_shortkey(basic_window* wd, unsigned long key) { //Thread-Safe Required! std::lock_guard lock(mutex_); if (impl_->wd_register.available(wd)) { //the root runtime must exist, because the wd is valid. Otherse, it's bug of library - return root_runtime(wd->root)->shortkeys.make(reinterpret_cast(wd), key); + return root_runtime(wd->root)->shortkeys.make(wd, key); } return false; } - void window_manager::unregister_shortkey(core_window_t* wd, bool with_children) + void window_manager::unregister_shortkey(basic_window* wd, bool with_children) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -1458,7 +1459,7 @@ namespace detail auto root_rt = root_runtime(wd->root); if (root_rt) { - root_rt->shortkeys.umake(reinterpret_cast(wd)); + root_rt->shortkeys.umake(wd); if (with_children) { for (auto child : wd->children) @@ -1467,7 +1468,7 @@ namespace detail } } - window_manager::core_window_t* window_manager::find_shortkey(native_window_type native_window, unsigned long key) + basic_window* window_manager::find_shortkey(native_window_type native_window, unsigned long key) { if(native_window) { @@ -1475,12 +1476,12 @@ namespace detail std::lock_guard lock(mutex_); auto object = root_runtime(native_window); if(object) - return reinterpret_cast(object->shortkeys.find(key)); + return object->shortkeys.find(key); } return nullptr; } - void window_manager::set_safe_place(core_window_t* wd, std::function&& fn) + void window_manager::set_safe_place(basic_window* wd, std::function&& fn) { if (fn) { @@ -1522,7 +1523,7 @@ namespace detail return false; } - void window_manager::_m_disengage(core_window_t* wd, core_window_t* for_new) + void window_manager::_m_disengage(basic_window* wd, basic_window* for_new) { auto * const wdpa = wd->parent; @@ -1536,7 +1537,7 @@ namespace detail //Holds the shortkeys of wd and its children, and then //register these shortkeys for establishing. - std::vector> sk_holder; + std::vector> sk_holder; if ((!established) || (pa_root_attr != root_attr)) { @@ -1598,10 +1599,8 @@ namespace detail if (!established) { - using effect_renderer = detail::edge_nimbus_renderer; - //remove the window from edge nimbus effect when it is destroying - effect_renderer::instance().erase(wd); + edge_nimbus_renderer::instance().erase(wd); } else if (pa_root_attr != root_attr) { @@ -1657,8 +1656,8 @@ namespace detail auto delta_pos = wd->pos_root - for_new->pos_root; - std::function set_pos_root; - set_pos_root = [&set_pos_root](core_window_t* wd, const nana::point& delta_pos) + std::function set_pos_root; + set_pos_root = [&set_pos_root](basic_window* wd, const nana::point& delta_pos) { for (auto child : wd->children) { @@ -1689,7 +1688,7 @@ namespace detail } } - void window_manager::_m_destroy(core_window_t* wd) + void window_manager::_m_destroy(basic_window* wd) { if(wd->flags.destroying) return; @@ -1705,13 +1704,11 @@ namespace detail wd->annex.caret_ptr = nullptr; } - using effect_renderer = detail::edge_nimbus_renderer; - //remove the window from edge nimbus effect when it is destroying - effect_renderer::instance().erase(wd); + edge_nimbus_renderer::instance().erase(wd); arg_destroy arg; - arg.window_handle = reinterpret_cast(wd); + arg.window_handle = wd; brock.emit(event_code::destroy, wd, arg, true, brock.get_thread_context()); //Delete the children widgets. @@ -1741,7 +1738,7 @@ namespace detail wd->drawer.graphics.release(); } - void window_manager::_m_move_core(core_window_t* wd, const point& delta) + void window_manager::_m_move_core(basic_window* wd, const point& delta) { if(category::flags::root != wd->other.category) //A root widget always starts at (0, 0) and its children are not to be changed { @@ -1763,14 +1760,14 @@ namespace detail } } - void window_manager::_m_shortkeys(core_window_t* wd, bool with_children, std::vector>& keys) const + void window_manager::_m_shortkeys(basic_window* wd, bool with_children, std::vector>& keys) const { if (impl_->wd_register.available(wd)) { //The root_rt must exist, because wd is valid. Otherwise, it's a bug of the library. auto root_rt = root_runtime(wd->root); - auto pkeys = root_rt->shortkeys.keys(reinterpret_cast(wd)); + auto pkeys = root_rt->shortkeys.keys(wd); if (pkeys) { for (auto key : *pkeys) @@ -1788,7 +1785,7 @@ namespace detail //_m_find //@brief: find a window on root window through a given root coordinate. // the given root coordinate must be in the rectangle of wnd. - window_manager::core_window_t* window_manager::_m_find(core_window_t* wd, const point& pos) + basic_window* window_manager::_m_find(basic_window* wd, const point& pos) { if(!wd->visible) return nullptr; @@ -1812,7 +1809,7 @@ namespace detail } //_m_effective, test if the window is a handle of window that specified by (root_x, root_y) - bool window_manager::_m_effective(core_window_t* wd, const point& root_pos) + bool window_manager::_m_effective(basic_window* wd, const point& root_pos) { if(wd == nullptr || false == wd->visible) return false; return rectangle{ wd->pos_root, wd->dimension }.is_hit(root_pos); diff --git a/source/gui/detail/window_register.hpp b/source/gui/detail/window_register.hpp index 7a2500e4..965a1afa 100644 --- a/source/gui/detail/window_register.hpp +++ b/source/gui/detail/window_register.hpp @@ -1,7 +1,7 @@ #ifndef NANA_WINDOW_REGISTER_HEADER_INCLUDED #define NANA_WINDOW_REGISTER_HEADER_INCLUDED -#include +#include "basic_window.hpp" #include #include #include //std::find diff --git a/source/gui/dragdrop.cpp b/source/gui/dragdrop.cpp index 18f51e52..5711fbd5 100644 --- a/source/gui/dragdrop.cpp +++ b/source/gui/dragdrop.cpp @@ -1,7 +1,7 @@ /** * Drag and Drop Implementation * Nana C++ Library(http://www.nanapro.org) -* Copyright(C) 2018 Jinhao(cnjinhao@hotmail.com) +* Copyright(C) 2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -13,9 +13,9 @@ #include #include - #include -#include + +#include "detail/basic_window.hpp" #include #include @@ -157,10 +157,16 @@ namespace nana }; #ifdef NANA_WINDOWS + template - class win32com_iunknown : public Interface + class win32com_iunknown final: public Interface { public: + template + win32com_iunknown(Args&& ... args) : + Interface(std::forward(args)...) + {} + //Implements IUnknown STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { @@ -188,6 +194,7 @@ namespace nana LONG ref_count_{ 1 }; }; + class win32com_drop_target : public IDropTarget, public dragdrop_session { public: @@ -273,296 +280,300 @@ namespace nana DWORD effect_{ DROPEFFECT_NONE }; }; - class drop_source : public win32com_iunknown +class drop_source_impl : public IDropSource +{ +public: + drop_source_impl(window wd) : + window_handle_(wd) + {} + + window source() const { - public: - drop_source(window wd) : - window_handle_(wd) - {} - - window source() const - { - return window_handle_; - } - private: - // IDropSource - STDMETHODIMP QueryContinueDrag(BOOL esc_pressed, DWORD key_state) override - { - if (esc_pressed) - return DRAGDROP_S_CANCEL; - - //Drop the object if left button is released. - if (0 == (key_state & (MK_LBUTTON))) - return DRAGDROP_S_DROP; - - return S_OK; - } - - STDMETHODIMP GiveFeedback(DWORD effect) override - { - return DRAGDROP_S_USEDEFAULTCURSORS; - } - private: - window const window_handle_; - }; - - class win32_dropdata : public win32com_iunknown + return window_handle_; + } +private: + // IDropSource + STDMETHODIMP QueryContinueDrag(BOOL esc_pressed, DWORD key_state) override { - public: - struct data_entry + if (esc_pressed) + return DRAGDROP_S_CANCEL; + + //Drop the object if left button is released. + if (0 == (key_state & (MK_LBUTTON))) + return DRAGDROP_S_DROP; + + return S_OK; + } + + STDMETHODIMP GiveFeedback(DWORD effect) override + { + return DRAGDROP_S_USEDEFAULTCURSORS; + } +private: + window const window_handle_; +}; +using drop_source = win32com_iunknown; + + +class win32_dropdata_impl: public IDataObject +{ +public: + struct data_entry + { + FORMATETC format; + STGMEDIUM medium; + bool read_from; //Indicates the data which is used for reading. + + ~data_entry() { - FORMATETC format; - STGMEDIUM medium; - bool read_from; //Indicates the data which is used for reading. + ::CoTaskMemFree(format.ptd); + ::ReleaseStgMedium(&medium); + } - ~data_entry() - { - ::CoTaskMemFree(format.ptd); - ::ReleaseStgMedium(&medium); - } - - bool compare(const FORMATETC& fmt, bool rdfrom) const - { - return (format.cfFormat == fmt.cfFormat && - (format.tymed & fmt.tymed) != 0 && - (format.dwAspect == DVASPECT_THUMBNAIL || format.dwAspect == DVASPECT_ICON || medium.tymed == TYMED_NULL || format.lindex == fmt.lindex || (format.lindex == 0 && fmt.lindex == -1) || (format.lindex == -1 && fmt.lindex == 0)) && - format.dwAspect == fmt.dwAspect && read_from == rdfrom); - } + bool compare(const FORMATETC& fmt, bool rdfrom) const + { + return (format.cfFormat == fmt.cfFormat && + (format.tymed & fmt.tymed) != 0 && + (format.dwAspect == DVASPECT_THUMBNAIL || format.dwAspect == DVASPECT_ICON || medium.tymed == TYMED_NULL || format.lindex == fmt.lindex || (format.lindex == 0 && fmt.lindex == -1) || (format.lindex == -1 && fmt.lindex == 0)) && + format.dwAspect == fmt.dwAspect && read_from == rdfrom); +} }; - data_entry * find(const FORMATETC& fmt, bool read_from) const + data_entry * find(const FORMATETC& fmt, bool read_from) const + { + data_entry * last_weak_match = nullptr; + + for (auto & entry : entries_) { - data_entry * last_weak_match = nullptr; - - for (auto & entry : entries_) + if (entry->compare(fmt, read_from)) { - if (entry->compare(fmt, read_from)) - { - auto entry_ptd = entry->format.ptd; - if (entry_ptd && fmt.ptd && entry_ptd->tdSize == fmt.ptd->tdSize && (0 == std::memcmp(entry_ptd, fmt.ptd, fmt.ptd->tdSize))) - return entry.get(); - else if (nullptr == entry_ptd && nullptr == fmt.ptd) - return entry.get(); + auto entry_ptd = entry->format.ptd; + if (entry_ptd && fmt.ptd && entry_ptd->tdSize == fmt.ptd->tdSize && (0 == std::memcmp(entry_ptd, fmt.ptd, fmt.ptd->tdSize))) + return entry.get(); + else if (nullptr == entry_ptd && nullptr == fmt.ptd) + return entry.get(); - last_weak_match = entry.get(); - } - } - return last_weak_match; - } - - void assign(const detail::dragdrop_data& data) - { - if (!data.files.empty()) - { - std::size_t bytes = sizeof(wchar_t); - for (auto & file : data.files) - { - auto file_s = file.wstring(); - bytes += (file_s.size() + 1) * sizeof(file_s.front()); - } - - auto hglobal = ::GlobalAlloc(GHND | GMEM_SHARE, sizeof(DROPFILES) + bytes); - - auto dropfiles = reinterpret_cast(::GlobalLock(hglobal)); - dropfiles->pFiles = sizeof(DROPFILES); - dropfiles->fWide = true; - - auto file_buf = reinterpret_cast(dropfiles) + sizeof(DROPFILES); - - for (auto & file : data.files) - { - auto file_s = file.wstring(); - std::memcpy(file_buf, file_s.data(), (file_s.size() + 1) * sizeof(file_s.front())); - file_buf += (file_s.size() + 1) * sizeof(file_s.front()); - } - *reinterpret_cast(file_buf) = 0; - - ::GlobalUnlock(hglobal); - - assign(hglobal); + last_weak_match = entry.get(); } } + return last_weak_match; + } - data_entry* assign(HGLOBAL hglobal) + void assign(const detail::dragdrop_data& data) + { + if (!data.files.empty()) { - FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; - auto entry = find(fmt, true); - if (entry) + std::size_t bytes = sizeof(wchar_t); + for (auto & file : data.files) { - //Free the current entry for reuse - ::CoTaskMemFree(entry->format.ptd); - ::ReleaseStgMedium(&entry->medium); - } - else - { - //Create a new entry - entries_.emplace_back(new data_entry); - entry = entries_.back().get(); + auto file_s = file.wstring(); + bytes += (file_s.size() + 1) * sizeof(file_s.front()); } - //Assign the format to the entry. - entry->read_from = true; - entry->format = fmt; + auto hglobal = ::GlobalAlloc(GHND | GMEM_SHARE, sizeof(DROPFILES) + bytes); - //Assign the stgMedium - entry->medium.tymed = TYMED_HGLOBAL; - entry->medium.hGlobal = hglobal; - entry->medium.pUnkForRelease = nullptr; + auto dropfiles = reinterpret_cast(::GlobalLock(hglobal)); + dropfiles->pFiles = sizeof(DROPFILES); + dropfiles->fWide = true; - return entry; - } - public: - // Implement IDataObject - STDMETHODIMP GetData(FORMATETC *request_format, STGMEDIUM *pmedium) override - { - if (!(request_format && pmedium)) - return E_INVALIDARG; + auto file_buf = reinterpret_cast(dropfiles)+sizeof(DROPFILES); - pmedium->hGlobal = nullptr; - - auto entry = find(*request_format, true); - if (entry) - return _m_copy_medium(pmedium, &entry->medium, &entry->format); - - return DV_E_FORMATETC; - } - - STDMETHODIMP GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium) override - { - return E_NOTIMPL; - } - - STDMETHODIMP QueryGetData(FORMATETC *pformatetc) override - { - if (NULL == pformatetc) - return E_INVALIDARG; - - if (!(DVASPECT_CONTENT & pformatetc->dwAspect)) - return DV_E_DVASPECT; - - HRESULT result = DV_E_TYMED; - - for (auto & entry : entries_) + for (auto & file : data.files) { - if (entry->format.tymed & pformatetc->tymed) - { - if (entry->format.cfFormat == pformatetc->cfFormat) - return S_OK; - - result = DV_E_FORMATETC; - } + auto file_s = file.wstring(); + std::memcpy(file_buf, file_s.data(), (file_s.size() + 1) * sizeof(file_s.front())); + file_buf += (file_s.size() + 1) * sizeof(file_s.front()); } - return result; + *reinterpret_cast(file_buf) = 0; + + ::GlobalUnlock(hglobal); + + assign(hglobal); } + } - STDMETHODIMP GetCanonicalFormatEtc(FORMATETC *pformatectIn, FORMATETC *pformatetcOut) override + data_entry* assign(HGLOBAL hglobal) + { + FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + auto entry = find(fmt, true); + if (entry) { - return E_NOTIMPL; + //Free the current entry for reuse + ::CoTaskMemFree(entry->format.ptd); + ::ReleaseStgMedium(&entry->medium); } - - STDMETHODIMP SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease) override + else { - if (!(pformatetc && pmedium)) - return E_INVALIDARG; - - if (pformatetc->tymed != pmedium->tymed) - return E_FAIL; - + //Create a new entry entries_.emplace_back(new data_entry); - auto entry = entries_.back().get(); - - entry->format = *pformatetc; - - _m_copy_medium(&entry->medium, pmedium, pformatetc); - - if (TRUE == fRelease) - ::ReleaseStgMedium(pmedium); - - return S_OK; + entry = entries_.back().get(); } - STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc) override + //Assign the format to the entry. + entry->read_from = true; + entry->format = fmt; + + //Assign the stgMedium + entry->medium.tymed = TYMED_HGLOBAL; + entry->medium.hGlobal = hglobal; + entry->medium.pUnkForRelease = nullptr; + + return entry; + } +public: + // Implement IDataObject + STDMETHODIMP GetData(FORMATETC *request_format, STGMEDIUM *pmedium) override + { + if (!(request_format && pmedium)) + return E_INVALIDARG; + + pmedium->hGlobal = nullptr; + + auto entry = find(*request_format, true); + if (entry) + return _m_copy_medium(pmedium, &entry->medium, &entry->format); + + return DV_E_FORMATETC; + } + + STDMETHODIMP GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium) override + { + return E_NOTIMPL; + } + + STDMETHODIMP QueryGetData(FORMATETC *pformatetc) override + { + if (NULL == pformatetc) + return E_INVALIDARG; + + if (!(DVASPECT_CONTENT & pformatetc->dwAspect)) + return DV_E_DVASPECT; + + HRESULT result = DV_E_TYMED; + + for (auto & entry : entries_) { - if (NULL == ppenumFormatEtc) + if (entry->format.tymed & pformatetc->tymed) + { + if (entry->format.cfFormat == pformatetc->cfFormat) + return S_OK; + + result = DV_E_FORMATETC; + } + } + return result; + } + + STDMETHODIMP GetCanonicalFormatEtc(FORMATETC *pformatectIn, FORMATETC *pformatetcOut) override + { + return E_NOTIMPL; + } + + STDMETHODIMP SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease) override + { + if (!(pformatetc && pmedium)) + return E_INVALIDARG; + + if (pformatetc->tymed != pmedium->tymed) + return E_FAIL; + + entries_.emplace_back(new data_entry); + auto entry = entries_.back().get(); + + entry->format = *pformatetc; + + _m_copy_medium(&entry->medium, pmedium, pformatetc); + + if (TRUE == fRelease) + ::ReleaseStgMedium(pmedium); + + return S_OK; + } + + STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc) override + { + if (NULL == ppenumFormatEtc) + return E_INVALIDARG; + + if (DATADIR_GET != dwDirection) + return E_NOTIMPL; + + *ppenumFormatEtc = nullptr; + + FORMATETC rgfmtetc[] = + { + //{ CF_UNICODETEXT, nullptr, DVASPECT_CONTENT, 0, TYMED_HGLOBAL } + { CF_HDROP, nullptr, DVASPECT_CONTENT, 0, TYMED_HGLOBAL } + }; + return ::SHCreateStdEnumFmtEtc(ARRAYSIZE(rgfmtetc), rgfmtetc, ppenumFormatEtc); + } + + STDMETHODIMP DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection) override + { + return OLE_E_ADVISENOTSUPPORTED; + } + + STDMETHODIMP DUnadvise(DWORD dwConnection) override + { + return OLE_E_ADVISENOTSUPPORTED; + } + + STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise) override + { + return OLE_E_ADVISENOTSUPPORTED; + } +private: + static HRESULT _m_copy_medium(STGMEDIUM* stgmed_dst, STGMEDIUM* stgmed_src, FORMATETC* fmt_src) + { + if (!(stgmed_dst && stgmed_src && fmt_src)) + return E_INVALIDARG; + + switch (stgmed_src->tymed) + { + case TYMED_HGLOBAL: + stgmed_dst->hGlobal = (HGLOBAL)OleDuplicateData(stgmed_src->hGlobal, fmt_src->cfFormat, 0); + break; + case TYMED_GDI: + case TYMED_ENHMF: + //GDI object can't be copied to an existing HANDLE + if (stgmed_dst->hGlobal) return E_INVALIDARG; - if (DATADIR_GET != dwDirection) - return E_NOTIMPL; - - *ppenumFormatEtc = nullptr; - - FORMATETC rgfmtetc[] = - { - //{ CF_UNICODETEXT, nullptr, DVASPECT_CONTENT, 0, TYMED_HGLOBAL } - { CF_HDROP, nullptr, DVASPECT_CONTENT, 0, TYMED_HGLOBAL } - }; - return ::SHCreateStdEnumFmtEtc(ARRAYSIZE(rgfmtetc), rgfmtetc, ppenumFormatEtc); + stgmed_dst->hGlobal = (HBITMAP)OleDuplicateData(stgmed_src->hGlobal, fmt_src->cfFormat, 0); + break; + case TYMED_MFPICT: + stgmed_dst->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(stgmed_src->hMetaFilePict, fmt_src->cfFormat, 0); + break; + case TYMED_FILE: + stgmed_dst->lpszFileName = (LPOLESTR)OleDuplicateData(stgmed_src->lpszFileName, fmt_src->cfFormat, 0); + break; + case TYMED_ISTREAM: + stgmed_dst->pstm = stgmed_src->pstm; + stgmed_src->pstm->AddRef(); + break; + case TYMED_ISTORAGE: + stgmed_dst->pstg = stgmed_src->pstg; + stgmed_src->pstg->AddRef(); + break; + case TYMED_NULL: + default: + break; } - - STDMETHODIMP DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection) override + stgmed_dst->tymed = stgmed_src->tymed; + stgmed_dst->pUnkForRelease = nullptr; + if (stgmed_src->pUnkForRelease) { - return OLE_E_ADVISENOTSUPPORTED; + stgmed_dst->pUnkForRelease = stgmed_src->pUnkForRelease; + stgmed_src->pUnkForRelease->AddRef(); } - - STDMETHODIMP DUnadvise(DWORD dwConnection) override - { - return OLE_E_ADVISENOTSUPPORTED; - } - - STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise) override - { - return OLE_E_ADVISENOTSUPPORTED; - } - private: - static HRESULT _m_copy_medium(STGMEDIUM* stgmed_dst, STGMEDIUM* stgmed_src, FORMATETC* fmt_src) - { - if (!(stgmed_dst && stgmed_src && fmt_src)) - return E_INVALIDARG; - - switch (stgmed_src->tymed) - { - case TYMED_HGLOBAL: - stgmed_dst->hGlobal = (HGLOBAL)OleDuplicateData(stgmed_src->hGlobal, fmt_src->cfFormat, 0); - break; - case TYMED_GDI: - case TYMED_ENHMF: - //GDI object can't be copied to an existing HANDLE - if (stgmed_dst->hGlobal) - return E_INVALIDARG; - - stgmed_dst->hGlobal = (HBITMAP)OleDuplicateData(stgmed_src->hGlobal, fmt_src->cfFormat, 0); - break; - case TYMED_MFPICT: - stgmed_dst->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(stgmed_src->hMetaFilePict, fmt_src->cfFormat, 0); - break; - case TYMED_FILE: - stgmed_dst->lpszFileName = (LPOLESTR)OleDuplicateData(stgmed_src->lpszFileName, fmt_src->cfFormat, 0); - break; - case TYMED_ISTREAM: - stgmed_dst->pstm = stgmed_src->pstm; - stgmed_src->pstm->AddRef(); - break; - case TYMED_ISTORAGE: - stgmed_dst->pstg = stgmed_src->pstg; - stgmed_src->pstg->AddRef(); - break; - case TYMED_NULL: - default: - break; - } - stgmed_dst->tymed = stgmed_src->tymed; - stgmed_dst->pUnkForRelease = nullptr; - if (stgmed_src->pUnkForRelease) - { - stgmed_dst->pUnkForRelease = stgmed_src->pUnkForRelease; - stgmed_src->pUnkForRelease->AddRef(); - } - return S_OK; - } - private: - std::vector> entries_; + return S_OK; + } +private: + std::vector> entries_; }; +using win32_dropdata = win32com_iunknown; + #elif defined(NANA_X11) class x11_dropdata @@ -710,7 +721,7 @@ namespace nana i->second->set_current_source(drag_wd); DWORD result_effect{ DROPEFFECT_NONE }; - auto status = ::DoDragDrop(dropdata, drop_src, DROPEFFECT_COPY, &result_effect); + ::DoDragDrop(dropdata, drop_src, DROPEFFECT_COPY, &result_effect); i->second->set_current_source(nullptr); @@ -961,8 +972,7 @@ namespace nana if (API::is_window(window_handle)) { dragging = true; - auto real_wd = reinterpret_cast(window_handle); - real_wd->other.dnd_state = dragdrop_status::not_ready; + window_handle->other.dnd_state = dragdrop_status::not_ready; } API::release_capture(window_handle); @@ -1000,9 +1010,7 @@ namespace nana if (arg.is_left_button() && API::is_window(impl_->window_handle)) { impl_->dragging = ((!impl_->predicate) || impl_->predicate()); - - auto real_wd = reinterpret_cast(impl_->window_handle); - real_wd->other.dnd_state = dragdrop_status::ready; + impl_->window_handle->other.dnd_state = dragdrop_status::ready; } }); @@ -1010,14 +1018,13 @@ namespace nana if (!(arg.is_left_button() && impl_->dragging && API::is_window(arg.window_handle))) return; - auto real_wd = reinterpret_cast(arg.window_handle); - real_wd->other.dnd_state = dragdrop_status::in_progress; + arg.window_handle->other.dnd_state = dragdrop_status::in_progress; std::unique_ptr dropdata{new dragdrop_service::dropdata_type}; auto has_dropped = dragdrop_service::instance().dragdrop(arg.window_handle, dropdata.get(), nullptr); - real_wd->other.dnd_state = dragdrop_status::not_ready; + arg.window_handle->other.dnd_state = dragdrop_status::not_ready; impl_->dragging = false; if (has_dropped) @@ -1116,9 +1123,7 @@ namespace nana if (arg.is_left_button() && API::is_window(impl_->source_handle)) { impl_->dragging = ((!impl_->predicate) || impl_->predicate()); - - auto real_wd = reinterpret_cast(impl_->source_handle); - real_wd->other.dnd_state = dragdrop_status::ready; + impl_->source_handle->other.dnd_state = dragdrop_status::ready; } }); @@ -1126,13 +1131,9 @@ namespace nana if (!(arg.is_left_button() && impl_->dragging && API::is_window(arg.window_handle))) return; - auto real_wd = reinterpret_cast(arg.window_handle); - real_wd->other.dnd_state = dragdrop_status::in_progress; - + arg.window_handle->other.dnd_state = dragdrop_status::in_progress; impl_->make_drop(); - - - real_wd->other.dnd_state = dragdrop_status::not_ready; + arg.window_handle->other.dnd_state = dragdrop_status::not_ready; impl_->dragging = false; }); } diff --git a/source/gui/drawing.cpp b/source/gui/drawing.cpp index 2e6e2142..9b1fb7e6 100644 --- a/source/gui/drawing.cpp +++ b/source/gui/drawing.cpp @@ -10,9 +10,9 @@ * @file: nana/gui/drawing.cpp */ +#include "detail/basic_window.hpp" #include #include -#include namespace nana { @@ -22,11 +22,9 @@ namespace nana { namespace { - using core_window_t = detail::basic_window; - inline detail::drawer& get_drawer(window wd) { - return reinterpret_cast(wd)->drawer; + return wd->drawer; } } } @@ -38,7 +36,7 @@ namespace nana if (!API::is_window(wd)) throw std::invalid_argument("drawing: invalid window parameter"); - if (reinterpret_cast(wd)->is_draw_through()) + if (wd->is_draw_through()) throw std::invalid_argument("drawing: the window is draw_through enabled"); } @@ -46,7 +44,7 @@ namespace nana bool drawing::empty() const { - return API::empty_window(handle_) || reinterpret_cast(handle_)->root_graph->empty(); + return API::empty_window(handle_) || handle_->root_graph->empty(); } void drawing::update() const diff --git a/source/gui/filebox.cpp b/source/gui/filebox.cpp index b748b5cf..06dfed84 100644 --- a/source/gui/filebox.cpp +++ b/source/gui/filebox.cpp @@ -1062,6 +1062,8 @@ namespace nana { if(text.length() == start_pos) return files; + else if(0 == start_pos) //single selection + return {text}; return {}; } diff --git a/source/gui/msgbox.cpp b/source/gui/msgbox.cpp index d11816fa..9d0467d0 100644 --- a/source/gui/msgbox.cpp +++ b/source/gui/msgbox.cpp @@ -12,7 +12,10 @@ * James Bremner */ -#include +#include +#include +#include +#include #include #include #include diff --git a/source/gui/place.cpp b/source/gui/place.cpp index b29d98b0..b9acf02e 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -617,7 +617,7 @@ namespace nana : std::invalid_argument{ what + " from place implementation " }, pos{ pos }, - field { field.empty() ? "unnamed" : field } + field(field.empty() ? "unnamed" : field) {} std::string::size_type pos; std::string field; @@ -3674,18 +3674,18 @@ namespace nana std::string field, std::string::size_type pos) - : std::invalid_argument{ "from widget '" + : std::invalid_argument( "from widget '" + API::window_caption(plc.window_handle()).substr(0,80) + "'; nana::place error " + what + "' in field '" + field + (pos == std::string::npos ? "' " : "' at position " + std::to_string(pos)) - + " in div_text:\n" + plc.div() }, - base_what{ what }, - owner_caption{ API::window_caption(plc.window_handle()).substr(0,80) }, - div_text{ plc.div() }, - field{ field }, - pos{ pos } + + " in div_text:\n" + plc.div() ), + base_what( what ), + owner_caption( API::window_caption(plc.window_handle()).substr(0,80) ), + div_text( plc.div() ), + field( field ), + pos( pos ) {} //end class place diff --git a/source/gui/place_parts.hpp b/source/gui/place_parts.hpp index 97295d60..85ef8dfe 100644 --- a/source/gui/place_parts.hpp +++ b/source/gui/place_parts.hpp @@ -126,6 +126,12 @@ namespace nana { close_fn_ = std::move(fn); } + + bool hit_close() const + { + return x_pointed_; + } + private: virtual void attached(widget_reference wdg, graph_reference graph) override { @@ -140,7 +146,7 @@ namespace nana //draw caption auto text = to_wstring(API::window_caption(window_handle_)); - text_rd_->render({ 3, 1 }, text.data(), text.size(), graph.size().width - 20, true); + text_rd_->render({ 3, 1 }, text.data(), text.size(), graph.size().width - 20, paint::text_renderer::mode::truncate_with_ellipsis); //draw x button auto r = _m_button_area(); @@ -310,7 +316,9 @@ namespace nana { move_pos += moves_.start_container_pos; API::move_window(container_->handle(), move_pos); - notifier_->notify_move(); + + if(!caption_.get_drawer_trigger().hit_close()) + notifier_->notify_move(); } } } diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index 28b61836..2610e17e 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -11,9 +11,9 @@ * @author: Jinhao */ +#include "detail/basic_window.hpp" #include #include -#include #include #include #include @@ -81,104 +81,100 @@ namespace API bool emit_event(event_code evt_code, window wd, const ::nana::event_arg& arg) { - return restrict::bedrock.emit(evt_code, reinterpret_cast<::nana::detail::basic_window*>(wd), arg, true, restrict::bedrock.get_thread_context(), false); + return restrict::bedrock.emit(evt_code, wd, arg, true, restrict::bedrock.get_thread_context(), false); } bool emit_internal_event(event_code evt_code, window wd, const ::nana::event_arg& arg) { - return restrict::bedrock.emit(evt_code, reinterpret_cast<::nana::detail::basic_window*>(wd), arg, true, restrict::bedrock.get_thread_context(), true); + return restrict::bedrock.emit(evt_code, wd, arg, true, restrict::bedrock.get_thread_context(), true); } void enum_widgets_function_base::enum_widgets(window wd, bool recursive) { - auto iwd = reinterpret_cast(wd); - internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - //Use a copy, because enum function may close a child window and the original children container would be changed, - //in the situation, the walking thorugh directly to the iwd->children would cause error. - auto children = iwd->children; + //Use a copy, because enumerating function may close a child window and the original children container would be changed, + //in the situation, the walking thorugh directly to the wd->children would cause error. + auto children = wd->children; for (auto child : children) { - auto widget_ptr = API::get_widget(reinterpret_cast(child)); + auto widget_ptr = API::get_widget(child); if (!widget_ptr) continue; _m_enum_fn(widget_ptr); if (recursive) - enum_widgets(reinterpret_cast(child), recursive); + enum_widgets(child, recursive); } } } general_events* get_general_events(window wd) { - if (!restrict::wd_manager().available(reinterpret_cast(wd))) + if (empty_window(wd)) return nullptr; - return reinterpret_cast(wd)->annex.events_ptr.get(); + return wd->annex.events_ptr.get(); } }//end namespace detail void effects_edge_nimbus(window wd, effects::edge_nimbus en) { - auto const iwd = reinterpret_cast(wd); - internal_scope_guard isg; - if(restrict::wd_manager().available(iwd)) + internal_scope_guard lock; + if(is_window(wd)) { - auto & cont = iwd->root_widget->other.attribute.root->effects_edge_nimbus; + auto & cont = wd->root_widget->other.attribute.root->effects_edge_nimbus; if(effects::edge_nimbus::none != en) { - if (iwd->effect.edge_nimbus == effects::edge_nimbus::none) + if (wd->effect.edge_nimbus == effects::edge_nimbus::none) { - cont.emplace_back(basic_window::edge_nimbus_action{ iwd, false}); + cont.emplace_back(basic_window::edge_nimbus_action{ wd, false}); } - iwd->effect.edge_nimbus = static_cast(static_cast(en) | static_cast(iwd->effect.edge_nimbus)); + wd->effect.edge_nimbus = static_cast(static_cast(en) | static_cast(wd->effect.edge_nimbus)); } else { - if(effects::edge_nimbus::none != iwd->effect.edge_nimbus) + if(effects::edge_nimbus::none != wd->effect.edge_nimbus) { for(auto i = cont.begin(); i != cont.end(); ++i) - if(i->window == iwd) + if(i->window == wd) { cont.erase(i); break; } } - iwd->effect.edge_nimbus = effects::edge_nimbus::none; + wd->effect.edge_nimbus = effects::edge_nimbus::none; } } } effects::edge_nimbus effects_edge_nimbus(window wd) { - auto const iwd = reinterpret_cast(wd); - internal_scope_guard isg; - return (restrict::wd_manager().available(iwd) ? iwd->effect.edge_nimbus : effects::edge_nimbus::none); + internal_scope_guard lock; + return (is_window(wd) ? wd->effect.edge_nimbus : effects::edge_nimbus::none); } void effects_bground(window wd, const effects::bground_factory_interface& factory, double fade_rate) { if (fade_rate < 0.0 || fade_rate > 1.0) throw std::invalid_argument("effects_bground: value range of fade_rate must be [0, 1]."); - auto const iwd = reinterpret_cast(wd); - internal_scope_guard isg; - if(restrict::wd_manager().available(iwd)) + + internal_scope_guard lock; + if(is_window(wd)) { auto new_effect_ptr = effects::effects_accessor::create(factory); if(nullptr == new_effect_ptr) return; - delete iwd->effect.bground; - iwd->effect.bground = new_effect_ptr; - iwd->effect.bground_fade_rate = fade_rate; - restrict::wd_manager().enable_effects_bground(iwd, true); + delete wd->effect.bground; + wd->effect.bground = new_effect_ptr; + wd->effect.bground_fade_rate = fade_rate; + restrict::wd_manager().enable_effects_bground(wd, true); if (fade_rate < 0.01) - iwd->flags.make_bground_declared = true; + wd->flags.make_bground_declared = true; API::refresh_window(wd); } @@ -192,21 +188,19 @@ namespace API bground_mode effects_bground_mode(window wd) { - auto const iwd = reinterpret_cast(wd); - internal_scope_guard isg; - if(restrict::wd_manager().available(iwd) && iwd->effect.bground) - return (iwd->effect.bground_fade_rate <= 0.009 ? bground_mode::basic : bground_mode::blend); + internal_scope_guard lock; + if(is_window(wd) && wd->effect.bground) + return (wd->effect.bground_fade_rate <= 0.009 ? bground_mode::basic : bground_mode::blend); return bground_mode::none; } void effects_bground_remove(window wd) { - const auto iwd = reinterpret_cast(wd); - internal_scope_guard isg; - if(restrict::wd_manager().available(iwd)) + internal_scope_guard lock; + if(is_window(wd)) { - if(restrict::wd_manager().enable_effects_bground(iwd, false)) + if(restrict::wd_manager().enable_effects_bground(wd, false)) API::refresh_window(wd); } } @@ -221,99 +215,92 @@ namespace API bool set_events(window wd, const std::shared_ptr& gep) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) - iwd->set_events(gep); + if (is_window(wd)) + return wd->set_events(gep); return false; } void set_scheme(window wd, widget_geometrics* wdg_geom) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) - iwd->annex.scheme = wdg_geom; + if (is_window(wd)) + wd->annex.scheme = wdg_geom; } widget_geometrics* get_scheme(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - return (restrict::wd_manager().available(iwd) ? iwd->annex.scheme : nullptr); + return (is_window(wd) ? wd->annex.scheme : nullptr); } void set_measurer(window wd, ::nana::dev::widget_content_measurer_interface* measurer) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) - iwd->annex.content_measurer = measurer; + if (is_window(wd)) + wd->annex.content_measurer = measurer; } - void attach_drawer(widget& wd, drawer_trigger& dr) + void attach_drawer(widget& wdg, drawer_trigger& dr) { - const auto iwd = reinterpret_cast(wd.handle()); - internal_scope_guard isg; - if(restrict::wd_manager().available(iwd)) + const auto wd = wdg.handle(); + internal_scope_guard lock; + if(is_window(wd)) { - iwd->drawer.graphics.make(iwd->dimension); - iwd->drawer.graphics.rectangle(true, iwd->annex.scheme->background.get_color()); - iwd->drawer.attached(wd, dr); - iwd->drawer.refresh(); //Always redraw no matter it is visible or invisible. This can make the graphics data correctly. + wd->drawer.graphics.make(wd->dimension); + wd->drawer.graphics.rectangle(true, wd->annex.scheme->background.get_color()); + wd->drawer.attached(wdg, dr); + wd->drawer.refresh(); //Always redraw no matter it is visible or invisible. This can make the graphics data correctly. } } ::nana::detail::native_string_type window_caption(window wd) noexcept { - auto const iwd = reinterpret_cast(wd); - internal_scope_guard isg; - - if(restrict::wd_manager().available(iwd)) + internal_scope_guard lock; + if(is_window(wd)) { - if (category::flags::root == iwd->other.category) - return interface_type::window_caption(iwd->root); - return iwd->title; + if (category::flags::root == wd->other.category) + return interface_type::window_caption(wd->root); + return wd->title; } return {}; } void window_caption(window wd, ::nana::detail::native_string_type title) { - auto const iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - iwd->title.swap(title); - if (iwd->other.category == category::flags::root) - interface_type::window_caption(iwd->root, iwd->title); + wd->title.swap(title); + if (wd->other.category == category::flags::root) + interface_type::window_caption(wd->root, wd->title); - restrict::wd_manager().update(iwd, true, false); + refresh_window(wd); } } window create_window(window owner, bool nested, const rectangle& r, const appearance& ap, widget* wdg) { - return reinterpret_cast(restrict::wd_manager().create_root(reinterpret_cast(owner), nested, r, ap, wdg)); + return restrict::wd_manager().create_root(owner, nested, r, ap, wdg); } window create_widget(window parent, const rectangle& r, widget* wdg) { - return reinterpret_cast(restrict::wd_manager().create_widget(reinterpret_cast(parent), r, false, wdg)); + return restrict::wd_manager().create_widget(parent, r, false, wdg); } window create_lite_widget(window parent, const rectangle& r, widget* wdg) { - return reinterpret_cast(restrict::wd_manager().create_widget(reinterpret_cast(parent), r, true, wdg)); + return restrict::wd_manager().create_widget(parent, r, true, wdg); } paint::graphics* window_graphics(window wd) { - internal_scope_guard isg; - if(restrict::wd_manager().available(reinterpret_cast(wd))) - return &reinterpret_cast(wd)->drawer.graphics; + internal_scope_guard lock; + if(is_window(wd)) + return &(wd->drawer.graphics); return nullptr; } @@ -325,25 +312,24 @@ namespace API void register_menu_window(window wd, bool has_keyboard) { internal_scope_guard lock; - if (restrict::wd_manager().available(reinterpret_cast(wd))) - restrict::bedrock.set_menu(reinterpret_cast(wd)->root, has_keyboard); + if (is_window(wd)) + restrict::bedrock.set_menu(wd->root, has_keyboard); } void set_menubar(window wd, bool attach) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - auto root_attr = iwd->root_widget->other.attribute.root; + auto root_attr = wd->root_widget->other.attribute.root; if (attach) { if (!root_attr->menubar) - root_attr->menubar = iwd; + root_attr->menubar = wd; } else { - if (iwd == root_attr->menubar) + if (wd == root_attr->menubar) root_attr->menubar = nullptr; } } @@ -351,35 +337,30 @@ 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; + if (is_window(wd)) + wd->flags.space_click_enabled = enable; } bool copy_transparent_background(window wd, paint::graphics& graph) { - auto & buf = reinterpret_cast(wd)->other.glass_buffer; internal_scope_guard lock; if (bground_mode::basic != API::effects_bground_mode(wd)) return false; - buf.paste(rectangle{ buf.size() }, graph, 0, 0); - + wd->other.glass_buffer.paste(rectangle{ wd->other.glass_buffer.size() }, graph, 0, 0); return true; } bool copy_transparent_background(window wd, const rectangle& src_r, paint::graphics& graph, const point& dst_pt) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; if (bground_mode::basic != API::effects_bground_mode(wd)) return false; - iwd->other.glass_buffer.paste(src_r, graph, dst_pt.x, dst_pt.y); - + wd->other.glass_buffer.paste(src_r, graph, dst_pt.x, dst_pt.y); return true; } @@ -413,18 +394,16 @@ namespace API void window_draggable(window wd, bool enabled) { - auto real_wd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(real_wd)) - real_wd->flags.draggable = enabled; + if (is_window(wd)) + wd->flags.draggable = enabled; } bool window_draggable(window wd) { - auto real_wd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(real_wd)) - return real_wd->flags.draggable; + if (is_window(wd)) + return wd->flags.draggable; return false; } @@ -435,8 +414,8 @@ namespace API widget* get_widget(window wd) { internal_scope_guard lock; - if (restrict::wd_manager().available(reinterpret_cast(wd))) - return reinterpret_cast(wd)->widget_notifier->widget_ptr(); + if (is_window(wd)) + return wd->widget_notifier->widget_ptr(); return nullptr; } @@ -495,15 +474,15 @@ namespace API bool register_shortkey(window wd, unsigned long key) { - return restrict::wd_manager().register_shortkey(reinterpret_cast(wd), key); + return restrict::wd_manager().register_shortkey(wd, key); } void unregister_shortkey(window wd) { - restrict::wd_manager().unregister_shortkey(reinterpret_cast(wd), false); + restrict::wd_manager().unregister_shortkey(wd, false); } - ::nana::point cursor_position() + ::nana::point cursor_position() { return interface_type::cursor_position(); } @@ -536,37 +515,35 @@ namespace API void window_icon(window wd, const paint::image& small_icon, const paint::image& big_icon) { if(nullptr != wd) - restrict::wd_manager().icon(reinterpret_cast(wd), small_icon, big_icon); + restrict::wd_manager().icon(wd, small_icon, big_icon); } bool empty_window(window wd) { - return (restrict::wd_manager().available(reinterpret_cast(wd)) == false); + return (restrict::wd_manager().available(wd) == false); } bool is_window(window wd) { - return restrict::wd_manager().available(reinterpret_cast(wd)); + return restrict::wd_manager().available(wd); } bool is_destroying(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (!restrict::wd_manager().available(iwd)) + if (!restrict::wd_manager().available(wd)) return false; - return iwd->flags.destroying; + return wd->flags.destroying; } void enable_dropfiles(window wd, bool enb) { internal_scope_guard lock; - auto iwd = reinterpret_cast(wd); auto native_handle = API::root(wd); if (native_handle) { - iwd->flags.dropable = enb; + wd->flags.dropable = enb; interface_type::enable_dropfiles(native_handle, enb); } } @@ -580,88 +557,83 @@ namespace API { internal_scope_guard lock; if(is_window(wd)) - return reinterpret_cast(wd)->root; + return wd->root; return nullptr; } window root(native_window_type wd) { - return reinterpret_cast(restrict::wd_manager().root(wd)); + return restrict::wd_manager().root(wd); } void enable_double_click(window wd, bool dbl) { - auto const iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) - iwd->flags.dbl_click = dbl; + if(is_window(wd)) + wd->flags.dbl_click = dbl; } void fullscreen(window wd, bool v) { internal_scope_guard lock; - if(restrict::wd_manager().available(reinterpret_cast(wd))) - reinterpret_cast(wd)->flags.fullscreen = v; + if(is_window(wd)) + wd->flags.fullscreen = v; } void close_window(window wd) { - restrict::wd_manager().close(reinterpret_cast(wd)); + restrict::wd_manager().close(wd); } void show_window(window wd, bool show) { - restrict::wd_manager().show(reinterpret_cast(wd), show); + restrict::wd_manager().show(wd, show); } bool visible(window wd) { - auto const iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) + if(is_window(wd)) { - if(iwd->other.category == category::flags::root) - return interface_type::is_window_visible(iwd->root); - return iwd->visible; + if(wd->other.category == category::flags::root) + return interface_type::is_window_visible(wd->root); + return wd->visible; } return false; } void restore_window(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) + if(is_window(wd)) { - if(iwd->other.category == category::flags::root) - interface_type::restore_window(iwd->root); + if(wd->other.category == category::flags::root) + interface_type::restore_window(wd->root); } } void zoom_window(window wd, bool ask_for_max) { - auto core_wd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(core_wd)) + if(is_window(wd)) { - if(category::flags::root == core_wd->other.category) - interface_type::zoom_window(core_wd->root, ask_for_max); + if(category::flags::root == wd->other.category) + interface_type::zoom_window(wd->root, ask_for_max); } } window get_parent_window(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - if (category::flags::root == iwd->other.category) + if (category::flags::root == wd->other.category) { - return reinterpret_cast(restrict::wd_manager().root( - interface_type::get_window(iwd->root, window_relationship::parent) - )); + return restrict::wd_manager().root( + interface_type::get_window(wd->root, window_relationship::parent) + ); } - return reinterpret_cast(iwd->parent); + return wd->parent; } return nullptr; @@ -669,13 +641,12 @@ namespace API window get_owner_window(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd) && (iwd->other.category == category::flags::root)) + if(is_window(wd) && (wd->other.category == category::flags::root)) { - auto owner = interface_type::get_window(iwd->root, window_relationship::owner); + auto owner = interface_type::get_window(wd->root, window_relationship::owner); if(owner) - return reinterpret_cast(restrict::wd_manager().root(owner)); + return restrict::wd_manager().root(owner); } return nullptr; @@ -683,7 +654,7 @@ namespace API bool set_parent_window(window wd, window new_parent) { - return restrict::wd_manager().set_parent(reinterpret_cast(wd), reinterpret_cast(new_parent)); + return restrict::wd_manager().set_parent(wd, new_parent); } void umake_event(event_handle eh) @@ -693,32 +664,30 @@ namespace API nana::point window_position(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) + if(is_window(wd)) { - return ( (iwd->other.category == category::flags::root) ? - interface_type::window_position(iwd->root) : iwd->pos_owner); + return ( (wd->other.category == category::flags::root) ? + interface_type::window_position(wd->root) : wd->pos_owner); } return nana::point{}; } void move_window(window wd, const point& pos) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().move(iwd, pos.x, pos.y, false)) + if(restrict::wd_manager().move(wd, pos.x, pos.y, false)) { basic_window* update_wd = nullptr; - if (iwd->displayed() && iwd->effect.bground) + if (wd->displayed() && wd->effect.bground) { - update_wd = iwd; - restrict::wd_manager().update(iwd, true, false); + update_wd = wd; + refresh_window(wd); } - basic_window* anc = iwd; - if (category::flags::root != iwd->other.category) - anc = iwd->seek_non_lite_widget_ancestor(); + basic_window* anc = wd; + if (category::flags::root != wd->other.category) + anc = wd->seek_non_lite_widget_ancestor(); if (anc != update_wd) restrict::wd_manager().update(anc, false, false); @@ -727,14 +696,13 @@ namespace API void move_window(window wd, const rectangle& r) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().move(iwd, r)) + if(restrict::wd_manager().move(wd, r)) { - if (category::flags::root != iwd->other.category) - iwd = iwd->seek_non_lite_widget_ancestor(); + if (category::flags::root != wd->other.category) + wd = wd->seek_non_lite_widget_ancestor(); - restrict::wd_manager().update(iwd, false, false); + restrict::wd_manager().update(wd, false, false); } } @@ -745,23 +713,21 @@ namespace API bool set_window_z_order(window wd, window wd_after, z_order_action action_if_no_wd_after) { - auto iwd = reinterpret_cast(wd); native_window_type native_after = nullptr; internal_scope_guard lock; - if (restrict::wd_manager().available(iwd) && (category::flags::root == iwd->other.category)) + if (is_window(wd) && (category::flags::root == wd->other.category)) { if(wd_after) { - auto iwd_after = reinterpret_cast(wd_after); - if (restrict::wd_manager().available(iwd_after) && (iwd_after->other.category == category::flags::root)) + if (is_window(wd_after) && (wd_after->other.category == category::flags::root)) { - native_after = iwd_after->root; + native_after = wd_after->root; action_if_no_wd_after = z_order_action::none; } else return false; } - interface_type::set_window_z_order(iwd->root, native_after, action_if_no_wd_after); + interface_type::set_window_z_order(wd->root, native_after, action_if_no_wd_after); return true; } return false; @@ -769,23 +735,21 @@ namespace API void draw_through(window wd, std::function draw_fn) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (!restrict::wd_manager().available(iwd)) + if (empty_window(wd)) throw std::invalid_argument("draw_through: invalid window parameter"); - if (::nana::category::flags::root != iwd->other.category) + if (::nana::category::flags::root != wd->other.category) throw std::invalid_argument("draw_through: the window is not a root widget"); - iwd->other.attribute.root->draw_through.swap(draw_fn); + wd->other.attribute.root->draw_through.swap(draw_fn); } void map_through_widgets(window wd, native_drawable_type drawable) { - auto iwd = reinterpret_cast<::nana::detail::basic_window*>(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd) && iwd->is_draw_through() ) - restrict::bedrock.map_through_widgets(iwd, drawable); + if (is_window(wd) && wd->is_draw_through() ) + restrict::bedrock.map_through_widgets(wd, drawable); } nana::size window_size(window wd) @@ -797,29 +761,27 @@ namespace API void window_size(window wd, const size& sz) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().size(iwd, sz, false, false)) + if(restrict::wd_manager().size(wd, sz, false, false)) { - if (category::flags::root != iwd->other.category) - iwd = iwd->seek_non_lite_widget_ancestor(); + if (category::flags::root != wd->other.category) + wd = wd->seek_non_lite_widget_ancestor(); - restrict::wd_manager().update(iwd, false, false); + restrict::wd_manager().update(wd, false, false); } } ::nana::size window_outline_size(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (!restrict::wd_manager().available(iwd)) + if (empty_window(wd)) return{}; auto sz = window_size(wd); - if(category::flags::root == iwd->other.category) + if(category::flags::root == wd->other.category) { - auto fm_extents = interface_type::window_frame_extents(iwd->root); + auto fm_extents = interface_type::window_frame_extents(wd->root); sz.width += fm_extents.left + fm_extents.right; sz.height += fm_extents.top + fm_extents.bottom; } @@ -829,13 +791,12 @@ namespace API void window_outline_size(window wd, const size& sz) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - if (category::flags::root == iwd->other.category) + if (category::flags::root == wd->other.category) { - auto fm_extents = interface_type::window_frame_extents(iwd->root); + auto fm_extents = interface_type::window_frame_extents(wd->root); size inner_size = sz; @@ -858,20 +819,18 @@ namespace API std::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); + if (is_window(wd)) + return rectangle(wd->pos_owner, wd->dimension); return{}; } bool get_window_rectangle(window wd, rectangle& r) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) + if(is_window(wd)) { - r = rectangle(iwd->pos_owner, iwd->dimension); + r = rectangle(wd->pos_owner, wd->dimension); return true; } return false; @@ -879,28 +838,27 @@ namespace API bool track_window_size(window wd, const nana::size& sz, bool true_for_max) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd) == false) + if(is_window(wd) == false) return false; - nana::size & ts = (true_for_max ? iwd->max_track_size : iwd->min_track_size); + nana::size & ts = (true_for_max ? wd->max_track_size : wd->min_track_size); if(!sz.empty()) { if(true_for_max) { //Make sure the new size is larger than min size - if (iwd->min_track_size.width > sz.width || iwd->min_track_size.height > sz.height) + if (wd->min_track_size.width > sz.width || wd->min_track_size.height > sz.height) return false; } else { //Make sure that the new size is less than max size - if ((iwd->max_track_size.width || iwd->max_track_size.height) && (iwd->max_track_size.width < sz.width || iwd->max_track_size.height < sz.height)) + if ((wd->max_track_size.width || wd->max_track_size.height) && (wd->max_track_size.width < sz.width || wd->max_track_size.height < sz.height)) return false; } - ts = interface_type::check_track_size(sz, iwd->extra_width, iwd->extra_height, true_for_max); + ts = interface_type::check_track_size(sz, wd->extra_width, wd->extra_height, true_for_max); } else ts.width = ts.height = 0; @@ -909,155 +867,145 @@ namespace API void window_enabled(window wd, bool enabled) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd) && (iwd->flags.enabled != enabled)) + if(is_window(wd) && (wd->flags.enabled != enabled)) { - iwd->flags.enabled = enabled; - restrict::wd_manager().update(iwd, true, true); - if(category::flags::root == iwd->other.category) - interface_type::enable_window(iwd->root, enabled); + wd->flags.enabled = enabled; + restrict::wd_manager().update(wd, true, true); + if(category::flags::root == wd->other.category) + interface_type::enable_window(wd->root, enabled); } } bool window_enabled(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - return (restrict::wd_manager().available(iwd) ? iwd->flags.enabled : false); + return (is_window(wd) ? wd->flags.enabled : false); } //refresh_window //@brief: Refresh the window and display it immediately. void refresh_window(window wd) { - restrict::wd_manager().update(reinterpret_cast(wd), true, false); + restrict::wd_manager().update(wd, true, false); } void refresh_window_tree(window wd) { - restrict::wd_manager().refresh_tree(reinterpret_cast(wd)); + restrict::wd_manager().refresh_tree(wd); } //update_window //@brief: it displays a window immediately without refreshing. void update_window(window wd) { - restrict::wd_manager().update(reinterpret_cast(wd), false, true); + restrict::wd_manager().update(wd, false, true); } void window_caption(window wd, const std::string& title_utf8) { throw_not_utf8(title_utf8); - auto const iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) - iwd->widget_notifier->caption(to_nstring(title_utf8)); + if (is_window(wd)) + wd->widget_notifier->caption(to_nstring(title_utf8)); } void window_caption(window wd, const std::wstring& title) { - auto const iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) - iwd->widget_notifier->caption(to_nstring(title)); + if (is_window(wd)) + wd->widget_notifier->caption(to_nstring(title)); } std::string window_caption(window wd) { - auto const iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) - return to_utf8(iwd->widget_notifier->caption()); + if (is_window(wd)) + return to_utf8(wd->widget_notifier->caption()); return{}; } void window_cursor(window wd, cursor cur) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) + if(is_window(wd)) { - iwd->predef_cursor = cur; - restrict::bedrock.update_cursor(iwd); + wd->predef_cursor = cur; + restrict::bedrock.update_cursor(wd); } } cursor window_cursor(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) - return iwd->predef_cursor; + if(is_window(wd)) + return wd->predef_cursor; return cursor::arrow; } bool is_focus_ready(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) - return (iwd->root_widget->other.attribute.root->focus == iwd); + if(is_window(wd)) + return (wd->root_widget->other.attribute.root->focus == wd); return false; } void activate_window(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - if(iwd->flags.take_active) - interface_type::activate_window(iwd->root); + if(wd->flags.take_active) + interface_type::activate_window(wd->root); } } window focus_window() { internal_scope_guard lock; - return reinterpret_cast(restrict::bedrock.focus()); + return restrict::bedrock.focus(); } void focus_window(window wd) { - restrict::wd_manager().set_focus(reinterpret_cast(wd), false, arg_focus::reason::general); - restrict::wd_manager().update(reinterpret_cast(wd), false, false); + restrict::wd_manager().set_focus(wd, false, arg_focus::reason::general); + restrict::wd_manager().update(wd, false, false); } window capture_window() { - return reinterpret_cast(restrict::wd_manager().capture_window()); + return restrict::wd_manager().capture_window(); } void set_capture(window wd, bool ignore_children) { - restrict::wd_manager().capture_window(reinterpret_cast(wd), true, ignore_children); + restrict::wd_manager().capture_window(wd, true, ignore_children); } void release_capture(window wd) { //The 3rd parameter is useless when the 2nd parameter is false. - restrict::wd_manager().capture_window(reinterpret_cast(wd), false, false); + restrict::wd_manager().capture_window(wd, false, false); } void modal_window(window wd) { - auto const iwd = reinterpret_cast(wd); - internal_scope_guard isg; + internal_scope_guard lock; - if (!restrict::wd_manager().available(iwd)) + if (empty_window(wd)) return; - if ((iwd->other.category == category::flags::root) && (iwd->flags.modal == false)) + if ((wd->other.category == category::flags::root) && (wd->flags.modal == false)) { - iwd->flags.modal = true; + wd->flags.modal = true; #if defined(NANA_X11) - interface_type::set_modal(iwd->root); + interface_type::set_modal(wd->root); #endif - restrict::wd_manager().show(iwd, true); + restrict::wd_manager().show(wd, true); } else return; @@ -1070,29 +1018,28 @@ namespace API void wait_for(window wd) { internal_scope_guard lock; - if (restrict::wd_manager().available(reinterpret_cast(wd))) + if (is_window(wd)) restrict::bedrock.pump_event(wd, false); } color fgcolor(window wd) { internal_scope_guard lock; - if (restrict::wd_manager().available(reinterpret_cast(wd))) - return reinterpret_cast(wd)->annex.scheme->foreground.get_color(); + if (is_window(wd)) + return wd->annex.scheme->foreground.get_color(); return{}; } color fgcolor(window wd, const color& clr) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - auto prev = iwd->annex.scheme->foreground.get_color(); + auto prev = wd->annex.scheme->foreground.get_color(); if (prev != clr) { - iwd->annex.scheme->foreground = clr; - restrict::wd_manager().update(iwd, true, false); + wd->annex.scheme->foreground = clr; + refresh_window(wd); } return prev; } @@ -1102,27 +1049,26 @@ namespace API color bgcolor(window wd) { internal_scope_guard lock; - if (restrict::wd_manager().available(reinterpret_cast(wd))) - return reinterpret_cast(wd)->annex.scheme->background.get_color(); + if (is_window(wd)) + return wd->annex.scheme->background.get_color(); return{}; } color bgcolor(window wd, const color& clr) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - auto prev = iwd->annex.scheme->background.get_color(); + auto prev = wd->annex.scheme->background.get_color(); if (prev != clr) { - iwd->annex.scheme->background = clr; + wd->annex.scheme->background = clr; //If the bground mode of this window is basic, it should remake the background - if (iwd->effect.bground && iwd->effect.bground_fade_rate < 0.01) // fade rate < 0.01 means it is basic mode - iwd->flags.make_bground_declared = true; + if (wd->effect.bground && wd->effect.bground_fade_rate < 0.01) // fade rate < 0.01 means it is basic mode + wd->flags.make_bground_declared = true; - restrict::wd_manager().update(iwd, true, false); + refresh_window(wd); } return prev; } @@ -1132,22 +1078,21 @@ namespace API color activated_color(window wd) { internal_scope_guard lock; - if (restrict::wd_manager().available(reinterpret_cast(wd))) - return reinterpret_cast(wd)->annex.scheme->activated.get_color(); + if (is_window(wd)) + return wd->annex.scheme->activated.get_color(); return{}; } color activated_color(window wd, const color& clr) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - auto prev = iwd->annex.scheme->activated.get_color(); + auto prev = wd->annex.scheme->activated.get_color(); if (prev != clr) { - iwd->annex.scheme->activated = clr; - restrict::wd_manager().update(iwd, true, false); + wd->annex.scheme->activated = clr; + refresh_window(wd); } return prev; } @@ -1236,7 +1181,7 @@ namespace API private: caret_interface* _m_caret() const { - if (restrict::wd_manager().available(window_) && window_->annex.caret_ptr) + if (is_window(window_) && window_->annex.caret_ptr) return window_->annex.caret_ptr; if (throw_) @@ -1251,27 +1196,25 @@ namespace API void create_caret(window wd, const size& caret_size) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd) && !(iwd->annex.caret_ptr)) - iwd->annex.caret_ptr = new ::nana::detail::caret(iwd, caret_size); + if (is_window(wd) && !(wd->annex.caret_ptr)) + wd->annex.caret_ptr = new ::nana::detail::caret(wd, caret_size); } void destroy_caret(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) + if(is_window(wd)) { - auto p = iwd->annex.caret_ptr; - iwd->annex.caret_ptr = nullptr; + auto p = wd->annex.caret_ptr; + wd->annex.caret_ptr = nullptr; delete p; } } std::unique_ptr open_caret(window window_handle, bool disable_throw) { - auto p = new caret_proxy{ reinterpret_cast(window_handle) }; + auto p = new caret_proxy{ window_handle }; if (disable_throw) p->disable_throw(); @@ -1280,72 +1223,63 @@ namespace API void tabstop(window wd) { - restrict::wd_manager().enable_tabstop(reinterpret_cast(wd)); + restrict::wd_manager().enable_tabstop(wd); } //eat_tabstop //@brief: set a eating tab window that it processes a pressing of tab itself void eat_tabstop(window wd, bool eat) { - if(wd) + internal_scope_guard lock; + if(is_window(wd)) { - auto iwd = reinterpret_cast(wd); - internal_scope_guard isg; - if(restrict::wd_manager().available(iwd)) - { - if(eat) - iwd->flags.tab |= ::nana::detail::tab_type::eating; - else - iwd->flags.tab &= ~::nana::detail::tab_type::eating; - } + if(eat) + wd->flags.tab |= ::nana::detail::tab_type::eating; + else + wd->flags.tab &= ~::nana::detail::tab_type::eating; } } window move_tabstop(window wd, bool next) { - basic_window* ts_wd = restrict::wd_manager().tabstop(reinterpret_cast(wd), next); - restrict::wd_manager().set_focus(ts_wd, false, arg_focus::reason::general); - restrict::wd_manager().update(ts_wd, false, false); - return reinterpret_cast(ts_wd); + auto prev_wd = restrict::wd_manager().tabstop(wd, next); + restrict::wd_manager().set_focus(prev_wd, false, arg_focus::reason::general); + restrict::wd_manager().update(prev_wd, false, false); + + return prev_wd; } void take_active(window wd, bool active, window take_if_active_false) { - auto const iwd = reinterpret_cast(wd); - auto take_if_false = reinterpret_cast(take_if_active_false); - internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - if (active || (take_if_false && (restrict::wd_manager().available(take_if_false) == false))) - take_if_false = 0; + if (active || (take_if_active_false && empty_window(take_if_active_false))) + take_if_active_false = nullptr; - iwd->flags.take_active = active; - iwd->other.active_window = take_if_false; + wd->flags.take_active = active; + wd->other.active_window = take_if_active_false; } } bool window_graphics(window wd, nana::paint::graphics& graph) { - auto iwd = reinterpret_cast(wd); - internal_scope_guard lock; - if (!restrict::wd_manager().available(iwd)) + if (empty_window(wd)) return false; - graph.make(iwd->drawer.graphics.size()); - graph.bitblt(0, 0, iwd->drawer.graphics); - nana::detail::window_layout::paste_children_to_graphics(iwd, graph); + graph.make(wd->drawer.graphics.size()); + graph.bitblt(0, 0, wd->drawer.graphics); + nana::detail::window_layout::paste_children_to_graphics(wd, graph); return true; } bool root_graphics(window wd, nana::paint::graphics& graph) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) + if(is_window(wd)) { - graph = *(iwd->root_graph); + graph = *(wd->root_graph); return true; } return false; @@ -1353,51 +1287,47 @@ namespace API bool get_visual_rectangle(window wd, nana::rectangle& r) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) - return nana::detail::window_layout::read_visual_rectangle(iwd, r); + if (is_window(wd)) + return nana::detail::window_layout::read_visual_rectangle(wd, r); return false; } void typeface(window wd, const nana::paint::font& font) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) + if(is_window(wd)) { - iwd->drawer.graphics.typeface(font); - iwd->drawer.typeface_changed(); - restrict::wd_manager().update(iwd, true, false); + wd->drawer.graphics.typeface(font); + wd->drawer.typeface_changed(); + refresh_window(wd); } } nana::paint::font typeface(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) - return iwd->drawer.graphics.typeface(); + if(is_window(wd)) + return wd->drawer.graphics.typeface(); return{}; } bool calc_screen_point(window wd, nana::point& pos) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) + if(is_window(wd)) { - pos += iwd->pos_root; - return interface_type::calc_screen_point(iwd->root, pos); + pos += wd->pos_root; + return interface_type::calc_screen_point(wd->root, pos); } return false; } bool calc_window_point(window wd, nana::point& pos) { - return restrict::wd_manager().calc_window_point(reinterpret_cast(wd), pos); + return restrict::wd_manager().calc_window_point(wd, pos); } window find_window(const nana::point& pos) @@ -1407,65 +1337,59 @@ namespace API { ::nana::point clipos{pos}; interface_type::calc_window_point(wd, clipos); - return reinterpret_cast( - restrict::wd_manager().find_window(wd, clipos, true)); + return restrict::wd_manager().find_window(wd, clipos, true); } return nullptr; } bool is_window_zoomed(window wd, bool ask_for_max) { - auto const iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - if (iwd->other.category == nana::category::flags::root) - return interface_type::is_window_zoomed(iwd->root, ask_for_max); + if (wd->other.category == nana::category::flags::root) + return interface_type::is_window_zoomed(wd->root, ask_for_max); } return false; } void widget_borderless(window wd, bool enabled) { - auto const iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - if ((category::flags::widget == iwd->other.category) && (iwd->flags.borderless != enabled)) + if ((category::flags::widget == wd->other.category) && (wd->flags.borderless != enabled)) { - iwd->flags.borderless = enabled; - restrict::wd_manager().update(iwd, true, false); + wd->flags.borderless = enabled; + refresh_window(wd); } } } bool widget_borderless(window wd) { - auto const iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) - return iwd->flags.borderless; + if (is_window(wd)) + return wd->flags.borderless; return false; } nana::mouse_action mouse_action(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) - return iwd->flags.action; + if(is_window(wd)) + return wd->flags.action; return nana::mouse_action::normal; } nana::element_state element_state(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) + if(is_window(wd)) { - const bool is_focused = (iwd->root_widget->other.attribute.root->focus == iwd); - switch(iwd->flags.action) + const bool is_focused = (wd->root_widget->other.attribute.root->focus == wd); + switch(wd->flags.action) { case nana::mouse_action::normal: case nana::mouse_action::normal_captured: @@ -1475,7 +1399,7 @@ namespace API case nana::mouse_action::pressed: return nana::element_state::pressed; default: - if(false == iwd->flags.enabled) + if(false == wd->flags.enabled) return nana::element_state::disabled; } } @@ -1484,12 +1408,11 @@ namespace API bool ignore_mouse_focus(window wd, bool ignore) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd)) + if (is_window(wd)) { - auto state = iwd->flags.ignore_mouse_focus; - iwd->flags.ignore_mouse_focus = ignore; + auto state = wd->flags.ignore_mouse_focus; + wd->flags.ignore_mouse_focus = ignore; return state; } return false; @@ -1497,24 +1420,22 @@ namespace API bool ignore_mouse_focus(window wd) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - return (restrict::wd_manager().available(iwd) ? iwd->flags.ignore_mouse_focus : false); + return (is_window(wd) ? wd->flags.ignore_mouse_focus : false); } void at_safe_place(window wd, std::function fn) { - restrict::wd_manager().set_safe_place(reinterpret_cast(wd), std::move(fn)); + restrict::wd_manager().set_safe_place(wd, std::move(fn)); } std::optional> content_extent(window wd, unsigned limited_px, bool limit_width) { - auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if (restrict::wd_manager().available(iwd) && iwd->annex.content_measurer) + if (is_window(wd) && wd->annex.content_measurer) { - paint::graphics* graph = &iwd->drawer.graphics; + paint::graphics* graph = &wd->drawer.graphics; paint::graphics temp_graph; if (graph->empty()) { @@ -1523,9 +1444,9 @@ namespace API graph = &temp_graph; } - auto extent = iwd->annex.content_measurer->measure(*graph, limited_px, limit_width); + auto extent = wd->annex.content_measurer->measure(*graph, limited_px, limit_width); if (extent) - return std::make_pair(extent.value(), extent.value() + iwd->annex.content_measurer->extension()); + return std::make_pair(extent.value(), extent.value() + wd->annex.content_measurer->extension()); } return{}; @@ -1538,11 +1459,9 @@ namespace API dragdrop_status window_dragdrop_status(::nana::window wd) { - auto real_wd = reinterpret_cast(wd); internal_scope_guard lock; - - if (restrict::wd_manager().available(real_wd)) - return real_wd->other.dnd_state; + if (is_window(wd)) + return wd->other.dnd_state; return dragdrop_status::not_ready; } diff --git a/source/gui/state_cursor.cpp b/source/gui/state_cursor.cpp index 5644ed83..817b6dec 100644 --- a/source/gui/state_cursor.cpp +++ b/source/gui/state_cursor.cpp @@ -9,18 +9,18 @@ * * @file: nana/gui/state_cursor.cpp */ + +#include "detail/basic_window.hpp" #include #include -#include #include namespace nana { - state_cursor::state_cursor(window handle, cursor cur) - : handle_(handle) + state_cursor::state_cursor(window wd, cursor cur) + : handle_(wd) { auto & brock = detail::bedrock::instance(); - auto wd = reinterpret_cast(handle); if (brock.wd_manager().available(wd)) brock.define_state_cursor(wd, cur, nullptr); else @@ -39,10 +39,9 @@ namespace nana { if (handle_) { + nana::internal_scope_guard lock; auto & brock = detail::bedrock::instance(); - auto wd = reinterpret_cast(handle_); - if (brock.wd_manager().available(wd)) - brock.undefine_state_cursor(wd, nullptr); + brock.undefine_state_cursor(handle_, nullptr); } handle_ = rhs.handle_; rhs.handle_ = nullptr; @@ -54,10 +53,9 @@ namespace nana { if (handle_) { + nana::internal_scope_guard lock; auto & brock = detail::bedrock::instance(); - auto wd = reinterpret_cast(handle_); - if (brock.wd_manager().available(wd)) - brock.undefine_state_cursor(wd, nullptr); + brock.undefine_state_cursor(handle_, nullptr); } } } \ No newline at end of file diff --git a/source/gui/timer.cpp b/source/gui/timer.cpp index 52981a8e..8374a5fb 100644 --- a/source/gui/timer.cpp +++ b/source/gui/timer.cpp @@ -28,24 +28,26 @@ #if defined(NANA_WINDOWS) #include #elif defined(NANA_POSIX) -#include "../detail/platform_spec_selector.hpp" +#include "../detail/posix/platform_spec.hpp" #include #endif namespace nana { - class timer_core; + namespace detail + { + class timer_core; + } + #if defined(NANA_WINDOWS) typedef UINT_PTR timer_identifier; #else - typedef timer_core* timer_identifier; + typedef const detail::timer_core* timer_identifier; #endif class timer_driver { - typedef std::lock_guard lock_guard; - - friend class timer_core; + friend class detail::timer_core; timer_driver() = default; public: @@ -56,7 +58,7 @@ namespace nana } template - timer_core* create(unsigned ms, Factory && factory) + detail::timer_core* create(unsigned ms, Factory && factory) { #if defined(NANA_WINDOWS) auto tmid = ::SetTimer(nullptr, 0, ms, &timer_driver::_m_timer_proc); @@ -68,9 +70,9 @@ namespace nana #else auto p = factory(); auto tmid = p; - ::nana::detail::platform_spec::instance().set_timer(reinterpret_cast(tmid), ms, &timer_driver::_m_timer_proc); + ::nana::detail::platform_spec::instance().set_timer(tmid, ms, &timer_driver::_m_timer_proc); #endif - lock_guard lock(mutex_); + ::nana::internal_scope_guard lock; timer_table_[tmid].reset(p); return p; } @@ -80,16 +82,17 @@ namespace nana return nullptr; } - void destroy(timer_identifier tid) + void destroy(timer_identifier handle) { - lock_guard lock(mutex_); - auto i = timer_table_.find(tid); + ::nana::internal_scope_guard lock; + + auto i = timer_table_.find(handle); if (i != timer_table_.end()) { #if defined(NANA_WINDOWS) - ::KillTimer(nullptr, tid); + ::KillTimer(nullptr, handle); #else - ::nana::detail::platform_spec::instance().kill_timer(reinterpret_cast(tid)); + ::nana::detail::platform_spec::instance().kill_timer(handle); #endif timer_table_.erase(i); } @@ -98,23 +101,26 @@ namespace nana #if defined(NANA_WINDOWS) static void __stdcall _m_timer_proc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime); #else - static void _m_timer_proc(std::size_t id); + static void _m_timer_proc(timer_identifier id); #endif private: - std::recursive_mutex mutex_; - std::map> timer_table_; + std::map> timer_table_; }; - class timer_core + class detail::timer_core { public: #if defined(NANA_WINDOWS) - timer_core(timer_identifier tmid, basic_event& evt_elapse) - : timer_(tmid), evt_elapse_(evt_elapse) + timer_core(timer* sender, timer_identifier tmid, basic_event& evt_elapse): + sender_(sender), + timer_(tmid), + evt_elapse_(evt_elapse) {} #else - timer_core(basic_event& evt_elapse) - : timer_(this), evt_elapse_(evt_elapse) + timer_core(timer* sender, basic_event& evt_elapse): + sender_(sender), + timer_(this), + evt_elapse_(evt_elapse) {} #endif @@ -128,45 +134,44 @@ namespace nana #if defined(NANA_WINDOWS) ::SetTimer(nullptr, timer_, ms, &timer_driver::_m_timer_proc); #else - ::nana::detail::platform_spec::instance().set_timer(reinterpret_cast(timer_), ms, &timer_driver::_m_timer_proc); + ::nana::detail::platform_spec::instance().set_timer(timer_, ms, &timer_driver::_m_timer_proc); #endif } - void emit(const arg_elapse& arg) + void emit() { + arg_elapse arg; + arg.sender = sender_; evt_elapse_.emit(arg, nullptr); } private: + timer * const sender_; const timer_identifier timer_; nana::basic_event & evt_elapse_; }; //end class timer_core + #if defined(NANA_WINDOWS) - void __stdcall timer_driver::_m_timer_proc(HWND /*hwnd*/, UINT /*uMsg*/, UINT_PTR id, DWORD /*dwTime*/) + void __stdcall timer_driver::_m_timer_proc(HWND /*hwnd*/, UINT /*uMsg*/, UINT_PTR handle, DWORD /*dwTime*/) #else - void timer_driver::_m_timer_proc(std::size_t id) + void timer_driver::_m_timer_proc(timer_identifier handle) #endif { - auto & driver = instance(); + auto & time_tbl = instance().timer_table_; - lock_guard lock(driver.mutex_); -#if defined(NANA_WINDOWS) - auto i = driver.timer_table_.find(id); -#else - auto i = driver.timer_table_.find(reinterpret_cast(id)); -#endif - if (i == driver.timer_table_.end()) + ::nana::internal_scope_guard lock; + + auto i = time_tbl.find(handle); + if (i == time_tbl.end()) return; - arg_elapse arg; - arg.id = id; - i->second->emit(arg); + i->second->emit(); } struct timer::implement { - unsigned interval = 1000; //Defaultly 1 second. - timer_core * tm_core = nullptr; + unsigned interval{ 1000 }; //1 second in default + detail::timer_core * tm_core{ nullptr }; }; //class timer @@ -183,8 +188,7 @@ namespace nana timer::~timer() { - if (impl_->tm_core) - timer_driver::instance().destroy(impl_->tm_core->id()); + stop(); delete impl_; } @@ -201,12 +205,12 @@ namespace nana #if defined(NANA_WINDOWS) impl_->tm_core = timer_driver::instance().create(impl_->interval, [this](timer_identifier id) { - return new timer_core(id, elapse_); + return new detail::timer_core(this, id, elapse_); }); #else impl_->tm_core = timer_driver::instance().create(impl_->interval, [this] { - return new timer_core(elapse_); + return new detail::timer_core(this, elapse_); }); #endif } diff --git a/source/gui/widgets/button.cpp b/source/gui/widgets/button.cpp index 96ff7c25..ecc09817 100644 --- a/source/gui/widgets/button.cpp +++ b/source/gui/widgets/button.cpp @@ -261,7 +261,7 @@ namespace nana{ namespace drawerbase graph.palette(true, text_color); if (attr_.omitted) - tr.render(pos, txtptr, txtlen, omitted_pixels, true); + tr.render(pos, txtptr, txtlen, omitted_pixels, paint::text_renderer::mode::truncate_with_ellipsis); else #ifdef _nana_std_has_string_view graph.bidi_string(pos, { txtptr, txtlen }); @@ -276,9 +276,9 @@ namespace nana{ namespace drawerbase graph.palette(true, color{ colors::white }); if(attr_.omitted) { - tr.render(point{ pos.x + 1, pos.y + 1 }, txtptr, txtlen, omitted_pixels, true); + tr.render(point{ pos.x + 1, pos.y + 1 }, txtptr, txtlen, omitted_pixels, paint::text_renderer::mode::truncate_with_ellipsis); graph.palette(true, color{ colors::gray }); - tr.render(pos, txtptr, txtlen, omitted_pixels, true); + tr.render(pos, txtptr, txtlen, omitted_pixels, paint::text_renderer::mode::truncate_with_ellipsis); } else { diff --git a/source/gui/widgets/categorize.cpp b/source/gui/widgets/categorize.cpp index fc88b2cc..596d7cd3 100644 --- a/source/gui/widgets/categorize.cpp +++ b/source/gui/widgets/categorize.cpp @@ -1,7 +1,7 @@ /** * A Categorize Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -10,7 +10,7 @@ * @file nana/gui/widgets/categorize.cpp */ -#include +#include #include #include #include diff --git a/source/gui/widgets/checkbox.cpp b/source/gui/widgets/checkbox.cpp index fc08fcac..4741d5b2 100644 --- a/source/gui/widgets/checkbox.cpp +++ b/source/gui/widgets/checkbox.cpp @@ -70,13 +70,13 @@ namespace nana{ namespace drawerbase if (!wdg->enabled()) { graph.palette(true, colors::white); - tr.render({ 17 + interval, 2 }, title.c_str(), title.length(), pixels); + tr.render({ 17 + interval, 2 }, title.c_str(), title.length(), pixels, paint::text_renderer::mode::word_wrap); graph.palette(true, static_cast(0x808080)); } else graph.palette(true, wdg->fgcolor()); - tr.render({ 16 + interval, 1 }, title.c_str(), title.length(), pixels); + tr.render({ 16 + interval, 1 }, title.c_str(), title.length(), pixels, paint::text_renderer::mode::word_wrap); } //draw crook diff --git a/source/gui/widgets/combox.cpp b/source/gui/widgets/combox.cpp index c5ef5f85..816d4ee9 100644 --- a/source/gui/widgets/combox.cpp +++ b/source/gui/widgets/combox.cpp @@ -10,9 +10,9 @@ * @file: nana/gui/widgets/combox.cpp */ -#include -#include +#include #include +#include #include #include #include diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 8ef8a453..460e28f4 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -15,7 +15,7 @@ * Benjamin Navarro(pr#81) * besh81(pr#130) * dankan1890(pr#158) - * ErrorFlynn(pr#418) + * ErrorFlynn(pr#418,pr#448,pr#454) * */ #include @@ -2059,6 +2059,11 @@ namespace nana }; } + unsigned suspension_width() const + { + return (graph ? graph->text_extent_size(L"...").width : 0); + } + bool cs_status(index_pair abs_pos, bool for_selection) const { if (abs_pos.is_category()) @@ -3352,7 +3357,7 @@ namespace nana else { //Default scheme - new_w = (std::max)(new_w, essence_->scheme_ptr->suspension_width + essence_->scheme_ptr->min_column_width); + new_w = (std::max)(new_w, essence_->suspension_width() + essence_->scheme_ptr->min_column_width); } if(col.width_px != new_w) @@ -3997,6 +4002,7 @@ namespace nana if (draw_column) { + //Draw item text paint::aligner text_aligner{*graph, col.alignment}; unsigned text_margin_right = 0; @@ -4142,7 +4148,6 @@ namespace nana if (graph.text_metrics(as, ds, il)) essence_->text_height = as + ds; - essence_->scheme_ptr->suspension_width = graph.text_extent_size("...").width; essence_->calc_content_size(true); } @@ -4337,7 +4342,7 @@ namespace nana else { auto selected = lister.pick_items(true); - if (selected.cend() != std::find(selected.cbegin(), selected.cend(), item_pos)) + if (selected.cend() != std::find(selected.cbegin(), selected.cend(), abs_item_pos)) { //If the current selected one has been selected before selecting, remains the selection states for all //selected items. But these items will be unselected when the mouse is released. @@ -6114,6 +6119,12 @@ namespace nana _m_ess().pred_msup_deselect = std::move(predicate); } + unsigned listbox::suspension_width() const + { + nana::internal_scope_guard lock; + return _m_ess().suspension_width(); + } + drawerbase::listbox::essence & listbox::_m_ess() const { return get_drawer_trigger().ess(); diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index e3b181e4..078844aa 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -13,12 +13,13 @@ * dankan1890(pr#158) */ +#include +#include #include #include #include #include -#include #include #include //introduces tolower #include @@ -147,7 +148,7 @@ namespace nana nana::paint::text_renderer tr(graph); auto wstr = to_wstring(text); - tr.render(pos, wstr.c_str(), wstr.length(), text_pixels, true); + tr.render(pos, wstr.c_str(), wstr.length(), text_pixels, paint::text_renderer::mode::truncate_with_ellipsis); } void sub_arrow(graph_reference graph, const nana::point& pos, unsigned pixels, const attr&) diff --git a/source/gui/widgets/tabbar.cpp b/source/gui/widgets/tabbar.cpp index 4cf17919..6a79c648 100644 --- a/source/gui/widgets/tabbar.cpp +++ b/source/gui/widgets/tabbar.cpp @@ -1050,7 +1050,7 @@ namespace nana std::wstring wtext = to_wstring(item.text); tr.render({ m.r.x + 24, m.r.y + static_cast(m.r.height - ts.height) / 2 }, - wtext.c_str(), wtext.length(), basis_.item_pixels - 24 - 18, true); + wtext.c_str(), wtext.length(), basis_.item_pixels - 24 - 18, paint::text_renderer::mode::truncate_with_ellipsis); } } diff --git a/source/gui/wvl.cpp b/source/gui/wvl.cpp index 7497d3c4..103355b1 100644 --- a/source/gui/wvl.cpp +++ b/source/gui/wvl.cpp @@ -1,6 +1,6 @@ /* * Nana GUI Library Definition - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -11,7 +11,8 @@ * the file contains the files required for running of Nana.GUI */ -#include +#include +#include #include #include #include @@ -29,7 +30,7 @@ namespace nana { void form_loader_private::insert_form(::nana::widget* p) { - bedrock::instance().manage_form_loader(reinterpret_cast(p->handle()), true); + bedrock::instance().manage_form_loader(p->handle(), true); } } diff --git a/source/paint/detail/native_paint_interface.cpp b/source/paint/detail/native_paint_interface.cpp index db01ea30..3d41b9a7 100644 --- a/source/paint/detail/native_paint_interface.cpp +++ b/source/paint/detail/native_paint_interface.cpp @@ -260,24 +260,8 @@ namespace detail #if defined(NANA_WINDOWS) ::TextOut(dw->context, pos.x, pos.y, str, static_cast(len)); #elif defined(NANA_X11) - auto disp = ::nana::detail::platform_spec::instance().open_display(); #if defined(NANA_USE_XFT) - - #if 0 - auto fs = reinterpret_cast(dw->font->native_handle()); - - //Fixed missing array declaration by dareg - std::unique_ptr glyphs_ptr(new FT_UInt[len]); - auto glyphs = glyphs_ptr.get(); - const auto endstr = str + len; - for(auto chr = str; chr != endstr; ++chr) - { - (*glyphs++) = XftCharIndex(disp, fs, *chr); - } - XftDrawGlyphs(dw->xftdraw, &(dw->xft_fgcolor), fs, pos.x, pos.y + fs->ascent, glyphs_ptr.get(), len); - #else nana_xft_draw_string(dw->xftdraw, &(dw->xft_fgcolor), dw->font.get(), pos, str, len); - #endif #else XFontSet fs = reinterpret_cast(dw->font->native_handle()); XFontSetExtents * ext = ::XExtentsOfFontSet(fs); diff --git a/source/paint/graphics.cpp b/source/paint/graphics.cpp index 9a89ba03..c622aa3f 100644 --- a/source/paint/graphics.cpp +++ b/source/paint/graphics.cpp @@ -506,8 +506,8 @@ namespace paint if (!text.empty()) { - unsigned tab_pixels = impl_->handle->string.tab_length * impl_->handle->string.whitespace_pixels; #if defined(NANA_WINDOWS) + unsigned tab_pixels = impl_->handle->string.tab_length * impl_->handle->string.whitespace_pixels; int * dx = new int[text.size()]; SIZE extents; ::GetTextExtentExPoint(impl_->handle->context, text.data(), static_cast(text.size()), 0, 0, dx, &extents); @@ -520,26 +520,7 @@ namespace paint } delete[] dx; #elif defined(NANA_X11) && defined(NANA_USE_XFT) - - #if 0 - auto disp = nana::detail::platform_spec::instance().open_display(); - auto xft = reinterpret_cast(impl_->handle->font->native_handle()); - - XGlyphInfo extents; - for (std::size_t i = 0; i < text.size(); ++i) - { - if (text[i] != '\t') - { - FT_UInt glyphs = ::XftCharIndex(disp, xft, text[i]); - ::XftGlyphExtents(disp, xft, &glyphs, 1, &extents); - pxbuf[i] = extents.xOff; - } - else - pxbuf[i] = tab_pixels; - } - #else return nana_xft_glyph_pixels(impl_->handle->font.get(), text.data(), text.size()); - #endif #endif } return pxbuf; @@ -1108,7 +1089,7 @@ namespace paint ::nana::color graphics::palette(bool for_text) const { if (impl_->handle) - return static_cast(for_text ? impl_->handle->get_text_color() : impl_->handle->get_color()); + return static_cast(for_text ? impl_->handle->fgcolor_rgb : impl_->handle->bgcolor_rgb); return{}; } @@ -1140,7 +1121,7 @@ namespace paint if (impl_->handle) { #if defined(NANA_WINDOWS) - ::SetPixel(impl_->handle->context, x, y, NANA_RGB(impl_->handle->get_color())); + ::SetPixel(impl_->handle->context, x, y, impl_->handle->bgcolor_native); #elif defined(NANA_X11) Display* disp = nana::detail::platform_spec::instance().open_display(); impl_->handle->update_color(); @@ -1336,14 +1317,14 @@ namespace paint #if defined(NANA_WINDOWS) if (pos1 != pos2) { - auto prv_pen = ::SelectObject(impl_->handle->context, ::CreatePen(PS_SOLID, 1, NANA_RGB(impl_->handle->get_color()))); + auto prv_pen = ::SelectObject(impl_->handle->context, ::CreatePen(PS_SOLID, 1, impl_->handle->bgcolor_native)); ::MoveToEx(impl_->handle->context, pos1.x, pos1.y, 0); ::LineTo(impl_->handle->context, pos2.x, pos2.y); ::DeleteObject(::SelectObject(impl_->handle->context, prv_pen)); } - ::SetPixel(impl_->handle->context, pos2.x, pos2.y, NANA_RGB(impl_->handle->get_color())); + ::SetPixel(impl_->handle->context, pos2.x, pos2.y, impl_->handle->bgcolor_native); #elif defined(NANA_X11) Display* disp = nana::detail::platform_spec::instance().open_display(); impl_->handle->update_color(); @@ -1369,7 +1350,7 @@ namespace paint { if (!impl_->handle) return; #if defined(NANA_WINDOWS) - auto prv_pen = ::SelectObject(impl_->handle->context, ::CreatePen(PS_SOLID, 1, NANA_RGB(impl_->handle->get_color()))); + auto prv_pen = ::SelectObject(impl_->handle->context, ::CreatePen(PS_SOLID, 1, impl_->handle->bgcolor_native)); ::LineTo(impl_->handle->context, pos.x, pos.y); @@ -1402,7 +1383,7 @@ namespace paint { #if defined(NANA_WINDOWS) - auto brush = ::CreateSolidBrush(NANA_RGB(impl_->handle->get_color())); + auto brush = ::CreateSolidBrush(impl_->handle->bgcolor_native); ::RECT native_r = { r.x, r.y, r.right(), r.bottom()}; @@ -1527,6 +1508,7 @@ namespace paint if (impl_->changed == false) impl_->changed = true; } +#define NANA_WINDOWS_RGB(a) (((DWORD)(a) & 0xFF)<<16) | ((DWORD)(a) & 0xFF00) | (((DWORD)(a) & 0xFF0000) >> 16 ) void graphics::round_rectangle(const ::nana::rectangle& r, unsigned radius_x, unsigned radius_y, const color& clr, bool solid, const color& solid_clr) { if (impl_->handle) @@ -1536,8 +1518,8 @@ namespace paint if (solid) { - auto prv_pen = ::SelectObject(impl_->handle->context, ::CreatePen(PS_SOLID, 1, NANA_RGB(impl_->handle->get_color()))); - auto prv_brush = ::SelectObject(impl_->handle->context, ::CreateSolidBrush(NANA_RGB(solid_clr.px_color().value))); + auto prv_pen = ::SelectObject(impl_->handle->context, ::CreatePen(PS_SOLID, 1, impl_->handle->bgcolor_native)); + auto prv_brush = ::SelectObject(impl_->handle->context, ::CreateSolidBrush(NANA_WINDOWS_RGB(solid_clr.px_color().value))); ::RoundRect(impl_->handle->context, r.x, r.y, r.right(), r.bottom(), static_cast(radius_x * 2), static_cast(radius_y * 2)); @@ -1546,7 +1528,7 @@ namespace paint } else { - auto brush = ::CreateSolidBrush(NANA_RGB(impl_->handle->get_color())); + auto brush = ::CreateSolidBrush(impl_->handle->bgcolor_native); auto region = ::CreateRoundRectRgn(r.x, r.y, r.x + static_cast(r.width) + 1, r.y + static_cast(r.height) + 1, static_cast(radius_x + 1), static_cast(radius_y + 1)); diff --git a/source/paint/text_renderer.cpp b/source/paint/text_renderer.cpp index 6f5654dd..19b305a9 100644 --- a/source/paint/text_renderer.cpp +++ b/source/paint/text_renderer.cpp @@ -16,7 +16,7 @@ namespace nana auto const end = str + len; for(auto i = str; i != end; ++i) { - if(*i == '\n') + if('\n' == *i) { top += static_cast(f(top, str, i - str)); str = i + 1; @@ -26,212 +26,180 @@ namespace nana f(top, str, end - str); } - struct draw_string - { - drawable_type dw; - const int x, endpos; - align text_align; - draw_string(drawable_type dw, int x, int endpos, align ta) - : dw(dw), x(x), endpos(endpos), text_align(ta) - {} + class string_drawer + { + public: + string_drawer(graphics& graph, int left, int right, align ta, bool use_ellipsis): + graph_(graph), + left_(left), + right_(right), + text_align_(ta) + { + if (use_ellipsis) + { +#ifdef _nana_std_has_string_view + ellipsis_px_ = graph.text_extent_size(std::string_view{ "...", 3 }).width; +#else + ellipsis_px_ = graph.text_extent_size("...", 3).width; +#endif + } + } + unsigned operator()(const int top, const wchar_t * buf, std::size_t bufsize) { + auto const drawable = graph_.handle(); auto const reordered = unicode_reorder(buf, bufsize); - if (reordered.empty()) - return 0; + + unsigned return_max_height = 0; + unsigned string_px = 0; + std::vector word_metrics; + for (auto & ent : reordered) + { + auto word_sz = detail::text_extent_size(drawable, ent.begin, ent.end - ent.begin); + word_metrics.push_back(word_sz); - nana::point pos{ x, top }; - unsigned pixels = 0; + string_px += word_sz.width; + if (word_sz.height > return_max_height) + return_max_height = word_sz.height; + } - switch(text_align) + auto text_align = text_align_; + // Checks if ellipsis is enabled and the total pixels of string is larger than the space. + if (ellipsis_px_ && (static_cast(string_px) > right_ - left_)) + { + //The string should be drawn from left most point no matter what text align is. + text_align = align::left; + } + + nana::point pos{ left_, top }; + + auto wdm = word_metrics.data(); + switch (text_align) { case align::left: - for(auto & ent : reordered) + for (auto & ent : reordered) { - std::size_t len = ent.end - ent.begin; - nana::size ts = detail::text_extent_size(dw, ent.begin, len); + if (pos.x + static_cast(wdm->width) > 0) + { + if (pos.x + static_cast(wdm->width) <= right_ - static_cast(ellipsis_px_)) + { + //This word can be fully painted. + detail::draw_string(drawable, pos, ent.begin, ent.end - ent.begin); + } + else + { + //This word is painted partially. Firstly, paints the word on a dummy graphics buffer. - if(ts.height > pixels) pixels = ts.height; - - if(pos.x + static_cast(ts.width) > 0) - detail::draw_string(dw, pos, ent.begin, len); + nana::rectangle r{ nana::size{ static_cast(right_ - ellipsis_px_) - pos.x, wdm->height } }; - pos.x += static_cast(ts.width); - if(pos.x >= endpos) + nana::paint::graphics dummy({ r.width, r.height }); + dummy.typeface(graph_.typeface()); + + dummy.bitblt(r, graph_, pos); + +#ifdef _nana_std_has_string_view + dummy.string({}, { ent.begin, static_cast(ent.end - ent.begin) }, graph_.palette(true)); +#else + dummy.palette(true, graph_.palette(true)); + dummy.string({}, ent.begin, ent.end - ent.begin); +#endif + r.x = pos.x; + r.y = top; + graph_.bitblt(r, dummy); + if (ellipsis_px_) + detail::draw_string(drawable, point{ right_ - static_cast(ellipsis_px_), top }, L"...", 3); + break; + } + } + + pos.x += static_cast(wdm->width); + if (pos.x > right_ - static_cast(ellipsis_px_)) break; + + ++wdm; } break; case align::center: + pos.x = (right_ - left_ - string_px) / 2; + for (auto & ent : reordered) { - unsigned lenpx = 0; - std::unique_ptr entity_pxs(new unsigned[reordered.size()]); - - auto ent_px = entity_pxs.get(); - - for(auto & ent : reordered) - { - auto ts = detail::text_extent_size(dw, ent.begin, ent.end - ent.begin); - if(ts.height > pixels) pixels = ts.height; - lenpx += ts.width; - *ent_px++ = ts.width; - } - - pos.x += (endpos - pos.x - static_cast(lenpx))/2; - ent_px = entity_pxs.get(); - - for(auto & ent : reordered) - { - if (pos.x + static_cast(*ent_px) > 0) - detail::draw_string(dw, pos, ent.begin, ent.end - ent.begin); - - pos.x += static_cast(*ent_px++); - - if(pos.x >= endpos) - break; - } + detail::draw_string(drawable, pos, ent.begin, ent.end - ent.begin); + pos.x += (wdm++)->width; } break; case align::right: + wdm = word_metrics.data() + word_metrics.size() - 1; + pos.x = right_; + for (auto i = reordered.crbegin(); i != reordered.crend(); ++i) { - int xend = endpos; - std::swap(pos.x, xend); - for(auto i = reordered.crbegin(); i != reordered.crend(); ++i) - { - auto & ent = *i; - std::size_t len = ent.end - ent.begin; - nana::size ts = detail::text_extent_size(dw, ent.begin, len); - if(ts.height > pixels) pixels = ts.height; - - if(pos.x > xend) - { - pos.x -= static_cast(ts.width); - detail::draw_string(dw, pos, i->begin, len); - } - - if(pos.x <= xend || pos.x <= 0) - break; - } + pos.x -= (wdm--)->width; + detail::draw_string(drawable, pos, i->begin, i->end - i->begin); } break; } - return pixels; - } - }; - - struct draw_string_omitted - { - graphics & graph; - int x, endpos; - unsigned omitted_pixels; - - draw_string_omitted(graphics& graph, int x, int endpos, bool omitted) - : graph(graph), x(x), endpos(endpos) - { -#ifdef _nana_std_has_string_view - omitted_pixels = (omitted ? graph.text_extent_size(std::string_view{ "...", 3 }).width : 0); -#else - omitted_pixels = (omitted ? graph.text_extent_size("...", 3).width : 0); -#endif - if (endpos - x > static_cast(omitted_pixels)) - this->endpos -= omitted_pixels; - else - this->endpos = x; - } - - unsigned operator()(const int top, const wchar_t * buf, std::size_t bufsize) - { - drawable_type dw = graph.handle(); - ::nana::point pos{ x, top }; - unsigned pixels = 0; - - auto const reordered = unicode_reorder(buf, bufsize); - - for(auto & i : reordered) - { - std::size_t len = i.end - i.begin; - nana::size ts = detail::text_extent_size(dw, i.begin, len); - if(ts.height > pixels) pixels = ts.height; - - if(pos.x + static_cast(ts.width) <= endpos) - { - detail::draw_string(dw, pos, i.begin, len); - pos.x += static_cast(ts.width); - } - else - { - nana::rectangle r; - r.width = endpos - pos.x; - r.height = ts.height; - - nana::paint::graphics dum_graph({ r.width, r.height }); - - dum_graph.bitblt(r, graph, pos); - -#ifdef _nana_std_has_string_view - dum_graph.string({}, { i.begin, len }, graph.palette(true)); -#else - dum_graph.palette(true, graph.palette(true)); - dum_graph.string({}, i.begin, len); -#endif - - r.x = pos.x; - r.y = top; - graph.bitblt(r, dum_graph); - if(omitted_pixels) - detail::draw_string(dw, point{ endpos, top }, L"...", 3); - break; - } - } - return pixels; + return return_max_height; } + private: + graphics& graph_; + const int left_, right_; //the range of rendering area in x-axis + const align text_align_; + unsigned ellipsis_px_{ 0 }; }; struct draw_string_auto_changing_lines { graphics & graph; - int x, endpos; - align text_align; + const int left, right; + const align text_align; - draw_string_auto_changing_lines(graphics& graph, int x, int endpos, align ta) - : graph(graph), x(x), endpos(endpos), text_align(ta) + draw_string_auto_changing_lines(graphics& graph, int left, int right, align ta): + graph(graph), + left(left), + right(right), + text_align(ta) {} unsigned operator()(const int top, const wchar_t * buf, std::size_t bufsize) { - unsigned pixels = 0; + unsigned return_max_height = 0; - auto const dw = graph.handle(); - unsigned str_w = 0; + auto const drawable = graph.handle(); + unsigned string_px = 0; - std::vector ts_keeper; + std::vector word_metrics; auto const reordered = unicode_reorder(buf, bufsize); for(auto & i : reordered) { - nana::size ts = detail::text_extent_size(dw, i.begin, i.end - i.begin); - if(ts.height > pixels) pixels = ts.height; - ts_keeper.emplace_back(ts); - str_w += ts.width; + auto word_sz = detail::text_extent_size(drawable, i.begin, i.end - i.begin); + + word_metrics.emplace_back(word_sz); + string_px += word_sz.width; + + if (return_max_height < word_sz.height) + return_max_height = word_sz.height; } + const nana::size* wdm = word_metrics.data(); + //Test whether the text needs the new line. - if(x + static_cast(str_w) > endpos) + if(left + static_cast(string_px) > right) { - pixels = 0; - unsigned line_pixels = 0; - nana::point pos{ x, top }; - int orig_top = top; - auto i_ts_keeper = ts_keeper.cbegin(); + unsigned max_height = 0; + + nana::point pos{ left, top }; + const int orig_top = top; + for(auto & i : reordered) { - if(line_pixels < i_ts_keeper->height) - line_pixels = i_ts_keeper->height; + if(max_height < wdm->height) + max_height = wdm->height; - bool beyond_edge = (pos.x + static_cast(i_ts_keeper->width) > endpos); + bool beyond_edge = (pos.x + static_cast(wdm->width) > right); if(beyond_edge) { const std::size_t len = i.end - i.begin; @@ -251,10 +219,10 @@ namespace nana { auto pxbuf = pixel_buf.get(); - idx_splitted = find_splitted(idx_head, len, pos.x, endpos, pxbuf); + idx_splitted = find_splitted(idx_head, len, pos.x, right, pxbuf); if(idx_splitted == len) { - detail::draw_string(dw, pos, i.begin + idx_head, idx_splitted - idx_head); + detail::draw_string(drawable, pos, i.begin + idx_head, idx_splitted - idx_head); for(std::size_t i = idx_head; i < len; ++i) pos.x += static_cast(pxbuf[i]); @@ -264,17 +232,16 @@ namespace nana //Check the word whether it is splittable. if(splittable(i.begin, idx_splitted)) { - detail::draw_string(dw, pos, i.begin + idx_head, idx_splitted - idx_head); + detail::draw_string(drawable, pos, i.begin + idx_head, idx_splitted - idx_head); idx_head = idx_splitted; - pos.x = x; - pos.y += static_cast(line_pixels); - line_pixels = i_ts_keeper->height; + pos.x = left; + pos.y += static_cast(max_height); } else { //Search the splittable character from idx_head to idx_splitted const wchar_t * u = i.begin + idx_splitted; - const wchar_t * head = i.begin + idx_head; + const wchar_t * const head = i.begin + idx_head; for(; head < u; --u) { @@ -284,112 +251,102 @@ namespace nana if(u != head) { - detail::draw_string(dw, pos, head, u - head); + detail::draw_string(drawable, pos, head, u - head); idx_head += u - head; - pos.x = x; - pos.y += static_cast(line_pixels); - line_pixels = i_ts_keeper->height; + pos.x = left; + pos.y += static_cast(max_height); } else { u = i.begin + idx_splitted; - const wchar_t * end = i.begin + len; - for(; u < end; ++u) + for(; u < i.begin + len; ++u) { if(splittable(head, u - head)) break; } std::size_t splen = u - head; - pos.y += static_cast(line_pixels); - pos.x = x; - detail::draw_string(dw, pos, head, splen); - line_pixels = i_ts_keeper->height; + pos.y += static_cast(max_height); + pos.x = left; + detail::draw_string(drawable, pos, head, splen); for(std::size_t k = idx_head; k < idx_head + splen; ++k) pos.x += static_cast(pxbuf[k]); - if (pos.x >= endpos) + if (pos.x >= right) { - pos.x = x; - pos.y += static_cast(line_pixels); + pos.x = left; + pos.y += static_cast(wdm->height); } idx_head += splen; } } + max_height = wdm->height; }while(idx_head < len); } else { - pos.x = x; - pos.y += static_cast(line_pixels); - detail::draw_string(dw, pos, i.begin, 1); - pos.x += static_cast(i_ts_keeper->width); + pos.x = left; + pos.y += static_cast(max_height); + detail::draw_string(drawable, pos, i.begin, 1); + pos.x += static_cast(wdm->width); } - line_pixels = 0; + max_height = 0; } else { - detail::draw_string(dw, pos, i.begin, i.end - i.begin); - pos.x += static_cast(i_ts_keeper->width); + detail::draw_string(drawable, pos, i.begin, i.end - i.begin); + pos.x += static_cast(wdm->width); } - ++i_ts_keeper; + ++wdm; } - pixels = (top - orig_top) + line_pixels; + return_max_height = (top - orig_top) + max_height; } else { + point pos{ left, top }; //The text could be drawn in a line. if((align::left == text_align) || (align::center == text_align)) { - point pos{ x, top }; if(align::center == text_align) - pos.x += (endpos - x - static_cast(str_w)) / 2; - auto i_ts_keeper = ts_keeper.cbegin(); + pos.x += (right - left - static_cast(string_px)) / 2; + for(auto & ent : reordered) { - const nana::size & ts = *i_ts_keeper; + if (pos.x + static_cast(wdm->width) > 0) + detail::draw_string(drawable, pos, ent.begin, ent.end - ent.begin); - if (pos.x + static_cast(ts.width) > 0) - detail::draw_string(dw, pos, ent.begin, ent.end - ent.begin); - - pos.x += static_cast(ts.width); - ++i_ts_keeper; + pos.x += static_cast(wdm->width); + ++wdm; } } else if(align::right == text_align) { - point pos{ endpos, top }; - auto i_ts_keeper = ts_keeper.crbegin(); + pos.x = right; for(auto i = reordered.crbegin(); i != reordered.crend(); ++i) { + if (pos.x < 0) + break; + auto & ent = *i; std::size_t len = ent.end - ent.begin; - const nana::size & ts = *i_ts_keeper; - pos.x -= static_cast(ts.width); - if (pos.x >= 0) - detail::draw_string(dw, pos, ent.begin, len); - ++i_ts_keeper; + pos.x -= static_cast(wdm->width); + detail::draw_string(drawable, pos, ent.begin, len); + ++wdm; } } } - return pixels; + return return_max_height; } static std::size_t find_splitted(std::size_t begin, std::size_t end, int x, int endpos, unsigned * pxbuf) { - unsigned acc_width = 0; - for(std::size_t i = begin; i < end; ++i) + for (std::size_t i = begin; i < end; ++i) { - if(x + static_cast(acc_width + pxbuf[i]) > endpos) - { - if(i == begin) - ++i; - return i; - } - acc_width += pxbuf[i]; + if ((x += static_cast(pxbuf[i])) > endpos) + return (begin == i ? i + 1 : i); } return end; } @@ -399,12 +356,11 @@ namespace nana wchar_t ch = str[index]; if(('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z')) { - wchar_t prch; if(index) { - prch = str[index - 1]; + auto prch = str[index - 1]; if('0' <= ch && ch <= '9') - return !(('0' <= prch && prch <= '9') || (str[index - 1] == '-')); + return !(('0' <= prch && prch <= '9') || (prch == '-')); return (('z' < prch || prch < 'a') && ('Z' < prch || prch < 'A')); } @@ -418,44 +374,53 @@ namespace nana struct extent_auto_changing_lines { graphics & graph; - int x, endpos; + const int left, right; + unsigned extents; - extent_auto_changing_lines(graphics& graph, int x, int endpos) - : graph(graph), x(x), endpos(endpos), extents(0) + extent_auto_changing_lines(graphics& graph, int left, int right): + graph(graph), + left(left), + right(right), + extents(0) {} unsigned operator()(int top, const wchar_t * buf, std::size_t bufsize) { - unsigned pixels = 0; + unsigned return_max_height = 0; - drawable_type dw = graph.handle(); - unsigned str_w = 0; - std::vector ts_keeper; + auto drawable = graph.handle(); + + std::vector word_metrics; + unsigned string_px = 0; auto const reordered = unicode_reorder(buf, bufsize); for(auto & i : reordered) { - nana::size ts = detail::text_extent_size(dw, i.begin, i.end - i.begin); - ts_keeper.emplace_back(ts); - str_w += ts.width; + auto word_sz = detail::text_extent_size(drawable, i.begin, i.end - i.begin); + word_metrics.emplace_back(word_sz); + string_px += word_sz.width; + + if (return_max_height < word_sz.height) + return_max_height = word_sz.height; } - auto i_ts_keeper = ts_keeper.cbegin(); //Test whether the text needs the new line. - if(x + static_cast(str_w) > endpos) + if(left + static_cast(string_px) > right) { - unsigned line_pixels = 0; - int xpos = x; - int orig_top = top; + unsigned max_height = 0; + int xpos = left; + const int orig_top = top; + + auto wdm = word_metrics.data(); for(auto & i : reordered) { - if(line_pixels < i_ts_keeper->height) - line_pixels = i_ts_keeper->height; + if(max_height < wdm->height) + max_height = wdm->height; - bool beyond_edge = (xpos + static_cast(i_ts_keeper->width) > endpos); + bool beyond_edge = (xpos + static_cast(wdm->width) > right); if(beyond_edge) { std::size_t len = i.end - i.begin; @@ -475,21 +440,22 @@ namespace nana do { - idx_splitted = draw_string_auto_changing_lines::find_splitted(idx_head, len, xpos, endpos, pxbuf); + idx_splitted = draw_string_auto_changing_lines::find_splitted(idx_head, len, xpos, right, pxbuf); if(idx_splitted == len) { for(std::size_t i = idx_head; i < len; ++i) xpos += static_cast(pxbuf[i]); + break; } //Check the word whether it is splittable. if(draw_string_auto_changing_lines::splittable(i.begin, idx_splitted)) { idx_head = idx_splitted; - xpos = x; - top += line_pixels; - line_pixels = i_ts_keeper->height; + xpos = left; + top += max_height; + max_height = wdm->height; } else { @@ -503,14 +469,11 @@ namespace nana break; } - if(u != head) - { - idx_head += u - head; - xpos = x; - top += line_pixels; - line_pixels = i_ts_keeper->height; - } - else + xpos = left; + top += max_height; + max_height = wdm->height; + + if(u == head) { u = i.begin + idx_splitted; const wchar_t * end = i.begin + len; @@ -520,52 +483,45 @@ namespace nana break; } std::size_t splen = u - head; - top += line_pixels; - xpos = x; - line_pixels = i_ts_keeper->height; for(std::size_t k = idx_head; k < idx_head + splen; ++k) xpos += static_cast(pxbuf[k]); - if(xpos >= endpos) + if(xpos >= right) { - xpos = x; - top += line_pixels; + xpos = left; + top += max_height; } idx_head += splen; } + else + idx_head += u - head; } }while(idx_head < len); } else - xpos = x + static_cast(i_ts_keeper->width); + xpos = left + static_cast(wdm->width); - line_pixels = 0; + max_height = 0; } else - xpos += static_cast(i_ts_keeper->width); + xpos += static_cast(wdm->width); - ++i_ts_keeper; + ++wdm; } - pixels = (top - orig_top) + line_pixels; + return_max_height = (top - orig_top) + max_height; } - else - { - while(i_ts_keeper != ts_keeper.cend()) - { - const nana::size & ts = *(i_ts_keeper++); - if(ts.height > pixels) pixels = ts.height; - } - } - extents += pixels; - return pixels; + + extents += return_max_height; + return return_max_height; } }; }//end namespace helper //class text_renderer - text_renderer::text_renderer(graph_reference graph, align ta) - : graph_(graph), text_align_(ta) + text_renderer::text_renderer(graph_reference graph, align ta): + graph_(graph), + text_align_(ta) {} nana::size text_renderer::extent_size(int x, int y, const wchar_t* str, std::size_t len, unsigned restricted_pixels) const @@ -585,26 +541,25 @@ namespace nana { if (graph_) { - helper::draw_string ds(graph_.handle(), pos.x, static_cast(graph_.width()), text_align_); - helper::for_each_line(str, len, pos.y, ds); + helper::string_drawer sd{ graph_, pos.x, pos.x + static_cast(graph_.width()), text_align_, false }; + helper::for_each_line(str, len, pos.y, sd); } } - void text_renderer::render(const point& pos, const wchar_t* str, std::size_t len, unsigned restricted_pixels, bool omitted) + void text_renderer::render(const point& pos, const wchar_t* str, std::size_t len, unsigned space_pixels, mode rendering_mode) { - if (graph_) + if (graph_ && str && len && space_pixels) { - helper::draw_string_omitted dso(graph_, pos.x, pos.x + static_cast(restricted_pixels), omitted); - helper::for_each_line(str, len, pos.y, dso); - } - } - - void text_renderer::render(const point& pos, const wchar_t * str, std::size_t len, unsigned restricted_pixels) - { - if (graph_) - { - helper::draw_string_auto_changing_lines dsacl(graph_, pos.x, pos.x + static_cast(restricted_pixels), text_align_); - helper::for_each_line(str, len, pos.y, dsacl); + if (mode::truncate_letter_with_ellipsis == rendering_mode || mode::truncate_with_ellipsis == rendering_mode) + { + helper::string_drawer sd{ graph_, pos.x, pos.x + static_cast(space_pixels), text_align_, true }; + helper::for_each_line(str, len, pos.y, sd); + } + else if (mode::word_wrap == rendering_mode) + { + helper::draw_string_auto_changing_lines dsacl(graph_, pos.x, pos.x + static_cast(space_pixels), text_align_); + helper::for_each_line(str, len, pos.y, dsacl); + } } } //end class text_renderer diff --git a/source/system/dataexch.cpp b/source/system/dataexch.cpp index 8c25ed5e..bd6e498c 100644 --- a/source/system/dataexch.cpp +++ b/source/system/dataexch.cpp @@ -15,15 +15,14 @@ #include #include #include -#include #include #if defined(NANA_WINDOWS) # include #elif defined(NANA_X11) -# include "../detail/platform_spec_selector.hpp" # include -# include +# include "../detail/platform_spec_selector.hpp" +# include "../gui/detail/basic_window.hpp" #endif namespace nana{ namespace system{ @@ -71,7 +70,6 @@ namespace nana{ namespace system{ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); HDC hDC = ::GetDC(NULL); if (::GetDIBits(hDC, (HBITMAP)g.pixmap(), 0, 1, NULL, (BITMAPINFO *)&bmi, DIB_RGB_COLORS) == 0) { - assert(false); ::ReleaseDC(NULL, hDC); return false; } @@ -109,7 +107,6 @@ namespace nana{ namespace system{ ::CloseClipboard(); } } - assert(false); ::GlobalFree(h_gmem); return false; @@ -266,8 +263,8 @@ namespace nana{ namespace system{ spec.lock_xlib(); { - internal_scope_guard isg; - detail::bedrock::core_window_t * wd = detail::bedrock::instance().focus(); + internal_scope_guard lock; + auto wd = detail::bedrock::instance().focus(); if(wd) requester = wd->root; } spec.unlock_xlib(); diff --git a/source/threads/pool.cpp b/source/threads/pool.cpp index d4b3af2f..c58f6d58 100644 --- a/source/threads/pool.cpp +++ b/source/threads/pool.cpp @@ -141,6 +141,7 @@ namespace threads ::pthread_join(thr->handle, 0); ::pthread_detach(thr->handle); #endif + delete thr; } std::lock_guard lock(mutex_); diff --git a/source/unicode_bidi.cpp b/source/unicode_bidi.cpp index 7b054e10..f71645c5 100644 --- a/source/unicode_bidi.cpp +++ b/source/unicode_bidi.cpp @@ -1,3 +1,17 @@ +/* + * Unicode Bidi-Language Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2019 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/unicode_bidi.cpp + * @contributors: + * glavangeorge(pr#440) + + */ #include #include