/*******************************************************************************
+
+  LEDA 3.5
+
+  graphwin.h
+
+  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.
+ 
*******************************************************************************/
#ifndef LEDA_GRAPHWIN_H
#define LEDA_GRAPHWIN_H

#include <LEDA/window.h>
#include <LEDA/graph.h>
#include <LEDA/node_map2.h>
#include <LEDA/map.h>

#define USE_BUFFERING

class __exportC GraphWin;


/****************************************************************************/
/*             Internal handling of menu-function calls                     */
/****************************************************************************/

struct gw_base_function { 

  bool enabled;

  virtual void call(GraphWin&)=0; 

  bool is_enabled() { return enabled; }
  void enable()  { enabled = true; }
  void disable() { enabled = false; }

  gw_base_function() { enabled = true; }
};



typedef void (*gw_action)(GraphWin&,const point&);


#if defined(__WATCOMC__)
typedef void (__exportC GraphWin::*gw_void_member_func)(void);
#else
typedef void (GraphWin::*gw_void_member_func)(void);
#endif


/****************************************************************************/
/*                           Constants                                      */
/****************************************************************************/

#define A_LEFT	 (1 << 0)
#define A_MIDDLE (1 << 1)
#define A_RIGHT	 (1 << 2)
#define A_SHIFT	 (1 << 3)
#define A_CTRL	 (1 << 4)
#define A_ALT	 (1 << 5)
#define A_DOUBLE (1 << 6)
#define A_DRAG   (1 << 7)
#define A_NODE   (1 << 8)
#define A_EDGE   (1 << 9)
#define A_STOP   (1 << 10)
  

#define M_NONE	   0
#define M_FILE	   (1 << 0)
#define M_EDIT	   (1 << 1)
#define M_GRAPH	   (1 << 2)
#define M_LAYOUT   (1 << 3)
#define M_WINDOW   (1 << 4)
#define M_OPTIONS  (1 << 5)
#define M_HELP	   (1 << 6)

#define M_DONE	   (1 << 7)
#define M_COMPLETE ((1 << 8) - 1)



#define N_COLOR	   (1 << 0)
#define N_SHAPE	   (1 << 1)
#define N_BCOLOR   (1 << 2)
#define N_WIDTH    (1 << 3)
#define N_HEIGHT   (1 << 4)
#define N_LABEL    (1 << 5)
#define N_LTYPE    (1 << 6)
#define N_LCOLOR   (1 << 7)
#define N_LPOS     (1 << 8)
#define N_SELECT   (1 << 9)
#define N_ALL      ((1 << 10) - 1)
#define N_XPOS     (1 << 10)
#define N_YPOS     (1 << 11)
#define N_POS      (N_XPOS | N_YPOS)
#define N_COMPLETE (N_ALL | N_POS)
#define N_SIZE     (N_WIDTH | N_HEIGHT)


#define E_COLOR	   (1 << 0)
#define E_STYLE    (1 << 1)
#define E_WIDTH    (1 << 2)
#define E_LABEL    (1 << 3)
#define E_LTYPE    (1 << 4)
#define E_LCOLOR   (1 << 5)
#define E_LPOS     (1 << 6)
#define E_SELECT   (1 << 7)
#define E_POLYGON  (1 << 8)

#define E_ALL      ((1 << 8) - 1)
#define E_COMPLETE (E_ALL | E_POLYGON)


#define STAT_CLEAR    0
#define STAT_NODES    1
#define STAT_EDGES    2
#define STAT_LOOPS    4
#define STAT_PLANAR   8
#define STAT_FLUSH   16
#define STAT_GRID    32
#define STAT_COORD   64 



extern color gw_auto_color;


enum gw_node_shape { circle_node, ellipse_node, square_node, rectangle_node };
enum node_move_t   { move_single_node , move_all_nodes };
enum gw_edge_style { solid_edge, dashed_edge, dotted_edge };
enum gw_position   { central_pos, northwest_pos, north_pos, northeast_pos,
                     east_pos, southeast_pos, south_pos, southwest_pos, 
                     west_pos };
enum gw_label_type { no_label , user_label , data_label , index_label };
    


/****************************************************************************/
/*               node_info & edge_info - structs                            */
/****************************************************************************/

struct node_info {
  bool          init;
  int           id;
  color         clr;
  gw_node_shape shape;
  color         border_clr;
  point         pos;
  double        r1;
  double        r2;
  gw_label_type label_t;
  string        label;
  color         label_clr;
  gw_position   label_pos;  
  bool          selected;
 
  LEDA_MEMORY(node_info)
};


struct edge_info {
  bool          init;
  color         clr;
  gw_edge_style style;
  int           width;
  gw_label_type label_t;
  string        label;
  color         label_clr;
  gw_position   label_pos;
  list<point>   p;
  bool          selected;  

  LEDA_MEMORY(edge_info)  
};


/****************************************************************************/
/*                         class  GraphWin                                  */
/****************************************************************************/

/*{\Manpage {GraphWin} {} {Graph Windows}}*/

class __exportC GraphWin {

/*{\Mdefinition
 
{\em GraphWin} combines the two types |graph| and |window| and
forms a bridge between the graph data types and algorithms
and the graphics interface of LEDA.
{\em GraphWin} can easily be used in LEDA programs for
constructing, displaying and manipulating graphs and for
animating and debugging graph algorithms.
We discuss some of the most important features of GraphWin
(see \ref{Luleich-Diplom} for a more detailed description).
 
\begin{itemize}
 
\item
The user interface of GraphWin is simple and intuitive.
When clicking a mouse button inside the drawing area
a corresponding default action is performed that can be
redefined by users. With the initial default settings,
the left mouse button is used for creating and moving objects,
the middle button for selecting objects, and the right button for
destroying objects.
A number of menues at the top of the window give access to
graph generators, modifiers, basic algorithms, embeddings, setup panels,
and file input and output.
 
\item
Graphwin can display and manipulate the data associated with the
nodes and edges of LEDA's parameterized graph type $GRAPH<vtype,etype>$.
When a GraphWin is opened for such a graph the associated node and edge
labels of type $vtype$ and $etype$ can be displayed and edited.
 
\item
Most of the actions of GraphWin can be customized by modifying or
extending the menues of the main window or by defining call-back functions.
So the user can define what happens if a node or edge is created, selected,
moved, or deleted.
 
\item
Graphwin offers a collection of graph generators, modifiers
and tests. The generators include functions for constructing random,
planar, complete, bipartite, grid graphs, connected graphs, biconnected,
graphs \dots
There are also methods for modifying existing graphs (e.g.
by removing or adding a certain set of edges) to fit in one of
these categories and for testing whether a given graph is
planar, connected, bipartite \dots

\item
The standard menu includes a choice of fundamental graph algorithms
and basic embedding algorithms.
 
\end{itemize}
 
\bigskip
For every node and edge of the graph GraphWin maintains a set of parameters.
 
With every node is associated\\
a {\em position} of type |point|,\\
a {\em shape} of type |gw_node_shape|,\\
a {\em color},{\em border color}, and  {\em label color} of type |color|,\\
a {\em width} and {\em height} of type |int|,\\
a {\em label type} of type |gw_label_type|,\\
a {\em user label} of type |string|, and\\
a {\em label position} of type |gw_position|.
 
\medskip
With every edge is associated\\
a list of {\em bends} of type |list<point>|,\\
a {\em color} and {\em label color} of type |color|,\\
a {\em style} of type |gw_edge_style|,\\
a {\em width} of type |int|,\\
a {\em label type} of type |gw_label_type|,\\
a {\em user label} of type |string|, and\\
a {\em label position} of type |gw_position|,\\
a {\em list of bends} of type |list<point>|.
 
The corresponding types are:
 
$gw\_node\_shape = \{\ circle\_node,\ ellipse\_node,\ square\_node,\ rectangle\_n
ode\ \}$ \\
$gw\_node\_style = \{\ simple\_node,\ filled\_node\ \}$
\vspace{-3ex}
\begin{tabbing}
$gw\_position = \{\ $\=$central\_pos,\ northwest\_pos,\ north\_pos,
                 northeast\_pos,\ east\_pos,$\\\>$southeast\_pos,\ south\_pos,
                 \ southwest\_pos,\ west\_pos\ \}$
\end{tabbing}
\vspace{-3ex} 
$gw\_edge\_style = \{\ solid\_edge,\ dashed\_edge,\ dotted\_edge\ \}$ \\
$gw\_label\_type = \{\ no\_label,\ user\_label,\ data\_label,\ index\_label\ \}$
 
}*/

  private :
  
    graph  *gr_p;			// graph
    window *win_p;			// window
    window *menu_p;			// menu window
    window *status_win;                 // status window
    window *msg_win;                    // message window
    
    node_map<node_info> n_info;
    edge_map<edge_info> e_info;
    
    bool edges_embedded;		// edges typified?
    bool ortho_mode;

    long  property_mask;
    long  status_show_mask;
    
    double x_min,x_max,y_min,y_max;	// window-size
    
    long menu_mask;

    node_move_t node_move;

    node_info n_model;
    edge_info e_model;

    list<node> selected_nodes;
    list<edge> selected_edges;
    
    double edge_distance;
    
    double units_per_pixel;    
    
    long create_flag;		// notice dynamic created memory objects

    int done_button,exit_button;

    int max_move_items;

    string gw_filename;
    string ps_filename;

    void init_once();
    void init(graph&,window&);
    void init_default();
    void init_node(node v);
    void init_edge(edge e); 
    void init_matrix();
    void init_window(int=MAXINT,int=MAXINT);
    void init_menu();
    void init_call_menu();
    void init_static();
    void init_graph();
    
    
    bool directed;			// draw graph directed?

    node found_node;
    node current_node;
    edge found_edge;


    list<node> n_anim_list;
    char*      n_anim_buf;
    bool       n_anim_flush;

    list<edge> e_anim_list;
    char*      e_anim_buf;
    bool       e_anim_flush;

    // bounding box
    double     anim_x0;
    double     anim_y0;
    double     anim_x1;
    double     anim_y1;

/****************************************************************************/
/*                                                                          */
/****************************************************************************/

static void s_redraw(window*,double,double,double,double);
static void coord_handler(window*,double,double);
static void status_redraw(window*);

    void update_win_bounds();

    int done_result;
    
    void save_embed(node,unsigned);
    void restore_embed(node,unsigned);
    void save_and_restore_embed(node,unsigned,unsigned);

    unsigned animation;

    bool flush;			// make changes on *gr_p visible

    bool constant_width;

    int buttons_per_line;

    int grid;

    bool show_crd;
    bool show_status;
    bool auto_create_target;

    color bg_color;

    double zoom_factor;
    double zoom_x0;
    double zoom_x1;
    double zoom_y0;
    double zoom_y1;

    int gen_nodes,gen_edges;

    bool win_init_done;

    double max_edge_distance(node v, node w);
    point  compute_leaving_point(node v, const point& p);
    double compute_ortho_leaving_points(node v,node w,point& pv,point& pw);
    point  first_hit(node v, const line& l, bool from_left, bool from_above);

    segment edge_segment(node v, point pv, node w, point pw);



/****************************************************************************/
/*        dynamic adjacency matrix                                          */
/****************************************************************************/

   node_map2<edge> adj_matrix_first;
   edge_map<edge>  adj_matrix_succ;

#define forall_incident_edges(e,v,w)\
   for(e=adj_matrix_first(v,w); e; e = adj_matrix_succ[e])


/****************************************************************************/
/*       Handlers - called at a specified action                            */
/****************************************************************************/

    bool (*pre_new_node_handler)(GraphWin& gw, const point& p);
    void (*post_new_node_handler)(GraphWin& gw, node v);

    bool (*pre_new_edge_handler)(GraphWin& gw, node s, node t);
    void (*post_new_edge_handler)(GraphWin& gw, edge e);
    
    bool (*pre_move_node_handler)(GraphWin& gw, node v, const point& p);
    void (*post_move_node_handler)(GraphWin& gw, node v);

    bool (*pre_start_move_node_handler)(GraphWin& gw, node v);
    void (*post_start_move_node_handler)(GraphWin& gw, node v);
    
    bool (*pre_end_move_node_handler)(GraphWin& gw, node v, const point& p);
    void (*post_end_move_node_handler)(GraphWin& gw, node v);

    bool (*pre_del_node_handler)(GraphWin& gw, node v);
    void (*post_del_node_handler)(GraphWin& gw); 

    bool (*pre_del_edge_handler)(GraphWin& gw, edge e);
    void (*post_del_edge_handler)(GraphWin& gw);

    bool (*pre_split_edge_handler)(GraphWin& gw, edge e);
    void (*post_split_edge_handler)(GraphWin& gw, node u);

    bool (*pre_move_component_handler)(GraphWin& gw, node v);
    void (*post_move_component_handler)(GraphWin& gw, node v);

    bool (*pre_init_graph_handler)(GraphWin& gw);
    void (*post_init_graph_handler)(GraphWin& gw);


/****************************************************************************/
/*       MENUS - Representation and default-menus                           */
/****************************************************************************/

    gw_base_function* menu_functions[MAX_ITEM_NUM];
    window*           sub_menus[MAX_ITEM_NUM];

    int call_entry_counter;
    int sub_menu_counter;
    
    void call_handler(int);

friend void gw_call_handler(int);


    map<long,gw_action>* action;


// pix maps

   char* leda_xpm;


