/* -*-C-*-
********************************************************************************
*
* File:         gtest.c
* RCS:          $Header: gtest.c,v 1.3 92/08/19 19:01:01 itosupt Exp $
* Description:  Test file for Graph widget
* Author:
* Created:      Thu Mar  8 10:11:44 1990
* Modified:
* Language:     C
* Package:      N/A
* Status:       Experimental (Do Not Distribute)
*
* Copyright (c) 1988 by Hewlett-Packard Company
* 
* Permission to use, copy, modify, and distribute this software 
* and its documentation for any purpose and without fee is hereby 
* granted, provided that the above copyright notice appear in all 
* copies and that both that copyright notice and this permission 
* notice appear in supporting documentation, and that the name of 
* Hewlett-Packard not be used in advertising or publicity pertaining 
* to distribution of the software without specific, written prior 
* permission.
*
********************************************************************************
*/

#include <Xm/Xm.h>
#include <Xm/PushBG.h>
#include <Xm/ToggleBG.h>
#include <Xm/PanedW.h>
#include <Xm/Label.h>
#include <Xm/Separator.h>
#include <Xm/Form.h>
#include <Xm/RowColumn.h>
#include "Graph.h"
#include "Arc.h"

Widget TheGraph, ThePanel, TheCommandPane;
Widget CreateGraph();

Pixel    get_pixel_by_name();

Boolean allow_edits = TRUE;


typedef struct {
   char       *name;
   void      (*func)();
   Boolean     set;
 } ButtonsAndCommands;

/*
 * Callbacks for the Graph widget.
 */

void new_node (w, client_data, calldata)
     Widget          w;
     XtPointer         client_data;
     XtPointer         calldata;
{
     XmGraphCallbackStruct    *call_data =( XmGraphCallbackStruct    *)calldata;
  XmString xmstr;
  char str[100];
  static int count = 0;
  Arg wargs[10];

  if(!allow_edits) {
      call_data->doit = FALSE;
      XBell(XtDisplay(w), 100);
      return;
    }

  sprintf(str, "Node Number %d", count++);
  xmstr =  XmStringLtoRCreate(str, XmSTRING_DEFAULT_CHARSET);
  XtSetArg(wargs[0], XmNlabelString, xmstr);
  XtSetValues(call_data->widget, wargs, 1);

  XmStringFree(xmstr);
}

void new_arc (w, client_data, calldata)
     Widget          w;
     XtPointer         client_data;
     XtPointer         calldata;
{ XmGraphCallbackStruct    *call_data = (XmGraphCallbackStruct    *)calldata;
  Arg wargs[10];
  if(!allow_edits) {
      call_data->doit = FALSE;
      XBell(XtDisplay(w), 100);
      return;
    }

  XtSetArg(wargs[0], XmNforeground, get_pixel_by_name(TheGraph, "Orange"));
  XtSetValues(call_data->widget, wargs, 1);

  printf("New Arc Created\n");

}

void node_moved (w, client_data, call_data)
     Widget          w;
     XtPointer         client_data;
     XtPointer    call_data;
{
  printf("Node Moved\n");
}

void arc_moved (w, client_data, calldata)
     Widget          w;
     XtPointer         client_data;
     XtPointer         calldata;
{
     XmGraphCallbackStruct    *call_data =(XmGraphCallbackStruct *)calldata;
  if(!allow_edits) {
      call_data->doit = FALSE;
      XBell(XtDisplay(w), 100);
      return;
    }
  printf("Arc Moved\n");
}

void double_click (w, client_data, calldata)
     Widget          w;
     XtPointer         client_data;
     XtPointer         calldata;
{ XmGraphCallbackStruct    *call_data =( XmGraphCallbackStruct *)calldata;
  Arg wargs[10];

  if(call_data->reason == XmCR_NODE_DOUBLE_CLICK) 
    {
      XmGraphUnselectNode(TheGraph, call_data->widget);
      printf("Double Click on Node\n");
    }
  else if(call_data->reason == XmCR_ARC_DOUBLE_CLICK) 
    {
      printf("Double Click on Arc\n");
      XmGraphUnselectArc(TheGraph, call_data->widget);
    }
  else if(call_data->reason == XmCR_DOUBLE_CLICK)
    printf("Double Click on Graph\n");
  else 
    printf("Error in Double Click\n");

}

void select_node (w, client_data, call_data)
     Widget          w;
     XtPointer         client_data;
     XtPointer    call_data;
{
  printf("Node Selected\n");
}

void select_arc (w, client_data, call_data)
     Widget          w;
     XtPointer        client_data;
     XtPointer    call_data;
{
  printf("Arc Selected\n");
}


void deselect (w, client_data, call_data)
     Widget          w;
     XtPointer         client_data;
     XtPointer         call_data;
{
  printf("Deselect\n");
}

void select_subgraph (w, client_data, call_data)
     Widget          w;
     XtPointer         client_data;
     XtPointer    call_data;
{
  printf("SubGraph Selected\n");
}


/*
 * Callbacks on nodes and arcs.
 */

void arm_me (w, client_data, call_data)
     Widget          w;
     XtPointer         client_data;
     XtPointer call_data;
{
  printf("arming\n");
}

void disarm_me (w, client_data, call_data)
     Widget          w;
     XtPointer         client_data;
     XtPointer call_data;
{
  printf("disarming\n");
}

void activate_me (w,client_data, call_data)
     Widget          w;
     XtPointer        client_data;
     XtPointer call_data;
{
  printf("activating\n");
}

/*
 * Option Callbacks
 */

void allow_edits_to_happen (w, client_data, call_data)
     Widget          w;
     caddr_t         client_data;
     XmToggleButtonCallbackStruct *call_data;
{
  allow_edits = call_data->set;
}

void edit_mode (w, client_data, call_data)
     Widget          w;
     caddr_t         client_data;
     XmToggleButtonCallbackStruct *call_data;
{
  Arg wargs[2];
  
  if(call_data->set)
    XtSetArg (wargs[0], XmNeditable, TRUE);
  else
    XtSetArg (wargs[0], XmNeditable, FALSE);

  XtSetValues (TheGraph, wargs, 1);
}

void allow_multiple_selections (w, client_data, call_data)
     Widget          w;
     caddr_t         client_data;
     XmToggleButtonCallbackStruct *call_data;
{
  Arg wargs[2];
  
  if(call_data->set)
    XtSetArg (wargs[0], XmNallowMultipleSelections, TRUE);
  else
    XtSetArg (wargs[0], XmNallowMultipleSelections, FALSE);

  XtSetValues (TheGraph, wargs, 1);
}


void show_crossing (w, client_data, call_data)
     Widget          w;
    caddr_t          client_data;
     XmToggleButtonCallbackStruct *call_data;
{
  Arg wargs[2];
  
  if(call_data->set)
    XtSetArg (wargs[0], XmNshowCrossingArcs, TRUE);
  else
    XtSetArg (wargs[0], XmNshowCrossingArcs, FALSE);

  XtSetValues (TheGraph, wargs, 1);
}

void moveable_nodes (w, client_data, call_data)
     Widget          w;
    caddr_t          client_data;
     XmToggleButtonCallbackStruct *call_data;
{
  Arg wargs[2];
  
  if(call_data->set)
    XtSetArg (wargs[0], XmNmovableNodes, TRUE);
  else
    XtSetArg (wargs[0], XmNmovableNodes, FALSE);

  XtSetValues (TheGraph, wargs, 1);
}

char * names[] = {"NEVER", "ALWAYS", "ARCS_ONLY", "NODES_ONLY", "PARTIAL"};

void auto_layout (w, client_data, call_data)
     Widget          w;
     XtPointer          client_data;
     XtPointer call_data;
{
  static int count = 0;
  Arg wargs[2];
  Arg b_args[2];
  XmString xmstr;

  switch(count)
    {
    case 0:
    XtSetArg (wargs[0], XmNautoLayoutMode, XmALWAYS);

    xmstr =  XmStringLtoRCreate("AutoLayoutMode: ALWAYS", XmSTRING_DEFAULT_CHARSET);
    XtSetArg(b_args[0], XmNlabelString, xmstr);
    XtSetValues(w, b_args, 1);
    count = 1;
    break;
 case 1:
    XtSetArg (wargs[0], XmNautoLayoutMode, XmARCS_ONLY);

    xmstr =  XmStringLtoRCreate("AutoLayoutMode: ARCS ONLY", XmSTRING_DEFAULT_CHARSET);
    XtSetArg(b_args[0], XmNlabelString, xmstr);
    XtSetValues(w, b_args, 1);
    count = 2;
    break;
 case 2:
  XtSetArg (wargs[0], XmNautoLayoutMode, XmNODES_ONLY);
    xmstr =  XmStringLtoRCreate("AutoLayoutMode: NODES ONLY", XmSTRING_DEFAULT_CHARSET);
    XtSetArg(b_args[0], XmNlabelString, xmstr);
    XtSetValues(w, b_args, 1);
    count = 3;
    break;
 case 3:
  XtSetArg (wargs[0], XmNautoLayoutMode, XmPARTIAL);
    xmstr =  XmStringLtoRCreate("AutoLayoutMode: PARTIAL", XmSTRING_DEFAULT_CHARSET);
    XtSetArg(b_args[0], XmNlabelString, xmstr);
    XtSetValues(w, b_args, 1);
    count = 4;
    break;
 case 4:
  XtSetArg (wargs[0], XmNautoLayoutMode, XmNEVER);
    xmstr =  XmStringLtoRCreate("AutoLayoutMode: NEVER", XmSTRING_DEFAULT_CHARSET);
    XtSetArg(b_args[0], XmNlabelString, xmstr);
    XtSetValues(w, b_args, 1);
    count = 0;
    break;
 default:
    XtSetArg (wargs[0], XmNautoLayoutMode, XmNEVER);
    xmstr =  XmStringLtoRCreate("AutoLayoutMode: NEVER", XmSTRING_DEFAULT_CHARSET);
    XtSetArg(b_args[0], XmNlabelString, xmstr);
    XtSetValues(w, b_args, 1);
    count = 0;
    break;
  }
  XtSetValues (TheGraph, wargs, 1);
}


void twins_visible (w, client_data, call_data)
     Widget          w;
     caddr_t         client_data;
     XmToggleButtonCallbackStruct *call_data;
{
  Arg wargs[2];
  
  if(call_data->set)
    XtSetArg (wargs[0], XmNtwinsVisible, TRUE);
  else
    XtSetArg (wargs[0], XmNtwinsVisible, FALSE);

  XtSetValues (TheGraph, wargs, 1);
}

void arc_draw_mode (w, client_data, call_data)
     Widget          w;
     caddr_t         client_data;
     XmToggleButtonCallbackStruct *call_data;
{
  Arg wargs[2];
  
  if(call_data->set)
    XtSetArg (wargs[0], XmNarcDrawMode, XmPOSITION_FIXED);
  else
    XtSetArg (wargs[0], XmNarcDrawMode, XmPOSITION_RELATIVE);

  XtSetValues (TheGraph, wargs, 1);
}

/*
 * Arc Options: affect current selected arc.
 */


void  change_foreground(w, client_data, call_data)
     Widget w;
     caddr_t client_data;
     XmToggleButtonCallbackStruct *call_data;
{
  WidgetList arcs;
  int num, i;  
  Arg wargs[10];

  arcs = XmGraphGetSelectedArcs(TheGraph,  &num);
 
  for(i=0;i<num;i++) 
    {
      if(call_data->set) 
	{
	  XtSetArg (wargs[0], XmNforeground, get_pixel_by_name(TheGraph, "White"));
	  XtSetValues (arcs[i], wargs, 1);
	}
      else
	{
	  XtSetArg (wargs[0], XmNforeground, get_pixel_by_name(TheGraph, "Black"));
	  XtSetValues (arcs[i], wargs, 1);
	}
    }
}

void  change_highlight(w, client_data, call_data)
     Widget w;
     caddr_t client_data;
     XmToggleButtonCallbackStruct *call_data;
{
  WidgetList arcs;
  int num, i;  
  Arg wargs[10];

  arcs =   XmGraphGetSelectedArcs(TheGraph, &num);
 
  for(i=0;i<num;i++) 
    {
      if(call_data->set) 
	{
	  XtSetArg (wargs[0], XmNhighlightColor,  get_pixel_by_name(TheGraph, "Red"));
	  XtSetValues (arcs[i], wargs, 1);
	}
      else
	{
	  XtSetArg (wargs[0], XmNhighlightColor, get_pixel_by_name(TheGraph, "Green"));
	  XtSetValues (arcs[i], wargs, 1);
	}
    }
}

