// This may look like C code, but it is really -*- C++ -*-
// Outils de manipulation des axes des PIScDrawWdg
//                                   R. Ansari 07/2001
// LAL (Orsay) / IN2P3-CNRS  DAPNIA/SPP (Saclay) / CEA

#include <stdlib.h>
#include <iostream>

#include "sopnamsp.h"
#include "piaxes.h"
#include "piaxestools.h"

//++
// Class	PIAxesTools
// Lib		PI
// include	piaxestools.h
//
//	Classe de fenêtre de dialogue permettant de modifier interactivement
//	Permet aussi de modifier les attributs d'axes pour les "PIScDrawWdg"
//--
// Links	Parents
// PIWindow
//--
//++
// Links	Voir aussi
// PIScDrawWdg
//--

//++
// Titre	Méthodes statiques
//--
//++
// void  ShowPIAxesTools() 	
//	Méthode statique permettant l'affichage de la fenêtre de contrôle des
//	attributs graphiques des "Drawer". L'instance de la classe
//	 "PIAxesTools" est créée si nécessaire.
// void  HidePIAxesTools() 
//	Désacative (cache) la fenêtre "PIAxesTools" (méthode statique).
// void  SetCurrentBaseWdg(PIBaseWdgGen* cbw)
//	Méthode statique permettant de sélectionner le "PIBaseWdg" courant.
// PIBaseWdgGen*  GetCurrentBaseWdg()
//	Retourne le "PIBaseWdg" courant (méthode statique).
//--


PIAxesTools* PIAxesTools::cwaxet = NULL;
PIScDrawWdg* PIAxesTools::curscdwdg = NULL;

/* --Methode-- */
void PIAxesTools::ShowPIAxesTools() 
{
if (cwaxet == NULL)  cwaxet = new PIAxesTools(PIApplicationGetApp());
cwaxet->Show();
}

/* --Methode-- */
void PIAxesTools::HidePIAxesTools() 
{
if (cwaxet == NULL)  return; 
cwaxet->Hide();
}

/* --Methode-- */
void PIAxesTools::SetCurrentScDrawWdg(PIScDrawWdg* csw)
{
if (curscdwdg == csw) return;
curscdwdg = csw;
}

/* --Methode-- */
PIScDrawWdg* PIAxesTools::GetCurrentScDrawWdg()
{
return(curscdwdg);
}

/* --Methode-- */
PIAxesTools::PIAxesTools(PIApplication* par)
: PIWindow((PIMsgHandler*)par, "PIAxesTools", PIWK_normal, 240, 240, 150, 150)
, mTypAction(0), mSclAction(0.)
{
int bsx, bsy, spx, spy;
int bsycb, spycb;

// On definit la taille a partir de la taille par defaut des composantes 
// PIApplicationPrefCompSize(bsx, bsy);
par->PrefCompSize(bsx, bsy);  // environ 6 lettres
spx = bsx/10;
spy = bsy/4;

bsycb = 0.80*bsy+0.5;  // Taille des checkbox
spycb = 0.80*spy+0.5;  // Espace-Y inter checkbox

int wszx = 6*spx+3.5*bsx; 
int wszy = 5*bsy+9*spy+4*bsycb+3*spycb;
SetSize(wszx, wszy);

int cpx = spx;
int cpy = spy*2;
mLab[0] = new PILabel(this, "X Min Max", 1.25*bsx, bsy, cpx, cpy);
cpy += spy+bsy; 
mLab[1] = new PILabel(this, "Y Min Max", 1.25*bsx, bsy, cpx, cpy);
mLab[0]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
mLab[1]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);

cpy = spy*2;
cpx += spx+1.25*bsx; 
mText[0] = new PIText(this, "x_min_max", 2.25*bsx+2*spx, bsy, cpx, cpy);
mText[0]->SetText("-1.0  1.0");
cpy += spy+bsy; 
mText[1] = new PIText(this, "y_min_max", 2.25*bsx+2*spx, bsy, cpx, cpy);
mText[1]->SetText("-1.0  1.0");
mText[0]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
mText[1]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);

cpy += spy+bsy; 
cpx = spx+0.25*bsx;
mCkb[3] = new PICheckBox(this,"LogScale-X", 2003, bsx*1.5, bsycb, cpx, cpy);
cpx += bsx*1.5+3*spx;
mCkb[4] = new PICheckBox(this,"LogScale-Y", 2004, bsx*1.5, bsycb, cpx, cpy);
mCkb[3]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
mCkb[4]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);

cpx = spx+0.25*bsx;
cpy += spycb+bsycb;
mCkb[0] = new PICheckBox(this,"X-RightLeft", 2000, bsx*1.5, bsycb, cpx, cpy);
cpx += bsx*1.5+3*spx;
mCkb[1] = new PICheckBox(this,"Y-UpDn", 2001, bsx*1.5, bsycb, cpx, cpy);
mCkb[0]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
mCkb[1]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);

