// Module PI : Peida Interactive     PIScDrawWdg
// Gestionnaire Drawer-2D  E.Aubourg, R. Ansari  96-98
// LAL (Orsay) / IN2P3-CNRS  DAPNIA/SPP (Saclay) / CEA

#include "machdefs.h"
#include <math.h>
#include <iostream.h>

#include "piscdrawwdg.h"
#include "pidrwtools.h"
#include "piaxestools.h"
#include "parradapter.h"

//++
// Class	PIScDrawWdg
// Lib		PI
// include	piscdrawwdg.h
//
//   	Classe pour la l'affichage et la manipulation d'un ensemble
//	de *Drawer* avec la gestion de zoom (agrandissement).
//	* Bouton-1 : Envoie le message "PIMsg_Active" et affiche
//	les coordonnées courantes (User-Coordinates)
//	* Bouton-2 : Permet de définir un rectangle pour le zoom.
//	* Bouton-3 : Permet de définir un rectangle pour le texte info.
//
//	Gestion du clavier :
//	* <Alt>O : Active/Affiche les  contrôles de paramètres spécifiques 
//	(Par défaut, action identique à <Alt>G)
//	* <Alt>G : Affichage de la fenêtre de changement des attributs graphiques
//	* <Alt>R : Rafraîchit l'affichage.
//	* <Alt>M : Active/Désactive l'affichage d'une réticule de mesure (Bouton-1)
//	* <Alt>V : Copier/*Coller* Ajout du texte du buffer copier/coller
//	sur l'objet à la position courante.
//	* <Alt>I : Affiche et met a jour la fenetre Texte-Info .
//	* <Alt>Z : Supprime les textes et signes ajoutés au dessin.
//--
//++
// Links	Parents
// PIBaseWdg
//--
//++
// Links	Voir aussi
// PIDrawer
//--

static inline void dbl_swap(double& a, double& b) { double tmp = a; a = b; b = tmp;  } 

//++
// Titre	Constructeurs, méthodes
//	Seule les méthodes les plus usuelles sont décrites ici. Se reporter
//	au fichier .h pour la liste complete des méthodes
//--
//++
//  PIScDrawWdg(PIContainerGen *par, const char *nom, int sx=100, int sy=100, int px=0, int py=0)
//	Constructeur. Contient uniquement le traceur de base, responsable du tracé
//	des axes et des éléments ajoutés (textes, ...)
// long  kind()
//	Renvoie le type ("=PIScDrawWdg::ClassId")
// void SetLimits(double xmin, double xmax, double ymin, double ymax, -
//           int axrl=kAxeDirSame, int ayud=kAxeDirSame, bool tmp=false)
//	Définit les limites de coordonnées.
// void	 UpdateLimits()
//	Recalcule les limites de coordonnées à partir du premier Drawer.
// void  SetAxesFlags(unsigned int flags=kAxesDflt)
//	Définit les attributs des axes.
// int  AddScDrawer(PIDrawer*, bool ad=false)
//	Ajoute un Drawer.
//--


PIScDrawWdg::PIScDrawWdg(PIContainerGen *par, const char *nom,
                         int sx, int sy, int px, int py)
:PIBaseWdg(par, nom, sx, sy, px, py)
{
  mFgReticule = false;
  mCPosX = mCPosY = 0;
  mPPos[0] = mPPos[1] = 0.;
  mPSz[0] = mPSz[1] = 0.;
  mFormatOpt[0] = "%-g"; mFormatOpt[1] = "%-g";

  mBDrw = new PIElDrawer;
  SetLimits(-1.,1.,-1.,1.,kAxeDirLtoR,kAxeDirDownUp);
  SetAxesFlags(kBoxAxes | kExtTicks | kLabels);  
  FreeLimits();
  xEndDrag = yEndDrag = xBegDrag = yBegDrag = 0;
  SetDefaultDrawRectangle(0.12, 0.12, 0.88, 0.88, true);
//  SetDefaultDrawRectangle(0.12, 0.08, 0.88, 0.92, true);
  AddDrawer(mBDrw, true, false, false);

//  Pour afficher les coordonnees courante (click-bouton-1)  
  mTrlb = mTxw = NULL;
  mTrW = NULL;
  SetTextWin(NULL);

//  Affichage eventuelle d'infos-texte
  mInfoW = NULL;
  mInfoTxt = NULL;

  ActivateKeyboard();
  ActivateButton(1);    // Pour pouvoir activer la fenetre et coordonnees
  ActivateMove(1);      //    "         "         "        "
  ActivateButton(2);    //  Pour gerer le zoom
  ActivateMove(2);      //    "         "
  ActivateButton(3);    //  Pour definir la zone info-texte
  ActivateMove(3);      //    "         "

}

