/* buttons.c */

#include "ml.h"


#ifdef __STDC__
ButtonList *new_buttonlist(void)
#else
ButtonList *new_buttonlist()
#endif
{
  ButtonList *buttonlist = (ButtonList *) fs_get(sizeof(ButtonList));
  buttonlist->w = NULL;
  buttonlist->state = 0L;
  buttonlist->next = NULL;
  return(buttonlist);
}

#ifdef __STDC__
void free_buttonlist(ButtonList *buttonlist)
#else
void free_buttonlist(buttonlist)
     ButtonList *buttonlist;
#endif
{
  if(buttonlist == NULL)
    return;
  free_buttonlist(buttonlist->next);
  fs_give((void **) &buttonlist);
  return;
}


/* 
 * A window flush is added to each button callback so that 
 * we can debug the program. Otherwise, the button retains focus
 * after breakpoints, and the debugger can't get input.
 */


#ifdef __STDC__
void flush_windows(Widget w, XtPointer xp, XtPointer cb)
#else
void flush_windows(w,xp,cb) 
     Widget w;
     XtPointer xp;
     XtPointer cb;
#endif
{
  XFlush(display);
}


#ifdef __STDC__ 
void make_pbuttons(Widget rowcol, Button_Menu *button_menu, 
		   unsigned long state, XtPointer callback)
#else
void make_pbuttons(rowcol, button_menu, state, callback)
     Widget rowcol;
     Button_Menu *button_menu;
     unsigned long state;
     XtPointer callback;
#endif
{
  Arg args[ARGLISTSIZE];
  int n = 0;
  Button_Menu *bmenu;
  Dimension height = 0;

  for(bmenu = button_menu; bmenu; bmenu = bmenu->next) {
    if(bmenu->label) {
      XtSetArg(args[n], XmNtraversalOn, FALSE); n ++;
      if(state &  bmenu->statemap) {
	XtSetArg(args[n],XmNsensitive, FALSE); n ++;
      }
      bmenu->widget =  XmCreatePushButton(rowcol, bmenu->label, args, n);
      n = 0;
      XtManageChild(bmenu->widget);
      if(height == 0)
	XtVaGetValues(bmenu->widget, XmNheight, &height, NULL);
      else
	XtVaSetValues(bmenu->widget, XmNheight, height, NULL);
      XtAddCallback(bmenu->widget,XmNactivateCallback, flush_windows, NULL );
      XtAddCallback(bmenu->widget,XmNactivateCallback, bmenu->func, callback);
    }
  }

}


#ifdef __STDC__ 
void make_secondbuttons(ButtonList *bl,
			Widget rowcol, 
			Button_Menu *button_menu,
			int total,
			ButtonState state, 
			XtPointer callback)
#else
void make_secondbuttons(bl, rowcol, button_menu, total, state, callback)
     ButtonList *bl;
     Widget rowcol;
     Button_Menu *button_menu;
     int total;
     unsigned long state;
     XtPointer callback;
#endif
{
  Arg args[ARGLISTSIZE];
  int n = 0;
  int count = 0;
  ButtonList *buttonlist;
  ButtonList *prev;

  for(count = 0; count < total; count ++) {
    buttonlist = new_buttonlist();
    for(prev = bl; prev->next; prev = prev->next)
      ;
    prev->next = buttonlist;
    buttonlist->state = button_menu[count].statemap;
    if(button_menu[count].label) {
      XtSetArg(args[n], XmNborderWidth, 0);           n ++;
      XtSetArg(args[n], XmNtraversalOn, FALSE); n ++;
      if(state &  button_menu[count].statemap) {
	XtSetArg(args[n],XmNsensitive, FALSE); n ++;
      }
      buttonlist->w = XmCreatePushButton(rowcol, 
					 button_menu[count].label, 
					 args, 
					 n);
      n = 0;
      XtManageChild(buttonlist->w);
      XtAddCallback(buttonlist->w,XmNactivateCallback, 
		    flush_windows, NULL );
      XtAddCallback(buttonlist->w,XmNactivateCallback, 
		    button_menu[count].func, callback);
    }
  }
  return;
}













/*
 * void create_buttons();
 *
 * Creates cascading menus on a menubar (parent widget must be a menubar).
 * If a menulist item already contains a callback data item it will
 * be used. Otherwise the data passed to the function will be used.
 * A button name containing the string "HELP" will be set up on the
 * right hand side of the menubar. Names _should_ be unique. This allows
 * us to track down the buttons later and change their state or callback,
 * regardless of the label -- which may have been changed.
 * Button state is determined by the menulist->state variable. Each bit
 * indicates a condition this button should be checked against ( a '1' bit
 * indicates the button should be insensitive when the condition matches.
 * The state variable passed to this function is used to determine initial 
 * sensitive state. 
 * Actually this function is overkill. But it does all the work of managing
 * buttons. I've had to abandon some of the functionality in order to
 * provide internationalization and customization. It's there if I ever need
 * hyper linked buttons which can change state and function at will. 
 */

#ifdef __STDC__
void create_buttons(char *name, Widget menu, 
		    Menu *menulist, int size,
		    unsigned long state, XtPointer callback, int level)
