/* * * Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * Further, this software is distributed without any warranty that it is * free of the rightful claim of any third person regarding infringement * or the like. Any license provided herein, whether implied or * otherwise, applies only to this software file. Patent licenses, if * any, provided herein do not apply to combinations of this program with * other software, or any other product whatsoever. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, * Mountain View, CA 94043, or: * * http://www.sgi.com * * For further information regarding this notice, see: * * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ * */ /* * Copyright (C) 1990-93 Silicon Graphics, Inc. * _______________________________________________________________________ ______________ S I L I C O N G R A P H I C S I N C . ____________ | | $Revision: 1.5 $ | | Classes: | _SoXtSlider | | Author(s) : Alain Dumesny | ______________ S I L I C O N G R A P H I C S I N C . ____________ _______________________________________________________________________ */ #include #include #include #include #include "SoFloatCallbackList.h" #include "_SoXtUIRegion.h" #include "_SoXtSlider.h" #include #include #include #include #include #include #include #include /* * Defines */ #define BOX_H 12 // thum height #define BOX_L 7 // thum width/2 #define SPACE 2 #define THUMB_SPACE 1 #define SIDE (UI_THICK + SPACE + UI_THICK) // pixels between the slider and the label #define TEXT_OFFSET 6 //////////////////////////////////////////////////////////////////////// // // Public constructor - build the widget right now // _SoXtSlider::_SoXtSlider( Widget parent, const char *name, SbBool buildInsideParent) : SoXtGLWidget( parent, name, buildInsideParent, SO_GLX_RGB, FALSE) // tell GLWidget not to build just yet // //////////////////////////////////////////////////////////////////////// { // In this case, this component is what the app wants, so buildNow = TRUE constructorCommon(TRUE); } //////////////////////////////////////////////////////////////////////// // // SoEXTENDER constructor - the subclass tells us whether to build or not // _SoXtSlider::_SoXtSlider( Widget parent, const char *name, SbBool buildInsideParent, SbBool buildNow) : SoXtGLWidget( parent, name, buildInsideParent, SO_GLX_RGB, FALSE) // tell GLWidget not to build just yet // //////////////////////////////////////////////////////////////////////// { // In this case, this component may be what the app wants, // or it may want a subclass of this component. Pass along buildNow // as it was passed to us. constructorCommon(buildNow); } //////////////////////////////////////////////////////////////////////// // // Called by the constructors // // private // void _SoXtSlider::constructorCommon(SbBool buildNow) // ////////////////////////////////////////////////////////////////////// { mouse = new SoXtMouse(ButtonPressMask | ButtonMotionMask | ButtonReleaseMask); // init local vars startCallbacks = new SoFloatCallbackList; changedCallbacks = new SoFloatCallbackList; finishCallbacks = new SoFloatCallbackList; interactive = FALSE; value = 0.0; sliderWidget = labelWidget = numberWidget = mgrWidget = NULL; labelStr = NULL; numberVisible = TRUE; // show the number by default // slider geometry vars which do not depend on window size slx1 = sly1 = SIDE; thumy1 = THUMB_SPACE; thumy2 = thumy1 + BOX_H; sliderSize.setValue(110, 25); // default slider size // Build the widget tree, and let SoXtComponent know about our base widget. if (buildNow) { Widget w = buildWidget(getParentWidget()); setBaseWidget(w); } } //////////////////////////////////////////////////////////////////////// // // Destructor. // _SoXtSlider::~_SoXtSlider() // //////////////////////////////////////////////////////////////////////// { delete startCallbacks; delete changedCallbacks; delete finishCallbacks; if (labelStr != NULL) free(labelStr); delete mouse; } //////////////////////////////////////////////////////////////////////// // // This routine draws the entire slider region. // // Use: virtual public void _SoXtSlider::redraw() // //////////////////////////////////////////////////////////////////////// { if (! isVisible()) return; glXMakeCurrent(getDisplay(), getNormalWindow(), getNormalContext()); // compute thum position position = slx1 + short(value * (slx2 - slx1)); thumx1 = position - BOX_L; thumx2 = position + BOX_L; // draw slider surrounding SbVec2s size = getGlxSize(); SoDrawDownUIRegion(0, 0, size[0]-1, size[1]-1); // now call the routine which does drawing inside the slider top region drawSliderTopRegion(); } //////////////////////////////////////////////////////////////////////// // // Sets the label string. // // Use: public void _SoXtSlider::setLabel(const char *newlabel) // //////////////////////////////////////////////////////////////////////// { // out with the old... if (labelStr != NULL) free(labelStr); labelStr = NULL; // in with the new... if (newlabel != NULL) labelStr = strdup(newlabel); if (getWidget() != NULL) doLabelLayout(); } //////////////////////////////////////////////////////////////////////// // // Sets visibility of the numeric field // // Use: public void _SoXtSlider::setNumericFieldVisible(SbBool setVisible) // //////////////////////////////////////////////////////////////////////// { if (setVisible) { if (numberVisible) return; // already visible else { // make the number visible numberVisible = TRUE; if (getWidget() != NULL) doNumberLayout(); } } else { if (! numberVisible) return; // already not visible else { // make the number not visible numberVisible = FALSE; if (getWidget() != NULL) doNumberLayout(); } } } //////////////////////////////////////////////////////////////////////// // // lays out the motif label (if any) and slider relative to it. // // Use: private void _SoXtSlider::doLabelLayout() // //////////////////////////////////////////////////////////////////////// { int n; Arg args[10]; if (labelStr == NULL) { XtSetArg(args[0], XmNleftAttachment, XmATTACH_FORM); XtSetValues(sliderWidget, args, 1); if (labelWidget != 0) { //??? XtUnmanage first? XtDestroyWidget(labelWidget); labelWidget = 0; } } else { if (labelWidget == 0) { labelWidget = XtCreateWidget(labelStr, xmLabelGadgetClass, mgrWidget, NULL, 0); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetValues(labelWidget, args, n); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, labelWidget); n++; XtSetArg(args[n], XmNleftOffset, TEXT_OFFSET); n++; XtSetValues(sliderWidget, args, n); XtManageChild(labelWidget); } else { XtSetArg(args[0], XmNname, labelStr); XtSetValues(labelWidget, args, 1); } } } //////////////////////////////////////////////////////////////////////// // // lays out the motif numeric text field (if any) and slider relative to it. // // Use: private void _SoXtSlider::doNumberLayout() // //////////////////////////////////////////////////////////////////////// { int n; Arg args[10]; if (! numberVisible) { XtSetArg(args[0], XmNrightAttachment, XmATTACH_FORM); XtSetValues(sliderWidget, args, 1); if (numberWidget != NULL) { //??? XtUnmanage first? XtDestroyWidget(numberWidget); numberWidget = NULL; } } else { if (numberWidget == NULL) { n = 0; XtSetArg(args[n], XmNhighlightThickness, 1); n++; XtSetArg(args[n], XmNcolumns, 4); n++; numberWidget = XtCreateWidget("sliderText", xmTextWidgetClass, mgrWidget, args, n); XtAddCallback(numberWidget, XmNactivateCallback, (XtCallbackProc) _SoXtSlider::textFieldCB, (XtPointer) this); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetValues(numberWidget, args, n); n = 0; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, numberWidget); n++; XtSetValues(sliderWidget, args, n); // now set the string to the slider value char valStr[6]; sprintf(valStr, "%.2f", getValue()); XmTextSetString(numberWidget, valStr); XtManageChild(numberWidget); } #ifdef DEBUG else { SoDebugError::post("_SoXtSlider::doNumberLayout::menuPick", "INTERNAL ERROR"); } #endif } } //////////////////////////////////////////////////////////////////////// // // Description: // This builds the parent Glx widget, then registers interest // in mouse events. // // Use: virtual protected Widget _SoXtSlider::buildWidget(Widget parent) // //////////////////////////////////////////////////////////////////////// { int n; Arg args[10]; // // create a top form to hold everything together // mgrWidget = XtCreateWidget(getWidgetName(), xmFormWidgetClass, parent, NULL, 0); // ??? do we need to register this widget class? // // create _SoXtSlider and text widget // sliderWidget = SoXtGLWidget::buildWidget(mgrWidget); SoXt::setWidgetSize(sliderWidget, sliderSize); mouse->enable(getNormalWidget(), (XtEventHandler) SoXtGLWidget::eventHandler, (XtPointer) this); // // do layout // n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetValues(sliderWidget, args, n); doLabelLayout(); doNumberLayout(); // manage that slider XtManageChild(sliderWidget); return mgrWidget; } //////////////////////////////////////////////////////////////////////// // // Resize the slider (only) widget // // Use: virtual public void _SoXtSlider::setSliderSize(const SbVec2s &newSize) // //////////////////////////////////////////////////////////////////////// { if (sliderWidget != NULL) SoXt::setWidgetSize(sliderWidget, newSize); sliderSize = newSize; } //////////////////////////////////////////////////////////////////////// // // Returns the slider (only) widget size // // Use: virtual public SbVec2s _SoXtSlider::getSliderSize() // //////////////////////////////////////////////////////////////////////// { return sliderSize; } //////////////////////////////////////////////////////////////////////// // // Process the passed X event. // // Use: virtual public void _SoXtSlider::processEvent(XAnyEvent *xe) // //////////////////////////////////////////////////////////////////////// { short x, y; XButtonEvent *be; XMotionEvent *me; SbVec2s size = getGlxSize(); switch (xe->type) { case ButtonPress: be = (XButtonEvent *) xe; if (be->button == Button1) { startCallbacks->invokeCallbacks(value); interactive = TRUE; // check for thumb picking region x = short(be->x); y = short(size[1] - be->y); if (x>thumx1 && xthumy1 && ybutton == Button1) { interactive = FALSE; finishCallbacks->invokeCallbacks(value); } break; case MotionNotify: me = (XMotionEvent *) xe; if (me->state & Button1Mask) setValue((me->x - slx1 - posdiff) / float(slx2 - slx1)); break; } } //////////////////////////////////////////////////////////////////////// // // Sets the slider to this value.. // // Use: public void _SoXtSlider::setValue(float v) // //////////////////////////////////////////////////////////////////////// { // assign the clipped value and check for redraw needs float old = value; value = (v > 1.0) ? 1.0 : ((v < 0.0) ? 0.0 : v) ; if (value == old) return; redraw(); // update text field if (numberWidget != NULL) { char valStr[6]; sprintf(valStr, "%.2f", value); XmTextSetString(numberWidget, valStr); } changedCallbacks->invokeCallbacks(value); } //////////////////////////////////////////////////////////////////////// // // This routine is when the window has changed size // // Use: virtual protected void _SoXtSlider::sizeChanged(const SbVec2s &newSize) // //////////////////////////////////////////////////////////////////////// { // calculate slider parameters which depends on window size slx2 = newSize[0] - SIDE -1; sly2 = newSize[1] - SIDE -1; // reset projection glXMakeCurrent(getDisplay(), getNormalWindow(), getNormalContext()); glViewport(0, 0, newSize[0], newSize[1]); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, newSize[0], 0, newSize[1], -1, 1); } //////////////////////////////////////////////////////////////////////// // // Draws the little white maker. subclasses can redefine this routine to // make the slider top region look like anything they want. // // Use: virtual protected void _SoXtSlider::drawSliderTopRegion() // //////////////////////////////////////////////////////////////////////// { MAIN_UI_COLOR; glRects(slx1, sly1, slx2, sly2); SoDrawThumbUIRegion(thumx1, thumy1, thumx2, thumy2); if (isDoubleBuffer()) glXSwapBuffers(getDisplay(), getNormalWindow()); else glFlush(); } void _SoXtSlider::addStartCallback(_SoXtSliderCB *f, void *userData) { startCallbacks->addCallback((SoFloatCallbackListCB *)f, userData); } void _SoXtSlider::addValueChangedCallback(_SoXtSliderCB *f, void *userData) { changedCallbacks->addCallback((SoFloatCallbackListCB *)f, userData); } void _SoXtSlider::addFinishCallback(_SoXtSliderCB *f, void *userData) { finishCallbacks->addCallback((SoFloatCallbackListCB *)f, userData); } void _SoXtSlider::removeStartCallback(_SoXtSliderCB *f, void *userData) { startCallbacks->removeCallback((SoFloatCallbackListCB *)f, userData); } void _SoXtSlider::removeValueChangedCallback(_SoXtSliderCB *f, void *userData) { changedCallbacks->removeCallback((SoFloatCallbackListCB *)f, userData); } void _SoXtSlider::removeFinishCallback(_SoXtSliderCB *f, void *userData) { finishCallbacks->removeCallback((SoFloatCallbackListCB *)f, userData); } // //////////////////////////////////////////////////////////////////////// // static callbacks stubs //////////////////////////////////////////////////////////////////////// // // // called whenever the user types a new value in the text field. // void _SoXtSlider::textFieldCB(Widget w, _SoXtSlider *p, XtPointer) { // get text value from the label char *str = XmTextGetString(w); float val; if (sscanf(str, "%f", &val)) p->setValue(val); else { // reformat the text field char valStr[6]; sprintf(valStr, "%.2f", p->getValue()); XmTextSetString(w, valStr); } free(str); // make the text field loose the focus XmProcessTraversal(SoXt::getShellWidget(w), XmTRAVERSE_CURRENT); }