summaryrefslogtreecommitdiff
path: root/wx+/rtl.h
blob: 42af52e19964aa8194d0781615becedff1e7960c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// *****************************************************************************
// * This file is part of the FreeFileSync project. It is distributed under    *
// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0          *
// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved *
// *****************************************************************************

#ifndef RTL_H_0183487180058718273432148
#define RTL_H_0183487180058718273432148

#include <wx/dcmemory.h>
#include <wx/image.h>
#include <wx/app.h>
#include "dc.h"


namespace zen
{
//functions supporting right-to-left GUI layout
void drawBitmapRtlMirror  (wxDC& dc, const wxImage& img, const wxRect& rect, int alignment, std::optional<wxBitmap>& buffer);
void drawBitmapRtlNoMirror(wxDC& dc, const wxImage& img, const wxRect& rect, int alignment);
//wxDC::DrawIcon DOES mirror by default -> implement RTL support when needed

wxImage mirrorIfRtl(const wxImage& img);

//manual text flow correction: https://www.w3.org/International/articles/inline-bidi-markup/








//---------------------- implementation ------------------------
namespace impl
{
//don't use wxDC::DrawLabel:
//  - expensive GetTextExtent() call even when passing an empty string!!!
//  - 1-off alignment bugs!
inline
void drawBitmapAligned(wxDC& dc, const wxImage& img, const wxRect& rect, int alignment)
{
    wxPoint pt = rect.GetTopLeft();
    if (alignment & wxALIGN_RIGHT) //note: wxALIGN_LEFT == 0!
        pt.x += rect.width - img.GetWidth();
    else if (alignment & wxALIGN_CENTER_HORIZONTAL)
        pt.x += (rect.width - img.GetWidth()) / 2;

    if (alignment & wxALIGN_BOTTOM) //note: wxALIGN_TOP == 0!
        pt.y += rect.height - img.GetHeight();
    else if (alignment & wxALIGN_CENTER_VERTICAL)
        pt.y += (rect.height - img.GetHeight()) / 2;

    dc.DrawBitmap(toScaledBitmap(img), pt);
}
}


inline
void drawBitmapRtlMirror(wxDC& dc, const wxImage& img, const wxRect& rect, int alignment, std::optional<wxBitmap>& buffer)
{
    switch (dc.GetLayoutDirection())
    {
        case wxLayout_LeftToRight:
            return impl::drawBitmapAligned(dc, img, rect, alignment);

        case wxLayout_RightToLeft:
            if (rect.GetWidth() > 0 && rect.GetHeight() > 0)
        {
            if (!buffer || buffer->GetSize() != rect.GetSize()) //[!] since we do a mirror, width needs to match exactly!
                buffer.emplace(rect.GetSize());

            if (buffer->GetScaleFactor() != dc.GetContentScaleFactor()) //needed here?
                buffer->SetScaleFactor(dc.GetContentScaleFactor());     //

            wxMemoryDC memDc(*buffer); //copies scale factor from wxBitmap
            memDc.Blit(wxPoint(0, 0), rect.GetSize(), &dc, rect.GetTopLeft()); //blit in: background is mirrored due to memDc, dc having different layout direction!

            impl::drawBitmapAligned(memDc, img, wxRect(0, 0, rect.width, rect.height), alignment);
            //note: we cannot simply use memDc.SetLayoutDirection(wxLayout_RightToLeft) due to some strange 1 pixel bug! 2022-04-04: maybe fixed in wxWidgets 3.1.6?

            dc.Blit(rect.GetTopLeft(), rect.GetSize(), &memDc, wxPoint(0, 0)); //blit out: mirror once again
        }
        break;

        case wxLayout_Default: //CAVEAT: wxPaintDC/wxMemoryDC on wxGTK/wxMAC does not implement SetLayoutDirection()!!! => GetLayoutDirection() == wxLayout_Default
            if (wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft)
                return impl::drawBitmapAligned(dc, img.Mirror(), rect, alignment);
            else
                return impl::drawBitmapAligned(dc, img, rect, alignment);
    }
}


inline
void drawBitmapRtlNoMirror(wxDC& dc, const wxImage& img, const wxRect& rect, int alignment)
{
    return impl::drawBitmapAligned(dc, img, rect, alignment); //wxDC::DrawBitmap does NOT mirror by default
}


inline
wxImage mirrorIfRtl(const wxImage& img)
{
    if (wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft)
        return img.Mirror();
    else
        return img;
}
}

#endif //RTL_H_0183487180058718273432148
bgstack15