wxWidgets / wxWidgets

Cross-Platform C++ GUI Library
https://www.wxwidgets.org/
6.13k stars 1.77k forks source link

wxTextCtrl with wxTE_RICH style causing too big font size in high dpi awareness environment #24189

Open richSpiegel opened 9 months ago

richSpiegel commented 9 months ago

Setup:

Procedure: Using the text sample, I create the frame in App::OnInit() with position on 4k monitor: MyFrame *frame = new MyFrame("Text wxWidgets sample", -3800, 50); The rich text control´s font is a lot bigger than it´s supposed to be.

Assumption: Values passed during creation of wxTextCtrl using wxTE_RICH style will be zoomed one time: void wxTextCtrl::MSWSetRichZoom() Text values set later during runtime won´t!

textSample

vadz commented 9 months ago

Just to make it clear, you see this with unmodified text sample? Because I don't, at least not on a system with a single 200% DPI monitor.

Also, could you please explain the MSWSetRichZoom() part?

richSpiegel commented 9 months ago

Apart from the position of the frame – Yes! You won´t see this bug, when having only a single monitor, as that one is of course the primary display. The conditions are: Standard monitor (primary), second monitor a high dpi display. The text sample app must now create a frame on that high dpi display, then the described scenario happens. Concerning: MSWSetRichZoom() It is called when style is wxTE_RICH // Determine the system DPI and the DPI of the display the rich control // is shown on, and calculate and apply the scaling factor. // When this control is created in a (wxFrame) constructor the zoom is // not correctly applied, use CallAfter to delay setting the zoom. m_richDPIscale = GetDPI().y / (float)::GetDeviceCaps(ScreenHDC(), LOGPIXELSY); CallAfter(&wxTextCtrl::MSWSetRichZoom); There might be a timing problem OR the m_richDPIscale has not been calculated correctly, because I noticed that when the high dpi monitor is not primary it uses the default std. monitor geometry.

richSpiegel commented 9 months ago

I also found this comment in the code which you can make use of more then me: // Rich text controls need temporary scaling when they are created on a // display with non-system DPI. float m_richDPIscale; What is a non-system DPI?

MaartenBent commented 9 months ago

DPI different than the primary monitor. I can reproduce it. Can you test with this line disabled? https://github.com/wxWidgets/wxWidgets/blob/3dde6bdeb0cec5af8b81a231b9deb851d975a2c2/src/msw/textctrl.cpp#L706

It seems the zoom correction is only needed after the first DPI change.

richSpiegel commented 9 months ago

Well, I tried that too, however it seems to have side effects: The font size is very small in text controls using wxTE_RICH2 style and even worse: If text is added in the ctor it is smaller than the text added the moment I edit the background color! On my system the zooming starts here: m_textrich->SetDefaultStyle(wxTextAttr(*wxCYAN, *wxBLUE)); m_textrich->AppendText("This text should be cyan on blue\n"); Maybe because the background of the text ctrl is changed, which triggers something msw intern?! 4kNoZooming Because when I change the style by defining a background color: m_textrich->SetDefaultStyle(wxTextAttr(*wxBLACK, *wxGREEN)); the appearance is this: textSampleBGchanged Doing this: m_textrich->SetDefaultStyle (wxTextAttr (*wxGREEN, wxNullColour, *wxITALIC_FONT)); results in this: textSampleBG_NullColor

Btw.:

  1. I have a different code base: The corresponding line I commented out is 684 yours is 706! The revision I use is SHA-1: 1d7f2becd49ffe1f32f5a1a5bcb9c48b1771fc45
  2. I adjusted the sample a little bit by introducing FromDIP e.g. here: m_enter = new MyTextCtrl( this, 100, "Multiline, allow <ENTER> processing.", FromDIP (wxPoint(180,170)), FromDIP (wxSize(200,70)), wxTE_MULTILINE | wxTE_PROCESS_ENTER | wxTE_RICH2 ); This makes no difference concerning the font size - the frame and text ctrls just look more proportional