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

#include <stdlib.h>

#include "sopnamsp.h"
#include "piimgtools.h"
#include "piimage.h"

//++
// Class	PIImgTools
// Lib		PI
// include	piimgtools.h
//
//	Classe de fenêtre de dialogue permettant de modifier interactivement
//	Les différents attributs de visualisation pour les *PIImage* .
//--
//++
// Links	Parents
// PIWindow
//--
//++
// Links	Voir aussi
// PIImage
//--

//++
// Titre	Méthodes statiques
//--
//++
// void  ShowPIImgTools() 	
//	Méthode statique permettant l'affichage de la fenêtre de contrôle des
//	paramètres de visualisation des images. L'instance de la classe
//	 "PIImgTools" est créée si nécessaire.
// void  HidePIImgTools() 
//	Désacative (cache) la fenêtre "PIImgTools" (méthode statique).
//--

// ------ Menu des options et fenetre de dialogue pour changement de LUT --------


PIImgTools* PIImgTools::curlutw = NULL;
/* --Methode-- */
void PIImgTools::ShowPIImgTools() 
{
if (curlutw == NULL)  curlutw = new PIImgTools(PIApplicationGetApp());
curlutw->Show();
}

/* --Methode-- */
void PIImgTools::HidePIImgTools() 
{
if (curlutw == NULL)  return;
curlutw->Hide();
}

/* --Methode-- */
PIImgTools::PIImgTools(PIApplication* par)
: PIWindow((PIMsgHandler*)par, "PIImageTools", PIWK_normal, 240, 240, 150, 150)
{
int bsx, bsy, spx, spy;

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

// int wszx = 8*spx+3*bsx+2*bsy; 
int wszx = 8*spx+3.5*bsx; 
int wszy = (10+4)*spy+9*bsy;
SetSize(wszx, wszy);

int cpx = spx*2;
int cpy = spy*2;
int csx = cpx;
int csy = cpy;
mLab[0] = new PILabel(this, "MinPixel", bsx, bsy, cpx, cpy);
cpy += spy+bsy; 
mLab[1] = new PILabel(this, "MaxPixel", 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+bsx; 
mText[0] = new PIText(this, "MinVal", 1.5*bsx, bsy, cpx, cpy);
mText[0]->SetText("1");
cpy += spy+bsy; 
mText[1] = new PIText(this, "MaxVal", 1.5*bsx, bsy, cpx, cpy);
mText[1]->SetText("32000");
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*2;
mOlb[0] = new PILabel(this, "LutType", bsx, bsy, cpx, cpy);
mOlb[0]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
cpx += spx+bsx; 
mOpt[0] = new PIOptMenu(this, "imglut-opt-1", 1.5*bsx, bsy, cpx, cpy);
mOpt[0]->AppendItem("Linear", 1100);
mOpt[0]->AppendItem("Log.", 1101);
mOpt[0]->AppendItem("Sqrt", 1102);
mOpt[0]->AppendItem("Square", 1103);
mOpt[0]->SetValue(1100);
mOpt[0]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);

cpy += spy+bsy; 
cpx = spx*2;
mOlb[1] = new PILabel(this, "AutoLut", bsx, bsy, cpx, cpy);
mOlb[1]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
cpx += spx+bsx; 
mOpt[1] = new PIOptMenu(this, "imglut-opt-2", 1.5*bsx, bsy, cpx, cpy);
mOpt[1]->AppendItem("+3 Sig", 1203);
mOpt[1]->AppendItem("+2 Sig", 1202);
mOpt[1]->AppendItem("+1 Sig", 1201);
mOpt[1]->AppendItem("NoAuto", 1200);
mOpt[1]->AppendItem("-1 Sig", 1199);
mOpt[1]->AppendItem("-2 Sig", 1198);
mOpt[1]->AppendItem("-3 Sig", 1197);
mOpt[1]->SetValue(1202);
mOpt[1]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);

