// Module PI : Peida Interactive     PIImage
// Affichage d'image            R. Ansari  05/95
// LAL (Orsay) / IN2P3-CNRS  DAPNIA/SPP (Saclay) / CEA
//                        Refonte   Reza   10/95


#include "sopnamsp.h"
#include "pisysdep.h"
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <ctype.h>
#include <math.h>

#include "piimage.h"
#include "piimgtools.h"
#include "pidrwtools.h"
#include "piscdrawwdg.h"
#include "piyfxdrw.h"
#include PIAPP_H

#define PERC_GARDE 0.05

//++
// Class	PIImage
// Lib		PI
// include	piimage.h
//
//   	Classe pour la l'affichage et la manipulation d'images.
//	Peut contrôler un PIPixmap pour l'affichage d'une zone
//	agrandie (zoom) et un PIPixmap pour l'affichage de toute
//	l'image (réduite). Peut aussi gerer une fenetre de coupes.
//	Utilise les adaptateur de tableaux 2D manipuler le
//	contenu des images ("P2DArrayAdapter").
//
//	* Bouton-1 : Envoie le message "PIMsg_Active" et affiche
//	les coordonnées courantes et la valeur du pixel, 
//	et positionne le pavé.
//	* Bouton-2 : Permet de définir une zone de l'image et repositionne le pavé.
//	* Bouton-3 : Permet de déplacer l'image dans la fenêtre
//
//	Gestion du clavier :
//	* <Alt>O : Affichage de la fenêtre de contrôle des paramètres de visualisation.
//	* <Alt>G : Affichage de la fenêtre de changement des attributs graphiques
//	* <Alt>D : Affichage du menu de manipulation des traceurs (drawers)
//	* <Alt>R : Rafraîchit l'affichage.
//	* <Alt>V : Copier/*Coller* Ajout du texte du buffer copier/coller
//	sur l'objet à la position courante.
//	* <Alt>C : *Copier*/Coller Permet de copier le contenu de la zone sélectionnée
//	de l'image sous forme texte.
//	* <Alt>P : Active/désactive l'affichage de l'indicateur de la postion du pavé
//	* <Alt>X : Active/désactive l'affichage des coupes X,Y
//	* <Alt>Z : Supprime les élément graphiques ajoutés au dessin.
//	* <Alt>E : Supprime le dernier élément graphique ajouté.
//	* <Alt>+ <Cntl>+ : Augmentation du facteur de zoom
//	* <Alt>- <Cntl>- : Diminution du facteur de zoom
//	* Touches Curseurs : déplace le pavé.
//--
//++
// Links	Parents
// PIPixmap
//--
//++
// Links	Voir aussi
// PIColorMap
// P2DArrayAdapter
// PIImgTools
// PIDrwTools
//--

//++
// Titre	Constructeurs
//--
//++
//  PIImage(PIContainerGen *par, const char *nom=NULL, int sx=0, int sy=0, int px=0, int py=0)
//	Constructeur
//  
//--

// --------------------------------------------------------------------------------
// ----------------------------- Classe PIImage -----------------------------------
// --------------------------------------------------------------------------------
// Variable globale pour la gestion de l'image courante 
PIImage* PIImage::cur_piimage = NULL;
/* --Methode-- */
PIImage* PIImage::CurrentPIImage() 
{ 
return(cur_piimage); 
}

/* --Methode-- */
void PIImage::SetCurrentPIImage(PIImage* curimg) 
{ 
cur_piimage = curimg;
}

/* --Methode-- */
PIImage::PIImage(PIContainerGen *par, const char *nom,
   int sx, int sy, int px, int py) :
  PIPixmap(par, nom, sx, sy, px, py)
{

img = NULL;
aisup = false;
curshow = true;
winovis = true;     // $CHECK$ Reza A enlever si possible 17/6/96


zow = NULL;   // Widget zoom
gvw = NULL;   // widget vue globale
cmvw = NULL;  // widget ColorMapView
fgshowcmap = 0;  // 0: Pas de vue ColMap, 1: top, 2:right,  3:bottom, 4:left
 cmdid = -1;
// Fenetre transient et Label pour affichage de l'info (texte PixVal)
int tx, ty;
PIApplicationPrefCompSize(tx, ty);
tx *= 5;    ty = (int)(ty*0.8);
trtw = new PIWindow(this, "PixVal", PIWK_transient, tx, ty, 0, 0);
trtw->SetAutoDelChilds(true);
trtlb = new PILabel(trtw, "PixVal", tx, ty, 0, 0);
trtlb->SetBinding(PIBK_fixed,PIBK_fixed, PIBK_fixed,PIBK_fixed);
ustrtw = atrtw = false;
if ((sx < 300) || (sy < 150) ) atrtw = true;
showinfo = false;

// Fenetre et ScDrawWdg pour les coupes
selcuts = 3;
cutwin = NULL;
cutscw = NULL; 

lut = NULL; 
offx = offy = 0;
xpav = ypav = 0;
xpv0 = ypv0 = 0;
xszpav = yszpav = 1;
xmv0 = ymv0 = -1;
dxmv = dymv = 0;
xcurs = ycurs = -1;
cuhsz = 8;  cuvsz = 8;
cucol = PI_Yellow; culat = PI_NormalLine; 
zoom = 1;
zmgv = 1;

mdrw = new PIElDrawer(false);
mdrw->SetAxesFlags(kAxesNone);
gvdrw = new PIElDrawer();
AddDrawer(mdrw, true, false, false, false);

SetLut(AutoLut_No, -9.e19, 9.e19, kLutType_Lin, 0, false);
SetColMapId(CMAP_COLRJ32);
// pour le copier-coller
cpbuffer = NULL;
cpbuflen = 0;

// Menu pour la manipulation des drawers 
mDrwMen = NULL;

SetBackgroundColor(PI_Black);

ActivateKeyboard();
ActivateButton(1);
ActivateMove(1);
ActivateButton(2);
ActivateMove(2);
ActivateButton(3);
ActivateMove(3);

cur_piimage = this;
}

/* --Methode-- */
PIImage::~PIImage()
{
if (zow) 
  {
  zow->SetPixmap(NULL);
  zow->EraseWindow();
  }
if (gvw) 
  {
  gvw->SetPixmap(NULL);
  gvw->EraseWindow();
  gvw->SetMsg(0); gvw->SetMsgParent(NULL); 
  gvw->SetUserData(NULL, 0); 
  }
if (cmvw)  cmvw->SetColMap(NULL, 1., -1., true);
if (cutwin)  delete cutwin;
if (lut) delete lut;
delete mdrw;
delete gvdrw;
if (aisup && img)  delete img;   // Suppression automatique d'image
delete trtw;
if (cpbuffer)  delete[] cpbuffer;
if (mDrwMen) delete mDrwMen;
if (this == cur_piimage)  cur_piimage = NULL;
}

/* --Methode-- */
void PIImage::Process(PIMessage msg, PIMsgHandler* sender, void* data)
{

if ((ModMsg(msg) == PIMsg_Close) && (sender == cutwin)) {
  cutwin->Hide();
  delete cutwin;
  cutwin = NULL;
  cutscw = NULL;
  }
else if (UserMsg(msg) == (Msg()+626))
  {
  if (ModMsg(msg) == PIMsg_Click) 
    { int* pxy=(int *)data;   SetPave(pxy[0]*zmgv, pxy[1]*zmgv); }
  if (ModMsg(msg) == PIMsg_Resize)
    { ComputeGloVPixmap();   SetGloVPixmap(); }
  }
else ReSend(msg, sender, data);
return;
}

//++
// Titre	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
//--

//++
// void SetImage(P2DArrayAdapter* pim, bool ad = true, bool refr=true)
//	Associe un tableau "P2DArrayAdapter* pim" a l'objet "PIImage"
//	pour affichage. si "ad==true", la tableau "pim" est detruit
//	(par delete) lors de la destruction de l'objet PIImage.
//	Si "ref==true", la fenetre est rafraichie.
// void SetZoomWin(PIPixmap * zw, bool refr=false)
//	Associe une fenetre "(PIPixmap * zw)" pour l'affichage
//	d'une portion d'image agrandie.
//	Si "refr=="true", la fenetre de zoom est rafraichie
// SetGloVWin(PIPixmap * zw, bool refr=false)
//	Associe une fenetre "(PIPixmap * zw)" comme fenetre de vue globale
//	de l'image.
//	Si "refr=="true", la fenetre de vue globale est rafraichie
// SetCMapWin(PICMapView * cw, bool refr=false)
//	Associe un objet "PICMapView * cw" pour l'affichage de la table
//	des couleurs.
//	Si "refr=="true", la fenetre de la table des couleurs est rafraichie
//--

