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

#include <math.h>


void GraphWin::call_handler(int n) {
   gw_base_function* mf = menu_functions[n];
   if (mf->is_enabled()) mf->call(*this); 
}

void gw_call_handler(int n) {
  window*   wp = window::get_call_window();
  GraphWin* gw = (GraphWin*)wp->get_inf();
  gw->call_handler(n);
}


int GraphWin::add_menu(string label, int sub_menu) {
  init_call_menu();
  menu *m_sub=new menu;
  m_sub->set_inf(this);
  sub_menus[sub_menu_counter]=m_sub;
  sub_menus[sub_menu]->button(label,*m_sub);
  return sub_menu_counter++;  
}


int GraphWin::add_call(gw_base_function* f, string label, int sub_menu) {
  init_call_menu();
  menu_functions[call_entry_counter]=f;
  sub_menus[sub_menu]->button(label,call_entry_counter,gw_call_handler);
  f->enable();
  return call_entry_counter++;
}


void GraphWin::set_default_menu(long mask) {
  menu_mask=mask;
}



//----------------------------------------------------------------------------
// zooming
//----------------------------------------------------------------------------

static void gw_fill_window(GraphWin& gw)   
{ bool b = gw.get_flush();
  gw.fill_window(); 
  gw.set_flush(b);
}

static void gw_unzoom(GraphWin& gw)   
{ bool b = gw.get_flush();
  gw.unzoom(); 
  gw.set_flush(b);
}

static void gw_zoom_up(GraphWin& gw)   
{ double f = gw.get_zoom_factor();
  bool b = gw.get_flush();
  gw.zoom(f); 
  gw.set_flush(b);
}

static void gw_zoom_down(GraphWin& gw)
{ double f = 1/gw.get_zoom_factor();
  bool b = gw.get_flush();
  gw.zoom(f); 
  gw.set_flush(b);
}


static void gw_zoom_area(GraphWin& gw) 
{
  window& W = gw.get_window();

  char* msg = "ZOOM AREA     click left: select center    click right: cancel";

  gw.open_msg_win();
  gw.show_msg(msg);

  point p;
  int but = W.read_mouse(p);

  if (but != DEL_BUTTON) gw_zoom_area(gw,p);

  gw.close_msg_win();
}



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


static void stretch(const graph& G, 
                    node_array<double>& destx,
                    node_array<double>& desty,
                    double x0, double y0, double x1, double y1) {
  double xd=x1-x0;
  double yd=y1-y0;

  double f=10;

  x0+=xd/f;
  y0+=yd/f;

  xd*=1.0-2.0/f;
  yd*=1.0-2.0/f;

  node v;
  forall_nodes(v,G) { 
    destx[v]=x0+destx[v]*xd;
    desty[v]=y0+desty[v]*yd;
  }
}

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

static void stretch(const graph& G, node_array<point>& dest,
                    double x0, double y0, double x1, double y1) {
 
// stretches unit-square coordinates given in dest to window (x0,y0)(x1,y1)

  node_array<double> x(G),y(G);

  node v;
  forall_nodes(v,G) {
    x[v]=dest[v].xcoord();
    y[v]=dest[v].ycoord();
  }

  stretch(G,x,y,x0,y0,x1,y1);

  forall_nodes(v,G) dest[v]=point(x[v],y[v]);
}

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