cpy += 2*spy+bsy; 
cpx = 3*spx+0.2*bsx;
mBut[0] = new PIButton(this, "Apply", 2500, bsx*1.6, bsy, cpx, cpy);
// mBut[0] = new PIButton(this, "Apply", 2500, bsx, bsy, cpx, cpy);
mBut[0]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
cpx += bsx*1.6+2*spx;
// cpx += bsx+2*spx;
mBut[1] = new PIButton(this, "Dismiss", 2600,  bsx*1.6, bsy, cpx, cpy);
// mBut[1] = new PIButton(this, "Dismiss", 2600, bsx, bsy, cpx, cpy);
mBut[1]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);

int offy = cpy+bsy+spy*3;
// printf("-DBG- PIImgTools()  SzX,Y= %d %d , ButPos= %d %d (off=%d)\n", wszx, wszy, cpx, cpy, offy);

// cpx = 4*spx+2.75*bsx;
cpx = wszx-bsx-3*spx;
cpy = 2*spy;
mSc[0] = new PIScale(this, "sc-offset-lut", 2700, kSDirDownUp, 0.5*bsx, 4.5*bsy, cpx, cpy); 
cpx += 0.50*bsx+spx;
mSc[1] = new PIScale(this, "sc-dyn-lut", 2800, kSDirDownUp, 0.55*bsx, 4.5*bsy, cpx, cpy); 
mSc[0]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
mSc[0]->SetMinMax(-50, 50);
mSc[0]->SetValue(0);
mSc[1]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
mSc[1]->SetMinMax(-50, 50);
mSc[1]->SetValue(0);

//  Option-Menu  Couleur/Zoom
cpx = 3*spx;
cpy = offy;
mOptzc[0] = new PIOptMenu(this, "imglut-opt-3", bsx*1.75, bsy, cpx, cpy);
int kcc;
//  Groupement des tables de couleurs
mCasc[0] = new PIMenu(mOptzc[0]->Menu(), "PIStd-128Col");
mCasc[1] = new PIMenu(mOptzc[0]->Menu(), "PIUniCol32");
mCasc[2] = new PIMenu(mOptzc[0]->Menu(), "MIDAS-CMap");

int nsct1,nsct2,nsct3,nsct4;
//  D'abord les tables standard de PI  32 couleurs
nsct1 = 5;   // Les 5 premieres tables
for(kcc=0; kcc<nsct1; kcc++) 
  mOptzc[0]->AppendItem(PIColorMap::GetStandardColorMapName(kcc).c_str(), 201+kcc);
//  Ensuite les tables standard de PI  128 couleurs
nsct2 = 9;   // Les 4 tables suivantes
for(kcc=nsct1; kcc<nsct2; kcc++) 
  mCasc[0]->AppendItem(PIColorMap::GetStandardColorMapName(kcc).c_str(), 201+kcc);
mOptzc[0]->AppendPDMenu(mCasc[0]);
nsct3 = 16;  // Les 7 tables de couleurs uniforme
for(kcc=nsct2; kcc<nsct3; kcc++) 
  mCasc[1]->AppendItem(PIColorMap::GetStandardColorMapName(kcc).c_str(), 201+kcc);
mOptzc[0]->AppendPDMenu(mCasc[1]);
//  Apres les tables importees de MIDAS
nsct4 = PIColorMap::NumberStandardColorMaps()-2; // Les reste jusqu'a l'avant derniere
for(kcc=nsct3; kcc<nsct4; kcc++) 
  mCasc[2]->AppendItem(PIColorMap::GetStandardColorMapName(kcc).c_str(), 201+kcc);
mOptzc[0]->AppendPDMenu(mCasc[2]);
// Les tables qui restent ( Col16 , ... )
for(kcc=nsct4; kcc<PIColorMap::NumberStandardColorMaps(); kcc++) 
mOptzc[0]->AppendItem(PIColorMap::GetStandardColorMapName(kcc).c_str(), 201+kcc);
// On ajoute un CheckItem pour inverser les index de table de couleur
mOptzc[0]->Menu()->AppendSeparator();
mOptzc[0]->Menu()->AppendCheckItem("Reverse CMap", 299);

mOptzc[0]->SetValue(203);  mLastCol = 203;
mOptzc[0]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);

cpx += bsx*1.75+2*spx;
mOptzc[1] = new PIOptMenu(this, "imglut-opt-4", bsx*1.75, bsy, cpx, cpy);
mOptzc[1]->AppendItem("Agr. x10", 110);
mOptzc[1]->AppendItem("Agr. x 8", 108);
mOptzc[1]->AppendItem("Agr. x 6", 106);
mOptzc[1]->AppendItem("Agr. x 5", 105);
mOptzc[1]->AppendItem("Agr. x 4", 104);
mOptzc[1]->AppendItem("Agr. x 3", 103);
mOptzc[1]->AppendItem("Agr. x 2", 102);
mOptzc[1]->AppendItem("Zoom x 1", 101);
mOptzc[1]->AppendItem("Red. / 2", 98);
mOptzc[1]->AppendItem("Red. / 3", 97);
mOptzc[1]->AppendItem("Red. / 4", 96);
mOptzc[1]->AppendItem("Red. / 5", 95);
mOptzc[1]->AppendItem("Red. / 6", 94);
mOptzc[1]->AppendItem("Red. / 8", 92);
mOptzc[1]->AppendItem("Red. /10", 90);
mOptzc[1]->SetValue(101);
mOptzc[1]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);

cpy += spy+bsy;
cpx = 4*spx+0.875*bsx;
mOptCut = new PIOptMenu(this, "Cut", bsx*1.75, bsy, cpx, cpy);
mOptCut->AppendItem("Cut X",301);
mOptCut->AppendItem("Cut Y",302);
mOptCut->AppendItem("CutXY",303);
mOptCut->AppendItem("Cut D",304);
mOptCut->AppendItem("Cut A",308);
mOptCut->AppendItem("CutDA",312);
mOptCut->AppendItem("CutAll",315);
mOptCut->SetValue(303);
mOptCut->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);

int pbsx = 0.45*bsx;
int pbsy = bsy;
int pspx = spy/2;
int pspy = spy;

cpx = spx;
cpy += bsy+spy;
mButsz[0] = new PIButton(this, "1x1", 3201,  pbsx, pbsy, cpx, cpy);
mButsz[0]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
cpx += pbsx+pspx;
mButsz[1] = new PIButton(this, "1x2", 3202,  pbsx, pbsy, cpx, cpy);
mButsz[1]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
cpx += pbsx+pspx;
mButsz[2] = new PIButton(this, "1x4", 3204,  pbsx, pbsy, cpx, cpy);
mButsz[2]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
cpx += pbsx+pspx;
mButsz[3] = new PIButton(this, "1/2", 3198,  pbsx, pbsy, cpx, cpy);
mButsz[3]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
cpx += pbsx+pspx;
mButsz[4] = new PIButton(this, "1/4", 3196,  pbsx, pbsy, cpx, cpy);
mButsz[4]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);

//cpx += pbsx+10*pspx;
cpx = wszx-3.0*pbsx-spx-pspx;
mButoa[0] = new PIButton(this, "+Info", 5311,  1.5*pbsx, pbsy, cpx, cpy);
mButoa[0]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
cpx += 1.5*pbsx+pspx;
mButoa[1] = new PIButton(this, "-Info", 5312,  1.5*pbsx, pbsy, cpx, cpy);
mButoa[1]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);


cpx = spx;
cpy += pbsy+pspy;
mButcax[0] = new PIButton(this, "-X", 5201,  pbsx, pbsy, cpx, cpy);
mButcax[0]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
cpx += pbsx+pspx;
mButcax[1] = new PIButton(this, "-Y", 5202,  pbsx, pbsy, cpx, cpy);
mButcax[1]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
cpx += pbsx+pspx;
mButcax[2] = new PIButton(this, "X-Y", 5203, pbsx, pbsy, cpx, cpy);
mButcax[2]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);