   GraphWin(const GraphWin&) {} // private copy constructor


window* set_win(window* p)
{ window* old = win_p;
  win_p = p;
  return old;
 }


//------------------------------------------------------------------------------
//  Drawing & Embedding
//------------------------------------------------------------------------------

unsigned long read_mouse_rect(double&,double&,double&,double&,bool);

    
void draw_node(node v);
void draw_node(node v, double dx, double dy);
void draw_node_with_edges(node v);
void draw_node_with_edges(node v, double dx, double dy);
void draw_edge(edge e);
void draw_edge(edge e, double dx, double dy);
void draw_edges(node v, node w);
void draw_edges(node v, node w, double dx, double dy);

void draw_graph();
void draw_graph(double dx, double dy);
void draw_graph(node v);
void draw_graph(const list<node>& L); 
void draw_graph(edge e); 
void draw_graph(const list<edge>& L);

char* graph_pixrect0(double& x0, double& y0, double x, double y, bool=false);
char* graph_pixrect(double& x0, double& y0, double x, double y, bool=false);

void embed_node_with_edges(node v);
void embed_edges(node v, node w);

void move_node(node v, const vector& trans);
void move_edge(edge e, const vector& trans);
void move_nodes_with_edges(const list<node>& L, const vector& trans);

void move_node_with_edges(node v, const point& dest, unsigned anim=0);
void move_nodes(const node_array<point>& dest, unsigned anim=0);


public:

double width2radius(int w) const { return win_p->pix_to_real(w)*0.5; }
double height2radius(int h) const { return width2radius(h); }
int    radius2width(double r) const { return 2*win_p->real_to_pix(r); }
int    radius2height(double r) const { return radius2width(r); }


void embed_edges();

void n_animation_start(const list<node>&);
void e_animation_start(const list<edge>&);

const list<node>& get_n_animation_list() { return n_anim_list; }
const list<edge>& get_e_animation_list() { return e_anim_list; }

void n_animation_end();
void e_animation_end();

void n_animation_step(bool nodes_only=false);
void e_animation_step();



  
/****************************************************************************/
/*                          CONSTRUCTORS                                    */
/****************************************************************************/

/*{\Xtext \def\gw{\mbox{$gw$\hspace{-0.3em}}} }*/
/*{\Mtext \def\gw{\mbox{$gw$}} }*/
/*{\Mtext \def\graphwin{\mbox{Graph\hspace{-0.1em}Win}} }*/

/*{\Mtext \newcommand{\Void}{{\it void}} }*/
/*{\Mtext \newcommand{\String}{{\it string}} }*/
/*{\Mtext \newcommand{\Int}{{\it int}} }*/
/*{\Mtext \newcommand{\Graphwin}{{\it\graphwin}} }*/
/*{\Mtext \newcommand{\Label}{{\it label}} }*/
/*{\Mtext \newcommand{\Submenu}{{\it submenu}} }*/
/*{\Mtext \newcommand{\Point}{{\it point}} }*/
/*{\Mtext \newcommand{\Const}{{\it const}} }*/
/*{\Mtext \newcommand{\Color}{{\it color}} }*/

/*{\Mtext 
\newenvironment{Example}{\small Example:\vspace{-3ex}\begin{quote}}{\end{quote}}
}*/

/*{\Mcreation gw }*/

GraphWin(graph& G, float w, float h, const char* win_label); 
/*{\Mcreate creates a graph window for graph $G$ with a display window 
            of size $w$ pixels $\times\ h$ pixels and label |win_label|. }*/

GraphWin(graph& G, float w, float h); 
/*{\Mcreate as above with the default window label. }*/  

GraphWin(graph& G, const char* win_label); 
/*{\Mcreate creates a graph window for graph $G$ with a display window
            of default size and label |win_label|. }*/

GraphWin(graph& G); 
/*{\Mcreate as above with the default window label. }*/  

GraphWin (graph& G, window& W);
/*{\Mcreate as above, but |W| is used as display window. }*/  


GraphWin(float w, float h, const char* win_label); 
/*{\Mcreate creates a graph window with a new empty graph, a display
            window of size $w$ pixels $\times\ h$ pixels, and
            window label |win_label|. }*/

GraphWin(float w, float h); 
/*{\Mcreate as above, but the default window label is used. }*/  

GraphWin(const char* win_label); 
/*{\Mcreate creates a graph window with a new empty graph and a
            display window of default size. The window label is set 
            to |win_label|. }*/

GraphWin(); 
/*{\Mcreate as above, but the default window label is used. }*/  

GraphWin (window& W);
/*{\Mcreate as above, but |W| is used as display window. }*/  


    
~GraphWin();
    

/*{\Moperations 3.1 4.4}*/
    
/****************************************************************************/
/*                            Window Operations                             */  
/****************************************************************************/
    
/*{\Mtext
\bigskip
\headerline {a) Window Operations} }*/

void display(int x, int y);
/*{\Mop displays graph window \Mvar with upper left corner at $(x,y)$. }*/

void display();
/*{\Mop displays graph window \Mvar at default position. }*/


int edit();
/*{\Mop enters edit mode ...\\
        Change graph interactive until the done button is pressed
	(|false| returned) or exit is selected from the file menu 
	(|true| returned). }*/
    
int open(int x, int y);
/*{\Mop \gw.display(x,y) + \gw.edit() }*/

int open();
/*{\Mop \gw.display() + \gw.edit() }*/

void close();
/*{\Mop closes \Mvar. }*/

void message(string msg) { win_p->message(msg); }
/*{\Mop displays message |msg|. }*/
    
void del_messages() { win_p->del_messages(); }
/*{\Mop deletes all messages. }*/

double get_xmin() const;
/*{\Mopl  returns the minimal x-coordinate of the drawing area. }*/

double get_ymin() const;
/*{\Mopl  returns the minimal y-coordinate of the drawing area. }*/

double get_xmax() const;
/*{\Mopl  returns the maximal x-coordinate of the drawing area. }*/

double get_ymax() const;
/*{\Mopl  returns the maximal y-coordinate of the drawing area. }*/

void win_init(double xmin, double xmax, double ymin);
/*{\Mopl	reinitializes the window. }*/

void redraw();			
/*{\Mop		clears the window and draws the graph. }*/

void set_frame_label(const char* label) { menu_p->set_frame_label(label); }
/*{\Mopl        makes $label$ the window frame label. }*/

window& get_window() { return *win_p; }
/*{\Mop       returns a reference to the display window used by |\Mvar|. }*/



  
/****************************************************************************/
/*                         Graph Operations                                 */
/****************************************************************************/


/*{\Mtext
\bigskip       
\headerline {b) Graph Operations} }*/

node new_node(const point& p);
/*{\Mopl  adds a new node at position $p$ to \gw. }*/

void del_node(node v);
/*{\Mop   deletes $v$ and all edges incident to $v$ from \gw. }*/

edge new_edge(node v, node w, const list<point>& P);
/*{\Mopl  adds a new edge $(v,w)$ to \gw\ with bend sequence $P$. }*/

edge new_edge(node v, node w);
/*{\Mopl  adds a new edge $(v,w)$ to \gw. }*/
                
void del_edge(edge e);
/*{\Mop   deletes edge $e$ from \gw. }*/

void clear_graph();
/*{\Mop  deletes all nodes and egdes. }*/

graph& get_graph() { return *gr_p; }
/*{\Mop       returns a reference of the graph used in |\Mvar|. }*/



/*{\Mtext
\bigskip
\headerline {c) Node Parameters } 

Node parameters can be retrieved or
changed by a collection of |get|- and |set|- operations.

We use |param| for .. and |param_type| for the corresponding value
type as described in the beginning of this manual page.
}*/


/*{\Mtext
\bigskip
{Individual Parameters}
}*/

/*{\Moptions nextwarning=no}*/
/*
param_type  get_param(node v);
*/
/*{\Mopl  returns the value of parameter |param| for node |v|. }*/


/*{\Moptions nextwarning=no}*/
/*
param_type  set_param(node v, param_type x);
*/
/*{\Mopl  sets the value of parameter |param| for node |v| to |x|.
          and returns its previous value.}*/


/*{\Moptions nextwarning=no}*/
/*
void  set_param(list<node>& L, param_type x);
*/
/*{\Mopl  sets the value of parameter |param| for all nodes in |L| to |x|. }*/



/*{\Mtext
\bigskip
{\bf Default Parameters}
}*/

/*{\Moptions nextwarning=no}*/
/*
param_type  get_node_param();
*/
/*{\Mopl  returns the current default value of parameter |param|. }*/

/*{\Moptions nextwarning=no}*/
/*
param_type  set_node_param(param_type x);
*/
/*{\Mopl  sets the default value of parameter |param| to |x|. 
          and returns its previous value.}*/



/*{\Mtext
\bigskip
\headerline {d) Edge Parameters } 
}*/

/*{\Mtext
{\bf Individual Parameters}
}*/

/*{\Moptions nextwarning=no}*/
/*
param_type  get_param(edge e);
*/
/*{\Mopl  returns the value of parameter |param| for edge |e|. }*/

/*{\Moptions nextwarning=no}*/
/*
param_type  set_param(edge e, param_type x);
*/
/*{\Mopl  sets the value of parameter |param| for edge |e| to |x|.
          and returns its previous value.}*/

/*{\Moptions nextwarning=no}*/
/*
void  set_param(list<edge>& L, param_type x);
*/
/*{\Mopl  sets the value of parameter |param| for all edges in |L| to |x|. }*/


/*{\Mtext
\bigskip
{\bf Default Parameters}
}*/

/*{\Moptions nextwarning=no}*/
/*
param_type  get_edge_param();
*/
/*{\Mopl  returns the current default value of parameter |param|. }*/

/*{\Moptions nextwarning=no}*/
/*
param_type  set_edge_param(param_type x);
*/
/*{\Mopl  sets the default value of parameter |param| to |x|.
          and returns its previous value.}*/


/****************************************************************************/
/*                 PARAMETERS FOR EXISTING NODES                            */
/****************************************************************************/

string get_data(node v) const;
string set_data(node v, string data);

const node_info& get_info(node v) const;

void set_info(const list <node>& L, const node_info& n, long mask=N_ALL);
void set_info(node v, const node_info& n, long mask=N_ALL);

int  get_index(node v) const;

point get_position(node v) const;
point set_position(node v, const point& p);

void set_position(const node_array<point>& dest);
/*{\Mopl  for all nodes $v$ of $G$ the position of $v$ is set 
          to $dest[v]$. }*/

void set_position(const node_array<double>& destx, const node_array<double>& desty);
/*{\Mopl  for all nodes $v$ of $G$ the position of $v$ is set 
          to $(destx[v],desty[v])$. }*/


color get_color(node v) const;
color set_color(node v, color c);
void  set_color(const list <node>& L, color c);


gw_node_shape get_shape(node v) const;
gw_node_shape set_shape(node v, gw_node_shape t);
void          set_shape(const list <node>& L, gw_node_shape t);


color get_border_color(node v) const;
color set_border_color(node v, color c);
void  set_border_color(const list <node>& L, color c);

double get_radius1(node v) const;
double set_radius1(node v, double r);
void   set_radius1(const list <node>& L, double r);

double get_radius(node v) const { return get_radius1(v); }
double set_radius(node v, double r) { return set_radius1(v,r); }
void   set_radius(const list <node>& L, double r) { set_radius1(L,r); }
    
double get_radius2(node v) const;
double set_radius2(node v, double r);
void   set_radius2(const list <node>& L, double r);
    
int  get_width(node v) const;
void set_width(const list <node>& L, int w);
int  set_width(node v, int w);

int  get_height(node v) const;
void set_height(const list <node>& L, int h);
int  set_height(node v, int h);


string get_user_label(node v) const;
void   set_user_label(const list<node>& L, string s);
string set_user_label(node v, string s);

gw_label_type get_label_type(node v) const;
void          set_label_type(const list<node>& L, gw_label_type lt);
gw_label_type set_label_type(node v, gw_label_type lt);


string get_label(node v) const;
void   set_label(const list<node>& L, string s);
string set_label(node v, string s);


gw_position get_label_pos(node v) const;
void        set_label_pos(const list<node>& L, gw_position lp);
gw_position set_label_pos(node v, gw_position lp);

color get_label_color(node v) const;
void  set_label_color(const list<node>& L, color c);
color set_label_color(node v, color c);

bool get_select(node v) const;
void set_select(const list<node>& L, bool b);
bool set_select(node v, bool b);

    
    
/****************************************************************************/
/*                 PARAMETERS FOR EXISTING EDGES                            */
/****************************************************************************/

string get_data(edge e) const;
string set_data(edge e, string data);

const edge_info& get_info(edge e) const;

void set_info(const list <edge>& L, const edge_info& i, long mask=E_ALL);
void set_info(edge e, const edge_info& i, long mask=E_ALL);

list<point> get_bends(edge e) const;
void        set_bends(edge e, const list<point>& P);

list<point> get_polygon(edge e) const { return get_bends(e); }
void        set_polygon(edge e, const list<point>& P) { set_bends(e,P); }

const list<point>& get_edge_points(edge e) const;
void               set_edge_points(edge e, const list<point>& P);


color get_color(edge e) const;
color set_color(edge e, color c);
void  set_color(const list <edge>& L, color c);

gw_edge_style get_style(edge e) const;
gw_edge_style set_style(edge e, gw_edge_style st);
void          set_style(const list <edge>& L, gw_edge_style st);

int  get_width(edge e) const;
int  set_width(edge e, int w);
void set_width(const list<edge>& L, int w);

string get_user_label(edge e) const;
string set_user_label(edge e, string s);
void   set_user_label(const list<edge>& L, string s);

string get_label(edge e) const;
string set_label(edge e, string s);
void   set_label(const list<edge>& L, string s);

gw_label_type get_label_type(edge e) const;
gw_label_type set_label_type(edge e, gw_label_type lt);
void          set_label_type(const list<edge>& L, gw_label_type lt);


gw_position get_label_pos(edge e) const;
gw_position set_label_pos(edge e, gw_position lp);
void        set_label_pos(const list<edge>& L, gw_position lp);

color get_label_color(edge e) const;
color set_label_color(edge e, color c);
void  set_label_color(const list<edge>& L, color c);

bool get_select(edge e) const;
void set_select(const list<edge>& L, bool b);
bool set_select(edge e, bool b);



    
/****************************************************************************/
/*                  DEFAUL PARAMETERS FOR NODES                             */
/****************************************************************************/


const node_info& get_node_info() const;
void             set_node_info(const node_info& n, long mask=N_ALL);

color get_node_color() const;
color set_node_color(color c);


gw_node_shape get_node_shape() const;
gw_node_shape set_node_shape(gw_node_shape shape);

color get_node_border_color() const;
color set_node_border_color(color c);

double get_node_radius1() const;
double set_node_radius1(double r);		

double get_node_radius() const { return get_node_radius1(); }
double set_node_radius(double r) { return set_node_radius1(r); }

double get_node_radius2() const;
double set_node_radius2(double r);		

int get_node_width() const;
int set_node_width(int w);

int get_node_height() const;
int set_node_height(int h);

gw_label_type get_node_label_type() const;
gw_label_type set_node_label_type(gw_label_type lt);


gw_position get_node_label_pos() const;
gw_position set_node_label_pos(gw_position lp);

color get_node_label_color() const;
color set_node_label_color(color c = gw_auto_color);


/****************************************************************************/
/*                  DEFAULT PARAMETERS FOR EDGES                            */
/****************************************************************************/

const edge_info& get_edge_info() const;
void             set_edge_info(const edge_info& i, long mask=E_ALL);

color get_edge_color() const;
color set_edge_color(color c);

gw_edge_style get_edge_style() const;
gw_edge_style set_edge_style(gw_edge_style st);

int get_edge_width() const;	
int set_edge_width(int w);		

gw_label_type get_edge_label_type() const;
gw_label_type set_edge_label_type(gw_label_type lt);

gw_position get_edge_label_pos() const;
gw_position set_edge_label_pos(gw_position lp);

color get_edge_label_color() const;
color set_edge_label_color(color c = gw_auto_color);




/****************************************************************************/
/*                      GLOBAL OPTIONS                                      */ 
/****************************************************************************/

/*{\Mtext
\headerline { e) Menu Options} }*/

int get_gen_nodes() const;

int set_gen_nodes(int n);
/*{\Mopl  sets the number of nodes to generate when chosen the
	  appropriate menu-item. }*/
    
int get_gen_edges() const;

int set_gen_edges(int m);
/*{\Mopl  sets the number of edges to generate when chosen the
	  appropriate menu-item. }*/
    
double get_edge_distance() const;

double set_edge_distance(double d);
/*{\Mopl  sets the maximum distance between multiple edges. }*/


int get_grid_mode() const;

int set_grid_mode(int b);
/*{\Mopl  sets the window-grid ($b>0$) or removes it ($b=0$). }*/


bool get_ortho_mode() const;

bool set_ortho_mode(bool);
/*{\Mopl  experimental. }*/

bool get_show_status() const;

bool set_show_status(bool b);
/*{\Mopl  display a status window ($b$={\it true}) or not ($b$={\it false}). }*/


color get_bg_color();

color set_bg_color(color c);
/*{\Mopl  ... }*/


unsigned get_animation_steps() const;

unsigned set_animation_steps(unsigned s);
/*{\Mopl  move a node in $s$ steps to its new position. }*/


node_move_t get_animation_mode() const;

node_move_t set_animation_mode(node_move_t nm);
/*{\Mopl  When using set\_position({\it node\_array}\<..\> ..) the nodes 
          can be moved (see set\_animation\_steps) one after another 
          ($nm=${\it \ move\_single\_node}) 
          or all together ($nm=${\it \ move\_all\_nodes}). }*/

bool get_flush() const { return flush; }

bool set_flush(bool b);
/*{\Mopl  show operations on $gw$ instantly ($b$={\it true}) 
               or not ($b$={\it false}). }*/


int get_max_move_items() const;

int set_max_move_items(int);
/*{\Mopl  ... }*/


double get_zoom_factor() const;

double set_zoom_factor(double f);
/*{\Mopl  sets the zoom factor to f used when zooming from menu. }*/


int get_done_result() const;

int set_done_result(int r);
/*{\Mopl  sets done to $r$. }*/



bool get_constant_width() const;

bool set_constant_width(bool b); 
/*{\Mopl  resize nodes when zooming (|b==false|) or not (|b==true|). }*/



/*{\Mtext
\bigskip
\headerline { f) Node and Edge Selections} }*/

void select(node v) { set_select(v,true); }
/*{\Mopl  adds $v$ to the list of selected nodes. }*/

void select_all_nodes();
/*{\Mop selects all nodes. }*/

void deselect(node v) { set_select(v,false); }    
/*{\Mopl  deletes $v$ from the list of selected nodes. }*/

void deselect_all_nodes();
/*{\Mop clears the current node selection. }*/

bool is_selected(node v) const { return get_select(v); }
/*{\Mopl  returns |true| is |v| is selected and |false| otherwise. }*/

const list<node>& get_selected_nodes() const { return selected_nodes; }
/*{\Mop returns the current node selection. }*/


void select(edge e) { set_select(e,true); }
/*{\Mopl  adds $e$ to the list of selected edges. }*/

void select_all_edges();
/*{\Mop selects all edges. }*/

void deselect(edge e) { set_select(e,false); }    
/*{\Mopl  deletes $e$ from the list of selected edges. }*/

void deselect_all_edges();
/*{\Mop clears the current node selection. }*/

bool is_selected(edge e) const { return get_select(e); }
/*{\Mopl  returns |true| is |e| is selected and |false| otherwise. }*/

const list<edge>& get_selected_edges() const { return selected_edges; }
/*{\Mop returns the current edge selection. }*/
    



/****************************************************************************/
/*                             EDIT                                         */ 
/****************************************************************************/

/*{\Mtext
\medskip
\headerline {g) Operations in Edit-mode} 

Before entering the edit-mode (\gw.edit() or \gw.open()), it is possible
to influence \graphwin's actions in certain kinds of situation.

First way to do that are call-back functions. These are defined for 
a fix number of user-actions. They exist in two forms. One is called
before a defined action (pre-handler), the other one when it was executed
(post-handler). The pre-handler returns a bool-value, which says
\graphwin\ to process or to ignore the query. The post-handler informs
about what happened. It is possible to define only one of it.
With no argument both are reset to their default.

The second way is to define, what to do, when a certain condition of
mouse- and keypress-events comes true.
Events are:
A\_LEFT	(left mouse-button), A\_MIDDLE (middle mouse-button),
A\_RIGHT (right mouse-button), A\_SHIFT (shift-key),
A\_CTRL (control-key), A\_ALT (alt-key),
A\_DRAG (button not released), A\_NODE (node-hit)
A\_EDGE (edge-hit).
To describe an event combine these constants using operator \vline ,
for instance\\
(A\_LEFT \vline\ A\_NODE) starts a new edge by default.
}*/



void set_new_node_handler(bool (*f)(GraphWin&,const point&));
/*{\Mopl	$f$ is called whenever the user wants to create a node at 
		point $p$. }*/

void set_new_node_handler(void (*f)(GraphWin&,node)=NULL);
/*{\Mopl	$f$ is called every time the user created a new node. The node
		is assigned to $v$. }*/

void set_new_edge_handler(bool (*f)(GraphWin&,node, node));
/*{\Mopl	$f$ is called whenever the user wants to create an edge from 
		$s$ to $t$. }*/

void set_new_edge_handler(void (*f)(GraphWin&,edge)=NULL);
/*{\Mopl	$f$ is called every time the user created a new edge. The edge
		is assigned to $e$. }*/

//sn:
bool has_move_node_handler() { return post_move_node_handler != 0; }

void set_move_node_handler(bool (*f)(GraphWin& gw, node v, const point& p));
/*{\Mopl	$f$ is called whenever a node should be moved. The node is
		assigned to $v$, the target-point to $p$. }*/

void set_move_node_handler(void (*f)(GraphWin&,node)=NULL);
/*{\Mopl	$f$ is called every time the user changed the position
		of a node. The moved node is assigned to $v$. }*/

void set_del_node_handler(bool (*f)(GraphWin&,node));
/*{\Mopl	$f$ is called whenever the user wants to remove a node.
		The node is assigned to v. }*/

void set_del_node_handler(void (*f)(GraphWin&)=NULL);
/*{\Mopl        $f$ is called every time the user deleted a node. }*/

void set_del_edge_handler(bool (*f)(GraphWin&, edge));
/*{\Mopl	$f$ is called whenever the user wants to remove an edge.
		The edge is assigned to $e$. }*/

void set_del_edge_handler(void (*f)(GraphWin&)=NULL);
/*{\Mopl        $f$ is called every time the user deleted an edge. }*/

void set_split_edge_handler(bool (*f)(GraphWin& gw, edge e));
void set_split_edge_handler(void (*f)(GraphWin&,node)=NULL);

void set_move_component_handler(bool (*f)(GraphWin&,node));
void set_move_component_handler(void (*f)(GraphWin&,node)=NULL);
    
void set_init_graph_handler(bool (*f)(GraphWin&));
/*{\Mopl	$f$ is called whenever the user wants to change the graph
		in greater dimension, for instance clearing the graph. }*/

void set_init_graph_handler(void (*f)(GraphWin&)=NULL);
/*{\Mopl	$f$ is called every time the user made fundamental changes
		to the graph. }*/
		
void set_start_move_node_handler(bool (*f)(GraphWin&,node)=NULL);
void set_start_move_node_handler(void (*f)(GraphWin&,node));

void set_end_move_node_handler(bool (*f)(GraphWin&,node,const point&)=NULL);
void set_end_move_node_handler(void (*f)(GraphWin&,node));
    
bool check_start_move_node_handler(node v);
void call_start_move_node_handler(node v);

bool check_end_move_node_handler(node v, const point& p);
void call_end_move_node_handler(node v);

bool check_new_node_handler(const point& p);
void call_new_node_handler(node v);
    
bool check_new_edge_handler(node s, node t);
void call_new_edge_handler(edge e);
        
bool check_move_node_handler(node v, const point& p);
void call_move_node_handler(node v);
    
bool check_del_node_handler(node v);
void call_del_node_handler();
    
bool check_del_edge_handler(edge e);
void call_del_edge_handler();
    
bool check_split_edge_handler(edge e);
void call_split_edge_handler(node u);
    
bool check_move_component_handler(node v);
void call_move_component_handler(node v);
    
bool check_init_graph_handler();
void call_init_graph_handler();
    

void set_action(long mask, gw_action f=NULL);
/*{\Mopl	set action on condition $mask$ to $f$. $gw\_action$ is defined
		as \Void\ ($\ast$)(\Graphwin\&,\Const\ \Point\&). }*/

void reset_actions();
/*{\Mopl	set all actions to their default values. }*/



/****************************************************************************/
/*                                MENUS                                     */
/****************************************************************************/

/*{\Mtext
\medskip
\headerline {h) Menus}
 
Menus of \graphwin\ are not fixed. New buttons and menus are easy 
includable to it, for instance to pass a graph -- created in an edit-session --
through your own function and to show its results.
To add your function $f$ of type {\it function\_t}, use (non-member-function!) 

\Int\ gw\_add\_call(\Graphwin\& \gw, {\it function\_t} $f$, 
                    \String\ \Label, \Int\ \Submenu=0).

\begin{Example} 
You have written a function \vspace{-3ex}
\begin{verbatim}
void mydfs(graph& G, node s, node_array<bool>& reached) { ... }
\end{verbatim}\vspace{-3ex}
that performs a depth first search starting at s. To make it available from
menu, type\vspace{-3ex} 
\begin{verbatim}
gw_add_call(gw,mydfs,"My dfs");
\end{verbatim}\vspace{-3ex}
for an existing object $gw$ of class \graphwin. 
\end{Example}

Since \graphwin\ don't know, how to handle with the arguments and the 
result of function $f$, you have to define 

\Void\ gw\_call(\Graphwin\& \gw, {\it function\_t} $f$) { \ldots }

for all your above used functions $f$. 
In gw\_call you create needed arguments, call $f$ with it and possibly show
the results (set\_color(..), set\_position(..) etc.).

\begin{Example}
Only you know, what preconditions to meet when calling 
{\tt mydfs}. Let's assume that argument $s$ from {\tt mydfs} may any node 
of graph $G$. Define a function as follows:\vspace{-3ex}
\begin{verbatim}
void gw_call(GraphWin& gw, void (*dfs)(graph&,node,node_array<bool>&)) {
  graph& G=gw.get_graph();
  node s=gw.get_node();
  node_array<bool> reached(G,false);
  dfs(G,s,reached);
  node v;
  forall_nodes(v,G) if (reached[v]) gw.set_color(v,red);
}
\end{verbatim}\vspace{-3ex}
That's all.
\end{Example}

Another possibility to extend the menu is to make the above used $gw\_call$ 
variable:

\begin{tabbing}
\Int\ gw\_add\_call(\=\Graphwin\& \gw, 
                    {\it function\_t} $f$, 
		    \Void\ ($\ast call$)(\Graphwin\&,{\it function\_t}),\\
		    \>\String\ \Label, \Int\ \Submenu=0).
\end{tabbing}
		 
In this version $call$ is executed whenever the assigned button is pressed.

\begin{Example}
Using function $gw\_call$ you'll get the same effect as above by writing\vspace{-3ex}
\begin{verbatim}
gw_add_call(gw,mydfs,gw_call,"My dfs");
\end{verbatim}\vspace{-3ex}
\end{Example}

For simple functions, that only change parameters of a \graphwin, can be used:

\begin{tabbing}
\Int\ gw\_add\_simple\_call(\=\Graphwin\& \gw,
                            \Void\ ($\ast f$)(\Graphwin\&),
                            \String\ \Label,\\\>\Int\ \Submenu=0);
\end{tabbing}

\graphwin\ offers a lot of functions, that combine many single actions in 
one call, for instance \gw.reset\_nodes(). These functions are of type
\mbox{\Void\ (\Graphwin::$\ast f$)(\Void)} and may also added to the menu by 

\begin{tabbing}
\Int\ gw\_add\_member\_call(\=\Graphwin\& \gw,
                           \Void\ (\Graphwin::$\ast f$)(\Void),
                           \String\ \Label,\\\>\Int\ \Submenu=0).
\end{tabbing}
\vspace{-3ex}
or
\vspace{-3ex}
\begin{tabbing}
\Int\ gw\_add\_member\_call(\=\Graphwin\& \gw, \Void\ (\Graphwin::$\ast f$)(\Void),\\
                            \>\Void\ ($\ast call$)(\Graphwin\&,\Void\ (\Graphwin::$\ast f$)(\Void)), 
           		    \String\ \Label,\\\>\Int\ \Submenu=0).
\end{tabbing}

Within $call$ the member-function $f$ can be called using

\Void\ \gw.call(\Void\ (\Graphwin::$\ast f$)(\Void)).

All functions discussed above return an integer. With it you are able
to forbid calls from menu using set\_call\_enabled(int,bool). See below.

To add a submenu, use

\Int\ gw\_add\_menu(\Graphwin\& \gw, \String\ \Label, \Int\ \Submenu=0);

which returns an integer corresponding to a submenu you can use as parameter 
submenu in all gw\_add\ldots-commands.

}*/

void call(gw_void_member_func f) { (this->*f)(); }

int add_call(gw_base_function *f, string label, int sub_menu=0);

int add_menu(string label, int sub_menu=0);

int set_buttons_per_line(int n);


void enable_call(int c);
/*{\Mopl	enable call to function $c$ when chosen from menu. }*/
  
void disable_call(int c);
/*{\Mopl	disable call to function $c$ when chosen from menu. }*/

bool is_call_enabled(int c);
/*{\Mopl        checks if call to function $c$ is enabled. }*/	
  
void enable_calls();
/*{\Mopl	enable all calls added with gw\_add\ldots\ . }*/
    
void disable_calls();
/*{\Mopl	disable all calls added with gw\_add\ldots\ . }*/


int get_done_button() const { return done_button; }
int get_exit_button() const { return exit_button; }
  
void set_default_menu(long mask);



/*{\Mtext
\medskip
\headerline {i) Input/Output} }*/

string get_filename() const { return gw_filename; }
string set_filename(string s);

string get_ps_filename() const { return ps_filename; }
string set_ps_filename(string s);

void file_handler(int);

int read(string fname);  
/*{\Mopl reads graph from file |fname|.}*/

bool save(string fname);  
/*{\Mopl saves graph to file |fname|.}*/

bool save_ps(string fname);
/*{\Mop saves a postscript representation of the graph to |fname|. }*/


// for backward compatibility
int read_gw(string fname) { return read(fname); }
int save_gw(string fname) { return save(fname); }



/*{\Mtext
\medskip
\headerline {j) Miscellaneous} }*/
               
bool get_directed() const { return directed; }

bool set_directed(bool b);    
/*{\Mop       show edges as arrows ($b$={\it true}) or not ($b$={\it false}). }*/

void open_msg_win();
void show_msg(const char*);
void close_msg_win() { msg_win->close(); }

void open_status_win();
void close_status_win(){ status_win->close(); }
bool status_win_open() { return status_win->is_open(); }


int wait(unsigned sec, const char* msg="");
/*{\Mopl       displays $msg$ and waits $sec$ seconds. 
               If the user presses the continue/quit-button from
               menu, wait terminates too. }*/

int wait(const char* msg="");
/*{\Mop		displays $msg$ and waits until continue/quit-button from
		menu is pressed. }*/
               
void acknowledge(string s);
/*{\Mopl     displays string $s$ and asks for acknowledgement. }*/


node read_node();
/*{\Mop     asks for node-determining and returns the chosen or nil, if
            there isn't one or the user canceled the action.}*/

edge read_edge();
/*{\Mop     asks for edge-determining and returns the chosen or nil, if
            there isn't one or the user canceled the action.}*/


bool define_area(double& x0, double& y0, double& x1, double& y1, 
                 const char* msg="");
/*{\Mop     displays message |msg| and returns coordinates of a rectangular
            area defined by clicking and dragging the mouse. }*/

list<node> get_nodes_in_area(double x0, double y0, double x1, double y1);
/*{\Mop     returns the list of nodes in the rectangular area 
            $(x0,y0,x1,y1)$. }*/


int  test_update_nodes();
int  test_update_edges();
bool test_update_graph();

void update_nodes();
void update_edges();



void update_graph();
/*{\Mopl  this function has to be called after any update operation
          that has been performed directly (i.e. not by \graphwin)
          on the underlying graph (e.g. deleting or inserting a 
          a node or edge. }*/


void reset_nodes(long mask=N_ALL);
/*{\Mopl  reset node parameters to their default values. }*/
    
void reset_edges(long mask=E_ALL);
/*{\Mopl  reset edge parameters to their default values. }*/

void reset();
/*{\Mopl  reset node and edge parameters to their default values. }*/



node get_found_node() const { return found_node; }
edge get_found_edge() const { return found_edge; }

    
node find_node(const point& p, node from=nil);
/*{\Mop ...}*/

edge find_edge(const point& p, edge from=nil);
/*{\Mop ...}*/


void adjust_zoom_rect(double&,double&,double&,double&);

void zoom_area(double,double,double,double);
/*{\Mop ...}*/

void unzoom();

void zoom(double f);
/*{\Mop ...}*/

void get_bounding_box(double&, double&, double&, double&);
/*{\Mop ...}*/

void fill_window();
/*{\Mop ...}*/

void remove_bends();
/*{\Mop ...}*/


// help functions

void help_about();
void help_mouse_left();
void help_mouse_middle();
void help_mouse_right();
void help_news();


//----------------------------------------------------------------------------
// friend functions
//----------------------------------------------------------------------------

friend void __exportF gw_zoom_area(GraphWin& gw, const point&);
friend void __exportF gw_setup_component(GraphWin& gw, const point&);
friend void __exportF gw_move_node(GraphWin& gw, const point& p);
friend void __exportF gw_move_edge(GraphWin& gw, const point& p);
friend void __exportF gw_move_nodes(GraphWin&, const point&, const list<node>&);
friend void __exportF gw_move_component(GraphWin& gw, const point& p);
friend void __exportF gw_select_component(GraphWin& gw, const point&);
friend void __exportF gw_select_all_nodes(GraphWin& gw, const point&);
friend void __exportF gw_deselect_all_nodes(GraphWin& gw, const point&);
friend void __exportF gw_select_node(GraphWin& gw, const point&);
friend void __exportF gw_new_node(GraphWin& gw, const point& p);
friend void __exportF gw_new_edge(GraphWin& gw, const point&);
friend void __exportF gw_del_node(GraphWin& gw, const point&);
friend void __exportF gw_del_edge(GraphWin& gw, const point&);
friend void __exportF gw_del_component(GraphWin& gw, const point&);
friend void __exportF gw_setup_node(GraphWin& gw, const point&);
friend void __exportF gw_setup_edge(GraphWin& gw, const point&);
friend void __exportF gw_global_setup(GraphWin& gw, const point&);
friend void __exportF gw_scroll_graph(GraphWin& gw, const point& p);
friend void __exportF gw_scroll_graph(GraphWin& gw,const point& p,bool scroll);
friend void __exportF gw_select_area(GraphWin& gw, const point& p);
friend void __exportF gw_split_edge(GraphWin& gw, const point& p);
friend void __exportF gw_del_selected_nodes(GraphWin& gw, const point&);

friend bool __exportF gw_setup(GraphWin& gw,const list<node>& L,
                                            long mask=N_COMPLETE);
friend bool __exportF gw_setup(GraphWin& gw,const list<edge>& L,
                                            long mask=E_COMPLETE);
friend void __exportF gw_global_setup(GraphWin& gw);
friend void __exportF gw_animation_setup(GraphWin& gw);

friend void __exportF gw_load_handler(GraphWin& gw);
friend void __exportF gw_save_handler(GraphWin& gw);
friend void __exportF gw_save_ps_handler(GraphWin& gw);
friend void __exportF gw_file_handler(GraphWin& gw);


};
 
