From f67dbdb14b9b8f5de7c38b0bb14be72cf5d0adb4 Mon Sep 17 00:00:00 2001 From: cnjinhao Date: Mon, 12 Jan 2015 09:39:28 +0800 Subject: [PATCH] draw-through it is possible to render with OpenGL/DX by using draw-through. --- include/nana/gui/basis.hpp | 2 ++ include/nana/gui/detail/basic_window.hpp | 6 ++++- include/nana/gui/detail/bedrock.hpp | 1 + include/nana/gui/programming_interface.hpp | 6 ++++- include/nana/gui/widgets/widget.hpp | 10 ++++++++ source/gui/detail/basic_window.cpp | 7 ++++++ source/gui/detail/win32/bedrock.cpp | 29 ++++++++++++++++++++++ source/gui/detail/window_manager.cpp | 4 +-- source/gui/drawing.cpp | 20 ++++++++++----- source/gui/programming_interface.cpp | 26 +++++++++++++++++++ 10 files changed, 101 insertions(+), 10 deletions(-) diff --git a/include/nana/gui/basis.hpp b/include/nana/gui/basis.hpp index 943d6a8c..14114ecd 100644 --- a/include/nana/gui/basis.hpp +++ b/include/nana/gui/basis.hpp @@ -25,6 +25,7 @@ namespace nana struct native_window_handle_impl{}; struct window_handle_impl{}; struct event_handle_impl{}; + struct native_drawable_impl{}; } enum class checkstate @@ -66,6 +67,7 @@ namespace nana 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*; struct keyboard diff --git a/include/nana/gui/detail/basic_window.hpp b/include/nana/gui/detail/basic_window.hpp index 0524db4b..84900952 100644 --- a/include/nana/gui/detail/basic_window.hpp +++ b/include/nana/gui/detail/basic_window.hpp @@ -74,7 +74,7 @@ namespace detail struct basic_window : public events_holder { - typedef std::vector container; + using container = std::vector; struct root_context { @@ -119,6 +119,8 @@ namespace detail bool is_ancestor_of(const basic_window* wd) const; bool visible_parents() const; bool belong_to_lazy() const; + + bool is_draw_through() const; ///< Determines whether it is a draw-through window. public: //Override event_holder bool set_events(const std::shared_ptr&) override; @@ -206,6 +208,8 @@ namespace detail #endif cursor state_cursor{nana::cursor::arrow}; basic_window* state_cursor_window{ nullptr }; + + std::function draw_through; ///< A draw through renderer for root widgets. }; const category::flags category; diff --git a/include/nana/gui/detail/bedrock.hpp b/include/nana/gui/detail/bedrock.hpp index b91c728f..d90543bc 100644 --- a/include/nana/gui/detail/bedrock.hpp +++ b/include/nana/gui/detail/bedrock.hpp @@ -67,6 +67,7 @@ namespace detail bool whether_keyboard_shortkey() const; element_store& get_element_store() const; + void map_through_widgets(core_window_t*, native_drawable_type); public: void event_expose(core_window_t *, bool exposed); void event_move(core_window_t*, int x, int y); diff --git a/include/nana/gui/programming_interface.hpp b/include/nana/gui/programming_interface.hpp index 9bcf2842..20d1c182 100644 --- a/include/nana/gui/programming_interface.hpp +++ b/include/nana/gui/programming_interface.hpp @@ -115,7 +115,8 @@ namespace API void window_icon_default(const paint::image&); void window_icon(window, const paint::image&); - bool empty_window(window); ///< Determines whether a window is existing. + bool empty_window(window); ///< Determines whether a window is existing. + bool is_window(window); ///< Determines whether a window is existing, equal to !empty_window. void enable_dropfiles(window, bool); /// \brief Retrieves the native window of a Nana.GUI window. @@ -176,6 +177,9 @@ namespace API void bring_top(window, bool activated); bool set_window_z_order(window wd, window wd_after, z_order_action action_if_no_wd_after); + void draw_through(window, std::function); + void map_through_widgets(window, native_drawable_type); + nana::size window_size(window); void window_size(window, const size&); bool window_rectangle(window, rectangle&); diff --git a/include/nana/gui/widgets/widget.hpp b/include/nana/gui/widgets/widget.hpp index bc1ba141..567074e3 100644 --- a/include/nana/gui/widgets/widget.hpp +++ b/include/nana/gui/widgets/widget.hpp @@ -401,6 +401,16 @@ namespace nana { return *scheme_; } + + void draw_through(std::function draw_fn) + { + API::draw_through(handle(), draw_fn); + } + + void map_through_widgets(native_drawable_type drawable) + { + API::map_through_widgets(handle(), drawable); + } protected: DrawerTrigger& get_drawer_trigger() { diff --git a/source/gui/detail/basic_window.cpp b/source/gui/detail/basic_window.cpp index a4f78b11..4218692b 100644 --- a/source/gui/detail/basic_window.cpp +++ b/source/gui/detail/basic_window.cpp @@ -292,6 +292,13 @@ namespace nana return false; } + bool basic_window::is_draw_through() const + { + if (::nana::category::flags::root == this->other.category) + return static_cast(other.attribute.root->draw_through); + return false; + } + void basic_window::_m_init_pos_and_size(basic_window* parent, const rectangle& r) { pos_owner = pos_root = r; diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp index 74b8cb30..ae241ff9 100644 --- a/source/gui/detail/win32/bedrock.cpp +++ b/source/gui/detail/win32/bedrock.cpp @@ -1265,6 +1265,15 @@ namespace detail brock.event_move(msgwnd, (int)(short) LOWORD(lParam), (int)(short) HIWORD(lParam)); break; case WM_PAINT: + if (msgwnd->is_draw_through()) + { + msgwnd->other.attribute.root->draw_through(); + + ::PAINTSTRUCT ps; + ::BeginPaint(root_window, &ps); + ::EndPaint(root_window, &ps); + } + else { ::PAINTSTRUCT ps; ::HDC dc = ::BeginPaint(root_window, &ps); @@ -1581,6 +1590,26 @@ namespace detail return impl_->estore; } + void bedrock::map_through_widgets(core_window_t* wd, native_drawable_type drawable) + { +#if defined(NANA_WINDOWS) + auto graph_context = reinterpret_cast(wd->root_graph->handle()->context); + + for (auto child : wd->children) + { + if (!child->visible) continue; + + if (::nana::category::flags::widget == child->other.category) + { + ::BitBlt(reinterpret_cast(drawable), child->pos_root.x, child->pos_root.y, static_cast(child->dimension.width), static_cast(child->dimension.height), + graph_context, child->pos_root.x, child->pos_root.y, SRCCOPY); + } + else if (::nana::category::flags::lite_widget == child->other.category) + map_through_widgets(child, drawable); + } +#endif + } + bool bedrock::emit(event_code evt_code, core_window_t* wd, const arg_mouse& arg, bool ask_update, thread_context* thrd) { if (evt_code != arg.evt_code) diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index ea956b24..783fd3c5 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -674,7 +674,7 @@ namespace detail { //Thread-Safe Required! std::lock_guard lock(mutex_); - if (impl_->wd_register.available(wd)) + if (impl_->wd_register.available(wd) && !wd->is_draw_through()) { //Copy the root buffer that wd specified into DeviceContext #if defined(NANA_LINUX) @@ -738,7 +738,7 @@ namespace detail if (false == impl_->wd_register.available(wd)) return false; - if(wd->visible) + if(wd->visible && (!wd->is_draw_through())) { if (wd->visible_parents()) { diff --git a/source/gui/drawing.cpp b/source/gui/drawing.cpp index e524d2e5..10fabaa7 100644 --- a/source/gui/drawing.cpp +++ b/source/gui/drawing.cpp @@ -20,19 +20,27 @@ namespace nana //@brief: This name is only visible for this compiling-unit namespace restrict { - typedef detail::bedrock::core_window_t core_window_t; - extern detail::bedrock& bedrock; - - inline detail::drawer& get_drawer(window wd) + namespace { - return reinterpret_cast(wd)->drawer; + using core_window_t = detail::bedrock::core_window_t; + + inline detail::drawer& get_drawer(window wd) + { + return reinterpret_cast(wd)->drawer; + } } } //class drawing drawing::drawing(window wd) :handle_(wd) - {} + { + if (!API::is_window(wd)) + throw std::invalid_argument("drawing: invalid window parameter"); + + if (reinterpret_cast(wd)->is_draw_through()) + throw std::invalid_argument("drawing: the window is draw_through enabled"); + } drawing::~drawing(){} //Just for polymorphism diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index 8979c61f..fc0cc59d 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -349,6 +349,11 @@ namespace API return (restrict::window_manager.available(reinterpret_cast(wd)) == false); } + bool is_window(window wd) + { + return restrict::window_manager.available(reinterpret_cast(wd)); + } + void enable_dropfiles(window wd, bool enb) { internal_scope_guard lock; @@ -564,6 +569,27 @@ namespace API return false; } + void draw_through(window wd, std::function draw_fn) + { + auto iwd = reinterpret_cast(wd); + internal_scope_guard lock; + if (!restrict::bedrock.wd_manager.available(iwd)) + throw std::invalid_argument("draw_through: invalid window parameter"); + + if (::nana::category::flags::root != iwd->other.category) + throw std::invalid_argument("draw_through: the window is not a root widget"); + + iwd->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::bedrock.wd_manager.available(iwd) && iwd->is_draw_through() ) + restrict::bedrock.map_through_widgets(iwd, drawable); + } + nana::size window_size(window wd) { nana::rectangle r;