summaryrefslogtreecommitdiff
path: root/wx+/graph.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'wx+/graph.cpp')
-rw-r--r--wx+/graph.cpp124
1 files changed, 46 insertions, 78 deletions
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
}
bgstack15