diff options
Diffstat (limited to 'wx+/graph.h')
-rwxr-xr-x[-rw-r--r--] | wx+/graph.h | 708 |
1 files changed, 354 insertions, 354 deletions
diff --git a/wx+/graph.h b/wx+/graph.h index 84927b6d..3b2d390d 100644..100755 --- a/wx+/graph.h +++ b/wx+/graph.h @@ -1,354 +1,354 @@ -// ***************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0 * -// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved * -// ***************************************************************************** - -#ifndef GRAPH_H_234425245936567345799 -#define GRAPH_H_234425245936567345799 - -#include <map> -#include <vector> -#include <memory> -#include <wx/panel.h> -#include <wx/settings.h> -#include <wx/bitmap.h> -#include <zen/string_tools.h> -#include <zen/optional.h> - -//elegant 2D graph as wxPanel specialization - -namespace zen -{ -/* -Example: - //init graph (optional) - m_panelGraph->setAttributes(Graph2D::MainAttributes(). - setLabelX(Graph2D::LABEL_X_BOTTOM, 20, std::make_shared<LabelFormatterTimeElapsed>()). - setLabelY(Graph2D::LABEL_Y_RIGHT, 60, std::make_shared<LabelFormatterBytes>())); - //set graph data - std::shared_ptr<CurveData> curveDataBytes = ... - m_panelGraph->setCurve(curveDataBytes, Graph2D::CurveAttributes().setLineWidth(2).setColor(wxColor(0, 192, 0))); -*/ - -struct CurvePoint -{ - CurvePoint() {} - CurvePoint(double xVal, double yVal) : x(xVal), y(yVal) {} - double x = 0; - double y = 0; -}; -inline bool operator==(const CurvePoint& lhs, const CurvePoint& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; } -inline bool operator!=(const CurvePoint& lhs, const CurvePoint& rhs) { return !(lhs == rhs); } - - -struct CurveData -{ - virtual ~CurveData() {} - - virtual std::pair<double, double> getRangeX() const = 0; - virtual std::vector<CurvePoint> getPoints(double minX, double maxX, int pixelWidth) const = 0; //points outside the draw area are automatically trimmed! -}; - -//special curve types: -struct ContinuousCurveData : public CurveData -{ - virtual double getValue(double x) const = 0; - -private: - std::vector<CurvePoint> getPoints(double minX, double maxX, int pixelWidth) const override; -}; - -struct SparseCurveData : public CurveData -{ - SparseCurveData(bool addSteps = false) : addSteps_(addSteps) {} //addSteps: add points to get a staircase effect or connect points via a direct line - - virtual Opt<CurvePoint> getLessEq (double x) const = 0; - virtual Opt<CurvePoint> getGreaterEq(double x) const = 0; - -private: - std::vector<CurvePoint> getPoints(double minX, double maxX, int pixelWidth) const override; - const bool addSteps_; -}; - - -struct ArrayCurveData : public SparseCurveData -{ - virtual double getValue(size_t pos) const = 0; - virtual size_t getSize () const = 0; - -private: - std::pair<double, double> getRangeX() const override { const size_t sz = getSize(); return std::make_pair(0.0, sz == 0 ? 0.0 : sz - 1.0); } - - Opt<CurvePoint> getLessEq(double x) const override - { - const size_t sz = getSize(); - const size_t pos = std::min<ptrdiff_t>(std::floor(x), sz - 1); //[!] expect unsigned underflow if empty! - if (pos < sz) - return CurvePoint(pos, getValue(pos)); - return NoValue(); - } - - Opt<CurvePoint> getGreaterEq(double x) const override - { - const size_t pos = std::max<ptrdiff_t>(std::ceil(x), 0); //[!] use std::max with signed type! - if (pos < getSize()) - return CurvePoint(pos, getValue(pos)); - return NoValue(); - } -}; - - -struct VectorCurveData : public ArrayCurveData -{ - std::vector<double>& refData() { return data; } -private: - double getValue(size_t pos) const override { return pos < data.size() ? data[pos] : 0; } - size_t getSize() const override { return data.size(); } - - std::vector<double> data; -}; - -//------------------------------------------------------------------------------------------------------------ - -struct LabelFormatter -{ - virtual ~LabelFormatter() {} - - //determine convenient graph label block size in unit of data: usually some small deviation on "sizeProposed" - virtual double getOptimalBlockSize(double sizeProposed) const = 0; - - //create human-readable text for x or y-axis position - virtual wxString formatText(double value, double optimalBlockSize) const = 0; -}; - - -double nextNiceNumber(double blockSize); //round to next number which is convenient to read, e.g. 2.13 -> 2; 2.7 -> 2.5 - -struct DecimalNumberFormatter : public LabelFormatter -{ - double getOptimalBlockSize(double sizeProposed ) const override { return nextNiceNumber(sizeProposed); } - wxString formatText (double value, double optimalBlockSize) const override { return zen::numberTo<wxString>(value); } -}; - -//------------------------------------------------------------------------------------------------------------ - -//emit data selection event -//Usage: wnd.Connect(wxEVT_GRAPH_SELECTION, GraphSelectEventHandler(MyDlg::OnGraphSelection), nullptr, this); -// void MyDlg::OnGraphSelection(GraphSelectEvent& event); - -extern const wxEventType wxEVT_GRAPH_SELECTION; - -struct SelectionBlock -{ - CurvePoint from; - CurvePoint to; -}; - -class GraphSelectEvent : public wxCommandEvent -{ -public: - GraphSelectEvent(const SelectionBlock& selBlock) : wxCommandEvent(wxEVT_GRAPH_SELECTION), selBlock_(selBlock) {} - wxEvent* Clone() const override { return new GraphSelectEvent(selBlock_); } - - SelectionBlock getSelection() { return selBlock_; } - -private: - SelectionBlock selBlock_; -}; - -using GraphSelectEventFunction = void (wxEvtHandler::*)(GraphSelectEvent&); - -#define GraphSelectEventHandler(func) \ - (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(GraphSelectEventFunction, &func) - -//------------------------------------------------------------------------------------------------------------ - -class Graph2D : public wxPanel -{ -public: - Graph2D(wxWindow* parent, - wxWindowID winid = wxID_ANY, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxTAB_TRAVERSAL | wxNO_BORDER, - const wxString& name = wxPanelNameStr); - - class CurveAttributes - { - public: - CurveAttributes() {} //required by GCC - CurveAttributes& setColor (const wxColor& col) { color = col; autoColor = false; return *this; } - CurveAttributes& fillCurveArea (const wxColor& col) { fillColor = col; fillMode = FILL_CURVE; return *this; } - CurveAttributes& fillPolygonArea(const wxColor& col) { fillColor = col; fillMode = FILL_POLYGON; return *this; } - CurveAttributes& setLineWidth(size_t width) { lineWidth = static_cast<int>(width); return *this; } - - private: - friend class Graph2D; - - bool autoColor = true; - wxColor color; - - enum FillMode - { - FILL_NONE, - FILL_CURVE, - FILL_POLYGON - }; - - FillMode fillMode = FILL_NONE; - wxColor fillColor; - - int lineWidth = 2; - }; - - void setCurve(const std::shared_ptr<CurveData>& data, const CurveAttributes& ca = CurveAttributes()); - void addCurve(const std::shared_ptr<CurveData>& data, const CurveAttributes& ca = CurveAttributes()); - - static wxColor getBorderColor() { return { 130, 135, 144 }; } //medium grey, the same Win7 uses for other frame borders => not accessible! but no big deal... - - enum PosLabelY - { - LABEL_Y_LEFT, - LABEL_Y_RIGHT, - LABEL_Y_NONE - }; - - enum PosLabelX - { - LABEL_X_TOP, - LABEL_X_BOTTOM, - LABEL_X_NONE - }; - - enum PosCorner - { - CORNER_TOP_LEFT, - CORNER_TOP_RIGHT, - CORNER_BOTTOM_LEFT, - CORNER_BOTTOM_RIGHT, - }; - - enum SelMode - { - SELECT_NONE, - SELECT_RECTANGLE, - SELECT_X_AXIS, - SELECT_Y_AXIS, - }; - - class MainAttributes - { - public: - MainAttributes& setMinX(double newMinX) { minX = newMinX; minXauto = false; return *this; } - MainAttributes& setMaxX(double newMaxX) { maxX = newMaxX; maxXauto = false; return *this; } - - MainAttributes& setMinY(double newMinY) { minY = newMinY; minYauto = false; return *this; } - MainAttributes& setMaxY(double newMaxY) { maxY = newMaxY; maxYauto = false; return *this; } - - MainAttributes& setAutoSize() { minXauto = maxXauto = minYauto = maxYauto = true; return *this; } - - MainAttributes& setLabelX(PosLabelX posX, size_t height = 25, std::shared_ptr<LabelFormatter> newLabelFmt = std::make_shared<DecimalNumberFormatter>()) - { - labelposX = posX; - xLabelHeight = static_cast<int>(height); - labelFmtX = newLabelFmt; - return *this; - } - MainAttributes& setLabelY(PosLabelY posY, size_t width = 60, std::shared_ptr<LabelFormatter> newLabelFmt = std::make_shared<DecimalNumberFormatter>()) - { - labelposY = posY; - yLabelWidth = static_cast<int>(width); - labelFmtY = newLabelFmt; - return *this; - } - - MainAttributes& setCornerText(const wxString& txt, PosCorner pos) { cornerTexts[pos] = txt; return *this; } - - MainAttributes& setBackgroundColor(const wxColor& col) { backgroundColor = col; return *this; } - - MainAttributes& setSelectionMode(SelMode mode) { mouseSelMode = mode; return *this; } - - private: - friend class Graph2D; - - bool minXauto = true; //autodetect range for X value - bool maxXauto = true; - double minX = 0; //x-range to visualize - double maxX = 0; // - - bool minYauto = true; //autodetect range for Y value - bool maxYauto = true; - double minY = 0; //y-range to visualize - double maxY = 0; // - - PosLabelX labelposX = LABEL_X_BOTTOM; - int xLabelHeight = 25; - std::shared_ptr<LabelFormatter> labelFmtX = std::make_shared<DecimalNumberFormatter>(); - - PosLabelY labelposY = LABEL_Y_LEFT; - int yLabelWidth = 60; - std::shared_ptr<LabelFormatter> labelFmtY = std::make_shared<DecimalNumberFormatter>(); - - std::map<PosCorner, wxString> cornerTexts; - - wxColor backgroundColor = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); - SelMode mouseSelMode = SELECT_RECTANGLE; - }; - void setAttributes(const MainAttributes& newAttr) { attr = newAttr; Refresh(); } - MainAttributes getAttributes() const { return attr; } - - std::vector<SelectionBlock> getSelections() const { return oldSel; } - void setSelections(const std::vector<SelectionBlock>& sel) - { - oldSel = sel; - activeSel.reset(); - Refresh(); - } - void clearSelection() { oldSel.clear(); Refresh(); } - -private: - void OnMouseLeftDown(wxMouseEvent& event); - void OnMouseMovement(wxMouseEvent& event); - void OnMouseLeftUp (wxMouseEvent& event); - void OnMouseCaptureLost(wxMouseCaptureLostEvent& event); - - void onPaintEvent(wxPaintEvent& event); - void onSizeEvent(wxSizeEvent& event) { Refresh(); event.Skip(); } - void onEraseBackGround(wxEraseEvent& event) {} - - void render(wxDC& dc) const; - - class MouseSelection - { - public: - MouseSelection(wxWindow& wnd, const wxPoint& posDragStart) : wnd_(wnd), posDragStart_(posDragStart), posDragCurrent(posDragStart) { wnd_.CaptureMouse(); } - ~MouseSelection() { if (wnd_.HasCapture()) wnd_.ReleaseMouse(); } - - wxPoint getStartPos() const { return posDragStart_; } - wxPoint& refCurrentPos() { return posDragCurrent; } - - SelectionBlock& refSelection() { return selBlock; } //updated in Graph2d::render(): this is fine, since only what's shown is selected! - - private: - wxWindow& wnd_; - const wxPoint posDragStart_; - wxPoint posDragCurrent; - SelectionBlock selBlock; - }; - std::vector<SelectionBlock> oldSel; //applied selections - std::shared_ptr<MouseSelection> activeSel; //set during mouse selection - - MainAttributes attr; //global attributes - - Opt<wxBitmap> doubleBuffer; - - using CurveList = std::vector<std::pair<std::shared_ptr<CurveData>, CurveAttributes>>; - CurveList curves_; - - //perf!!! generating the font is *very* expensive! don't do this repeatedly in Graph2D::render()! - const wxFont labelFont { wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, L"Arial" }; -}; -} - -#endif //GRAPH_H_234425245936567345799 +// *****************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0 *
+// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved *
+// *****************************************************************************
+
+#ifndef GRAPH_H_234425245936567345799
+#define GRAPH_H_234425245936567345799
+
+#include <map>
+#include <vector>
+#include <memory>
+#include <wx/panel.h>
+#include <wx/settings.h>
+#include <wx/bitmap.h>
+#include <zen/string_tools.h>
+#include <zen/optional.h>
+
+//elegant 2D graph as wxPanel specialization
+
+namespace zen
+{
+/*
+Example:
+ //init graph (optional)
+ m_panelGraph->setAttributes(Graph2D::MainAttributes().
+ setLabelX(Graph2D::LABEL_X_BOTTOM, 20, std::make_shared<LabelFormatterTimeElapsed>()).
+ setLabelY(Graph2D::LABEL_Y_RIGHT, 60, std::make_shared<LabelFormatterBytes>()));
+ //set graph data
+ std::shared_ptr<CurveData> curveDataBytes = ...
+ m_panelGraph->setCurve(curveDataBytes, Graph2D::CurveAttributes().setLineWidth(2).setColor(wxColor(0, 192, 0)));
+*/
+
+struct CurvePoint
+{
+ CurvePoint() {}
+ CurvePoint(double xVal, double yVal) : x(xVal), y(yVal) {}
+ double x = 0;
+ double y = 0;
+};
+inline bool operator==(const CurvePoint& lhs, const CurvePoint& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; }
+inline bool operator!=(const CurvePoint& lhs, const CurvePoint& rhs) { return !(lhs == rhs); }
+
+
+struct CurveData
+{
+ virtual ~CurveData() {}
+
+ virtual std::pair<double, double> getRangeX() const = 0;
+ virtual std::vector<CurvePoint> getPoints(double minX, double maxX, int pixelWidth) const = 0; //points outside the draw area are automatically trimmed!
+};
+
+//special curve types:
+struct ContinuousCurveData : public CurveData
+{
+ virtual double getValue(double x) const = 0;
+
+private:
+ std::vector<CurvePoint> getPoints(double minX, double maxX, int pixelWidth) const override;
+};
+
+struct SparseCurveData : public CurveData
+{
+ SparseCurveData(bool addSteps = false) : addSteps_(addSteps) {} //addSteps: add points to get a staircase effect or connect points via a direct line
+
+ virtual Opt<CurvePoint> getLessEq (double x) const = 0;
+ virtual Opt<CurvePoint> getGreaterEq(double x) const = 0;
+
+private:
+ std::vector<CurvePoint> getPoints(double minX, double maxX, int pixelWidth) const override;
+ const bool addSteps_;
+};
+
+
+struct ArrayCurveData : public SparseCurveData
+{
+ virtual double getValue(size_t pos) const = 0;
+ virtual size_t getSize () const = 0;
+
+private:
+ std::pair<double, double> getRangeX() const override { const size_t sz = getSize(); return std::make_pair(0.0, sz == 0 ? 0.0 : sz - 1.0); }
+
+ Opt<CurvePoint> getLessEq(double x) const override
+ {
+ const size_t sz = getSize();
+ const size_t pos = std::min<ptrdiff_t>(std::floor(x), sz - 1); //[!] expect unsigned underflow if empty!
+ if (pos < sz)
+ return CurvePoint(pos, getValue(pos));
+ return NoValue();
+ }
+
+ Opt<CurvePoint> getGreaterEq(double x) const override
+ {
+ const size_t pos = std::max<ptrdiff_t>(std::ceil(x), 0); //[!] use std::max with signed type!
+ if (pos < getSize())
+ return CurvePoint(pos, getValue(pos));
+ return NoValue();
+ }
+};
+
+
+struct VectorCurveData : public ArrayCurveData
+{
+ std::vector<double>& refData() { return data; }
+private:
+ double getValue(size_t pos) const override { return pos < data.size() ? data[pos] : 0; }
+ size_t getSize() const override { return data.size(); }
+
+ std::vector<double> data;
+};
+
+//------------------------------------------------------------------------------------------------------------
+
+struct LabelFormatter
+{
+ virtual ~LabelFormatter() {}
+
+ //determine convenient graph label block size in unit of data: usually some small deviation on "sizeProposed"
+ virtual double getOptimalBlockSize(double sizeProposed) const = 0;
+
+ //create human-readable text for x or y-axis position
+ virtual wxString formatText(double value, double optimalBlockSize) const = 0;
+};
+
+
+double nextNiceNumber(double blockSize); //round to next number which is convenient to read, e.g. 2.13 -> 2; 2.7 -> 2.5
+
+struct DecimalNumberFormatter : public LabelFormatter
+{
+ double getOptimalBlockSize(double sizeProposed ) const override { return nextNiceNumber(sizeProposed); }
+ wxString formatText (double value, double optimalBlockSize) const override { return zen::numberTo<wxString>(value); }
+};
+
+//------------------------------------------------------------------------------------------------------------
+
+//emit data selection event
+//Usage: wnd.Connect(wxEVT_GRAPH_SELECTION, GraphSelectEventHandler(MyDlg::OnGraphSelection), nullptr, this);
+// void MyDlg::OnGraphSelection(GraphSelectEvent& event);
+
+extern const wxEventType wxEVT_GRAPH_SELECTION;
+
+struct SelectionBlock
+{
+ CurvePoint from;
+ CurvePoint to;
+};
+
+class GraphSelectEvent : public wxCommandEvent
+{
+public:
+ GraphSelectEvent(const SelectionBlock& selBlock) : wxCommandEvent(wxEVT_GRAPH_SELECTION), selBlock_(selBlock) {}
+ wxEvent* Clone() const override { return new GraphSelectEvent(selBlock_); }
+
+ SelectionBlock getSelection() { return selBlock_; }
+
+private:
+ SelectionBlock selBlock_;
+};
+
+using GraphSelectEventFunction = void (wxEvtHandler::*)(GraphSelectEvent&);
+
+#define GraphSelectEventHandler(func) \
+ (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(GraphSelectEventFunction, &func)
+
+//------------------------------------------------------------------------------------------------------------
+
+class Graph2D : public wxPanel
+{
+public:
+ Graph2D(wxWindow* parent,
+ wxWindowID winid = wxID_ANY,
+ const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxDefaultSize,
+ long style = wxTAB_TRAVERSAL | wxNO_BORDER,
+ const wxString& name = wxPanelNameStr);
+
+ class CurveAttributes
+ {
+ public:
+ CurveAttributes() {} //required by GCC
+ CurveAttributes& setColor (const wxColor& col) { color = col; autoColor = false; return *this; }
+ CurveAttributes& fillCurveArea (const wxColor& col) { fillColor = col; fillMode = FILL_CURVE; return *this; }
+ CurveAttributes& fillPolygonArea(const wxColor& col) { fillColor = col; fillMode = FILL_POLYGON; return *this; }
+ CurveAttributes& setLineWidth(size_t width) { lineWidth = static_cast<int>(width); return *this; }
+
+ private:
+ friend class Graph2D;
+
+ bool autoColor = true;
+ wxColor color;
+
+ enum FillMode
+ {
+ FILL_NONE,
+ FILL_CURVE,
+ FILL_POLYGON
+ };
+
+ FillMode fillMode = FILL_NONE;
+ wxColor fillColor;
+
+ int lineWidth = 2;
+ };
+
+ void setCurve(const std::shared_ptr<CurveData>& data, const CurveAttributes& ca = CurveAttributes());
+ void addCurve(const std::shared_ptr<CurveData>& data, const CurveAttributes& ca = CurveAttributes());
+
+ static wxColor getBorderColor() { return { 130, 135, 144 }; } //medium grey, the same Win7 uses for other frame borders => not accessible! but no big deal...
+
+ enum PosLabelY
+ {
+ LABEL_Y_LEFT,
+ LABEL_Y_RIGHT,
+ LABEL_Y_NONE
+ };
+
+ enum PosLabelX
+ {
+ LABEL_X_TOP,
+ LABEL_X_BOTTOM,
+ LABEL_X_NONE
+ };
+
+ enum PosCorner
+ {
+ CORNER_TOP_LEFT,
+ CORNER_TOP_RIGHT,
+ CORNER_BOTTOM_LEFT,
+ CORNER_BOTTOM_RIGHT,
+ };
+
+ enum SelMode
+ {
+ SELECT_NONE,
+ SELECT_RECTANGLE,
+ SELECT_X_AXIS,
+ SELECT_Y_AXIS,
+ };
+
+ class MainAttributes
+ {
+ public:
+ MainAttributes& setMinX(double newMinX) { minX = newMinX; minXauto = false; return *this; }
+ MainAttributes& setMaxX(double newMaxX) { maxX = newMaxX; maxXauto = false; return *this; }
+
+ MainAttributes& setMinY(double newMinY) { minY = newMinY; minYauto = false; return *this; }
+ MainAttributes& setMaxY(double newMaxY) { maxY = newMaxY; maxYauto = false; return *this; }
+
+ MainAttributes& setAutoSize() { minXauto = maxXauto = minYauto = maxYauto = true; return *this; }
+
+ MainAttributes& setLabelX(PosLabelX posX, size_t height = 25, std::shared_ptr<LabelFormatter> newLabelFmt = std::make_shared<DecimalNumberFormatter>())
+ {
+ labelposX = posX;
+ xLabelHeight = static_cast<int>(height);
+ labelFmtX = newLabelFmt;
+ return *this;
+ }
+ MainAttributes& setLabelY(PosLabelY posY, size_t width = 60, std::shared_ptr<LabelFormatter> newLabelFmt = std::make_shared<DecimalNumberFormatter>())
+ {
+ labelposY = posY;
+ yLabelWidth = static_cast<int>(width);
+ labelFmtY = newLabelFmt;
+ return *this;
+ }
+
+ MainAttributes& setCornerText(const wxString& txt, PosCorner pos) { cornerTexts[pos] = txt; return *this; }
+
+ MainAttributes& setBackgroundColor(const wxColor& col) { backgroundColor = col; return *this; }
+
+ MainAttributes& setSelectionMode(SelMode mode) { mouseSelMode = mode; return *this; }
+
+ private:
+ friend class Graph2D;
+
+ bool minXauto = true; //autodetect range for X value
+ bool maxXauto = true;
+ double minX = 0; //x-range to visualize
+ double maxX = 0; //
+
+ bool minYauto = true; //autodetect range for Y value
+ bool maxYauto = true;
+ double minY = 0; //y-range to visualize
+ double maxY = 0; //
+
+ PosLabelX labelposX = LABEL_X_BOTTOM;
+ int xLabelHeight = 25;
+ std::shared_ptr<LabelFormatter> labelFmtX = std::make_shared<DecimalNumberFormatter>();
+
+ PosLabelY labelposY = LABEL_Y_LEFT;
+ int yLabelWidth = 60;
+ std::shared_ptr<LabelFormatter> labelFmtY = std::make_shared<DecimalNumberFormatter>();
+
+ std::map<PosCorner, wxString> cornerTexts;
+
+ wxColor backgroundColor = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
+ SelMode mouseSelMode = SELECT_RECTANGLE;
+ };
+ void setAttributes(const MainAttributes& newAttr) { attr = newAttr; Refresh(); }
+ MainAttributes getAttributes() const { return attr; }
+
+ std::vector<SelectionBlock> getSelections() const { return oldSel; }
+ void setSelections(const std::vector<SelectionBlock>& sel)
+ {
+ oldSel = sel;
+ activeSel.reset();
+ Refresh();
+ }
+ void clearSelection() { oldSel.clear(); Refresh(); }
+
+private:
+ void OnMouseLeftDown(wxMouseEvent& event);
+ void OnMouseMovement(wxMouseEvent& event);
+ void OnMouseLeftUp (wxMouseEvent& event);
+ void OnMouseCaptureLost(wxMouseCaptureLostEvent& event);
+
+ void onPaintEvent(wxPaintEvent& event);
+ void onSizeEvent(wxSizeEvent& event) { Refresh(); event.Skip(); }
+ void onEraseBackGround(wxEraseEvent& event) {}
+
+ void render(wxDC& dc) const;
+
+ class MouseSelection
+ {
+ public:
+ MouseSelection(wxWindow& wnd, const wxPoint& posDragStart) : wnd_(wnd), posDragStart_(posDragStart), posDragCurrent(posDragStart) { wnd_.CaptureMouse(); }
+ ~MouseSelection() { if (wnd_.HasCapture()) wnd_.ReleaseMouse(); }
+
+ wxPoint getStartPos() const { return posDragStart_; }
+ wxPoint& refCurrentPos() { return posDragCurrent; }
+
+ SelectionBlock& refSelection() { return selBlock; } //updated in Graph2d::render(): this is fine, since only what's shown is selected!
+
+ private:
+ wxWindow& wnd_;
+ const wxPoint posDragStart_;
+ wxPoint posDragCurrent;
+ SelectionBlock selBlock;
+ };
+ std::vector<SelectionBlock> oldSel; //applied selections
+ std::shared_ptr<MouseSelection> activeSel; //set during mouse selection
+
+ MainAttributes attr; //global attributes
+
+ Opt<wxBitmap> doubleBuffer;
+
+ using CurveList = std::vector<std::pair<std::shared_ptr<CurveData>, CurveAttributes>>;
+ CurveList curves_;
+
+ //perf!!! generating the font is *very* expensive! don't do this repeatedly in Graph2D::render()!
+ const wxFont labelFont { wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, L"Arial" };
+};
+}
+
+#endif //GRAPH_H_234425245936567345799
|