/*

 *** callbacks.c - Tamara Munzner, Sept. 1992
 rewritten by Ed H. Chi (chi@geom.umn.edu) summer 1994
 
 $Id: callbacks.c,v 1.20 1996/10/07 16:53:13 slevy Exp $
 $Log: callbacks.c,v $
 * Revision 1.20  1996/10/07  16:53:13  slevy
 * Back-port to Forms 0.75 -- the only version available for Irix 4.
 *
 * Revision 1.19  1996/10/07  15:33:42  slevy
 * Remove all conditional code for SGI & VOGL -- we're now pure X,
 * using only XForms.
 *
 * Revision 1.18  1996/10/04 21:46:47  slevy
 * Finish adapting to vogl-less mode.  Clean up.
 * 
 * Revision 1.17  1996/09/30 22:59:04  slevy
 * Convert to new vogl-less mode.
 *
 * Revision 1.16  1996/09/28  03:17:03  slevy
 * Don't turn off "lit" flag when we're not actually redrawing!
 * Add SavePSProc() for "Print To" button.
 * Use new paler color for background blues.
 *
 * Revision 1.15  1996/09/27 15:21:17  slevy
 * Add fl_ wrappers for some flx_ functions, taking account of Y-flipped
 * conventions for X.
 * Allow internal mode setting (from keyboard shortcuts).
 *
 * Revision 1.14  1994/12/15  05:18:47  munzner
 * add options to load file, specify window placement on command line.
 * minor cleanup: use function pointer in forms_init
 *
 * Revision 1.13  1994/09/12  23:14:41  chi
 * version 3.0 changes
 * rewrote the file handling procedures, it now uses forms file selector
 * disable delete and move button when in X
 *
 * Revision 1.12  1994/08/26  16:29:02  chi
 * rewritten by Ed H. Chi (chi@geom)
 * start of a port to X11
 *
 * Revision 1.2  1994/08/15  20:05:38  chi
 * significant code cleanup.
 * header files created.
 * main.h created
 * changed #defines in main.h from DRAW to KALIDRAW, CUT to
 .... etc
 *
 
 */

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



#include "main.h"
#include "io.h"
#include "symmetry.h"
#include "kali.h"

#include "icons.h"
#include "help.h"

#define SAVE 0
#define LOAD 1

#ifndef TRUE
#define TRUE 1
#endif


#ifdef __GNUC__	/* Ugh.  Prevent Linux X11/Xlib.h from mis-defining wchar_t */
#define __EMX__ 1
#endif

#include "forms.h"


#if FL_INCLUDE_VERSION <= 75  /* Old XForms */

#define DrawButton DrawBtn	/* Avoid name conflict with XForms typedef! */
#define FLXWRAPPER(xfunc, formsfunc) \
 FL_OBJECT *xfunc(int kind, float x, float y, float w, float h, char *name) { \
   return formsfunc(kind, x, y, w, h, name); \
 }

#else /* Modern XForms */

#define FLXWRAPPER(xfunc, formsfunc) \
 FL_OBJECT *xfunc(int kind, float x, float y, float w, float h, char *name) { \
   return formsfunc(kind, x, fl_current_form->h-(y)-(h), w, h, name); \
 }
FLXWRAPPER(flx_add_bitmap, fl_add_bitmap)
FLXWRAPPER(flx_add_box, fl_add_box)
FLXWRAPPER(flx_add_browser, fl_add_browser)
FLXWRAPPER(flx_add_button, fl_add_button)
FLXWRAPPER(flx_add_choice, fl_add_choice)
FLXWRAPPER(flx_add_text, fl_add_text)

#define fl_add_bitmap  flx_add_bitmap
#define fl_add_box  flx_add_box
#define fl_add_browser  flx_add_browser
#define fl_add_button  flx_add_button
#define fl_add_choice  flx_add_choice
#define fl_add_text  flx_add_text

#endif

			/* Image-button colors */
#define WHITEINDEX 7
#define BLUEINDEX 29
#define BLACKINDEX 0

#include "panel.c"

void set_linebutton(int new);
void set_symbutton(int new);
void set_angrat();
FL_OBJECT *linelist(int button);
FL_OBJECT *symlist(int button);
void flx_enable(FL_OBJECT *obj);
void flx_disable(FL_OBJECT *obj);

void forms_init(RECTANGLE *pwin)
{
  int i;
  void (*bitmap_func)(FL_OBJECT *, int, int, unsigned char *);

#if FL_INCLUDE_VERSION <= 75
  fl_mapcolor(BLUEINDEX, 0, 128, 255);
#endif

  create_the_forms();

  bitmap_func = fl_set_bitmap_data;

  (*bitmap_func)(P6MBitmap, icon_width, icon_height, p6m_bits);
  (*bitmap_func)(P6Bitmap, icon_width, icon_height, p6_bits);
  (*bitmap_func)(P31MBitmap, icon_width, icon_height, p31m_bits);
  (*bitmap_func)(P3M1Bitmap, icon_width, icon_height, p3m1_bits);
  (*bitmap_func)(P3Bitmap, icon_width, icon_height, p3_bits);
  (*bitmap_func)(P4MBitmap, icon_width, icon_height, p4m_bits);
  (*bitmap_func)(P4GBitmap, icon_width, icon_height, p4g_bits);
  (*bitmap_func)(P4Bitmap, icon_width, icon_height, p4_bits);
  (*bitmap_func)(PMMBitmap, icon_width, icon_height, pmm_bits);
  (*bitmap_func)(CMMBitmap, icon_width, icon_height, cmm_bits);
  (*bitmap_func)(P2Bitmap, icon_width, icon_height, p2_bits);
  (*bitmap_func)(PMGBitmap, icon_width, icon_height, pmg_bits);
  (*bitmap_func)(PGGBitmap, icon_width, icon_height, pgg_bits);
  (*bitmap_func)(CMBitmap, icon_width, icon_height, cm_bits);
  (*bitmap_func)(PGBitmap, icon_width, icon_height, pg_bits);
  (*bitmap_func)(PMBitmap, icon_width, icon_height, pm_bits);
  (*bitmap_func)(P1Bitmap, icon_width, icon_height, p1_bits);

  (*bitmap_func)(HopBitmap, bigicon_width, bigicon_height, hop_bits);
  (*bitmap_func)(StepBitmap, bigicon_width, bigicon_height, step_bits);
  (*bitmap_func)(JumpBitmap, bigicon_width, bigicon_height, jump_bits);
  (*bitmap_func)(SidleBitmap, bigicon_width, bigicon_height, sidle_bits);
  (*bitmap_func)(SpinHopBitmap, bigicon_width, bigicon_height, spinhop_bits);
  (*bitmap_func)(SpinJumpBitmap, bigicon_width, bigicon_height, spinjump_bits);
  (*bitmap_func)
    (SpinSidleBitmap, bigicon_width, bigicon_height, spinsidle_bits);

  fl_addto_choice(DimChoice, "Wallpaper Groups");
  fl_addto_choice(DimChoice, "Frieze Groups");


  SymmetryProc(NULL, sym_index);
  fl_set_choice(DimChoice, frieze+1);
  DimProc(NULL, 0);
  if (moron) {
    flx_disable(DimChoice);
    /*flx_disable(DeleteButton);*/
    flx_disable(MoveButton);
  }
  fl_initial_wingeometry((int)pwin->x, (int)pwin->y, (int)pwin->width, (int)pwin->height);
  winset(fl_show_form(KaliForm, FL_PLACE_FREE, TRUE, "Symmetry Groups"));
  winconstraints();

  for (i=0; help[i][0] != '.'; i++) {
    fl_add_browser_line(InfoBrowser, help[i]);
  }

}


void load_a_file(FILE *pat)
{
  LoadProc(pat);
  set_symbutton(sym_index);
  fl_set_choice(DimChoice, (sym_index > 16) +1 );
  DimProc(NULL, 1);
  winset(win);
}

void DimProc(FL_OBJECT *obj, long val)
{
  frieze = fl_get_choice(DimChoice)-1;
  if (frieze) {
    fl_hide_object(Wallpaper);
    fl_show_object(Frieze);
    if (!val) SymmetryProc(NULL,HOP);
  } else {
    fl_hide_object(Frieze);
    fl_show_object(Wallpaper);
    if (!val) SymmetryProc(NULL,P1);
  }
  
}  


void SymmetryProc(FL_OBJECT *obj, long val)
{
  sym_index = val;
  sym_storage = (SYMTAB[sym_index]);
  zoom = 1.0;
  Lines = ThrowAwayLines(Lines);
  set_symbutton(val);
  DefineSymWindow(&sym_rect,sym,&win_rect,zoom);
  count = SetUpSymmetry(sym,&sym_pts,xforms,&sym_rect,&win_rect);
  scheduleRedraw();
  /* we don't set mode to DRAW since we don't want to rubberband */
  /* yet, but we will be in draw mode as soon as mouse is used.  */
  set_linebutton(KALIDRAW);
  /* set_linebutton(KALIDRAW); */
  set_angrat();
  mode = 0;
}

void DrawProc(FL_OBJECT *obj, long val)
{
  scheduleRedraw();
  mode = 0;
  set_linebutton(val);
}

void PickProc(FL_OBJECT *obj, long val)
{
  if ((mode == KALIDRAW) && (Lines != NULL))
    {
      Lines = DropLine(Lines);
      scheduleRedraw();
    }
  mode=KALIPICK;
  pick_for = val;   /* KALIMOVE or KALICUT */
  set_linebutton(val);
}

void LineProc(FL_OBJECT *obj, long val)
{
  mode = KALITRANSFORM;
  switch (val) {
  case KALIZOOM: 
    xformfnc = ChangeScale;
    break;
  case KALIROTATE: 
    xformfnc = ChangeRotation;
    break;
  }
  set_linebutton(val);
}

void AngleProc(FL_OBJECT *obj, long val)
{
  mode = KALITRANSFORM;
  xformfnc = ChangeAngle;
  set_linebutton(val);
}

void RatioProc(FL_OBJECT *obj, long val)
{
  mode = KALITRANSFORM;
  xformfnc = ChangeRatio;
  set_linebutton(val);
}

void StartSaveProc(FL_OBJECT *obj, long val)
{
  const char* filename;
  FILE *pat;

  filename = fl_show_file_selector("Save into a Kali File",
				   ".","","");
  if (filename == NULL) return;
  pat = fopen(filename, "w");
  if (pat == NULL) {
    fl_show_message("Can't write to file!", "", "");
    return;
  }
  SaveProc(pat);
  winset(win);
}

void SavePSProc(FL_OBJECT *obj, long val)
{
  const char *filename;
  char *ispipe;
  FILE *psf;

  filename = fl_show_file_selector("Save into Postscript File",
				".","","");
  if (filename == NULL) return;

  if((ispipe = strchr(filename, '|')) != NULL) {
    filename = ispipe + 1;
    psf = popen(filename, "w");
  } else {
    psf = fopen(filename, "w");
  }
  
  if(psf == NULL) {
    fl_show_message("Can't write to Postscript file!",
			"", "");
    return;
  }
  PrintOut(psf, sym, sym_rect, Lines);
  if(ispipe != NULL) pclose(psf);
  else fclose(psf);
  winset(win);
}

void StartLoadProc(FL_OBJECT *obj, long val)
{
  const char* filename;
  FILE *pat;

  fl_set_button(DrawButton, 1);
  set_linebutton(KALIDRAW);
  set_linebutton(KALIDRAW);
  mode = 0;

  filename = fl_show_file_selector("Load In a Kali File",
				   ".", "","");
  if (filename == NULL) return;

  pat = fopen(filename, "r");
  if (pat == NULL) {
    fl_show_message("Bogus file name!", "", "");
    return;
  }
  load_a_file(pat);
}


void GridProc(FL_OBJECT *obj, long val) {
  GridDisplay = !GridDisplay;
  scheduleRedraw();
}