PIScDrawWdg::~PIScDrawWdg()
{
  delete mBDrw;
  if (mTrW)  delete mTrW;
  if (mInfoW) delete mInfoW;
  if (PIAxesTools::GetCurrentScDrawWdg() == this) 
    PIAxesTools::SetCurrentScDrawWdg(NULL);
  // Pour PIDrwTools, c'est fait par le destructeur de PIBaseWdgGen
}

void 
PIScDrawWdg::Keyboard(int key, PIKeyModifier kmod)
{
if (kmod == PIKM_Alt) {
  if      (key == 'R' || key == 'r')  Refresh(); // rafraichir l'affichage
  else if (key == 'M' || key == 'm') mFgReticule = !mFgReticule; // reticule de mesure 
  else if (key == 'V' || key == 'v') RequestSelection();  // Pour coller (copier/coller)  
  else if (key == 'Z' || key == 'z') { mBDrw->ElDelAll();  Refresh(); } // Pour supprimer tous les signes 
  else if (key == 'O' || key == 'o') ActivateSpecializedControls();
  else if (key == 'G' || key == 'g') { 
    PIDrwTools::SetCurrentBaseWdg(this);
    PIDrwTools::ShowPIDrwTools();   // Fentre axes et options de trace
    }
  else if (key == 'A' || key == 'a') { 
    PIAxesTools::SetCurrentScDrawWdg(this);
    PIAxesTools::ShowPIAxesTools();  // Fenetre de gestion des axes
  }
  else if (key == 'I' || key == 'i') UpdateInfoWindow();  // Fenetre Text-Info 
  }
}
void 
PIScDrawWdg::PasteSelection(unsigned int typ, void *pdata, unsigned int l)
{
if (typ != PICP_string) return;
int ll = (l<256) ? l+1 : 256;
char pc[256];
strncpy(pc, (char*)pdata, ll-1);  pc[ll-1] = '\0';
mBDrw->ElAddText(mPPos[0], mPPos[1], pc );
mBDrw->Refresh();
}

void
PIScDrawWdg::SetLimits(double xmin, double xmax, double ymin, double ymax,
                       int axrl, int ayud, bool tmp)
{
//  if (xmax <= xmin || ymax <= ymin) {
//    cerr << "PIScDrawWdg::SetLimits() Error - xmax <= xmin or ymax <= ymin !" << endl;
//    return; 
//    }
  double xym;
  xym = fabs(xmax+xmin); xym = (xym > 1.e-39) ? xym : 1.e-39;
  if ((xmax-xmin)/xym < 1.e-5) { xmin = xmin - 5.e-6*xym;  xmax = xmin + 1.e-5*xym; }
  xym = fabs(ymax+ymin); xym = (xym > 1.e-39) ? xym : 1.e-39;
  if ((ymax-ymin)/xym < 1.e-5) { ymin = ymin - 5.e-6*xym;  ymax = ymin + 1.e-5*xym; }

  SetDefaultDrawerLimits(xmin, xmax, ymin, ymax, axrl, ayud);
  mBDrw->SetLimits(xmin, xmax, ymin, ymax, axrl, ayud);
  mPPos[0] = 0.5*(XMin()+XMax());
  mPPos[1] = 0.5*(YMin()+YMax());
  mPSz[0] = 0.05*(XMax()+XMin());
  mPSz[1] = 0.05*(YMax()+YMin());
  if (!tmp) {
    xMinS = xmin;
    xMaxS = xmax;
    yMinS = ymin;
    yMaxS = ymax;
  }
  mFormatOpt[0] = SetFormatOpt(xmin,xmax);
  mFormatOpt[1] = SetFormatOpt(ymin,ymax);
}
  
void
PIScDrawWdg::UpdateLimits()
{
  if (NbDrawers() < 2)  return;
  PIDrawer* d = GetDrawer(1);
  if (d == NULL) return;
  d->UpdateLimits();
  SetLimits(d->XMin(), d->XMax(), d->YMin(), d->YMax(), mDXdir, mDYdir); 
  Refresh();
  return;  
}

