/*******************************************************************************
+
+  LEDA 3.5
+
+  get_set.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 <LEDA/stream.h>
#include <LEDA/graphwin.h>
#include <math.h>
#include "../../src/graphwin/local.h"

color gw_auto_color = -1;

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

const node_info& GraphWin::get_info(node v) const { return n_info[v]; }

#define GW_NODE_GET(f,el,t) t GraphWin::get_##f(node v) const { return n_info[v].el; }

GW_NODE_GET(index,       id,        int)
GW_NODE_GET(position,    pos,       point)
GW_NODE_GET(color,       clr,       color)
GW_NODE_GET(shape,       shape,     gw_node_shape)
GW_NODE_GET(border_color,border_clr,color)
GW_NODE_GET(radius1,     r1,        double)
GW_NODE_GET(radius2,     r2,        double)
GW_NODE_GET(label_type,  label_t,   gw_label_type)
GW_NODE_GET(label_pos,   label_pos, gw_position)
GW_NODE_GET(label_color, label_clr, color)
GW_NODE_GET(select,      selected,  bool)

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

const edge_info& GraphWin::get_info(edge e) const { return e_info[e]; }

#define GW_EDGE_GET(f,el,t) t GraphWin::get_##f(edge e) const { return e_info[e].el; }

GW_EDGE_GET(edge_points, p, const list<point>&)
GW_EDGE_GET(color,clr,color)
GW_EDGE_GET(style,style,gw_edge_style)
GW_EDGE_GET(width,width,int)
GW_EDGE_GET(label_type,label_t,gw_label_type)
GW_EDGE_GET(label_pos,label_pos,gw_position)
GW_EDGE_GET(select,selected,bool)

list<point> GraphWin::get_bends(edge e) const { 
  list<point> L(e_info[e].p); 
  L.pop();
  L.Pop();
  return L;
}

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

const node_info& GraphWin::get_node_info() const { return n_model; }

#define GW_NMODEL_GET(f,e,t) t GraphWin::get_node_##f() const { return n_model.e; }

GW_NMODEL_GET(color,clr,color)
GW_NMODEL_GET(shape,shape,gw_node_shape)
GW_NMODEL_GET(border_color,border_clr,color)
GW_NMODEL_GET(radius1,r1,double)
GW_NMODEL_GET(radius2,r2,double)
GW_NMODEL_GET(label_type,label_t,gw_label_type)
GW_NMODEL_GET(label_color,label_clr,color)
GW_NMODEL_GET(label_pos,label_pos,gw_position)

int GraphWin::get_node_width() const 
{ return win_p->real_to_pix(get_node_radius1()*2.0); } 

int GraphWin::get_node_height() const 
{ return win_p->real_to_pix(get_node_radius2()*2.0); } 

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

const edge_info& GraphWin::get_edge_info() const { return e_model; }

#define GW_EMODEL_GET(f,el,t) t GraphWin::get_edge_##f() const { return e_model.el; }

GW_EMODEL_GET(color,clr,color)
GW_EMODEL_GET(style,style,gw_edge_style)
GW_EMODEL_GET(width,width,int)
GW_EMODEL_GET(label_type,label_t,gw_label_type)
GW_EMODEL_GET(label_pos,label_pos,gw_position)
GW_EMODEL_GET(label_color,label_clr,color)

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

int GraphWin::get_gen_nodes() const { return gen_nodes; }
int GraphWin::get_gen_edges() const { return gen_edges; }

double      GraphWin::get_edge_distance() const    { return edge_distance; }
int         GraphWin::get_grid_mode() const        { return grid; }
bool        GraphWin::get_show_status() const      { return show_status; }
unsigned    GraphWin::get_animation_steps() const  { return animation; }
node_move_t GraphWin::get_animation_mode() const   { return node_move; }
double      GraphWin::get_zoom_factor() const      { return zoom_factor; }
int         GraphWin::get_done_result() const      { return done_result; }
bool        GraphWin::get_constant_width() const   { return constant_width; }
int         GraphWin::get_max_move_items() const   { return max_move_items; }
bool        GraphWin::get_ortho_mode() const       { return ortho_mode; }

double GraphWin::get_xmin() const { return x_min; }
double GraphWin::get_ymin() const { return y_min; }
double GraphWin::get_xmax() const { return x_max; }
double GraphWin::get_ymax() const { return y_max; }

int GraphWin::set_max_move_items(int i) {
  int old_max_move_items = max_move_items;
  max_move_items=i;  
  return old_max_move_items; 
}

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

#define GW_HANDLER(h,pre,post)                                               \
  void GraphWin::set_##h##_handler(bool (*f) pre  ) {                        \
    pre_##h##_handler=f; }                                                   \
  void GraphWin::set_##h##_handler(void (*f) post ) {                        \
    post_##h##_handler=f;                                                    \
    if (!f) pre_##h##_handler=NULL;                                          }


GW_HANDLER(new_node,(GraphWin& gw, const point& p),(GraphWin& gw, node v))
GW_HANDLER(new_edge,(GraphWin& gw, node s, node t),(GraphWin& gw, edge e))
GW_HANDLER(move_node,(GraphWin& gw, node v, const point& p),(GraphWin& gw, node v))
GW_HANDLER(del_node,(GraphWin& gw, node v),(GraphWin& gw))
GW_HANDLER(del_edge,(GraphWin& gw, edge e),(GraphWin& gw))
GW_HANDLER(split_edge,(GraphWin& gw, edge e),(GraphWin& gw, node v))
GW_HANDLER(move_component,(GraphWin& gw, node v),(GraphWin& gw, node v))
GW_HANDLER(init_graph,(GraphWin& gw),(GraphWin& gw))
GW_HANDLER(start_move_node,(GraphWin& gw, node v),(GraphWin& gw, node v))
GW_HANDLER(end_move_node,(GraphWin& gw, node v, const point& p),(GraphWin& gw, node v))

bool GraphWin::check_start_move_node_handler(node v) {
  return (pre_start_move_node_handler ? pre_start_move_node_handler(*this,v) : true);
}
void GraphWin::call_start_move_node_handler(node v) {
  if (post_start_move_node_handler) post_start_move_node_handler(*this,v);
}
bool GraphWin::check_end_move_node_handler(node v, const point& p) {
  return (pre_end_move_node_handler ? pre_end_move_node_handler(*this,v,p) : true);
}
void GraphWin::call_end_move_node_handler(node v) {
  if (post_end_move_node_handler) post_end_move_node_handler(*this,v);
}


bool GraphWin::check_new_node_handler(const point& p) {
  return (pre_new_node_handler ? pre_new_node_handler(*this,p) : true);
}
void GraphWin::call_new_node_handler(node v) {
  if (post_new_node_handler) post_new_node_handler(*this,v);
}
bool GraphWin::check_new_edge_handler(node s, node t) {
  return (pre_new_edge_handler ? pre_new_edge_handler(*this,s,t) : true);
}
void GraphWin::call_new_edge_handler(edge e) {
  if (post_new_edge_handler) post_new_edge_handler(*this,e);
}
bool GraphWin::check_move_node_handler(node v, const point& p) {
  return (pre_move_node_handler ? pre_move_node_handler(*this,v,p) : true);
}

void GraphWin::call_move_node_handler(node v) {
  if (post_move_node_handler) post_move_node_handler(*this,v);
}
bool GraphWin::check_del_node_handler(node v) {
  return (pre_del_node_handler ? pre_del_node_handler(*this,v) : true);
}
void GraphWin::call_del_node_handler() {
  if (post_del_node_handler) post_del_node_handler(*this);
}
bool GraphWin::check_del_edge_handler(edge e) {
  return (pre_del_edge_handler ? pre_del_edge_handler(*this,e) : true);
}
void GraphWin::call_del_edge_handler() {
  if (post_del_edge_handler) post_del_edge_handler(*this);
}
bool GraphWin::check_split_edge_handler(edge e) {
  return (pre_split_edge_handler ? pre_split_edge_handler(*this,e) : true);
}
void GraphWin::call_split_edge_handler(node u) {
  if (post_split_edge_handler) post_split_edge_handler(*this,u);
}
bool GraphWin::check_move_component_handler(node v) {
  return (pre_move_component_handler ? pre_move_component_handler(*this,v) : true);
}
void GraphWin::call_move_component_handler(node v) { 
  if (post_move_component_handler) post_move_component_handler(*this,v);
}
bool GraphWin::check_init_graph_handler() {
  return (pre_init_graph_handler ? pre_init_graph_handler(*this) : true);
}
void GraphWin::call_init_graph_handler() {
  if (post_init_graph_handler) post_init_graph_handler(*this);
}



/****************************************************************************/
/*                     Settings for existing nodes                          */
/****************************************************************************/

#define GW_NODE_UNDRAW(v)
#define GW_EDGE_UNDRAW(e)
#define GW_EDGES_UNDRAW(v,w)
#define GW_NODE_EDGE_UNDRAW(v) 

#define GW_NODE_REDRAW(v)       if (get_flush()) { draw_node(v);    }
#define GW_EDGE_REDRAW(e)       if (get_flush()) { draw_edge(e);    }
#define GW_EDGES_REDRAW(v,w)    if (get_flush()) { redraw(); }
#define GW_NODE_EDGE_REDRAW(v)  if (get_flush()) { embed_node_with_edges(v);\
                                                   redraw(); }


#define GW_NODE_SET(f,e,t)                                                  \
t GraphWin::set_##f(node v, t n) {                                          \
    t& e=n_info[v].e;                                                       \
    t old=e;                                                                \
    if (old == n) return n;                                                 \
    GW_NODE_UNDRAW(v);                                                      \
    e = n;                                                                  \
    GW_NODE_REDRAW(v);                                                      \
    return old;                                                             }


void GraphWin::set_info(node v, const node_info& n, long mask) {

  node_info& v_inf=n_info[v];
  bool ee=true;

  GW_NODE_EDGE_UNDRAW(v);

  bool old_flush=set_flush(false);

  if (mask & N_COLOR)  v_inf.clr=n.clr;
  if (mask & N_SHAPE)
    if  (v_inf.shape != n.shape) { ee=false; v_inf.shape=n.shape; }
  if (mask & N_BCOLOR) v_inf.border_clr=n.border_clr; 
  if (mask & N_WIDTH)  if (v_inf.r1 != n.r1) { ee=false; v_inf.r1=n.r1; }
  if (mask & N_HEIGHT) if (v_inf.r2 != n.r2) { ee=false; v_inf.r2=n.r2; }

  if (mask & N_LCOLOR) v_inf.label_clr=n.label_clr;
  if (mask & N_LPOS)   v_inf.label_pos=n.label_pos;

  if (mask & N_LTYPE) v_inf.label_t=n.label_t;
  if (mask & N_LABEL) v_inf.label = n.label;

  if (mask & N_POS) {
    double x=v_inf.pos.xcoord(),y=v_inf.pos.ycoord(),x1,y1;
    if (mask & N_XPOS) { x1=n.pos.xcoord(); if (x != x1) { ee=false; x=x1; } }
    if (mask & N_YPOS) { y1=n.pos.ycoord(); if (y != y1) { ee=false; y=y1; } }
    v_inf.pos=point(x,y);
  }

  if (mask & N_SELECT) set_select(v,n.selected);

  set_flush(old_flush);

  if (old_flush) {
    if (!ee) embed_node_with_edges(v);

 // GW_NODE_EDGE_REDRAW(v);
    redraw();
  }
  else {
   if ((!ee) && (gr_p->degree(v))) edges_embedded=false;
  }

}

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

bool GraphWin::set_select(node v, bool b) {
  bool& selected=n_info[v].selected;
  bool old_selected=selected;
  if (old_selected == b) return b;
  GW_NODE_UNDRAW(v);
  selected=b;
  if (b) selected_nodes.push(v);
  else selected_nodes.del_item(selected_nodes.search(v));
// GW_NODE_REDRAW(v);
  if (get_flush()) redraw();
  return old_selected;
}

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

string GraphWin::get_data(node v) const { 
  return gr_p->get_node_entry_string(v);
}

string GraphWin::set_data(node v, string data) { 
  string old_data(get_data(v));
  gr_p->set_node_entry(v,data);
  return old_data;
}

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

string GraphWin::get_label(node v) const { 
  switch (get_label_type(v)) {
    case data_label  : return get_data(v);
    case index_label : return string("%d",index(v));
    case user_label  : return n_info[v].label;
    default:           return "";
  }
}

string GraphWin::get_user_label(node v) const { 
  return n_info[v].label;
}

string GraphWin::set_user_label(node v, string label) {
  string old_label = n_info[v].label;
  GW_NODE_UNDRAW(v);                                                      \
  n_info[v].label = label;
  GW_NODE_REDRAW(v);
  return old_label;
}


string GraphWin::set_label(node v, string label) {
  string old_label = set_user_label(v,label);
  set_label_type(v,user_label);
  return old_label;
}

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

GW_NODE_SET(color,clr,color)
GW_NODE_SET(border_color,border_clr,color)
GW_NODE_SET(label_type,label_t,gw_label_type)
GW_NODE_SET(label_color,label_clr,color)
GW_NODE_SET(label_pos,label_pos,gw_position)

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

double GraphWin::set_radius1(node v, double r) {
  double &v_r1=n_info[v].r1;            
  double old_r1=v_r1;
  if (old_r1 == r) return r;
  GW_NODE_EDGE_UNDRAW(v);
  if (r>0) v_r1=r;
  GW_NODE_EDGE_REDRAW(v)
  else if (gr_p->degree(v)) edges_embedded=false;
  return old_r1;
}

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

double GraphWin::set_radius2(node v, double r) {
  double &v_r2=n_info[v].r2;
  double old_r2=v_r2;
  if (old_r2 == r) return r;
  GW_NODE_EDGE_UNDRAW(v);
  if (r>0) v_r2=r;
  GW_NODE_EDGE_REDRAW(v)
  else edges_embedded=false;
  return old_r2;
}

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

int  GraphWin::get_width(node v) const 
{ return win_p->real_to_pix(2*get_radius1(v)); }

int  GraphWin::get_height(node v) const 
{ return win_p->real_to_pix(2*get_radius2(v)); }

int  GraphWin::set_width(node v, int w) {
   double r =0.5 *  win_p->pix_to_real(w);
   double old_r = set_radius1(v,r);
   int    old_w = 2 * win_p->real_to_pix(old_r);
   return old_w;
}

int  GraphWin::set_height(node v, int h) {
   double r =0.5 *  win_p->pix_to_real(h);
   double old_r = set_radius2(v,r);
   int    old_w = 2 * win_p->real_to_pix(old_r);
   return old_w;
}

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

point GraphWin::set_position(node v, const point& p) {
  point &v_pos=n_info[v].pos;
  point old_p=v_pos;
  if (old_p == p) return p;
  if (get_flush()) move_node_with_edges(v,p,animation);
  else {
    v_pos=p;
    if (gr_p->degree(v)) edges_embedded=false;
  }
  return old_p;
}

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

gw_node_shape GraphWin::set_shape(node v, gw_node_shape new_shape) {
  gw_node_shape &v_shape=n_info[v].shape;
  gw_node_shape old_shape=v_shape;
  if (old_shape == new_shape) return new_shape;
  GW_NODE_EDGE_UNDRAW(v);
  v_shape=new_shape;
  GW_NODE_EDGE_REDRAW(v);
  return old_shape;
}

    
/****************************************************************************/
/*                     Settings for existing edges                          */
/****************************************************************************/

bool GraphWin::set_select(edge e, bool b) {
  bool& selected=e_info[e].selected;
  bool old_selected=selected;
  if (old_selected == b) return b;
  GW_EDGE_UNDRAW(e);
  selected=b;
  if (b) selected_edges.push(e);
  else selected_edges.del_item(selected_edges.search(e));
//GW_EDGE_REDRAW(e);
  if (get_flush()) redraw();
  return old_selected;
}

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

void GraphWin::set_info(edge e, const edge_info& i, long mask) {
  edge_info& e_inf=e_info[e];
  GW_EDGE_UNDRAW(e);
  bool old_flush=set_flush(false);

  if (mask & E_COLOR)  e_inf.clr=i.clr;
  if (mask & E_STYLE)  e_inf.style=i.style; 
  if (mask & E_WIDTH)  e_inf.width=i.width;
  if (mask & E_LCOLOR) e_inf.label_clr=i.label_clr;
  if (mask & E_LPOS)   e_inf.label_pos=i.label_pos;
  
  if (mask & E_LTYPE) e_inf.label_t = i.label_t;
  if (mask & E_LABEL) e_inf.label = i.label;

  if (mask & E_SELECT) set_select(e,i.selected);

  if (mask & E_POLYGON) {
    set_bends(e,i.p);
    if (old_flush) embed_edges(source(e),target(e));
  }

  set_flush(old_flush);

  GW_EDGE_REDRAW(e);
}

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

