/*******************************************************************************
+
+  LEDA 3.5
+
+  setup.c
+
+  This file is part of the LEDA research version (LEDA-R) that can be 
+  used free of charge in academic research and teaching. Any commercial
+  use of this software requires a license which is distributed by the
+  LEDA Software GmbH, Postfach 151101, 66041 Saarbruecken, FRG
+  (fax +49 681 31104).
+
+  Copyright (c) 1991-1997  by  Max-Planck-Institut fuer Informatik
+  Im Stadtwald, 66123 Saarbruecken, Germany     
+  All rights reserved.
+ 
*******************************************************************************/
#include <math.h>
#include <LEDA/graphwin.h>
#include "../../src/graphwin/bitmaps.h"
#include "../../src/graphwin/local.h"

#define lstyle_width	solid_width
#define lstyle_height	solid_height

static char* lstyle_bits[]= { solid_bits, dashed_bits, dotted_bits };

#define lpos_width	c_width
#define lpos_height	c_height

static char* lpos_bits[]= { c_bits, lo_bits, o_bits, ro_bits, r_bits, 
                            ru_bits, u_bits, lu_bits, l_bits};

#define nshape_width	rectangle_width
#define nshape_height	rectangle_height

static char* nshape_bits[]= { circle_bits, ellipse_bits, square_bits, rectangle_bits };

#define elab_width  clab_width
#define elab_height clab_height

static char* elab_bits[]= { clab_bits, llab_bits, rlab_bits };

//----------------------------------------------------------------------------


enum gw_epos { cpos, lpos, rpos };

struct panel_node_info {  // node_info with members usable for panel-items
  color  clr;
  int    shape;
  color  border_clr;
//double x;
//double y;
  int    x;
  int    y;
  int    width;
  int    height;
  string label;
  string data_label;
  color  label_clr;
  int    label_pos;
  int    label_t;
  bool   selected;
};


struct panel_edge_info {  // edge_info with members usable for panel-items
  color  clr;
  int    style;
  int    width;
  string label;
  string data_label;
  color  label_clr;
  int    label_pos;
  int    label_t;
  list<point> p;
  bool   selected;
};

//----------------------------------------------------------------------------

static panel*           current_panel;
static panel_item       current_wpit;
static panel_item       current_hpit;
static panel_node_info* current_pinf;
static panel_edge_info* current_einf;
static node_array<node_info>* current_nsave_i;
static edge_array<edge_info>* current_esave_i;


static void e_color_handler(int c)
{ GraphWin* gw = (GraphWin*)window::get_call_window()->get_inf();
  const list<edge>& L = gw->get_e_animation_list();
  edge e;
  forall(e,L) gw->set_color(e,color(c)); 
  gw->e_animation_step();
}

static void e_lcolor_handler(int c)
{ GraphWin* gw = (GraphWin*)window::get_call_window()->get_inf();
  const list<edge>& L = gw->get_e_animation_list();
  edge e;
  forall(e,L) gw->set_label_color(e,color(c)); 
  gw->e_animation_step();
}

static void e_width_handler(int w)
{ GraphWin* gw = (GraphWin*)window::get_call_window()->get_inf();
  const list<edge>& L = gw->get_e_animation_list();
  edge e;
  forall(e,L) gw->set_width(e,w); 
  gw->e_animation_step();
}


static void e_style_handler(int s)
{ GraphWin* gw = (GraphWin*)window::get_call_window()->get_inf();
  const list<edge>& L = gw->get_e_animation_list();
  edge e;
  forall(e,L) gw->set_style(e,(gw_edge_style)s); 
  gw->e_animation_step();
}



static void e_ltype_handler(int t)
{ GraphWin* gw = (GraphWin*)window::get_call_window()->get_inf();
  const list<edge>& L = gw->get_e_animation_list();
  edge e;
  forall(e,L) gw->set_label_type(e,(gw_label_type)t); 
  gw->e_animation_step();
}


static void e_lpos_handler(int p)
{ GraphWin* gw = (GraphWin*)window::get_call_window()->get_inf();
  const list<edge>& L = gw->get_e_animation_list();
  edge e;
  forall(e,L)
  { gw_position pos = central_pos;
    switch (p) {
      case lpos: pos = west_pos;    break;
      case rpos: pos = east_pos;    break;
     }
    gw->set_label_pos(e,pos); 
  }
  gw->e_animation_step();
}

static void e_label_handler(char* s) 
{ GraphWin* gw = (GraphWin*)window::get_call_window()->get_inf();
  const list<edge>& L = gw->get_e_animation_list();
  edge e;
  forall(e,L) gw->set_user_label(e,s); 
  gw->e_animation_step();
}



static void make_panel(GraphWin& gw, panel& P, panel_edge_info& p, long mask) {

  graph& G = gw.get_graph();

  // create panel_items 

  if (mask & E_COLOR) 
     P.color_item("color",p.clr,e_color_handler);

  if (mask & E_STYLE) 
     P.choice_item("style",p.style,3,lstyle_width,lstyle_height,lstyle_bits,
                                                             e_style_handler);

  if (mask & E_WIDTH) 
    P.int_item("width",p.width,1,5,1,e_width_handler);

  P.text_item("");
  P.text_item("\\blue label");

  if (mask & E_LTYPE) 
  { list<string> L;
    L.append("none");
    L.append("user");
    L.append("data");
    L.append("index");
    P.choice_item("type",p.label_t,L,e_ltype_handler);
   }

  if (mask & E_LABEL) 
    P.string_item("user",p.label,e_label_handler);

  string et = G.edge_type(); 
  if (et != "void")
    P.string_item(string("data (%s)",~et),p.data_label);

  if (mask & E_LCOLOR) 
     P.color_item("color",p.label_clr,e_lcolor_handler);

  if (mask & E_LPOS) 
     P.choice_item("position",p.label_pos,3,elab_width,elab_height,
                                                       elab_bits,
                                                       e_lpos_handler);
  P.text_item("");

} 



static void n_color_handler(int c)
{ GraphWin* gw = (GraphWin*)window::get_call_window()->get_inf();
  const list<node>& L = gw->get_n_animation_list();
  node v;
  forall(v,L) gw->set_color(v,color(c)); 
  gw->n_animation_step();
}

static void n_lcolor_handler(int c)
{ GraphWin* gw = (GraphWin*)window::get_call_window()->get_inf();
  const list<node>& L = gw->get_n_animation_list();
  node v;
  forall(v,L)
  { if (c == (int)gw->get_color(v)) c = -1;   // auto
    gw->set_label_color(v,color(c)); 
   }
  gw->n_animation_step();
}


static void n_xpos_handler(int x)
{ GraphWin* gw = (GraphWin*)window::get_call_window()->get_inf();
  const list<node>& L = gw->get_n_animation_list();
  node v;
  forall(v,L)
  { point p = gw->get_position(v);
    gw->set_position(v,point(x,p.ycoord())); 
   }
  gw->n_animation_step();
}


static void n_ypos_handler(int y)
{ GraphWin* gw = (GraphWin*)window::get_call_window()->get_inf();
  const list<node>& L = gw->get_n_animation_list();
  node v;
  forall(v,L)
  { point p = gw->get_position(v);
    gw->set_position(v,point(p.xcoord(),y)); 
   }
  gw->n_animation_step();
}




static void n_width_handler(int w)
{ 
  GraphWin* gw = (GraphWin*)window::get_call_window()->get_inf();

  if (current_pinf->shape == square_node || current_pinf->shape == circle_node)
  { current_pinf->height = w;
    if (current_hpit) current_panel->redraw_panel(current_hpit);
   }  

  const list<node>& L = gw->get_n_animation_list();

  node v;
  forall(v,L) 
  { gw->set_width(v,w); 
    if (gw->get_shape(v) == square_node || gw->get_shape(v) == circle_node)
      gw->set_height(v,w);
   }
  gw->n_animation_step();
}

static void n_height_handler(int h)
{ GraphWin* gw = (GraphWin*)window::get_call_window()->get_inf();

  if (current_pinf->shape == square_node || current_pinf->shape == circle_node)
  { current_pinf->width = h;
    if (current_wpit) current_panel->redraw_panel(current_wpit);
   }  

  const list<node>& L = gw->get_n_animation_list();

  node v;
  forall(v,L) 
  { gw->set_height(v,h); 
    if (gw->get_shape(v) == square_node || gw->get_shape(v) == circle_node)
      gw->set_width(v,h);
   }
  gw->n_animation_step();
}



static void n_shape_handler(int s)
{ GraphWin* gw = (GraphWin*)window::get_call_window()->get_inf();
  int w = current_pinf->width;
  if (s == square_node || s == circle_node)
  { current_pinf->height = w;
    if (current_hpit) current_panel->redraw_panel(current_hpit);
   }
  const list<node>& L = gw->get_n_animation_list();
  node v;
  forall(v,L)
  { gw->set_shape(v,(gw_node_shape)s); 
    if (s == square_node || s == circle_node) 
      gw->set_height(v,gw->get_width(v));
   }
  gw->n_animation_step();
}


static void n_border_color_handler(int c)
{ GraphWin* gw = (GraphWin*)window::get_call_window()->get_inf();
  const list<node>& L = gw->get_n_animation_list();
  node v;
  forall(v,L) gw->set_border_color(v,color(c)); 
  gw->n_animation_step();
}


static void n_ltype_handler(int t)
{ GraphWin* gw = (GraphWin*)window::get_call_window()->get_inf();
  const list<node>& L = gw->get_n_animation_list();
  node v;
  forall(v,L)
  { gw_label_type lt = (gw_label_type)t; 
    gw->set_label_type(v,lt); 
    string s = gw->get_label(v);
    if (lt != no_label && gw->get_label_pos(v) == central_pos && s.length() > 0)
    { string s = gw->get_label(v);
      window& W = gw->get_window();
      double tw = W.text_width(s)/2 + W.text_width("  ");
      if (lt == index_label) tw = gw->width2radius(DefNodeWidth);
      gw->set_radius1(v,tw);
      current_pinf->width = gw->get_width(v);
      if (current_wpit) current_panel->redraw_panel(current_wpit);
     }
   }
  gw->n_animation_step();
}


static void n_lpos_handler(int p)
{ GraphWin* gw = (GraphWin*)window::get_call_window()->get_inf();
  const list<node>& L = gw->get_n_animation_list();
  node v;
  forall(v,L) gw->set_label_pos(v,(gw_position)p); 
  gw->n_animation_step();
}


static void n_label_handler(char* s) 
{ GraphWin* gw = (GraphWin*)window::get_call_window()->get_inf();
  const list<node>& L = gw->get_n_animation_list();
  node v;
  forall(v,L) gw->set_user_label(v,s); 
  if (current_pinf->label_t == user_label)
  { window& W = gw->get_window();
    double tw = W.text_width(s)+ W.text_width("   ");
    node v;
    forall(v,L)
    { if (gw->get_label_pos(v) == central_pos)
      { gw->set_radius1(v,tw/2);
        current_pinf->width = gw->get_width(v);
        if (current_wpit) current_panel->redraw_panel(current_wpit);
        if (gw->get_shape(v) == square_node ||
            gw->get_shape(v) == circle_node)
        { gw->set_radius2(v,tw/2);
          current_pinf->height = gw->get_height(v);
          if (current_hpit) current_panel->redraw_panel(current_hpit);
         }
       }
    }
   gw->n_animation_step();
  }
}


static void make_panel(GraphWin& gw, panel& P, panel_node_info& p, long mask) {

  graph& G = gw.get_graph();

  current_panel = &P;

  // create panel_items 

  if (mask & N_COLOR) 
      P.color_item("color",p.clr,n_color_handler);

  if (mask & N_BCOLOR) 
      P.color_item("border",p.border_clr,n_border_color_handler);

  if (mask & N_SHAPE) 
      P.choice_item("shape",p.shape,4,nshape_width,nshape_height,nshape_bits,
                                                             n_shape_handler);
  if (mask & N_XPOS) 
      P.int_item("xcoord",p.x,(int)gw.get_xmin(),(int)gw.get_xmax(),
                                                  n_xpos_handler);

  if (mask & N_YPOS) 
      P.int_item("ycoord",p.y,(int)gw.get_ymin(),(int)gw.get_ymax(),
                                                  n_ypos_handler);

  int W = gw.get_window().width()/2;

  if (mask & N_WIDTH) 
    current_wpit = P.int_item("width",p.width,0,W, n_width_handler);
  else 
    current_wpit = 0;

  if (mask & N_HEIGHT) 
    current_hpit = P.int_item("height",p.height,(p.height == 0 ? 0 : 1), W,
                                                 n_height_handler);
  else 
    current_hpit = 0;


  P.text_item("");
  P.text_item("\\blue label");

  if (mask & N_LTYPE) 
  { list<string> L;
    L.append("none");
    L.append("user");
    L.append("data");
    L.append("index");
    P.choice_item("type",p.label_t,L,n_ltype_handler);
   }

  if (mask & N_LABEL) 
    P.string_item("user",p.label,n_label_handler);

  string nt = G.node_type(); 
  if (nt != "void")
    P.string_item(string("data (%s)",~nt),p.data_label);

  if (mask & N_LCOLOR) 
  { string s = "color";
    P.color_item(s,p.label_clr,n_lcolor_handler);
   }

  if (mask & N_LPOS) 
     P.choice_item("position",p.label_pos,9,lpos_width,lpos_height,
                                                       lpos_bits,
                                                       n_lpos_handler);

  P.text_item("");

} 