#else
void create_buttons(name, menu, menulist, size, state, callback, level )
     char *name;
     Widget menu;
     Menu *menulist;
     int size;
     unsigned long state;
     XtPointer callback;
     int level;
#endif
{
  Arg args[ARGLISTSIZE];
  int n = 0;
  int cnt;
  WidgetList buttons;
  XmString label;
  char buffer[256];

  buttons = (WidgetList) XtMalloc(size * sizeof(Widget));

  for(cnt = 0; cnt < size; cnt ++) {
    if(menulist[cnt].func) {
      if(menulist[cnt].label) {
	label = XmStringCreateSimple(menulist[cnt].label);
	XtSetArg(args[n], XmNlabelString, label); n ++;
      }
      XtSetArg(args[n], XmNborderWidth, 0); n ++;
      if(menulist[cnt].mnemonic) {
	XtSetArg(args[n], XmNmnemonic, menulist[cnt].mnemonic); n ++;
      }
      if(state &  menulist[cnt].statemap) {
	XtSetArg(args[n],XmNsensitive, FALSE); n ++;
      }
      if(level == ROOTMENULEVEL)
	buttons[cnt] = XmCreateCascadeButton(menu, menulist[cnt].name,
					     args,n);
      else
	buttons[cnt] = XmCreatePushButton(menu, menulist[cnt].name, args, n);
      n = 0;
      menulist[cnt].widget = buttons[cnt];
      if(menulist[cnt].label)
	XmStringFree(label);
      XtAddCallback(buttons[cnt],XmNactivateCallback, flush_windows, NULL );
      XtAddCallback(buttons[cnt],XmNactivateCallback, menulist[cnt].func, 
		    (menulist[cnt].data) ? menulist[cnt].data : callback);
    }
    else {
      Widget submenu;
#ifndef NO_TEAROFF
      if(preferences.tear_off == TRUE) {
	XtSetArg(args[n], XmNtearOffModel, XmTEAR_OFF_ENABLED ); n ++;
      }
#endif
      sprintf(buffer,"%s_PDmenu",menulist[cnt].name);
      submenu = XmCreatePulldownMenu(menu,buffer,args,n); n = 0;
      if(menulist[cnt].label) {
	label = XmStringCreateSimple(menulist[cnt].label);
	XtSetArg(args[n], XmNlabelString, label); n ++;
      }
      XtSetArg(args[n], XmNsubMenuId, submenu); n ++;
      XtSetArg(args[n], XmNborderWidth, 0); n ++;
      if(menulist[cnt].mnemonic) {
	XtSetArg(args[n], XmNmnemonic, menulist[cnt].mnemonic); n ++;
      }
      if(state &  menulist[cnt].statemap) {
	XtSetArg(args[n],XmNsensitive, FALSE); n ++;
      }
      buttons[cnt] = XmCreateCascadeButton(menu, menulist[cnt].name, args, n);
      n = 0;
      menulist[cnt].widget = buttons[cnt];
      if(menulist[cnt].label)
	XmStringFree(label);
      create_buttons(menulist[cnt].label, submenu, menulist[cnt].sub_menu,
			  menulist[cnt].size, state, callback, level + 1);
    }
  }
  XtManageChildren(buttons, size);
  for(cnt = 0; cnt < size; cnt ++) {
    if((ML_Strstr(menulist[cnt].name,"HELP")) != NULL) {
      XtSetArg(args[n],XmNmenuHelpWidget, buttons[cnt]); n ++;
      XtSetValues(menu, args, n);
      n = 0;
    }
  }
  return;
}
      




#ifdef __STDC__
void make_buttons(ButtonList **bl, char *name, Widget menu, 
		  Menu *menulist, int size,
		  unsigned long state, XtPointer callback, int level)
#else
void make_buttons(bl,name, menu, menulist, size, state, callback, level )
     ButtonList **bl;
     char *name;
     Widget menu;
     Menu *menulist;
     int size;
     unsigned long state;
     XtPointer callback;
     int level;