// cpx += 1.5*pbsx+pspx+10*pspx;
cpx = wszx-4.5*pbsx-spx-2*pspx;
mButoa[2] = new PIButton(this, "-All", 5300,  1.5*pbsx, pbsy, cpx, cpy);
mButoa[2]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
cpx += 1.5*pbsx+pspx;
mButoa[3] = new PIButton(this, "+Curs", 5321,  1.5*pbsx, pbsy, cpx, cpy);
mButoa[3]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);
cpx += 1.5*pbsx+pspx;
mButoa[4] = new PIButton(this, "+Axe", 5331,  1.5*pbsx, pbsy, cpx, cpy);
mButoa[4]->SetBinding(PIBK_elastic,PIBK_elastic, PIBK_elastic,PIBK_elastic);

curlutw = this;

}

/* --Methode-- */
PIImgTools::~PIImgTools()
{
if (curlutw == this)  curlutw = NULL;
int i;
for(i=0; i<2; i++)
  {
  delete mLab[i];
  delete mBut[i];
  delete mText[i];
  delete mOpt[i];
  delete mOlb[i];
  delete mSc[i];
  delete mOptzc[i];
  }
for(i=0; i<2; i++)  delete mCasc[i];
for(i=0; i<5; i++)  delete mButsz[i];
for(i=0; i<3; i++)  delete mButcax[i];
for(i=0; i<5; i++)  delete mButoa[i];
delete mOptCut;
}

/* --Methode-- */
void PIImgTools::Show()
{
char buff[32];
PIImage *mpii;
PIWindow::Show();
mpii = PIImage::CurrentPIImage();
if (mpii == NULL) {
  mOptzc[0]->Menu()->SetStateMsg(299, false);
  mOptzc[0]->SetValue(203);  mLastCol = 203;
  mOptzc[1]->SetValue(101);
  mOptCut->SetValue(303);
  return;
}
min_lut = mpii->Lut()->Min();
max_lut = mpii->Lut()->Max();
sprintf(buff,"%g", min_lut);
mText[0]->SetText(buff);
sprintf(buff,"%g", max_lut);
mText[1]->SetText(buff);
if     ( (mpii->Lut())->Type() == kLutType_Lin )    mOpt[0]->SetValue(1100);
else if( (mpii->Lut())->Type() == kLutType_Log )    mOpt[0]->SetValue(1101);
else if( (mpii->Lut())->Type() == kLutType_Sqrt )   mOpt[0]->SetValue(1102);
else if( (mpii->Lut())->Type() == kLutType_Square ) mOpt[0]->SetValue(1103);
else                                                mOpt[0]->SetValue(1100);
string s("NoAuto");
mOpt[1]->SetValueStr(s);
mSc[0]->SetValue(0);
mSc[1]->SetValue(0);

// Pour mettre a jour le menu de la table de couleur
mOptzc[0]->Menu()->SetStateMsg(299, mpii->GetColMap()->IsColorIndexReversed());
int cmnum = PIColorMap::ColorMapId2Num(mpii->GetColMapId());
mLastCol =  (cmnum < 0) ? 203 : 201+cmnum;
mOptzc[0]->SetValue(mLastCol);

// Pour le facteur de zoom
mOptzc[1]->SetValue(mpii->GetZoom()+100);

mOptCut->SetValue(303);
return;
}