//----------------------------------------------------------------------------

static long find_diff(GraphWin& gw, const list<edge>& L) {

  // returns or'd members of the edge_info-struct that are invalid  

  if (L.empty()) return E_COMPLETE;

  long mask=0;

  const edge_info& ei=gw.get_info(L.head());

  edge e;

  forall(e,L) {
    const edge_info& ni=gw.get_info(e);
    if (ei.clr       != ni.clr)		 mask |= E_COLOR;
    if (ei.style     != ni.style)	 mask |= E_STYLE;
    if (ei.width     != ni.width)      	 mask |= E_WIDTH;
    if (ei.label     != ni.label)	 mask |= E_LABEL;
    if (ei.label_t   != ni.label_t)	 mask |= E_LTYPE;
    if (ei.label_clr != ni.label_clr)	 mask |= E_LCOLOR;
    if (ei.label_pos != ni.label_pos)	 mask |= E_LPOS;
    if (mask == E_COMPLETE) break;	// all invalid
  }

  return mask;
}

static long find_diff(GraphWin& gw, const list<node>& L) {

  // returns or'd members of the node_info-struct that are invalid  

  if (L.empty()) return N_COMPLETE;

  long mask=0;

  const node_info& ni=gw.get_info(L.head());

  double x=ni.pos.xcoord();
  double y=ni.pos.ycoord();

  node v;

  forall(v,L) {
    const node_info& ni=gw.get_info(v);
    if (ni.clr       != ni.clr)		 mask |= N_COLOR;
    if (ni.shape     != ni.shape)	 mask |= N_SHAPE;
    if (ni.border_clr!= ni.border_clr)	 mask |= N_BCOLOR;
    if (x            != ni.pos.xcoord()) mask |= N_XPOS;
    if (y            != ni.pos.ycoord()) mask |= N_YPOS;
    if (ni.r1        != ni.r1) 		 mask |= N_WIDTH;
    if (ni.r2        != ni.r2) 		 mask |= N_HEIGHT;
    if (ni.label     != ni.label)	 mask |= N_LABEL;
    if (ni.label_t   != ni.label_t)	 mask |= N_LTYPE;
    if (ni.label_clr != ni.label_clr)	 mask |= N_LCOLOR;
    if (ni.label_pos != ni.label_pos)	 mask |= N_LPOS;
    if (mask == N_COMPLETE) break;	// all invalid
  }

  return mask;
}

//----------------------------------------------------------------------------

static long make_panel_info(GraphWin& gw,const list<edge>& L,panel_edge_info& e)
{
  edge_info ei;
  long mask = 0;

  if (L.empty())
     ei = gw.get_edge_info();
  else
   { mask = find_diff(gw,L);
     ei   = gw.get_info(L.head());
    }

  e.clr       = ( mask & E_COLOR  ? color(-1) : ei.clr );
  e.style     = ( mask & E_STYLE  ? -1 : ei.style );
  e.width     = ( mask & E_WIDTH  ?  0 : ei.width );
  e.label_t   = ( mask & E_LTYPE  ? -1 : ei.label_t);
  e.label_clr = ( mask & E_LCOLOR ? color(-1) : ei.label_clr);

  //  e.label_pos = ( mask & E_LPOS   ? -1 : ei.label_pos );

  if (mask & E_LPOS) e.label_pos = -1;
  else {
    switch(ei.label_pos) {
      case west_pos: e.label_pos = lpos; break;
      case east_pos: e.label_pos = rpos; break;
      default      : e.label_pos = cpos; break;
    }
  }

  if (mask & E_LABEL) 
     e.label = ""; 
  else 
     e.label = ei.label;

  e.data_label = "";
  if (!L.empty()) e.data_label = gw.get_data(L.head());

  e.selected  = false;

  return mask;
}



static long make_panel_info(GraphWin& gw, const list<node>& L, 
                                          panel_node_info& n) 
{
  node_info ni;
  long mask;

   if (L.empty())
     { mask = N_POS;
       ni = gw.get_node_info();
      }
   else
     { mask = find_diff(gw,L);
       ni   = gw.get_info(L.head());
     }

  n.x         = ( mask & N_XPOS   ) ? -MAXINT : (int)ni.pos.xcoord();
  n.y         = ( mask & N_YPOS   ) ? -MAXINT : (int)ni.pos.ycoord();
  n.clr       = ( mask & N_COLOR  ) ? color(-1) : ni.clr;
  n.shape     = ( mask & N_SHAPE  ) ? -1 : ni.shape;
  n.border_clr= ( mask & N_BCOLOR ) ? color(-1) : ni.border_clr;
  n.width     = ( mask & N_WIDTH  ) ? -1 : gw.radius2width(ni.r1);
  n.height    = ( mask & N_HEIGHT ) ? -1 : gw.radius2height(ni.r2);
  n.label_clr = ( mask & N_LCOLOR ) ? color(-1) : ni.label_clr;
  n.label_t   = ( mask & N_LTYPE  ) ? -1 : ni.label_t;
  n.label_pos = ( mask & N_LPOS   ) ? -1 : ni.label_pos;

  if (mask & N_LABEL) 
      n.label = ""; 
  else 
      n.label = ni.label;

  n.data_label = "";
  if (!L.empty()) n.data_label = gw.get_data(L.head());

  n.selected  = false;

  return mask;
}

//----------------------------------------------------------------------------

static long make_info(GraphWin&, const panel_edge_info& p,
		      edge_info& i, long mask) {

  // creates edge_info from panel_edge_info

  if (mask & E_COLOR) {
    if (p.clr != -1) i.clr = p.clr;
    else mask &= ~E_COLOR; 
  }
  if (mask & E_STYLE) {
    if (p.style != -1) i.style = (gw_edge_style) p.style;
    else mask &= ~E_STYLE;
  }
  if (mask & E_WIDTH) { 
    if (p.width != 0) i.width = p.width;
    else mask &= ~E_WIDTH;
  }

  if (mask & E_LTYPE) i.label_t = (gw_label_type)p.label_t;

  if (mask & E_LABEL) {
     if (p.label != "") i.label = p.label;
     else mask &= ~N_LABEL;
  }

  if (mask & E_LCOLOR)i.label_clr = p.label_clr;

  if (mask & E_LPOS) {
    if (p.label_pos != -1) {

      switch (p.label_pos) {

	case lpos: i.label_pos = west_pos;    break;
	case rpos: i.label_pos = east_pos;    break;
	default  : i.label_pos = central_pos; break;

      }

      //      i.label_pos = (gw_position) p.label_pos; 
    }
    else mask &= ~E_LPOS;
  }

  return mask;
}

static long make_info(GraphWin& gw, const panel_node_info& p,
		      node_info& i, long mask) {

  // creates node_info from panel_node_info

  if (mask & N_COLOR) {
    if (p.clr != -1) i.clr = p.clr;
    else mask &= ~N_COLOR; 
  }
  if (mask & N_SHAPE) {
    if (p.shape != -1) i.shape = (gw_node_shape) p.shape;
    else mask &= ~N_SHAPE;
  }
  if (mask & N_BCOLOR) {
    if (p.border_clr != -1) i.border_clr = p.border_clr;
    else mask &= ~N_BCOLOR;
  }

  if (mask & N_POS) {
    if (p.x == -MAXINT) mask &= ~N_XPOS;
    if (p.y == -MAXINT) mask &= ~N_YPOS;
    i.pos = point(p.x,p.y);
  }

  if (mask & N_WIDTH) { 
    if (p.width != -1) i.r1 = gw.width2radius(p.width);
    else mask &= ~N_WIDTH;
  }
  if (mask & N_HEIGHT) {
    if (p.height != -1) i.r2 = gw.height2radius(p.height); 
    else mask &= ~N_HEIGHT;
  }

  if (mask & N_LTYPE) i.label_t = (gw_label_type)p.label_t;

  if (mask & N_LABEL) {
     if (p.label != "") i.label = p.label;
     else mask &= ~N_LABEL;
  }

  if (mask & N_LCOLOR) 
  { i.label_clr = p.label_clr;
    if (p.label_clr == p.clr) i.label_clr = color(-1);  // auto
   }

  if (mask & N_LPOS) {
    if (p.label_pos != -1) i.label_pos = (gw_position) p.label_pos; 
    else mask &= ~N_LPOS;
  }


  return mask;
}

//----------------------------------------------------------------------------


#define APPLY_NONE   0
#define APPLY_NEW    1
#define APPLY_SELECT 2
#define APPLY_ALL    4

#define P_DEFAULT 101
#define P_DONE    102
#define P_RESET   103