static void embed_planar( GraphWin& gw, 
                  int (*f)(graph&,node_array<int>&,node_array<int>&) ) 
{
  graph& G=gw.get_graph();
  int n=G.number_of_nodes();
  if (n == 0) return;
  if (!PLANAR(G)) {
    gw.acknowledge("graph is not planar");
    return;
  }
  if (!gw.check_init_graph_handler()) return;
  list<edge> inserted_edges;
  Make_Biconnected(G,inserted_edges);
  Make_Bidirected(G,inserted_edges);
  PLANAR(G,true);
  node_array<int> xcoord(G);
  node_array<int> ycoord(G);
  int k=f(G,xcoord,ycoord);
  // restore original graph
  edge e;
  forall(e,inserted_edges) G.del_edge(e);
  node_array<point> dest(G);
  node v;
  forall_nodes(v,G) dest[v]=point((double)xcoord[v]/k,(double)ycoord[v]/k);
  double xmin=gw.get_xmin(),ymin=gw.get_ymin();
  double xmax=gw.get_xmax(),ymax=gw.get_ymax();
  stretch(G,dest,xmin,ymin,xmax,ymax);
  gw.remove_bends();
  gw.set_position(dest);
  if (!gw.get_flush()) {
    gw.embed_edges();
    gw.redraw();
  }
  gw.call_init_graph_handler();
}

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

static void gw_spring_embed(GraphWin& gw)
{
  graph&  G = gw.get_graph();
  window& W = gw.get_window();
 
  double xleft  = gw.get_xmin();
  double xright = gw.get_xmax();
  double ybottom= gw.get_ymin();
  double ytop   = gw.get_ymax();

  node_array<double>    xpos(G);
  node_array<double>    ypos(G);
 
  node v;
  forall_nodes(v,G) {
    point p = gw.get_position(v);
    xpos[v] = p.xcoord();
    ypos[v] = p.ycoord();
  }
 
  SPRING_EMBEDDING(G,xpos,ypos,xleft,xright,ybottom,ytop,400);
  gw.remove_bends();
  gw.set_position(xpos,ypos);
  if (!gw.get_flush()) gw.redraw();
}

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

static void embed_grid(const graph& G, node_array<point>& dest) { 
  int n = G.number_of_nodes();
  if (n == 0) return;
  n = (int) (sqrt((float)n));
  if (n*n < G.number_of_nodes()) ++n;
  double d = 1.0/(n-1);
  int i = 0;
  node v;
  forall_nodes(v,G) { 
    int row = i/n;
    int col = i%n;
    dest[v]=point(d*col,d*row);
    i++;
  }
}
  
//----------------------------------------------------------------------------

static void snap_to_grid(GraphWin& gw)
{
  window& W = gw.get_window();
  graph&  G = gw.get_graph();

  int d = gw.get_grid_mode();
 
  if (d == 0)
  { d = 5;
    panel P;
    P.text_item("No grid defined, please give a grid distance.");
    P.text_item("");
    P.int_item("grid dist",d,1,32);
    P.buttons_per_line(3);
    P.button("snap",1);
    P.button("grid",2);
    P.button("cancel",0);

    int but = P.open(W);

    if (but == 0) return;
    if (but == 2)
    { gw.set_grid_mode(d);
      return;
     }
  }

  node v;
  node_array<point> dest(G);
  forall_nodes(v,G)
  { point pos = gw.get_position(v);
    double x = int((pos.xcoord()+0.5*d)/d) * d;
    double y = int((pos.ycoord()+0.5*d)/d) * d;
    dest[v] = point(x,y);
   }

  gw.set_position(dest);
  if (!gw.get_flush())
  { gw.embed_edges();
    gw.redraw();
   }

}

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

static void embed_circular(const graph& G, node_array<point>& dest) {
  int n=G.number_of_nodes();
  if (n == 0) return;
  point  m = point(0.5,0.5);
  double alpha = 0;
  double step  = 6.2832/n;
  node v;
  forall_nodes(v,G) { 
    dest[v]=m.translate_by_angle(alpha,0.5);
    alpha+=step;
  }
}

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

static void embed_random(const graph& G, node_array<point>& dest) { 
  random_source ran;
  node v;
  double x,y;
  forall_nodes(v,G) {
    ran >> x >> y;
    dest[v]=point(x,y);
  }
}

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

