summaryrefslogtreecommitdiff
path: root/wx+
diff options
context:
space:
mode:
Diffstat (limited to 'wx+')
-rw-r--r--wx+/bitmap_button.h23
-rw-r--r--wx+/dc.h99
-rw-r--r--wx+/graph.cpp124
-rw-r--r--wx+/graph.h2
-rw-r--r--wx+/grid.cpp81
-rw-r--r--wx+/image_resources.cpp23
-rw-r--r--wx+/image_tools.cpp21
-rw-r--r--wx+/popup_dlg.cpp6
-rw-r--r--wx+/rtl.h8
-rw-r--r--wx+/std_button_layout.h12
-rw-r--r--wx+/tooltip.cpp8
-rw-r--r--wx+/window_layout.h4
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));
diff --git a/wx+/dc.h b/wx+/dc.h
index 5f744282..619f6628 100644
--- a/wx+/dc.h
+++ b/wx+/dc.h
@@ -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)
diff --git a/wx+/rtl.h b/wx+/rtl.h
index 80a75671..07488b6c 100644
--- a/wx+/rtl.h
+++ b/wx+/rtl.h
@@ -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
}
bgstack15