static void e_apply_to_all_handler(int b)
{ GraphWin* gw = (GraphWin*)window::get_call_window()->get_inf();
  graph& G = gw->get_graph();
  bool f = gw->set_flush(false);
  edge e;
  if (b)
    { edge_info i;
      long mask = make_info(*gw,*current_einf,i,E_COMPLETE & ~E_SELECT & ~E_POLYGON);
      forall_edges(e,G) gw->set_info(e,i,mask);
      gw->e_animation_end();
      gw->e_animation_start(G.all_edges());
     }
  else
    { forall_edges(e,G) gw->set_info(e,(*current_esave_i)[e],E_COMPLETE & ~E_POLYGON);
      gw->e_animation_end();
      list<edge> empty;
      gw->e_animation_start(empty);
     }
  gw->set_flush(f);
}



bool gw_setup(GraphWin& gw, const list<edge>& L0, long mask)
{
  window& W = gw.get_window();
  graph&  G = gw.get_graph();

  mask &= ~E_POLYGON;
  mask &= ~E_SELECT;

  panel_edge_info p;
  current_einf = &p;

  string s;
  list<edge> L = L0;
  bool apply_to_all = false;
  bool default_setup = false;

  long m = make_panel_info(gw,L,p);

  panel P("GaphWin Edge Setup");
  P.set_inf(&gw);

  if (L.size() == 0) 
   { default_setup = true;
     s = "Default Parameters for Edges";
     //apply_to_all = true;
     //L = G.all_edges();
   }
  else 
  { if (L.size() == 1) 
       s = "Edge ";
    else 
       s = "Edges "; 
    int count = 4;
    edge e;
    forall(e,L)
    { if (count-- == 0) { s += "  ... "; break; }
      node v = source(e);
      node w = target(e);
      s += string(" [%d-->%d] ",index(v),index(w)); 
    }
  }  

  if (L.size() != 1) mask &= ~E_POLYGON;
   
  P.text_item(string("\\blue ") + s);

  edge_array<edge_info> save_i(G);
  current_esave_i = &save_i;

  edge e;
  forall_edges(e,G) save_i[e] = gw.get_info(e);

  gw.e_animation_start(L);

  make_panel(gw,P,p,mask & ~(m & E_POLYGON)); 


  if (default_setup) 
    P.bool_item("apply",apply_to_all,e_apply_to_all_handler);
  else
    P.bool_item("selected",p.selected);

  P.text_item("");
  P.button("reset",    P_RESET);
  P.button("defaults", P_DEFAULT);
  P.button("done",     P_DONE);

  //gw.disable_calls();
  W.disable_panel();

  // display and read panel

  P.buttons_per_line(4);

  { int x_mid = W.xpos() + W.width()/2; 
    int y = W.ypos() - 23;
    if (y < 0) y = 0;
    if (x_mid > window::screen_width()/2)
       P.display(-(W.xpos()-8),y);
    else
       P.display(W.xpos()+W.width()+6,y);
   }


  int but;
  while ( (but=P.read_mouse()) != P_DONE )
  {
    switch (but)  {

    case P_DEFAULT: {

      edge_info i;

      if (default_setup)
      { p.label_t=DefEdgeLabelType;
        p.clr=DefEdgeColor;
        p.style=DefEdgeStyle;
        p.width=DefEdgeWidth;
        p.label=DefEdgeLabel;
        p.label_clr=DefEdgeLabelClr;
        switch(DefEdgeLabelPos) {
        case west_pos: p.label_pos = lpos; break;
        case east_pos: p.label_pos = rpos; break;
        default      : p.label_pos = cpos; break;
        }
      }
      else
      { list<edge> empty;
        make_panel_info(gw,empty,p);
       }

      make_info(gw,p,i,E_COMPLETE);

      const list<edge>& L = gw.get_e_animation_list();
      edge e;
      forall(e,L) gw.set_info(e,i,E_COMPLETE & ~E_SELECT & ~E_POLYGON);
      gw.e_animation_step();
      P.redraw_panel();
      break;
    }

    case P_RESET: { 
      const list<edge>& L = gw.get_e_animation_list();
      edge e;
      forall(e,L) gw.set_info(e,save_i[e],E_COMPLETE & ~E_POLYGON);
      gw.e_animation_step();
      make_panel_info(gw,L,p);
      P.redraw_panel();
      break;
     }

   }

  }

  gw.e_animation_end();
  
  P.close();

  //gw.enable_calls();
  W.enable_panel();

  if (default_setup)
  { edge_info i;
    mask=make_info(gw,p,i,mask & ~E_POLYGON); 
    gw.set_edge_info(i,mask);
   }

  return p.selected;
}