int 
PIScDrawWdg::AddScDrawer(PIDrawer* d, bool ad)
{
  if (d == NULL)  return(-1);
  if (! LimitsFixed() ) {  //  On met a jour les limites 
    d->UpdateLimits();
    SetLimits(d->XMin(), d->XMax(), d->YMin(), d->YMax(), mDXdir, mDYdir);
  }
  return(AddDrawer(d, true, true, ad));
}


void
PIScDrawWdg::SetTextWin(PILabel * tw, bool trw, int tx, int ty)
{
mTxw = tw;
if (trw)
  {
  if (mTrW)  mTrW->SetSize(tx, ty);
  else
    {
    mTrW = new PIWindow(this, "Point", PIWK_transient, tx, ty, 0, 0);
    mTrW->SetAutoDelChilds(true);
    mTrlb = new PILabel(mTrW, "PointCoord", tx, ty, 0, 0);
    mTrlb->SetBinding(PIBK_fixed,PIBK_fixed, PIBK_fixed,PIBK_fixed);
    }
  }
else
  if (mTrW) { delete mTrW; mTrW = NULL;  mTrlb = NULL; }

return;
}



// Gestion affichage coordonnees du point 

string   
PIScDrawWdg::GetClickText(double x, double y) 
// Donne le texte a afficher pour position x,y  
{
  char buff[128];
  string format  = "X= ";  format += mFormatOpt[0].c_str();
         format += " Y= "; format += mFormatOpt[1].c_str();
  sprintf(buff,format.c_str(),x,y);
  return((string)buff);
}

void
PIScDrawWdg::ActivateSpecializedControls()
// Par défaut affiche la fenetres des attributs graphiques et axes
{
  PIDrwTools::SetCurrentBaseWdg(this);
  PIDrwTools::ShowPIDrwTools();   // Fentre axes et options de trace
}

void
PIScDrawWdg::UpdateInfoWindow()
{

if (mInfoW == NULL) { // Creation de la fenetre info
  string nom = Nom() + "-Info";
  int tpx, tpy;
  GetScreenPos(tpx, tpy);
  int sx, sy;
  int ssx, ssy;
  PIApplicationScreenSize(ssx, ssy);
  if ( (ssx > 1000) && (ssy > 1000) ) { sx = 400;  sy = 200; }
  else { sx = 300; sy = 160; }
  mInfoW = new PIWindow(this, nom.c_str(), PIWK_normal,  sx, sy, tpx, tpy+YSize()+10);
  mInfoW->SetAutoDelChilds(true);
  nom = Nom() + "-InfoText";
  mInfoTxt = new PIText(mInfoW, nom.c_str(), true, true, sx, sy, 0, 0);
  mInfoTxt->SetBinding(PIBK_fixed, PIBK_fixed, PIBK_fixed, PIBK_fixed);
  mInfoTxt->SetMutiLineMode(true);
  mInfoTxt->SetTextEditable(false);
  }

//  Boucle sur tous les drawers :
vector<BWDrwId>::iterator it;
char buff[128];
sprintf(buff, "Info: NDrawer= %d - Pos=%g %g  (Sz=%g,%g) \n", (int)mDrwList.size()-1, 
        mPPos[0], mPPos[1], mPSz[0], mPSz[1] );
double xmin, ymin, xmax, ymax;
xmin = mPPos[0] - 0.5*mPSz[0];
xmax = mPPos[0] + 0.5*mPSz[0];
ymin = mPPos[1] - 0.5*mPSz[1];
ymax = mPPos[1] + 0.5*mPSz[1];

string info = buff;
int k=0;
for(it = mDrwList.begin(); it != mDrwList.end(); it++) {
  if ((*it).drw == mBDrw )  continue;
  k++;
  sprintf(buff," --------- Drawer %d ----------- \n", k); 
  info += buff; 
  (*it).drw->AppendTextInfo(info, xmin, ymin, xmax, ymax);
  }

mInfoW->Show();
mInfoTxt->Manage();
mInfoTxt->SetText(info);
}

// .............................
// Bouton-1 : Position courante 

void
PIScDrawWdg::But1Press(int x, int y)
{
  int pos = (x>XSize()/2) ? PI_HorizontalRight: PI_HorizontalLeft;
  UpdateText(x, y);
  if (mTrW)
    { 
    int tpx, tpy;
    GetScreenPos(tpx, tpy);       
    tpy -= (mTrW->YSize()+5);
    if (tpy < 0)  tpy = 0;
    mTrW->SetPos(tpx, tpy);
    mTrW->Show();
    }
  if (mFgReticule) { // On trace une reticule
    cForCol = mWGrC->GetForeground();
    cGOmod  = mWGrC->GetGOMode();
    cLatt = mWGrC->GetLineAtt();
    mWGrC->SelForeground(PI_Magenta);
    mWGrC->SelGOMode(PI_GOXOR);
    mWGrC->SelLine(PI_ThinLine);
    mWGrC->DrawLine(x, 0, x, YSize());
    mWGrC->DrawLine(0, y, XSize(), y);
    mCPosX = x;   mCPosY = y;
    char buff[128];
    string format1 = "X= "; format1 += mFormatOpt[0].c_str();
    string format2 = "Y= "; format2 += mFormatOpt[1].c_str();
    sprintf(buff,format1.c_str(), mPPos[0], pos);
    mWGrC->DrawString(x+10, y-10, buff); 
    sprintf(buff,format2.c_str(), mPPos[1], pos);
    mWGrC->DrawString(x+10, y+20, buff); 
    }
  else SelPointerShape(PI_CrossPointer);

  Send(Msg(), PIMsg_Active);
  PIDrwTools::SetCurrentBaseWdg(this);
  PIAxesTools::SetCurrentScDrawWdg(this);
}

void
PIScDrawWdg::Ptr1Move(int x, int y)
{
  int pos = (x>XSize()/2) ? PI_HorizontalRight: PI_HorizontalLeft;
  char buff[128];
  string format1 = "X= "; format1 += mFormatOpt[0].c_str();
  string format2 = "Y= "; format2 += mFormatOpt[1].c_str();
  if (mFgReticule) { // On trace une reticule
    mWGrC->DrawLine(mCPosX, 0, mCPosX, YSize());
    mWGrC->DrawLine(0, mCPosY, XSize(), mCPosY);
    sprintf(buff,format1.c_str(), mPPos[0]);
    mWGrC->DrawString(mCPosX+10, mCPosY-10, buff, pos); 
    sprintf(buff,format2.c_str(), mPPos[1]);
    mWGrC->DrawString(mCPosX+10, mCPosY+20, buff, pos); 
    mWGrC->DrawLine(x, 0, x, YSize());
    mWGrC->DrawLine(0, y, XSize(), y);
    mCPosX = x;   mCPosY = y;
    }  
  UpdateText(x, y);  // Met a jour mPPos
  if (mFgReticule) {
    sprintf(buff,format1.c_str(), mPPos[0]);
    mWGrC->DrawString(mCPosX+10, mCPosY-10, buff, pos); 
    sprintf(buff,format2.c_str(), mPPos[1]);
    mWGrC->DrawString(mCPosX+10, mCPosY+20, buff, pos); 
    }
}

void
PIScDrawWdg::But1Release(int x, int y)
{
  int pos = (x>XSize()/2) ? PI_HorizontalRight: PI_HorizontalLeft;
  UpdateText(x, y);
  if (mFgReticule) { // On efface la reticule
    mWGrC->DrawLine(mCPosX, 0, mCPosX, YSize());
    mWGrC->DrawLine(0, mCPosY, XSize(), mCPosY);
    char buff[128];
    string format1 = "X= "; format1 += mFormatOpt[0].c_str();
    string format2 = "Y= "; format2 += mFormatOpt[1].c_str();
    sprintf(buff,format1.c_str(), mPPos[0]);
    mWGrC->DrawString(mCPosX+10, mCPosY-10, buff, pos); 
    sprintf(buff,format2.c_str(), mPPos[1]);
    mWGrC->DrawString(mCPosX+10, mCPosY+20, buff, pos); 
    mWGrC->SelForeground(cForCol);
    mWGrC->SelGOMode(cGOmod);
    mWGrC->SelLine(cLatt); 
    mCPosX = mCPosY = 0;
    }
  else SelPointerShape(PI_ArrowPointer);
  if (mTrW)  mTrW->Hide();
}

