/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ #include #include #include #include #include #include #include #include "XmUtility.h" #include "defines.h" #include "SelectorInteractor.h" #include "InteractorStyle.h" #include "ListIterator.h" #include "SelectorNode.h" #include "SelectorInstance.h" #include "DXApplication.h" #include "ErrorDialogManager.h" #include "../widgets/XmDX.h" boolean SelectorInteractor::SelectorInteractorClassInitialized = FALSE; String SelectorInteractor::DefaultResources[] = { "*allowHorizontalResizing: True", "*optionMenu.spacing: 0", "*optionMenu.topOffset: 4", "*optionMenu.leftOffset: 1", "*optionMenu.rightOffset: 1", "*optionMenu.bottomOffset: 4", "*optionMenu.marginHeight: 1", "*optionMenu.marginWidth: 0", "*interactive_form.resizePolicy: XmRESIZE_NONE", NUL(char*) }; SelectorInteractor::SelectorInteractor(const char *name, InteractorInstance *ii) : Interactor(name,ii) { this->pulldown = NULL; this->optionMenu = NULL; this->optionForm = NULL; this->visinit = FALSE; } // // One time class initializations. // void SelectorInteractor::initialize() { // // Initialize default resources (once only). // if (NOT SelectorInteractor::SelectorInteractorClassInitialized) { ASSERT(theApplication); this->setDefaultResources(theApplication->getRootWidget(), SelectorInteractor::DefaultResources); this->setDefaultResources(theApplication->getRootWidget(), Interactor::DefaultResources); SelectorInteractor::SelectorInteractorClassInitialized = TRUE; } } // // Allocate an n-dimensional stepper for the given instance. // Interactor *SelectorInteractor::AllocateInteractor(const char *name, InteractorInstance *ii) { SelectorInteractor *si = new SelectorInteractor(name,ii); return (Interactor*)si; } // // Accepts value changes and reflects them into other interactors, cdbs // and off course the interactor node output. // extern "C" void SelectorInteractor_OptionMenuCB(Widget widget, XtPointer clientData, XtPointer callData) { SelectorInteractor *si = (SelectorInteractor*)clientData; int component; ASSERT(widget); ASSERT(si); int optnum = (int)GetUserData(widget); si->optionMenuCallback(widget, optnum, callData); } // // Perform anything that needs to be done after the parent of // this->interactivePart has been managed. // void SelectorInteractor::completeInteractivePart() { } // // Build the selector interactor option menu. // Note that we also use this to rebuild the list of options seen in the menu // In this case the // Widget SelectorInteractor::createInteractivePart(Widget form) { SelectorNode *node; SelectorInstance *si = (SelectorInstance*)this->interactorInstance; Arg wargs[3]; int n; ASSERT(si); node = (SelectorNode*)si->getNode(); ASSERT(si->getStyle()->getStyleEnum() == SelectorOptionMenuStyle); ASSERT(form); ASSERT(node); ASSERT(EqualString(node->getClassName(), ClassSelectorNode)); this->optionForm = form; // // Build the option menu // this->reloadMenuOptions(); XtManageChild(this->optionForm); return this->optionForm; } // // [Re]load the options into this->pulldown. // void SelectorInteractor::reloadMenuOptions() { SelectorInstance *si = (SelectorInstance*) this->interactorInstance; Widget sbutton; int options, n, i; Arg wargs[20]; Pixel bg, fg; unsigned char rsp, rsproot; XtVaGetValues (this->optionForm, XmNresizePolicy, &rsp, NULL); XtVaSetValues (this->optionForm, XmNresizePolicy, XmRESIZE_GROW, NULL); ASSERT(this->optionForm); if (this->optionMenu) { XtUnmanageChild (this->optionMenu); XtDestroyWidget (this->optionMenu); this->optionMenu = NULL; XtDestroyWidget (this->pulldown); } /* * The pulldown already exists so remove all its children, * which are assumed to be contained in this->optionWidgets. */ this->optionWidgets.clear(); // // colors change with panel style. It's better to start out with // the proper colors than to switch to ther proper colors. // XtVaGetValues (this->optionForm, XmNforeground, &fg, XmNbackground, &bg, NULL); n = 0; XtSetArg (wargs[n], XmNbackground, bg); n++; XtSetArg (wargs[n], XmNforeground, fg); n++; this->pulldown = XmCreatePulldownMenu(this->optionForm, "pulldownMenu", wargs, n); /* * Create the options in the pulldown menu according to specified * option list. */ Dimension strw, strh; int maxw = 0; XmFontList xmfl = 0; options = si->getOptionCount(); XmString xmstr; if (options > 0) { int selectedOption = si->getSelectedOptionIndex(); ASSERT(selectedOption <= options); sbutton = NULL; for (i = 1; i <= options; i++) { char *optname = (char*)si->getOptionNameString(i); ASSERT(optname); Widget button; xmstr = XmStringCreateSimple(optname); n = 0; XtSetArg(wargs[n], XmNuserData, i); n++; XtSetArg(wargs[n], XmNlabelString, xmstr ); n++; XtSetArg (wargs[n], XmNbackground, bg); n++; XtSetArg (wargs[n], XmNforeground, fg); n++; button = XmCreatePushButton(this->pulldown, optname, wargs, n); if (!xmfl) XtVaGetValues (button, XmNfontList, &xmfl, NULL); XmStringExtent (xmfl, xmstr, &strw, &strh); maxw = MAX(maxw, strw); XtAddCallback (button, XmNactivateCallback, (XtCallbackProc)SelectorInteractor_OptionMenuCB, (XtPointer)this); XtManageChild(button); if (i == selectedOption) { sbutton = button; } this->appendOptionWidget(button); delete optname; XmStringFree(xmstr); } ASSERT(sbutton); // Certainly not a solution to the problem, but using multi columns // makes marginally better those situations in which a huge number of // options makes the list go off the screen. // FIXME: MAX_OPTIONS must be determined at run time by comparing the // height of the XmStrings with the height of the display. Besides // the number 40 is almost certainly wrong. #define MAX_OPTIONS 40 int columns = (options/MAX_OPTIONS) + ((options%MAX_OPTIONS)?1:0); if (columns > 1) { XtVaSetValues (this->pulldown, XmNpacking, XmPACK_COLUMN, XmNnumColumns, columns, NULL); } } else { n = 0; xmstr = XmStringCreateSimple("(empty)"); XtSetArg(wargs[n], XmNlabelString, xmstr); n++; sbutton = XmCreatePushButton(this->pulldown, "(empty)", wargs, n); XtManageChild(sbutton); if (!xmfl) XtVaGetValues (sbutton, XmNfontList, &xmfl, NULL); XmStringExtent (xmfl, xmstr, &strw, &strh); maxw = MAX(maxw, strw); this->appendOptionWidget(sbutton); XmStringFree(xmstr); } /* * Create the option menu itself or just reset the current selection * if the menu already exists. */ n = 0; XtSetArg(wargs[n], XmNmenuHistory, sbutton); n++; if (!this->optionMenu) { XtSetArg(wargs[n], XmNsubMenuId, this->pulldown); n++; XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(wargs[n], XmNleftOffset, -(18 + (maxw>>1))); n++; XtSetArg(wargs[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(wargs[n], XmNbottomAttachment, XmATTACH_FORM); n++; if (this->currentLayout & WorkSpaceComponent::Vertical) { XtSetArg (wargs[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg (wargs[n], XmNleftPosition, 50); n++; } else { XtSetArg (wargs[n], XmNleftAttachment, XmATTACH_NONE); n++; } XtSetArg(wargs[n], XmNbackground, bg); n++; XtSetArg(wargs[n], XmNforeground, fg); n++; this->optionMenu = XmCreateOptionMenu(this->optionForm, "optionMenu", wargs, n); // // Every motif option menu comes with its own label widget which we // never use. // For the sake of dgux, set the labelString to "", because it defaults // to "OptionLabel" unlike everywhere else. // xmstr = XmStringCreateLtoR ("", "bold"); Widget labelgadget = XmOptionLabelGadget (this->optionMenu); XtVaSetValues (labelgadget, XmNlabelString, xmstr, NULL); XmStringFree (xmstr); XtManageChild(this->optionMenu); } if (options <= 0) XtSetSensitive(this->optionMenu,False); else if (!XtIsSensitive (this->optionMenu)) XtSetSensitive(this->optionMenu,True); XtVaSetValues (this->optionForm, XmNresizePolicy, rsp, NULL); } // // Accepts value changes and reflects them into other interactors, cdbs // and off course the interactor node output. // void SelectorInteractor::optionMenuCallback(Widget w, int optnum, XtPointer cb) { SelectorInstance *si = (SelectorInstance*)this->interactorInstance; SelectorNode *snode; ASSERT(w); ASSERT(optnum > 0); si->setSelectedOptionIndex(optnum, TRUE); } // // Update the displayed values for this interactor. // void SelectorInteractor::updateDisplayedInteractorValue() { Arg wargs[10]; int i,components,n; // FIXME: should check to make sure we have the correct class of node. SelectorInstance *si = (SelectorInstance*)this->interactorInstance; ASSERT(si); // // There are no options, so there is nothing to update. // if (si->getOptionCount() <= 0) return; /* * Just display the currently selected option. */ int option = si->getSelectedOptionIndex(); if (option == 0) return; Widget w = this->getOptionWidget(option); ASSERT(w); XtVaSetValues(this->optionMenu, XmNmenuHistory, w, NULL); } // // Make sure the attributes match the resources for the widgets. // void SelectorInteractor::handleInteractivePartStateChange( InteractorInstance *src_ii, boolean major_change) { this->reloadMenuOptions(); if (this->currentLayout & WorkSpaceComponent::Horizontal) { this->currentLayout|= WorkSpaceComponent::NotSet; this->layoutInteractor(); } } void SelectorInteractor::layoutInteractorHorizontally() { Widget button; this->Interactor::layoutInteractorHorizontally(); if (!this->optionMenu) return ; XtVaSetValues (this->optionMenu, XmNleftAttachment, XmATTACH_NONE, NULL); } // // The setting and resetting of marginHeight and topAttachment deals with the // absence of a topAttachment. XmNtopAttachment is NONE because it permits // the optionmenu to wind up roughly in the middle of its parent even if a change // in the implementation of the interactor causes us to crave a different height // than is saved in the .cfg file. The button widget musn't change height but // the rowcolumn can. // void SelectorInteractor::layoutInteractorVertically() { this->Interactor::layoutInteractorVertically(); if (!this->optionMenu) return ; XtVaSetValues (this->optionMenu, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 50, NULL); } void SelectorInteractor::setAppearance(boolean developer_style) { boolean changing = (developer_style != this->getAppearance()); this->Interactor::setAppearance(developer_style); if ((changing) || (this->visinit == FALSE)) { this->reloadMenuOptions(); this->visinit = TRUE; } }