/* --Methode-- */
void PIImage::SetImage(P2DArrayAdapter *pim, bool ad, bool refr)
{

offx = offy = 0;
xpav = ypav = 0;
xszpav = yszpav = 1;
img = pim;
gpixm.DeAlloc();
zmgv = 1;

if (img)  {
//  SetSize(img->XSize(), img->YSize());
// Reza, Aout 2007 : SetLut par defaut passe a AutoLut MeanSigma a 2 sigmas
// a l'occasion des corrections et nouveaux types de calculs d'autolut
  CenterPave();
  double min=1., max=-1.;
  SetLut(AutoLut_MeanSigma, min, max, kLutType_Lin, 2., refr);
  aisup = ad;
  }
else aisup = false;
return;
}

/* --Methode-- */
void PIImage::ChangeAxesConfiguration(bool ix, bool iy, bool xy, bool refr)
{
if (!img) return;
bool invx, invy, exy;
img->GetAxesConfiguration(invx, invy, exy);
if (ix)  invx = !invx;
if (iy)  invy = !invy;
if (xy)  exy = !exy;
img->ConfigureAxes(invx, invy, exy);
ComputeGloVPixmap();
if (refr) Apply();
}

/* --Methode-- */
void PIImage::SetZoomWin(PIPixmap * zw, bool refr) 
{
zow = zw;
if (zow && refr && img)
  ComputeZoomPixmap();
return;
}

/* --Methode-- */
void PIImage::SetGloVWin(PIPixmap * zw, bool refr) 
{
gvw = zw;
if (gvw && img)  
  { ComputeGloVPixmap();
  if (refr) SetGloVPixmap(); } 
return;
}

/* --Methode-- */
void PIImage::SetCMapWin(PICMapView * cw, bool refr)
{
cmvw = cw;
if (cmvw && refr) cmvw->SetColMap(cmap, Lut()->Min(), Lut()->Max(), true);
}


/* --Methode-- */
void PIImage::UseInfoWin(bool trw)
{
ustrtw = trw;
}

/* --Methode-- */
void PIImage::ShowInfo(bool si)
{
if (showinfo == si) return;
showinfo = si;
if (showinfo && img)  { 
  char * ibuff = img->InfoString(xpav, ypav);
  DrawInfo(mWGrC, ibuff);
  }
else DrawInfo(mWGrC, NULL);
}

/* --Methode-- */
void PIImage::ShowCursor(bool sc)
{
if (curshow == sc) return;
curshow = sc;
if (curshow)  DrawCursor(mWGrC);
else DrawCursor(mWGrC, -1, -1);
return;
}


/* --Methode-- */
void PIImage::ShowCuts(bool cuts)
{
if (cuts) {
  if (cutwin) { cutwin->Show(); return; }
  int tpx, tpy;
  GetScreenPos(tpx, tpy);
  string nom = Nom() + "-Cuts";
  int sx, sy;
  int ssx, ssy;
  PIApplicationScreenSize(ssx, ssy);
  if ( (ssx > 1000) && (ssy > 1000) ) { sx = 400;  sy = 250; }
  else { sx = 300; sy = 200; }
  cutwin = new PIWindow(this, nom.c_str(), PIWK_normal, sx, sy, tpx, tpy+YSize()+10);
  cutwin->SetAutoDelChilds(true);
  nom += "_ScWdg";
  cutscw = new PIScDrawWdg(cutwin, nom.c_str(), sx, sy, 0, 0);
  cutscw->SetBinding(PIBK_fixed, PIBK_fixed, PIBK_fixed, PIBK_fixed);
  cutarrx = new PIImg1DArrAdapter();
  cutarry = new PIImg1DArrAdapter();
  cutarrd = new PIImg1DArrAdapter();
  cutarra = new PIImg1DArrAdapter();
  PIYfXDrawer * drw;
  string dum = "";
  drw = new PIYfXDrawer(cutarrx, NULL, true);
    drw->GetGraphicAtt().SetColAtt(PI_Red);
    drw->GetGraphicAtt().SetMarkerAtt(5, PI_CrossMarker);
    drw->GetGraphicAtt().SetLineAtt(PI_ThinLine);
    cutscw->AddScDrawer(drw, true);
    dum += "Red: X, ";
  drw = new PIYfXDrawer(cutarry, NULL, true);
    drw->GetGraphicAtt().SetColAtt(PI_Blue);
    drw->GetGraphicAtt().SetMarkerAtt(5, PI_TriangleMarker);
    drw->GetGraphicAtt().SetLineAtt(PI_ThinLine);
    cutscw->AddScDrawer(drw, true);
    dum += "Blue: Y, ";
  drw = new PIYfXDrawer(cutarrd, NULL, true);
    drw->GetGraphicAtt().SetColAtt(PI_Green);
    drw->GetGraphicAtt().SetMarkerAtt(5, PI_PlusMarker);
    drw->GetGraphicAtt().SetLineAtt(PI_ThinLine);
    cutscw->AddScDrawer(drw, true);
    dum += "Green: XY, ";
  drw = new PIYfXDrawer(cutarra, NULL, true);
    drw->GetGraphicAtt().SetColAtt(PI_Orange);
    drw->GetGraphicAtt().SetMarkerAtt(5, PI_BoxMarker);
    drw->GetGraphicAtt().SetLineAtt(PI_ThinLine);
    cutscw->AddScDrawer(drw, true);
    dum += "Orange: -XY";
  cutscw->SetTitles(dum, "");
  // UpdateCuts contient Refresh fait apres Show (21/08/2007)
  // pour regler le pb de la fenetre de CutXY blanche + clic -> coredump
  cutwin->Show();
  UpdateCuts();
  }
else {
  if (!cutwin)  return;
  cutwin->Hide();
  delete cutwin;
  cutwin = NULL;
  cutscw = NULL;
  }
}

/* --Methode-- */
void PIImage::SelectCuts(unsigned xyda)
// choix des cuts pour le display:
// 1=axe des (X), 2=axe des (Y), 4=diag (X,Y), 8=anti-diag (X,-Y)
{
selcuts = xyda;
if(!(selcuts&15)) selcuts = 3;
UpdateCuts();
}

//++
// SetLut(AutoLutType alt, double min, double max, int typlut=kLutType_Lin, \
//        double nsa=1., bool refr=true)
//	Definit la LUT pour l'affichage
//	Si "refr=="true", la fenetre est rafraichie
// SetLut(LUT *clut, bool refr=true)
//	Associe l'objet "LUT* clut", a l'objet PIImage. "clut" doit 
//	etre construit avec new 
// SetZoom(int zm, bool refr=true);
//	Changement du facteur d'agrandissement - si zm Negatif, l'image
//	sera reduit (taille d'affichage) du facteur 1/(-zm)
//	Si "refr=="true", la fenetre est rafraichie
// SetZoomF(float fzm, bool refr=true)
//	Specification du facteur d'agrandissement en valeur flottante.
// SetColMap(PIColorMap* cmp, bool refr=true)
//	Specification d'une nouvelle table de couleur, "PIColorMap* cmp"
//	qui doit etre obtenu par new.
//	Si "refr=="true", la fenetre est rafraichie
// SetColMapId(CMapId cmapid, bool refr=true)
//	pecification d'une nouvelle table de couleur	
//--

/* --Methode-- */
void PIImage::SetLut(AutoLutType alt, double min, double max, int typlut, double nsa, bool refr)
{
t_al = alt; 
if (alt != AutoLut_No) { 
  min_al = min; max_al = max; ns_al = nsa;
}
if (lut) delete(lut);
int nbnul, nbsat;
double moy, sig, fracmax;
double dmx, smin, smax;
bool fgtail;

switch (alt)
{
 case AutoLut_No :
   if (min >= max)  img->CheckDyn(min, max, moy, sig, nbnul, nbsat);
   break;
 case AutoLut_Range :
   img->ComputeLut_Range(min, max,(1.-nsa)/2.,(1.-nsa)/2., 5000);
   break;
 case AutoLut_MinMax :
   min = 1.; max = -1.;  
   img->CheckDyn(min, max, moy, sig, nbnul, nbsat);
   if (max <= min) max = min+0.1*fabs(min);
   if ((nsa <= 0.)||(nsa > 1.))  nsa = 1.;
   dmx = (1.-nsa)*(max-min);
   min = min+dmx/2.;  max = max-dmx/2.;
   break; 
 case AutoLut_MeanSigma :
   img->CheckDyn(min, max, moy, sig, nbnul, nbsat);
   smin = min, smax = max;
   min = moy - nsa*sig;   max = moy + nsa*sig;
   if (min < smin) min = smin;
   if (max > smax) max = smax;
   break;
 case AutoLut_HistoPeak :
 case AutoLut_HistoTail :
   fracmax = 1.-0.05*nsa;
   if (min >= max)  img->CheckDyn(min, max, moy, sig, nbnul, nbsat);
   fgtail = (alt == AutoLut_HistoTail) ? true : false;
   img->ComputeLut_PicHisto(min, max, fgtail, nsa, fracmax);
   break;
} 

if (max <= min) max = min + 0.1*fabs(min);
lut = new LUT(min, max, NbCol(), typlut);

ComputeGloVPixmap();
if (refr) Apply();
return;
}


