22 #include "wx/wxprec.h" 
   29 #include "wx/dcbuffer.h" 
   30 #include "wx/gdicmn.h" 
   31 #include "ObjCryst/ObjCryst/General.h" 
   32 #include "ObjCryst/wxCryst/wxMultiGraph.h" 
   33 #include "ObjCryst/wxCryst/wxCryst.h" 
   39 static const char* swxColourNameList[]={
 
   67 "DARK SLATE GREY DARK TURQUOISE",
 
   81 "MEDIUM FOREST GREEN",
 
   86 "MEDIUM SPRING GREEN",
 
  114 static const long ID_UPDATEUI=              WXCRYST_ID();
 
  115 static const long ID_MENU_AUTOSCALE=        WXCRYST_ID();
 
  117 BEGIN_EVENT_TABLE(WXMultiGraph, wxWindow)
 
  118    EVT_PAINT(                                   WXMultiGraph::OnPaint)
 
  119    EVT_MOUSE_EVENTS(                            WXMultiGraph::OnMouse)
 
  120    EVT_CHAR(                                    WXMultiGraph::OnKeyDown)
 
  121    EVT_MOUSEWHEEL(                              WXMultiGraph::OnMouseWheel)
 
  122    EVT_UPDATE_UI(ID_UPDATEUI,                   WXMultiGraph::OnUpdateUI)
 
  123    EVT_SIZE(                                    WXMultiGraph::OnSize)
 
  127 WXMultiGraph::WXMultiGraph(wxFrame *frame):
 
  128 wxWindow(frame,-1,wxPoint(-1,-1),wxSize(-1,-1)),
 
  129 mMinX(0.0),mMaxX(1.0),mMinY(0.0),mMaxY(1.0),
 
  130 mLeft(40),mRight(10),mTop(10),mBottom(25),
 
  131 mIsDragging(false),mpParentFrame(frame)
 
  133    #ifdef VFN_CRYST_MUTEX 
  134    cout <<
"new CrystMutex("<<&mMutexData<<
")for WXMultiGraph:"<<
this<<endl;
 
  136    mpPopUpMenu=
new wxMenu(_T(
"Graph"));
 
  137    mpPopUpMenu->Append(ID_MENU_AUTOSCALE, _T(
"&AutoScale"));
 
  141 WXMultiGraph::~WXMultiGraph()
 
  143    VFN_DEBUG_MESSAGE(
"WXMultiGraph::~WXMultiGraph():",4)
 
  145    #ifdef VFN_CRYST_MUTEX 
  146    cout <<
"Deleting CrystMutex("<<&mMutexData<<
")for WXMultiGraph:"<<
this<<endl;
 
  150 unsigned long WXMultiGraph::AddGraph(
const string &name)
 
  152    wxMutexLocker mlock(mMutexData);
 
  154    for(
id=mvData.size();
id>=0;
id--)
 
  155       if(mvData.end()==mvData.find(
id)) 
break;
 
  156    mvData[id].name=name;
 
  158    mvData[id].xmax=-1.0;
 
  160    mvData[id].ymax=-1.0;
 
  164 void WXMultiGraph::SetGraphData
 
  165    (
const unsigned long id,
const std::valarray<float> &vx,
 
  166     const std::valarray<float> &vy)
 
  170    if(mvData[
id].xmin>mvData[
id].xmax)rescale=
true;
 
  171    mvData[id].vx.resize(vx.size());
 
  172    mvData[id].vy.resize(vx.size());
 
  177       mvData[id].xmin=mvData[id].vx.min();
 
  178       mvData[id].xmax=mvData[id].vx.max();
 
  179       mvData[id].ymin=mvData[id].vy.min();
 
  180       mvData[id].ymax=mvData[id].vy.max();
 
  181       VFN_DEBUG_MESSAGE(
"WXMultiGraph::SetGraphData():"<<mvData[
id].vx.size()<<
":" 
  182                         << mvData[id].xmin<<
","<< mvData[id].xmax<<
"," 
  183                         << mvData[id].ymin<<
","<< mvData[id].ymax<<
",",3)
 
  188    else mMutexData.Unlock();
 
  192 void WXMultiGraph::DeleteGraph(
const unsigned long id)
 
  197 void WXMultiGraph::OnPaint(wxPaintEvent &event)
 
  199    wxMutexLocker mlock(mMutexData);
 
  200    if(mvData.size()<1) 
return;
 
  201    VFN_DEBUG_ENTRY(
"WXMultiGraph::OnPaint()",4)
 
  202    wxBufferedPaintDC dc(this);
 
  204    mpParentFrame->PrepareDC(dc);
 
  206    dc.DestroyClippingRegion();
 
  207    dc.SetBackground(wxBrush(_T("white"), wxSOLID));
 
  212    dc.SetFont(*wxNORMAL_FONT);
 
  214    dc.SetFont(*wxSMALL_FONT);
 
  217    wxCoord width,height;
 
  218    this->GetSize(&width, &height);
 
  221    VFN_DEBUG_MESSAGE(
"WXMultiGraph::OnPaint():Axis",3)
 
  223       dc.SetPen(*wxBLACK_PEN);
 
  224       dc.SetTextForeground(*wxBLACK);
 
  229          float yStep,xStep,dx,dy;
 
  234          yStep=pow((
float)10,(
float)floor(log10(dy/nbTick)));
 
  235          yStep *= floor((dy/yStep+0.1)/nbTick);
 
  237          xStep=pow((
float)10,(
float)floor(log10(dx/nbTick)));
 
  238          xStep *= floor((dx/xStep+0.1)/nbTick);
 
  241          for(
float y=yStep*ceil(mMinY/yStep);y<mMaxY;y+=yStep)
 
  243             fontInfo.Printf(_T(
"%g"),y);
 
  244             dc.GetTextExtent(fontInfo, &tmpW, &tmpH);
 
  245             if((tmpW+3)>mLeft) mLeft=tmpW+3;
 
  248          fontInfo.Printf(_T(
"%g"),xStep);
 
  249          dc.GetTextExtent(fontInfo, &tmpW, &tmpH);
 
  253          dc.DrawLine(mLeft,height-mBottom,mLeft,mTop);
 
  254          VFN_DEBUG_MESSAGE(
"WXMultiGraph::OnPaint():AxisStep="<<yStep<<
","<<mMinY<<
","<<mMaxY,3)
 
  255          nbTick=
int(dy/yStep);
 
  256          for(
int i=0;i<nbTick;i++)
 
  258             float y=yStep*ceil(mMinY/yStep)+i*yStep;
 
  261             this->Data2Screen(xs,ys);
 
  262             VFN_DEBUG_MESSAGE(
"WXMultiGraph::OnPaint():Axis:"<<xs<<
","<<ys,3)
 
  263             dc.DrawLine(wxCoord(xs-3),wxCoord(ys),wxCoord(xs+3),wxCoord(ys));
 
  264             fontInfo.Printf(_T("%g"),y);
 
  265             dc.GetTextExtent(fontInfo, &tmpW, &tmpH);
 
  266             dc.DrawText(fontInfo,wxCoord(xs-tmpW-3),wxCoord(ys-tmpH/2));
 
  269          dc.DrawLine(mLeft,height-mBottom,width-mRight,height-mBottom);
 
  270          nbTick=
int(dx/xStep);
 
  271          for(
int i=0;i<nbTick;i++)
 
  273             float x=xStep*ceil(mMinX/xStep)+i*xStep;
 
  276             this->Data2Screen(xs,ys);
 
  277             dc.DrawLine(wxCoord(xs),wxCoord(ys-3),wxCoord(xs),wxCoord(ys+3));
 
  278             fontInfo.Printf(_T(
"%g"),x);
 
  279             dc.GetTextExtent(fontInfo, &tmpW, &tmpH);
 
  280             dc.DrawText(fontInfo,wxCoord(xs-tmpW/2),wxCoord(ys+tmpH/2));
 
  283       dc.GetTextExtent(mYLabel, &tmpW, &tmpH);
 
  284       dc.DrawText(mYLabel,wxCoord(0),wxCoord(0));
 
  285       xs=xStep*ceil(mMinX/xStep)+(nbTick-1.5)*xStep;
 
  287       this->Data2Screen(xs,ys);
 
  288       dc.GetTextExtent(mXLabel, &tmpW, &tmpH);
 
  289       dc.DrawText(mXLabel,wxCoord(xs-tmpW/2),wxCoord(ys+tmpH/2+3));
 
  292    map<unsigned long, GraphData >::const_iterator pos;
 
  293    long ix=-1,ixdrawn=-1;
 
  294    for(pos=mvData.begin();pos!=mvData.end();++pos)
 
  297       VFN_DEBUG_MESSAGE(
"WXMultiGraph::OnPaint():Data#"<<ix,3)
 
  298       if((pos->second.vx.size()<1)||(pos->second.vx.size()!=pos->second.vy.size())) continue;
 
  300       dc.SetPen(wxPen(wxTheColourDatabase->Find(wxString::FromAscii(swxColourNameList[ix])),1,wxSOLID));
 
  302       x2=pos->second.vx[0];
 
  303       y2=pos->second.vy[0];
 
  304       this->Data2Screen(x2,y2);
 
  305       for(
unsigned long i=0;i<pos->second.vx.size();i++)
 
  309          x2=pos->second.vx[i];
 
  310          y2=pos->second.vy[i];
 
  311          this->Data2Screen(x2,y2);
 
  312          if(  ((x1>=mLeft)&&(x1<=(width-mRight))&&(y1>=mBottom)&&(y1<=(height-mTop)))
 
  313             ||((x2>=mLeft)&&(x2<=(width-mRight))&&(y2>=mBottom)&&(y2<=(height-mTop))))
 
  314             dc.DrawLine(wxCoord(x1),wxCoord(y1),wxCoord(x2),wxCoord(y2));
 
  317       dc.SetTextForeground(wxPen(wxTheColourDatabase->Find(wxString::FromAscii(swxColourNameList[ix])),1,wxSOLID).GetColour());
 
  319       fontInfo.Printf(wxString::FromAscii(pos->second.name.c_str()));
 
  320       dc.GetTextExtent(fontInfo, &tmpW, &tmpH);
 
  321       dc.DrawText(fontInfo,wxCoord(width-tmpW-2),wxCoord(tmpH*(ixdrawn)+2));
 
  324    VFN_DEBUG_EXIT(
"WXMultiGraph::OnPaint()",4)
 
  327 void WXMultiGraph::OnMouse(wxMouseEvent &event)
 
  331    if(event.Leaving()) 
return;
 
  332    wxCoord width,height;
 
  333    this->GetSize(&width, &height);
 
  337       mpParentFrame->PrepareDC(dc);
 
  339       wxPoint pos=
event.GetPosition();
 
  340       float x= float(dc.DeviceToLogicalX(pos.x));
 
  341       float y= float(dc.DeviceToLogicalY(pos.y));
 
  343       if((x>width)||(y>height))
 
  347       this->Screen2Data(x,y);
 
  349       str.Printf(_T(
"x=%f    ,y=%f"),x,y);
 
  350       mpParentFrame->SetStatusText(str);
 
  352    if(event.RightIsDown())
 
  354       this->PopupMenu(mpPopUpMenu, event.GetX(), 
event.GetY() );
 
  357    if (event.Dragging() && 
event.LeftIsDown() && (!mIsDragging))
 
  364    if(event.LeftUp() && mIsDragging)
 
  388       if(mMaxX<=mMinX) mMaxX=mMinX+1e-6;
 
  389       if(mMaxY<=mMinY) mMaxY=mMinY+1e-6;
 
  391       this->UpdateDisplay();
 
  394    if(
false==event.Dragging()) mIsDragging=
false;
 
  396    if(event.LeftDClick())
 
  399       this->UpdateDisplay();
 
  404 void WXMultiGraph::OnMouseWheel(wxMouseEvent &event)
 
  406    if(event.GetWheelRotation()>=
event.GetWheelDelta())
 
  408       const REAL range=mMaxX-mMinX;
 
  412    if(event.GetWheelRotation()<=(-
event.GetWheelDelta()))
 
  414       const REAL range=mMaxX-mMinX;
 
  418    this->UpdateDisplay();
 
  421 void WXMultiGraph::AutoScale(
const long id,
const bool xmin,
const bool xmax,
 
  422                                            const bool ymin,
const bool ymax)
 
  424    wxMutexLocker mlock(mMutexData);
 
  425    if(mvData.size()==0) 
return;
 
  426    std::map<unsigned long, GraphData>::const_iterator pos;
 
  427    if(
id<0)pos=mvData.end();
 
  428    else pos=mvData.find((
unsigned long)
id);
 
  429    if(pos==mvData.end())
 
  432       if(xmax) mMaxX=pos->second.xmax;
 
  433       if(xmin) mMinX=pos->second.xmin;
 
  434       if(ymax) mMaxY=pos->second.ymax;
 
  435       if(ymin) mMinY=pos->second.ymin;
 
  437       for(;pos!=mvData.end();++pos)
 
  439          if(xmax) 
if(mMaxX<pos->second.xmax) mMaxX=pos->second.xmax;
 
  440          if(xmin) 
if(mMinX>pos->second.xmin) mMinX=pos->second.xmin;
 
  441          if(ymax) 
if(mMaxY<pos->second.ymax) mMaxY=pos->second.ymax;
 
  442          if(ymin) 
if(mMinY>pos->second.ymin) mMinY=pos->second.ymin;
 
  447       if(xmax) mMaxX=pos->second.xmax;
 
  448       if(xmin) mMinX=pos->second.xmin;
 
  449       if(ymax) mMaxY=pos->second.ymax;
 
  450       if(ymin) mMinY=pos->second.ymin;
 
  452    if(mMaxX<=mMinX) mMaxX=mMinX+1e-6;
 
  453    if(mMaxY<=mMinY) mMaxY=mMinY+1e-6;
 
  457 void WXMultiGraph::OnKeyDown(wxKeyEvent& event)
 
  459    switch(event.GetKeyCode())
 
  463          const REAL range=mMaxX-mMinX;
 
  470          const REAL range=mMaxX-mMinX;
 
  477          const REAL range=mMaxY-mMinY;
 
  484          const REAL range=mMaxY-mMinY;
 
  491          const REAL range=mMaxX-mMinX;
 
  492          const REAL center=(mMaxX+mMinX)/2;
 
  493          mMinX=center-range/3.0;
 
  494          mMaxX=center+range/3.0;
 
  499          const REAL range=mMaxX-mMinX;
 
  500          const REAL center=(mMaxX+mMinX)/2;
 
  501          mMinX=center-range*2.0/3.0;
 
  502          mMaxX=center+range*2.0/3.0;
 
  507          const REAL range=mMaxY-mMinY;
 
  508          mMaxY=mMinY+range*2.0/3.0;
 
  513          const REAL range=mMaxY-mMinY;
 
  514          mMaxY=mMinY+range*4.0/3.0;
 
  519          VFN_DEBUG_MESSAGE(
"WXMultiGraph::OnKeyDown(): no command for key #"<<event.GetKeyCode(),5);
 
  522    this->UpdateDisplay();
 
  526 void WXMultiGraph::OnUpdateUI(wxUpdateUIEvent &event)
 
  528    VFN_DEBUG_MESSAGE(
"WXMultiGraph::OnUpdateUI()",4)
 
  529    this->Refresh(false);
 
  533 void WXMultiGraph::OnSize(wxSizeEvent &event)
 
  535    this->Refresh(
false);
 
  537 void WXMultiGraph::SetXLabel(
const wxString &xlabel)
 
  542 void WXMultiGraph::SetYLabel(
const wxString &ylabel)
 
  547 void WXMultiGraph::UpdateDisplay()
 
  549    VFN_DEBUG_ENTRY(
"WXMultiGraph::UpdateDisplay()",4)
 
  550    if(wxThread::IsMain()) this->Refresh(false);
 
  553       wxUpdateUIEvent event(ID_UPDATEUI);
 
  554       wxPostEvent(
this,event);
 
  556    VFN_DEBUG_EXIT(
"WXMultiGraph::UpdateDisplay()",4)
 
  560 void WXMultiGraph::Screen2Data(
float &x,
float &y)
 
  562    wxCoord width,height;
 
  563    this->GetSize(&width, &height);
 
  565    float range=float(width-(mLeft+mRight));
 
  566    if(range<=0) range=1.0;
 
  568    x=mMinX+x*(mMaxX-mMinX);
 
  570    range=float(height-(mTop+mBottom));
 
  571    if(range<=0) range=1.0;
 
  572    y=(height-mBottom-y)/range;
 
  573    y=mMinY+y*(mMaxY-mMinY);
 
  576 void WXMultiGraph::Data2Screen(
float &x,
float &y)
 
  578    VFN_DEBUG_ENTRY(
"WXMultiGraph::Data2Screen()"<<x<<
","<<y,2)
 
  579    wxCoord width,height;
 
  580    this->GetSize(&width, &height);
 
  582    float range=float(width-(mLeft+mRight));
 
  583    x=(x-mMinX)/(mMaxX-mMinX);
 
  586    range=float(height-(mTop+mBottom));
 
  587    y=(y-mMinY)/(mMaxY-mMinY);
 
  588    y=height-mBottom-y*range;
 
  589    VFN_DEBUG_EXIT(
"WXMultiGraph::Data2Screen()->"<<x<<
","<<y,2)
 
The namespace which includes all objects (crystallographic and algorithmic) in ObjCryst++.