void  map_label(w, client_data, call_data)
     Widget w;
     caddr_t client_data;
     XmToggleButtonCallbackStruct *call_data;
{

  WidgetList arcs;
  int num, i;  
  Arg wargs[10];

  arcs = XmGraphGetSelectedArcs(TheGraph,  &num);
 
  for(i=0;i<num;i++) 
    {
      if(call_data->set) 
	{
	  XtSetArg (wargs[0], XmNmapLabel, TRUE);
	  XtSetValues (arcs[i], wargs, 1);
	}
      else
	{
	  XtSetArg (wargs[0], XmNmapLabel, FALSE);
	  XtSetValues (arcs[i], wargs, 1);
	}
    }
}

void  default_width(w, client_data, call_data)
     Widget w;
     caddr_t client_data;
     XmToggleButtonCallbackStruct *call_data;
{
  WidgetList arcs;
  int num, i;  
  Arg wargs[10];


  arcs = XmGraphGetSelectedArcs(TheGraph, &num);
 
  for(i=0;i<num;i++) 
    {
      if(call_data->set) 
	{
	  XtSetArg (wargs[0], XmNarcWidth, 1);
	  XtSetValues (arcs[i], wargs, 1);
	}
      else
	{
	  XtSetArg (wargs[0], XmNarcWidth, 4);
	  XtSetValues (arcs[i], wargs, 1);
	}
    }
}

void  default_style(w, client_data, call_data)
     Widget w;
     caddr_t client_data;
     XmToggleButtonCallbackStruct *call_data;
{
  WidgetList arcs;
  int num, i;  
  Arg wargs[10];

  arcs = XmGraphGetSelectedArcs(TheGraph,  &num);
 
  for(i=0;i<num;i++) 
    {
      if(call_data->set) 
	{
	  XtSetArg (wargs[0],  XmNstyle, LineSolid);
	  XtSetValues (arcs[i], wargs, 1);
	}
      else
	{
	  XtSetArg (wargs[0],  XmNstyle, LineOnOffDash);
	  XtSetValues (arcs[i], wargs, 1);
	}
    }
}


/*
 * Commands Callbacks
 */

void print_graph (w, client_data, call_data)
     Widget              w;
     caddr_t             client_data;
     XmAnyCallbackStruct *call_data;
{
/*  PrintGraph(TheGraph); */
}

void add_new_node (w, client_data, call_data)
     Widget              w;
     caddr_t             client_data;
     XmAnyCallbackStruct *call_data;
{
  XmGraphAddNode(TheGraph);
}

void destroy_all_arcs (w, client_data, call_data)
     Widget              w;
     caddr_t             client_data;
     XmAnyCallbackStruct *call_data;
{
  XmGraphDestroyAllArcs(TheGraph);
}

void destroy_all_nodes (w, client_data, call_data)
     Widget              w;
     caddr_t             client_data;
     XmAnyCallbackStruct *call_data;
{
  XmGraphDestroyAllNodes(TheGraph);
}


void relay_subgraph (w, client_data, call_data)
     Widget              w;
     caddr_t             client_data;
     XmAnyCallbackStruct *call_data;
{
  WidgetList nodes;
  int num, i;  

  nodes = XmGraphGetSelectedNodes(TheGraph, &num);
 
  for(i=0;i<num; i++)
    XmGraphRelaySubgraph(TheGraph, nodes[i]);

}

void zoom (w, client_data, call_data)
     Widget          w;
     caddr_t         client_data;
     XmAnyCallbackStruct *call_data;
{
  XmGraphZoom(TheGraph, 2.0);
/*  Arg wargs[2];
  short cs, ss;
  XtSetArg (wargs[0], XmNchildSpacing,   &cs);
  XtSetArg (wargs[1], XmNsiblingSpacing, &ss);
  XtGetValues (TheGraph, wargs, 2);

  XtSetArg (wargs[0], XmNchildSpacing,   cs * 2 + 1);
  XtSetArg (wargs[1], XmNsiblingSpacing, ss * 2 + 1);
  XtSetValues (TheGraph, wargs, 2); */
}

