From d577d991b97ae2b5ee1af23641bcffc3f83af5b2 Mon Sep 17 00:00:00 2001 From: Pixel Date: Wed, 4 Nov 2009 11:56:41 -0800 Subject: Initial import. Contains the im, cd and iup librairies, and a "working" Makefile for them under linux. --- iup/srcpplot/Makefile | 6 + iup/srcpplot/config.mak | 25 + iup/srcpplot/iupPPlot.cpp | 2470 ++++++++++++++++++++++++++++ iup/srcpplot/iupPPlot.h | 645 ++++++++ iup/srcpplot/iupPPlotInteraction.cpp | 832 ++++++++++ iup/srcpplot/iupPPlotInteraction.h | 328 ++++ iup/srcpplot/iup_pplot.cpp | 2959 ++++++++++++++++++++++++++++++++++ iup/srcpplot/iup_pplot.def | 11 + iup/srcpplot/iup_pplot.dep | 12 + iup/srcpplot/iuppplot.hpp | 137 ++ iup/srcpplot/make_uname | 3 + iup/srcpplot/make_uname.bat | 4 + 12 files changed, 7432 insertions(+) create mode 100755 iup/srcpplot/Makefile create mode 100755 iup/srcpplot/config.mak create mode 100755 iup/srcpplot/iupPPlot.cpp create mode 100755 iup/srcpplot/iupPPlot.h create mode 100755 iup/srcpplot/iupPPlotInteraction.cpp create mode 100755 iup/srcpplot/iupPPlotInteraction.h create mode 100755 iup/srcpplot/iup_pplot.cpp create mode 100755 iup/srcpplot/iup_pplot.def create mode 100644 iup/srcpplot/iup_pplot.dep create mode 100755 iup/srcpplot/iuppplot.hpp create mode 100755 iup/srcpplot/make_uname create mode 100755 iup/srcpplot/make_uname.bat (limited to 'iup/srcpplot') diff --git a/iup/srcpplot/Makefile b/iup/srcpplot/Makefile new file mode 100755 index 0000000..e10ef19 --- /dev/null +++ b/iup/srcpplot/Makefile @@ -0,0 +1,6 @@ + +.PHONY: do_all iup_pplot +do_all: iup_pplot + +iup_pplot: + @$(MAKE) --no-print-directory -f ../tecmake_compact.mak diff --git a/iup/srcpplot/config.mak b/iup/srcpplot/config.mak new file mode 100755 index 0000000..7c3975b --- /dev/null +++ b/iup/srcpplot/config.mak @@ -0,0 +1,25 @@ +PROJNAME = iup +LIBNAME = iup_pplot +OPT = YES + +USE_CD = Yes + +ifdef DBG + DEFINES += IUP_ASSERT +endif + +INCLUDES = ../include ../src +LDIR = ../lib/$(TEC_UNAME) +LIBS = iup iupcd + +DEFINES = _IUP_PPLOT_ CD_NO_OLD_INTERFACE + +SRC = iupPPlot.cpp iupPPlotInteraction.cpp iup_pplot.cpp + +ifneq ($(findstring owc, $(TEC_UNAME)), ) + CPPFLAGS = -xr -xst +endif + +ifeq "$(TEC_UNAME)" "vc6" + INCLUDES += C:\LNG\STLport\include +endif diff --git a/iup/srcpplot/iupPPlot.cpp b/iup/srcpplot/iupPPlot.cpp new file mode 100755 index 0000000..c0d07c9 --- /dev/null +++ b/iup/srcpplot/iupPPlot.cpp @@ -0,0 +1,2470 @@ +/*************************************************************************** + * * + * Copyright notice: * + * * + * This is free Pier ware. You may do whatever you want with this code, * + * except that you should not remove this copyright notice. * + * * + ***************************************************************************/ + +#ifdef _MSC_VER +#pragma warning(disable: 4100) +#pragma warning(disable: 4512) +#endif + +#include +#include +#include + +#include "iupPPlot.h" + +const float kFloatSmall = 1e-20f; +const float kLogMin = 1e-10f;// min argument for log10 function +const float kExpMax = 1e10f;// max argument for pow10 function +const float kLogMinClipValue = 1e-10f;// pragmatism to avoid problems with small values in log plot +const float kEps = 1e-4f; +const float kRelMajorTickSize = 0.02f; +const float kRelMinorTickSize = 0.01f; +const int kMinMinorTickScreenSize = 1;// minor ticks should not become smaller than this +const float kMaxMajorTickSizeInFontHeight = 0.5f;// not larger than half the font height +const float kLittleIncrease = 1.0001f; +const float kLittleDecrease = 0.9999f; +const float kTickValueVeryBig = 1.0e4;// switch to scientific format +const float kTickValueVerySmall = (float)1.0e-3; +const float kMajorTickXInitialFac = 2.0f; +const float kMajorTickYInitialFac = 3.0f; +const PMargins kDefaultMargins = PMargins (40,20,5,42); + +const float PPlot::kRangeVerySmall = (float)1.0e-3; // also in ZoomInteraction + +template const T & PMax (const T &a, const T &b) { + return b> a ? b: a; +} + +inline float SafeLog (float inFloat, float inBase, float inFac) { + if (inFloatkExpMax) { + inFloat = kExpMax; + } + return pow(inBase, inFloat/inFac); +} + +long PlotDataBase::GetSize () const { + if (GetRealPlotData ()) { + return GetRealPlotData ()->size (); + } + if (GetCalculatedData ()) { + return GetCalculatedData ()->GetSize (); + } + return 0; +} + +float PlotDataBase::GetValue (long inIndex) const { + if (GetRealPlotData ()) { + return (*GetRealPlotData ())[inIndex]; + } + if (GetCalculatedData ()) { + return GetCalculatedData ()->GetValue (inIndex); + } + return 0; +} + +bool PlotDataBase::CalculateRange (float &outXMin, float &outXMax) { + const RealData *theData = GetRealPlotData (); + if (theData && theData->size () >0) { + vector::const_iterator imin = min_element (theData->begin (), theData->end ()); + vector::const_iterator imax = max_element (theData->begin (), theData->end ()); + outXMin = *imin; + outXMax = *imax; + return true; + } + else { + const CalculatedDataBase *theCalculated = GetCalculatedData (); + if (theCalculated) { + outXMin = theCalculated->GetValue (0); + outXMax = theCalculated->GetValue (theCalculated->GetSize () - 1); + return true; + } + } + + return false; +} + +DummyPlotData::DummyPlotData (long inSize) { + for (int theI=0;theI0; +} + +long PlotDataSelection::GetSelectedCount () const { + long theCount = 0; + for (int theI=0;theI1) { + while (theSpan>10) { + theSpan/=10; + if (theSpan == inSpan) { // not a number + return (float)-1.234567; + } + thePow++; + } + } + else { + while (theSpan<1) { + theSpan*=10; + thePow--; + } + } + int theRoundedFirstDigit = PPlot::Round (theSpan); + int thePreferredFirstDigit = 1; + switch (theRoundedFirstDigit) { + case 1: + thePreferredFirstDigit = 1; + break; + case 2: + case 3: + case 4: + thePreferredFirstDigit = 2; + break; + case 5: + case 6: + case 7: + case 8: + case 9: + thePreferredFirstDigit = 5; + break; + case 10: + thePreferredFirstDigit = 1; + thePow++; + break; + default: + // error + return (float)-1.234567; + break; + } + float theRes = thePreferredFirstDigit*pow (10., thePow); /* M.T. changed to force a double cast */ + return theRes; +} + +void TickInfo::MakeFormatString (float inValue, string &outFormatString) { + if (inValue<0) { + inValue = - inValue; + } + if (inValue > kTickValueVeryBig || inValue < kTickValueVerySmall) { + outFormatString = "%.1e"; + } + else { + + int thePrecision = 0; + if (inValue<1) { + float theSpan = inValue; + while (theSpan<1) { + thePrecision++; + theSpan *=10; + } + } + + char theBuf[128] = "%.0f"; + theBuf[2] = '0'+thePrecision; + + outFormatString = theBuf; + } +} + + +PlotDataBase::~PlotDataBase (){ +}; + + +PlotDataContainer::PlotDataContainer (){ +} +PlotDataContainer::~PlotDataContainer (){ + ClearData (); +} + +PlotDataBase * PlotDataContainer::GetXData (int inIndex) { + if (inIndex < 0 || inIndex >= mXDataList.size ()) { + return 0; + } + return mXDataList[inIndex]; +} + +PlotDataBase * PlotDataContainer::GetYData (int inIndex) { + if (inIndex < 0 || inIndex >= mYDataList.size ()) { + return 0; + } + return mYDataList[inIndex]; +} + +LegendData * PlotDataContainer::GetLegendData (int inIndex) { + if (inIndex < 0 || inIndex >= mLegendDataList.size ()) { + return 0; + } + return mLegendDataList[inIndex]; +} + +DataDrawerBase * PlotDataContainer::GetDataDrawer (int inIndex) { + if (inIndex < 0 || inIndex >= mDataDrawerList.size ()) { + return 0; + } + return mDataDrawerList[inIndex]; +} + +PlotDataSelection * PlotDataContainer::GetPlotDataSelection (int inIndex) { + if (inIndex < 0 || inIndex >= mPlotDataSelectionList.size ()) { + return 0; + } + return mPlotDataSelectionList[inIndex]; +} + +const PlotDataBase * PlotDataContainer::GetConstXData (int inIndex) const { + if (inIndex < 0 || inIndex >= mXDataList.size ()) { + return 0; + } + return mXDataList[inIndex]; +} + +const PlotDataBase * PlotDataContainer::GetConstYData (int inIndex) const { + if (inIndex < 0 || inIndex >= mYDataList.size ()) { + return 0; + } + return mYDataList[inIndex]; +} + +const LegendData * PlotDataContainer::GetConstLegendData (int inIndex) const { + if (inIndex < 0 || inIndex >= mLegendDataList.size ()) { + return 0; + } + return mLegendDataList[inIndex]; +} + +const DataDrawerBase * PlotDataContainer::GetConstDataDrawer (int inIndex) const { + if (inIndex < 0 || inIndex >= mDataDrawerList.size ()) { + return 0; + } + return mDataDrawerList[inIndex]; +} + +const PlotDataSelection * PlotDataContainer::GetConstPlotDataSelection (int inIndex) const { + if (inIndex < 0 || inIndex >= mPlotDataSelectionList.size ()) { + return 0; + } + return mPlotDataSelectionList[inIndex]; +} + +void PlotDataContainer::RemoveElement (int inIndex) { + if (!(inIndex < mXDataList.size () && inIndex < mYDataList.size () && + inIndex < mLegendDataList.size () && inIndex < mDataDrawerList.size ())) { + // Invalid index + return; + } + + PlotDataList::iterator theXI = mXDataList.begin () + inIndex; + PlotDataList::iterator theYI = mYDataList.begin () + inIndex; + LegendDataList::iterator theLI = mLegendDataList.begin () + inIndex; + DataDrawerList::iterator theDI = mDataDrawerList.begin () + inIndex; + PlotDataSelectionList::iterator thePI = mPlotDataSelectionList.begin () + inIndex; + + delete *theXI; + delete *theYI; + delete *theLI; + delete *theDI; + delete *thePI; + + mXDataList.erase (theXI); + mYDataList.erase (theYI); + mLegendDataList.erase (theLI); + mDataDrawerList.erase (theDI); + mPlotDataSelectionList.erase (thePI); +} + +void PlotDataContainer::ClearData () { + PlotDataList::iterator theXI = mXDataList.begin (); + PlotDataList::iterator theYI = mYDataList.begin (); + LegendDataList::iterator theLI = mLegendDataList.begin (); + DataDrawerList::iterator theDI = mDataDrawerList.begin (); + PlotDataSelectionList::iterator thePI = mPlotDataSelectionList.begin (); + + for (;theXI!=mXDataList.end () && theYI!=mYDataList.end () && theLI!=mLegendDataList.end () && theDI != mDataDrawerList.end () && thePI != mPlotDataSelectionList.end ();) { + PlotDataBase *theX = *theXI; + PlotDataBase *theY = *theYI; + LegendData *theL = *theLI; + DataDrawerBase *theD = *theDI; + PlotDataSelection *theP = *thePI; + + delete theX; + delete theY; + delete theL; + delete theD; + delete theP; + + theXI++; + theYI++; + theLI++; + theDI++; + thePI++; + } + mXDataList.clear (); + mYDataList.clear (); + mLegendDataList.clear (); + mDataDrawerList.clear (); + mPlotDataSelectionList.clear (); +} + +/* M.T. - changed to return the index of the added plot; returns -1 on error */ +int PlotDataContainer::AddXYPlot (PlotDataBase *inXData, PlotDataBase *inYData, LegendData *inLegendData, DataDrawerBase *inDataDrawer, PlotDataSelection *inPlotDataSelection) { + if (!inYData || (!inYData->GetRealPlotData () && !inYData->GetCalculatedData ())) { + return -1; + } + PlotDataBase *theXData = inXData; + if (!theXData) { + theXData = new DummyPlotData (inYData->GetSize ()); + } + mXDataList.push_back (theXData); + mYDataList.push_back (inYData); + + LegendData *theLegendData = inLegendData; + if (!theLegendData) { + theLegendData = new LegendData (); + theLegendData->SetDefaultValues (mLegendDataList.size ()); + } + mLegendDataList.push_back (theLegendData); + + DataDrawerBase *theDataDrawer = inDataDrawer; + if (!theDataDrawer) { + theDataDrawer = new LineDataDrawer (); + } + mDataDrawerList.push_back (theDataDrawer); + + PlotDataSelection *thePlotDataSelection = inPlotDataSelection; + if (!thePlotDataSelection) { + thePlotDataSelection = new PlotDataSelection (); + } + else { + thePlotDataSelection->resize (inYData->GetSize ()); + } + mPlotDataSelectionList.push_back (thePlotDataSelection); + return ( mYDataList.size() - 1 ); +} + +void PlotDataContainer::SetXYPlot (int inIndex, PlotDataBase *inXData, PlotDataBase *inYData, LegendData *inLegendData, DataDrawerBase *inDataDrawer, PlotDataSelection *inPlotDataSelection) { + if (!inYData || !inYData->GetRealPlotData ()) { + return; + } + if (!CheckState ()) { + return; + } + long thePlotCount = GetPlotCount (); + if (inIndex<0||inIndex>thePlotCount) { + return; + } + PlotDataBase *theXData = inXData; + + if (!theXData) { + theXData = new DummyPlotData (inYData->GetRealPlotData ()->size ()); + } + LegendData *theLegendData = inLegendData; + DataDrawerBase *theDataDrawer = inDataDrawer; + if (!theLegendData) { + theLegendData = new LegendData (); + if (inIndex >= 0 && inIndex < mYDataList.size () ) { + *theLegendData = *mLegendDataList[inIndex]; // copy old values... + } else { + theLegendData->SetDefaultValues (mLegendDataList.size ()); + } + } + if (!theDataDrawer) { + theDataDrawer = new LineDataDrawer (); + } + PlotDataSelection *thePlotDataSelection = inPlotDataSelection; + if (!thePlotDataSelection) { + thePlotDataSelection = new PlotDataSelection (inYData->GetSize ()); + // thePlotDataSelection = new PlotDataSelection (); + } + if (inIndex >= 0 && inIndex < mYDataList.size () ) { + delete mXDataList[inIndex]; + delete mYDataList[inIndex]; + delete mLegendDataList[inIndex]; + delete mDataDrawerList[inIndex]; + delete mPlotDataSelectionList[inIndex]; + + mXDataList[inIndex] = theXData; + mYDataList[inIndex] = inYData; + mLegendDataList[inIndex] = theLegendData; + mDataDrawerList[inIndex] = theDataDrawer; + mPlotDataSelectionList[inIndex] = thePlotDataSelection; + } else { // add at end + mXDataList.push_back (theXData); + mYDataList.push_back (inYData); + mLegendDataList.push_back (theLegendData); + mDataDrawerList.push_back (theDataDrawer); + mPlotDataSelectionList.push_back (thePlotDataSelection); + } +} + +bool PlotDataContainer::SetDataDrawer (int inIndex, DataDrawerBase* inDataDrawer) { + if (inIndex < 0 || inIndex >= mYDataList.size () ) { + return false; + } + DataDrawerBase* theDataDrawer = inDataDrawer; + if (!inDataDrawer) { + theDataDrawer = new LineDataDrawer; + } + delete mDataDrawerList[inIndex]; + mDataDrawerList[inIndex] = theDataDrawer; + return true; +} + +int PlotDataContainer::GetPlotIndexByName (const string &inName) const { + + if (CheckState ()) { + for (int theI=0;theImName == inName) { + return theI; + } + } + } + return -1; +} + + +bool PlotDataContainer::CalculateXRange (float &outXMin, float &outXMax) const { + bool theFirst = true; + outXMin = 0; + outXMax = 0; + for (PlotDataList::const_iterator theI=mXDataList.begin();theI!=mXDataList.end ();theI++) { + PlotDataBase *theXDataBase = *theI; + if (!theXDataBase) { + return false; + } + if (theXDataBase->GetSize () == 0) { + continue; + } + float theXMin; + float theXMax; + if (!theXDataBase->CalculateRange (theXMin, theXMax)) { + return false; + } + if (theXMax < theXMin) { + return false; + } + if (theFirst) { + outXMin = theXMin; + outXMax = theXMax; + theFirst = false; + } + if (theXMax>outXMax) { + outXMax = theXMax; + } + if (theXMinoutYMax) { + outYMax = theYMax; + } + + } + return true; +} + +bool PlotDataContainer::CalculateYRangePlot (float inXMin, float inXMax, const PlotDataBase &inXData, const PlotDataBase &inYData, float &outYMin, float &outYMax) const { + outYMin = 0; + outYMax = 0; + bool initialized = false; + + if (inXData.GetSize () != inYData.GetSize ()) { + return false; + } + + for (long theI = 0; theI < inXData.GetSize (); theI++) { + float theX = inXData.GetValue (theI); + float theY = inYData.GetValue (theI); + + if (theX>=inXMin && theX <= inXMax) { + if (!initialized) { + initialized = true; + outYMin = theY; + outYMax = theY; + } else { + if (theYoutYMax) { + outYMax = theY; + } + } + } + } + return true; +} + +bool PlotDataContainer::CheckState () const { + long theSize1 = mXDataList.size (); + long theSize2 = mYDataList.size (); + long theSize3 = mLegendDataList.size (); + long theSize4 = mDataDrawerList.size (); + long theSize5 = mPlotDataSelectionList.size (); + if (theSize1!=theSize2 || theSize1!=theSize3 || theSize1!=theSize4 || theSize1!=theSize5) { + return false; + } + return true; +} + +float LinTrafo::Transform (float inValue) const { + return inValue * mSlope + mOffset; +} +float LinTrafo::TransformBack (float inValue) const { + if (mSlope != 0) { + return (inValue - mOffset) / mSlope; + } else { + return 0; + } +} + + +float LogTrafo::Transform (float inValue) const{ + if (inValuemMin; + float theMajorTickSpan = mAxisSetup->mTickInfo.mMajorTickSpan; + int theDiv = mAxisSetup->mTickInfo.mTickDivision; + mDelta = theMajorTickSpan/theDiv; + mCount = ceil (theMin/mDelta); + mCurrentTick = mCount*mDelta; + + mFormatString = mAxisSetup->mTickInfo.mFormatString; + + return true; + +} + +bool LinTickIterator::GetNextTick (float &outTick, bool &outIsMajorTick, string &outFormatString) { + if (!mAxisSetup) { + return false; + } + if (mCurrentTick>mAxisSetup->mMax*kLittleIncrease) { + return false; + } + outTick = mCurrentTick; + outIsMajorTick = (mCount%mAxisSetup->mTickInfo.mTickDivision == 0); + outFormatString = mFormatString; + + mCurrentTick += mDelta; + mCount++; + return true; +} + +bool LinTickIterator::InitFromRanges (float inParRange, float inOrthoScreenRange, float inDivGuess, TickInfo &ioTickInfo) const { + if (inDivGuess <= kFloatSmall) { + return false; + } + float thePreferredSpan = TickInfo::RoundSpan (inParRange/inDivGuess); + if (thePreferredSpan < 0) { + return false; + } + + float thePreferredNrOfTicks = inParRange/thePreferredSpan; + if (thePreferredNrOfTicks <1) { + ioTickInfo.mMajorTickSpan = inParRange; + } + else { + ioTickInfo.mMajorTickSpan = thePreferredSpan; + } + + ioTickInfo.mTickDivision = 5; + if (ioTickInfo.mAutoTickSize) { + ioTickInfo.mMinorTickScreenSize = PMax (kMinMinorTickScreenSize, PPlot::Round (inOrthoScreenRange*kRelMinorTickSize)); + ioTickInfo.mMajorTickScreenSize = PMax (ioTickInfo.mMinorTickScreenSize+1, PPlot::Round (inOrthoScreenRange*kRelMajorTickSize)); + } + + TickInfo::MakeFormatString (ioTickInfo.mMajorTickSpan, ioTickInfo.mFormatString); + return true; +} + +bool LogTickIterator::Init () { + if (!mAxisSetup) { + return false; + } + + float theMin = mAxisSetup->mMin; + // float theMax = mAxisSetup->mMax; + float theMajorTickSpan = mAxisSetup->mTickInfo.mMajorTickSpan; + int theDiv = mAxisSetup->mTickInfo.mTickDivision; + mDelta = theMajorTickSpan/theDiv; + float theBase = mAxisSetup->mLogBase; + long theLogFac = 1;//mAxisSetup->mLogFactor; + long thePowMin = (long)floor(SafeLog(theMin, theBase, theLogFac)); + mCurrentTick = SafeExp (thePowMin, theBase, theLogFac); + mCount = 0; + + // walk to the first tick + + if (theMin<=0) { + return false; + // error + } + else { + // walk forward + float theNext = mCurrentTick+mDelta*SafeExp (thePowMin, theBase, theLogFac); + while (theNext<=theMin*kLittleDecrease) { + mCurrentTick = theNext; + theNext += mDelta*SafeExp (thePowMin,theBase, theLogFac); + mCount++; + } + } + return true; +} + +bool LogTickIterator::InitFromRanges (float inParRange, float inOrthoScreenRange, float inDivGuess, TickInfo &ioTickInfo) const { + if (inDivGuess<=kFloatSmall) { + return false; + } + /* + float thePreferredSpan = TickInfo::RoundSpan (inParRange/inDivGuess); + float thePreferredNrOfTicks = inParRange/thePreferredSpan; + if (thePreferredNrOfTicks <1) { + ioTickInfo.mMajorTickSpan = inParRange; + } + else { + ioTickInfo.mMajorTickSpan = thePreferredSpan; + } + */ + float theBase = mAxisSetup->mLogBase; + ioTickInfo.mMajorTickSpan = theBase-1;// relative + + ioTickInfo.mTickDivision = PPlot::Round (ioTickInfo.mMajorTickSpan); + ioTickInfo.mMinorTickScreenSize = PMax (kMinMinorTickScreenSize, PPlot::Round (inOrthoScreenRange*kRelMinorTickSize)); + ioTickInfo.mMajorTickScreenSize = PMax (ioTickInfo.mMinorTickScreenSize+1, PPlot::Round (inOrthoScreenRange*kRelMajorTickSize)); + + ioTickInfo.mFormatString = "%.1e"; + return true; +} + +bool LogTickIterator::GetNextTick (float &outTick, bool &outIsMajorTick, string &outFormatString) { + if (!mAxisSetup) { + return false; + } + if (mCurrentTick>mAxisSetup->mMax*kLittleIncrease) { + return false; + } + outTick = mCurrentTick; + outIsMajorTick = (mCount%mAxisSetup->mTickInfo.mTickDivision == 0); + TickInfo::MakeFormatString (outTick, outFormatString); + float theBase = mAxisSetup->mLogBase; + float theLogFac = 1;//mAxisSetup->mLogFactor; + float theLogNow = SafeLog(mCurrentTick, theBase, theLogFac); + int thePowNow = (int)floor(theLogNow); + outIsMajorTick = false; + if (fabs (theLogNow-thePowNow)mLogFactor>1) { + char theBuf[128]; + sprintf (theBuf, "%d", thePowNow*20); + outFormatString = theBuf; + } + + mCurrentTick += mDelta*SafeExp (thePowNow, theBase, theLogFac); + mCount++; + + return true; +} + +bool LogTickIterator::AdjustRange (float &ioMin, float &ioMax) const { + + float theBase = mAxisSetup->mLogBase; + long theLogFac = 1;//mAxisSetup->mLogFactor; + if (mAxisSetup->mMaxDecades > 0) { + ioMin = ioMax/SafeExp (mAxisSetup->mMaxDecades, theBase, theLogFac); + } + if (ioMin == 0 && ioMax == 0) { + ioMin = kLogMinClipValue; + ioMax = 1.0f; + } + if (ioMin <= 0 || ioMax<=0) { + return false; + } + ioMin = RoundDown (ioMin*kLittleIncrease); + ioMax = RoundUp (ioMax*kLittleDecrease); + + if (ioMinmMaxDecades > 0) { + ioMin = ioMax/SafeExp (mAxisSetup->mMaxDecades, theBase, theLogFac); + } + return true; +} + +float LogTickIterator::RoundUp (float inFloat) const { + float theBase = mAxisSetup->mLogBase; + float theLogFac = 1;//mAxisSetup->mLogFactor; + int thePow = (int)ceil(SafeLog(inFloat, theBase, theLogFac)); + return pow (theBase, thePow); +} + +float LogTickIterator::RoundDown (float inFloat) const { + float theBase = mAxisSetup->mLogBase; + long theLogFac = 1;//mAxisSetup->mLogFactor; + int thePow = (int)floor(SafeLog(inFloat,theBase, theLogFac)); + return pow (theBase, thePow); +} + +bool NamedTickIterator::GetNextTick (float &outTick, bool &outIsMajorTick, string &outFormatString) { + if (LinTickIterator::GetNextTick (outTick, outIsMajorTick, outFormatString)) { + int theIndex = PPlot::Round (outTick); + + // TO DO: improve this + if (fabs(outTick - (float)theIndex) > 0.1 ) { + outFormatString = ""; + return true; + } + + if (theIndex>=0 && theIndex < (int)mStringList.size ()) { + outFormatString = mStringList[theIndex]; + return true; + } + } + return false; +} + +bool NamedTickIterator::InitFromRanges (float inParRange, float inOrthoScreenRange, float inDivGuess, TickInfo &outTickInfo) const { + if (LinTickIterator::InitFromRanges (inParRange, inOrthoScreenRange, inDivGuess, outTickInfo)) { + outTickInfo.mTickDivision = 1; + return true; + } + return false; +} + +bool PainterTester::Draw (Painter &inPainter) { + + const char * theString = "The quick brown fox..."; + int theWidth = inPainter.CalculateTextDrawSize (theString); + int theOffset = theWidth/10; + + // a horizontal lines + int theHAscent_x = theOffset+2*inPainter.GetFontHeight (); + int theHAscent_y = 10; + int theHAscent_w = theWidth; + inPainter.DrawLine (theHAscent_x, theHAscent_y, theHAscent_x+theHAscent_w, theHAscent_y); + + int theHDescent_x = theHAscent_x; + int theHDescent_y = theHAscent_y+inPainter.GetFontHeight (); + int theHDescent_w = theHAscent_w; + inPainter.DrawLine (theHDescent_x, theHDescent_y, theHDescent_x+theHDescent_w, theHDescent_y); + + // a vertical lines + int theVAscent_x = theOffset; + int theVAscent_y = theHAscent_y+theWidth; + int theVAscent_h = -theWidth; + inPainter.DrawLine (theVAscent_x, theVAscent_y, theVAscent_x, theVAscent_y+theVAscent_h); + + int theVDescent_x = theVAscent_x+inPainter.GetFontHeight (); + int theVDescent_y = theVAscent_y; + int theVDescent_h = theVAscent_h; + inPainter.DrawLine (theVDescent_x, theVDescent_y, theVDescent_x, theVDescent_y+theVDescent_h); + + // Draw vertical text, followed by horizontal. +#ifdef _IUP_PPLOT_ /* M.T. - the alignment of the text is simply requested */ + inPainter.DrawRotatedText (theVDescent_x, theVDescent_y, -90, PPLOT_NORTH_WEST, theString); + inPainter.DrawText (theHDescent_x, theHDescent_y, PPLOT_NORTH_WEST, theString); +#else + inPainter.DrawRotatedText (theVDescent_x, theVDescent_y, -90, theString); + inPainter.DrawText (theHDescent_x, theHDescent_y, theString); +#endif + + return true; +} + +PPlot::PPlot (): + mShowLegend(true), // M.T. - show|hide legend + mLegendPos(PPLOT_TOPRIGHT), + mXTrafo (&mXLinTrafo), + mYTrafo (&mYLinTrafo), + mXTickIterator (&mXLinTickIterator), + mYTickIterator (&mYLinTickIterator), + mPPlotDrawer (0), + mOwnsPPlotDrawer (true), + mHasAnyModifyingCalculatorBeenActive (false) +{ + mMargins = kDefaultMargins; + mYAxisSetup.mAscending = false; +} + +PPlot::~PPlot () { + if (mOwnsPPlotDrawer) { + delete mPPlotDrawer; + } + mPPlotDrawer = 0; +} + +bool PPlot::Draw (Painter &inPainter) { + PRect theRect; + theRect.mX = mMargins.mLeft; + theRect.mY = mMargins.mTop; + theRect.mW = inPainter.GetWidth () - mMargins.mLeft - mMargins.mRight; + theRect.mH = inPainter.GetHeight () - mMargins.mTop - mMargins.mBottom; + + if (mPPlotDrawer) { + mPPlotDrawer->Prepare (inPainter, *this); + return mPPlotDrawer->Draw (inPainter); + } + if (!mPlotDataContainer.GetPlotCount ()) { + return true; + } + + if (!ConfigureSelf ()) { + return false; + } + bool theShouldRepeat = true; + long theRepeatCount = 0; + + while (theShouldRepeat && theRepeatCount<2) { + theRepeatCount++; + + if (!ValidateData ()) { + return false; + } + + if (!CalculateAxisRanges ()) { + return false; + } + + if (!this->CheckRange (mXAxisSetup)) { + return false; + } + + if (!this->CheckRange (mYAxisSetup)) { + return false; + } + + if (!CalculateTickInfo (theRect, inPainter)) { + return false; + } + + if (!CalculateXTransformation (theRect)) { + return false; + } + + if (!CalculateYTransformation (theRect)) { + return false; + } + if (theRepeatCount>1) { + break; + } + // hooks for some final calculations + bool theShouldRepeat = false; + for (PCalculator::tList::iterator theModifyingC=mModifyingCalculatorList.begin ();theModifyingC!=mModifyingCalculatorList.end();theModifyingC++) { + PCalculator *theModifyingCalculator = *theModifyingC; + if (theModifyingCalculator->ShouldCalculate ()) { + theShouldRepeat = true; + theModifyingCalculator->Calculate (inPainter, *this); + mHasAnyModifyingCalculatorBeenActive = true; + } + } +// theShouldRepeat = mModifyingCalculatorList.size ()>0; + } + + // hooks for some final calculations + for (PCalculator::tList::iterator thePostC=mPostCalculatorList.begin ();thePostC!=mPostCalculatorList.end();thePostC++) { + PCalculator *thePostCalculator = *thePostC; + thePostCalculator->Calculate (inPainter, *this); + } + + for (PDrawer::tList::iterator thePre1=mPreDrawerList.begin();thePre1!=mPreDrawerList.end ();thePre1++) { + PDrawer *thePreDrawer = *thePre1; + thePreDrawer->Prepare (inPainter, *this); + } + + // Drawing ! + + inPainter.SetLineColor (0,0,0); + inPainter.SetClipRect (0, 0, inPainter.GetWidth (), inPainter.GetHeight ()); + + // draw entire background, including the margins (for scrolling...) + PRect fullRect; + fullRect.mX = 0; + fullRect.mY = 0; + fullRect.mW = inPainter.GetWidth (); + fullRect.mH = inPainter.GetHeight (); + if (!DrawPlotBackground (fullRect, inPainter)) { + return false; + } + + for (PDrawer::tList::iterator thePre=mPreDrawerList.begin ();thePre!=mPreDrawerList.end();thePre++) { + PDrawer *thePreDrawer = *thePre; + thePreDrawer->Draw (inPainter); + } + + + if (!DrawGridXAxis (theRect, inPainter)) { + return false; + } + + if (!DrawGridYAxis (theRect, inPainter)) { + return false; + } + + if (!DrawXAxis (theRect, inPainter)) { + return false; + } + + if (!DrawYAxis (theRect, inPainter)) { + return false; + } + + // clip the plotregion while drawing plots + inPainter.SetClipRect (theRect.mX, theRect.mY, theRect.mW, theRect.mH); + + for (int theI=0;theIDraw (inPainter); + } + + return true; +} + +void PPlot::SetPPlotDrawer (PDrawer *inPDrawer) { + if (mOwnsPPlotDrawer) { + delete mPPlotDrawer;// delete (if any) + } + mOwnsPPlotDrawer = true; + mPPlotDrawer = inPDrawer; +} + +void PPlot::SetPPlotDrawer (PDrawer &inPDrawer) { + mOwnsPPlotDrawer = false; + mPPlotDrawer = &inPDrawer; +} + +bool PPlot::DrawPlotBackground (const PRect &inRect, Painter &inPainter) const { + if (!mPlotBackground.mTransparent) { + PColor theC = mPlotBackground.mPlotRegionBackColor; + inPainter.SetFillColor (theC.mR, theC.mG, theC.mB); + inPainter.FillRect (inRect.mX, inRect.mY, inRect.mW, inRect.mH); + } +#ifndef _IUP_PPLOT_ + string theTitle = mPlotBackground.mTitle; + if (theTitle.size ()>0) { + int theW = inPainter.CalculateTextDrawSize (theTitle.c_str()); + int theX = inRect.mX + (inRect.mW-theW)/2; + int theY = inRect.mY + mMargins.mTop; + inPainter.DrawText (theX, theY, theTitle.c_str ()); + } +#endif + return true; +} + +#ifdef _IUP_PPLOT_ +bool PPlot::DrawPlotTitle(const PRect &inRect, Painter &inPainter) const { + if (mPlotBackground.mTitle.size ()>0) { + inPainter.SetStyle (mPlotBackground.mStyle); + int theX = inRect.mX + inRect.mW/2; + int theY = inRect.mY + 5; // do not depend on margin + PColor theC = mPlotBackground.mPlotRegionBackColor; + inPainter.SetFillColor (theC.mR, theC.mG, theC.mB); + int textSize = inPainter.CalculateTextDrawSize(mPlotBackground.mTitle.c_str()); + inPainter.FillRect (theX-textSize/2-3, theY, textSize+6, inPainter.GetFontHeight()+3); + theC = mPlotBackground.mTitleColor; + inPainter.SetFillColor (theC.mR, theC.mG, theC.mB); + inPainter.DrawText (theX, theY, PPLOT_NORTH, mPlotBackground.mTitle.c_str()); + } + return true; +} +#endif + +bool PPlot::DrawGridXAxis (const PRect &inRect, Painter &inPainter) const { + + // ticks + inPainter.SetStyle (mXAxisSetup.mTickInfo.mStyle); + if (!mXTickIterator->Init ()) { + return false; + } + + float theX; + bool theIsMajorTick; + string theFormatString; + +/* M.T. - modified to allow customisation + inPainter.SetFillColor (200,200,200); + inPainter.SetLineColor (200,200,200); +*/ + inPainter.SetLineColor(mGridInfo.mGridColor.mR, + mGridInfo.mGridColor.mG, + mGridInfo.mGridColor.mB); + inPainter.SetStyle (mGridInfo.mStyle); + + // draw gridlines + if (mGridInfo.mXGridOn) { + while (mXTickIterator->GetNextTick (theX, theIsMajorTick, theFormatString)) { + + if (theIsMajorTick && mGridInfo.mXGridOn) { + float theScreenX = mXTrafo->Transform(theX); + inPainter.DrawLine (theScreenX, inRect.mY, theScreenX, inRect.mY + inRect.mH); + } + } + } + + return true; +} + +bool PPlot::DrawGridYAxis (const PRect &inRect, Painter &inPainter) const { + + // ticks + inPainter.SetStyle (mYAxisSetup.mTickInfo.mStyle); + if (!mYTickIterator->Init ()) { + return false; + } + + float theY; + bool theIsMajorTick; + string theFormatString; + PRect theTickRect; + +/* M.T. - modified to allow customisation + inPainter.SetFillColor (200,200,200); + inPainter.SetLineColor (200,200,200); +*/ + inPainter.SetLineColor(mGridInfo.mGridColor.mR, + mGridInfo.mGridColor.mG, + mGridInfo.mGridColor.mB); + inPainter.SetStyle (mGridInfo.mStyle); + + // draw gridlines + if (mYAxisSetup.mTickInfo.mTicksOn) { + while (mYTickIterator->GetNextTick (theY, theIsMajorTick, theFormatString)) { + + if (theIsMajorTick && mGridInfo.mYGridOn) { + float theScreenY = mYTrafo->Transform(theY); + inPainter.DrawLine (inRect.mX, theScreenY, inRect.mX + inRect.mW, theScreenY); + } + } + } + + return true; +} + +#ifdef _IUP_PPLOT_ +static void DrawArrow(Painter &inPainter, float rx, float ry, int vert, int ascen, int size) +{ + int x = (int)(rx + 0.5); + int y = (int)(ry + 0.5); + size += 2; // to avoid too small sizes + int size2 = (int)(size*0.7f + 0.5); + if (vert) + { + y-=ascen*size; + inPainter.DrawLine(x, y, x, y+ascen*size); + + int y2 = y+ascen*size2; + inPainter.FillArrow(x, y, x-size2, y2, x+size2, y2); + } + else + { + x+=ascen*size; + inPainter.DrawLine(x, y, x-ascen*size, y); + + int x2 = x-ascen*size2; + inPainter.FillArrow(x, y, x2, y-size2, x2, y+size2); + } +} +#endif + +bool PPlot::DrawXAxis (const PRect &inRect, Painter &inPainter) const { + inPainter.SetStyle (mXAxisSetup.mStyle); + + float theX1 = inRect.mX; + float theY1; + float theTargetY = 0; + if (!mXAxisSetup.mCrossOrigin) { + if (mYAxisSetup.mAscending) { + theTargetY = mYAxisSetup.mMax; + } else { + theTargetY = mYAxisSetup.mMin; + } + } + theY1 = mYTrafo->Transform (theTargetY); + + inPainter.SetLineColor(mXAxisSetup.mColor.mR, + mXAxisSetup.mColor.mG, + mXAxisSetup.mColor.mB); + + // x-axis + float theX2 = theX1+inRect.mW; + float theY2 = theY1; + inPainter.DrawLine (theX1, theY1, theX2, theY2); + +#ifdef _IUP_PPLOT_ + if (mXAxisSetup.mAscending) + DrawArrow(inPainter, theX2, theY2, 0, 1, mXAxisSetup.mTickInfo.mMinorTickScreenSize); + else + DrawArrow(inPainter, theX1, theY1, 0, -1, mXAxisSetup.mTickInfo.mMinorTickScreenSize); +#endif + + // ticks + inPainter.SetStyle (mXAxisSetup.mTickInfo.mStyle); + if (!mXTickIterator->Init ()) { + return false; + } + + float theX; + bool theIsMajorTick; + string theFormatString; + + int theYMax = 0; + PRect theTickRect; + PRect theRect = inRect; + + if (mXAxisSetup.mTickInfo.mTicksOn) { + while (mXTickIterator->GetNextTick (theX, theIsMajorTick, theFormatString)) { + if (!DrawXTick (theX, theY1, theIsMajorTick, theFormatString, inPainter, theTickRect)) { + return false; + } + + if (theTickRect.mY+theTickRect.mH>theYMax) { + theYMax = theTickRect.mY+theTickRect.mH; + } + } + } + + if (theYMax>theRect.mY+theRect.mH) { + theRect.mH = theYMax-theRect.mY; + } + +#ifdef _IUP_PPLOT_ /* M.T. - the alignment of the text is simply requested */ + if (mXAxisSetup.mLabel.size ()>0) { + inPainter.SetStyle (mXAxisSetup.mStyle); + int theY = theRect.mY + theRect.mH + 3*inPainter.GetFontHeight()/2; + if (mXAxisSetup.mLabelCentered) + { + int theX = theRect.mX + theRect.mW/2; + inPainter.DrawText (theX, theY, PPLOT_NORTH, mXAxisSetup.mLabel.c_str ()); + } + else + { + int theX = theRect.mX + theRect.mW; + inPainter.DrawText (theX, theY, PPLOT_NORTH_EAST, mXAxisSetup.mLabel.c_str ()); + } + } +#else + inPainter.SetStyle (mXAxisSetup.mStyle); + string theLabel = mXAxisSetup.mLabel; + if (theLabel.size ()>0) { + int theW = inPainter.CalculateTextDrawSize (theLabel.c_str ()); + int theX = theRect.mX + (theRect.mW-theW)/2; + int theY = 1 + theRect.mY + theRect.mH + inPainter.GetFontHeight (); // M.T. was too close to ticks + inPainter.DrawText (theX, theY, theLabel.c_str ()); + } +#endif + return true; +} + +bool PPlot::DrawXTick (float inX, int inScreenY, bool inMajor, const string &inFormatString, Painter &inPainter, PRect &outRect) const{ + char theBuf[128]; + int theTickSize; + float theScreenX = mXTrafo->Transform(inX); + outRect.mX = theScreenX; + outRect.mY = inScreenY; + outRect.mW = 0; + if (inMajor) { + theTickSize = mXAxisSetup.mTickInfo.mMajorTickScreenSize; + sprintf (theBuf, inFormatString.c_str (), inX); +#ifdef _IUP_PPLOT_ /* M.T. - the alignment of the text is simply requested */ + outRect.mH = theTickSize + mXAxisSetup.mTickInfo.mMinorTickScreenSize; + inPainter.DrawText (theScreenX, inScreenY+outRect.mH, PPLOT_NORTH, theBuf); +#else + outRect.mH = inPainter.GetFontHeight () + theTickSize + + mXAxisSetup.mTickInfo.mMinorTickScreenSize; + inPainter.DrawText (theScreenX, inScreenY+outRect.mH, theBuf); +#endif + } + else { + theTickSize = mXAxisSetup.mTickInfo.mMinorTickScreenSize; + outRect.mH = theTickSize; + } + + inPainter.DrawLine (theScreenX, inScreenY,theScreenX, inScreenY+theTickSize); + return true; +} + +bool PPlot::DrawYAxis (const PRect &inRect, Painter &inPainter) const { + inPainter.SetStyle (mYAxisSetup.mStyle); + float theX1; + float theTargetX = 0; + if (!mYAxisSetup.mCrossOrigin) { + if (mXAxisSetup.mAscending) { + theTargetX = mXAxisSetup.mMin; + } + else { + theTargetX = mXAxisSetup.mMax; + } + } + if (mXAxisSetup.mDiscrete) + theTargetX -= 0.5; + + theX1 = mXTrafo->Transform (theTargetX); + + int theY1 = inRect.mY; + float theX2 = theX1; + int theY2 = theY1+inRect.mH; + + inPainter.SetLineColor(mYAxisSetup.mColor.mR, + mYAxisSetup.mColor.mG, + mYAxisSetup.mColor.mB); + + // draw y axis + inPainter.DrawLine (theX1, theY1, theX2, theY2); + +#ifdef _IUP_PPLOT_ + if (mYAxisSetup.mAscending) + DrawArrow(inPainter, theX2, theY2, 1, -1, mYAxisSetup.mTickInfo.mMinorTickScreenSize); + else + DrawArrow(inPainter, theX1, theY1, 1, 1, mYAxisSetup.mTickInfo.mMinorTickScreenSize); +#endif + + // ticks + inPainter.SetStyle (mYAxisSetup.mTickInfo.mStyle); + if (!mYTickIterator->Init ()) { + return false; + } + + float theY; + bool theIsMajorTick; + string theFormatString; + PRect theTickRect; + PRect theRect = inRect; + + if (mYAxisSetup.mTickInfo.mTicksOn) { + while (mYTickIterator->GetNextTick (theY, theIsMajorTick, theFormatString)) { + if (!DrawYTick (theY, theX1, theIsMajorTick, theFormatString, inPainter, theTickRect)) { + return false; + } + + if (theTickRect.mX < theRect.mX) { + theRect.mX = theTickRect.mX; + } + } + } + + // draw label +#ifdef _IUP_PPLOT_ /* M.T. - the alignment of the text is simply requested */ + if (mYAxisSetup.mLabel.size ()>0) { + inPainter.SetStyle (mYAxisSetup.mStyle); + int theX = theRect.mX - 3*inPainter.GetFontHeight()/2; + if (mYAxisSetup.mLabelCentered) + { + int theY = theRect.mY + theRect.mH/2; + inPainter.DrawRotatedText (theX, theY, -90, PPLOT_NORTH, mYAxisSetup.mLabel.c_str ()); + } + else + { + int theY = theRect.mY; + inPainter.DrawRotatedText (theX, theY, -90, PPLOT_NORTH_EAST, mYAxisSetup.mLabel.c_str ()); + } + } +#else + inPainter.SetStyle (mYAxisSetup.mStyle); + string theLabel = mYAxisSetup.mLabel; + if (theLabel.size ()>0) { + int theW = inPainter.CalculateTextDrawSize (theLabel.c_str ()); + int theX = theRect.mX - 1; // M.T. - was too close to ticks + int theY = theRect.mY + theRect.mH - (theRect.mH-theW)/2; + inPainter.DrawRotatedText (theX, theY, -90, theLabel.c_str ()); + } +#endif + + return true; +} + +bool PPlot::DrawYTick (float inY, int inScreenX, bool inMajor, const string &inFormatString, Painter &inPainter, PRect &outRect) const { + char theBuf[128]; + int theTickSize; + float theScreenY = mYTrafo->Transform(inY); + outRect.mX = inScreenX; + outRect.mY = theScreenY; + outRect.mW = 0;// not used + outRect.mH = 0;// not used + if (inMajor) { + theTickSize = mYAxisSetup.mTickInfo.mMajorTickScreenSize; + sprintf (theBuf, inFormatString.c_str (), inY); +#ifdef _IUP_PPLOT_ /* M.T. - the alignment of the text is simply requested */ + outRect.mX -= (theTickSize + mYAxisSetup.mTickInfo.mMinorTickScreenSize); + inPainter.DrawText (outRect.mX, theScreenY, PPLOT_EAST, theBuf); + outRect.mX -= inPainter.CalculateTextDrawSize (theBuf); // update the position +#else + int theStringWidth = inPainter.CalculateTextDrawSize (theBuf); + outRect.mX -= (theStringWidth+theTickSize+mYAxisSetup.mTickInfo.mMinorTickScreenSize); + int theHalfFontHeight = inPainter.GetFontHeight ()/2;// for sort of vertical centralizing + inPainter.DrawText (outRect.mX, theScreenY+theHalfFontHeight, theBuf); +#endif + + } + else { + theTickSize = mYAxisSetup.mTickInfo.mMinorTickScreenSize; + outRect.mX -= theTickSize; + } + + inPainter.DrawLine (inScreenX, theScreenY, inScreenX-theTickSize, theScreenY); + return true; +} + +#ifdef _IUP_PPLOT_ +static void DrawRect(Painter &inPainter, int inX, int inY, int inW, int inH) +{ + inPainter.DrawLine(inX, inY, inX+inW-1, inY); + inPainter.DrawLine(inX+inW-1, inY, inX+inW-1, inY+inH-1); + inPainter.DrawLine(inX+inW-1, inY+inH-1, inX, inY+inH-1); + inPainter.DrawLine(inX, inY+inH-1, inX, inY); +} + +bool PPlot::DrawLegend (const PRect &inRect, Painter &inPainter) const { + PColor theC; + int theI; + + int theHeight = inPainter.GetFontHeight(); + int margin = theHeight/2; + int plotCount = mPlotDataContainer.GetPlotCount(); + int totalHeight = plotCount*(1.2*theHeight) - 0.2*theHeight + 2*margin; + + int maxWidth = 0; + for (theI=0; theImShow) { + inPainter.SetStyle (theLegendData->mStyle); + int size = inPainter.CalculateTextDrawSize(theLegendData->mName.c_str()); + + const DataDrawerBase* drawer = mPlotDataContainer.GetConstDataDrawer(theI); + if (drawer->mHasMarks) + { + LineDataDrawer* linedrawer = (LineDataDrawer*)drawer; + if (linedrawer->mDrawPoint) + size += linedrawer->mStyle.mMarkSize+8; + } + + if (size > maxWidth) + maxWidth = size; + } + } + + if (maxWidth == 0) + return false; + + maxWidth += 2*margin; + + int theX = inRect.mX; + int theY = inRect.mY; + + switch (mLegendPos) + { + case PPLOT_TOPLEFT: + theX += 2; + theY += 2; + break; + case PPLOT_BOTTOMLEFT: + theX += 2; + theY += inRect.mH - totalHeight - 2; + break; + case PPLOT_BOTTOMRIGHT: + theX += inRect.mW - maxWidth - 2; + theY += inRect.mH - totalHeight - 2; + break; + default: // PPLOT_TOPRIGHT + theX += inRect.mW - maxWidth - 2; + theY += 2; + break; + } + + theC = mPlotBackground.mPlotRegionBackColor; + inPainter.SetFillColor (theC.mR, theC.mG, theC.mB); + inPainter.FillRect(theX, theY, maxWidth, totalHeight); + inPainter.SetLineColor (theC.mR/1.5, theC.mG/1.5, theC.mB/1.5); + DrawRect(inPainter, theX, theY, maxWidth, totalHeight); + + for (theI=0; theImShow) { + theC = theLegendData->mColor; + inPainter.SetLineColor (theC.mR, theC.mG, theC.mB); + + int X = theX + margin; + int Y = theY + theI*(theHeight*1.2) + margin; + + int mark_size = 0; + const DataDrawerBase* drawer = mPlotDataContainer.GetConstDataDrawer(theI); + if (drawer->mHasMarks) + { + LineDataDrawer* linedrawer = (LineDataDrawer*)drawer; + if (linedrawer->mDrawPoint) + { + mark_size = linedrawer->mStyle.mMarkSize+8; + inPainter.SetStyle (linedrawer->mStyle); + linedrawer->DrawPoint(X+mark_size/2, Y+3*inPainter.GetFontHeight()/4, inRect, inPainter); + } + } + + inPainter.SetStyle (theLegendData->mStyle); + inPainter.DrawText (X+mark_size, Y, PPLOT_NORTH_WEST, theLegendData->mName.c_str ()); + } + } + return true; +} +#else +bool PPlot::DrawLegend (const PRect &inRect, Painter &inPainter) const { + const int kXoffsetLegend(20); + + for (int theI=0; theImStyle); + theC = theLegendData->mColor; + if (theLegendData->mShow) { + theText = theLegendData->mName; + } + } + inPainter.SetLineColor (theC.mR, theC.mG, theC.mB); + + // cut legend if it doesn't fit in plot + int theSize (0); + if (inPainter.CalculateTextDrawSize (theText.c_str ()) >= inRect.mW - kXoffsetLegend) { + theText.insert(0, "..."); + while (inPainter.CalculateTextDrawSize (theText.c_str ()) >= inRect.mW - kXoffsetLegend) { + theSize = theText.size (); + // display dots and at least 3 characters + if (theSize >= 9) { + theText.erase (3, 3); + } + else if (theSize >= 7) { + theText.erase (3, theSize - 6); + } else { + // keep dots only + theText.erase (3, theSize - 3); + break; + } + } + } + + int theHeight = inPainter.GetFontHeight (); + int theX = inRect.mX + kXoffsetLegend; + int theY = inRect.mY + theI*(theHeight*2)+theHeight; + inPainter.DrawText (theX, theY, theText.c_str ()); + } + return true; +} +#endif + +static float GetMaxFromRange (const PlotDataBase &inData, long inStartIndex, long inEndIndex) { + float max = 0; + float fabsMax = 0; + for (long theI = inStartIndex; theI <= inEndIndex; theI++) { + if (theI == inStartIndex) { + max = inData.GetValue (theI); + fabsMax = fabs (max); + } + else { + float data = inData.GetValue (theI); + if (fabs (data) > fabsMax) { + max = data; + fabsMax = fabs (data); + } + } + } + + return max; +} + +static void FindRange (const PlotDataBase &inData, float inMin, float inMax, long& outStartIndex, long& outEndIndex) { + outStartIndex = 0; + while (outStartIndex < inData.GetSize () && inData.GetValue (outStartIndex) <= inMin) { + outStartIndex++; + } + + if (outStartIndex == inData.GetSize ()) { + outStartIndex = inData.GetSize () - 1; + outEndIndex = outStartIndex; + assert (outStartIndex>-1); + return; + } + + // We want the value at outStartIndex smaller than or equal to inMin + if (outStartIndex > 0) { + outStartIndex--; + } + + outEndIndex = outStartIndex; + while (outEndIndex < inData.GetSize () && inData.GetValue (outEndIndex) < inMax) { + outEndIndex++; + } + + if (outEndIndex == inData.GetSize ()) { + outEndIndex--; + } + assert (outStartIndex>-1); +} + +static void DrawValue(int theTraX, int theTraY, float theX, float theY, const PlotDataBase &inXData, const AxisSetup &inXAxisSetup, Painter &inPainter) +{ + char theBuf[128]; + string FormatString; + if (inXData.IsString()) + { + const StringPlotData *theStringXData = (const StringPlotData *)(&inXData); + FormatString = "(%s, " + inXAxisSetup.mTickInfo.mFormatString + ")"; + const StringData* stdata = theStringXData->GetStringData(); + sprintf (theBuf, FormatString.c_str(), (*stdata)[(int)theX].c_str(), theY); + } + else + { + FormatString = "(" + inXAxisSetup.mTickInfo.mFormatString + ", " + inXAxisSetup.mTickInfo.mFormatString + ")"; + sprintf (theBuf, FormatString.c_str(), theX, theY); + } + inPainter.DrawRotatedText (theTraX, theTraY-10, -45, PPLOT_WEST, theBuf); +} + +bool LineDataDrawer::DrawData (const PlotDataBase &inXData, const PlotDataBase &inYData, const PlotDataSelection &inPlotDataSelection, const AxisSetup &inXAxisSetup, const PRect &inRect, Painter &inPainter) const { + if (!mXTrafo || !mYTrafo) { + return false; + } + if ((inXData.GetSize () == 0) || (inYData.GetSize () == 0)) { + return false; + } + long theXSize = inXData.GetSize (); + long theYSize = inYData.GetSize (); + if (theXSize>theYSize) { + return false; + } + inPainter.SetStyle (mStyle); + float thePrevX = 0; + float thePrevY = 0; + bool theFirst = true; + float theTraX, theTraY; + + long theStart = 0; + long theEnd = inXData.GetSize () - 1; + int theStride = 1; + if (mDrawFast) { + FindRange (inXData, inXAxisSetup.mMin, inXAxisSetup.mMax, theStart, theEnd); + + theStride = (theEnd - theStart + 1) / inPainter.GetWidth (); + if (theStride == 0) { + theStride = 1; + } + } + + for (int theI = theStart; theI <= theEnd; theI+=theStride) { + + float theY; + float theX = inXData.GetValue (theI); + theTraX = mXTrafo->Transform (theX); + if (theStride > 1) { + long theLast = theI + theStride - 1; + if (theLast>theEnd) { + theLast = theEnd; + } + theY = GetMaxFromRange (inYData, theI, theLast); + } + else { + theY = inYData.GetValue (theI); + } + theTraY = mYTrafo->Transform (theY); + + if (!theFirst && mDrawLine) { + inPainter.DrawLine (thePrevX, thePrevY, theTraX, theTraY); + } + else { + theFirst = false; + } + bool theDrawPoint = mDrawPoint; + + if (theDrawPoint && !DrawPoint (theTraX, theTraY, inRect, inPainter)) { + return false; + } + if (inPlotDataSelection.IsSelected (theI) && !DrawSelection (theTraX, theTraY, inRect, inPainter)) { + return false; + } +#ifdef _IUP_PPLOT_ + if (mShowValues) + DrawValue(theTraX, theTraY, theX, theY, inXData, inXAxisSetup, inPainter); +#endif + thePrevX = theTraX; + thePrevY = theTraY; + } + return true; +} + +DataDrawerBase* LineDataDrawer::Clone () const { + return new LineDataDrawer (*this); +} + +bool LineDataDrawer::DrawPoint (int inScreenX, int inScreenY, const PRect &inRect, Painter &inPainter) const { + inPainter.DrawLine (inScreenX-5, inScreenY+5, inScreenX+5, inScreenY-5); + inPainter.DrawLine (inScreenX-5, inScreenY-5, inScreenX+5, inScreenY+5); + return true; +} + +bool LineDataDrawer::DrawSelection (int inScreenX, int inScreenY, const PRect &inRect, Painter &inPainter) const { +// inPainter.DrawLine (inScreenX-5, inScreenY+5, inScreenX+5, inScreenY-5); +// inPainter.DrawLine (inScreenX-5, inScreenY-5, inScreenX+5, inScreenY+5); + inPainter.FillRect (inScreenX-5, inScreenY-5, 10, 10); + return true; +} + +bool DotDataDrawer::DrawPoint (int inScreenX, int inScreenY, const PRect &inRect, Painter &inPainter) const { + inPainter.DrawLine (inScreenX, inScreenY, inScreenX + 1, inScreenY); + return true; +} + +bool BarDataDrawer::DrawData (const PlotDataBase &inXData, const PlotDataBase &inYData, const PlotDataSelection &inPlotDataSelection, const AxisSetup &inXAxisSetup, const PRect &inRect, Painter &inPainter) const { + if (!mXTrafo || !mYTrafo) { + return false; + } + if (inXData.GetSize ()>inYData.GetSize ()) { + return false; + } + if (!mPlotCount) { + return false; + } + if (mDrawOnlyLastPoint) { + return DrawOnlyLastPoint (inXData, inYData, inPlotDataSelection, inXAxisSetup, inRect, inPainter); + } + + int theTraX, theTraY; + int theTraY0 = mYTrafo->Transform (0); + + int theLeft, theTop, theWidth, theHeight; + + theWidth = inRect.mW/inXData.GetSize (); + theWidth *= 0.9f; + + for (long theI=0;theITransform (theX); + theTraY = mYTrafo->Transform (theY); + + theLeft = theTraX-theWidth/2; + theTop = theTraY; + theHeight = theTraY0-theTop; + + inPainter.FillRect (theLeft, theTop, theWidth, theHeight); + +#ifdef _IUP_PPLOT_ + if (mShowValues) + DrawValue(theTraX, theTraY, theX, theY, inXData, inXAxisSetup, inPainter); +#endif + } + return true; +} + + +bool BarDataDrawer::DrawOnlyLastPoint (const PlotDataBase &inXData, const PlotDataBase &inYData, const PlotDataSelection &inPlotDataSelection, const AxisSetup &inXAxisSetup, const PRect &inRect, Painter &inPainter) const { + + PRect theRect = inRect; + theRect.mW = inRect.mW / mPlotCount; + theRect.mX = inRect.mX + mPlotIndex * theRect.mW; + + int theTraX, theTraY; + int theTraY0 = mYTrafo->Transform (0); + + int theLeft, theTop, theWidth, theHeight; + + theWidth = theRect.mW; + + // only draw last point: + long theI = inXData.GetSize () - 1; + if (theI >= 0) { + theTraX = mXTrafo->Transform (inXData.GetValue (theI)); + theTraY = mYTrafo->Transform (inYData.GetValue (theI)); + + theLeft = theRect.mX; + theTop = theTraY; + theHeight = theTraY0-theTop; + + inPainter.FillRect (theLeft, theTop, theWidth, theHeight); + } + return true; +} + + +DataDrawerBase* BarDataDrawer::Clone () const { + return new BarDataDrawer (*this); +} + +bool PPlot::DrawPlot (int inIndex, const PRect &inRect, Painter &inPainter) const { + + if (inIndex>=mPlotDataContainer.GetPlotCount ()) { + return false; + } + + const PlotDataBase *theXData = mPlotDataContainer.GetConstXData (inIndex); + const PlotDataBase *theYData = mPlotDataContainer.GetConstYData (inIndex); + if (!theXData || !theYData) { + return false; + } + const LegendData *theLegendData = mPlotDataContainer.GetConstLegendData (inIndex); + PColor theC; + if (theLegendData) { + theC = theLegendData->mColor; + } + inPainter.SetLineColor (theC.mR, theC.mG, theC.mB); + inPainter.SetFillColor (theC.mR, theC.mG, theC.mB); + + const DataDrawerBase *theD = mPlotDataContainer.GetConstDataDrawer (inIndex); + if (!theD) { + return false; + } + const PlotDataSelection *thePlotDataSelection = mPlotDataContainer.GetConstPlotDataSelection (inIndex); + if (!thePlotDataSelection) { + return false; + } + + return theD->DrawData (*theXData, *theYData, *thePlotDataSelection, mXAxisSetup, inRect, inPainter); + } + +bool PPlot::ConfigureSelf () { + long thePlotCount = mPlotDataContainer.GetPlotCount (); + if (thePlotCount == 0) { + return false; + } + if (mXAxisSetup.mLogScale) { + mXTickIterator = &mXLogTickIterator; + mXTrafo = &mXLogTrafo; + mYAxisSetup.mCrossOrigin = false; + } + else { + const PlotDataBase *theGlue = mPlotDataContainer.GetConstXData (0); + if (theGlue->IsString()) { + const StringPlotData *theStringXData = (const StringPlotData *)(theGlue); + mXTickIterator = &mXNamedTickIterator; + mXNamedTickIterator.SetStringList (*(theStringXData->GetStringData ())); + } + else { + mXTickIterator = &mXLinTickIterator; + } + mXTrafo = &mXLinTrafo; + } + if (mYAxisSetup.mLogScale) { + mYTickIterator = &mYLogTickIterator; + mYTrafo = &mYLogTrafo; + mXAxisSetup.mCrossOrigin = false; + } + else { + mYTickIterator = &mYLinTickIterator; + mYTrafo = &mYLinTrafo; + } + mXTickIterator->SetAxisSetup (&mXAxisSetup); + mYTickIterator->SetAxisSetup (&mYAxisSetup); + + // set trafo's for data drawers + for (int theI=0; theISetXTrafo (mXTrafo); + theD->SetYTrafo (mYTrafo); + theD->SetPlotCount (mPlotDataContainer.GetPlotCount ()); + theD->SetPlotIndex (theI); + } + } + + return true; +} + +bool PPlot::ValidateData () { + + /* check x data ascending + for (int theI=0; theI (mPlotDataContainer.GetConstXData (theI)); + if (theX && theX->size ()>0) { + float thePrev = (*theX)[0]; + for (RealData::const_iterator theJ=theX->begin ();theJ!=theX->end ();theJ++) { + float theNext = *theJ; + if (theNextAdjustRange (mXAxisSetup.mMin, mXAxisSetup.mMax)) { + return false; + } + } + + if (mYAxisSetup.mAutoScaleMin || mYAxisSetup.mAutoScaleMax) { + float theYMin; + float theYMax; + + mPlotDataContainer.CalculateYRange (mXAxisSetup.mMin, mXAxisSetup.mMax, + theYMin, theYMax); + + if (mYAxisSetup.mAutoScaleMin) { + mYAxisSetup.mMin = theYMin; + if (mYAxisSetup.mLogScale && (theYMin < kLogMinClipValue) ) { + mYAxisSetup.mMin = kLogMinClipValue; + } + } + if (mYAxisSetup.mAutoScaleMax) { + mYAxisSetup.mMax = theYMax; + } + + if (!mYTickIterator->AdjustRange (mYAxisSetup.mMin, mYAxisSetup.mMax)) { + return false; + } + } + + return true; +} + +bool PPlot::CheckRange (const AxisSetup &inAxisSetup) const { + if (inAxisSetup.mLogScale) { + if (inAxisSetup.mMin < kLogMinClipValue) { + return false; + } + + } + return true; +} + +bool PPlot::CalculateTickInfo (const PRect &inRect, Painter &inPainter) { + float theXRange = mXAxisSetup.mMax - mXAxisSetup.mMin; + float theYRange = mYAxisSetup.mMax - mYAxisSetup.mMin; + + if (theXRange <= 0 || theYRange < 0) { + return false; + } + + if ((mYAxisSetup.mMax != 0 && fabs (theYRange / mYAxisSetup.mMax) < kRangeVerySmall) || + theYRange == 0) { + float delta = 0.1f; + if (mYAxisSetup.mMax != 0) { + delta *= fabs(mYAxisSetup.mMax); + } + + mYAxisSetup.mMax += delta; + mYAxisSetup.mMin -= delta; + theYRange = mYAxisSetup.mMax - mYAxisSetup.mMin; + } + + if (mXAxisSetup.mTickInfo.mAutoTick) { + inPainter.SetStyle(mXAxisSetup.mTickInfo.mStyle); + int theTextWidth = inPainter.CalculateTextDrawSize ("12345"); + float theDivGuess = inRect.mW/(kMajorTickXInitialFac*theTextWidth); + if (!mXTickIterator->InitFromRanges (theXRange, inRect.mH, theDivGuess, mXAxisSetup.mTickInfo)) { + return false; + } + } + if (mYAxisSetup.mTickInfo.mAutoTick) { + float theTextHeight = inPainter.GetFontHeight (); + float theDivGuess = inRect.mH/(kMajorTickYInitialFac*theTextHeight); + if (!mYTickIterator->InitFromRanges (theYRange, inRect.mW, theDivGuess, mYAxisSetup.mTickInfo)) { + return false; + } + } + + SetTickSizes (inPainter.GetFontHeight (), mXAxisSetup.mTickInfo); + SetTickSizes (inPainter.GetFontHeight (), mYAxisSetup.mTickInfo); + + return true; +} + +void PPlot::SetTickSizes (int inFontHeight, TickInfo &ioTickInfo) { + if (ioTickInfo.mAutoTickSize) { + float theFac = kRelMinorTickSize/kRelMajorTickSize; + float theMax = Round (inFontHeight*kMaxMajorTickSizeInFontHeight); + if (ioTickInfo.mMajorTickScreenSize>theMax) { + ioTickInfo.mMajorTickScreenSize = theMax; + } + ioTickInfo.mMinorTickScreenSize = Round (ioTickInfo.mMajorTickScreenSize*theFac); + } +} + + +bool PPlot::CalculateLogTransformation (int inBegin, int inEnd, const AxisSetup& inAxisSetup, LogTrafo& outTrafo) { + + float theBase = inAxisSetup.mLogBase; + long theLogFac = 1;//inAxisSetup.mLogFactor; + float theDataRange = SafeLog (inAxisSetup.mMax, theBase, theLogFac) - SafeLog(inAxisSetup.mMin, theBase, theLogFac); + if (theDataRange < kFloatSmall) { + return false; + } + float theTargetRange = inEnd - inBegin; + float theScale = theTargetRange / theDataRange; + + if (inAxisSetup.mAscending ) { + outTrafo.mOffset = inBegin - SafeLog(inAxisSetup.mMin, theBase, theLogFac) * theScale; + } else { + outTrafo.mOffset = inEnd + SafeLog(inAxisSetup.mMin, theBase, theLogFac) * theScale; + } + outTrafo.mSlope = -theScale; + outTrafo.mBase = theBase; +// outTrafo.mFactor = inAxisSetup.mLogFactor; + + if (inAxisSetup.mAscending) { + outTrafo.mSlope *= -1; + } + return true; +} + +bool PPlot::CalculateLinTransformation (int inBegin, int inEnd, const AxisSetup& inAxisSetup, LinTrafo& outTrafo) { + float theDataRange = inAxisSetup.mMax - inAxisSetup.mMin; + if (theDataRange < kFloatSmall) { + return false; + } + float theMin = inAxisSetup.mMin; + if (inAxisSetup.mDiscrete) + { + theDataRange++; + theMin -= 0.5f; + } + + float theTargetRange = inEnd - inBegin; + float theScale = theTargetRange / theDataRange; + + if (inAxisSetup.mAscending) { + outTrafo.mOffset = inBegin - theMin * theScale; + } else { + outTrafo.mOffset = inEnd + theMin * theScale; + } + outTrafo.mSlope = -theScale; + + if (inAxisSetup.mAscending) { + outTrafo.mSlope *= -1; + } + return true; +} + +bool PPlot::CalculateXTransformation (const PRect &inRect) { + if (mXAxisSetup.mLogScale) { + return CalculateLogTransformation (inRect.mX, inRect.mX + inRect.mW, mXAxisSetup, mXLogTrafo); + } + else { + return CalculateLinTransformation (inRect.mX, inRect.mX + inRect.mW, mXAxisSetup, mXLinTrafo); + } +} + +bool PPlot::CalculateYTransformation (const PRect &inRect) { + if (mYAxisSetup.mLogScale) { + return CalculateLogTransformation (inRect.mY, inRect.mY + inRect.mH, mYAxisSetup, mYLogTrafo); + } + else { + return CalculateLinTransformation (inRect.mY, inRect.mY + inRect.mH, mYAxisSetup, mYLinTrafo); + } +} + +#ifndef _IUP_PPLOT_ +bool MakeExamplePlot (int inExample, PPlot &ioPPlot) { + switch (inExample) { + case 1: + MakeExamplePlot1 (ioPPlot); + return true; + break; + case 2: + MakeExamplePlot2 (ioPPlot); + return true; + break; + case 3: + MakeExamplePlot3 (ioPPlot); + return true; + break; + case 4: + MakeExamplePlot4 (ioPPlot); + return true; + break; + case 5: + MakeExamplePlot5 (ioPPlot); + return true; + break; + case 6: + MakeExamplePlot6 (ioPPlot); + return true; + break; + case 7: + MakeExamplePlot7 (ioPPlot); + return true; + break; + case 8: + MakeExamplePlot8 (ioPPlot); + return true; + break; + } + return false; +} + +void MakeExamplePlot1 (PPlot &ioPPlot) { + + int theI; + PlotData *theX1 = new PlotData (); + PlotData *theY1 = new PlotData (); + float theFac = (float)1.0/(100*100*100); + for (theI=-100;theI<=100;theI++) { + theX1->push_back (theI+50); + theY1->push_back (theFac*theI*theI*theI); + } + LineDataDrawer *theDataDrawer1 = new LineDataDrawer (); + theDataDrawer1->mStyle.mPenWidth = 3; + ioPPlot.mPlotDataContainer.AddXYPlot (theX1, theY1, 0, theDataDrawer1); + ioPPlot.mPlotBackground.mTitle = "Bar"; + ioPPlot.mPlotBackground.mStyle.mFontSize = 20; + ioPPlot.mMargins.mTop = 60; + ioPPlot.mXAxisSetup.mLabel = "gnu (Foo)"; + ioPPlot.mYAxisSetup.mLabel = "Space (m^3)"; + ioPPlot.mYAxisSetup.mStyle.mFontSize = 9; + ioPPlot.mYAxisSetup.mTickInfo.mStyle.mFontSize = 5; + ioPPlot.mYAxisSetup.mStyle.mPenWidth = 2; + ioPPlot.mXAxisSetup.mStyle = ioPPlot.mYAxisSetup.mStyle; + ioPPlot.mXAxisSetup.mTickInfo.mStyle = ioPPlot.mYAxisSetup.mTickInfo.mStyle; + + PlotData *theX2 = new PlotData (); + PlotData *theY2 = new PlotData (); + theFac = (float)2.0/100; + for (theI=-100;theI<=100;theI++) { + theX2->push_back (theI); + theY2->push_back (-theFac*theI); + } + ioPPlot.mPlotDataContainer.AddXYPlot (theX2, theY2); + LegendData *theLegendData2 = ioPPlot.mPlotDataContainer.GetLegendData (1); + theLegendData2->mStyle.mFontSize = 9; + + PlotData *theX3 = new PlotData (); + PlotData *theY3 = new PlotData (); + for (theI=-100;theI<=100;theI++) { + theY3->push_back (0.01*theI); + theX3->push_back (0.01*theI*theI-30); + } + ioPPlot.mPlotDataContainer.AddXYPlot (theX3, theY3); +} + +void MakeExamplePlot2 (PPlot &ioPPlot) { + + int theI; + PlotData *theX1 = new PlotData (); + PlotData *theY1 = new PlotData (); + float theFac = (float)1.0/(100*100*100); + for (theI=0;theI<=100;theI++) { + theX1->push_back (theI); + theY1->push_back (theFac*theI*theI*theI); + } + ioPPlot.mPlotDataContainer.AddXYPlot (theX1, theY1, 0); + + PlotData *theX2 = new PlotData (); + PlotData *theY2 = new PlotData (); + theFac = (float)2.0/100; + for (theI=0;theI<=100;theI++) { + theX2->push_back (theI); + theY2->push_back (-theFac*theI); + } + ioPPlot.mPlotDataContainer.AddXYPlot (theX2, theY2, 0); + + ioPPlot.mPlotBackground.mTitle = "no autoscale"; + ioPPlot.mPlotBackground.mStyle.mFontSize = 15; + ioPPlot.mPlotBackground.mTransparent = false; + ioPPlot.mPlotBackground.mPlotRegionBackColor = PColor (200,200,200); + ioPPlot.mMargins.mTop = 60; + ioPPlot.mMargins.mRight = 30; + ioPPlot.mXAxisSetup.mLabel = "Tg (X)"; + ioPPlot.mXAxisSetup.SetAutoScale (false); + ioPPlot.mXAxisSetup.mMin = 10; + ioPPlot.mXAxisSetup.mMax = 60; + ioPPlot.mYAxisSetup.SetAutoScale (false); + ioPPlot.mYAxisSetup.mMin = -0.5; + ioPPlot.mYAxisSetup.mMax = 0.5; + + ioPPlot.mXAxisSetup.mCrossOrigin = false; + ioPPlot.mYAxisSetup.mCrossOrigin = false; + ioPPlot.mXAxisSetup.mAscending = false; + ioPPlot.mYAxisSetup.mAscending = true; + + // M.T. - use a color different from background + ioPPlot.mGridInfo.mGridColor = PColor(128,255,128); // some sort of green +} + +void MakeExamplePlot3 (PPlot &ioPPlot) { + + PlotData *theX1 = new PlotData (); + PlotData *theY1 = new PlotData (); + float theFac = 1.0f/(100*100*100); + for (int theI=0;theI<=100;theI++) { + // theX1->push_back (theI*0.001); + theX1->push_back (theI); + theY1->push_back (theFac*theI*theI*theI); + } + ioPPlot.mPlotDataContainer.AddXYPlot (0, theY1, 0); + + ioPPlot.mPlotBackground.mTitle = "narrow margins"; + ioPPlot.mPlotBackground.mTransparent = false; + ioPPlot.mPlotBackground.mPlotRegionBackColor = PColor (200,200,200); + ioPPlot.mMargins.mTop = 50; + ioPPlot.mMargins.mRight = 10; + ioPPlot.mMargins.mLeft = 10; + ioPPlot.mMargins.mBottom = 10; + + // M.T. - use a color different from background + ioPPlot.mGridInfo.mGridColor = PColor(128,255,128); // some sort of green +} + +void MakeExamplePlot4 (PPlot &ioPPlot) { + + PlotData *theX1 = new PlotData (); + PlotData *theY1 = new PlotData (); + float theFac = 100.0f/(100*100*100); + for (int theI=0;theI<=100;theI++) { + theX1->push_back (0.0001+theI*0.001); + theY1->push_back (0.01+theFac*theI*theI*theI); + } + LegendData *theLegend = new LegendData (); + theLegend->mName = "foo"; + theLegend->mColor = PColor (100,100,200); + ioPPlot.mPlotDataContainer.AddXYPlot (theX1, theY1, theLegend); + ioPPlot.mXAxisSetup.mLogScale = true; + ioPPlot.mYAxisSetup.mLogScale = true; + ioPPlot.mYAxisSetup.mLogBase = 2; + ioPPlot.mMargins.mLeft = 50; + ioPPlot.mMargins.mTop = 20; + + ioPPlot.mGridInfo.mXGridOn = true; + ioPPlot.mGridInfo.mYGridOn = true; +} + +void MakeExamplePlot5 (PPlot &ioPPlot) { + + const char * kLables[12] = {"jan","feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"}; + const float kData[12] = {1,2,3,4,5,6,7,8,9,0,1,2}; + + StringPlotData *theX1 = new StringPlotData (); + PlotData *theY1 = new PlotData (); + for (int theI=0;theI<12;theI++) { + theX1->AddItem (kLables[theI]); + theY1->push_back (kData[theI]); + } + LegendData *theLegend = new LegendData (); + theLegend->mName = "bar"; + theLegend->mColor = PColor (100,100,200); + BarDataDrawer *theDataDrawer = new BarDataDrawer (); + ioPPlot.mPlotDataContainer.AddXYPlot (theX1, theY1, theLegend, theDataDrawer); + ioPPlot.mMargins.mLeft = 50; + ioPPlot.mMargins.mTop = 20; +} + +void MakeExamplePlot6 (PPlot &ioPPlot) { + + int theI; + + ioPPlot.mPlotBackground.mTitle = "line styles"; + PlotData *theX1 = new PlotData (); + PlotData *theY1 = new PlotData (); + float theFac = 100.0f/(100*100*100); + for (theI=0;theI<=10;theI++) { + theX1->push_back (0.0001+theI*0.001); + theY1->push_back (0.01+theFac*theI*theI); + } + LineDataDrawer *theDataDrawer1 = new LineDataDrawer (); + theDataDrawer1->mDrawPoint = true; + theDataDrawer1->mStyle.mPenWidth = 3; + ioPPlot.mPlotDataContainer.AddXYPlot (theX1, theY1, 0, theDataDrawer1); + + PlotData *theX2 = new PlotData (); + PlotData *theY2 = new PlotData (); + for (theI=0;theI<=10;theI++) { + theX2->push_back (0.0001+theI*0.001); + theY2->push_back (0.2-theFac*theI*theI); + } + LineDataDrawer *theDataDrawer2 = new LineDataDrawer (); + theDataDrawer2->mDrawPoint = true; + theDataDrawer2->mDrawLine = false; + ioPPlot.mPlotDataContainer.AddXYPlot (theX2, theY2, 0, theDataDrawer2); + + ioPPlot.mMargins.mLeft = 50; + ioPPlot.mMargins.mTop = 40; +} + +void MakeExamplePlot7 (PPlot &ioPPlot) { + + PlotData *theX1 = new PlotData (); + PlotData *theY1 = new PlotData (); + float theFac = 100.0f/(100*100*100); + for (int theI=0;theI<=100;theI++) { + theX1->push_back (0.0001+theI*0.001); + theY1->push_back (0.01+theFac*theI*theI*theI); + } + LegendData *theLegend = new LegendData (); + theLegend->mName = "foo"; + theLegend->mColor = PColor (100,100,200); + ioPPlot.mPlotDataContainer.AddXYPlot (theX1, theY1, theLegend); + ioPPlot.mYAxisSetup.mLogScale = true; + ioPPlot.mYAxisSetup.mLogFactor = 20; + ioPPlot.mMargins.mLeft = 50; + ioPPlot.mMargins.mTop = 20; + + ioPPlot.mGridInfo.mXGridOn = true; + ioPPlot.mGridInfo.mYGridOn = true; +} + +void MakeExamplePlot8 (PPlot &ioPPlot) { + + ioPPlot.mPlotBackground.mTitle = "data selection and editing"; + PlotData *theX1 = new PlotData (); + PlotData *theY1 = new PlotData (); + float theFac = 100.0f/(100*100*100); + for (int theI=-10;theI<=10;theI++) { + theX1->push_back (0.001*theI); + theY1->push_back (0.01+theFac*theI*theI*theI); + } + LegendData *theLegend = new LegendData (); + theLegend->mName = "foo"; + theLegend->mColor = PColor (100,100,200); + + PlotDataSelection *thePlotDataSelection = new PlotDataSelection (); + ioPPlot.mPlotDataContainer.AddXYPlot (theX1, theY1, theLegend, 0, thePlotDataSelection); + ioPPlot.mMargins.mLeft = 30; + ioPPlot.mMargins.mTop = 30; + ioPPlot.mMargins.mBottom = 30; + ioPPlot.mMargins.mRight = 30; +} + +void MakePainterTester (PPlot &ioPPlot) { + ioPPlot.SetPPlotDrawer (new PainterTester ()); +} + +static PPlot *sCurrentPPlot=0; + +void SetCurrentPPlot (PPlot *inPPlot) { + sCurrentPPlot = inPPlot; +} +#include +PPlot & GetCurrentPPlot () { + fprintf (stderr, "getplot\n"); + if (sCurrentPPlot) { + return *sCurrentPPlot; + } + assert (0); + fprintf (stderr, "aargh\n"); + + return *sCurrentPPlot;// this should not happen +} + + + +void MakeCopy (const PPlot &inPPlot, PPlot &outPPlot) { + // copy settings + outPPlot.mGridInfo = inPPlot.mGridInfo; + outPPlot.mMargins = inPPlot.mMargins; + outPPlot.mXAxisSetup = inPPlot.mXAxisSetup; + outPPlot.mYAxisSetup = inPPlot.mYAxisSetup; + outPPlot.mPlotBackground = inPPlot.mPlotBackground; + + // now the data + for (int theI=0;theIClone (); + + outPPlot.mPlotDataContainer.AddXYPlot (theNewXData, theNewYData, theNewLegendData, theNewDrawer); + + } + +} +#endif diff --git a/iup/srcpplot/iupPPlot.h b/iup/srcpplot/iupPPlot.h new file mode 100755 index 0000000..bab2f94 --- /dev/null +++ b/iup/srcpplot/iupPPlot.h @@ -0,0 +1,645 @@ +/*************************************************************************** + * * + * Copyright notice: * + * * + * This is free Pier ware. You may do whatever you want with this code. * + * You may cont(r)act me by email: pierphil@xs4all.nl * + * * + ***************************************************************************/ + +#ifndef __PPLOT_H__ +#define __PPLOT_H__ + + +#pragma warning (disable: 4786) + +#include +#include +#include +#include +#include +using namespace std; + +#ifdef __WATCOMC__ /* M.T. - 2006-09-26 - hacked to compile with OW ver. 1.5 */ +#pragma off (unreferenced); +#endif + +/* M.T. - these are text alignment values usable here */ +#ifdef _IUP_PPLOT_ +// Text alignment +enum { /* text alignment */ + PPLOT_NORTH, + PPLOT_SOUTH, + PPLOT_EAST, + PPLOT_WEST, + PPLOT_NORTH_EAST, + PPLOT_NORTH_WEST, + PPLOT_SOUTH_EAST, + PPLOT_SOUTH_WEST, + PPLOT_CENTER, + PPLOT_BASE_LEFT, + PPLOT_BASE_CENTER, + PPLOT_BASE_RIGHT +}; + +// Legend Position +enum PLegendPos {PPLOT_TOPLEFT, PPLOT_TOPRIGHT, PPLOT_BOTTOMLEFT, PPLOT_BOTTOMRIGHT}; +#endif + +typedef vector RealData; +typedef vector StringData; + +class PStyle { + public: +#ifdef _IUP_PPLOT_ + PStyle (): mFontSize(0), mFontStyle(-1), mPenWidth(1), mPenStyle(0), mMarkSize(7), mMarkStyle(3) {}; + int mFontSize; + int mFontStyle; + int mPenWidth; + int mPenStyle; + int mMarkStyle; + int mMarkSize; +#else + PStyle (): mFontSize(10), mPenWidth(1) {}; + int mFontSize; + string mFont; + int mPenWidth; + string mPenStyle; + map mVar; +#endif +}; + +class CalculatedDataBase { + public: + virtual float GetValue (long inIndex) const = 0; + virtual long GetSize () const = 0; +}; + +// data +class PlotDataBase { + public: + PlotDataBase(): mIsString(false) {}; + virtual ~PlotDataBase (); + virtual const RealData * GetRealPlotData () const = 0; + virtual const CalculatedDataBase * GetCalculatedData () const {return 0;} + bool IsString () const {return mIsString;} + long GetSize () const; + float GetValue (long inIndex) const; + virtual bool CalculateRange (float &outMin, float &outMax); +protected: + bool mIsString; +}; + +typedef vector PlotDataList; + +class PlotDataPointer: public PlotDataBase { + public: + PlotDataPointer (const PlotDataBase *inPlotData):mPlotData (inPlotData){};// does not own them + virtual const RealData * GetRealPlotData () const {return mPlotData->GetRealPlotData ();}; + virtual const CalculatedDataBase * GetCalculatedData () const {return mPlotData->GetCalculatedData ();} + private: + const PlotDataBase *mPlotData; +}; + +// default data class +class PlotData: public RealData, public PlotDataBase { + public: + virtual const RealData * GetRealPlotData () const {return this;}; +}; + +class CalculatedData: public CalculatedDataBase { + public: + CalculatedData (float inMin, float inDelta, long inSize): + mMin (inMin), mDelta (inDelta), mSize (inSize) {} + virtual float GetValue (long inIndex) const { return mMin + inIndex * mDelta; } + virtual long GetSize () const { return mSize; } + + float mMin; + float mDelta; + long mSize; +}; + +class CalculatedPlotData: public PlotDataBase { + public: + CalculatedPlotData (CalculatedDataBase* inCalculatedData): + mCalculatedData (inCalculatedData) {} + ~CalculatedPlotData () {delete mCalculatedData;} + virtual const RealData * GetRealPlotData () const {return 0;} + virtual const CalculatedDataBase * GetCalculatedData () const {return mCalculatedData;} + + CalculatedDataBase* mCalculatedData; +}; + +class DummyPlotData: public PlotDataBase { + public: + DummyPlotData (long inSize=0); + virtual const RealData * GetRealPlotData () const {return &mRealPlotData;}; + private: + RealData mRealPlotData; +}; + +class StringPlotData: public PlotDataBase { + public: + StringPlotData() {mIsString = true;} + void AddItem (const char *inString); + void InsertItem (int inIndex, const char *inString); + const StringData * GetStringData () const {return &mStringPlotData;}; + virtual const RealData * GetRealPlotData () const {return &mRealPlotData;}; +// private: + RealData mRealPlotData; + StringData mStringPlotData; +}; + + +float SafeLog (float inFloat, float inBase, float inFac=1); +float SafeExp (float inFloat, float inBase, float inFac=1); + +class PRect { + public: + PRect ():mX(0),mY(0),mW(0),mH(0){}; + long mX; + long mY; + long mW; + long mH; +}; + +class PMargins { + public: + PMargins ():mLeft (0), mRight(0), mTop (0), mBottom (0){}; + PMargins (long inLeft, long inRight, long inTop, long inBottom):mLeft (inLeft), mRight (inRight), mTop(inTop), mBottom (inBottom) {}; + long mLeft; + long mRight; + long mTop; + long mBottom; +}; + +class PColor { + public: + PColor (): mR(0), mG(0), mB(0){}; + PColor (int inR, int inG, int inB): mR((unsigned char)inR), mG((unsigned char)inG), mB((unsigned char)inB){}; // M.T. added typecast + unsigned char mR; + unsigned char mG; + unsigned char mB; +}; + +class LegendData { + public: + LegendData (): mShow (true) {}; + string mName; + PColor mColor; + bool mShow; + + void SetDefaultColor (int inPlotIndex); + void SetDefaultValues (int inPlotIndex); + static PColor GetDefaultColor (int inPlotIndex); + + PStyle mStyle; +}; + +typedef vector LegendDataList; + +class PlotDataSelection: public vector { + public: + PlotDataSelection (long inSize=0):vector(inSize){}; + bool IsSelected (long inIndex) const; + long GetSelectedCount () const; +}; + +typedef vector PlotDataSelectionList; + +class Painter { + public: + virtual void DrawLine (float inX1, float inY1, float inX2, float inY2)=0; + virtual void FillRect (int inX, int inY, int inW, int inH)=0; + virtual void InvertRect (int inX, int inY, int inW, int inH)=0; + virtual void SetClipRect (int inX, int inY, int inW, int inH)=0; + virtual long GetWidth () const=0; + virtual long GetHeight () const=0; + virtual void SetLineColor (int inR, int inG, int inB)=0; + virtual void SetFillColor (int inR, int inG, int inB)=0; + virtual long CalculateTextDrawSize (const char *inString)=0; + virtual long GetFontHeight () const =0; +#ifdef _IUP_PPLOT_ + virtual void FillArrow (int inX1, int inY1, int inX2, int inY2, int inX3, int inY3)=0; + virtual void DrawText (int inX, int inY, short align, const char *inString)=0; + virtual void DrawRotatedText (int inX, int inY, float inDegrees, + short align, const char *inString)=0; +#else + virtual void DrawText (int inX, int inY, const char *inString)=0; + virtual void DrawRotatedText (int inX, int inY, float inDegrees, const char *inString)=0; +#endif + virtual void SetStyle (const PStyle &inStyle){}; +}; + +class DummyPainter: public Painter { + public: + virtual void DrawLine (float inX1, float inY1, float inX2, float inY2){}; + virtual void FillRect (int inX, int inY, int inW, int inH){}; + virtual void InvertRect (int inX, int inY, int inW, int inH){}; + virtual void SetClipRect (int inX, int inY, int inW, int inH){}; + virtual long GetWidth () const {return 100;}; + virtual long GetHeight () const {return 100;}; + virtual void SetLineColor (int inR, int inG, int inB){}; + virtual void SetFillColor (int inR, int inG, int inB){}; + virtual long CalculateTextDrawSize (const char *inString){return 0;}; + virtual long GetFontHeight () const {return 10;}; +#ifdef _IUP_PPLOT_ + virtual void FillArrow (int inX1, int inY1, int inX2, int inY2, int inX3, int inY3){}; + virtual void DrawText (int inX, int inY, short align, const char *inString){}; + virtual void DrawRotatedText (int inX, int inY, float inDegrees, + short align, const char *inString){}; +#else + virtual void DrawText (int inX, int inY, const char *inString){}; + virtual void DrawRotatedText (int inX, int inY, float inDegrees, const char *inString){}; +#endif +}; + +class Trafo; +class AxisSetup; + +class DataDrawerBase { + public: + DataDrawerBase (): mXTrafo (0), mYTrafo (0), mDrawFast (false), mPlotCount (1), mPlotIndex (0), mHasMarks(false), mShowValues(false), mMode(0) {}; + virtual ~DataDrawerBase (){}; + void SetXTrafo (Trafo *inTrafo) {mXTrafo = inTrafo;}; + void SetYTrafo (Trafo *inTrafo) {mYTrafo = inTrafo;}; + void SetDrawFast (bool inDrawFast) {mDrawFast = inDrawFast;} + void SetPlotCount (int inPlotCount) {mPlotCount = inPlotCount;} + void SetPlotIndex (int inPlotIndex) {mPlotIndex = inPlotIndex;} + virtual bool DrawData (const PlotDataBase &inXData, const PlotDataBase &inYData, const PlotDataSelection &inPlotDataSelection, const AxisSetup &inXAxisSetup, const PRect &inRect, Painter &inPainter) const =0; + virtual DataDrawerBase* Clone () const = 0; + bool mHasMarks; + bool mShowValues; + PStyle mStyle; + const char* mMode; + protected: + Trafo *mXTrafo; + Trafo *mYTrafo; + bool mDrawFast; + int mPlotCount; + int mPlotIndex; +}; + +typedef vector DataDrawerList; + +class LineDataDrawer: public DataDrawerBase { + public: + LineDataDrawer ():mDrawLine (true), mDrawPoint (false) {mMode = "LINE"; mHasMarks = true;}; + virtual bool DrawData (const PlotDataBase &inXData, const PlotDataBase &inYData, const PlotDataSelection &inPlotDataSelection, const AxisSetup &inXAxisSetup, const PRect &inRect, Painter &inPainter) const; + + virtual DataDrawerBase* Clone () const; + virtual bool DrawPoint (int inScreenX, int inScreenY, const PRect &inRect, Painter &inPainter) const; + virtual bool DrawSelection (int inScreenX, int inScreenY, const PRect &inRect, Painter &inPainter) const; + + bool mDrawLine; + bool mDrawPoint; +}; + +class DotDataDrawer: public LineDataDrawer { + public: + DotDataDrawer () { mDrawLine = false; mDrawPoint = true;}; + virtual bool DrawPoint (int inScreenX, int inScreenY, const PRect &inRect, Painter &inPainter) const; +}; + +class BarDataDrawer: public DataDrawerBase { + public: + BarDataDrawer (bool inDrawOnlyLastPoint = false):mDrawOnlyLastPoint (inDrawOnlyLastPoint){ mMode = "BAR"; }; + virtual bool DrawData (const PlotDataBase &inXData, const PlotDataBase &inYData, const PlotDataSelection &inPlotDataSelection, const AxisSetup &inXAxisSetup, const PRect &inRect, Painter &inPainter) const; + virtual DataDrawerBase* Clone () const; + + protected: + bool mDrawOnlyLastPoint;// special mode + virtual bool DrawOnlyLastPoint (const PlotDataBase &inXData, const PlotDataBase &inYData, const PlotDataSelection &inPlotDataSelection, const AxisSetup &inXAxisSetup, const PRect &inRect, Painter &inPainter) const; +}; + + +class PlotDataContainer { + public: + PlotDataContainer (); + ~PlotDataContainer (); + + void RemoveElement (int inIndex); + void ClearData (); + + /* M.T. - changed to return the index of the added plot; returns -1 on error */ + int AddXYPlot (PlotDataBase *inXData, PlotDataBase *inYData, LegendData *inLegendData=0, DataDrawerBase *inDataDrawer=0, PlotDataSelection *inPlotDataSelection=0);//takes ownership + void SetXYPlot (int inIndex, PlotDataBase *inXData, PlotDataBase *inYData, LegendData *inLegendData=0, DataDrawerBase *inDataDrawer=0, PlotDataSelection *inPlotDataSelection=0);//takes ownership + + int GetPlotCount () const {return mYDataList.size ();}; + + PlotDataBase * GetXData (int inIndex); + PlotDataBase * GetYData (int inIndex); + LegendData * GetLegendData (int inIndex); + DataDrawerBase * GetDataDrawer (int inIndex); + PlotDataSelection * GetPlotDataSelection (int inIndex); + bool SetDataDrawer (int inIndex, DataDrawerBase* inDataDrawer); // takes ownership + + int GetPlotIndexByName (const string &inName) const;// negative value: not found + + const PlotDataBase * GetConstXData (int inIndex) const; + const PlotDataBase * GetConstYData (int inIndex) const; + const LegendData * GetConstLegendData (int inIndex) const; + const DataDrawerBase * GetConstDataDrawer (int inIndex) const; + const PlotDataSelection * GetConstPlotDataSelection (int inIndex) const; + + bool CalculateXRange (float &outXMin, float &outXMax) const; + bool CalculateYRange (float inXMin, float inXMax, float &outYMin, float &outYMax) const; + bool CalculateYRangePlot (float inXMin, float inXMax, const PlotDataBase &inXData, const PlotDataBase &inYData, float &outYMin, float &outYMax) const; + + protected: + bool CheckState () const; + PlotDataList mXDataList; + PlotDataList mYDataList; + LegendDataList mLegendDataList; + DataDrawerList mDataDrawerList; + PlotDataSelectionList mPlotDataSelectionList; +}; + +// M.T. - added custom grid color - was (200,200,200) +class GridInfo { + public: + GridInfo (const bool inXGridOn = false, const bool inYGridOn = false) : mXGridOn (inXGridOn), mYGridOn (inYGridOn), mGridColor(200,200,200) {}; + + bool mXGridOn; + bool mYGridOn; + PColor mGridColor; + PStyle mStyle; +}; + +class TickInfo { + public: + TickInfo ():mAutoTick (true), mAutoTickSize (true), mTickDivision(1), mMajorTickSpan(1), mMajorTickScreenSize (1), mMinorTickScreenSize (1), mFormatString ("%.0f"), mTicksOn (true) {}; + + + static float RoundSpan (float inSpan); + static void MakeFormatString (float inValue, string &outFormatString); + + bool mAutoTick; + bool mAutoTickSize; + bool mTicksOn; + + int mTickDivision; + float mMajorTickSpan; // in plot units + int mMajorTickScreenSize; + int mMinorTickScreenSize; + string mFormatString; + PStyle mStyle; +}; + +class AxisSetup { + + public: + AxisSetup (): mMin(0),mMax(0), mAutoScaleMin(true), mAutoScaleMax (true), mAscending (true), mLogScale(false), mCrossOrigin(true), mMaxDecades(-1), mLogFactor (1), mLogBase (10), mLabelCentered(true), mDiscrete(false) {}; + + void SetMin (float inMin) {mMin = inMin;}; + void SetMax (float inMax) {mMax = inMax;}; + void SetAutoScale (bool inBool) {mAutoScaleMin = mAutoScaleMax = inBool;}; + bool IsAutoScale () const {return mAutoScaleMin && mAutoScaleMax;}; + + float mMin; + float mMax; + bool mAutoScaleMin; + bool mAutoScaleMax; + bool mAscending; // not Ascending: Descending + bool mLogScale; + bool mCrossOrigin; + long mMaxDecades;// property for auto logscale + long mLogFactor;// to make db possible with logscale + float mLogBase; + bool mDiscrete; + + bool mLabelCentered; + PColor mColor; + string mLabel; + PStyle mStyle; + + TickInfo mTickInfo; + + private: +}; + +class Trafo { + public: + virtual ~Trafo (){}; + virtual float Transform (float inValue) const=0; + virtual float TransformBack (float inValue) const = 0; +}; + +class LinTrafo: public Trafo { + public: + LinTrafo ():mOffset (0), mSlope(0){}; + virtual float Transform (float inValue) const; + virtual float TransformBack (float inValue) const; + + float mOffset; + float mSlope; +}; + +class LogTrafo: public Trafo { + public: + LogTrafo ():mOffset (0), mSlope(0), mBase (10), mFactor (1){}; + virtual float Transform (float inValue) const; + virtual float TransformBack (float inValue) const; + + float mOffset; + float mSlope; + float mBase; + float mFactor; +}; + +class TickIterator { + public: + TickIterator ():mAxisSetup (0){}; + virtual ~TickIterator () {}; + virtual bool Init ()=0; + virtual bool GetNextTick (float &outTick, bool &outIsMajorTick, string &outFormatString)=0; + + virtual bool InitFromRanges (float inParRange, float inOrthoScreenRange, float inDivGuess, TickInfo &outTickInfo) const=0; + virtual bool AdjustRange (float &ioMin, float &ioMax) const{return true;}; + void SetAxisSetup (const AxisSetup *inAxisSetup) {mAxisSetup = inAxisSetup;}; + + protected: + const AxisSetup *mAxisSetup; +}; + +class LinTickIterator: public TickIterator { + public: + LinTickIterator ():mCurrentTick (0), mDelta (0){} + virtual bool Init (); + virtual bool GetNextTick (float &outTick, bool &outIsMajorTick, string &outFormatString); + bool InitFromRanges (float inParRange, float inOrthoScreenRange, float inDivGuess, TickInfo &outTickInfo) const; + protected: + float mCurrentTick; + long mCount; + float mDelta; + string mFormatString; +}; + +class LogTickIterator: public TickIterator { + public: + LogTickIterator ():mCurrentTick (0), mDelta (0){} + virtual bool Init (); + virtual bool GetNextTick (float &outTick, bool &outIsMajorTick, string &outFormatString); + + bool InitFromRanges (float inParRange, float inOrthoScreenRange, float inDivGuess, TickInfo &outTickInfo) const; + virtual bool AdjustRange (float &ioMin, float &ioMax) const; + float RoundUp (float inFloat) const; + float RoundDown (float inFloat) const; + + protected: + float mCurrentTick; + long mCount; + float mDelta; +}; + +class NamedTickIterator: public LinTickIterator { + public: + NamedTickIterator (){} + void SetStringList (const StringData &inStringList) {mStringList = inStringList;}; + + // virtual bool Init (); + virtual bool GetNextTick (float &outTick, bool &outIsMajorTick, string &outFormatString); + bool InitFromRanges (float inParRange, float inOrthoScreenRange, float inDivGuess, TickInfo &outTickInfo) const; + protected: + StringData mStringList; +}; + +class PlotBackground { + public: + PlotBackground ():mTransparent (true), mPlotRegionBackColor (255,255,255) {}; + bool mTransparent; + PColor mPlotRegionBackColor; + string mTitle; + PStyle mStyle; +#ifdef _IUP_PPLOT_ + PColor mTitleColor; +#endif +}; + +class PPlot; + +class PDrawer { + public: + typedef vector tList; + + virtual ~PDrawer (){}; + virtual bool Prepare (Painter &inPainter, PPlot& inPPlot) {return true;}; + virtual bool Draw (Painter &inPainter)=0; +}; + +class PCalculator {// base class to do additional calculations on a PPlot + public: + typedef vector tList; + + virtual ~PCalculator (){}; + + virtual bool ShouldCalculate () const {return true;}; + virtual bool Calculate (Painter &inPainter, PPlot& inPPlot) {return true;}; +}; + + +class PainterTester: public PDrawer { + public: + virtual bool Draw (Painter &inPainter); +}; + +class PPlot: public PDrawer { + public: + PPlot (); + virtual ~PPlot (); + + virtual bool Draw (Painter &inPainter); + + PlotDataContainer mPlotDataContainer; + AxisSetup mXAxisSetup; + AxisSetup mYAxisSetup; + GridInfo mGridInfo; + PMargins mMargins;// [pixels] + PlotBackground mPlotBackground; + bool mShowLegend; // M.T. - hide|show legend + PLegendPos mLegendPos; + + void SetPPlotDrawer (PDrawer *inPDrawer);// taker ownership. Used to bypass normal Draw function, i.e., set Draw function by composition. + void SetPPlotDrawer (PDrawer &inPDrawer);// same as above: does not take ownership + + bool mHasAnyModifyingCalculatorBeenActive; + PCalculator::tList mModifyingCalculatorList; + PCalculator::tList mPostCalculatorList; + PDrawer::tList mPreDrawerList; + PDrawer::tList mPostDrawerList; + + TickIterator *mXTickIterator; + TickIterator *mYTickIterator; + + virtual bool CalculateXTransformation (const PRect &inRect); + virtual bool CalculateYTransformation (const PRect &inRect); + virtual bool DrawGridXAxis (const PRect &inRect, Painter &inPainter) const; + virtual bool DrawGridYAxis (const PRect &inRect, Painter &inPainter) const; + virtual bool DrawXAxis (const PRect &inRect, Painter &inPainter) const; + virtual bool DrawYAxis (const PRect &inRect, Painter &inPainter) const; + virtual bool CalculateTickInfo (const PRect &inRect, Painter &inPainter); + + Trafo *mXTrafo; + Trafo *mYTrafo; + + static int Round (float inFloat); + static const float kRangeVerySmall; + + protected: + PPlot (const PPlot&); + PPlot& operator=(const PPlot&); + + static bool CalculateLogTransformation (int inBegin, int inEnd, const AxisSetup& inAxisSetup, LogTrafo& outTrafo); + static bool CalculateLinTransformation (int inBegin, int inEnd, const AxisSetup& inAxisSetup, LinTrafo& outTrafo); + + virtual bool DrawPlotBackground (const PRect &inRect, Painter &inPainter) const; +#ifdef _IUP_PPLOT_ + virtual bool DrawPlotTitle(const PRect &inRect, Painter &inPainter) const; +#endif + virtual bool DrawXTick (float inX, int inScreenY, bool inMajor, const string &inFormatString, Painter &inPainter, PRect &outRect) const; + virtual bool DrawYTick (float inY, int inScreenX, bool inMajor, const string &inFormatString, Painter &inPainter, PRect &outRect) const; + virtual bool DrawLegend (const PRect &inRect, Painter &inPainter) const; + virtual bool DrawPlot (int inIndex, const PRect &inRect, Painter &inPainter) const; + virtual bool ConfigureSelf ();// change here implementations of interfaces + virtual bool ValidateData ();// check preconditions here things like x is ascending + virtual bool CalculateAxisRanges (); + virtual bool CheckRange (const AxisSetup &inAxisSetup) const; + + void SetTickSizes (int inFontHeight, TickInfo &ioTickInfo); + + // trafo's between plot coordinates and screen coordinates. + LinTrafo mXLinTrafo; + LinTrafo mYLinTrafo; + LogTrafo mXLogTrafo; + LogTrafo mYLogTrafo; + + LinTickIterator mXLinTickIterator; + LinTickIterator mYLinTickIterator; + LogTickIterator mXLogTickIterator; + LogTickIterator mYLogTickIterator; + NamedTickIterator mXNamedTickIterator; + + PDrawer * mPPlotDrawer; + bool mOwnsPPlotDrawer; +}; + +#ifndef _IUP_PPLOT_ +bool MakeExamplePlot (int inExample, PPlot &ioPPlot); +void MakeExamplePlot1 (PPlot &ioPPlot); +void MakeExamplePlot2 (PPlot &ioPPlot); +void MakeExamplePlot3 (PPlot &ioPPlot); +void MakeExamplePlot4 (PPlot &ioPPlot); +void MakeExamplePlot5 (PPlot &ioPPlot); +void MakeExamplePlot6 (PPlot &ioPPlot); +void MakeExamplePlot7 (PPlot &ioPPlot); +void MakeExamplePlot8 (PPlot &ioPPlot); +void MakePainterTester (PPlot &ioPPlot); + +void MakeCopy (const PPlot &inPPlot, PPlot &outPPlot); + +// following functions can be used to interface with scripts +void SetCurrentPPlot (PPlot *inPPlot); +PPlot & GetCurrentPPlot (); +#endif + +#endif diff --git a/iup/srcpplot/iupPPlotInteraction.cpp b/iup/srcpplot/iupPPlotInteraction.cpp new file mode 100755 index 0000000..389dbcc --- /dev/null +++ b/iup/srcpplot/iupPPlotInteraction.cpp @@ -0,0 +1,832 @@ +/*************************************************************************** + * * + * Copyright notice: * + * * + * This is free Pier ware. You may do whatever you want with this code. * + * You may cont(r)act me by email: pierphil@xs4all.nl * + * * + ***************************************************************************/ + +#include +#include + +#include "iupPPlotInteraction.h" + +const float kHitDistance = (float)10.0;//pixels + +float pmax (float inX1, float inX2) { + if (inX1>inX2) { + return inX1; + } + return inX2; +} +float pmin (float inX1, float inX2) { + if (inX1 inY2) ? inY1 : inY2; + if (fabs (theYRange / theYMax) < PPlot::kRangeVerySmall) { + return; + } + + StoreCurrentAxisSetup (); + + if (IsZoomRegion () || IsZoomX ()) { + mPPlot.mXAxisSetup.SetAutoScale (false); + mPPlot.mXAxisSetup.mMin = pmin (inX1, inX2); + mPPlot.mXAxisSetup.mMax = pmax (inX1, inX2); + } + if (IsZoomRegion () || IsZoomY ()) { + mPPlot.mYAxisSetup.SetAutoScale (false); + mPPlot.mYAxisSetup.mMin = pmin (inY1, inY2); + mPPlot.mYAxisSetup.mMax = pmax (inY1, inY2); + } + + return; +} + +void PZoomInteraction::StoreCurrentAxisSetup () { + PAxisInfo theInfo;// store the current axis setup + + theInfo.mXAxisSetup = mPPlot.mXAxisSetup; + theInfo.mYAxisSetup = mPPlot.mYAxisSetup; + + mZoomHistory.push (theInfo); +} + +void PZoomInteraction::DoZoomIn () { + float theX1 = mPPlot.mXTrafo->TransformBack (mX1); + float theX2 = mPPlot.mXTrafo->TransformBack (mX2); + float theY1 = mPPlot.mYTrafo->TransformBack (mY1); + float theY2 = mPPlot.mYTrafo->TransformBack (mY2); + + DoZoomIn (theX1, theX2, theY1, theY2); +}; + +// arguments allow us to zoom out in X direction but change the Y-axis +void PZoomInteraction::DoZoomOut (float inY1, float inY2) { + if (mZoomHistory.size () == 0) { + return; + } + PAxisInfo theInfo = mZoomHistory.top (); + mZoomHistory.pop (); + + mPPlot.mXAxisSetup = theInfo.mXAxisSetup; + if (inY1 != -1) { + mPPlot.mYAxisSetup.mMin = pmin (inY1, inY2); + mPPlot.mYAxisSetup.mMax = pmax (inY1, inY2); + } else { + mPPlot.mYAxisSetup = theInfo.mYAxisSetup; + } +} + +PSelectionInteraction::PSelectionInteraction (PPlot &inPPlot): + PPlotInteraction (inPPlot), + mCommand (kNone), + mListener (0) +{ + inPPlot.mPostCalculatorList.push_back (this); +} + + +bool PSelectionInteraction::HandleKeyEvent (const PKeyEvent &inEvent) { + + mCommand = kNone; + if (inEvent.IsOnlyControlKeyDown () && inEvent.IsChar () && inEvent.GetChar () == 'a') { +// mCalculate = true; + mCommand = kSelectAll; + mKeyEvent = inEvent; + } + return mCommand != kNone; +}; + +void PSelectionInteraction::UpdateSelection (int inIndex, int inSampleIndex, PlotDataBase *inXData, PlotDataBase *inYData, bool inHit, PlotDataSelection *inPlotDataSelection) { + if ((*inPlotDataSelection)[inSampleIndex] != inHit) + { + if (SelectNotify(inIndex, inSampleIndex, inXData, inYData, inHit)) + (*inPlotDataSelection)[inSampleIndex] = inHit; + } +} + +void PSelectionInteraction::SelectAll (int inIndex, PlotDataBase *inXData, PlotDataBase *inYData, PlotDataSelection *inPlotDataSelection) { + for (long theI=0;theIsize ();theI++) { + UpdateSelection (inIndex, theI, inXData, inYData, true, inPlotDataSelection); + } +} + + +bool PSelectionInteraction::HandleMouseEvent (const PMouseEvent &inEvent) { + + mCommand = kNone; + if (inEvent.IsMouseDown ()) { + if (!(inEvent.IsOnlyControlKeyDown () || inEvent.IsOnlyShiftKeyDown ())) { + return false; + } +// fprintf (stderr, "selection\n"); +// mCalculate = true; + if (inEvent.IsOnlyControlKeyDown ()) { + mCommand = kPointwiseSelection; + } + else if (inEvent.IsOnlyShiftKeyDown ()) { + mCommand = kGlobalSelection; + } + mMouseEvent = inEvent; + return true; + } + return false; +} + +bool PSelectionInteraction::Calculate (Painter &inPainter, PPlot& inPPlot) { + + if (mCommand == kNone) { + return true; + } + + PlotDataContainer &theContainer = inPPlot.mPlotDataContainer; + long thePlotCount = theContainer.GetPlotCount (); + float theDist = -1; + + for (long theI=0;theIHandlePSelectionInteraction (); + } + + mCommand = kNone; + + return true; +} + +void PSelectionInteraction::HandleGlobalInteraction (int inIndex, PlotDataBase *inXData, PlotDataBase *inYData, bool inHit, long inNearestPointIndex, DataDrawerBase *inDataDrawer, PlotDataSelection *inPlotDataSelection) { + if (inPlotDataSelection->size ()>0) { + for (int theI=0;theIsize ();theI++) { + UpdateSelection (inIndex, theI, inXData, inYData, inHit, inPlotDataSelection); + } + } +} + +void PSelectionInteraction::HandlePointwiseInteraction (int inIndex, PlotDataBase *inXData, PlotDataBase *inYData, bool inHit, long inNearestPointIndex, DataDrawerBase *inDataDrawer, PlotDataSelection *inPlotDataSelection) { + if (!inHit) { + return; + } + if (inPlotDataSelection->size ()>inNearestPointIndex) { + bool theWasHit = (*inPlotDataSelection)[inNearestPointIndex] !=0; + UpdateSelection (inIndex, inNearestPointIndex, inXData, inYData, !theWasHit, inPlotDataSelection); + /* + for (int theI=0;theIsize ();theI++) { + bool theWasHit = (*inPlotDataSelection)[theI] !=0; + bool theIsHit = false; + if (theI==inNearestPointIndex) { + theIsHit = !theWasHit; + } + (*inPlotDataSelection)[theI] = theIsHit; + }*/ + } +} + +float PSelectionInteraction::CalculateDistanceToPlot (const PlotDataBase *inXData, const PlotDataBase *inYData, long &outNearestPointIndex) { + +// const RealData *theXData = inXData->GetRealPlotData (); +// const RealData *theYData = inYData->GetRealPlotData (); + outNearestPointIndex = -1; + float theDist = -1; + for (int theI=0;theIGetSize ();theI++) { +// float theX = (*theXData)[theI]; +// float theY = (*theYData)[theI]; + float theX = inXData->GetValue (theI); + float theY = inYData->GetValue (theI); + // transform to pixels + theX = mPPlot.mXTrafo->Transform (theX)-mMouseEvent.mX; + theY = mPPlot.mYTrafo->Transform (theY)-mMouseEvent.mY; + + float theTmp = theX*theX+theY*theY; + + if (theTmpmUpperBound) { + return false; + } + return true; +} + + +bool PlotDataIncrementer::Increment (const vector &inIncrementList, vector &inData, const PlotDataIncrementerBounds &inGlobalBounds, const vector &inBoundList) const { + bool theDontChange = true; + + if (!Impl_Increment (inIncrementList, inData, inGlobalBounds, inBoundList, theDontChange)) { + return false; + } + theDontChange = false; + Impl_Increment (inIncrementList, inData, inGlobalBounds, inBoundList, theDontChange); + return true; +} + +bool PlotDataIncrementer::Impl_Increment (const vector &inIncrementList, vector &inData, const PlotDataIncrementerBounds &inGlobalBounds, const vector &inBoundList, bool inDontChange) const { + + if (inBoundList.size ()>0 && inBoundList.size () != inData.size ()) { + return false; + } + if (inIncrementList.size () != inData.size ()) { + return false; + } + + for (int theI=0;theI0) { + if (!inBoundList[theI].CheckBounds (theIncrementedValue)) { + return false; + } + } + if (!inDontChange) { + *theValue = theIncrementedValue; + } + } + return true; +} + + + +PEditInteraction::PEditInteraction (PPlot &inPPlot): + PPlotInteraction (inPPlot), + mCalculate (false), + mListener (0) +{ + inPPlot.mModifyingCalculatorList.push_back (this); +} + +bool PEditInteraction::HandleKeyEvent (const PKeyEvent &inEvent) { + + mCalculate = Impl_HandleKeyEvent (inEvent); + mKeyEvent = inEvent; + return mCalculate; +}; + +bool PEditInteraction::Calculate (Painter &inPainter, PPlot& inPPlot) { + if (!mCalculate) { + return true; + } + + Impl_Calculate (inPainter, inPPlot); + + if (mListener) { + mListener->HandlePEditInteraction (); + } + mCalculate = false; + return true; +} + + + +PVerticalCursorInteraction::PVerticalCursorInteraction (PPlot &inPPlot): + PEditInteraction (inPPlot) +{ +} + +bool PVerticalCursorInteraction::Impl_HandleKeyEvent (const PKeyEvent &inEvent) { + + if (inEvent.IsArrowDown () || inEvent.IsArrowUp ()) { + return true; + } + return false; +}; + +bool PVerticalCursorInteraction::Impl_Calculate (Painter &inPainter, PPlot& inPPlot) { + + PlotDataContainer &theContainer = inPPlot.mPlotDataContainer; + long thePlotCount = theContainer.GetPlotCount (); + for (long theI=0;theI(inYData); + if (!theYData) { + return; + } + vector theIncrementList (inPlotDataSelection->GetSelectedCount ()); + vector theSelectedData (inPlotDataSelection->GetSelectedCount ()); + float theDelta = 1;// pixels + if (mKeyEvent.IsArrowDown ()) { + theDelta *= -1; + } + if (mKeyEvent.IsOnlyControlKeyDown ()) { + theDelta *= 10; + } + long theIndex = 0; + for (int theI=0;theIGetSize ();theI++) { + if (inPlotDataSelection->IsSelected (theI)) { + float *theNow = &((*theYData)[theI]); + float theNowPixels = mPPlot.mYTrafo->Transform (*theNow); + float theNow2 = mPPlot.mYTrafo->TransformBack (theNowPixels); + theNowPixels -= theDelta; + float theShiftedNow = mPPlot.mYTrafo->TransformBack (theNowPixels); + float theDeltaData = theShiftedNow-*theNow; + theIncrementList[theIndex] = theDeltaData; + theSelectedData[theIndex] = theNow; +// float theNew = theNow + theDelta; +// (*theYData)[theI] = theNew; + theIndex++; + } + } + PlotDataIncrementer theIncremter; + vector theDummyList; + theIncremter.Increment (theIncrementList, theSelectedData, mGlobalBounds, theDummyList); +} + + +PDeleteInteraction::PDeleteInteraction (PPlot &inPPlot): + PEditInteraction (inPPlot) +{ +} + +bool PDeleteInteraction::Impl_HandleKeyEvent (const PKeyEvent &inEvent) { + + if (inEvent.IsDelete ()) { + return true; + } + return false; +}; + +bool PDeleteInteraction::Impl_Calculate (Painter &inPainter, PPlot& inPPlot) { + + PlotDataContainer &theContainer = inPPlot.mPlotDataContainer; + long thePlotCount = theContainer.GetPlotCount (); + + if (!DeleteNotify(-1, 0, NULL, NULL)) + return true; + + for (long theI=0;theI vectorOfInt; + +template bool Erase (const vectorOfInt &inEraseList, T &ioVec) { + vectorOfInt theSortedList = inEraseList; + sort (theSortedList.begin (), theSortedList.end ()); + reverse (theSortedList.begin (), theSortedList.end ()); +// M.T. this is missing in OW: unique (theSortedList.begin (), theSortedList.end ());// remove duplicates + for (vectorOfInt::iterator theI=theSortedList.begin();theI!=theSortedList.end ();theI++) { + int theEraseIndex = *theI; + // vector ::iterator theX; + // theX = ioVec[theEraseIndex]; + // T *theX = &(ioVec[theEraseIndex]); + ioVec.erase (ioVec.begin ()+theEraseIndex); + } + + return true; +} + +/* + +bool Erase (const vectorOfInt &inEraseList, PlotData &ioVec) { + vectorOfInt theSortedList = inEraseList; + sort (theSortedList.begin (), theSortedList.end ()); + reverse (theSortedList.begin (), theSortedList.end ()); +// unique (theSortedList.begin (), theSortedList.end ());// remove duplicates + for (vectorOfInt::iterator theI=theSortedList.begin();theI!=theSortedList.end ();theI++) { + int theEraseIndex = *theI; + ioVec.erase (ioVec.begin ()+theEraseIndex); + } + + return true; +} + +bool Erase (const vectorOfInt &inEraseList, PlotDataSelection &ioVec) + { + vectorOfInt theSortedList = inEraseList; + sort (theSortedList.begin (), theSortedList.end ()); + reverse (theSortedList.begin (), theSortedList.end ()); +// unique (theSortedList.begin (), theSortedList.end ());// remove duplicates + for (vectorOfInt::iterator theI=theSortedList.begin();theI!=theSortedList.end ();theI++) { + int theEraseIndex = *theI; + ioVec.erase (ioVec.begin ()+theEraseIndex); + } + + return true; +} +*/ +#else +template bool Erase (const vector &inEraseList, vector &ioVec) { + vector theSortedList = inEraseList; + sort (theSortedList.begin (), theSortedList.end ()); + reverse (theSortedList.begin (), theSortedList.end ()); + unique (theSortedList.begin (), theSortedList.end ());// remove duplicates + for (vector::iterator theI=theSortedList.begin();theI!=theSortedList.end ();theI++) { + int theEraseIndex = *theI; + // vector ::iterator theX; + // theX = ioVec[theEraseIndex]; + // T *theX = &(ioVec[theEraseIndex]); + ioVec.erase (ioVec.begin ()+theEraseIndex); + } + + return true; +} +#endif + +void PDeleteInteraction::HandleDeleteKey (PlotDataBase *inXData, PlotDataBase *inYData, PlotDataSelection *inPlotDataSelection, int inIndex) { + vector theDeleteList (inPlotDataSelection->GetSelectedCount ()); + long theIndex = 0; + for (int theI=0;theIGetSize ();theI++) { + if (inPlotDataSelection->IsSelected (theI)) { + if (DeleteNotify(inIndex, theI, inXData, inYData)) + { + theDeleteList[theIndex] = theI; + theIndex++; + } + } + } + + if (inXData->IsString()) + { + StringPlotData *theXData = (StringPlotData*)(inXData); + PlotData *theYData = (PlotData*)(inYData); + Erase (theDeleteList, theXData->mRealPlotData); + Erase (theDeleteList, theXData->mStringPlotData); + Erase (theDeleteList, *theYData); + Erase (theDeleteList, *inPlotDataSelection); + } + else + { + PlotData *theXData = (PlotData*)(inXData); + PlotData *theYData = (PlotData*)(inYData); + Erase (theDeleteList, *theXData); + Erase (theDeleteList, *theYData); + Erase (theDeleteList, *inPlotDataSelection); + } +} + +PCrosshairInteraction::PCrosshairInteraction (PPlot &inPPlot): + PPlotInteraction (inPPlot), + mActive (false), + mX (0), + mListener (0) +{ + inPPlot.mPostDrawerList.push_back (this); +} + +bool PCrosshairInteraction::HandleMouseEvent (const PMouseEvent &inEvent) { + if (!mActive) { + if (inEvent.IsMouseDown ()) { + if (inEvent.IsShiftKeyDown () && inEvent.IsControlKeyDown ()) { + mActive = true; + mX = inEvent.mX; + return true; + } + } + } + else { + if (inEvent.IsMouseUp ()) { + mActive = false; + return true; + } + if (inEvent.IsMouseMove ()) { + mX = inEvent.mX; + return true; + } + } + return false; +} + +bool PCrosshairInteraction::Draw (Painter &inPainter) { + if (mActive) { + float theX1 = mX; + float theY1 = mPPlot.mMargins.mTop; + float theX2 = mX; + float theY2 = inPainter.GetHeight () - mPPlot.mMargins.mBottom; + + inPainter.SetLineColor (0, 0, 0); + inPainter.DrawLine (theX1, theY1, theX2, theY2); + + PlotDataContainer &theContainer = mPPlot.mPlotDataContainer; + long thePlotCount = theContainer.GetPlotCount (); + + for (long theI=0;theITransformBack (mX); + float theYTarget = mPPlot.mYTrafo->TransformBack (theY); + mListener->HandleCrosshair (theI, thePlotCount, theXTarget, theYTarget); + } + theX1 = mPPlot.mMargins.mLeft; + theX2 = inPainter.GetWidth ()-mPPlot.mMargins.mLeft; + theY1 = theY2 = theY; + PColor theC = theLegendData->mColor; + inPainter.SetLineColor (theC.mR, theC.mG, theC.mB); + inPainter.DrawLine (theX1, theY1, theX2, theY2); + } + } + } + return true; +} + +bool PCrosshairInteraction::GetCrossPoint (const PlotDataBase *inXData, const PlotDataBase *inYData, float &outY) { + if (inXData->GetSize ()==0 ){ + return false; + } + float theXTarget = mPPlot.mXTrafo->TransformBack (mX); + bool theFirstIsLess = inXData->GetValue (0) < theXTarget; + for (int theI=0;theIGetSize ();theI++) { + float theX = inXData->GetValue (theI); + float theY = inYData->GetValue (theI); + bool theCurrentIsLess = theX < theXTarget; + + if (theCurrentIsLess != theFirstIsLess) { + outY = mPPlot.mYTrafo->Transform (theY);// transform to pixels + return true; + } + } + return false; +} + + +bool InteractionContainer::HandleMouseEvent (const PMouseEvent &inEvent) { + for (int theI=0;theIIsEnabled () && theInteraction->HandleMouseEvent (inEvent)) { + return true; + } + } + return false; +} + +bool InteractionContainer::HandleKeyEvent (const PKeyEvent &inEvent) { + for (int theI=0;theIIsEnabled () && theInteraction->HandleKeyEvent (inEvent)) { + return true; + } + } + return false; +} + + +DefaultInteractionContainer::DefaultInteractionContainer (PPlot &inPPlot): + mZoomInteraction (inPPlot), + mSelectionInteraction (inPPlot), + mVerticalCursorInteraction (inPPlot), + mDeleteInteraction (inPPlot), + mCrosshairInteraction (inPPlot) +{ + AddInteraction (mZoomInteraction); + AddInteraction (mSelectionInteraction); + AddInteraction (mVerticalCursorInteraction); + AddInteraction (mDeleteInteraction); + AddInteraction (mCrosshairInteraction); +/* + mVerticalCursorInteraction.mGlobalBounds.mLowerBoundEnabled = true; + mVerticalCursorInteraction.mGlobalBounds.mLowerBound = 0; + mVerticalCursorInteraction.mGlobalBounds.mUpperBoundEnabled = true; + mVerticalCursorInteraction.mGlobalBounds.mUpperBound = 10;*/ +} diff --git a/iup/srcpplot/iupPPlotInteraction.h b/iup/srcpplot/iupPPlotInteraction.h new file mode 100755 index 0000000..eacf790 --- /dev/null +++ b/iup/srcpplot/iupPPlotInteraction.h @@ -0,0 +1,328 @@ +/*************************************************************************** + * * + * Copyright notice: * + * * + * This is free Pier ware. You may do whatever you want with this code. * + * You may cont(r)act me by email: pierphil@xs4all.nl * + * * + ***************************************************************************/ + +#ifndef __PPLOTINTERACTION_H__ +#define __PPLOTINTERACTION_H__ + +#include "iupPPlot.h" + +class PModifierKeys { +public: + enum { + kShift=1, + kControl=2, + kAlt=4 + }; + PModifierKeys (int inModifierKeys=0):mModifierKeys (inModifierKeys) {}; + + + bool IsShiftKeyDown () const {return mModifierKeys & kShift? true: false;}; + bool IsControlKeyDown () const {return mModifierKeys & kControl? true: false;}; + bool IsAltKeyDown () const {return mModifierKeys & kAlt? true: false;}; + bool IsOnlyShiftKeyDown () const {return mModifierKeys == kShift? true: false;}; + bool IsOnlyControlKeyDown () const {return mModifierKeys == kControl? true: false;}; + bool IsOnlyAltKeyDown () const {return mModifierKeys == kAlt? true: false;}; + + bool HasModifierKeys () const {return mModifierKeys != 0;}; + + void SetModifierKeys (int inModifierKeys) {mModifierKeys = inModifierKeys;}; +private: + int mModifierKeys;// values like kShift | kAlt +}; + +class PMouseEvent: public PModifierKeys { +public: + enum EType { + kNone, + kDown, + kUp, + kMove + }; + + PMouseEvent (int inX=0, int inY=0, EType inType=kNone, int inModifierKeys=0); + + int mX; + int mY; + + + EType mType; + + bool IsNone () const {return mType == kNone;}; + bool IsMouseDown () const {return mType == kDown;}; + bool IsMouseUp () const {return mType == kUp;}; + bool IsMouseMove () const {return mType == kMove;}; +}; + +class PKeyEvent: public PModifierKeys { +public: + + enum EKey { + kNone, + kArrowUp, + kArrowDown, + kArrowLeft, + kArrowRight, + kDelete, + kChar + }; + + PKeyEvent (EKey inKey=kNone, int inRepeatCount=0, int inModifierKeys=0, char inChar=0); + + + bool IsNone () const {return mKey == kNone;}; + bool IsArrowUp () const {return mKey == kArrowUp;}; + bool IsArrowDown () const {return mKey == kArrowDown;}; + bool IsArrowLeft () const {return mKey == kArrowLeft;}; + bool IsArrowRight () const {return mKey == kArrowRight;}; + bool IsDelete () const {return mKey == kDelete;}; + bool IsChar () const {return mKey == kChar;}; + + int GetRepeatCount () const {return mRepeatCount;}; + char GetChar () const {return mChar;}; +protected: + EKey mKey; + char mChar; + + int mRepeatCount; +}; + + +class PPlotInteraction { + public: + + typedef vectortList; + + PPlotInteraction (PPlot &inPPlot); + + virtual bool HandleMouseEvent (const PMouseEvent &inEvent)=0; + virtual bool HandleKeyEvent (const PKeyEvent &inEvent) {return false;}; + + void SetEnabled (bool inBool) {mIsEnabled = inBool;}; + bool IsEnabled () const {return mIsEnabled;}; +protected: + PPlot &mPPlot; + bool mIsEnabled; +}; + +class PAxisInfo { +public: + typedef vector tList; + AxisSetup mXAxisSetup; + AxisSetup mYAxisSetup; +}; + +class PZoomInteraction: public PPlotInteraction, public PDrawer { +public: + + enum EZoomMode { + kZoom_Region, + kZoom_X, + kZoom_Y + }; + + PZoomInteraction (PPlot &inPPlot); + + virtual bool HandleMouseEvent (const PMouseEvent &inEvent); + virtual bool HandleKeyEvent (const PKeyEvent &inEvent); + + void DoZoomIn (float inX1, float inX2, float inY1, float inY2); + void DoZoomOut (float inY1 = -1, float inY2 = -1); + bool CanZoomOut () { return !mZoomHistory.empty (); }; + int GetZoomStackSize () { return mZoomHistory.size (); }; + + stack mZoomHistory; + EZoomMode mZoomMode; + + bool IsZoomRegion () const {return mZoomMode == kZoom_Region;}; + bool IsZoomX () const {return mZoomMode == kZoom_X;}; + bool IsZoomY () const {return mZoomMode == kZoom_Y;}; +protected: + void StoreCurrentAxisSetup (); + virtual bool Draw (Painter &inPainter); + bool CheckRange (float inFloat1, float inFloat2); + + void DoZoomIn (); + + bool mDragging; + int mX1; + int mY1; + int mX2; + int mY2; + +}; + +class PlotDataIncrementerBounds { +public: + PlotDataIncrementerBounds (); + + bool CheckBounds (float inValue) const; + + bool mLowerBoundEnabled; + float mLowerBound; + bool mUpperBoundEnabled; + float mUpperBound; +}; + +class PlotDataIncrementer { +public: + + // all are none are incremented + bool Increment (const vector &inIncrementList, vector &inData, const PlotDataIncrementerBounds &inGlobalBounds, const vector &inBoundList) const; + +protected: + bool Impl_Increment (const vector &inIncrementList, vector &inData, const PlotDataIncrementerBounds &inGlobalBounds, const vector &inBoundList, bool inDontChange) const; +}; + +class PSelectionInteractionListener { +public: + virtual void HandlePSelectionInteraction ()=0; +}; + +class PSelectionInteraction: public PPlotInteraction, public PCalculator { +public: + + enum ECommand { + kNone, + kPointwiseSelection, + kGlobalSelection, + kSelectAll + }; + + PSelectionInteraction (PPlot &inPPlot); + + virtual bool HandleKeyEvent (const PKeyEvent &inEvent); + virtual bool HandleMouseEvent (const PMouseEvent &inEvent); + virtual bool Calculate (Painter &inPainter, PPlot& inPPlot); + + void SetCommand (ECommand inCommand, const PKeyEvent &inKeyEvent, const PMouseEvent &inMouseEvent); + void SetListener (PSelectionInteractionListener *inListener) {mListener = inListener;}; +protected: + PSelectionInteractionListener *mListener; + + virtual bool SelectNotify(int inIndex, int inSampleIndex, PlotDataBase *inXData, PlotDataBase *inYData, bool inSelect) {return true;} + void UpdateSelection (int inIndex, int inSampleIndex, PlotDataBase *inXData, PlotDataBase *inYData, bool inHit, PlotDataSelection *inPlotDataSelection); + void HandleGlobalInteraction (int inIndex, PlotDataBase *inXData, PlotDataBase *inYData, bool inHit, long inNearestPointIndex, DataDrawerBase *inDataDrawer, PlotDataSelection *inPlotDataSelection); + void HandlePointwiseInteraction (int inIndex, PlotDataBase *inXData, PlotDataBase *inYData, bool inHit, long inNearestPointIndex, DataDrawerBase *inDataDrawer, PlotDataSelection *inPlotDataSelection); + float CalculateDistanceToPlot (const PlotDataBase *inXData, const PlotDataBase *inYData, long &outNearestPointIndex); + void SelectAll (int inIndex, PlotDataBase *inXData, PlotDataBase *inYData, PlotDataSelection *inPlotDataSelection); +// int mX; +// int mY; + ECommand mCommand; + PMouseEvent mMouseEvent; + PKeyEvent mKeyEvent; +}; + + +class PKeySelectionInteraction: public PPlotInteraction, public PCalculator { +public: + PKeySelectionInteraction (PPlot &inPPlot); + + virtual bool Calculate (Painter &inPainter, PPlot& inPPlot); + +protected: + + bool mCalculate; +}; + +class PEditInteractionListener { +public: + virtual void HandlePEditInteraction ()=0; +}; + +class PEditInteraction: public PPlotInteraction, public PCalculator { +public: + PEditInteraction (PPlot &inPPlot); + + virtual bool HandleMouseEvent (const PMouseEvent &inEvent) {return false;}; + virtual bool HandleKeyEvent (const PKeyEvent &inEvent); + virtual bool ShouldCalculate () const {return mCalculate;}; + virtual bool Calculate (Painter &inPainter, PPlot& inPPlot); + + virtual bool Impl_HandleKeyEvent (const PKeyEvent &inEvent)=0; + virtual bool Impl_Calculate (Painter &inPainter, PPlot& inPPlot)=0; + void SetListener (PEditInteractionListener *inListener) {mListener = inListener;}; +protected: + PEditInteractionListener *mListener; + PKeyEvent mKeyEvent; +private: + bool mCalculate; +}; + +class PVerticalCursorInteraction: public PEditInteraction { +public: + + PVerticalCursorInteraction (PPlot &inPPlot); + + virtual bool Impl_HandleKeyEvent (const PKeyEvent &inEvent); + virtual bool Impl_Calculate (Painter &inPainter, PPlot& inPPlot); + + PlotDataIncrementerBounds mGlobalBounds; +protected: + void HandleVerticalCursorKey (const PlotDataSelection *inPlotDataSelection, PlotDataBase *inYData); +}; + +class PDeleteInteraction: public PEditInteraction { +public: + + PDeleteInteraction (PPlot &inPPlot); + + virtual bool Impl_HandleKeyEvent (const PKeyEvent &inEvent); + virtual bool Impl_Calculate (Painter &inPainter, PPlot& inPPlot); + +protected: + void HandleDeleteKey (PlotDataBase *inXData, PlotDataBase *inYData, PlotDataSelection *inPlotDataSelection, int inIndex); + virtual bool DeleteNotify(int inIndex, int inSampleIndex, PlotDataBase *inXData, PlotDataBase *inYData) {return true;} +}; + +class PCrosshairInteractionListener { +public: + virtual void HandleCrosshair (int inIndex, int inPlotCount, float inX, float inY)=0; +}; + +class PCrosshairInteraction: public PPlotInteraction, public PDrawer { +public: + PCrosshairInteraction (PPlot &inPPlot); + + void SetListener (PCrosshairInteractionListener *inListener) {mListener = inListener;}; +protected: + virtual bool HandleMouseEvent (const PMouseEvent &inEvent); + virtual bool Draw (Painter &inPainter); + + bool GetCrossPoint (const PlotDataBase *inXData, const PlotDataBase *inYData, float &outY); + bool mActive; + int mX; + PCrosshairInteractionListener *mListener; +}; + +class InteractionContainer { +public: + InteractionContainer (){}; + virtual ~InteractionContainer (){}; + + bool HandleMouseEvent (const PMouseEvent &inEvent); + bool HandleKeyEvent (const PKeyEvent &inEvent); + + void AddInteraction (PPlotInteraction &inInteraction){mList.push_back(&inInteraction);}; + +protected: + PPlotInteraction::tList mList; +}; + +class DefaultInteractionContainer: public InteractionContainer { +public: + DefaultInteractionContainer (PPlot &inPPlot); + + PZoomInteraction mZoomInteraction; + PSelectionInteraction mSelectionInteraction; + PVerticalCursorInteraction mVerticalCursorInteraction; + PDeleteInteraction mDeleteInteraction; + PCrosshairInteraction mCrosshairInteraction; +}; + +#endif diff --git a/iup/srcpplot/iup_pplot.cpp b/iup/srcpplot/iup_pplot.cpp new file mode 100755 index 0000000..6f5c93a --- /dev/null +++ b/iup/srcpplot/iup_pplot.cpp @@ -0,0 +1,2959 @@ +/* + * IupPPlot component + * + * Description : A component, derived from PPlot and IUP canvas + * Remark : Depend on libs IUP, CD, IUPCD + */ + + +#ifdef _MSC_VER +#pragma warning(disable: 4100) +#pragma warning(disable: 4512) +#endif + +#include +#include +#include +#include + +#include "iup.h" +#include "iupcbs.h" +#include "iup_pplot.h" +#include "iupkey.h" + +#include +#include +#include +#include +#include + +#include "iup_class.h" +#include "iup_register.h" +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_stdcontrols.h" +#include "iup_assert.h" + +#include "iupPPlot.h" +#include "iupPPlotInteraction.h" +#include "iuppplot.hpp" + + +#ifndef M_E +#define M_E 2.71828182846 +#endif + +struct _IcontrolData +{ + iupCanvas canvas; /* from IupCanvas (must reserve it) */ + PPainterIup* plt; +}; + + +static int iPPlotGetCDFontStyle(const char* value); + + +/* PPlot function pointer typedefs. */ +typedef int (*IFnC)(Ihandle*, cdCanvas*); /* postdraw_cb, predraw_cb */ +typedef int (*IFniiff)(Ihandle*, int, int, float, float); /* delete_cb */ +typedef int (*IFniiffi)(Ihandle*, int, int, float, float, int); /* select_cb */ +typedef int (*IFniiffff)(Ihandle*, int, int, float, float, float*, float*); /* edit_cb */ + + +/* callback: forward redraw request to PPlot object */ +static int iPPlotRedraw_CB(Ihandle* ih) +{ + ih->data->plt->Draw(0); /* full redraw only if nothing changed */ + return IUP_DEFAULT; +} + +/* callback: forward resize request to PPlot object */ +static int iPPlotResize_CB(Ihandle* ih) +{ + ih->data->plt->Resize(); + return IUP_DEFAULT; +} + +/* callback: forward mouse button events to PPlot object */ +static int iPPlotMouseButton_CB(Ihandle* ih, int btn, int stat, int x, int y, char* r) +{ + ih->data->plt->MouseButton(btn, stat, x, y, r); + return IUP_DEFAULT; +} + +/* callback: forward mouse button events to PPlot object */ +static int iPPlotMouseMove_CB(Ihandle* ih, int x, int y) +{ + ih->data->plt->MouseMove(x, y); + return IUP_DEFAULT; +} + +/* callback: forward keyboard events to PPlot object */ +static int iPPlotKeyPress_CB(Ihandle* ih, int c, int press) +{ + ih->data->plt->KeyPress(c, press); + return IUP_DEFAULT; +} + +/* user level call: add dataset to plot */ +void IupPPlotBegin(Ihandle* ih, int strXdata) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; + + if (ih->iclass->nativetype != IUP_TYPECANVAS || + !iupStrEqual(ih->iclass->name, "pplot")) + return; + + PlotDataBase* inXData = (PlotDataBase*)iupAttribGet(ih, "_IUP_PPLOT_XDATA"); + PlotDataBase* inYData = (PlotDataBase*)iupAttribGet(ih, "_IUP_PPLOT_YDATA"); + + if (inXData) delete inXData; + if (inYData) delete inYData; + + if (strXdata) + inXData = (PlotDataBase*)(new StringPlotData()); + else + inXData = (PlotDataBase*)(new PlotData()); + + inYData = (PlotDataBase*)new PlotData(); + + iupAttribSetStr(ih, "_IUP_PPLOT_XDATA", (char*)inXData); + iupAttribSetStr(ih, "_IUP_PPLOT_YDATA", (char*)inYData); + iupAttribSetStr(ih, "_IUP_PPLOT_STRXDATA", (char*)(strXdata? "1": "0")); +} + +void IupPPlotAdd(Ihandle* ih, float x, float y) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; + + if (ih->iclass->nativetype != IUP_TYPECANVAS || + !iupStrEqual(ih->iclass->name, "pplot")) + return; + + PlotData* inXData = (PlotData*)iupAttribGet(ih, "_IUP_PPLOT_XDATA"); + PlotData* inYData = (PlotData*)iupAttribGet(ih, "_IUP_PPLOT_YDATA"); + int strXdata = iupAttribGetInt(ih, "_IUP_PPLOT_STRXDATA"); + + if (!inYData || !inXData || strXdata) + return; + + inXData->push_back(x); + inYData->push_back(y); +} + +void IupPPlotAddStr(Ihandle* ih, const char* x, float y) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; + + if (ih->iclass->nativetype != IUP_TYPECANVAS || + !iupStrEqual(ih->iclass->name, "pplot")) + return; + + StringPlotData *inXData = (StringPlotData*)iupAttribGet(ih, "_IUP_PPLOT_XDATA"); + PlotData *inYData = (PlotData*)iupAttribGet(ih, "_IUP_PPLOT_YDATA"); + int strXdata = iupAttribGetInt(ih, "_IUP_PPLOT_STRXDATA"); + + if (!inYData || !inXData || !strXdata) + return; + + inXData->AddItem(x); + inYData->push_back(y); +} + +void IupPPlotInsertStr(Ihandle* ih, int inIndex, int inSampleIndex, const char* inX, float inY) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; + + if (ih->iclass->nativetype != IUP_TYPECANVAS || + !iupStrEqual(ih->iclass->name, "pplot")) + return; + + PlotDataBase* theXDataBase = ih->data->plt->_plot.mPlotDataContainer.GetXData(inIndex); + PlotDataBase* theYDataBase = ih->data->plt->_plot.mPlotDataContainer.GetYData(inIndex); + StringPlotData *theXData = (StringPlotData*)theXDataBase; + PlotData *theYData = (PlotData*)theYDataBase; + if (!theYData || !theXData) + return; + + theXData->InsertItem(inSampleIndex, inX); + theYData->insert(theYData->begin()+inSampleIndex, inY); +} + +void IupPPlotInsert(Ihandle* ih, int inIndex, int inSampleIndex, float inX, float inY) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; + + if (ih->iclass->nativetype != IUP_TYPECANVAS || + !iupStrEqual(ih->iclass->name, "pplot")) + return; + + PlotDataBase* theXDataBase = ih->data->plt->_plot.mPlotDataContainer.GetXData(inIndex); + PlotDataBase* theYDataBase = ih->data->plt->_plot.mPlotDataContainer.GetYData(inIndex); + PlotData* theXData = (PlotData*)theXDataBase; + PlotData* theYData = (PlotData*)theYDataBase; + if (!theYData || !theXData) + return; + + theXData->insert(theXData->begin()+inSampleIndex, inX); + theYData->insert(theYData->begin()+inSampleIndex, inY); +} + +int IupPPlotEnd(Ihandle* ih) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return -1; + + if (ih->iclass->nativetype != IUP_TYPECANVAS || + !iupStrEqual(ih->iclass->name, "pplot")) + return -1; + + PlotDataBase* inXData = (PlotDataBase*)iupAttribGet(ih, "_IUP_PPLOT_XDATA"); + PlotDataBase* inYData = (PlotDataBase*)iupAttribGet(ih, "_IUP_PPLOT_YDATA"); + if (!inYData || !inXData) + return -1; + + /* add to plot */ + ih->data->plt->_currentDataSetIndex = ih->data->plt->_plot.mPlotDataContainer.AddXYPlot(inXData, inYData); + + LegendData* legend = ih->data->plt->_plot.mPlotDataContainer.GetLegendData(ih->data->plt->_currentDataSetIndex); + legend->mStyle.mFontStyle = iPPlotGetCDFontStyle(IupGetAttribute(ih, "LEGENDFONTSTYLE")); + legend->mStyle.mFontSize = IupGetInt(ih, "LEGENDFONTSIZE"); + + iupAttribSetStr(ih, "_IUP_PPLOT_XDATA", NULL); + iupAttribSetStr(ih, "_IUP_PPLOT_YDATA", NULL); + + ih->data->plt->_redraw = 1; + return ih->data->plt->_currentDataSetIndex; +} + +void IupPPlotTransform(Ihandle* ih, float x, float y, int *ix, int *iy) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; + + if (ih->iclass->nativetype != IUP_TYPECANVAS || + !iupStrEqual(ih->iclass->name, "pplot")) + return; + + if (ix) *ix = ih->data->plt->_plot.Round(ih->data->plt->_plot.mXTrafo->Transform(x)); + if (iy) *iy = ih->data->plt->_plot.Round(ih->data->plt->_plot.mYTrafo->Transform(y)); +} + +/* user level call: plot on the given device */ +void IupPPlotPaintTo(Ihandle* ih, void* _cnv) +{ + iupASSERT(iupObjectCheck(ih)); + if (!iupObjectCheck(ih)) + return; + + if (ih->iclass->nativetype != IUP_TYPECANVAS || + !iupStrEqual(ih->iclass->name, "pplot")) + return; + + ih->data->plt->DrawTo((cdCanvas *)_cnv); +} + +/* -------------------------------------------------------------------- + class implementation + -------------------------------------------------------------------- */ + +PostPainterCallbackIup::PostPainterCallbackIup (PPlot &inPPlot, Ihandle* inHandle): + _ih(inHandle) +{ + inPPlot.mPostDrawerList.push_back (this); +} + +bool PostPainterCallbackIup::Draw(Painter &inPainter) +{ + IFnC cb = (IFnC)IupGetCallback(_ih, "POSTDRAW_CB"); + + if (cb) + { + PPainterIup* iupPainter = (PPainterIup*)(&inPainter); + cb(_ih, iupPainter->_cddbuffer); + } + + return true; +} + +PrePainterCallbackIup::PrePainterCallbackIup (PPlot &inPPlot, Ihandle* inHandle): + _ih(inHandle) +{ + inPPlot.mPreDrawerList.push_back (this); +} + +bool PrePainterCallbackIup::Draw(Painter &inPainter) +{ + IFnC cb = (IFnC)IupGetCallback(_ih, "PREDRAW_CB"); + if (cb) + { + PPainterIup* iupPainter = (PPainterIup*)(&inPainter); + cb(_ih, iupPainter->_cddbuffer); + } + + return true; +} + +bool PDeleteInteractionIup::DeleteNotify(int inIndex, int inSampleIndex, PlotDataBase* inXData, PlotDataBase* inYData) +{ + IFniiff cb = (IFniiff)IupGetCallback(_ih, "DELETE_CB"); + if (cb) + { + if (inIndex == -1) + { + Icallback cbb = IupGetCallback(_ih, "DELETEBEGIN_CB"); + if (cbb && cbb(_ih) == IUP_IGNORE) + return false; + } + else if (inIndex == -2) + { + Icallback cbb = IupGetCallback(_ih, "DELETEEND_CB"); + if (cbb) + cbb(_ih); + } + else + { + float theX = inXData->GetValue(inSampleIndex); + float theY = inYData->GetValue(inSampleIndex); + int ret = cb(_ih, inIndex, inSampleIndex, theX, theY); + if (ret == IUP_IGNORE) + return false; + } + } + + return true; +} + +bool PSelectionInteractionIup::SelectNotify(int inIndex, int inSampleIndex, PlotDataBase* inXData, PlotDataBase* inYData, bool inSelect) +{ + IFniiffi cb = (IFniiffi)IupGetCallback(_ih, "SELECT_CB"); + if (cb) + { + if (inIndex == -1) + { + Icallback cbb = IupGetCallback(_ih, "SELECTBEGIN_CB"); + if (cbb && cbb(_ih) == IUP_IGNORE) + return false; + } + else if (inIndex == -2) + { + Icallback cbb = IupGetCallback(_ih, "SELECTEND_CB"); + if (cbb) + cbb(_ih); + } + else + { + float theX = inXData->GetValue(inSampleIndex); + float theY = inYData->GetValue(inSampleIndex); + int ret = cb(_ih, inIndex, inSampleIndex, theX, theY, (int)inSelect); + if (ret == IUP_IGNORE) + return false; + } + } + + return true; +} + +bool PEditInteractionIup::Impl_HandleKeyEvent (const PKeyEvent &inEvent) +{ + if (inEvent.IsArrowDown () || inEvent.IsArrowUp () || + inEvent.IsArrowLeft () || inEvent.IsArrowRight ()) + return true; + + return false; +}; + +bool PEditInteractionIup::Impl_Calculate (Painter &inPainter, PPlot& inPPlot) +{ + PlotDataContainer &theContainer = inPPlot.mPlotDataContainer; + long thePlotCount = theContainer.GetPlotCount(); + + if (!EditNotify(-1, 0, 0, 0, NULL, NULL)) + return false; + + for (long theI=0;theIGetSize ();theI++) + { + if (inPlotDataSelection->IsSelected (theI)) + { + float theX = inXData->GetValue(theI); + float newX = theX; + + if (theXDelta) + { + float theXPixels = mPPlot.mXTrafo->Transform(theX); + theXPixels += theXDelta; + newX = mPPlot.mXTrafo->TransformBack(theXPixels); + } + + float theY = inYData->GetValue(theI); + float newY = theY; + if (theYDelta) + { + float theYPixels = mPPlot.mYTrafo->Transform(theY); + theYPixels -= theYDelta; // in pixels Y is descending + newY = mPPlot.mYTrafo->TransformBack(theYPixels); + } + + if (!EditNotify(inIndex, theI, theX, theY, &newX, &newY)) + return; + + if (inXData->IsString()) + { + StringPlotData *theXData = (StringPlotData*)(inXData); + PlotData* theYData = (PlotData*)(inYData); + theXData->mRealPlotData[theI] = newX; + (*theYData)[theI] = newY; + } + else + { + PlotData* theXData = (PlotData*)(inXData); + PlotData* theYData = (PlotData*)(inYData); + (*theXData)[theI] = newX; + (*theYData)[theI] = newY; + } + } + } +} + +bool PEditInteractionIup::EditNotify(int inIndex, int inSampleIndex, float inX, float inY, float *inNewX, float *inNewY) +{ + IFniiffff cb = (IFniiffff)IupGetCallback(_ih, "EDIT_CB"); + if (cb) + { + if (inIndex == -1) + { + Icallback cbb = IupGetCallback(_ih, "EDITBEGIN_CB"); + if (cbb && cbb(_ih) == IUP_IGNORE) + return false; + } + else if (inIndex == -2) + { + Icallback cbb = IupGetCallback(_ih, "EDITEND_CB"); + if (cbb) + cbb(_ih); + } + else + { + int ret = cb(_ih, inIndex, inSampleIndex, inX, inY, inNewX, inNewY); + if (ret == IUP_IGNORE) + return false; + } + } + + return true; +} + +InteractionContainerIup::InteractionContainerIup(PPlot &inPPlot, Ihandle* inHandle): + mZoomInteraction (inPPlot), + mSelectionInteraction (inPPlot, inHandle), + mEditInteraction (inPPlot, inHandle), + mDeleteInteraction (inPPlot, inHandle), + mCrosshairInteraction (inPPlot), + mPostPainterCallback(inPPlot, inHandle), + mPrePainterCallback(inPPlot, inHandle) +{ + AddInteraction (mZoomInteraction); + AddInteraction (mSelectionInteraction); + AddInteraction (mEditInteraction); + AddInteraction (mDeleteInteraction); + AddInteraction (mCrosshairInteraction); +} + +PPainterIup::PPainterIup(Ihandle *ih) : + Painter(), + _ih(ih), + _cdcanvas(NULL), + _cddbuffer(NULL), + _mouseDown(0), + _currentDataSetIndex(-1), + _redraw(1) +{ + _plot.mShowLegend = false; // change default to hidden + _plot.mPlotBackground.mTransparent = false; // always draw the background + _plot.mMargins.mLeft = 15; + _plot.mMargins.mBottom = 15; + _plot.mMargins.mTop = 30; + _plot.mMargins.mRight = 15; + _plot.mXAxisSetup.mTickInfo.mTickDivision = 5; + _plot.mYAxisSetup.mTickInfo.mTickDivision = 5; + _plot.mXAxisSetup.mTickInfo.mMinorTickScreenSize = 5; + _plot.mYAxisSetup.mTickInfo.mMinorTickScreenSize = 5; + _plot.mXAxisSetup.mTickInfo.mMajorTickScreenSize = 8; + _plot.mYAxisSetup.mTickInfo.mMajorTickScreenSize = 8; + + _InteractionContainer = new InteractionContainerIup(_plot, _ih); + +} /* c-tor */ + + +PPainterIup::~PPainterIup() +{ + if (_cddbuffer != NULL) + cdKillCanvas(_cddbuffer); + + delete _InteractionContainer; +} /* d-tor */ + +class MarkDataDrawer: public LineDataDrawer +{ + public: + MarkDataDrawer (bool inDrawLine) + { + mDrawLine = inDrawLine; + mDrawPoint = true; + mMode = inDrawLine ? "MARKLINE" : "MARK"; + }; + virtual bool DrawPoint (int inScreenX, int inScreenY, const PRect &inRect, Painter &inPainter) const; +}; + +bool MarkDataDrawer::DrawPoint (int inScreenX, int inScreenY, const PRect &inRect, Painter &inPainter) const +{ + PPainterIup* painter = (PPainterIup*)&inPainter; + cdCanvasMark(painter->_cddbuffer, inScreenX, cdCanvasInvertYAxis(painter->_cddbuffer, inScreenY)); + + return true; +} + +static void RemoveSample(PPlot& inPPlot, int inIndex, int inSampleIndex) +{ + PlotDataBase* theXDataBase = inPPlot.mPlotDataContainer.GetXData(inIndex); + PlotDataBase* theYDataBase = inPPlot.mPlotDataContainer.GetYData(inIndex); + + if (theXDataBase->IsString()) + { + StringPlotData *theXData = (StringPlotData *)theXDataBase; + PlotData* theYData = (PlotData*)theYDataBase; + theXData->mRealPlotData.erase(theXData->mRealPlotData.begin()+inSampleIndex); + theXData->mStringPlotData.erase(theXData->mStringPlotData.begin()+inSampleIndex); + theYData->erase(theYData->begin()+inSampleIndex); + } + else + { + PlotData* theXData = (PlotData*)theXDataBase; + PlotData* theYData = (PlotData*)theYDataBase; + theXData->erase(theXData->begin()+inSampleIndex); + theYData->erase(theYData->begin()+inSampleIndex); + } +} + +/* -------------------------------------------------------------------- + CD Gets - size and style + -------------------------------------------------------------------- */ + +static int iPPlotGetCDFontStyle(const char* value) +{ + if (!value) + return -1; + if (iupStrEqualNoCase(value, "PLAIN")) + return CD_PLAIN; + if (iupStrEqualNoCase(value, "BOLD")) + return CD_BOLD; + if (iupStrEqualNoCase(value, "ITALIC")) + return CD_ITALIC; + if (iupStrEqualNoCase(value, "BOLDITALIC")) + return CD_BOLD_ITALIC; + return -1; +} + +static char* iPPlotGetPlotFontSize(int size) +{ + if (size) + { + char* buffer = iupStrGetMemory(50); + sprintf(buffer, "%d", size); + return buffer; + } + else + return NULL; +} + +static char* iPPlotGetPlotFontStyle(int style) +{ + if (style >= CD_PLAIN && style <= CD_BOLD_ITALIC) + { + char* style_str[4] = {"PLAIN", "BOLD", "ITALIC", "BOLDITALIC"}; + return style_str[style]; + } + else + return NULL; +} + +static char* iPPlotGetPlotPenStyle(int style) +{ + if (style >= CD_CONTINUOUS && style <= CD_DASH_DOT_DOT) + { + char* style_str[5] = {"CONTINUOUS", "DASHED", "DOTTED", "DASH_DOT", "DASH_DOT_DOT"}; + return style_str[style]; + } + else + return NULL; +} + +static int iPPlotGetCDPenStyle(const char* value) +{ + if (!value || iupStrEqualNoCase(value, "CONTINUOUS")) + return CD_CONTINUOUS; + else if (iupStrEqualNoCase(value, "DASHED")) + return CD_DASHED; + else if (iupStrEqualNoCase(value, "DOTTED")) + return CD_DOTTED; + else if (iupStrEqualNoCase(value, "DASH_DOT")) + return CD_DASH_DOT; + else if (iupStrEqualNoCase(value, "DASH_DOT_DOT")) + return CD_DASH_DOT_DOT; + else + return CD_CONTINUOUS; +} + +static char* iPPlotGetPlotMarkStyle(int style) +{ + if (style >= CD_PLUS && style <= CD_HOLLOW_DIAMOND) + { + char* style_str[9] = {"PLUS", "STAR", "CIRCLE", "X", "BOX", "DIAMOND", "HOLLOW_CIRCLE", "HOLLOW_BOX", "HOLLOW_DIAMOND"}; + return style_str[style]; + } + else + return NULL; +} + +static int iPPlotGetCDMarkStyle(const char* value) +{ + if (!value || iupStrEqualNoCase(value, "PLUS")) + return CD_PLUS; + else if (iupStrEqualNoCase(value, "STAR")) + return CD_STAR; + else if (iupStrEqualNoCase(value, "CIRCLE")) + return CD_CIRCLE; + else if (iupStrEqualNoCase(value, "X")) + return CD_X; + else if (iupStrEqualNoCase(value, "BOX")) + return CD_BOX; + else if (iupStrEqualNoCase(value, "DIAMOND")) + return CD_DIAMOND; + else if (iupStrEqualNoCase(value, "HOLLOW_CIRCLE")) + return CD_HOLLOW_CIRCLE; + else if (iupStrEqualNoCase(value, "HOLLOW_BOX")) + return CD_HOLLOW_BOX; + else if (iupStrEqualNoCase(value, "HOLLOW_DIAMOND")) + return CD_HOLLOW_DIAMOND; + else + return CD_PLUS; +} + +/*****************************************************************************/ +/***** SET AND GET ATTRIBUTES ************************************************/ +/*****************************************************************************/ + +/* refresh plot window (write only) */ +static int iPPlotSetRedrawAttrib(Ihandle* ih, const char* value) +{ + (void)value; /* not used */ + ih->data->plt->Draw(1); /* force a full redraw here */ + return 0; +} + +/* total number of datasets (read only) */ +static char* iPPlotGetCountAttrib(Ihandle* ih) +{ + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%d", ih->data->plt->_plot.mPlotDataContainer.GetPlotCount()); + return att_buffer; +} + +/* legend box visibility */ +static int iPPlotSetLegendShowAttrib(Ihandle* ih, const char* value) +{ + if (iupStrEqualNoCase(value, "YES") || iupStrEqualNoCase(value, "ON")) + ih->data->plt->_plot.mShowLegend = true; + else + ih->data->plt->_plot.mShowLegend = false; + + ih->data->plt->_redraw = 1; + return 0; +} + +static char* iPPlotGetLegendShowAttrib(Ihandle* ih) +{ + if (ih->data->plt->_plot.mShowLegend) + return "YES"; + else + return "NO"; +} + +/* legend box visibility */ +static int iPPlotSetLegendPosAttrib(Ihandle* ih, const char* value) +{ + if (iupStrEqualNoCase(value, "TOPLEFT")) + ih->data->plt->_plot.mLegendPos = PPLOT_TOPLEFT; + if (iupStrEqualNoCase(value, "BOTTOMLEFT")) + ih->data->plt->_plot.mLegendPos = PPLOT_BOTTOMLEFT; + if (iupStrEqualNoCase(value, "BOTTOMRIGHT")) + ih->data->plt->_plot.mLegendPos = PPLOT_BOTTOMRIGHT; + else + ih->data->plt->_plot.mLegendPos = PPLOT_TOPRIGHT; + + ih->data->plt->_redraw = 1; + return 0; +} + +static char* iPPlotGetLegendPosAttrib(Ihandle* ih) +{ + char* legendpos_str[4] = {"TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT"}; + + return legendpos_str[ih->data->plt->_plot.mLegendPos]; +} + +/* background color */ +static int iPPlotSetBGColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char rr, gg, bb; + if (iupStrToRGB(value, &rr, &gg, &bb)) + { + ih->data->plt->_plot.mPlotBackground.mPlotRegionBackColor = PColor(rr, gg, bb); + ih->data->plt->_redraw = 1; + } + return 0; +} + +static char* iPPlotGetBGColorAttrib(Ihandle* ih) +{ + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%d %d %d", + ih->data->plt->_plot.mPlotBackground.mPlotRegionBackColor.mR, + ih->data->plt->_plot.mPlotBackground.mPlotRegionBackColor.mG, + ih->data->plt->_plot.mPlotBackground.mPlotRegionBackColor.mB); + return att_buffer; +} + + +/* title color */ +static int iPPlotSetFGColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char rr, gg, bb; + if (iupStrToRGB(value, &rr, &gg, &bb)) + { + ih->data->plt->_plot.mPlotBackground.mTitleColor = PColor(rr, gg, bb); + ih->data->plt->_redraw = 1; + } + return 0; +} + +static char* iPPlotGetFGColorAttrib(Ihandle* ih) +{ + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%d %d %d", + ih->data->plt->_plot.mPlotBackground.mTitleColor.mR, + ih->data->plt->_plot.mPlotBackground.mTitleColor.mG, + ih->data->plt->_plot.mPlotBackground.mTitleColor.mB); + return att_buffer; +} + + +/* plot title */ +static int iPPlotSetTitleAttrib(Ihandle* ih, const char* value) +{ + if (value && value[0] != 0) + ih->data->plt->_plot.mPlotBackground.mTitle = value; + else + ih->data->plt->_plot.mPlotBackground.mTitle.resize(0); + + ih->data->plt->_redraw = 1; + return 0; +} + +static char* iPPlotGetTitleAttrib(Ihandle* ih) +{ + char* att_buffer = iupStrGetMemory(256); + strncpy(att_buffer, ih->data->plt->_plot.mPlotBackground.mTitle.c_str(), 256); + att_buffer[255]='\0'; + return att_buffer; +} + + +/* plot title font size */ +static int iPPlotSetTitleFontSizeAttrib(Ihandle* ih, const char* value) +{ + int ii; + if (iupStrToInt(value, &ii)) + { + ih->data->plt->_plot.mPlotBackground.mStyle.mFontSize = ii; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static char* iPPlotGetTitleFontSizeAttrib(Ihandle* ih) +{ + return iPPlotGetPlotFontSize(ih->data->plt->_plot.mPlotBackground.mStyle.mFontSize); +} + + +/* plot title font style */ +static int iPPlotSetTitleFontStyleAttrib(Ihandle* ih, const char* value) +{ + int style = iPPlotGetCDFontStyle(value); + if (style != -1) + { + ih->data->plt->_plot.mPlotBackground.mStyle.mFontStyle = style; + ih->data->plt->_redraw = 1; + } + return 0; +} + +/* legend font size */ +static int iPPlotSetLegendFontSizeAttrib(Ihandle* ih, const char* value) +{ + int ii, xx; + if (!iupStrToInt(value, &xx)) + return 0; + + for (ii = 0; ii < ih->data->plt->_plot.mPlotDataContainer.GetPlotCount(); ii++) + { + LegendData* legend = ih->data->plt->_plot.mPlotDataContainer.GetLegendData(ii); + legend->mStyle.mFontSize = xx; + } + + ih->data->plt->_redraw = 1; + return 1; +} + +/* legend font style */ +static int iPPlotSetLegendFontStyleAttrib(Ihandle* ih, const char* value) +{ + int ii; + int style = iPPlotGetCDFontStyle(value); + if (style == -1) + return 0; + + for (ii = 0; ii < ih->data->plt->_plot.mPlotDataContainer.GetPlotCount(); ii++) + { + LegendData* legend = ih->data->plt->_plot.mPlotDataContainer.GetLegendData(ii); + legend->mStyle.mFontStyle = style; + } + + ih->data->plt->_redraw = 1; + return 1; +} + +/* plot margins */ +static int iPPlotSetMarginLeftAttrib(Ihandle* ih, const char* value) +{ + int ii; + if (iupStrToInt(value, &ii)) + { + ih->data->plt->_plot.mMargins.mLeft = ii; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static int iPPlotSetMarginRightAttrib(Ihandle* ih, const char* value) +{ + int ii; + if (iupStrToInt(value, &ii)) + { + ih->data->plt->_plot.mMargins.mRight = ii; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static int iPPlotSetMarginTopAttrib(Ihandle* ih, const char* value) +{ + int ii; + if (iupStrToInt(value, &ii)) + { + ih->data->plt->_plot.mMargins.mTop = ii; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static int iPPlotSetMarginBottomAttrib(Ihandle* ih, const char* value) +{ + int ii; + if (iupStrToInt(value, &ii)) + { + ih->data->plt->_plot.mMargins.mBottom = ii; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static char* iPPlotGetMarginLeftAttrib(Ihandle* ih) +{ + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%d", ih->data->plt->_plot.mMargins.mLeft); + return att_buffer; +} + +static char* iPPlotGetMarginRightAttrib(Ihandle* ih) +{ + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%d", ih->data->plt->_plot.mMargins.mRight); + return att_buffer; +} + +static char* iPPlotGetMarginTopAttrib(Ihandle* ih) +{ + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%d", ih->data->plt->_plot.mMargins.mTop); + return att_buffer; +} + +static char* iPPlotGetMarginBottomAttrib(Ihandle* ih) +{ + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%d", ih->data->plt->_plot.mMargins.mBottom); + return att_buffer; +} + +/* plot grid color */ +static int iPPlotSetGridColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char rr, gg, bb; + if (iupStrToRGB(value, &rr, &gg, &bb)) + { + ih->data->plt->_plot.mGridInfo.mGridColor = PColor(rr, gg, bb); + ih->data->plt->_redraw = 1; + } + return 0; +} + +static char* iPPlotGetGridColorAttrib(Ihandle* ih) +{ + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%d %d %d", + ih->data->plt->_plot.mGridInfo.mGridColor.mR, + ih->data->plt->_plot.mGridInfo.mGridColor.mG, + ih->data->plt->_plot.mGridInfo.mGridColor.mB); + return att_buffer; +} + +/* plot grid line style */ +static int iPPlotSetGridLineStyleAttrib(Ihandle* ih, const char* value) +{ + ih->data->plt->_plot.mGridInfo.mStyle.mPenStyle = iPPlotGetCDPenStyle(value); + ih->data->plt->_redraw = 1; + return 0; +} + +static char* iPPlotGetGridLineStyleAttrib(Ihandle* ih) +{ + return iPPlotGetPlotPenStyle(ih->data->plt->_plot.mGridInfo.mStyle.mPenStyle); +} + +/* grid */ +static int iPPlotSetGridAttrib(Ihandle* ih, const char* value) +{ + if (iupStrEqualNoCase(value, "VERTICAL")) /* vertical grid - X axis */ + { + ih->data->plt->_plot.mGridInfo.mXGridOn = true; + ih->data->plt->_plot.mGridInfo.mYGridOn = false; + } + else if (iupStrEqualNoCase(value, "HORIZONTAL")) /* horizontal grid - Y axis */ + { + ih->data->plt->_plot.mGridInfo.mYGridOn = true; + ih->data->plt->_plot.mGridInfo.mXGridOn = false; + } + else if (iupStrEqualNoCase(value, "YES")) + { + ih->data->plt->_plot.mGridInfo.mXGridOn = true; + ih->data->plt->_plot.mGridInfo.mYGridOn = true; + } + else + { + ih->data->plt->_plot.mGridInfo.mYGridOn = false; + ih->data->plt->_plot.mGridInfo.mXGridOn = false; + } + + ih->data->plt->_redraw = 1; + return 0; +} + +static char* iPPlotGetGridAttrib(Ihandle* ih) +{ + if (ih->data->plt->_plot.mGridInfo.mXGridOn && ih->data->plt->_plot.mGridInfo.mYGridOn) + return "YES"; + else if (ih->data->plt->_plot.mGridInfo.mYGridOn) + return "HORIZONTAL"; + else if (ih->data->plt->_plot.mGridInfo.mXGridOn) + return "VERTICAL"; + else + return "NO"; +} + +/* current dataset index */ +static int iPPlotSetCurrentAttrib(Ihandle* ih, const char* value) +{ + int ii; + if (iupStrToInt(value, &ii)) + { + int imax = ih->data->plt->_plot.mPlotDataContainer.GetPlotCount(); + ih->data->plt->_currentDataSetIndex = ( (ii>=0) && (iidata->plt->_redraw = 1; + } + return 0; +} + +static char* iPPlotGetCurrentAttrib(Ihandle* ih) +{ + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%d", ih->data->plt->_currentDataSetIndex); + return att_buffer; +} + +/* remove a dataset */ +static int iPPlotSetRemoveAttrib(Ihandle* ih, const char* value) +{ + int ii; + if (iupStrToInt(value, &ii)) + { + ih->data->plt->_plot.mPlotDataContainer.RemoveElement(ii); + ih->data->plt->_redraw = 1; + } + return 0; +} + +/* clear all datasets */ +static int iPPlotSetClearAttrib(Ihandle* ih, const char* value) +{ + ih->data->plt->_plot.mPlotDataContainer.ClearData(); + ih->data->plt->_redraw = 1; + return 0; +} + +/* =============================== */ +/* current plot dataset attributes */ +/* =============================== */ + +/* current plot line style */ +static int iPPlotSetDSLineStyleAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->plt->_currentDataSetIndex < 0 || + ih->data->plt->_currentDataSetIndex >= ih->data->plt->_plot.mPlotDataContainer.GetPlotCount()) + return 0; + + DataDrawerBase* drawer = ih->data->plt->_plot.mPlotDataContainer.GetDataDrawer(ih->data->plt->_currentDataSetIndex); + drawer->mStyle.mPenStyle = iPPlotGetCDPenStyle(value); + + ih->data->plt->_redraw = 1; + return 0; +} + +static char* iPPlotGetDSLineStyleAttrib(Ihandle* ih) +{ + if (ih->data->plt->_currentDataSetIndex < 0 || + ih->data->plt->_currentDataSetIndex >= ih->data->plt->_plot.mPlotDataContainer.GetPlotCount()) + return NULL; + + DataDrawerBase* drawer = ih->data->plt->_plot.mPlotDataContainer.GetDataDrawer(ih->data->plt->_currentDataSetIndex); + + return iPPlotGetPlotPenStyle(drawer->mStyle.mPenStyle); +} + +/* current plot line width */ +static int iPPlotSetDSLineWidthAttrib(Ihandle* ih, const char* value) +{ + int ii; + + if (ih->data->plt->_currentDataSetIndex < 0 || + ih->data->plt->_currentDataSetIndex >= ih->data->plt->_plot.mPlotDataContainer.GetPlotCount()) + return 0; + + if (iupStrToInt(value, &ii)) + { + DataDrawerBase* drawer = ih->data->plt->_plot.mPlotDataContainer.GetDataDrawer(ih->data->plt->_currentDataSetIndex); + drawer->mStyle.mPenWidth = ii; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static char* iPPlotGetDSLineWidthAttrib(Ihandle* ih) +{ + if (ih->data->plt->_currentDataSetIndex < 0 || + ih->data->plt->_currentDataSetIndex >= ih->data->plt->_plot.mPlotDataContainer.GetPlotCount()) + return NULL; + + DataDrawerBase* drawer = ih->data->plt->_plot.mPlotDataContainer.GetDataDrawer(ih->data->plt->_currentDataSetIndex); + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%d", drawer->mStyle.mPenWidth); + return att_buffer; +} + +/* current plot mark style */ +static int iPPlotSetDSMarkStyleAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->plt->_currentDataSetIndex < 0 || + ih->data->plt->_currentDataSetIndex >= ih->data->plt->_plot.mPlotDataContainer.GetPlotCount()) + return 0; + + DataDrawerBase* drawer = ih->data->plt->_plot.mPlotDataContainer.GetDataDrawer(ih->data->plt->_currentDataSetIndex); + drawer->mStyle.mMarkStyle = iPPlotGetCDMarkStyle(value); + ih->data->plt->_redraw = 1; + return 0; +} + +static char* iPPlotGetDSMarkStyleAttrib(Ihandle* ih) +{ + if (ih->data->plt->_currentDataSetIndex < 0 || + ih->data->plt->_currentDataSetIndex >= ih->data->plt->_plot.mPlotDataContainer.GetPlotCount()) + return NULL; + + DataDrawerBase* drawer = ih->data->plt->_plot.mPlotDataContainer.GetDataDrawer(ih->data->plt->_currentDataSetIndex); + + return iPPlotGetPlotMarkStyle(drawer->mStyle.mMarkStyle); +} + +/* current plot mark size */ +static int iPPlotSetDSMarkSizeAttrib(Ihandle* ih, const char* value) +{ + int ii; + + if (ih->data->plt->_currentDataSetIndex < 0 || + ih->data->plt->_currentDataSetIndex >= ih->data->plt->_plot.mPlotDataContainer.GetPlotCount()) + return 0; + + if (iupStrToInt(value, &ii)) + { + DataDrawerBase* drawer = ih->data->plt->_plot.mPlotDataContainer.GetDataDrawer(ih->data->plt->_currentDataSetIndex); + drawer->mStyle.mMarkSize = ii; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static char* iPPlotGetDSMarkSizeAttrib(Ihandle* ih) +{ + if (ih->data->plt->_currentDataSetIndex < 0 || + ih->data->plt->_currentDataSetIndex >= ih->data->plt->_plot.mPlotDataContainer.GetPlotCount()) + return NULL; + + DataDrawerBase* drawer = ih->data->plt->_plot.mPlotDataContainer.GetDataDrawer(ih->data->plt->_currentDataSetIndex); + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%d", drawer->mStyle.mMarkSize); + return att_buffer; +} + +/* current dataset legend */ +static int iPPlotSetDSLegendAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->plt->_currentDataSetIndex < 0 || + ih->data->plt->_currentDataSetIndex >= ih->data->plt->_plot.mPlotDataContainer.GetPlotCount()) + return 0; + + LegendData* legend = ih->data->plt->_plot.mPlotDataContainer.GetLegendData(ih->data->plt->_currentDataSetIndex); + + if (value) + legend->mName = value; + else + legend->mName.resize(0); + + ih->data->plt->_redraw = 1; + return 0; +} + +static char* iPPlotGetDSLegendAttrib(Ihandle* ih) +{ + if (ih->data->plt->_currentDataSetIndex < 0 || + ih->data->plt->_currentDataSetIndex >= ih->data->plt->_plot.mPlotDataContainer.GetPlotCount()) + return NULL; + + LegendData* legend = ih->data->plt->_plot.mPlotDataContainer.GetLegendData(ih->data->plt->_currentDataSetIndex); + char* att_buffer = iupStrGetMemory(256); + strncpy(att_buffer, legend->mName.c_str(), 255); + att_buffer[255]='\0'; + return att_buffer; +} + +/* current dataset line and legend color */ +static int iPPlotSetDSColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char rr, gg, bb; + + if (ih->data->plt->_currentDataSetIndex < 0 || + ih->data->plt->_currentDataSetIndex >= ih->data->plt->_plot.mPlotDataContainer.GetPlotCount()) + return 0; + + if (iupStrToRGB(value, &rr, &gg, &bb)) + { + LegendData* legend = ih->data->plt->_plot.mPlotDataContainer.GetLegendData(ih->data->plt->_currentDataSetIndex); + legend->mColor = PColor(rr, gg, bb); + ih->data->plt->_redraw = 1; + } + return 0; +} + +static char* iPPlotGetDSColorAttrib(Ihandle* ih) +{ + if (ih->data->plt->_currentDataSetIndex < 0 || + ih->data->plt->_currentDataSetIndex >= ih->data->plt->_plot.mPlotDataContainer.GetPlotCount()) + return NULL; + + LegendData* legend = ih->data->plt->_plot.mPlotDataContainer.GetLegendData(ih->data->plt->_currentDataSetIndex); + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%d %d %d", legend->mColor.mR, legend->mColor.mG, legend->mColor.mB); + return att_buffer; +} + +/* show values */ +static int iPPlotSetDSShowValuesAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->plt->_currentDataSetIndex < 0 || + ih->data->plt->_currentDataSetIndex >= ih->data->plt->_plot.mPlotDataContainer.GetPlotCount()) + return 0; + + DataDrawerBase* drawer = ih->data->plt->_plot.mPlotDataContainer.GetDataDrawer(ih->data->plt->_currentDataSetIndex); + + if (iupStrEqualNoCase(value, "YES") || iupStrEqualNoCase(value, "ON")) + drawer->mShowValues = true; + else + drawer->mShowValues = false; + + ih->data->plt->_redraw = 1; + return 0; +} + +static char* iPPlotGetDSShowValuesAttrib(Ihandle* ih) +{ + if (ih->data->plt->_currentDataSetIndex < 0 || + ih->data->plt->_currentDataSetIndex >= ih->data->plt->_plot.mPlotDataContainer.GetPlotCount()) + return NULL; + + DataDrawerBase* drawer = ih->data->plt->_plot.mPlotDataContainer.GetDataDrawer(ih->data->plt->_currentDataSetIndex); + if (drawer->mShowValues) + return "YES"; + else + return "NO"; +} + +/* current dataset drawing mode */ +static int iPPlotSetDSModeAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->plt->_currentDataSetIndex < 0 || + ih->data->plt->_currentDataSetIndex >= ih->data->plt->_plot.mPlotDataContainer.GetPlotCount()) + return 0; + + DataDrawerBase *theDataDrawer = NULL; + ih->data->plt->_plot.mXAxisSetup.mDiscrete = false; + + if(iupStrEqualNoCase(value, "BAR")) + { + theDataDrawer = new BarDataDrawer(); + ih->data->plt->_plot.mXAxisSetup.mDiscrete = true; + } + else if(iupStrEqualNoCase(value, "MARK")) + theDataDrawer = new MarkDataDrawer(0); + else if(iupStrEqualNoCase(value, "MARKLINE")) + theDataDrawer = new MarkDataDrawer(1); + else /* LINE */ + theDataDrawer = new LineDataDrawer(); + + ih->data->plt->_plot.mPlotDataContainer.SetDataDrawer(ih->data->plt->_currentDataSetIndex, theDataDrawer); + + ih->data->plt->_redraw = 1; + return 0; +} + +static char* iPPlotGetDSModeAttrib(Ihandle* ih) +{ + if (ih->data->plt->_currentDataSetIndex < 0 || + ih->data->plt->_currentDataSetIndex >= ih->data->plt->_plot.mPlotDataContainer.GetPlotCount()) + return NULL; + + DataDrawerBase* drawer = ih->data->plt->_plot.mPlotDataContainer.GetDataDrawer(ih->data->plt->_currentDataSetIndex); + + return (char*)drawer->mMode; +} + +/* allows selection and editing */ +static int iPPlotSetDSEditAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->plt->_currentDataSetIndex < 0 || + ih->data->plt->_currentDataSetIndex >= ih->data->plt->_plot.mPlotDataContainer.GetPlotCount()) + return 0; + + PlotDataSelection* dataselect = ih->data->plt->_plot.mPlotDataContainer.GetPlotDataSelection(ih->data->plt->_currentDataSetIndex); + + if (iupStrEqualNoCase(value, "YES") || iupStrEqualNoCase(value, "ON")) + dataselect->resize(ih->data->plt->_plot.mPlotDataContainer.GetConstYData(ih->data->plt->_currentDataSetIndex)->GetSize()); + else + dataselect->clear(); + + ih->data->plt->_redraw = 1; + return 0; +} + +static char* iPPlotGetDSEditAttrib(Ihandle* ih) +{ + if (ih->data->plt->_currentDataSetIndex < 0 || + ih->data->plt->_currentDataSetIndex >= ih->data->plt->_plot.mPlotDataContainer.GetPlotCount()) + return NULL; + + PlotDataSelection* dataselect = ih->data->plt->_plot.mPlotDataContainer.GetPlotDataSelection(ih->data->plt->_currentDataSetIndex); + if (dataselect->empty()) + return "NO"; + else + return "YES"; +} + +/* remove a sample */ +static int iPPlotSetDSRemoveAttrib(Ihandle* ih, const char* value) +{ + int ii; + + if (ih->data->plt->_currentDataSetIndex < 0 || + ih->data->plt->_currentDataSetIndex >= ih->data->plt->_plot.mPlotDataContainer.GetPlotCount()) + return 0; + + if (iupStrToInt(value, &ii)) + { + RemoveSample(ih->data->plt->_plot, ih->data->plt->_currentDataSetIndex, ii); + ih->data->plt->_redraw = 1; + } + return 0; +} + +/* ========== */ +/* axis props */ +/* ========== */ + +/* ========== */ +/* axis props */ +/* ========== */ + +/* axis title */ +static int iPPlotSetAXSXLabelAttrib(Ihandle* ih, const char* value) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + + if (value) + axis->mLabel = value; + else + axis->mLabel = ""; + + ih->data->plt->_redraw = 1; + return 0; +} + +static int iPPlotSetAXSYLabelAttrib(Ihandle* ih, const char* value) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + + if (value) + axis->mLabel = value; + else + axis->mLabel = ""; + + ih->data->plt->_redraw = 1; + return 0; +} + +static char* iPPlotGetAXSXLabelAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + char* att_buffer = iupStrGetMemory(256); + strncpy(att_buffer, axis->mLabel.c_str(), 255); + att_buffer[255]='\0'; + return att_buffer; +} + +static char* iPPlotGetAXSYLabelAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + char* att_buffer = iupStrGetMemory(256); + strncpy(att_buffer, axis->mLabel.c_str(), 255); + att_buffer[255]='\0'; + return att_buffer; +} + +/* axis title position */ +static int iPPlotSetAXSXLabelCenteredAttrib(Ihandle* ih, const char* value) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + + if (iupStrEqualNoCase(value, "YES") || iupStrEqualNoCase(value, "ON")) + axis->mLabelCentered = true; + else + axis->mLabelCentered = false; + + ih->data->plt->_redraw = 1; + return 0; +} + +static int iPPlotSetAXSYLabelCenteredAttrib(Ihandle* ih, const char* value) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + + if (iupStrEqualNoCase(value, "YES") || iupStrEqualNoCase(value, "ON")) + axis->mLabelCentered = true; + else + axis->mLabelCentered = false; + + ih->data->plt->_redraw = 1; + return 0; +} + +static char* iPPlotGetAXSXLabelCenteredAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + + if (axis->mLabelCentered) + return "YES"; + else + return "NO"; +} + +static char* iPPlotGetAXSYLabelCenteredAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + + if (axis->mLabelCentered) + return "YES"; + else + return "NO"; +} + +/* axis, ticks and label color */ +static int iPPlotSetAXSXColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char rr, gg, bb; + if (iupStrToRGB(value, &rr, &gg, &bb)) + { + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + axis->mColor = PColor(rr, gg, bb); + ih->data->plt->_redraw = 1; + } + return 0; +} + +static int iPPlotSetAXSYColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char rr, gg, bb; + if (iupStrToRGB(value, &rr, &gg, &bb)) + { + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + axis->mColor = PColor(rr, gg, bb); + ih->data->plt->_redraw = 1; + } + return 0; +} + +static char* iPPlotGetAXSXColorAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%d %d %d", + axis->mColor.mR, + axis->mColor.mG, + axis->mColor.mB); + return att_buffer; +} + +static char* iPPlotGetAXSYColorAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%d %d %d", + axis->mColor.mR, + axis->mColor.mG, + axis->mColor.mB); + return att_buffer; +} + +/* autoscaling */ +static int iPPlotSetAXSXAutoMinAttrib(Ihandle* ih, const char* value) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + + if(iupStrEqualNoCase(value, "YES") || iupStrEqualNoCase(value, "ON")) + axis->mAutoScaleMin = true; + else + axis->mAutoScaleMin = false; + + ih->data->plt->_redraw = 1; + return 0; +} + +static int iPPlotSetAXSYAutoMinAttrib(Ihandle* ih, const char* value) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + + if(iupStrEqualNoCase(value, "YES") || iupStrEqualNoCase(value, "ON")) + axis->mAutoScaleMin = true; + else + axis->mAutoScaleMin = false; + + ih->data->plt->_redraw = 1; + return 0; +} + +static char* iPPlotGetAXSXAutoMinAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + + if (axis->mAutoScaleMin) + return "YES"; + else + return "NO"; +} + +static char* iPPlotGetAXSYAutoMinAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + + if (axis->mAutoScaleMin) + return "YES"; + else + return "NO"; +} + +/* autoscaling */ +static int iPPlotSetAXSXAutoMaxAttrib(Ihandle* ih, const char* value) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + + if(iupStrEqualNoCase(value, "YES") || iupStrEqualNoCase(value, "ON")) + axis->mAutoScaleMax = true; + else + axis->mAutoScaleMax = false; + + ih->data->plt->_redraw = 1; + return 0; +} + +static int iPPlotSetAXSYAutoMaxAttrib(Ihandle* ih, const char* value) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + + if(iupStrEqualNoCase(value, "YES") || iupStrEqualNoCase(value, "ON")) + axis->mAutoScaleMax = true; + else + axis->mAutoScaleMax = false; + + ih->data->plt->_redraw = 1; + return 0; +} + +static char* iPPlotGetAXSXAutoMaxAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + + if (axis->mAutoScaleMax) + return "YES"; + else + return "NO"; +} + +static char* iPPlotGetAXSYAutoMaxAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + + if (axis->mAutoScaleMax) + return "YES"; + else + return "NO"; +} + +/* min visible val */ +static int iPPlotSetAXSXMinAttrib(Ihandle* ih, const char* value) +{ + float xx; + if (iupStrToFloat(value, &xx)) + { + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + axis->mMin = xx; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static int iPPlotSetAXSYMinAttrib(Ihandle* ih, const char* value) +{ + float xx; + if (iupStrToFloat(value, &xx)) + { + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + axis->mMin = xx; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static char* iPPlotGetAXSXMinAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%g", axis->mMin); + return att_buffer; +} + +static char* iPPlotGetAXSYMinAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%g", axis->mMin); + return att_buffer; +} + +/* max visible val */ +static int iPPlotSetAXSXMaxAttrib(Ihandle* ih, const char* value) +{ + float xx; + if (iupStrToFloat(value, &xx)) + { + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + axis->mMax = xx; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static int iPPlotSetAXSYMaxAttrib(Ihandle* ih, const char* value) +{ + float xx; + if (iupStrToFloat(value, &xx)) + { + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + axis->mMax = xx; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static char* iPPlotGetAXSXMaxAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%g", axis->mMax); + return att_buffer; +} + +static char* iPPlotGetAXSYMaxAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%g", axis->mMax); + return att_buffer; +} + +/* values from left/top to right/bottom */ +static int iPPlotSetAXSXReverseAttrib(Ihandle* ih, const char* value) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + + if(iupStrEqualNoCase(value, "YES") || iupStrEqualNoCase(value, "ON")) + axis->mAscending = false; // inverted + else + axis->mAscending = true; + + ih->data->plt->_redraw = 1; + return 0; +} + +static int iPPlotSetAXSYReverseAttrib(Ihandle* ih, const char* value) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + + if(iupStrEqualNoCase(value, "YES") || iupStrEqualNoCase(value, "ON")) + axis->mAscending = false; // inverted + else + axis->mAscending = true; + + ih->data->plt->_redraw = 1; + return 0; +} + +static char* iPPlotGetAXSXReverseAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + + if (axis->mAscending) + return "NO"; /* inverted */ + else + return "YES"; +} + +static char* iPPlotGetAXSYReverseAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + + if (axis->mAscending) + return "NO"; /* inverted */ + else + return "YES"; +} + +/* axis mode */ +static int iPPlotSetAXSXCrossOriginAttrib(Ihandle* ih, const char* value) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + + if(iupStrEqualNoCase(value, "YES") || iupStrEqualNoCase(value, "ON")) + axis->mCrossOrigin = true; + else + axis->mCrossOrigin = false; + + ih->data->plt->_redraw = 1; + return 0; +} + +static int iPPlotSetAXSYCrossOriginAttrib(Ihandle* ih, const char* value) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + + if(iupStrEqualNoCase(value, "YES") || iupStrEqualNoCase(value, "ON")) + axis->mCrossOrigin = true; + else + axis->mCrossOrigin = false; + + ih->data->plt->_redraw = 1; + return 0; +} + +static char* iPPlotGetAXSXCrossOriginAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + + if (axis->mCrossOrigin) + return "YES"; + else + return "NO"; +} + +static char* iPPlotGetAXSYCrossOriginAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + + if (axis->mCrossOrigin) + return "YES"; + else + return "NO"; +} + +/* log/lin scale */ +static int iPPlotSetAXSXScaleAttrib(Ihandle* ih, const char* value) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + + if(iupStrEqualNoCase(value, "LIN")) + { + axis->mLogScale = false; + } + else if(iupStrEqualNoCase(value, "LOG10")) + { + axis->mLogScale = true; + axis->mLogBase = 10.0; + } + else if(iupStrEqualNoCase(value, "LOG2")) + { + axis->mLogScale = true; + axis->mLogBase = 2.0; + } + else + { + axis->mLogScale = true; + axis->mLogBase = (float)M_E; + } + + ih->data->plt->_redraw = 1; + return 0; +} + +static int iPPlotSetAXSYScaleAttrib(Ihandle* ih, const char* value) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + + if(iupStrEqualNoCase(value, "LIN")) + { + axis->mLogScale = false; + } + else if(iupStrEqualNoCase(value, "LOG10")) + { + axis->mLogScale = true; + axis->mLogBase = 10.0; + } + else if(iupStrEqualNoCase(value, "LOG2")) + { + axis->mLogScale = true; + axis->mLogBase = 2.0; + } + else + { + axis->mLogScale = true; + axis->mLogBase = (float)M_E; + } + + ih->data->plt->_redraw = 1; + return 0; +} + +static char* iPPlotGetAXSXScaleAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + char* att_buffer = iupStrGetMemory(30); + + if (axis->mLogScale) + { + if (axis->mLogBase == 10.0) + strcpy(att_buffer, "LOG10"); + else if (axis->mLogBase == 2.0) + strcpy(att_buffer, "LOG2"); + else + strcpy(att_buffer, "LOGN"); + } + else + strcpy(att_buffer, "LIN"); + + return att_buffer; +} + +static char* iPPlotGetAXSYScaleAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + char* att_buffer = iupStrGetMemory(30); + + if (axis->mLogScale) + { + if (axis->mLogBase == 10.0) + strcpy(att_buffer, "LOG10"); + else if (axis->mLogBase == 2.0) + strcpy(att_buffer, "LOG2"); + else + strcpy(att_buffer, "LOGN"); + } + else + strcpy(att_buffer, "LIN"); + + return att_buffer; +} + +/* axis label font size */ +static int iPPlotSetAXSXFontSizeAttrib(Ihandle* ih, const char* value) +{ + int ii; + if (iupStrToInt(value, &ii)) + { + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + axis->mStyle.mFontSize = ii; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static int iPPlotSetAXSYFontSizeAttrib(Ihandle* ih, const char* value) +{ + int ii; + if (iupStrToInt(value, &ii)) + { + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + axis->mStyle.mFontSize = ii; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static char* iPPlotGetAXSXFontSizeAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + return iPPlotGetPlotFontSize(axis->mStyle.mFontSize); +} + +static char* iPPlotGetAXSYFontSizeAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + return iPPlotGetPlotFontSize(axis->mStyle.mFontSize); +} + +/* axis label font style */ +static int iPPlotSetAXSXFontStyleAttrib(Ihandle* ih, const char* value) +{ + int style = iPPlotGetCDFontStyle(value); + if (style != -1) + { + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + axis->mStyle.mFontStyle = style; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static int iPPlotSetAXSYFontStyleAttrib(Ihandle* ih, const char* value) +{ + int style = iPPlotGetCDFontStyle(value); + if (style != -1) + { + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + axis->mStyle.mFontStyle = style; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static char* iPPlotGetAXSXFontStyleAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + return iPPlotGetPlotFontStyle(axis->mStyle.mFontStyle); +} + +static char* iPPlotGetAXSYFontStyleAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + return iPPlotGetPlotFontStyle(axis->mStyle.mFontStyle); +} + +/* automatic tick size */ +static int iPPlotSetAXSXAutoTickSizeAttrib(Ihandle* ih, const char* value) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + + if(iupStrEqualNoCase(value, "YES") || iupStrEqualNoCase(value, "ON")) + axis->mTickInfo.mAutoTickSize = true; + else + axis->mTickInfo.mAutoTickSize = false; + + ih->data->plt->_redraw = 1; + return 0; +} + +static int iPPlotSetAXSYAutoTickSizeAttrib(Ihandle* ih, const char* value) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + + if(iupStrEqualNoCase(value, "YES") || iupStrEqualNoCase(value, "ON")) + axis->mTickInfo.mAutoTickSize = true; + else + axis->mTickInfo.mAutoTickSize = false; + + ih->data->plt->_redraw = 1; + return 0; +} + +static char* iPPlotGetAXSXAutoTickSizeAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + + if (axis->mTickInfo.mAutoTickSize) + return "YES"; + else + return "NO"; +} + +static char* iPPlotGetAXSYAutoTickSizeAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + + if (axis->mTickInfo.mAutoTickSize) + return "YES"; + else + return "NO"; +} + +/* size of ticks (in pixels) */ +static int iPPlotSetAXSXTickSizeAttrib(Ihandle* ih, const char* value) +{ + int ii; + if (iupStrToInt(value, &ii)) + { + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + axis->mTickInfo.mMinorTickScreenSize = ii; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static int iPPlotSetAXSYTickSizeAttrib(Ihandle* ih, const char* value) +{ + int ii; + if (iupStrToInt(value, &ii)) + { + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + axis->mTickInfo.mMinorTickScreenSize = ii; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static char* iPPlotGetAXSXTickSizeAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%d", axis->mTickInfo.mMinorTickScreenSize); + return att_buffer; +} + +static char* iPPlotGetAXSYTickSizeAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%d", axis->mTickInfo.mMinorTickScreenSize); + return att_buffer; +} + +/* size of major ticks (in pixels) */ +static int iPPlotSetAXSXTickMajorSizeAttrib(Ihandle* ih, const char* value) +{ + int ii; + if (iupStrToInt(value, &ii)) + { + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + axis->mTickInfo.mMajorTickScreenSize = ii; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static int iPPlotSetAXSYTickMajorSizeAttrib(Ihandle* ih, const char* value) +{ + int ii; + if (iupStrToInt(value, &ii)) + { + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + axis->mTickInfo.mMajorTickScreenSize = ii; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static char* iPPlotGetAXSXTickMajorSizeAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%d", axis->mTickInfo.mMajorTickScreenSize); + return att_buffer; +} + +static char* iPPlotGetAXSYTickMajorSizeAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%d", axis->mTickInfo.mMajorTickScreenSize); + return att_buffer; +} + +/* axis ticks font size */ +static int iPPlotSetAXSXTickFontSizeAttrib(Ihandle* ih, const char* value) +{ + int ii; + if (iupStrToInt(value, &ii)) + { + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + axis->mTickInfo.mStyle.mFontSize = ii; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static int iPPlotSetAXSYTickFontSizeAttrib(Ihandle* ih, const char* value) +{ + int ii; + if (iupStrToInt(value, &ii)) + { + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + axis->mTickInfo.mStyle.mFontSize = ii; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static char* iPPlotGetAXSXTickFontSizeAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + + return iPPlotGetPlotFontSize(axis->mTickInfo.mStyle.mFontSize); +} + +static char* iPPlotGetAXSYTickFontSizeAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + + return iPPlotGetPlotFontSize(axis->mTickInfo.mStyle.mFontSize); +} + +/* axis ticks number font style */ +static int iPPlotSetAXSXTickFontStyleAttrib(Ihandle* ih, const char* value) +{ + int style = iPPlotGetCDFontStyle(value); + if (style != -1) + { + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + axis->mTickInfo.mStyle.mFontStyle = style; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static int iPPlotSetAXSYTickFontStyleAttrib(Ihandle* ih, const char* value) +{ + int style = iPPlotGetCDFontStyle(value); + if (style != -1) + { + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + axis->mTickInfo.mStyle.mFontStyle = style; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static char* iPPlotGetAXSXTickFontStyleAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + + return iPPlotGetPlotFontSize(axis->mTickInfo.mStyle.mFontStyle); +} + +static char* iPPlotGetAXSYTickFontStyleAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + + return iPPlotGetPlotFontSize(axis->mTickInfo.mStyle.mFontStyle); +} + +/* axis ticks number format */ +static int iPPlotSetAXSXTickFormatAttrib(Ihandle* ih, const char* value) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + + if (value && value[0]!=0) + axis->mTickInfo.mFormatString = value; + else + axis->mTickInfo.mFormatString = "%.0f"; + + ih->data->plt->_redraw = 1; + return 0; +} + +static int iPPlotSetAXSYTickFormatAttrib(Ihandle* ih, const char* value) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + + if (value && value[0]!=0) + axis->mTickInfo.mFormatString = value; + else + axis->mTickInfo.mFormatString = "%.0f"; + + ih->data->plt->_redraw = 1; + return 0; +} + +static char* iPPlotGetAXSXTickFormatAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + char* att_buffer = iupStrGetMemory(256); + strncpy(att_buffer, axis->mTickInfo.mFormatString.c_str(), 255); + att_buffer[255]='\0'; + return att_buffer; +} + +static char* iPPlotGetAXSYTickFormatAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + char* att_buffer = iupStrGetMemory(256); + strncpy(att_buffer, axis->mTickInfo.mFormatString.c_str(), 255); + att_buffer[255]='\0'; + return att_buffer; +} + +/* axis ticks */ +static int iPPlotSetAXSXTickAttrib(Ihandle* ih, const char* value) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + + if(iupStrEqualNoCase(value, "YES") || iupStrEqualNoCase(value, "ON")) + axis->mTickInfo.mTicksOn = true; + else + axis->mTickInfo.mTicksOn = false; + + ih->data->plt->_redraw = 1; + return 0; +} + +static int iPPlotSetAXSYTickAttrib(Ihandle* ih, const char* value) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + + if(iupStrEqualNoCase(value, "YES") || iupStrEqualNoCase(value, "ON")) + axis->mTickInfo.mTicksOn = true; + else + axis->mTickInfo.mTicksOn = false; + + ih->data->plt->_redraw = 1; + return 0; +} + +static char* iPPlotGetAXSXTickAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + + if (axis->mTickInfo.mTicksOn) + return "YES"; + else + return "NO"; +} + +static char* iPPlotGetAXSYTickAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + + if (axis->mTickInfo.mTicksOn) + return "YES"; + else + return "NO"; +} + +/* major tick spacing */ +static int iPPlotSetAXSXTickMajorSpanAttrib(Ihandle* ih, const char* value) +{ + float xx; + if (iupStrToFloat(value, &xx)) + { + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + axis->mTickInfo.mMajorTickSpan = xx; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static int iPPlotSetAXSYTickMajorSpanAttrib(Ihandle* ih, const char* value) +{ + float xx; + if (iupStrToFloat(value, &xx)) + { + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + axis->mTickInfo.mMajorTickSpan = xx; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static char* iPPlotGetAXSXTickMajorSpanAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%g", axis->mTickInfo.mMajorTickSpan); + return att_buffer; +} + +static char* iPPlotGetAXSYTickMajorSpanAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%g", axis->mTickInfo.mMajorTickSpan); + return att_buffer; +} + +/* number of ticks between major ticks */ +static int iPPlotSetAXSXTickDivisionAttrib(Ihandle* ih, const char* value) +{ + int ii; + if (iupStrToInt(value, &ii)) + { + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + axis->mTickInfo.mTickDivision = ii; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static int iPPlotSetAXSYTickDivisionAttrib(Ihandle* ih, const char* value) +{ + int ii; + if (iupStrToInt(value, &ii)) + { + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + axis->mTickInfo.mTickDivision = ii; + ih->data->plt->_redraw = 1; + } + return 0; +} + +static char* iPPlotGetAXSXTickDivisionAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%d", axis->mTickInfo.mTickDivision); + return att_buffer; +} + +static char* iPPlotGetAXSYTickDivisionAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + char* att_buffer = iupStrGetMemory(30); + sprintf(att_buffer, "%d", axis->mTickInfo.mTickDivision); + return att_buffer; +} + +/* auto tick spacing */ +static int iPPlotSetAXSXAutoTickAttrib(Ihandle* ih, const char* value) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + + if(iupStrEqualNoCase(value, "YES") || iupStrEqualNoCase(value, "ON")) + axis->mTickInfo.mAutoTick = true; + else + axis->mTickInfo.mAutoTick = false; + + ih->data->plt->_redraw = 1; + return 0; +} + +static int iPPlotSetAXSYAutoTickAttrib(Ihandle* ih, const char* value) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + + if(iupStrEqualNoCase(value, "YES") || iupStrEqualNoCase(value, "ON")) + axis->mTickInfo.mAutoTick = true; + else + axis->mTickInfo.mAutoTick = false; + + ih->data->plt->_redraw = 1; + return 0; +} + +static char* iPPlotGetAXSXAutoTickAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mXAxisSetup; + + if (axis->mTickInfo.mAutoTick) + return "YES"; + else + return "NO"; +} + +static char* iPPlotGetAXSYAutoTickAttrib(Ihandle* ih) +{ + AxisSetup* axis = &ih->data->plt->_plot.mYAxisSetup; + + if (axis->mTickInfo.mAutoTick) + return "YES"; + else + return "NO"; +} + +/* MouseButton */ +void PPainterIup::MouseButton(int btn, int stat, int x, int y, char *r) +{ + PMouseEvent theEvent; + int theModifierKeys = 0; + + theEvent.mX = x; + theEvent.mY = y; + + if(btn == IUP_BUTTON1) + { + theEvent.mType = ( stat!=0 ? (PMouseEvent::kDown) : (PMouseEvent::kUp) ); + _mouseDown = ( stat!=0 ? 1 : 0 ); + } + else return; + + _mouse_ALT = 0; + _mouse_SHIFT = 0; + _mouse_CTRL = 0; + + if (iup_isalt(r)) /* signal Alt */ + { + theModifierKeys = (theModifierKeys | PMouseEvent::kAlt); + _mouse_ALT = 1; + } + if (iup_iscontrol(r)) /* signal Ctrl */ + { + theModifierKeys = (theModifierKeys | PMouseEvent::kControl); + _mouse_SHIFT = 1; + } + if (iup_isshift(r)) /* signal Shift */ + { + theModifierKeys = (theModifierKeys | PMouseEvent::kShift); + _mouse_CTRL = 1; + } + theEvent.SetModifierKeys (theModifierKeys); + + if( _InteractionContainer->HandleMouseEvent(theEvent)) + { + this->Draw(1); + } + else + { + /* ignore the event */ + } +} + +/* MouseMove */ +void PPainterIup::MouseMove(int x, int y) +{ + PMouseEvent theEvent; + int theModifierKeys = 0; + + if(!_mouseDown ) return; + + theEvent.mX = x; + theEvent.mY = y; + + theEvent.mType = PMouseEvent::kMove; + if(_mouse_ALT) /* signal Alt */ + { + theModifierKeys = (theModifierKeys | PMouseEvent::kAlt); + } + if(_mouse_SHIFT) /* signal Shift */ + { + theModifierKeys = (theModifierKeys | PMouseEvent::kControl); + } + if(_mouse_CTRL) /* signal Ctrl */ + { + theModifierKeys = (theModifierKeys | PMouseEvent::kShift); + } + theEvent.SetModifierKeys (theModifierKeys); + + if(_InteractionContainer->HandleMouseEvent(theEvent)) + { + this->Draw(1); + } + else + { + /* ignore the event */ + } +} + +/* KeyPress */ +void PPainterIup::KeyPress(int c, int press) +{ + int theModifierKeys = 0; + int theRepeatCount = 0; + PKeyEvent::EKey theKeyCode = PKeyEvent::kNone; + char theChar = 0; + + if(!press) return; + + switch(c) + { + case K_cX: /* CTRL + X */ + theModifierKeys = PMouseEvent::kControl; + theKeyCode = PKeyEvent::kChar; + theChar = 'x'; + break; + case K_cY: /* CTRL + Y */ + theModifierKeys = PMouseEvent::kControl; + theKeyCode = PKeyEvent::kChar; + theChar = 'y'; + break; + case K_cR: /* CTRL + R */ + theModifierKeys = PMouseEvent::kControl; + theKeyCode = PKeyEvent::kChar; + theChar = 'r'; + break; + case K_cUP: /* CTRL + Arrow */ + theModifierKeys = PMouseEvent::kControl; + case K_UP: /* Arrow */ + theKeyCode = PKeyEvent::kArrowUp; + break; + case K_cDOWN: /* CTRL + Arrow */ + theModifierKeys = PMouseEvent::kControl; + case K_DOWN: /* Arrow */ + theKeyCode = PKeyEvent::kArrowDown; + break; + case K_cLEFT: /* CTRL + Arrow */ + theModifierKeys = PMouseEvent::kControl; + case K_LEFT: /* Arrow */ + theKeyCode = PKeyEvent::kArrowLeft; + break; + case K_cRIGHT: /* CTRL + Arrow */ + theModifierKeys = PMouseEvent::kControl; + case K_RIGHT: /* Arrow */ + theKeyCode = PKeyEvent::kArrowRight; + break; + case K_cDEL: /* CTRL + Arrow */ + theModifierKeys = PMouseEvent::kControl; + case K_DEL: /* Arrow */ + theKeyCode = PKeyEvent::kDelete; + break; + } + + PKeyEvent theEvent (theKeyCode, theRepeatCount, theModifierKeys, theChar); + + if(_InteractionContainer->HandleKeyEvent(theEvent)) + { + this->Draw(1); + } + else + { + /* ignore the event */ + } +} + +/* Draw */ +void PPainterIup::Draw(int force) +{ + if (!_cddbuffer) + return; + + cdCanvasActivate(_cddbuffer); + + if (force || _redraw) + { + cdCanvasClear(_cddbuffer); + _plot.Draw(*this); + _redraw = 0; + } + + cdCanvasFlush(_cddbuffer); +} + +/* Resize */ +void PPainterIup::Resize() +{ + if (!_cddbuffer) + { + /* update canvas size */ + cdCanvasActivate(_cdcanvas); + + /* this can fail if canvas size is zero */ + if (IupGetInt(_ih, "USE_IMAGERGB")) + _cddbuffer = cdCreateCanvas(CD_DBUFFERRGB, _cdcanvas); + else + _cddbuffer = cdCreateCanvas(CD_DBUFFER, _cdcanvas); + } + + if (!_cddbuffer) + return; + + /* update canvas size */ + cdCanvasActivate(_cddbuffer); + + _redraw = 1; + + return; +} + +/* send plot to some other device */ +void PPainterIup::DrawTo(cdCanvas *usrCnv) +{ + cdCanvas *old_cddbuffer = _cddbuffer; + cdCanvas *old_cdcanvas = _cdcanvas; + + _cdcanvas = _cddbuffer = usrCnv; + + if(!_cddbuffer) + return; + + Draw(1); + + _cddbuffer = old_cddbuffer; + _cdcanvas = old_cdcanvas; +} + +void PPainterIup::FillArrow(int inX1, int inY1, int inX2, int inY2, int inX3, int inY3) +{ + if (!_cddbuffer) + return; + + cdCanvasBegin(_cddbuffer, CD_FILL); + cdCanvasVertex(_cddbuffer, inX1, cdCanvasInvertYAxis(_cddbuffer, inY1)); + cdCanvasVertex(_cddbuffer, inX2, cdCanvasInvertYAxis(_cddbuffer, inY2)); + cdCanvasVertex(_cddbuffer, inX3, cdCanvasInvertYAxis(_cddbuffer, inY3)); + cdCanvasEnd(_cddbuffer); +} + +/* DrawLine */ +void PPainterIup::DrawLine(float inX1, float inY1, float inX2, float inY2) +{ + if (!_cddbuffer) + return; + + cdfCanvasLine(_cddbuffer, inX1, cdfCanvasInvertYAxis(_cddbuffer, inY1), + inX2, cdfCanvasInvertYAxis(_cddbuffer, inY2)); +} + +/* FillRect */ +void PPainterIup::FillRect(int inX, int inY, int inW, int inH) +{ + if (!_cddbuffer) + return; + + cdCanvasBox(_cddbuffer, inX, inX+inW, + cdCanvasInvertYAxis(_cddbuffer, inY), + cdCanvasInvertYAxis(_cddbuffer, inY + inH - 1)); +} + +/* InvertRect */ +void PPainterIup::InvertRect(int inX, int inY, int inW, int inH) +{ + long cprev; + + if (!_cddbuffer) + return; + + cdCanvasWriteMode(_cddbuffer, CD_XOR); + cprev = cdCanvasForeground(_cddbuffer, CD_WHITE); + cdCanvasRect(_cddbuffer, inX, inX + inW - 1, + cdCanvasInvertYAxis(_cddbuffer, inY), + cdCanvasInvertYAxis(_cddbuffer, inY + inH - 1)); + cdCanvasWriteMode(_cddbuffer, CD_REPLACE); + cdCanvasForeground(_cddbuffer, cprev); +} + +/* SetClipRect */ +void PPainterIup::SetClipRect(int inX, int inY, int inW, int inH) +{ + if (!_cddbuffer) + return; + + cdCanvasClipArea(_cddbuffer, inX, inX + inW - 1, + cdCanvasInvertYAxis(_cddbuffer, inY), + cdCanvasInvertYAxis(_cddbuffer, inY + inH - 1)); + cdCanvasClip(_cddbuffer, CD_CLIPAREA); +} + +/* GetWidth */ +long PPainterIup::GetWidth() const +{ + int iret; + + if (!_cddbuffer) + return IUP_DEFAULT; + + cdCanvasGetSize(_cddbuffer, &iret, NULL, NULL, NULL); + + return (long)iret; +} + +/* GetHeight */ +long PPainterIup::GetHeight() const +{ + int iret; + + if (!_cddbuffer) + return IUP_NOERROR; + + cdCanvasGetSize(_cddbuffer, NULL, &iret, NULL, NULL); + + return (long)iret; +} + +/* SetLineColor */ +void PPainterIup::SetLineColor(int inR, int inG, int inB) +{ + if (!_cddbuffer) + return; + + cdCanvasForeground(_cddbuffer, cdEncodeColor((unsigned char)inR, + (unsigned char)inG, + (unsigned char)inB)); +} + +/* SetFillColor */ +void PPainterIup::SetFillColor(int inR, int inG, int inB) +{ + if (!_cddbuffer) + return; + + cdCanvasForeground(_cddbuffer, cdEncodeColor((unsigned char)inR, + (unsigned char)inG, + (unsigned char)inB)); +} + +/* CalculateTextDrawSize */ +long PPainterIup::CalculateTextDrawSize(const char *inString) +{ + int iw; + + if (!_cddbuffer) + return IUP_NOERROR; + + cdCanvasGetTextSize(_cddbuffer, const_cast(inString), &iw, NULL); + + return iw; +} + +/* GetFontHeight */ +long PPainterIup::GetFontHeight() const +{ + int ih; + + if (!_cddbuffer) + return IUP_NOERROR; + + cdCanvasGetFontDim(_cddbuffer, NULL, &ih, NULL, NULL); + + return ih; +} + +/* DrawText */ +/* this call leave all the hard job of alignment on painter side */ +void PPainterIup::DrawText(int inX, int inY, short align, const char *inString) +{ + if (!_cddbuffer) + return; + + cdCanvasTextAlignment(_cddbuffer, align); + cdCanvasText(_cddbuffer, inX, cdCanvasInvertYAxis(_cddbuffer, inY), const_cast(inString)); +} + +/* DrawRotatedText */ +void PPainterIup::DrawRotatedText(int inX, int inY, float inDegrees, short align, const char *inString) +{ + double aprev; + + if (!_cddbuffer) + return; + + cdCanvasTextAlignment(_cddbuffer, align); + aprev = cdCanvasTextOrientation(_cddbuffer, -inDegrees); + cdCanvasText(_cddbuffer, inX, cdCanvasInvertYAxis(_cddbuffer, inY), const_cast(inString)); + cdCanvasTextOrientation(_cddbuffer, aprev); +} + +void PPainterIup::SetStyle(const PStyle &inStyle) +{ + if (!_cddbuffer) + return; + + cdCanvasLineWidth(_cddbuffer, inStyle.mPenWidth); + cdCanvasLineStyle(_cddbuffer, inStyle.mPenStyle); + + cdCanvasNativeFont(_cddbuffer, IupGetAttribute(_ih, "FONT")); + + if (inStyle.mFontStyle != -1 || inStyle.mFontSize != 0) + cdCanvasFont(_cddbuffer, NULL, inStyle.mFontStyle, inStyle.mFontSize); + + cdCanvasMarkType(_cddbuffer, inStyle.mMarkStyle); + cdCanvasMarkSize(_cddbuffer, inStyle.mMarkSize); +} + +int iPPlotMapMethod(Ihandle* ih) +{ + int old_gdi = 0; + + if (IupGetInt(ih, "USE_GDI+")) + old_gdi = cdUseContextPlus(1); + + ih->data->plt->_cdcanvas = cdCreateCanvas(CD_IUP, ih); + if (!ih->data->plt->_cdcanvas) + return IUP_ERROR; + + /* this can fail if canvas size is zero */ + if (IupGetInt(ih, "USE_IMAGERGB")) + ih->data->plt->_cddbuffer = cdCreateCanvas(CD_DBUFFERRGB, ih->data->plt->_cdcanvas); + else + ih->data->plt->_cddbuffer = cdCreateCanvas(CD_DBUFFER, ih->data->plt->_cdcanvas); + + if (IupGetInt(ih, "USE_GDI+")) + cdUseContextPlus(old_gdi); + + ih->data->plt->_redraw = 1; + + return IUP_NOERROR; +} + +void iPPlotDestroyMethod(Ihandle* ih) +{ + delete ih->data->plt; +} + +int iPPlotCreateMethod(Ihandle* ih, void **params) +{ + (void)params; + + /* free the data alocated by IupCanvas */ + if (ih->data) free(ih->data); + ih->data = iupALLOCCTRLDATA(); + + /* Initializing object with no cd canvases */ + ih->data->plt = new PPainterIup(ih); + + /* IupCanvas callbacks */ + IupSetCallback(ih, "ACTION", (Icallback)iPPlotRedraw_CB); + IupSetCallback(ih, "RESIZE_CB", (Icallback)iPPlotResize_CB); + IupSetCallback(ih, "BUTTON_CB", (Icallback)iPPlotMouseButton_CB); + IupSetCallback(ih, "MOTION_CB", (Icallback)iPPlotMouseMove_CB); + IupSetCallback(ih, "KEYPRESS_CB", (Icallback)iPPlotKeyPress_CB); + + return IUP_NOERROR; +} + +static Iclass* iupPPlotGetClass(void) +{ + Iclass* ic = iupClassNew(iupCanvasGetClass()); + + ic->name = "pplot"; + ic->format = NULL; /* none */ + ic->nativetype = IUP_TYPECANVAS; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 1; + ic->has_attrib_id = 1; /* has attributes with IDs that must be parsed */ + + /* Class functions */ + ic->Create = iPPlotCreateMethod; + ic->Destroy = iPPlotDestroyMethod; + ic->Map = iPPlotMapMethod; + + /* IupPPlot Callbacks */ + iupClassRegisterCallback(ic, "POSTDRAW_CB", "v"); + iupClassRegisterCallback(ic, "PREDRAW_CB", "v"); + iupClassRegisterCallback(ic, "DELETE_CB", "iiff"); + iupClassRegisterCallback(ic, "DELETEBEGIN_CB", ""); + iupClassRegisterCallback(ic, "DELETEEND_CB", ""); + iupClassRegisterCallback(ic, "SELECT_CB", "iiffi"); + iupClassRegisterCallback(ic, "SELECTBEGIN_CB", ""); + iupClassRegisterCallback(ic, "SELECTEND_CB", ""); + iupClassRegisterCallback(ic, "EDIT_CB", "iiffvv"); + iupClassRegisterCallback(ic, "EDITBEGIN_CB", ""); + iupClassRegisterCallback(ic, "EDITEND_CB", ""); + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", iPPlotGetBGColorAttrib, iPPlotSetBGColorAttrib, IUPAF_SAMEASSYSTEM, "255 255 255", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "FGCOLOR", iPPlotGetFGColorAttrib, iPPlotSetFGColorAttrib, IUPAF_SAMEASSYSTEM, "0 0 0", IUPAF_NOT_MAPPED); + + /* IupPPlot only */ + + iupClassRegisterAttribute(ic, "REDRAW", NULL, iPPlotSetRedrawAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TITLE", iPPlotGetTitleAttrib, iPPlotSetTitleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TITLEFONTSIZE", iPPlotGetTitleFontSizeAttrib, iPPlotSetTitleFontSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TITLEFONTSTYLE", NULL, iPPlotSetTitleFontStyleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "LEGENDSHOW", iPPlotGetLegendShowAttrib, iPPlotSetLegendShowAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "LEGENDPOS", iPPlotGetLegendPosAttrib, iPPlotSetLegendPosAttrib, IUPAF_SAMEASSYSTEM, "TOPRIGHT", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "LEGENDFONTSIZE", NULL, iPPlotSetLegendFontSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "LEGENDFONTSTYLE", NULL, iPPlotSetLegendFontStyleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MARGINLEFT", iPPlotGetMarginLeftAttrib, iPPlotSetMarginLeftAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MARGINRIGHT", iPPlotGetMarginRightAttrib, iPPlotSetMarginRightAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MARGINTOP", iPPlotGetMarginTopAttrib, iPPlotSetMarginTopAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MARGINBOTTOM", iPPlotGetMarginBottomAttrib, iPPlotSetMarginBottomAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "GRIDLINESTYLE", iPPlotGetGridLineStyleAttrib, iPPlotSetGridLineStyleAttrib, IUPAF_SAMEASSYSTEM, "CONTINUOUS", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "GRIDCOLOR", iPPlotGetGridColorAttrib, iPPlotSetGridColorAttrib, IUPAF_SAMEASSYSTEM, "200 200 200", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "GRID", iPPlotGetGridAttrib, iPPlotSetGridAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "DS_LINESTYLE", iPPlotGetDSLineStyleAttrib, iPPlotSetDSLineStyleAttrib, IUPAF_SAMEASSYSTEM, "CONTINUOUS", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DS_LINEWIDTH", iPPlotGetDSLineWidthAttrib, iPPlotSetDSLineWidthAttrib, IUPAF_SAMEASSYSTEM, "1", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DS_MARKSTYLE", iPPlotGetDSMarkStyleAttrib, iPPlotSetDSMarkStyleAttrib, IUPAF_SAMEASSYSTEM, "X", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DS_MARKSIZE", iPPlotGetDSMarkSizeAttrib, iPPlotSetDSMarkSizeAttrib, IUPAF_SAMEASSYSTEM, "7", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DS_LEGEND", iPPlotGetDSLegendAttrib, iPPlotSetDSLegendAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DS_COLOR", iPPlotGetDSColorAttrib, iPPlotSetDSColorAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DS_SHOWVALUES", iPPlotGetDSShowValuesAttrib, iPPlotSetDSShowValuesAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DS_MODE", iPPlotGetDSModeAttrib, iPPlotSetDSModeAttrib, IUPAF_SAMEASSYSTEM, "LINE", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DS_EDIT", iPPlotGetDSEditAttrib, iPPlotSetDSEditAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DS_REMOVE", NULL, iPPlotSetDSRemoveAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "AXS_XLABEL", iPPlotGetAXSXLabelAttrib, iPPlotSetAXSXLabelAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_YLABEL", iPPlotGetAXSYLabelAttrib, iPPlotSetAXSYLabelAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_XLABELCENTERED", iPPlotGetAXSXLabelCenteredAttrib, iPPlotSetAXSXLabelCenteredAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_YLABELCENTERED", iPPlotGetAXSYLabelCenteredAttrib, iPPlotSetAXSYLabelCenteredAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_XCOLOR", iPPlotGetAXSXColorAttrib, iPPlotSetAXSXColorAttrib, IUPAF_SAMEASSYSTEM, "0 0 0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_YCOLOR", iPPlotGetAXSYColorAttrib, iPPlotSetAXSYColorAttrib, IUPAF_SAMEASSYSTEM, "0 0 0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_XAUTOMIN", iPPlotGetAXSXAutoMinAttrib, iPPlotSetAXSXAutoMinAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_YAUTOMIN", iPPlotGetAXSYAutoMinAttrib, iPPlotSetAXSYAutoMinAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_XAUTOMAX", iPPlotGetAXSXAutoMaxAttrib, iPPlotSetAXSXAutoMaxAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_YAUTOMAX", iPPlotGetAXSYAutoMaxAttrib, iPPlotSetAXSYAutoMaxAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_XMIN", iPPlotGetAXSXMinAttrib, iPPlotSetAXSXMinAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_YMIN", iPPlotGetAXSYMinAttrib, iPPlotSetAXSYMinAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_XMAX", iPPlotGetAXSXMaxAttrib, iPPlotSetAXSXMaxAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_YMAX", iPPlotGetAXSYMaxAttrib, iPPlotSetAXSYMaxAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_XREVERSE", iPPlotGetAXSXReverseAttrib, iPPlotSetAXSXReverseAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_YREVERSE", iPPlotGetAXSYReverseAttrib, iPPlotSetAXSYReverseAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_XCROSSORIGIN", iPPlotGetAXSXCrossOriginAttrib, iPPlotSetAXSXCrossOriginAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_YCROSSORIGIN", iPPlotGetAXSYCrossOriginAttrib, iPPlotSetAXSYCrossOriginAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_XSCALE", iPPlotGetAXSXScaleAttrib, iPPlotSetAXSXScaleAttrib, IUPAF_SAMEASSYSTEM, "LIN", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_YSCALE", iPPlotGetAXSYScaleAttrib, iPPlotSetAXSYScaleAttrib, IUPAF_SAMEASSYSTEM, "LIN", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_XFONTSIZE", iPPlotGetAXSXFontSizeAttrib, iPPlotSetAXSXFontSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_YFONTSIZE", iPPlotGetAXSYFontSizeAttrib, iPPlotSetAXSYFontSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_XFONTSTYLE", iPPlotGetAXSXFontStyleAttrib, iPPlotSetAXSXFontStyleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_YFONTSTYLE", iPPlotGetAXSYFontStyleAttrib, iPPlotSetAXSYFontStyleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_XTICK", iPPlotGetAXSXTickAttrib, iPPlotSetAXSXTickAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_YTICK", iPPlotGetAXSYTickAttrib, iPPlotSetAXSYTickAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_XTICKSIZE", iPPlotGetAXSXTickSizeAttrib, iPPlotSetAXSXTickSizeAttrib, IUPAF_SAMEASSYSTEM, "5", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_YTICKSIZE", iPPlotGetAXSYTickSizeAttrib, iPPlotSetAXSYTickSizeAttrib, IUPAF_SAMEASSYSTEM, "5", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_XTICKFORMAT", iPPlotGetAXSXTickFormatAttrib, iPPlotSetAXSXTickFormatAttrib, IUPAF_SAMEASSYSTEM, "%.0f", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_YTICKFORMAT", iPPlotGetAXSYTickFormatAttrib, iPPlotSetAXSYTickFormatAttrib, IUPAF_SAMEASSYSTEM, "%.0f", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_XTICKFONTSIZE", iPPlotGetAXSXTickFontSizeAttrib, iPPlotSetAXSXTickFontSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_YTICKFONTSIZE", iPPlotGetAXSYTickFontSizeAttrib, iPPlotSetAXSYTickFontSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_XTICKFONTSTYLE", iPPlotGetAXSXTickFontStyleAttrib, iPPlotSetAXSXTickFontStyleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_YTICKFONTSTYLE", iPPlotGetAXSYTickFontStyleAttrib, iPPlotSetAXSYTickFontStyleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_XAUTOTICK", iPPlotGetAXSXAutoTickAttrib, iPPlotSetAXSXAutoTickAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_YAUTOTICK", iPPlotGetAXSYAutoTickAttrib, iPPlotSetAXSYAutoTickAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_XAUTOTICKSIZE", iPPlotGetAXSXAutoTickSizeAttrib, iPPlotSetAXSXAutoTickSizeAttrib, IUPAF_SAMEASSYSTEM, "5", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_YAUTOTICKSIZE", iPPlotGetAXSYAutoTickSizeAttrib, iPPlotSetAXSYAutoTickSizeAttrib, IUPAF_SAMEASSYSTEM, "5", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_XTICKMAJORSPAN", iPPlotGetAXSXTickMajorSpanAttrib, iPPlotSetAXSXTickMajorSpanAttrib, IUPAF_SAMEASSYSTEM, "1", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_YTICKMAJORSPAN", iPPlotGetAXSYTickMajorSpanAttrib, iPPlotSetAXSYTickMajorSpanAttrib, IUPAF_SAMEASSYSTEM, "1", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_XTICKDIVISION", iPPlotGetAXSXTickDivisionAttrib, iPPlotSetAXSXTickDivisionAttrib, IUPAF_SAMEASSYSTEM, "5", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_YTICKDIVISION", iPPlotGetAXSYTickDivisionAttrib, iPPlotSetAXSYTickDivisionAttrib, IUPAF_SAMEASSYSTEM, "5", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_XAUTOTICKSIZE", iPPlotGetAXSXAutoTickSizeAttrib, iPPlotSetAXSXAutoTickSizeAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_YAUTOTICKSIZE", iPPlotGetAXSYAutoTickSizeAttrib, iPPlotSetAXSYAutoTickSizeAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_XTICKMAJORSIZE", iPPlotGetAXSXTickMajorSizeAttrib, iPPlotSetAXSXTickMajorSizeAttrib, IUPAF_SAMEASSYSTEM, "8", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AXS_YTICKMAJORSIZE", iPPlotGetAXSYTickMajorSizeAttrib, iPPlotSetAXSYTickMajorSizeAttrib, IUPAF_SAMEASSYSTEM, "8", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "REMOVE", NULL, iPPlotSetRemoveAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CLEAR", NULL, iPPlotSetClearAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "COUNT", iPPlotGetCountAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CURRENT", iPPlotGetCurrentAttrib, iPPlotSetCurrentAttrib, IUPAF_SAMEASSYSTEM, "-1", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + return ic; +} + +/* user level call: create control */ +Ihandle* IupPPlot(void) +{ + return IupCreate("pplot"); +} + +void IupPPlotOpen(void) +{ + if (!IupGetGlobal("_IUP_PPLOT_OPEN")) + { + iupRegisterClass(iupPPlotGetClass()); + IupSetGlobal("_IUP_PPLOT_OPEN", "1"); + } +} diff --git a/iup/srcpplot/iup_pplot.def b/iup/srcpplot/iup_pplot.def new file mode 100755 index 0000000..8143bab --- /dev/null +++ b/iup/srcpplot/iup_pplot.def @@ -0,0 +1,11 @@ +EXPORTS + IupPPlotOpen + IupPPlot + IupPPlotBegin + IupPPlotAdd + IupPPlotAddStr + IupPPlotEnd + IupPPlotInsertStr + IupPPlotInsert + IupPPlotTransform + IupPPlotPaintTo diff --git a/iup/srcpplot/iup_pplot.dep b/iup/srcpplot/iup_pplot.dep new file mode 100644 index 0000000..6542ce3 --- /dev/null +++ b/iup/srcpplot/iup_pplot.dep @@ -0,0 +1,12 @@ +$(OBJDIR)/iupPPlot.o: iupPPlot.cpp iupPPlot.h +$(OBJDIR)/iupPPlotInteraction.o: iupPPlotInteraction.cpp iupPPlotInteraction.h \ + iupPPlot.h +$(OBJDIR)/iup_pplot.o: iup_pplot.cpp ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h ../include/iup_pplot.h \ + ../../cd/include/cd.h ../../cd/include/cdiup.h \ + ../../cd/include/cddbuf.h ../../cd/include/cdirgb.h \ + ../../cd/include/cdgdiplus.h ../src/iup_class.h ../src/iup_table.h \ + ../src/iup_classbase.h ../src/iup_register.h ../src/iup_object.h \ + ../src/iup_class.h ../src/iup_attrib.h ../src/iup_str.h \ + ../src/iup_drv.h ../src/iup_stdcontrols.h ../src/iup_assert.h \ + iupPPlot.h iupPPlotInteraction.h iuppplot.hpp diff --git a/iup/srcpplot/iuppplot.hpp b/iup/srcpplot/iuppplot.hpp new file mode 100755 index 0000000..62e3db7 --- /dev/null +++ b/iup/srcpplot/iuppplot.hpp @@ -0,0 +1,137 @@ +/* + * IupPPlot component - private include file + * + * Description : A component, derived from PPlot and IUP canvas + * Remark : Depend on libs IUP, CD, IUPCD + */ + + +#ifndef __IUP_PPLOT_H +#define __IUP_PPLOT_H + +/* + PPainterIup class definition +*/ + + +class PostPainterCallbackIup: public PDrawer +{ + public: + PostPainterCallbackIup(PPlot &inPPlot, Ihandle* inHandle); + virtual bool Draw (Painter &inPainter); + protected: + Ihandle *_ih; // IUP handle +}; + +class PrePainterCallbackIup: public PDrawer +{ + public: + PrePainterCallbackIup(PPlot &inPPlot, Ihandle* inHandle); + virtual bool Draw (Painter &inPainter); + protected: + Ihandle *_ih; // IUP handle +}; + +class PDeleteInteractionIup: public PDeleteInteraction +{ + public: + PDeleteInteractionIup(PPlot &inPPlot, Ihandle* inHandle): + PDeleteInteraction(inPPlot), _ih(inHandle) {} + + protected: + Ihandle *_ih; // IUP handle + bool DeleteNotify(int inIndex, int inSampleIndex, PlotDataBase *inXData, PlotDataBase *inYData); +}; + +class PSelectionInteractionIup: public PSelectionInteraction +{ + public: + PSelectionInteractionIup(PPlot &inPPlot, Ihandle* inHandle): + PSelectionInteraction(inPPlot), _ih(inHandle) {} + + protected: + Ihandle *_ih; // IUP handle + bool SelectNotify(int inIndex, int inSampleIndex, PlotDataBase *inXData, PlotDataBase *inYData, bool inSelect); +}; + +class PEditInteractionIup: public PEditInteraction +{ + public: + PEditInteractionIup (PPlot &inPPlot, Ihandle* inHandle): + PEditInteraction(inPPlot), _ih(inHandle) {} + + virtual bool Impl_HandleKeyEvent (const PKeyEvent &inEvent); + virtual bool Impl_Calculate (Painter &inPainter, PPlot& inPPlot); + + protected: + Ihandle *_ih; // IUP handle + void HandleCursorKey (const PlotDataSelection *inPlotDataSelection, PlotDataBase *inXData, PlotDataBase *inYData, int inIndex); + bool EditNotify(int inIndex, int inSampleIndex, float inX, float inY, float *inNewX, float *inNewY); +}; + +class InteractionContainerIup: public InteractionContainer +{ + public: + InteractionContainerIup(PPlot &inPPlot, Ihandle* inHandle); + + PZoomInteraction mZoomInteraction; + PSelectionInteractionIup mSelectionInteraction; + PEditInteractionIup mEditInteraction; + PDeleteInteractionIup mDeleteInteraction; + PCrosshairInteraction mCrosshairInteraction; + + PostPainterCallbackIup mPostPainterCallback; + PrePainterCallbackIup mPrePainterCallback; +}; + +class PPainterIup: public Painter +{ + public: + PPainterIup(Ihandle *ih); + virtual ~PPainterIup(); + cdCanvas *_cdcanvas; /* iup drawing surface */ + cdCanvas *_cddbuffer; /* double buffer drawing surface */ + PPlot _plot; /* plot data holder */ + int _redraw; /* must update the double buffer before flush */ + int _currentDataSetIndex; /* dataset index used for DS_ attributes in SetAttribute and GetAttribute */ + + // Called from C functions + void Draw(int force); // paint the stuff + void Resize(); // called when resizing + void MouseButton(int btn, int stat, int x, int y, char *r); // mouse event + void MouseMove(int x, int y); // mouse event + void KeyPress(int c, int press); // keyboard event + void DrawTo(cdCanvas *usrCnv); // send plot to some user defined device + + protected: + InteractionContainer *_InteractionContainer; + Ihandle *_ih; // IUP handle + short int _mouseDown; + short int _mouse_ALT; + short int _mouse_SHIFT; + short int _mouse_CTRL; + + PPainterIup() { }; + + virtual void FillArrow(int inX1, int inY1, int inX2, int inY2, int inX3, int inY3); + virtual void DrawLine(float inX1, float inY1, float inX2, float inY2); + virtual void FillRect(int inX, int inY, int inW, int inH); + virtual void InvertRect(int inX, int inY, int inW, int inH); + virtual void SetClipRect(int inX, int inY, int inW, int inH); + virtual long GetWidth() const; + virtual long GetHeight() const; + virtual void SetLineColor(int inR, int inG, int inB); + virtual void SetFillColor(int inR, int inG, int inB); + virtual long CalculateTextDrawSize(const char *inString); + virtual long GetFontHeight() const; + virtual void DrawText(int inX, int inY, short align, const char *inString); + virtual void DrawRotatedText(int inX, int inY, float inDegrees, + short align, const char *inString); + virtual void SetStyle(const PStyle &inStyle); + + private: + +}; // PPainterIup + + +#endif /* #ifndef __IUP_PPLOT_HPP */ diff --git a/iup/srcpplot/make_uname b/iup/srcpplot/make_uname new file mode 100755 index 0000000..cc4b881 --- /dev/null +++ b/iup/srcpplot/make_uname @@ -0,0 +1,3 @@ +#This builds all the libraries of the folder for 1 uname + +tecmake $1 $2 $3 $4 $5 $6 $7 diff --git a/iup/srcpplot/make_uname.bat b/iup/srcpplot/make_uname.bat new file mode 100755 index 0000000..f0a0722 --- /dev/null +++ b/iup/srcpplot/make_uname.bat @@ -0,0 +1,4 @@ +@echo off +REM This builds all the libraries of the folder for 1 uname + +call tecmake %1 %2 %3 %4 %5 %6 -- cgit v1.2.3