From e4382239e59a1da1e647a7e9424d765fa67ead23 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 22 Mar 2015 11:19:27 +0800 Subject: [PATCH] refactor the class screen --- include/nana/gui/screen.hpp | 20 +++- include/nana/gui/widgets/panel.hpp | 6 +- source/gui/screen.cpp | 186 +++++++++++++++-------------- source/gui/tooltip.cpp | 4 +- source/gui/widgets/label.cpp | 8 +- source/gui/widgets/menu.cpp | 2 +- 6 files changed, 124 insertions(+), 102 deletions(-) diff --git a/include/nana/gui/screen.hpp b/include/nana/gui/screen.hpp index ef2aaac1..ef9126e8 100644 --- a/include/nana/gui/screen.hpp +++ b/include/nana/gui/screen.hpp @@ -27,25 +27,37 @@ namespace nana /// The index of monitor. virtual std::size_t get_index() const = 0; + virtual bool is_primary_monitor() const = 0; + /// Returns the positional coordinates and size of the display device in reference to the desktop area virtual const ::nana::rectangle& area() const = 0; + virtual const ::nana::rectangle& workarea() const = 0; }; class screen { + struct implement; public: static ::nana::size desktop_size(); static ::nana::size primary_monitor_size(); - static std::shared_ptr from_point(const point&); - static std::shared_ptr from_window(window); + + screen(); + + /// Reload has no preconditions, it's safe to call on moved-from + void reload(); /// Returns the number of display monitors std::size_t count() const; - std::shared_ptr get_display(std::size_t index) const; - std::shared_ptr get_primary() const; + display& from_point(const point&); + display& from_window(window); + + display& get_display(std::size_t index) const; + display& get_primary() const; void for_each(std::function) const; + private: + std::shared_ptr impl_; }; }//end namespace nana diff --git a/include/nana/gui/widgets/panel.hpp b/include/nana/gui/widgets/panel.hpp index 2547f157..d5c0bbe7 100644 --- a/include/nana/gui/widgets/panel.hpp +++ b/include/nana/gui/widgets/panel.hpp @@ -8,6 +8,8 @@ * http://www.boost.org/LICENSE_1_0.txt) * * @file: nana/gui/widgets/panel.hpp + * @author: Jinhao + * @contributors: qPCR4vir * * @brief panel is a widget used for placing some widgets. */ @@ -44,13 +46,13 @@ namespace nana panel(window wd, bool visible) { this->create(wd, rectangle(), visible); - bgcolor(API::bgcolor(wd)); + bgcolor(API::bgcolor(wd)); } panel(window wd, const nana::rectangle& r = rectangle(), bool visible = true) { this->create(wd, r, visible); - bgcolor(API::bgcolor(wd)); + bgcolor(API::bgcolor(wd)); } bool transparent() const diff --git a/source/gui/screen.cpp b/source/gui/screen.cpp index ef6c8fec..952a17db 100644 --- a/source/gui/screen.cpp +++ b/source/gui/screen.cpp @@ -25,39 +25,22 @@ namespace nana : public display { public: - real_display(std::size_t number) - : index_(number) - { -#if defined(NANA_WINDOWS) - DISPLAY_DEVICE disp; - disp.cb = sizeof disp; - if (::EnumDisplayDevices(nullptr, static_cast(index_), &disp, 0)) - { - DEVMODE mode; - mode.dmSize = sizeof mode; - if (::EnumDisplaySettings(disp.DeviceName, ENUM_CURRENT_SETTINGS, &mode)) - { - area_.x = mode.dmPosition.x; - area_.y = mode.dmPosition.y; - area_.width = mode.dmPelsWidth; - area_.height = mode.dmPelsHeight; - return; - } - } -#else - if (0 == index_) - { - area_ = detail::native_interface::primary_monitor_size(); - return; - } -#endif - throw std::invalid_argument("Nana.Screen: Invalid monitor index."); - } + real_display() = default; //For requirement of vector - real_display(std::size_t number, const ::nana::rectangle& r) - : index_(number), area_(r) +#if defined(NANA_WINDOWS) + real_display(std::size_t number, const MONITORINFOEX& mi) + : index_(number), + is_primary_(mi.dwFlags & MONITORINFOF_PRIMARY), + area_(mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top), + workarea_(mi.rcWork.left, mi.rcWork.top, mi.rcWork.right - mi.rcWork.left, mi.rcWork.bottom - mi.rcWork.top) { } +#else + real_display(std::size_t number, const ::nana::rectangle& r) + : index_(number), is_primary_(true), area_(r), workarea_(r) + { + } +#endif public: //Implementation of display std::size_t get_index() const override @@ -65,13 +48,25 @@ namespace nana return index_; } + bool is_primary_monitor() const override + { + return is_primary_; + } + const ::nana::rectangle& area() const override { return area_; } + + const ::nana::rectangle& workarea() const override + { + return workarea_; + } private: - const std::size_t index_; + std::size_t index_; + bool is_primary_; ::nana::rectangle area_; + ::nana::rectangle workarea_; }; //class screen @@ -92,7 +87,58 @@ namespace nana return ::nana::detail::native_interface::primary_monitor_size(); } - std::shared_ptr screen::from_point(const point& pos) + + struct screen::implement + { + std::vector displays; + +#if defined(NANA_WINDOWS) + void load_monitors() + { + std::vector tmp; + ::EnumDisplayMonitors(nullptr, nullptr, implement::enum_proc, reinterpret_cast(&tmp)); + tmp.swap(displays); + } + + static BOOL __stdcall enum_proc(HMONITOR handle, HDC context, LPRECT r, LPARAM self_ptr) + { + auto disp_cont = reinterpret_cast*>(self_ptr); + MONITORINFOEX mi; + mi.cbSize = sizeof(MONITORINFOEX); + if (::GetMonitorInfo(handle, &mi)) + disp_cont->emplace_back(disp_cont->size(), mi); + + return TRUE; + } +#else + void load_monitors() + { + displays.emplace_back(0, primary_monitor_size()); + } +#endif + + }; + + screen::screen() + : impl_(std::make_shared()) + { + impl_->load_monitors(); + } + + + void screen::reload() + { + impl_.reset(std::make_shared()); + impl_->load_monitors(); + } + + std::size_t screen::count() const + { + return impl_->displays.size(); + } + + + display& screen::from_point(const point& pos) { #if defined(NANA_WINDOWS) typedef HMONITOR(__stdcall * MonitorFromPointT)(POINT, DWORD); @@ -107,87 +153,47 @@ namespace nana mi.cbSize = sizeof mi; if (::GetMonitorInfo(monitor, &mi)) { - DISPLAY_DEVICE disp; - disp.cb = sizeof disp; - - DWORD index = 0; - while (::EnumDisplayDevices(nullptr, index++, &disp, 0)) + for (auto & disp : impl_->displays) { - DEVMODE mode; - mode.dmSize = sizeof mode; - if (::EnumDisplaySettings(disp.DeviceName, ENUM_CURRENT_SETTINGS, &mode)) - { - if (mode.dmPosition.x == mi.rcWork.left && mode.dmPosition.y == mi.rcWork.top && - (static_cast(mode.dmPelsWidth) == mi.rcWork.right - mi.rcWork.left) && - (static_cast(mode.dmPelsHeight) == mi.rcWork.bottom - mi.rcWork.top)) - { - return std::make_shared(static_cast(index - 1), rectangle{ mode.dmPosition.x, mode.dmPosition.y, static_cast(mode.dmPelsWidth), static_cast(mode.dmPelsHeight) }); - } - } + auto & r = disp.area(); + if (r.x == mi.rcMonitor.left && r.y == mi.rcMonitor.top && + r.width == unsigned(mi.rcMonitor.right - mi.rcMonitor.left) && + r.height == unsigned(mi.rcMonitor.bottom - mi.rcMonitor.top) + ) + return disp; } } } #endif - return screen().get_primary(); + return get_primary(); } - std::shared_ptr screen::from_window(window wd) + display& screen::from_window(window wd) { ::nana::point pos; API::calc_screen_point(wd, pos); return from_point(pos); } - std::size_t screen::count() const - { -#if defined(NANA_WINDOWS) - DISPLAY_DEVICE disp; - disp.cb = sizeof disp; - DWORD index = 0; - while (::EnumDisplayDevices(nullptr, index++, &disp, 0)); - return static_cast(index - 1); -#else - return 1; -#endif + display& screen::get_display(std::size_t index) const + { + return impl_->displays.at(index); } - std::shared_ptr screen::get_display(std::size_t index) const + display& screen::get_primary() const { - return std::make_shared(index); - } + for (auto & disp : impl_->displays) + if (disp.is_primary_monitor()) + return disp; - std::shared_ptr screen::get_primary() const - { -#if defined(NANA_WINDOWS) - //return rectangle(mi.rcWork.left, mi.rcWork.top, - // mi.rcWork.right - mi.rcWork.left, mi.rcWork.bottom - mi.rcWork.top); - DISPLAY_DEVICE disp; - disp.cb = sizeof disp; - - DWORD index = 0; - while (::EnumDisplayDevices(nullptr, index++, &disp, 0)) - { - DEVMODE mode; - mode.dmSize = sizeof mode; - if (::EnumDisplaySettings(disp.DeviceName, ENUM_CURRENT_SETTINGS, &mode)) - { - if (mode.dmPosition.x == 0 && mode.dmPosition.y == 0) - return std::make_shared(static_cast(index - 1), rectangle{ mode.dmPosition.x, mode.dmPosition.y, static_cast(mode.dmPelsWidth), static_cast(mode.dmPelsHeight) }); - } - } -#endif - return std::make_shared(0); + throw std::logic_error("no primary monitor found"); } void screen::for_each(std::function fn) const { - auto n = count(); - for (decltype(n) i = 0; i < n; ++i) - { - real_display disp(i); + for (auto & disp : impl_->displays) fn(disp); - } } //end class screen } diff --git a/source/gui/tooltip.cpp b/source/gui/tooltip.cpp index 02eae44d..45656d01 100644 --- a/source/gui/tooltip.cpp +++ b/source/gui/tooltip.cpp @@ -34,7 +34,7 @@ namespace nana nana::point pos_by_screen(nana::point pos, const nana::size& sz, bool overlap_allowed) { - auto scr_area = screen::from_point(pos)->area(); + auto scr_area = screen().from_point(pos).workarea(); if (pos.x + sz.width > scr_area.x + scr_area.width) pos.x = static_cast(scr_area.x + scr_area.width - sz.width); if (pos.x < scr_area.x) @@ -77,7 +77,7 @@ namespace nana void tooltip_text(const nana::string& text) override { label_.caption(text); - auto text_s = label_.measure(screen::from_window(label_)->area().width * 2 / 3); + auto text_s = label_.measure(screen().from_window(label_).workarea().width * 2 / 3); this->size(nana::size{ text_s.width + 10, text_s.height + 10 }); label_.move(rectangle{ 5, 5, text_s.width, text_s.height }); diff --git a/source/gui/widgets/label.cpp b/source/gui/widgets/label.cpp index b68162d7..c0cf78c8 100644 --- a/source/gui/widgets/label.cpp +++ b/source/gui/widgets/label.cpp @@ -8,6 +8,8 @@ * http://www.boost.org/LICENSE_1_0.txt) * * @file: source/gui/widgets/label.cpp + * @author: Jinhao + * @contributors: qPCR4vir */ #include @@ -771,21 +773,21 @@ namespace nana label::label(window wd, const nana::string& text, bool visible) { create(wd, rectangle(), visible); - bgcolor(API::bgcolor(wd)); + bgcolor(API::bgcolor(wd)); caption(text); } label::label(window wd, const nana::char_t* text, bool visible) { create(wd, rectangle(), visible); - bgcolor(API::bgcolor(wd)); + bgcolor(API::bgcolor(wd)); caption(text); } label::label(window wd, const rectangle& r, bool visible) { create(wd, r, visible); - bgcolor(API::bgcolor(wd)); + bgcolor(API::bgcolor(wd)); } label& label::transparent(bool enabled) diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index 129cb7bc..2b25810b 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -659,7 +659,7 @@ namespace nana API::calc_screen_point(*widget_, pos); //get the screen coordinates of the widget pos. - auto scr_area = screen::from_point(detail_.monitor_pos)->area(); + auto scr_area = screen().from_point(detail_.monitor_pos).workarea(); if(pos.x + size.width > scr_area.x + scr_area.width) pos.x = static_cast(scr_area.x + scr_area.width - size.width);