Opened 22 months ago

Closed 4 months ago

Last modified 4 months ago

#15031 closed defect (fixed)

wxStatusBar not redrawn correctly when using RTL in wxMSW

Reported by: vadz Owned by: VZ
Priority: normal Milestone: 3.1.0
Component: wxMSW Version: dev-latest
Keywords: RTL child window Cc:
Blocked By: Blocking:
Patch: yes

Description

Applying this patch

  • samples/minimal/minimal.cpp

    a b bool MyApp::OnInit() 
    167167    SetMenuBar(menuBar); 
    168168#endif // wxUSE_MENUS 
    169169 
     170    SetLayoutDirection(wxLayout_RightToLeft); 
     171 
    170172#if wxUSE_STATUSBAR 
    171173    // create a status bar just for fun (by default with 1 pane only) 
    172174    CreateStatusBar(2); 

and resizing the window vertically shows traces of status bar over the frame client area.

Attachments (4)

status-bar-RTL.png download (16.7 KB) - added by awi 4 months ago.
Artifacts during resizing.
Parent-window-RTL-mode-has-precedence.patch download (1.1 KB) - added by awi 4 months ago.
Parent window layout has precedence over application settings.
Parent-window-RTL-mode-has-precedence.2.patch download (1.4 KB) - added by awi 4 months ago.
Parent window layout has precedence over application settings.
Update-layout-in-the-client-area-after-changing-RTL-flag.patch download (331 bytes) - added by awi 4 months ago.
Update client area if RTL flag has been changed.

Download all attachments as: .zip

Change History (13)

comment:1 Changed 4 months ago by awi

  • Keywords child window added
  • Patch set
  • Status changed from new to confirmed
  • Version set to dev-latest

I can confirm this issue - see attached screenshot.
Artifacts during resizing.
These artficts appear when main window is resized in both directions at once ('diagonally').

In fact, wxStatusBar itself is OK with regards to this issue and it is involved only because it is a child window of wxFrame in the test case.
The cause of the problem is incorrect positioning of the child windows when there is a discrepancy between RTL layout of the application and RTL layout of the parent window. In the test case the application is set to default LTR mode but wxFrame window is set explicitly to RTL mode. Currently, child window (e.g. wxStatusBar) always (and only) checks RTL layout of the application and based on this check its horizontal position is mirrored or not. But if parent window has a different layout direction then application then this position is interpreted by the parent in a wrong way.

To fix this issue there is necessary to check first for RTL layout of parent window (if it exists) and next if there is no parent check for RTL layout of the application.
attachment:Parent-window-RTL-mode-has-precedence.patch

Another small fix is unrelated to to the issue. In http://msdn.microsoft.com/en-us/goglobal/bb688119.aspx#EDC there is claimed that when RTL flag for window is changed then window client area should be updated to refresh the view. At the moment this is not done.
attachment:Update-layout-in-the-client-area-after-changing-RTL-flag.patch

Changed 4 months ago by awi

Artifacts during resizing.

comment:2 follow-up: Changed 4 months ago by vadz

  • Milestone set to 3.1.0

I wonder if we shouldn't add something like wxWindow::GetEffectiveLayoutDirection() which would always return either wxLayout_LeftToRight or wxLayout_RightToLeft, i.e. go to the parent window and/or the application object if the window doesn't have any specific layout style associated with it. Because it seems like this shouldn't be the only place where it would be useful. What do you think?

Changed 4 months ago by awi

Parent window layout has precedence over application settings.

Changed 4 months ago by awi

Parent window layout has precedence over application settings.

Changed 4 months ago by awi

Update client area if RTL flag has been changed.

comment:3 in reply to: ↑ 2 Changed 4 months ago by awi

Replying to vadz:

I wonder if we shouldn't add something like wxWindow::GetEffectiveLayoutDirection() which would always return either wxLayout_LeftToRight or wxLayout_RightToLeft, i.e. go to the parent window and/or the application object if the window doesn't have any specific layout style associated with it.

It seems that current situation looks like:

  1. TLW inherits RTL attribute from the application (in wxTopLevelWindowMSW::CreateFrame).
  2. Child window inherits by default RTL attribute from its parent window (http://msdn.microsoft.com/en-us/library/windows/desktop/ms632599%28v=vs.85%29.aspx#layout_mirroring).
  3. Non-TLW without parent doesn't inherit RTL attribute from anywhere and then it has assigned left-to-right layout by default.
  4. Every further explicit change of the layout via SetLayoutDirection() changes 'physical' WS_EX_LAYOUTRTL flag for the window.

Becaue GetLayoutDirection() directly checks WS_EX_LAYOUTRTL flag I think we can assume it returns reliable and accurate value and this function should be sufficient, at least under wxMSW.

comment:4 Changed 4 months ago by awi

Modified patch (using dedicated Win API) to mirror window coordinates based on parent window layout settings is attached.

attachment:Parent-window-RTL-mode-has-precedence.2.patch

comment:5 Changed 4 months ago by vadz

Thanks! I'm going to apply the second patch and also the one refreshing the window on layout change (I also think we need SendSizeEvent() in it to ensure that the children are relaid out if necessary, so I'll add it too).

comment:6 Changed 4 months ago by VZ

In 76979:

Refresh the window when its layout direction changes in wxMSW.

Rearrange the window children and/or redraw its contents when its layout
direction changes.

See #15031.

comment:7 Changed 4 months ago by VZ

  • Owner set to VZ
  • Resolution set to fixed
  • Status changed from confirmed to closed

In 76980:

Fix window position calculation in wxMSW when using RTL.

Just use the native ::MapWindowPoints() to do the coordinate transformation
instead of doing it ourselves: we did it wrongly by inheriting the layout
direction from wxTheApp instead of from the parent window, so fix this in the
best possible way by not doing it at all and just relying on Windows to do it
for us.

In particular, this corrects the display of wxStatusBar in RTL frames.

Closes #15031.

comment:8 Changed 4 months ago by VZ

In 76991:

Refresh the window when its layout direction changes in wxMSW.

Rearrange the window children and/or redraw its contents when its layout
direction changes.

See #15031.

comment:9 Changed 4 months ago by VZ

In 76992:

Fix window position calculation in wxMSW when using RTL.

Just use the native ::MapWindowPoints() to do the coordinate transformation
instead of doing it ourselves: we did it wrongly by inheriting the layout
direction from wxTheApp instead of from the parent window, so fix this in the
best possible way by not doing it at all and just relying on Windows to do it
for us.

In particular, this corrects the display of wxStatusBar in RTL frames.

Closes #15031.

Note: See TracTickets for help on using tickets.