refactor the class screen

This commit is contained in:
Jinhao 2015-03-22 11:19:27 +08:00
parent 2ca3573049
commit e4382239e5
6 changed files with 124 additions and 102 deletions

View File

@ -27,25 +27,37 @@ namespace nana
/// The index of monitor. /// The index of monitor.
virtual std::size_t get_index() const = 0; 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 /// 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& area() const = 0;
virtual const ::nana::rectangle& workarea() const = 0;
}; };
class screen class screen
{ {
struct implement;
public: public:
static ::nana::size desktop_size(); static ::nana::size desktop_size();
static ::nana::size primary_monitor_size(); static ::nana::size primary_monitor_size();
static std::shared_ptr<display> from_point(const point&);
static std::shared_ptr<display> from_window(window); screen();
/// Reload has no preconditions, it's safe to call on moved-from
void reload();
/// Returns the number of display monitors /// Returns the number of display monitors
std::size_t count() const; std::size_t count() const;
std::shared_ptr<display> get_display(std::size_t index) const; display& from_point(const point&);
std::shared_ptr<display> get_primary() const; display& from_window(window);
display& get_display(std::size_t index) const;
display& get_primary() const;
void for_each(std::function<void(display&)>) const; void for_each(std::function<void(display&)>) const;
private:
std::shared_ptr<implement> impl_;
}; };
}//end namespace nana }//end namespace nana

View File

@ -8,6 +8,8 @@
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: nana/gui/widgets/panel.hpp * @file: nana/gui/widgets/panel.hpp
* @author: Jinhao
* @contributors: qPCR4vir
* *
* @brief panel is a widget used for placing some widgets. * @brief panel is a widget used for placing some widgets.
*/ */

View File

@ -25,39 +25,22 @@ namespace nana
: public display : public display
{ {
public: public:
real_display(std::size_t number) real_display() = default; //For requirement of vector
: index_(number)
{
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
DISPLAY_DEVICE disp; real_display(std::size_t number, const MONITORINFOEX& mi)
disp.cb = sizeof disp; : index_(number),
if (::EnumDisplayDevices(nullptr, static_cast<DWORD>(index_), &disp, 0)) 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)
{ {
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 #else
if (0 == index_) real_display(std::size_t number, const ::nana::rectangle& r)
: index_(number), is_primary_(true), area_(r), workarea_(r)
{ {
area_ = detail::native_interface::primary_monitor_size();
return;
} }
#endif #endif
throw std::invalid_argument("Nana.Screen: Invalid monitor index.");
}
real_display(std::size_t number, const ::nana::rectangle& r)
: index_(number), area_(r)
{
}
public: public:
//Implementation of display //Implementation of display
std::size_t get_index() const override std::size_t get_index() const override
@ -65,13 +48,25 @@ namespace nana
return index_; return index_;
} }
bool is_primary_monitor() const override
{
return is_primary_;
}
const ::nana::rectangle& area() const override const ::nana::rectangle& area() const override
{ {
return area_; return area_;
} }
const ::nana::rectangle& workarea() const override
{
return workarea_;
}
private: private:
const std::size_t index_; std::size_t index_;
bool is_primary_;
::nana::rectangle area_; ::nana::rectangle area_;
::nana::rectangle workarea_;
}; };
//class screen //class screen
@ -92,7 +87,58 @@ namespace nana
return ::nana::detail::native_interface::primary_monitor_size(); return ::nana::detail::native_interface::primary_monitor_size();
} }
std::shared_ptr<display> screen::from_point(const point& pos)
struct screen::implement
{
std::vector<real_display> displays;
#if defined(NANA_WINDOWS)
void load_monitors()
{
std::vector<real_display> tmp;
::EnumDisplayMonitors(nullptr, nullptr, implement::enum_proc, reinterpret_cast<LPARAM>(&tmp));
tmp.swap(displays);
}
static BOOL __stdcall enum_proc(HMONITOR handle, HDC context, LPRECT r, LPARAM self_ptr)
{
auto disp_cont = reinterpret_cast<std::vector<real_display>*>(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<implement>())
{
impl_->load_monitors();
}
void screen::reload()
{
impl_.reset(std::make_shared<implement>());
impl_->load_monitors();
}
std::size_t screen::count() const
{
return impl_->displays.size();
}
display& screen::from_point(const point& pos)
{ {
#if defined(NANA_WINDOWS) #if defined(NANA_WINDOWS)
typedef HMONITOR(__stdcall * MonitorFromPointT)(POINT, DWORD); typedef HMONITOR(__stdcall * MonitorFromPointT)(POINT, DWORD);
@ -107,87 +153,47 @@ namespace nana
mi.cbSize = sizeof mi; mi.cbSize = sizeof mi;
if (::GetMonitorInfo(monitor, &mi)) if (::GetMonitorInfo(monitor, &mi))
{ {
DISPLAY_DEVICE disp; for (auto & disp : impl_->displays)
disp.cb = sizeof disp;
DWORD index = 0;
while (::EnumDisplayDevices(nullptr, index++, &disp, 0))
{ {
DEVMODE mode; auto & r = disp.area();
mode.dmSize = sizeof mode; if (r.x == mi.rcMonitor.left && r.y == mi.rcMonitor.top &&
if (::EnumDisplaySettings(disp.DeviceName, ENUM_CURRENT_SETTINGS, &mode)) r.width == unsigned(mi.rcMonitor.right - mi.rcMonitor.left) &&
{ r.height == unsigned(mi.rcMonitor.bottom - mi.rcMonitor.top)
if (mode.dmPosition.x == mi.rcWork.left && mode.dmPosition.y == mi.rcWork.top && )
(static_cast<int>(mode.dmPelsWidth) == mi.rcWork.right - mi.rcWork.left) && return disp;
(static_cast<int>(mode.dmPelsHeight) == mi.rcWork.bottom - mi.rcWork.top))
{
return std::make_shared<real_display>(static_cast<std::size_t>(index - 1), rectangle{ mode.dmPosition.x, mode.dmPosition.y, static_cast<unsigned>(mode.dmPelsWidth), static_cast<unsigned>(mode.dmPelsHeight) });
}
}
} }
} }
} }
#endif #endif
return screen().get_primary(); return get_primary();
} }
std::shared_ptr<display> screen::from_window(window wd) display& screen::from_window(window wd)
{ {
::nana::point pos; ::nana::point pos;
API::calc_screen_point(wd, pos); API::calc_screen_point(wd, pos);
return from_point(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; display& screen::get_display(std::size_t index) const
while (::EnumDisplayDevices(nullptr, index++, &disp, 0)); {
return static_cast<std::size_t>(index - 1); return impl_->displays.at(index);
#else
return 1;
#endif
} }
std::shared_ptr<display> screen::get_display(std::size_t index) const display& screen::get_primary() const
{ {
return std::make_shared<real_display>(index); for (auto & disp : impl_->displays)
} if (disp.is_primary_monitor())
return disp;
std::shared_ptr<display> screen::get_primary() const throw std::logic_error("no primary monitor found");
{
#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<real_display>(static_cast<std::size_t>(index - 1), rectangle{ mode.dmPosition.x, mode.dmPosition.y, static_cast<unsigned>(mode.dmPelsWidth), static_cast<unsigned>(mode.dmPelsHeight) });
}
}
#endif
return std::make_shared<real_display>(0);
} }
void screen::for_each(std::function<void(display&)> fn) const void screen::for_each(std::function<void(display&)> fn) const
{ {
auto n = count(); for (auto & disp : impl_->displays)
for (decltype(n) i = 0; i < n; ++i)
{
real_display disp(i);
fn(disp); fn(disp);
} }
}
//end class screen //end class screen
} }

View File

@ -34,7 +34,7 @@ namespace nana
nana::point pos_by_screen(nana::point pos, const nana::size& sz, bool overlap_allowed) 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) if (pos.x + sz.width > scr_area.x + scr_area.width)
pos.x = static_cast<int>(scr_area.x + scr_area.width - sz.width); pos.x = static_cast<int>(scr_area.x + scr_area.width - sz.width);
if (pos.x < scr_area.x) if (pos.x < scr_area.x)
@ -77,7 +77,7 @@ namespace nana
void tooltip_text(const nana::string& text) override void tooltip_text(const nana::string& text) override
{ {
label_.caption(text); 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 }); this->size(nana::size{ text_s.width + 10, text_s.height + 10 });
label_.move(rectangle{ 5, 5, text_s.width, text_s.height }); label_.move(rectangle{ 5, 5, text_s.width, text_s.height });

View File

@ -8,6 +8,8 @@
* http://www.boost.org/LICENSE_1_0.txt) * http://www.boost.org/LICENSE_1_0.txt)
* *
* @file: source/gui/widgets/label.cpp * @file: source/gui/widgets/label.cpp
* @author: Jinhao
* @contributors: qPCR4vir
*/ */
#include <nana/gui/widgets/label.hpp> #include <nana/gui/widgets/label.hpp>

View File

@ -659,7 +659,7 @@ namespace nana
API::calc_screen_point(*widget_, pos); API::calc_screen_point(*widget_, pos);
//get the screen coordinates of the 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) if(pos.x + size.width > scr_area.x + scr_area.width)
pos.x = static_cast<int>(scr_area.x + scr_area.width - size.width); pos.x = static_cast<int>(scr_area.x + scr_area.width - size.width);