void unzoom (w, client_data, call_data)
     Widget          w;
     caddr_t         client_data;
     XmAnyCallbackStruct *call_data;
{
/*  Arg wargs[2];
  short cs, ss;
  
  XtSetArg (wargs[0], XmNchildSpacing, &cs);
  XtSetArg (wargs[1], XmNsiblingSpacing, &ss);
  XtGetValues (TheGraph, wargs, 2);

  XtSetArg (wargs[0], XmNchildSpacing,   cs );
  XtSetArg (wargs[1], XmNsiblingSpacing, ss);
  XtSetValues (TheGraph, wargs, 2);
*/
  XmGraphZoom(TheGraph, -2.0);
}


void center_graph (w, client_data, call_data)
     Widget          w;
     caddr_t         client_data;
     XmGraphCallbackStruct    *call_data;
{
  WidgetList nodes;
  int num, i;  

  nodes = XmGraphGetSelectedNodes(TheGraph, &num);

  if(num == 1)
    XmGraphCenterAroundWidget(TheGraph, nodes[0]);

}

void destroy_graph (w, panel, call_data)
     Widget          w;
     Widget          panel;
     XmGraphCallbackStruct    *call_data;
{
  XtDestroyWidget(TheGraph);
  TheGraph = NULL;
}

void new_graph (w, panel, call_data)
     Widget          w;
     Widget          panel;
     XmGraphCallbackStruct    *call_data;
{
  Arg wargs[10];
  int n;

  if (TheGraph)
    return;

  TheGraph = CreateGraph(ThePanel);
  n = 0;
  XtSetArg(wargs[n], XmNtopAttachment,   XmATTACH_FORM);  n++;
  XtSetArg(wargs[n], XmNbottomAttachment,XmATTACH_FORM);  n++;
  XtSetArg(wargs[n], XmNleftAttachment,  XmATTACH_WIDGET);n++;
  XtSetArg(wargs[n], XmNleftWidget,      TheCommandPane); n++;
  XtSetArg(wargs[n], XmNrightAttachment, XmATTACH_FORM); n++;
  XtSetValues(XtParent(XtParent(TheGraph)), wargs, n);
}

void re_orient (w, client_data, call_data)
     Widget        w;
     caddr_t       client_data;
     caddr_t       call_data;
{
    Arg wargs[2];

    XtSetArg (wargs[0], XmNreorient, True);
    XtSetValues (TheGraph, wargs, 1);
}

void delete_widget (w, client_data, call_data)
     Widget          w;
    caddr_t client_data;
     caddr_t         call_data;
{
  XmGraphDestroySelectedArcsOrNodes (TheGraph);
}

void delete_and_relay (w, client_data, call_data)
     Widget          w;
    caddr_t client_data;
     caddr_t         call_data;
{
  XmGraphDestroySelectedArcsOrNodes (TheGraph);
  XmGraphLayout (TheGraph);
}

void re_layout (w, client_data, call_data)
     Widget      w;
     caddr_t     client_data;
     caddr_t     call_data;
{
    Arg wargs[2];
    XmGraphLayout(TheGraph);
}

void quit (w, client_data, call_data)
     Widget          w;
     caddr_t         client_data;
     caddr_t         call_data;
{
  exit(0);
}


