mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-11-02 20:51:23 -07:00 
			
		
		
		
	Implement per-screen DPI on Windows, DPI change event, wxDialog & wxFrame mixin base classes
This commit is contained in:
		
							parent
							
								
									af05e5fc2c
								
							
						
					
					
						commit
						7e32f2df71
					
				
					 5 changed files with 159 additions and 2 deletions
				
			
		| 
						 | 
				
			
			@ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue