/*===========================================================================*\ * * * OpenFlipper * * Copyright (C) 2001-2010 by Computer Graphics Group, RWTH Aachen * * www.openflipper.org * * * *---------------------------------------------------------------------------* * This file is part of OpenFlipper. * * * * OpenFlipper 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 3 of * * the License, or (at your option) any later version with the * * following exceptions: * * * * If other files instantiate templates or use macros * * or inline functions from this file, or you compile this file and * * link it with other files to produce an executable, this file does * * not by itself cause the resulting executable to be covered by the * * GNU Lesser General Public License. This exception does not however * * invalidate any other reasons why the executable file might be * * covered by the GNU Lesser General Public License. * * * * OpenFlipper 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. * * * * You should have received a copy of the GNU LesserGeneral Public * * License along with OpenFlipper. If not, * * see . * * * \*===========================================================================*/ /*===========================================================================*\ * * * $Revision$ * * $Author$ * * $Date$ * * * \*===========================================================================*/ #include "SelectionBasePlugin.hh" #include // Standard selection mode icon files #define TOGGLE_IMG "selection_toggle.png" #define LASSO_IMG "selection_lasso.png" #define VOLUME_LASSO_IMG "selection_lasso2.png" #define SURFACE_LASSO_IMG "surface-lasso.png" #define SPHERE_IMG "selection_paintSphere.png" #define BOUNDARY_IMG "selection_boundary.png" #define FLOODFILL_IMG "selection_floodFill.png" #define COMPONENTS_IMG "selection_connected.png" // Standard selection mode descriptions #define TOGGLE_DESC "Toggle Selection" #define LASSO_DESC "Lasso Selection" #define VOLUME_LASSO_DESC "Volume Lasso Selection" #define SURFACE_LASSO_DESC "Surface Lasso Selection" #define SPHERE_DESC "Sphere Selection" #define BOUNDARY_DESC "Boundary Selection" #define FLOODFILL_DESC "Floodfill Selection" #define COMPONENTS_DESC "Selected Components Selection" // Standard selection mode names #define SB_TOGGLE "sb_toggle" #define SB_LASSO "sb_lasso" #define SB_VOLUME_LASSO "sb_volumelasso" #define SB_SURFACE_LASSO "sb_surfacelasso" #define SB_SPHERE "sb_sphere" #define SB_BOUNDARY "sb_closestboundary" #define SB_FLOODFILL "sb_floodfill" #define SB_COMPONENTS "sb_components" // Constant to set if no selection picking is enabled #define NO_SELECTION_PICKING "No_Selection_Picking" #define NO_SELECTION_MODE "No_Selection_Mode" #define SELECTION_PICKING "SelectionBasePicking" // Constructor SelectionBasePlugin::SelectionBasePlugin() : toolBar_(0), tool_(0), primitivesBarGroup_(0), pickModeToolBar_(0), selectionModesGroup_(0), toggleSelectionAction_(0), lassoSelectionAction_(0), volumeLassoSelectionAction_(0), surfaceLassoSelectionAction_(0), sphereSelectionAction_(0), boundarySelectionAction_(0), floodFillSelectionAction_(0), componentsSelectionAction_(0), nextFreePrimitiveType_(1u), sphere_mat_node_(0), sphere_node_(0), line_node_(0), lassoSelection_(false), toolIcon_(0), availableObjectTypes_(0u) { // Reset active pick mode currentPickMode_ = NO_SELECTION_PICKING; lastPickMode_ = NO_SELECTION_PICKING; currentSelectionMode_ = NO_SELECTION_MODE; currentPrimitiveType_ = 0u; // We initially want selection, not deselection deselection_ = false; sphere_radius_ = 0.0; } //============================================================================================ void SelectionBasePlugin::initializePlugin() { // Skip if no gui is available if (OpenFlipper::Options::nogui()) return; // Create tool box tool_ = new SelectionBaseToolboxWidget(); QSize size(300, 300); tool_->resize(size); // Connect load/save buttons connect(tool_->loadSelection, SIGNAL(clicked()), this, SLOT(slotLoadSelectionButton())); connect(tool_->saveSelection, SIGNAL(clicked()), this, SLOT(slotSaveSelectionButton())); // Add toolbox to OpenFlipper main window toolIcon_ = new QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"selection_base.png"); emit addToolbox("Selections", tool_, toolIcon_ ); // Create toolbar that holds the selection environment buttons toolBar_ = new QToolBar(tr("Selection Base")); emit addToolbar(toolBar_); QString iconPath = OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator(); QAction* selectionEnvironmentButton = new QAction(QIcon(iconPath + "selection_base.png"), "Selections", toolBar_); toolBar_->addAction(selectionEnvironmentButton); // Connect QAction to local function that switches mode connect(selectionEnvironmentButton, SIGNAL(triggered(bool)), this, SLOT(slotSelectionEnvironmentRequested(bool))); // Register keys emit registerKey(Qt::Key_Control, Qt::NoModifier, tr("Deselection"), true); emit registerKey(Qt::Key_Control, Qt::ControlModifier, tr("Deselection"), true); emit registerKey(Qt::Key_Shift, Qt::NoModifier, tr("Source/Target Selection"), true); emit registerKey(Qt::Key_Shift, Qt::ShiftModifier, tr("Source/Target Selection"), true); // Add pickmode for the selection environment emit addPickMode(SELECTION_PICKING); // Enable mouse tracking for all pick modes emit setPickModeMouseTracking(SELECTION_PICKING, true); // Set tabs widget movable tool_->typeTabWidget->setMovable(true); // Set pick mode toolbar pickModeToolBar_ = new QToolBar("Selection Picking Toolbar"); pickModeToolBar_->setObjectName("Selection_Picking_Toolbar"); // Create primitive toolbar primitivesBarGroup_ = new QActionGroup(pickModeToolBar_); primitivesBarGroup_->setExclusive(true); // Create default selection mode actions selectionModesGroup_ = new QActionGroup(pickModeToolBar_); selectionModesGroup_->setExclusive(true); toggleSelectionAction_ = new HandleAction(QIcon(iconPath + TOGGLE_IMG), TOGGLE_DESC, selectionModesGroup_); toggleSelectionAction_->setCheckable(true); toggleSelectionAction_->selectionModeHandle(SB_TOGGLE); connect(toggleSelectionAction_, SIGNAL(triggered(bool)), this, SLOT(slotEnterSelectionMode(bool))); lassoSelectionAction_ = new HandleAction(QIcon(iconPath + LASSO_IMG), LASSO_DESC, selectionModesGroup_); lassoSelectionAction_->setCheckable(true); lassoSelectionAction_->selectionModeHandle(SB_LASSO); connect(lassoSelectionAction_, SIGNAL(triggered(bool)), this, SLOT(slotEnterSelectionMode(bool))); volumeLassoSelectionAction_ = new HandleAction(QIcon(iconPath + VOLUME_LASSO_IMG), VOLUME_LASSO_DESC, selectionModesGroup_); volumeLassoSelectionAction_->setCheckable(true); volumeLassoSelectionAction_->selectionModeHandle(SB_VOLUME_LASSO); connect(volumeLassoSelectionAction_, SIGNAL(triggered(bool)), this, SLOT(slotEnterSelectionMode(bool))); surfaceLassoSelectionAction_ = new HandleAction(QIcon(iconPath + SURFACE_LASSO_IMG), SURFACE_LASSO_DESC, selectionModesGroup_); surfaceLassoSelectionAction_->setCheckable(true); surfaceLassoSelectionAction_->selectionModeHandle(SB_SURFACE_LASSO); connect(surfaceLassoSelectionAction_, SIGNAL(triggered(bool)), this, SLOT(slotEnterSelectionMode(bool))); sphereSelectionAction_ = new HandleAction(QIcon(iconPath + SPHERE_IMG), SPHERE_DESC, selectionModesGroup_); sphereSelectionAction_->setCheckable(true); sphereSelectionAction_->selectionModeHandle(SB_SPHERE); connect(sphereSelectionAction_, SIGNAL(triggered(bool)), this, SLOT(slotEnterSelectionMode(bool))); boundarySelectionAction_ = new HandleAction(QIcon(iconPath + BOUNDARY_IMG), BOUNDARY_DESC, selectionModesGroup_); boundarySelectionAction_->setCheckable(true); boundarySelectionAction_->selectionModeHandle(SB_BOUNDARY); connect(boundarySelectionAction_, SIGNAL(triggered(bool)), this, SLOT(slotEnterSelectionMode(bool))); floodFillSelectionAction_ = new HandleAction(QIcon(iconPath + FLOODFILL_IMG), FLOODFILL_DESC, selectionModesGroup_); floodFillSelectionAction_->setCheckable(true); floodFillSelectionAction_->selectionModeHandle(SB_FLOODFILL); connect(floodFillSelectionAction_, SIGNAL(triggered(bool)), this, SLOT(slotEnterSelectionMode(bool))); componentsSelectionAction_ = new HandleAction(QIcon(iconPath + COMPONENTS_IMG), COMPONENTS_DESC, selectionModesGroup_); componentsSelectionAction_->setCheckable(true); componentsSelectionAction_->selectionModeHandle(SB_COMPONENTS); connect(componentsSelectionAction_, SIGNAL(triggered(bool)), this, SLOT(slotEnterSelectionMode(bool))); pickModeToolBar_->clear(); pickModeToolBar_->addActions(primitivesBarGroup_->actions()); pickModeToolBar_->addSeparator(); pickModeToolBar_->addActions(selectionModesGroup_->actions()); emit setPickModeToolbar(SELECTION_PICKING, pickModeToolBar_); } //============================================================================================ void SelectionBasePlugin::pluginsInitialized() { // Initialize scenegraph nodes that are used for the // rendering of the selection tools (e.g. sphere, lasso, etc.) // Sphere node std::string nodeName = std::string( tr("Selection Base Plugin: Selection Sphere Material").toUtf8() ); sphere_mat_node_ = new ACG::SceneGraph::MaterialNode(0, nodeName ); PluginFunctions::addGlobalNode(sphere_mat_node_); sphere_mat_node_->applyProperties( MaterialNode::Blending | MaterialNode::Material | MaterialNode::AlphaTest | MaterialNode::BackFaceCulling ); sphere_mat_node_->set_color(ACG::Vec4f(1.0, 0.0, 0.0, 0.3)); sphere_mat_node_->enable_blending(); sphere_mat_node_->disable_alpha_test(); sphere_mat_node_->enable_backface_culling(); nodeName = std::string( tr("Selection Base Plugin: Selection Sphere").toUtf8() ); sphere_node_ = new ACG::SceneGraph::GlutPrimitiveNode(ACG::SceneGraph::GlutPrimitiveNode::SPHERE, sphere_mat_node_, nodeName); sphere_node_->drawMode(ACG::SceneGraph::DrawModes::SOLID_SMOOTH_SHADED); sphere_node_->get_primitive(0).color = ACG::Vec4f(1.0, 0.0, 0.0,0.3); sphere_node_->hide(); // Line node nodeName = std::string( tr("Selection Base Plugin: Lasso Selection Line").toUtf8() ); line_node_ = new ACG::SceneGraph::LineNode (ACG::SceneGraph::LineNode::PolygonMode, 0, nodeName ); PluginFunctions::addGlobalNode(line_node_); line_node_->set_line_width (2.0); line_node_->alwaysOnTop() = true; line_node_->setTraverseMode (BaseNode::NodeFirst | BaseNode::SecondPass); line_node_->set_color(ACG::Vec4f(1.0,0.0,0.0,1.0)); line_node_->set_base_color(ACG::Vec4f(1.0,0.0,0.0,1.0)); line_node_->hide(); } //============================================================================================ SelectionTypeFrameWidget* SelectionBasePlugin::createNewTypeFrame(SelectionEnvironment& _env) { SelectionTypeFrameWidget* tab = new SelectionTypeFrameWidget(tool_->typeTabWidget); // Layout in tool box that contains the primitive buttons _env.primitivesBar = new QHBoxLayout(tab->toolPrimitivesBar); // Layout in tool box that contains the operation buttons _env.operationsBar = new QVBoxLayout(tab->toolOperationsWidget); QSizePolicy policy; policy.setVerticalPolicy(QSizePolicy::MinimumExpanding); policy.setHorizontalPolicy(QSizePolicy::Preferred); tab->selectionGroup->setSizePolicy(policy); tab->toolPrimitivesBar->setLayout(_env.primitivesBar); tab->toolPrimitivesBar->setMinimumHeight(68); tab->toolOperationsWidget->setLayout(_env.operationsBar); tab->toolOperationsWidget->setMinimumHeight(150); _env.primitiveActions = new QActionGroup(0); _env.primitiveActions->setExclusive(true); return tab; } //============================================================================================ void SelectionBasePlugin::slotLoadSelectionButton() { // Load selection button has been clicked QString filename = QFileDialog::getOpenFileName(0, tr("Load Selection"), "selection.ini", tr("Selection files ( *.ini )")); if(filename.length() > 0) { INIFile file; if(!file.connect(filename, false)) { emit log(LOGERR, QString("Could not read file '%1'!").arg(filename)); return; } // Pass ini-file to all object selection implementations emit loadSelection(file); // Close file file.disconnect(); } } //============================================================================================ void SelectionBasePlugin::slotSaveSelectionButton() { // Save selection button has been clicked QString filename = QFileDialog::getSaveFileName(0, tr("Save Selection"), "selection.ini", tr("Selection files ( *.ini )")); if(filename.length() > 0) { INIFile file; if(!file.connect(filename, true)) { emit log(LOGERR, QString("Could not create file '%1'!").arg(filename)); return; } // Pass ini-file to all object selection implementations emit saveSelection(file); // Write all data to the file file.disconnect(); } } //============================================================================================ void SelectionBasePlugin::slotKeyEvent(QKeyEvent* _event) { // Check if we want to select or deselect if ((_event->modifiers() & Qt::ControlModifier) || (_event->key() == Qt::Key_Control)) { deselection_ = true; primitivesBarGroup_->setExclusive(false); } else { deselection_ = false; primitivesBarGroup_->setExclusive(true); } // Check if we want to source or target selection if ((_event->modifiers() & Qt::ShiftModifier) || (_event->key() == Qt::Key_Shift)) tool_->restrictOnTargets->setChecked(true); else tool_->restrictOnTargets->setChecked(false); // We have to store and search for registered key combinations at this point // in order to preserve the possibility to register some key events exclusively // for SelectionBasePlugin (whithout passing them on to al type selection plugins... // Search for key combination std::set >::iterator f = registeredKeys_.find(std::pair(_event->key(), _event->modifiers())); if(f != registeredKeys_.end()) { // Some registered key found emit keyShortcutEvent((*f).first,(*f).second); } } //============================================================================================ void SelectionBasePlugin::slotKeyReleaseEvent(QKeyEvent* _event) { //check if we want to select or deselect if ((_event->modifiers() & Qt::ControlModifier) || (_event->key() == Qt::Key_Control)) { deselection_ = false; primitivesBarGroup_->setExclusive(true); } // Check if we want to source or target selection if ((_event->modifiers() & Qt::ShiftModifier) || (_event->key() == Qt::Key_Shift)) tool_->restrictOnTargets->setChecked(false); } //============================================================================================ void SelectionBasePlugin::slotAddSelectionEnvironment(QString _modeName, QString _description, QIcon _icon, QString& _handleName) { /* A new selection environment is to be added. We first test if the associated selection environment already exists. If not, we create a new button and hide it. */ std::map::iterator it = selectionEnvironments_.begin(); for(; it != selectionEnvironments_.end(); ++it) { if(_modeName == (*it).second.name) { emit log(LOGINFO, QString("Selection environment %1 already exists.").arg(_modeName)); return; } } // Create new selection environment SelectionEnvironment env; env.name = _modeName; SelectionTypeFrameWidget* tab = createNewTypeFrame(env); // Add type frame to tab widget int index = tool_->typeTabWidget->addTab(tab, _icon, _modeName); env.tabWidget = tool_->typeTabWidget->widget(index); // Disable type frame unless there's at least one // object of the desired type in the scene tool_->typeTabWidget->setTabEnabled(index, false); tool_->typeTabWidget->widget(index)->setEnabled(false); // Create a unique handle name for this selection environment _handleName = getUniqueHandleName("h_" + _modeName.replace(" ", "_")); // Set handle for selection environment env.handle = _handleName; // Update pick mode toolbar updatePickModeToolBar(); // Add selection environment to local map selectionEnvironments_.insert(std::pair(_handleName, env)); } //============================================================================================ void SelectionBasePlugin::slotRegisterType(QString _handleName, DataType _type) { /* Register new data type under the selection environment with handle name _handleName. */ std::map::iterator it = selectionEnvironments_.find(_handleName); // If the associated selection environment has been found, // we add the specified data type to the list of supported data types if(it != selectionEnvironments_.end()) { // Search if the data type has already been added before... for(std::vector::iterator t_it = (*it).second.types.begin(); t_it != (*it).second.types.end(); ++t_it) { // If the type already exists in the list -> return if ((*t_it) == _type) return; } // ...if not, add it. (*it).second.types.push_back(_type); // And show selection environment button if at least one object // of the associated type already exists in the scenegraph if(typeExists(_type)) { // Show selection environment's tab widget tool_->typeTabWidget->setTabEnabled(tool_->typeTabWidget->indexOf((*it).second.tabWidget), true); (*it).second.tabWidget->setEnabled(true); } } else { emit log(LOGERR, "The specified selection environment has not been found! The data type could not be registered."); } } void SelectionBasePlugin::updatePickModeToolBar() { // Add newly added primitive and tool buttons QList primitivesList = primitivesBarGroup_->actions(); for(QList::iterator it = primitivesList.begin(); it != primitivesList.end(); ++it) { (*it)->setEnabled(false); // If at least one object of this type exists in the scene, // don't grey out the button PrimitiveAction* act = dynamic_cast(*it); if(act) { std::map::iterator sit = selectionEnvironments_.find(act->selectionEnvironmentHandle()); if(sit != selectionEnvironments_.end()) { bool atLeastOne = false; for(std::vector::iterator tit = (*sit).second.types.begin(); tit != (*sit).second.types.end(); ++tit) { if(typeExists(*tit)) { atLeastOne = true; break; } } if(atLeastOne) { (*it)->setEnabled(true); } } } } // Only activate those tools, that are available for the current // active primitive type for(std::map::iterator it = selectionEnvironments_.begin(); it != selectionEnvironments_.end(); ++it) { // Default selection modes toggleSelectionAction_->setEnabled(toggleSelectionAction_->isAssociated(currentPrimitiveType_, true)); lassoSelectionAction_->setEnabled(lassoSelectionAction_->isAssociated(currentPrimitiveType_, true)); volumeLassoSelectionAction_->setEnabled(volumeLassoSelectionAction_->isAssociated(currentPrimitiveType_, true)); surfaceLassoSelectionAction_->setEnabled(surfaceLassoSelectionAction_->isAssociated(currentPrimitiveType_, true)); sphereSelectionAction_->setEnabled(sphereSelectionAction_->isAssociated(currentPrimitiveType_, true)); boundarySelectionAction_->setEnabled(boundarySelectionAction_->isAssociated(currentPrimitiveType_, true)); floodFillSelectionAction_->setEnabled(floodFillSelectionAction_->isAssociated(currentPrimitiveType_, true)); componentsSelectionAction_->setEnabled(componentsSelectionAction_->isAssociated(currentPrimitiveType_, true)); // Custom selection modes for(std::set::iterator cit = (*it).second.customSelectionModes.begin(); cit != (*it).second.customSelectionModes.end(); ++cit) { (*cit)->setEnabled((availableObjectTypes_ & (*cit)->objectTypeRestriction()) && (*cit)->isAssociated(currentPrimitiveType_, true)); } } } //============================================================================================ void SelectionBasePlugin::slotMouseWheelEvent(QWheelEvent* _event, const std::string& _mode) { if(currentPickMode_ == NO_SELECTION_PICKING) return; // Increase sphere radius if (currentSelectionMode_ == SB_SPHERE) { float d = -(float)_event->delta() / 120.0 * 0.1; sphere_radius_ *= 1.0 + d; sphere_node_->set_size(sphere_radius_); sphere_node_->show(); emit updateView(); } } //============================================================================================ void SelectionBasePlugin::slotMouseEvent(QMouseEvent* _event) { if(currentPickMode_ == NO_SELECTION_PICKING) return; // Go into appropriate pick processing if(currentSelectionMode_ == SB_TOGGLE) { slotMouseToggleSelection(_event); } else if (currentSelectionMode_ == SB_LASSO) { slotMouseLassoSelection(_event); } else if (currentSelectionMode_ == SB_VOLUME_LASSO) { slotMouseVolumeLassoSelection(_event); } else if (currentSelectionMode_ == SB_SURFACE_LASSO) { slotMouseSurfaceLassoSelection(_event); } else if (currentSelectionMode_ == SB_SPHERE) { slotMouseSphereSelection(_event); } else if (currentSelectionMode_ == SB_BOUNDARY) { slotMouseBoundarySelection(_event); } else if (currentSelectionMode_ == SB_FLOODFILL) { slotMouseFloodFillSelection(_event); } else if (currentSelectionMode_ == SB_COMPONENTS) { slotMouseComponentsSelection(_event); } else { // Custom selection mode slotMouseCustomSelection(_event); } } //============================================================================================ void SelectionBasePlugin::slotAddPrimitiveType(QString _handleName, QString _name, QIcon _icon, SelectionInterface::PrimitiveType& _typeHandle) { // Get selection environment std::map::iterator it = selectionEnvironments_.find(_handleName); if(it == selectionEnvironments_.end()) { emit log(LOGERR, QString("Could not find selection environment width handle '%1'!").arg(_handleName)); return; } SelectionEnvironment& env = (*it).second; // Test if there's a free primitive type available // Note: This is actually limited to 31 if(nextFreePrimitiveType_ > nextFreePrimitiveType_ << 1) { emit log(LOGERR, "Maximum number of custom primitive types for selection reached!"); return; } // Test if there's a custom type with the same name already QList::const_iterator a_it = env.primitiveActions->actions().constBegin(); for(; a_it != env.primitiveActions->actions().constEnd(); ++a_it) { if((*a_it)->text() == _name) { emit log(LOGERR, QString("A custom primitive type with name \"%1\" already exists!").arg(_name)); return; } } // Add custom primitive type PrimitiveAction* action = new PrimitiveAction(_icon, _name, env.primitiveActions); action->setCheckable(true); action->selectionEnvironmentHandle(_handleName); primitivesBarGroup_->addAction(action); pickModeToolBar_->clear(); pickModeToolBar_->addActions(primitivesBarGroup_->actions()); pickModeToolBar_->addSeparator(); pickModeToolBar_->addActions(selectionModesGroup_->actions()); // Also add type button to tool box of environment tab ActionButton* button = new ActionButton(action); button->setMinimumSize(QSize(32,32)); button->setMaximumSize(QSize(64,64)); env.primitivesBar->addWidget(button); _typeHandle = nextFreePrimitiveType_; action->primitiveType(_typeHandle); // Add primitive type to environment env.primitiveTypes |= _typeHandle; primitiveTypeButtons_.insert(std::pair(_typeHandle,action)); // Go over to next free primitive type nextFreePrimitiveType_ <<= 1; // Connect action to local slot in order to keep track of active primitive types connect(action, SIGNAL(toggled(bool)), this, SLOT(updateActivePrimitiveTypes(bool))); updatePickModeToolBar(); } //============================================================================================ void SelectionBasePlugin::updateActivePrimitiveTypes(bool _checked) { QObject* sender = QObject::sender(); PrimitiveAction* clickedAction = 0; clickedAction = dynamic_cast(sender); if(!clickedAction) return; // Change button state clickedAction->setChecked(_checked); // Reset types currentPrimitiveType_ = 0u; QList actions = primitivesBarGroup_->actions(); for(int i = 0; i < actions.size(); ++i) { if(actions[i]->isChecked()) { PrimitiveAction* pa = 0; pa = dynamic_cast(actions[i]); if(pa) { currentPrimitiveType_ |= pa->primitiveType(); } } } // If the primitive type button has been activated, // automatically go into the associated selection environment's // picking mode if(_checked) { slotSelectionEnvironmentRequested(_checked); } // If currently selected selection mode is not available // for the currently active primitive types, reset selection mode QList sm_actions = selectionModesGroup_->actions(); bool atLeastOneSelectionMode = false; for(int i = 0; i < sm_actions.size(); ++i) { if(sm_actions[i]->isChecked()) { atLeastOneSelectionMode = true; HandleAction* ha = 0; ha = dynamic_cast(sm_actions[i]); if(ha) { if(!ha->isAssociated(currentPrimitiveType_)) { ha->blockSignals(true); ha->setChecked(false); ha->blockSignals(false); toggleSelectionAction_->trigger(); } } } } // If no selection mode is active, automatically go into toggle mode if(!atLeastOneSelectionMode) { toggleSelectionAction_->trigger(); } // Automatically show tab widget associated to this primitive type std::map::iterator sit = selectionEnvironments_.find(clickedAction->selectionEnvironmentHandle()); if(sit != selectionEnvironments_.end() && _checked) { tool_->typeTabWidget->setCurrentIndex(tool_->typeTabWidget->indexOf((*sit).second.tabWidget)); } // Clear lines line_node_->clear(); linePoints_.clear(); lassoSelection_ = false; // Hide and show selection functions that are associated // with the currently active primitive types slotShowAndHideOperations(); // Update pick modes bar updatePickModeToolBar(); } //============================================================================================ void SelectionBasePlugin::slotAddSelectionOperations(QString _handleName, QStringList _operationsList, QString _category, PrimitiveType _type) { // Get selection environment std::map::iterator e_it = selectionEnvironments_.find(_handleName); if(e_it == selectionEnvironments_.end()) { emit log(LOGERR, QString("Could not find selection environment with handle '%1'!").arg(_handleName)); return; } SelectionEnvironment& env = (*e_it).second; // Find associated layout from category std::map >::iterator it = env.categories.find(_category); if(it == env.categories.end()) { // Create new category FillingLayout* fillLayout = new FillingLayout(2); QGroupBox* group = new QGroupBox(_category); group->setLayout(fillLayout); // Insert newly created fillLayout into map std::pair >::iterator,bool> ret; ret = env.categories.insert(std::pair >(_category, std::pair(fillLayout,group))); it = ret.first; // Add group box to vertical operations layout env.operationsBar->addWidget(group); } // Add buttons with function names to operations widget for(int i = 0; i < _operationsList.size(); ++i) { QPushButton* button = new QPushButton(_operationsList[i]); button->setDisabled(true); button->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); int width = button->fontMetrics().width(_operationsList[i]); button->setMinimumWidth(width); button->setFixedHeight(26); connect(button, SIGNAL(clicked()), this, SLOT(slotOperationRequested())); // Add operation to local list env.operations.insert(std::pair(_type, button)); // Add button to operations widget in tool box (*it).second.first->addWidget(button); } // Show operations if in supported primitive type mode slotShowAndHideOperations(); } //============================================================================================ void SelectionBasePlugin::slotOperationRequested() { QObject* sender = QObject::sender(); QPushButton* button = 0; button = dynamic_cast(sender); if(!button) return; emit selectionOperation(button->text()); } //============================================================================================ void SelectionBasePlugin::slotShowAndHideOperations() { for(std::map::iterator e_it = selectionEnvironments_.begin(); e_it != selectionEnvironments_.end(); ++e_it) { for(std::multimap::iterator it = (*e_it).second.operations.begin(); it != (*e_it).second.operations.end(); ++it) { if((currentPrimitiveType_ & (*it).first) || (*it).first == 0u) { // Type is currently active -> show button (*it).second->setDisabled(false); } else { // Type is currently not active -> hide button (*it).second->setDisabled(true); } } } } //============================================================================================ void SelectionBasePlugin::slotSelectionEnvironmentRequested(bool _checked) { updatePickModeToolBar(); PluginFunctions::actionMode(Viewer::PickingMode); PluginFunctions::pickMode(SELECTION_PICKING); currentPickMode_ = SELECTION_PICKING; } //============================================================================================ void SelectionBasePlugin::slotEnterSelectionMode(bool _checked) { QObject* obj = QObject::sender(); HandleAction* act = 0; act = dynamic_cast(obj); if(act == 0) return; // Make button checked act->setChecked(_checked); // Keep active selection mode if(_checked) { currentSelectionMode_ = act->selectionModeHandle(); } // Clear lines line_node_->clear(); linePoints_.clear(); lassoSelection_ = false; if(currentSelectionMode_ == SB_SPHERE) { // Adjust sphere radius to have size defined relatively to the scene radius sphere_radius_ = 0.03 * PluginFunctions::sceneRadius(); } } //============================================================================================ void SelectionBasePlugin::slotPickModeChanged (const std::string& _pickmode) { // Test if current pickmode is a selection pick mode bool selectionPicking = (_pickmode == "SelectionBasePicking"); // Show/hode line and sphere node if(currentSelectionMode_ == SB_SPHERE) sphere_node_->show(); else sphere_node_->hide(); if(currentSelectionMode_ == SB_LASSO || currentSelectionMode_ == SB_VOLUME_LASSO) line_node_->show(); else line_node_->hide(); bool resetPickToolBar = false; if(currentPickMode_ != NO_SELECTION_PICKING) { // We go into examiner (or some other) mode for the first time // Just hide line and sphere nodes sphere_node_->hide(); line_node_->hide(); // Save values lastPickMode_ = currentPickMode_; currentPickMode_ = NO_SELECTION_PICKING; } else if (selectionPicking && currentPickMode_ == NO_SELECTION_PICKING && lastPickMode_ != NO_SELECTION_PICKING) { // We come back from examiner mode (windows key hit) currentPickMode_ = lastPickMode_; } else if (!selectionPicking && currentPickMode_ == NO_SELECTION_PICKING) { // We go into some other picking mode // Clear line nodes linePoints_.clear(); line_node_->clear_points(); // A completely different pick mode has been chosen that // is not handled by this plugin, so reset current pickmode currentPickMode_ = NO_SELECTION_PICKING; currentSelectionMode_ = NO_SELECTION_MODE; lastPickMode_ = NO_SELECTION_PICKING; // We don't want no tool to be selected anymore resetPickToolBar = true; } else { // We return from some other pickimg mode (or mutliple examiner sessions) // to selection mode lastPickMode_ = currentPickMode_ = _pickmode.c_str(); // Reset pick toolbar resetPickToolBar = true; // Clear line nodes linePoints_.clear(); line_node_->clear_points(); } // Make sure that the pick mode buttons are in correct state toggleSelectionAction_->setChecked(!resetPickToolBar && currentSelectionMode_ == SB_TOGGLE); lassoSelectionAction_->setChecked(!resetPickToolBar && currentSelectionMode_ == SB_LASSO); volumeLassoSelectionAction_->setChecked(!resetPickToolBar && currentSelectionMode_ == SB_VOLUME_LASSO); surfaceLassoSelectionAction_->setChecked(!resetPickToolBar && currentSelectionMode_ == SB_SURFACE_LASSO); sphereSelectionAction_->setChecked(!resetPickToolBar && currentSelectionMode_ == SB_SPHERE); boundarySelectionAction_->setChecked(!resetPickToolBar && currentSelectionMode_ == SB_BOUNDARY); floodFillSelectionAction_->setChecked(!resetPickToolBar && currentSelectionMode_ == SB_FLOODFILL); componentsSelectionAction_->setChecked(!resetPickToolBar && currentSelectionMode_ == SB_COMPONENTS); for(std::map::iterator it = selectionEnvironments_.begin(); it != selectionEnvironments_.end(); ++it) { // Custom selection modes for(std::set::iterator csm_it = (*it).second.customSelectionModes.begin(); csm_it != (*it).second.customSelectionModes.end(); ++csm_it) { (*csm_it)->setChecked(!resetPickToolBar && currentSelectionMode_ == (*csm_it)->selectionModeHandle()); } } if(selectionPicking) updatePickModeToolBar(); } //============================================================================================ void SelectionBasePlugin::showSelectionMode(QString _mode, QIcon _icon, QString _desc, QString _handleName, bool _show, SelectionInterface::PrimitiveType _associatedTypes, QString& _customIdentifier, bool _custom, DataType _objectTypeRestriction) { // Find selection environment that is associated to _handleName std::map::iterator it = selectionEnvironments_.find(_handleName); // Return if the requested selection environment was not found if(it == selectionEnvironments_.end()) return; if(!_custom) { if(_mode == SB_TOGGLE) { if(_show) { (*it).second.defaultSelectionModes.insert(toggleSelectionAction_); toggleSelectionAction_->addAssociatedType(_associatedTypes); } else { std::set::iterator e = (*it).second.defaultSelectionModes.find(toggleSelectionAction_); if(e != (*it).second.defaultSelectionModes.end()) { (*it).second.defaultSelectionModes.erase(e); toggleSelectionAction_->removeAssociatedType(_associatedTypes); } } } else if (_mode == SB_LASSO) { if(_show) { (*it).second.defaultSelectionModes.insert(lassoSelectionAction_); lassoSelectionAction_->addAssociatedType(_associatedTypes); } else { std::set::iterator e = (*it).second.defaultSelectionModes.find(lassoSelectionAction_); if(e != (*it).second.defaultSelectionModes.end()) { (*it).second.defaultSelectionModes.erase(e); lassoSelectionAction_->removeAssociatedType(_associatedTypes); } } } else if (_mode == SB_VOLUME_LASSO) { if(_show) { (*it).second.defaultSelectionModes.insert(volumeLassoSelectionAction_); volumeLassoSelectionAction_->addAssociatedType(_associatedTypes); } else { std::set::iterator e = (*it).second.defaultSelectionModes.find(volumeLassoSelectionAction_); if(e != (*it).second.defaultSelectionModes.end()) { (*it).second.defaultSelectionModes.erase(e); volumeLassoSelectionAction_->removeAssociatedType(_associatedTypes); } } } else if (_mode == SB_SURFACE_LASSO) { if(_show) { (*it).second.defaultSelectionModes.insert(surfaceLassoSelectionAction_); surfaceLassoSelectionAction_->addAssociatedType(_associatedTypes); } else { std::set::iterator e = (*it).second.defaultSelectionModes.find(surfaceLassoSelectionAction_); if(e != (*it).second.defaultSelectionModes.end()) { (*it).second.defaultSelectionModes.erase(e); surfaceLassoSelectionAction_->removeAssociatedType(_associatedTypes); } } } else if (_mode == SB_SPHERE) { if(_show) { (*it).second.defaultSelectionModes.insert(sphereSelectionAction_); sphereSelectionAction_->addAssociatedType(_associatedTypes); } else { std::set::iterator e = (*it).second.defaultSelectionModes.find(sphereSelectionAction_); if(e != (*it).second.defaultSelectionModes.end()) { (*it).second.defaultSelectionModes.erase(e); sphereSelectionAction_->removeAssociatedType(_associatedTypes); } } } else if (_mode == SB_BOUNDARY) { if(_show) { (*it).second.defaultSelectionModes.insert(boundarySelectionAction_); boundarySelectionAction_->addAssociatedType(_associatedTypes); } else { std::set::iterator e = (*it).second.defaultSelectionModes.find(boundarySelectionAction_); if(e != (*it).second.defaultSelectionModes.end()) { (*it).second.defaultSelectionModes.erase(e); boundarySelectionAction_->removeAssociatedType(_associatedTypes); } } } else if (_mode == SB_FLOODFILL) { if(_show) { (*it).second.defaultSelectionModes.insert(floodFillSelectionAction_); floodFillSelectionAction_->addAssociatedType(_associatedTypes); } else { std::set::iterator e = (*it).second.defaultSelectionModes.find(floodFillSelectionAction_); if(e != (*it).second.defaultSelectionModes.end()) { (*it).second.defaultSelectionModes.erase(e); floodFillSelectionAction_->removeAssociatedType(_associatedTypes); } } } else if (_mode == SB_COMPONENTS) { if(_show) { (*it).second.defaultSelectionModes.insert(componentsSelectionAction_); componentsSelectionAction_->addAssociatedType(_associatedTypes); } else { std::set::iterator e = (*it).second.defaultSelectionModes.find(componentsSelectionAction_); if(e != (*it).second.defaultSelectionModes.end()) { (*it).second.defaultSelectionModes.erase(e); componentsSelectionAction_->removeAssociatedType(_associatedTypes); } } } } else { if(_show) { // Create custom function // Create action for associated function _customIdentifier = getUniqueIdentifierName(QString(_handleName + "_" + _mode).replace(" ", "_")); // Create action HandleAction* action = new HandleAction(_icon, _desc, selectionModesGroup_, _objectTypeRestriction); action->setCheckable(true); action->selectionEnvironmentHandle(_handleName); action->selectionModeHandle(_customIdentifier); action->addAssociatedType(_associatedTypes); // Add action to tools bar selectionModesGroup_->addAction(action); pickModeToolBar_->clear(); pickModeToolBar_->addActions(primitivesBarGroup_->actions()); pickModeToolBar_->addSeparator(); pickModeToolBar_->addActions(selectionModesGroup_->actions()); // Add pickmode name and button to selection environment's container (*it).second.customSelectionModes.insert(action); connect(action, SIGNAL(triggered(bool)), this, SLOT(slotEnterSelectionMode(bool))); } else { // Search custom selection mode std::set::iterator e = (*it).second.customSelectionModes.begin(); for(; e != (*it).second.customSelectionModes.end(); ++e) { if((*e)->selectionEnvironmentHandle() == _handleName) break; } // Delete action from list if(e != (*it).second.customSelectionModes.end()) { (*e)->removeAssociatedType(_associatedTypes); (*it).second.customSelectionModes.erase(e); } } } } //============================================================================================ void SelectionBasePlugin::slotAddCustomSelectionMode(QString _handleName, QString _modeName, QString _description, QIcon _icon, SelectionInterface::PrimitiveType _associatedTypes, QString& _customIdentifier) { showSelectionMode(_modeName, _icon, _description, _handleName, true, _associatedTypes, _customIdentifier, true); updatePickModeToolBar(); } //============================================================================================ void SelectionBasePlugin::slotAddCustomSelectionMode(QString _handleName, QString _modeName, QString _description, QIcon _icon, SelectionInterface::PrimitiveType _associatedTypes, QString& _customIdentifier, DataType _objectTypeRestriction) { showSelectionMode(_modeName, _icon, _description, _handleName, true, _associatedTypes, _customIdentifier, true, _objectTypeRestriction); updatePickModeToolBar(); } //============================================================================================ void SelectionBasePlugin::slotShowToggleSelectionMode(QString _handleName, bool _show, SelectionInterface::PrimitiveType _associatedTypes) { QString iconPath = OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator(); QIcon icon(iconPath + TOGGLE_IMG); QString dummy; showSelectionMode(SB_TOGGLE, icon, TOGGLE_DESC, _handleName, _show, _associatedTypes, dummy); updatePickModeToolBar(); } //============================================================================================ void SelectionBasePlugin::slotShowLassoSelectionMode(QString _handleName, bool _show, SelectionInterface::PrimitiveType _associatedTypes) { QString iconPath = OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator(); QIcon icon(iconPath + LASSO_IMG); QString dummy; showSelectionMode(SB_LASSO, icon, LASSO_DESC, _handleName, _show, _associatedTypes, dummy); updatePickModeToolBar(); } //============================================================================================ void SelectionBasePlugin::slotShowVolumeLassoSelectionMode(QString _handleName, bool _show, SelectionInterface::PrimitiveType _associatedTypes) { QString iconPath = OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator(); QIcon icon(iconPath + VOLUME_LASSO_IMG); QString dummy; showSelectionMode(SB_VOLUME_LASSO, icon, VOLUME_LASSO_DESC, _handleName, _show, _associatedTypes, dummy); updatePickModeToolBar(); } //============================================================================================ void SelectionBasePlugin::slotShowSurfaceLassoSelectionMode(QString _handleName, bool _show, SelectionInterface::PrimitiveType _associatedTypes) { QString iconPath = OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator(); QIcon icon(iconPath + SURFACE_LASSO_IMG); QString dummy; showSelectionMode(SB_SURFACE_LASSO, icon, SURFACE_LASSO_DESC, _handleName, _show, _associatedTypes, dummy); updatePickModeToolBar(); } //============================================================================================ void SelectionBasePlugin::slotShowSphereSelectionMode(QString _handleName, bool _show, SelectionInterface::PrimitiveType _associatedTypes) { QString iconPath = OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator(); QIcon icon(iconPath + SPHERE_IMG); QString dummy; showSelectionMode(SB_SPHERE, icon, SPHERE_DESC, _handleName, _show, _associatedTypes, dummy); updatePickModeToolBar(); } //============================================================================================ void SelectionBasePlugin::slotShowClosestBoundarySelectionMode(QString _handleName, bool _show, SelectionInterface::PrimitiveType _associatedTypes) { QString iconPath = OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator(); QIcon icon(iconPath + BOUNDARY_IMG); QString dummy; showSelectionMode(SB_BOUNDARY, icon, BOUNDARY_DESC, _handleName, _show, _associatedTypes, dummy); updatePickModeToolBar(); } //============================================================================================ void SelectionBasePlugin::slotShowFloodFillSelectionMode(QString _handleName, bool _show, SelectionInterface::PrimitiveType _associatedTypes) { QString iconPath = OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator(); QIcon icon(iconPath + FLOODFILL_IMG); QString dummy; showSelectionMode(SB_FLOODFILL, icon, FLOODFILL_DESC, _handleName, _show, _associatedTypes, dummy); updatePickModeToolBar(); } //============================================================================================ void SelectionBasePlugin::slotShowComponentsSelectionMode(QString _handleName, bool _show, SelectionInterface::PrimitiveType _associatedTypes) { QString iconPath = OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator(); QIcon icon(iconPath + COMPONENTS_IMG); QString dummy; showSelectionMode(SB_COMPONENTS, icon, COMPONENTS_DESC, _handleName, _show, _associatedTypes, dummy); updatePickModeToolBar(); } //============================================================================================ void SelectionBasePlugin::slotGetActiveDataTypes(TypeList& _types) { if(currentPickMode_ == NO_SELECTION_PICKING) { _types = TypeList(); } else { std::map::iterator it = selectionEnvironments_.find(currentPickMode_); if(it == selectionEnvironments_.end()) { _types = TypeList(); } else { _types = (*it).second.types; } } } //============================================================================================ void SelectionBasePlugin::slotGetActivePrimitiveType(SelectionInterface::PrimitiveType& _type) { _type = currentPrimitiveType_; } //============================================================================================ void SelectionBasePlugin::slotMouseToggleSelection(QMouseEvent* _event) { // Only emit toggleSelection if left mouse button was clicked if (_event->type() == QEvent::MouseButtonPress) { if (_event->button() == Qt::RightButton) return; emit toggleSelection(_event, currentPrimitiveType_, deselection_); } } //============================================================================================ void SelectionBasePlugin::slotMouseLassoSelection(QMouseEvent* _event) { // Ignore context menu for lasso selection if (_event->button() == Qt::RightButton) return; unsigned int node_idx, target_idx; ACG::Vec3d hit_point; int y = PluginFunctions::viewerProperties().glState().context_height() - _event->pos().y(); if (!PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE, _event->pos(), node_idx, target_idx, &hit_point)) hit_point = PluginFunctions::viewerProperties().glState().unproject(ACG::Vec3d(_event->pos().x(), y, 0.5)); // Do rendering of mouse tool... if(_event->type() == QEvent::MouseButtonPress && _event->button() == Qt::LeftButton) { // If mouse button has been pressed if(!lassoSelection_) { // Initiate lasso selection linePoints_.clear(); lassoSelection_ = true; } if(line_node_->hidden()) line_node_->show(); linePoints_.push_back(hit_point); // Inform selection plugins about the performed action emit lassoSelection(_event, currentPrimitiveType_, deselection_); } else if(_event->type() == QEvent::MouseMove) { if(!lassoSelection_) return; if (deselection_) { line_node_->set_color(ACG::Vec4f(1.0,0.0,0.0,1.0)); line_node_->set_base_color(ACG::Vec4f(1.0,0.0,0.0,1.0)); } else { line_node_->set_color(ACG::Vec4f(0.0, 1.0, 0.0, 1.0)); line_node_->set_base_color(ACG::Vec4f(0.0, 1.0, 0.0, 1.0)); } line_node_->clear(); for (std::vector< ACG::Vec3d >::iterator it = linePoints_.begin(); it != linePoints_.end(); ++it) line_node_->add_point(*it); line_node_->add_point(hit_point); // Close lasso if( !linePoints_.empty() ) line_node_->add_point(linePoints_[0]); } else if(_event->type() == QEvent::MouseButtonDblClick) { // Double click lassoSelection_ = false; linePoints_.clear(); line_node_->clear(); line_node_->hide(); // Inform selection plugins about the performed action emit lassoSelection(_event, currentPrimitiveType_, deselection_); } } //============================================================================================ void SelectionBasePlugin::slotMouseVolumeLassoSelection(QMouseEvent* _event) { // Ignore context menu for volume lasso selection if (_event->button() == Qt::RightButton) return; unsigned int node_idx, target_idx; ACG::Vec3d hit_point; int y = PluginFunctions::viewerProperties().glState().context_height() - _event->pos().y(); if (!PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE, _event->pos(), node_idx, target_idx, &hit_point)) hit_point = PluginFunctions::viewerProperties().glState().unproject(ACG::Vec3d(_event->pos().x(), y, 0.5)); // Do rendering of mouse tool... if(_event->type() == QEvent::MouseButtonPress && _event->button() == Qt::LeftButton) { // If mouse button has been pressed if(!lassoSelection_) { // Initiate lasso selection linePoints_.clear(); lassoSelection_ = true; line_node_->show(); } if(line_node_->hidden()) line_node_->show(); linePoints_.push_back(hit_point); // Inform selection plugins about the performed action emit volumeLassoSelection(_event, currentPrimitiveType_, deselection_); } else if(_event->type() == QEvent::MouseMove) { if(!lassoSelection_) return; if (deselection_) { line_node_->set_color(ACG::Vec4f(1.0,0.0,0.0,1.0)); line_node_->set_base_color(ACG::Vec4f(1.0,0.0,0.0,1.0)); } else { line_node_->set_color(ACG::Vec4f(0.0, 1.0, 0.0, 1.0)); line_node_->set_base_color(ACG::Vec4f(0.0, 1.0, 0.0, 1.0)); } line_node_->clear(); for (std::vector< ACG::Vec3d >::iterator it = linePoints_.begin(); it != linePoints_.end(); ++it) line_node_->add_point(*it); line_node_->add_point(hit_point); // Close lasso if( !linePoints_.empty() ) line_node_->add_point(linePoints_[0]); } else if(_event->type() == QEvent::MouseButtonDblClick) { // Double click lassoSelection_ = false; linePoints_.clear(); line_node_->clear(); line_node_->hide(); // Inform selection plugins about the performed action emit volumeLassoSelection(_event, currentPrimitiveType_, deselection_); } } //============================================================================================ void SelectionBasePlugin::slotMouseSurfaceLassoSelection(QMouseEvent* _event) { /* NOT IMPLEMENTED YET */ } //============================================================================================ void SelectionBasePlugin::slotMouseSphereSelection(QMouseEvent* _event) { // Ignore context menu for sphere selection if (_event->button() == Qt::RightButton) return; // Do rendering of mouse tool... unsigned int node_idx, target_idx; ACG::Vec3d hit_point; // Hide sphere node in order to avoid self picking sphere_node_->hide(); // Pick anything to find all possible objects if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_ANYTHING, _event->pos(), node_idx, target_idx, &hit_point)) { BaseObjectData* object = 0; if (PluginFunctions::getPickedObject(node_idx, object)) { // update brush sphere sphere_node_->show(); sphere_node_->set_position(hit_point); sphere_node_->set_size(sphere_radius_); sphere_node_->enablePicking(false); if( (_event->buttons() & Qt::LeftButton) //left button ||( (_event->buttons() == Qt::NoButton) && (_event->type() == QEvent::MouseButtonRelease)) // or release of left button ) { // Inform selection plugins about the performed action emit sphereSelection(_event, sphere_radius_, currentPrimitiveType_, deselection_); } } } else { // Hide sphere node if no object was picked sphere_node_->hide(); } } //============================================================================================ void SelectionBasePlugin::slotMouseBoundarySelection(QMouseEvent* _event) { // Only emit toggleSelection if left mouse button was clicked if (_event->type() == QEvent::MouseButtonPress) { if (_event->button() == Qt::RightButton) return; emit closestBoundarySelection(_event, currentPrimitiveType_, deselection_); } } //============================================================================================ void SelectionBasePlugin::slotMouseFloodFillSelection(QMouseEvent* _event) { // Only emit toggleSelection if left mouse button was clicked if (_event->type() == QEvent::MouseButtonPress) { if (_event->button() == Qt::RightButton) return; double maxAngle = 2*M_PI; if(!OpenFlipper::Options::nogui()) maxAngle = tool_->maxFloodFillAngle->value(); emit floodFillSelection(_event, maxAngle, currentPrimitiveType_, deselection_); } } //============================================================================================ void SelectionBasePlugin::slotMouseComponentsSelection(QMouseEvent* _event) { // Only emit componentsSelection if left mouse button was clicked if (_event->type() == QEvent::MouseButtonPress) { if (_event->button() == Qt::RightButton) return; emit componentsSelection(_event, currentPrimitiveType_, deselection_); } } //============================================================================================ void SelectionBasePlugin::slotMouseCustomSelection(QMouseEvent* _event) { emit customSelection(_event, currentPrimitiveType_, currentSelectionMode_, deselection_); } //============================================================================================ void SelectionBasePlugin::addedEmptyObject (int _id) { /* If an empty object has been added we will check if there exists a selection environment for the associated object type. If so and if this selection environment is not yet available, we will make it available from now on. */ std::map::iterator it = selectionEnvironments_.begin(); bool found = false; BaseObjectData* obj; PluginFunctions::getObject(_id, obj); if (obj) { DataType t = obj->dataType(); // Iterate over all selection environments for(;it != selectionEnvironments_.end(); ++it) { // Iterate over all supported data types per selection environment for(std::vector::iterator t_it = (*it).second.types.begin(); t_it != (*it).second.types.end(); ++t_it) { if(t == (*t_it)) { found = true; break; } } if(found) break; } // Keep track of all data types in the scene availableObjectTypes_ |= obj->dataType(); } else { BaseObject* bObject = 0; PluginFunctions::getObject(_id, bObject); // Groups are ok, others will cause an error if (!bObject->isGroup()) { emit log(LOGERR, "Could not retrieve object type! Maybe a selection environment will be missing."); } return; } if(found) { // We have found a selection environment for the // recently loaded data type -> show tab widget tool_->typeTabWidget->setTabEnabled(tool_->typeTabWidget->indexOf((*it).second.tabWidget), true); (*it).second.tabWidget->setEnabled(true); } // Increase the number of available objects for that type QMap::iterator iterator = typeCounter_.find(obj->dataType()); if ( iterator != typeCounter_.end() ) { typeCounter_[obj->dataType()] = typeCounter_[obj->dataType()] + 1; } else { typeCounter_[obj->dataType()] = 1; } updatePickModeToolBar(); updateTabsOrder(); } //============================================================================================ void SelectionBasePlugin::objectDeleted (int _id) { /* If an object was deleted, we will check if there exists a selection environment for the associated object type. If so and if this selection environment is available, we will remove it if there's no object of the given data type left in the scenegraph. */ std::map::iterator it = selectionEnvironments_.begin(); bool found = false; DataType t; std::vector typeVec; BaseObjectData* obj; PluginFunctions::getObject(_id, obj); if (obj) { t = obj->dataType(); // Iterate over all selection environments for(;it != selectionEnvironments_.end(); ++it) { // Iterate over all supported data types of a selection environment for(std::vector::iterator t_it = (*it).second.types.begin(); t_it != (*it).second.types.end(); ++t_it) { if(t == (*t_it)) { found = true; break; } } if(found) break; } availableObjectTypes_ = (availableObjectTypes_ & ~obj->dataType().value()); } else { emit log(LOGERR, "Could not retrieve object type!"); return; } if(found) { // If we have found a selection environment for the // recently loaded data type AND if there's no // other object with the same data type in the // scene graph -> hide button // Search for other objects for *all* supported data types bool atLeastOne = false; for(std::vector::iterator t_it = (*it).second.types.begin(); t_it != (*it).second.types.end(); ++t_it) { if(typeExists(*t_it, _id)) { atLeastOne = true; break; } } // Show tab widget if at least one object of supported data type was found // Hide it otherwise tool_->typeTabWidget->setTabEnabled(tool_->typeTabWidget->indexOf((*it).second.tabWidget), atLeastOne); (*it).second.tabWidget->setEnabled(atLeastOne); } // Decrease the number of available objects for that type // We track that here because otherwise we had to iterate over all objects // which would cause a linear runtime which is bad for high object counts. QMap::iterator iterator = typeCounter_.find(obj->dataType()); if ( iterator != typeCounter_.end() ) { typeCounter_[obj->dataType()] = typeCounter_[obj->dataType()] - 1; if ( typeCounter_[obj->dataType()] < 0 ) { std::cerr << "====== ERROR =======" << std::endl; std::cerr << "Negative counter for type " << obj->dataType().name().toStdString() << std::endl; } } else { std::cerr << "Error: No counter for type " << obj->dataType().name().toStdString() << std::endl; } updatePickModeToolBar(); updateTabsOrder(); } //============================================================================================ void SelectionBasePlugin::updateTabsOrder() { std::map newMappings; int firstFree = 0; for(int i = 0; i < tool_->typeTabWidget->count(); ++i) { if(tool_->typeTabWidget->isTabEnabled(i)) { tool_->typeTabWidget->insertTab(firstFree, tool_->typeTabWidget->widget(i), tool_->typeTabWidget->tabText(i)); newMappings.insert(std::pair(i,firstFree)); firstFree++; } else { // Tab remains in old order newMappings.insert(std::pair(i,i)); } } // Choose first active tab if(tool_->typeTabWidget->count() > 0) tool_->typeTabWidget->setCurrentIndex(0); } //============================================================================================ void SelectionBasePlugin::slotTargetObjectsOnly(bool& _targetsOnly) { if(OpenFlipper::Options::nogui() || tool_ == 0) _targetsOnly = true; _targetsOnly = tool_->restrictOnTargets->isChecked(); } //============================================================================================ QString SelectionBasePlugin::getUniqueIdentifierName(QString _name, int _num) { /* This makes sure that we always have unique pickmode names in order to avoid double mappings. So we iterate over all selection modes and look if _name already exists as pickmode name. If the name exists, we append a number at the end of the string. */ QString needle = _name;; if(_num != 0) { needle.append(QString::number(_num)); } // Iterate over all selection environments for(std::map::iterator it = selectionEnvironments_.begin(); it != selectionEnvironments_.end(); ++it) { // Iterate over all selection modes for this selection environment // This also includes the standard selection modes (toggle, sphere, etc.) for(std::set::iterator dsm_it = (*it).second.defaultSelectionModes.begin(); dsm_it != (*it).second.defaultSelectionModes.end(); ++dsm_it) { if((*dsm_it)->selectionModeHandle() == needle) { // Recursive call with increased number return getUniqueIdentifierName(_name, _num + 1); } } } return needle; } //============================================================================================ QString SelectionBasePlugin::getUniqueHandleName(QString _name, int _num) { /* This makes sure that we always have unique handle names in order to avoid double mappings. So we iterate over all selection environments and look if _name already exists as handle name. If the name exists, we append a number at the end of the string. */ QString needle = _name;; if(_num != 0) { needle.append(QString::number(_num)); } // Iterate over all selection environments for(std::map::iterator it = selectionEnvironments_.begin(); it != selectionEnvironments_.end(); ++it) { if((*it).first == needle) { // Recursive call with increased number return getUniqueHandleName(_name, _num + 1); } } return needle; } //============================================================================================ bool SelectionBasePlugin::typeExists(DataType _type, int _excludeId) { // Check the number of available objects for that type QMap::iterator iterator = typeCounter_.find(_type); if ( iterator != typeCounter_.end() ) { // We count objects of a specific type and decrease the number by one // which basically happens, if we are about to remove an object. if ( _excludeId != -1 ) { // Sanity check. If the object is of a different type, something went wrong. BaseObject* object; PluginFunctions::getObject(_excludeId,object); if ( object == 0 ) { std::cerr << "Unable to get Object for type exists" << std::endl; } else { // mismatching exclude type if (_type != object->dataType()) { // return as if not excluded if ( typeCounter_[_type] > 0) { return true; // At least one object of this type exists } else if ( typeCounter_[_type] == 0 ){ return false; // No object of this type exists } else { std::cerr << "Type exists Error after mismatch exclude: " << _type.name().toStdString() << " negative count" << std::endl; return false; } } } // Check the counter of the type if ( typeCounter_[_type] - 1 > 0) { return true; // At least one object of this type exists if we delete the excluded one } else if ( typeCounter_[_type] - 1 == 0 ){ return false; // No object of this type exists if we delete the excluded one } else { std::cerr << "Type exists Error " << _type.name().toStdString() << " negative count" << std::endl; return false; } } else { // If we don't exclude items, we directly take the number we found. if ( typeCounter_[_type] > 0) { return true; // At least one object of this type exists } else if ( typeCounter_[_type] == 0 ){ return false; // No object of this type exists } else { std::cerr << "Type exists Error " << _type.name().toStdString() << " negative count" << std::endl; return false; } } } else { // No counter available, which basically means it is equal to zero return false; } // This should never be reached! return false; } //============================================================================================ void SelectionBasePlugin::slotRegisterKeyShortcut(int _key, Qt::KeyboardModifiers _modifiers) { std::set >::iterator f = registeredKeys_.find(std::pair(_key,_modifiers)); if(f == registeredKeys_.end()) { // Register key shortcut emit registerKey(_key, _modifiers, QString("Selection base key %1").arg(_key), true); registeredKeys_.insert(std::pair(_key,_modifiers)); } } //============================================================================================ Q_EXPORT_PLUGIN2(selectionbaseplugin, SelectionBasePlugin);