/* --Methode-- */
void PIImage::SetLut(LUT *clut, bool refr)
{
t_al = AutoLut_No;
LUT * olut = lut;
lut = new LUT(clut->Min(), clut->Max(), NbCol(), clut->Type());
if (olut) delete olut;

ComputeGloVPixmap();
if (refr) Apply();
return;
}

/* --Methode-- */
void PIImage::SetZoomF(float fzm, bool refr)
{
int zm;

if (fzm < 0.001) return;
if (fzm < 1.)  zm = (int)(-(1./fzm));
else zm = (int)(fzm+0.25);
SetZoom(zm, refr);
return;
}

/* --Methode-- */
void PIImage::SetZoom(int zm, bool refr)
{
if ((zm == 0) || (zm == -1) )  zoom = 1;
else if (zm > 128)  zoom = 128;
else if (zm < -128) zoom = -128;
else zoom = zm;
if (img)
  { SetOffsetFromPave();
  if (refr) Apply(); }
return;
}

/* --Methode-- */
float PIImage::GetZoomF() const 
{
if (zoom >= 1)  return((float)zoom);
else return(-1./(float)zoom);
}


/* --Methode-- */
void PIImage::SetOffset(int ox, int oy, bool refr)
{
if (img == NULL)  {offx = offy = 0;  return; }
if (ox < 0)  ox = 0;
if (ox >= (img->XSize()-1))  ox = img->XSize()-2;
if (oy < 0)  oy = 0;
if (oy >= (img->YSize()-1))  oy = img->YSize()-2;
offx = ox;  offy = oy;
CenterPave();
if (refr) Apply();
return;
}


/* --Methode-- */
int PIImage::DecodeOptionString(vector<string> & opt, bool rmdecopt)
{
  vector<string> udopt;
  unsigned int k = 0;
  int ndec = opt.size();  
  int optsz1 = ndec;
  bool fgcmapid=false, revcmapid=false; CMapId cmapid=CMAP_COLRJ32;
  bool invx = false;
  bool invy = false;
  bool exchxy = false;
  bool confaxes = false;

  for( k=0; k<opt.size(); k++ ) {
    string opts = opt[k];
    // Couleur d'arriere plan du widget
    if (opts.substr(0,7) == "wbgcol=") {
      vector<string> vsc;
      vsc.push_back(opts.substr(7));
      SetBackgroundColor(PIGraphicAtt(vsc).GetColor());
      continue;
    }
    // Facteur de zoom
    if (opts.substr(0,5) == "zoomx") {
      int zf = atoi(opts.substr(5).c_str());
      SetZoom(zf, false);
      continue;
    }
    if (opts.substr(0,5) == "zoom/") {
      int zf = -atoi(opts.substr(5).c_str());
      SetZoom(zf, false);
      continue;
    }
    // Reverse table de couleur
    if (opts == "revcmap") {
      revcmapid = true;
      continue;
    }
    // Table de couleur
    bool fgcmap = false;
    for(int kcc=0; kcc<PIColorMap::NumberStandardColorMaps(); kcc++) {
      string colname = PIColorMap::GetStandardColorMapName(kcc);
      for(unsigned int jll=0; jll<colname.length(); jll++)
	colname[jll] = tolower(colname[jll]);
      if (opts == colname) {
	fgcmapid = fgcmap = true;
        cmapid = PIColorMap::GetStandardColorMapId(kcc);
	break;
      }
    }
    if (fgcmap) continue;
    // Position du centre d'image
    if (opts.substr(0,12) == "imagecenter=") {
      int xc = XPave();  
      int yc = YPave();
      sscanf(opts.substr(12).c_str(),"%d,%d",&xc, &yc);
      SetPave(xc, yc, false, true);
      continue;
    }
    // Configuration axes 
    if (opts == "invx") {
      invx = true;
      confaxes = true;
      continue;
    }
    if (opts == "invy") {
      invy = true;
      confaxes = true;
      continue;
    }
    if (opts == "exchxy") {
      exchxy = true;
      confaxes = true;
      continue;
    }
    // Changementr de lut - avec specification type de lut [et min/max] 
    if (opts.substr(0,4) == "lut=") {
      double min = Lut()->Min();
      double max = Lut()->Max();
      int typlut=kLutType_Lin;      ;
      if (opts.substr(4,3) == "lin")  typlut=kLutType_Lin;
      else if (opts.substr(4,3) == "log")  typlut=kLutType_Log;
      else if (opts.substr(4,3) == "exp")  typlut=kLutType_Exp;
      else if (opts.substr(4,4) == "sqrt")  typlut=kLutType_Sqrt;
      else if (opts.substr(4,6) == "square")  typlut=kLutType_Square;
      else if (opts.substr(4,3) == "rgb")  { 
        typlut=kLutType_RGB;
        min = 0;  max = 255;
      } 
      size_t q = opts.find(',');
      if (q < opts.length()-1)
	sscanf(opts.substr(q+1).c_str(),"%lg,%lg",&min, &max);

      SetLut(AutoLut_No, min, max, typlut, 0, false);
      continue;
    }
    // Auto lut avec specification type auto-lut [et nb-sigmas] (Aout2007)
    if (opts.substr(0,8) == "autolut=") {
      double min = min_al;
      double max = max_al;
      int ctlut = Lut()->Type();
      double pnsal = ns_al; 
      size_t q = opts.find(',');
      if (q < opts.length()-1) {
	string suop = opts.substr(q+1);
	size_t q2 = suop.find(','); 
	if (q2 < suop.length()-1) 
	  sscanf(suop.c_str(),"%lg,%lg,%lg",&pnsal,&min, &max);
	else pnsal = atof( suop.c_str() );
      }
      AutoLutType palt = AutoLut_No;
      if (opts.substr(8,6) == "minmax")  palt = AutoLut_MinMax;
      else if (opts.substr(8,7) == "meansig")  palt = AutoLut_MeanSigma;
      else if (opts.substr(8,7) == "hispeak")  palt = AutoLut_HistoPeak;
      else if (opts.substr(8,6) == "hispic")   palt = AutoLut_HistoPeak;
      else if (opts.substr(8,7) == "histail")  palt = AutoLut_HistoTail;
      else if (opts.substr(8,6) == "hisrng")   palt = AutoLut_Range;
      if ( palt != AutoLut_No )  SetLut(palt, min, max, ctlut, pnsal, false);
      continue;
    }
    if (opts == "showcmap")  UpdateCMapDrawer(1);
    else if (opts == "noshowcmap")  UpdateCMapDrawer(0);
    else if (opts.substr(0,9) == "showcmap=") {
      if (opts.substr(9,2) == "no")   UpdateCMapDrawer(0); 
      else if (opts.substr(9,3) == "top")     UpdateCMapDrawer(1); 
      else if (opts.substr(9,5) == "right")   UpdateCMapDrawer(2); 
      else if (opts.substr(9,6) == "bottom")  UpdateCMapDrawer(3); 
      else if (opts.substr(9,4) == "left")    UpdateCMapDrawer(4); 
      else if (opts.substr(9,5) == "horiz")   UpdateCMapDrawer(1); 
      else if (opts.substr(9,4) == "vert")    UpdateCMapDrawer(2); 
      else UpdateCMapDrawer(0); 
    }

    ndec--;
    udopt.push_back(opts);
  }
  // Set color map if requested
  if(fgcmapid || revcmapid) 
    SetColMapId(cmapid,revcmapid,false);  

  // Configure axes if requested 
  if (confaxes) ChangeAxesConfiguration(invx, invy, exchxy, false);

  // Is there any more options to decode ?
  if (udopt.size() > 0) 
    ndec += mdrw->DecodeOptionString(udopt, rmdecopt);


  if (rmdecopt)  opt = udopt;

  // Decodage des options par le array-adapter
  int ndec2 = 0;
  if ( ( optsz1-ndec > 0) && (img) ) {
    ndec2 = img->DecodeOptionString(opt, rmdecopt);
    // On recalcule la LUT si on est en auto-lut, le contenu de l'image peut avoir change (Aout2007)
    if ((ndec2 > 0) && (t_al != AutoLut_No))  
      SetLut(t_al, min_al, max_al, Lut()->Type(), ns_al, false);
  }

  return(ndec+ndec2);
}