void
PIScDrawWdg::UpdateText(int xp, int yp)
{

  double dx, dy;
  mBDrw->GetGraphicUC()->GrC2UC(xp, yp, dx, dy); 
  mPPos[0] = dx;  mPPos[1] = dy; 
  
  string ctxt =  GetClickText(dx, dy);
//DEBUG  char buff[32];    sprintf(buff, " %d:%d",xp,yp); ctxt += buff;
  if (mTxw)
    mTxw->SetLabel(ctxt);
  if (mTrlb)
    mTrlb->SetLabel(ctxt);
  return;

}

// .............................
// Bouton-2 Gestion du zoom 

void
PIScDrawWdg::But2Press(int x, int y)
{
  xEndDrag = xBegDrag = x;
  yEndDrag = yBegDrag = y;
  cForCol = mWGrC->GetForeground();
  cGOmod  = mWGrC->GetGOMode();
  cPointer = GetPointerShape();
  cLatt = mWGrC->GetLineAtt();
  SelPointerShape(PI_CrossPointer);
  mWGrC->SelForeground(PI_Magenta);
  mWGrC->SelGOMode(PI_GOXOR);
  mWGrC->SelLine(PI_ThinLine);
  Send(Msg(), PIMsg_Active);
  PIDrwTools::SetCurrentBaseWdg(this);
  PIAxesTools::SetCurrentScDrawWdg(this);
}

void
PIScDrawWdg::But2Release(int /*x*/, int /*y*/)
{

  mWGrC->DrawBox(xBegDrag, yBegDrag, xEndDrag-xBegDrag, yEndDrag-yBegDrag);

  mWGrC->SelForeground(cForCol);
  mWGrC->SelGOMode(cGOmod);
  SelPointerShape(cPointer); 
  mWGrC->SelLine(cLatt); 

  //  Pour rendre le changement de zoom moins delicat $REZA - 05/99$  
  int dxd = xEndDrag-xBegDrag;
  if (dxd < 0) dxd = -dxd;
  int dyd = yEndDrag-yBegDrag;
  if (dyd < 0) dyd = -dyd;
  //  if (xBegDrag == xEndDrag || yBegDrag == yEndDrag) // $REZA - 05/99$  
  if ( (dxd < 5) || (dyd < 5) )    // $REZA - 05/99$  
    SetLimits(xMinS, xMaxS, yMinS, yMaxS, kAxeDirSame, kAxeDirSame );
  else {
    double xl,yl,xh,yh;
    mBDrw->GetGraphicUC()->GrC2UC(xBegDrag, yBegDrag, xl, yl);
    mBDrw->GetGraphicUC()->GrC2UC(xEndDrag, yEndDrag, xh, yh);
    if (xl > xh) dbl_swap(xl, xh);
    if (yl > yh) dbl_swap(yl, yh);
    SetLimits(xl,xh,yl,yh, kAxeDirSame, kAxeDirSame, true);
  }
  
  Refresh();
}

void
PIScDrawWdg::Ptr2Move(int x, int y)
{
  mWGrC->DrawBox(xBegDrag, yBegDrag, xEndDrag-xBegDrag, yEndDrag-yBegDrag);
  xEndDrag = x;
  yEndDrag = y;
  mWGrC->DrawBox(xBegDrag, yBegDrag, xEndDrag-xBegDrag, yEndDrag-yBegDrag);
}


// .............................
// Bouton-3 : Gestion de definition de la taille de rectangle Text-Info

void
PIScDrawWdg::But3Press(int x, int y)
{
  xEndDrag = xBegDrag = x;
  yEndDrag = yBegDrag = y;
  cForCol = mWGrC->GetForeground();
  cGOmod  = mWGrC->GetGOMode();
  cPointer = GetPointerShape();
  cLatt = mWGrC->GetLineAtt();
  SelPointerShape(PI_CrossPointer);
  mWGrC->SelForeground(PI_Magenta);
  mWGrC->SelGOMode(PI_GOXOR);
  mWGrC->SelLine(PI_ThinLine);
  Send(Msg(), PIMsg_Active);
  PIDrwTools::SetCurrentBaseWdg(this);
  PIAxesTools::SetCurrentScDrawWdg(this);
}

