/* 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; }