static void embed_bigraph(const list<node>& A, const list<node>& B,
                                                     node_array<point>& dest) { 
  double d=1.0/(A.size()-1);
  double f=0;
  node v;
  forall(v,A) { dest[v]=point(0,f); f+=d; }
  d=1.0/(B.size()-1);
  f=0;
  forall(v,B) { dest[v]=point(1,f); f+=d; }
}

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



static bool gen_dialog(GraphWin& gw, char* s, int* n, int* e=0) {

  window& W=gw.get_window();

  panel P;
  P.text_item(string("Create %s graph",s));
  P.int_item("nodes",*n,0,200);
  if (e) P.int_item("edges",*e,0,200);
  P.button("ok",1);
  P.button("cancel",0);
  if (P.open(W) == 0) return false;
  gw.set_gen_nodes(*n);
  if (e) gw.set_gen_edges(*e);
  return true;
}

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

static void gen_circular_graph(GraphWin& gw, void (*f)(graph&,int)) {
  if (!gw.check_init_graph_handler()) return;

  int n=gw.get_gen_nodes();
  if (!gen_dialog(gw,"complete ",&n)) return; 

  bool old_flush=gw.set_flush(false); 
  gw.clear_graph();
  graph& G=gw.get_graph();
  f(G,gw.get_gen_nodes());
  node_array<point> dest(G);
  embed_circular(G,dest);
  double xmin=gw.get_xmin(),ymin=gw.get_ymin();
  double xmax=gw.get_xmax(),ymax=gw.get_ymax();
  double d=xmax-xmin;
  if (d > ymax-ymin) { d=(d-ymax+ymin)/2; xmin+=d; xmax-=d; }
  else { d=(ymax-ymin-d)/2; ymin+=d; ymax-=d; }
  stretch(G,dest,xmin,ymin,xmax,ymax);
  gw.update_graph();
  gw.set_position(dest);
  gw.embed_edges();
  gw.set_flush(old_flush);
  gw.redraw();
  gw.call_init_graph_handler();
}

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

static void gen_random_graph(GraphWin& gw, void (*f)(graph&,int,int)) {
  if (!gw.check_init_graph_handler()) return;

  int n=gw.get_gen_nodes();
  int e=gw.get_gen_edges();
  if (!gen_dialog(gw,"random ",&n,&e)) return;

  bool old_flush=gw.set_flush(false); 
  gw.clear_graph();
  graph& G=gw.get_graph();
  f(G,gw.get_gen_nodes(),gw.get_gen_edges());
  node_array<point> dest(G);
  embed_random(G,dest);
  stretch(G,dest,gw.get_xmin(),gw.get_ymin(),gw.get_xmax(),gw.get_ymax());
  gw.update_graph();
  gw.set_position(dest);
  gw.embed_edges();
  gw.set_flush(old_flush);
  gw.redraw();
  gw.call_init_graph_handler();
}

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

static void gen_complete_bigraph(graph& G,int a, int b, int, list<node>& A, 
                                                             list<node>& B)
{ complete_bigraph(G,a,b,A,B); }

static void gen_random_bigraph(graph& G,int a, int b, int m, list<node>& A, 
                                                             list<node>& B) 
{ random_bigraph(G,a,b,m,A,B); }

static void gen_bigraph(GraphWin& gw, 
                        void (*f)(graph&,int,int,int,list<node>&,list<node>&)) 
{
  if (!gw.check_init_graph_handler()) return;

  int n=gw.get_gen_nodes();
  int e=gw.get_gen_edges();
  if (f == gen_complete_bigraph) {
    if (!gen_dialog(gw,"complete bi",&n)) return;
  }
  else {
    if (f == gen_random_bigraph) 
      if (!gen_dialog(gw,"random bi",&n,&e)) return;
  }

  n=gw.get_gen_nodes();
  e=gw.get_gen_edges();

  bool old_flush=gw.set_flush(false);
  gw.clear_graph(); 
  graph& G=gw.get_graph();
  list<node> A,B;
  f(G,n/2,n-n/2,gw.get_gen_edges(),A,B);
  node_array<point> dest(G);
  embed_bigraph(A,B,dest);
  stretch(G,dest,gw.get_xmin(),gw.get_ymin(),gw.get_xmax(),gw.get_ymax());
  gw.update_graph();
  gw.set_position(dest);
  gw.embed_edges();
  gw.set_flush(old_flush);
  gw.redraw();
  gw.call_init_graph_handler();
}

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