main (argc, argv)
    Cardinal   argc;
    char  *argv[];
  {
    Widget  toplevel, sep;
    Arg     wargs[10];
    int     n;

    toplevel = XtInitialize (argv[0], "Gtest", NULL, 0, &argc, argv);

    ThePanel = XmCreateForm (toplevel, "panel", NULL, 0);
    TheCommandPane = XmCreateRowColumn (ThePanel, "command", NULL, 0);

    XtCreateManagedWidget("Graph Options", xmLabelWidgetClass, TheCommandPane, NULL, 0);

    create_options_buttons(TheCommandPane);

    sep = XmCreateSeparator(TheCommandPane, "sep1", NULL, 0);

    XtManageChild(sep);

    XtCreateManagedWidget("Selected Arc Options", xmLabelWidgetClass, TheCommandPane, NULL, 0);
    create_arc_options_buttons(TheCommandPane);

    sep = XmCreateSeparator(TheCommandPane, "sep2", NULL, 0);

    XtManageChild(sep);

    XtCreateManagedWidget("Graph Commands", xmLabelWidgetClass, TheCommandPane, NULL, 0);
    create_command_buttons(TheCommandPane);

    TheGraph = CreateGraph(ThePanel);


    n = 0;
    XtSetArg(wargs[n], XmNtopAttachment,    XmATTACH_FORM);n++;
    XtSetArg(wargs[n], XmNbottomAttachment, XmATTACH_FORM);n++;
    XtSetArg(wargs[n], XmNleftAttachment,   XmATTACH_FORM);n++;
    XtSetValues(TheCommandPane, wargs, n);
    
    n = 0;
    XtSetArg(wargs[n], XmNtopAttachment,   XmATTACH_FORM);  n++;
    XtSetArg(wargs[n], XmNbottomAttachment,XmATTACH_FORM);  n++;
    XtSetArg(wargs[n], XmNleftAttachment,  XmATTACH_WIDGET);n++;
    XtSetArg(wargs[n], XmNleftWidget,      TheCommandPane); n++;
    XtSetArg(wargs[n], XmNrightAttachment, XmATTACH_FORM); n++;
    XtSetValues(XtParent(XtParent(TheGraph)), wargs, n);

    XtManageChild (TheCommandPane);
    XtManageChild (ThePanel);

    XtRealizeWidget (toplevel);
    XtMainLoop(); 
}

ButtonsAndCommands command_buttons[] = {
  {"Quit",            quit, NULL},
  {"Reorient",        re_orient,},
  {"Relay",           re_layout,},
  {"Add Node",        add_new_node,},
  {"Delete Arc/Node", delete_widget,},
  {"Delete and Relay",delete_and_relay,},
  {"Center Graph",    center_graph,},
  {"Destroy Graph",   destroy_graph,},
  {"New Graph",       new_graph,},
  {"Zoom In",         zoom,},
  {"Zoom Out",        unzoom,},
  {"Destroy All Arcs",destroy_all_arcs},
  {"Destroy All Nodes",destroy_all_nodes,},
  {"Relay Subgraph",  relay_subgraph},
  {"Print Graph",     print_graph},
};

create_command_buttons(parent)
     Widget parent;
{
  int    i;
  Widget panel = parent;

  for(i=0; i< XtNumber(command_buttons) ; i++) 
    {
      Widget button = XmCreatePushButtonGadget (panel, command_buttons[i].name, NULL, 0);
      XtAddCallback (button,   XmNactivateCallback, command_buttons[i].func, NULL);
      XtManageChild (button);
    }
  XtManageChild(panel);
}


ButtonsAndCommands option_buttons [] =  {
  {"Edit Mode",           edit_mode,      TRUE},
  {"Show Crossing Arcs",  show_crossing,  TRUE},
  {"Movable Nodes",       moveable_nodes, TRUE},
  {"Twins Visible",       twins_visible,  FALSE},
  {"Arc Draw Fixed",      arc_draw_mode,  FALSE},
  {"Allow Multiple Selections",  allow_multiple_selections, TRUE},
  {"Allow Edits (test)",  allow_edits_to_happen, TRUE},
};

create_options_buttons(parent)
     Widget parent;
{
  int i;
  Widget panel = parent;

  Widget button = XmCreatePushButtonGadget (panel, "AutoLayoutMode: NEVER       ", NULL, 0);
  XtAddCallback (button,   XmNactivateCallback, auto_layout, NULL);
  XtManageChild (button);

  for(i=0; i< XtNumber(option_buttons) ; i++) 
    {
      Arg wargs[2];
      Widget button;
      XtSetArg(wargs[0], XmNset, option_buttons[i].set);
      button = XmCreateToggleButtonGadget (panel, option_buttons[i].name, wargs, 1);
      XtAddCallback (button, XmNvalueChangedCallback, option_buttons[i].func, NULL);
      XtManageChild (button);
    }


  XtManageChild(panel);
}


ButtonsAndCommands arc_option_buttons [] =  {
  {"White Foreground",  change_foreground,   TRUE},
  {"Red Highlight",     change_highlight,    TRUE},
  {"Map Label",         map_label,           TRUE},
  {"Thin Line",         default_width,       TRUE},
  {"Line Solid",        default_style,       TRUE},
};