void GraphWin::set_edge_points(edge e, const list<point>& P) {
  node v=source(e);
  node w=target(e);
  GW_EDGES_UNDRAW(v,w);
  e_info[e].p=P;
  GW_EDGES_REDRAW(v,w);
}

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

void GraphWin::set_bends(edge e, const list<point>& P) {
  node v=source(e);
  node w=target(e);

  GW_EDGES_UNDRAW(v,w);

  list<point>& L=e_info[e].p;

  L=P;

  L.push(get_position(v));
  L.append(get_position(w));

  gw_reduce_polygon(L);

  if (L.size() == 1) L.append(get_position(w));

  if (get_flush()) {
    embed_edges(v,w);
    GW_EDGES_REDRAW(v,w);
  }
  else edges_embedded=false;
}

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

string GraphWin::get_data(edge e) const { 
  return gr_p->get_edge_entry_string(e);
}

string GraphWin::set_data(edge e, string data) { 
  string old_data(get_data(e));
  gr_p->set_edge_entry(e,data);
  return old_data;
}

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

string GraphWin::get_label(edge e) const { 
  switch (get_label_type(e)) {
    case data_label  : return get_data(e);
    case index_label : return string("%d",index(e));
    case user_label  : return e_info[e].label;
    default:           return "";
  }
}


string GraphWin::get_user_label(edge e) const { 
  // user_label
  return e_info[e].label; 
}

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

string GraphWin::set_user_label(edge e, string label) {
  string old_label = e_info[e].label;
  GW_EDGE_UNDRAW(e);
  e_info[e].label = label;
  GW_EDGE_REDRAW(e);
  return old_label;
}

string GraphWin::set_label(edge e, string label) {
  string old_label = set_user_label(e,label);
  set_label_type(e,user_label);
  return old_label;
}


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

color GraphWin::set_label_color(edge e, color c) {
  color& clr=e_info[e].label_clr;
  color old_clr=clr;
  if (old_clr == c) return c;
  GW_EDGE_UNDRAW(e);
  clr=c;
  GW_EDGE_REDRAW(e);
  return old_clr;
}

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

color GraphWin::set_color(edge e, color c) {
  color &e_clr=e_info[e].clr;
  color old_color=e_clr;
  if (old_color == c) return c;
  GW_EDGE_UNDRAW(e);
  e_clr=c;
  GW_EDGE_REDRAW(e);
  return old_color;
}

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

int GraphWin::set_width(edge e, int w) {
  int &e_width=e_info[e].width;
  int old_width=e_width;
  if (old_width == w) return w;
  GW_EDGE_UNDRAW(e);
  e_width=w;
  GW_EDGE_REDRAW(e);
  return old_width;
}

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

gw_edge_style GraphWin::set_style(edge e, gw_edge_style st) {
  gw_edge_style &e_style=e_info[e].style;
  gw_edge_style old_style=e_style;
  if (old_style == st) return st;
  GW_EDGE_UNDRAW(e);
  e_style=st;
  GW_EDGE_REDRAW(e);
  return old_style;
}

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

gw_position GraphWin::set_label_pos(edge e, gw_position lp) {
  gw_position &e_lp=e_info[e].label_pos;
  gw_position old_lp=e_lp;
  if (old_lp == lp) return lp;
  GW_EDGE_UNDRAW(e);
  e_lp=lp;
  GW_EDGE_REDRAW(e);
  return old_lp;
}


gw_label_type GraphWin::set_label_type(edge e, gw_label_type lt) {
  gw_label_type &e_lt=e_info[e].label_t;
  gw_label_type old_lt=e_lt;
  GW_EDGE_UNDRAW(e);
  e_lt=lt;
  GW_EDGE_REDRAW(e);
  return old_lt;
}

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

/****************************************************************************/
/*                        Settings for new nodes                            */
/****************************************************************************/

