File: [Development] / inventor / libSoXt / src / mtlEdit / SoXtMtlEdit.c++ (download)
Revision 1.2, Fri Jun 22 22:06:58 2001 UTC (16 years, 4 months ago) by jlim
Branch: MAIN
Changes since 1.1: +1 -7
lines
Made several changes:
1. Removed unreferenced variables.
2. Fixed miscellaneous warnings (typedefs and function declarations).
3. Moved MENUS_IN_POPUP from various files to make/ivcommondefs.
4. Fixed IRIX build problems.
|
/*
*
* 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) 1991-93 Silicon Graphics, Inc.
*
_______________________________________________________________________
______________ S I L I C O N G R A P H I C S I N C . ____________
|
| $Revision: 1.2 $
|
| Classes:
| SoXtMaterialEditor
|
| Author(s): Alain Dumesny, David Mott
|
|
______________ S I L I C O N G R A P H I C S I N C . ____________
_______________________________________________________________________
*/
#include <inttypes.h>
#include <string.h>
#include <X11/StringDefs.h>
#include <Xm/Xm.h>
#include <Xm/CascadeBG.h>
#include <Xm/Form.h>
#include <Xm/RowColumn.h>
#include <Xm/PushB.h>
#include <Xm/PushBG.h>
#include <Xm/Separator.h>
#include <Xm/SeparatoG.h>
#include <Xm/ToggleB.h>
#include <Xm/ToggleBG.h>
#include <Xm/Label.h>
#include <Xm/LabelG.h>
#include <Inventor/sensors/SoNodeSensor.h>
#include <Inventor/actions/SoGLRenderAction.h>
#include <Inventor/actions/SoSearchAction.h>
#include <Inventor/nodes/SoComplexity.h>
#include <Inventor/nodes/SoDirectionalLight.h>
#include <Inventor/nodes/SoMaterial.h>
#include <Inventor/nodes/SoOrthographicCamera.h>
#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/nodes/SoSphere.h>
#include <Inventor/nodes/SoMaterialBinding.h>
#include <Inventor/nodes/SoBaseColor.h>
#include <Inventor/nodes/SoQuadMesh.h>
#include <Inventor/nodes/SoCoordinate3.h>
#include <Inventor/nodes/SoLightModel.h>
#include <Inventor/Xt/SoXt.h>
#include <Inventor/Xt/SoXtClipboard.h>
#include <Inventor/Xt/SoXtMaterialList.h>
#include <Inventor/Xt/SoXtRenderArea.h>
#include <Inventor/Xt/SoXtResource.h>
#include <Inventor/Xt/SoXtMaterialEditor.h>
#include "_SoXtColorEditor.h"
#include "_SoXtColorSlider.h"
#include <GL/gl.h>
#include <Inventor/errors/SoDebugError.h>
/*
* Defines
*/
#define SCREEN(w) XScreenNumberOfScreen( XtScreen(w) )
// default window height/width and layout
#define DEFAULT_WIDTH 420
#define DEFAULT_HEIGHT 210
#define SCENE_RIGHT_POSITION 36
#define OFFSET 5 // offset at window borders
// space between the color sliders (amb,diff,spec,emiss) and
// the other 2 sliders (shin, tranps)
#define SLIDER_SPACE 50
// menu items
enum {
k_MATERIAL_LIST = 0,
k_CONTINUOUS,
k_AFTER_ACCEPT,
k_EDIT_COPY,
k_EDIT_PASTE,
k_EDIT_HELP,
k_MENU_NUM // length of menu
};
// ids used in array of sliders and toggles
// Note: the order (amb/diff/spec/Emiss then the rest) is important
// for array of sliders.
enum {
k_AMBIENT_ID = 0,
k_DIFFUSE_ID,
k_SPECULAR_ID,
k_EMISSIVE_ID,
k_SHININESS_ID,
k_TRANSPARENCY_ID
};
// constants for callback functions (separate bits)
#define k_none 0x0000
#define k_ambient 0x0001
#define k_diffuse 0x0002
#define k_specular 0x0004
#define k_emissive 0x0008
#define k_shininess 0x0010
#define k_transparency 0x0020
// titles for color editor (also check updateColorEditor() routine)
static char *ambientString;
static char *diffuseString;
static char *specularString;
static char *emissiveString;
static char *deftitles[]={
"Material Ambient Color",
"Material Diffuse Color",
"Material Specular Color",
"Material Emissive Color"
};
static char *mtlDir = "/usr/share/data/materials";
static char *slider_labels[] = { (char *)NULL, (char *)NULL, (char *)NULL,
(char *)NULL, (char *)NULL, (char *)NULL
};
static char *slider_defs[] = { "Amb: ", "Diff: ", "Spec: ",
"Emis: ", "Shininess: ", "Transp: "
};
static const float tileColors[][3] = {
{.3, .3, .3}, {.6, .6, .6},
{.6, .6, .6}, {.3, .3, .3}
};
static const float tileCoords[][3] = {
{-3, 3, 0}, {0, 3, 0}, {3, 3, 0},
{-3, 0, 0}, {0, 0, 0}, {3, 0, 0},
{-3, -3, 0}, {0, -3, 0}, {3, -3, 0}
};
static char *thisClassName = "SoXtMaterialEditor";
#define TOGGLE_ON(BUTTON) \
XmToggleButtonSetState((Widget) BUTTON, TRUE, FALSE)
#define TOGGLE_OFF(BUTTON) \
XmToggleButtonSetState((Widget) BUTTON, FALSE, FALSE)
////////////////////////////////////////////////////////////////////////
//
// Public constructor - build the widget right now
//
SoXtMaterialEditor::SoXtMaterialEditor(
Widget parent,
const char *name,
SbBool buildInsideParent)
: SoXtComponent(
parent,
name,
buildInsideParent)
//
////////////////////////////////////////////////////////////////////////
{
// 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
//
SoXtMaterialEditor::SoXtMaterialEditor(
Widget parent,
const char *name,
SbBool buildInsideParent,
SbBool buildNow)
: SoXtComponent(
parent,
name,
buildInsideParent)
//
////////////////////////////////////////////////////////////////////////
{
// 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
SoXtMaterialEditor::constructorCommon(SbBool buildNow)
//
//////////////////////////////////////////////////////////////////////
{
// init local vars
setClassName(thisClassName);
addVisibilityChangeCallback(visibilityChangeCB, this);
material = NULL;
acceptButton = NULL;
menuItemsList = new Widget[k_MENU_NUM];
activeColor = k_none;
clipboard = NULL;
ignoreCallback = FALSE;
callbackList = new SoCallbackList;
updateFreq = CONTINUOUS;
renderArea = NULL;
for (int i=0; i<6; i++) {
sliders[i] = NULL;
changedIt[i] = FALSE;
}
setSize( SbVec2s(DEFAULT_WIDTH, DEFAULT_HEIGHT) );
// components that are not built until needed
materialList = NULL;
colorEditor = NULL;
openMaterialList = FALSE;
//
// Create local scene graph for viewing materials
//
localMaterial = new SoMaterial;
light0 = new SoDirectionalLight;
light1 = new SoDirectionalLight;
tileColor = new SoBaseColor;
root = new SoSeparator;
SoOrthographicCamera *camera = new SoOrthographicCamera;
SoComplexity *complexity = new SoComplexity;
SoSphere *sphere = new SoSphere;
SoCoordinate3 *coord = new SoCoordinate3;
SoQuadMesh *quadMesh = new SoQuadMesh;
SoMaterialBinding *matBinding = new SoMaterialBinding;
SoLightModel *lightModel1 = new SoLightModel;
SoLightModel *lightModel2 = new SoLightModel;
root->ref();
root->addChild(camera);
root->addChild(lightModel1);
root->addChild(tileColor);
root->addChild(matBinding);
root->addChild(coord);
root->addChild(quadMesh);
root->addChild(lightModel2);
root->addChild(light0);
root->addChild(light1);
root->addChild(localMaterial);
root->addChild(complexity);
root->addChild(sphere);
// setup the scene viewing
camera->position.setValue(0, 0, 2);
camera->nearDistance.setValue(1);
camera->farDistance.setValue(3);
camera->height.setValue(2);
complexity->value.setValue(0.8);
sphere->radius.setValue(0.85);
// setup the sphere background
tileColor->rgb.setValues(0, 4, tileColors);
matBinding->value.setValue(SoMaterialBinding::PER_FACE);
coord->point.setValues(0, 9, tileCoords);
quadMesh->verticesPerColumn.setValue(3);
quadMesh->verticesPerRow.setValue(3);
lightModel1->model.setValue(SoLightModel::BASE_COLOR);
lightModel2->model.setValue(SoLightModel::PHONG);
// Default for lights
light0->direction.setValue(.556, -.623, -.551);
light1->direction.setValue(-.556, -.623, -.551);
//
// set up the material sensor -
// this tells us if someone else changed the material we attach to
// (the sensor gets attached later)
//
sensor = new SoNodeSensor(SoXtMaterialEditor::sensorCB, this);
// Build the widget tree, and let SoXtComponent know about our base widget.
if (buildNow) {
Widget w = buildWidget(getParentWidget());
setBaseWidget(w);
}
}
////////////////////////////////////////////////////////////////////////
//
// Destructor.
//
SoXtMaterialEditor::~SoXtMaterialEditor()
//
////////////////////////////////////////////////////////////////////////
{
unregisterWidget(mgrWidget);
if ( isAttached() )
detach();
// delete other components
delete materialList;
delete colorEditor;
delete sensor;
delete callbackList;
delete clipboard;
delete [] menuItemsList;
delete sliders[k_AMBIENT_ID];
delete sliders[k_DIFFUSE_ID];
delete sliders[k_SPECULAR_ID];
delete sliders[k_EMISSIVE_ID];
delete sliders[k_SHININESS_ID];
delete sliders[k_TRANSPARENCY_ID];
delete renderArea; // this should delete the local graph
root->unref();
}
////////////////////////////////////////////////////////////////////////
//
// This routine sets the update frequency.
//
// usage: virtual public
//
void
SoXtMaterialEditor::setUpdateFrequency(SoXtMaterialEditor::UpdateFrequency freq)
//
////////////////////////////////////////////////////////////////////////
{
if (updateFreq == freq)
return;
updateFreq = freq;
// show/hide the accept button
if (acceptButton != NULL) {
if (updateFreq == CONTINUOUS)
XtUnmanageChild(acceptButton);
else
XtManageChild(acceptButton);
}
// update the attached node if we switch to continous
if (material != NULL && updateFreq == CONTINUOUS) {
copyMaterial(material, index, localMaterial, 0);
undoIgnoresIfChanged();
}
}
////////////////////////////////////////////////////////////////////////
//
// Show the material editor and its color editor.
//
// usage: public
//
void
SoXtMaterialEditor::show()
//
////////////////////////////////////////////////////////////////////////
{
SoXtComponent::show();
// now also show the other components if there were previously shown
if (colorEditor != NULL && activeColor != k_none)
colorEditor->show();
if (materialList != NULL && openMaterialList)
materialList->show();
}
////////////////////////////////////////////////////////////////////////
//
// Hide the material editor and its color editor.
//
// usage: public
//
void
SoXtMaterialEditor::hide()
//
////////////////////////////////////////////////////////////////////////
{
SoXtComponent::hide();
if (colorEditor != NULL)
colorEditor->hide();
if (materialList != NULL)
materialList->hide();
}
////////////////////////////////////////////////////////////////////////
//
// This builds the pulldown menu for the material editor.
//
// usage: private
//
Widget
SoXtMaterialEditor::buildPulldownMenu(Widget parent)
//
////////////////////////////////////////////////////////////////////////
{
Widget menubar, pulldown, buttons[1];
Arg args[5];
int n;
Widget menu1W[20];
int num1 = 0;
menubar = XmCreateMenuBar(parent, "menuBar", NULL, 0);
Arg popupargs[4];
int popupn = 0;
#ifdef MENUS_IN_POPUP
SoXt::getPopupArgs(XtDisplay(menubar), SCREEN(menubar), popupargs, &popupn);
#endif
pulldown = XmCreatePulldownMenu(menubar, "editPulldown", popupargs, popupn);
#ifdef MENUS_IN_POPUP
// register callbacks to load/unload the pulldown colormap
SoXt::registerColormapLoad(pulldown, SoXt::getShellWidget(parent));
#endif
XtAddCallback(pulldown, XmNmapCallback,
(XtCallbackProc) SoXtMaterialEditor::menuDisplay, (XtPointer) this);
n = 0;
XtSetArg(args[n], XmNsubMenuId, pulldown); n++;
buttons[0] = XtCreateWidget("Edit",
xmCascadeButtonGadgetClass, menubar, args, n);
n = 0;
XtSetArg(args[n], XmNuserData, this); n++;
#define TOGGLE_ITEM(NAME,KONST) \
menu1W[num1++] = menuItemsList[KONST] = XtCreateWidget(NAME, \
xmToggleButtonGadgetClass, pulldown, args, n); \
XtAddCallback(menuItemsList[KONST], XmNvalueChangedCallback,\
(XtCallbackProc) SoXtMaterialEditor::menuPick, \
(XtPointer) KONST)
#define PUSH_ITEM(NAME,KONST) \
menu1W[num1++] = menuItemsList[KONST] = XtCreateWidget(NAME, \
xmPushButtonGadgetClass, pulldown, args, n); \
XtAddCallback(menuItemsList[KONST], XmNactivateCallback,\
(XtCallbackProc) SoXtMaterialEditor::menuPick, \
(XtPointer) KONST)
// the items...
PUSH_ITEM("Material List", k_MATERIAL_LIST);
menu1W[num1++] = XtCreateWidget("separator",
xmSeparatorGadgetClass, pulldown, NULL, 0);
XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); n++;
TOGGLE_ITEM("Continuous", k_CONTINUOUS);
TOGGLE_ITEM("Manual", k_AFTER_ACCEPT);
n--;
menu1W[num1++] = XtCreateWidget("separator",
xmSeparatorGadgetClass, pulldown, NULL, 0);
PUSH_ITEM("Copy", k_EDIT_COPY);
PUSH_ITEM("Paste", k_EDIT_PASTE);
menu1W[num1++] = XtCreateWidget("separator",
xmSeparatorGadgetClass, pulldown, NULL, 0);
PUSH_ITEM("Help", k_EDIT_HELP);
#undef TOGGLE_ITEM
#undef PUSH_ITEM
// manage childrens
XtManageChildren(menu1W, num1);
XtManageChildren(buttons, 1);
return menubar;
}
////////////////////////////////////////////////////////////////////////
//
// This builds the sliders form (ambient to transparency sliders,
// with toggles buttons).
//
// usage: private
//
Widget
SoXtMaterialEditor::buildSlidersForm(Widget parent)
//
////////////////////////////////////////////////////////////////////////
{
Widget form, textForm, labelW[6], slidersW[6];
int n, i;
Arg args[12];
// create a form to hold everything together
n = 0;
XtSetArg(args[n], XmNfractionBase, 1000); n++;
form = XtCreateWidget("sliderForm", xmFormWidgetClass, parent, args, n);
textForm = XtCreateWidget("textForm", xmFormWidgetClass, form, args, n);
// build sliders
for (i=0; i<6; i++) {
sliders[i] = new _SoXtColorSlider(form, NULL, TRUE, _SoXtColorSlider::INTENSITY_SLIDER);
changedIt[i] = FALSE;
slidersW[i] = sliders[i]->getWidget();
}
// set base colors for the non-color sliders: white
SbColor white(1, 1, 1);
ignoreCallback = TRUE;
sliders[k_SHININESS_ID]->setBaseColor(white.getValue());
sliders[k_TRANSPARENCY_ID]->setBaseColor(white.getValue());
ignoreCallback = FALSE;
// Callbacks
#define ADD_SLIDER_CALLBACK(SLIDER,CB) \
SLIDER->addValueChangedCallback( \
&SoXtMaterialEditor::CB, this);
ADD_SLIDER_CALLBACK(sliders[k_AMBIENT_ID], ambientSliderCB);
ADD_SLIDER_CALLBACK(sliders[k_DIFFUSE_ID], diffuseSliderCB);
ADD_SLIDER_CALLBACK(sliders[k_SPECULAR_ID], specularSliderCB);
ADD_SLIDER_CALLBACK(sliders[k_EMISSIVE_ID], emissiveSliderCB);
ADD_SLIDER_CALLBACK(sliders[k_SHININESS_ID], shininessSliderCB);
ADD_SLIDER_CALLBACK(sliders[k_TRANSPARENCY_ID], transparencySliderCB);
#undef ADD_SLIDER_CALLBACK
// build diamond buttons
n = 0;
XtSetArg(args[n], XmNuserData, this); n++;
XtSetArg(args[n], XmNhighlightThickness, 0); n++;
XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); n++;
for (i=0; i<4; i++) {
diamondButtons[i] = XtCreateWidget("", xmToggleButtonGadgetClass,
textForm, args, n);
XtAddCallback(diamondButtons[i], XmNvalueChangedCallback,
(XtCallbackProc) SoXtMaterialEditor::diamondButtonPick, (XtPointer) i);
}
// build radio buttons
n = 0;
XtSetArg(args[n], XmNuserData, this); n++;
XtSetArg(args[n], XmNhighlightThickness, 0); n++;
for (i=0; i<4; i++) {
radioButtons[i] = XtCreateWidget("", xmToggleButtonGadgetClass,
textForm, args, n);
XtAddCallback(radioButtons[i], XmNvalueChangedCallback,
(XtCallbackProc) SoXtMaterialEditor::radioButtonPick, (XtPointer) i);
}
// build label widgets
for (i=0; i<6; i++)
labelW[i] = XtCreateWidget(slider_labels[i], xmLabelGadgetClass,
textForm, NULL, 0);
//
// layout
//
// layout the text form
n = 0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightAttachment, XmNONE); n++;
XtSetValues(textForm, args, n);
// layout the toggles, text and sliders
int y1, y2;
for (i=0; i<6; i++) {
y1 = int((i*(1000-SLIDER_SPACE))/6.0);
y2 = int(((i+1)*(1000-SLIDER_SPACE))/6.0);
if (i >= 4) {
y1 += SLIDER_SPACE;
y2 += SLIDER_SPACE;
}
// set the vertical attachement for all widgets
XtSetArg(args[0], XmNtopAttachment, XmATTACH_POSITION);
XtSetArg(args[1], XmNtopPosition, y1);
XtSetArg(args[2], XmNbottomAttachment, XmATTACH_POSITION);
XtSetArg(args[3], XmNbottomPosition, y2);
// layout the sliders
XtSetArg(args[4], XmNleftAttachment, XmATTACH_WIDGET);
XtSetArg(args[5], XmNleftWidget, textForm);
XtSetArg(args[6], XmNrightAttachment, XmATTACH_FORM);
XtSetValues(slidersW[i], args, 7);
// layout the toggles
if (i < 4) {
// layout diamonds
XtSetArg(args[4], XmNleftAttachment, XmATTACH_FORM);
XtSetValues(diamondButtons[i], args, 5);
// layout radio
XtSetArg(args[4], XmNleftAttachment, XmATTACH_WIDGET);
XtSetArg(args[5], XmNleftWidget, diamondButtons[i]);
XtSetValues(radioButtons[i], args, 6);
}
// layout the text
XtSetArg(args[4], XmNrightAttachment, XmATTACH_FORM);
XtSetArg(args[5], XmNalignment, XmALIGNMENT_END);
if (i < 4) {
XtSetArg(args[6], XmNleftAttachment, XmATTACH_WIDGET);
XtSetArg(args[7], XmNleftWidget, radioButtons[i]);
XtSetValues(labelW[i], args, 8);
}
else
XtSetValues(labelW[i], args, 6);
}
// manage all children (order is important)
XtManageChildren(diamondButtons, 4);
XtManageChildren(radioButtons, 4);
XtManageChildren(labelW, 6);
XtManageChild(textForm);
XtManageChildren(slidersW, 6);
return form;
}
////////////////////////////////////////////////////////////////////////
//
// Builds and layout the edit label with the slider form.
//
// usage: private
//
Widget
SoXtMaterialEditor::buildControls(Widget parent)
//
////////////////////////////////////////////////////////////////////////
{
Widget form, sliderForm, labelW, separatorW;
int n;
Arg args[12];
// create a form to hold everything together
form = XtCreateWidget("Controls", xmFormWidgetClass, parent, NULL, 0);
labelW = XtCreateWidget("Edit Color", xmLabelGadgetClass, form, NULL, 0);
separatorW = XtCreateWidget("", xmSeparatorGadgetClass, form, NULL, 0);
sliderForm = buildSlidersForm(form);
// layout
n = 0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetValues(labelW, args, n);
n = 0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNtopWidget, labelW); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
XtSetArg(args[n], XmNleftWidget, labelW); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
XtSetArg(args[n], XmNrightWidget, labelW); n++;
XtSetValues(separatorW, args, n);
n = 0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNtopWidget, separatorW); n++;
XtSetArg(args[n], XmNtopOffset, 2); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetValues(sliderForm, args, n);
// manage children
XtManageChild(labelW);
XtManageChild(separatorW);
XtManageChild(sliderForm);
return form;
}
#ifdef DEBUG
// ??? add XK_Print event to dump the scene to stdout
#include <X11/keysym.h>
#include <Inventor/actions/SoWriteAction.h>
static SbBool dump(void *p, XAnyEvent *xe)
{
if (xe->type == KeyPress && XLookupKeysym((XKeyEvent *)xe, 0) == XK_Print) {
SoWriteAction wa;
wa.getOutput()->setFilePointer(stderr);
fprintf(stderr, "\n___SoXtMaterialEditor____scene____\n");
wa.apply( ((SoXtRenderArea *)p)->getSceneGraph() );
}
return FALSE;
}
#endif
////////////////////////////////////////////////////////////////////////
//
// This routine builds all the widgets, sets up callback routines,
// and does the layout using motif.
//
// usage: private
//
Widget
SoXtMaterialEditor::buildWidget(Widget parent)
//
////////////////////////////////////////////////////////////////////////
{
int n;
Arg args[12];
//
// create a top level form to hold everything together
//
SbVec2s size = getSize();
n = 0;
if ((size[0] != 0) && (size[1] != 0)) {
XtSetArg(args[n], XtNwidth, size[0]); n++;
XtSetArg(args[n], XtNheight, size[1]); n++;
}
// create the top level widget, and register it with a class name
mgrWidget = XtCreateWidget(getWidgetName(), xmFormWidgetClass, parent, args, n);
registerWidget(mgrWidget);
//
// read the X resource for this widget (1)
//
SoXtResource xr(mgrWidget);
if (!xr.getResource("ambientLabel", "AmbientLabel", ambientString))
ambientString = deftitles[0];
if (!xr.getResource("diffuseLabel", "DiffuseLabel", diffuseString))
diffuseString = deftitles[1];
if (!xr.getResource("specularLabel","SpecularLabel",specularString))
specularString = deftitles[2];
if (!xr.getResource("emissiveLabel","EmissiveLabel",emissiveString))
emissiveString = deftitles[3];
if (!xr.getResource("slideLabel1", "SlideLabel1", slider_labels[0]))
slider_labels[0] = slider_defs[0];
if (!xr.getResource("slideLabel2", "SlideLabel2", slider_labels[1]))
slider_labels[1] = slider_defs[1];
if (!xr.getResource("slideLabel3", "SlideLabel3", slider_labels[2]))
slider_labels[2] = slider_defs[2];
if (!xr.getResource("slideLabel4", "SlideLabel4", slider_labels[3]))
slider_labels[3] = slider_defs[3];
if (!xr.getResource("slideLabel5", "SlideLabel5", slider_labels[4]))
slider_labels[4] = slider_defs[4];
if (!xr.getResource("slideLabel6", "SlideLabel6", slider_labels[5]))
slider_labels[5] = slider_defs[5];
//
// build the subcomponents
//
Widget menubar = buildPulldownMenu(mgrWidget);
// create the render area
renderArea = new SoXtRenderArea(mgrWidget);
renderArea->setSceneGraph(root);
renderArea->setTransparencyType(SoGLRenderAction::BLEND); // sphere is last
renderArea->setClearBeforeRender(FALSE); // reduce flicker
#ifdef DEBUG
// ??? add XK_Print event to dump the scene to stdout
renderArea->setEventCallback(dump, renderArea);
#endif
#if 0
int32_t bitnum = getgdesc(GD_BITS_NORM_DBL_RED)
+ getgdesc(GD_BITS_NORM_DBL_GREEN)
+ getgdesc(GD_BITS_NORM_DBL_BLUE);
if (bitnum < 12)
renderArea->setDoubleBuffer(FALSE);
#endif
Widget controls = buildControls(mgrWidget);
n = 0;
XtSetArg(args[n], XmNhighlightThickness, 0); n++;
acceptButton = XtCreateWidget("Accept", xmPushButtonGadgetClass, mgrWidget, args, n);
XtAddCallback(acceptButton, XmNactivateCallback,
(XtCallbackProc) &SoXtMaterialEditor::acceptButtonCB,
(XtPointer) this);
//
// Layout
//
n = 0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNrightPosition, SCENE_RIGHT_POSITION); n++;
XtSetValues(menubar, args, n);
n = 0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNtopWidget, menubar); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNrightPosition, SCENE_RIGHT_POSITION); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomOffset, 34); n++;
XtSetValues(renderArea->getWidget(), args, n);
n = 0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNleftPosition, SCENE_RIGHT_POSITION/2 - 7); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNrightPosition, SCENE_RIGHT_POSITION/2 + 7); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomOffset, OFFSET); n++;
XtSetValues(acceptButton, args, n);
n = 0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNtopOffset, OFFSET); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNleftPosition, SCENE_RIGHT_POSITION); n++;
XtSetArg(args[n], XmNleftOffset, OFFSET); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightOffset, OFFSET); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomOffset, OFFSET); n++;
XtSetValues(controls, args, n);
//
// manage all children
//
XtManageChild(menubar);
renderArea->show();
XtManageChild(controls);
//
// read the X resource for this widget (2)
//
char *val;
SbColor c;
if (xr.getResource("tile1Color", "Tile1Color", c)) {
tileColor->rgb.setValues(0, 1, &c);
tileColor->rgb.setValues(3, 1, &c);
}
if (xr.getResource("tile2Color", "Tile2Color", c)) {
tileColor->rgb.setValues(1, 1, &c);
tileColor->rgb.setValues(2, 1, &c);
}
if (xr.getResource("light1Color", "Light1Color", c)) {
light0->color.setValue(c);
}
if (xr.getResource("light2Color", "Light2Color", c)) {
light1->color.setValue(c);
}
if (xr.getResource("updateFrequency", "UpdateFrequency", val)) {
if (strcmp(val, "continuous") == 0)
updateFreq = CONTINUOUS;
else if (strcmp(val, "manual") == 0)
updateFreq = AFTER_ACCEPT;
}
if (updateFreq == AFTER_ACCEPT)
XtManageChild(acceptButton);
// update the sliders based on local scene
updateLocalComponents();
return mgrWidget;
}
////////////////////////////////////////////////////////////////////////
//
// This routine attaches itself to a material node and edit the given
// material index.
//
// usage: public
//
void
SoXtMaterialEditor::attach(SoMaterial *mtl, int ind)
//
////////////////////////////////////////////////////////////////////////
{
if ( isAttached() )
detach();
if (mtl != NULL && ind >= 0) {
material = mtl;
material->ref();
index = ind;
// set all parameters as unchanged by the editor
for (int i=0; i<6; i++)
changedIt[i] = FALSE;
if (isVisible())
activate(); // updates and attaches sensor
}
}
////////////////////////////////////////////////////////////////////////
//
// This routine detaches itself from the material node.
//
// usage: public
void
SoXtMaterialEditor::detach()
//
////////////////////////////////////////////////////////////////////////
{
if ( ! isAttached() )
return;
deactivate(); // detaches sensor
material->unref();
material = NULL;
}
////////////////////////////////////////////////////////////////////////
//
// This routine activates the editor's sensor, if it is indeed attached.
// It does not affect the editor's attachment status.
//
// usage: private
//
void
SoXtMaterialEditor::activate()
//
////////////////////////////////////////////////////////////////////////
{
// attach sensor to its material
if ( isAttached() && sensor->getAttachedNode() == NULL) {
copyMaterial(localMaterial, 0, material, index);
updateLocalComponents();
sensor->attach(material); // attach AFTER update
}
}
////////////////////////////////////////////////////////////////////////
//
// This routine deactivates the editor's sensor without affecting
// it's attachent status.
//
// usage: private
void
SoXtMaterialEditor::deactivate()
//
////////////////////////////////////////////////////////////////////////
{
sensor->detach();
}
////////////////////////////////////////////////////////////////////////
//
// Callback routine from the color editor, this changes the color
// of the material node we are attached to.
//
// usage: static, private
//
void
SoXtMaterialEditor::colorEditorCB(
void *userData,
const SbColor *rgbColor)
//
////////////////////////////////////////////////////////////////////////
{
SoXtMaterialEditor *me = (SoXtMaterialEditor *) userData;
SbColor finalColor;
SbBool updateMaterial = (me->material != NULL && me->updateFreq == CONTINUOUS);
if (me->ignoreCallback)
return;
//
// check which slider(s) needs to be updated
//
// update the slider base color, the local material
// and the attached material. The final material color is
// finalColor = baseColor * sliderScaleValue.
//
// detach sensor while we update the fields and prevent slider callbacks
if (updateMaterial)
me->sensor->detach();
me->ignoreCallback = TRUE;
if (me->activeColor & k_ambient) {
me->sliders[k_AMBIENT_ID]->setBaseColor(rgbColor->getValue());
finalColor = rgbColor->getValue();
finalColor *= me->sliders[k_AMBIENT_ID]->getValue();
me->localMaterial->ambientColor.setValue(finalColor);
me->changedIt[k_AMBIENT_ID] = TRUE;
if (updateMaterial) {
me->material->ambientColor.set1Value(me->index, finalColor);
if ( me->material->ambientColor.isIgnored() )
me->material->ambientColor.setIgnored( FALSE );
}
}
if (me->activeColor & k_diffuse) {
me->sliders[k_DIFFUSE_ID]->setBaseColor(rgbColor->getValue());
finalColor = rgbColor->getValue();
finalColor *= me->sliders[k_DIFFUSE_ID]->getValue();
me->localMaterial->diffuseColor.setValue(finalColor);
me->changedIt[k_DIFFUSE_ID] = TRUE;
if (updateMaterial) {
me->material->diffuseColor.set1Value(me->index, finalColor);
if ( me->material->diffuseColor.isIgnored() )
me->material->diffuseColor.setIgnored( FALSE );
}
}
if (me->activeColor & k_specular) {
me->sliders[k_SPECULAR_ID]->setBaseColor(rgbColor->getValue());
finalColor = rgbColor->getValue();
finalColor *= me->sliders[k_SPECULAR_ID]->getValue();
me->localMaterial->specularColor.setValue(finalColor);
me->changedIt[k_SPECULAR_ID] = TRUE;
if (updateMaterial) {
me->material->specularColor.set1Value(me->index, finalColor);
if ( me->material->specularColor.isIgnored() )
me->material->specularColor.setIgnored( FALSE );
}
}
if (me->activeColor & k_emissive) {
me->sliders[k_EMISSIVE_ID]->setBaseColor(rgbColor->getValue());
finalColor = rgbColor->getValue();
finalColor *= me->sliders[k_EMISSIVE_ID]->getValue();
me->localMaterial->emissiveColor.setValue(finalColor);
me->changedIt[k_EMISSIVE_ID] = TRUE;
if (updateMaterial) {
me->material->emissiveColor.set1Value(me->index, finalColor);
if ( me->material->emissiveColor.isIgnored() )
me->material->emissiveColor.setIgnored( FALSE );
}
}
// invoke the callbacks with the new material
if (me->updateFreq == CONTINUOUS)
me->callbackList->invokeCallbacks(me->localMaterial);
// re-attach the sensor and callbacks
if (updateMaterial)
me->sensor->attach(me->material);
me->ignoreCallback = FALSE;
}
////////////////////////////////////////////////////////////////////////
//
// Callback invoked when shininess slider changes value.
//
// usage: static, private
//
void
SoXtMaterialEditor::shininessSliderCB(
void *userData,
float value)
//
////////////////////////////////////////////////////////////////////////
{
SoXtMaterialEditor *me = (SoXtMaterialEditor *) userData;
if (me->ignoreCallback)
return;
if (me->material != NULL && me->updateFreq == CONTINUOUS) {
// detach the sensor while we update the field
me->sensor->detach();
me->material->shininess.set1Value(me->index, value);
if ( me->material->shininess.isIgnored() )
me->material->shininess.setIgnored( FALSE );
me->sensor->attach(me->material);
}
me->localMaterial->shininess.setValue(value);
me->changedIt[k_SHININESS_ID] = TRUE;
// invoke the callbacks with the new material
if (me->updateFreq == CONTINUOUS)
me->callbackList->invokeCallbacks(me->localMaterial);
}
////////////////////////////////////////////////////////////////////////
//
// Callback invoked when transparency slider changes value.
//
// usage: static, private
//
void
SoXtMaterialEditor::transparencySliderCB(
void *userData,
float value)
//
////////////////////////////////////////////////////////////////////////
{
SoXtMaterialEditor *me = (SoXtMaterialEditor *) userData;
if (me->ignoreCallback)
return;
if (me->material != NULL && me->updateFreq == CONTINUOUS) {
// detach the sensor while we update the field
me->sensor->detach();
me->material->transparency.set1Value(me->index, value);
if ( me->material->transparency.isIgnored() )
me->material->transparency.setIgnored( FALSE );
me->sensor->attach(me->material);
}
me->localMaterial->transparency.setValue(value);
me->changedIt[k_TRANSPARENCY_ID] = TRUE;
// invoke the callbacks with the new material
if (me->updateFreq == CONTINUOUS)
me->callbackList->invokeCallbacks(me->localMaterial);
}
////////////////////////////////////////////////////////////////////////
//
// Convenience routine invoked when ambient/diffuse/specualr/emissive
// sliders value changed.
//
// usage: private
//
void
SoXtMaterialEditor::updateMaterialColor(
SoMFColor *editMtlColor,
SoMFColor *localMtlColor,
const float *rgb,
float intensity)
//
////////////////////////////////////////////////////////////////////////
{
SbColor intensityColor(rgb);
intensityColor *= intensity;
if (editMtlColor != NULL && updateFreq == CONTINUOUS) {
// detach the sensor while we update the field
sensor->detach();
editMtlColor->set1Value(index, intensityColor);
if ( editMtlColor->isIgnored() )
editMtlColor->setIgnored( FALSE );
sensor->attach(material);
}
localMtlColor->setValue(intensityColor);
// invoke the callbacks with the new material
if (updateFreq == CONTINUOUS)
callbackList->invokeCallbacks(localMaterial);
}
////////////////////////////////////////////////////////////////////////
//
// Callback routine invoked when ambient slider value changed.
// We use the ambient slider base color and slider value to determine
// the new color for the edit and local material ambientColor field.
//
// usage: static, private
//
void
SoXtMaterialEditor::ambientSliderCB(
void *userData,
float intensity)
//
////////////////////////////////////////////////////////////////////////
{
SoXtMaterialEditor *me = (SoXtMaterialEditor *) userData;
if (me->ignoreCallback)
return;
me->updateMaterialColor(
(me->material != NULL) ? &me->material->ambientColor : NULL,
&me->localMaterial->ambientColor,
me->sliders[k_AMBIENT_ID]->getBaseColor(),
intensity);
me->changedIt[k_AMBIENT_ID] = TRUE;
}
////////////////////////////////////////////////////////////////////////
//
// Callback routine invoked when diffuse slider value changed.
// We use the diffuse slider base color and slider value to determine
// the new color for the edit and local material diffuseColor field.
//
// usage: static, private
//
void
SoXtMaterialEditor::diffuseSliderCB(
void *userData,
float intensity)
//
////////////////////////////////////////////////////////////////////////
{
SoXtMaterialEditor *me = (SoXtMaterialEditor *) userData;
if (me->ignoreCallback)
return;
me->updateMaterialColor(
(me->material != NULL) ? &me->material->diffuseColor : NULL,
&me->localMaterial->diffuseColor,
me->sliders[k_DIFFUSE_ID]->getBaseColor(),
intensity);
me->changedIt[k_DIFFUSE_ID] = TRUE;
}
////////////////////////////////////////////////////////////////////////
//
// Callback routine invoked when specular slider value changed.
// We use the specular slider base color and slider value to determine
// the new color for the edit and local material specularColor field.
//
// usage: static, private
//
void
SoXtMaterialEditor::specularSliderCB(
void *userData,
float intensity)
//
////////////////////////////////////////////////////////////////////////
{
SoXtMaterialEditor *me = (SoXtMaterialEditor *) userData;
if (me->ignoreCallback)
return;
me->updateMaterialColor(
(me->material != NULL) ? &me->material->specularColor : NULL,
&me->localMaterial->specularColor,
me->sliders[k_SPECULAR_ID]->getBaseColor(),
intensity);
me->changedIt[k_SPECULAR_ID] = TRUE;
}
////////////////////////////////////////////////////////////////////////
//
// Callback routine invoked when emissive slider value changed.
// We use the emissive slider base color and slider value to determine
// the new color for the edit and local material emissiveColor field.
//
// usage: static, private
//
void
SoXtMaterialEditor::emissiveSliderCB(
void *userData,
float intensity)
//
////////////////////////////////////////////////////////////////////////
{
SoXtMaterialEditor *me = (SoXtMaterialEditor *) userData;
if (me->ignoreCallback)
return;
me->updateMaterialColor(
(me->material != NULL) ? &me->material->emissiveColor : NULL,
&me->localMaterial->emissiveColor,
me->sliders[k_EMISSIVE_ID]->getBaseColor(),
intensity);
me->changedIt[k_EMISSIVE_ID] = TRUE;
}
////////////////////////////////////////////////////////////////////////
//
// Convenience routine which updates the given slider, from the given
// material color (have to split the base color and intensity).
//
// Use: private
//
void
SoXtMaterialEditor::updateColorSlider(
_SoXtColorSlider *slider,
const float rgb[3])
//
////////////////////////////////////////////////////////////////////////
{
float max;
float baseColor[3];
// get color intensity
max = (rgb[0] > rgb[1]) ?
((rgb[0] > rgb[2]) ? rgb[0] : rgb[2]) :
((rgb[1] > rgb[2]) ? rgb[1] : rgb[2]);
if (max == 0.0) // handle special case
baseColor[0] = baseColor[1] = baseColor[2] = 1.0;
else {
// scale the color to full intensity
float scale = 1.0 / max;
baseColor[0] = rgb[0] * scale;
baseColor[1] = rgb[1] * scale;
baseColor[2] = rgb[2] * scale;
}
// now set the slider to the right baseColor and value
ignoreCallback = TRUE;
slider->setBaseColor(baseColor);
slider->setValue(max);
ignoreCallback = FALSE;
}
////////////////////////////////////////////////////////////////////////
//
// Copies material2 onto material1
//
// Use: private
//
void
SoXtMaterialEditor::copyMaterial(SoMaterial *mat1, int ind1,
const SoMaterial *mat2, int ind2)
//
////////////////////////////////////////////////////////////////////////
{
mat1->ambientColor.set1Value(ind1, mat2->ambientColor[ind2]);
mat1->diffuseColor.set1Value(ind1, mat2->diffuseColor[ind2]);
mat1->specularColor.set1Value(ind1, mat2->specularColor[ind2]);
mat1->emissiveColor.set1Value(ind1, mat2->emissiveColor[ind2]);
mat1->shininess.set1Value(ind1, mat2->shininess[ind2]);
mat1->transparency.set1Value(ind1, mat2->transparency[ind2]);
}
////////////////////////////////////////////////////////////////////////
//
// For each of the 6 sliders (or sets of sliders) sets the ignore flag
// of the material node being editted to FALSE if it has been changed.
//
// Use: private
//
void
SoXtMaterialEditor::undoIgnoresIfChanged()
//
////////////////////////////////////////////////////////////////////////
{
if ( changedIt[k_AMBIENT_ID] )
material->ambientColor.setIgnored( FALSE );
if ( changedIt[k_DIFFUSE_ID] )
material->diffuseColor.setIgnored( FALSE );
if ( changedIt[k_SPECULAR_ID] )
material->specularColor.setIgnored( FALSE );
if ( changedIt[k_EMISSIVE_ID] )
material->emissiveColor.setIgnored( FALSE );
if ( changedIt[k_SHININESS_ID] )
material->shininess.setIgnored( FALSE );
if ( changedIt[k_TRANSPARENCY_ID] )
material->transparency.setIgnored( FALSE );
}
////////////////////////////////////////////////////////////////////////
//
// Update the sliders and colorEditor based on the local material.
//
// Use: private
//
void
SoXtMaterialEditor::updateLocalComponents()
//
////////////////////////////////////////////////////////////////////////
{
// Update the color sliders to reflect these values
updateColorSlider(sliders[k_AMBIENT_ID], localMaterial->ambientColor[0].getValue());
updateColorSlider(sliders[k_DIFFUSE_ID], localMaterial->diffuseColor[0].getValue());
updateColorSlider(sliders[k_SPECULAR_ID], localMaterial->specularColor[0].getValue());
updateColorSlider(sliders[k_EMISSIVE_ID], localMaterial->emissiveColor[0].getValue());
// update non color sliders
ignoreCallback = TRUE;
sliders[k_SHININESS_ID]->setValue(localMaterial->shininess[0]);
sliders[k_TRANSPARENCY_ID]->setValue(localMaterial->transparency[0]);
ignoreCallback = FALSE;
updateColorEditor();
}
////////////////////////////////////////////////////////////////////////
//
// updates the colorEditor (show/hide and update color) based on
// the activeColor flag.
//
// usage: private
//
void
SoXtMaterialEditor::updateColorEditor(SbBool updateTitle)
//
////////////////////////////////////////////////////////////////////////
{
// show/hide the colorEditor
if (activeColor == k_none) {
if (colorEditor == NULL || ! colorEditor->isVisible())
return;
colorEditor->hide();
return;
}
else {
if (colorEditor == NULL) {
// build comp under our shell widget
colorEditor = new _SoXtColorEditor(
SoXt::getShellWidget(getWidget()),
NULL, FALSE);
colorEditor->setCurrentSliders(_SoXtColorEditor::NONE);
colorEditor->addColorChangedCallback(
SoXtMaterialEditor::colorEditorCB, this);
// add a close window callback so that toggles
// can reflect the change (turn them off)
colorEditor->setWindowCloseCallback(
SoXtMaterialEditor::colorEditorCloseCB, this);
}
colorEditor->show();
}
// sets the right color, ignoring the colorEditor callback
ignoreCallback = TRUE;
switch (activeColor) {
case k_none:
break;
case k_ambient:
colorEditor->setColor(sliders[k_AMBIENT_ID]->getBaseColor());
if (updateTitle)
colorEditor->setTitle(ambientString);
break;
case k_diffuse:
colorEditor->setColor(sliders[k_DIFFUSE_ID]->getBaseColor());
if (updateTitle)
colorEditor->setTitle(diffuseString);
break;
case k_specular:
colorEditor->setColor(sliders[k_SPECULAR_ID]->getBaseColor());
if (updateTitle)
colorEditor->setTitle(specularString);
break;
case k_emissive:
colorEditor->setColor(sliders[k_EMISSIVE_ID]->getBaseColor());
if (updateTitle)
colorEditor->setTitle(emissiveString);
break;
default:
// ??? this is not really perfect because the colorEditor
// ??? doesn't yet support a mutiple attach state (where sliders
// ??? also reflect the conficting colors)
if (updateTitle) {
char str[50];
strcpy(str, "Material ");
if (activeColor & k_ambient)
strcat(str, "Amb/");
if (activeColor & k_diffuse)
strcat(str, "Diff/");
if (activeColor & k_specular)
strcat(str, "Spec/");
if (activeColor & k_emissive)
strcat(str, "Emis/");
str[strlen(str) - 1] = ' ';
strcat(str, "Color");
colorEditor->setTitle(str);
}
break;
}
ignoreCallback = FALSE;
}
////////////////////////////////////////////////////////////////////////
//
// Sensor callback, invoked whenever the edited material node changes
// (other than when we change it).
//
// Use: private
//
void
SoXtMaterialEditor::sensorCB(void *p, SoSensor *)
//
////////////////////////////////////////////////////////////////////////
{
SoXtMaterialEditor *me = (SoXtMaterialEditor *)p;
if (!me->isVisible())
return;
// copy edited material over and update sliders/colorEditor
me->copyMaterial(me->localMaterial, 0, me->material, me->index);
me->updateLocalComponents();
}
////////////////////////////////////////////////////////////////////////
//
// Called by Xt when a menu is about to be displayed.
// This gives us a chance to update any items in the menu.
//
// Use: private
//
void
SoXtMaterialEditor::menuDisplay(Widget, SoXtMaterialEditor *me, XtPointer)
//
////////////////////////////////////////////////////////////////////////
{
if (me->updateFreq == CONTINUOUS) {
TOGGLE_ON(me->menuItemsList[k_CONTINUOUS]);
TOGGLE_OFF(me->menuItemsList[k_AFTER_ACCEPT]);
}
else {
TOGGLE_OFF(me->menuItemsList[k_CONTINUOUS]);
TOGGLE_ON(me->menuItemsList[k_AFTER_ACCEPT]);
}
}
////////////////////////////////////////////////////////////////////////
//
// Called by Xt when a menu item is picked.
//
// Use: private
//
void
SoXtMaterialEditor::menuPick(
Widget w,
int id,
XmAnyCallbackStruct *cb)
//
////////////////////////////////////////////////////////////////////////
{
SoXtMaterialEditor *p;
XtVaGetValues(w, XmNuserData, &p, NULL);
Time eventTime = cb->event->xbutton.time;
switch (id) {
case k_CONTINUOUS:
p->setUpdateFrequency(CONTINUOUS);
break;
case k_AFTER_ACCEPT:
p->setUpdateFrequency(AFTER_ACCEPT);
break;
case k_MATERIAL_LIST:
// build comp under our shell widget
if (p->materialList == NULL) {
p->materialList = new SoXtMaterialList(
SoXt::getShellWidget(p->getWidget()),
NULL, FALSE, mtlDir);
p->materialList->addCallback(
SoXtMaterialEditor::materialListCB, p);
p->materialList->setWindowCloseCallback(
SoXtMaterialEditor::materialListCloseCB, p);
}
p->materialList->show();
p->openMaterialList = TRUE;
break;
case k_EDIT_COPY:
if (p->clipboard == NULL)
p->clipboard = new SoXtClipboard(p->getWidget());
p->clipboard->copy(p->localMaterial, eventTime);
break;
case k_EDIT_PASTE:
if (p->clipboard == NULL)
p->clipboard = new SoXtClipboard(p->getWidget());
p->clipboard->paste(eventTime,
SoXtMaterialEditor::pasteDone,
p);
break;
default:
#if DEBUG
SoDebugError::post("SoXtMaterialEditor::menuPick",
"id %d", id);
#endif
break;
case k_EDIT_HELP:
p->openHelpCard("SoXtMaterialEditor.help");
break;
}
}
////////////////////////////////////////////////////////////////////////
//
// Called by Xt when a diamond radio button is picked.
//
// Use: static private
//
void
SoXtMaterialEditor::diamondButtonPick(Widget w, int ID, XtPointer)
//
////////////////////////////////////////////////////////////////////////
{
SoXtMaterialEditor *p;
Arg args[1];
int i;
XtSetArg(args[0], XmNuserData, &p);
XtGetValues(w, args, 1);
if (XmToggleButtonGetState(w)) { // select only this slider
// clear all other toggles
for (i=0; i<4; i++) {
if (i == ID)
TOGGLE_ON(p->radioButtons[i]);
else {
TOGGLE_OFF(p->diamondButtons[i]);
TOGGLE_OFF(p->radioButtons[i]);
}
}
// set the activeColor flag
switch(ID) {
case k_AMBIENT_ID: p->activeColor = k_ambient; break;
case k_DIFFUSE_ID: p->activeColor = k_diffuse; break;
case k_SPECULAR_ID: p->activeColor = k_specular; break;
case k_EMISSIVE_ID: p->activeColor = k_emissive; break;
}
}
else { // no slider selected, clear the activeColor flag
TOGGLE_OFF(p->radioButtons[ID]);
p->activeColor = k_none;
}
// finally update the colorEditor
p->updateColorEditor(TRUE);
}
////////////////////////////////////////////////////////////////////////
//
// Called by Xt when a radio button is picked.
//
// Use: static private
//
void
SoXtMaterialEditor::radioButtonPick(Widget w, int ID, XtPointer)
//
////////////////////////////////////////////////////////////////////////
{
SoXtMaterialEditor *p;
Arg args[1];
int i;
XtSetArg(args[0], XmNuserData, &p);
XtGetValues(w, args, 1);
if (XmToggleButtonGetState(w)) { // select this slider
if (p->activeColor == k_none)
TOGGLE_ON(p->diamondButtons[ID]);
else {
for (i=0; i<4; i++)
TOGGLE_OFF(p->diamondButtons[i]);
}
// set the right bit
switch(ID) {
case k_AMBIENT_ID: p->activeColor |= k_ambient; break;
case k_DIFFUSE_ID: p->activeColor |= k_diffuse; break;
case k_SPECULAR_ID: p->activeColor |= k_specular; break;
case k_EMISSIVE_ID: p->activeColor |= k_emissive; break;
}
}
else { // unselect this slider
TOGGLE_OFF(p->diamondButtons[ID]);
// clear the right bit
switch(ID) {
case k_AMBIENT_ID: p->activeColor &= ~k_ambient; break;
case k_DIFFUSE_ID: p->activeColor &= ~k_diffuse; break;
case k_SPECULAR_ID: p->activeColor &= ~k_specular; break;
case k_EMISSIVE_ID: p->activeColor &= ~k_emissive; break;
}
// check if a diamond button can be set (i.e. only one slider selected)
switch (p->activeColor) {
case k_ambient: TOGGLE_ON(p->diamondButtons[k_AMBIENT_ID]); break;
case k_diffuse: TOGGLE_ON(p->diamondButtons[k_DIFFUSE_ID]); break;
case k_specular: TOGGLE_ON(p->diamondButtons[k_SPECULAR_ID]); break;
case k_emissive: TOGGLE_ON(p->diamondButtons[k_EMISSIVE_ID]); break;
}
}
// finally update the colorEditor
p->updateColorEditor(TRUE);
}
////////////////////////////////////////////////////////////////////////
//
// called when the accept button gets pressed.
//
// usage: static, private
//
void
SoXtMaterialEditor::acceptButtonCB(Widget, SoXtMaterialEditor *me, XtPointer)
//
////////////////////////////////////////////////////////////////////////
{
// copy the local material to the edited material
if (me->material != NULL) {
// detach the sensor while we update the fields
me->sensor->detach();
me->copyMaterial(me->material, me->index, me->localMaterial, 0);
me->undoIgnoresIfChanged();
me->sensor->attach(me->material);
}
// invoke the callbacks with the new material
me->callbackList->invokeCallbacks(me->localMaterial);
}
////////////////////////////////////////////////////////////////////////
//
// Set the local material and the edited material to the passed value.
//
// usage: public
//
void
SoXtMaterialEditor::setMaterial(const SoMaterial &mtl)
//
////////////////////////////////////////////////////////////////////////
{
// copy the new material locally and update the sliders
copyMaterial(localMaterial, 0, &mtl, 0);
updateLocalComponents();
// signal that values have been loaded into all fields
for (int i = 0; i < 6; i++)
changedIt[i] = TRUE;
// update the attached material
if (material != NULL && updateFreq == CONTINUOUS) {
// detach the sensor while we update the fields
sensor->detach();
copyMaterial(material, index, &mtl, 0);
undoIgnoresIfChanged();
sensor->attach(material);
}
// invoke the callbacks with the new material
if (updateFreq == CONTINUOUS)
callbackList->invokeCallbacks(localMaterial);
}
////////////////////////////////////////////////////////////////////////
//
// Callback invoked when a material is chosen from whithin the material list
//
// usage: static, private
//
void
SoXtMaterialEditor::materialListCB(
void *me,
const SoMaterial *mtl)
//
////////////////////////////////////////////////////////////////////////
{
((SoXtMaterialEditor *)me)->setMaterial(*mtl);
}
////////////////////////////////////////////////////////////////////////
//
// The X server has finished getting the selection data, and the
// paste is complete. Look through the paste data for a material node.
//
// Use: static private
//
void
SoXtMaterialEditor::pasteDone(void *pt, SoPathList *pathList)
//
////////////////////////////////////////////////////////////////////////
{
SoXtMaterialEditor *p = (SoXtMaterialEditor *) pt;
SoSearchAction sa;
SoPath *path = NULL;
//
// search for first material in that pasted scene
//
sa.setType(SoMaterial::getClassTypeId());
for (int i=0; i < pathList->getLength(); i++) {
sa.apply( (*pathList)[i] );
if ( (path = sa.getPath()) != NULL) {
// assign new material
p->setMaterial(*((SoMaterial *) path->getTail()));
break;
}
}
// ??? what if a color is pasted. I guess they should paste into the
// ??? color editor used by the component, rather than us trying
// ??? to create a material based on the given color. (alain)
// ??? We delete the callback data when done with it.
delete pathList;
}
//
// called when the color editor gets closed by the user (turn the toggle off
// and hide the component).
//
void
SoXtMaterialEditor::colorEditorCloseCB(void *pt, SoXtComponent *comp)
{
SoXtMaterialEditor *p = (SoXtMaterialEditor *)pt;
for (int i=0; i<4; i++) {
TOGGLE_OFF(p->diamondButtons[i]);
TOGGLE_OFF(p->radioButtons[i]);
}
p->activeColor = k_none;
comp->hide();
}
//
// called when the material list gets closed by the user.
//
void
SoXtMaterialEditor::materialListCloseCB(void *pt, SoXtComponent *comp)
{
SoXtMaterialEditor *p = (SoXtMaterialEditor *)pt;
p->openMaterialList = FALSE;
comp->hide();
}
//
// called whenever the component becomes visibble or not
//
void
SoXtMaterialEditor::visibilityChangeCB(void *pt, SbBool visible)
{
SoXtMaterialEditor *p = (SoXtMaterialEditor *)pt;
if (visible)
p->activate();
else
p->deactivate();
}
//
// redefine those generic virtual functions
//
const char *
SoXtMaterialEditor::getDefaultWidgetName() const
{ return thisClassName; }
const char *
SoXtMaterialEditor::getDefaultTitle() const
{ return "Material Editor"; }
const char *
SoXtMaterialEditor::getDefaultIconTitle() const
{ return "Mat Editor"; }