/* --Methode-- */
void PIImgTools::Process(PIMessage msg, PIMsgHandler* /*sender*/, void* /*data*/)
{
double min, max, del;
int lauto, typ;
int typlut[4] = {kLutType_Lin, kLutType_Log, kLutType_Sqrt, kLutType_Square} ; 

msg = UserMsg(msg);

if (msg == 2600)  { this->Hide();  return; }
PIImage* mpii = PIImage::CurrentPIImage();
if (mpii == NULL)  return;

switch (msg)
  {
  case 2500:
  case 2700 :
  case 2800 :
    {
    if (mText[0]->GetText().length() > 0)   
      min = atof(mText[0]->GetText().c_str());
    else min = mpii->Lut()->Min();
    if (mText[1]->GetText().length() > 0)   
      max = atof(mText[1]->GetText().c_str());
    else max = mpii->Lut()->Max();

    if (msg == 2700) {
      del = max_lut-min_lut;
      min = min_lut+(double)mSc[0]->GetValue()/100*del;
      max = max_lut+(double)mSc[0]->GetValue()/100*del;
    }
    if (msg == 2800) {
      del = max_lut-min_lut;
      min = min_lut-(double)mSc[1]->GetValue()/100.*del*0.5;
      max = max_lut+(double)mSc[1]->GetValue()/100.*del*0.5;
    }
    if ( (msg == 2700) || (msg == 2800) ) {
      char buff[92];
      sprintf(buff,"%g", min);
      mText[0]->SetText(buff);
      sprintf(buff,"%g", max);
      mText[1]->SetText(buff);
      lauto = 0;
    }
    else lauto = mOpt[1]->GetValue() - 1200;
    typ = mOpt[0]->GetValue() - 1100;
    if ( (typ < 0) || (typ > 3) )  typ = 0;
    (PIImage::CurrentPIImage())->SetLut(min, max, typlut[typ], lauto);
    if (msg == 2500) { 
      min_lut = min;   max_lut = max;
      mSc[0]->SetValue(0);
      mSc[1]->SetValue(0);
      }
//    ((PIImage::CurrentPIImage())->Lut())->Print();
    }
    break;

  case 3201 :
  case 3202 :
  case 3204 :
  case 3198 :
  case 3196 :
    {
    PIImage* pimg = PIImage::CurrentPIImage();
    int zm = msg-3200;
    pimg->SetZoom(zm, false);
    int sx, sy, snx, sny;
    sx = pimg->XSize();
    sy = pimg->YSize();
    if (zm > 0)
      {
      snx = pimg->Image()->XSize()*zm;
      sny = pimg->Image()->YSize()*zm;
      }
    else 
      {
      snx = pimg->Image()->XSize()/(-zm);
      sny = pimg->Image()->YSize()/(-zm);
      }
    if ((snx != sx) || (sny != sy))
      {
      int szinc[2];
      pimg->SetOffset(0, 0, false);
      szinc[0] = snx-sx;   szinc[1] = sny-sy;
      pimg->Send(pimg->Msg(), PIMsg_ResizeRequest, szinc);  
      }
    else   pimg->SetOffset(0, 0);
    
    }
    break;

  case 5201 :
    mpii->ChangeAxesConfiguration(true, false, false);
    break;
  case 5202 :
    mpii->ChangeAxesConfiguration(false, true, false);
    break;
  case 5203 :
    mpii->ChangeAxesConfiguration(false, false, true);
    break;


  case 5300 :
    mpii->SetDrawAxesFlags(kAxesNone);
    mpii->ShowCursor(false);
    mpii->MyElDrawer()->ElDelAll();
    mpii->Refresh();
    break;

  case 5311 :
    mpii->ShowInfo(true);
    break;

  case 5312 :
    mpii->ShowInfo(false);
    break;

  case 5321 :
    mpii->ShowCursor(true);
    break;

  case 5331 :
    mpii->SetDrawAxesFlags();
    break;

  default:
//    printf("PIImgTools::Process Msg %d received \n", (int)msg);
    break;
  }


if ((msg <= 110) && (msg >= 90))  // Zoom
  PIImage::CurrentPIImage()->SetZoom((int)(msg-100), true);
else if (msg == 299) { // Revert CMap index 
  mOptzc[0]->SetValue(mLastCol);
}
else if ((msg > 200) && (msg < 299)) { // Changement de couleur 
  //  bool irev = PIImage::CurrentPIImage()->GetColMap()->IsColorIndexReversed();
  bool revidx = mOptzc[0]->Menu()->GetStateMsg(299);
  //  cout << " DBG PIImgTools::Process() revidx= " ;
  //  if (revidx) cout << " TRUE " ;
  //  else cout << " FALSE " ;
  //  if (irev) cout << " Img::RevIdx= TRUE " << endl;
  //  else cout << " Img::RevIdx= FALSE " << endl;
  PIImage::CurrentPIImage()->SetColMapId(PIColorMap::GetStandardColorMapId(msg-201), revidx, true);
  mLastCol = msg;
}

// Cuts
if(301<=msg && msg<=315) {
  PIImage::CurrentPIImage()->SelectCuts((unsigned short) (msg-300));
}

return;
}