//----------------------------------------------------------------------------

class gw_function_1 : public gw_base_function {
 public :
  typedef gw_void_member_func f_t;
  typedef void (*c_t)(GraphWin&,f_t);
  f_t f;
  c_t c;
  gw_function_1(f_t g, c_t d) : f(g), c(d) {};
  void call(GraphWin& gw) { if (c) c(gw,f); else gw.call(f); } 
};

template<class function_t>
class gw_function_2 : public gw_base_function {
 public :
  typedef function_t f_t;
  typedef void (*c_t)(GraphWin&,f_t);
  f_t f;
  c_t c;
  gw_function_2(f_t g, c_t d) : f(g), c(d) {};
  void call(GraphWin& gw) { 
    if (c) c(gw,f);
    else {
      void (*g)(GraphWin&)=(void(*)(GraphWin&))f; 
      g(gw); 
    } 
  }
};


//----------------------------------------------------------------------------
// gw_add_member_call
//----------------------------------------------------------------------------

inline int gw_add_member_call(GraphWin& gw, gw_void_member_func f, 
                              void (*c)(GraphWin&, gw_void_member_func), 
 		              string label, int submenu=0) 
{ gw_base_function *bf_p=new gw_function_1(f,c);
  return gw.add_call(bf_p,label,submenu);
 } 

