diff options
Diffstat (limited to 'wx+')
-rw-r--r-- | wx+/bitmap_button.h | 23 | ||||
-rw-r--r-- | wx+/dc.h | 99 | ||||
-rw-r--r-- | wx+/graph.cpp | 124 | ||||
-rw-r--r-- | wx+/graph.h | 2 | ||||
-rw-r--r-- | wx+/grid.cpp | 81 | ||||
-rw-r--r-- | wx+/image_resources.cpp | 23 | ||||
-rw-r--r-- | wx+/image_tools.cpp | 21 | ||||
-rw-r--r-- | wx+/popup_dlg.cpp | 6 | ||||
-rw-r--r-- | wx+/rtl.h | 8 | ||||
-rw-r--r-- | wx+/std_button_layout.h | 12 | ||||
-rw-r--r-- | wx+/tooltip.cpp | 8 | ||||
-rw-r--r-- | wx+/window_layout.h | 4 |
12 files changed, 194 insertions, 217 deletions
diff --git a/wx+/bitmap_button.h b/wx+/bitmap_button.h index bbae6397..a3f160e8 100644 --- a/wx+/bitmap_button.h +++ b/wx+/bitmap_button.h @@ -36,7 +36,7 @@ public: }; //wxButton::SetBitmap() also supports "image + text", but screws up proper gap and border handling -void setBitmapTextLabel(wxBitmapButton& btn, const wxImage& img, const wxString& text, int gap = fastFromDIP(5), int border = fastFromDIP(5)); +void setBitmapTextLabel(wxBitmapButton& btn, const wxImage& img, const wxString& text, int gap = dipToWxsize(5), int border = dipToWxsize(5)); //set bitmap label flicker free: void setImage(wxAnyButton& button, const wxImage& bmp); @@ -65,12 +65,12 @@ void setBitmapTextLabel(wxBitmapButton& btn, const wxImage& img, const wxString& wxImage imgTxt = createImageFromText(text, btn.GetFont(), btn.GetForegroundColour()); if (img.IsOk()) imgTxt = btn.GetLayoutDirection() != wxLayout_RightToLeft ? - stackImages(img, imgTxt, ImageStackLayout::horizontal, ImageStackAlignment::center, gap) : - stackImages(imgTxt, img, ImageStackLayout::horizontal, ImageStackAlignment::center, gap); + stackImages(img, imgTxt, ImageStackLayout::horizontal, ImageStackAlignment::center, wxsizeToScreen(gap)) : + stackImages(imgTxt, img, ImageStackLayout::horizontal, ImageStackAlignment::center, wxsizeToScreen(gap)); //SetMinSize() instead of SetSize() is needed here for wxWindows layout determination to work correctly - btn.SetMinSize({imgTxt.GetWidth () + 2 * border, - std::max(imgTxt.GetHeight() + 2 * border, getDefaultButtonHeight())}); + btn.SetMinSize({screenToWxsize(imgTxt.GetWidth()) + 2 * border, + std::max(screenToWxsize(imgTxt.GetHeight()) + 2 * border, getDefaultButtonHeight())}); setImage(btn, imgTxt); } @@ -107,11 +107,12 @@ inline wxImage generatePressedButtonBack(const wxSize& sz) { #if 1 - return rectangleImage(sz, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW), {0x11, 0x79, 0xfe} /*light blue*/, fastFromDIP(2)); + return rectangleImage(sz, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW), {0x11, 0x79, 0xfe} /*light blue*/, dipToScreen(2)); #else //rectangle border with gradient as background - wxBitmap bmp(sz); //seems we don't need to pass 24-bit depth here even for high-contrast color schemes - bmp.SetScaleFactor(getDisplayScaleFactor()); + wxBitmap bmp(wxsizeToScreen(sz.x), + wxsizeToScreen(sz.y)); //seems we don't need to pass 24-bit depth here even for high-contrast color schemes + bmp.SetScaleFactor(getScreenDpiScale()); { //draw rectangle border with gradient const wxColor colFrom = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE); @@ -120,9 +121,9 @@ wxImage generatePressedButtonBack(const wxSize& sz) wxMemoryDC dc(bmp); dc.SetPen(*wxTRANSPARENT_PEN); //wxTRANSPARENT_PEN is about 2x faster than redundantly drawing with col! - wxRect rect(bmp.GetSize()); + wxRect rect(sz); - const int borderSize = fastFromDIP(3); + const int borderSize = dipToWxsize(3); for (int i = 1 ; i <= borderSize; ++i) { const wxColor colGradient((colFrom.Red () * (borderSize - i) + colTo.Red () * i) / borderSize, @@ -130,7 +131,7 @@ wxImage generatePressedButtonBack(const wxSize& sz) (colFrom.Blue () * (borderSize - i) + colTo.Blue () * i) / borderSize); dc.SetBrush(colGradient); dc.DrawRectangle(rect); - rect.Deflate(1); + rect.Deflate(dipToWxsize(1)); } dc.SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); @@ -35,14 +35,14 @@ namespace zen inline void clearArea(wxDC& dc, const wxRect& rect, const wxColor& col) { + assert(col.IsSolid()); if (rect.width > 0 && //clearArea() is surprisingly expensive rect.height > 0) { - assert(col.IsSolid()); //wxDC::DrawRectangle() just widens inner area if wxTRANSPARENT_PEN is used! //bonus: wxTRANSPARENT_PEN is about 2x faster than redundantly drawing with col! - wxDCPenChanger areaPen (dc, *wxTRANSPARENT_PEN); - wxDCBrushChanger areaBrush(dc, col); + dc.SetPen(*wxTRANSPARENT_PEN); + dc.SetBrush(col); dc.DrawRectangle(rect); } } @@ -50,78 +50,98 @@ void clearArea(wxDC& dc, const wxRect& rect, const wxColor& col) //properly draw rectangle respecting high DPI (and avoiding wxPen position fuzzyness) inline -void drawFilledRectangle(wxDC& dc, wxRect rect, const wxColor& innerCol, const wxColor& borderCol, int borderWidth) +void drawFilledRectangle(wxDC& dc, wxRect rect, const wxColor& innerCol, const wxColor& borderCol, int borderSize) { + assert(innerCol.IsSolid() && borderCol.IsSolid()); if (rect.width > 0 && rect.height > 0) { - assert(innerCol.IsSolid() && borderCol.IsSolid()); - wxDCPenChanger rectPen (dc, *wxTRANSPARENT_PEN); - wxDCBrushChanger rectBrush(dc, borderCol); + dc.SetPen(*wxTRANSPARENT_PEN); + dc.SetBrush(borderCol); dc.DrawRectangle(rect); - rect.Deflate(borderWidth); //attention, more wxWidgets design mistakes: behavior of wxRect::Deflate depends on object being const/non-const!!! - dc.SetBrush(innerCol); - dc.DrawRectangle(rect); + rect.Deflate(borderSize); //more wxWidgets design mistakes: behavior of wxRect::Deflate depends on object being const/non-const!!! + + if (rect.width > 0 && + rect.height > 0) + { + dc.SetBrush(innerCol); + dc.DrawRectangle(rect); + } } } inline -void drawRectangleBorder(wxDC& dc, const wxRect& rect, const wxColor& col, int borderWidth) +void drawRectangleBorder(wxDC& dc, const wxRect& rect, const wxColor& col, int borderSize) { + assert(col.IsSolid()); if (rect.width > 0 && rect.height > 0) { - assert(col.IsSolid()); - wxDCPenChanger areaPen (dc, *wxTRANSPARENT_PEN); - wxDCBrushChanger areaBrush(dc, col); - dc.DrawRectangle(rect.GetTopLeft(), {borderWidth, rect.height}); - dc.DrawRectangle(rect.GetTopLeft() + wxPoint{rect.width - borderWidth, 0}, {borderWidth, rect.height}); - dc.DrawRectangle(rect.GetTopLeft(), {rect.width, borderWidth}); - dc.DrawRectangle(rect.GetTopLeft() + wxPoint{0, rect.height - borderWidth}, {rect.width, borderWidth}); + if (2 * borderSize >= std::min(rect.width, rect.height)) + return clearArea(dc, rect, col); + + dc.SetPen(*wxTRANSPARENT_PEN); + dc.SetBrush(col); + dc.DrawRectangle(rect.x, rect.y, borderSize, rect.height); //left + dc.DrawRectangle(rect.x + rect.width - borderSize, rect.y, borderSize, rect.height); //right + dc.DrawRectangle(rect.x, rect.y, rect.width, borderSize); //top + dc.DrawRectangle(rect.x, rect.y + rect.height - borderSize, rect.width, borderSize); //bottom } } -/* Standard DPI: - Windows/Ubuntu: 96 x 96 - macOS: wxWidgets uses DIP (note: wxScreenDC().GetPPI() returns 72 x 72 which is a lie; looks like 96 x 96) */ -constexpr int defaultDpi = 96; //on Windows same as wxDisplay::GetStdPPIValue() (however returns 72 on macOS!) +/* figure out wxWidgets cross-platform high DPI mess: + + 1. "wxsize" := what wxWidgets is using: device-dependent on Windows, device-indepent on macOS (...mostly) + 2. screen unit := device-dependent size in pixels + 3. DIP := device-independent pixels + + corollary: + macOS: "wxsize = DIP" + Windows: "wxsize = screen unit" + cross-platform: images are in "screen unit" */ inline -int getDPI() +double getScreenDpiScale() { -#ifndef wxHAS_DPI_INDEPENDENT_PIXELS -#error why is wxHAS_DPI_INDEPENDENT_PIXELS not defined? -#endif //GTK2 doesn't properly support high DPI: https://freefilesync.org/forum/viewtopic.php?t=6114 //=> requires general fix at wxWidgets-level //https://github.com/wxWidgets/wxWidgets/blob/d9d05c2bb201078f5e762c42458ca2f74af5b322/include/wx/window.h#L2060 - return defaultDpi; //e.g. macOS, GTK3 + const double scale = 1.0; //e.g. macOS, GTK3 + + return scale; } inline -double getDisplayScaleFactor() +double getWxsizeDpiScale() { - return static_cast<double>(getDPI()) / defaultDpi; +#ifndef wxHAS_DPI_INDEPENDENT_PIXELS +#error why is wxHAS_DPI_INDEPENDENT_PIXELS not defined? +#endif + return 1.0; //e.g. macOS, GTK3 } -inline -int fastFromDIP(int d) //like wxWindow::FromDIP (but tied to primary monitor and buffered) -{ - return numeric::intDivRound(d * getDPI() - 10 /*round values like 1.5 down => 1 pixel on 150% scale*/, defaultDpi); -} -int fastFromDIP(double d) = delete; +//similar to wxWindow::FromDIP (but tied to primary monitor and buffered) +inline int dipToWxsize (int d) { return std::round(d * getWxsizeDpiScale() - 0.1 /*round values like 1.5 down => 1 pixel on 150% scale*/); } +inline int dipToScreen (int d) { return std::round(d * getScreenDpiScale()); } +inline int wxsizeToScreen(int u) { return std::round(u / getWxsizeDpiScale() * getScreenDpiScale()); } +inline int screenToWxsize(int s) { return std::round(s / getScreenDpiScale() * getWxsizeDpiScale()); } + +int dipToWxsize (double d) = delete; +int dipToScreen (double d) = delete; +int wxsizeToScreen(double d) = delete; +int screenToWxsize(double d) = delete; inline int getDpiScalePercent() { - return numeric::intDivRound(100 * getDPI(), defaultDpi); + return std::round(100 * getScreenDpiScale()); } @@ -130,7 +150,7 @@ wxBitmap toScaledBitmap(const wxImage& img /*expected to be DPI-scaled!*/) { //wxBitmap(const wxImage& image, int depth = -1, double WXUNUSED(scale) = 1.0) => wxWidgets just ignores scale parameter! WTF! wxBitmap bmpScaled(img); - bmpScaled.SetScaleFactor(getDisplayScaleFactor()); + bmpScaled.SetScaleFactor(getScreenDpiScale()); return bmpScaled; //when testing use 175% scaling: wxWidgets' scaling logic doesn't kick in for 150% only } @@ -161,7 +181,7 @@ class RecursiveDcClipper public: RecursiveDcClipper(wxDC& dc, const wxRect& r) : dc_(dc) { - if (auto it = clippingAreas_.find(&dc); + if (auto it = clippingAreas_.find(&dc_); it != clippingAreas_.end()) { oldRect_ = it->second; @@ -196,6 +216,7 @@ private: RecursiveDcClipper (const RecursiveDcClipper&) = delete; RecursiveDcClipper& operator=(const RecursiveDcClipper&) = delete; + //associate "active" clipping area with each DC inline static std::unordered_map<wxDC*, wxRect> clippingAreas_; @@ -219,7 +240,7 @@ public: BufferedPaintDC(wxWindow& wnd, std::optional<wxBitmap>& 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 (clientSize.GetWidth() > 0 && clientSize.GetHeight() > 0) //wxBitmap asserts this!! width can be 0; test case "Grid::CornerWin": compare both sides, then change config { if (!buffer_ || buffer->GetSize() != clientSize) buffer.emplace(clientSize); diff --git a/wx+/graph.cpp b/wx+/graph.cpp index d755a839..ad7fd3ec 100644 --- a/wx+/graph.cpp +++ b/wx+/graph.cpp @@ -145,19 +145,15 @@ void drawXLabel(wxDC& dc, double xMin, double xMax, int blockCount, const Conver if (blockCount <= 0) return; - wxDCPenChanger dummy(dc, wxPen(wxColor(192, 192, 192), fastFromDIP(1))); //light grey => not accessible! but no big deal... - wxDCTextColourChanger textColor(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); - const double valRangePerBlock = (xMax - xMin) / blockCount; for (int i = 1; i < blockCount; ++i) { - //draw grey vertical lines const double valX = xMin + i * valRangePerBlock; //step over raw data, not graph area pixels, to not lose precision const int x = graphArea.x + cvrtX.realToScreenRound(valX); - if (graphArea.height > 0) - dc.DrawLine(wxPoint(x, graphArea.y), wxPoint(x, graphArea.y + graphArea.height)); //wxDC::DrawLine() doesn't draw last pixel + //draw grey vertical lines + clearArea(dc, {x - dipToWxsize(1) / 2, graphArea.y, dipToWxsize(1), graphArea.height}, wxColor(192, 192, 192)); //light grey => not accessible! but no big deal... //draw x axis labels const wxString label = labelFmt.formatText(valX, valRangePerBlock); @@ -173,9 +169,6 @@ void drawYLabel(wxDC& dc, double yMin, double yMax, int blockCount, const Conver if (blockCount <= 0) return; - wxDCPenChanger dummy(dc, wxPen(wxColor(192, 192, 192), fastFromDIP(1))); //light grey => not accessible! but no big deal... - wxDCTextColourChanger textColor(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); - const double valRangePerBlock = (yMax - yMin) / blockCount; for (int i = 1; i < blockCount; ++i) @@ -184,8 +177,7 @@ void drawYLabel(wxDC& dc, double yMin, double yMax, int blockCount, const Conver const double valY = yMin + i * valRangePerBlock; //step over raw data, not graph area pixels, to not lose precision const int y = graphArea.y + cvrtY.realToScreenRound(valY); - if (graphArea.width > 0) - dc.DrawLine(wxPoint(graphArea.x, y), wxPoint(graphArea.x + graphArea.width, y)); //wxDC::DrawLine() doesn't draw last pixel + clearArea(dc, {graphArea.x, y - dipToWxsize(1) / 2, graphArea.width, dipToWxsize(1)}, wxColor(192, 192, 192)); //light grey => not accessible! but no big deal... //draw y axis labels const wxString label = labelFmt.formatText(valY, valRangePerBlock); @@ -199,7 +191,7 @@ void drawCornerText(wxDC& dc, const wxRect& graphArea, const wxString& txt, Grap { if (txt.empty()) return; - const wxSize border(fastFromDIP(5), fastFromDIP(2)); + const wxSize border(dipToWxsize(5), dipToWxsize(2)); //it looks like wxDC::GetMultiLineTextExtent() precisely returns width, but too large a height: maybe they consider "text row height"? const wxSize boxExtent = dc.GetMultiLineTextExtent(txt) + 2 * border; @@ -223,7 +215,7 @@ void drawCornerText(wxDC& dc, const wxRect& graphArea, const wxString& txt, Grap //add text shadow to improve readability: wxDCTextColourChanger textColor(dc, colorBack); - dc.DrawText(txt, drawPos + border + wxSize(1, 1) /*better without fastFromDIP()?*/); + dc.DrawText(txt, drawPos + border + wxSize(1, 1) /*better without dipToWxsize()?*/); textColor.Set(colorText); dc.DrawText(txt, drawPos + border); @@ -525,6 +517,7 @@ void Graph2D::render(wxDC& dc) const { //set label font right at the start so that it is considered by wxDC::GetTextExtent() below! dc.SetFont(GetFont()); + dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); const wxRect clientRect = GetClientRect(); //DON'T use wxDC::GetSize()! DC may be larger than visible area! @@ -532,7 +525,7 @@ void Graph2D::render(wxDC& dc) const //wxPanel::GetClassDefaultAttributes().colBg : //wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE); - const int xLabelHeight = attr_.xLabelHeight ? *attr_.xLabelHeight : GetCharHeight() + fastFromDIP(2) /*margin*/; + const int xLabelHeight = attr_.xLabelHeight ? *attr_.xLabelHeight : GetCharHeight() + dipToWxsize(2) /*margin*/; const int yLabelWidth = attr_.yLabelWidth ? *attr_.yLabelWidth : dc.GetTextExtent(L"1.23457e+07").x; /* ----------------------- @@ -576,13 +569,12 @@ void Graph2D::render(wxDC& dc) const assert(attr_.yLabelpos == YLabelPos::none || attr_.labelFmtY); //paint graph background (excluding label area) - drawFilledRectangle(dc, graphArea, attr_.colorBack, getBorderColor(), fastFromDIP(1)); - graphArea.Deflate(fastFromDIP(1)); + drawFilledRectangle(dc, graphArea, attr_.colorBack, getBorderColor(), dipToWxsize(1)); + graphArea.Deflate(dipToWxsize(1)); //set label areas respecting graph area border! const wxRect xLabelArea(graphArea.x, xLabelPosY, graphArea.width, xLabelHeight); const wxRect yLabelArea(yLabelPosX, graphArea.y, yLabelWidth, graphArea.height); - const wxPoint graphAreaOrigin = graphArea.GetTopLeft(); //detect x value range double minX = attr_.minX ? *attr_.minX : std::numeric_limits<double>::infinity(); //automatic: ensure values are initialized by first curve @@ -685,38 +677,28 @@ void Graph2D::render(wxDC& dc) const auto& dp = drawPoints[index]; for (const CurvePoint& pt : cp) - dp.push_back(wxPoint(cvrtX.realToScreenRound(pt.x), - cvrtY.realToScreenRound(pt.y)) + graphAreaOrigin); + dp.push_back(wxSize(cvrtX.realToScreenRound(pt.x), + cvrtY.realToScreenRound(pt.y)) + graphArea.GetTopLeft()); } //update active mouse selection if (activeSel_) { - auto widen = [](double* low, double* high) - { - if (*low > *high) - std::swap(low, high); - *low -= 0.5; - *high += 0.5; - }; - - const wxPoint screenStart = activeSel_->getStartPos() - graphAreaOrigin; //make relative to graphArea - const wxPoint screenCurrent = activeSel_->refCurrentPos() - graphAreaOrigin; - - //normalize positions: a mouse selection is symmetric and *not* an half-open range! - double screenFromX = std::clamp(screenStart .x, 0, graphArea.width - 1); - double screenFromY = std::clamp(screenStart .y, 0, graphArea.height - 1); - double screenToX = std::clamp(screenCurrent.x, 0, graphArea.width - 1); - double screenToY = std::clamp(screenCurrent.y, 0, graphArea.height - 1); - widen(&screenFromX, &screenToX); //use full pixel range for selection! - widen(&screenFromY, &screenToY); + wxPoint screenFrom = activeSel_->getStartPos() - graphArea.GetTopLeft(); //make relative to graphArea + wxPoint screenTo = activeSel_->refCurrentPos() - graphArea.GetTopLeft(); + + //normalize positions: + screenFrom.x = std::clamp(screenFrom.x, 0, graphArea.width - 1); + screenFrom.y = std::clamp(screenFrom.y, 0, graphArea.height - 1); + screenTo .x = std::clamp(screenTo .x, 0, graphArea.width - 1); + screenTo .y = std::clamp(screenTo .y, 0, graphArea.height - 1); //save current selection as "double" coordinates - activeSel_->refSelection().from = CurvePoint{cvrtX.screenToReal(screenFromX), - cvrtY.screenToReal(screenFromY)}; + activeSel_->refSelection().from = CurvePoint{cvrtX.screenToReal(screenFrom.x), + cvrtY.screenToReal(screenFrom.y)}; - activeSel_->refSelection().to = CurvePoint{cvrtX.screenToReal(screenToX), - cvrtY.screenToReal(screenToY)}; + activeSel_->refSelection().to = CurvePoint{cvrtX.screenToReal(screenTo.x), + cvrtY.screenToReal(screenTo.y)}; } //#################### begin drawing #################### @@ -727,9 +709,9 @@ void Graph2D::render(wxDC& dc) const points.size() >= 3) { //wxDC::DrawPolygon() draws *transparent* border if wxTRANSPARENT_PEN is used! - //unlike wxDC::DrawRectangle() which just widens inner area! - wxDCPenChanger dummy (dc, wxPen(it->second.fillColor, 1 /*[!] width*/)); - wxDCBrushChanger dummy2(dc, it->second.fillColor); + //unlike wxDC::DrawRectangle() which widens inner area instead! + dc.SetPen ({it->second.fillColor, 1 /*[!] width*/}); + dc.SetBrush(it->second.fillColor); dc.DrawPolygon(static_cast<int>(points.size()), points.data()); } @@ -740,51 +722,37 @@ void Graph2D::render(wxDC& dc) const if (!allSelections.empty()) { - //alpha channel not supported on wxMSW, so draw selection before curves - wxDCBrushChanger dummy(dc, wxColor(168, 202, 236)); //light blue - wxDCPenChanger dummy2(dc, wxPen(wxColor(51, 153, 255), fastFromDIP(1))); //dark blue - - auto shrink = [](double* low, double* high) - { - if (*low > *high) - std::swap(low, high); - *low += 0.5; - *high -= 0.5; - if (*low > *high) - *low = *high = (*low + *high) / 2; - }; + const wxColor innerCol(168, 202, 236); //light blue + const wxColor borderCol(51, 153, 255); //dark blue + //alpha channel not supported on wxMSW, so draw selection before curves for (const SelectionBlock& sel : allSelections) { //harmonize with active mouse selection above - double screenFromX = cvrtX.realToScreen(sel.from.x); - double screenFromY = cvrtY.realToScreen(sel.from.y); - double screenToX = cvrtX.realToScreen(sel.to.x); - double screenToY = cvrtY.realToScreen(sel.to.y); - shrink(&screenFromX, &screenToX); - shrink(&screenFromY, &screenToY); - - screenFromX = std::clamp(screenFromX, 0.0, graphArea.width - 1.0); - screenFromY = std::clamp(screenFromY, 0.0, graphArea.height - 1.0); - screenToX = std::clamp(screenToX, 0.0, graphArea.width - 1.0); - screenToY = std::clamp(screenToY, 0.0, graphArea.height - 1.0); - - const wxPoint pixelFrom = wxPoint(std::round(screenFromX), - std::round(screenFromY)) + graphAreaOrigin; - const wxPoint pixelTo = wxPoint(std::round(screenToX), - std::round(screenToY)) + graphAreaOrigin; + int screenFromX = cvrtX.realToScreenRound(sel.from.x); + int screenFromY = cvrtY.realToScreenRound(sel.from.y); + int screenToX = cvrtX.realToScreenRound(sel.to.x); + int screenToY = cvrtY.realToScreenRound(sel.to.y); + + if (screenFromX > screenToX) std::swap(screenFromX, screenToX); + if (screenFromY > screenToY) std::swap(screenFromY, screenToY); + + const wxRect rectSel{graphArea.GetTopLeft() + wxSize(screenFromX, + screenFromY), + wxSize(screenToX - screenFromX + 1, //mouse selection is symmetric + screenToY - screenFromY + 1)}; //and *not* a half-open range! switch (attr_.mouseSelMode) { case GraphSelMode::none: break; case GraphSelMode::rect: - dc.DrawRectangle(wxRect(pixelFrom, pixelTo)); //wxRect considers area *including* both points + drawFilledRectangle(dc, rectSel, innerCol, borderCol, dipToWxsize(1)); break; case GraphSelMode::x: - dc.DrawRectangle(wxRect(wxPoint(pixelFrom.x, graphArea.y), wxPoint(pixelTo.x, graphArea.y + graphArea.height - 1))); + drawFilledRectangle(dc, {rectSel.x, graphArea.y, rectSel.width, graphArea.height}, innerCol, borderCol, dipToWxsize(1)); break; case GraphSelMode::y: - dc.DrawRectangle(wxRect(wxPoint(graphArea.x, pixelFrom.y), wxPoint(graphArea.x + graphArea.width - 1, pixelTo.y))); + drawFilledRectangle(dc, {graphArea.x, rectSel.y, graphArea.width, rectSel.height}, innerCol, borderCol, dipToWxsize(1)); break; } } @@ -801,7 +769,7 @@ void Graph2D::render(wxDC& dc) const for (auto it = curves_.begin(); it != curves_.end(); ++it) { - wxDCPenChanger dummy(dc, wxPen(it->second.color, it->second.lineWidth)); + dc.SetPen({it->second.color, it->second.lineWidth}); const size_t index = it - curves_.begin(); const std::vector<wxPoint>& points = drawPoints[index]; @@ -818,7 +786,7 @@ void Graph2D::render(wxDC& dc) const const int pointCount = static_cast<int>(drawIndexLast - drawIndexFirst); if (pointCount > 0) { - if (pointCount >= 2) //on OS X wxWidgets has a nasty assert on this + if (pointCount >= 2) //on macOS wxWidgets has a nasty assert on this dc.DrawLines(pointCount, &points[drawIndexFirst]); dc.DrawPoint(points[drawIndexLast - 1]); //wxDC::DrawLines() doesn't draw last pixel } diff --git a/wx+/graph.h b/wx+/graph.h index 2f73a643..d7ea51b5 100644 --- a/wx+/graph.h +++ b/wx+/graph.h @@ -212,7 +212,7 @@ public: CurveFillMode fillMode = CurveFillMode::none; wxColor fillColor; - int lineWidth = fastFromDIP(2); + int lineWidth = dipToWxsize(2); }; void addCurve(const SharedRef<CurveData>& data, const CurveAttributes& ca = CurveAttributes()); diff --git a/wx+/grid.cpp b/wx+/grid.cpp index 8e9fe592..07196eaf 100644 --- a/wx+/grid.cpp +++ b/wx+/grid.cpp @@ -30,7 +30,7 @@ using namespace zen; wxColor GridData::getColorSelectionGradientFrom() { return {137, 172, 255}; } //blue: HSL: 158, 255, 196 HSV: 222, 0.46, 1 wxColor GridData::getColorSelectionGradientTo () { return {225, 234, 255}; } // HSL: 158, 255, 240 HSV: 222, 0.12, 1 -int GridData::getColumnGapLeft() { return fastFromDIP(4); } +int GridData::getColumnGapLeft() { return dipToWxsize(4); } namespace @@ -129,23 +129,16 @@ void GridData::renderCell(wxDC& dc, const wxRect& rect, size_t row, ColumnType c int GridData::getBestSize(wxDC& dc, size_t row, ColumnType colType) { - return dc.GetTextExtent(getValue(row, colType)).GetWidth() + 2 * getColumnGapLeft() + fastFromDIP(1); //gap on left and right side + border + return dc.GetTextExtent(getValue(row, colType)).GetWidth() + 2 * getColumnGapLeft() + dipToWxsize(1); //gap on left and right side + border } wxRect GridData::drawCellBorder(wxDC& dc, const wxRect& rect) //returns remaining rectangle { - //following code is adapted from clearArea(): - assert(getColorGridLine().IsSolid()); - //wxDC::DrawRectangle() just widens inner area if wxTRANSPARENT_PEN is used! - //bonus: wxTRANSPARENT_PEN is about 2x faster than redundantly drawing with col! - wxDCPenChanger areaPen (dc, *wxTRANSPARENT_PEN); - wxDCBrushChanger areaBrush(dc, getColorGridLine()); + clearArea(dc, {rect.x + rect.width - dipToWxsize(1), rect.y, dipToWxsize(1), rect.height}, getColorGridLine()); //right border + clearArea(dc, {rect.x, rect.y + rect.height - dipToWxsize(1), rect.width, dipToWxsize(1)}, getColorGridLine()); //bottom border - dc.DrawRectangle(rect.x + rect.width - fastFromDIP(1), rect.y, fastFromDIP(1), rect.height); //right border - dc.DrawRectangle(rect.x, rect.y + rect.height - fastFromDIP(1), rect.width, fastFromDIP(1)); //bottom border - - return wxRect(rect.GetTopLeft(), wxSize(rect.width - fastFromDIP(1), rect.height - fastFromDIP(1))); + return {rect.x, rect.y, rect.width - dipToWxsize(1), rect.height - dipToWxsize(1)}; } @@ -238,17 +231,16 @@ wxRect GridData::drawColumnLabelBackground(wxDC& dc, const wxRect& rect, bool hi dc.GradientFillLinear(rect, getColorLabelGradientFrom(), getColorLabelGradientTo(), wxSOUTH); //left border - clearArea(dc, wxRect(rect.GetTopLeft(), wxSize(fastFromDIP(1), rect.height)), wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); + clearArea(dc, wxRect(rect.GetTopLeft(), wxSize(dipToWxsize(1), rect.height)), wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); //right border - dc.GradientFillLinear(wxRect(rect.x + rect.width - fastFromDIP(1), rect.y, fastFromDIP(1), rect.height), + dc.GradientFillLinear(wxRect(rect.x + rect.width - dipToWxsize(1), rect.y, dipToWxsize(1), rect.height), getColorLabelGradientFrom(), wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW), wxSOUTH); //bottom border - clearArea(dc, wxRect(rect.x, rect.y + rect.height - fastFromDIP(1), rect.width, fastFromDIP(1)), wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW)); + clearArea(dc, wxRect(rect.x, rect.y + rect.height - dipToWxsize(1), rect.width, dipToWxsize(1)), wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW)); - return rect.Deflate(fastFromDIP(1), - fastFromDIP(1)); + return rect.Deflate(dipToWxsize(1), dipToWxsize(1)); } @@ -420,19 +412,19 @@ private: dc.GradientFillLinear(rect, getColorLabelGradientFrom(), getColorLabelGradientTo(), wxSOUTH); //left border - dc.GradientFillLinear(wxRect(rect.GetTopLeft(), wxSize(fastFromDIP(1), rect.height)), + dc.GradientFillLinear(wxRect(rect.GetTopLeft(), wxSize(dipToWxsize(1), rect.height)), getColorLabelGradientFrom(), wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW), wxSOUTH); //left border2 - clearArea(dc, wxRect(rect.x + fastFromDIP(1), rect.y, fastFromDIP(1), rect.height), + clearArea(dc, wxRect(rect.x + dipToWxsize(1), rect.y, dipToWxsize(1), rect.height), wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); //right border - dc.GradientFillLinear(wxRect(rect.x + rect.width - fastFromDIP(1), rect.y, fastFromDIP(1), rect.height), + dc.GradientFillLinear(wxRect(rect.x + rect.width - dipToWxsize(1), rect.y, dipToWxsize(1), rect.height), getColorLabelGradientFrom(), wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW), wxSOUTH); //bottom border - clearArea(dc, wxRect(rect.x, rect.y + rect.height - fastFromDIP(1), rect.width, fastFromDIP(1)), + clearArea(dc, wxRect(rect.x, rect.y + rect.height - dipToWxsize(1), rect.width, dipToWxsize(1)), wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW)); } }; @@ -445,7 +437,7 @@ class Grid::RowLabelWin : public SubWindow public: explicit RowLabelWin(Grid& parent) : SubWindow(parent), - rowHeight_(parent.GetCharHeight() + fastFromDIP(2) + fastFromDIP(1)) {} //default height; don't call any functions on "parent" other than those from wxWindow during construction! + rowHeight_(parent.GetCharHeight() + dipToWxsize(2) + dipToWxsize(1)) {} //default height; don't call any functions on "parent" other than those from wxWindow during construction! //2 for some more space, 1 for bottom border (gives 15 + 2 + 1 on Windows, 17 + 2 + 1 on Ubuntu) int getBestWidth(ptrdiff_t rowFrom, ptrdiff_t rowTo) @@ -456,7 +448,7 @@ public: int bestWidth = 0; for (ptrdiff_t i = rowFrom; i <= rowTo; ++i) - bestWidth = std::max(bestWidth, dc.GetTextExtent(formatRowNum(i)).GetWidth() + fastFromDIP(2 * ROW_LABEL_BORDER_DIP)); + bestWidth = std::max(bestWidth, dc.GetTextExtent(formatRowNum(i)).GetWidth() + dipToWxsize(2 * ROW_LABEL_BORDER_DIP)); return bestWidth; } @@ -514,24 +506,20 @@ private: dc.GradientFillLinear(rect, getColorLabelGradientFrom(), getColorLabelGradientTo(), wxEAST); //clear overlapping cells //top border - clearArea(dc, wxRect(rect.GetTopLeft(), wxSize(rect.width, fastFromDIP(1))), - wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); + clearArea(dc, wxRect(rect.x, rect.y, rect.width, dipToWxsize(1)), wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); //left border - clearArea(dc, wxRect(rect.GetTopLeft(), wxSize(fastFromDIP(1), rect.height)), - wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW)); + clearArea(dc, wxRect(rect.x, rect.y, dipToWxsize(1), rect.height), wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW)); //right border - clearArea(dc, wxRect(rect.x + rect.width - fastFromDIP(1), rect.y, fastFromDIP(1), rect.height), - wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW)); + clearArea(dc, wxRect(rect.x + rect.width - dipToWxsize(1), rect.y, dipToWxsize(1), rect.height), wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW)); //bottom border - clearArea(dc, wxRect(rect.x, rect.y + rect.height - fastFromDIP(1), rect.width, fastFromDIP(1)), - wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW)); + clearArea(dc, wxRect(rect.x, rect.y + rect.height - dipToWxsize(1), rect.width, dipToWxsize(1)), wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW)); //label text wxRect textRect = rect; - textRect.Deflate(fastFromDIP(1)); + textRect.Deflate(dipToWxsize(1)); wxDCTextColourChanger textColor(dc, getColorLabelText(enabled)); //accessibility: always set both foreground AND background colors! GridData::drawCellText(dc, textRect, formatRowNum(row), wxALIGN_CENTRE); @@ -621,7 +609,7 @@ public: labelFont_(GetFont().Bold()) { //coordinate with ColLabelWin::render(): - colLabelHeight_ = fastFromDIP(2 * DEFAULT_COL_LABEL_BORDER_DIP) + labelFont_.GetPixelSize().GetHeight(); + colLabelHeight_ = dipToWxsize(2 * DEFAULT_COL_LABEL_BORDER_DIP) + labelFont_.GetPixelSize().GetHeight(); } int getColumnLabelHeight() const { return colLabelHeight_; } @@ -633,14 +621,12 @@ private: void render(wxDC& dc, const wxRect& rect) override { clearArea(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); - //caveat: system colors can bes partially transparent on macOS: + //caveat: system colors can be partially transparent on macOS - const bool enabled = renderAsEnabled(*this); - - //coordinate with "colLabelHeight" in Grid constructor: - dc.SetFont(labelFont_); + dc.SetFont(labelFont_); //coordinate with "colLabelHeight" in Grid constructor + dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); - wxDCTextColourChanger textColor(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); //use user setting for labels + const bool enabled = renderAsEnabled(*this); wxPoint labelAreaTL(refParent().CalcScrolledPosition(wxPoint(0, 0)).x, 0); //client coordinates @@ -687,7 +673,7 @@ private: if (refParent().allowColumnMove_) if (activeClickOrMove_ && activeClickOrMove_->isRealMove()) { - const int markerWidth = fastFromDIP(COLUMN_MOVE_MARKER_WIDTH_DIP); + const int markerWidth = dipToWxsize(COLUMN_MOVE_MARKER_WIDTH_DIP); if (col + 1 == activeClickOrMove_->refColumnTo()) //handle pos 1, 2, .. up to "at end" position dc.GradientFillLinear(wxRect(rect.x + rect.width - markerWidth, rect.y, markerWidth, rect.height), getColorLabelGradientFrom(), *wxBLUE, wxSOUTH); @@ -703,7 +689,7 @@ private: if (const int absPosX = refParent().CalcUnscrolledPosition(pos).x; absPosX >= 0) { - const int resizeTolerance = refParent().allowColumnResize_ ? fastFromDIP(COLUMN_RESIZE_TOLERANCE_DIP) : 0; + const int resizeTolerance = refParent().allowColumnResize_ ? dipToWxsize(COLUMN_RESIZE_TOLERANCE_DIP) : 0; const std::vector<ColumnWidth>& absWidths = refParent().getColWidths(); //resolve stretched widths int accuWidth = 0; @@ -858,7 +844,7 @@ private: //check if there's a small gap after last column, if yes, fill it const int gapWidth = GetClientSize().GetWidth() - refParent().getColWidthsSum(GetClientSize().GetWidth()); - if (std::abs(gapWidth) < fastFromDIP(COLUMN_FILL_GAP_TOLERANCE_DIP)) + if (std::abs(gapWidth) < dipToWxsize(COLUMN_FILL_GAP_TOLERANCE_DIP)) refParent().setColumnWidth(newWidth + gapWidth, col, GridEventPolicy::allow); Refresh(); @@ -867,7 +853,7 @@ private: else if (activeClickOrMove_) { const int clientPosX = clientPos.x; - if (std::abs(clientPosX - activeClickOrMove_->getStartPosX()) > fastFromDIP(COLUMN_MOVE_DELAY_DIP)) //real move (not a single click) + if (std::abs(clientPosX - activeClickOrMove_->getStartPosX()) > dipToWxsize(COLUMN_MOVE_DELAY_DIP)) //real move (not a single click) { activeClickOrMove_->setRealMove(); activeClickOrMove_->refColumnTo() = clientPosToMoveTargetColumn(clientPos); @@ -1003,8 +989,7 @@ private: if (auto prov = refParent().getDataProvider()) { dc.SetFont(GetFont()); //harmonize with Grid::getBestColumnSize() - - wxDCTextColourChanger textColor(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); //use user setting for labels + dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); const std::vector<ColumnWidth>& absWidths = refParent().getColWidths(); //resolve stretched widths @@ -2306,7 +2291,7 @@ void Grid::setColumnWidth(int width, size_t col, GridEventPolicy columnResizeEve //I. fixed-size columns: normalize offset so that resulting width is at least COLUMN_MIN_WIDTH_DIP: this is NOT enforced by getColWidths()! //II. stretched columns: do not allow user to set offsets so small that they result in negative (non-normalized) widths: this gives an //unusual delay when enlarging the column again later - width = std::max(width, fastFromDIP(COLUMN_MIN_WIDTH_DIP)); + width = std::max(width, dipToWxsize(COLUMN_MIN_WIDTH_DIP)); vcRs.offset = width - stretchedWidths[col]; //width := stretchedWidth + offset @@ -2318,7 +2303,7 @@ void Grid::setColumnWidth(int width, size_t col, GridEventPolicy columnResizeEve //4. now verify that the stretched column is resizing immediately if main window is enlarged again for (size_t col2 = 0; col2 < visibleCols_.size(); ++col2) if (visibleCols_[col2].stretch > 0) //normalize stretched columns only - visibleCols_[col2].offset = std::max(visibleCols_[col2].offset, fastFromDIP(COLUMN_MIN_WIDTH_DIP) - stretchedWidths[col2]); + visibleCols_[col2].offset = std::max(visibleCols_[col2].offset, dipToWxsize(COLUMN_MIN_WIDTH_DIP) - stretchedWidths[col2]); if (columnResizeEventPolicy == GridEventPolicy::allow) { @@ -2409,7 +2394,7 @@ std::vector<Grid::ColumnWidth> Grid::getColWidths(int mainWinWidth) const //eval int width = stretchedWidths[col2] + vc.offset; if (vc.stretch > 0) - width = std::max(width, fastFromDIP(COLUMN_MIN_WIDTH_DIP)); //normalization really needed here: e.g. smaller main window would result in negative width + width = std::max(width, dipToWxsize(COLUMN_MIN_WIDTH_DIP)); //normalization really needed here: e.g. smaller main window would result in negative width else width = std::max(width, 0); //support smaller width than COLUMN_MIN_WIDTH_DIP if set via configuration diff --git a/wx+/image_resources.cpp b/wx+/image_resources.cpp index 0ccab219..6157f381 100644 --- a/wx+/image_resources.cpp +++ b/wx+/image_resources.cpp @@ -144,7 +144,7 @@ private: ImageBuffer& operator=(const ImageBuffer&) = delete; const wxImage& getRawImage (const std::string& name); - const wxImage& getScaledImage(const std::string& name); + const wxImage& getHqScaledImage(const std::string& name); std::unordered_map<std::string, wxImage> imagesRaw_; std::unordered_map<std::string, wxImage> imagesScaled_; @@ -211,7 +211,7 @@ ImageBuffer::ImageBuffer(const Zstring& zipPath) //throw FileError wxImage::AddHandler(new wxPNGHandler/*ownership passed*/); //activate support for .png files //do we need xBRZ scaling for high quality DPI images? - const int hqScale = std::clamp(numeric::intDivCeil(fastFromDIP(1000), 1000), 1, xbrz::SCALE_FACTOR_MAX); + const int hqScale = std::clamp(static_cast<int>(std::ceil(getScreenDpiScale())), 1, xbrz::SCALE_FACTOR_MAX); //even for 125% DPI scaling, "2xBRZ + bilinear downscale" gives a better result than mere "125% bilinear upscale"! if (hqScale > 1) hqScaler_ = std::make_unique<HqParallelScaler>(hqScale); @@ -255,7 +255,7 @@ const wxImage& ImageBuffer::getRawImage(const std::string& name) } -const wxImage& ImageBuffer::getScaledImage(const std::string& name) +const wxImage& ImageBuffer::getHqScaledImage(const std::string& name) { //test: this function is first called about 220ms after ImageBuffer::ImageBuffer() has ended // => should be enough time to finish xBRZ scaling in parallel (which takes 50ms) @@ -279,8 +279,8 @@ const wxImage& ImageBuffer::getImage(const std::string& name, int maxWidth /*opt { const wxImage& rawImg = getRawImage(name); - const wxSize dpiSize(fastFromDIP(rawImg.GetWidth ()), - fastFromDIP(rawImg.GetHeight())); + const wxSize dpiSize(dipToScreen(rawImg.GetWidth ()), + dipToScreen(rawImg.GetHeight())); int outHeight = dpiSize.y; if (maxWidth >= 0 && maxWidth < dpiSize.x) @@ -289,18 +289,17 @@ const wxImage& ImageBuffer::getImage(const std::string& name, int maxWidth /*opt if (maxHeight >= 0 && maxHeight < outHeight) outHeight = maxHeight; - const OutImageKey imkey{name, outHeight}; + const OutImageKey imgKey{name, outHeight}; - auto it = imagesOut_.find(imkey); + auto it = imagesOut_.find(imgKey); if (it == imagesOut_.end()) { if (rawImg.GetHeight() >= outHeight) //=> skip needless xBRZ upscaling - it = imagesOut_.emplace(imkey, shrinkImage(rawImg, -1 /*maxWidth*/, outHeight)).first; + it = imagesOut_.emplace(imgKey, shrinkImage(rawImg, -1 /*maxWidth*/, outHeight)).first; else if (rawImg.GetHeight() >= 0.9 * outHeight) //almost there: also no need for xBRZ-scale - it = imagesOut_.emplace(imkey, bilinearScale(rawImg, numeric::intDivRound(outHeight * rawImg.GetWidth(), rawImg.GetHeight()), outHeight)).first; - //however: for 125% DPI scaling, "2xBRZ + bilinear downscale" gives a better result than mere "125% bilinear upscale" - else - it = imagesOut_.emplace(imkey, shrinkImage(getScaledImage(name), -1 /*maxWidth*/, outHeight)).first; + it = imagesOut_.emplace(imgKey, bilinearScale(rawImg, numeric::intDivRound(outHeight * rawImg.GetWidth(), rawImg.GetHeight()), outHeight)).first; + else //however: for 125% DPI scaling, "2xBRZ + bilinear downscale" gives a better result than mere "125% bilinear upscale" + it = imagesOut_.emplace(imgKey, shrinkImage(getHqScaledImage(name), -1 /*maxWidth*/, outHeight)).first; } return it->second; } diff --git a/wx+/image_tools.cpp b/wx+/image_tools.cpp index b054ad78..e95797ca 100644 --- a/wx+/image_tools.cpp +++ b/wx+/image_tools.cpp @@ -168,7 +168,7 @@ wxImage zen::stackImages(const wxImage& img1, const wxImage& img2, ImageStackLay wxImage zen::createImageFromText(const wxString& text, const wxFont& font, const wxColor& col, ImageStackAlignment textAlign) { wxMemoryDC dc; //the context used for bitmaps - setScaleFactor(dc, getDisplayScaleFactor()); + setScaleFactor(dc, getScreenDpiScale()); dc.SetFont(font); //the font parameter of GetTextExtent() is not evaluated on OS X, wxWidgets 2.9.5, so apply it to the DC directly! std::vector<std::pair<wxString, wxSize>> lineInfo; //text + extent @@ -186,8 +186,9 @@ wxImage zen::createImageFromText(const wxString& text, const wxFont& font, const if (maxWidth == 0 || lineHeight == 0) return wxNullImage; - wxBitmap newBitmap(maxWidth, lineHeight * lineInfo.size()); //seems we don't need to pass 24-bit depth here even for high-contrast color schemes - newBitmap.SetScaleFactor(getDisplayScaleFactor()); + wxBitmap newBitmap(wxsizeToScreen(maxWidth), + wxsizeToScreen(static_cast<int>(lineHeight * lineInfo.size()))); //seems we don't need to pass 24-bit depth here even for high-contrast color schemes + newBitmap.SetScaleFactor(getScreenDpiScale()); { dc.SelectObject(newBitmap); //copies scale factor from wxBitmap ZEN_ON_SCOPE_EXIT(dc.SelectObject(wxNullBitmap)); @@ -377,10 +378,10 @@ void zen::convertToVanillaImage(wxImage& img) const int height = img.GetHeight(); if (width <= 0 || height <= 0) return; - unsigned char mask_r = 0; - unsigned char mask_g = 0; - unsigned char mask_b = 0; - const bool haveMask = img.HasMask() && img.GetOrFindMaskColour(&mask_r, &mask_g, &mask_b); + unsigned char maskR = 0; + unsigned char maskG = 0; + unsigned char maskB = 0; + const bool haveMask = img.HasMask() && img.GetOrFindMaskColour(&maskR, &maskG, &maskB); //check for mask before calling wxImage::GetOrFindMaskColour() to skip needlessly searching for new mask color img.SetAlpha(); @@ -402,9 +403,9 @@ void zen::convertToVanillaImage(wxImage& img) const unsigned char g = *rgb++; const unsigned char b = *rgb++; - if (r == mask_r && - g == mask_g && - b == mask_b) + if (r == maskR && + g == maskG && + b == maskB) alpha[i] = wxIMAGE_ALPHA_TRANSPARENT; } } diff --git a/wx+/popup_dlg.cpp b/wx+/popup_dlg.cpp index 5254ff29..c48bf592 100644 --- a/wx+/popup_dlg.cpp +++ b/wx+/popup_dlg.cpp @@ -27,7 +27,7 @@ namespace { void setBestInitialSize(wxRichTextCtrl& ctrl, const wxString& text, wxSize maxSize) { - const int scrollbarWidth = fastFromDIP(25); /*not only scrollbar, but also left/right padding (on macOS)! + const int scrollbarWidth = dipToWxsize(25); /*not only scrollbar, but also left/right padding (on macOS)! better use slightly larger than exact value (Windows: 17, Linux(CentOS): 14, macOS: 25) => worst case: minor increase in rowCount (no big deal) + slightly larger bestSize.x (good!) */ @@ -164,8 +164,8 @@ public: titleTmp = wxTheApp->GetAppDisplayName() + (!titleTmp.empty() ? SPACED_DASH + titleTmp : wxString()); SetTitle(titleTmp); - int maxWidth = fastFromDIP(500); - int maxHeight = fastFromDIP(400); //try to determine better value based on actual display resolution: + int maxWidth = dipToWxsize(500); + int maxHeight = dipToWxsize(400); //try to determine better value based on actual display resolution: if (parent) if (const int disPos = wxDisplay::GetFromWindow(parent); //window must be visible disPos != wxNOT_FOUND) @@ -42,14 +42,14 @@ void drawBitmapAligned(wxDC& dc, const wxImage& img, const wxRect& rect, int ali { wxPoint pt = rect.GetTopLeft(); if (alignment & wxALIGN_RIGHT) //note: wxALIGN_LEFT == 0! - pt.x += rect.width - img.GetWidth(); + pt.x += rect.width - screenToWxsize(img.GetWidth()); else if (alignment & wxALIGN_CENTER_HORIZONTAL) - pt.x += (rect.width - img.GetWidth()) / 2; + pt.x += (rect.width - screenToWxsize(img.GetWidth())) / 2; if (alignment & wxALIGN_BOTTOM) //note: wxALIGN_TOP == 0! - pt.y += rect.height - img.GetHeight(); + pt.y += rect.height - screenToWxsize(img.GetHeight()); else if (alignment & wxALIGN_CENTER_VERTICAL) - pt.y += (rect.height - img.GetHeight()) / 2; + pt.y += (rect.height - screenToWxsize(img.GetHeight())) / 2; dc.DrawBitmap(toScaledBitmap(img), pt); } diff --git a/wx+/std_button_layout.h b/wx+/std_button_layout.h index 8abc9e3a..86558026 100644 --- a/wx+/std_button_layout.h +++ b/wx+/std_button_layout.h @@ -33,9 +33,9 @@ void setStandardButtonLayout(wxBoxSizer& sizer, const StdButtons& buttons = StdB inline -int getDefaultMenuIconSize() +constexpr int getMenuIconDipSize() { - return fastFromDIP(20); + return 20; } @@ -43,7 +43,7 @@ inline int getDefaultButtonHeight() { const int defaultHeight = wxButton::GetDefaultSize().GetHeight(); //buffered by wxWidgets - return std::max(defaultHeight, fastFromDIP(31)); //default button height is much too small => increase! + return std::max(defaultHeight, dipToWxsize(31)); //default button height is much too small => increase! } @@ -62,9 +62,9 @@ void setStandardButtonLayout(wxBoxSizer& sizer, const StdButtons& buttons) assert(sizer.GetOrientation() == wxHORIZONTAL); //GNOME Human Interface Guidelines: https://developer.gnome.org/hig-book/3.2/hig-book.html#alert-spacing - const int spaceH = fastFromDIP( 6); //OK - const int spaceRimH = fastFromDIP(12); //OK - const int spaceRimV = fastFromDIP(12); //OK + const int spaceH = dipToWxsize( 6); //OK + const int spaceRimH = dipToWxsize(12); //OK + const int spaceRimV = dipToWxsize(12); //OK StdButtons buttonsTmp = buttons; diff --git a/wx+/tooltip.cpp b/wx+/tooltip.cpp index 79d4fa1a..01b5ead4 100644 --- a/wx+/tooltip.cpp +++ b/wx+/tooltip.cpp @@ -75,8 +75,10 @@ void Tooltip::show(const wxString& text, wxPoint mousePos, const wxImage* img) if (txtChanged) { lastUsedText_ = text; + { tipWindow_->staticTextMain_->SetLabelText(text); - tipWindow_->staticTextMain_->Wrap(fastFromDIP(600)); + tipWindow_->staticTextMain_->Wrap(dipToWxsize(600)); + } } if (imgChanged || txtChanged) @@ -88,8 +90,8 @@ void Tooltip::show(const wxString& text, wxPoint mousePos, const wxImage* img) #endif const wxPoint newPos = wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft ? - mousePos - wxPoint(fastFromDIP(TIP_WINDOW_OFFSET_DIP) + tipWindow_->GetSize().GetWidth(), 0) : - mousePos + wxPoint(fastFromDIP(TIP_WINDOW_OFFSET_DIP), 0); + mousePos - wxPoint(dipToWxsize(TIP_WINDOW_OFFSET_DIP) + tipWindow_->GetSize().GetWidth(), 0) : + mousePos + wxPoint(dipToWxsize(TIP_WINDOW_OFFSET_DIP), 0); if (newPos != tipWindow_->GetScreenPosition()) tipWindow_->Move(newPos); diff --git a/wx+/window_layout.h b/wx+/window_layout.h index 8a86ec86..553485bd 100644 --- a/wx+/window_layout.h +++ b/wx+/window_layout.h @@ -66,7 +66,7 @@ void setDefaultWidth(wxSpinCtrl& m_spinCtrl) //get rid of excessive default width on old GTK3 3.14 (Debian); //gtk_entry_set_width_chars() not working => mitigate - m_spinCtrl.SetMinSize({fastFromDIP(100), -1}); //must be wider than gtk_entry_set_width_chars(), or it breaks newer GTK e.g. 3.22! + m_spinCtrl.SetMinSize({dipToWxsize(100), -1}); //must be wider than gtk_entry_set_width_chars(), or it breaks newer GTK e.g. 3.22! #if 0 //generic property syntax: GValue bval = G_VALUE_INIT; @@ -76,7 +76,7 @@ void setDefaultWidth(wxSpinCtrl& m_spinCtrl) ::g_object_set_property(G_OBJECT(m_spinCtrl.m_widget), "visibility", &bval); #endif #else - m_spinCtrl.SetMinSize({fastFromDIP(70), -1}); + m_spinCtrl.SetMinSize({dipToWxsize(70), -1}); #endif } |