/* --Methode-- */
void PIImage::SetPave(int x, int y, bool refr, bool cent)
{
int xc, yc;

if (img == NULL)  
  { offx = offy = 0; 
  xpav = ypav = 0; 
  return; }

if ( (x >= (img->XSize()-1)) || ( x < 0)  ||
     (y >= (img->YSize()-1)) || ( y < 0)  ) return;

if ( (x == xpav) && (y == ypav) )  return;
xpav = x;  ypav = y;

if ( PosImg2W(xpav,ypav,&xc, &yc) || cent)  // Il faut recenter l'image
  { SetOffsetFromPave();  
  if (refr) Apply(true);  }
else if (refr)
  { Apply(false);  if (curshow)  DrawCursor(mWGrC);  }

return;
}

/* --Methode-- */
void PIImage::SetColMap(PIColorMap* cmp, bool refr)
{
if (!cmp)  return;
int ncolold = 0;
if (cmap) ncolold = cmap->NCol();
bool fgapp = false;
if (refr && cmp->NCol() != ncolold) {
  fgapp = true;  refr = false;
}
int cmapid = cmp->Type();
if ( (cmapid == CMAP_GREY32) || (cmapid == CMAP_GREYINV32) || 
     (cmapid == CMAP_GREY128) || (cmapid == CMAP_GREYINV128))  mdrw->GetGraphicAtt().SetColAtt(PI_Red);
else mdrw->GetGraphicAtt().SetColAtt(PI_Turquoise);
if (lut) lut->SetNCol(cmp->NCol());
PIPixmap::SetColMap(cmp, refr);
if (refr) { xcurs =  ycurs = -1; }
if (zow)  zow->SetColMap(cmp, refr);
if (gvw)  { 
    if (cmap->NCol() != ncolold) { 
    ComputeGloVPixmap();
    SetGloVPixmap();
  }
  else  gvw->SetColMap(cmp, refr);
}
if (cmvw) cmvw->SetColMap(cmap, Lut()->Min(), Lut()->Max(), refr);
if (fgapp)  Apply();
return;
}

/* --Methode-- */
void PIImage::SetColMapId(CMapId cmapid, bool revidx, bool refr)
{
int ncolold = 0;
if (cmap) ncolold = cmap->NCol();
if ( (cmapid == CMAP_GREY32) || (cmapid == CMAP_GREYINV32) || 
     (cmapid == CMAP_GREY128) || (cmapid == CMAP_GREYINV128))  mdrw->GetGraphicAtt().SetColAtt(PI_Red);
else mdrw->GetGraphicAtt().SetColAtt(PI_Turquoise);
PIPixmap::SetColMapId(cmapid, revidx, false);
if (refr) { xcurs =  ycurs = -1; }
bool fgapp = false;
if (refr && cmap->NCol() != ncolold) {
  fgapp = true;  refr = false;
}
if (lut) lut->SetNCol(GetColMap()->NCol());
if (refr) Refresh();
if (zow)  zow->SetColMapId(cmapid, revidx, refr);
if (gvw)  { 
    if (cmap->NCol() != ncolold) { 
    ComputeGloVPixmap();
    SetGloVPixmap();
  }
  else  gvw->SetColMapId(cmapid, revidx, refr);
}
if (cmvw) cmvw->SetColMapId(cmapid, revidx, Lut()->Min(), Lut()->Max(), refr);
if (fgapp)  Apply();
return;
}


/* --Methode-- */
void PIImage::Apply(bool mw)
{
if (img == NULL)  return;
if (fgshowcmap>0)  {
  cmpd.SetColMap(GetColMap());
  cmpd.SetBornes(*Lut());
}
if (mw)  {  
  ComputePixmap();
  Send(Msg(), PIMsg_Active);
  cur_piimage = this;
  PIDrwTools::SetCurrentBaseWdg(this);
  }
else {
  char * ibuff = img->InfoString(xpav, ypav);
  if (ustrtw || atrtw)  trtlb->SetLabel((string)ibuff);
  else DrawInfo(mWGrC, ibuff);
  }
if (zow != NULL)   ComputeZoomPixmap();
if (cutwin) UpdateCuts();
if (gvw != NULL)
  if ( (gvw->UserData() != this) || (mw) )  SetGloVPixmap();
if (cmvw) cmvw->SetColMap(cmap, Lut()->Min(), Lut()->Max(), true);
  
return;
}

/* --Methode-- */
void PIImage::Resize()
{
//printf("PIImage::Resize\n");
// On bascule sur la fenetre transient pour l'affichage des valeurs si fenetre trop petite
if ((XSize() < 300) || (YSize() < 150) ) atrtw = true;  
else atrtw = false;
PIPixmap::Resize();
CenterPave();
Apply();
return;
}

/* --Methode-- */
void PIImage::Draw(PIGraphic* g, int x0, int y0, int dx, int dy)
{
PIPixmap::Draw(g, x0, y0, dx, dy);
xcurs = ycurs = -1;
winovis = false;    // $CHECK$ Reza A enlever si possible 17/6/96
if (curshow) {
  int xc,yc;
  PosImg2W(xpav, ypav, &xc, &yc);
  if ((xc >= x0) && (xc < x0+dx) && 
      (yc >= y0) && (yc < y0+dy) )  DrawCursor(g, xc, yc);
  }

if (showinfo && img) {
  char * ibuff = img->InfoString(xpav, ypav);
  DrawInfo(mWGrC, ibuff); 
  }

return;
}

/* --Methode-- */
void PIImage::Keyboard(int key, PIKeyModifier kmod)
{
cur_piimage = this;
if (kmod & PIKM_Alt) {
  if      (key == 'R' || key == 'r') Apply(true);  // Pour tout rafraichir  
  else if (key == 'V' || key == 'v') RequestSelection();  // Pour coller (copier/coller)  
  else if (key == 'Z' || key == 'z') { mdrw->ElDelAll();  Refresh(); } // Pour supprimer tous les signes 
  else if (key == 'E' || key == 'e') { mdrw->ElDelLast();  Refresh(); } // Pour supprimer le dernier element ajoute
  else if (key == 'O' || key == 'o') PIImgTools::ShowPIImgTools();   // Fentre LUT et options 
  else if (key == 'G' || key == 'g') {   // Fentre attributs graphiques 
    PIDrwTools::SetCurrentBaseWdg(this);
    PIDrwTools::ShowPIDrwTools();   // Fentre axes et options de trace
    }
  else if (key == 'D' || key == 'd') {  // Menu de manipulation des drawers
    if (mDrwMen) delete mDrwMen;
    mDrwMen = new PIDrwMgrMenu(this, true);
    mDrwMen->Show();
  }  
  else if (key == 'P' || key == 'p') {   // Activation/desactivation affichage curseur
    bool sc = !curshow;
    ShowCursor(sc);
    }
  else if (key == 'X' || key == 'x') {   // Activation/desactivation affichage coupes X,Y 
    bool cut = (cutwin == NULL) ? true : false; 
    ShowCuts(cut);
    }
  else if (key == '+') {   // Zoom in (Augmentation du facteur de zoom)
    //    cout << " ++Changing zoom factor " << GetZoomF() << " ---> " 
    //	 << 2*GetZoomF() << endl;
    SetZoomF(GetZoomF()*2., true);
    }
  else if (key == '-') {   // Zoom out (diminution du facteur de zoom)
    //    cout << " --Changing zoom factor " << GetZoomF() << " ---> " 
    //	 << 0.5*GetZoomF() << endl;
    SetZoomF(GetZoomF()*0.5, true);
    }
// ----  Le copier ---- 
  else if ((key == 'C' || key == 'c') && img) { 
    // On limite la taille a 48x48
    int i1 = XPave();  
    int i2 = ( XSzPave() < 48 ) ? i1+XSzPave() : i1+48;
    int j1 = YPave();  
    int j2 = ( YSzPave() < 48 ) ? j1+YSzPave() : i1+48;
    if ( ( (i2-i1) < 1 ) || ((j2-j1) < 1) ) return;
    if (!ClaimSelection())  return;  // On n'a pas pu prendre possession de la zone d'echange
    if (cpbuffer)  delete[] cpbuffer;
    cpbuflen = (j2-j1)*(i2-i1+2)*12+(j2-j1)+128;
    cpbuffer = new char[cpbuflen];
    sprintf(cpbuffer,"PIImage: Pave(%dx%d) en (%d, %d) MaxCopie= 48x48 \n", 
            XSzPave(), YSzPave(), i1, j1);
    int i,j;
    int l = strlen(cpbuffer);
    for(j=j1; j<j2; j++) {
      sprintf(cpbuffer+l,"L %3d:",j);
      l += 6;
      for(i=i1; i<i2; i++) { sprintf(cpbuffer+l," %10g", (*img)(i, j));  l += 11; }
      cpbuffer[l] = '\n';  l++;
      }
    cpbuffer[l] = '\0';
    cpbuflen = l+1;
    }
  }
else if (kmod & PIKM_Cntl) {
  if (key == '+') {   // Zoom in (Augmentation du facteur de zoom)
    SetZoomF(GetZoomF()*2., true);
    }
  else if (key == '-') {   // Zoom out (diminution du facteur de zoom)
    SetZoomF(GetZoomF()*0.5, true);
    }
}
else if (kmod == PIKM_Blank) {
  switch (key) {
    case PIK_Up :
      SetPave(xpav, ypav-1, true, false);
      break;
    case PIK_Down :
      SetPave(xpav, ypav+1, true, false);
      break;
    case PIK_Left :
      SetPave(xpav-1, ypav, true, false);
      break;
    case PIK_Right :
      SetPave(xpav+1, ypav, true, false);
      break;
    default :
      break;
  }
}

}


