void LayersPanel::DeleteSelectedLayers() { // If anything selected in the grid if ( m_Scene && m_Grid->IsAnythingSelected() ) { LayerSelectedItems( false ); // Begin undo batch Undo::BatchCommandPtr batch = new Undo::BatchCommand (); // Get an ordered list of the selected rows, and traverse the list in reverse order. // This makes sure that removing an item doesn't change the row number of another // item that will be removed later in the loop. If we don't do this, we run the // risk of invalidating the selection array as we iterate over it. const std::set< uint32_t >& selection = m_Grid->GetSelectedRows(); std::set< uint32_t >::const_reverse_iterator rowItr = selection.rbegin(); std::set< uint32_t >::const_reverse_iterator rowEnd = selection.rend(); for ( ; rowItr != rowEnd; ++rowItr ) { M_LayerDumbPtr::iterator layerItr = m_Layers.find( m_Grid->GetRowName( *rowItr ) ); HELIUM_ASSERT( layerItr != m_Layers.end() ); // NOTE: m_Layers is changing as we iterate over the selection (items are being // removed via callbacks), so don't hold on to any iterators that point into the list. // Recalculate m_Layers.end() each time through the loop. if ( layerItr != m_Layers.end() ) { Layer* layer = layerItr->second; // If the layer that we are about to delete is in the scene's selection list, // we had better just clear out the selection list (otherwise the attribute // editor will still be showing a layer that is no longer in the scene). This // has to be done before actually deleting the layer. if ( m_Scene->GetSelection().Contains( layer ) ) { batch->Push( m_Scene->GetSelection().Clear() ); } // If the layer has any members, we should remove them before removing the layer, // otherwise if those members are deleted, they will be pointing to an invalid // layer that will eventually be Disconnected. S_SceneNodeSmartPtr descendents = layer->GetDescendants(); for ( S_SceneNodeSmartPtr::iterator itr = descendents.begin(), end = descendents.end(); itr != end; ++itr ) { batch->Push( new DependencyCommand( DependencyCommand::Disconnect, layer, *itr ) ); } // Push the command to delete the layer batch->Push( new SceneNodeExistenceCommand( Undo::ExistenceActions::Remove, m_Scene, layer ) ); } } // End undo batch m_Scene->Push( batch ); m_Scene->Execute( false ); } }
void CurveCreateTool::AddToScene() { if ( !m_Instance.ReferencesObject() ) { return; } if ( !m_Scene->IsEditable() ) { return; } uint32_t countControlPoints = m_Instance->GetNumberControlPoints(); if ( countControlPoints > 2 ) { m_Instance->RemoveControlPointAtIndex( countControlPoints - 1 ); m_Instance->Evaluate( GraphDirections::Downstream ); } // remove temp reference m_Scene->RemoveObject( m_Instance ); Undo::BatchCommandPtr batch = new Undo::BatchCommand (); if ( !m_Created ) { batch->Push( m_Scene->GetSelection().Clear() ); m_Created = true; } m_Instance->SetTransient( false ); for ( OS_HierarchyNodeDumbPtr::Iterator childItr = m_Instance->GetChildren().Begin(), childEnd = m_Instance->GetChildren().End(); childItr != childEnd; ++childItr ) { (*childItr)->SetTransient( false ); } // add the existence of this object to the batch batch->Push( new SceneNodeExistenceCommand( Undo::ExistenceActions::Add, m_Scene, m_Instance ) ); // initialize m_Instance->SetOwner( m_Scene ); m_Instance->Initialize(); // center origin m_Instance->CenterTransform(); // append instance to selection m_Selection.Append( m_Instance ); // commit the changes m_Scene->Push( batch ); m_Scene->Execute( false ); m_Instance = NULL; CreateInstance( Vector3::Zero ); }
/////////////////////////////////////////////////////////////////////////////// // Called at the end of a drag-and-drop event. Called when the user // releases the mouse button. Moves all the selected items to be under a // new parent (the item that was dropped onto in the tree). You cannot drop // onto an item that is already selected (your command will be ignored if // you do). All the reparenting is handled through the undo stack so that // it can be undone and redone. This function does not update the tree // hierarchy; that is handled in a callback. // void HierarchyOutliner::OnEndDrag( wxTreeEvent& args ) { const wxTreeItemId& dropItem = args.GetItem(); // You can only drop on a valid item that's not already selected. if ( dropItem.IsOk() && !m_TreeCtrl->IsSelected( dropItem ) ) { m_TreeCtrl->Freeze(); // Reparent every selected item into the item that was dropped on SceneGraph::HierarchyNode* newParent = GetTreeItemData( dropItem )->GetHierarchyNode(); HELIUM_ASSERT( newParent ); Undo::BatchCommandPtr batch = new Undo::BatchCommand (); const OS_SceneNodeDumbPtr& selection = m_CurrentScene->GetSelection().GetItems(); OS_SceneNodeDumbPtr::Iterator selItr = selection.Begin(); const OS_SceneNodeDumbPtr::Iterator selEnd = selection.End(); for ( ; selItr != selEnd; ++selItr ) { SceneGraph::HierarchyNode* hNode = Reflect::ObjectCast< SceneGraph::HierarchyNode >( *selItr ); if ( hNode ) { batch->Push( new ParentCommand( hNode, newParent ) ); } } m_CurrentScene->Push( batch ); m_TreeCtrl->Thaw(); } // else: drop target was not valid }
/////////////////////////////////////////////////////////////////////////////// // Called when the "New Layer From Selection" button is clicked on the toolbar. // void LayersPanel::OnNewLayerFromSelection( wxCommandEvent& dummyEvt ) { if ( m_Scene ) { if(IsSelectionValid() == false) { return; } Undo::BatchCommandPtr batch = new Undo::BatchCommand (); LayerPtr layer = new Layer(); layer->SetOwner( m_Scene ); layer->Initialize(); // Generate a name for this layer GenerateLayerName(layer); batch->Push( new SceneNodeExistenceCommand( Undo::ExistenceActions::Add, m_Scene, layer ) ); // Step 2: add all the selected items to the layer const OS_SceneNodeDumbPtr& selection = m_Scene->GetSelection().GetItems(); OS_SceneNodeDumbPtr::Iterator itr = selection.Begin(); OS_SceneNodeDumbPtr::Iterator end = selection.End(); for ( ; itr != end; ++itr ) { //If the element is a supported type if( *itr ) { SceneNode* node = Reflect::SafeCast< SceneNode >( *itr ); if ( node ) { batch->Push( new DependencyCommand( DependencyCommand::Connect, layer, node ) ); } } } m_Scene->Push( batch ); m_Scene->Execute( false ); } }
/////////////////////////////////////////////////////////////////////////////// // Adds undoable commands to m_Scene's undo queue which will do one of two thing: // // Either... // 1. Adds the currently selected scene items to the currently highlighted // layers. Set addToLayer to true for this option. // or... // 2. Removes the currently selected scene items from the currently highlighted // layers. Set addToLayer to false for this option. // // If there are no selected items, or no selected layers, nothing happens. It // is also safe to remove items from a layer even if they are not part of the // layer (nothing happens), or add items to a layer that already belong to // that layer (again, nothing happens). // void LayersPanel::LayerSelectedItems( bool addToLayer ) { HELIUM_ASSERT( m_Scene ); // Decide whether we are adding the selected scene items to the highlighted // layers, or removing the items from the layers. const DependencyCommand::DependencyAction action = addToLayer ? DependencyCommand::Connect : DependencyCommand::Disconnect; // If there are selected nodes in the scene, and selected rows in this control... const OS_SceneNodeDumbPtr& selectedNodes = m_Scene->GetSelection().GetItems(); std::set< uint32_t > selectedRows = m_Grid->GetSelectedRows(); if ( selectedNodes.Size() > 0 && selectedRows.size() > 0 ) { //Log::Debug( "LayerSelectedItems\n" ); Undo::BatchCommandPtr batch = new Undo::BatchCommand (); OS_SceneNodeDumbPtr::Iterator nodeItr = selectedNodes.Begin(); OS_SceneNodeDumbPtr::Iterator nodeEnd = selectedNodes.End(); std::set< uint32_t >::const_iterator rowItr; const std::set< uint32_t >::const_iterator rowEnd = selectedRows.end(); const M_LayerDumbPtr::const_iterator layerEnd = m_Layers.end(); // For each node in the scene's selection list... for ( ; nodeItr != nodeEnd; ++nodeItr ) { // ensure that we are not trying to add one layer to another layer { Layer* layerTest = Reflect::SafeCast< Layer >( *nodeItr ); if( layerTest ) { continue; } } //Check the current selection if( *nodeItr == NULL ) { //Invalid or incompatible continue; } SceneNode* node = Reflect::SafeCast< SceneNode >( *nodeItr ); if ( node ) { // For each row that is highlighted... for ( rowItr = selectedRows.begin(); rowItr != rowEnd; ++rowItr ) { // Find the layer that goes with the highlighted row M_LayerDumbPtr::iterator layerItr = m_Layers.find( m_Grid->GetRowName( *rowItr ) ); if ( layerItr != layerEnd ) { // Check to see if the node is already in the current layer... Layer* layer = layerItr->second; S_SceneNodeSmartPtr::const_iterator foundDescendant = layer->GetDescendants().find( node ); // If the node is already in this layer, and we are suppose to be adding the node to the layer, // just skip the command (doCommand = false). If the node is not in this layer, and we are // suppose to be removing the node from the layer, skip the command as well. Otherwise, go // ahead and carry out the command (doCommand = true). const bool doCommand = addToLayer ? ( foundDescendant == layer->GetDescendants().end() ) : ( foundDescendant != layer->GetDescendants().end() ); if ( doCommand ) { // Finally make an undoable command to add/remove the node to/from the layer batch->Push( new DependencyCommand( action, layer, node ) ); //Log::Debug( "\t\t%s node %s %s layer %s [row=%d]\n", addToLayer ? "Added" : "Removed", node->GetName().c_str(), addToLayer ? "to" : "from", layer->GetName().c_str(), *rowItr ); } else { //Log::Debug( "\t\tNode %s was already a member of layer %s [row=%d]\n", node->GetName().c_str(), layer->GetName().c_str(), *rowItr ); } } else { // Something is wrong. The rows that are selected in the grid do not correspond to // items in our list of layers (m_Layers). Somehow those lists got out of sync. Log::Error( TXT( "Unable to add selection to layer [row=%d] because it doesn't exist\n" ), *rowItr ); HELIUM_BREAK(); } } } } //Log::Debug( "\n" ); if( !batch->IsEmpty() ) { m_Scene->Push( batch ); m_Scene->Execute( false ); } } }