#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <iostream.h>

#include "pisysdep.h"
#include PIAPP_H
#include PIWIN_H 
#include PIMENU_H 
#include PISTDWDG_H 
#include PIBWDG_H
#include "piscdrawwdg.h"
#include "pievthandler.h"
#include "parradapter.h"

#include "piyfxdrw.h"

/*  Exemple d'utilisation PIBaseWdg - Creation d'une nouvelle composante graphique  */

// ---- Declaration de la classe ExBWdg --------
class ExBWdg : public PIBaseWdg
{
public:
// Les methodes ...

                  ExBWdg(PIContainerGen *par, char *nom,
                         int sx=10, int sy=10, int px=0, int py=0);
  virtual         ~ExBWdg();

// Traitement des evenements   
//  virtual void   Resize();
  virtual void   Draw(PIGraphic* g, int x0, int y0, int dx, int dy);

  virtual void   But1Press(int x, int y);
  virtual void   But1Release(int x, int y);
  virtual void   But2Press(int x, int y);
  virtual void   But2Release(int x, int y);
  virtual void   But3Press(int x, int y);
  virtual void   But3Release(int x, int y);
  virtual void   Keyboard(int key, PIKeyModifier kmod);

protected:
  int mfnt, mmrk;
  int nc;
  char str[32];
};


/* ........................................................... */
/*     Classe ExBWdg (Implementation des methodes)             */
/* ........................................................... */

/* --Methode-- */
ExBWdg::ExBWdg(PIContainerGen *par, char *nom,
                       int sx, int sy, int px, int py) 
: PIBaseWdg(par, nom, sx, sy, px, py)