inline int gw_add_member_call(GraphWin& gw, gw_void_member_func f,
                              string label, int submenu=0) 
{ return gw_add_member_call(gw,f,NULL,label,submenu);  }



//----------------------------------------------------------------------------
// gw_add_call
//----------------------------------------------------------------------------

template<class function_t> void gw_call(GraphWin& gw, function_t f);


template<class function_t>
inline int gw_add_call(GraphWin& gw, function_t f, 
                       void (*c)(GraphWin&,function_t), 
                       string label, int submenu) 
{ gw_base_function *bf_p=new gw_function_2<function_t>(f,c);
  return gw.add_call(bf_p,label,submenu);
} 


template<class function_t>
inline int gw_add_call(GraphWin& gw, function_t f, 
                       void (*c)(GraphWin&,function_t), string label) 
{ return gw_add_call(gw,f,c,label,0); } 


template<class function_t>
inline int gw_add_call(GraphWin& gw, function_t f, 
                       void (*c)(GraphWin&,function_t),char* label,int submenu)
{ return gw_add_call(gw,f,c,string(label),submenu); } 


template<class function_t>
inline int gw_add_call(GraphWin& gw, function_t f, 
                       void (*c)(GraphWin&,function_t), char* label) 
{ return gw_add_call(gw,f,c,string(label)); } 


