From 197765d1a4e20631a12cbc09598a245897fc5c52 Mon Sep 17 00:00:00 2001 From: dolik Date: Wed, 1 Dec 2010 12:28:49 +0000 Subject: [PATCH] bazaar: PlotLib,PlotCtrl git-svn-id: svn://ultimatepp.org/upp/trunk@2877 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- bazaar/PlotCtrl/LegendCtrl.cpp | 33 +++ bazaar/PlotCtrl/PlotCtrl.cpp | 158 ++++++++++++ bazaar/PlotCtrl/PlotCtrl.h | 76 ++++++ bazaar/PlotCtrl/PlotCtrl.lay | 34 +++ bazaar/PlotCtrl/PlotCtrl.upp | 15 ++ bazaar/PlotCtrl/PlotDlg.lay | 27 ++ bazaar/PlotCtrl/PlotStyleDlg.cpp | 75 ++++++ bazaar/PlotCtrl/cursors.iml | 11 + bazaar/PlotCtrl/icons.iml | 18 ++ bazaar/PlotCtrl/init | 5 + bazaar/PlotCtrlExample/PlotCtrlExample.upp | 11 + bazaar/PlotCtrlExample/init | 5 + bazaar/PlotCtrlExample/main.cpp | 99 ++++++++ bazaar/PlotCtrlExample/symbol.iml | 16 ++ bazaar/PlotLib/Legend.cpp | 48 ++++ bazaar/PlotLib/Plot.cpp | 281 +++++++++++++++++++++ bazaar/PlotLib/PlotData.cpp | 86 +++++++ bazaar/PlotLib/PlotLib.h | 186 ++++++++++++++ bazaar/PlotLib/PlotLib.upp | 15 ++ bazaar/PlotLib/PlotSymbol.cpp | 61 +++++ bazaar/PlotLib/PlotSymbol.h | 108 ++++++++ bazaar/PlotLib/init | 4 + bazaar/PlotLibExample/PlotLibExample.upp | 13 + bazaar/PlotLibExample/init | 5 + bazaar/PlotLibExample/main.cpp | 66 +++++ bazaar/PlotLibExample/symbol.iml | 16 ++ 26 files changed, 1472 insertions(+) create mode 100644 bazaar/PlotCtrl/LegendCtrl.cpp create mode 100644 bazaar/PlotCtrl/PlotCtrl.cpp create mode 100644 bazaar/PlotCtrl/PlotCtrl.h create mode 100644 bazaar/PlotCtrl/PlotCtrl.lay create mode 100644 bazaar/PlotCtrl/PlotCtrl.upp create mode 100644 bazaar/PlotCtrl/PlotDlg.lay create mode 100644 bazaar/PlotCtrl/PlotStyleDlg.cpp create mode 100644 bazaar/PlotCtrl/cursors.iml create mode 100644 bazaar/PlotCtrl/icons.iml create mode 100644 bazaar/PlotCtrl/init create mode 100755 bazaar/PlotCtrlExample/PlotCtrlExample.upp create mode 100755 bazaar/PlotCtrlExample/init create mode 100755 bazaar/PlotCtrlExample/main.cpp create mode 100644 bazaar/PlotCtrlExample/symbol.iml create mode 100644 bazaar/PlotLib/Legend.cpp create mode 100644 bazaar/PlotLib/Plot.cpp create mode 100644 bazaar/PlotLib/PlotData.cpp create mode 100644 bazaar/PlotLib/PlotLib.h create mode 100644 bazaar/PlotLib/PlotLib.upp create mode 100644 bazaar/PlotLib/PlotSymbol.cpp create mode 100644 bazaar/PlotLib/PlotSymbol.h create mode 100644 bazaar/PlotLib/init create mode 100755 bazaar/PlotLibExample/PlotLibExample.upp create mode 100755 bazaar/PlotLibExample/init create mode 100755 bazaar/PlotLibExample/main.cpp create mode 100755 bazaar/PlotLibExample/symbol.iml diff --git a/bazaar/PlotCtrl/LegendCtrl.cpp b/bazaar/PlotCtrl/LegendCtrl.cpp new file mode 100644 index 000000000..2249adafa --- /dev/null +++ b/bazaar/PlotCtrl/LegendCtrl.cpp @@ -0,0 +1,33 @@ +#include "PlotCtrl.h" + +LegendCtrl::LegendCtrl(Plot& p):Legend(p){ + IgnoreMouse(); + Transparent(); +} + +void LegendCtrl::Paint(Draw& w){ + Legend::SetSize(Ctrl::GetSize()); + if(hash!=Legend::GetHashValue()){ + img=GetLegend(); + if(img.IsEmpty()){ + Refresh(); + Sync(); + return; + }else{ + hash=Legend::GetHashValue(); + WhenSync(); + } + } + w.DrawImage(0,0,img); +} + +Size LegendCtrl::GetSize()const{ + return Ctrl::GetSize(); +} +void LegendCtrl::SetSize(const Size& sz){ + Rect r=GetRect(); + r.SetSize(sz); + SetRect(r); + //Legend::SetSize(sz); +} + diff --git a/bazaar/PlotCtrl/PlotCtrl.cpp b/bazaar/PlotCtrl/PlotCtrl.cpp new file mode 100644 index 000000000..bc3206077 --- /dev/null +++ b/bazaar/PlotCtrl/PlotCtrl.cpp @@ -0,0 +1,158 @@ +#include "PlotCtrl.h" + +#define IMAGECLASS PlotCursors +#define IMAGEFILE +#include + +PlotCtrl::PlotCtrl():tr(*this),mpos(Null),cursor(PC_ARROW){ + tr.sync=THISBACK(TrackerSync); + BackPaint(); +} +PlotCtrl& PlotCtrl::Zoom(double rx,double ry,Pointf C){ + //OverrideCursor(Image::Wait()); + cursor=PC_WAIT; + Rectf g=GetLimits(); + if(C.IsNullInstance()){C=g.CenterPoint();} + SetLimits(RectfC(C.x-rx*(C.x-g.left),C.y-ry*(C.y-g.top),rx*g.Width(),ry*g.Height())); + SetModify(); + Refresh(); + Sync(); + MouseMove(GetMousePos(),0); + return *this; +} +PlotCtrl& PlotCtrl::ZoomIn(double ratio,const Pointf& C){ + return Zoom(1/ratio,1/ratio,C); +} +PlotCtrl& PlotCtrl::ZoomOut(double ratio,const Pointf& C){ + return Zoom(ratio,ratio,C); +} +PlotCtrl& PlotCtrl::ZoomAll(bool visibleonly){ + //OverrideCursor(Image::Wait()); + cursor=PC_WAIT; + Rectf bb=BoundingBox(visibleonly);DUMP(bb); + if(bb.Width()==0||bb.Height()==0){ + SetLimits(-1,1,-1,1);LOG("empty"); + }else{ + SetLimits(bb);LOG("not empty"); + } + SetModify(); + Refresh(); + Sync(); + MouseMove(GetMousePos(),0); + return *this; +} +void PlotCtrl::Layout(){ + SetPlotSize(GetSize()); + SetModify(); +} +void PlotCtrl::Paint(Draw& w){ + if(IsModified()){ + WhenSync(); + img=GetImage(); + if(img.IsEmpty()){ + SetLimits(-1,1,-1,1); + PromptOK("You've reached precision limits.&Zoom setting was reset."); + Refresh(); + Sync(); + return; + }else{ + ClearModify(); + } + } + w.DrawImage(0,0,img); +} +void PlotCtrl::LeftDown(Point pt,dword keyflags){ + if(keyflags&K_SHIFT){ + MiddleDown(pt,keyflags); + }else if(keyflags&K_CTRL){ + ZoomAll(); + }else{ + if(tr.InLoop()){tr.Close();tr.OverrideCursor(Null);} //sometimes RectTracker "forgets" to leave the loop... + Rectf r=tr.Track(RectfC(pt.x,pt.y,0,0),ALIGN_NULL,ALIGN_NULL); + tr.OverrideCursor(Null); + if(r.IsEmpty()){ + ZoomIn(2,ImgToPlot(pt)); + }else{ + SetLimits(ImgToPlot(r)); + } + //OverrideCursor(PlotCursors::cross); + if(CheckRange()){ + SetModify(); + Refresh(); + Sync(); + } + } +} +void PlotCtrl::MouseMove(Point pt, dword keyflags){ + if(!mpos.IsNullInstance()){ + SetLimits(lim); //this is to make ImgToPlot conversion work correctly + SetLimits(lim.Offseted(mpos-ImgToPlot(pt))); + SetModify(); + //OverrideCursor(PlotCursors::pan); + cursor=PC_PAN; + Refresh();Sync(); + return; + } + String pos=ImgToPlotFormatted(pt); + ImageDraw w(15+StrWidth(pos),15+GetFont().GetHeight()); + w.DrawRect(0,0,15+StrWidth(pos),15+GetFont().GetHeight(),Black()); + w.Alpha().DrawRect(0,0,15+StrWidth(pos),15+GetFont().GetHeight(),GrayColor(0)); + w.Alpha().DrawImage(0,0,PlotCursors::cross,GrayColor(255)); + w.Alpha().DrawText(11,11,pos,GetFont(),GrayColor(255)); + ImageBuffer b(w); + b.SetHotSpot(Point(8,8)); + cimg=b; + cursor=PC_LOCAL; +} +void PlotCtrl::RightDown(Point pt,dword keyflags){ + Pointf pf(1.0*pt.x,1.0*pt.y); + ZoomOut(2,ImgToPlot(pt)); + if(!CheckRange()){ + SetModify(); + PromptOK("Oups, you'have reached double precision limits...&Plot changed its zoom settings to avoid freezing application."); + } +} +void PlotCtrl::MouseWheel(Point pt, int zdelta, dword keyflags){ + if(IsModified()) return; // only accept event if ready + if(zdelta<0){ZoomOut(-zdelta/90.0,ImgToPlot(pt));} + else{ZoomIn(zdelta/90.0,ImgToPlot(pt));} +} +void PlotCtrl::MiddleDown(Point pt,dword keyflags){ + mpos=ImgToPlot(pt); + lim=GetLimits(); + cursor=PC_PAN; +} +void PlotCtrl::MiddleUp(Point pt,dword keyflags){ + mpos=Null; + MouseMove(pt,keyflags); +} +void PlotCtrl::LeftUp(Point pt,dword keyflags){ + mpos=Null; + MouseMove(pt,keyflags); +} +void PlotCtrl::MouseLeave(){ + mpos=Null; +} + +void PlotCtrl::TrackerSync(Rect r){ + String pos=ImgToPlotFormatted(r); + Rect t(0,0,15+StrWidth(pos),15+2*GetFont().GetHeight()); + ImageDraw w(t.Width(),t.Height()); + w.DrawRect(t,Black()); + w.Alpha().DrawRect(t,GrayColor(0)); + w.Alpha().DrawImage(0,0,PlotCursors::cross,GrayColor(255)); + w.Alpha().DrawText(11,11,pos,GetFont(),GrayColor(255)); + ImageBuffer b(w); + b.SetHotSpot(Point(8,8)); + tr.OverrideCursor(b); +} + +Image PlotCtrl::CursorImage(Point p, dword keyflags) { + switch (cursor) { + case PC_LOCAL: if(GetShift()) return PlotCursors::pan(); else return cimg; + case PC_PAN: return PlotCursors::pan(); + case PC_CROSS: return PlotCursors::cross(); + case PC_ARROW: return Image::Arrow(); + case PC_WAIT: return Image::Wait(); + } +} \ No newline at end of file diff --git a/bazaar/PlotCtrl/PlotCtrl.h b/bazaar/PlotCtrl/PlotCtrl.h new file mode 100644 index 000000000..7bc8c17fc --- /dev/null +++ b/bazaar/PlotCtrl/PlotCtrl.h @@ -0,0 +1,76 @@ +#ifndef _PlotCtrl_PlotCtrl_h +#define _PlotCtrl_PlotCtrl_h + +#include +#include + +#define LAYOUTFILE +#include + +using namespace Upp; + +class PlotCtrl : public Ctrl, public Plot{ +public: + typedef PlotCtrl CLASSNAME; + PlotCtrl(); + PlotCtrl& Zoom(double rx,double ry,Pointf C=Null); + PlotCtrl& ZoomIn(double ratio=2,const Pointf& C=Null); + PlotCtrl& ZoomOut(double ratio=2,const Pointf& C=Null); + PlotCtrl& ZoomAll(bool visibleonly=false); + virtual void Layout(); + virtual void Paint(Draw& w); + virtual void LeftDown(Point pt,dword keyflags); + virtual void LeftUp(Point pt,dword keyflags); + virtual void RightDown(Point pt,dword keyflags); + virtual void MouseMove(Point pt, dword keyflags); + virtual void MiddleDown(Point pt,dword keyflags); + virtual void MiddleUp(Point pt,dword keyflags); + virtual void MouseLeave(); + virtual void MouseWheel(Point pt, int zdelta, dword keyflags); + virtual Image CursorImage(Point p, dword keyflags); + Callback WhenSync; + void TrackerSync(Rect r); +protected: + RectTracker tr; + Image img; + Pointf mpos; + Rectf lim; +private: + enum{PC_CROSS,PC_ARROW,PC_PAN,PC_WAIT,PC_LOCAL}; + int cursor; + Image cimg; +}; + +class LegendCtrl : public Ctrl, public Legend{ +public: + typedef LegendCtrl CLASSNAME; + LegendCtrl(Plot& p); + Callback WhenSync; + virtual void Paint(Draw& w); + void SetSize(const Size& sz); + Size GetSize()const; +protected: + unsigned hash; + Image img; +}; + +class PlotStyleDlg : public WithStyleDlg{ +public: + typedef PlotStyleDlg CLASSNAME; + PlotStyleDlg(PlotCtrl& parent,int index=0); +private: + PlotCtrl& p; + void Change(); + void UpdateFields(); + void Rename(); + class RenameDlg:public WithRenameDlg{ + PlotCtrl& p; + int idx; + public: + typedef RenameDlg CLASSNAME; + RenameDlg(PlotCtrl& plot,int index); + void Update(); + }; +}; + +#endif diff --git a/bazaar/PlotCtrl/PlotCtrl.lay b/bazaar/PlotCtrl/PlotCtrl.lay new file mode 100644 index 000000000..15483cd46 --- /dev/null +++ b/bazaar/PlotCtrl/PlotCtrl.lay @@ -0,0 +1,34 @@ +LAYOUT(StyleDlg, 280, 204) + ITEM(Label, dv___0, SetLabel(t_("Series:")).LeftPosZ(4, 52).TopPosZ(8, 19)) + ITEM(DropList, series, HSizePosZ(60, 76).TopPosZ(8, 19)) + ITEM(Button, btn, SetLabel(t_("Done")).Tip(t_("Close this dialog")).RightPosZ(4, 60).TopPosZ(180, 19)) + ITEM(LabelBox, dv___3, SetLabel(t_("Symbol")).HSizePosZ(4, 4).TopPosZ(32, 84)) + ITEM(Label, dv___4, SetLabel(t_("Symbol:")).HSizePosZ(12, 224).TopPosZ(48, 19)) + ITEM(DropList, symbol, HSizePosZ(60, 76).TopPosZ(48, 19)) + ITEM(Label, dv___6, SetLabel(t_("Color:")).HSizePosZ(12, 236).TopPosZ(72, 19)) + ITEM(ColorPusher, scol, HSizePosZ(52, 208).TopPosZ(72, 19)) + ITEM(Label, dv___8, SetLabel(t_("Frame:")).HSizePosZ(80, 164).TopPosZ(72, 19)) + ITEM(ColorPusher, frame, HSizePosZ(120, 140).TopPosZ(72, 19)) + ITEM(Label, dv___10, SetLabel(t_("Thickness:")).HSizePosZ(148, 80).TopPosZ(72, 19)) + ITEM(EditDoubleSpin, sthick, SetInc(0.5).Min(0.0001).NotNull(true).HSizePosZ(204, 8).TopPosZ(72, 19)) + ITEM(Label, dv___12, SetLabel(t_("Size:")).HSizePosZ(12, 236).TopPosZ(92, 19)) + ITEM(EditDoubleSpin, sizex, SetInc(0.5).Min(0).NotNull(true).HSizePosZ(52, 180).TopPosZ(92, 19)) + ITEM(Label, dv___14, SetLabel(t_("x")).HSizePosZ(104, 164).TopPosZ(92, 19)) + ITEM(EditDoubleSpin, sizey, SetInc(0.5).Min(0).NotNull(true).HSizePosZ(116, 116).TopPosZ(92, 19)) + ITEM(LabelBox, dv___16, SetLabel(t_("Line:")).HSizePosZ(4, 4).TopPosZ(120, 56)) + ITEM(Label, dv___17, SetLabel(t_("Color:")).HSizePosZ(12, 216).TopPosZ(132, 19)) + ITEM(ColorPusher, col, HSizePosZ(68, 192).TopPosZ(132, 19)) + ITEM(Option, vis, SetLabel(t_("Visible")).HSizePosZ(148, 76).TopPosZ(132, 16)) + ITEM(EditString, dash, HSizePosZ(68, 144).TopPosZ(152, 19)) + ITEM(Label, dv___21, SetLabel(t_("Dash:")).HSizePosZ(12, 216).TopPosZ(152, 19)) + ITEM(Label, dv___22, SetLabel(t_("Thickness:")).HSizePosZ(148, 80).TopPosZ(152, 19)) + ITEM(EditDoubleSpin, thick, Min(0.0001).NotNull(true).HSizePosZ(204, 8).TopPosZ(152, 19)) + ITEM(Button, rename, SetLabel(t_("Rename...")).Tip(t_("Rename currently selected series")).LeftPosZ(216, 60).TopPosZ(8, 19)) +END_LAYOUT + +LAYOUT(RenameDlg, 424, 28) + ITEM(Label, dv___0, SetLabel(t_("New name:")).LeftPosZ(4, 60).TopPosZ(4, 21)) + ITEM(EditString, name, HSizePosZ(68, 56).TopPosZ(4, 21)) + ITEM(Button, ok, SetLabel(t_("OK")).RightPosZ(4, 48).TopPosZ(4, 21)) +END_LAYOUT + diff --git a/bazaar/PlotCtrl/PlotCtrl.upp b/bazaar/PlotCtrl/PlotCtrl.upp new file mode 100644 index 000000000..d847b50e3 --- /dev/null +++ b/bazaar/PlotCtrl/PlotCtrl.upp @@ -0,0 +1,15 @@ +description "Widget for plotting graphs\377"; + +uses + Painter, + PlotLib; + +file + PlotCtrl.h, + PlotStyleDlg.cpp, + PlotCtrl.cpp, + LegendCtrl.cpp, + PlotCtrl.lay, + cursors.iml, + icons.iml; + diff --git a/bazaar/PlotCtrl/PlotDlg.lay b/bazaar/PlotCtrl/PlotDlg.lay new file mode 100644 index 000000000..cf77f4c15 --- /dev/null +++ b/bazaar/PlotCtrl/PlotDlg.lay @@ -0,0 +1,27 @@ +LAYOUT(StyleDlg, 280, 180) + ITEM(Label, dv___0, SetLabel(t_("Series:")).LeftPosZ(4, 52).TopPosZ(8, 19)) + ITEM(DropList, series, HSizePosZ(60, 68).TopPosZ(8, 19)) + ITEM(Button, btn, SetLabel(t_("Done")).RightPosZ(4, 60).TopPosZ(8, 19)) + ITEM(LabelBox, dv___3, SetLabel(t_("Symbol")).HSizePosZ(4, 4).TopPosZ(32, 84)) + ITEM(Label, dv___4, SetLabel(t_("Symbol:")).HSizePosZ(12, 224).TopPosZ(48, 19)) + ITEM(DropList, symbol, HSizePosZ(64, 72).TopPosZ(48, 19)) + ITEM(Label, dv___6, SetLabel(t_("Color:")).HSizePosZ(12, 236).TopPosZ(72, 19)) + ITEM(ColorPusher, scol, HSizePosZ(52, 208).TopPosZ(72, 19)) + ITEM(Label, dv___8, SetLabel(t_("Frame:")).HSizePosZ(80, 164).TopPosZ(72, 19)) + ITEM(ColorPusher, frame, HSizePosZ(120, 140).TopPosZ(72, 19)) + ITEM(Label, dv___10, SetLabel(t_("Thickness:")).HSizePosZ(148, 80).TopPosZ(72, 19)) + ITEM(EditDoubleSpin, sthick, SetInc(0.5).Min(0.0001).NotNull(true).HSizePosZ(204, 8).TopPosZ(72, 19)) + ITEM(Label, dv___12, SetLabel(t_("Size:")).HSizePosZ(12, 236).TopPosZ(92, 19)) + ITEM(EditDoubleSpin, sizex, SetInc(0.5).Min(0).NotNull(true).HSizePosZ(52, 144).TopPosZ(92, 19)) + ITEM(Label, dv___14, SetLabel(t_("x")).HSizePosZ(140, 128).TopPosZ(92, 19)) + ITEM(EditDoubleSpin, sizey, SetInc(0.5).Min(0).NotNull(true).HSizePosZ(156, 40).TopPosZ(92, 19)) + ITEM(LabelBox, dv___16, SetLabel(t_("Line:")).HSizePosZ(4, 4).TopPosZ(120, 56)) + ITEM(Label, dv___17, SetLabel(t_("Color:")).HSizePosZ(12, 216).TopPosZ(132, 19)) + ITEM(ColorPusher, col, HSizePosZ(68, 192).TopPosZ(132, 19)) + ITEM(Option, vis, SetLabel(t_("Visible")).HSizePosZ(148, 76).TopPosZ(132, 16)) + ITEM(EditString, dash, HSizePosZ(68, 144).TopPosZ(152, 19)) + ITEM(Label, dv___21, SetLabel(t_("Dash:")).HSizePosZ(12, 216).TopPosZ(152, 19)) + ITEM(Label, dv___22, SetLabel(t_("Thickness:")).HSizePosZ(148, 80).TopPosZ(152, 19)) + ITEM(EditDoubleSpin, thick, Min(0.0001).NotNull(true).HSizePosZ(204, 8).TopPosZ(152, 19)) +END_LAYOUT + diff --git a/bazaar/PlotCtrl/PlotStyleDlg.cpp b/bazaar/PlotCtrl/PlotStyleDlg.cpp new file mode 100644 index 000000000..7a4d8bec3 --- /dev/null +++ b/bazaar/PlotCtrl/PlotStyleDlg.cpp @@ -0,0 +1,75 @@ +#include "PlotCtrl.h" + +PlotStyleDlg::PlotStyleDlg(PlotCtrl& parent,int index):p(parent){ + CtrlLayout(*this); + for(int i=0; iGetType()); + scol<<=Color(symb->GetColor()); + frame<<=Color(symb->GetFrameColor()); + sthick<<=symb->GetThickness()>0?symb->GetThickness():1; + sizex<<=symb->GetSize().cx; + sizey<<=symb->GetSize().cy; + col<<=Color(sel.GetColor()); + vis<<=sel.IsVisible(); + dash<<=sel.GetDash(); + thick<<=sel.GetThickness()>0?sel.GetThickness():1; +} + +PlotStyleDlg::RenameDlg::RenameDlg(PlotCtrl& plot,int index):p(plot),idx(index){ + CtrlLayout(*this); + name<<=p.data[idx].GetTitle(); + name.SetSelection(); + name<<=THISBACK(Update); + ok<<=THISBACK(Close); +} + +void PlotStyleDlg::RenameDlg::Update(){ + p.data[idx].SetTitle(~name); + p.SetModify(); + p.Refresh(); +} + diff --git a/bazaar/PlotCtrl/cursors.iml b/bazaar/PlotCtrl/cursors.iml new file mode 100644 index 000000000..5175ccfe1 --- /dev/null +++ b/bazaar/PlotCtrl/cursors.iml @@ -0,0 +1,11 @@ +PREMULTIPLIED +IMAGE_ID(cross) +IMAGE_ID(crossPlus) +IMAGE_ID(pan) + +IMAGE_BEGIN_DATA +IMAGE_DATA(120,156,99,224,103,224,103,96,135,66,2,224,63,33,5,163,122,233,2,254,99,193,200,114,196,168,27,76,96,40,198,47) +IMAGE_DATA(237,244,226,200,144,216,52,17,235,8,114,244,18,155,200,168,109,47,53,244,210,27,140,102,200,225,172,87,128,129,7,152) +IMAGE_DATA(21,217,192,24,135,230,255,36,176,81,244,30,132,2,98,217,104,230,145,163,159,100,61,196,232,39,6,12,54,253,164,2) +IMAGE_DATA(42,233,103,32,199,12,44,233,135,104,51,112,164,61,148,116,68,0,195,1,0,121,237,195,30,0,0,0,0,0,0,0) +IMAGE_END_DATA(128, 3) diff --git a/bazaar/PlotCtrl/icons.iml b/bazaar/PlotCtrl/icons.iml new file mode 100644 index 000000000..ab362657a --- /dev/null +++ b/bazaar/PlotCtrl/icons.iml @@ -0,0 +1,18 @@ +PREMULTIPLIED +IMAGE_ID(Graph) +IMAGE_ID(AddGraph) +IMAGE_ID(RemoveGraph) + +IMAGE_BEGIN_DATA +IMAGE_DATA(120,156,237,148,191,138,2,49,16,198,183,183,17,31,65,4,65,176,63,176,179,179,83,124,10,95,71,11,45,45,60,69) +IMAGE_DATA(68,100,107,139,180,214,234,93,181,96,175,224,35,204,156,179,176,127,146,76,76,86,3,114,104,96,88,146,205,239,75,102) +IMAGE_DATA(146,124,65,57,40,7,158,27,190,154,199,198,83,26,197,121,33,205,47,198,11,109,110,220,207,107,124,53,118,152,132,133) +IMAGE_DATA(77,249,68,67,101,210,190,144,245,57,158,198,217,92,204,108,202,231,199,37,13,145,253,103,216,120,58,55,30,107,240,249) +IMAGE_DATA(58,241,196,146,134,195,217,200,188,208,215,181,232,100,245,181,236,55,209,81,180,240,193,120,190,125,204,192,3,255,63,204) +IMAGE_DATA(192,245,66,153,204,0,239,53,149,103,204,64,155,111,226,77,38,225,131,231,242,190,203,103,143,218,121,125,133,43,188,127) +IMAGE_DATA(83,56,214,223,212,236,231,255,49,3,15,252,155,152,193,242,22,191,147,137,116,9,127,198,99,92,181,90,160,242,156,25) +IMAGE_DATA(16,251,93,169,192,97,52,138,217,253,112,136,97,183,11,120,189,58,63,102,98,103,165,18,132,189,30,108,58,29,192,243) +IMAGE_DATA(185,152,153,156,78,184,168,215,129,114,137,166,83,187,153,228,205,32,138,112,94,171,193,186,221,6,188,92,144,214,79,114) +IMAGE_DATA(209,234,199,152,193,188,90,133,69,179,153,238,153,190,219,193,64,203,223,20,97,191,15,106,253,137,197,227,209,139,25,252) +IMAGE_DATA(1,87,169,115,235,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) +IMAGE_END_DATA(352, 3) diff --git a/bazaar/PlotCtrl/init b/bazaar/PlotCtrl/init new file mode 100644 index 000000000..8be8c4c97 --- /dev/null +++ b/bazaar/PlotCtrl/init @@ -0,0 +1,5 @@ +#ifndef _PlotCtrl_icpp_init_stub +#define _PlotCtrl_icpp_init_stub +#include "Painter/init" +#include "PlotLib/init" +#endif diff --git a/bazaar/PlotCtrlExample/PlotCtrlExample.upp b/bazaar/PlotCtrlExample/PlotCtrlExample.upp new file mode 100755 index 000000000..c9b517339 --- /dev/null +++ b/bazaar/PlotCtrlExample/PlotCtrlExample.upp @@ -0,0 +1,11 @@ +uses + CtrlLib, + PlotCtrl; + +file + main.cpp, + symbol.iml; + +mainconfig + "" = "GUI"; + diff --git a/bazaar/PlotCtrlExample/init b/bazaar/PlotCtrlExample/init new file mode 100755 index 000000000..f30eeb2be --- /dev/null +++ b/bazaar/PlotCtrlExample/init @@ -0,0 +1,5 @@ +#ifndef _PlotCtrlExample_icpp_init_stub +#define _PlotCtrlExample_icpp_init_stub +#include "CtrlLib/init" +#include "PlotCtrl/init" +#endif diff --git a/bazaar/PlotCtrlExample/main.cpp b/bazaar/PlotCtrlExample/main.cpp new file mode 100755 index 000000000..3d442cc29 --- /dev/null +++ b/bazaar/PlotCtrlExample/main.cpp @@ -0,0 +1,99 @@ +#include +#include +using namespace Upp; + +#define IMAGECLASS Symbol +#define IMAGEFILE +#include + +// If you wish, you can define virtualy anything as symbol, just use the WithPlotSymbol +// template, which will setup almost everything for you and override the PaintOp method +class Bug: public WithPlotSymbol{ +public: + virtual void PaintOp(Painter& sw)const{ + sw.Rectangle(0,0,s.cx,s.cy).Fill(Symbol::bug(),0,0,s.cx,0); + } + Bug(){s=Sizef(11,11);}; +}; + +class PlotWindow : public TopWindow{ +public: + typedef PlotWindow CLASSNAME; + PlotCtrl plot; + LegendCtrl legend; + PlotWindow():legend(plot){ + Sizeable().Title("PlotCtrl Example").SetRect(200,200,640,480); + plot.SetMode(PLOT_AA).SetLimits(-4,4,-4,4); + Add(plot.HSizePos(0,0).VSizePos(0,0)); + legend.SetRect(60,10,1,1); // We adjust the size later, when we know how much space it needs + legend.SetBackground(White()); + legend.WhenSync=THISBACK(ResizeLegend); + Add(legend); + // alternative styles are up to your imagination, e.g.: +// plot.SetBackground(Color(0x444444,0)).SetFrameColor(Color(0x660000,0)) +// .SetFontColor(White()).SetAxisColor(LtGreen()); +// legend.SetFrameColor(LtGreen()).SetBackground(Color(0x666666,0)); + } + void ResizeLegend(){ + legend.SetSize(legend.GetSizeHint()); + } + bool Key(dword keys, int count){ + if (keys==K_CTRL_A){ + plot.ZoomAll(true); + return true; + } + if (keys==K_CTRL_L){ + if(legend.IsShown()){legend.Hide();} + else{legend.Show();} + return true; + } + if (keys==K_CTRL_O){ + PlotStyleDlg(plot).Run(); + return true; + } + return false; + } +}; + +GUI_APP_MAIN{ + PlotWindow p; + // Register your PlotSymbol. This is not mandatory, + // it only makes the symbol appear in PlotStyleDlg + PlotSymbol::Register("Ladybug"); + + // You can create your data directly in plot ... + p.plot.data.Add(); + p.plot.data[0].SetColor(LtRed()).SetTitle("Butterfly Curve"); + for(double t = -12*M_PI; t <= 12*M_PI; t+=0.02){ + double r=(exp(cos(t))-2*cos(4*t)+pow(sin(t/12),5)); + p.plot.data[0].AddXY(r*sin(t),r*cos(t)); + } + + // ... or take your data from elsewhere and copy them in plot. Supported types are + // Vector, VectorMap, and Vector of reasonable formats (i.e. convertable + // to double) + the same containers in Array flavor + VectorMap v; + for(double x = -4; x <= 4; x+=0.05){ + v.Add(x,4*exp(-0.25*x*x)*sin(10*x)); + } + p.plot.data.Add(v); + p.plot.data[1].SetDash("1.5").SetTitle("4*exp(-x^2/4)*sin(10*x)").SetThickness(1.5) + .SetSymbol("Cross",Size(9,9),Black()); + v.Clear(); + + // random Ladybugs! :-) + PlotData dataset; + for(double x = -4; x <= 4; x+=0.5){ + dataset.AddXY(x,int(Random(7))-3); + } + p.plot.data.Add(dataset); + p.plot.data[2].SetColor(Green()).SetTitle("Totally random") + .SetThickness(2).SetSymbol("Ladybug"); + + // And now, just start the gui and watch what you painted... + p.Run(); + + // If you want to take a "screenshot", nothing is easier. Just call GetImage() + // and you'll get current view (well, last view in this example, but you get the idea ;-) ) + PNGEncoder().SaveFile(GetHomeDirFile("plot.png"), p.plot.GetImage()); +} diff --git a/bazaar/PlotCtrlExample/symbol.iml b/bazaar/PlotCtrlExample/symbol.iml new file mode 100644 index 000000000..398487b01 --- /dev/null +++ b/bazaar/PlotCtrlExample/symbol.iml @@ -0,0 +1,16 @@ +PREMULTIPLIED +IMAGE_ID(bug) + +IMAGE_BEGIN_DATA +IMAGE_DATA(120,156,149,84,177,106,195,48,16,213,40,60,41,6,79,198,83,49,116,42,25,179,246,195,187,150,76,165,80,40,136,78) +IMAGE_DATA(198,171,200,20,180,94,223,139,159,64,184,137,155,8,30,39,157,238,222,61,201,58,187,157,219,185,59,134,7,6,32,2) +IMAGE_DATA(159,64,11,244,43,120,197,246,218,247,85,46,215,35,240,13,28,128,23,197,5,160,3,222,133,94,57,71,173,89,179,7) +IMAGE_DATA(193,8,130,136,205,4,156,100,103,250,176,183,71,204,135,248,215,186,70,236,71,56,103,108,38,8,207,128,17,95,178,40) +IMAGE_DATA(146,81,228,204,24,191,112,20,221,23,237,244,65,96,66,156,225,240,246,3,56,33,86,243,194,213,56,55,73,55,207,214) +IMAGE_DATA(50,31,139,9,2,243,181,188,122,142,24,67,172,249,37,150,60,207,188,135,182,210,94,98,143,170,89,206,18,53,87,190) +IMAGE_DATA(121,239,173,105,154,12,75,30,222,95,162,6,92,150,61,9,99,197,135,15,98,7,105,104,229,67,190,113,192,206,188,79) +IMAGE_DATA(28,232,21,130,206,177,170,93,107,162,31,197,12,49,22,228,11,33,88,215,117,180,23,14,234,64,92,158,171,60,206,147) +IMAGE_DATA(144,133,184,161,227,63,142,147,108,220,184,143,242,93,10,79,18,199,35,223,165,188,143,97,209,179,201,113,235,125,60,240) +IMAGE_DATA(78,169,33,35,102,242,75,126,253,78,239,237,23,190,113,214,223,175,122,246,90,223,6,245,212,65,125,59,86,125,53,168) +IMAGE_DATA(222,27,208,184,219,131,124,252,95,68,247,87,115,249,47,212,53,221,47,83,163,251,76,0,0,0,0,0,0,0,0,0) +IMAGE_END_DATA(352, 1) diff --git a/bazaar/PlotLib/Legend.cpp b/bazaar/PlotLib/Legend.cpp new file mode 100644 index 000000000..0e46a11bc --- /dev/null +++ b/bazaar/PlotLib/Legend.cpp @@ -0,0 +1,48 @@ +#include "PlotLib.h" + +Legend::Legend(Plot& plot): + p(plot),fwidth(1),framecol(Black()),bgcol(RGBAZero()){size=GetSizeHint();} + +Legend::Legend(Plot& plot,RGBA frame,RGBA background,double width): + p(plot),fwidth(width),framecol(frame),bgcol(background){size=GetSizeHint();} + +Size Legend::GetSizeHint()const{ + int maxlen=0; + int vis=0; + for(int i=0; iPaint(bp,Pointf(25,y-h*0.5)); + } + } + return ib; +} + +unsigned Legend::GetHashValue()const{ + CombineHash hash; + hash<2)&(s<=5)){s=5;} + else if((s>1)&(s<=2)){s=2;} + else if((s>5)&(s<=10)){s=1;e++;} + else {s=1;} +} +bool Plot::Axes(Painter& sw){ + String str="×10"; + int fh=f.GetHeight(); + int e; + double d,s; + //Ticks X + s=g.Width()/p.Width()*spaceH; //step based on axis length and spacing + NormalizeStep(s,e); // makes step s 1,2 or 5; e is order of magnitude + if(fabs(log10(fabs(g.left-g.right))-e)>16){ + //TODO: find correct check + g.SetSize(0,0); + CheckRange(); + return false; + } + sx=ipow10(-e); + d=s*ipow10(e); //full value of step + for(double x=ceil(g.left/d)*s; x<=g.right*sx; x+=s){TickH(x,e,sw);} + //Scale X + sw.DrawText(p.right+spaceH/2,p.bottom+6,str,f,fontcol); + sw.DrawText(p.right+spaceH/2+StrWidth(str)-2,p.bottom+4,IntStr(e),f.Height(fh*0.6),fontcol); + f.Height(fh); + //Ticks Y + s=g.Height()/p.Height()*fh*2; + NormalizeStep(s,e); + if(fabs(log10(fabs(g.top-g.bottom))-e)>16){ + //TODO: find correct check + g.SetSize(0,0); + CheckRange(); + return false; + } + sy=ipow10(-e); + d=s*ipow10(e); + for(double y=ceil(g.top/d)*s; y<=g.bottom*sy; y+=s){TickV(y,e,sw);} + //Scale y + sw.DrawText(5,margin,str,f,fontcol); + sw.DrawText(5+StrWidth(str)-2,margin-2,IntStr(e),f.Height(fh*0.6),fontcol); + f.Height(fh); + //Frame + Rect t=p.Inflated(1); + sw.DrawRect(t.left,t.bottom,p.Width()+5,-1,axiscol); + sw.DrawRect(t.left,t.bottom,1,-p.Height()-5,axiscol); + sw.DrawLine(t.left+p.Width()+6,p.bottom,t.left+p.Width()+2,p.bottom+4,1,axiscol); + sw.DrawLine(t.left+p.Width()+6,p.bottom,t.left+p.Width()+2,p.bottom-3,1,axiscol); + sw.DrawLine(p.left-1,p.bottom-p.Height()-4,p.left+3,p.bottom-p.Height(),1,axiscol); + sw.DrawLine(p.left,p.bottom-p.Height()-4,p.left-4,p.bottom-p.Height(),1,axiscol); + return true; +} +void Plot::PaintData(const PlotData& data,Painter& sw){ + if(data.visible&&data.GetCount()>=2){ + sw.Move(S(data[0])); + for(int i=1;iGetSize().cx>0&&data.symbol->GetSize().cy>0){ + for(int i = 0; i < data.GetCount(); i++){ + if(g.Contains(data[i])){data.symbol->Paint(sw,S(data[i]));} + } + } + } +} +int Plot::LineClip(double& x1, double& y1, double& x2, double& y2)const{ + int r=0; + if(y1>g.bottom){ + if(y2>g.bottom) return -1; //no intersect + x1=(x2-x1)*(g.bottom-y1)/(y2-y1)+x1; + y1=g.bottom; + r=1; // 1st endpoint below viewport + }else if(y1g.bottom){ + x2=(x2-x1)*(g.bottom-y1)/(y2-y1)+x1; + y2=g.bottom; + r|=2; // 2nd endpoint below viewport + }else if(y2g.right){ + y2=(y2-y1)*(g.right-x1)/(x2-x1)+y1; + x1=g.left; + x2=g.right; + return 3; // both endpoints outside + } + x1=g.left; + return r|1; // 1st endpoint outside + }else if(x1>g.right){ + if(x2>g.right) return -1; //no intersect + y1=(y2-y1)*(g.right-x1)/(x2-x1)+y1; + if(x2g.right){ + y2=(y2-y1)*(g.right-x1)/(x2-x1)+y1; + x2=g.right; + return r|2; // 2nd endpoint outside + } + return r; //depends on data gathered during clipping +} +//#include +Image Plot::GetImage(){ + ImageBuffer ib(size); + BufferPainter bp(ib, mode); + bp.Clear(framecol); + bp.DrawRect(p,bgcol); + if(!Axes(bp)){LOG("Axes failed");return Image();} // something is wrong with limits, let user deal with it ;-) + bp.Offset(p.TopLeft()); + for(int i=0; iGetHashValue():(unsigned)0); + } + return hash; +} diff --git a/bazaar/PlotLib/PlotData.cpp b/bazaar/PlotLib/PlotData.cpp new file mode 100644 index 000000000..3188b17a8 --- /dev/null +++ b/bazaar/PlotLib/PlotData.cpp @@ -0,0 +1,86 @@ +#include "PlotLib.h" + +/* PlotData */ + +PlotData& PlotData::SetSymbol(String Symbol,Sizef size,RGBA color,RGBA frame,double thickness){ + symbol=PlotSymbol::Create(PlotSymbol::TypeIndex(Symbol)); + if(size.cx<0||size.cy<0){size.cx=size.cy=0;} + if(symbol->GetThickness()<0){thickness=1;} + symbol->SetSize(size).SetColor(color).SetFrameColor(frame).SetThickness(thickness); + return *this; +} +PlotData& PlotData::SetSymbol(String Symbol){ + symbol=PlotSymbol::Create(PlotSymbol::TypeIndex(Symbol)); + if(symbol->GetSize().cx<0||symbol->GetSize().cy<0){symbol->SetSize(Sizef(0,0));} + if(symbol->GetThickness()<0){symbol->SetThickness(1);} + return *this; +} +PlotData& PlotData::SetSymbol(PlotSymbol* Symbol){ + symbol=Symbol->Copy(); + return *this; +} + +Image PlotData::GetIcon(){ + ImageBuffer ib(40,20); + BufferPainter bp(ib); + bp.Clear(White()); + bp.Dash(dash).DrawLine(0,20,40,0,t,color); + if(symbol){ + symbol->Paint(bp,Pointf(20,10)); + } + return ib; +} +void PlotData::AddXY(double x,double y){Vector::Add(Pointf(x,y));} + +String PlotData::ToString()const{ + return title+(visible?" (visible) ":" (invisible) "); +} + +PlotData::PlotData(){ + SetDefaults(); +} +PlotData::PlotData(const PlotData& pd,int): + Vector(pd,1), + color(pd.color), + t(pd.t), + dash(pd.dash), + title(pd.title), + visible(pd.visible), + BB(pd.BB) +{ + symbol=pd.symbol->Copy(); +} + +PlotData::PlotData(const Vector& data,const char* name){ + SetDefaults(); + SetCount(data.GetCount()); + for(int i=0;i& data,const char* name){ + SetDefaults(); + SetCount(data.GetCount()); + for(int i=0;i +using namespace Upp; + +#include "PlotSymbol.h" + +enum{ + PLOT_AA = MODE_ANTIALIASED, + PLOT_NOAA = MODE_NOAA, + PLOT_SUBPIXEL = MODE_SUBPIXEL +}; +class Plot; + +class PlotData:public Vector, public MoveableAndDeepCopyOption{ +protected: + RGBA color; + double t; + String dash,title; + bool visible; + Rectf BB; + void RefreshBB(); + One symbol; +public: + PlotData& SetColor(RGBA col) {color=col; return *this;} + PlotData& Visible(bool vis) {visible=vis; return *this;} + PlotData& Invisible() {visible=false; return *this;} + PlotData& SetDash(String pattern) {dash=pattern; return *this;} + PlotData& SetTitle(String str) {title=str; return *this;} + PlotData& SetThickness(double thickness){t=thickness; return *this;} + + RGBA GetColor()const {return color; } + bool IsVisible()const {return visible; } + String GetDash()const {return dash; } + String GetTitle()const {return title; } + double GetThickness()const {return t; } + PlotSymbol* GetSymbol() {return ~symbol; } + + PlotData& SetDefaults(); + PlotData& SetSymbol(String symbol,Sizef size,RGBA color=RGBAZero(),RGBA frame=RGBAZero(),double thickness=1); + PlotData& SetSymbol(String symbol); + PlotData& SetSymbol(PlotSymbol* symbol); + void AddXY(double x,double y); + Image GetIcon(); + String ToString()const; + friend class Legend; + friend class Plot; + PlotData(); + PlotData(const PlotData& pd,int); + PlotData(const Vector& data,const char* name=""); + PlotData(const Array& data,const char* name=""); + template + PlotData(const Vector& data,const char* name=""){ + SetDefaults(); + SetCount(data.GetCount()); + for(int i=0;i + PlotData(const Array& data,const char* name=""){ + SetDefaults(); + SetCount(data.GetCount()); + for(int i=0;i + PlotData(const VectorMap& data,const char* name=""){ + SetDefaults(); + SetCount(data.GetCount()); + for(int i=0;i + PlotData(const ArrayMap& data,const char* name=""){ + SetDefaults(); + SetCount(data.GetCount()); + for(int i=0;i data; + + Plot& SetLimits(const Rectf& rect) {return SetLimits(rect.left,rect.right,rect.top,rect.bottom);} + Plot& SetLimits(double x_min,double x_max,double y_min,double y_max); + Plot& SetFont(const Font& font) {f=font; return *this;} + Plot& SetBackground(const Color& c) {bgcol=c; return *this;} + Plot& SetFrameColor(const Color& c) {framecol=c; return *this;} + Plot& SetFontColor(const Color& c) {fontcol=c; return *this;} + Plot& SetAxisColor(const Color& c) {axiscol=c; return *this;} + Plot& SetMode(int quality) {mode=quality; return *this;} + Plot& SetPlotSize(double cx,double cy) {return SetPlotSize(Size(cx,cy));} + Plot& SetPlotSize(const Size& sz); + + Rectf GetLimits()const {return g;} + Font GetFont()const {return f;} + Color GetBackground()const {return bgcol;} + Color GetFrameColor()const {return framecol;} + Color GetFontColor()const {return fontcol;} + Color GetAxisColor()const {return axiscol;} + Size GetPlotSize()const {return size;} + + Rectf BoundingBox(bool visibleonly=false); + + Image GetImage(); + bool CheckRange()const; + String ImgToPlotFormatted(const Point& X)const; + String ImgToPlotFormatted(const Rect& X)const; + int StrWidth(const char *str)const; + Pointf ImgToPlot(const Pointf& X)const; + Rectf ImgToPlot(const Rectf& X)const; + Pointf PlotToImg(const Pointf& X)const; + Rectf PlotToImg(const Rectf& X)const; + unsigned GetHashValue()const; + friend class Legend; +private: + int mode; + double sx,sy; + Rectf g; + Rect p; + Font f; + FontInfo fi; + Size size; + Color bgcol,framecol,fontcol,axiscol; + int marginB,marginL,marginR,marginT,margin,spaceH; + double Gx(double x)const; + double Gy(double y)const; + Pointf G(Pointf X)const; + Rectf G(Rectf X)const; + double Sx(double x)const; + double Sy(double y)const; + Pointf S(Pointf X)const; + Rectf S(Rectf X)const; + void TickH(double x,int e,Painter& sw); + void TickV(double y,int e,Painter& sw); + void NormalizeStep(double& s,int& e)const; + bool Axes(Painter& sw); + void PaintData(const PlotData& data,Painter& sw); + int LineClip(double& x1, double& y1, double& x2, double& y2)const; +}; + +#endif + diff --git a/bazaar/PlotLib/PlotLib.upp b/bazaar/PlotLib/PlotLib.upp new file mode 100644 index 000000000..14d9ebcae --- /dev/null +++ b/bazaar/PlotLib/PlotLib.upp @@ -0,0 +1,15 @@ +description "General charting library\377"; + +optimize_speed; + +uses + Painter; + +file + PlotLib.h, + PlotSymbol.h, + PlotSymbol.cpp, + PlotData.cpp, + Legend.cpp, + Plot.cpp optimize_speed; + diff --git a/bazaar/PlotLib/PlotSymbol.cpp b/bazaar/PlotLib/PlotSymbol.cpp new file mode 100644 index 000000000..383175a0f --- /dev/null +++ b/bazaar/PlotLib/PlotSymbol.cpp @@ -0,0 +1,61 @@ +#include "PlotSymbol.h" + +PlotSymbol::PlotSymbol(): + s(0,0), + c(RGBAZero()), + f(RGBAZero()), + t(0) +{ + paint=THISBACK(PaintOp); +}; +PlotSymbol::PlotSymbol(Sizef size,RGBA color,RGBA frame,double thickness): + s(size),c(color),f(frame),t(thickness) +{ + paint=THISBACK(PaintOp); +}; + +void PlotSymbol::Paint(Painter& sw,Pointf pos)const{ + if(hash!=GetHashValue()){Refresh();} + //sw.Rectangle(pos.x-s.cx*0.5,pos.y-s.cy*0.5,s.cx,s.cy); + //sw.Fill(img,Pointf(pos.x-s.cx*0.5,pos.y-s.cy*0.5),Pointf(pos.x+s.cx*0.5,pos.y+s.cy*0.5)); + sw.Offset(pos.x-s.cx*0.5,pos.y-s.cy*0.5); + sw.Rectangle(0,0,s.cx,s.cy).Fill(img,0,0,s.cx,0); + sw.End(); +} +void PlotSymbol::DoPaint(Painter& sw)const{ + PaintOp(sw); +} +unsigned PlotSymbol::GetHashValue()const{ + return CombineHash(Color(c),Color(f),s,t); +} +void PlotSymbol::Refresh()const{ + if(s.cx<=0||s.cy<=0){img=Image();return;} + ImageBuffer ib(s); + BufferPainter bp(ib); + bp.Clear(RGBAZero()); + DoPaint(bp); + img=ib; + hash=GetHashValue(); +} + +String PlotSymbol::ToString()const{ + return String().Cat()< tmp(Create(GetType())); + tmp->s=s; + tmp->c=c; + tmp->f=f; + tmp->t=t; + return tmp.Detach(); +} + +INITBLOCK{ + PlotSymbol::Register("None"); + PlotSymbol::Register("Cross"); + PlotSymbol::Register("Diagonal cross"); + PlotSymbol::Register("Circle"); + PlotSymbol::Register("Square"); + PlotSymbol::Register("Star"); +} diff --git a/bazaar/PlotLib/PlotSymbol.h b/bazaar/PlotLib/PlotSymbol.h new file mode 100644 index 000000000..63807e59f --- /dev/null +++ b/bazaar/PlotLib/PlotSymbol.h @@ -0,0 +1,108 @@ +#ifndef _PlotLib_PlotSymbol_h_ +#define _PlotLib_PlotSymbol_h_ + +#include +using namespace Upp; + +class PlotSymbol{ +private: + typedef PlotSymbol CLASSNAME; + typedef PlotSymbol* (*CreateFunc)(); + template + static PlotSymbol* __Create() {return (PlotSymbol*)new T;} + static VectorMap& classMap() {static VectorMap cMap; return cMap;} + static VectorMap& typeMap() {static VectorMap tMap; return tMap;} +public: + template + static void Register(const String& name){ + classMap().FindAdd(name, __Create); + typeMap().FindAdd(typeid(T).name(),name); + } + static void Unregister(const String& name){ + int i=TypeIndex(name); + ASSERT(i>=0); + classMap().Remove(i); + typeMap().Remove(i); + } + static String TypeName(int i) {return typeMap()[i];} + static int TypeIndex(const String& name) {return max(classMap().Find(name),0);} + static int GetCount() {return classMap().GetCount();} + static PlotSymbol* Create(int i) {return classMap()[i]();} + static Vector GetTypes() {return VectorMap(typeMap(),1).GetValues();} + int GetType()const {return typeMap().Find(typeid(*this).name());} + PlotSymbol* Copy()const; +protected: + Callback1 paint; +public: + PlotSymbol(); + PlotSymbol(Sizef size,RGBA color,RGBA frame,double thickness); + + void Paint(Painter& sw,Pointf pos)const; + unsigned GetHashValue()const; + String ToString()const; + + void DoPaint(Painter& sw)const; + virtual void PaintOp(Painter& sw)const{} + + PlotSymbol& SetSize(Sizef size) {s=size; return *this;} + PlotSymbol& SetSize(double cx,double cy) {s=Sizef(cx,cy); return *this;} + PlotSymbol& SetColor(RGBA color) {c=color; return *this;} + PlotSymbol& SetFrameColor(RGBA color) {f=color; return *this;} + PlotSymbol& SetThickness(double thickness){t=thickness; return *this;} + Sizef GetSize()const {return s;} + RGBA GetColor()const {return c;} + RGBA GetFrameColor()const {return f;} + double GetThickness()const {return t;} + +protected: + Sizef s; + RGBA c,f; + double t; +private: + mutable unsigned hash; + mutable Image img; + void Refresh()const; +}; + +template +class WithPlotSymbol:public PlotSymbol{ +public: + WithPlotSymbol(){paint=callback((T*)(this),&T::PaintOp);} +}; + +// Basic PlotSymbols + +struct Cross:public WithPlotSymbol{ + virtual void PaintOp(Painter& sw)const{ + sw.Move(0,0.5*s.cy).Line(s.cx,0,true).Stroke(t,c); + sw.Move(0.5*s.cx,0).Line(0,s.cy,true).Stroke(t,c); + } +}; + +struct XCross:public WithPlotSymbol{ + virtual void PaintOp(Painter& sw)const{ + sw.Move(0, 0).Line(s.cx, s.cy,true).Stroke(t,c); + sw.Move(0,s.cy).Line(s.cx,-s.cy,true).Stroke(t,c); + } +}; +struct Circle:public WithPlotSymbol{ + virtual void PaintOp(Painter& sw)const{ + sw.Ellipse(0.5*s.cx,0.5*s.cy,0.5*(s.cx-t),0.5*(s.cy-t)); + sw.Fill(c).Stroke(t,f); + } +}; +struct Square:public WithPlotSymbol{ + virtual void PaintOp(Painter& sw)const{ + sw.Rectangle(t*0.5,t*0.5,s.cx-t,s.cy-t); + sw.Fill(c).Stroke(t,f); + } +}; +struct Star:public WithPlotSymbol{ + virtual void PaintOp(Painter& sw)const{ + sw.Move(0,0.5*s.cy).Line(s.cx,0,true).Stroke(t,c); + sw.Move(0.5*s.cx,0).Line(0,s.cy,true).Stroke(t,c); + sw.Move(0, 0).Line(s.cx, s.cy,true).Stroke(t,c); + sw.Move(0,s.cy).Line(s.cx,-s.cy,true).Stroke(t,c); + } +}; +#endif diff --git a/bazaar/PlotLib/init b/bazaar/PlotLib/init new file mode 100644 index 000000000..cf19c9f12 --- /dev/null +++ b/bazaar/PlotLib/init @@ -0,0 +1,4 @@ +#ifndef _PlotLib_icpp_init_stub +#define _PlotLib_icpp_init_stub +#include "Painter/init" +#endif diff --git a/bazaar/PlotLibExample/PlotLibExample.upp b/bazaar/PlotLibExample/PlotLibExample.upp new file mode 100755 index 000000000..e7db26829 --- /dev/null +++ b/bazaar/PlotLibExample/PlotLibExample.upp @@ -0,0 +1,13 @@ +description "Using PlotLib to create charts, even on head-less machines\377"; + +uses + plugin\png, + PlotLib; + +file + main.cpp, + symbol.iml; + +mainconfig + "" = ""; + diff --git a/bazaar/PlotLibExample/init b/bazaar/PlotLibExample/init new file mode 100755 index 000000000..12db878c1 --- /dev/null +++ b/bazaar/PlotLibExample/init @@ -0,0 +1,5 @@ +#ifndef _PlotLibExample_icpp_init_stub +#define _PlotLibExample_icpp_init_stub +#include "plugin\png/init" +#include "PlotLib/init" +#endif diff --git a/bazaar/PlotLibExample/main.cpp b/bazaar/PlotLibExample/main.cpp new file mode 100755 index 000000000..51488e286 --- /dev/null +++ b/bazaar/PlotLibExample/main.cpp @@ -0,0 +1,66 @@ +#include +#include +using namespace Upp; + +#define IMAGECLASS Symbol +#define IMAGEFILE +#include + +// If you wish, you can define virtualy anything as symbol, just use the WithPlotSymbol +// template, which will setup almost everything for you and override the PaintOp method +class Bug: public WithPlotSymbol{ +public: + virtual void PaintOp(Painter& sw)const{ + sw.Rectangle(0,0,s.cx,s.cy).Fill(Symbol::bug(),0,0,s.cx,0); + } + Bug(){s=Sizef(11,11);}; +}; + + +CONSOLE_APP_MAIN { + Plot plot; + // Register your PlotSymbol. This is not mandatory, + // it only makes the symbol appear in PlotStyleDlg + PlotSymbol::Register("Ladybug"); + + // You can create your data directly in plot ... + plot.data.Add(); + plot.data[0].SetColor(LtRed()).SetTitle("Butterfly Curve"); + for(double t = -12*M_PI; t <= 12*M_PI; t+=0.02){ + double r=(exp(cos(t))-2*cos(4*t)+pow(sin(t/12),5)); + plot.data[0].AddXY(r*sin(t),r*cos(t)); + } + + // ... or take your data from elsewhere and copy them in plot. Supported types are + // Vector, VectorMap, and Vector of reasonable formats (i.e. convertable + // to double) + the same containers in Array flavor + VectorMap v; + for(double x = -4; x <= 4; x+=0.05){ + v.Add(x,4*exp(-0.25*x*x)*sin(10*x)); + } + plot.data.Add(v); + plot.data[1].SetDash("1.5").SetTitle("4*exp(-x^2/4)*sin(10*x)").SetThickness(1.5) + .SetSymbol("Cross",Size(9,9),Black()); + v.Clear(); + + // random Ladybugs! :-) + PlotData dataset; + for(double x = -4; x <= 4; x+=0.5){ + dataset.AddXY(x,int(Random(7))-3); + } + plot.data.Add(dataset); + plot.data[2].SetColor(Green()).SetTitle("Totally random") + .SetThickness(2).SetSymbol("Ladybug"); + + // Plot can be setup any time before painting + plot.SetMode(PLOT_AA).SetLimits(-4.0,4.0,-4.0,4.0).SetPlotSize(640,480); + + // When it's all prepared, just call GetImage to get the plot and use the returned image + // in whatever way you want, e.g. save it into PNG file: + PNGEncoder().SaveFile(GetHomeDirFile("plot.png"), plot.GetImage()); + + // If you want a legend, just create one ;-) It is a separate picture, + // if you want it combined with the plot, it's up to you... + PNGEncoder().SaveFile(GetHomeDirFile("legend.png"), + Legend(plot).SetBackground(White()).GetLegend()); +} diff --git a/bazaar/PlotLibExample/symbol.iml b/bazaar/PlotLibExample/symbol.iml new file mode 100755 index 000000000..30fd29ecf --- /dev/null +++ b/bazaar/PlotLibExample/symbol.iml @@ -0,0 +1,16 @@ +PREMULTIPLIED +IMAGE_ID(bug) + +IMAGE_BEGIN_DATA +IMAGE_DATA(120,156,149,84,177,106,195,48,20,212,40,60,41,6,79,38,83,49,116,42,25,179,230,155,61,119,45,153,74,161,80,16) +IMAGE_DATA(157,140,87,147,41,104,125,189,139,79,32,92,215,77,12,199,147,158,239,221,59,201,146,221,206,237,220,29,143,7,246,64) +IMAGE_DATA(4,62,128,186,200,215,130,87,174,93,204,51,167,3,190,128,35,240,34,94,0,26,224,13,120,5,42,213,156,149,99,207) +IMAGE_DATA(22,2,29,4,34,10,38,224,162,56,50,135,119,7,112,222,165,191,244,209,97,18,145,28,241,114,130,241,4,24,241,169) +IMAGE_DATA(136,38,9,77,174,228,248,89,35,215,223,188,51,7,131,19,120,134,197,219,55,224,132,88,140,179,22,22,48,200,55,215) +IMAGE_DATA(86,179,30,147,1,6,211,90,93,57,6,199,192,53,63,115,169,243,204,125,168,11,239,153,123,86,207,188,150,168,177,234) +IMAGE_DATA(205,123,111,85,85,37,68,234,112,255,38,122,192,102,217,147,208,21,122,248,32,118,148,135,90,57,212,91,223,247,140,35) +IMAGE_DATA(247,19,11,58,193,208,53,22,189,75,79,204,163,153,129,99,65,185,16,130,53,77,195,120,211,160,15,240,210,88,212,113) +IMAGE_DATA(60,9,73,136,27,62,254,211,184,40,198,141,253,200,223,37,235,76,210,120,228,187,228,243,177,159,253,108,106,252,117,62) +IMAGE_DATA(30,56,167,244,144,192,25,252,92,95,158,211,123,239,11,207,56,251,31,212,183,212,88,222,219,160,59,117,212,189,237,196) +IMAGE_DATA(105,213,103,121,103,215,30,234,241,127,17,221,111,207,107,255,14,247,3,78,169,248,252,0,0,0,0,0,0,0,0,0) +IMAGE_END_DATA(352, 1)