// ***************************************************************************** // * 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 DC_H_4987123956832143243214 #define DC_H_4987123956832143243214 #include #include #include //for macro: wxALWAYS_NATIVE_DOUBLE_BUFFER namespace zen { /* 1. wxDCClipper does *not* stack: another fix for yet another poor wxWidgets implementation class RecursiveDcClipper { RecursiveDcClipper(wxDC& dc, const wxRect& r) : dc_(dc) }; ------------------------------------------------------------------------------------------------ 2. wxAutoBufferedPaintDC skips one pixel on left side when RTL layout is active: a fix for a poor wxWidgets implementation class BufferedPaintDC { BufferedPaintDC(wxWindow& wnd, std::unique_ptr& buffer); }; */ inline void clearArea(wxDC& dc, const wxRect& rect, const wxColor& col) { wxDCPenChanger dummy (dc, col); wxDCBrushChanger dummy2(dc, col); dc.DrawRectangle(rect); } //---------------------- implementation ------------------------ class RecursiveDcClipper { public: RecursiveDcClipper(wxDC& dc, const wxRect& r) : dc_(dc) { auto it = refDcToAreaMap().find(&dc); if (it != refDcToAreaMap().end()) { oldRect_ = it->second; wxRect tmp = r; tmp.Intersect(*oldRect_); //better safe than sorry dc_.SetClippingRegion(tmp); // it->second = tmp; } else { dc_.SetClippingRegion(r); refDcToAreaMap().emplace(&dc_, r); } } ~RecursiveDcClipper() { dc_.DestroyClippingRegion(); if (oldRect_) { dc_.SetClippingRegion(*oldRect_); refDcToAreaMap()[&dc_] = *oldRect_; } else refDcToAreaMap().erase(&dc_); } private: //associate "active" clipping area with each DC static std::unordered_map& refDcToAreaMap() { static std::unordered_map clippingAreas; return clippingAreas; } Opt oldRect_; wxDC& dc_; }; #ifndef wxALWAYS_NATIVE_DOUBLE_BUFFER #error we need this one! #endif #if wxALWAYS_NATIVE_DOUBLE_BUFFER struct BufferedPaintDC : public wxPaintDC { BufferedPaintDC(wxWindow& wnd, Opt& buffer) : wxPaintDC(&wnd) {} }; #else class BufferedPaintDC : public wxMemoryDC { public: BufferedPaintDC(wxWindow& wnd, Opt& buffer) : buffer_(buffer), paintDc_(&wnd) { const wxSize clientSize = wnd.GetClientSize(); if (clientSize.GetWidth() > 0 && clientSize.GetHeight() > 0) //wxBitmap asserts this!! width may be 0; test case "Grid::CornerWin": compare both sides, then change config { if (!buffer_ || clientSize != wxSize(buffer->GetWidth(), buffer->GetHeight())) buffer = wxBitmap(clientSize.GetWidth(), clientSize.GetHeight()); SelectObject(*buffer); if (paintDc_.IsOk() && paintDc_.GetLayoutDirection() == wxLayout_RightToLeft) SetLayoutDirection(wxLayout_RightToLeft); } else buffer = NoValue(); } ~BufferedPaintDC() { if (buffer_) { if (GetLayoutDirection() == wxLayout_RightToLeft) { paintDc_.SetLayoutDirection(wxLayout_LeftToRight); //workaround bug in wxDC::Blit() SetLayoutDirection(wxLayout_LeftToRight); // } const wxPoint origin = GetDeviceOrigin(); paintDc_.Blit(0, 0, buffer_->GetWidth(), buffer_->GetHeight(), this, -origin.x, -origin.y); } } private: Opt& buffer_; wxPaintDC paintDc_; }; #endif } #endif //DC_H_4987123956832143243214