create_arc_options_buttons(parent)
     Widget parent;
{
  int i; 
  Widget panel = parent;
  for(i=0; i< XtNumber(arc_option_buttons) ; i++) 
    {
      Arg wargs[2];
      Widget button;
      XtSetArg(wargs[0], XmNset, arc_option_buttons[i].set);
      button = XmCreateToggleButtonGadget (panel, arc_option_buttons[i].name, wargs, 1);
      XtAddCallback (button, XmNvalueChangedCallback, arc_option_buttons[i].func, NULL);
      XtManageChild (button);
    }
  XtManageChild(panel);
}


Widget CreateGraph(parent)
     Widget parent;
{
  Widget graph;
  int    n = 0, i = 0;
  Arg    wargs[10];
  WidgetList arcs;
  Widget nodes [100];
  int    num_nodes = 0, num_arcs = 0;

  XtSetArg (wargs[n], XmNeditable, TRUE); n++;  
  XtSetArg (wargs[n], XmNshowCrossingArcs, TRUE); n++;  
  XtSetArg (wargs[n], XmNmovableNodes, TRUE); n++;  
/*  XtSetArg (wargs[n], XmNautoLayoutMode, FALSE); n++;   */
  XtSetArg (wargs[n], XmNtwinsVisible, FALSE); n++;  
  XtSetArg (wargs[n], XmNarcDrawMode, XmPOSITION_RELATIVE); n++;  
  graph = XmCreateScrolledGraph (parent, "graph", wargs, n);
  
  XmAddTabGroup(graph);
  
  XtAddCallback (graph, XmNnewNodeCallback,       new_node,     NULL);
  XtAddCallback (graph, XmNnewArcCallback,        new_arc,      NULL);
  XtAddCallback (graph, XmNnodeMovedCallback,     node_moved,   NULL);
  XtAddCallback (graph, XmNarcMovedCallback,      arc_moved,    NULL);
  XtAddCallback (graph, XmNdefaultActionCallback, double_click, NULL);
  XtAddCallback (graph, XmNselectNodeCallback,    select_node,  NULL);
  XtAddCallback (graph, XmNselectArcCallback,     select_arc,   NULL);
  XtAddCallback (graph, XmNdeselectCallback,      deselect,     NULL);
  XtAddCallback (graph, XmNselectSubgraphCallback,select_subgraph, NULL);
  
  /***********************************************
    
    Create the nodes and arcs
    
    **********************************************/
  
  
  for(i = 0; i < 8; i++ )
    {
      char buf[10];
      sprintf(buf, "Node %d", i);
      nodes [i] =  XmCreatePushButtonGadget (graph, buf, NULL, 0); 
    }
  num_nodes = i;
  
  
  n = 0;
  XtSetArg (wargs[n], XmNarcDirection, XmBIDIRECTED); n++;
  XtSetArg (wargs[n], XmNmapLabel,     FALSE); n++;
  XtSetArg (wargs[n], XmNlabel,        "Arc 1"); n++;
  XtSetArg (wargs[n], XmNto,           nodes[1]); n++;
  XtSetArg (wargs[n], XmNfrom,         nodes[0]); n++;
  XmCreateArc (graph, "A1", wargs, n); 
  
  n = 0;
  XtSetArg (wargs[n], XmNarcDirection, XmBIDIRECTED); n++;
  XtSetArg (wargs[n], XmNlabel,        "Arc 2"); n++;
  XtSetArg (wargs[n], XmNto,           nodes[2]); n++;
  XtSetArg (wargs[n], XmNfrom,         nodes[1] ); n++;
  XmCreateArc (graph, "A2",  wargs, n);
  
  n = 0;
  XtSetArg (wargs[n], XmNarcDirection, XmBIDIRECTED); n++;
  XtSetArg (wargs[n], XmNlabel,        "Arc 3"); n++;
  XtSetArg (wargs[n], XmNto,           nodes[3]); n++;
  XtSetArg (wargs[n], XmNfrom,         nodes[2] ); n++;
  XmCreateArc (graph, "A3", wargs, n); 
  
  n = 0;
  XtSetArg (wargs[n], XmNlabel,        "A4"); n++;
  XtSetArg (wargs[n], XmNto,           nodes[4]); n++;
  XtSetArg (wargs[n], XmNfrom,         nodes[3] ); n++;
  XmCreateArc (graph, "A4", wargs, n); 
  
  
  n = 0;
  XtSetArg (wargs[n], XmNlabel,        "A5"); n++;
  XtSetArg (wargs[n], XmNto,           nodes[5]); n++;
  XtSetArg (wargs[n], XmNfrom,         nodes[3] ); n++;
  XmCreateArc (graph, "A5", wargs, n);
  
  n = 0;
  XtSetArg (wargs[n], XmNlabel,       "A6"); n++;
  XtSetArg (wargs[n], XmNto,          nodes[6]); n++;
  XtSetArg (wargs[n], XmNfrom,        nodes[3] ); n++;
  XmCreateArc (graph, "A6", wargs, n);
  
  n = 0;
  XtSetArg (wargs[n], XmNlabel,       "A7"); n++;
  XtSetArg (wargs[n], XmNto,          nodes[1]); n++;
  XtSetArg (wargs[n], XmNfrom,        nodes[4] ); n++;
  XtCreateWidget ("A7", xmArcWidgetClass, graph, wargs, n); 
  
  n = 0;
  XtSetArg (wargs[n], XmNarcDirection, XmBIDIRECTED); n++;
  XtSetArg (wargs[n], XmNto,           nodes[0]); n++;
  XtSetArg (wargs[n], XmNfrom,         nodes[0]); n++;
  XmCreateArc (graph, "SELF", wargs, n);
  
  n = 0;
  XtSetArg (wargs[n], XmNarcDirection, XmBIDIRECTED); n++;
  XtSetArg (wargs[n], XmNto,           nodes[0]); n++;
  XtSetArg (wargs[n], XmNfrom,         nodes[0]); n++;
  XmCreateArc (graph, "SELF_1", wargs, n);
  
  n = 0;
  XtSetArg (wargs[n], XmNarcDirection, XmBIDIRECTED); n++;
  XtSetArg (wargs[n], XmNto,           nodes[0]); n++;
  XtSetArg (wargs[n], XmNfrom,         nodes[0] ); n++;
  XmCreateArc (graph, "SELF_2", wargs, n); 
  
  n = 0;
  XtSetArg (wargs[n], XmNarcDirection, XmBIDIRECTED); n++;
  XtSetArg (wargs[n], XmNto,           nodes[0]); n++;
  XtSetArg (wargs[n], XmNfrom,         nodes[0] ); n++;
  XmCreateArc (graph, "SELF_3", wargs, n);
  
  n = 0;
  XtSetArg (wargs[n], XmNlabel,        "A8"); n++;
  XtSetArg (wargs[n], XmNto,           nodes[6]); n++;
  XtSetArg (wargs[n], XmNfrom,         nodes[0] ); n++;
  XtCreateWidget ("A8", xmArcWidgetClass, graph, wargs, n); 
  
  arcs =  XmGraphGetArcs (graph,  &num_arcs);
  
  for (i = 0; i < num_arcs; i++) 
    {
      XtAddCallback (arcs[i], XmNarmCallback,      arm_me,      graph);
      XtAddCallback (arcs[i], XmNactivateCallback, activate_me, graph);
      XtAddCallback (arcs[i], XmNdisarmCallback,   disarm_me,   graph);
    }
  
  
  for (i = 0; i < num_nodes; i++) {
    XtAddCallback (nodes[i], XmNactivateCallback, activate_me, graph);
    XtAddCallback (nodes[i], XmNarmCallback,      arm_me,      graph);
    XtAddCallback (nodes[i], XmNdisarmCallback,   disarm_me,   graph);
  }
  
  XtManageChildren(nodes, num_nodes); 
  XtManageChildren(arcs, num_arcs); 
  XtManageChild(graph);

  return graph;
 }


Pixel get_pixel_by_name(w, colorname)
   Widget w;
   char  *colorname;
{
  Display *dpy  = XtDisplay(w);
  int      scr  = DefaultScreen(dpy);
  Colormap cmap = DefaultColormap(dpy, scr);
  XColor   color, ignore;
  /* 
   * Allocate the named color.
   */
  if(XAllocNamedColor(dpy, cmap, colorname, &color, &ignore))
    return (color.pixel);
  else{
    printf("Warning: Couldn't allocate color %s\n", colorname);
    return (BlackPixel(dpy, scr));
  }
}
