/////////////////////////////////////////////////////////////////////////////// // 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 Editor::HierarchyNode* newParent = GetTreeItemData( dropItem )->GetHierarchyNode(); HELIUM_ASSERT( newParent ); BatchUndoCommandPtr batch = new BatchUndoCommand (); const OS_ObjectDumbPtr& selection = m_CurrentScene->GetSelection().GetItems(); OS_ObjectDumbPtr::Iterator selItr = selection.Begin(); const OS_ObjectDumbPtr::Iterator selEnd = selection.End(); for ( ; selItr != selEnd; ++selItr ) { Editor::HierarchyNode* hNode = Reflect::SafeCast< Editor::HierarchyNode >( *selItr ); if ( hNode ) { batch->Push( new ParentCommand( hNode, newParent ) ); } } m_CurrentScene->Push( batch ); m_TreeCtrl->Thaw(); } // else: drop target was not valid }
void LayersPanel::DeleteSelectedLayers() { // If anything selected in the grid if ( m_Scene && m_Grid->IsAnythingSelected() ) { LayerSelectedItems( false ); // Begin undo batch BatchUndoCommandPtr batch = new BatchUndoCommand (); // 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( ExistenceActions::Remove, m_Scene, layer ) ); } } // End undo batch m_Scene->Push( batch ); m_Scene->Execute( false ); } }
/////////////////////////////////////////////////////////////////////////////// // 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; } BatchUndoCommandPtr batch = new BatchUndoCommand (); LayerPtr layer = new Layer(); layer->SetOwner( m_Scene ); layer->Initialize(); // Generate a name for this layer GenerateLayerName(layer); batch->Push( new SceneNodeExistenceCommand( ExistenceActions::Add, m_Scene, layer ) ); // Step 2: add all the selected items to the layer const OS_ObjectDumbPtr& selection = m_Scene->GetSelection().GetItems(); OS_ObjectDumbPtr::Iterator itr = selection.Begin(); OS_ObjectDumbPtr::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_ObjectDumbPtr& selectedNodes = m_Scene->GetSelection().GetItems(); std::set< uint32_t > selectedRows = m_Grid->GetSelectedRows(); if ( selectedNodes.Size() > 0 && selectedRows.size() > 0 ) { //Log::Debug( "LayerSelectedItems\n" ); BatchUndoCommandPtr batch = new BatchUndoCommand (); OS_ObjectDumbPtr::Iterator nodeItr = selectedNodes.Begin(); OS_ObjectDumbPtr::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 ); } } }
UndoCommandPtr Curve::CenterTransform() { BatchUndoCommandPtr batch = new BatchUndoCommand(); batch->Push( Base::CenterTransform() ); if ( GetNumberControlPoints() == 0 ) { return batch; } // // We are going to move all control points, so just snap shot // batch->Push( SnapShot() ); // // Compute the centered position // Vector3 position = Vector3::Zero; { uint32_t controlPointCount = 0; OS_HierarchyNodeDumbPtr::Iterator childItr = GetChildren().Begin(); OS_HierarchyNodeDumbPtr::Iterator childEnd = GetChildren().End(); for ( ; childItr != childEnd; ++childItr ) { CurveControlPoint* point = Reflect::SafeCast< CurveControlPoint >( *childItr ); if ( point ) { ++controlPointCount; position += point->GetPosition(); } } position /= (float32_t)controlPointCount; } m_GlobalTransform.TransformVertex( position ); // // Offset the control points // Matrix4 m = m_GlobalTransform; m.t = position; m = m_GlobalTransform * m.Inverted(); { OS_HierarchyNodeDumbPtr::Iterator childItr = GetChildren().Begin(); OS_HierarchyNodeDumbPtr::Iterator childEnd = GetChildren().End(); for ( ; childItr != childEnd; ++childItr ) { CurveControlPoint* point = Reflect::SafeCast< CurveControlPoint >( *childItr ); if ( point ) { Vector3 p = point->GetPosition(); m.TransformVertex( p ); batch->Push( new PropertyUndoCommand< Vector3 >( new Helium::MemberProperty< CurveControlPoint, Vector3 >( point, &CurveControlPoint::GetPosition, &CurveControlPoint::SetPosition ), p ) ); } } } // // Recompute global transform // // our new global transform is just translated to the new position m_GlobalTransform.t = position; // this will recompute the local components SetGlobalTransform( m_GlobalTransform ); // update the transform object Evaluate( GraphDirections::Downstream ); // update each child's local transform to stay in the same global position for ( OS_HierarchyNodeDumbPtr::Iterator itr = m_Children.Begin(), end = m_Children.End(); itr != end; ++itr ) { HierarchyNode* n = *itr; Transform* t = Reflect::SafeCast<Transform>( n ); if ( !t ) { continue; } batch->Push( t->ComputeObjectComponents() ); } Dirty(); return batch; }
void CreateTool::AddToScene() { if (!m_Instance.ReferencesObject()) { return; } if (!m_Scene->IsEditable()) { return; } { HELIUM_EDITOR_SCENE_SCOPE_TIMER( "Remove Transient Instance" ); m_Scene->RemoveObject( m_Instance.Ptr() ); } BatchUndoCommandPtr batch = new BatchUndoCommand (); if (!m_Created) { batch->Push( m_Scene->GetSelection().Clear() ); m_Created = true; } m_Instance->SetTransient( false ); { HELIUM_EDITOR_SCENE_SCOPE_TIMER( "Push Undo Command Adding Instance Into Batch" ); batch->Push( new SceneNodeExistenceCommand( ExistenceActions::Add, m_Scene, m_Instance ) ); } { HELIUM_EDITOR_SCENE_SCOPE_TIMER( "Initialize Instance" ); if ( !m_Instance->IsInitialized() ) { m_Instance->SetOwner( m_Scene ); m_Instance->Initialize(); } HELIUM_ASSERT( m_Instance->GetOwner() == m_Scene ); } { HELIUM_EDITOR_SCENE_SCOPE_TIMER( "Append To Selection" ); m_Selection.Append( m_Instance ); } { HELIUM_EDITOR_SCENE_SCOPE_TIMER( "Push Undo Batch Into Scene" ); m_Scene->Push( batch ); } { HELIUM_EDITOR_SCENE_SCOPE_TIMER( "Place New Instance At Origin" ); m_Instance = NULL; Place( Matrix4::Identity ); } }