From e57139bb21128ae0a873589b2179725f4d5d6932 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Thu, 6 Oct 2016 23:46:28 +0200 Subject: [PATCH 01/21] Use system DPI for some native Windows dialogs Some native dialogs do not scale correctly (color picker, font picker, open file with custom controls). ALl other native dialogs do scale correctly (open file, open directory, find replace, print). Change the DPI Awareness Context temporarily to SystemAware, so Windows handles the scaling. --- include/wx/msw/private/dpiaware.h | 72 +++++++++++++++++++++++++++++++ src/msw/colordlg.cpp | 3 ++ src/msw/filedlg.cpp | 7 +++ src/msw/fontdlg.cpp | 3 ++ 4 files changed, 85 insertions(+) create mode 100644 include/wx/msw/private/dpiaware.h diff --git a/include/wx/msw/private/dpiaware.h b/include/wx/msw/private/dpiaware.h new file mode 100644 index 0000000000..2ff769fc35 --- /dev/null +++ b/include/wx/msw/private/dpiaware.h @@ -0,0 +1,72 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/msw/private/dpiaware.h +// Purpose: AutoSystemDpiAware class +// Author: Maarten Bent +// Created: 10/6/2016 +// Copyright: (c) Maarten Bent +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_MSW_DPI_AWARE_H_ +#define _WX_MSW_DPI_AWARE_H_ + +#ifndef WX_PRECOMP + #include "wx/msw/missing.h" +#endif + +#include "wx/dynlib.h" + +#if wxUSE_DYNLIB_CLASS + +// ---------------------------------------------------------------------------- +// Temporarily change the DPI Awareness context to System +// ---------------------------------------------------------------------------- + +class AutoSystemDpiAware +{ + #define WXDPI_AWARENESS_CONTEXT_UNAWARE ((WXDPI_AWARENESS_CONTEXT)-1) + #define WXDPI_AWARENESS_CONTEXT_SYSTEM_AWARE ((WXDPI_AWARENESS_CONTEXT)-2) + typedef WXDPI_AWARENESS_CONTEXT + (WINAPI *SetThreadDpiAwarenessContext_t)(WXDPI_AWARENESS_CONTEXT); + +public: + AutoSystemDpiAware() + : m_prevContext(WXDPI_AWARENESS_CONTEXT_UNAWARE), + m_pfnSetThreadDpiAwarenessContext((SetThreadDpiAwarenessContext_t)-1) + { + if ( m_pfnSetThreadDpiAwarenessContext == (SetThreadDpiAwarenessContext_t)-1) + { + wxLoadedDLL dllUser32("user32.dll"); + wxDL_INIT_FUNC(m_pfn, SetThreadDpiAwarenessContext, dllUser32); + } + + if ( m_pfnSetThreadDpiAwarenessContext ) + { + m_prevContext = m_pfnSetThreadDpiAwarenessContext( + WXDPI_AWARENESS_CONTEXT_SYSTEM_AWARE); + } + + } + + ~AutoSystemDpiAware() + { + if ( m_pfnSetThreadDpiAwarenessContext ) + { + m_pfnSetThreadDpiAwarenessContext(m_prevContext); + } + } + +private: + WXDPI_AWARENESS_CONTEXT m_prevContext; + + SetThreadDpiAwarenessContext_t m_pfnSetThreadDpiAwarenessContext; +}; + +#else // !wxUSE_DYNLIB_CLASS + +// Just a stub to avoid littering the code with wxUSE_DYNLIB_CLASS checks. +class AutoSystemDpiAware { }; + +#endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS + +#endif // _WX_MSW_DPI_AWARE_H_ diff --git a/src/msw/colordlg.cpp b/src/msw/colordlg.cpp index ab9a671525..38fac558cc 100644 --- a/src/msw/colordlg.cpp +++ b/src/msw/colordlg.cpp @@ -40,6 +40,7 @@ #include "wx/scopeguard.h" #include "wx/msw/private.h" +#include "wx/msw/private/dpiaware.h" #include #include @@ -216,6 +217,8 @@ int wxColourDialog::ShowModal() gs_activeDialog = this; wxON_BLOCK_EXIT_NULL(gs_activeDialog); + AutoSystemDpiAware dpiAwareness; + // do show the modal dialog if ( !::ChooseColor(&chooseColorStruct) ) { diff --git a/src/msw/filedlg.cpp b/src/msw/filedlg.cpp index ec0529c47d..1801adcbd3 100644 --- a/src/msw/filedlg.cpp +++ b/src/msw/filedlg.cpp @@ -47,6 +47,7 @@ #include "wx/scopeguard.h" #include "wx/tokenzr.h" #include "wx/modalhook.h" +#include "wx/msw/private/dpiaware.h" // ---------------------------------------------------------------------------- // constants @@ -375,6 +376,12 @@ void wxFileDialog::MSWOnTypeChange(WXHWND WXUNUSED(hDlg), int nFilterIndex) // err is filled with the CDERR_XXX constant static bool DoShowCommFileDialog(OPENFILENAME *of, long style, DWORD *err) { + // Extra controls do not handle per-monitor DPI, fall back to system DPI + // so entire file-dialog is resized. + wxScopedPtr dpiAwareness; + if ( of->Flags & OFN_ENABLEHOOK ) + dpiAwareness.reset(new AutoSystemDpiAware()); + if ( style & wxFD_SAVE ? GetSaveFileName(of) : GetOpenFileName(of) ) return true; diff --git a/src/msw/fontdlg.cpp b/src/msw/fontdlg.cpp index 610b2c21b1..29d62d2a19 100644 --- a/src/msw/fontdlg.cpp +++ b/src/msw/fontdlg.cpp @@ -37,6 +37,7 @@ #endif #include "wx/fontutil.h" +#include "wx/msw/private/dpiaware.h" #include #include @@ -149,6 +150,8 @@ int wxFontDialog::ShowModal() chooseFontStruct.Flags = flags; + AutoSystemDpiAware dpiAwareness; + if ( ChooseFont(&chooseFontStruct) != 0 ) { wxRGBToColour(m_fontData.m_fontColour, chooseFontStruct.rgbColors); From 8bff737438cb185d8032ffff1f8090a60bfce082 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Sun, 16 Oct 2016 14:44:58 +0200 Subject: [PATCH 02/21] Support DPI change in wxToolBar Manually resize the embedded controls and Realize the toolbar again. --- include/wx/msw/toolbar.h | 3 +++ src/msw/toolbar.cpp | 50 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/include/wx/msw/toolbar.h b/include/wx/msw/toolbar.h index ba3581515b..1fa4a5260b 100644 --- a/include/wx/msw/toolbar.h +++ b/include/wx/msw/toolbar.h @@ -139,6 +139,9 @@ protected: // set native toolbar padding void MSWSetPadding(WXWORD padding); + void RealizeHelper(); + void OnDPIChanged(wxDPIChangedEvent& event); + // the big bitmap containing all bitmaps of the toolbar buttons WXHBITMAP m_hBitmap; diff --git a/src/msw/toolbar.cpp b/src/msw/toolbar.cpp index dc9c50fcd8..a38bbc7bca 100644 --- a/src/msw/toolbar.cpp +++ b/src/msw/toolbar.cpp @@ -38,6 +38,7 @@ #include "wx/region.h" #include "wx/dcmemory.h" #include "wx/control.h" + #include "wx/choice.h" #include "wx/app.h" // for GetComCtl32Version #include "wx/image.h" #include "wx/stattext.h" @@ -127,6 +128,7 @@ wxBEGIN_EVENT_TABLE(wxToolBar, wxToolBarBase) EVT_MOUSE_EVENTS(wxToolBar::OnMouseEvent) EVT_SYS_COLOUR_CHANGED(wxToolBar::OnSysColourChanged) EVT_ERASE_BACKGROUND(wxToolBar::OnEraseBackground) + EVT_DPI_CHANGED(wxToolBar::OnDPIChanged) wxEND_EVENT_TABLE() // ---------------------------------------------------------------------------- @@ -1001,7 +1003,7 @@ bool wxToolBar::Realize() // Strangely, toolbar expects bitmaps with transparency to not // be premultiplied, unlike most of the rest of win32. Without this // conversion, e.g. antialiased lines would be subtly, but - // noticeably misrendered. + // noticeably misrendered. hBitmap = wxDIB(bitmap.ConvertToImage(), wxDIB::PixelFormat_NotPreMultiplied).Detach(); } @@ -1895,6 +1897,52 @@ void wxToolBar::OnEraseBackground(wxEraseEvent& event) #endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK } +void wxToolBar::RealizeHelper() +{ + Realize(); +} + +void wxToolBar::OnDPIChanged(wxDPIChangedEvent& event) +{ + // Manually scale the size of the controls. Even though the font has been + // updated, the internal size of the controls does not. + const float scaleFactor = (float)event.GetNewDPI().y / event.GetOldDPI().y; + + wxToolBarToolsList::compatibility_iterator node; + for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) + { + wxToolBarTool* const tool = static_cast(node->GetData()); + if ( !tool->IsControl() ) + continue; + + if ( wxControl* const control = tool->GetControl() ) + { + const wxSize oldSize = control->GetSize(); + wxSize newSize = oldSize * scaleFactor; + + // choice based controls seem to automatically adjust their height + // when the font size increases, keep this size + if ( dynamic_cast(control) && scaleFactor > 1 ) + newSize.y = oldSize.y; + + control->SetSize(newSize); + } + + if ( wxStaticText* const staticText = tool->GetStaticText() ) + { + // Use the best size for the label + staticText->SetSize(staticText->GetBestSize()); + } + } + + // Use CallAfter because creating the toolbar directly does sometimes not + // work. E.g. when switching from 125% to 150%. All the sizes are set + // correctly, but after all dpi events are handled, 5px of the toolbar are + // gone and a dark-gray bar appears. After resizing the window, the gray + // bar disapears as well. + CallAfter(&wxToolBar::RealizeHelper); +} + bool wxToolBar::HandleSize(WXWPARAM WXUNUSED(wParam), WXLPARAM WXUNUSED(lParam)) { // wait until we have some tools From 32aabf7a413d8e6d0d318477ee209f0c0e1d1045 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Sun, 30 Dec 2018 23:10:20 +0100 Subject: [PATCH 03/21] Update font of wxSpinCtrl when DPI changes Fix position of spin control in wxSpinCtrlDouble after DPI change The old size of the control was used to determine the position. Use GetBestSize instead, which will return the correct size. --- include/wx/msw/spinctrl.h | 1 + src/generic/spinctlg.cpp | 9 ++++++++- src/msw/spinctrl.cpp | 11 ++++++++++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/include/wx/msw/spinctrl.h b/include/wx/msw/spinctrl.h index c81ed26665..2152ca828d 100644 --- a/include/wx/msw/spinctrl.h +++ b/include/wx/msw/spinctrl.h @@ -131,6 +131,7 @@ protected: virtual bool MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) wxOVERRIDE; virtual bool MSWOnScroll(int orientation, WXWORD wParam, WXWORD pos, WXHWND control) wxOVERRIDE; + virtual void MSWUpdateFontOnDPIChange(const wxSize& newDPI) wxOVERRIDE; // handle processing of special keys void OnChar(wxKeyEvent& event); diff --git a/src/generic/spinctlg.cpp b/src/generic/spinctlg.cpp index feef3a6c5f..b49c5db77b 100644 --- a/src/generic/spinctlg.cpp +++ b/src/generic/spinctlg.cpp @@ -298,7 +298,14 @@ void wxSpinCtrlGenericBase::DoMoveWindow(int x, int y, int width, int height) wxControl::DoMoveWindow(x, y, width, height); // position the subcontrols inside the client area - wxSize sizeBtn = m_spinButton->GetSize(); + + // Use GetBestSize instead of GetSize to get the size of the spin control. + // This fixes a problem on wxMSW when the size is set after a DPI change. + // GetSize returns the old, invalid, size. GetBestSize will return the size + // that the control should be. Normally, GetBestSize and GetSize should + // always return the same value because the size of the spinButton never + // changes. + wxSize sizeBtn = m_spinButton->GetBestSize(); wxCoord wText = width - sizeBtn.x - MARGIN; m_textCtrl->SetSize(0, 0, wText, height); diff --git a/src/msw/spinctrl.cpp b/src/msw/spinctrl.cpp index 6f1e8c7864..f76ad61968 100644 --- a/src/msw/spinctrl.cpp +++ b/src/msw/spinctrl.cpp @@ -223,6 +223,14 @@ void wxSpinCtrl::OnKillFocus(wxFocusEvent& event) event.Skip(); } +void wxSpinCtrl::MSWUpdateFontOnDPIChange(const wxSize& newDPI) +{ + wxSpinButton::MSWUpdateFontOnDPIChange(newDPI); + + if ( m_font.IsOk() ) + wxSetWindowFont(GetBuddyHwnd(), m_font); +} + void wxSpinCtrl::OnSetFocus(wxFocusEvent& event) { // when we get focus, give it to our buddy window as it needs it more than @@ -577,7 +585,8 @@ bool wxSpinCtrl::SetFont(const wxFont& font) return false; } - wxSetWindowFont(GetBuddyHwnd(), GetFont()); + if ( m_font.IsOk() ) + wxSetWindowFont(GetBuddyHwnd(), m_font); return true; } From 37be4adec6c4d88289477912f05efb7e3b30f51f Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 31 Dec 2018 01:52:12 +0100 Subject: [PATCH 04/21] Don't change RICHEDIT control font on DPI change The control seems to somehow react to DPI changes on its own (which is rather mysterious as we don't forward WM_DPICHANGED to it, so it's not really clear how does it do it, but it does) and changing its font is worse than useless, as it's not just redundant, but also resets all the styles used inside the control and so is really undesirable. Hence override the just added MSWUpdateFontOnDPIChange() to do nothing for rich edit controls, while still updating the font for the plain EDIT ones (which is required as they don't scale correctly on their own). --- include/wx/msw/textctrl.h | 2 ++ src/msw/textctrl.cpp | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/include/wx/msw/textctrl.h b/include/wx/msw/textctrl.h index 5ef3128a7c..f7be3725be 100644 --- a/include/wx/msw/textctrl.h +++ b/include/wx/msw/textctrl.h @@ -240,6 +240,8 @@ protected: virtual wxSize DoGetSizeFromTextSize(int xlen, int ylen = -1) const wxOVERRIDE; #if wxUSE_RICHEDIT + virtual void MSWUpdateFontOnDPIChange(const wxSize& newDPI) wxOVERRIDE; + // Apply the character-related parts of wxTextAttr to the given selection // or the entire control if start == end == -1. // diff --git a/src/msw/textctrl.cpp b/src/msw/textctrl.cpp index 7b138bc75f..9118db73bd 100644 --- a/src/msw/textctrl.cpp +++ b/src/msw/textctrl.cpp @@ -2633,6 +2633,16 @@ wxMenu *wxTextCtrl::MSWCreateContextMenu() return m; } +void wxTextCtrl::MSWUpdateFontOnDPIChange(const wxSize& newDPI) +{ + // Don't do anything for the rich edit controls, they (somehow?) update + // their appearance on their own and changing their HFONT, as the base + // class version does, would reset all the styles used by them when the DPI + // changes, which is unwanted. + if ( !IsRich() ) + wxTextCtrlBase::MSWUpdateFontOnDPIChange(newDPI); +} + // ---------------------------------------------------------------------------- // EN_LINK processing // ---------------------------------------------------------------------------- From 123da5330605e6b8c1c44655c82232b9e7cffdae Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Tue, 1 Jan 2019 19:26:34 +0100 Subject: [PATCH 05/21] Fix wxBitmapComboBox size in high DPI Convert hard-coded sizes to DPI depended size, remove unused size. Implement MSWUpdateFontOnDPIChange() and update the control elements. --- include/wx/msw/bmpcbox.h | 1 + src/common/bmpcboxcmn.cpp | 15 +++++++++++---- src/msw/bmpcbox.cpp | 11 +++++++++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/include/wx/msw/bmpcbox.h b/include/wx/msw/bmpcbox.h index b6d5a47998..d71fc8d728 100644 --- a/include/wx/msw/bmpcbox.h +++ b/include/wx/msw/bmpcbox.h @@ -104,6 +104,7 @@ protected: WXDWORD MSWGetStyle(long style, WXDWORD *exstyle) const wxOVERRIDE; virtual bool MSWOnDraw(WXDRAWITEMSTRUCT *item) wxOVERRIDE; virtual bool MSWOnMeasure(WXMEASUREITEMSTRUCT *item) wxOVERRIDE; + virtual void MSWUpdateFontOnDPIChange(const wxSize& newDPI) wxOVERRIDE; // Event handlers void OnSize(wxSizeEvent& event); diff --git a/src/common/bmpcboxcmn.cpp b/src/common/bmpcboxcmn.cpp index 1fa3c83ffa..103da719e1 100644 --- a/src/common/bmpcboxcmn.cpp +++ b/src/common/bmpcboxcmn.cpp @@ -68,7 +68,8 @@ void wxBitmapComboBoxBase::Init() void wxBitmapComboBoxBase::UpdateInternals() { - m_fontHeight = GetControl()->GetCharHeight() + EXTRA_FONT_HEIGHT; + m_fontHeight = GetControl()->GetCharHeight() + + GetControl()->FromDIP(EXTRA_FONT_HEIGHT); while ( m_bitmaps.GetCount() < GetItemContainer()->GetCount() ) m_bitmaps.Add( new wxBitmap() ); @@ -159,7 +160,9 @@ int wxBitmapComboBoxBase::DetermineIndent() if ( m_usedImgSize.x > 0 ) { - indent = m_usedImgSize.x + IMAGE_SPACING_LEFT + IMAGE_SPACING_RIGHT; + indent = m_usedImgSize.x + + GetControl()->FromDIP(IMAGE_SPACING_LEFT) + + GetControl()->FromDIP(IMAGE_SPACING_RIGHT); m_imgAreaWidth = indent; indent -= 3; @@ -214,9 +217,12 @@ void wxBitmapComboBoxBase::DrawItem(wxDC& dc, wxCoord w = bmp.GetWidth(); wxCoord h = bmp.GetHeight(); + const wxWindow* win = const_cast(this)->GetControl(); + const int imgSpacingLeft = win->FromDIP(IMAGE_SPACING_LEFT); + // Draw the image centered dc.DrawBitmap(bmp, - rect.x + (m_usedImgSize.x-w)/2 + IMAGE_SPACING_LEFT, + rect.x + (m_usedImgSize.x-w)/2 + imgSpacingLeft, rect.y + (rect.height-h)/2, true); } @@ -235,7 +241,8 @@ wxCoord wxBitmapComboBoxBase::MeasureItem(size_t WXUNUSED(item)) const return imgHeightArea > m_fontHeight ? imgHeightArea : m_fontHeight; } - return wxBCB_DEFAULT_ITEM_HEIGHT; + const wxWindow* win = const_cast(this)->GetControl(); + return win->FromDIP(wxBCB_DEFAULT_ITEM_HEIGHT); } #endif // wxBITMAPCOMBOBOX_OWNERDRAWN_BASED diff --git a/src/msw/bmpcbox.cpp b/src/msw/bmpcbox.cpp index 6f1b9bd0e1..d2d48ab06c 100644 --- a/src/msw/bmpcbox.cpp +++ b/src/msw/bmpcbox.cpp @@ -39,8 +39,6 @@ #include "wx/odcombo.h" -#define IMAGE_SPACING_CTRL_VERTICAL 7 // Spacing used in control size calculation - // ============================================================================ // implementation @@ -532,4 +530,13 @@ bool wxBitmapComboBox::MSWOnMeasure(WXMEASUREITEMSTRUCT *item) return true; } +void wxBitmapComboBox::MSWUpdateFontOnDPIChange(const wxSize& newDPI) +{ + wxComboBox::MSWUpdateFontOnDPIChange(newDPI); + + UpdateInternals(); + + RecreateControl(); +} + #endif // wxUSE_BITMAPCOMBOBOX From fd2cf1f4e282e6b834458b372f1b3217dab17bd5 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Thu, 10 Jan 2019 21:54:16 +0100 Subject: [PATCH 06/21] Fix wx[Check]ListBox font and margin on DPI change These control are drawn using a wxDC. When the DPI changes, call SetFont to update the font of the wxDC. First call wxListBoxBase::SetFont() so m_font is updated to the new DPI, then use this font in the wxDC. For wxCheckListBox update the margins to fit the changed checkbox size. --- include/wx/msw/checklst.h | 2 ++ include/wx/msw/listbox.h | 2 ++ src/msw/checklst.cpp | 15 ++++++++++++++- src/msw/listbox.cpp | 16 ++++++++++++---- 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/include/wx/msw/checklst.h b/include/wx/msw/checklst.h index 8fa50253ba..91180c6a3e 100644 --- a/include/wx/msw/checklst.h +++ b/include/wx/msw/checklst.h @@ -81,6 +81,8 @@ protected: ProcessCommand(event); } + virtual void MSWUpdateFontOnDPIChange(const wxSize& newDPI) wxOVERRIDE; + wxSize DoGetBestClientSize() const wxOVERRIDE; wxDECLARE_EVENT_TABLE(); diff --git a/include/wx/msw/listbox.h b/include/wx/msw/listbox.h index 3ba0175320..3c910e325e 100644 --- a/include/wx/msw/listbox.h +++ b/include/wx/msw/listbox.h @@ -181,6 +181,8 @@ protected: return wxSize(w, h); } + virtual void MSWUpdateFontOnDPIChange(const wxSize& newDPI) wxOVERRIDE; + // free memory (common part of Clear() and dtor) void Free(); diff --git a/src/msw/checklst.cpp b/src/msw/checklst.cpp index 753bccc335..911dd1cb86 100644 --- a/src/msw/checklst.cpp +++ b/src/msw/checklst.cpp @@ -255,7 +255,20 @@ bool wxCheckListBox::MSWOnMeasure(WXMEASUREITEMSTRUCT *item) } return false; - } +} + +void wxCheckListBox::MSWUpdateFontOnDPIChange(const wxSize& newDPI) +{ + wxCheckListBoxBase::MSWUpdateFontOnDPIChange(newDPI); + + wxSize size = wxRendererNative::Get().GetCheckBoxSize(this); + size.x += 2 * CHECKMARK_EXTRA_SPACE + CHECKMARK_LABEL_SPACE; + + for ( unsigned int i = 0; i < GetCount(); ++i ) + { + GetItem(i)->SetMarginWidth(size.GetWidth()); + } +} // check items // ----------- diff --git a/src/msw/listbox.cpp b/src/msw/listbox.cpp index 02f2ecb9e5..128f679d2c 100644 --- a/src/msw/listbox.cpp +++ b/src/msw/listbox.cpp @@ -190,6 +190,14 @@ WXDWORD wxListBox::MSWGetStyle(long style, WXDWORD *exstyle) const return msStyle; } +void wxListBox::MSWUpdateFontOnDPIChange(const wxSize& newDPI) +{ + wxListBoxBase::MSWUpdateFontOnDPIChange(newDPI); + + if ( m_font.IsOk() ) + SetFont(m_font); +} + void wxListBox::OnInternalIdle() { wxWindow::OnInternalIdle(); @@ -695,22 +703,22 @@ bool wxListBox::MSWCommand(WXUINT param, WXWORD WXUNUSED(id)) bool wxListBox::SetFont(const wxFont &font) { + wxListBoxBase::SetFont(font); + if ( HasFlag(wxLB_OWNERDRAW) ) { const unsigned count = m_aItems.GetCount(); for ( unsigned i = 0; i < count; i++ ) - m_aItems[i]->SetFont(font); + m_aItems[i]->SetFont(m_font); // Non owner drawn list boxes update the item height on their own, but // we need to do it manually in the owner drawn case. wxClientDC dc(this); - dc.SetFont(font); + dc.SetFont(m_font); SendMessage(GetHwnd(), LB_SETITEMHEIGHT, 0, dc.GetCharHeight() + 2 * LISTBOX_EXTRA_SPACE); } - wxListBoxBase::SetFont(font); - return true; } From 56fab0aabb00513f45df6b28362d43e53479af7d Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Thu, 10 Jan 2019 22:24:45 +0100 Subject: [PATCH 07/21] Improve wxDataView on DPI change Fix the row heights after a DPI change and adjust the column widths. Use DPIChangedEvent instead of MSWUpdateFontOnDPIChange because the child controls (m_clientArea, m_headerArea) need to update their font sizes first. --- include/wx/dataview.h | 6 ++--- include/wx/generic/dataview.h | 2 ++ src/generic/datavgen.cpp | 49 ++++++++++++++++++++++++++--------- 3 files changed, 42 insertions(+), 15 deletions(-) diff --git a/include/wx/dataview.h b/include/wx/dataview.h index 193682e6d7..f6bc5a4a93 100644 --- a/include/wx/dataview.h +++ b/include/wx/dataview.h @@ -895,9 +895,9 @@ public: void SetDropEffect( wxDragResult effect ) { m_dropEffect = effect; } wxDragResult GetDropEffect() const { return m_dropEffect; } // for plaforms (currently only OSX) that support Drag/Drop insertion of items, - // this is the proposed child index for the insertion - void SetProposedDropIndex(int index) { m_proposedDropIndex = index; } - int GetProposedDropIndex() const { return m_proposedDropIndex;} + // this is the proposed child index for the insertion + void SetProposedDropIndex(int index) { m_proposedDropIndex = index; } + int GetProposedDropIndex() const { return m_proposedDropIndex;} #endif // wxUSE_DRAG_AND_DROP virtual wxEvent *Clone() const wxOVERRIDE { return new wxDataViewEvent(*this); } diff --git a/include/wx/generic/dataview.h b/include/wx/generic/dataview.h index 6742e048ba..b6fc60857e 100644 --- a/include/wx/generic/dataview.h +++ b/include/wx/generic/dataview.h @@ -316,6 +316,8 @@ protected: virtual void DoEnableSystemTheme(bool enable, wxWindow* window) wxOVERRIDE; + void OnDPIChanged(wxDPIChangedEvent& event); + public: // utility functions not part of the API // returns the "best" width for the idx-th column diff --git a/src/generic/datavgen.cpp b/src/generic/datavgen.cpp index dcb6792ca5..bca358a7e0 100644 --- a/src/generic/datavgen.cpp +++ b/src/generic/datavgen.cpp @@ -193,7 +193,7 @@ int wxDataViewColumn::GetWidth() const switch ( m_width ) { case wxCOL_WIDTH_DEFAULT: - return wxDVC_DEFAULT_WIDTH; + return wxWindow::FromDIP(wxDVC_DEFAULT_WIDTH, m_owner); case wxCOL_WIDTH_AUTOSIZE: wxCHECK_MSG( m_owner, wxDVC_DEFAULT_WIDTH, "no owner control" ); @@ -709,8 +709,7 @@ public: bool Cleared(); void Resort() { - if ( m_rowHeightCache ) - m_rowHeightCache->Clear(); + ClearRowHeightCache(); if (!IsVirtualList()) { @@ -718,6 +717,11 @@ public: } UpdateDisplay(); } + void ClearRowHeightCache() + { + if ( m_rowHeightCache ) + m_rowHeightCache->Clear(); + } SortOrder GetSortOrder() const { @@ -1188,7 +1192,8 @@ wxSize wxDataViewTextRenderer::GetSize() const return GetTextExtent(m_text); } else - return wxSize(wxDVC_DEFAULT_RENDERER_SIZE,wxDVC_DEFAULT_RENDERER_SIZE); + return GetView()->FromDIP(wxSize(wxDVC_DEFAULT_RENDERER_SIZE, + wxDVC_DEFAULT_RENDERER_SIZE)); } // --------------------------------------------------------- @@ -1251,7 +1256,8 @@ wxSize wxDataViewBitmapRenderer::GetSize() const else if (m_icon.IsOk()) return wxSize( m_icon.GetWidth(), m_icon.GetHeight() ); - return wxSize(wxDVC_DEFAULT_RENDERER_SIZE,wxDVC_DEFAULT_RENDERER_SIZE); + return GetView()->FromDIP(wxSize(wxDVC_DEFAULT_RENDERER_SIZE, + wxDVC_DEFAULT_RENDERER_SIZE)); } // --------------------------------------------------------- @@ -2770,11 +2776,8 @@ bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem & parent, const wxData } else { - if ( m_rowHeightCache ) - { - // specific position (row) is unclear, so clear whole height cache - m_rowHeightCache->Clear(); - } + // specific position (row) is unclear, so clear whole height cache + ClearRowHeightCache(); wxDataViewTreeNode *parentNode = FindNode(parent); @@ -3039,8 +3042,7 @@ bool wxDataViewMainWindow::Cleared() m_selection.Clear(); m_currentRow = (unsigned)-1; - if ( m_rowHeightCache ) - m_rowHeightCache->Clear(); + ClearRowHeightCache(); if (GetModel()) { @@ -5107,6 +5109,7 @@ void wxDataViewMainWindow::UpdateColumnSizes() wxIMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl, wxDataViewCtrlBase); wxBEGIN_EVENT_TABLE(wxDataViewCtrl, wxDataViewCtrlBase) EVT_SIZE(wxDataViewCtrl::OnSize) + EVT_DPI_CHANGED(wxDataViewCtrl::OnDPIChanged) wxEND_EVENT_TABLE() wxDataViewCtrl::~wxDataViewCtrl() @@ -5251,6 +5254,28 @@ void wxDataViewCtrl::OnSize( wxSizeEvent &WXUNUSED(event) ) } } +void wxDataViewCtrl::OnDPIChanged(wxDPIChangedEvent& event) +{ + if ( m_clientArea ) + { + m_clientArea->ClearRowHeightCache(); + m_clientArea->SetRowHeight(m_clientArea->GetDefaultRowHeight()); + } + + for ( unsigned i = 0; i < m_cols.size(); ++i ) + { + int minWidth = m_cols[i]->GetMinWidth(); + if ( minWidth > 0 ) + minWidth = minWidth * event.GetNewDPI().x / event.GetOldDPI().x; + m_cols[i]->SetMinWidth(minWidth); + + int width = m_cols[i]->WXGetManuallySetWidth(); + if ( width > 0 ) + width = width * event.GetNewDPI().x / event.GetOldDPI().x; + m_cols[i]->SetWidth(width); + } +} + void wxDataViewCtrl::SetFocus() { if (m_clientArea) From 2c6d132efea340105325dc7b65c61a57c2843633 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Sun, 13 Jan 2019 15:12:25 +0100 Subject: [PATCH 08/21] Resize wxListCtrl columns on DPI change Fix font of custom attributes in wxListCtrl on DPI change. --- include/wx/msw/listctrl.h | 4 +++ src/msw/listctrl.cpp | 62 +++++++++++++++++++++++++++++++++++---- 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/include/wx/msw/listctrl.h b/include/wx/msw/listctrl.h index da1cb79063..f35585d58f 100644 --- a/include/wx/msw/listctrl.h +++ b/include/wx/msw/listctrl.h @@ -394,6 +394,10 @@ protected: virtual void DoSetToolTip(wxToolTip *tip) wxOVERRIDE; #endif // wxUSE_TOOLTIPS + virtual void MSWUpdateFontOnDPIChange(const wxSize& newDPI) wxOVERRIDE; + + void OnDPIChanged(wxDPIChangedEvent& event); + wxSize MSWGetBestViewRect(int x, int y) const; // Implement base class pure virtual methods. diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp index d1508e1f39..d0d9b9d36b 100644 --- a/src/msw/listctrl.cpp +++ b/src/msw/listctrl.cpp @@ -265,6 +265,7 @@ private: wxBEGIN_EVENT_TABLE(wxListCtrl, wxListCtrlBase) EVT_PAINT(wxListCtrl::OnPaint) EVT_CHAR_HOOK(wxListCtrl::OnCharHook) + EVT_DPI_CHANGED(wxListCtrl::OnDPIChanged) wxEND_EVENT_TABLE() // ============================================================================ @@ -421,6 +422,46 @@ WXDWORD wxListCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const return wstyle; } +void wxListCtrl::MSWUpdateFontOnDPIChange(const wxSize& newDPI) +{ + wxListCtrlBase::MSWUpdateFontOnDPIChange(newDPI); + + for ( int i = 0; i < GetItemCount(); i++ ) + { + wxMSWListItemData *data = MSWGetItemData(i); + if ( data && data->attr && data->attr->HasFont() ) + { + wxFont f = data->attr->GetFont(); + f.WXAdjustToPPI(newDPI); + SetItemFont(i, f); + } + } + + if ( m_headerCustomDraw && m_headerCustomDraw->m_attr.HasFont() ) + { + wxItemAttr item(m_headerCustomDraw->m_attr); + wxFont f = item.GetFont(); + f.WXAdjustToPPI(newDPI); + item.SetFont(f); + + // reset the item attribute first so wxListCtrl::SetHeaderAttr + // will detect the font change + SetHeaderAttr(wxItemAttr()); + SetHeaderAttr(item); + } +} + +void wxListCtrl::OnDPIChanged(wxDPIChangedEvent &event) +{ + const int numCols = GetColumnCount(); + for ( int i = 0; i < numCols; ++i ) { + int width = GetColumnWidth(i); + if ( width > 0 ) + width = width * event.GetNewDPI().x / event.GetOldDPI().x; + SetColumnWidth(i, width); + } +} + #if WXWIN_COMPATIBILITY_3_0 // Deprecated void wxListCtrl::UpdateStyle() @@ -632,11 +673,16 @@ bool wxListCtrl::SetHeaderAttr(const wxItemAttr& attr) // Don't just reset the font if no font is specified, as the header // uses the same font as the listview control and not the ugly // default GUI font by default. - const wxFont& font = attr.HasFont() ? attr.GetFont() : GetFont(); - - // We need to tell the header about its new font to let it compute - // its new height. - wxSetWindowFont(hwndHdr, font); + if ( attr.HasFont() ) + { + wxSetWindowFont(hwndHdr, attr.GetFont()); + } + else + { + // make sure m_font is valid before using its HFONT reference + SetFont(GetFont()); + wxSetWindowFont(hwndHdr, m_font); + } } // Refreshing the listview makes it notice the change in height of its @@ -953,6 +999,12 @@ bool wxListCtrl::SetItem(wxListItem& info) data->attr->AssignFrom(attrNew); else data->attr = new wxItemAttr(attrNew); + + if ( data->attr->HasFont() ) { + wxFont f = data->attr->GetFont(); + f.WXAdjustToPPI(GetDPI()); + data->attr->SetFont(f); + } } } From a98d8448faa6eb093d76472a192151331577e51d Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Sun, 13 Jan 2019 15:23:31 +0100 Subject: [PATCH 09/21] Fix size of wxDateTimePickerCtrl after DPI change Do not use DateTime_GetIdealSize or DTM_GETIDEALSIZE. They return incorrect sizes after the DPI of the window has changed. For every DPI change, the returned size is 4 pixels higher, even if the DPI is lowered. Improve the existing method to also take the minimum height of the scroll-arrows into account. --- src/msw/datetimectrl.cpp | 55 +++++++++++++++------------------------- 1 file changed, 21 insertions(+), 34 deletions(-) diff --git a/src/msw/datetimectrl.cpp b/src/msw/datetimectrl.cpp index e1a3cd9534..604c2dcf0c 100644 --- a/src/msw/datetimectrl.cpp +++ b/src/msw/datetimectrl.cpp @@ -112,50 +112,37 @@ wxDateTime wxDateTimePickerCtrl::GetValue() const wxSize wxDateTimePickerCtrl::DoGetBestSize() const { - // Since Vista, the control can compute its best size itself, just ask it. - wxSize size; - if ( wxGetWinVersion() >= wxWinVersion_Vista ) - { - SIZE idealSize; + // Do not use DateTime_GetIdealSize / DTM_GETIDEALSIZE. It returns + // incorrect sizes after the DPI of the window has changed. For every DPI + // change, the returned size is 4 pixels higher, even if the DPI is + // lowered. - // Work around https://bugs.winehq.org/show_bug.cgi?id=44680 by - // checking for the return value: even if all "real" MSW systems do - // support this message, Wine does not, even when it's configured to - // return Vista or later version to the application. - if ( ::SendMessage(m_hWnd, DTM_GETIDEALSIZE, 0, (LPARAM)&idealSize) ) - { - size = wxSize(idealSize.cx, idealSize.cy); - } - } + wxClientDC dc(const_cast(this)); - if ( !size.x || !size.y ) - { - wxClientDC dc(const_cast(this)); - - // Use the same native format as the underlying native control. + // Use the same native format as the underlying native control. #if wxUSE_INTL - wxString s = wxDateTime::Now().Format(wxLocale::GetOSInfo(MSWGetFormat())); + wxString s = wxDateTime::Now().Format(wxLocale::GetOSInfo(MSWGetFormat())); #else // !wxUSE_INTL - wxString s("XXX-YYY-ZZZZ"); + wxString s("XXX-YYY-ZZZZ"); #endif // wxUSE_INTL/!wxUSE_INTL - // the best size for the control is bigger than just the string - // representation of the current value because the control must accommodate - // any date and while the widths of all digits are usually about the same, - // the width of the month string varies a lot, so try to account for it - s += wxS("W"); + // the best size for the control is bigger than just the string + // representation of the current value because the control must accommodate + // any date and while the widths of all digits are usually about the same, + // the width of the month string varies a lot, so try to account for it + s += wxS("W"); - size = dc.GetTextExtent(s); + wxSize size = dc.GetTextExtent(s); - // account for the drop-down arrow or spin arrows - size.x += wxSystemSettings::GetMetric(wxSYS_HSCROLL_ARROW_X, m_parent); - } + // Account for the drop-down arrow or spin arrows. + size.x += wxSystemSettings::GetMetric(wxSYS_HSCROLL_ARROW_X, m_parent); - // We need to account for the checkbox, if we have one, ourselves as - // DTM_GETIDEALSIZE doesn't seem to take it into account, at least under - // Windows 7. + int scrollY = wxSystemSettings::GetMetric(wxSYS_HSCROLL_ARROW_Y, m_parent); + size.y = wxMax(size.y, scrollY); + + // We need to account for the checkbox, if we have one. if ( MSWAllowsNone() ) - size.x += 3*GetCharWidth(); + size.x += 3 * GetCharWidth(); // In any case, adjust the height to be the same as for the text controls. size.y = EDIT_HEIGHT_FROM_CHAR_HEIGHT(size.y); From b075465645098366d1a9cce885b2d84773496875 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Sun, 3 Feb 2019 17:21:20 +0100 Subject: [PATCH 10/21] Fix wxSearchCtrl buttons on DPI change --- include/wx/generic/srchctlg.h | 2 ++ src/generic/srchctlg.cpp | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/include/wx/generic/srchctlg.h b/include/wx/generic/srchctlg.h index 79151ea5af..a123fcfab3 100644 --- a/include/wx/generic/srchctlg.h +++ b/include/wx/generic/srchctlg.h @@ -206,6 +206,8 @@ protected: void OnSize( wxSizeEvent& event ); + void OnDPIChanged(wxDPIChangedEvent& event); + bool HasMenu() const { #if wxUSE_MENUS diff --git a/src/generic/srchctlg.cpp b/src/generic/srchctlg.cpp index 88091fd239..583c6fd710 100644 --- a/src/generic/srchctlg.cpp +++ b/src/generic/srchctlg.cpp @@ -248,6 +248,7 @@ wxEND_EVENT_TABLE() wxBEGIN_EVENT_TABLE(wxSearchCtrl, wxSearchCtrlBase) EVT_SEARCH_CANCEL(wxID_ANY, wxSearchCtrl::OnCancelButton) EVT_SIZE(wxSearchCtrl::OnSize) + EVT_DPI_CHANGED(wxSearchCtrl::OnDPIChanged) wxEND_EVENT_TABLE() wxIMPLEMENT_DYNAMIC_CLASS(wxSearchCtrl, wxSearchCtrlBase); @@ -1234,6 +1235,11 @@ void wxSearchCtrl::OnSize( wxSizeEvent& WXUNUSED(event) ) LayoutControls(); } +void wxSearchCtrl::OnDPIChanged(wxDPIChangedEvent &WXUNUSED(event)) +{ + RecalcBitmaps(); +} + #if wxUSE_MENUS void wxSearchCtrl::PopupSearchMenu() From 017978a139c6e2a2f59037593467ed692f36a41a Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Sun, 17 Feb 2019 19:47:01 +0100 Subject: [PATCH 11/21] Fix font of custom attributes in wxTreeCtrl on DPI change --- include/wx/msw/treectrl.h | 1 + src/msw/treectrl.cpp | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/wx/msw/treectrl.h b/include/wx/msw/treectrl.h index eeca2d15b3..11a654429d 100644 --- a/include/wx/msw/treectrl.h +++ b/include/wx/msw/treectrl.h @@ -261,6 +261,7 @@ protected: // return true if the key was processed, false otherwise bool MSWHandleSelectionKey(unsigned vkey); + virtual void MSWUpdateFontOnDPIChange(const wxSize& newDPI) wxOVERRIDE; // data used only while editing the item label: wxTextCtrl *m_textCtrl; // text control in which it is edited diff --git a/src/msw/treectrl.cpp b/src/msw/treectrl.cpp index 8080f7cc03..12dd26bc36 100644 --- a/src/msw/treectrl.cpp +++ b/src/msw/treectrl.cpp @@ -1253,7 +1253,9 @@ void wxTreeCtrl::SetItemFont(const wxTreeItemId& item, const wxFont& font) attr = it->second; } - attr->SetFont(font); + wxFont f = font; + f.WXAdjustToPPI(GetDPI()); + attr->SetFont(f); // Reset the item's text to ensure that the bounding rect will be adjusted // for the new font. @@ -2270,6 +2272,17 @@ bool wxTreeCtrl::MSWCommand(WXUINT cmd, WXWORD id_) return true; } +void wxTreeCtrl::MSWUpdateFontOnDPIChange(const wxSize& newDPI) +{ + wxTreeCtrlBase::MSWUpdateFontOnDPIChange(newDPI); + + for ( wxMapTreeAttr::const_iterator it = m_attrs.begin(); it != m_attrs.end(); ++it ) + { + if ( it->second->HasFont() ) + SetItemFont(it->first, it->second->GetFont()); + } +} + bool wxTreeCtrl::MSWIsOnItem(unsigned flags) const { unsigned mask = TVHT_ONITEM; From 54d514489eaa7f71a205e020883305c71057d549 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Wed, 18 Sep 2019 01:26:18 +0200 Subject: [PATCH 12/21] Update custom header font after DPI change --- src/msw/headerctrl.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/msw/headerctrl.cpp b/src/msw/headerctrl.cpp index 25dcc7f632..68ee831c55 100644 --- a/src/msw/headerctrl.cpp +++ b/src/msw/headerctrl.cpp @@ -124,6 +124,7 @@ protected: virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO) wxOVERRIDE; + virtual void MSWUpdateFontOnDPIChange(const wxSize& newDPI) wxOVERRIDE; private: // override MSW-specific methods needed for new control @@ -324,6 +325,16 @@ wxSize wxMSWHeaderCtrl::DoGetBestSize() const return wxSize(wxDefaultCoord, wpos.cy); } +void wxMSWHeaderCtrl::MSWUpdateFontOnDPIChange(const wxSize& newDPI) +{ + wxControl::MSWUpdateFontOnDPIChange(newDPI); + + if ( wxMSWHeaderCtrlCustomDraw * customDraw = GetCustomDraw() ) + { + customDraw->m_attr.SetFont(m_font); + } +} + // ---------------------------------------------------------------------------- // wxMSWHeaderCtrl columns managements // ---------------------------------------------------------------------------- @@ -701,7 +712,7 @@ bool wxMSWHeaderCtrl::SetFont(const wxFont& font) if ( wxMSWHeaderCtrlCustomDraw* customDraw = GetCustomDraw() ) { - customDraw->m_attr.SetFont(font); + customDraw->m_attr.SetFont(m_font); } return true; From 370ae40b35755c58c399ed438bc2717f24cc9c63 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Sat, 28 Sep 2019 22:44:38 +0200 Subject: [PATCH 13/21] Use more FromDIP for hardcoded sizes --- samples/dataview/dataview.cpp | 22 +++++++++++----------- samples/toolbar/toolbar.cpp | 7 ++++--- src/common/choiccmn.cpp | 2 +- src/common/combocmn.cpp | 2 +- src/generic/animateg.cpp | 2 +- src/msw/anybutton.cpp | 2 +- src/msw/gauge.cpp | 4 ++-- src/richtext/richtextctrl.cpp | 2 +- 8 files changed, 22 insertions(+), 21 deletions(-) diff --git a/samples/dataview/dataview.cpp b/samples/dataview/dataview.cpp index c15d582cca..b879d3e7d8 100644 --- a/samples/dataview/dataview.cpp +++ b/samples/dataview/dataview.cpp @@ -763,7 +763,7 @@ void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned l wxDataViewTextRenderer *tr = new wxDataViewTextRenderer( "string", wxDATAVIEW_CELL_INERT ); wxDataViewColumn *column0 = - new wxDataViewColumn( "title", tr, 0, 200, wxALIGN_LEFT, + new wxDataViewColumn( "title", tr, 0, FromDIP(200), wxALIGN_LEFT, wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_RESIZABLE ); m_ctrl[Page_Music]->AppendColumn( column0 ); #if 0 @@ -776,10 +776,10 @@ void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned l tr = new wxDataViewTextRenderer( "string", wxDATAVIEW_CELL_EDITABLE ); wxDataViewColumn *column1 = - new wxDataViewColumn( "artist", tr, 1, 150, wxALIGN_LEFT, + new wxDataViewColumn( "artist", tr, 1, FromDIP(150), wxALIGN_LEFT, wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE ); - column1->SetMinWidth(150); // this column can't be resized to be smaller + column1->SetMinWidth(FromDIP(150)); // this column can't be resized to be smaller m_ctrl[Page_Music]->AppendColumn( column1 ); // column 2 of the view control: @@ -788,7 +788,7 @@ void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned l new wxDataViewSpinRenderer( 0, 2010, wxDATAVIEW_CELL_EDITABLE, wxALIGN_RIGHT | wxALIGN_CENTRE_VERTICAL); wxDataViewColumn *column2 = - new wxDataViewColumn( "year", sr, 2, 60, wxALIGN_LEFT, + new wxDataViewColumn( "year", sr, 2, FromDIP(60), wxALIGN_LEFT, wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_REORDERABLE ); m_ctrl[Page_Music]->AppendColumn( column2 ); @@ -802,19 +802,19 @@ void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned l new wxDataViewChoiceRenderer( choices, wxDATAVIEW_CELL_EDITABLE, wxALIGN_RIGHT | wxALIGN_CENTRE_VERTICAL); wxDataViewColumn *column3 = - new wxDataViewColumn( "rating", c, 3, 100, wxALIGN_LEFT, + new wxDataViewColumn( "rating", c, 3, FromDIP(100), wxALIGN_LEFT, wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE ); m_ctrl[Page_Music]->AppendColumn( column3 ); // column 4 of the view control: - m_ctrl[Page_Music]->AppendProgressColumn( "popularity", 4, wxDATAVIEW_CELL_INERT, 80 ); + m_ctrl[Page_Music]->AppendProgressColumn( "popularity", 4, wxDATAVIEW_CELL_INERT, FromDIP(80) ); // column 5 of the view control: MyCustomRenderer *cr = new MyCustomRenderer(wxDATAVIEW_CELL_ACTIVATABLE); wxDataViewColumn *column5 = - new wxDataViewColumn( "custom", cr, 5, -1, wxALIGN_LEFT, + new wxDataViewColumn( "custom", cr, 5, wxCOL_WIDTH_DEFAULT, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE ); column5->SetBitmap(wxArtProvider::GetBitmap(wxART_INFORMATION, wxART_MENU)); m_ctrl[Page_Music]->AppendColumn( column5 ); @@ -900,7 +900,7 @@ void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned l lc->AppendColumn(colRadio, "bool"); lc->AppendTextColumn( "Text" ); - lc->AppendProgressColumn( "Progress" )->SetMinWidth(100); + lc->AppendProgressColumn( "Progress" )->SetMinWidth(FromDIP(100)); wxVector data; for (unsigned int i=0; i<10; i++) @@ -957,17 +957,17 @@ void MyFrame::BuildDataViewCtrl(wxPanel* parent, unsigned int nPanel, unsigned l MultiLineCustomRenderer *tr = new MultiLineCustomRenderer(); wxDataViewColumn *column0 = - new wxDataViewColumn("title", tr, 0, 200, wxALIGN_LEFT, + new wxDataViewColumn("title", tr, 0, FromDIP(200), wxALIGN_LEFT, wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_RESIZABLE); m_ctrl[Page_VarHeight]->AppendColumn(column0); // column 1 of the view control: tr = new MultiLineCustomRenderer(); wxDataViewColumn *column1 = - new wxDataViewColumn("artist", tr, 1, 150, wxALIGN_LEFT, + new wxDataViewColumn("artist", tr, 1, FromDIP(150), wxALIGN_LEFT, wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE); - column1->SetMinWidth(150); // this column can't be resized to be smaller + column1->SetMinWidth(FromDIP(150)); // this column can't be resized to be smaller m_ctrl[Page_VarHeight]->AppendColumn(column1); } break; diff --git a/samples/toolbar/toolbar.cpp b/samples/toolbar/toolbar.cpp index 6ade05c7d2..0666e8a6f8 100644 --- a/samples/toolbar/toolbar.cpp +++ b/samples/toolbar/toolbar.cpp @@ -307,7 +307,8 @@ bool MyApp::OnInit() // Create the main frame window MyFrame* frame = new MyFrame((wxFrame *) NULL, wxID_ANY, "wxToolBar Sample", - wxPoint(100, 100), wxSize(650, 350)); + wxPoint(100, 100), wxDefaultSize); + frame->SetSize(frame->FromDIP(wxSize(650, 350))); frame->Show(true); @@ -440,7 +441,7 @@ void MyFrame::PopulateToolbar(wxToolBarBase* toolBar) // adding a combo to a vertical toolbar is not very smart if ( !toolBar->IsVertical() ) { - wxComboBox *combo = new wxComboBox(toolBar, ID_COMBO, wxEmptyString, wxDefaultPosition, wxSize(100,-1) ); + wxComboBox *combo = new wxComboBox(toolBar, ID_COMBO, wxEmptyString, wxDefaultPosition, FromDIP(wxSize(100,-1)) ); combo->Append("This"); combo->Append("is a"); combo->Append("combobox with extremely, extremely, extremely, extremely long label"); @@ -891,7 +892,7 @@ void MyFrame::OnToggleSearch(wxCommandEvent& WXUNUSED(event)) if ( !m_searchTool ) { wxSearchCtrl * const srch = new wxSearchCtrl(tb, wxID_ANY, "needle"); - srch->SetMinSize(wxSize(80, -1)); + srch->SetMinSize(FromDIP(wxSize(80, -1))); m_searchTool = tb->AddControl(srch); } else // tool already exists diff --git a/src/common/choiccmn.cpp b/src/common/choiccmn.cpp index 7018527266..5c17f9bc5e 100644 --- a/src/common/choiccmn.cpp +++ b/src/common/choiccmn.cpp @@ -107,7 +107,7 @@ wxChoiceBase::~wxChoiceBase() wxSize wxChoiceBase::DoGetBestSize() const { // a reasonable width for an empty choice list - wxSize best(80, -1); + wxSize best(FromDIP(80), -1); const unsigned int nItems = GetCount(); if ( nItems > 0 ) diff --git a/src/common/combocmn.cpp b/src/common/combocmn.cpp index 1ad0db9f63..4e87e9f75b 100644 --- a/src/common/combocmn.cpp +++ b/src/common/combocmn.cpp @@ -1374,7 +1374,7 @@ void wxComboCtrlBase::PositionTextCtrl( int textCtrlXAdjust, int textCtrlYAdjust wxSize wxComboCtrlBase::DoGetBestSize() const { - int width = m_text ? m_text->GetBestSize().x : 80; + int width = m_text ? m_text->GetBestSize().x : FromDIP(80); return GetSizeFromTextSize(width); } diff --git a/src/generic/animateg.cpp b/src/generic/animateg.cpp index 1d95134114..c27fc524a9 100644 --- a/src/generic/animateg.cpp +++ b/src/generic/animateg.cpp @@ -327,7 +327,7 @@ wxSize wxAnimationCtrl::DoGetBestSize() const if (m_animation.IsOk() && !this->HasFlag(wxAC_NO_AUTORESIZE)) return m_animation.GetSize(); - return wxSize(100, 100); + return FromDIP(wxSize(100, 100)); } void wxAnimationCtrl::SetAnimation(const wxAnimation& animation) diff --git a/src/msw/anybutton.cpp b/src/msw/anybutton.cpp index e74c535b90..76021aa0ae 100644 --- a/src/msw/anybutton.cpp +++ b/src/msw/anybutton.cpp @@ -431,7 +431,7 @@ wxSize wxMSWButton::IncreaseToStdSizeAndCache(wxControl *btn, const wxSize& size // // Note that we intentionally don't use GetDefaultSize() here, because // it's inexact -- dialog units depend on this dialog's font. - const wxSize sizeDef = btn->ConvertDialogToPixels(wxSize(50, 14)); + const wxSize sizeDef = btn->ConvertDialogToPixels(btn->FromDIP(wxSize(50, 14))); sizeBtn.IncTo(sizeDef); } diff --git a/src/msw/gauge.cpp b/src/msw/gauge.cpp index ac03441790..af7cefdee5 100644 --- a/src/msw/gauge.cpp +++ b/src/msw/gauge.cpp @@ -122,9 +122,9 @@ wxSize wxGauge::DoGetBestSize() const // the smaller one. if (HasFlag(wxGA_VERTICAL)) - return ConvertDialogToPixels(wxSize(8, 107)); + return ConvertDialogToPixels(FromDIP(wxSize(8, 107))); else - return ConvertDialogToPixels(wxSize(107, 8)); + return ConvertDialogToPixels(FromDIP(wxSize(107, 8))); } // ---------------------------------------------------------------------------- diff --git a/src/richtext/richtextctrl.cpp b/src/richtext/richtextctrl.cpp index 7840ef29a9..a369de8a37 100644 --- a/src/richtext/richtextctrl.cpp +++ b/src/richtext/richtextctrl.cpp @@ -3808,7 +3808,7 @@ void wxRichTextCtrl::OnDropFiles(wxDropFilesEvent& event) wxSize wxRichTextCtrl::DoGetBestSize() const { - return wxSize(10, 10); + return FromDIP(wxSize(10, 10)); } // ---------------------------------------------------------------------------- From b39c79cb4a9449f7713f86e7481b4f4676bf4d19 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Sat, 28 Sep 2019 22:44:58 +0200 Subject: [PATCH 14/21] Set column count to 1 in wxListCtrl with list view --- src/msw/listctrl.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp index d0d9b9d36b..ddb156bc38 100644 --- a/src/msw/listctrl.cpp +++ b/src/msw/listctrl.cpp @@ -320,6 +320,9 @@ bool wxListCtrl::Create(wxWindow *parent, if ( InReportView() ) MSWSetExListStyles(); + if ( HasFlag(wxLC_LIST) ) + m_colCount = 1; + return true; } From 85a2769ae5063d26d01ebe086f2e4f9f6ba63d7b Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Sat, 28 Sep 2019 22:45:12 +0200 Subject: [PATCH 15/21] Use the already determined hwnd in wxWindowMSW::GetDPI --- src/msw/window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/msw/window.cpp b/src/msw/window.cpp index e00ac4b25f..a4e2e0c5f4 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -4830,7 +4830,7 @@ wxSize wxWindowMSW::GetDPI() const if ( !dpi.x || !dpi.y ) { - WindowHDC hdc(GetHwnd()); + WindowHDC hdc(hwnd); dpi.x = ::GetDeviceCaps(hdc, LOGPIXELSX); dpi.y = ::GetDeviceCaps(hdc, LOGPIXELSY); } From 092d5077146960cef8ef30ce73b2528da4897fd1 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Sat, 28 Sep 2019 22:45:23 +0200 Subject: [PATCH 16/21] Update comment in wxRendererMSW::GetCheckBoxSize related to DPI --- src/msw/renderer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/msw/renderer.cpp b/src/msw/renderer.cpp index 9372afbd29..6645283603 100644 --- a/src/msw/renderer.cpp +++ b/src/msw/renderer.cpp @@ -550,8 +550,8 @@ wxRendererMSW::DrawTitleBarBitmap(wxWindow *win, wxSize wxRendererMSW::GetCheckBoxSize(wxWindow* win) { - // Even though we don't use the window in this implementation, still check - // that it's valid to avoid surprises when using themes. + // We must have a valid window in order to return the size which is correct + // for the display this window is on. wxCHECK_MSG( win, wxSize(0, 0), "Must have a valid window" ); return wxSize(wxGetSystemMetrics(SM_CXMENUCHECK, win), From 459ffcff617dd59d6129c804af8a25636782c38f Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Sat, 28 Sep 2019 23:00:33 +0200 Subject: [PATCH 17/21] Remember wxBitmapComboBox selection when recreating the control Recreate the control with the correct height when adding the first item with bitmap. --- src/msw/bmpcbox.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/msw/bmpcbox.cpp b/src/msw/bmpcbox.cpp index d2d48ab06c..1d8fc3fa7b 100644 --- a/src/msw/bmpcbox.cpp +++ b/src/msw/bmpcbox.cpp @@ -127,6 +127,7 @@ void wxBitmapComboBox::RecreateControl() // mouse-wheel behaviour. // wxString value = GetValue(); + int selection = GetSelection(); wxPoint pos = GetPosition(); wxSize size = GetSize(); size.y = GetBestSize().y; @@ -210,6 +211,8 @@ void wxBitmapComboBox::RecreateControl() // Revert the old string value if ( !HasFlag(wxCB_READONLY) ) ChangeValue(value); + else if ( selection != wxNOT_FOUND ) + SetSelection(selection); // If disabled we'll have to disable it again after re-creating if ( !IsEnabled() ) @@ -407,7 +410,7 @@ int wxBitmapComboBox::DoInsertItems(const wxArrayStringsAdapter & items, bool wxBitmapComboBox::OnAddBitmap(const wxBitmap& bitmap) { - if ( wxBitmapComboBoxBase::OnAddBitmap(bitmap) ) + if ( wxBitmapComboBoxBase::OnAddBitmap(bitmap) || !GetCount() ) { // Need to recreate control for a new measureitem call? int prevItemHeight = ::SendMessage(GetHwnd(), CB_GETITEMHEIGHT, 0, 0); From a24d58a6d32ecc6bec04984c8a9ffc82d4d0db9c Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Sat, 28 Sep 2019 23:02:12 +0200 Subject: [PATCH 18/21] Use wxWindow instead of wxDisplay for wxGraphicsContext::GetDPI --- src/common/graphcmn.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/common/graphcmn.cpp b/src/common/graphcmn.cpp index 99f1e81532..540dc4042e 100644 --- a/src/common/graphcmn.cpp +++ b/src/common/graphcmn.cpp @@ -29,10 +29,9 @@ #include "wx/pen.h" #include "wx/region.h" #include "wx/log.h" + #include "wx/window.h" #endif -#include "wx/display.h" - #ifdef __WXMSW__ #include "wx/msw/enhmeta.h" #endif @@ -624,7 +623,7 @@ void wxGraphicsContext::GetDPI( wxDouble* dpiX, wxDouble* dpiY) { if ( m_window ) { - const wxSize ppi = wxDisplay(m_window).GetPPI(); + const wxSize ppi = m_window->GetDPI(); *dpiX = ppi.x; *dpiY = ppi.y; } From 0a7c191e27f8bf793b3805aba65f32ea68344240 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Sun, 29 Sep 2019 18:31:22 +0200 Subject: [PATCH 19/21] Fix wxChoice-based control height in wxToolBar on DPI change --- src/msw/toolbar.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/msw/toolbar.cpp b/src/msw/toolbar.cpp index a38bbc7bca..4aa60f31dc 100644 --- a/src/msw/toolbar.cpp +++ b/src/msw/toolbar.cpp @@ -1920,10 +1920,15 @@ void wxToolBar::OnDPIChanged(wxDPIChangedEvent& event) const wxSize oldSize = control->GetSize(); wxSize newSize = oldSize * scaleFactor; - // choice based controls seem to automatically adjust their height - // when the font size increases, keep this size - if ( dynamic_cast(control) && scaleFactor > 1 ) - newSize.y = oldSize.y; + // Use the best height for choice-based controls. + // Scaling the current size does not work, because the control + // automatically increases size when the font-size increases. + if ( wxDynamicCast(control, wxComboBox) || + wxDynamicCast(control, wxChoice) ) + { + const wxSize bestSize = control->GetBestSize(); + newSize.y = bestSize.y; + } control->SetSize(newSize); } From 2b41ba27029f2122fcdf725a28bd17fef37399d9 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Sun, 29 Sep 2019 19:03:23 +0200 Subject: [PATCH 20/21] Apply review comments --- include/wx/msw/private/dpiaware.h | 7 ++++++- samples/toolbar/toolbar.cpp | 3 ++- src/msw/colordlg.cpp | 2 +- src/msw/filedlg.cpp | 4 ++-- src/msw/fontdlg.cpp | 2 +- src/msw/listctrl.cpp | 6 ++++-- src/msw/toolbar.cpp | 2 +- 7 files changed, 17 insertions(+), 9 deletions(-) diff --git a/include/wx/msw/private/dpiaware.h b/include/wx/msw/private/dpiaware.h index 2ff769fc35..8467ef3b30 100644 --- a/include/wx/msw/private/dpiaware.h +++ b/include/wx/msw/private/dpiaware.h @@ -2,7 +2,7 @@ // Name: wx/msw/private/dpiaware.h // Purpose: AutoSystemDpiAware class // Author: Maarten Bent -// Created: 10/6/2016 +// Created: 2016-10-06 // Copyright: (c) Maarten Bent // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -18,6 +18,9 @@ #if wxUSE_DYNLIB_CLASS +namespace wxMSWImpl +{ + // ---------------------------------------------------------------------------- // Temporarily change the DPI Awareness context to System // ---------------------------------------------------------------------------- @@ -69,4 +72,6 @@ class AutoSystemDpiAware { }; #endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS +} // namespace wxMSWImpl + #endif // _WX_MSW_DPI_AWARE_H_ diff --git a/samples/toolbar/toolbar.cpp b/samples/toolbar/toolbar.cpp index 0666e8a6f8..0c42388dac 100644 --- a/samples/toolbar/toolbar.cpp +++ b/samples/toolbar/toolbar.cpp @@ -308,7 +308,6 @@ bool MyApp::OnInit() MyFrame* frame = new MyFrame((wxFrame *) NULL, wxID_ANY, "wxToolBar Sample", wxPoint(100, 100), wxDefaultSize); - frame->SetSize(frame->FromDIP(wxSize(650, 350))); frame->Show(true); @@ -653,6 +652,8 @@ MyFrame::MyFrame(wxFrame* parent, sizer->Add(m_extraToolBar, 0, wxEXPAND, 0); #endif sizer->Add(m_textWindow, 1, wxEXPAND, 0); + + SetInitialSize(FromDIP(wxSize(650, 350))); } MyFrame::~MyFrame() diff --git a/src/msw/colordlg.cpp b/src/msw/colordlg.cpp index 38fac558cc..4eaf44f255 100644 --- a/src/msw/colordlg.cpp +++ b/src/msw/colordlg.cpp @@ -217,7 +217,7 @@ int wxColourDialog::ShowModal() gs_activeDialog = this; wxON_BLOCK_EXIT_NULL(gs_activeDialog); - AutoSystemDpiAware dpiAwareness; + wxMSWImpl::AutoSystemDpiAware dpiAwareness; // do show the modal dialog if ( !::ChooseColor(&chooseColorStruct) ) diff --git a/src/msw/filedlg.cpp b/src/msw/filedlg.cpp index 1801adcbd3..737b001439 100644 --- a/src/msw/filedlg.cpp +++ b/src/msw/filedlg.cpp @@ -378,9 +378,9 @@ static bool DoShowCommFileDialog(OPENFILENAME *of, long style, DWORD *err) { // Extra controls do not handle per-monitor DPI, fall back to system DPI // so entire file-dialog is resized. - wxScopedPtr dpiAwareness; + wxScopedPtr dpiAwareness; if ( of->Flags & OFN_ENABLEHOOK ) - dpiAwareness.reset(new AutoSystemDpiAware()); + dpiAwareness.reset(new wxMSWImpl::AutoSystemDpiAware()); if ( style & wxFD_SAVE ? GetSaveFileName(of) : GetOpenFileName(of) ) return true; diff --git a/src/msw/fontdlg.cpp b/src/msw/fontdlg.cpp index 29d62d2a19..06b73674ac 100644 --- a/src/msw/fontdlg.cpp +++ b/src/msw/fontdlg.cpp @@ -150,7 +150,7 @@ int wxFontDialog::ShowModal() chooseFontStruct.Flags = flags; - AutoSystemDpiAware dpiAwareness; + wxMSWImpl::AutoSystemDpiAware dpiAwareness; if ( ChooseFont(&chooseFontStruct) != 0 ) { diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp index ddb156bc38..aa5afe781c 100644 --- a/src/msw/listctrl.cpp +++ b/src/msw/listctrl.cpp @@ -457,7 +457,8 @@ void wxListCtrl::MSWUpdateFontOnDPIChange(const wxSize& newDPI) void wxListCtrl::OnDPIChanged(wxDPIChangedEvent &event) { const int numCols = GetColumnCount(); - for ( int i = 0; i < numCols; ++i ) { + for ( int i = 0; i < numCols; ++i ) + { int width = GetColumnWidth(i); if ( width > 0 ) width = width * event.GetNewDPI().x / event.GetOldDPI().x; @@ -1003,7 +1004,8 @@ bool wxListCtrl::SetItem(wxListItem& info) else data->attr = new wxItemAttr(attrNew); - if ( data->attr->HasFont() ) { + if ( data->attr->HasFont() ) + { wxFont f = data->attr->GetFont(); f.WXAdjustToPPI(GetDPI()); data->attr->SetFont(f); diff --git a/src/msw/toolbar.cpp b/src/msw/toolbar.cpp index 4aa60f31dc..1a40d6f65d 100644 --- a/src/msw/toolbar.cpp +++ b/src/msw/toolbar.cpp @@ -1940,7 +1940,7 @@ void wxToolBar::OnDPIChanged(wxDPIChangedEvent& event) } } - // Use CallAfter because creating the toolbar directly does sometimes not + // Use CallAfter because creating the toolbar directly sometimes doesn't // work. E.g. when switching from 125% to 150%. All the sizes are set // correctly, but after all dpi events are handled, 5px of the toolbar are // gone and a dark-gray bar appears. After resizing the window, the gray From 059838f5ed3fdbdeb9dd3ff4316efda0aa2de46d Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 29 Sep 2019 23:21:55 +0200 Subject: [PATCH 21/21] Compilation fix for PCH-less build Include wx/combobox.h as we use wxDynamicCast(wxComboBox). --- src/msw/toolbar.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/msw/toolbar.cpp b/src/msw/toolbar.cpp index 1a40d6f65d..8f03aee595 100644 --- a/src/msw/toolbar.cpp +++ b/src/msw/toolbar.cpp @@ -39,6 +39,7 @@ #include "wx/dcmemory.h" #include "wx/control.h" #include "wx/choice.h" + #include "wx/combobox.h" #include "wx/app.h" // for GetComCtl32Version #include "wx/image.h" #include "wx/stattext.h"