void GraphWin::set_node_info(const node_info& n, long mask) {
  if (mask & N_COLOR)  n_model.clr=n.clr;
  if (mask & N_SHAPE)  n_model.shape=n.shape;
  if (mask & N_BCOLOR) n_model.border_clr=n.border_clr; 
  if (mask & N_WIDTH)  n_model.r1=n.r1;
  if (mask & N_HEIGHT) n_model.r2=n.r2;
  if (mask & N_LTYPE)  n_model.label_t=n.label_t;
  if (mask & N_LABEL)  n_model.label=n.label;
  if (mask & N_LCOLOR) n_model.label_clr=n.label_clr;
  if (mask & N_LPOS)   n_model.label_pos=n.label_pos;
  if (mask & N_POS)    n_model.pos=n.pos;
  if (mask & N_SELECT) n_model.selected=n.selected;
}

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

#define GW_NMODEL_SET(f,e,t)                                              \
t GraphWin::set_node_##f(t n) { t old=n_model.e; n_model.e=n; return old; }

GW_NMODEL_SET(color,clr,color)
GW_NMODEL_SET(shape,shape,gw_node_shape)
GW_NMODEL_SET(border_color,border_clr,color)
GW_NMODEL_SET(radius1,r1,double)
GW_NMODEL_SET(radius2,r2,double)
GW_NMODEL_SET(label_type,label_t,gw_label_type)
GW_NMODEL_SET(label_pos,label_pos,gw_position)
/*
GW_NMODEL_SET(label_color,label_clr,color)
*/

int GraphWin::set_node_width(int w) 
{ return 2*win_p->real_to_pix(set_node_radius1(win_p->pix_to_real(w)*0.5)); }

int GraphWin::set_node_height(int h) 
{ return 2*win_p->real_to_pix(set_node_radius2(win_p->pix_to_real(h)*0.5)); }

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

color GraphWin::set_node_label_color(color n) {
  color old = n_model.label_clr;
  n_model.label_clr = n;
  return old;
}



/****************************************************************************/
/*                        Settings for new edges                            */
/****************************************************************************/

void GraphWin::set_edge_info(const edge_info& i, long mask) {
  if (mask & E_COLOR)   e_model.clr=i.clr;
  if (mask & E_STYLE)   e_model.style=i.style; 
  if (mask & E_WIDTH)   e_model.width=i.width;
  if (mask & E_LTYPE)   e_model.label_t=i.label_t;
  if (mask & E_LABEL)   e_model.label=i.label;
  if (mask & E_LCOLOR)  e_model.label_clr=i.label_clr;
  if (mask & E_LPOS)    e_model.label_pos=i.label_pos;
  if (mask & E_POLYGON) e_model.p=i.p;
  if (mask & E_SELECT)  e_model.selected=i.selected;
}

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

#define GW_EMODEL_SET(f,el,t)                                               \
t GraphWin::set_edge_##f(t n) { t old=e_model.el; e_model.el=n; return old; }

GW_EMODEL_SET(color,clr,color)
GW_EMODEL_SET(style,style,gw_edge_style)
GW_EMODEL_SET(width,width,int)
GW_EMODEL_SET(label_type,label_t,gw_label_type)
GW_EMODEL_SET(label_pos,label_pos,gw_position)
/*
GW_EMODEL_SET(label_color,label_clr,color)
*/

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

color GraphWin::set_edge_label_color(color n) {
  color old = e_model.label_clr;
  e_model.label_clr = n;
   return old;
}


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

/****************************************************************************/
/*                     Settings for list of nodes                           */
/****************************************************************************/

#define NLIST_SET(f,arg_t)	                                              \
  void GraphWin::set_##f(const list<node>& L, arg_t a) {                      \
    node v;                                                                   \
    bool old_flush=set_flush(false);                                          \
    forall(v,L) set_##f(v,a);                                                 \
    redraw();                                                                 \
    set_flush(old_flush);                                                     }

NLIST_SET(color,color)
NLIST_SET(shape,gw_node_shape)
NLIST_SET(border_color,color)
NLIST_SET(radius1,double)
NLIST_SET(radius2,double)
NLIST_SET(user_label,string)
NLIST_SET(label,string)
NLIST_SET(label_type,gw_label_type)
NLIST_SET(label_pos,gw_position)
NLIST_SET(label_color,color)
NLIST_SET(width,int)
NLIST_SET(height,int)
NLIST_SET(select,bool)

