iup-stack/iup/srcplot/iupPlot.h

793 lines
27 KiB
C
Raw Normal View History

2023-02-20 16:44:45 +00:00
/* Single plot class.
Multiple plots can be used in the same IupPlot element.
This is a re-write of the PPlot library,
directly using CD for drawing and IUP callback for interaction.
*/
#include "iup.h"
#include "iupcbs.h"
#include "iup_array.h"
#include "iup_str.h"
#include <cd.h>
#ifndef __IUPPLOT_H__
#define __IUPPLOT_H__
enum iupPlotMode { IUP_PLOT_LINE, IUP_PLOT_MARK, IUP_PLOT_MARKLINE, IUP_PLOT_AREA, IUP_PLOT_BAR, IUP_PLOT_STEM, IUP_PLOT_MARKSTEM, IUP_PLOT_HORIZONTALBAR, IUP_PLOT_MULTIBAR, IUP_PLOT_STEP, IUP_PLOT_ERRORBAR, IUP_PLOT_PIE };
enum iupPlotLegendPosition { IUP_PLOT_TOPRIGHT, IUP_PLOT_TOPLEFT, IUP_PLOT_BOTTOMRIGHT, IUP_PLOT_BOTTOMLEFT, IUP_PLOT_BOTTOMCENTER, IUP_PLOT_XY };
enum iupPlotSliceLabel { IUP_PLOT_NONE, IUP_PLOT_X, IUP_PLOT_Y, IUP_PLOT_PERCENT };
enum iupPlotHighlight { IUP_PLOT_HIGHLIGHT_NONE, IUP_PLOT_HIGHLIGHT_SAMPLE, IUP_PLOT_HIGHLIGHT_CURVE, IUP_PLOT_HIGHLIGHT_BOTH };
enum iupPlotClipping { IUP_PLOT_CLIPNONE, IUP_PLOT_CLIPAREA, IUP_PLOT_CLIPAREAOFFSET };
enum iupPlotAxisPosition { IUP_PLOT_START, IUP_PLOT_CROSSORIGIN, IUP_PLOT_END };
#define IUP_PLOT_DEF_NUMBERFORMAT "%.0f"
#define IUP_PLOT_DEF_NUMBERFORMATSIGNED "% .0f"
#define IUP_PLOT_DEF_TIPFORMAT "%.2f"
const double kFloatSmall = 1e-20;
const double kLogMinClipValue = 1e-10; // pragmatism to avoid problems with small values in log plot
long iupPlotDrawGetSampleColorTable(Ihandle* ih, int index);
int iupPlotCalcPrecision(double inValue);
inline int iupPlotRound(double inFloat)
{
return (int)(inFloat > 0 ? inFloat + 0.5 : inFloat - 0.5);
}
inline double iupPlotLog(double inFloat, double inBase)
{
const double kLogMin = 1e-10; // min argument for log10 function
if (inFloat<kLogMin) inFloat = kLogMin;
return log10(inFloat) / log10(inBase);
}
inline int iupPlotMax(int a, int b)
{
return a>b ? a: b;
}
inline double iupPlotExp(double inFloat, double inBase)
{
const double kExpMax = 1e10; // max argument for pow10 function
if (inFloat>kExpMax) inFloat = kExpMax;
return pow(inBase, inFloat);
}
inline void iupPlotDrawSetLineStyle(cdCanvas* canvas, int inLineStyle, int inLineWidth)
{
cdCanvasLineStyle(canvas, inLineStyle);
cdCanvasLineWidth(canvas, inLineWidth);
}
inline void iPlotSetMark(cdCanvas* canvas, int inMarkStyle, int inMarkSize)
{
cdCanvasMarkType(canvas, inMarkStyle);
cdCanvasMarkSize(canvas, inMarkSize);
}
inline void iupPlotDrawText(cdCanvas* canvas, double inX, double inY, int inAlignment, const char* inString)
{
cdCanvasTextAlignment(canvas, inAlignment);
cdfCanvasText(canvas, inX, inY, inString);
}
inline void iupPlotDrawRect(cdCanvas* canvas, double inX, double inY, double inW, double inH)
{
cdfCanvasRect(canvas, inX, inX + inW - 1, inY, inY + inH - 1);
}
inline void iupPlotDrawBox(cdCanvas* canvas, double inX, double inY, double inW, double inH)
{
cdfCanvasBox(canvas, inX, inX + inW - 1, inY, inY + inH - 1);
}
class iupPlotRect
{
public:
iupPlotRect() :mX(0), mY(0), mWidth(0), mHeight(0) {}
iupPlotRect(int inX, int inY, int inWidth, int inHeight)
: mX(inX), mY(inY), mWidth(inWidth), mHeight(inHeight) {}
int mX;
int mY;
int mWidth;
int mHeight;
};
class iupPlotMargin
{
public:
iupPlotMargin() :mLeft(0), mRight(0), mTop(0), mBottom(0) {}
iupPlotMargin(int inLeft, int inRight, int inTop, int inBottom)
: mLeft(inLeft), mRight(inRight), mTop(inTop), mBottom(inBottom) {}
int mLeft;
int mRight;
int mTop;
int mBottom;
};
class iupPlotAxis;
class iupPlotTrafo
{
public:
virtual ~iupPlotTrafo() {}
virtual double Transform(double inValue) const = 0;
virtual double TransformBack(double inValue) const = 0;
virtual bool Calculate(int inBegin, int inEnd, const iupPlotAxis& inAxis) = 0;
};
class iupPlotTrafoLinear : public iupPlotTrafo
{
public:
iupPlotTrafoLinear() :mOffset(0), mSlope(0) {}
double Transform(double inValue) const;
double TransformBack(double inValue) const;
bool Calculate(int inBegin, int inEnd, const iupPlotAxis& inAxis);
double mOffset;
double mSlope;
};
class iupPlotTrafoLog : public iupPlotTrafo
{
public:
iupPlotTrafoLog() :mOffset(0), mSlope(0), mBase(10) {}
double Transform(double inValue) const;
double TransformBack(double inValue) const;
bool Calculate(int inBegin, int inEnd, const iupPlotAxis& inAxis);
double mOffset;
double mSlope;
double mBase;
};
class iupPlotData
{
public:
iupPlotData(int inSize) : mCount(0), mIsString(false) { mArray = iupArrayCreate(20, inSize); }
virtual ~iupPlotData() { iupArrayDestroy(mArray); }
bool IsString() const { return mIsString; }
int GetCount() const { return mCount; }
virtual bool CalculateRange(double &outMin, double &outMax) const = 0;
virtual double GetSample(int inSampleIndex) const = 0;
void RemoveSample(int inSampleIndex) {
if (inSampleIndex < 0) inSampleIndex = 0; if (inSampleIndex > mCount) inSampleIndex = mCount;
iupArrayRemove(mArray, inSampleIndex, 1); mCount--;
}
protected:
int mCount;
Iarray* mArray;
bool mIsString;
};
class iupPlotDataReal : public iupPlotData
{
public:
iupPlotDataReal() :iupPlotData(sizeof(double)) { mData = (double*)iupArrayGetData(mArray); }
double GetSample(int inSampleIndex) const { return mData[inSampleIndex]; }
void SetSample(int inSampleIndex, double inReal) const { mData[inSampleIndex] = inReal; }
void AddSample(double inReal) { mData = (double*)iupArrayInc(mArray); mData[mCount] = inReal; mCount++; }
void InsertSample(int inSampleIndex, double inReal) {
if (inSampleIndex < 0) inSampleIndex = 0; if (inSampleIndex > mCount) inSampleIndex = mCount;
mData = (double*)iupArrayInsert(mArray, inSampleIndex, 1); mData[inSampleIndex] = inReal; mCount++;
}
bool CalculateRange(double &outMin, double &outMax) const;
protected:
double* mData;
};
class iupPlotDataString : public iupPlotData
{
public:
iupPlotDataString() :iupPlotData(sizeof(char*)) { mIsString = true; mData = (char**)iupArrayGetData(mArray); }
~iupPlotDataString();
double GetSample(int inSampleIndex) const { return inSampleIndex; }
const char* GetSampleString(int inSampleIndex) const { return mData[inSampleIndex]; }
void SetSampleString(int inSampleIndex, const char *inString) const {
if (inString == mData[inSampleIndex]) return; // set for the same pointer does nothing
free(mData[inSampleIndex]);
mData[inSampleIndex] = iupStrDup(inString);
}
void AddSample(const char *inString) { mData = (char**)iupArrayInc(mArray); mData[mCount] = iupStrDup(inString); mCount++; }
void InsertSample(int inSampleIndex, const char *inString) {
if (inSampleIndex < 0) inSampleIndex = 0; if (inSampleIndex > mCount) inSampleIndex = mCount;
mData = (char**)iupArrayInsert(mArray, inSampleIndex, 1); mData[inSampleIndex] = iupStrDup(inString); mCount++;
}
bool CalculateRange(double &outMin, double &outMax) const;
protected:
char** mData;
};
class iupPlotDataBool : public iupPlotData
{
public:
iupPlotDataBool() :iupPlotData(sizeof(bool)) { mData = (bool*)iupArrayGetData(mArray); }
double GetSample(int inSampleIndex) const { return (int)mData[inSampleIndex]; }
bool GetSampleBool(int inSampleIndex) const { return mData[inSampleIndex]; }
void SetSampleBool(int inSampleIndex, bool inBool) { mData[inSampleIndex] = inBool; }
void AddSample(bool inBool) { mData = (bool*)iupArrayInc(mArray); mData[mCount] = inBool; mCount++; }
void InsertSample(int inSampleIndex, bool inBool) {
if (inSampleIndex < 0) inSampleIndex = 0; if (inSampleIndex > mCount) inSampleIndex = mCount;
mData = (bool*)iupArrayInsert(mArray, inSampleIndex, 1); mData[inSampleIndex] = inBool; mCount++;
}
bool CalculateRange(double &outMin, double &outMax) const;
protected:
bool* mData;
};
struct iupPlotSampleNotify
{
Ihandle* ih;
int ds;
IFniiddi cb;
};
class iupPlotDataSet
{
public:
iupPlotDataSet(bool strXdata);
~iupPlotDataSet();
void SetName(const char* inName) { if (inName == mName) return; if (mName) free(mName); mName = iupStrDup(inName); }
const char* GetName() { return mName; }
bool FindSample(iupPlotTrafo *inTrafoX, iupPlotTrafo *inTrafoY, double inScreenX, double inScreenY, double inScreenTolerance, int &outSampleIndex, double &outX, double &outY) const;
bool FindPointSample(iupPlotTrafo *inTrafoX, iupPlotTrafo *inTrafoY, double inScreenX, double inScreenY, double inScreenTolerance, int &outSampleIndex, double &outX, double &outY) const;
bool FindMultipleBarSample(iupPlotTrafo *inTrafoX, iupPlotTrafo *inTrafoY, double inScreenX, double inScreenY, int &outSampleIndex, double &outX, double &outY) const;
bool FindBarSample(iupPlotTrafo *inTrafoX, iupPlotTrafo *inTrafoY, double inScreenX, double inScreenY, int &outSampleIndex, double &outX, double &outY) const;
bool FindHorizontalBarSample(iupPlotTrafo *inTrafoX, iupPlotTrafo *inTrafoY, double inScreenX, double inScreenY, int &outSampleIndex, double &outX, double &outY) const;
bool FindPieSample(iupPlotTrafo *inTrafoX, iupPlotTrafo *inTrafoY, double inScreenX, double inScreenY, int &outSampleIndex, double &outX, double &outY) const;
bool FindSegment(iupPlotTrafo *mTrafoX, iupPlotTrafo *mTrafoY, double inScreenX, double inScreenY, double inScreenTolerance, int &outSampleIndex1, int &outSampleIndex2, double &outX1, double &outY1, double &outX2, double &outY2) const;
void DrawData(const iupPlotTrafo *inTrafoX, const iupPlotTrafo *inTrafoY, cdCanvas* canvas, const iupPlotSampleNotify* inNotify) const;
void DrawDataPie(const iupPlotTrafo *inTrafoX, const iupPlotTrafo *inTrafoY, cdCanvas* canvas, const iupPlotSampleNotify* inNotify, const iupPlotAxis& inAxisY, long inBackColor) const;
int GetCount();
void AddSample(double inX, double inY);
void InsertSample(int inSampleIndex, double inX, double inY);
void AddSampleSegment(double inX, double inY, bool inSegment);
void InsertSampleSegment(int inSampleIndex, double inX, double inY, bool inSegment);
void AddSample(const char* inX, double inY);
void InsertSample(int inSampleIndex, const char* inX, double inY);
void RemoveSample(int inSampleIndex);
void GetSample(int inSampleIndex, double *inX, double *inY);
void GetSample(int inSampleIndex, const char* *inX, double *inY);
bool GetSampleSelection(int inSampleIndex);
double GetSampleExtra(int inSampleIndex);
void SetSample(int inSampleIndex, double inX, double inY);
void SetSample(int inSampleIndex, const char* inX, double inY);
void SetSampleSelection(int inSampleIndex, bool inSelected);
void SetSampleExtra(int inSampleIndex, double inExtra);
const iupPlotData* GetDataX() const { return mDataX; }
const iupPlotData* GetDataY() const { return mDataY; }
const iupPlotDataBool* GetSelection() const { return mSelection; }
const iupPlotDataBool* GetSegment() const { return mSegment; }
const iupPlotDataReal* GetExtra() const { return mExtra; }
bool SelectSamples(double inMinX, double inMaxX, double inMinY, double inMaxY, const iupPlotSampleNotify* inNotify);
bool ClearSelection(const iupPlotSampleNotify* inNotify);
bool DeleteSelectedSamples(const iupPlotSampleNotify* inNotify);
long mColor;
iupPlotMode mMode;
int mLineStyle;
int mLineWidth;
unsigned char mAreaTransparency;
int mMarkStyle;
int mMarkSize;
int mMultibarIndex;
int mMultibarCount;
long mBarOutlineColor;
bool mBarShowOutline;
bool mBarMulticolor;
int mBarSpacingPercent;
double mPieRadius;
double mPieStartAngle;
bool mPieContour;
double mPieHole;
iupPlotSliceLabel mPieSliceLabel;
double mPieSliceLabelPos;
void* mUserData;
bool mOrderedX;
bool mSelectedCurve;
// Aux
int mHighlightedSample;
bool mHighlightedCurve;
protected:
char* mName;
iupPlotData* mDataX;
iupPlotData* mDataY;
iupPlotDataBool* mSelection;
iupPlotDataReal* mExtra;
iupPlotDataBool* mSegment;
bool mHasSelected;
void InitSegment();
void InitExtra();
void DrawDataLine(const iupPlotTrafo *inTrafoX, const iupPlotTrafo *inTrafoY, cdCanvas* canvas, const iupPlotSampleNotify* inNotify, bool inShowMark, bool inErrorBar) const;
void DrawDataMark(const iupPlotTrafo *inTrafoX, const iupPlotTrafo *inTrafoY, cdCanvas* canvas, const iupPlotSampleNotify* inNotify) const;
void DrawDataStem(const iupPlotTrafo *inTrafoX, const iupPlotTrafo *inTrafoY, cdCanvas* canvas, const iupPlotSampleNotify* inNotify, bool inShowMark) const;
void DrawDataArea(const iupPlotTrafo *inTrafoX, const iupPlotTrafo *inTrafoY, cdCanvas* canvas, const iupPlotSampleNotify* inNotify) const;
void DrawDataBar(const iupPlotTrafo *inTrafoX, const iupPlotTrafo *inTrafoY, cdCanvas* canvas, const iupPlotSampleNotify* inNotify) const;
void DrawDataHorizontalBar(const iupPlotTrafo *inTrafoX, const iupPlotTrafo *inTrafoY, cdCanvas* canvas, const iupPlotSampleNotify* inNotify) const;
void DrawDataMultiBar(const iupPlotTrafo *inTrafoX, const iupPlotTrafo *inTrafoY, cdCanvas* canvas, const iupPlotSampleNotify* inNotify) const;
void DrawSelection(const iupPlotTrafo *inTrafoX, const iupPlotTrafo *inTrafoY, cdCanvas* canvas, const iupPlotSampleNotify* inNotify) const;
void DrawDataStep(const iupPlotTrafo *inTrafoX, const iupPlotTrafo *inTrafoY, cdCanvas* canvas, const iupPlotSampleNotify* inNotify) const;
void DrawErrorBar(const iupPlotTrafo *inTrafoY, cdCanvas* canvas, int index, double theY, double theScreenX) const;
void SetSampleExtraMarkSize(const iupPlotTrafo *inTrafoY, cdCanvas* canvas, int inSampleIndex) const;
};
class iupPlotTick;
class iupPlotTickIter
{
public:
iupPlotTickIter() :mAxis(NULL){}
virtual ~iupPlotTickIter() {}
virtual bool Init() = 0;
virtual bool GetNextTick(double &outTick, bool &outIsMajorTick, char* outFormatString) = 0;
virtual bool CalculateSpacing(double inParRange, double inDivGuess, iupPlotTick &outTickInfo) const = 0;
virtual bool AdjustRange(double &, double &) const { return true; };
void SetAxis(const iupPlotAxis *inAxis) { mAxis = inAxis; };
protected:
const iupPlotAxis *mAxis;
};
class iupPlotTickIterLinear : public iupPlotTickIter
{
public:
iupPlotTickIterLinear() :mCurrentTick(0), mCount(0), mDelta(0){}
virtual bool Init();
virtual bool GetNextTick(double &outTick, bool &outIsMajorTick, char* outFormatString);
bool CalculateSpacing(double inParRange, double inDivGuess, iupPlotTick &outTickInfo) const;
protected:
double mCurrentTick;
long mCount;
double mDelta;
};
class iupPlotTickIterLog : public iupPlotTickIter
{
public:
iupPlotTickIterLog() :mCurrentTick(0), mCount(0), mDelta(0){}
virtual bool Init();
virtual bool GetNextTick(double &outTick, bool &outIsMajorTick, char* outFormatString);
bool CalculateSpacing(double inParRange, double inDivGuess, iupPlotTick &outTickInfo) const;
virtual bool AdjustRange(double &ioMin, double &ioMax) const;
double RoundUp(double inFloat) const;
double RoundDown(double inFloat) const;
protected:
double mCurrentTick;
long mCount;
double mDelta;
};
class iupPlotTickIterNamed : public iupPlotTickIterLinear
{
public:
iupPlotTickIterNamed(){}
void SetStringList(const iupPlotDataString* inStringData) { mStringData = inStringData; };
virtual bool GetNextTick(double &outTick, bool &outIsMajorTick, char* outFormatString);
bool CalculateSpacing(double inParRange, double inDivGuess, iupPlotTick &outTickInfo) const;
protected:
const iupPlotDataString* mStringData;
};
class iupPlotTick
{
public:
iupPlotTick()
:mAutoSpacing(true), mAutoSize(true), mMinorDivision(1), mShowNumber(true),
mMajorSpan(1), mMajorSize(1), mMinorSize(1), mShow(true), mRotateNumberAngle(90),
mFontSize(0), mFontStyle(-1), mRotateNumber(false), mFormatAuto(true)
{
strcpy(mFormatString, IUP_PLOT_DEF_NUMBERFORMAT);
}
bool mShow;
bool mShowNumber;
bool mRotateNumber;
double mRotateNumberAngle;
char mFormatString[30];
bool mFormatAuto;
int mFontSize;
int mFontStyle;
bool mAutoSpacing;
int mMinorDivision;
double mMajorSpan; // in plot units
bool mAutoSize;
int mMajorSize;
int mMinorSize;
};
class iupPlotAxis
{
public:
iupPlotAxis(int inDefaultFontStyle, int inDefaultFontSize, bool inVertical)
: mShow(true), mMin(0), mMax(0), mAutoScaleMin(true), mAutoScaleMax(true),
mReverse(false), mLogScale(false), mPosition(IUP_PLOT_START), mColor(CD_BLACK),
mMaxDecades(-1), mLogBase(10), mLabelCentered(true), mHasZoom(false),
mDiscrete(false), mLabel(NULL), mShowArrow(true), mLineWidth(1), mLabelSpacing(-1),
mFontSize(0), mFontStyle(-1), mDefaultFontSize(inDefaultFontSize),
mTrafo(NULL), mTickIter(NULL), mDefaultFontStyle(inDefaultFontStyle),
mNoZoomMin(0), mNoZoomMax(0), mNoZoomAutoScaleMin(false), mNoZoomAutoScaleMax(false),
mPanMin(0), mReverseTicksLabel(false), mVertical(inVertical)
{
strcpy(mTipFormatString, IUP_PLOT_DEF_TIPFORMAT);
}
~iupPlotAxis() { SetLabel(NULL); }
void SetLabel(const char* inLabel) { if (inLabel == mLabel) return; if (mLabel) free(mLabel); mLabel = iupStrDup(inLabel); }
const char* GetLabel() const { return mLabel; }
void Init();
void SetNamedTickIter(const iupPlotDataString *inStringXData);
void GetTickNumberSize(cdCanvas* canvas, int *outWitdh, int *outHeight) const;
int GetTickNumberHeight(cdCanvas* canvas) const;
int GetTickNumberWidth(cdCanvas* canvas) const;
int GetArrowSize() const;
bool HasZoom() const { return mHasZoom; }
bool ResetZoom();
bool ZoomIn(double inCenter);
bool ZoomOut(double inCenter);
bool ZoomTo(double inMin, double inMax);
void PanStart() { mPanMin = mMin; }
bool Pan(double inOffset);
bool Scroll(double inDelta, bool inFullPage);
bool ScrollTo(double inMin);
void SetFont(cdCanvas* canvas, int inFontStyle, int inFontSize) const;
bool mShow;
bool mVertical;
long mColor;
double mMin;
double mMax;
bool mAutoScaleMin;
bool mAutoScaleMax;
bool mReverse;
iupPlotAxisPosition mPosition;
bool mShowArrow;
char mTipFormatString[30];
bool mReverseTicksLabel;
int mFontSize;
int mFontStyle;
bool mLabelCentered;
int mDefaultFontSize;
int mDefaultFontStyle;
int mLabelSpacing;
bool mLogScale;
int mMaxDecades;// property for auto logscale
double mLogBase;
bool mDiscrete;
int mLineWidth;
iupPlotTick mTick;
iupPlotTrafo *mTrafo;
iupPlotTickIter *mTickIter;
protected:
char* mLabel;
iupPlotTrafoLinear mLinTrafo;
iupPlotTrafoLog mLogTrafo;
iupPlotTickIterLinear mLinTickIter;
iupPlotTickIterLog mLogTickIter;
iupPlotTickIterNamed mNamedTickIter;
void InitZoom();
void CheckZoomOutLimit(double inRange);
bool mHasZoom;
double mNoZoomMin;
double mNoZoomMax;
bool mNoZoomAutoScaleMin;
bool mNoZoomAutoScaleMax;
double mPanMin;
};
class iupPlotAxisX : public iupPlotAxis
{
public:
iupPlotAxisX(int inDefaultFontStyle, int inDefaultFontSize) :
iupPlotAxis(inDefaultFontStyle, inDefaultFontSize, false) {}
bool DrawX(const iupPlotRect &inRect, cdCanvas* canvas, const iupPlotAxis& inAxisY, Ihandle* ih) const;
protected:
void DrawXTick(double inX, double inScreenY, bool inMajor, const char* inFormatString, cdCanvas* canvas, Ihandle* ih, IFnssds formatticknumber_cb) const;
double GetScreenYOriginX(const iupPlotAxis& inAxisY) const;
};
class iupPlotAxisY : public iupPlotAxis
{
public:
iupPlotAxisY(int inDefaultFontStyle, int inDefaultFontSize) :
iupPlotAxis(inDefaultFontStyle, inDefaultFontSize, true) {}
bool DrawY(const iupPlotRect &inRect, cdCanvas* canvas, const iupPlotAxis& inAxisX, Ihandle* ih) const;
protected:
void DrawYTick(double inY, double inScreenX, bool inMajor, const char* inFormatString, cdCanvas* canvas, Ihandle* ih, IFnssds formatticknumber_cb) const;
double GetScreenXOriginY(const iupPlotAxis& inAxisX) const;
};
class iupPlotGrid
{
public:
iupPlotGrid(bool inMajor)
: mShowX(false), mShowY(false), mColor(cdEncodeColor(200, 200, 200)),
mLineStyle(CD_CONTINUOUS), mLineWidth(1), mMajor(inMajor) {}
bool DrawX(iupPlotTickIter* inTickIter, iupPlotTrafo* inTrafo, const iupPlotRect &inRect, cdCanvas* canvas) const;
bool DrawY(iupPlotTickIter* inTickIter, iupPlotTrafo* inTrafo, const iupPlotRect &inRect, cdCanvas* canvas) const;
bool mMajor;
bool mShowX;
bool mShowY;
long mColor;
int mLineStyle;
int mLineWidth;
};
class iupPlotBox
{
public:
iupPlotBox()
: mShow(false), mColor(CD_BLACK),
mLineStyle(CD_CONTINUOUS), mLineWidth(1) {}
void Draw(const iupPlotRect &inRect, cdCanvas* canvas) const;
bool mShow;
long mColor;
int mLineStyle;
int mLineWidth;
};
class iupPlotLegend
{
public:
iupPlotLegend()
: mShow(false), mBoxShow(true), mFontSize(0), mFontStyle(-1), mPosition(IUP_PLOT_TOPRIGHT),
mBoxLineStyle(CD_CONTINUOUS), mBoxLineWidth(1), mBoxColor(CD_BLACK), mBoxBackColor(CD_WHITE)
{}
bool mShow;
iupPlotLegendPosition mPosition;
iupPlotRect mPos;
int mFontSize;
int mFontStyle;
bool mBoxShow;
long mBoxColor;
long mBoxBackColor;
int mBoxLineStyle;
int mBoxLineWidth;
};
class iupPlotTitle
{
public:
iupPlotTitle()
: mColor(CD_BLACK), mText(NULL), mFontSize(0), mFontStyle(-1),
mAutoPos(true), mPosX(0), mPosY(0) {}
~iupPlotTitle() { if (mText) free(mText); }
void SetText(const char* inText) { if (inText == mText) return; if (mText) free(mText); mText = iupStrDup(inText); }
const char* GetText() const { return mText; }
long mColor;
int mFontSize;
int mFontStyle;
bool mAutoPos;
int mPosX, mPosY;
protected:
char* mText;
};
class iupPlotBackground
{
public:
iupPlotBackground()
: mColor(CD_WHITE), mMarginAuto(1, 1, 1, 1), mImage(NULL), mHorizPadding(5), mVertPadding(5), mTransparent(false){}
~iupPlotBackground() { if (mImage) free(mImage); }
void SetImage(const char* inImage) { if (inImage == mImage) return; if (mImage) free(mImage); mImage = iupStrDup(inImage); }
const char* GetImage() const { return mImage; }
iupPlotMargin mMargin,
mMarginAuto; // Used as boolean
long mColor;
double mImageMinX,
mImageMaxX,
mImageMinY,
mImageMaxY;
int mHorizPadding, mVertPadding;
bool mTransparent;
protected:
char* mImage;
};
class iupPlot
{
public:
iupPlot(Ihandle* ih, int inDefaultFontStyle, int inDefaultFontSize);
~iupPlot();
/*********************************/
bool mRedraw;
iupPlotRect mViewport;
bool mViewportSquare;
int mDefaultFontSize;
int mDefaultFontStyle;
bool mScaleEqual;
iupPlotClipping mDataSetClipping;
bool mCrossHairH, mCrossHairV;
int mCrossHairX, mCrossHairY;
bool mShowSelectionBand;
iupPlotRect mSelectionBand;
iupPlotHighlight mHighlightMode;
double mScreenTolerance;
iupPlotBackground mBack;
iupPlotGrid mGrid;
iupPlotGrid mGridMinor;
iupPlotAxisX mAxisX;
iupPlotAxisY mAxisY;
iupPlotBox mBox;
iupPlotLegend mLegend;
iupPlotTitle mTitle;
iupPlotDataSet* *mDataSetList;
int mDataSetListCount;
int mDataSetListMax;
int mCurrentDataSet;
bool PrepareRender(cdCanvas* canvas);
bool Render(cdCanvas* canvas);
void SetViewport(int x, int y, int w, int h);
void ResetZoom() { if (mAxisX.ResetZoom()) mRedraw = true; if (mAxisY.ResetZoom()) mRedraw = true; }
void ZoomIn(double inCenterX, double inCenterY) { if (mAxisX.ZoomIn(inCenterX)) mRedraw = true; if (mAxisY.ZoomIn(inCenterY)) mRedraw = true; }
void ZoomOut(double inCenterX, double inCenterY) { if (mAxisX.ZoomOut(inCenterX)) mRedraw = true; if (mAxisY.ZoomOut(inCenterY)) mRedraw = true; }
void ZoomTo(double inMinX, double inMaxX, double inMinY, double inMaxY) { if (mAxisX.ZoomTo(inMinX, inMaxX)) mRedraw = true; if (mAxisY.ZoomTo(inMinY, inMaxY)) mRedraw = true; }
void PanStart() { mAxisX.PanStart(); mAxisY.PanStart(); }
void Pan(double inOffsetX, double inOffsetY) { if (mAxisX.Pan(inOffsetX)) mRedraw = true; if (mAxisY.Pan(inOffsetY)) mRedraw = true; }
void Scroll(double inDelta, bool inFullPage, bool inVertical) { if (inVertical) { if (mAxisY.Scroll(inDelta, inFullPage)) mRedraw = true; } else { if (mAxisX.Scroll(inDelta, inFullPage)) mRedraw = true; } }
void ScrollTo(double inMinX, double inMinY) { if (mAxisX.ScrollTo(inMinX)) mRedraw = true; if (mAxisY.ScrollTo(inMinY)) mRedraw = true; }
void TransformBack(int inX, int inY, double &outX, double &outY) const {
outX = mAxisX.mTrafo->TransformBack((double)inX);
outY = mAxisY.mTrafo->TransformBack((double)inY);
}
bool CheckInsideTitle(cdCanvas* canvas, int x, int y) const;
bool CheckInsideLegend(int x, int y) const;
void AddDataSet(iupPlotDataSet* inDataSet);
void RemoveDataSet(int inIndex);
int FindDataSet(const char* inName) const;
void RemoveAllDataSets();
bool FindDataSetSample(double inScreenX, double inScreenY, int &outIndex, const char* &outName, int &outSampleIndex, double &outX, double &outY, const char* &outStrX) const;
bool FindDataSetSegment(double inScreenX, double inScreenY, int &outIndex, const char* &outName, int &outSampleIndex1, double &outX1, double &outY1, int &outSampleIndex2, double &outX2, double &outY2) const;
void SelectDataSetSamples(double inMinX, double inMaxX, double inMinY, double inMaxY);
void DeleteSelectedDataSetSamples();
void ClearDataSetSelection();
void ClearHighlight();
void UpdateMultibarCount();
protected:
Ihandle* ih;
iupPlotRect mViewportBack;
void DataSetClipArea(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax) const;
void ConfigureAxis();
void SetFont(cdCanvas* canvas, int inFontStyle, int inFontSize) const;
void SetTitleFont(cdCanvas* canvas) const;
bool CheckRange(const iupPlotAxis &inAxis) const;
bool HasZoom() const { return mAxisX.HasZoom() || mAxisY.HasZoom(); }
long GetNextDataSetColor() const;
iupPlotDataSet* HasPie() const;
/*********************************/
void DrawTitle(cdCanvas* canvas) const;
void DrawBackground(cdCanvas* canvas) const;
void DrawBackgroundImage(cdCanvas* canvas) const;
bool DrawLegend(const iupPlotRect &inRect, cdCanvas* canvas, iupPlotRect &ioPos) const;
bool DrawSampleColorLegend(iupPlotDataSet *inData, const iupPlotRect &inRect, cdCanvas* canvas, iupPlotRect &ioPos) const;
void DrawCrossHairH(const iupPlotRect &inRect, cdCanvas* canvas) const;
void DrawCrossSamplesH(const iupPlotRect &inRect, const iupPlotData *inXData, const iupPlotData *inYData, cdCanvas* canvas) const;
void DrawCrossHairV(const iupPlotRect &inRect, cdCanvas* canvas) const;
void DrawCrossSamplesV(const iupPlotRect &inRect, const iupPlotData *inXData, const iupPlotData *inYData, cdCanvas* canvas) const;
void DrawInactive(cdCanvas* canvas) const;
/*********************************/
void CalculateTitlePos();
void CalculateMargins(cdCanvas* canvas);
bool CalculateAxisRange();
void CalculateXRange(double &outXMin, double &outXMax) const;
void CalculateYRange(double &outYMin, double &outYMax) const;
bool CalculateYTransformation(const iupPlotRect &inRect);
bool CalculateXTransformation(const iupPlotRect &inRect);
bool CalculateLinTransformation(int inBegin, int inEnd, const iupPlotAxis& inAxis, iupPlotTrafoLinear* outTrafo);
bool CalculateLogTransformation(int inBegin, int inEnd, const iupPlotAxis& inAxis, iupPlotTrafoLog* outTrafo);
bool CalculateTickSpacing(const iupPlotRect &inRect, cdCanvas* canvas);
void CalculateTickSize(cdCanvas* canvas, iupPlotTick &ioTick);
int CalcYTickVerticalMargin(cdCanvas* canvas, bool start) const;
int CalcXTickHorizontalMargin(cdCanvas* canvas, bool start) const;
int CalcXTickVerticalMargin(cdCanvas* canvas) const;
int CalcYTickHorizontalMargin(cdCanvas* canvas) const;
int CalcTitleVerticalMargin(cdCanvas* canvas) const;
};
#endif