/* greebo: This gets called by the SelectObserver if the user drags a box and holds down * any of the selection modifiers. Possible selection candidates are determined and selected/deselected */ void RadiantSelectionSystem::SelectArea(const View& view, const Vector2& device_point, const Vector2& device_delta, SelectionSystem::EModifier modifier, bool face) { // If we are in replace mode, deselect all the components or previous selections if (modifier == SelectionSystem::eReplace) { if (face) { setSelectedAllComponents(false); } else { deselectAll(); } } { // Construct the selection test according to the area the user covered with his drag View scissored(view); ConstructSelectionTest(scissored, Rectangle::ConstructFromArea(device_point, device_delta)); SelectionVolume volume(scissored); // The posssible candidates go here SelectionPool pool; SelectablesList candidates; if (face) { ComponentSelector selectionTester(pool, volume, eFace); GlobalSceneGraph().foreachVisibleNodeInVolume(scissored, selectionTester); // Load them all into the vector for (SelectionPool::iterator i = pool.begin(); i != pool.end(); ++i) { candidates.push_back(i->second); } } else { testSelectScene(candidates, volume, scissored, Mode(), ComponentMode()); } // Cycle through the selection pool and toggle the candidates, but only if we are in toggle mode for (SelectablesList::iterator i = candidates.begin(); i != candidates.end(); i++) { (*i)->setSelected(!(modifier == SelectionSystem::eToggle && (*i)->isSelected())); } } }
/* greebo: This is called by the ManipulateObserver class on the mouseDown event. It checks, if a manipulator * can be selected where the mouse is pointing to. */ bool RadiantSelectionSystem::SelectManipulator(const View& view, const Vector2& device_point, const Vector2& device_epsilon) { if (!nothingSelected() || (ManipulatorMode() == eDrag && Mode() == eComponent)) { // Unselect any currently selected manipulators to be sure _manipulator->setSelected(false); // Test, if the current manipulator can be selected if (!nothingSelected() || (ManipulatorMode() == eDrag && Mode() == eComponent)) { View scissored(view); ConstructSelectionTest(scissored, Rectangle::ConstructFromPoint(device_point, device_epsilon)); // The manipulator class checks on its own, if any of its components can be selected _manipulator->testSelect(scissored, GetPivot2World()); } // Save the pivot2world matrix startMove(); // This is true, if a manipulator could be selected _pivotMoving = _manipulator->isSelected(); // is a manipulator selected / the pivot moving? if (_pivotMoving) { Pivot2World pivot; pivot.update(GetPivot2World(), view.GetModelview(), view.GetProjection(), view.GetViewport()); _manip2pivotStart = _pivot2worldStart.getFullInverse().getMultipliedBy(pivot._worldSpace); Matrix4 device2manip; ConstructDevice2Manip(device2manip, _pivot2worldStart, view.GetModelview(), view.GetProjection(), view.GetViewport()); _manipulator->getActiveComponent()->Construct(device2manip, device_point[0], device_point[1]); _deviceStart = Vector2(device_point[0], device_point[1]); _undoBegun = false; } SceneChangeNotify(); } return _pivotMoving; }
/* greebo: This is called by the ManipulateObserver class on the mouseDown event. It checks, if a manipulator * can be selected where the mouse is pointing to. */ bool RadiantSelectionSystem::SelectManipulator(const View& view, const float device_point[2], const float device_epsilon[2]) { if (!nothingSelected() || (ManipulatorMode() == eDrag && Mode() == eComponent)) { #if defined (DEBUG_SELECTION) g_render_clipped.destroy(); #endif // Unselect any currently selected manipulators to be sure _manipulator->setSelected(false); // Test, if the current manipulator can be selected if (!nothingSelected() || (ManipulatorMode() == eDrag && Mode() == eComponent)) { View scissored(view); ConstructSelectionTest(scissored, SelectionBoxForPoint(device_point, device_epsilon)); // The manipulator class checks on its own, if any of its components can be selected _manipulator->testSelect(scissored, GetPivot2World()); } // Save the pivot2world matrix startMove(); // This is true, if a manipulator could be selected _pivotMoving = _manipulator->isSelected(); // is a manipulator selected / the pivot moving? if (_pivotMoving) { Pivot2World pivot; pivot.update(GetPivot2World(), view.GetModelview(), view.GetProjection(), view.GetViewport()); _manip2pivotStart = matrix4_multiplied_by_matrix4(matrix4_full_inverse(_pivot2worldStart), pivot.m_worldSpace); Matrix4 device2manip; ConstructDevice2Manip(device2manip, _pivot2worldStart, view.GetModelview(), view.GetProjection(), view.GetViewport()); _manipulator->GetManipulatable()->Construct(device2manip, device_point[0], device_point[1]); _undoBegun = false; } SceneChangeNotify(); } return _pivotMoving; }
/* greebo: This gets called by the SelectObserver if the user drags a box and holds down * any of the selection modifiers. Possible selection candidates are determined and selected/deselected */ void RadiantSelectionSystem::SelectArea(const View& view, const float device_point[2], const float device_delta[2], SelectionSystem::EModifier modifier, bool face) { // If we are in replace mode, deselect all the components or previous selections if (modifier == SelectionSystem::eReplace) { if (face) { setSelectedAllComponents(false); } else { deselectAll(); } } #if defined (DEBUG_SELECTION) g_render_clipped.destroy(); #endif { // Construct the selection test according to the area the user covered with his drag View scissored(view); ConstructSelectionTest(scissored, SelectionBoxForArea(device_point, device_delta)); SelectionVolume volume(scissored); // The posssible candidates go here SelectionPool pool; if (face) { Scene_TestSelect_Component(pool, volume, scissored, eFace); } else { Scene_TestSelect(pool, volume, scissored, Mode(), ComponentMode()); } // Cycle through the selection pool and toggle the candidates, but only if we are in toggle mode for (SelectionPool::iterator i = pool.begin(); i != pool.end(); ++i) { (*i).second->setSelected(!(modifier == SelectionSystem::eToggle && (*i).second->isSelected())); } } }
/* greebo: This gets called by SelectObserver if the user just clicks into the scene (without dragging) * It checks for any possible targets (in the "line of click") and takes the actions according * to the modifiers that are held down (Alt-Shift, etc.) */ void RadiantSelectionSystem::SelectPoint(const View& view, const Vector2& device_point, const Vector2& device_epsilon, SelectionSystem::EModifier modifier, bool face) { ASSERT_MESSAGE(fabs(device_point[0]) <= 1.0f && fabs(device_point[1]) <= 1.0f, "point-selection error"); // If the user is holding the replace modifiers (default: Alt-Shift), deselect the current selection if (modifier == SelectionSystem::eReplace) { if (face) { setSelectedAllComponents(false); } else { deselectAll(); } } { View scissored(view); // Construct a selection test according to a small box with 2*epsilon edge length ConstructSelectionTest(scissored, Rectangle::ConstructFromPoint(device_point, device_epsilon)); // Create a new SelectionPool instance and fill it with possible candidates SelectionVolume volume(scissored); // The possible candidates are stored in the SelectablesSet SelectablesList candidates; if (face) { SelectionPool selector; ComponentSelector selectionTester(selector, volume, eFace); GlobalSceneGraph().foreachVisibleNodeInVolume(scissored, selectionTester); // Load them all into the vector for (SelectionPool::iterator i = selector.begin(); i != selector.end(); ++i) { candidates.push_back(i->second); } } else { testSelectScene(candidates, volume, scissored, Mode(), ComponentMode()); } // Was the selection test successful (have we found anything to select)? if (candidates.size() > 0) { // Yes, now determine how we should interpret the click switch (modifier) { // If we are in toggle mode (Shift-Left-Click by default), just toggle the // selection of the "topmost" item case SelectionSystem::eToggle: { Selectable* best = *candidates.begin(); // toggle selection of the object with least depth (=first in the list) best->setSelected(!best->isSelected()); } break; // greebo: eReplace mode gets active as soon as the user holds the replace modifiers down // and clicks (by default: Alt-Shift). eReplace is only active during the first click // afterwards we are in cycle mode. // if cycle mode not enabled, enable it case SelectionSystem::eReplace: { // select closest (=first in the list) (*candidates.begin())->setSelected(true); } break; // select the next object in the list from the one already selected // greebo: eCycle is set if the user keeps holding the replace modifiers (Alt-Shift) // and does NOT move the mouse between the clicks, otherwise we fall back into eReplace mode // Note: The mode is set in SelectObserver::testSelect() case SelectionSystem::eCycle: { // Cycle through the selection pool and activate the item right after the currently selected SelectablesList::iterator i = candidates.begin(); while (i != candidates.end()) { if ((*i)->isSelected()) { // unselect the currently selected one (*i)->setSelected(false); // check if there is a "next" item in the list, if not: select the first item ++i; if (i != candidates.end()) { (*i)->setSelected(true); } else { (*candidates.begin())->setSelected(true); } break; } ++i; } // while } // case break; default: break; } // switch } } }
/* greebo: This gets called by SelectObserver if the user just clicks into the scene (without dragging) * It checks for any possible targets (in the "line of click") and takes the actions according * to the modifiers that are held down (Alt-Shift, etc.) */ void RadiantSelectionSystem::SelectPoint(const View& view, const float device_point[2], const float device_epsilon[2], SelectionSystem::EModifier modifier, bool face) { ASSERT_MESSAGE(fabs(device_point[0]) <= 1.0f && fabs(device_point[1]) <= 1.0f, "point-selection error"); // If the user is holding the replace modifiers (default: Alt-Shift), deselect the current selection if (modifier == SelectionSystem::eReplace) { if (face) { setSelectedAllComponents(false); } else { deselectAll(); } } #if defined (DEBUG_SELECTION) g_render_clipped.destroy(); #endif { View scissored(view); // Construct a selection test according to a small box with 2*epsilon edge length ConstructSelectionTest(scissored, SelectionBoxForPoint(device_point, device_epsilon)); // Create a new SelectionPool instance and fill it with possible candidates SelectionVolume volume(scissored); // The possible candidates are stored in the SelectionPool SelectionPool selector; if (face) { Scene_TestSelect_Component(selector, volume, scissored, eFace); } else { Scene_TestSelect(selector, volume, scissored, Mode(), ComponentMode()); } // Was the selection test successful (have we found anything to select)? if (!selector.failed()) { // Yes, now determine how we should interpret the click switch (modifier) { // If we are in toggle mode (Shift-Left-Click by default), just toggle the // selection of the "topmost" item case SelectionSystem::eToggle: { SelectableSortedSet::iterator best = selector.begin(); // toggle selection of the object with least depth (=first in the list) if ((*best).second->isSelected()) (*best).second->setSelected(false); else (*best).second->setSelected(true); } break; // greebo: eReplace mode gets active as soon as the user holds the replace modifiers down // and clicks (by default: Alt-Shift). eReplace is only active during the first click // afterwards we are in cycle mode. // if cycle mode not enabled, enable it case SelectionSystem::eReplace: { // select closest (=first in the list) (*selector.begin()).second->setSelected(true); } break; // select the next object in the list from the one already selected // greebo: eCycle is set if the user keeps holding the replace modifiers (Alt-Shift) // and does NOT move the mouse between the clicks, otherwise we fall back into eReplace mode // Note: The mode is set in SelectObserver::testSelect() case SelectionSystem::eCycle: { // Cycle through the selection pool and activate the item right after the currently selected SelectionPool::iterator i = selector.begin(); while (i != selector.end()) { if ((*i).second->isSelected()) { // unselect the currently selected one (*i).second->setSelected(false); // check if there is a "next" item in the list, if not: select the first item ++i; if (i != selector.end()) { i->second->setSelected(true); } else { selector.begin()->second->setSelected(true); } break; } ++i; } // while } // case break; default: break; } // switch } } }
// Handles the mouseDown event, basically determines which action should be performed (select or manipulate) void RadiantWindowObserver::onMouseDown(const WindowVector& position, GdkEventButton* ev) { // Retrieve the according ObserverEvent for the GdkEventButton ui::ObserverEvent observerEvent = GlobalEventManager().MouseEvents().getObserverEvent(ev); // Check if the user wants to copy/paste a texture if (observerEvent == ui::obsCopyTexture || observerEvent == ui::obsPasteTextureProjected || observerEvent == ui::obsPasteTextureNatural || observerEvent == ui::obsPasteTextureCoordinates || observerEvent == ui::obsPasteTextureToBrush || observerEvent == ui::obsJumpToObject) { // Get the mouse position DeviceVector devicePosition(device_constrained(window_to_normalised_device(position, _width, _height))); // Check the target object render::View scissored(*_selectObserver._view); ConstructSelectionTest(scissored, Rectangle::ConstructFromPoint(devicePosition, _selectObserver._epsilon)); SelectionVolume volume(scissored); // Do we have a camera view (fill() == true)? if (_selectObserver._view->fill()) { if (observerEvent == ui::obsJumpToObject) { CamWndPtr cam = GlobalCamera().getActiveCamWnd(); if (cam != NULL) { cam->jumpToObject(volume); } } // If the apply texture modifier is held else if (observerEvent == ui::obsPasteTextureProjected) { // Paste the shader projected (TRUE), but not to an entire brush (FALSE) selection::algorithm::pasteShader(volume, true, false); } // If the copy texture modifier is held else if (observerEvent == ui::obsCopyTexture) { // Set the source texturable from the given test GlobalShaderClipboard().setSource(volume); } else if (observerEvent == ui::obsPasteTextureNatural) { // Paste the shader naturally (FALSE), but not to an entire brush (FALSE) selection::algorithm::pasteShader(volume, false, false); } else if (observerEvent == ui::obsPasteTextureCoordinates) { // Clone the texture coordinates from the patch in the clipboard selection::algorithm::pasteTextureCoords(volume); } else if (observerEvent == ui::obsPasteTextureToBrush) { // Paste the shader projected (TRUE), and to the entire brush (TRUE) selection::algorithm::pasteShader(volume, true, true); } } } // Have any of the "selection" events occurred? // greebo: This could be an "else if (observerEvent != obsNothing)" as well, // but perhaps there will be more events in the future that aren't selection events. if (observerEvent == ui::obsManipulate || observerEvent == ui::obsSelect || observerEvent == ui::obsToggle || observerEvent == ui::obsToggleFace || observerEvent == ui::obsToggleGroupPart || observerEvent == ui::obsReplace || observerEvent == ui::obsReplaceFace) { _mouseDown = true; // Determine the current mouse position DeviceVector devicePosition(window_to_normalised_device(position, _width, _height)); if (observerEvent == ui::obsManipulate && _manipulateObserver.mouseDown(devicePosition)) { // This is a manipulation operation, register the callbacks // Note: the mouseDown call in the if clause returned already true, // so a manipulator could be successfully selected _mouseMotionCallback = boost::bind(&ManipulateObserver::mouseMoved, &_manipulateObserver, _1); _mouseUpCallback = boost::bind(&ManipulateObserver::mouseUp, &_manipulateObserver, _1); _listenForCancelEvents = true; } else { // Call the mouseDown method of the selector class, this covers all of the other events _selectObserver.mouseDown(devicePosition); _mouseMotionCallback = boost::bind(&SelectObserver::mouseMoved, &_selectObserver, _1); _mouseUpCallback = boost::bind(&SelectObserver::mouseUp, &_selectObserver, _1); // greebo: the according actions (toggle face, replace, etc.) are handled in the mouseUp methods. } } }