void PrintProc(FL_OBJECT *obj, long val)
{
  char quest[80];
  char *printer = getenv("PRINTER");
  sprintf(quest, "Do you really want to print this on the \"%s\" printer?",
	  printer);
  if (fl_show_question(quest,"","")) {
    FILE *p;
    p = popen(" lpr ","w");
    PrintOut(p, sym, sym_rect, Lines);
    pclose(p);
  }
  winset(win);
}


void QuitProc(FL_OBJECT *obj, long val)
{
  fl_hide_form(KaliForm);
  exit(0);
}


void InfoProc(FL_OBJECT *obj, long val)
{
  static int winid = 0;
  winid = fl_show_form(InfoForm, FL_PLACE_SIZE, TRUE, "Kali Help");
#if FL_INCLUDE_VERSION > 75
  fl_raise_form(InfoForm);
#endif
}
  
void CloseThisPanel(FL_OBJECT *obj, long val)
{
  fl_hide_form(obj->form);
  winset(win);
}

FL_OBJECT *linelist(int button)
{
  switch (button) {
  case KALIDRAW: return DrawButton; break;
/*case KALICUT: return DeleteButton; break; */
/*case KALIDELETE: return DeleteButton; break; */
  case KALIMOVE: return MoveButton; break;
  case KALIZOOM: return ZoomButton; break;
  case KALIROTATE: return RotateButton; break;
  case KALIANGLE: return AngleButton; break;
  case KALIRATIO: return RatioButton; break;
  default: return NULL;
  }
}

FL_OBJECT *symlist(int button)
{
  switch (button) {
  case P1: return P1Bitmap; break;
  case P2: return P2Bitmap; break;  
  case P3: return P3Bitmap; break;  
  case PG: return PGBitmap; break;  
  case PGG: return PGGBitmap; break;  
  case PMG: return PMGBitmap; break;  
  case PM: return PMBitmap; break;  
  case CM: return CMBitmap; break;  
  case PMM: return PMMBitmap; break;  
  case CMM: return CMMBitmap; break;  
  case P31M: return P31MBitmap; break;  
  case P3M1: return P3M1Bitmap; break;  
  case P4: return P4Bitmap; break;  
  case P4G: return P4GBitmap; break;  
  case P4M: return P4MBitmap; break;  
  case P6: return P6Bitmap; break;  
  case P6M: return P6MBitmap; break;  

  case HOP: return HopBitmap; break;
  case JUMP: return JumpBitmap; break;
  case STEP: return StepBitmap; break;
  case SPINJUMP: return SpinJumpBitmap; break;
  case SPINSIDLE: return SpinSidleBitmap; break;
  case SPINHOP: return SpinHopBitmap; break;
  case SIDLE: return SidleBitmap; break;
  }
}


void set_linebutton(int new)
{
  static int old = KALIDRAW;
  fl_set_button(linelist(old), 0);
  fl_set_button(linelist(new), 1);
  old = new;
}


void set_symbutton(int new)
{
  static int old = P3;
  fl_set_object_color(symlist(old), BLUEINDEX, WHITEINDEX);
  fl_set_object_color(symlist(new), WHITEINDEX, BLUEINDEX);
  old = new;
}


void flx_enable(FL_OBJECT *obj) {
  
  obj->active = 1;
  fl_set_object_lcol(obj, BLACKINDEX);

}

void flx_disable(FL_OBJECT *obj) {

  obj->active = 0;
  fl_set_object_lcol(obj, WHITEINDEX);

}

void set_angrat()
{
  if (sym->dof & ANG && !moron)
    flx_enable(AngleButton);
  else 
    flx_disable(AngleButton);
  if (sym->dof & RAT && !moron)
    flx_enable(RatioButton);
  else 
    flx_disable(RatioButton);
}

void set_mode(int newmode)
{
  FL_OBJECT *btn = linelist(newmode);
  switch(newmode) {
  case KALIANGLE: if(moron || !(sym->dof & ANG)) return;
  case KALIRATIO: if(moron || !(sym->dof & RAT)) return;
  }

  if(btn) {
    if(! fl_get_button(btn)) {
	fl_set_button(btn, 1);		/* Set the button, and ... */
	if(btn->object_callback)	/* Pretend it was pressed. */
	   (*btn->object_callback)(btn, btn->argument);
    }
  }
}