void
PIScDrawWdg::But3Release(int /*x*/, int /*y*/)
{

  mWGrC->DrawBox(xBegDrag, yBegDrag, xEndDrag-xBegDrag, yEndDrag-yBegDrag);

  mWGrC->SelForeground(cForCol);
  mWGrC->SelGOMode(cGOmod);
  SelPointerShape(cPointer); 
  mWGrC->SelLine(cLatt); 

  double xl,yl,xh,yh;
  mBDrw->GetGraphicUC()->GrC2UC(xBegDrag, yBegDrag, xl, yl);
  mBDrw->GetGraphicUC()->GrC2UC(xEndDrag, yEndDrag, xh, yh);
  if (xl > xh) dbl_swap(xl, xh);
  if (yl > yh) dbl_swap(yl, yh);
  mPPos[0] = 0.5*(xl+xh);
  mPPos[1] = 0.5*(yl+yh);
  mPSz[0] = xh-xl;
  mPSz[1] = yh-yl;
  mCPosX =  0.5*(xBegDrag+xEndDrag);
  mCPosY =  0.5*(yBegDrag+yEndDrag);

  return;
}

void
PIScDrawWdg::Ptr3Move(int x, int y)
{
  mWGrC->DrawBox(xBegDrag, yBegDrag, xEndDrag-xBegDrag, yEndDrag-yBegDrag);
  xEndDrag = x;
  yEndDrag = y;
  mWGrC->DrawBox(xBegDrag, yBegDrag, xEndDrag-xBegDrag, yEndDrag-yBegDrag);
}

