// $Id: opdupbar.cpp 1282 2006-06-09 09:46:49Z alex $ /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE ================================XARAHEADERSTART=========================== Xara LX, a vector drawing and manipulation program. Copyright (C) 1993-2006 Xara Group Ltd. Copyright on certain contributions may be held in joint with their respective authors. See AUTHORS file for details. LICENSE TO USE AND MODIFY SOFTWARE ---------------------------------- This file is part of Xara LX. Xara LX is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. Xara LX and its component source files are 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 General Public License for more details. You should have received a copy of the GNU General Public License along with Xara LX (see the file GPL in the root directory of the distribution); if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ADDITIONAL RIGHTS ----------------- Conditional upon your continuing compliance with the GNU General Public License described above, Xara Group Ltd grants to you certain additional rights. The additional rights are to use, modify, and distribute the software together with the wxWidgets library, the wxXtra library, and the "CDraw" library and any other such library that any version of Xara LX relased by Xara Group Ltd requires in order to compile and execute, including the static linking of that library to XaraLX. In the case of the "CDraw" library, you may satisfy obligation under the GNU General Public License to provide source code by providing a binary copy of the library concerned and a copy of the license accompanying it. Nothing in this section restricts any of the rights you have under the GNU General Public License. SCOPE OF LICENSE ---------------- This license applies to this program (XaraLX) and its constituent source files only, and does not necessarily apply to other Xara products which may in part share the same code base, and are subject to their own licensing terms. This license does not apply to files in the wxXtra directory, which are built into a separate library, and are subject to the wxWindows license contained within that directory in the file "WXXTRA-LICENSE". This license does not apply to the binary libraries (if any) within the "libs" directory, which are subject to a separate license contained within that directory in the file "LIBS-LICENSE". ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS ---------------------------------------------- Subject to the terms of the GNU Public License (see above), you are free to do whatever you like with your modifications. However, you may (at your option) wish contribute them to Xara's source tree. You can find details of how to do this at: http://www.xaraxtreme.org/developers/ Prior to contributing your modifications, you will need to complete our contributor agreement. This can be found at: http://www.xaraxtreme.org/developers/contribute/ Please note that Xara will not accept modifications which modify any of the text between the start and end of this header (marked XARAHEADERSTART and XARAHEADEREND). MARKS ----- Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara designs are registered or unregistered trademarks, design-marks, and/or service marks of Xara Group Ltd. All rights in these marks are reserved. Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. http://www.xara.com/ =================================XARAHEADEREND============================ */ // Code for the Duplication of bars // and the synchronisation of text across a bar #include "camtypes.h" //#include "sliceres.h" //#include "simon.h" #include "transop.h" //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "slice.h" //#include "cxfrech.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "userattr.h" #include "tmpltatr.h" #include "progress.h" //#include "fillval.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "ngcore.h" #include "ngitem.h" #include "ngprop.h" #include "ngsentry.h" #include "slicehelper.h" #include "opdupbar.h" #include "slicetool.h" #include "nodetxtl.h" // for textline def #include "objchge.h" // for child change stuff #include "sprdmsg.h" // SpreadMsg #ifdef _DEBUG #undef THIS_FILE static char BASED_CODE THIS_FILE[] = __FILE__; #endif DECLARE_SOURCE("$Revision: 1282 $"); CC_IMPLEMENT_DYNCREATE(OpDuplicateBar, CarbonCopyOp) CC_IMPLEMENT_DYNCREATE(OpShortenBar, CarbonCopyOp) CC_IMPLEMENT_DYNCREATE(OpDelBar, CarbonCopyOp) CC_IMPLEMENT_DYNCREATE(OpShowState, UndoableOperation) #define new CAM_DEBUG_NEW /******************************************************************************************** > OpClone::OpDuplicateBar() Author: Simon_Knight (Xara Group Ltd) Created: 30/9/99 Purpose: OpBarCreation constructor Errors: - SeeAlso: CarbonCopyOp ********************************************************************************************/ OpDuplicateBar::OpDuplicateBar(): CarbonCopyOp() { m_ExistingButtonsInBar = 0; } /******************************************************************************************** > BOOL OpDuplicateBar::Init() Author: Simon_Knight (Xara Group Ltd) Created: 30/9/99 Returns: TRUE if the operation could be successfully initialised FALSE if no more memory could be allocated Purpose: OpDuplicateBar initialiser method Errors: ERROR will be called if there was insufficient memory to allocate the operation. SeeAlso: - ********************************************************************************************/ BOOL OpDuplicateBar::Init() { return (RegisterOpDescriptor(0, _R(IDS_BARDUPLICATIONOP), CC_RUNTIME_CLASS(OpDuplicateBar), OPTOKEN_BARDUPLICATIONOP, OpDuplicateBar::GetState, 0, // help ID 0, //_R(IDBBL_BARDUPLICATIONOP),// bubble help 0, // resource ID 0, //_R(IDC_BC_CREATE), // control ID SYSTEMBAR_ILLEGAL, // Bar ID TRUE, // Receive messages FALSE, FALSE, 0, (GREY_WHEN_NO_CURRENT_DOC | DONT_GREY_WHEN_SELECT_INSIDE) )); } /******************************************************************************************** > OpState OpDuplicateBar::GetState(String_256*, OpDescriptor*) Author: Simon_Knight (Xara Group Ltd) based on Jason Created: 30/9/99 Returns: The state of the OpDuplicateBar Purpose: For finding the operations state. ********************************************************************************************/ OpState OpDuplicateBar::GetState(String_256* UIDescription, OpDescriptor *Bob) { OpState OpSt; // if we don't allow it OpSt.Greyed = TRUE; Spread* pSpread = Document::GetSelectedSpread(); if (pSpread && !pSpread->FindActiveLayer()->IsFrame()) OpSt.Greyed = FALSE; return(OpSt); } /******************************************************************************************** > void OpDuplicateBar::DoWithParam(OpDescriptor* token, OpParam* pOpParam) Author: Simon_Knight (Xara Group Ltd) Created: 30/9/99 Inputs: OpParam - describes the bar to be dupicated - and the name to call the copy Outputs: - Returns: - Purpose: Clones a bar, but gives the bar a new name and each button in the bar and new name. This is so each bar can work independantly or together. If they are just copied they would have the same bar IDs and the same button names which is not likely to be what the user would expect. Errors: - SeeAlso: OpBarCreation::DoWithParam, CarbonCopyOp::DoProcessing ********************************************************************************************/ void OpDuplicateBar::DoWithParam(OpDescriptor* token, OpParam* pOpParam) { if (DoStartSelOp(FALSE,TRUE)) // Try to record the selection state { // unpack the names of the bar to be copied and the new bars name from the params DuplicateBar(((OpParamBarDuplication *)pOpParam)->m_OldBarName, ((OpParamBarDuplication *)pOpParam)->m_NewBarName, ((OpParamBarDuplication *)pOpParam)->m_ButtonsToAdd, ((OpParamBarDuplication *)pOpParam)->m_Spacing, ((OpParamBarDuplication *)pOpParam)->m_IsHoriz); // end the op End(); DialogBarOp::SetSystemStateChanged(); DialogBarOp::UpdateStateOfAllBars(); } else { FailAndExecute(); End(); } } /******************************************************************************************** > void OpDuplicateBar::DuplicateBar(String_256 &OriginalBarName, String_256 &NewBarName) Author: Simon_Knight (Xara Group Ltd) Created: 30/9/99 Inputs: OriginalBarName - the bar to be dupicated NewBarName - the name to call the copy ButtonsToAdd - 0 means it copies the bar over with an exact clone any other number implies add this many buttons to the bar must be less or equal to the number of buttons in the bar to start with, since it duplicates the existing ones of that number. Spacing - In conjunction with the buttons to add only spaces out the new buttons. Outputs: - Returns: - Purpose: Clones a bar, but gives the bar a new name and each button in the bar and new name. This is so each bar can work independantly or together. If they are just copied they would have the same bar IDs and the same button names which is not likely to be what the user would expect. ********************************************************************************************/ void OpDuplicateBar::DuplicateBar(String_256 &OriginalBarName, String_256 &NewBarName, INT32 ButtonsToAdd, INT32 Spacing, BOOL IsHoriz) { // scan each of the special state layers for the original bar members // pionters to these template attributes are stored in the BarList // I don't want bar duplication at the moment thanks. // I just want to ASSERT (ButtonsToAdd > 0); String_256 templayer; Layer * pLayer = NULL; List BarList; templayer.Load(_R(IDS_ROLLOVER_DEFAULT)); pLayer = SliceHelper::FindLayerCalled(templayer); Layer * pDefLayer = pLayer; if (pLayer) SliceHelper::BuildListOfNodesInBar(&BarList, pLayer, OriginalBarName); templayer.Load(_R(IDS_ROLLOVER_MOUSE)); pLayer = SliceHelper::FindLayerCalled(templayer); if (pLayer) SliceHelper::BuildListOfNodesInBar(&BarList, pLayer, OriginalBarName); templayer.Load(_R(IDS_ROLLOVER_CLICKED)); pLayer = SliceHelper::FindLayerCalled(templayer); if (pLayer) SliceHelper::BuildListOfNodesInBar(&BarList, pLayer, OriginalBarName); templayer.Load(_R(IDS_ROLLOVER_SELECTED)); pLayer = SliceHelper::FindLayerCalled(templayer); if (pLayer) SliceHelper::BuildListOfNodesInBar(&BarList, pLayer, OriginalBarName); // calculate the dimensions of the bar // this is so we can work out where to place the bar copy // which is incidently placed either just to the right // or just bellow depending upon orientation NodeListItem *pNodeListItem = (NodeListItem *)BarList.GetHead(); NodeListItem *pDelThisToo = NULL; // find the number of buttons in the bar and what they are called m_ExistingButtonsInBar = 0; SliceHelper::CountButtonsInBarScan(pDefLayer, (TemplateAttribute **) m_ppFoundButton, &m_ExistingButtonsInBar, OriginalBarName); templayer = ((TemplateAttribute *) m_ppFoundButton[0])->GetParam(); DocRect BarDim; DocRect FirstButtonDim; BarDim.MakeEmpty(); FirstButtonDim.MakeEmpty(); while(pNodeListItem) { Node* pNode = pNodeListItem->pNode->FindParent(); if (pNode) { BarDim = BarDim.Union(((NodeRenderableBounded *) pNode)->GetBoundingRect()); if (templayer.CompareTo(((TemplateAttribute *)pNodeListItem->pNode)->GetParam()) == 0) FirstButtonDim = FirstButtonDim.Union(((NodeRenderableBounded *) pNode)->GetBoundingRect()); } pNodeListItem = (NodeListItem *)BarList.GetNext(pNodeListItem); } // calc the transform matrix to be applied to each element when we copy it Trans2DMatrix Transformer; // test differences between the first button and the whole bar in with compared to height if (BarDim.hix - BarDim.lox + FirstButtonDim.hix - FirstButtonDim.lox > BarDim.hiy - BarDim.loy + FirstButtonDim.hiy - FirstButtonDim.loy) Transformer.SetTransform(0, BarDim.loy - BarDim.hiy); else Transformer.SetTransform(BarDim.hix - BarDim.lox, 0); // find new names for the new buttons String_256 TempButtonName; INT32 i = 0, listbuttonno = 0; for (i = 0; i < MAX_BUTTONS_IN_A_BAR; i++) { m_ButtonNumberList[i] = i; if (i < max(m_ExistingButtonsInBar, ButtonsToAdd)) { // get the next free button name and put it into listbuttonno SliceHelper::GetNextFreeButtonName(listbuttonno); m_ButtonNumberList[i] = listbuttonno; } } // copy each item referenced by a template attrib marked with this bar ID pNodeListItem = (NodeListItem *)BarList.GetHead(); String_256 Name = ""; // Prepare an ObjChangeParam so we can mark which nodes will allow this op to happen to them ObjChangeFlags cFlags; //cFlags.MultiReplaceNode = TRUE; ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,this); while(pNodeListItem) { pDelThisToo = pNodeListItem; Node *pNode = pNodeListItem->pNode; if (pNode && pNode->AllowOp(&ObjChange)) { if (ButtonsToAdd == 0) // add the whole lot as a new bar { Node * NewNode = CopyBarMember(pNode, OriginalBarName, NewBarName, &Transformer); if (NewNode) NewNode->AllowOp(&ObjChange); } else { // add a few buttons on the end Name = ((TemplateAttribute *)pNode)->GetParam(); // note it just copies the first button several times to make the new buttons if (Name.CompareTo(((TemplateAttribute *) m_ppFoundButton[0])->GetParam()) == 0) for (i = 0; i < ButtonsToAdd; i++) { // alter tranformer for each button if (IsHoriz) Transformer.SetTransform(BarDim.hix - BarDim.lox + (i+1)*(Spacing) + i*(FirstButtonDim.hix - FirstButtonDim.lox), 0); else Transformer.SetTransform(0, BarDim.loy - BarDim.hiy - ((i+1)*(Spacing) + i*( FirstButtonDim.hiy - FirstButtonDim.loy))); Node * NewNode = CopyBarMember(pNode, OriginalBarName, OriginalBarName, &Transformer, &i); if (NewNode) NewNode->AllowOp(&ObjChange); } } } pNodeListItem = (NodeListItem *)BarList.GetNext(pNodeListItem); // tidy up the list as we go along BarList.RemoveItem((NodeListItem *)pDelThisToo); delete pDelThisToo; } // touch the bar in question NameGallery * pNameGallery = NameGallery::Instance(); if (pNameGallery) { pNameGallery->m_TouchedBar = SliceHelper::GetBarNumberFromBarName(NewBarName); } ObjChange.Define(OBJCHANGE_FINISHED,cFlags,NULL,this); UpdateChangedNodes(&ObjChange); BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::NONCOLOURATTCHANGED)); } /******************************************************************************************** > void OpDuplicateBar::CopyBarMember(Node * pNode, const String_256 &OriginalBarName, const String_256 &NewBarName, Trans2DMatrix * pTransformer) Author: Simon_Knight (Xara Group Ltd) Created: 30/9/99 Inputs: pNode - Ptr to the Template attribute that marks this nodes parent as being a member of the bar OriginalBarName - The name of the bar that is being copied NewBarName - The name of the copy of the bar pTransformer - The transform matrix that is applied to all copies pKnownButtonIndex- Ptr to an INT32 that if defined saves a bit of calculation since it is the index into the m_ButtonNumberList that stores the button number of the button being made. If not defined it gets this number from a scan based on the button name of this node being copied. Outputs: - Returns: - Purpose: Copies a single member of a bar. Any template attributes that relate to the old original bar are replaced with references to the new bar. Also will generate new stretching attributes for a new button based on those of the source. Errors: - ********************************************************************************************/ Node* OpDuplicateBar::CopyBarMember(Node * pNode, const String_256 &OriginalBarName, const String_256 &NewBarName, Trans2DMatrix * pTransformer, const INT32 * pKnownButtonIndex) { // Make a copy of the current node Node* pTheCopy; // Assumes that the parent of the wix attribute is the main node that needs // copying. This is a fair assumption being as that is where the bar creation // op puts it. Node* pCurrent = pNode->FindParent(); BOOL CopiedOK = TRUE; String_256 Target = ""; // the button name of the selection String_256 Extender = ""; // the thing in this button that extends it DocRect rTarget; DocRect rExtender; BYTE ExtenderFlags = 0; INT32 RequiredLevel = 0; RequiredLevel = SliceHelper::FindTargetAndExtender(pCurrent, Target, Extender, RequiredLevel, &ExtenderFlags, &rTarget, &rExtender); // no longer unselect the old bar as this fn is only used for adding buttons from button 1 really now //pCurrent->SetSelected(FALSE); // where to insert this new node Node * pInsertPt = pCurrent->FindParent(); while (!pInsertPt->IsLayer()) pInsertPt = pInsertPt->FindParent(); // create a copy of the node CALL_WITH_FAIL(pCurrent->NodeCopy(&pTheCopy), this, CopiedOK); if (!CopiedOK) return NULL; // couldn't copy -> fail // insert the copy into the tree DoInsertNewNode((NodeRenderableBounded *)pTheCopy, pInsertPt, LASTCHILD, TRUE, // Do Invalidate region FALSE); // Don't Clear the selections // don't have any of these new nodes selected pTheCopy->SetSelected(FALSE); // clean the attributes of the copy. // remove all references to the old bar and // replace with references to the new bar. // Also update the name given to the button set. Node* pAttrib = pTheCopy->FindFirstChild(); Node* pNext = NULL; BOOL goon = TRUE; while(pAttrib && goon) { pNext = pAttrib->FindNext(); if (pAttrib->IsAnAttribute()) { if (IS_A(pAttrib, TemplateAttribute)) { String_256 ButtonName = ((TemplateAttribute *)pAttrib)->GetParam(); String_256 AttrName = ((TemplateAttribute *)pAttrib)->GetQuestion(); // found the actual button marker // since this has the marker of the bar name BOOL IsBarButton = (OriginalBarName.CompareTo(AttrName) == 0); BOOL IsExtender = (ButtonName.CompareTo(Extender) == 0); if (IsBarButton || IsExtender) { String_256 NewButtonName = ""; if (pKnownButtonIndex) NewButtonName.MakeMsg(_R(IDS_BUTTONNAME), m_ButtonNumberList[*pKnownButtonIndex]); else NewButtonName = GetNewButtonName(ButtonName); String_256 ExtenderPostfix; ExtenderPostfix.Load(_R(IDS_EXTENDER_POSTFIX)); String_256 NewExtenderName = NewButtonName; NewExtenderName += ExtenderPostfix; TemplateAttribute* pNewAttr = new TemplateAttribute(String_256(TEXT("ObjectName")), IsBarButton ? NewBarName : "", IsBarButton ? NewButtonName : NewExtenderName); if (pNewAttr) // create the node ok { pNewAttr->AttachNode(pTheCopy, FIRSTCHILD); if (IsBarButton) { if (!Target.IsEmpty() && RequiredLevel > 1) // create the properties for the button/Target that this extender extends SliceHelper::CreatePropertiesForSet(NewButtonName, NewBarName, TRUE, TRUE, FALSE, ExtenderFlags, NewExtenderName, FALSE, &rTarget, &rExtender, this); else // create none stretching attribs for the button SliceHelper::CreatePropertiesForSet(NewButtonName, NewBarName, TRUE, FALSE, FALSE, 0, TEXT(""), FALSE, NULL, NULL, this); // test to see if this button is in fact a trigger for something bigger // if the source is ButtonName then add NewButtonName to that list SliceHelper::MakeTriggerLikeExample(NewButtonName, ButtonName); } else // create the properties for the extender { SliceHelper::CreatePropertiesForSet(NewExtenderName, TEXT(""), FALSE, FALSE, FALSE, 0, TEXT(""), FALSE, NULL, NULL, this); // test to see if this extender is in fact a trigger for something bigger // but not just the button we already know it to trigger // if the source is ButtonName then add NewButtonName to that list SliceHelper::MakeTriggerLikeExample(NewExtenderName, Extender, &Target); } DoHideNode(pAttrib, TRUE); } } } } pAttrib = pNext; } // transform the node into its new location in the bar ((NodeRenderableBounded *)pTheCopy)->Transform(*pTransformer); return pTheCopy; } /******************************************************************************************** > String_256 OpDuplicateBar::GetNewButtonName(String_256 &Name) Author: Simon_Knight (Xara Group Ltd) Created: 30/9/99 Inputs: Name - The name of the button in the original bar Outputs: - Returns: The corresponding button in the new bar Purpose: Generates names for the new bar. ********************************************************************************************/ String_256 OpDuplicateBar::GetNewButtonName(String_256 &Name) { String_256 TempButtonName; INT32 butno = -1; INT32 i = 0; for (i = 0; butno < 0 && i < m_ExistingButtonsInBar; i++) { if (Name.CompareTo(((TemplateAttribute *) m_ppFoundButton[i])->GetParam()) == 0) butno = i; } // return the button if we have found the extender if (butno < 0) { String_256 ExtenderPostfix; ExtenderPostfix.Load(_R(IDS_EXTENDER_POSTFIX)); for (i = 0; butno < 0 && i < m_ExistingButtonsInBar; i++) { TempButtonName = ((TemplateAttribute *) m_ppFoundButton[i])->GetParam(); TempButtonName += ExtenderPostfix; if (Name.CompareTo(TempButtonName) == 0) butno = i; } } if (butno < 0) butno = m_ExistingButtonsInBar; TempButtonName.MakeMsg(_R(IDS_BUTTONNAME), m_ButtonNumberList[butno]); return TempButtonName; } /******************************************************************************************** > OpShortenBar::OpShortenBar() Author: Simon_Knight (Xara Group Ltd) Created: 15/10/99 Purpose: OpShortenBar constructor Errors: - SeeAlso: CarbonCopyOp ********************************************************************************************/ OpShortenBar::OpShortenBar(): CarbonCopyOp() { } /******************************************************************************************** > BOOL OpShortenBar::Init() Author: Simon_Knight (Xara Group Ltd) Created: 15/10/99 Returns: TRUE if the operation could be successfully initialised FALSE if no more memory could be allocated Purpose: OpShortenBar initialiser method Errors: ERROR will be called if there was insufficient memory to allocate the operation. SeeAlso: - ********************************************************************************************/ BOOL OpShortenBar::Init() { return (RegisterOpDescriptor(0, _R(IDS_BARDUPLICATIONOP), CC_RUNTIME_CLASS(OpShortenBar), OPTOKEN_SHORTENBAROP, OpShortenBar::GetState, 0, // help ID 0, //_R(IDBBL_BARDUPLICATIONOP),// bubble help 0, // resource ID 0, //_R(IDC_BC_CREATE), // control ID SYSTEMBAR_ILLEGAL, // Bar ID TRUE, // Receive messages FALSE, FALSE, 0, (GREY_WHEN_NO_CURRENT_DOC | DONT_GREY_WHEN_SELECT_INSIDE) )); } /******************************************************************************************** > OpState OpShortenBar::GetState(String_256*, OpDescriptor*) Author: Simon_Knight (Xara Group Ltd) based on Jason Created: 15/10/99 Returns: The state of the OpShortenBar Purpose: For finding the operations state. ********************************************************************************************/ OpState OpShortenBar::GetState(String_256* UIDescription, OpDescriptor *Bob) { OpState OpSt; // if we don't allow it OpSt.Greyed = TRUE; Spread* pSpread = Document::GetSelectedSpread(); if (pSpread && !pSpread->FindActiveLayer()->IsFrame()) OpSt.Greyed = FALSE; return(OpSt); } /******************************************************************************************** > void OpShortenBar::DoWithParam(OpDescriptor* token, OpParam* pOpParam) Author: Simon_Knight (Xara Group Ltd) Created: 15/10/99 Inputs: OpParam - describes the bar to be dupicated - and the name to call the copy Outputs: - Returns: - Purpose: Removes buttons from the bar so as to leave fewer. Errors: - SeeAlso: TrimBarDownToThisManyButtons ********************************************************************************************/ void OpShortenBar::DoWithParam(OpDescriptor* token, OpParam* pOpParam) { if (DoStartSelOp(FALSE,TRUE)) // Try to record the selection state { // unpack the names of the bar to be copied and the new bars name from the params TrimBarDownToThisManyButtons(((OpParamShortenBar *)pOpParam)->m_BarName, ((OpParamShortenBar *)pOpParam)->m_NoOfButtons); // end the op End(); DialogBarOp::SetSystemStateChanged(); DialogBarOp::UpdateStateOfAllBars(); } else { FailAndExecute(); End(); } } /******************************************************************************************** > BOOL OpShortenBar::TrimBarDownToThisManyButtons(const StringBase &BarName, INT32 NewNoOfButtons) Author: Simon_Knight (Xara Group Ltd) Created: 15/10/99 Inputs: BarName - Name of the bar in for a trim NewNoOfButtons - No of buttons that we want in this bar Outputs: - Returns: TRUE if it succeeds. FALSE if you try to increase the number of buttons by using this function or it fails in some way. Purpose: Removes buttons from the bar so as to leave fewer. Errors: - ********************************************************************************************/ BOOL OpShortenBar::TrimBarDownToThisManyButtons(const StringBase &BarName, INT32 NewNoOfButtons) { // find me the buttons in this bar String_256 templayer; templayer.Load(_R(IDS_ROLLOVER_DEFAULT)); // count the buttons on the default layer // every button bar requires a member to be on the default layer // so there is no point in counting any other layer Layer * pDef = SliceHelper::FindLayerCalled(templayer); if (!pDef) return FALSE; // no default layer found INT32 NumberOfButtons = 0; // store of example attribs of each button in this bar // but we don't need this data so we can throw it away afterwards // MAX_BUTTONS_IN_A_BAR = 20 TemplateAttribute ** ppFoundButton[MAX_BUTTONS_IN_A_BAR]; DocRect ButtonRect[MAX_BUTTONS_IN_A_BAR]; BYTE Order[MAX_BUTTONS_IN_A_BAR]; // scan down from the default layer counting the different button names // that all have the same bar name SliceHelper::CountButtonsInBarScan(pDef, (TemplateAttribute **) ppFoundButton, &NumberOfButtons, BarName); if (NumberOfButtons == 0 || NumberOfButtons <= NewNoOfButtons ) return FALSE; // build up a list of the buttons in the bar // so that we can shift them along // it must be better to use a list than keep on // scanning each time Layer * pLayer = NULL; List BarList; templayer.Load(_R(IDS_ROLLOVER_DEFAULT)); pLayer = SliceHelper::FindLayerCalled(templayer); if (pLayer) SliceHelper::BuildListOfNodesInBar(&BarList, pLayer, BarName); templayer.Load(_R(IDS_ROLLOVER_MOUSE)); pLayer = SliceHelper::FindLayerCalled(templayer); if (pLayer) SliceHelper::BuildListOfNodesInBar(&BarList, pLayer, BarName); templayer.Load(_R(IDS_ROLLOVER_CLICKED)); pLayer = SliceHelper::FindLayerCalled(templayer); if (pLayer) SliceHelper::BuildListOfNodesInBar(&BarList, pLayer, BarName); templayer.Load(_R(IDS_ROLLOVER_SELECTED)); pLayer = SliceHelper::FindLayerCalled(templayer); if (pLayer) SliceHelper::BuildListOfNodesInBar(&BarList, pLayer, BarName); // init stuff for the translation String_256 ButtonName = ""; NodeListItem *pNodeListItem = NULL; NodeListItem *pDelThisToo = NULL; Node *pNode = NULL; Node *pParent = NULL; INT32 i = 0; // how big is each rect of the gallery? for (i = 0; i < NumberOfButtons; i++) { Order[i] = i; // init order ButtonName = ((TemplateAttribute *) ppFoundButton[i])->GetParam(); pNodeListItem = (NodeListItem *)BarList.GetHead(); ButtonRect[i].MakeEmpty(); while(pNodeListItem) { pNode = pNodeListItem->pNode; if (pNode) { pParent = pNode->FindParent(); if (pParent && ButtonName.CompareTo(((TemplateAttribute *)pNode)->GetParam()) == 0) { // transform the node into its new location in the bar ButtonRect[i] = ButtonRect[i].Union(((NodeRenderableBounded *)pParent)->GetBoundingRect()); } } // find the next item in the list pNodeListItem = (NodeListItem *)BarList.GetNext(pNodeListItem); } } // sort them by location for (i = 0; i < NumberOfButtons; i++) { for (INT32 j = i+1; j < NumberOfButtons; j++) { if (ButtonRect[Order[j]].hiy > ButtonRect[Order[i]].hiy) { BYTE t = Order[j]; Order[j] = Order[i]; Order[i] = t; } else if (ButtonRect[Order[j]].hiy == ButtonRect[Order[i]].hiy && ButtonRect[Order[j]].lox < ButtonRect[Order[i]].lox) { BYTE t = Order[j]; Order[j] = Order[i]; Order[i] = t; } } } // tidy up the list pNodeListItem = (NodeListItem *)BarList.GetHead(); pParent = NULL; // Prepare an ObjChangeParam so we can mark which nodes will allow this op to happen to them ObjChangeFlags cFlags(TRUE); // flag says deleting okay? ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,this); while(pNodeListItem) { pDelThisToo = pNodeListItem; // delete any node that is ordered after NewNoOfButtons // by finding out if the name of this item in the bar // is the same as any that occur after the required // number of buttons in the bar pParent = pNodeListItem->pNode->FindParent(); if (pParent) { ButtonName = ((TemplateAttribute *)pNodeListItem->pNode)->GetParam(); for (i = NewNoOfButtons; i < NumberOfButtons; i++) { if (ButtonName.CompareTo(((TemplateAttribute *) ppFoundButton[Order[i]])->GetParam()) == 0 && pParent->AllowOp(&ObjChange)) { // We also need to invalidate the region of the node now that it has been transformed DoInvalidateNodeRegion((NodeRenderableBounded*) pParent, TRUE, FALSE); // remove the node from the excess button pParent->SetSelected(FALSE); DoHideNode(pParent, TRUE); i = NumberOfButtons; // shortcut out } } } pNodeListItem = (NodeListItem *)BarList.GetNext(pNodeListItem); // tidy up the list as we go along BarList.RemoveItem((NodeListItem *)pDelThisToo); delete pDelThisToo; } // touch the bar in question NameGallery * pNameGallery = NameGallery::Instance(); if (pNameGallery) { pNameGallery->m_TouchedBar = SliceHelper::GetBarNumberFromBarName(BarName); } ObjChange.Define(OBJCHANGE_FINISHED,cFlags,NULL,this); UpdateChangedNodes(&ObjChange); BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::NONCOLOURATTCHANGED)); return TRUE; } // contructor OpDelBar::OpDelBar(): CarbonCopyOp() { } /******************************************************************************************** > BOOL OpDelBar::Init() Author: Simon_Knight (Xara Group Ltd) Created: 3/5/00 Returns: TRUE if the operation could be successfully initialised FALSE if no more memory could be allocated Purpose: OpDelBar initialiser method Errors: ERROR will be called if there was insufficient memory to allocate the operation. SeeAlso: - ********************************************************************************************/ BOOL OpDelBar::Init() { return (RegisterOpDescriptor(0, _R(IDS_DEL_BAR), CC_RUNTIME_CLASS(OpDelBar), OPTOKEN_DELBAROP, OpDelBar::GetState, 0, // help ID 0, // bubble help 0, // resource ID 0, // control ID SYSTEMBAR_ILLEGAL, // Bar ID TRUE, // Receive messages FALSE, FALSE, 0, (GREY_WHEN_NO_CURRENT_DOC | DONT_GREY_WHEN_SELECT_INSIDE) )); } /******************************************************************************************** > OpState OpDelBar::GetState(String_256* UIDescription, OpDescriptor *Bob) Author: Simon_Knight (Xara Group Ltd) based on Jason Created: 3/5/00 Purpose: For finding the operations state. ********************************************************************************************/ OpState OpDelBar::GetState(String_256* UIDescription, OpDescriptor *Bob) { OpState OpSt; // if we don't allow it OpSt.Greyed = TRUE; Spread* pSpread = Document::GetSelectedSpread(); if (pSpread && !pSpread->FindActiveLayer()->IsFrame()) OpSt.Greyed = FALSE; return(OpSt); } /******************************************************************************************** > void OpDelBar::DoWithParam(OpDescriptor* token, OpParam* pOpParam) Author: Simon_Knight (Xara Group Ltd) Created: 3/5/00 Inputs: OpParam - describes the bar to be deleted - and the layers to delete it from Outputs: - Returns: - Errors: - *******************************************************************************************/ void OpDelBar::DoWithParam(OpDescriptor* token, OpParam* pOpParam) { if (DoStartSelOp(FALSE,TRUE)) // Try to record the selection state { // Delete the bar DelBar(((OpParamDelBar *)pOpParam)->m_BarName, ((OpParamDelBar *)pOpParam)->m_State, this); // end the op End(); DialogBarOp::SetSystemStateChanged(); DialogBarOp::UpdateStateOfAllBars(); } else { FailAndExecute(); End(); } } BOOL OpDelBar::DelBar(const StringBase &BarName, INT32 State, UndoableOperation * pOp) { String_256 templayer; Layer * pLayer = NULL; // Prepare an ObjChangeParam so we can mark which nodes will allow this op to happen to them ObjChangeFlags cFlags; cFlags.DeleteNode = TRUE; ObjChangeParam ObjChange(OBJCHANGE_STARTING,cFlags,NULL,pOp); List BarList; templayer.Load(_R(IDS_ROLLOVER_DEFAULT)); pLayer = SliceHelper::FindLayerCalled(templayer); Layer * pDefLayer = pLayer; if ((State == 0 || State == 5 ) && pLayer) SliceHelper::BuildListOfNodesInBar(&BarList, pLayer, BarName); templayer.Load(_R(IDS_ROLLOVER_MOUSE)); pLayer = SliceHelper::FindLayerCalled(templayer); if ((State == 1 || State == 5 ) && pLayer) SliceHelper::BuildListOfNodesInBar(&BarList, pLayer, BarName); templayer.Load(_R(IDS_ROLLOVER_CLICKED)); pLayer = SliceHelper::FindLayerCalled(templayer); if ((State == 2 || State == 5 ) && pLayer) SliceHelper::BuildListOfNodesInBar(&BarList, pLayer, BarName); templayer.Load(_R(IDS_ROLLOVER_SELECTED)); pLayer = SliceHelper::FindLayerCalled(templayer); if ((State == 3 || State == 5 ) && pLayer) SliceHelper::BuildListOfNodesInBar(&BarList, pLayer, BarName); templayer.Load(_R(IDS_BACK_BAR)); pLayer = SliceHelper::FindLayerCalled(templayer); if ((State == 4 || State == 5 ) && pLayer) SliceHelper::BuildListOfNodesInBar(&BarList, pLayer, BarName); // loop through all nodes in the list to delete NodeListItem *pNodeListItem = (NodeListItem *)BarList.GetHead(); while (pNodeListItem) { NodeListItem *pNextNodeListItem = (NodeListItem *)BarList.GetNext(pNodeListItem); Node * pNode = pNodeListItem->pNode->FindParent(); if (pNode && pNode->AllowOp(&ObjChange)) { pOp->DoInvalidateNodeRegion((NodeRenderableBounded*) pNode, TRUE, FALSE); pOp->DoHideNode(pNode, TRUE); } // tidy up the list as we go along BarList.RemoveItem((NodeListItem *)pNodeListItem); delete pNodeListItem; pNodeListItem = pNextNodeListItem; } ObjChange.Define(OBJCHANGE_FINISHED,cFlags,NULL,pOp); pOp->UpdateChangedNodes(&ObjChange); BROADCAST_TO_ALL(SelChangingMsg(SelChangingMsg::NONCOLOURATTCHANGED)); return TRUE; } // contructor OpShowState::OpShowState(): UndoableOperation() { } /******************************************************************************************** > BOOL OpShowState::Init() Author: Simon_Knight (Xara Group Ltd) Created: 6/7/00 Returns: TRUE if the operation could be successfully initialised FALSE if no more memory could be allocated Purpose: OpShowState initialiser method Errors: ERROR will be called if there was insufficient memory to allocate the operation. SeeAlso: - ********************************************************************************************/ BOOL OpShowState::Init() { return (RegisterOpDescriptor(0, _R(IDS_SHOWSTATEOP), CC_RUNTIME_CLASS(OpShowState), OPTOKEN_SHOWSTATE, OpShowState::GetState, 0, // help ID 0, // bubble help 0, // resource ID 0, // control ID SYSTEMBAR_ILLEGAL, // Bar ID TRUE, // Receive messages FALSE, FALSE, 0, (GREY_WHEN_NO_CURRENT_DOC | DONT_GREY_WHEN_SELECT_INSIDE) )); } /******************************************************************************************** > OpState OpShowState::GetState(String_256* UIDescription, OpDescriptor *Bob) Author: Simon_Knight (Xara Group Ltd) based on Jason Created: 6/7/00 Purpose: For finding the operations state. ********************************************************************************************/ OpState OpShowState::GetState(String_256* UIDescription, OpDescriptor *Bob) { OpState OpSt; // if we don't allow it OpSt.Greyed = TRUE; Spread* pSpread = Document::GetSelectedSpread(); if (pSpread && !pSpread->FindActiveLayer()->IsFrame()) OpSt.Greyed = FALSE; return(OpSt); } /******************************************************************************************** > void OpShowState::DoWithParam(OpDescriptor* token, OpParam* pOpParam) Author: Simon_Knight (Xara Group Ltd) Created: 6/7/00 Inputs: OpParam - Param1 has the layer/state id in it Outputs: - Returns: - Errors: - *******************************************************************************************/ void OpShowState::DoWithParam(OpDescriptor* token, OpParam* pOpParam) { // Delete the bar ShowState(pOpParam->Param1, this); // end the op End(); DialogBarOp::SetSystemStateChanged(); DialogBarOp::UpdateStateOfAllBars(); } /******************************************************************************************** > void OpShowState::ShowState(INT32 ShowLayer, UndoableOperation * pOp) Author: Simon_Knight (Xara Group Ltd) Created: 6/7/00 Inputs: ShowLayer - number of the specail layers to display 0 = mouseoff, 1 = mouseover, 2= clicked, 3 = selected, 4 = all the above pOp - Unodable Op to use, can be NULL in which case not undoable. Outputs: - Returns: - *******************************************************************************************/ void OpShowState::ShowState(INT32 ShowLayer, UndoableOperation * pOp) { Spread* pSelSpread = Document::GetSelectedSpread(); if (pSelSpread == NULL) return; String_32 StateName[4]; StateName[DEFAULT].Load(_R(IDS_ROLLOVER_DEFAULT)); // = "Default"; StateName[MOUSE].Load(_R(IDS_ROLLOVER_MOUSE)); // = "Mouse"; StateName[CLICKED].Load(_R(IDS_ROLLOVER_CLICKED)); // = "Clicked"; StateName[SELECTED].Load(_R(IDS_ROLLOVER_SELECTED)); // = "Selected"; Layer * pLayer = pSelSpread->FindFirstLayer(); Layer * pLayerTopLayer = NULL; BOOL ActiveLayerIsAState = FALSE; BOOL SetAnActiveLayer = FALSE; DocRect InvalidRect; InvalidRect.MakeEmpty(); while (pLayer) { BOOL IsStateLayer = FALSE; INT32 i = 0; for (i = 0; i < 4 ; i++) { if (pLayer->GetLayerID().CompareTo(StateName[i]) == 0) { IsStateLayer = TRUE; if (ShowLayer == 4 /* show all layers at once */ || ShowLayer == i) { if (!pLayer->IsVisible()) { if (pOp) SliceHelper::ShowLayer(TRUE, pLayer, pSelSpread, pOp); else pLayer->SetVisible(TRUE); InvalidRect = InvalidRect.Union(pLayer->GetBoundingRect()); } } else { if (pLayer->IsVisible()) { if (pOp) SliceHelper::ShowLayer(FALSE, pLayer, pSelSpread, pOp); else pLayer->SetVisible(FALSE); InvalidRect = InvalidRect.Union(pLayer->GetBoundingRect()); // If layer has just about to become invisible, // remove the selections on the layer //NodeRenderableInk::DeselectAllOnLayer(pLayer); } } if (pLayer->IsActive()) ActiveLayerIsAState = TRUE; } } if (pLayer->IsVisible() && !IsStateLayer) pLayerTopLayer = pLayer; pLayer = pLayer->FindNextLayer(); } }