void GraphWin::set_info(const list<node>& L, const node_info& n, long mask) {
  node v;
  if (&L == &selected_nodes) mask &= ~N_SELECT;
  bool old_flush=set_flush(false);
  forall(v,L) set_info(v,n,mask);
  set_flush(old_flush);
  if (old_flush) redraw();
  
}

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

/****************************************************************************/
/*                     Settings for list of edges                           */
/****************************************************************************/

#define ELIST_SET(f,arg_t)	                                            \
  void GraphWin::set_##f(const list<edge>& L, arg_t a) {                    \
    edge e;                                                                 \
    bool old_flush=set_flush(false);                                        \
    forall(e,L) set_##f(e,a);                                               \
    redraw();                                                               \
    set_flush(old_flush);                                                   \
                                                                            }
ELIST_SET(color,color)
ELIST_SET(style,gw_edge_style)
ELIST_SET(user_label,string)
ELIST_SET(label,string)
ELIST_SET(label_type,gw_label_type)
ELIST_SET(label_pos,gw_position)
ELIST_SET(label_color,color)
ELIST_SET(width,int)
ELIST_SET(select,bool)

void GraphWin::set_info(const list<edge>& L, const edge_info& i, long mask) {
  edge e;
  if (&L == &selected_edges) mask &= ~E_SELECT; 
  bool old_flush=set_flush(false);
  forall(e,L) set_info(e,i,mask);
  set_flush(old_flush);
  if (old_flush) redraw();
}

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

/****************************************************************************/
/*                      Settings for arrays of nodes                        */
/****************************************************************************/

void GraphWin::set_position(const node_array<point>& dest) {
  if (get_flush()) {
    move_nodes(dest,animation);
  }
  else {
    node v;
    forall_nodes(v,*gr_p) n_info[v].pos=dest[v]; 
    edges_embedded=false;
  }
}  

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

void GraphWin::set_position(const node_array<double>& destx, 
			    const node_array<double>& desty  ) {
  node_array<point> dest(*gr_p);
  node v;
  forall_nodes(v,*gr_p) dest[v]=point(destx[v],desty[v]);
  set_position(dest);
}  

/****************************************************************************/
/*                          global Settings                                 */
/****************************************************************************/

#define GW_SET(f,e,t) t GraphWin::set_##f(t n) { t old=e; e=n; return old; }

GW_SET(flush,flush,bool)
GW_SET(constant_width,constant_width,bool)
GW_SET(done_result,done_result,int)
GW_SET(filename,gw_filename,string)
GW_SET(ps_filename,ps_filename,string)
/*
GW_SET(leda_extension,leda_ext,string)
GW_SET(gw_extension,gw_ext,string)
GW_SET(ps_extension,ps_ext,string)
*/
GW_SET(animation_steps,animation,unsigned)
GW_SET(animation_mode,node_move,node_move_t)

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

bool GraphWin::is_call_enabled(int c) {
  return menu_functions[c]->is_enabled();
}

void GraphWin::enable_call(int c) 
{ menu_functions[c]->enable(); 
  menu_p->enable_button(c);
}

void GraphWin::disable_call(int c) 
{ 
  menu_functions[c]->disable();
  menu_p->disable_button(c);
}


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

void GraphWin::enable_calls() {
  for(int c=0;c<call_entry_counter;c++) enable_call(c);
  if (done_button != -1) enable_call(done_button);
  if (exit_button != -1) enable_call(exit_button);
}

void GraphWin::disable_calls() {
  for(int c=0;c<call_entry_counter;c++) disable_call(c);
  if (done_button != -1) enable_call(done_button);
  if (exit_button != -1) enable_call(exit_button);
}

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

bool GraphWin::set_directed(bool b) {
  bool b0 = directed;
  directed = b;
  if (get_flush()) redraw();
  return b0;
}

bool GraphWin::set_ortho_mode(bool b) {
  bool b0 = ortho_mode;
  ortho_mode = b;
  if (get_flush()) redraw();
  return b0;
}

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

int GraphWin::set_grid_mode(int d) {

  window& W = get_window();
  graph&  G = get_graph();

  W.set_grid_mode(d);
  W.set_show_cursor(false);

  int old_flush = set_flush(false);
  int old_grid = grid;
  grid = d;
  if (grid > 0)
  { node v;
    forall_nodes(v,G)
    { point pos = get_position(v);
      double x = int((pos.xcoord()+0.5*d)/d) * d;
      double y = int((pos.ycoord()+0.5*d)/d) * d;
      set_position(v,point(x,y));
     }
    draw_graph();
   }
  set_flush(old_flush);
  return old_grid;
}

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

