SODRAGGER(3iv)
π SoDragger(3IV) π
okay so bestie, you opened SoDragger(3IV) and honestly? iconic. this is the base-class baddie that every click-drag-release nodekit inherits its whole personality from. grab a strawberry π and let's go.
π NAME π
SoDragger β base class for nodekits that move in response to click-drag-release mouse events
πΈ INHERITS FROM πΈ
SoBase > SoFieldContainer > SoNode > SoBaseKit > SoInteractionKit > SoDragger
β¨ SYNOPSIS β¨
#include <Inventor/draggers/SoDragger.h>
typedef void SoDraggerCB(void *userData, SoDragger *dragger)
Fields from class SoDragger:
SoSFBool isActive
Fields from class SoInteractionKit:
SoSFEnum renderCaching
SoSFEnum boundingBoxCaching
SoSFEnum renderCulling
SoSFEnum pickCulling
Parts from class SoBaseKit:
(SoNodeKitListPart) callbackList
Methods from class SoDragger:
void addStartCallback(SoDraggerCB *f, void *userData =
NULL)
void removeStartCallback(SoDraggerCB *f, void *userData =
NULL)
void addMotionCallback(SoDraggerCB *f, void *userData =
NULL)
void removeMotionCallback(SoDraggerCB *f, void *userData =
NULL)
void addFinishCallback(SoDraggerCB *f, void *userData =
NULL)
void removeFinishCallback(SoDraggerCB *f, void *userData =
NULL)
void addValueChangedCallback(SoDraggerCB *f, void *userData
= NULL)
void removeValueChangedCallback(SoDraggerCB *f, void
*userData = NULL)
SbBool enableValueChangedCallbacks()
void setMinGesture(int pixels)
int getMinGesture() const
static void setMinScale(float newMinScale)
static float getMinScale()
static const SoNodekitCatalog *
getClassNodekitCatalog() const
static SoType getClassTypeId()
Methods from class SoInteractionKit:
virtual SbBool setPartAsPath(const SbName &partName, SoPath
*surrogatePath )
Methods from class SoBaseKit:
virtual const SoNodekitCatalog *
getNodekitCatalog() const
virtual SoNode * getPart(const SbName &partName, SbBool
makeIfNeeded)
SbString getPartString(const SoBase *part)
virtual SoNodeKitPath * createPathToPart(const SbName &partName, SbBool
makeIfNeeded, const SoPath *pathToExtend =
NULL)
virtual SbBool setPart(const SbName &partName, SoNode *newPart)
SbBool set(char *partName, char *parameters)
SbBool set(char *nameValuePairs)
static SbBool isSearchingChildren()
static void setSearchingChildren(SbBool newVal)
Methods from class SoNode:
void setOverride(SbBool state)
SbBool isOverride() const
SoNode * copy(SbBool copyConnections = FALSE) const
virtual SbBool affectsState() const
static SoNode * getByName(const SbName &name)
static int getByName(const SbName &name, SoNodeList &list)
Methods from class SoFieldContainer:
void setToDefaults()
SbBool hasDefaultValues() const
SbBool fieldsAreEqual(const SoFieldContainer *fc) const
void copyFieldValues(const SoFieldContainer *fc, SbBool
copyConnections = FALSE)
void get(SbString &fieldDataString)
virtual int getFields(SoFieldList &resultList) const
virtual SoField * getField(const SbName &fieldName) const
SbBool getFieldName(const SoField *field, SbName &fieldName)
const
SbBool isNotifyEnabled() const
SbBool enableNotify(SbBool flag)
Methods from class SoBase:
void ref()
void unref() const
void unrefNoDelete() const
void touch()
virtual SoType getTypeId() const
SbBool isOfType(SoType type) const
virtual void setName(const SbName &name)
virtual SbName getName() const
Macros from class SoBaseKit:
SO_GET_PART(kit, partName, partClass)
SO_CHECK_PART(kit, partName, partClass)
π¦ DESCRIPTION π¦
okay so <pink>SoDragger</pink> is THE base class for every nodekit you move around with the mouse β the whole click β drag β release` situation. but like, more precisely, because precision is the vibe:
- start β mouse button 1 gets pressed while you're hovering over the dragger, which picks it
- dragging β the mouse motion events come in and the dragger interprets them, and that turns into some kind of motion and/or a change to a field
- finish β mouse goes up
periodt. that's the whole lifecycle. π
every dragger has its own lil paradigm for reading mouse motion and changing its fields because of it. draggers map that 2D mouse motion into motion of a point on 3D <purple>lines</purple>, <purple>planes</purple>, <purple>spheres</purple> or <purple>cylinders</purple> β (peep the SbProjector reference pages for the lore on that one). then they react to that point moving through 3-space by <mint>scaling</mint>, <mint>translating</mint>, or <mint>rotating</mint>. for example: SoTranslate2Dragger maps mouse motion onto a 3D plane, then translates to follow the cursor as it moves around inside that plane. lowkey elegant fr fr.
every dragger has fields describing its current state, like it's posting a status update. scaling draggers have a scaleFactor field, rotational draggers have a rotation field, etc etc. and literally all of them have the isActive field, which is defined right here in this class. it's TRUE while the dragger is being dragged, FALSE otherwise. simple as. β¨
draggers that only have one part to pick and one motion field are called <yellow>simple draggers. examples: SoRotateDiscDragger, SoScale1Dragger, and SoTranslate2Dragger`. cute, focused, no drama.
draggers that build assemblies out of other draggers and then orchestrate the motion of the whole assembly are called <yellow>composite draggers. SoTransformBoxDraggeris a composite dragger made entirely out of simple draggers.SoDirectionalLightDragger contains both a simple dragger (SoRotateSphericalDragger) and a composite dragger (SoDragPointDragger). when you're using a composite dragger, the fields of the compositedragger are the ones you should be working with β that's the main character. the draggers lower down in the assemblage usually have zeroed out values, they're just there to support. for example, when you drag the face of a transformBox, anSoTranslate2Dragger`, the transformBox "steals" the translation from the child dragger and transfers it up to the top of the composite dragger, where it effects all pieces of the assemblage. the way that works?? π«Ά
draggers always keep their fields up to date, <rainbow>including while they're being dragged</rainbow>. so you can use field-to-field connections and engines to hook dragger values up to other parts of your scene graph. which means draggers can be utilized as input devices for mouse-driven 3D interface elements, no cap. you can also register value-changed callbacks, and those get called whenever any of the fields changes.
also β and this is the part that's giving genius β if you set the field of a dragger through some method other than dragging (by calling setValue(), for example), the dragger's internal SoFieldSensor will sense it, and the dragger will <pink>move itself to satisfy that new value</pink>. obsessed.
this makes it easy to constrain draggers so their fields stay inside certain limits: if the limit gets exceeded, you just set it back to the exceeded maximum or minimum. you can do this even while the dragger is in use, by constraining the field value inside a value-changed callback that you add with addValueChangedCallback(). but listen β in that case, be sure to <red>temporarily disable the other value-changed callbacks</red> using enableValueChangedCallbacks(). doing that prevents <red>infinite-looping`; changing the value followed by calling the callbacks which change the value ad infinitum. we do NOT want that spiral bestie π
β οΈ important vibe check: when you drag a dragger, the dragger only moves itself. draggers do not change the state or affect objects that follow in the scene graph. for example a dragger does not ever behave like anSoTransformand change the current transformation matrix. draggers are not transforms, even if they have field names liketranslation,rotation,scaleFactor.
many draggers, such as SoTrackballDragger, have a corresponding SoTransformManip β in this case SoTrackballManip. the manipulator is a subclass of SoTransform, and it affects other objects in the scene; it uses a trackball dragger to provide its user interface. so draggers get employed extensively by manipulators. callback functions on the dragger let its employer get notified of <mint>start, motion</mint>, <mint>finish, and value changes</mint>. in all cases, the callback function is passed a pointer to the dragger which initiated the callback. (see the various man pages for more details on specific draggers and manipulators).
all draggers are nodekits. however β plot twist β draggers do not list their parts in the Parts section of the reference page. instead there's a section called <lavender>Dragger Resources, which is way more suited to describing the parts made available to the programmer. and because of space limitations, the Dragger Resources section only shows up in the online` versions of the reference pages. fyi.
every dragger has some parts you can pick on, and other parts that replace them when they're active or moving. those active parts are often just the same geometry in another color. draggers also have pieces for displaying feedback. each of these pieces has a default scene graph, plus a special function within the dragger. each part also has a <purple>resource name. all of this info lives in the DRAGGER RESOURCES` section.
since draggers are nodekits, you can set the parts in any instance of a dragger using setPart().
but draggers also give each part a resource name. when a dragger builds a part, it looks in the global dictionary for the node with that resourceName. by putting a new entry in the dictionary, you can override that default. the default part geometries are defined as resources for each class, and each class has a file you can change to alter the defaults. those files are listed in each dragger's man page. you can make your program use different default resources for the parts by:
- copying the listed file from the directory
/usr/share/data/draggerDefaultsinto your own directory, - editing the file,
- and then setting the environment variable
SO_DRAGGER_DIRto be a path to that directory.
slay. customization era. π
π FIELDS π
SoSFBoolisActiveβTRUEwhen mouse is down and dragging, elseFALSE.
more of this page is coming bestie, don't go anywhere π§π
β¨ METHODS β¨
Okay bestie, these are the functions you actually call. All of them live on the dragger, all of them matter. Let's go one by one π
void addStartCallback(SoDraggerCB *f, void *userData = NULL)void removeStartCallback(SoDraggerCB *f, void *userData = NULL)
Start callbacks fire after mouse button 1 goes down and the dragger has figured out that it got picked. If it's actually gonna start dragging, it grabs events and invokes the startCallbacks. So likeβ¦ the moment it commits to the bit π
void addMotionCallback(SoDraggerCB *f, void *userData = NULL)void removeMotionCallback(SoDraggerCB *f, void *userData = NULL)
Motion callbacks get called after every single movement of the mouse while dragging is happening. Every wiggle. Every scoot. It's giving constant updates β¨
void addFinishCallback(SoDraggerCB *f, void *userData = NULL)void removeFinishCallback(SoDraggerCB *f, void *userData = NULL)
Finish callbacks run after dragging ends and the dragger has stopped grabbing events. The grand finale π
void addValueChangedCallback(SoDraggerCB *f, void *userData = NULL)void removeValueChangedCallback(SoDraggerCB *f, void *userData = NULL)
Value-changed callbacks happen after a dragger changes any of its fields. Important caveat bestie: this does not include changes to the isActive field. Also peep enableValueChangedCallbacks below π
SbBool enableValueChangedCallbacks()
Okay so you can temporarily disable a dragger's valueChangedCallbacks, and this method returns a value telling you whether callbacks were already enabled before you messed with them. Use this if you're writing your own valueChanged callback and you change one of the dragger's fields inside that callback β like, say, when you're writing a callback to constrain your dragger. The move is: disable first, then change the field, then re-enable the callbacks (only if they were enabled to start with). All of this exists to stop you from falling into an infinite loop of changing values β calling callbacks β which change values β which call callbacks β forever and ever ππ
void setMinGesture(int pixels)int getMinGesture() const
Set and get the number of pixels of movement required to initiate a constraint gesture. Default is 8. No cap π«Ά
static void setMinScale(float newMinScale)static float getMinScale()
The smallest scale that any dragger will write. If the user tries to go below this amount, the dragger just sets it to this minimum instead. Default is .001. It's a floor, not a suggestion π
static const SoNodekitCatalog *getClassNodekitCatalog() const
Returns an SoNodekitCatalog for this class. Yep. That's the whole thing π¦
static SoType getClassTypeId()
Returns the type identifier for this class. Your little ID badge πͺͺ
ποΈ CATALOG PARTS ποΈ
Here's the part where we list the parts. Meta, I know. Obsessed.
All parts
callbackListβ Part Type:NodeKitListPart, Default Type:--, NULL by Default: yes
Extra information for list parts from above table
callbackListβ Container Type:Separator, Permissible Types:Callback,EventCallback
So thecallbackListpart is the only one on the menu, it defaults toNULL, and if you do populate it, it's aSeparatorthat can holdCallbackandEventCallbacknodes. That's the whole tea β
π FILE FORMAT/DEFAULTS π
This is literally what a Dragger looks like when it spawns into the world, no edits, straight out the box:
Dragger {
renderCaching AUTO
boundingBoxCaching AUTO
renderCulling AUTO
pickCulling AUTO
isActive FALSE
callbackList NULL
}
Every single one of those defaults is exactly as written. Don't come for me, I'm just the messenger π§
π SEE ALSO π
Go read these next, bestie, they're all in the family:
SoInteractionKitSoCenterballDraggerSoDirectionalLightDraggerSoDragPointDraggerSoHandleBoxDraggerSoJackDraggerSoPointLightDraggerSoRotateCylindricalDraggerSoRotateDiscDraggerSoRotateSphericalDraggerSoScale1DraggerSoScale2DraggerSoScale2UniformDraggerSoScaleUniformDraggerSoSpotLightDraggerSoTabBoxDraggerSoTabPlaneDraggerSoTrackballDraggerSoTransformBoxDraggerSoTransformerDraggerSoTranslate1DraggerSoTranslate2Dragger
And that's the whole page, periodt. This one came to you from the SoDragger(3IV) manual page β version 3IV energy, dated however long ago, and honestly? Iconic. Stay draggin' πβ¨
π¦ where this page comes from
- debian bookworm: inventor-doc 2.1.5-10+dfsg-2 Β· LGPL-2.0-or-later
- debian trixie: inventor-doc 2.1.6+ds-2 Β· LGPL-2.0-or-later
- ubuntu jammy: inventor-doc 2.1.5-10-24
- ubuntu noble: inventor-doc 2.1.5-10+dfsg-2.1build2 Β· LGPL-2.0-or-later
- ubuntu questing: inventor-doc 2.1.6+ds-2
- ubuntu resolute: inventor-doc 2.1.6.1+ds-1 Β· LGPL-2.0-or-later
- ubuntu stonking: inventor-doc 2.1.6.1+ds-1 Β· LGPL-2.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms