#include <cutop.h>
Inheritance diagram for CarbonCopyOp:
Public Member Functions | |
CarbonCopyOp () | |
CarbonCopyOp constructor - does nothing itself, just calls the parent constructor. | |
BOOL | DoProcessing (Trans2DMatrix Transformer, BOOL SelectCopy) |
Performs the common processing of the Clone, Duplicate and CopyAndTransform operations. Clones are not offset from the original, whilst Duplicated objects are offset by the amount in the parameter matrix. CopyAndTransform creates a copy transformed by the specified matrix. | |
Static Public Member Functions | |
static OpState | GetState (String_256 *, OpDescriptor *) |
For finding the operations state. |
Definition at line 304 of file cutop.h.
|
CarbonCopyOp constructor - does nothing itself, just calls the parent constructor.
Definition at line 1776 of file cutop.cpp. 01776 : SelOperation() 01777 { 01778 }
|
|
Performs the common processing of the Clone, Duplicate and CopyAndTransform operations. Clones are not offset from the original, whilst Duplicated objects are offset by the amount in the parameter matrix. CopyAndTransform creates a copy transformed by the specified matrix.
FALSE if the original is to remain selected and the copy unselected (as in dropping copies with CopyAndTransform)
Definition at line 1832 of file cutop.cpp. 01833 { 01834 //Help the user with their selection... 01835 Range* Selection = GetApplication()->FindSelection(); 01836 RangeControl TransFlags = Selection->GetRangeControlFlags(); 01837 TransFlags.IgnoreNoneRenderable=TRUE; 01838 TransFlags.IgnoreInvisibleLayers = TRUE; 01839 Selection->SetRangeControl(TransFlags); 01840 SliceHelper::ModifySelectionToContainWholeButtonElements(); 01841 01842 // Obtain the current selections 01843 NodeListItem * pItem = NULL; 01844 01845 // DMc - build a list of the original selection, so we can reselect them later 01846 Range Sel(*(GetApplication()->FindSelection())); 01847 01848 List * pSelList = Sel.MakeListOfNodes(FALSE); 01849 01850 RangeControl rg = Sel.GetRangeControlFlags(); 01851 rg.PromoteToParent = TRUE; 01852 Sel.Range::SetRangeControl(rg); 01853 01854 ObjChangeFlags cFlags; 01855 ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,this); 01856 01857 if (!Sel.AllowOp(&ObjChange)) 01858 { 01859 SliceHelper::RestoreSelection(); 01860 return FALSE; 01861 } 01862 01863 01864 // Find the first node which is selected 01865 Node* FirstSelectedNode = Sel.FindFirst(); 01866 01867 Node* Current; 01868 01869 // RangeControl LyrCntrl = { TRUE, FALSE, FALSE }; // Selected + don't cross layers 01870 Range LayerRange; 01871 01872 Node* FirstNodeToCopyOnLyr; 01873 Node* LastNodeToCopyOnLyr; 01874 Node* Tail; 01875 01876 ERROR2IF(FirstSelectedNode == NULL, FALSE, "Called CarbonCopy operation with no nodes selected"); 01877 01878 // init the vars needed for the mesh layers bit later on 01879 Node * pFirstNodeOfImportedLayer[5]; 01880 String_256 StateLayerNames[5]; 01881 Node * pLayer = NULL; 01882 01883 StateLayerNames[0].Load(_R(IDS_ROLLOVER_DEFAULT)); // = "Default"; 01884 StateLayerNames[1].Load(_R(IDS_ROLLOVER_MOUSE)); // = "Mouse"; 01885 StateLayerNames[2].Load(_R(IDS_ROLLOVER_CLICKED)); // = "Clicked"; 01886 StateLayerNames[3].Load(_R(IDS_ROLLOVER_SELECTED)); // = "Selected"; 01887 StateLayerNames[4].Load(_R(IDS_BACK_BAR)); // = "BackBar"; 01888 01889 INT32 i; 01890 for (i = 0; i < 5; i++) 01891 pFirstNodeOfImportedLayer[i] = NULL; 01892 01893 //Graham 30/9/96: Tell the current drag operation to clear its list 01894 //of nodes to select at the end of the drag. 01895 TransOperation* pTransOperation=(TransOperation*) GetCurrentDragOp(); 01896 01897 if(pTransOperation) 01898 pTransOperation->ClearNodesToSelect(); 01899 01900 if (!DoStartSelOp(FALSE,TRUE)) // Try to record the selection state 01901 { 01902 goto EndOperation; 01903 } 01904 01905 // The following is error checking to make sure the copy doesn't go off the edge of the 01906 // pasteboard. 01907 01908 // Is the transform matrix going to move or transform the copy? 01909 if (Transformer.GetMatrix().Type!=TRANS_IDENTITY) 01910 { 01911 //Yes. So check the copy will not spill off the pasteboard. 01912 01913 // Find the bounding rectangle of the selection 01914 DocRect CurrentBounds = Sel.GetBoundingRect(); 01915 01916 //And the bounding rectangle of the selection once transformed 01917 DocRect NewBounds=CurrentBounds; 01918 Transformer.GetMatrix().TransformBounds(&NewBounds); 01919 01920 //And the current spread if there is one 01921 Spread* pSpread = pOurDoc->GetSelectedSpread(); 01922 01923 //Is there a spread currently selected? 01924 if (pSpread!=NULL) 01925 { 01926 //Yes. Will its pasteboard expand to include the bounds of the transformed selection? 01927 //(Note: ExpandPasteboardToInclude doesn't actually expand the pasteboard 01928 //currently. It just checks whether NewBounds fits within the pasteboard area.) 01929 if(!pSpread->ExpandPasteboardToInclude(NewBounds)) 01930 { 01931 //No, the transformed copy will not fit in the pasteboard. 01932 //Is the transform a translation? 01933 if(Transformer.GetMatrix().IsTranslation()) 01934 { 01935 //Yes. So restrict the translation so it fits within the 01936 //pasteboard. 01937 01938 //First get the translation in "INT32" form 01939 INT32 XOffset; 01940 INT32 YOffset; 01941 01942 Transformer.GetMatrix().GetTranslation(XOffset, YOffset); 01943 01944 DocRect PasteRect = pSpread->GetPasteboardRect(); 01945 pSpread->DocCoordToSpreadCoord(&PasteRect); 01946 01947 // Find out how far we can move 01948 INT32 MaxX = 0; 01949 INT32 MaxY = 0; 01950 01951 // First the X direction 01952 if (XOffset<0) 01953 { 01954 // The offset is negative, so work out the maximum negative offset allowed 01955 MaxX = PasteRect.lo.x - CurrentBounds.lo.x; 01956 if (XOffset<MaxX) XOffset = MaxX; 01957 } 01958 else 01959 { 01960 MaxX = PasteRect.hi.x - CurrentBounds.hi.x; 01961 if (XOffset>MaxX) 01962 XOffset = MaxX; 01963 } 01964 01965 // and then the Y direction 01966 if (YOffset<0) 01967 { 01968 // The offset is negative, so work out the maximum negative offset allowed 01969 MaxY = PasteRect.lo.y - CurrentBounds.lo.y; 01970 if (YOffset<MaxY) YOffset = MaxY; 01971 } 01972 else 01973 { 01974 MaxY = PasteRect.hi.y - CurrentBounds.hi.y; 01975 if (YOffset>MaxY) 01976 YOffset = MaxY; 01977 } 01978 01979 //And put the translations back into the Transformer matrix 01980 Matrix TranslateMatrix=Transformer.GetMatrix(); 01981 TranslateMatrix.SetTranslation(XOffset, YOffset); 01982 01983 Transformer=Trans2DMatrix(TranslateMatrix); 01984 } 01985 else 01986 { 01987 //No, this is not a translation. 01988 //End the operation without copying the selection. 01989 //This should not be confusing to the user, because the user can see 01990 //he has dragged the selection over the edge of the pasteboard. 01991 //So he should not be surprised that the operation does nothing. 01992 01993 goto EndOperation; 01994 } 01995 } 01996 } 01997 else 01998 { 01999 //No, there is no spread selected. 02000 //We do not want to risk creating a copy outside the current bounds 02001 //of the object. So we set the Transformer matrix to the identity, which simply 02002 //clones the object 02003 Transformer=Trans2DMatrix(); 02004 } 02005 } 02006 02007 // Now start the copying procedure, which we do one layer at a time 02008 02009 //The first node to copy on the first layer is the first selected node 02010 FirstNodeToCopyOnLyr = FirstSelectedNode; 02011 02012 // When there are no more objects to copy, FirstNodeToCopyOnLyr will be NULL 02013 while (FirstNodeToCopyOnLyr != NULL) 02014 { 02015 02016 // Tail is the position to insert the new Duplicate nodes 02017 Tail = FirstNodeToCopyOnLyr->FindParent()->FindLastChild(TRUE); // Excludes InsertionNode 02018 02019 // Create a range of selected nodes on this layer 02020 // LayerRange = Range(FirstNodeToCopyOnLyr, NULL, RangeControl(TRUE,FALSE,FALSE,FALSE, 02021 // FALSE,FALSE,FALSE,TRUE) ); 02022 Range temp(FirstNodeToCopyOnLyr, NULL, RangeControl(TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,TRUE)); 02023 LayerRange = temp; 02024 02025 //When we enter the loop, Current should signify the last copied node on this layer. 02026 //Set to null to signify we need to copy the first node on this layer. 02027 Current=NULL; 02028 LastNodeToCopyOnLyr = LayerRange.FindLast(); 02029 02030 Node * pFirstNewNodeInLayer = NULL; 02031 02032 // Loop for each node on this layer 02033 do 02034 { 02035 //Get the next node in the layer to copy. If Current is NULL, this 02036 //is the first node in the layer to be copied. 02037 02038 if(Current==NULL) 02039 Current=FirstNodeToCopyOnLyr; 02040 else 02041 Current = LayerRange.FindNext(Current); 02042 02043 // Make a copy of the current node 02044 Node* TheCopy; 02045 BOOL CopiedOK; 02046 02047 CALL_WITH_FAIL(Current->NodeCopy(&TheCopy), this, CopiedOK); 02048 if (!CopiedOK) 02049 { 02050 goto EndOperation; 02051 } 02052 02053 // store this to tidy up later in meshing layers 02054 if (!pFirstNewNodeInLayer) 02055 pFirstNewNodeInLayer = TheCopy; 02056 02057 // make sure that it is bounded 02058 ERROR2IF(!TheCopy->IsBounded(), FALSE, "Object being pasted is not a NodeRenderableBounded"); 02059 NodeRenderableBounded* BoundCopy = (NodeRenderableBounded*)TheCopy; 02060 02061 // Insert the copied node at the tail position 02062 if (!DoInsertNewNode(BoundCopy, Tail, NEXT, 02063 FALSE, // Don't Invalidate region 02064 FALSE)) // Don't Clear the selections 02065 { 02066 // Failed, so tidy up before returning 02067 TheCopy->CascadeDelete(); 02068 delete TheCopy; 02069 goto EndOperation; 02070 } 02071 02072 // DMc - to fix bug with r-hand clicks on drags 02073 BoundCopy->SetSelected(TRUE); 02074 BoundCopy->SetRender(TRUE, TRUE); 02075 02076 //If we need to Transform the copy, do so 02077 if (Transformer.GetMatrix().Type!=TRANS_IDENTITY) 02078 { 02079 BoundCopy->Transform(Transformer); 02080 } 02081 02082 ERROR2IF(!Current->IsAnObject(), FALSE, "Current should be an ink node"); 02083 02084 // Call PostDuplicate on the copied node and all it's children 02085 BOOL ok = TRUE; 02086 Node* pCurrent = BoundCopy->FindFirstDepthFirst(); 02087 while (pCurrent!=NULL && ok) 02088 { 02089 ok = pCurrent->PostDuplicate(this); 02090 pCurrent = pCurrent->FindNextDepthFirst(BoundCopy); 02091 } 02092 if (!ok) goto EndOperation; 02093 02094 02095 //Now we need to select the copy and deselect the original. 02096 02097 //This code isn't too elegant, because it's four days until deadline 02098 //and I want to get this "bug" fixed. So... 02099 02100 //Is there a transform drag going on? 02101 Operation* pDragOp=GetCurrentDragOp(); 02102 TransOperation* pTransDragOp=(TransOperation*) pDragOp; 02103 02104 if (!pTransDragOp) 02105 { 02106 //No. So we can deselect the original now. 02107 //((NodeRenderableInk*)Current)->DeSelect(TRUE); 02108 } 02109 else 02110 { 02111 //Yes, there's a transform drag going on. 02112 //Transform drags start acting strangely if you 02113 //change the selection halfway through. 02114 //So first we need to deselect the copy, to ensure 02115 //we haven't changed the selection. 02116 //((NodeRenderableInk*)BoundCopy)->DeSelect(TRUE); 02117 02118 //And tell the drag to select the copy after the 02119 //drag has finished. 02120 pTransDragOp->SelectNodeAfterDrag(BoundCopy); 02121 } 02122 02123 // We also need to invalidate the region of the node now that it has been transformed 02124 BoundCopy->ReleaseCached(TRUE, FALSE, FALSE, FALSE); // Release Parents because of change 02125 if (!DoInvalidateNodeRegion(BoundCopy, TRUE, FALSE, FALSE, FALSE)) // Don't recache everything 02126 { 02127 // Tidyup 02128 TheCopy->CascadeDelete(); 02129 delete TheCopy; 02130 goto EndOperation; 02131 } 02132 02133 // We also need to invalidate the region of the node now that it has been transformed 02134 BoundCopy->ReleaseCached(TRUE, FALSE, FALSE, FALSE); // Release Parents because of change 02135 DoInvalidateNodeRegion((NodeRenderableBounded*) Current, TRUE, FALSE, FALSE, FALSE); // Don't recache everything 02136 02137 02138 //New insertion position is after the last copied node 02139 Tail = BoundCopy; 02140 02141 } while (Current != LastNodeToCopyOnLyr); 02142 02143 02144 // is this a rollover layer? 02145 pLayer = pFirstNewNodeInLayer->FindParent(); 02146 if (pLayer->IsLayer()) 02147 for (i = 0; i < 5; i++) 02148 { 02149 if (pFirstNodeOfImportedLayer[i] == NULL 02150 && StateLayerNames[i].CompareTo(((Layer *)pLayer)->GetLayerID() ) == 0) 02151 pFirstNodeOfImportedLayer[i] = pFirstNewNodeInLayer; 02152 } 02153 02154 02155 //And get the first node on the next layer to copy 02156 FirstNodeToCopyOnLyr = Sel.FindNext(Tail); 02157 } 02158 02159 // Mesh the buttons duplicated onto the layers 02160 // if we have any of these special layers 02161 if (pFirstNodeOfImportedLayer[0] || pFirstNodeOfImportedLayer[1] || pFirstNodeOfImportedLayer[2] || pFirstNodeOfImportedLayer[3]) 02162 SliceHelper::MeshImportedLayersWithExistingButtonBars(pFirstNodeOfImportedLayer, this, FALSE); 02163 02164 // DMc - deselect the original selection 02165 if (pSelList) 02166 { 02167 pItem = (NodeListItem *)pSelList->GetHead(); 02168 02169 while (pItem) 02170 { 02171 if (pItem->pNode) 02172 { 02173 pItem->pNode->SetSelected(FALSE); 02174 } 02175 02176 pItem = (NodeListItem *)pSelList->GetNext(pItem); 02177 } 02178 02179 pSelList->DeleteAll(); 02180 delete pSelList; 02181 } 02182 02183 //Just incase we helped the user with their selection - restore it back again 02184 TRACEUSER( "Matt", _T("Changing Selection in CarbonCopyOp::DoProcessing()\n")); 02185 SliceHelper::RestoreSelection(); 02186 02187 ObjChange.Define(OBJCHANGE_FINISHED,cFlags,NULL,this); 02188 UpdateChangedNodes(&ObjChange); 02189 02190 End(); 02191 02192 return TRUE; 02193 02194 EndOperation: 02195 02196 if (pSelList) 02197 { 02198 pSelList->DeleteAll(); 02199 delete pSelList; 02200 } 02201 02202 //Just incase we helped the user with their selection - restore it back again 02203 TRACEUSER( "Matt", _T("Restoring Selection in CarbonCopyOp::DoProcessing()\n")); 02204 SliceHelper::RestoreSelection(); 02205 02206 End(); 02207 return FALSE; 02208 }
|
|
For finding the operations state.
Reimplemented in OpDuplicate, OpClone, OpCopyAndTransform, OpBarCreation, OpDuplicateBar, OpShortenBar, and OpDelBar. Definition at line 1797 of file cutop.cpp. 01798 { 01799 OpState OpSt; 01800 01801 return(OpSt); 01802 }
|