// g++ -g  -Wall -I/usr/X11R6/include -L/usr/X11R6/lib -lX11 -lforms -lm -lGL  -o chgsize chgsize.cpp glcanvas.c
#inlude "chgsize.h"
//
/*-----------------------------------------------------------------------------
 *  File Name:    chgsize.cpp 
 *
 *  To test glcanvas size changes
 *
 *  Author:       David Scriven
 *
 *  Date:         March 6, 2002
 *---------------------------------------------------------------------------*/

//  menu contents

static FL_PUP_ENTRY imagepopup[] =
{
        {"Zoom"},
        {"_Squeeze"},
        {"Quit  <esc>"},
        {0},
};
int main(int argc, char ** argv) 
{
	ChgSize GVar;

	GVar.Run(argc, argv);
        return 0;
}

ChgSize::ChgSize()
{
   bZoom = false;
   nZoom = 1;
   nXSize = 200;
   nYSize = 200;
}
ChgSize::~ChgSize()
{   
   if(fl_form_is_visible(Form()))fl_hide_form(Form());
   fl_free_form(Form());
   fl_free(chgsize);
}
int ChgSize::InitForm(int argc, char* argv[])
{
    Display* dsply = fl_initialize( &argc, argv, "ChangeSize", 0, 0 );
    if(dsply == NULL)
    {
      std::cerr << "Cannot initialize XForms!" << endl;
      exit(0);
    }

    chgsize = create_form_chgsize();
    chgsize->chgsize->u_vdata=this;

//static int glcanvas_attributes[] = 
//   {GLX_RGBA, GLX_DEPTH_SIZE, 16, None};
//   fl_set_glcanvas_attributes(ChgSize->canvas,glcanvas_attributes);
    
// Handlers for events we want to trap
    fl_add_canvas_handler(chgsize->canvas, KeyPress, ChgSize::ProcessEvent, 0); 
    fl_add_canvas_handler(chgsize->canvas, Expose, ChgSize::ProcessEvent, 0);
    fl_add_canvas_handler(chgsize->canvas, ButtonPress, ChgSize::ProcessEvent, 0);
    fl_add_canvas_handler(chgsize->canvas, ButtonRelease, ChgSize::ProcessEvent, 0);
    fl_add_canvas_handler(chgsize->canvas, MotionNotify, ChgSize::ProcessEvent, 0);
    fl_add_canvas_handler(chgsize->canvas, ConfigureNotify, ChgSize::ProcessEvent,0);

    imagemenu = fl_defpup(window,"Size %t");
 
    fl_setpup_entries(imagemenu,imagepopup);
    fl_setpup_shadow(imagemenu,1);

// resize window to size of image
    fl_set_form_size( chgsize->chgsize, nXSize, nYSize);  
    window = fl_show_form( chgsize->chgsize, FL_PLACE_CENTER |FL_FREE_SIZE, FL_FULLBORDER, "Change" );
    int xw, yw, wi, he;
    fl_get_wingeometry(window, &xw, &yw, &wi, &he);
    std::cerr << " Zoom = " << nZoom << endl; 
    std::cerr << "Window geometry before Zoom : x = " << xw << " y = " << yw << " w = " << wi << " h = " << he << std::endl; 
    fl_get_object_geometry(chgsize->canvas,&xw, &yw, &wi, &he);
    std::cerr << "Canvas geometry before Zoom : x = " << xw << " y = " << yw << " w = " << wi << " h = " << he << std::endl;

// Setup OpenGl - do this after the show_form because it
// initialises OpenGL and would overwrite earlier settings
// Enable Color Tables & disable everything that will slow 
// down glDrawPixels

    glEnable(GL_COLOR_TABLE);
    glDisable(GL_BLEND);
    glDisable(GL_DITHER);
    glDisable(GL_FOG);
    glDisable(GL_LIGHTING);
    glDisable(GL_LINE_STIPPLE);
    glDisable(GL_STENCIL_TEST);
    glDisable(GL_TEXTURE_1D);
    glDisable(GL_TEXTURE_2D);
    glShadeModel(GL_FLAT);

// set viewport
    glViewport(0,0,nXSize-1,nYSize-1);

    makeFont("10x20");
    DisplayImage();
    return 0;
}
ChgSize* ChgSize::GetThis(FL_OBJECT *obj) 
{
    return (ChgSize*) obj->form->u_vdata; 
}
void ChgSize::Run(int argc, char* argv[])
{
   if(InitForm(argc, argv)> 0)return;
// Process events 
    fl_do_forms( ); 

    exit( 0 );
}
void ChgSize::ImageMenu( int selected )
{
   switch (selected)
   {
      case 1:   //          Zoom
         if(nZoom < 5)nZoom++;
	 OnZoom();
         break;
      case 2:  //          Squeeze
         if(nZoom > 1)nZoom--;
	 OnZoom();
         break;
      case 3:  //          Quit
         exit(0);
         break;
      default:
         break;
   }
}
/****************************************************************
    Event processing  
*****************************************************************/ 
int ChgSize::ProcessEvent(FL_OBJECT *ob, Window win, int w, int h, XEvent *xev, void *ud)
{
   int button;

   int key, shift;
   ChgSize* winl = GetThis(ob);

   switch(xev->type)
   {
     case KeyPress:
        shift = fl_keysym_pressed(XK_Shift_L) || fl_keysym_pressed(XK_Shift_R);
        key = XKeycodeToKeysym(fl_display,xev->xkey.keycode,shift);
        winl->OnKeyPress(key);
        break;
     case ButtonPress:
        button = xev->xbutton.button;
        if(button == 1)cout << " L Mouse Button Down " << endl;
        if(button == 2)cout << " M Mouse Button Down " << endl;
        if(button == 3)winl->OnRButtonDown();
        break;
     case ButtonRelease:
        button = xev->xbutton.button;
        if(button == 0)cout << " Mouse Button Released " << endl;
        if(button == 1)cout << " L Mouse Button Up " << endl;
        if(button == 2)cout << " M Mouse Button Up " << endl;
        if(button == 3)cout << " R Mouse Button Up " << endl;
        break;
     case ConfigureNotify:
        winl->ConfigNotify();
     case Expose:
        winl->DisplayImage();
        break;
     case MotionNotify:
        break;
     default:
        std::cerr << "Event = " << xev->type << endl;
     }
     return 0;
}
void ChgSize::OnKeyPress(int key)
{
     if( !strcmp("Escape",XKeysymToString(key)))exit(0);
     switch(key)
     {
        
     }
}
void ChgSize::ConfigNotify()
{
       std::cerr << "ConfigureNotify sent" << std::endl;
       if(bZoom)
       {
        int cx, cy, cw, ch;
        fl_get_object_geometry(chgsize->canvas,&cx, &cy, &cw, &ch);
        std::cerr << "Canvas geometry after Zoom : x = " << cx << " y = " << cy << " w = " << cw << " h = " << ch << std::endl; 
        fl_get_wingeometry(window,&cx, &cy, &cw, &ch);
        std::cerr << "Window geometry after Zoom : x = " << cx << " y = " << cy << " w = " << cw << " h = " << ch << std::endl; 
        bZoom = false;
       }
}
/***********************************************************************
      Handle Mouse Events
************************************************************************/
void ChgSize::OnRButtonDown() 
{
	ImageMenu(fl_dopup(imagemenu));
}
/******************************************************************
        Image Display
*******************************************************************/
void ChgSize::DisplayImage()
{
   fl_activate_glcanvas(chgsize->canvas);
   glDrawBuffer(GL_BACK);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glOrtho(0, nXSize, 0, nYSize, 0.0, 1.0);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   glViewport(0, 0, nXSize, nYSize);
   glClearColor(0.0,0.0,0.0,0.0);
   glClear(GL_COLOR_BUFFER_BIT);
   glClear(GL_DEPTH_BUFFER_BIT);

   glRasterPos2i(0,0);
   CheckGLError();
   GLfloat blue[] = {0.0, 0.0, 1.0};
   GLfloat white[] = {1.0, 1.0, 1.0};
   GLfloat cyan[] = {0.0,1.0,1.0};
   glColor3fv(blue); 
   glRecti(0, 0, nXSize, nYSize);
   glColor3fv(cyan); 
   glRecti(50, 50, nXSize-50, nYSize-50);
   glColor3fv(white); 
   glRecti(75, 75, nXSize-75, nYSize-75);
   displaystring(5*nZoom, 5*nZoom, RED, "Not GREEN");
   glBegin(GL_LINES);
     glVertex2i(0,0);
     glVertex2i(nXSize, nYSize);
   glEnd();
   
   displaystring(20*nZoom, 50*nZoom, GREEN, "Not RED");
   glXSwapBuffers(fl_display, fl_get_canvas_id(chgsize->canvas));
}
void ChgSize::OnZoom()
{
    nXSize = nZoom*200;
    nYSize = nZoom*200;
    std::cerr << " Zoom = " << nZoom << endl; 
    fl_freeze_form(Form());
    int cx, cy, cw, ch;
    fl_get_wingeometry(window,&cx, &cy, &cw, &ch);
    std::cerr << "Window geometry before Zoom : x = " << cx << " y = " << cy << " w = " << cw << " h = " << ch << std::endl; 
    fl_get_object_geometry(chgsize->canvas,&cx, &cy, &cw, &ch);
    std::cerr << "Canvas geometry before Zoom : x = " << cx << " y = " << cy << " w = " << cw << " h = " << ch << std::endl;
    fl_set_form_size( Form(), nXSize, nYSize);
    fl_get_wingeometry(window,&cx, &cy, &cw, &ch);
    fl_unfreeze_form(Form());
    bZoom = true;
    glViewport(0, 0, nXSize -1 , nYSize -1);
    DisplayImage();  
}
/*************************************************************
           Create Fonts for display
*************************************************************/
void ChgSize::makeFont(char* fontname)
{
    XFontStruct *fontInfo;
    Font id;
    unsigned int first, last;
    fontInfo = XLoadQueryFont(fl_display, fontname);
    
    if (fontInfo == NULL) 
    {
        std::cerr << "No font found!\n" << endl;
        exit (0);
    }

    id = fontInfo->fid;
    first = fontInfo->min_char_or_byte2;
    last = fontInfo->max_char_or_byte2;

    rangebase = glGenLists(last+1);
    if (rangebase == 0) 
    {
        std::cerr <<"out of display lists\n";
        exit (0);
    }
    glXUseXFont(id, first, last-first+1, rangebase+first);
}


void ChgSize::displaystring(int x, int y, int color, const char *s)
{
  GLfloat red[] = {1.0, 0.0, 0.0};
  GLfloat green[] = {0.0, 1.0, 0.0};
  GLfloat blue[] = {0.0,0.0,1.0};
  if(color == RED)
     glColor3fv(red); // red
  if(color == GREEN)
     glColor3fv(green); // green
  if(color == BLUE)
     glColor3fv(blue); // blue
  glRasterPos2f(x, y);
  glListBase(rangebase);
  glCallLists(strlen(s), GL_UNSIGNED_BYTE, (unsigned char *)s);
}
bool ChgSize::CheckGLError()
{
  GLenum glerr = glGetError();
  if(glerr == GL_NO_ERROR)return false;
  string glMess;
  switch(glerr)
  {
    case GL_INVALID_ENUM:
      glMess = "Glenum argument out of range";
      break;
    case GL_INVALID_VALUE:
      glMess = "Numeric argument out of range";
      break;
    case GL_INVALID_OPERATION:
      glMess = "Operation illegal in current state";
      break;
    case GL_STACK_OVERFLOW:
      glMess = "Command would cause a stack overflow";
      break;
    case GL_STACK_UNDERFLOW:
      glMess = "Command would cause a stack underflow";
      break;
    case GL_OUT_OF_MEMORY:
      glMess = "Not enough memory left to execute command";
      break;
    default:
      glMess = "Unknown Error";
  }
  std::cout << "Gl Error " << glMess << endl;
  return true;
}
FD_chgsize *create_form_chgsize(void)
{
  FL_OBJECT *obj;
  FD_chgsize *fdui = (FD_chgsize *) fl_calloc(1, sizeof(*fdui));

  fdui->chgsize = fl_bgn_form(FL_NO_BOX, 50,50);
  obj = fl_add_box( FL_UP_BOX, 0, 0, 50, 50, "" );

  obj = fl_add_frame(FL_DOWN_FRAME,0, 0, 340, 280, "");
    fl_set_object_gravity(obj, FL_NorthWest, FL_SouthEast);
  fdui->canvas =obj= fl_add_glcanvas(FL_NORMAL_CANVAS,0,0,50,50,"");
    fl_set_object_gravity(obj, FL_NorthWest, FL_SouthEast);
  fl_end_form();

  fdui->chgsize->fdui = fdui;

  return fdui;
}