/* --Methode-- */
void PIImage::But1Press(int x, int y)
{
int xp, yp;

Send(Msg(), PIMsg_Active);
cur_piimage = this;
PIDrwTools::SetCurrentBaseWdg(this);
if (img == NULL)  return;
if ( PosW2Img(x, y, &xp, &yp) )  return;
SelPointerShape(PI_CrossPointer);
xpav = xp;  ypav = yp;
if (ustrtw || atrtw) ShowTrTxW();
Apply(false);
if (curshow)  DrawCursor(mWGrC, -1,-1);
return;
}


/* --Methode-- */
void PIImage::Ptr1Move(int x, int y)
{
int xp, yp;
if (img == NULL)  return;
if ( PosW2Img(x, y, &xp, &yp) )  return;
xpav = xp;  ypav = yp;
Apply(false);
return;
}


/* --Methode-- */
void PIImage::But1Release(int /*x*/,  int /*y*/)
{
SelPointerShape(PI_ArrowPointer);
if (curshow)  DrawCursor(mWGrC);
if (ustrtw || atrtw) trtw->Hide();
else if (!showinfo) DrawInfo(mWGrC, NULL);
return;
}


/* --Methode-- */
void PIImage::But2Press(int x, int y)
{

Send(Msg(), PIMsg_Active);
cur_piimage = this;
PIDrwTools::SetCurrentBaseWdg(this);
if (img == NULL)  return;
if ( PosW2Img(x, y, &xpv0, &ypv0) )  {  xmv0 = -1;  return; }
xmv0 = x;  ymv0 = y;  dxmv = dymv = 0;
if (curshow)  DrawCursor(mWGrC,-1,-1);
mWGrC->SelGOMode(PI_GOXOR);
PIColors xc;
if ((GetColMapId() == CMAP_COLRJ32) || (GetColMapId() == CMAP_COLRJ128))  xc = PI_Yellow;
else  xc = PI_ColorAllBits1;
mWGrC->SelForeground(xc);
mWGrC->SelLine(PI_NormalLine);
if (ustrtw || atrtw) ShowTrTxW();
return;
}

/* --Methode-- */
void PIImage::Ptr2Move(int x, int y)
{
int xp, yp;
if (img == NULL)  return;
if (xmv0 < 0)  return;
if ( PosW2Img(x, y, &xp, &yp) )  return;
mWGrC->DrawBox(xmv0, ymv0, dxmv, dymv);
dxmv = x-xmv0;  dymv = y-ymv0;
mWGrC->DrawBox(xmv0, ymv0, dxmv, dymv);

 {
  char * ibuff = img->InfoString((xp+xpv0)/2, (yp+ypv0)/2 );
 if (ustrtw || atrtw) trtlb->SetLabel((string)ibuff);
 else DrawInfo(mWGrC, ibuff);
 }

return;
}

/* --Methode-- */
void PIImage::But2Release(int x, int y)
{
int xp2, yp2;

if (img == NULL)  return;
if (xmv0 < 0)  return;
mWGrC->DrawBox(xmv0, ymv0, dxmv, dymv);
mWGrC->SelGOMode(PI_GOCopy);
mWGrC->SelForeground(PI_White);
if ( PosW2Img(x, y, &xp2, &yp2) )  
  PosW2Img(xmv0+dxmv, ymv0+dymv, &xp2, &yp2);
xpav = (xpv0+xp2)/2;
ypav = (ypv0+yp2)/2;
xszpav = xp2-xpv0;
yszpav = yp2-ypv0;
if (xszpav < 0)  xszpav = -xszpav;
if (yszpav < 0)  yszpav = -yszpav;

Apply(false);
if (curshow)  DrawCursor(mWGrC);
if (ustrtw || atrtw) trtw->Hide();
else if (!showinfo) DrawInfo(mWGrC, NULL);
return;
}


/* --Methode-- */
void PIImage::But3Press(int x, int y)
{
int xp, yp;

Send(Msg(), PIMsg_Active);
cur_piimage = this;
PIDrwTools::SetCurrentBaseWdg(this);
if (img == NULL)  return;
if ( PosW2Img(x, y, &xp, &yp) )  { xmv0 = -1;  return; }
if (curshow)  DrawCursor(mWGrC,-1,-1);
if (ustrtw || atrtw) ShowTrTxW();
SelPointerShape(PI_TDLRArrowPointer);
xmv0 = xp;
ymv0 = yp;
return;
}


/* --Methode-- */
void PIImage::Ptr3Move(int x, int y)
{
int xp, yp;
if (img == NULL)  return;
if (xmv0 < 0)  return;
if ( PosW2Img(x, y, &xp, &yp) )  return;

char buff[256];
sprintf(buff," DelX= %d , DelY= %d    ", xp-xmv0, yp-ymv0);
if (ustrtw || atrtw) trtlb->SetLabel((string)buff);
else DrawInfo(mWGrC, buff);
}

/* --Methode-- */
void PIImage::But3Release(int x, int y)
{
int xp, yp;

SelPointerShape(PI_ArrowPointer);
if (ustrtw || atrtw) trtw->Hide();
if (img == NULL)  return;
if (xmv0 < 0)  return;
if ( PosW2Img(x, y, &xp, &yp) )  return;

offx -= (xp-xmv0);
offy -= (yp-ymv0);

if (offx < 0)  offx = 0;
if (offy < 0)  offy = 0;
if (offx >= img->XSize())  offx = img->XSize();
if (offy >= img->YSize())  offy = img->YSize();
xpav = xmv0;  ypav = ymv0;
xmv0 = ymv0 = -1;
Apply();
return;
}


/* --Methode-- */
void PIImage::PasteSelection(unsigned int typ, void *pdata, unsigned int l)
{
if (!img) return;
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';
double fx, fy;
img->Coord(xpav, ypav, fx, fy); 
mdrw->ElAddText(fx, fy, pc );
mdrw->Refresh();
}

/* --Methode-- */
void * PIImage::ProvideSelection(unsigned int& typ, unsigned int& len)
{
typ = PICP_string;
len = cpbuflen;
return(cpbuffer);
}

/* --Methode-- */
void PIImage::SelectionLost()
{
if (cpbuffer)  delete[] cpbuffer;
cpbuffer = NULL;
cpbuflen = 0;
return;
}