template<class function_t>
inline int gw_add_call(GraphWin& gw, function_t f, string label, int submenu) 
{ gw_base_function *bf_p=new gw_function_2<function_t>(f,gw_call);
  return gw.add_call(bf_p,label,submenu);
} 

template<class function_t>
inline int gw_add_call(GraphWin& gw, function_t f, string label) 
{ return gw_add_call(gw,f,label,0); } 

template<class function_t>
inline int gw_add_call(GraphWin& gw, function_t f, char* label, int submenu) 
{ return gw_add_call(gw,f,string(label),submenu); } 

template<class function_t>
inline int gw_add_call(GraphWin& gw, function_t f, char* label) 
{ return gw_add_call(gw,f,label,0); } 



//----------------------------------------------------------------------------
// gw_add_simple_call
//----------------------------------------------------------------------------

inline int gw_add_simple_call(GraphWin& gw, void (*f)(GraphWin&), 
                              string label, int submenu=0) 
{ void (*nil_f)(GraphWin&, void (*)(GraphWin&)) = NULL;
  return gw_add_call(gw,f,nil_f,label,submenu);
} 


//----------------------------------------------------------------------------
// gw_add_menu
//----------------------------------------------------------------------------

inline int gw_add_menu(GraphWin& gw, string label, int submenu=0) 
{ return gw.add_menu(label, submenu); }



#endif /* LEDA_GRAPHWIN_H */