cpx = spx+0.25*bsx;
cpy += spycb+bsycb;
mCkb[5] = new PICheckBox(this,"Centerd-Axes", 2005, bsx*1.5, bsycb, cpx, cpy);
cpx += bsx*1.5+3*spx;
mCkb[2] = new PICheckBox(this,"Grid", 2002, bsx*1.5, bsycb, cpx, cpy);
mCkb[5]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
mCkb[2]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);

cpx = spx+0.25*bsx;
cpy += spycb+bsycb;
mCkb[6] = new PICheckBox(this,"Minor-Ticks", 2006, bsx*1.5, bsycb, cpx, cpy);
cpx += 3*spx+1.5*bsx; 
mCkb[7] = new PICheckBox(this,"AutoFontSize", 2007, bsx*1.5, bsycb, cpx, cpy);
mCkb[6]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
mCkb[7]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);


cpy += spy+bsy; 
cpx = spx+0.25*bsx;
mBut[0] = new PIButton(this, "GetAxesInfo", 2100, bsx*1.5, bsy, cpx, cpy);
cpx += bsx*1.5+4*spx;
mBut[1] = new PIButton(this, "AutoLimits", 2200, bsx*1.5, bsy, cpx, cpy);
mBut[0]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
mBut[1]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);

cpy += spy+bsy; 
cpx = spx+0.25*bsx;
mBut[2] = new PIButton(this, "SetAxes", 2500, bsx*1.5, bsy, cpx, cpy);
cpx += bsx*1.5+4*spx;
mBut[3] = new PIButton(this, "Dismiss", 2777, bsx*1.5, bsy, cpx, cpy);
mBut[2]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
mBut[3]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);

  cpy += spy+bsy; 
  cpx = spx;
mBut[4] = new PIButton(this,"<<",2801,0.5*bsx,bsy,cpx,cpy);
mBut[4]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
 cpx += spx+0.5*bsx;
mBut[5] = new PIButton(this,"<",2802,0.5*bsx,bsy,cpx,cpy);
mBut[5]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
 cpx += spx+0.5*bsx;
mOpt = new PIOptMenu(this,"choix-action",1.5*bsx,bsy,cpx,cpy);
mOpt->AppendItem("Transl X",2850);  // mTypAction=0
mOpt->AppendItem("Transl Y",2851);  // mTypAction=1
mOpt->AppendItem("Zoom X",2852);    // mTypAction=2
mOpt->AppendItem("Zoom Y",2853);    // mTypAction=3
mOpt->AppendItem("Zoom X-Y",2854);  // mTypAction=4
mOpt->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
 string sdum="Transl X"; mOpt->SetValueStr(sdum); mTypAction=0;
 cpx += spx+1.5*bsx;
mBut[6] = new PIButton(this,">",2803,0.5*bsx,bsy,cpx,cpy);
mBut[6]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
 cpx += spx+0.5*bsx;
mBut[7] = new PIButton(this,">>",2804,0.5*bsx,bsy,cpx,cpy);
mBut[7]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);

cwaxet = this;
}

/* --Methode-- */
PIAxesTools::~PIAxesTools()
{
if (cwaxet == this)  cwaxet = NULL;
int i;
for(i=0;i<2;i++) delete mLab[i];
for(i=0;i<2;i++) delete mText[i];
for(i=0;i<8;i++) delete mBut[i];
for(i=0;i<8;i++) delete mCkb[i];
delete mOpt;
}

/* --Methode-- */
void PIAxesTools::Show()
{
PIWindow::Show();
UpdateAxesInfoFromScWdg();
return;
}

/* --Methode-- */
void PIAxesTools::UpdateAxesInfoFromScWdg()
{
char buff[128];
if (curscdwdg != NULL) {
  string format,dum;
  PIScDrawWdg* scd = curscdwdg;
    PIAxes::BonFormatAxes(scd->XMin(),scd->XMax(),-1.,format,0,2);
    dum = format; dum += "  "; dum += format;
  sprintf(buff,dum.c_str(),scd->XMin(),scd->XMax());
  mText[0]->SetText(buff);
    PIAxes::BonFormatAxes(scd->YMin(),scd->YMax(),-1.,format,0,2);
    dum = format; dum += "  "; dum += format;
  sprintf(buff,dum.c_str(),scd->YMin(),scd->YMax());
  mText[1]->SetText(buff);
  int xa, ya;
  scd->GetAxesConfig(xa, ya);
  if (xa & kAxeDirRtoL) mCkb[0]->SetState(true);
  else mCkb[0]->SetState(false);
  if (ya & kAxeDirUpDown)  mCkb[1]->SetState(true);
  else mCkb[1]->SetState(false);
  if (scd->GetAxesFlags() & kGridOn) mCkb[2]->SetState(true);
  else mCkb[2]->SetState(false);
  if (scd->GetAxesFlags() & kCentAxes) mCkb[5]->SetState(true);
  else mCkb[5]->SetState(false);
  if (scd->GetAxesFlags() & kMinTicks) mCkb[6]->SetState(true);
  else mCkb[6]->SetState(false);
  mCkb[3]->SetState(scd->isLogScaleX());
  mCkb[4]->SetState(scd->isLogScaleY());
  mCkb[7]->SetState(scd->BaseDrawer()->isAxesAutoFontSize());
  }
else {
  mText[0]->SetText("-1.0  1.0");
  mText[1]->SetText("-1.0  1.0");
  mCkb[0]->SetState(false);
  mCkb[1]->SetState(false);
  mCkb[2]->SetState(false);
  mCkb[3]->SetState(false);
  mCkb[4]->SetState(false);
  mCkb[5]->SetState(false);
  mCkb[6]->SetState(false);
  mCkb[7]->SetState(true);
  }

return;
}