/* --Methode-- */
void PIImage::ComputePixmap()
{
unsigned int xwsz, ywsz;

if (img == NULL)  return;
xwsz = XSize();
ywsz = YSize();

img->ComputePixmap(lut, offx, offy, zoom, xwsz, ywsz, pixm);
int xw1, yw1, xw2, yw2;
xw1 = (xwsz-pixm.XSize())/2;
if (xw1 < 0) xw1 = 0;
yw1 = (ywsz-pixm.YSize())/2;
if (yw1 < 0) yw1 = 0;
xw2 = pixm.XSize()+xw1;
yw2 = pixm.YSize()+yw1;
SetDefaultDrawRectangle(xw1, yw1, xw2, yw2, false);
// printf("--DBG-- ComputePixmap() %d %d $ %d %d :: %d %d , %d %d \n", xwsz, ywsz, pixm.XSize(), pixm.YSize(), xw1, yw1, xw2, yw2);
int x1,y1, x2,y2;
ofx = xw1;  ofy = yw1;
PosW2Img(xw1, yw1, &x1, &y1);
PosW2Img(xw2, yw2, &x2, &y2);
double fx1,fy1, fx2, fy2; 
img->Coord(x1,y1, fx1, fy2);  // fy1 et fy2 echange expres pour utiliser kAxeDirAuto  
img->Coord(x2,y2, fx2, fy1);  // En effet Image de haut vers bas, Axes de bas vers haut par defaut 
SetDefaultDrawerLimits(fx1, fx2, fy1, fy2, kAxeDirAuto, kAxeDirAuto);
// printf("--DBG2-- ComputePixmap() %g %g  %g %g  \n", fx1, fx2, fy1, fy2);
xcurs = ycurs = -1;
SetPixmap(&pixm, true, xw1, yw1); 
// Refresh();
return; 
}


/* --Methode-- */
void PIImage::ComputeZoomPixmap()
{
unsigned int xwsz, ywsz;
int lofx, lofy;
int zm;

if (zow == NULL)  return;
if (img == NULL)  return;

xwsz = zow->XSize();
ywsz = zow->YSize();

zm = zoom+4;
// Calcul du facteur de zoom pour la petite fenetre de zoom
float fzm = 1.0;
if (zoom < 0) fzm = -1./(float)zoom;
else  fzm = zoom;

if (fzm < 0.25) zm = (-1./(fzm*4.0))-0.1;
else if (fzm < 3.5)  zm = fzm*4.+0.1;
else if (fzm < 7.5) zm = fzm*3.+0.1;

if ( (zm==-1) || (zm == 0) ) zm = 1;
if (zm > 0)
  {
  lofx = xpav-(xwsz/2/zm);
  lofy = ypav-(ywsz/2/zm);
  }
else 
  {
  lofx = xpav-(-((int)xwsz)*zm/2);
  lofy = ypav-(-((int)ywsz)*zm/2);
  }
if (lofx < 0)  lofx = 0;
if (lofy < 0)  lofy = 0;

img->ComputePixmap(lut, lofx, lofy, zm, xwsz, ywsz, zpixm);
zow->SetColMap(cmap, false);
zow->SetPixmap(&zpixm); 
zow->SetUserData((void *)this, 0);
// zow->Refresh();
return; 

}


/* --Methode-- */
void PIImage::ComputeGloVPixmap()
{
unsigned int xwsz, ywsz;
int zmx,zmy;

if (gvw == NULL)  return;
if (img == NULL)  return;

xwsz = gvw->XSize();
ywsz = gvw->YSize();

zmx = img->XSize()/xwsz;
zmy = img->YSize()/ywsz;

if (zmx < zmy)   zmx = zmy;
if (zmx < 1)  zmx = 1;
zmgv = zmx;
if (zmx > 1)  zmx = -zmx;
img->ComputePixmap(lut, 0, 0, zmx, xwsz, ywsz, gpixm);
// printf("DEBUG-ComputeGloVPixmap()  %d-%d , (%d,%d) , %d-%d \n", xwsz, ywsz, zmx, zmy, gpixm.XSize(), gpixm.YSize());
return;
}

/* --Methode-- */
void PIImage::SetGloVPixmap()
{
float zm;
int x,y, dx,dy;

int xw1, yw1, xw2, yw2;
xw1 = (gvw->XSize()-gpixm.XSize())/2;
if (xw1 < 0) xw1 = 0;
yw1 = (gvw->YSize()-gpixm.YSize())/2;
if (yw1 < 0) yw1 = 0;
xw2 = gpixm.XSize()+xw1;
yw2 = gpixm.YSize()+yw1;

if (zoom > 0) zm = zmgv*zoom;
else zm = (float)zmgv/(float)(-zoom);
x = offx/zmgv+1+xw1;
y = offy/zmgv+1+yw1;
dx =  (int) ( (float)XSize()/zm-1. );  
dy =  (int) ( (float)YSize()/zm-1. );  

gvw->DeleteDrawers();
gvdrw->ElDelAll();
gvdrw->SetLimits(xw1, xw2, yw1, yw2, kAxeDirLtoR, kAxeDirUpDown);
int cmapid = cmap->Type();
PIGraphicAtt gatt;
if ( (cmapid == CMAP_GREY32) || (cmapid == CMAP_GREYINV32) || 
     (cmapid == CMAP_GREY128) || (cmapid == CMAP_GREYINV128)) 
  gatt.SetColAtt(PI_Red); 
else gatt.SetColAtt(PI_Turquoise);
gatt.SetLineAtt(PI_NormalLine);
gvdrw->ElDrwMgr().ElAddRect(x,y,dx,dy,gatt);
gvw->AddDrawer(gvdrw, xw1, yw1, xw2, yw2, false); 
gvw->SetColMap(cmap, false);
gvw->SetPixmap(&gpixm, true, xw1, yw1); 
gvw->SetUserData((void *)this, 0);
gvw->SetMsg(Msg()+626);
gvw->SetMsgParent(this);

return; 
}

/* --Methode-- */
void PIImage::UpdateCuts()
{
if (!cutwin || !img) return;

int hsx, hsy, hsmin;
P2DArrayAdapter * img0=NULL;
hsx = XSzPave()/2;
hsy = YSzPave()/2;
hsmin = (hsx<hsy)? hsx: hsy;
if(selcuts&1) img0=img; else img0=NULL;
  cutarrx->SetData(img0, 1, 2*hsx+1, XPave(), YPave());
if(selcuts&2) img0=img; else img0=NULL;
  cutarry->SetData(img0, 2, 2*hsy+1, XPave(), YPave());
if(selcuts&4) img0=img; else img0=NULL;
  cutarrd->SetData(img0, 4, 2*hsmin+1, XPave(), YPave());
if(selcuts&8) img0=img; else img0=NULL;
  cutarra->SetData(img0, 8, 2*hsmin+1, XPave(), YPave());

double x1,y1,x2,y2;
img->Coord(XPave()-hsx, YPave()-hsy, x1, y1);
img->Coord(XPave()+hsx, YPave()+hsy, x2, y2);
  if(x1<x2) cutarrx->DefineXCoordinate(-cutarrx->Size()/2,  1.);
    else    cutarrx->DefineXCoordinate( cutarrx->Size()/2, -1.);
  if(y1<y2) cutarry->DefineXCoordinate(-cutarry->Size()/2,  1.);
    else    cutarry->DefineXCoordinate( cutarry->Size()/2, -1.);
img->Coord(XPave()-hsmin, YPave()-hsmin, x1, y1);
img->Coord(XPave()+hsmin, YPave()+hsmin, x2, y2);
  if(x1<x2) cutarrd->DefineXCoordinate(-cutarrd->Size()/2,  1.);
    else    cutarrd->DefineXCoordinate( cutarrd->Size()/2, -1.);
  if(x1<x2) cutarra->DefineXCoordinate(-cutarra->Size()/2,  1.);
    else    cutarra->DefineXCoordinate( cutarra->Size()/2, -1.);

// On calcule les limites :
double xmin=0., xmax=0., ymin=0., ymax=0.; bool vue=false;
if(cutarrx->Size()) {
  if(!vue) vue=true;
  xmax=cutarrx->Size()/2.+1.; xmin=-xmax; 
}
if(cutarry->Size()) {
  if(!vue)
    {vue=true; xmax=cutarry->Size()/2.+1.; xmin=-xmax;}
  else if(cutarry->Size()>xmax)
    {xmax=cutarry->Size()/2.+1.; xmin=-xmax;}
}
if(cutarrd->Size()) {
  if(!vue)
    {vue=true; xmax=cutarrd->Size()/2.+1.; xmin=-xmax;}
  else if(cutarrd->Size()>xmax)
    {xmax=cutarrd->Size()/2.+1.; xmin=-xmax;}
}
if(cutarra->Size()) {
  if(!vue)
    {vue=true; xmax=cutarra->Size()/2.+1.; xmin=-xmax;}
  else if(cutarra->Size()>xmax)
    {xmax=cutarra->Size()/2.+1.; xmin=-xmax;}
}

int i; double cv; vue = false;
if(cutarrx->Size()) {
  vue=true; ymax=ymin=cutarrx->Value(0);
  for(i=0; i<cutarrx->Size(); i++) {
    cv = cutarrx->Value(i);
    if (cv < ymin)  ymin = cv;
    if (cv > ymax)  ymax = cv;
  }
}
if(cutarry->Size()) {
  if(!vue) {vue=true; ymax=ymin=cutarry->Value(0);}
  for(i=0; i<cutarry->Size(); i++) {
    cv = cutarry->Value(i);
    if (cv < ymin)  ymin = cv;
    if (cv > ymax)  ymax = cv;
  }
}
if(cutarrd->Size()) {
  if(!vue) {vue=true; ymax=ymin=cutarrd->Value(0);}
  for(i=0; i<cutarrd->Size(); i++) {
    cv = cutarrd->Value(i);
    if (cv < ymin)  ymin = cv;
    if (cv > ymax)  ymax = cv;
  }
}
if(cutarra->Size()) {
  if(!vue) {vue=true; ymax=ymin=cutarra->Value(0);}
  for(i=0; i<cutarra->Size(); i++) {
    cv = cutarra->Value(i);
    if (cv < ymin)  ymin = cv;
    if (cv > ymax)  ymax = cv;
  }
}
ymin -= PERC_GARDE*(ymax-ymin);
ymax += PERC_GARDE*(ymax-ymin);
cutscw->SetLimits(xmin, xmax, ymin, ymax);
//cutscw->UpdateLimits();
cutscw->Refresh();
//printf("UpdateCuts()-DBG X: %d  -> %g  , Y: %d -> %g \n", cutarrx->Size(), cutarrx->Value(0),
//       cutarry->Size(), cutarry->Value(0));
}