static void n_apply_to_all_handler(int b)
{ GraphWin* gw = (GraphWin*)window::get_call_window()->get_inf();
  graph& G = gw->get_graph();
  bool f = gw->set_flush(false);
  node v;
  if (b)
    { node_info i;
      long mask = make_info(*gw,*current_pinf,i,N_COMPLETE & ~N_SELECT);
      forall_nodes(v,G) gw->set_info(v,i,mask);
      gw->n_animation_end();
      gw->n_animation_start(G.all_nodes());
     }
  else
    { forall_nodes(v,G) gw->set_info(v,(*current_nsave_i)[v],N_COMPLETE);
      gw->n_animation_end();
      list<node> empty;
      gw->n_animation_start(empty);
     }
  gw->set_flush(f);
}


bool gw_setup(GraphWin& gw, const list<node>& L0, long mask)
{
  window& W = gw.get_window();
  graph&  G = gw.get_graph();

  mask &= ~N_SELECT;

  panel_node_info p;
  current_pinf = &p;

  string s;
  list<node> L = L0;
  bool apply_to_all = false;
  bool default_setup = false;

  long m = make_panel_info(gw,L,p);

  panel P("GaphWin Node Setup");
  P.set_inf(&gw);


  if (L.size() == 0) 
   { default_setup = true;
     s = "Default Parameters for Nodes";
     mask &= ~N_POS;
     //apply_to_all = true;
     //L = G.all_edges();
   }
  else 
  { if (L.size() == 1) 
       s = "Node ";
    else 
       s = "Nodes "; 
    int count = 10;
    node v;
    forall(v,L)
    { if (count-- == 0) { s += "  ... "; break; }
      s += string(" [%d] ",index(v)); 
    }
  }  


  P.text_item(string("\\blue ") + s);


  gw.n_animation_start(L);

  node_array<node_info> save_i(G);
  current_nsave_i = &save_i;

  node v;
  forall_nodes(v,G) save_i[v] = gw.get_info(v);


  make_panel(gw,P,p,mask);

  if (default_setup)
    P.bool_item("apply",apply_to_all,n_apply_to_all_handler);
  else
    P.bool_item("selected",p.selected);


  P.text_item("");
  P.button("reset",    P_RESET);
  P.button("defaults", P_DEFAULT);
  P.button("done",     P_DONE);

  //gw.disable_calls();
  W.disable_panel();

  // display and read panel

  P.buttons_per_line(4);

  { int x_mid = W.xpos() + W.width()/2; 
    int y = W.ypos() - 23;
    if (y < 0) y = 0;
    if (x_mid > window::screen_width()/2)
       P.display(-(W.xpos()-8),y);
    else
       P.display(W.xpos()+W.width()+6,y);
   }

  int but;
  while ( (but=P.read_mouse()) != P_DONE )
  { 
    if (but == P_DEFAULT)
    { node_info i;
      if (default_setup)
        { p.label_t=DefNodeLabelType;
          p.clr=DefNodeColor;
          p.shape=DefNodeShape;
          p.border_clr=DefNodeBorderColor;
          p.width=DefNodeWidth;
          p.height=DefNodeHeight;
          p.label=DefNodeLabel;
          p.label_clr=DefNodeLabelClr;
          p.label_pos=DefNodeLabelPos;
       }
       else
       { list<node> empty;
         make_panel_info(gw,empty,p);
        }
      make_info(gw,p,i,N_COMPLETE);
      const list<node>& L = gw.get_n_animation_list();
      node v;
      forall(v,L) gw.set_info(v,i,N_COMPLETE & ~N_POS & ~N_SELECT);
      gw.n_animation_step();
      P.redraw_panel();
    }

    if (but == P_RESET) 
    { const list<node>& L = gw.get_n_animation_list();
      node v;
      forall(v,L) gw.set_info(v,save_i[v],N_COMPLETE);
      gw.n_animation_step();
      make_panel_info(gw,L,p);
      P.redraw_panel();
     }
  }


  gw.n_animation_end();

  P.close();

  //gw.enable_calls();
  W.enable_panel();

  if (default_setup)
  { node_info i;
    mask = make_info(gw,p,i,mask & ~N_POS);
    gw.set_node_info(i,mask);
  }
  
  return p.selected;
}

//----------------------------------------------------------------------------

static void status_handler(int b)
{ GraphWin* gw = (GraphWin*)window::get_call_window()->get_inf();
  gw->set_show_status(b);
}