void PIAxesTools::SetAxes(bool refr)
{
  PIScDrawWdg* scd = curscdwdg;
  if ( scd == NULL )  return;

  double xmin, xmax, ymin, ymax;
  if(mText[0]->GetText().length()>1 && mSclAction==0.) {
    xmin = -1.;   xmax = 1.;
    sscanf(mText[0]->GetText().c_str(), "%lg %lg" , &xmin, &xmax);
  } else {
    xmin = scd->XMin();
    xmax = scd->XMax();
  }
  if(mText[1]->GetText().length()>1 && mSclAction==0.) {
    ymin = -1.;   ymax = 1.;
    sscanf(mText[1]->GetText().c_str(), "%lg %lg" , &ymin, &ymax);
  } else {
    ymin = scd->YMin();
    ymax = scd->YMax();
  }

  if(mSclAction!=0.) {
    double d;
    if(mTypAction==0) { // Translation X
      d = mSclAction*(xmax-xmin); xmin += d; xmax += d;
    } else if(mTypAction==1) { // Translation Y
      d = mSclAction*(ymax-ymin); ymin += d; ymax += d;
    } else { // Zoom X, Y ou X-Y
      double c, s=(mSclAction>0.)? 1./(1.+mSclAction): (1.-mSclAction);
      if((mTypAction==2 || mTypAction==4) && xmax-xmin>0.) {
        c = (xmin+xmax)/2.; d = s*(xmax-xmin)/2.;
        xmin = c - d; xmax = c + d;
      }
      if((mTypAction==3 || mTypAction==4) && ymax-ymin>0.) {
        c = (ymin+ymax)/2.; d = s*(ymax-ymin)/2.;
        ymin = c - d; ymax = c + d;
      }
    }
  }

  int axrl = kAxeDirLtoR;
  int ayud = kAxeDirDownUp;
  if (mCkb[0]->GetState())  axrl = kAxeDirRtoL ;
  if (mCkb[1]->GetState())  ayud = kAxeDirUpDown;
  scd->SetLimits(xmin, xmax, ymin, ymax, axrl, ayud);
  unsigned int flags = scd->GetAxesFlags();

  if (mCkb[2]->GetState()) flags |= kGridOn;
  else  flags &= ~kGridOn;
  if (mCkb[5]->GetState()) { flags |= kCentAxes;  flags &= ~kBoxAxes; }
  else { flags &= ~kCentAxes;  flags |= kBoxAxes; }
  if (mCkb[6]->GetState()) flags |= kMinTicks;
  else  flags &= ~kMinTicks;

  scd->SetAxesFlags(flags);

  scd->SetLogScale(mCkb[3]->GetState(), mCkb[4]->GetState() );
  scd->BaseDrawer()->SetAxesAutoFontSize(mCkb[7]->GetState() );
  if (refr) scd->Refresh();
  return;
}

/* --Methode-- */
void PIAxesTools::Process(PIMessage msg, PIMsgHandler* /*sender*/, void* /*data*/)
{
// Petit deplacement (zoom) ">"  ou "<"  de 20%
// Grand deplacement (zoom) ">>" ou "<<" de 50%
// *** ATTENTION: Valeurs OBLIGATOIREMENT ]0,1[ bornes exclues ***
double smallstep=0.2, bigstep=0.5;

msg = UserMsg(msg);
mSclAction = 0.;

switch (msg) {

  case 2100 :
    UpdateAxesInfoFromScWdg();
    break;
  case 2200 :
    if ( curscdwdg != NULL ) { 
      curscdwdg->UpdateLimits();
      UpdateAxesInfoFromScWdg();
    }
    break;
  case 2500 :
    SetAxes(true);
    break;

  case 2777 :
    Hide();
    break;

  case 2801 :  // <
    mSclAction = -bigstep;
    SetAxes(true);
    break;
  case 2802 :  // <<
    mSclAction = -smallstep;
    SetAxes(true);
    break;
  case 2803 :  // >
    mSclAction = smallstep;
    SetAxes(true);
    break;
  case 2804 :  // >>
    mSclAction = bigstep;
    SetAxes(true);
    break;

  case 2850 :
  case 2851 :
  case 2852 :
  case 2853 :
  case 2854 :
    mTypAction = msg - 2850;
    break;

  default :
    break;
  }

return;
}