/* --Methode-- */
void PIImage::UpdateCMapDrawer(int fgshow)
{
  if ((fgshow<0)||(fgshow>4))  fgshow=0;
  if (fgshow==fgshowcmap) return;
  fgshowcmap=fgshow;
  switch (fgshowcmap ) {
  case 0 :
    RemoveDrawer(cmdid); 
    break;
  case 1 :
    cmpd.SetHorizontal();
    cmdid=AddDrawer(&cmpd, 0.10, 0.02, 0.90, 0.10, true, false);
    break;
  case 2 :
    cmpd.SetVertical();
    cmdid=AddDrawer(&cmpd, 0.90, 0.1, 0.98, 0.9, true, false);
    break;
  case 3 :
    cmpd.SetHorizontal();
    cmdid=AddDrawer(&cmpd, 0.10, 0.90, 0.90, 0.98, true, false);
    break;
  case 4 :
    cmpd.SetVertical();
    cmdid=AddDrawer(&cmpd, 0.02, 0.1, 0.10, 0.9, true, false);
    break;   
  } 
  if (fgshowcmap>0) cmpd.GetGraphicAtt().SetColAtt(PI_Turquoise);
}

/* --Methode-- */
void PIImage::DrawCursor(PIGraphic* g) 
{
int xc, yc;
if (PosImg2W(xpav, ypav, &xc, &yc)) DrawCursor(g, -1, -1);
else DrawCursor(g, xc, yc);
return;
}

 
/* --Methode-- */
void PIImage::DrawCursor(PIGraphic* g, int xc, int yc)
{

if (winovis)  return;      // $CHECK$ Reza A enlever si possible 17/6/96
//printf("DBG-DrawCursor(g, %d, %d) \n", xc, yc);
int cmapid = cmap->Type();
if ( (xcurs>=0) && (ycurs>=0) ) {
  if (g->kind() == PI_PSFileGraphics ) {
    g->SelGOMode(PI_GOCopy);
    if ( (cmapid == CMAP_GREY32) || (cmapid == CMAP_GREYINV32) ||
         (cmapid == CMAP_GREY128) || (cmapid == CMAP_GREYINV128) )  g->SelForeground(PI_Red);
    else  g->SelForeground(PI_Turquoise);
    }
  else  {
    g->SelGOMode(PI_GOXOR);
    //    g->SelGOMode(PI_GOInvert);
    g->SelForeground(cucol);
    }
  g->SelLine(culat);
  //  On efface le curseur precedant ou on le trace ds le postscript
  g->DrawLine(xcurs-cuhsz, ycurs, xcurs-4, ycurs);
  g->DrawLine(xcurs+4, ycurs, xcurs+cuhsz, ycurs);
  g->DrawLine(xcurs, ycurs-cuvsz, xcurs, ycurs-4);
  g->DrawLine(xcurs, ycurs+4, xcurs, ycurs+cuvsz);
  //  printf("DrawCursor/Erase() %d %d - %d %d -> %d %d \n", xcurs, ycurs, cuhsz, cuvsz, xc, yc);
  }

if (g->kind() == PI_PSFileGraphics )  { 
  g->SelLine(PI_NormalLine);
  g->SelForeground(PI_White);  
  return;
  }

if ((xc >= 0) && (yc >= 0)) 
  {
  g->SelGOMode(PI_GOXOR);
  //  g->SelGOMode(PI_GOInvert);
  // Nouvelle epaisseur de trait du curseur
  if (zoom < -2) culat = PI_ThinLine;
  else if (zoom < 4) culat = PI_NormalLine;
  else culat = PI_ThickLine;
  g->SelLine(culat);

  // couleur  de trait du curseur
  if ((cmapid == CMAP_COLRJ32) || (cmapid == CMAP_COLRJ128))  cucol = PI_Yellow;
  else  cucol = PI_ColorAllBits1;
  g->SelForeground(cucol);

  // Nouveau taille du curseur
  cuhsz = xszpav/2;  cuvsz = yszpav/2;
  if (zoom > 0)  { cuhsz = xszpav*zoom/2;  cuvsz = yszpav*zoom/2; }
  else { cuhsz = xszpav/(-zoom*2);  cuvsz = yszpav/(-zoom*2); }
  if ( cuhsz < 10) cuhsz = 10;
  if ( cuvsz < 10) cuvsz = 10;

  xcurs = xc;   ycurs = yc;

  g->DrawLine(xcurs-cuhsz, ycurs, xcurs-4, ycurs);
  g->DrawLine(xcurs+4, ycurs, xcurs+cuhsz, ycurs);
  g->DrawLine(xcurs, ycurs-cuvsz, xcurs, ycurs-4);
  g->DrawLine(xcurs, ycurs+4, xcurs, ycurs+cuvsz);
  //  printf("DrawCursor() %d %d - %d %d \n", xcurs, ycurs, cuhsz, cuvsz);
  }
else { 
  xcurs = ycurs = -1; cuhsz = cuvsz = 10; 
  cucol = PI_Yellow; culat = PI_NormalLine; 
  }

g->SelGOMode(PI_GOCopy);
g->SelLine(PI_NormalLine);
g->SelForeground(PI_White);
return;
}

 
/* --Methode-- */
void PIImage::DrawInfo(PIGraphic* g, char* txt)
{
g->SelFont(PI_NormalSizeFont, PI_RomanFont);
if (txt) { 
  PIColors fgc = g->GetForeground();
  PIGOMode gm = g->GetGOMode();
  g->SelGOMode(PI_GOCopy);
  int cmapid = cmap->Type();
  if ( (cmapid == CMAP_GREY32) || (cmapid == CMAP_GREYINV32) || 
       (cmapid == CMAP_GREY128) || (cmapid == CMAP_GREYINV128))  g->SelForeground(PI_Red);
  else g->SelForeground(PI_Turquoise);
//  g->SelForeground(PI_White);
  g->SelBackground(PI_Black);
  g->DrawOpaqueString(20, YSize()-5, txt);
  g->SelGOMode(gm);
  g->SelForeground(fgc);
  }
else {
  int a,d,h;
  h = g->GetFont().GetFontHeight(a, d);
  if (g->kind() != PI_PSFileGraphics )   PIPixmap::Draw(g, 0, YSize()-10-h, XSize(), h+10); 
  }
return;
}

/* --Methode-- */
void PIImage::ShowTrTxW()
{
if (trtw) 
  {
  int tpx, tpy;
  GetScreenPos(tpx, tpy);
  tpy -= (trtw->YSize()+5);
  if (tpy < 0)  tpy = 0;
  trtw->SetPos(tpx, tpy);
  trtw->Show();  
  }

return;
}

