Implement wxDC mirroring for RTL layout with GTK3
Co-Authored-By: AliKet <aliket1435@gmail.com>
This commit is contained in:
176
src/gtk/dc.cpp
176
src/gtk/dc.cpp
@@ -25,17 +25,14 @@
|
||||
wxGTKCairoDCImpl::wxGTKCairoDCImpl(wxDC* owner)
|
||||
: wxGCDCImpl(owner)
|
||||
{
|
||||
m_layoutDir = wxLayout_Default;
|
||||
}
|
||||
|
||||
wxGTKCairoDCImpl::wxGTKCairoDCImpl(wxDC* owner, double scaleFactor)
|
||||
: wxGCDCImpl(owner, 0)
|
||||
{
|
||||
m_contentScaleFactor = scaleFactor;
|
||||
}
|
||||
|
||||
wxGTKCairoDCImpl::wxGTKCairoDCImpl(wxDC* owner, wxWindow* window)
|
||||
wxGTKCairoDCImpl::wxGTKCairoDCImpl(wxDC* owner, wxWindow* window, wxLayoutDirection dir, int width)
|
||||
: wxGCDCImpl(owner, 0)
|
||||
, m_size(width, 0)
|
||||
{
|
||||
m_layoutDir = dir;
|
||||
if ( window )
|
||||
{
|
||||
m_window = window;
|
||||
@@ -62,6 +59,12 @@ void wxGTKCairoDCImpl::DoDrawBitmap(const wxBitmap& bitmap, int x, int y, bool u
|
||||
if (cr)
|
||||
{
|
||||
cairo_save(cr);
|
||||
if (m_layoutDir == wxLayout_RightToLeft)
|
||||
{
|
||||
// bitmap is not mirrored
|
||||
cairo_scale(cr, -1, 1);
|
||||
x = -x - bitmap.GetWidth();
|
||||
}
|
||||
bitmap.Draw(cr, x, y, useMask, &m_textForegroundColour, &m_textBackgroundColour);
|
||||
cairo_restore(cr);
|
||||
}
|
||||
@@ -81,6 +84,108 @@ bool wxGTKCairoDCImpl::DoFloodFill(int x, int y, const wxColour& col, wxFloodFil
|
||||
}
|
||||
#endif
|
||||
|
||||
void wxGTKCairoDCImpl::DoDrawText(const wxString& text, int x, int y)
|
||||
{
|
||||
wxCHECK_RET(IsOk(), "invalid DC");
|
||||
|
||||
if (text.empty())
|
||||
return;
|
||||
|
||||
if (m_layoutDir == wxLayout_RightToLeft && text.find('\n') != wxString::npos)
|
||||
{
|
||||
// RTL needs each line separately to position text properly.
|
||||
// DrawLabel() will split the text and call back for each line.
|
||||
GetOwner()->DrawLabel(text, wxRect(x, y, 0, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
int w, h;
|
||||
DoGetTextExtent(text, &w, &h);
|
||||
|
||||
CalcBoundingBox(x, y);
|
||||
CalcBoundingBox(x + w, y + h);
|
||||
|
||||
if (m_layoutDir == wxLayout_RightToLeft)
|
||||
{
|
||||
m_graphicContext->PushState();
|
||||
// text is not mirrored
|
||||
m_graphicContext->Scale(-1, 1);
|
||||
x = -x - w;
|
||||
}
|
||||
|
||||
wxCompositionMode curMode = m_graphicContext->GetCompositionMode();
|
||||
m_graphicContext->SetCompositionMode(wxCOMPOSITION_OVER);
|
||||
|
||||
if (m_backgroundMode == wxBRUSHSTYLE_TRANSPARENT)
|
||||
m_graphicContext->DrawText(text, x, y);
|
||||
else
|
||||
m_graphicContext->DrawText(text, x, y, m_graphicContext->CreateBrush(m_textBackgroundColour));
|
||||
|
||||
m_graphicContext->SetCompositionMode(curMode);
|
||||
|
||||
if (m_layoutDir == wxLayout_RightToLeft)
|
||||
m_graphicContext->PopState();
|
||||
}
|
||||
|
||||
void wxGTKCairoDCImpl::DoDrawRotatedText(const wxString& text, int x, int y, double angle)
|
||||
{
|
||||
wxCHECK_RET(IsOk(), "invalid DC");
|
||||
|
||||
// save current bounding box
|
||||
// rotation will cause DoDrawText() to update it incorrectly
|
||||
const bool isBBoxValid = m_isBBoxValid;
|
||||
const int minX = m_minX;
|
||||
const int minY = m_minY;
|
||||
const int maxX = m_maxX;
|
||||
const int maxY = m_maxY;
|
||||
|
||||
const double rad = wxDegToRad(-angle);
|
||||
m_graphicContext->PushState();
|
||||
m_graphicContext->Translate(x, y);
|
||||
m_graphicContext->Rotate(rad);
|
||||
DoDrawText(text, 0, 0);
|
||||
m_graphicContext->PopState();
|
||||
|
||||
// restore bounding box and update it correctly
|
||||
m_isBBoxValid = isBBoxValid;
|
||||
m_minX = minX;
|
||||
m_minY = minY;
|
||||
m_maxX = maxX;
|
||||
m_maxY = maxY;
|
||||
|
||||
CalcBoundingBox(x, y);
|
||||
int w, h;
|
||||
DoGetTextExtent(text, &w, &h);
|
||||
cairo_matrix_t m;
|
||||
cairo_matrix_init_translate(&m, x, y);
|
||||
cairo_matrix_rotate(&m, rad);
|
||||
double xx = w, yy = 0;
|
||||
cairo_matrix_transform_point(&m, &xx, &yy);
|
||||
CalcBoundingBox(int(xx), int(yy));
|
||||
xx = w; yy = h;
|
||||
cairo_matrix_transform_point(&m, &xx, &yy);
|
||||
CalcBoundingBox(int(xx), int(yy));
|
||||
xx = 0; yy = h;
|
||||
cairo_matrix_transform_point(&m, &xx, &yy);
|
||||
CalcBoundingBox(int(xx), int(yy));
|
||||
}
|
||||
|
||||
void wxGTKCairoDCImpl::DoDrawCheckMark(int x, int y, int width, int height)
|
||||
{
|
||||
if (m_layoutDir == wxLayout_RightToLeft)
|
||||
{
|
||||
wxCHECK_RET(IsOk(), "invalid DC");
|
||||
|
||||
// checkmark is not mirrored
|
||||
m_graphicContext->PushState();
|
||||
m_graphicContext->Scale(-1, 1);
|
||||
BaseType::DoDrawCheckMark(-x - width, y, width, height);
|
||||
m_graphicContext->PopState();
|
||||
}
|
||||
else
|
||||
BaseType::DoDrawCheckMark(x, y, width, height);
|
||||
}
|
||||
|
||||
wxBitmap wxGTKCairoDCImpl::DoGetAsBitmap(const wxRect* /*subrect*/) const
|
||||
{
|
||||
wxFAIL_MSG("DoGetAsBitmap not implemented");
|
||||
@@ -183,6 +288,12 @@ bool wxGTKCairoDCImpl::DoStretchBlit(int xdest, int ydest, int dstWidth, int dst
|
||||
}
|
||||
}
|
||||
cairo_save(cr);
|
||||
if (m_layoutDir == wxLayout_RightToLeft)
|
||||
{
|
||||
// blit is not mirrored
|
||||
cairo_scale(cr, -1, 1);
|
||||
xdest = -xdest - dstWidth;
|
||||
}
|
||||
cairo_translate(cr, xdest, ydest);
|
||||
cairo_rectangle(cr, 0, 0, dstWidth, dstHeight);
|
||||
double sx, sy;
|
||||
@@ -250,6 +361,40 @@ wxSize wxGTKCairoDCImpl::GetPPI() const
|
||||
return wxGCDCImpl::GetPPI();
|
||||
}
|
||||
|
||||
void wxGTKCairoDCImpl::SetLayoutDirection(wxLayoutDirection dir)
|
||||
{
|
||||
if (dir == wxLayout_Default && m_window)
|
||||
dir = m_window->GetLayoutDirection();
|
||||
|
||||
if (m_layoutDir != dir)
|
||||
{
|
||||
if (m_graphicContext)
|
||||
{
|
||||
if (dir == wxLayout_RightToLeft)
|
||||
{
|
||||
// wxDC is mirrored for RTL
|
||||
m_graphicContext->Translate(m_size.x, 0);
|
||||
m_graphicContext->Scale(-1, 1);
|
||||
}
|
||||
else if (m_layoutDir == wxLayout_RightToLeft)
|
||||
{
|
||||
m_graphicContext->Scale(-1, 1);
|
||||
m_graphicContext->Translate(-m_size.x, 0);
|
||||
}
|
||||
}
|
||||
|
||||
m_layoutDir = dir;
|
||||
}
|
||||
}
|
||||
|
||||
wxLayoutDirection wxGTKCairoDCImpl::GetLayoutDirection() const
|
||||
{
|
||||
// LTR unless explicitly RTL
|
||||
return
|
||||
m_layoutDir == wxLayout_RightToLeft
|
||||
? wxLayout_RightToLeft
|
||||
: wxLayout_LeftToRight;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
wxWindowDCImpl::wxWindowDCImpl(wxWindowDC* owner, wxWindow* window)
|
||||
@@ -292,6 +437,8 @@ wxWindowDCImpl::wxWindowDCImpl(wxWindowDC* owner, wxWindow* window)
|
||||
}
|
||||
if (x || y)
|
||||
SetDeviceLocalOrigin(x, y);
|
||||
|
||||
SetLayoutDirection(wxLayout_Default);
|
||||
}
|
||||
else
|
||||
SetGraphicsContext(wxGraphicsContext::Create());
|
||||
@@ -326,6 +473,7 @@ wxClientDCImpl::wxClientDCImpl(wxClientDC* owner, wxWindow* window)
|
||||
cairo_clip(cr);
|
||||
SetDeviceLocalOrigin(a.x, a.y);
|
||||
}
|
||||
SetLayoutDirection(wxLayout_Default);
|
||||
}
|
||||
else
|
||||
SetGraphicsContext(wxGraphicsContext::Create());
|
||||
@@ -342,6 +490,8 @@ wxPaintDCImpl::wxPaintDCImpl(wxPaintDC* owner, wxWindow* window)
|
||||
wxGraphicsContext* gc = wxGraphicsContext::CreateFromNative(cr);
|
||||
gc->EnableOffset(m_contentScaleFactor <= 1);
|
||||
SetGraphicsContext(gc);
|
||||
// context is already adjusted for RTL
|
||||
m_layoutDir = window->GetLayoutDirection();
|
||||
}
|
||||
|
||||
void wxPaintDCImpl::DestroyClippingRegion()
|
||||
@@ -433,15 +583,23 @@ void wxMemoryDCImpl::Setup()
|
||||
gc->EnableOffset(m_contentScaleFactor <= 1);
|
||||
}
|
||||
SetGraphicsContext(gc);
|
||||
|
||||
// re-apply layout direction
|
||||
const wxLayoutDirection dir = m_layoutDir;
|
||||
m_layoutDir = wxLayout_Default;
|
||||
SetLayoutDirection(dir);
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
wxGTKCairoDC::wxGTKCairoDC(cairo_t* cr, wxWindow* window)
|
||||
: wxDC(new wxGTKCairoDCImpl(this, window->GetContentScaleFactor()))
|
||||
wxGTKCairoDC::wxGTKCairoDC(cairo_t* cr, wxWindow* window, wxLayoutDirection dir, int width)
|
||||
: wxDC(new wxGTKCairoDCImpl(this, window, dir, width))
|
||||
{
|
||||
wxGraphicsContext* gc = wxGraphicsContext::CreateFromNative(cr);
|
||||
gc->EnableOffset(window->GetContentScaleFactor() <= 1);
|
||||
SetGraphicsContext(gc);
|
||||
if (dir == wxLayout_Default)
|
||||
SetLayoutDirection(window->GetLayoutDirection());
|
||||
// else context is already adjusted for RTL
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
Reference in New Issue
Block a user