string
PIScDrawWdg::SetFormatOpt(double xmin,double xmax)
{
  string format = "%-g";
  //PIDrawer::BonFormatAxes(xmin,xmax,(xmax-xmin)*0.9999,format,2);
  double xm = (fabs(xmax)>fabs(xmin)) ? fabs(xmax): fabs(xmin);
  double dx = fabs(xmax-xmin)/500.;
  PIDrawer::BonFormatAxes(xm,xm+dx,dx*0.9999,format,0);
  return format;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// ----------------------------------------------------------
//  Classe de trace de points/fonctions Y=f(X)
//  Trace Y=ay->Value() = f(X= ax->Value()) si ax et ay != NULL
//  Trace Y=ax->Value() = f(X= ax->X())  si ay == NULL
// ----------------------------------------------------------
// --------------------------------------------------------------------------

//++
// Class	PIYfXDrawer
// Lib		PI
// include	piscdrawwdg.h
//
//	Classe de traceur de points/fonctions Y = f(X).
//--
//++
// Links	Parents
// PIDrawer
//--
//++
// Links	Voir aussi
// P1DArrayAdapter
//--
//++
// Titre	Constructeur
//--

//++
// PIYfXDrawer(P1DArrayAdapter* ax, P1DArrayAdapter* ay, bool ad)
//	Constructeur. Tracé de 
//|	 Y=ay->Value() = f(X= ax->Value()) si ax et ay != NULL
//|	Y=ax->Value() = f(X= ax->X())  si ay == NULL
//	Si "ad==true" les objets "ax" et "ay" sont détruits par 
//	le destructeur de "PIYfXDrawer".
//--

/* --Methode-- */
PIYfXDrawer::PIYfXDrawer(P1DArrayAdapter* ax, P1DArrayAdapter* ay, bool ad)
    : PIDrawer()
{
  mAdDO = ad;
  mAx = ax;
  mAy = ay;
} 

/* --Methode-- */
PIYfXDrawer::~PIYfXDrawer()
{
  if (mAdDO && mAx)  delete mAx;
  if (mAdDO && mAy)  delete mAy;
}

/* --Methode-- */
void PIYfXDrawer::UpdateLimits()
{
  if ((mAx == NULL))  mSz = 0;
  else {
    if (!mAy)  mSz = mAx->Size();
    else   mSz = (mAx->Size() < mAy->Size()) ? mAx->Size() :  mAy->Size();
    }
  if (mSz <= 0)  return;
  double xmin, xmax, ymin, ymax;
  int i=0;
  double cv;
  if (mAy) {
    xmin = xmax = mAx->Value(0);
    ymin = ymax = mAy->Value(0);
    for(i=1; i<mSz; i++) {
      cv = mAx->Value(i); 
      if (cv < xmin)  xmin = cv;
      if (cv > xmax)  xmax = cv;
      cv = mAy->Value(i); 
      if (cv < ymin)  ymin = cv;
      if (cv > ymax)  ymax = cv;
      }
    }
  else {
    xmin = xmax = mAx->X(0);
    ymin = ymax = mAx->Value(0);
    for(i=1; i<mSz; i++) {
      cv = mAx->X(i); 
      if (cv < xmin)  xmin = cv;
      if (cv > xmax)  xmax = cv;
      cv = mAx->Value(i); 
      if (cv < ymin)  ymin = cv;
      if (cv > ymax)  ymax = cv;
      }
    }

  double dx, dy;
  dx = 0.02*(xmax-xmin);
  dy = 0.02*(ymax-ymin);

  SetLimits(xmin-dx, xmax+dx, ymin-dy, ymax+dy);
  SetAxesFlags(kBoxAxes | kExtTicks | kLabels);
}


/* --Methode-- */
void PIYfXDrawer::Draw(PIGraphicUC* g, double xmin, double ymin, double xmax, double ymax)
{
  double xp,yp;
  int i;

  if ((mAx == NULL))  mSz = 0;
  else {
    if (!mAy)  mSz = mAx->Size();
    else   mSz = (mAx->Size() < mAy->Size()) ? mAx->Size() :  mAy->Size();
    }
  if (mSz <= 0)  return;

//  Trace des markers 
  if ( (mMrk != PI_NotDefMarker) ||  (mLAtt == PI_NotDefLineAtt) ) {
    for(i=0; i<mSz; i++) {
      if (mAy) { xp = mAx->Value(i); yp = mAy->Value(i); }
      else { xp = mAx->X(i);  yp = mAx->Value(i); }
      if ( (xp < xmin) || (xp > xmax) || (yp < ymin) || (yp > ymax) )  continue;
      g->DrawMarker(xp, yp);
    }
  }

  if (mLAtt == PI_NotDefLineAtt)    return;

// Trace des lignes 
  double xp2, yp2;
  if (mAy) { xp2 = mAx->Value(0); yp2 = mAy->Value(0); }
  else { xp2 = mAx->X(0);  yp2 = mAx->Value(0); }
  for(i=1; i<mSz; i++) {
    xp = xp2; yp = yp2;
    if (mAy) { xp2 = mAx->Value(i); yp2 = mAy->Value(i); }
    else { xp2 = mAx->X(i);  yp2 = mAx->Value(i); }
    if ( ((xp < xmin) || (xp > xmax) || (yp < ymin) || (yp > ymax)) &&
         ((xp2 < xmin) || (xp2 > xmax) || (yp2 < ymin) || (yp2 > ymax)) )  continue;
    g->DrawLine(xp, yp, xp2, yp2);
  }
}


//================================================================
// PIFuncDrawer
// Classe de traceur de fonction  double = f(fouble)
//================================================================

//++
// Class	PIFuncDrawer
// Lib		PI
// include	piscdrawwdg.h
//
//	Classe de traceur de fonctions Y = f(double X).
//--
//++
// Links	Parents
// PIDrawer
//--
//++
// Titre	Constructeur
//--
//++
//  PIFuncDrawer(FUNC f)
//	Cosntructeur de traceur d'une fonction "FUNC f" avec
//|	typedef double(*FUNC)(double)
//--


/* --Methode-- */
PIFuncDrawer::PIFuncDrawer(PIFuncDrawer::FUNC f)
: mFunc(f)
{}

/* --Methode-- */
PIFuncDrawer::~PIFuncDrawer()
{
}

/* --Methode-- */
void
PIFuncDrawer::Draw(PIGraphicUC* g, double /*xmin*/, double/*ymin*/, double/*xmax*/, double/*ymax*/)
{
  PIGrCoord x1, x2, y1, y2;
  g->GetGrSpace(x1, x2, y1, y2);
  double xMax = x2;
  double xMin = x1;
  double yMax = y2;
  double yMin = y1;
  double xStep = (xMax - xMin)/100;
  double xOld = xMin;
  double yOld = mFunc(xMin);
  for (double x = xMin+xStep; x<xMax; x+=xStep) {
    double y = mFunc(x);
    if (y>yMin && yOld>yMin && 
        y<yMax && yOld<yMax) 
           g->DrawLine(xOld, yOld, x, y);
    xOld = x;
    yOld = y;
  }
}