/* --Methode-- */
int PIImage::PosW2Img(int xiw, int yiw, int * xp, int * yp)
{
if (!img) { *xp = *yp = 0;  return(1); }
xiw -= ofx;  yiw -= ofy;   // Offset d'affichage du pixmap
if (zoom > 0)
  {
  *xp = xiw/zoom+offx;
  *yp = yiw/zoom+offy;
  }
else
  {
  *xp = offx-xiw*zoom;
  *yp = offy-yiw*zoom;
  }

if ( (*xp >= 0) && (*xp < img->XSize() ) &&
     (*yp >= 0) && (*yp < img->YSize() )  )   return(0);
else return(1);
}


/* --Methode-- */
int PIImage::PosImg2W(int xp, int yp, int * xiw, int * yiw)
{
if (!img) { *xiw = *yiw = -1;  return(1); }
if (zoom > 0)
  {
  *xiw = (xp-offx)*zoom+(zoom/2);
  *yiw = (yp-offy)*zoom+(zoom/2);
  }
else
  {
  *xiw = (offx-xp)/zoom;
  *yiw = (offy-yp)/zoom;
  }

*xiw += ofx;  *yiw += ofy;    // Offset d'affichage du pixmap
if (*xiw > XSize())  *xiw = -1;
if (*yiw > YSize())  *yiw = -1;

if ((*xiw < 0) || (*yiw < 0))  return(1);
else return(0);
}


/* --Methode-- */
void PIImage::SetOffsetFromPave()
{
if (!img) { offx = offy = 0; return; }
if (zoom > 0)
  {
  offx = xpav-XSize()/2/zoom;
  offy = ypav-YSize()/2/zoom;
  }
else
  {
  offx = xpav+XSize()/2*zoom;
  offy = ypav+YSize()/2*zoom;
  }

if (offx < 0)  offx = 0;
if (offx >= (img->XSize()-1))  offx = img->XSize()-2;
if (offy < 0)  offy = 0;
if (offy >= (img->YSize()-1))  offy = img->YSize()-2;

return;
}

/* --Methode-- */
void PIImage::CenterPave()
{
int xwsz, ywsz;

if (zoom > 0)
  { xwsz = XSize()/zoom;  
  ywsz = YSize()/zoom;  }
else
  { xwsz = -(XSize()*zoom); 
  ywsz = -(YSize()*zoom); }

if (img) {   
// --- cmv+rz 21/08/2007 : Correction plantage lors agrandissement fenetre , 
  if (xwsz >= img->XSize()) offx = 0; 
  if (ywsz >= img->YSize()) offy = 0; 
// Fin correction cmv+rz 21/08/2007 -----
  if (xwsz > (img->XSize()-offx)) xwsz = (img->XSize()-offx);
  if (ywsz > (img->YSize()-offy)) ywsz = (img->YSize()-offy);
  }
xpav = offx+xwsz/2; 
ypav = offy+ywsz/2; // --- cmv+rz 21/08/2007 : c'etait offx au lieu de offy
xszpav = ((xwsz+ywsz)/15) ;
if (xszpav < 1) xszpav = 1;
yszpav = xszpav; 

return;
}


//---------------------------------------------------------------------------------
//-------  On definit une classe ArrayAdapter pour les donnees des coupes  --------
//---------------------------------------------------------------------------------

/* --Methode-- */
PIImage::PIImg1DArrAdapter::PIImg1DArrAdapter() : P1DArrayAdapter(0) 
{
data = NULL;
fgaxyda = 1;
off1 = off2 = 0;
}

/* --Methode-- */
void PIImage::PIImg1DArrAdapter::SetData(P2DArrayAdapter* d, unsigned short axyda
                                        ,int sz,int o1,int o2)
// axyda&1 axe (X), axyda&2 axe (Y), axyda&4 diag (X,Y), axyda&8 anti-diag (X,-Y)
{
data = d; mSize = 0;
fgaxyda = axyda;
if(!data) return;
if (o1 < 0)  o1 = 0;
if (o2 < 0)  o2 = 0;
if (o1 >= d->XSize()) o1 = d->XSize()-1; 
if (o2 >= d->YSize()) o2 = d->YSize()-1; 
off1 = o1;
off2 = o2;
if ((sz%2) == 0)  sz++;
if (sz < 0) sz = 1;
mSize = sz;
}

/* --Methode-- */
double PIImage::PIImg1DArrAdapter::Value(int i)
{
if (!data) return(0.);
int j,k;
if (fgaxyda&1) {          // Axe X
  j = off1-mSize/2+i;
  if (j<0) j=0; if(j>=data->XSize()) j=data->XSize()-1;
  return((*data)(j,off2));
  }
else if (fgaxyda&2) {     // Axe Y
  k = off2-mSize/2+i;
  if(k<0) k=0; if(k>=data->YSize()) k=data->YSize()-1;
  return((*data)(off1,k));
  }
else if (fgaxyda&4) {     // Axe XY
  j = off1-mSize/2+i;
  k = off2-mSize/2+i;
  if(j<0) j=0; if(j>=data->XSize()) j=data->XSize()-1;
  if(k<0) k=0; if(k>=data->YSize()) k=data->YSize()-1;
  return((*data)(j,k));
  }
else if (fgaxyda&8) {     // Axe -XY
  j = off1-mSize/2+i;
  k = off2+mSize/2-i;
  if(j<0) j=0; if(j>=data->XSize()) j=data->XSize()-1;
  if(k<0) k=0; if(k>=data->YSize()) k=data->YSize()-1;
  return((*data)(j,k));
  }
return(0.);
}
//++
// Class	PIImageNavigator
// Lib		PI
// include	piimage.h
//
//   	Classe regroupant un PIImage, un widget Zoom, un widget 
//	de vue globale et un widget afficheur de colormap dans 
//	un conteneur (PIContainer).
//++
// Links	Parents
// PIContainer
//--
//++
// Links	Voir aussi
// PIImage
//--

//++
// Titre	Constructeurs
//--
//++
//  PIImageNavigator(PIContainerGen *par, const char *nom, int sx=0, int sy=0, int px=0, int py=0)
//	Constructeur
//  
//--
/* --Methode-- */
PIImageNavigator::PIImageNavigator(PIContainer *par, const char *nom, 
				  int sx, int sy, int px, int py)
  : PIContainer(par, nom, sx, sy, px, py)
{
  int csx, csy;
  int cpx, cpy,bss;
  string name = nom;
  name += "::";
  string nomw = name;
  nomw += "Navigator";
  bss = 5; // 5 pixels
  csx = 0.2*sx;  csy = 0.2*sy;
  cpx = bss; cpy = bss;
  gimv = new PIPixmap(this, nomw.c_str(), csx, csy, cpx, cpy);
  gimv->SetBinding(PIBK_elastic,PIBK_elastic,PIBK_elastic, PIBK_elastic); 
  nomw = name;
  nomw += "Zoom";
  cpx += (bss+csx);
  zoom = new PIPixmap(this, nomw.c_str(), csx, csy, cpx, cpy);
  zoom->SetBinding(PIBK_elastic,PIBK_elastic,PIBK_elastic, PIBK_elastic); 
  nomw = name;
  nomw += "ColorMap";
  cpx = bss; cpy += (bss+csy);
  csx = sx-2*bss;  csy = 0.2*sy*0.2;
  cmapv = new PICMapView(this, nomw.c_str(), csx, csy, cpx, cpy);
  cmapv->SetBinding(PIBK_elastic,PIBK_elastic,PIBK_elastic, PIBK_elastic); 
  nomw = name;
  nomw += "Image";
  cpx = bss; cpy += (bss+csy);
  csx = sx-2*bss;  csy = sy-bss-cpy;
  piimg = new PIImage(this, nomw.c_str(), csx, csy, cpx, cpy);
  piimg->SetBinding(PIBK_elastic,PIBK_elastic,PIBK_elastic, PIBK_elastic); 

  piimg->SetZoomWin(zoom, false);
  piimg->SetGloVWin(gimv, false);
  piimg->SetCMapWin(cmapv, false);
}

/* --Methode-- */
PIImageNavigator::~PIImageNavigator()
{
  if (piimg) delete piimg;
  if (zoom)  delete zoom;
  if (gimv)  delete gimv;
  if (cmapv) delete cmapv;
}


//++
// Titre	Méthodes
//--

//++
// inline PIImage*    ImageWdg() 
//	Acces a l'objet PIImage associe. 
//--