static void gen_planar_graph(GraphWin& gw, 
              void (*f)(graph&,node_array<double>&,node_array<double>&,int)) 
{
  if (!gw.check_init_graph_handler()) return;

  void (*g)(graph&,node_array<double>&,node_array<double>&,int);

  int n=gw.get_gen_nodes();

  char* s;
  if (f == (g=grid_graph)) s="grid ";
  if (f == (g=random_planar_graph)) s="random planar ";
  if (f == (g=triangulated_planar_graph)) s="triangulated planar ";

  if (!gen_dialog(gw,s,&n)) return;

  bool old_flush=gw.set_flush(false); 
  gw.clear_graph();

  graph& G=gw.get_graph();

  node_array<double> x;
  node_array<double> y;

  n=gw.get_gen_nodes();

  if (f == (g=grid_graph)) n=(int)sqrt((float)n);

  f(G,x,y,n);

  node v=G.first_node();
  if (v != nil) {  
    double xmin=x[v],xmax=x[v],ymin=y[v],ymax=y[v];
    forall_nodes(v,G) {
      if (x[v] < xmin) xmin=x[v]; else if (x[v] > xmax) xmax=x[v];
      if (y[v] < ymin) ymin=y[v]; else if (y[v] > ymax) ymax=y[v];
    }
    if ((xmax != xmin) && (ymax != ymin)) {
      double xmid=(xmin+xmax)/2.0, ymid=(ymin+ymax)/2.0;
      double xd=xmax-xmin;
      double yd=ymax-ymin;
      forall_nodes(v,G) {
        x[v]-=xmid; x[v]/=xd; x[v]+=0.5;
        y[v]-=ymid; y[v]/=yd; y[v]+=0.5;
      }
    }
  }


  stretch(G,x,y,gw.get_xmin(),gw.get_ymin(),gw.get_xmax(),gw.get_ymax());

  if (f == (g=random_planar_graph))
    SPRING_EMBEDDING(G,x,y,gw.get_xmin(),gw.get_xmax(),
                           gw.get_ymin(),gw.get_ymax(),100);

  gw.update_graph();
  gw.set_position(x,y);

  gw.embed_edges();
  gw.set_flush(old_flush);
  gw.redraw();
  gw.call_init_graph_handler();
}

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

static void embed(GraphWin& gw, void (*f)(const graph&, node_array<point>&)) 
{
  if (!gw.check_init_graph_handler()) return;
  graph& G=gw.get_graph();
  node_array<point> dest(G);
  f(G,dest);
  double xmin=gw.get_xmin(),ymin=gw.get_ymin();
  double xmax=gw.get_xmax(),ymax=gw.get_ymax();
  if (f == embed_circular) {
    double d=xmax-xmin;
    if (d > ymax-ymin) { d=(d-ymax+ymin)/2; xmin+=d; xmax-=d; }
    else { d=(ymax-ymin-d)/2; ymin+=d; ymax-=d; }
  }
  stretch(G,dest,xmin,ymin,xmax,ymax);
  gw.remove_bends();
  gw.set_position(dest);
  if (!gw.get_flush()) {
    gw.embed_edges();
    gw.redraw();
  }
  gw.call_init_graph_handler();
}  

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

static void gw_menu_call(GraphWin& gw, gw_void_member_func f) 
{ if (f == &GraphWin::clear_graph && !gw.check_init_graph_handler()) return;
  bool old_flush=gw.set_flush(true);
  gw.call(f);
  gw.set_flush(old_flush); 
  if (f == &GraphWin::clear_graph) gw.call_init_graph_handler();
}

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

static void d_pressed(GraphWin& gw) { gw.set_done_result(done_pressed); }
static void e_pressed(GraphWin& gw) { gw.set_done_result(exit_pressed); }

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

static void gw_test_graph(GraphWin& gw,  bool (*f)(const graph&)) 
{ 
  bool (*g)(const graph&);

  char* s =  "?????";

  g = Is_Simple;
  if (f == g) s = "simple";
  g = Is_Connected;
  if (f == g) s = "connected";
  g = Is_Biconnected;
  if (f == g) s = "biconnected";
  g = Is_Bidirected;
  if (f == g) s = "bidirected";
  g = Is_Bipartite;
  if (f == g) s = "bipartite";
  g = Is_Planar;
  if (f == g) s = "planar";

  if ( f(gw.get_graph()) )
     gw.acknowledge(string("Graph is %s.",s));
  else
     gw.acknowledge(string("Graph is not %s.",s));
}


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

static void gw_make(GraphWin& gw, list<edge> (*f)(graph&)) {
  f(gw.get_graph());
  gw.update_edges();
  if (!gw.get_flush()) {
    gw.embed_edges();
    gw.redraw();
  }
}

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

static void gw_no_loops(GraphWin& gw) {
  if (!Delete_Loops(gw.get_graph()).empty()) {
    gw.update_edges();
    if (!gw.get_flush()) {
      gw.embed_edges();
      gw.redraw();
    }
  }
}

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

static void setup_selected_nodes(GraphWin& gw) 
{ bool old_flush=gw.set_flush(true);
  const list<node>& L=gw.get_selected_nodes();
  if (!L.empty()) 
  { if (!gw_setup(gw,L)) 
      gw.deselect_all_nodes();
   }
  gw.set_flush(old_flush);
}

static void setup_all_nodes(GraphWin& gw) 
{ gw.select_all_nodes();
  setup_selected_nodes(gw);
}

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

static void node_setup(GraphWin& gw) 
{ bool old_flush=gw.set_flush(true);
  list<node> empty_list;
  gw_setup(gw,empty_list);
  gw.set_flush(old_flush);
}

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

static void setup_selected_edges(GraphWin& gw) 
{ bool old_flush=gw.set_flush(true);
  const list<edge>& L=gw.get_selected_edges();
  if (!L.empty()) 
  { if (!gw_setup(gw,L)) 
      gw.deselect_all_edges();
   }
  gw.set_flush(old_flush);
}

static void setup_all_edges(GraphWin& gw) 
{ gw.select_all_edges();
  setup_selected_edges(gw);
}

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

static void edge_setup(GraphWin& gw) {
  bool old_flush=gw.set_flush(true);
  list<edge> empty_list;
  gw_setup(gw,empty_list);
  gw.set_flush(old_flush);
}

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

static void del_all_nodes(GraphWin& gw) { gw.clear_graph(); }

static void del_selected_nodes(GraphWin& gw) 
{ bool b = gw.set_flush(false);
  list<node> L = gw.get_selected_nodes();
  node v;
  forall(v,L) gw.del_node(v);
  gw.redraw();
  gw.set_flush(true);
}

static void del_all_edges(GraphWin& gw) 
{ bool b = gw.set_flush(false);
  list<edge> L = gw.get_graph().all_edges();
  edge e;
  forall(e,L) gw.del_edge(e);
  gw.redraw();
  gw.set_flush(true);
}

static void del_selected_edges(GraphWin& gw) 
{ bool b = gw.set_flush(false);
  list<edge> L = gw.get_selected_edges();
  edge e;
  forall(e,L) gw.del_edge(e);
  gw.redraw();
  gw.set_flush(true);
}


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

void GraphWin::init_menu() {


  if (menu_p != win_p) set_buttons_per_line(buttons_per_line);

  if (menu_mask & M_FILE) {
    int f_menu=gw_add_menu(*this,"File");
    gw_add_simple_call(*this,::gw_load_handler,   "Load Graph ...",f_menu);
    gw_add_simple_call(*this,::gw_save_handler,   "Save Graph ...",f_menu);
    gw_add_simple_call(*this,::gw_save_ps_handler,"Save PsFile ...",f_menu);
    exit_button=gw_add_simple_call(*this,::e_pressed,"Exit",f_menu);
  }

  if (menu_mask & M_EDIT) {

    int edit_menu=gw_add_menu(*this,"Edit");

    int x = gw_add_simple_call(*this,::edge_setup,"Faces",edit_menu);
    sub_menus[edit_menu]->disable_button(x);


    int n_edit_menu=gw_add_menu(*this,"Nodes",edit_menu);

    gw_add_simple_call(*this,::setup_selected_nodes, "selected",
                                                      n_edit_menu);
    gw_add_simple_call(*this,::setup_all_nodes, "existing",
                                                      n_edit_menu);
    gw_add_simple_call(*this,::node_setup,"defaults",n_edit_menu);


    int e_edit_menu=gw_add_menu(*this,"Edges",edit_menu);

    gw_add_simple_call(*this,::setup_selected_edges,"selected",
                                                     e_edit_menu);
    gw_add_simple_call(*this,::setup_all_edges,"existing",
                                                     e_edit_menu);
    gw_add_simple_call(*this,::edge_setup,"defaults",e_edit_menu);



    int s_edit_menu=gw_add_menu(*this,"Selection",edit_menu);

    gw_add_member_call(*this,&GraphWin::select_all_nodes,gw_menu_call,
                                                         "select all nodes",
                                                          s_edit_menu);
    gw_add_member_call(*this,&GraphWin::select_all_edges,gw_menu_call,
                                                         "select all edges",
                                                          s_edit_menu);

    gw_add_member_call(*this,&GraphWin::deselect_all_nodes,gw_menu_call,
                                                         "deselect all nodes",
                                                          s_edit_menu);
    gw_add_member_call(*this,&GraphWin::deselect_all_edges,gw_menu_call,
                                                         "deselect all edges",
                                                          s_edit_menu);
  }


  if (menu_mask & M_GRAPH) {

  int graph_menu = gw_add_menu(*this,"Graph");

  gw_add_member_call(*this,&GraphWin::clear_graph, gw_menu_call, 
                                                   "Clear", 
                                                   graph_menu);

    int gen_menu=gw_add_menu(*this,"Create",graph_menu);

    void (*f0)(graph&,int);
    void (*f1)(graph&,int,int);
    void (*f2)(graph&,node_array<double>&,node_array<double>&,int);
    void (*f3)(graph&,int,int,int,list<node>&,list<node>&);
    f0 = complete_ugraph;
    gw_add_call(*this,f0,gen_circular_graph,"complete graph",gen_menu);
    f1 = random_graph;
    gw_add_call(*this,f1,gen_random_graph,"random graph",gen_menu);
    f3 = gen_complete_bigraph;
    gw_add_call(*this,f3,gen_bigraph,"complete bipartite",gen_menu);
    f3 = gen_random_bigraph;
    gw_add_call(*this,f3,gen_bigraph,"random bipartite",gen_menu);
    f2 = random_planar_graph;
    gw_add_call(*this,f2,gen_planar_graph,"planar graph",gen_menu);
    f2 = triangulated_planar_graph;
    gw_add_call(*this,f2,gen_planar_graph,"triangulated",gen_menu);
    f2 = grid_graph;
    gw_add_call(*this,f2,gen_planar_graph,"grid graph",gen_menu);

   typedef list<edge> edge__list;

   int make_menu=gw_add_menu(*this,"Change",graph_menu);

   edge__list (*f)(graph&);
   gw_add_call(*this,f=Make_Simple,::gw_make,     "make simple",     make_menu);
   gw_add_call(*this,f=Make_Connected,::gw_make,  "make connected",  make_menu);
   gw_add_call(*this,f=Make_Biconnected,::gw_make,"make biconnected",make_menu);
   gw_add_call(*this,f=Make_Bidirected,::gw_make, "make bidirected", make_menu);
   gw_add_simple_call(*this,::gw_no_loops,        "delete loops",    make_menu);

int test_menu=gw_add_menu(*this,"test",make_menu);
int test_menu1=gw_add_menu(*this,"test1",test_menu);
int test_menu2=gw_add_menu(*this,"test2",test_menu);
int test_menu11=gw_add_menu(*this,"test11",test_menu1);
int test_menu12=gw_add_menu(*this,"test12",test_menu1);
int test_menu21=gw_add_menu(*this,"test21",test_menu2);
int test_menu22=gw_add_menu(*this,"test22",test_menu2);

gw_add_call(*this,f=Make_Simple,::gw_make,     "make simple",    test_menu11);
gw_add_call(*this,f=Make_Connected,::gw_make,  "make connected", test_menu11);
gw_add_call(*this,f=Make_Biconnected,::gw_make,"make biconnected",test_menu11);
gw_add_call(*this,f=Make_Bidirected,::gw_make, "make bidirected", test_menu11);

gw_add_call(*this,f=Make_Simple,::gw_make,     "make simple",    test_menu12);
gw_add_call(*this,f=Make_Connected,::gw_make,  "make connected", test_menu12);
gw_add_call(*this,f=Make_Biconnected,::gw_make,"make biconnected",test_menu12);
gw_add_call(*this,f=Make_Bidirected,::gw_make, "make bidirected", test_menu12);

gw_add_call(*this,f=Make_Simple,::gw_make,     "make simple",    test_menu21);
gw_add_call(*this,f=Make_Connected,::gw_make,  "make connected", test_menu21);
gw_add_call(*this,f=Make_Biconnected,::gw_make,"make biconnected",test_menu21);
gw_add_call(*this,f=Make_Bidirected,::gw_make, "make bidirected", test_menu21);

gw_add_call(*this,f=Make_Simple,::gw_make,     "make simple",    test_menu22);
gw_add_call(*this,f=Make_Connected,::gw_make,  "make connected", test_menu22);
gw_add_call(*this,f=Make_Biconnected,::gw_make,"make biconnected",test_menu22);
gw_add_call(*this,f=Make_Bidirected,::gw_make, "make bidirected", test_menu22);


#ifndef __hpuxcc__
  {
    int t_menu=gw_add_menu(*this,"Check",graph_menu);
    bool (*f)(const graph&);
    f = Is_Simple;
    gw_add_call(*this,f,gw_test_graph,"simple",t_menu);
    f = Is_Connected;
    gw_add_call(*this,f,gw_test_graph,"connected",t_menu);
    f = Is_Biconnected;
    gw_add_call(*this,f,gw_test_graph,"biconnected",t_menu);
    f = Is_Bidirected;
    gw_add_call(*this,f,gw_test_graph,"bidirected",t_menu);
    f = Is_Bipartite;
    gw_add_call(*this,f,gw_test_graph,"bipartite",t_menu);
    f = Is_Planar;
    gw_add_call(*this,f,gw_test_graph,"planar",t_menu);
  }
#endif

  int clear_menu=gw_add_menu(*this,"Delete",graph_menu);
  gw_add_simple_call(*this,::del_selected_nodes,"selected nodes", clear_menu);
  gw_add_simple_call(*this,::del_selected_edges,"selected edges", clear_menu);
  gw_add_simple_call(*this,::del_all_nodes,     "all nodes", clear_menu);
  gw_add_simple_call(*this,::del_all_edges,     "all edges", clear_menu);

 }




#if !defined(__WATCOMC__)

  if (menu_mask & M_LAYOUT) {
    int (*f)(graph&,node_array<int>&,node_array<int>&);
    int e_menu=gw_add_menu(*this,"Layout");

    gw_add_simple_call(*this,::snap_to_grid,"Snap To Grid",e_menu);

    gw_add_member_call(*this,&GraphWin::remove_bends,gw_menu_call,
                                                     "Remove Bends", 
                                                      e_menu);


#ifndef __hpuxcc__
    gw_add_call(*this,::embed_circular,::embed,"Circular Layout",e_menu);
    gw_add_call(*this,::embed_random,  ::embed,"Random Layout",e_menu);
#endif

    f = STRAIGHT_LINE_EMBEDDING;
    gw_add_call(*this,f,embed_planar,"Straight Line Planar 1",e_menu);
    f = STRAIGHT_LINE_EMBEDDING2;
    gw_add_call(*this,f,embed_planar,"Straight Line Planar 2",e_menu);
    gw_add_simple_call(*this,  gw_spring_embed,"Spring Embedder (FR)",e_menu);

int x;
x = gw_add_simple_call(*this,gw_spring_embed,"Orthogonal (Tamassia)",e_menu);
sub_menus[e_menu]->disable_button(x);
x = gw_add_simple_call(*this,gw_spring_embed,"DAG Layout (Sugiyama)",e_menu);
sub_menus[e_menu]->disable_button(x);

  }


  if (menu_mask & M_WINDOW) {
    int w_menu=gw_add_menu(*this,"Window");

    gw_add_member_call(*this,&GraphWin::redraw,     "redraw",     w_menu);
    gw_add_simple_call(*this,gw_fill_window, "fill window",w_menu);

/*
    int x=gw_add_member_call(*this,&GraphWin::fill_window,"fill area",w_menu);
    sub_menus[w_menu]->disable_button(x);
*/

    int z_menu=gw_add_menu(*this,"zooming",w_menu);
    gw_add_simple_call(*this,gw_zoom_area, "zoom area", z_menu);
    gw_add_simple_call(*this,gw_zoom_up,   "zoom up",   z_menu);
    gw_add_simple_call(*this,gw_zoom_down, "zoom down", z_menu);
    gw_add_simple_call(*this,gw_unzoom,    "undo",      z_menu);
  }



  if (menu_mask & M_OPTIONS)
  { int o_menu=gw_add_menu(*this,"Options");
    gw_add_simple_call(*this,gw_global_setup,   "General Setup", o_menu);
    gw_add_simple_call(*this,gw_animation_setup,"Animation",     o_menu);
    gw_add_simple_call(*this,::node_setup,      "Node Defaults", o_menu);
    gw_add_simple_call(*this,::edge_setup,      "Edge Defaults", o_menu);
/*
    int x;
    x= gw_add_simple_call(*this,gw_global_setup,"Mouse Setup",o_menu);
    sub_menus[o_menu]->disable_button(x);
    x= gw_add_simple_call(*this,gw_global_setup,"Layout",o_menu);
    sub_menus[o_menu]->disable_button(x);
*/
   }



  if (menu_mask & M_HELP)
  { int h_menu=gw_add_menu(*this,"Help");
    gw_add_member_call(*this,&GraphWin::help_about,       "About GraphWin",
                                                                        h_menu);
    gw_add_member_call(*this,&GraphWin::help_mouse_left,  "Mouse Button 1", 
                                                                        h_menu);
    gw_add_member_call(*this,&GraphWin::help_mouse_middle,"Mouse Button 2",
                                                                        h_menu);
    gw_add_member_call(*this,&GraphWin::help_mouse_right, "Mouse Button 3",
                                                                        h_menu);
   }
 
#endif


  if (menu_mask & M_DONE)
    done_button=gw_add_simple_call(*this,::d_pressed,"done");

  if (menu_p == win_p) menu_p->make_menu_bar();

}