static void grid_handler(int d)
{ GraphWin* gw = (GraphWin*)window::get_call_window()->get_inf();
  window& W = gw->get_window();
  W.set_grid_mode(d);
  gw->redraw();
}



void gw_global_setup(GraphWin& gw) 
{
  int grid_dist    = gw.get_grid_mode();
  int edge_dist    = int(100 * gw.get_edge_distance());
  int zoom_factor  = int(100 * gw.get_zoom_factor());
  bool directed    = gw.get_directed();
  bool const_width = gw.get_constant_width();
  bool ortho_mode  = gw.get_ortho_mode();
  bool flush       = gw.get_flush();
  bool status      = gw.get_show_status();

  color bg_col     = gw.get_bg_color();

  bool auto_create = gw.auto_create_target;

  int  show_mask1  = (int)gw.status_show_mask & 15;
  int  show_mask2  = (int)gw.status_show_mask >> 4 ;

  list<string> show_list1;
  show_list1.append("nodes");
  show_list1.append("edges");
  show_list1.append("loops");
  show_list1.append("planar");

  list<string> show_list2;
  show_list2.append("flush");
  show_list2.append("grid");
  show_list2.append("coord");


  bool status_save = status;
  int  grid_save   = grid_dist;

  panel P;
  P.set_inf(&gw);

  P.text_item("\\blue Grid");
  P.int_item ("grid distance",grid_dist,0,20);
  P.text_item("");

  P.text_item("\\blue Edges");
  P.bool_item("directed edges",  directed);  
  P.bool_item("orthogonal edges",ortho_mode);
  P.int_item ("edge distance",   edge_dist,1,100);
  P.text_item("");

  P.text_item("\\blue Zooming");
  P.int_item ("zoom factor",zoom_factor,100,200);
  P.bool_item("fixed size nodes", const_width);
  P.text_item("");

  P.text_item("\\blue Status Line");
  P.bool_item("show status line",status);
  P.choice_mult_item("status entries",show_mask1,show_list1);
  P.choice_mult_item("              ",show_mask2,show_list2);
  P.text_item("");

  P.text_item("\\blue Miscellaneous");
  P.bool_item("auto create target",auto_create);
  P.color_item("background color",bg_col);
  P.text_item("");


  P.button("apply",   2);
  P.button("defaults",1);
  P.button("cancel",  0);


  int but;

  while ( (but = P.open(gw.get_window())) == 1 )
  { grid_dist   = DefGridDist;
    zoom_factor = int(100*DefZoomFactor);
    edge_dist   = int(100*DefEdgeDist);
    directed    = DefDirected;
    ortho_mode  = DefOrthoMode;
    status      = DefShowStatus;
    auto_create = DefAutoCreateTarget;
    bg_col      = DefBgColor;
    show_mask1  = DefShowMask & 15;
    show_mask2  = DefShowMask >> 4 ;
   }


  if (but == 0) 
  { bool b = gw.set_flush(false);
    gw.set_grid_mode(grid_save);
    gw.set_show_status(status_save);
    gw.set_flush(b);
    gw.redraw();
    return; 
   }

  bool b = gw.set_flush(false);
  gw.set_grid_mode(grid_dist);
  gw.set_zoom_factor(zoom_factor/100.0);
  gw.set_edge_distance(edge_dist/100.0);
  gw.set_constant_width(const_width);
  gw.set_directed(directed);
  gw.set_ortho_mode(ortho_mode);
  gw.set_bg_color(bg_col);
  gw.set_flush(b);
  gw.status_show_mask = show_mask1 | (show_mask2 << 4);
  gw.set_show_status(status);
  gw.auto_create_target = auto_create;
  gw.redraw();
}

void gw_animation_setup(GraphWin& gw) {

  int anim_steps   = gw.get_animation_steps();
  int max_items    = gw.get_max_move_items();
  int node_move    = (int) gw.get_animation_mode();
  bool flush       = gw.get_flush();

  panel P;
  P.set_inf(&gw);
  P.text_item("\\blue Animation");
  P.choice_item("mode",node_move,"move single"," move all");
  P.int_item("steps",anim_steps,0,50);
  P.int_item("moving",max_items,0,200);
  P.bool_item("flush",flush);

  P.button("apply",1);
  P.button("cancel",0);

  if (P.open(gw.get_window()) == 1) 
  { gw.set_flush(false);
    gw.set_animation_steps(anim_steps);
    gw.set_animation_mode((node_move_t)node_move);
    gw.set_max_move_items(max_items);
    gw.redraw();
    gw.set_flush(flush);
  }
}

