/* * * 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/ * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "DisplayGraph.h" #include "FieldEditor.h" #include "GraphIcon.h" SoGetBoundingBoxAction *GraphIcon::bboxAct; //////////////////////////////////////////////////////////////////////// // // Description: // One-time initialization // void GraphIcon::init() // //////////////////////////////////////////////////////////////////////// { // Use default viewport region for now - we really should change ??? // it later when we know the real size, but that would require ??? // passing the vp info around. ??? bboxAct = new SoGetBoundingBoxAction(SbViewportRegion()); } //////////////////////////////////////////////////////////////////////// // // Description: // Constructor. // GraphIcon::GraphIcon() // //////////////////////////////////////////////////////////////////////// { sceneNode = NULL; icon = NULL; iconGraph = NULL; numChildren = -1; // Not a group children = NULL; instanceOf = NULL; // Not an instance state = HIDDEN; // Not visible fieldsShown = FALSE; } //////////////////////////////////////////////////////////////////////// // // Description: // Destructor. // GraphIcon::~GraphIcon() // //////////////////////////////////////////////////////////////////////// { } //////////////////////////////////////////////////////////////////////// // // Description: // Constructs and returns a display subgraph for the given icon. // The subgraph depends on the current state of the icon. // SoNode * GraphIcon::buildGraph() // //////////////////////////////////////////////////////////////////////// { SoSeparator *sep; sep = new SoSeparator; iconSwitch = new SoSwitch; translation = new SoTranslation; // Translation value will be set when positions are computed sep->addChild(translation); sep->addChild(iconSwitch); iconSwitch->addChild(icon); iconSwitch->addChild(DisplayGraph::getClosedIcon()); iconSwitch->addChild(DisplayGraph::getInstanceIcon()); // Turn switch on, depending on state of icon setIconSwitch(); // Save root of graph iconGraph = sep; return iconGraph; } //////////////////////////////////////////////////////////////////////// // // Description: // Computes size of sub-display graph rooted by this. // void GraphIcon::computeSize(const SbVec2f &iconSpacing) // //////////////////////////////////////////////////////////////////////// { float x, y, z; // Reset translation to keep bounding box at origin translation->translation.setValue(0.0, 0.0, 0.0); // Compute size of the icon bboxAct->apply(iconGraph); bboxAct->getBoundingBox().getSize(x, y, z); iconSize.setValue(x, y); heightOffset = bboxAct->getBoundingBox().getMax()[1]; subgraphSize = iconSize; // If the node is closed or has no children, the subgraph size is // the same. Otherwise, compute the children's sizes and add these // to the icon size to get the subgraph size. Use the appropriate // spacing values. if (numChildren > 0 && state == NORMAL) { int i; GraphIcon *child; SbVec2f childrenSize(0.0, 0.0); for (i = 0; i < numChildren; i++) { child = &children[i]; child->computeSize(iconSpacing); // Keep track of maximum Y size if (child->subgraphSize[1] > childrenSize[1]) childrenSize[1] = child->subgraphSize[1]; // Keep track of total X size childrenSize[0] += child->subgraphSize[0]; if (i > 0) childrenSize[0] += iconSpacing[0]; } // The size in y is the y size of this icon + the maximum // y size of the children's icons plus the vertical spacing. // The size in x is the size of the children's icons, if // bigger than this node's icon. subgraphSize[1] += childrenSize[1] + iconSpacing[1]; if (childrenSize[0] > subgraphSize[0]) subgraphSize[0] = childrenSize[0]; } } //////////////////////////////////////////////////////////////////////// // // Description: // Computes position of visible children given position of this. // Also sets translation node in icon graph. // void GraphIcon::computePosition(const SbVec2f thisPosition, const SbVec2f &iconSpacing) // //////////////////////////////////////////////////////////////////////// { position = thisPosition; // Set translation to center of icon translation->translation.setValue(position[0], position[1] - heightOffset, 0.0); // Compute visible children's positions if (numChildren > 0 && state == NORMAL) { SbVec2f childPosition; // Height of children is below this one, figuring in the spacing childPosition[1] = position[1] - (iconSize[1] + iconSpacing[1]); // Just one child is easy if (numChildren == 1) { childPosition[0] = position[0]; children[0].computePosition(childPosition, iconSpacing); } // More than 1 child is a little harder else { int i; // Position of first child childPosition[0] = position[0] - 0.5 * (subgraphSize[0] - children[0].subgraphSize[0]); for (i = 0; i < numChildren; i++) { children[i].computePosition(childPosition, iconSpacing); childPosition[0] += (0.5 * children[i].subgraphSize[0] + iconSpacing[0]); if (i < numChildren - 1) childPosition[0] += 0.5 * children[i+1].subgraphSize[0]; } } } } //////////////////////////////////////////////////////////////////////// // // Description: // Shows icon if it is HIDDEN. Returns TRUE if graph needs to be // rebuilt. // SbBool GraphIcon::show() // //////////////////////////////////////////////////////////////////////// { // Change state if necessary if (state == HIDDEN) { setState(NORMAL); return TRUE; } return FALSE; } //////////////////////////////////////////////////////////////////////// // // Description: // Hides icon if it is not HIDDEN. Returns TRUE if graph needs to be // rebuilt. // SbBool GraphIcon::hide() // //////////////////////////////////////////////////////////////////////// { // Change state if necessary if (state != HIDDEN) { setState(HIDDEN); return TRUE; } return FALSE; } //////////////////////////////////////////////////////////////////////// // // Description: // Opens the icon if it is a CLOSED group. If openAll is TRUE, // opens all descendent groups. Returns TRUE if the graph needs to // be rebuilt as a result. // SbBool GraphIcon::openGroup(SbBool openAll) // //////////////////////////////////////////////////////////////////////// { SbBool rebuild = FALSE; // Change state if (state != NORMAL) { setState(NORMAL); rebuild = TRUE; } // Open children if necessary if (openAll) { int i; for (i = 0; i < numChildren; i++) if (children[i].openGroup(openAll)) rebuild = TRUE; } return rebuild; } //////////////////////////////////////////////////////////////////////// // // Description: // Closes the icon if it is a NORMAL group. Returns TRUE if the // graph needs to be rebuilt as a result. // SbBool GraphIcon::closeGroup() // //////////////////////////////////////////////////////////////////////// { // Can't close it if it is already closed or it has no children if (state != CLOSED && numChildren > 0) { setState(CLOSED); return TRUE; } return FALSE; } //////////////////////////////////////////////////////////////////////// // // Description: // Toggles group between NORMAL (open) state and CLOSED. Should // only be called on a group icon. Returns TRUE if the graph needs // to be rebuilt as a result. // SbBool GraphIcon::toggleGroup() // //////////////////////////////////////////////////////////////////////// { SbBool rebuild = FALSE; switch (state) { case NORMAL: setState(CLOSED); rebuild = TRUE; break; case CLOSED: // If it is currently closed, open it and display children setState(NORMAL); rebuild = TRUE; break; case HIDDEN: // Do nothing break; } return rebuild; } //////////////////////////////////////////////////////////////////////// // // Description: // Swaps instance icon with icon it is an instance of. This allows // selection under an instance of a group. // void GraphIcon::swapInstance() // //////////////////////////////////////////////////////////////////////// { GraphIcon *otherIcon = instanceOf; // Set up instance connections in other direction otherIcon->setInstance(this); setInstance(NULL); // Make sure they are both displayed correctly otherIcon->setIconSwitch(); setIconSwitch(); setState(otherIcon->state); otherIcon->setState(NORMAL); if (otherIcon->isGroup()) { setGroup(otherIcon->getNumChildren(), otherIcon->getChild(0)); otherIcon->setGroup(-1, NULL); // Reparent the children for (int i = 0; i < numChildren; i++) children[i].setParent(this); } } //////////////////////////////////////////////////////////////////////// // // Description: // Brings up window to show field data for node represented by icon. // void GraphIcon::showFields() // //////////////////////////////////////////////////////////////////////// { // Don't do anything if fields are already displayed or there are // no fields in the node if (fieldsShown || FieldEditor::getNumFields(sceneNode) == 0) return; // Create and display an instance of the FieldEditor FieldEditor *editor = new FieldEditor(sceneNode); editor->setFinishCallback(&GraphIcon::finishShowFieldsCB, this); editor->show(); fieldsShown = TRUE; } //////////////////////////////////////////////////////////////////////// // // Description: // Changes the state of the icon to the given state. Recurses to // change children to an appropriate state. Changing the state may // also require a change in icon representation. // void GraphIcon::setState(IconState newState) // //////////////////////////////////////////////////////////////////////// { // If this is not a group or it is a group with no children, never // set it to CLOSED (use NORMAL) if (numChildren <= 0) { if (newState == CLOSED) state = NORMAL; else state = newState; } // Set the group's state else { int i; IconState childState; state = newState; // Set all children to appropriate state switch (newState) { case NORMAL: childState = CLOSED; break; case CLOSED: case HIDDEN: childState = HIDDEN; break; } for (i = 0; i < numChildren; i++) children[i].setState(childState); } setIconSwitch(); } //////////////////////////////////////////////////////////////////////// // // Description: // Sets the icon switch based on the icon's state. // void GraphIcon::setIconSwitch() // //////////////////////////////////////////////////////////////////////// { switch (state) { case NORMAL: if (isInstance()) iconSwitch->whichChild = 2; // Use instance icon else iconSwitch->whichChild = 0; // Use regular icon break; case CLOSED: iconSwitch->whichChild = 1; // Use closed icon break; case HIDDEN: iconSwitch->whichChild = SO_SWITCH_NONE; // No icon! break; } } //////////////////////////////////////////////////////////////////////// // // Description: // Callback for when field editing is finished. // void GraphIcon::finishShowFieldsCB(void *userData, FieldEditor *) // //////////////////////////////////////////////////////////////////////// { ((GraphIcon *) userData)->fieldsShown = FALSE; }