bool GraphWin::set_show_status(bool b) {
  bool old_show_status=show_status;
  if (b != show_status)
  { if (b) open_status_win();
    else close_status_win();
    show_status=b;
   }
  return old_show_status;
}

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

double GraphWin::set_zoom_factor(double f) {
  double old_zoom_factor=zoom_factor;
  f=fabs(f);
  if (f > 0.0) zoom_factor=(f > 1.0 ? f : 1.0/f);
  return old_zoom_factor;
}

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

color GraphWin::get_bg_color() { return bg_color; }

color GraphWin::set_bg_color(color c) 
{ color old_bg = bg_color;
  bg_color = c;
  win_p->set_bg_color(c);
  redraw();
  return old_bg;
}


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

int GraphWin::set_gen_nodes(int n) {
  if (n < 0) return gen_nodes;
  int old_gen_nodes=gen_nodes;
  gen_nodes=n;
  return old_gen_nodes;
}

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

int GraphWin::set_gen_edges(int m) {
  if (m < 0) return gen_edges;
  int old_gen_edges=gen_edges;
  gen_edges=m;
  return old_gen_edges;
}

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

int GraphWin::set_buttons_per_line(int c) {
  int old_buttons_per_line=buttons_per_line;
  menu_p->buttons_per_line(c);
  buttons_per_line=c;
  return old_buttons_per_line;
}  

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

double GraphWin::set_edge_distance(double d) {
  if (d == edge_distance) return d;
  double old_distance=edge_distance;
  edge_distance=fabs(d);
  if (get_flush()) {
    embed_edges();
    redraw();
  }
  else edges_embedded=(gr_p->number_of_edges()?false:true);
  return old_distance;
}

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

/****************************************************************************/
/*                           reset - functions                              */
/****************************************************************************/


void GraphWin::reset_nodes(long mask) {
  bool old_flush=set_flush(false);

  node_info v_inf;

  v_inf.pos       = DefNodePos;
  v_inf.clr       = DefNodeColor;
  v_inf.shape     = DefNodeShape;
  v_inf.border_clr= DefNodeBorderColor;
  v_inf.r1        = width2radius(DefNodeWidth);
  v_inf.r2        = height2radius(DefNodeHeight);
  v_inf.label     = DefNodeLabel;
  v_inf.label_t   = DefNodeLabelType;
  v_inf.label_clr = DefNodeLabelClr;
  v_inf.label_pos = DefNodeLabelPos;
  v_inf.selected  = DefNodeMarked;

  node v;
  forall_nodes(v,*gr_p) {
    set_info(v,v_inf,mask);
  }

  set_flush(old_flush);
  if (old_flush) redraw();
}

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

void GraphWin::reset_edges(long mask) {
  bool old_flush=set_flush(false);

  edge_info e_inf;

  e_inf.clr       = DefEdgeColor;
  e_inf.style     = DefEdgeStyle;
  e_inf.width     = DefEdgeWidth;
  e_inf.label     = DefEdgeLabel;
  e_inf.label_t   = DefEdgeLabelType;
  e_inf.label_clr = DefEdgeLabelClr;
  e_inf.label_pos = DefEdgeLabelPos;
  e_inf.selected  = DefEdgeMarked;

  edge e;
  forall_edges(e,*gr_p) {
    e_inf.p.clear();
    e_inf.p.push(get_position(source(e)));
    e_inf.p.append(get_position(target(e)));
    set_info(e,e_inf,mask);
  }                     

  set_flush(old_flush); 
  if (old_flush) redraw();
}

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

void GraphWin::reset() {
  bool old_flush=set_flush(false);
  reset_nodes();
  reset_edges();
  set_flush(old_flush);
  if (old_flush) redraw();
}    

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

void GraphWin::select_all_nodes() { set_select(gr_p->all_nodes(),true); }
void GraphWin::select_all_edges() { set_select(gr_p->all_edges(),true); }

void GraphWin::deselect_all_nodes() { set_select(gr_p->all_nodes(),false); }
void GraphWin::deselect_all_edges() { set_select(gr_p->all_edges(),false); }