{
mmrk = mfnt = nc = 0;
strcpy(str, "Hello !");
for(int i=strlen(str); i<20; i++) str[i] = ' ';
str[20] = '\0';

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

/* --Methode-- */
ExBWdg::~ExBWdg()
{
}
 
/* --Methode-- 
void ExBWdg::Resize()
{
}
*/

/* --Methode-- */
void ExBWdg::Draw(PIGraphicGen* g, int /*x0*/, int /*y0*/, int /*dx*/, int /*dy*/)
{
PIFontAtt att[4] = { PI_RomanFont, PI_BoldFont, PI_ItalicFont, PI_BoldItalicFont};
PIFontSize fsz[4] = { PI_TinySizeFont, PI_SmallSizeFont, PI_NormalSizeFont, PI_LargeSizeFont};
PIMarker  pmk[11] = { PI_DotMarker , PI_PlusMarker, PI_CrossMarker,  
                 PI_CircleMarker, PI_FCircleMarker,
                 PI_BoxMarker, PI_FBoxMarker,
                 PI_TriangleMarker, PI_FTriangleMarker,
                 PI_StarMarker, PI_FStarMarker };

if (g->kind() != PI_PSFileGraphics ) EraseWindow();

g->SelMarker(8, pmk[mmrk]);

g->SelLine(PI_NormalLine);
g->DrawBox(10,10, XSize()-20, YSize()-20);

g->SelLine(PI_ThinLine);
g->DrawFBox(20, 20, 20, 20);
g->DrawCircle(30, 30, 15);

g->SelForeground(PI_Red);
g->DrawFCircle(70, 30, 15);

g->SelForeground(PI_Yellow);
g->DrawFBox(10, 60, 120, 20);

PIFont f0;
g->SelFont(f0);
g->SelForeground(PI_Black);
g->DrawString(20, 110, str);
PIFont f(PI_TimesFont);
f.SetFontSz(fsz[mfnt]);
g->SelFont(f);
g->DrawString(20, 130, "Times-Font");
PIFont f2(14,PI_CourierFont, att[mfnt]);
g->SelFont(f2);
g->SelForeground(PI_Red);
g->DrawString(20, 150, "Courier-Font");
PIFont f3(14,PI_TimesFont, att[mfnt]);
g->SelFont(f3);
g->SelForeground(PI_Blue);
g->DrawString(20, 170, "Times-Font");
PIFont f4(14,PI_HelveticaFont, att[mfnt]);
g->SelFont(f4);
g->SelForeground(PI_Black);
g->DrawString(20, 190, "Helvetica-Font");
PIFont f5(14,PI_SymbolFont);
g->SelFont(f5);
g->DrawString(20, 210, "Symbol-Font");
g->SelFont(f0);


g->SelLine(PI_ThinLine);
g->DrawLine(20, 140, 50, 130);
g->SelLine(PI_NormalLine);
g->DrawLine(50, 140, 80, 130);
g->SelLine(PI_ThickLine);
g->DrawLine(80, 140, 110, 130);

g->SelForeground(PI_Magenta);
g->DrawFCircle(120, 30, 15);
g->SelForeground(PI_Grey);
g->DrawFCircle(120, 60, 15);




PIGrCoord x[5] = { 150, 165, 180, 195, 210 };
PIGrCoord y[5] = { 50, 50, 50, 50, 50 };

g->SelForeground(PI_Black);
g->DrawMarkers(x, y, 5);
return;
}


static char strbuff[128];
/* --Methode-- */
void ExBWdg::But1Press(int x, int y)
{
SelPointerShape(PI_CrossPointer);
sprintf(strbuff,"Pos X= %d Y= %d", x, y);
mWGrC->SelFont(PI_NormalSizeFont, PI_BoldFont);
mWGrC->DrawString(x+10, y, strbuff);
Send(Msg(), PIMsg_Active);
return;
}

/* --Methode-- */
void ExBWdg::But1Release(int x, int y)
{
SelPointerShape(PI_ArrowPointer);
Refresh();
return;
}

/* --Methode-- */
void ExBWdg::But2Press(int x, int y)
{
if (++mfnt > 3)  mfnt = 0;
if (++mmrk > 10)  mmrk = 0; 
return;
}

/* --Methode-- */
void ExBWdg::But2Release(int x, int y)
{
Refresh();
return;
}

/* --Methode-- */
void ExBWdg::But3Press(int x, int y)
{
SelPointerShape(PI_HandPointer);
mWGrC->SelForeground(PI_Blue);
mWGrC->DrawFBox(XSize()/3, YSize()/3, XSize()/8, YSize()/8);
return;
}

/* --Methode-- */
void ExBWdg::But3Release(int x, int y)
{
mWGrC->SelForeground(PI_White);
mWGrC->DrawFBox(XSize()/3, YSize()/3, XSize()/8, YSize()/8);
mWGrC->SelForeground(PI_Black);
SelPointerShape(PI_ArrowPointer);
return;
}

/* --Methode-- */
void ExBWdg::Keyboard(int key, PIKeyModifier kmod)
{
str[nc] = key;  str[nc+1] = '\0';
if (++nc > 30)  nc = 0;
char buf[16];

if (key == PIK_Return) { Refresh(); nc = 0; return; }
mWGrC->SelFont(PI_NormalSizeFont, PI_BoldFont);
sprintf(buf," %c (%3d) ", (char) key, key, (int)kmod);
mWGrC->DrawOpaqueString(20, 75, buf);

if ( (kmod == PIKM_Alt) && (key == 'c') ) {
  printf("ExBWdg::Keyboard: Test-Copy ... \n"); 
  ClaimSelection();
}
if ( (kmod == PIKM_Alt) && (key == 'v') ) {
  printf("ExBWdg::Keyboard: Test-Paste ... \n"); 
  RequestSelection();
}

return;
}

// ----- Exemple d'une classe heritant de PIScDrawWdg ----
/* ........................................................... */
/*                         Classe ScSample                     */
/* ........................................................... */

class ScSample : public PIScDrawWdg {
public:
  ScSample(PIContainerGen *par, char *nom,
           int sx=10, int sy=10, int px=0, int py=0);
  virtual ~ScSample();
};

static double fpol(double x) {return (0.3*x*x*x-x*x+7.);}
static float xpts[10] =  {-2.4, -2  , -1., 1., 1.7, 2.2, 3., 3.75, 4.3,  4.8};
static float ypts[10] =   {-5  , -1.5, 2.5, 5., 8.0, 12., 9., 6.00, 2.2, -3.0};

ScSample::ScSample(PIContainerGen *par, char *nom,
                  int sx, int sy, int px, int py)
:PIScDrawWdg(par, nom, sx, sy, px, py)

{
// Definition des limites
SetLimits(-3,5,-10,15);

// Creation et ajout d'un drawer de fonctions
PIFuncDrawer* mfd = new PIFuncDrawer(fpol);
mfd->GetGraphicAtt().SetColAtt(PI_Blue);
mfd->GetGraphicAtt().SetLineAtt(PI_NormalLine);
AddScDrawer(mfd,true);

// Creation et ajout d'un drawer de points
PIYfXDrawer* mxyd = new PIYfXDrawer(new P1DAdapter<float>(xpts, 10, false), 
                                    new P1DAdapter<float>(ypts, 10, false), true);
mxyd->GetGraphicAtt().SetColAtt(PI_Magenta);
mxyd->GetGraphicAtt().SetMarkerAtt(7, PI_FBoxMarker);
AddScDrawer(mxyd, true);

// Ajout de texte
BaseDrawer()->GetGraphicAtt().SetFontAtt(PI_NormalSizeFont, PI_BoldFont);
PIGraphicAtt gatt;
gatt.SetColAtt(PI_Red);
BaseDrawer()->ElDrwMgr().ElAddText(-2.8, 12., "---- ScSample ----", gatt, 0);
BaseDrawer()->ElDrwMgr().ElAddText(-2.8, 10.,  "f(x)=0.3*x^3-x^2+7.", gatt, 0);

SetAxesFlags(kAxesDflt);
}

ScSample::~ScSample()
{
}

//      ----------- Une classe EventHandler ----------
class MyEvHandler :  public PIEventHandler {
public :
			MyEvHandler();
			~MyEvHandler();
  virtual void		Draw(PIGraphic* g, int x0, int y0, int dx, int dy);
  virtual void		ProcessEvent();
  inline bool 		GrabOK() { return(grabok); }

protected :
  PIScreenBuffer* mscb;
  int mposx, mposy;
  int mposx2, mposy2;
  int msx, msy;
  bool grabok;
};

/* --Methode-- */
MyEvHandler::MyEvHandler()
        : PIEventHandler()
{
mscb = new PIScreenBuffer(100, 100);
msx = 100;   msy = 100;
mposx = mposy = 0;
mposx2 = mposy2 = 0;
grabok = false;
}

/* --Methode-- */
MyEvHandler::~MyEvHandler()
{
delete mscb;
}

/* --Methode-- */
void MyEvHandler::Draw(PIGraphic* g, int, int, int, int)
{
if (GrabOK()) {
  printf("MyEvHandler::Draw() : Copying from ScreenBuffer to wdg (%lx) \n", (unsigned long)CurrentWdg());
  mscb->CopyToWdg(CurrentWdg(), 0, 0, msx, msy, CurrentWdg()->XSize()/2, CurrentWdg()->YSize()/2);
  }
else printf("MyEvHandler::Draw() : Grab first from source \n");
}

/* --Methode-- */
void MyEvHandler::ProcessEvent()
{
printf("MyEvHandler::ProcessEvent() \n");
switch (EventType()) {

  case PIEvent_But3Press : 
    mposx = GetPosX();
    mposy = GetPosY();
    break;

  case PIEvent_But3Release : 
    mposx2 = GetPosX();
    mposy2 = GetPosY();
    printf("MyEvHandler::ProcessEvent(): Rectangle(%d,%d - %d,%d) \n", mposx, mposy, mposx2, mposy2);
//    ((PIBaseWdg*)CurrentWdg())->WindowGraphic()->DrawBox(mposx, mposy, (mposx2-mposx), (mposy2-mposy));
    break;

  case PIEvent_Keyboard :
    if ((GetKeyMod() == PIKM_Alt) && ((GetKey() == 'G') || (GetKey() == 'g')) ) {
      printf("MyEvHandler::ProcessEvent(): Grabbing(%dx%d) from Wdg(%lx)@(%d,%d) \n", 
             msx, msy, (unsigned long)CurrentWdg(), mposx, mposy);
      mscb->CopyFromWdg(CurrentWdg(), mposx, mposy, msx, msy, 0, 0);
      grabok = true;
      }
    break;

  default :
    printf("MyEvHandler::ProcessEvent(): Unexpected Event (Type = %d) received \n", (int)EventType());
    break;
  }

return;
}

/* ........................................................... */
/*                       Classe PITApp                         */
/* ........................................................... */
class PITApp : public PIApplication {
public:
     PITApp(int narg=0, char* arg[]=NULL);
     ~PITApp();
     virtual void   Process(PIMessage msg, PIMsgHandler* sender, void* data=NULL);
private :
  PIMenu* m[2];
  PIText* txt;
  MyEvHandler* evh;
  PIWindow* mcurwin;
  PIWdg* mdrhw;
  PIWdg* mevhw;
  PIWdg* mcurw;  
};


/* --Methode-- */
PITApp::PITApp(int narg, char* arg[])
: PIApplication(300, 100, narg, arg)
{

//  Menus, les numeros ds AppendItem sont les numeros de messages
//  qui seront passes a Process() et permettent d'identifier l'action

//  Creation du premier menu  

m[0] = new PIMenu(Menubar(),"Actions");
m[0]->AppendItem("Info", 10101);
m[0]->AppendItem("New ExBwdg", 10102);
m[0]->AppendItem("New ScSample", 10103);
m[0]->AppendItem("->eps", 10111);
m[0]->AppendItem("Exit", 10105);
// On accroche le menu au Menubar
AppendMenu(m[0]);

m[1] = new PIMenu(Menubar(),"Edit");
m[1]->AppendItem("Copy", 10201);
m[1]->AppendItem("Paste", 10202);
// On accroche le menu au Menubar
AppendMenu(m[1]);

// Creation d' zone texte multiligne
txt = new PIText(MainWin(), "mltext", true, true, 290, 90, 5, 5);
txt->SetBinding(PIBK_elastic,PIBK_elastic,PIBK_elastic,PIBK_elastic);
// txt->SetMutiLineMode(true);
txt->SetTextEditable(false);
txt->SetText("");

evh = new MyEvHandler; 
mcurwin = NULL;
mcurw = NULL;  
mdrhw = NULL;
mdrhw = NULL;
SetReady();
}

/* --Methode-- */
PITApp::~PITApp()
{
delete m[0]; delete m[1]; delete txt;
}  

static int numpsf = 0;
static int nbwin = 0;
/* --Methode-- */
void PITApp::Process(PIMessage msg, PIMsgHandler* sender, void* /*data*/)
{

char strg[256];

// Gestion des actions en fonctions des messages

if ( ( ModMsg(msg) == PIMsg_Active) || (ModMsg(msg) == PIMsg_Close) ) {
  PIWdg *sndw;
  sndw = (PIWdg *)sender;      
  if (sndw->kind() ==  PIWindow::ClassId)  {
    if (ModMsg(msg) == PIMsg_Close)  { 
//      printf("PITApp::Process()/Debug : Closing Window %lx \n", (long)sender);
      if (mcurwin->UserData() == mcurw) mcurw = NULL;
      if (mcurwin->UserData() == mdrhw) mdrhw = NULL;
      if (mcurwin->UserData() == mevhw) mevhw = NULL;
      delete (PIWindow *)sender;  
      mcurwin = NULL;  
      }
    else mcurwin = (PIWindow *)sender;
  }
  else if ( ModMsg(msg) ==  PIMsg_Active) mcurw = sndw;
}

else switch(UserMsg(msg))    {

    case 10101:     // Info 
      txt->SetText("pit1: PITApp \n PIBaseWdg - PIScDrawWdg test \n ExBWdg (:PIBaseWdg) Creation \n ScSample (:PIScDrawWdg) creation");
    break;

    case 10102: // Creation d'un ExBWdg
      {
      nbwin++;
      sprintf(strg, "Creation ExBwdg \n Fenetre No %d \n Test keyborard, button 1/2/3", nbwin);
      txt->SetText(strg);
      sprintf(strg,"Window %d - ExBwdg", nbwin);
      PIWindow* wp = new PIWindow(this, strg, PIWK_normal,  250, 250, 150, 150);
      wp->SetAutoDelChilds(true);
      ExBWdg* exb  = new ExBWdg(wp, "bwdg", 250, 250, 0, 0);
      exb->SetBinding(PIBK_fixed,PIBK_elastic,PIBK_elastic,PIBK_elastic);
      wp->SetUserData(exb);
      wp->Show();
      }
    break;

    case 10103:   // Creation d'un ScSample
      {
      nbwin++;
      sprintf(strg, "Creation Scsample \n Fenetre No %d \n Button 1 -> mouse position \n Button 2 -> Zoom \n keyboard <Alt>O <Alt>V", nbwin);
      txt->SetText(strg);
      sprintf(strg,"Window %d - ScSample", nbwin);
      PIWindow* wp = new PIWindow(this, strg, PIWK_normal,  400, 400, 200, 200);
      wp->SetAutoDelChilds(true);
      ScSample* sc  = new ScSample(wp, "scsample", 400, 400, 0, 0);
      sc->SetBinding(PIBK_elastic,PIBK_elastic,PIBK_elastic,PIBK_elastic);
      wp->SetUserData(sc);
      wp->Show();
      }
      break;

    case 10111:          // -> eps
      if (mcurwin) {
        char buff[64];
        sprintf(buff, "pit_%d.eps", numpsf);        numpsf++;
        printf("Creating EPS File %s (Encapsulated PostScript) \n", buff);
        PSFile *mps;
	mps = new PSFile(buff);
	mcurwin->PSPrint(mps,0,0);
	delete mps;
        }
      break;        
    case 10105:          // Sortie d'application
      Stop();
      break;


    case 10201:          // 2 eme menu  Copy
      if (mcurw == NULL) { printf("PITApp::Process()/Warning : Select a window for copy \n"); 
        sprintf(strg, "Warning : Select a window for copy");
        txt->SetText(strg);
        }
      else {
        printf("Adding EventHandler to Wdg %lx", (long)mcurw);
        sprintf(strg, "Adding EventHandler to Wdg %lx \n, Use button 3 to select copy zone \n, <Alt>G to Get copy",
                (long)mcurw);
        txt->SetText(strg);
        if (mevhw != NULL) mevhw->RemoveEventHandler(evh);  mevhw = NULL;  
        mcurw->AddEventHandler(evh, PIEvent_But3Press | PIEvent_But3Release | PIEvent_Keyboard, false);
        }
      break;
      
    case 10202:          //   2eme Menu - Paste
      if (mcurw == NULL) { printf("PITApp::Process()/Warning : Select a window for paste \n"); 
        sprintf(strg, "Warning : Select a window for paste");
        txt->SetText(strg);
        }
      else {
        printf("Adding DrawHandler to Wdg %lx \n - Refreshing Wdg", (long)mcurw);
        sprintf(strg, "Adding DrawHandler to Wdg %lx \n - Refreshing Wdg", (long)mcurw);
        txt->SetText(strg); 
        mcurw->AddDrawHandler(evh, false); 
        mdrhw = mcurw;
        ((PIBaseWdg*)mcurw)->Refresh();
        }
      break;
      
    default :
      //      printf("PITApp::Process() Msg= %d (%d - %d)??? \n", 
      //            (int)msg, (int)UserMsg(msg),(int)ModMsg(msg));
     break;
    
  }
return;
}


// ................................................................
//                   programme principal 
// ................................................................

int main(int narg, char *arg[])
{
if ( (narg > 1) && (strcmp(arg[1],"-h") == 0) ) {
  printf("pit1 : ExBWdg (:PIBaseWdg) / ScSample (:PIScDrawWdg) test \n");
  printf("  Usage : pit1 [Xt options] \n");
  }
//  Creation de l'objet application et appel de Run()
PITApp* app = new PITApp(narg, arg);
// puts("appel de Application.Run() ... ");
app->Run();

delete app;
exit(0);
}