#endif
{
  ButtonList *curr;
  ButtonList *prev = NULL;

  Arg args[ARGLISTSIZE];
  int n = 0;
  int cnt;
  WidgetList buttons;
  XmString label;
  char buffer[256];

  buttons = (WidgetList) XtMalloc(size * sizeof(Widget));

  for(cnt = 0; cnt < size; cnt ++) {

    curr = new_buttonlist();
    if(*bl == NULL)
      *bl = curr;
    else {
      for(prev = *bl; prev->next; prev = prev->next)
	;
      prev->next = curr;
    }
    curr->state = menulist[cnt].statemap;

    if(menulist[cnt].func) {
      if(menulist[cnt].label) {
	label = XmStringCreateSimple(menulist[cnt].label);
	XtSetArg(args[n], XmNlabelString, label); n ++;
      }
      XtSetArg(args[n], XmNborderWidth, 0); n ++;
      if(menulist[cnt].mnemonic) {
	XtSetArg(args[n], XmNmnemonic, menulist[cnt].mnemonic); n ++;
      }
      if(state &  menulist[cnt].statemap) {
	XtSetArg(args[n],XmNsensitive, FALSE); n ++;
      }
      if(level == ROOTMENULEVEL)
	buttons[cnt] = XmCreateCascadeButton(menu, menulist[cnt].name,
					     args,n);
      else
	buttons[cnt] = XmCreatePushButton(menu, menulist[cnt].name, args, n);
      n = 0;
      menulist[cnt].widget = curr->w = buttons[cnt];
      if(menulist[cnt].label)
	XmStringFree(label);
      XtAddCallback(buttons[cnt],XmNactivateCallback, flush_windows, NULL );
      XtAddCallback(buttons[cnt],XmNactivateCallback, menulist[cnt].func, 
		    (menulist[cnt].data) ? menulist[cnt].data : callback);
    }
    else {
      Widget submenu;
#ifndef NO_TEAROFF
      if(preferences.tear_off == TRUE) {
	XtSetArg(args[n], XmNtearOffModel, XmTEAR_OFF_ENABLED ); n ++;
      }
#endif
      sprintf(buffer,"%s_PDmenu",menulist[cnt].name);
      submenu = XmCreatePulldownMenu(menu,buffer,args,n); n = 0;
      
      if(menulist[cnt].label) {
	label = XmStringCreateSimple(menulist[cnt].label);
	XtSetArg(args[n], XmNlabelString, label); n ++;
      }
      XtSetArg(args[n], XmNsubMenuId, submenu); n ++;
      XtSetArg(args[n], XmNborderWidth, 0); n ++;
      if(menulist[cnt].mnemonic) {
	XtSetArg(args[n], XmNmnemonic, menulist[cnt].mnemonic); n ++;
      }
      if(state &  menulist[cnt].statemap) {
	XtSetArg(args[n],XmNsensitive, FALSE); n ++;
      }
      buttons[cnt] = XmCreateCascadeButton(menu, menulist[cnt].name, args, n);
      n = 0;
      menulist[cnt].widget = curr->w = buttons[cnt];
      if(menulist[cnt].label)
	XmStringFree(label);
      make_buttons(bl,menulist[cnt].label, submenu, menulist[cnt].sub_menu,
		   menulist[cnt].size, state, callback, level + 1);
    }
  }
  XtManageChildren(buttons, size);
  for(cnt = 0; cnt < size; cnt ++) {
    if((ML_Strstr(menulist[cnt].name,"HELP")) != NULL) {
      XtSetArg(args[n],XmNmenuHelpWidget, buttons[cnt]); n ++;
      XtSetValues(menu, args, n);
      n = 0;
    }
  }
  return;
}
      

#ifdef __STDC__
void update_buttons(ButtonList *buttonlist, ButtonState state)
#else
void update_buttons(buttonlist, state)
     ButtonList *buttonlist;
     ButtonState state;
#endif
{
  ButtonList *curr;

  for(curr = buttonlist; curr; curr = curr->next)
    if(curr->state & state)
      XtVaSetValues(curr->w, XmNsensitive, FALSE, NULL);
    else
      XtVaSetValues(curr->w, XmNsensitive, TRUE,  NULL);

  return;
}




/*
 * Given a top-level menu structure, and a statemap of conditions
 * where the button would be insensitive, walk the entire tree of
 * buttons emanating from this menu and set the state of each button.
 * See buttons.h for the bitmask associations. 
 */

#ifdef __STDC__
void check_buttons(Menu *menulist, int size, 
		   Button_Menu *button_menu, unsigned long state)
#else
void check_buttons(menulist, size, button_menu, state)
     Menu *menulist;
     int size;
     Button_Menu *button_menu;
     unsigned long state;
#endif
{
  Arg args[ARGLISTSIZE];
  int n = 0;
  Button_Menu *bmenu;
  int cnt;

  for(cnt = 0; cnt < size; cnt ++) {
    if(menulist[cnt].func) {
      if(state &  menulist[cnt].statemap) {
	XtSetArg(args[n],XmNsensitive, FALSE); n ++;
      }
      else {
	XtSetArg(args[n],XmNsensitive, TRUE); n ++;
      }
      XtSetValues(menulist[cnt].widget, args, n); n = 0;
    }
    else {
      if(state &  menulist[cnt].statemap) {
	XtSetArg(args[n],XmNsensitive, FALSE); n ++;
      }
      else {
	XtSetArg(args[n],XmNsensitive, TRUE); n ++;
      }
      XtSetValues(menulist[cnt].widget, args, n); n = 0;
      check_buttons(menulist[cnt].sub_menu,menulist[cnt].size,
		    button_menu,state);
    }
  }
  if(button_menu) {
    for(bmenu = button_menu; bmenu; bmenu = bmenu->next) {
      if(bmenu->label) {
	if(state &  bmenu->statemap) {
	  XtSetArg(args[n],XmNsensitive, FALSE); n ++;
	}
	else {
	  XtSetArg(args[n],XmNsensitive, TRUE); n ++;
	}
	XtSetValues(bmenu->widget, args, n); n = 0;
      }
    }
  }
  return;
}





syntax highlighted by Code2HTML, v. 0.9.1