Implement per-screen DPI on Windows, DPI change event, wxDialog & wxFrame mixin base classes
This commit is contained in:
parent
af05e5fc2c
commit
7e32f2df71
@ -76,6 +76,24 @@ wxString file_wildcards(FileType file_type, const std::string &custom_extension)
|
||||
|
||||
static std::string libslic3r_translate_callback(const char *s) { return wxGetTranslation(wxString(s, wxConvUTF8)).utf8_str().data(); }
|
||||
|
||||
static void register_dpi_event()
|
||||
{
|
||||
#ifdef WIN32
|
||||
enum { WM_DPICHANGED_ = 0x02e0 };
|
||||
|
||||
wxWindow::MSWRegisterMessageHandler(WM_DPICHANGED_, [](wxWindow *win, WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) {
|
||||
const int dpi = wParam & 0xffff;
|
||||
const auto rect = reinterpret_cast<PRECT>(lParam);
|
||||
const wxRect wxrect(wxPoint(rect->top, rect->left), wxPoint(rect->bottom, rect->right));
|
||||
|
||||
DpiChangedEvent evt(EVT_DPI_CHANGED, dpi, wxrect);
|
||||
win->GetEventHandler()->AddPendingEvent(evt);
|
||||
|
||||
return true;
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
IMPLEMENT_APP(GUI_App)
|
||||
|
||||
GUI_App::GUI_App()
|
||||
@ -149,6 +167,8 @@ bool GUI_App::OnInit()
|
||||
show_error(nullptr, ex.what());
|
||||
}
|
||||
|
||||
register_dpi_event();
|
||||
|
||||
// Let the libslic3r know the callback, which will translate messages on demand.
|
||||
Slic3r::I18N::set_translate_callback(libslic3r_translate_callback);
|
||||
|
||||
|
@ -4,9 +4,14 @@
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include <wx/toplevel.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/dcclient.h>
|
||||
|
||||
#include "libslic3r/Config.hpp"
|
||||
|
||||
@ -48,6 +53,64 @@ void on_window_geometry(wxTopLevelWindow *tlw, std::function<void()> callback)
|
||||
#endif
|
||||
}
|
||||
|
||||
wxDEFINE_EVENT(EVT_DPI_CHANGED, DpiChangedEvent);
|
||||
|
||||
#ifdef _WIN32
|
||||
template<class F> typename F::FN winapi_get_function(const wchar_t *dll, const char *fn_name) {
|
||||
static HINSTANCE dll_handle = LoadLibraryExW(dll, nullptr, 0);
|
||||
|
||||
if (dll_handle == nullptr) { return nullptr; }
|
||||
return (F::FN)GetProcAddress(dll_handle, fn_name);
|
||||
}
|
||||
#endif
|
||||
|
||||
int get_dpi_for_window(wxWindow *window)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
enum MONITOR_DPI_TYPE_ {
|
||||
// This enum is inlined here to avoid build-time dependency
|
||||
MDT_EFFECTIVE_DPI_ = 0,
|
||||
MDT_ANGULAR_DPI_ = 1,
|
||||
MDT_RAW_DPI_ = 2,
|
||||
MDT_DEFAULT_ = MDT_EFFECTIVE_DPI_,
|
||||
};
|
||||
|
||||
// Need strong types for winapi_get_function() to work
|
||||
struct GetDpiForWindow_t { typedef HRESULT (WINAPI *FN)(HWND hwnd); };
|
||||
struct GetDpiForMonitor_t { typedef HRESULT (WINAPI *FN)(HMONITOR hmonitor, MONITOR_DPI_TYPE_ dpiType, UINT *dpiX, UINT *dpiY); };
|
||||
|
||||
static auto GetDpiForWindow_fn = winapi_get_function<GetDpiForWindow_t>(L"User32.dll", "GetDpiForWindow");
|
||||
static auto GetDpiForMonitor_fn = winapi_get_function<GetDpiForMonitor_t>(L"Shcore.dll", "GetDpiForMonitor");
|
||||
|
||||
const HWND hwnd = window->GetHandle();
|
||||
|
||||
if (GetDpiForWindow_fn != nullptr) {
|
||||
// We're on Windows 10, we have per-screen DPI settings
|
||||
return GetDpiForWindow_fn(hwnd);
|
||||
} else if (GetDpiForMonitor_fn != nullptr) {
|
||||
// We're on Windows 8.1, we have per-system DPI
|
||||
// Note: MonitorFromWindow() is available on all Windows.
|
||||
|
||||
const HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
UINT dpiX;
|
||||
UINT dpiY;
|
||||
return GetDpiForMonitor_fn(monitor, MDT_EFFECTIVE_DPI_, &dpiX, &dpiY) == S_OK ? dpiX : DPI_DEFAULT;
|
||||
} else {
|
||||
// We're on Windows earlier than 8.1, use DC
|
||||
|
||||
const HDC hdc = GetDC(hwnd);
|
||||
if (hdc == NULL) { return DPI_DEFAULT; }
|
||||
return GetDeviceCaps(hdc, LOGPIXELSX);
|
||||
}
|
||||
#elif defined __linux__
|
||||
// TODO
|
||||
return DPI_DEFAULT;
|
||||
#elif defined __APPLE__
|
||||
// TODO
|
||||
return DPI_DEFAULT;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
CheckboxFileDialog::ExtraPanel::ExtraPanel(wxWindow *parent)
|
||||
: wxPanel(parent, wxID_ANY)
|
||||
|
@ -8,10 +8,13 @@
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <wx/frame.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/filedlg.h>
|
||||
#include <wx/gdicmn.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/dcclient.h>
|
||||
#include <wx/debug.h>
|
||||
|
||||
class wxCheckBox;
|
||||
@ -27,6 +30,68 @@ wxTopLevelWindow* find_toplevel_parent(wxWindow *window);
|
||||
|
||||
void on_window_geometry(wxTopLevelWindow *tlw, std::function<void()> callback);
|
||||
|
||||
enum { DPI_DEFAULT = 96 };
|
||||
|
||||
int get_dpi_for_window(wxWindow *window);
|
||||
|
||||
struct DpiChangedEvent : public wxEvent {
|
||||
int dpi;
|
||||
wxRect rect;
|
||||
|
||||
DpiChangedEvent(wxEventType eventType, int dpi, wxRect rect)
|
||||
: wxEvent(0, eventType), dpi(dpi), rect(rect)
|
||||
{}
|
||||
|
||||
virtual wxEvent *Clone() const
|
||||
{
|
||||
return new DpiChangedEvent(*this);
|
||||
}
|
||||
};
|
||||
|
||||
wxDECLARE_EVENT(EVT_DPI_CHANGED, DpiChangedEvent);
|
||||
|
||||
template<class P> class DPIAware : public P
|
||||
{
|
||||
public:
|
||||
DPIAware(wxWindow *parent, wxWindowID id, const wxString &title, const wxPoint &pos=wxDefaultPosition,
|
||||
const wxSize &size=wxDefaultSize, long style=wxDEFAULT_FRAME_STYLE, const wxString &name=wxFrameNameStr)
|
||||
: P(parent, id, title, pos, size, style, name)
|
||||
{
|
||||
m_scale_factor = (float)get_dpi_for_window(this) / (float)DPI_DEFAULT;
|
||||
recalc_font();
|
||||
|
||||
this->Bind(EVT_DPI_CHANGED, [this](const DpiChangedEvent &evt) {
|
||||
m_scale_factor = (float)evt.dpi / (float)DPI_DEFAULT;
|
||||
on_dpi_changed(evt.rect);
|
||||
});
|
||||
}
|
||||
|
||||
virtual ~DPIAware() {}
|
||||
|
||||
float scale_factor() const { return m_scale_factor; }
|
||||
int em_unit() const { return m_em_unit; }
|
||||
int font_size() const { return m_font_size; }
|
||||
|
||||
protected:
|
||||
virtual void on_dpi_changed(const wxRect &suggested_rect) = 0;
|
||||
|
||||
private:
|
||||
int m_scale_factor;
|
||||
int m_em_unit;
|
||||
int m_font_size;
|
||||
|
||||
void recalc_font()
|
||||
{
|
||||
wxClientDC dc(this);
|
||||
const auto metrics = dc.GetFontMetrics();
|
||||
m_font_size = metrics.height;
|
||||
m_em_unit = metrics.averageWidth;
|
||||
}
|
||||
};
|
||||
|
||||
typedef DPIAware<wxFrame> DPIFrame;
|
||||
typedef DPIAware<wxDialog> DPIDialog;
|
||||
|
||||
|
||||
class EventGuard
|
||||
{
|
||||
|
@ -32,7 +32,7 @@ namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
MainFrame::MainFrame() :
|
||||
wxFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, "mainframe"),
|
||||
DPIFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, "mainframe"),
|
||||
m_printhost_queue_dlg(new PrintHostQueueDialog(this))
|
||||
{
|
||||
// Load the icon either from the exe, or from the ico file.
|
||||
@ -256,6 +256,11 @@ bool MainFrame::can_delete_all() const
|
||||
return (m_plater != nullptr) ? !m_plater->model().objects.empty() : false;
|
||||
}
|
||||
|
||||
void MainFrame::on_dpi_changed(const wxRect &suggested_rect)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void MainFrame::init_menubar()
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "GUI_Utils.hpp"
|
||||
#include "Plater.hpp"
|
||||
#include "Event.hpp"
|
||||
|
||||
@ -40,7 +41,7 @@ struct PresetTab {
|
||||
PrinterTechnology technology;
|
||||
};
|
||||
|
||||
class MainFrame : public wxFrame
|
||||
class MainFrame : public DPIFrame
|
||||
{
|
||||
bool m_loaded {false};
|
||||
|
||||
@ -68,6 +69,9 @@ class MainFrame : public wxFrame
|
||||
bool can_delete() const;
|
||||
bool can_delete_all() const;
|
||||
|
||||
protected:
|
||||
virtual void on_dpi_changed(const wxRect &suggested_rect);
|
||||
|
||||
public:
|
||||
MainFrame();
|
||||
~MainFrame() {}
|
||||
|
Loading…
Reference in New Issue
Block a user