slice.cpp

Go to the documentation of this file.
00001 // $Id: slice.cpp 1282 2006-06-09 09:46:49Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 // code to perform image slicing when selected from the menu
00099 
00100 #include "camtypes.h"
00101 
00102 //#include "barsdlgs.h"     //For _R(IDD_BARCONTROLSTORE)
00103 //#include "resimmap.h"     //For _R(IDS_HTMLIMPORT_FILEDOWNLOAD)
00104 #include "slice.h"
00105 
00106 #include "ngcore.h"
00107 #include "ngitem.h"
00108 
00109 #include "xshelpid.h"       //For the help ID
00110 //#include "helppath.h"
00111 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00112 //#include "simon.h"            // the string r%dc%d is in here
00113 #include "progress.h"
00114 #include "osrndrgn.h"
00115 
00116 #include "giffiltr.h"       // for TI_GIFFilter
00117 #include "bmpfiltr.h"
00118 #include "pngfiltr.h"
00119 #include "extfilts.h"
00120 
00121 #include "exjpeg.h"         // jpeg export options
00122 
00123 #include "page.h"
00124 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00125 
00126 #include "mrhbits.h"        // for the bitmap render in to test if a slice is empty
00127 #include "selall.h"         // for the select all op in the test if a slice is empty
00128 
00129 #include "slicehelper.h"
00130 //#include "sliceres.h"
00131 
00132 #include "bmapprev.h"       // for setting the export type in the preview
00133 
00134 #include "ngprop.h"
00135 #include "ngsentry.h"
00136 
00137 #include "webattr.h"        // for the URL attrib
00138 
00139 // for the use of wix temple attribs
00140 //#include "cxfrech.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00141 #include "userattr.h"
00142 #include "tmpltatr.h"
00143 
00144 #include "desnotes.h"
00145 #include <io.h>             // for _taccess()
00146 #include "helpuser.h"       // for the SetNextMsgHelpContext function
00147 //#include "andy.h"         //For _R(IDM_OVERWRITE)
00148 //#include "resource.h"     //For _R(IDS_CANCEL)
00149 
00150 #include "nodetxts.h"
00151 #include "nodetxtl.h"
00152 #include "nodetext.h"
00153 
00154 //#include "mario.h"            // For _R(IDE_NOMORE_MEMORY) - Matt 12/11/2000
00155 
00156 
00157 #ifdef _DEBUG
00158 #undef THIS_FILE
00159 static char BASED_CODE THIS_FILE[] = __FILE__;
00160 #endif
00161 
00162 DECLARE_SOURCE("$Revision: 1282 $");
00163 
00164 CC_IMPLEMENT_DYNCREATE(OpSlice, OpMenuImport);
00165 
00166 #define new CAM_DEBUG_NEW
00167 
00168 
00169 /********************************************************************************************
00170 
00171 >   CSlice::CSlice()
00172 
00173     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
00174     Created:    20/7/99
00175     Returns:    
00176     Purpose:    Creates a slice object either empty or pre-filled
00177     Errors:     -
00178 
00179 ********************************************************************************************/
00180 CSlice::CSlice()
00181 {
00182     top = bottom = left = right = 0;
00183     row = colm = -1;
00184     rowspan = colmspan = 1;
00185     rowheight = colmwidth = 0;
00186     name.Empty();
00187     FileTypeExtStr = "gif";
00188     deleteme = FALSE;
00189     IsNamedSlice = FALSE;
00190     ButtonNumber = 0;
00191     IsEmpty = FALSE;
00192     HasURL = FALSE;
00193     pFrameText = NULL;
00194     ExistsOnLayerState[0] = 0;
00195     ExistsOnLayerState[1] = 0;
00196     ExistsOnLayerState[2] = 0;
00197     ExistsOnLayerState[3] = 0;
00198 }
00199 
00200 CSlice::CSlice(INT32 Ax, INT32 Ay, INT32 Cx, INT32 Cy, String_256 ThisName, String_16 FileExt, BOOL Named)
00201 {
00202     top = min(Ay, Cy);
00203     left = min(Ax, Cx);
00204     right = max(Ax, Cx);
00205     bottom = max(Ay, Cy);
00206     name = ThisName;
00207     row = colm = -1;
00208     rowspan = colmspan = 1;
00209     rowheight = colmwidth = 0;
00210     FileTypeExtStr = FileExt;
00211     deleteme = FALSE;
00212     IsNamedSlice = Named;
00213     ButtonNumber = 0;
00214     IsEmpty = FALSE;
00215     HasURL = FALSE;
00216     pFrameText = NULL;
00217     ExistsOnLayerState[0] = 0;
00218     ExistsOnLayerState[1] = 0;
00219     ExistsOnLayerState[2] = 0;
00220     ExistsOnLayerState[3] = 0;
00221 }
00222 
00223 /********************************************************************************************
00224 
00225 >   void CSlice::SwapSpreadAndSliceCoords()
00226 
00227     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
00228     Created:    27/7/99
00229     Returns:    
00230     Purpose:    Reverses the y-axis to convert between spread co-ords and slice co-ords
00231                 Call it again to swap back between co-ord systems.
00232     Errors:     -
00233 
00234 ********************************************************************************************/
00235 void CSlice::SwapSpreadAndSliceCoords()
00236 {
00237     INT32 temp = top;
00238     top = -bottom;
00239     bottom = -temp;
00240 }
00241 
00242 /********************************************************************************************
00243 
00244 >   BOOL OpSlice::Init()
00245 
00246     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
00247     Created:    20/7/99
00248     Returns:    TRUE if worked, FALSE if failed (out of memory)
00249     Purpose:    Declares the OpDescriptor
00250     Errors:     -
00251 
00252 ********************************************************************************************/
00253 BOOL OpSlice::Init()
00254 {
00255     return RegisterOpDescriptor(
00256             0,                          // Tool ID
00257             _R(IDS_IMAGESLICE),                 // String resource ID
00258             CC_RUNTIME_CLASS(OpSlice),  // Runtime class
00259             OPTOKEN_IMAGESLICE,         // Token string
00260             GetState,                   // GetState function
00261             _R(IDH_Command_Import_from_Web),// help ID GTODO: Is this needed?
00262             _R(IDBBL_IMAGESLICE),           // bubble help
00263             _R(IDD_BARCONTROLSTORE),        // resource ID
00264             _R(IDC_IMAGESLICE),             // control ID
00265             SYSTEMBAR_FILE,             // Bar ID
00266             TRUE,                       // Receive system messages
00267             FALSE,                      // Smart duplicate operation
00268             TRUE,                       // Clean operation
00269             0,      // String for one copy only error
00270             (DONT_GREY_WHEN_SELECT_INSIDE | GREY_WHEN_NO_CURRENT_DOC) // Auto state flags
00271         );
00272     
00273 }
00274 
00275 /********************************************************************************************
00276 
00277 >   void OpSlice::Do(OpDescriptor*)
00278 
00279     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
00280     Created:    20/7/99
00281     Purpose:    Exports the current document as slices defined by named selections
00282     Errors:     -
00283 
00284 ********************************************************************************************/
00285 void OpSlice::Do(OpDescriptor*)
00286 {
00287     // there needs to be a spread
00288     Spread* pSelSpread = Document::GetSelectedSpread();
00289     if (pSelSpread == NULL)
00290         return;
00291 
00292     //  Let's set a variable in BmapPrevDlg which will be used to determine
00293     //  which of the tab controls should be enabled or disabled.
00294     BmapPrevDlg::m_bSlicingImage = TRUE;
00295 
00296     m_ErrorStr = "none";
00297     m_HTMLext = "htm";
00298 
00299     m_NumberOfButtons = 0;
00300 
00301     // init the export path - which probably isn't needed
00302     // but better safe than sorry etc...
00303     // set to .non so that any slices that are defined from this can be
00304     // found and redefined later. see UpdateSliceFileExts() - sjk
00305     m_PathName.SetPathName("c:\\untitled.non");
00306 
00307     m_InjectHTML = FALSE; // don't inject without thinking about it - you know it makes sense!
00308 
00309     m_ExportedHTMLOK = TRUE; // asumes the best :-)
00310 
00311     // start a slow job
00312     Progress LongJob;
00313     LongJob.Start();
00314 
00315     // test if we use design notes
00316     m_UsesDesignNotes = UsesDesignNotes();
00317 
00318     // calculate the background colour
00319     DocColour dcol = Page::GetPageColour();
00320     m_lRed = m_lGreen = m_lBlue = 255;
00321 
00322     BOOL HasBitmapBackground = FALSE;
00323 
00324     Layer * pLayer = pSelSpread->FindFirstPageBackgroundLayer();
00325     if (pLayer)
00326     {
00327         Node * pNode = SliceHelper::FindNextOfClass(pLayer, pLayer, CC_RUNTIME_CLASS(AttrFlatColourFill));
00328         if (pNode)
00329             dcol = *(((AttrFlatFill *)pNode)->GetStartColour());
00330         else
00331         {
00332             if (SliceHelper::FindNextOfClass(pLayer, pLayer, CC_RUNTIME_CLASS(AttrBitmapColourFill)))
00333                 HasBitmapBackground = TRUE;
00334         }
00335     }
00336 
00337     dcol.GetRGBValue(&m_lRed, &m_lGreen, &m_lBlue);
00338 
00339     
00340     // calculate the bounds of the entire image
00341     // init the mosaic list which stores all the parts of the image
00342 
00343     CList <CSlice *, CSlice *> MosaicList;
00344     MosaicList.RemoveAll();
00345 
00346     // the bounds of the drawing
00347     DocRect SpreadBounds = BaseBitmapFilter::GetSizeOfDrawing(pSelSpread); // returns in spread co-ords ignoring silly layers
00348     
00349     // get the selection
00350     Range Sel(*(GetApplication()->FindSelection()));
00351 
00352     // set the range flags so it includes shadow and bevel manager nodes
00353     RangeControl rg = Sel.GetRangeControlFlags();
00354     rg.PromoteToParent = TRUE;
00355     Sel.Range::SetRangeControl(rg);
00356     BOOL UseWholeDrawing = TRUE;
00357     
00358     // get the size of the selection
00359     // if there is a selection use this as the area to export rather than the drawing area
00360     // which we will use if there is no selection made
00361     if (!Sel.IsEmpty())
00362     {
00363         SpreadBounds = Sel.GetBoundingRect();
00364         UseWholeDrawing = FALSE;
00365     }
00366 
00367     PixelAlignedInflate(&SpreadBounds); // pixel align the starting rect
00368 
00369     // find the defined slices
00370     NameGallery* pNameGallery = NameGallery::Instance();
00371     SGUsedNames* pNames = pNameGallery?NameGallery->GetUsedNames():NULL;
00372 
00373     if (!pNames)
00374     {
00375         InformWarning( _R(IDS_NOSLICES) );
00376         //  Reset:
00377         BmapPrevDlg::m_bSlicingImage = FALSE;
00378         return;
00379     }
00380 
00381     // make sure we are dealing with the most uptodate information
00382     pNameGallery->FastUpdateNamedSetSizes();
00383 
00384     // for each defined slice in the name gallery
00385     BOOL NoProblems = TRUE;
00386     BOOL AddedASlice = FALSE;
00387     BOOL OutsideSpread = FALSE;
00388 
00389     INT32 Attempts = 0; // first try with the large rects then if that fails try the smaller ones
00390     String_256 strName(TEXT("Empty"));
00391     String_256 Slice1ErrorStr = "";
00392     String_256 Slice2ErrorStr = "";
00393     INT32 SlicesDefinedInDrawing = 0;
00394 
00395     do
00396     {
00397         NoProblems = TRUE;
00398         AddedASlice = FALSE;
00399         OutsideSpread = FALSE;
00400         SlicesDefinedInDrawing = 0;
00401 
00402         // the original mosaic piece is the whole bounded image
00403         // which will be broken up
00404         TidyMosaicList(&MosaicList);
00405         MosaicList.AddHead(new CSlice(SpreadBounds.lox, SpreadBounds.loy, SpreadBounds.hix, SpreadBounds.hiy));
00406 
00407         SGNameItem* pItem = (SGNameItem*) pNames->GetChild();
00408 
00409         while (pItem != 0 && NoProblems)
00410         {
00411             // is the tick set in the name gallery to use this slice?
00412             BOOL UseThisSlice = TRUE;
00413             NamedTickboxProp * pSliceTick = (NamedTickboxProp *) pItem->GetProperty(1); // 1 is slices
00414             if (pSliceTick)
00415             {
00416                 UseThisSlice = pSliceTick->GetState();
00417                 if (UseThisSlice)
00418                     SlicesDefinedInDrawing++;
00419             }
00420 
00421             // dont use an unselected slice if it is not the whole drawing being exported
00422             if (!UseWholeDrawing && pItem->IsNoneSelected())
00423                 UseThisSlice = FALSE;
00424 
00425             if (UseThisSlice)
00426             {
00427                 DocRect r;
00428                 r = pItem->GetSetBounds();          // (returned in spread co-ords)
00429 
00430                 pItem->GetNameText(&strName);
00431 
00432                 // expand for actual text story visible size
00433                 ScanTextStorySliceBounds(strName, r);
00434 
00435                 if (Attempts == 0)
00436                 {
00437                     DocRect rLarge = ScanLargeSliceBounds(strName);
00438                     r = r.Union(rLarge); // use the large rects
00439                 }
00440 
00441                 // r must be in the spread bounds
00442                 // if it is outside the bounds it should be ignored
00443                 PixelAlignedInflate(&r);        // pixel align the slice
00444 
00445                 // trim anything that just strays over the bounds
00446                 r = r.Intersection(SpreadBounds);
00447 
00448                 // cut the existing mosaic pieces by the edges of this new piece
00449                 // which of course creates even more pieces
00450                 if (r.IsValid() && r.Height() > 0 && r.Width() > 0)
00451                 {
00452                     NoProblems = NoProblems && AddSlice(r.lox, r.loy, r.hix, r.hiy, &MosaicList, strName);
00453                     AddedASlice = TRUE;
00454                 }
00455                 else
00456                 {
00457                     TRACEUSER( "SimonK", _T("Slice outside bounds of the drawing!!!\n"));
00458                 }
00459             }
00460 
00461             if (NoProblems) pItem = (SGNameItem*) pItem->GetNext();
00462         }
00463 
00464         Attempts++;
00465         if (!NoProblems)
00466         {
00467             Slice1ErrorStr = m_ErrorStr;
00468             Slice2ErrorStr = strName;
00469         }
00470 
00471     } while (!NoProblems && Attempts < 2); // try twice , first with the max size slices, then with the smaller slices
00472 
00473 /* Dont ask the question Asumme that the user will choose to have the shadows cut if they do overlap (sjk 20/12/00)
00474     if (Attempts == 2 && NoProblems && AddedASlice)
00475     {   // worked with the smaller rects but not with the larger ones
00476 
00477         // I need to force this message to reappear again if they click 'Help' - Matt 10/11/2000
00478         INT32 result = 3;
00479         while (result == 3)
00480         {
00481             result = AskQuestion(_R(IDS_SLICES_MAY_OVERLAP), _R(IDS_YES), _R(IDS_NO), _R(IDS_HELP));
00482             if (result == 2)
00483             {
00484                 NoProblems = FALSE; // it is a problem if you say it is
00485                 m_ErrorStr = Slice1ErrorStr; // restore the shapes that were causing problems for the first case
00486                 strName = Slice2ErrorStr;
00487             }
00488             if (result == 3)
00489             {
00490                 HelpUserTopic(_R(IDH_Alert_Exclude_peripheral_elements));
00491             }
00492         }
00493     }
00494 */
00495     POSITION Test = NULL;
00496 
00497     if (NoProblems && AddedASlice) 
00498     {
00499         // sort the mosaic using SortSlices()
00500         // it also merges small bits back together if it can
00501         SortSlices(&MosaicList, SpreadBounds);
00502 
00503         // mark which states exist
00504         m_FoundRolloverStates = ScanForRolloverStates(&MosaicList);
00505 
00506         BOOL ReplaceFiles = TRUE;
00507         BOOL FilesOverwriten = FALSE;
00508         do // loop to ask where to save to which may be asked more than once if they dont want
00509             // to overwrite files
00510         {
00511 
00512             // ask where to save the files
00513             // and find out which slice export type to use
00514             if (!SaveFileDlg())
00515             {
00516                 // tidy up and leave if cancelled
00517                 TidyMosaicList(&MosaicList);
00518                 Error::ClearError();
00519                 //  Reset:
00520                 BmapPrevDlg::m_bSlicingImage = FALSE;
00521                 return;
00522             }
00523 
00524 
00525             // cope with things being .html, which the BmapPrevDlg doesn't set correctly as its not 8.3
00526             String_256 temp = m_PathName.GetFileName(FALSE);
00527             INT32 dot = temp.FindNextChar(TCHAR ('.'));
00528             if (dot > 0)
00529             {
00530                 String_256 end = "";
00531                 temp.Split(&temp, &end, dot, FALSE);
00532                 if (end.CompareTo(".html", FALSE) == 0)
00533                 {
00534                     m_HTMLext = "html";
00535                     m_PathName.SetFileName(temp);
00536                 }
00537             }
00538 
00539             CString ClickedFile(temp);
00540             ClickedFile += "." + m_HTMLext;
00541 
00542             ReplaceFiles = FileExists(ClickedFile);
00543             FilesOverwriten = FALSE;
00544 
00545             if (!ReplaceFiles)
00546             {
00547                 // test if these names we are creating are already in existance
00548                 Test = MosaicList.GetHeadPosition();
00549                 while (Test && !FilesOverwriten)
00550                 {
00551                     CSlice* pTestSlice = MosaicList.GetNext(Test);
00552                     CString TestName (pTestSlice->name);
00553 
00554                     // we dont know exactly what file type for each element will be
00555                     // but it is best to warn the user that they may be overwriting their files
00556                     FilesOverwriten = FileExists(TestName + ".gif");
00557                     if (!FilesOverwriten) FilesOverwriten = FileExists(TestName + ".jpg");
00558                     if (!FilesOverwriten) FilesOverwriten = FileExists(TestName + ".jpeg");
00559                     if (!FilesOverwriten) FilesOverwriten = FileExists(TestName + ".png");
00560                     if (!FilesOverwriten) FilesOverwriten = FileExists(TestName + ".bmp");
00561                 }
00562             }
00563 
00564             if (FilesOverwriten && !ReplaceFiles)
00565             {
00566                 // ask the user "This folder contains a graphic file with a conflicting name.
00567                 // Do you want to overwrite any conflicting files in this folder?"
00568                 if (InformWarning(_R(IDS_CONFLICTING_SLICE_FILENAMES), _R(IDS_OVERWRITE_GRAPHIC), _R(IDS_SAVE_ELSEWHERE)) == 1)
00569                     ReplaceFiles = TRUE;
00570             }
00571 
00572         } while (FilesOverwriten && !ReplaceFiles); // end of overwrite loop
00573 
00574 
00575         // The preview dlg wants to know the path of the image being
00576         // exported so give it the m_PathName
00577         BmapPrevDlg::m_pthExport = m_PathName;
00578 
00579         // set up the export options
00580         BitmapExportOptions * pExportOptions = NULL;
00581         BOOL ok = TRUE;
00582 
00583         ShowRolloverLayer(ALL_LAYERS);
00584 
00585         // WARNING SetUpExportOptions() actually 'new's the ExportOptions
00586         // so you will have to delete them or pass them to a function
00587         // that deletes them for you
00588         String_256 strExt = m_PathName.GetType();
00589         strExt.toLower();
00590         if (strExt.CompareTo("jpg") == 0)
00591         {
00592             JPEGExportFilter f;
00593             ok = f.SetUpExportOptions(&pExportOptions);
00594         }
00595         else
00596         if (strExt.CompareTo("bmp") == 0)
00597         {
00598             BMPFilter f;
00599             ok = f.SetUpExportOptions(&pExportOptions);
00600         }
00601         else
00602         if (strExt.CompareTo("png") == 0)
00603         {
00604             PNGFilter f;
00605             ok = f.SetUpExportOptions(&pExportOptions);
00606         }
00607         else
00608         //if (strExt == "gif")
00609         {
00610             TI_GIFFilter f;
00611             ok = f.SetUpExportOptions(&pExportOptions);
00612         }
00613 
00614         // the export options may have changed types
00615         // so ask the export dlg for the actual export options
00616         pExportOptions = BmapPrevDlg::m_pExportOptions;
00617         // take responsibility for the export options away from the bmp preview dlg
00618         BmapPrevDlg::m_pExportOptions = 0;
00619 
00620         // Cancelled from the export options dlg
00621         if (!ok)
00622         {
00623             if (pExportOptions)
00624             {
00625                 delete pExportOptions;
00626             }
00627             // tidy up and leave
00628             TidyMosaicList(&MosaicList);
00629             Error::ClearError();
00630             //  Reset:
00631             BmapPrevDlg::m_bSlicingImage = FALSE;
00632             return;
00633         }
00634 
00635         // read the m_PathName back since
00636         // setting up the export options could
00637         // have changed this value
00638         m_PathName = BmapPrevDlg::m_pthExport;
00639 
00640 
00641         // clear the screen by calling an idle
00642         (DocView::GetSelected())->ForceRedraw();
00643         GetApplication()->OnIdle(TRUE);             // Phil 2/7/2004 YUK! What's wrong with ServiceRendering?
00644 
00645         // change the non-user defined slices to use the graphic type
00646         // just picked by the user in the SaveFileDlg
00647         UpdateSliceFileExts(&MosaicList);
00648 
00649         // mark any "empty" slices in the list
00650         // but not if we have a background bitmap
00651         if (!HasBitmapBackground)
00652             MarkEmptySlices(&MosaicList, SpreadBounds, pExportOptions);
00653 
00654         // export each section of the mosaic as a seperate graphic
00655         Test = MosaicList.GetHeadPosition();
00656         while (Test)
00657         {
00658             CSlice* pTestSlice = MosaicList.GetNext(Test);
00659 
00660             if (m_FoundRolloverStates && pTestSlice->IsNamedSlice)
00661                 // export this slice as a rollover
00662                 ExportRollOverSlice(pTestSlice, pExportOptions);
00663             else
00664                 // do a normal slice
00665             {
00666                 // only export the graphic for a none-empty slice
00667                 if (!pTestSlice->IsEmpty)
00668                     ExportSliceGraphic(pTestSlice, pExportOptions, pTestSlice->name);
00669             }
00670 
00671             // This function calls DoExportWithParams() which used to
00672             // delete the export options (and not zero the pointer - tusk!)
00673             // Behaviour now changed by using DontLetFilterDeleteMyPointer()
00674             // so we can keep using the same export options, but of course we
00675             // must then delete them ourselves.
00676         }
00677 
00678         // tidy up our generated export options
00679         if (pExportOptions != 0)
00680         {
00681             delete pExportOptions;
00682             pExportOptions = 0;
00683         }
00684 
00685         // And clean up the image export options in the bitmap dialogue.
00686 //      BmapPrevDlg::CancelTransparency ();
00687 
00688         // export the HTML to display the mosaic put back together
00689         // the name is that typed in but with the htm extension
00690 
00691         // build up the list of link names with each button
00692         // rather than just going on adding a number to the file
00693         // users want to not have to edit HTML, do it all for them!
00694         m_UsedShimGraphic = FALSE;
00695         PathName HTMLPath = m_PathName;
00696         HTMLPath.SetType(m_HTMLext);
00697         m_pLinkName = NULL;
00698         INT32 i = 0;
00699         String_256 LaunchString = HTMLPath.GetFileName();
00700 
00701         INT32 LinkEntries = max (m_NumberOfButtons, 1);
00702         m_pLinkName = new String_256[LinkEntries];
00703 
00704         if (m_pLinkName)
00705         {
00706             m_pLinkName[0] = HTMLPath.GetPath();
00707 
00708             INT32 FileNumber = 0;
00709             // fill the link names with default names if there are no URLs found
00710             for (i = 0; i < m_NumberOfButtons; i++)
00711             {
00712                 m_pLinkName[i] = m_PathName.GetFileName(FALSE);
00713 
00714                 CSlice * pTestSlice = GetButtonNumber (&MosaicList, i+1);
00715                 if (pTestSlice && pTestSlice->ExistsOnLayerState[SELECTED])
00716                 {
00717                     FileNumber++;
00718 
00719                     if (m_FoundRolloverStates && m_RolloverState[SELECTED].Exists && FileNumber > 1)
00720                     {
00721                         String_256 NewName;
00722                         NewName.MakeMsg(_R(IDS_HTML_NAME_SPEC), (LPCSTR) m_PathName.GetFileName(FALSE), FileNumber);
00723                         m_pLinkName[i] = NewName;
00724                     }
00725                 }
00726 
00727                 m_pLinkName[i] += ".";
00728                 m_pLinkName[i] += m_HTMLext;
00729             }
00730 
00731             // scan the tree for any URLs used associated with the buttons in the Mosaic list
00732             // this will overwrite the defaults already set in m_pLinkName
00733             URLScan(m_pLinkName, &MosaicList);
00734 
00735             FileNumber = 0;
00736 
00737             // export each HTML file required
00738             if (m_RolloverState[SELECTED].Exists)
00739                 for (i = 0; i < LinkEntries; i++)
00740                 {
00741                     String_256 NewName = m_pLinkName[i];
00742                     String_256 Temp = "";
00743 
00744                     // dont try to create a file http://www.stuff...
00745                     NewName.Left(&Temp,5);
00746                     BOOL isURL = (Temp.CompareTo("http:", FALSE) == 0);
00747                     if (!isURL)
00748                     {
00749                         NewName.Right(&Temp,1);
00750                         isURL = (Temp.CompareTo("/") == 0);
00751                     }
00752 
00753                     CSlice * pTestSlice = GetButtonNumber (&MosaicList, i+1);
00754                     if (pTestSlice && pTestSlice->ExistsOnLayerState[SELECTED])
00755                     {
00756                         FileNumber++;
00757 
00758                         if (isURL)
00759                         {
00760                             NewName.MakeMsg(_R(IDS_HTML_NAME_SPEC), (LPCSTR) m_PathName.GetFileName(FALSE), FileNumber);
00761                             NewName += ".";
00762                             NewName += m_HTMLext;
00763                         }
00764 
00765                         HTMLPath.SetPathName(NewName);
00766 
00767                         if (!ExportImageSliceHTML(&MosaicList, HTMLPath.GetPath(), i+1))
00768                             FailledToExportHTML (HTMLPath.GetPath());
00769 
00770                         // set file to launch if changed by the URL
00771                         if (FileNumber == 1)
00772                         {
00773                             LaunchString = HTMLPath.GetFileName();
00774                         }
00775                     }
00776 
00777                 }
00778             else
00779                 if (!ExportImageSliceHTML(&MosaicList, HTMLPath.GetPath()))
00780                     FailledToExportHTML (HTMLPath.GetPath());
00781 
00782             delete [] m_pLinkName;
00783             m_pLinkName = NULL;
00784         }
00785 
00786         // Export out the required shim
00787         if (m_UsedShimGraphic)
00788         {
00789             // also needs shim.gif exported
00790             // set up the path of where to save it
00791             PathName ShimPath = m_PathName;
00792 
00793             ShimPath.SetFileName("shim");
00794             ShimPath.SetType("gif");
00795 
00796             CCDiskFile File;
00797             if(File.open(ShimPath.GetPath(), (ios::in | ios::out | ios::binary)))
00798             {
00799                 BYTE buf[] =   {0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x01, 0x00,
00800                                 0x01, 0x00, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
00801                                 0x00, 0x00, 0x00, 0x21, 0xF9, 0x04, 0x01, 0x14,
00802                                 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00,
00803                                 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x44,
00804                                 0x01, 0x00, 0x3B, 0x00  };
00805 
00806                 // make the shim of the correct colour
00807                 buf[13] = (BYTE) m_lRed;
00808                 buf[14] = (BYTE) m_lGreen;
00809                 buf[15] = (BYTE) m_lBlue;
00810 
00811                 // write the file
00812                 File.write((BYTE *)buf, 44);
00813                 File.close();
00814             }
00815         }
00816         
00817         // display the export HTML now?
00818         if (m_ExportedHTMLOK && AskQuestion(_R(IDS_SHOW_HTML_NOW), _R(IDS_YES), _R(IDS_NO)) == 1)
00819         {
00820             // shell execute the browser
00821             HINSTANCE hChild = ShellExecute(HWND_DESKTOP, "open", LaunchString, NULL, NULL ,SW_SHOW);
00822 
00823             // If the function (ShellExecute()) fails, then an error value that is less than or equal to 32 is returned. 
00824             INT32 Result = (INT32)hChild;
00825             // problems?
00826             if (Result <= 32)
00827             {
00828                 InformWarning(_R(IDS_NO_BROWSER));
00829             }
00830         }
00831     
00832     }
00833     else if (!AddedASlice) // user forgot to define any slices
00834     {
00835         if (SlicesDefinedInDrawing == 0)
00836             InformWarning( _R(IDS_NOSLICES) );
00837         else
00838             InformWarning( _R(IDS_NOSLICES_SELECTED) );
00839     }
00840     else // some error occured such as intersecting named slices
00841     {
00842         if (OutsideSpread)
00843         {
00844             // An invisible slice is outside the bounds of the rendered spread
00845             InformWarning(_R(IDS_SLICE_OUT_OF_BOUNDS));
00846         }
00847         else
00848         {
00849             // should mention that it is pTestSlice->name that is overlapping       
00850             String_256 temp(TEXT(""));
00851             temp.MakeMsg(_R(IDS_SLICES_OVERLAP), (LPCTSTR) m_ErrorStr, (LPCTSTR) strName);
00852 
00853             ErrorInfo Info;
00854             Info.ErrorMsg = 0;
00855             Info.Button[0] = _R(IDS_OK);
00856             Info.Button[1] = _R(IDS_HELP);
00857             Info.OK = 1;
00858             Info.Help = 2;
00859             Info.Title = _R(IDBBL_IMAGESLICE);
00860 
00861             BOOL Again;
00862             do
00863             {
00864                 // Set the error message
00865                 Error::SetError( 0, temp, 0 );
00866 
00867                 Again = FALSE;
00868                 switch (AskQuestion(&Info))
00869                 {
00870                     case _R(IDS_HELP):
00871                         HelpUserTopic(_R(IDS_HELPPATH_Alert_Named_Objects_Overlap));
00872                         Again = TRUE;
00873                         break;
00874                 }
00875             } while (Again);
00876         }
00877     }
00878 
00879     // tidey up before leaving
00880     TidyMosaicList(&MosaicList);
00881 
00882     // end a slow job
00883     // done through the progress class being destroyed
00884 
00885     //  Reset:
00886     BmapPrevDlg::m_bSlicingImage = FALSE;
00887 }
00888 
00889 /********************************************************************************************
00890 
00891 >   INT32 OpSlice::TidyMosaicList(CList <CSlice *, CSlice *> * pMosaicList)
00892 
00893     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
00894     Created:    3/8/99
00895     Purpose:    Deletes all the slices in the list now that we are done with them.
00896                 So there will be no memory leeks.
00897 
00898 ********************************************************************************************/
00899 INT32 OpSlice::TidyMosaicList(CList <CSlice *, CSlice *> * pMosaicList)
00900 {
00901     // tidy the mosaic list by deleting all its entries
00902     INT32 Pieces = 0;
00903     POSITION Test = pMosaicList->GetHeadPosition();
00904     while (Test)
00905         {
00906             CSlice * pTestSlice = pMosaicList->GetNext(Test);
00907             pMosaicList->RemoveHead();
00908             delete pTestSlice;
00909             Pieces++;
00910         }
00911 
00912     return Pieces;
00913 }
00914 
00915 /********************************************************************************************
00916 
00917 >   void OpSlice::UpdateSliceFileExts(CList <CSlice *, CSlice *> * pMosaicList)
00918 
00919     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
00920     Created:    3/8/99
00921     Purpose:    Changes all non set file types to be the type the user picks from the file dlg.
00922 
00923 ********************************************************************************************/
00924 void OpSlice::UpdateSliceFileExts(CList <CSlice *, CSlice *> * pMosaicList)
00925 {
00926     POSITION Test = pMosaicList->GetHeadPosition();
00927     while (Test)
00928         {
00929             CSlice * pTestSlice = pMosaicList->GetNext(Test);
00930             if (pTestSlice->FileTypeExtStr.CompareTo("non") == 0) // using non as a standard we haven't set this yet
00931                 pTestSlice->FileTypeExtStr = m_PathName.GetType();
00932         }
00933 
00934 }
00935 
00936 /********************************************************************************************
00937 
00938 >   OpState OpSlice::GetState(String_256*, OpDescriptor*)
00939 
00940     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
00941     Created:    20/7/99
00942     Purpose:    This item is always available, so long as a document is visible.
00943                 Not really sure if I even need this!!!
00944 
00945 ********************************************************************************************/
00946 OpState OpSlice::GetState(String_256*, OpDescriptor*)
00947 {
00948     OpState OpSt;
00949 
00950     // if we don't allow it
00951     OpSt.Greyed = TRUE;
00952     Spread* pSpread = Document::GetSelectedSpread();
00953     if (pSpread && !pSpread->FindActiveLayer()->IsFrame())
00954         OpSt.Greyed = FALSE;
00955 
00956     return OpSt;
00957 }
00958 
00959 /********************************************************************************************
00960 
00961 >BOOL OpSlice::AddSlice (INT32 Ax, INT32 Ay, INT32 Cx, INT32 Cy, CList <CSlice *, CSlice *> * pMosaicList, String_256 SliceName)
00962 
00963     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
00964     Created:    23/7/99
00965     Purpose:    
00966                  slice rect ABCD
00967                    A---B
00968                    |   |
00969                    D---C
00970                  pMosaicList should start with one entry which is the whole drawing extent
00971                  that is to be split up into sections.
00972                  The passed in slice (AC) is added to the list of pieces which is a named user
00973                  defined slice. Existing pieces that are occupy the same area are cut into
00974                  smaller parts or absorbed.
00975 
00976     Params:     Axy, Cxy defines the new slice
00977                 pMosaic is this list of the slices
00978                 SliceName is the name of the new slice
00979 
00980     Returns:    TRUE if it worked - FALSE if something failled
00981 
00982 ********************************************************************************************/   
00983 BOOL OpSlice::AddSlice (INT32 Ax, INT32 Ay, INT32 Cx, INT32 Cy, CList <CSlice *, CSlice *> * pMosaicList, String_256 SliceName)
00984 {
00985     // ignore empty slices as we could hardly export them
00986     // but since slices containing nothing could exist we should cater
00987     // for the possibility
00988     if (Ax == Cx || Ay == Cy) return TRUE;
00989 
00990     // if the inflate to pixel aligned rect has swapped over two named slices
00991     // set them to being on the same boundry
00992     NudgeSliceIfClose(Ax, Ay, Cx, Cy, pMosaicList);
00993 
00994     BOOL ok = TRUE;
00995     POSITION pos = pMosaicList->GetHeadPosition();
00996 
00997     while (pos)
00998     {
00999         POSITION thispos = pos;
01000         CSlice * pRect = pMosaicList->GetNext(pos);
01001         BOOL RemoveMe = TRUE;
01002         
01003         if (Ax == pRect->left && Cx == pRect->right && Ay == pRect->top && Cy == pRect->bottom)
01004         {
01005             // remove existing identical slices
01006             // keep the name if it has one and the replacement doesn't.
01007             if (!pRect->name.IsEmpty())
01008             {
01009                 TRACE( _T("Identically named slices\n"));
01010                 if (SliceName.IsEmpty())
01011                     SliceName = pRect->name;
01012             }
01013         }
01014         else
01015         if (InRect(pRect, Ax, Ay)) // A in rect
01016             ok = Slice (pRect, Ax, Ay, Cx, Ay, pMosaicList); // slice AB
01017         else
01018         if (InRect(pRect, Cx, Ay)) // B in rect
01019             ok = Slice (pRect, Ax, Ay, Cx, Ay, pMosaicList); // slice AB
01020         else
01021         if (CutsRect(pRect, Ax, Ay, Cx, Ay)) // cuts AB
01022             ok = Slice (pRect, Ax, Ay, Cx, Ay, pMosaicList); // slice AB
01023         else
01024         if (InRect(pRect, Cx, Cy)) // C in rect
01025             ok = Slice (pRect, Cx, Ay, Cx, Cy, pMosaicList); // slice BC
01026         else
01027         if (CutsRect(pRect, Cx, Ay, Cx, Cy)) // cuts BC
01028             ok = Slice (pRect, Cx, Ay, Cx, Cy, pMosaicList); // slice BC
01029         else
01030         if (InRect(pRect, Ax, Cy)) // D in rect
01031             ok = Slice (pRect, Ax, Ay, Ax, Cy, pMosaicList); // slice AD
01032         else
01033         if (CutsRect(pRect, Ax, Ay, Ax, Cy)) // cuts AD
01034             ok = Slice (pRect, Ax, Ay, Ax, Cy, pMosaicList); // slice AD
01035         else
01036         if (CutsRect(pRect, Ax, Cy, Cx, Cy)) // cuts DC
01037             ok = Slice (pRect, Ax, Cy, Cx, Cy, pMosaicList); // slice DC
01038         else
01039         if (pRect->left >= Ax && pRect->right <= Cx && pRect->top >= Ay && pRect->bottom <= Cy) // rect in ABCD
01040             //remove rect from list
01041         {
01042             TRACE( _T("remove sub rect\n"));
01043             // NB doing nothing will result in it being removed
01044         }
01045         else // this piece doesn't interact with the slice at all
01046             RemoveMe = FALSE; // so don't let it be taken from us
01047 
01048         if (!ok)
01049             return FALSE; // an error occurred
01050         
01051         pos = thispos;
01052         // reget the next item to check that we haven't extended the list
01053         pRect = pMosaicList->GetNext(pos);
01054 
01055         if (RemoveMe)
01056         {
01057             pMosaicList->RemoveAt(thispos);
01058             delete pRect;
01059         }
01060     }
01061 
01062     // add the slice passed in
01063     // remember to give it the users individually selected graphic type
01064     // which isn't yet implimented
01065     RemoveIlligalFileAndJavaChars(SliceName);
01066     pMosaicList->AddHead(new CSlice(Ax, Ay, Cx, Cy, SliceName, m_PathName.GetType(), TRUE));
01067 
01068     return ok;
01069 }
01070 
01071 /********************************************************************************************
01072 
01073 >   BOOL OpSlice::InRect(CSlice * pRect, INT32 x, INT32 y)
01074 
01075     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
01076     Created:    23/7/99
01077     Purpose:    Tests if the point X,Y is in the rectangle defined by the slice
01078     Returns:    TRUE if x,y is in the rect
01079 
01080 ********************************************************************************************/
01081 BOOL OpSlice::InRect(CSlice * pRect, INT32 x, INT32 y)
01082 {
01083     if (x > pRect->left && x < pRect->right
01084         && y > pRect->top && y < pRect->bottom)
01085         return TRUE;
01086         
01087     return FALSE;
01088 }
01089 
01090 /********************************************************************************************
01091 
01092 >   BOOL OpSlice::Slice (CSlice * pRect, INT32 Ax, INT32 Ay, INT32 Bx, INT32 By, CList <CSlice *, CSlice *> * pMosaicList, POSITION pos)
01093 
01094     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
01095     Created:    23/7/99
01096     Purpose:    Split the Slice pRect into smaller rectangles along the line AB
01097     Returns:    TRUE if it performed a slice
01098     Errors:     On overlapped named slices
01099 
01100 ********************************************************************************************/
01101 BOOL OpSlice::Slice (CSlice * pRect, INT32 Ax, INT32 Ay, INT32 Bx, INT32 By, CList <CSlice *, CSlice *> * pMosaicList)
01102 {
01103     if (!pRect->name.IsEmpty()) // Overlapping named slices
01104     {
01105         m_ErrorStr = pRect->name; // set the error string to be the name 
01106                                   // of the offending overlapping one
01107         return FALSE;
01108     }
01109 
01110     BOOL ok = FALSE;
01111     
01112     if (Ax == Bx) // Vert slice
01113     {
01114         pMosaicList->AddTail(new CSlice(pRect->left, pRect->top, Ax, pRect->bottom, "", m_PathName.GetType()));
01115         pMosaicList->AddTail(new CSlice(Ax, pRect->top, pRect->right, pRect->bottom, "", m_PathName.GetType()));
01116         ok = TRUE;
01117     }
01118     else
01119     if (Ay == By) // Horiz slice
01120     {
01121         pMosaicList->AddTail(new CSlice(pRect->left, pRect->top, pRect->right, Ay, "", m_PathName.GetType()));
01122         pMosaicList->AddTail(new CSlice(pRect->left, Ay, pRect->right, pRect->bottom, "", m_PathName.GetType()));
01123         ok = TRUE;
01124     }
01125     
01126     return ok;
01127 }
01128 
01129 /********************************************************************************************
01130 
01131 >   BOOL OpSlice::CutsRect(CSlice * pRect, INT32 Ax, INT32 Ay, INT32 Bx, INT32 By)
01132 
01133     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
01134     Created:    23/7/99
01135     Purpose:    Tests to see if the line AB cuts the rectangle pRect
01136     Returns:    TRUE if it does cut
01137 
01138 ********************************************************************************************/
01139 BOOL OpSlice::CutsRect(CSlice * pRect, INT32 Ax, INT32 Ay, INT32 Bx, INT32 By)
01140 {
01141     if (Ax == Bx) // Vert cut
01142     {
01143         // top & bottom outside rect
01144         // while the vertical line cuts through the rect
01145         if (Ay <= pRect->top && By >= pRect->bottom
01146             && Ax < pRect->right && Ax > pRect->left)
01147             return TRUE;
01148     }
01149     else
01150     if (Ay == By) // Horiz cut
01151     {
01152         // left & right outside rect
01153         // while the horizontal line cuts through the rect
01154         if (Ax <= pRect->left && Bx >= pRect->right
01155             && Ay < pRect->bottom && Ay > pRect->top)
01156             return TRUE;
01157     }
01158     
01159     return FALSE;
01160 }
01161 
01162 // moves all edges slightly from one location to another keeping them all in line
01163 void ReAlignEdge ( INT32 OldEdge, INT32 NewEdge, BOOL Horiz, CList <CSlice *, CSlice *> * pMosaicList)
01164 {
01165     POSITION pos = pMosaicList->GetHeadPosition();
01166 
01167     while (pos)
01168     {
01169         CSlice * pRect = pMosaicList->GetNext(pos);
01170 
01171         if (Horiz)
01172         {
01173             if (pRect->left == OldEdge)
01174                 pRect->left = NewEdge;
01175             else
01176             if (pRect->right == OldEdge)
01177                 pRect->right = NewEdge;
01178         }
01179         else
01180         {
01181             if (pRect->bottom == OldEdge)
01182                 pRect->bottom = NewEdge;
01183             else
01184             if (pRect->top == OldEdge)
01185                 pRect->top = NewEdge;
01186         }
01187     }
01188 }
01189 
01190 /********************************************************************************************
01191 
01192 >   void OpSlice::NudgeSliceIfClose(INT32 &Ax, INT32 &Ay, INT32 &Cx, INT32 &Cy, CList <CSlice *, CSlice *> * pMosaicList)
01193 
01194     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
01195     Created:    4/8/99
01196     Purpose:    Moves the new slice over a bit if it just overlaps with an
01197                 existing slice due to the pixel infation.
01198                 It does this by adjusting the AC rectangle passed in
01199     Returns:    nothing
01200 
01201 ********************************************************************************************/
01202 void OpSlice::NudgeSliceIfClose(INT32 &Ax, INT32 &Ay, INT32 &Cx, INT32 &Cy, CList <CSlice *, CSlice *> * pMosaicList)
01203 {
01204     INT32 OldAx = Ax;
01205     INT32 OldAy = Ay;
01206     INT32 OldCx = Cx;
01207     INT32 OldCy = Cy;
01208 
01209     BOOL done = FALSE;
01210 
01211     // allow how many pixels to be fudged?
01212     for (INT32 size = 750 ; size <= 1500 && !done ; size += 750)
01213     {
01214         POSITION pos = pMosaicList->GetHeadPosition();
01215 
01216         while (pos)
01217         {
01218             CSlice * pRect = pMosaicList->GetNext(pos);
01219             if (!pRect->name.IsEmpty())
01220             {
01221                 if (pRect->bottom - size == OldAy  && OldCy != pRect->bottom)
01222                 {
01223                     if (size == 750)
01224                     {
01225                         Ay = pRect->bottom;
01226                         done = TRUE;
01227                     }
01228                     else
01229                     {
01230                     // anything in the whole slice list that equals pRect->bottom should be reduced by 750
01231                     // and the same for all the others
01232                         //Ay = pRect->bottom - 750;
01233                         ReAlignEdge ( pRect->bottom, Ay, FALSE, pMosaicList);
01234                         done = TRUE;
01235                     }
01236                 }
01237                 if (pRect->top + size == OldCy && OldAy != pRect->top)
01238                 {
01239                     if (size == 750)
01240                     {
01241                         Cy = pRect->top;
01242                         done = TRUE;
01243                     }
01244                     else
01245                     {
01246                         //Cy = pRect->top + 750;
01247                         ReAlignEdge ( pRect->top, Cy, FALSE, pMosaicList);
01248                         done = TRUE;
01249                     }
01250                 }
01251                 if (pRect->left + size == OldCx && OldAx != pRect->left)
01252                 {
01253                     if (size == 750)
01254                     {
01255                         Cx = pRect->left;
01256                         done = TRUE;
01257                     }
01258                     else
01259                     {
01260                         //Cx = pRect->left + 750;
01261                         ReAlignEdge ( pRect->left, Cx, TRUE, pMosaicList);
01262                         done = TRUE;
01263                     }
01264                 }
01265                 if (pRect->right - size == OldAx && OldCx != pRect->right)
01266                 {
01267                     if (size == 750)
01268                     {
01269                         Ax = pRect->right;
01270                         done = TRUE;
01271                     }
01272                     else
01273                     {
01274                         //Ax = pRect->right - 750;
01275                         ReAlignEdge ( pRect->right, Ax, TRUE, pMosaicList);
01276                         done = TRUE;
01277                     }
01278                 }
01279             }
01280         }
01281     }
01282 }
01283 
01284 
01285 /********************************************************************************************
01286 
01287 >   BOOL OpSlice::SortSlices (CList <CSlice *, CSlice *> * pMosaicList)
01288 
01289     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
01290     Created:    23/7/99
01291     Purpose:    Sorts the slices into order.
01292                 Merges together suitable slices.
01293                 Fills in colm & row positions, spans and width/heights
01294                 for defining an HTML table.
01295                 Gives names to nameless slices in the form r*c*
01296 
01297     Returns:    FALSE if some error occured
01298 
01299 ********************************************************************************************/
01300 BOOL OpSlice::SortSlices (CList <CSlice *, CSlice *> * pMosaicList, const DocRect & Bounds)
01301 {
01302     POSITION ToDo = pMosaicList->GetHeadPosition();
01303 
01304     // go to Slice Co-ords from spread co-ords
01305     while (ToDo)
01306     {
01307         CSlice * pTopSlice = pMosaicList->GetNext(ToDo);
01308         pTopSlice->SwapSpreadAndSliceCoords();
01309     }
01310 
01311     // sort the Slices into order top left to bottom right
01312 
01313     ToDo = pMosaicList->GetHeadPosition();
01314 
01315     // ToDo moves through the whole mosaic list
01316     while (ToDo)
01317     {
01318         CSlice * pTopSlice = pMosaicList->GetNext(ToDo);
01319         POSITION Test = ToDo;
01320 
01321         // Test marks the iteration through the unsorted mosaic list
01322         // Is always between ToDo and the end of the list
01323         while (Test && !pTopSlice->deleteme)
01324         {
01325             CSlice * pTestSlice = pMosaicList->GetNext(Test);
01326 
01327             if (!pTestSlice->deleteme)
01328             {
01329                 BOOL merge = FALSE;
01330 
01331                 // test for merging the two rects together again
01332                 if (pTestSlice->name.IsEmpty() && pTopSlice->name.IsEmpty()) // don't merge selected rects!
01333                 {
01334                     // same height and y position
01335                     if (pTestSlice->top == pTopSlice->top && pTestSlice->bottom == pTopSlice->bottom)
01336                     {
01337                         if (pTestSlice->left == pTopSlice->right)
01338                         {
01339                             pTopSlice->right = pTestSlice->right;
01340                             merge = TRUE;
01341                         }
01342                         else if (pTestSlice->right == pTopSlice->left)
01343                         {
01344                             pTopSlice->left = pTestSlice->left;
01345                             merge = TRUE;
01346                         }
01347                     }
01348                     if (pTestSlice->left == pTopSlice->left && pTestSlice->right == pTopSlice->right)
01349                     {
01350                         if (pTestSlice->top == pTopSlice->bottom)
01351                         {
01352                             pTopSlice->bottom = pTestSlice->bottom;
01353                             merge = TRUE;
01354                         }
01355                         else if (pTestSlice->bottom == pTopSlice->top)
01356                         {
01357                             pTopSlice->top = pTestSlice->top;
01358                             merge = TRUE;
01359                         }
01360                     }
01361                 }
01362                 
01363                 if (merge)
01364                 {
01365                     //TRACE( _T("merged slices\n"));
01366                     // remove the test slice
01367                     // it has been absorbed
01368                     pTestSlice->deleteme = TRUE;
01369                 }
01370             }
01371         }
01372     }
01373 
01374     // delete marked slices
01375     ToDo = pMosaicList->GetHeadPosition();
01376 
01377     // Remove any slices marked for deletion
01378     // since they have been merged with another slice
01379     while (ToDo)
01380     {
01381         POSITION Test = ToDo;
01382         CSlice * pTestSlice = pMosaicList->GetNext(ToDo);
01383         if (pTestSlice->deleteme)
01384         {
01385             pMosaicList->RemoveAt(Test);
01386             delete pTestSlice;
01387         }
01388     }
01389 
01390 
01391 
01392     // sort the Slices into order top left to bottom right
01393 
01394     ToDo = pMosaicList->GetHeadPosition();
01395 
01396     // TopPosition == ToDo-1 marks the start of the unsorted mosaic list
01397     while (ToDo)
01398     {
01399         POSITION TopPosition = ToDo;
01400         CSlice * pTopSlice = pMosaicList->GetNext(ToDo);
01401         POSITION Test = ToDo;
01402 
01403 
01404         // LastTest == Test-1 marks the iteration through the unsorted mosaic list
01405         while (Test)
01406         {
01407             POSITION LastTest = Test;
01408             CSlice * pTestSlice = pMosaicList->GetNext(Test);
01409             
01410             // swap the two entries to sort them
01411             // ordering on the position of the top corner first
01412             // then if these are equal which is left most goes first
01413             if (pTestSlice->top < pTopSlice->top || 
01414             (pTestSlice->top == pTopSlice->top && pTestSlice->left < pTopSlice->left) )
01415             {
01416                 // swap the order of these two slices in the mosaic list
01417                 pMosaicList->SetAt(LastTest, pTopSlice);
01418                 pMosaicList->SetAt(TopPosition, pTestSlice);
01419 
01420                 // change what the top slice is for future compares
01421                 // during the lifetime of pTopSlice
01422                 pTopSlice = pTestSlice;
01423             }
01424         }
01425     }
01426 
01427     /*** WARNING *** Use of INT32_MIN assumes that the Slice rects and the DocRect/Spread coords
01428                      that defined them are in the range of a INT32.
01429                      This is a pretty safe asumption though */
01430     
01431     // set the row position
01432     INT32 LowestUnSetRow = INT32_MIN+1, LastLowestUnSetRow = INT32_MIN+1;
01433     INT32 RowHeight = 0;
01434     INT32 RowNumber = 1;
01435     while (LowestUnSetRow != INT32_MIN) 
01436     {
01437         // find the lowest unset row
01438         LowestUnSetRow = INT32_MIN;
01439         POSITION Test = pMosaicList->GetHeadPosition();
01440         while (Test)
01441             {
01442                 CSlice * pTestSlice = pMosaicList->GetNext(Test);
01443                 if (pTestSlice->row == -1 &&
01444                     (LowestUnSetRow == INT32_MIN || pTestSlice->top < LowestUnSetRow )
01445                     )
01446                 {
01447                     LowestUnSetRow = pTestSlice->top;
01448                 }
01449             }
01450 
01451         // calc the row height
01452         RowHeight = LowestUnSetRow - LastLowestUnSetRow;
01453         LastLowestUnSetRow = LowestUnSetRow;
01454 
01455         // set the lowest rows
01456         Test = pMosaicList->GetHeadPosition();
01457         while (Test)
01458             {
01459                 CSlice * pTestSlice = pMosaicList->GetNext(Test);
01460 
01461                 // set the row number if it hasn't been set and it is the lowest
01462                 if (pTestSlice->row == -1 && pTestSlice->top == LowestUnSetRow )
01463                 {
01464                     pTestSlice->row = RowNumber;
01465                     pTestSlice->rowheight = RowHeight;
01466                 }
01467 
01468                 // calculate the rows used by this slice
01469                 if (pTestSlice->top < LowestUnSetRow && pTestSlice->bottom > LowestUnSetRow /*&& pTestSlice->row != -1*/)
01470                 {
01471                     pTestSlice->rowspan++;
01472                 }
01473             }
01474         RowNumber ++;
01475     }
01476 
01477 
01478     // set the colm position    
01479     INT32 LowestUnSetColm = INT32_MIN + 1, LastLowestUnSetColm = Bounds.lox;
01480     INT32 ColmWidth = 0;
01481     INT32 ColmNumber = 1;
01482     while (LowestUnSetColm != INT32_MIN)
01483     {
01484         LowestUnSetColm = INT32_MIN;
01485         POSITION Test = pMosaicList->GetHeadPosition();
01486 
01487         // find the least left most point that doesn't have a set colm
01488         while (Test)
01489             {
01490                 CSlice * pTestSlice = pMosaicList->GetNext(Test);
01491                 if (pTestSlice->colm == -1 &&
01492                     (LowestUnSetColm == INT32_MIN || pTestSlice->left < LowestUnSetColm )
01493                     )
01494                 {
01495                     LowestUnSetColm = pTestSlice->left;
01496                 }
01497             }
01498 
01499         // calc the colm widths
01500         // extra bit of fiddling to get the last width by using the 
01501         // image bounding rect
01502         if (LowestUnSetColm != INT32_MIN)
01503             ColmWidth = (LowestUnSetColm - LastLowestUnSetColm);
01504         else
01505             ColmWidth = Bounds.hix - LastLowestUnSetColm;
01506 
01507         LastLowestUnSetColm = LowestUnSetColm;
01508 
01509         // Set the colm numbers
01510         Test = pMosaicList->GetHeadPosition();
01511         while (Test)
01512             {
01513                 CSlice * pTestSlice = pMosaicList->GetNext(Test);
01514 
01515                 // set the colm number if it hasn't been set and it is the lowest
01516                 if (pTestSlice->colm == -1 && pTestSlice->left == LowestUnSetColm )
01517                 {
01518                     pTestSlice->colm = ColmNumber;
01519                     pTestSlice->colmwidth = ColmWidth;
01520                     
01521                     // set the slice name if it doesn't have one
01522                     String_256 temp = "";
01523                     temp.MakeMsg(_R(IDS_SLICENAME), pTestSlice->row, pTestSlice->colm);
01524                     if (pTestSlice->name.IsEmpty())
01525                         pTestSlice->name = temp;
01526                 }
01527                 
01528                 // calculate the colms used by this slice
01529                 if (pTestSlice->left < LowestUnSetColm && pTestSlice->right > LowestUnSetColm /*&& pTestSlice->colm != -1*/)
01530                 {
01531                     pTestSlice->colmspan++;
01532                 }
01533             }
01534         ColmNumber ++;
01535     }
01536 
01537     
01538     // go from Slice Co-ords back to spread co-ords
01539     // so we can happily use a standard co-ord system again other places in Camelot
01540     m_NumberOfButtons = 0;
01541     ToDo = pMosaicList->GetHeadPosition();
01542     while (ToDo)
01543     {
01544         CSlice * pTestSlice = pMosaicList->GetNext(ToDo);
01545         pTestSlice->SwapSpreadAndSliceCoords();
01546 
01547         // and while we are here set the button number
01548         if (pTestSlice->IsNamedSlice)
01549         {
01550             m_NumberOfButtons++;
01551             pTestSlice->ButtonNumber = m_NumberOfButtons;
01552         }
01553     }
01554 
01555     return TRUE;
01556 }
01557 
01558 // search the list of slices for the button numbered buttonno and return a ptr to it
01559 CSlice * OpSlice::GetButtonNumber (CList <CSlice *, CSlice *> * pMosaicList, INT32 buttonno)
01560 {
01561     POSITION ToDo = pMosaicList->GetHeadPosition();
01562     while (ToDo)
01563     {
01564         CSlice * pTestSlice = pMosaicList->GetNext(ToDo);
01565 
01566         // and while we are here set the button number
01567         if (pTestSlice->IsNamedSlice && pTestSlice->ButtonNumber == buttonno)
01568         {
01569             return pTestSlice;
01570         }
01571     }
01572 
01573     return NULL;
01574 }
01575 
01576 /********************************************************************************************
01577 
01578 >BOOL OpSlice::ExportSliceGraphic(CSlice * pSlice)
01579 
01580     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
01581     Created:    26/7/99
01582     Purpose:    Generates a graphic of a section of the whole image defined by the
01583                 rectangular area of the slice.
01584     Params:     pSlice - the slice to export contains area rect and name
01585     Returns:    FALSE if some error occured
01586 
01587 ********************************************************************************************/
01588 BOOL OpSlice::ExportSliceGraphic(CSlice * pSlice, BitmapExportOptions * pExportOptions, const String_256 & GraphicFileName)
01589 {
01590     // This is the clip rect that is required to be in spread co-ords
01591     DocRect r(pSlice->left, pSlice->top, pSlice->right, pSlice->bottom);
01592 
01593     // Get the export filter for this slice if
01594     // it is a named slice and has been exported before in which case get
01595     // its type and its exportoptions (if the user wishes to use them)
01596     // and use those instead
01597     BitmapExportOptions * pOverRideExportOptions = pExportOptions;
01598     SGNameItem* pItem = SliceHelper::LookupNameGalleryItem(pSlice->name);
01599     if (!pItem && pSlice->IsNamedSlice)
01600     {
01601         // someone may have mundged the slice name due to javascript and filename requirements
01602         // will have to mundge each gallery name in turn since we didn't find a direct match
01603         NameGallery * pNameGallery = NameGallery::Instance();
01604         SGUsedNames* pNames = pNameGallery ? pNameGallery->GetUsedNames() : NULL;
01605         pItem = pNames ? (SGNameItem*) pNames->GetChild() : NULL;
01606 
01607         BOOL Found = FALSE;
01608 
01609         String_256 str;
01610 
01611         // check all the name gallery items
01612         while (pItem && !Found)
01613         {
01614             pItem->GetNameText(&str);
01615 
01616             // do the mundge
01617             RemoveIlligalFileAndJavaChars(str);
01618 
01619             // if the name matches its your man
01620             if (pSlice->name.CompareTo(str) == 0)
01621                 Found = TRUE;
01622             else
01623                 // no then try the next one?
01624                 pItem = (SGNameItem *) pItem->GetNext();
01625         }
01626     }
01627 
01628     if (pItem)
01629     {
01630         NodeSetProperty* pPropNode = pItem->GetPropertyNode();
01631         if (pPropNode)
01632         {
01633             NamedExportProp * pProp = (NamedExportProp*) pPropNode->GetProperty(NamedExportProp::nIndex);
01634             if (pProp && pProp->GetOptions() && !pProp->IsVirgin())
01635             {   // update the slice to use this name and export type
01636                 pOverRideExportOptions = pProp->GetOptions();
01637 
01638                 //PathName TempPath = pOverRideExportOptions->GetPathName();
01639                 //pSlice->FileTypeExtStr = TempPath.GetType();
01640 
01641                 // have to use the ptr class type on the options to work out which filter to use (not very good really)
01642                 if (IS_A(pOverRideExportOptions, JPEGExportOptions))
01643                 {
01644                     pSlice->FileTypeExtStr = "jpg";
01645                 }
01646                 else if (IS_A(pOverRideExportOptions, BMPExportOptions))
01647                 {
01648                     pSlice->FileTypeExtStr = "bmp";
01649                 }
01650                 else if (IS_A(pOverRideExportOptions, PNGExportOptions))
01651                 {
01652                     pSlice->FileTypeExtStr = "png";
01653                 }
01654                 else if (IS_A(pOverRideExportOptions, GIFExportOptions))
01655                 {
01656                     pSlice->FileTypeExtStr = "gif";
01657                 }
01658                 else // not a type we can deal with from here
01659                     pOverRideExportOptions = pExportOptions;
01660             }
01661         }
01662     }
01663 
01664     // set up the path of where to save it
01665     PathName Path = m_PathName;
01666     Path.SetFileName(GraphicFileName);
01667     Path.SetType(pSlice->FileTypeExtStr);
01668 
01669     // use screen AA for all image slicing
01670     pOverRideExportOptions->SetAntiAliasing(MAINTAIN_SCREEN_AA);
01671 
01672     // since we have been messing around with the rect to export and the layers we
01673     // should assume that the palette we hold is no longer valid
01674     pOverRideExportOptions->BitmapSourceHasChanged();
01675 
01676     CCDiskFile File;
01677     if(!File.open(Path.GetPath(), ios::in | ios::out | ios::binary))
01678         return FALSE;       // error!
01679 
01680     // have to use the ptr class type on the options to work out which filter to use (not very good really)
01681     if (IS_A(pOverRideExportOptions, JPEGExportOptions))
01682     {
01683         JPEGExportFilter ExportFilter;
01684         ExportFilter.DoExportWithOptions(this, &File, &Path, 
01685                                         Document::GetCurrent(),
01686                                         (JPEGExportOptions*) pOverRideExportOptions, &r);
01687     }
01688     else if (IS_A(pOverRideExportOptions, BMPExportOptions))
01689     {
01690         BMPFilter ExportFilter;
01691         ExportFilter.DoExportWithOptions(this, &File, &Path, 
01692                                         Document::GetCurrent(),
01693                                         (BMPExportOptions*) pOverRideExportOptions, &r);
01694     }
01695     else if (IS_A(pOverRideExportOptions, PNGExportOptions))
01696     {
01697         PNGFilter ExportFilter;
01698         ExportFilter.DoExportWithOptions(this, &File, &Path, 
01699                                         Document::GetCurrent(),
01700                                         (PNGExportOptions*) pOverRideExportOptions, &r);
01701     }
01702     else if (IS_A(pOverRideExportOptions, GIFExportOptions))
01703     {
01704         TI_GIFFilter ExportFilter;
01705         ExportFilter.DoExportWithOptions(this, &File, &Path, 
01706                                         Document::GetCurrent(),
01707                                         (GIFExportOptions*) pOverRideExportOptions, &r);
01708     }
01709 
01710     File.close();
01711 
01712     // integrate with Dream Weaver by creating design notes for each exported graphic file
01713     if (m_UsesDesignNotes && pExportOptions->GetCanUseDesignNotes())
01714     {
01715         CString DocName(Document::GetCurrent()->GetLocation()); 
01716         DocName += TEXT("\\") + Document::GetCurrent()->GetPathName();
01717 
01718         if (DocName == TEXT("\\"))
01719         {
01720             InformWarning (_R(IDS_NOTES_WARNING));
01721             m_UsesDesignNotes = FALSE;
01722         }
01723         else
01724         {
01725             CString GraphicFile(Path.GetPath());
01726 
01727             // create or modify a .mno forward source file
01728             CreateDesignNoteWithForwardSource(GraphicFile, DocName);
01729         }
01730     }
01731 
01732 
01733     return TRUE;
01734 }
01735 
01736 
01737 /********************************************************************************************
01738 
01739 >   BOOL OpSlice::ExportImageSliceHTML(CList <CSlice *, CSlice *> * pMosaicList, String_256 HTMLFile)
01740 
01741     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
01742     Created:    23/7/99
01743     Purpose:    Creates an HTML file with a table that re-weaves the sliced images back together
01744                 Also if rollovers have been defined they are also incorperated.
01745     Returns:    FALSE if some error occured
01746     SideEffect: On m_UsedShimGraphic to set it correctly - assuming it is FALSE to start with.
01747 
01748 ********************************************************************************************/
01749 BOOL OpSlice::ExportImageSliceHTML(CList <CSlice *, CSlice *> * pMosaicList, const String_256 & HTMLFile, INT32 FileNumber)
01750 {
01751     BOOL InjectFile = m_InjectHTML;
01752 
01753     // varibales used in the inject file and reinject file modes
01754     BYTE * pPreviousHTML = NULL;
01755     DWORD PreviousHTMLSize = 0;
01756     BYTE * pHeadEnd = NULL;
01757     BYTE * pBodyStart = NULL;
01758     BYTE * pBodyStartAbsolute = NULL;
01759     BYTE * pNavDefStart = NULL;
01760     BYTE * pNavDefEnd = NULL;
01761     BYTE * pNavTableStart = NULL;
01762     BYTE * pNavTableEnd = NULL;
01763 
01764     // file doesn't exist? then we cant inject!
01765     CString tempFile(HTMLFile);
01766     if (InjectFile && !FileExists(tempFile))
01767         InjectFile = FALSE;
01768 
01769     if (InjectFile)
01770     {
01771         // read the previous file into memory and identify important locations within it
01772         pPreviousHTML = LoadFileIntoMemory(HTMLFile, PreviousHTMLSize);
01773         if (!pPreviousHTML)
01774             return FALSE;
01775 
01776         // find where the <head> tag finishes
01777         pHeadEnd = FindNextOccuranceOf((BYTE *)&"</head>", pPreviousHTML);
01778         if (!pHeadEnd)
01779             return FALSE;
01780 
01781         // find the navbar definition by looking for the marker comment
01782         // this will be in the header part inside the dummy javascript comment
01783         pNavDefStart = FindNextOccuranceOf((BYTE *)&"<!-- Navbar def -->", pPreviousHTML);
01784         if (pNavDefStart)
01785         {
01786             // find the end of the navbar definition by looking for the marker comment
01787             pNavDefEnd = FindNextOccuranceOf((BYTE *)&"<!-- Navbar def end -->", pNavDefStart);
01788             if (pNavDefEnd)
01789                 pNavDefEnd += 23;
01790         }
01791 
01792         // find where the <body> tag starts & ends
01793         pBodyStartAbsolute = FindNextOccuranceOf((BYTE *)&"<body", pHeadEnd);
01794         if (!pBodyStartAbsolute)
01795             return FALSE;
01796         pBodyStart = FindNextOccuranceOf((BYTE *)&">", pBodyStartAbsolute);
01797         if (!pBodyStart)
01798             return FALSE;
01799 
01800         // the table that holds the navbar is marked by having name tag of "XaraTable"
01801         // find this and the locate the start of the table tag
01802         pNavTableStart = FindNextOccuranceOf((BYTE *)&"name=\"XaraTable", pBodyStart);
01803         if (pNavTableStart)
01804         {
01805             BYTE * pTemp = FindPreviousChar('<', pNavTableStart, pBodyStart);
01806             BYTE * pTemp2 = FindNextOccuranceOf((BYTE *)&"<table", pTemp);
01807 
01808             if (pTemp == pTemp2) // is in start of <table>
01809             {
01810                 pNavTableStart = pTemp;
01811 
01812                 // find the end of the table tag
01813                 pNavTableEnd = FindNextOccuranceOf((BYTE *)&"</table>", pNavTableStart);
01814                 if (pNavTableEnd)
01815                     pNavTableEnd += 8;
01816             }
01817             else
01818                 pNavTableStart = NULL;
01819         }
01820     }
01821 
01822     // injecting HTML where we have injected before?
01823     // ie we have found the markers and can just replace these bits of code
01824     BOOL ReInject = pNavTableEnd ? TRUE : FALSE;
01825 
01826     // open the file to output the HTML
01827     ofstream f(HTMLFile);
01828     if ( !f.is_open() )
01829     {
01830         return FALSE;
01831     }
01832 
01833     POSITION pos = 0;
01834 
01835     if (ReInject)
01836     {
01837         // write the stuff till the start navbar marker
01838         if (pNavDefEnd)
01839             WriteText (f, pPreviousHTML, pNavDefStart - pPreviousHTML);
01840     }
01841     else
01842     {
01843         if (InjectFile)
01844         {
01845             // write everything in the file up to the <\head>
01846             WriteText(f, pPreviousHTML, pHeadEnd - pPreviousHTML);
01847         }
01848         else
01849         {
01850             // export HTML
01851             f << "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 transitional//EN\">\n";
01852             f << "<html>\n<head>\n";
01853             f << "<title>Sliced Image</title>\n";
01854         }
01855     }
01856 
01857     // any javascript images go in here
01858 
01859     if (m_FoundRolloverStates)
01860     {
01861         // add the start java button marker
01862         f << "<!-- Navbar def -->\n";
01863 
01864         f << "<script language=\"JavaScript\">\n";
01865         f << "<!-- Dummy comment to hide code from non-JavaScript browsers.\n\n";
01866         f << "if (document.images) {\n";
01867 
01868         // iterate throught the slices for named slices to add their images to the document
01869         pos = pMosaicList->GetHeadPosition();
01870         while (pos)
01871         {
01872             CSlice * pSlice = pMosaicList->GetNext(pos);
01873 
01874             if (pSlice->IsNamedSlice)
01875             {
01876                 for (INT32 i = 0; i < 3 ; i++) // not including SELECTED
01877                     if (m_RolloverState[i].Exists && pSlice->ExistsOnLayerState[i])
01878                     {
01879                         f << pSlice->name;
01880                         f << m_RolloverState[i].Name;
01881                         f << " = new Image(); ";
01882                         f << pSlice->name;
01883                         f << m_RolloverState[i].Name;
01884                         f << ".src = \"";
01885                         f << pSlice->name;
01886                         if (i > 0 && m_RolloverState[i].Exists)
01887                             f << m_RolloverState[i].Name;
01888 
01889                         f << "." << pSlice->FileTypeExtStr;
01890                         f << "\"\n";
01891                     }
01892             }
01893         }
01894         f << "}\n\n";
01895 
01896         // set up the list of graphics
01897         for (INT32 n = 0; n < 3; n++) // not including selected
01898             if (m_RolloverState[n].Exists)
01899             {
01900                 f << "function turn" << m_RolloverState[n].Name;
01901                 f << "(ImageName) {\n";
01902                 f << "\tif (document.images != null) {\n";
01903                 f << "\t\tdocument[ImageName].src = eval(ImageName + \"";
01904                 f << m_RolloverState[n].Name;
01905                 f << ".src\");\n\t}\n";
01906                 //if (n == CLICKED)
01907                 //  f << "return true;\n";
01908                     
01909                 f << "}\n\n";
01910             }
01911 
01912         f << "// End of dummy comment -->\n";
01913         f << "</script>\n";
01914         // mark the end of the java script buttons def
01915         f << "<!-- Navbar def end -->\n";
01916 
01917     } // end of m_FoundRolloverStates - adding rollover start javascript
01918 
01919 
01920     if (ReInject)
01921     {
01922             // write the stuff between the end of the navr bar def and
01923             // the begining of the table
01924         if (pNavDefEnd)
01925             WriteText(f, pNavDefEnd, pNavTableStart - pNavDefEnd);
01926         else
01927             // write the stuff from the begining of the old file to the table start marker
01928             WriteText(f, pPreviousHTML, pNavTableStart - pPreviousHTML);
01929     }
01930     else
01931     {
01932 
01933         f << "</head>\n\n";
01934 
01935         if (InjectFile)
01936         {
01937             // recover the exisitng body tag
01938             WriteText(f, pBodyStartAbsolute, pBodyStart - pBodyStartAbsolute + 1);
01939         }
01940         else
01941         {
01942             // set body tag something like this
01943             f << "<body bgcolor=\"";
01944 
01945             char col[8];
01946             wsprintf(col, "#%02x%02x%02x", (BYTE) m_lRed, (BYTE) m_lGreen, (BYTE) m_lBlue);
01947             f << col;
01948 
01949             f << "\" text=\"";
01950 
01951             // sort out the text colour
01952             if (m_lRed + m_lGreen + m_lBlue < 300)
01953                 f << "white";
01954             else
01955                 f << "black";
01956                 
01957             // set the rest of the body tag
01958             f << "\" link=\"red\" vlink=\"blue\" alink=\"yellow\">\n";
01959         }
01960     }
01961 
01962     // Sliced images are set into a table
01963     f << "<table name=\"XaraTable\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n\n";
01964 
01965     BOOL RequireEndOfRowShims = FALSE;
01966     BOOL RequireShimRow = FALSE;
01967     pos = pMosaicList->GetHeadPosition();
01968     while (pos)
01969     {
01970         CSlice * pSlice = pMosaicList->GetNext(pos);
01971         if (pSlice->rowspan > 1)
01972             RequireEndOfRowShims = TRUE;
01973         if (pSlice->colmspan > 1)
01974             RequireShimRow = TRUE;
01975     }
01976 
01977     // add a shim row if there is any colm spanning
01978     if (RequireShimRow)
01979     {
01980         BOOL AddedShimRow = FALSE;
01981         pos = pMosaicList->GetHeadPosition();
01982         INT32 shimcolm = 2; // they are all out of sinc by one so start at 2!?!
01983                             // never mind they only have to be (nearly) all there and in order
01984         while (pos)
01985         {
01986             CSlice * pSlice = pMosaicList->GetNext(pos);
01987 
01988             if (pSlice->colm == shimcolm)
01989             {
01990                 // add the shim row if required and we found something to put in it
01991                 if (!AddedShimRow)
01992                 {
01993                     f << "<!-- shim row--><tr>";
01994                     AddedShimRow = TRUE;
01995                 }
01996 
01997                 // output the HTML for the shim
01998                 f << "<td><img src=\"shim.gif\" width=\"" << pSlice->colmwidth/750 << "\" height=\"1\" border=\"0\"></td>\n";
01999                 shimcolm++;
02000                 m_UsedShimGraphic = TRUE;
02001                 // start looking for the next colm width from the begining of the list
02002                 // since the x co-ord is not ordered directly through the list
02003                 pos = pMosaicList->GetHeadPosition();
02004             }
02005         }
02006 
02007         // if we started the row - end it here
02008         if (AddedShimRow)
02009         {
02010             // add the last tag (unknown width, but then we dont need to know this width
02011             // just fill the cell in with a shim
02012             f << "<td><img src=\"shim.gif\"";
02013             if (RequireEndOfRowShims) // if we have end of row shims expand this shim into the top corner with a colm span of 2
02014                 f << " colspan=\"2\"";
02015             f << " height=\"1\" border=\"0\"></td>\n</tr>\n\n";
02016         }
02017     }
02018 
02019     // loop round all entries in the list
02020     pos = pMosaicList->GetHeadPosition();
02021     
02022     INT32 CurrentRow = 0;
02023 
02024     while (pos)
02025     {
02026         CSlice * pSlice = pMosaicList->GetNext(pos);
02027         
02028         if (pSlice->row > CurrentRow)
02029         {
02030             // finish the last row off
02031             if (CurrentRow > 0)
02032             {
02033                 // add a shim for the row height
02034                 if (RequireEndOfRowShims)
02035                 {
02036                     f << "<td><img src=\"shim.gif\" width=\"1\" height=\"" << pSlice->rowheight/750 << "\" border=\"0\"></td>";
02037                     m_UsedShimGraphic = TRUE;
02038                 }
02039 
02040                 // finish off the row
02041                 f << "</tr>\n\n";
02042             }
02043                 
02044             CurrentRow = pSlice->row;
02045             // start a new row
02046             f << "<!-- Row " << CurrentRow << " --><tr>\n";
02047         }
02048 
02049         // add the table entry for this slice
02050         // open the table data entry
02051         f << "<td";
02052         
02053         // add spanning data
02054         if (pSlice->rowspan > 1)
02055             {
02056             f << " rowspan=\"" << pSlice->rowspan << "\"";
02057             }
02058         
02059         if (pSlice->colmspan > 1)
02060             {
02061             f << " colspan=\"" << pSlice->colmspan << "\"";
02062             }
02063         // end the table definition start entry
02064         f << ">";
02065 
02066         // debug data
02067         //f << "<!-- ";
02068         //f << "(" << pSlice->top << "," << pSlice->left << "),(" << pSlice->bottom << "," << pSlice->right << ") ";
02069         //f << " row " << pSlice->row << " colm " << pSlice->colm << " ";
02070         //f << " --> ";
02071 
02072         // so we know when to close it
02073         BOOL AddedAnchor = FALSE;
02074         
02075         // Add the anchor data if this is a rollover
02076         // and it is not the selected state button
02077         if ( (m_FoundRolloverStates || pSlice->HasURL)
02078             && pSlice->IsNamedSlice 
02079             && (FileNumber != pSlice->ButtonNumber || !m_RolloverState[SELECTED].Exists))
02080         {
02081             //<a href="Index.htm" onmouseover="turnmouse('general_info')" onmouseout="turnoff('general_info')" onclick="turnon('general_info')" >
02082             f << "<a href = \"";
02083             AddedAnchor = TRUE;
02084 
02085             // link in destination of the link]
02086             if (m_pLinkName && pSlice->ButtonNumber > 0 && (pSlice->HasURL || pSlice->ExistsOnLayerState[SELECTED]))
02087             {
02088                 f << m_pLinkName[pSlice->ButtonNumber - 1];
02089                 f << "\"";
02090 
02091                 if (pSlice->pFrameText && *(pSlice->pFrameText))
02092                 {
02093                     f << " TARGET=\"";
02094                     f << pSlice->pFrameText;
02095                     f << "\"";
02096                 }
02097             }
02098             else
02099             {
02100                 f << m_PathName.GetFileName(FALSE); // just the name stem of the HTML file please
02101                 f << ".";
02102                 f << m_HTMLext;
02103                 f << "\"";
02104             }
02105 
02106             if (m_FoundRolloverStates)
02107             {
02108                 if (m_RolloverState[MOUSE].Exists && pSlice->ExistsOnLayerState[MOUSE])
02109                 {
02110                     // add mouse state
02111                     f << " onmouseover=\"turn";
02112                     f << m_RolloverState[MOUSE].Name;
02113                     f << "('";
02114                     f << pSlice->name;
02115                     f << "')\"";
02116                 }
02117 
02118                 if (pSlice->ExistsOnLayerState[DEFAULT])
02119                 {
02120                     // add default state state
02121                     f << " onmouseout=\"turn";
02122                     f << m_RolloverState[DEFAULT].Name;
02123                     f << "('";
02124                     f << pSlice->name;
02125                     f << "')\"";
02126                 }
02127 
02128                 if (m_RolloverState[CLICKED].Exists && pSlice->ExistsOnLayerState[CLICKED])
02129                 {
02130                     // add click state
02131                     f << " onmousedown=\"turn";
02132                     f << m_RolloverState[CLICKED].Name;
02133                     f << "('";
02134                     f << pSlice->name;
02135                     f << "')\"";
02136                 }
02137             }
02138 
02139             f << ">";
02140         }
02141 
02142         // add the slice image
02143         f << "<img name=\"";
02144         f << pSlice->name;
02145         f << "\" src=\"";
02146             
02147         if (!pSlice->IsEmpty)
02148         {   
02149             f << pSlice->name;
02150 
02151             // if this is the selected page and the selected button
02152             // show the selected graphic not the default one
02153             // by adding the word "selected" after the name
02154             if (FileNumber == pSlice->ButtonNumber && m_RolloverState[SELECTED].Exists && pSlice->ExistsOnLayerState[SELECTED])
02155                 f << m_RolloverState[SELECTED].Name;
02156 
02157             f << "." + pSlice->FileTypeExtStr;
02158         }
02159         else // it was just blank anyway so use the shim instead
02160         {
02161             f << "shim.gif";
02162             m_UsedShimGraphic = TRUE;
02163         }
02164 
02165         f << "\"";
02166 
02167         // add alternative text
02168         if (pSlice->IsNamedSlice)
02169         {
02170             f << " alt=\"";
02171             f << TurnUnderScoreIntoSpace(pSlice->name);
02172             f << "\"";
02173         }
02174 
02175         // use the matrix to work out the pixel values of height and width
02176         Matrix Identity;
02177         DocRect r(pSlice->left, pSlice->top, pSlice->right, pSlice->bottom);
02178         WinRect Rect = OSRenderRegion::BitmapDocRectToWin( Identity, r, 96.0 );
02179 
02180         // bitmap width
02181         f << " width=\"" << Rect.right - Rect.left <<"\"";
02182         
02183         // bitmap height
02184         f << " height=\"" << Rect.bottom - Rect.top <<"\"";
02185         
02186         // finish the image tag
02187         f << " border=\"0\">";
02188         
02189         // chose the anchor tag if this is a rollover
02190         if (AddedAnchor)
02191         {
02192             f << "</a>";
02193         }
02194 
02195         // close the table definition entery
02196         f << "</td>\n";
02197     }
02198 
02199     // add a shim to the end of the last row if needed
02200     if (RequireEndOfRowShims)
02201     {
02202         f << "<td><img src=\"shim.gif\" width=\"1\" border=\"0\"></td>";
02203         m_UsedShimGraphic = TRUE;
02204     }
02205 
02206     // end the last row
02207     f << "</tr>\n";
02208     
02209     // end the table
02210     f << "</table>\n";
02211 
02212     if (ReInject)
02213     {
02214         // copy the data from the end of the table to the end of the file
02215         WriteText(f, pNavTableEnd, PreviousHTMLSize - (pNavTableEnd - pPreviousHTML));
02216     }
02217     else
02218     {
02219         if (InjectFile)
02220         {
02221             // write everything from after the <body> tag onwards
02222             WriteText(f, pBodyStart+1, PreviousHTMLSize - (pBodyStart+1 - pPreviousHTML));
02223         }
02224         else
02225         {
02226             // close the html file
02227             f << "<p>\n\n</body>\n</html>\n";
02228         }
02229     }
02230 
02231     // close the file
02232     f.close();
02233     
02234     // we are done with the old HTML file in memory
02235     if (pPreviousHTML)
02236         delete [] pPreviousHTML;
02237 
02238     return TRUE;
02239 }
02240 
02241 /********************************************************************************************
02242 
02243 >   void OpSlice::PixelAlignedInflate(DocRect * r)
02244 
02245     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
02246     Created:    27/7/99
02247     Purpose:    Infates a DocRect to the nearest pixel aligned boundary
02248 
02249 ********************************************************************************************/
02250 void OpSlice::PixelAlignedInflate(DocRect * r)
02251 {
02252     INT32 lox, loy, hix, hiy = 0;
02253     
02254     lox = ((r->lox)/750) * 750; // likely round down
02255     loy = ((r->loy)/750) * 750;
02256     hix = ((r->hix + 749)/750) * 750; // likely round up
02257     hiy = ((r->hiy + 749)/750) * 750;
02258 
02259     DocRect newr(lox, loy, hix, hiy);
02260     *r = newr;
02261 }
02262 
02263 
02264 /********************************************************************************************
02265 
02266 >   BOOL OpSlice::SaveFileDlg()
02267 
02268     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
02269     Created:    30/7/99
02270     Purpose:    Brings up the save dlg to ask the user where to save the html
02271                 and the slices too. Also has the filter selection to choose from
02272                 when picking the default slice.
02273                 Sets the path location, name and graphic type into the variable
02274                 m_PathName
02275     Returns:    TRUE if the user clicks save, FALSE otherwise
02276 
02277 ********************************************************************************************/
02278 BOOL OpSlice::SaveFileDlg()
02279 {
02280     // Set up the dialog
02281 
02282     // list of filters available is a cut down version of the filter list
02283     // offering just the bitmap versions
02284     String_256 FilterString(_R(IDS_SLICE_USABLE_FILTERS));
02285 
02286     // Get the filename.
02287     String_256 Str("untitled.htm");
02288 
02289     // Build a pathname out of it
02290     PathName Path(Str);
02291 
02292     // Get some details, ready for the dialog
02293     String_256 LocString = Path.GetLocation(FALSE);
02294     String_256 NameString = Path.GetFileName();
02295 
02296     // create a dialog and use the path and name of the file if available, or
02297     // use the default path if not.
02298     String_256 DocName = Document::GetCurrent()->GetDocName();
02299 
02300     // Sorry about the INT32 names, but we are into OS Specific scary stuff here
02301     // Under Windows 95 the OnFileNameOK() function of CFileDialog does not work
02302     // As a Result we have to do the tests ourselves afterwards under win95
02303     // by default we do not need to put the dialog up
02304     BOOL WeNeedToPutSaveAsDialogUpAgain = FALSE;
02305     
02306     // try the dialog
02307     do
02308     {
02309         // Default to only putting the dialog up the once.
02310         WeNeedToPutSaveAsDialogUpAgain = FALSE;
02311 
02312         // Create and display prepare the dialog
02313         SliceSaveFileDlg /*SaveFileDialog*/ SaveDialog(FilterString, LocString, NameString, DocName);
02314         SaveDialog.PrepareDialog();
02315         CString temp;
02316         
02317         temp.LoadString(_R(IDS_SLICE_EXPORT_TITLE));
02318         SaveDialog.m_ofn.lpstrTitle = temp;
02319 
02320         // Display the dialog
02321         BOOL Result = SaveDialog.OpenAndGetFileName();
02322         m_InjectHTML = SaveDialog.m_Inject; // did we ask to inject the HTML?
02323 
02324         // If they did not click on OK then stop right now
02325         if (!Result)
02326             return FALSE;
02327 
02328         // Make sure that the file name is OK
02329         // we only need to do this under windows 95, as other OS's will have already done it
02330         // Disable for VC4.0/MFC 4.0 as they have fixed it.
02331     #if _MFC_VER < 0x400
02332         if (IsWin32c())
02333         {   
02334             //TRACE( _T("Windows 95, testing for same file name after the event\n"));
02335             if (!SaveDialog.IsValidFilename()) WeNeedToPutSaveAsDialogUpAgain = TRUE;
02336         }
02337     #endif
02338 
02339         // Get the filename.
02340         CString TempName(SaveDialog.m_ofn.lpstrFile);
02341         SaveDialog.AppendExtension(&TempName);
02342         Str = String_256(TempName);
02343         Path = PathName(Str);
02344 
02345         // read the filter type to use
02346         // if the user hasn't picked (or typed) one of this list
02347         // then make it a gif.
02348         // Otherwise set the Path Type to store the default type for each slice made
02349         if (Path.GetType() != "jpg" && Path.GetType() != "bmp" && Path.GetType() != "gif" && Path.GetType() != "png")
02350             switch(SaveDialog.GetSelectedFilterIndex())
02351             {
02352             default:
02353             case 1:
02354                 Path.SetType("gif");
02355                 break;
02356             case 2:
02357                 Path.SetType("jpg");
02358                 break;
02359             case 3:
02360                 Path.SetType("bmp");
02361                 break;
02362             case 4:
02363                 Path.SetType("png");
02364                 break;
02365             }
02366 
02367         // Extract directory name (minus terminating backslash) and remember for next time.
02368         SaveDialog.SetDefaultPath(Path.GetLocation(FALSE));
02369 
02370     } while(WeNeedToPutSaveAsDialogUpAgain);
02371 
02372     // Put the file name into the var set aside for it
02373     m_PathName = Path;
02374 
02375     return TRUE;
02376 }
02377 
02378 /********************************************************************************************
02379 
02380 >   BOOL OpSlice::ScanForRolloverStates()
02381 
02382     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
02383     Created:    5/8/99
02384     Purpose:    Sets the m_RolloverState member variable by scanning the layers
02385                 and finding out what specail named layers exist for the creation
02386                 of rollovers.
02387     Returns:    TRUE if enough layers were defined to make a rollover
02388                 FALSE otherwise
02389 ********************************************************************************************/
02390 BOOL OpSlice::ScanForRolloverStates(CList <CSlice *, CSlice *> * pMosaicList)
02391 {
02392     INT32 i = 0;
02393     for (i = 0; i < 4; i++)
02394     {
02395         m_RolloverState[i].Exists = FALSE;
02396         m_RolloverState[i].pLayer = NULL;
02397         m_RolloverState[i].WasVisibleToStartWith = FALSE;
02398     }
02399 
02400     m_RolloverState[DEFAULT].Name.Load(_R(IDS_ROLLOVER_DEFAULT)); // = "Default";
02401     m_RolloverState[MOUSE].Name.Load(_R(IDS_ROLLOVER_MOUSE)); // = "Mouse";
02402     m_RolloverState[CLICKED].Name.Load(_R(IDS_ROLLOVER_CLICKED)); // = "Clicked";
02403     m_RolloverState[SELECTED].Name.Load(_R(IDS_ROLLOVER_SELECTED)); // = "Selected";
02404 
02405     Spread* pSelSpread = Document::GetSelectedSpread();
02406     if (pSelSpread == NULL)
02407         return FALSE;
02408 
02409     Layer * pLayer = pSelSpread->FindFirstLayer();
02410     while (pLayer)
02411     {
02412         for (i = 0; i < 4 ; i++)
02413         {
02414             if (pLayer->GetLayerID().CompareTo(m_RolloverState[i].Name) == 0)
02415             {
02416                 m_RolloverState[i].pLayer = pLayer;
02417                 m_RolloverState[i].WasVisibleToStartWith = pLayer->IsVisible();
02418 
02419                 // does this layer exist within the mosaic list?
02420                 m_RolloverState[i].Exists = FALSE;
02421 
02422                 // find a wix marker on this layer
02423                 Node * pNode = SliceHelper::FindNextOfClass(pLayer, pLayer, CC_RUNTIME_CLASS(TemplateAttribute) );
02424 
02425                 while (pNode/* && !m_RolloverState[i].Exists*/)
02426                 {
02427                     POSITION EachSlice = pMosaicList->GetHeadPosition();
02428 
02429                     // having found a marker does it match with any of the slices in the mosaic list?
02430                     while (EachSlice)
02431                     {
02432                         CSlice * pSlice = pMosaicList->GetNext(EachSlice);
02433                         if (pSlice->IsNamedSlice && pSlice->name.CompareTo(((TemplateAttribute *)pNode)->GetParam(), FALSE) == 0)
02434                         {
02435                             m_RolloverState[i].Exists = TRUE; // if it does than we need to export this state
02436                             pSlice->ExistsOnLayerState[i] = 1; // this slice exists on this state
02437                         }
02438                     }
02439 
02440                     pNode = SliceHelper::FindNextOfClass(pNode, pLayer, CC_RUNTIME_CLASS(TemplateAttribute) );
02441                 }
02442             }
02443         }
02444 
02445         pLayer = pLayer->FindNextLayer();
02446     }
02447 
02448     return (m_RolloverState[DEFAULT].Exists && 
02449             (m_RolloverState[MOUSE].Exists || m_RolloverState[CLICKED].Exists || m_RolloverState[SELECTED].Exists ));
02450     
02451 }
02452 
02453 
02454 /********************************************************************************************
02455 
02456 >   BOOL OpSlice::ExportRollOverSlice(CSlice * pSlice, BitmapExportOptions * pExportOptions)
02457 
02458     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
02459     Created:    5/8/99
02460     Purpose:    Exports all the rollover states of this given slice if they are defined.
02461     Returns:    FALSE if any of the exports failled
02462 ********************************************************************************************/
02463 BOOL OpSlice::ExportRollOverSlice(CSlice * pSlice, BitmapExportOptions * pExportOptions)
02464 {
02465     BOOL ok = TRUE;
02466 
02467     for (INT32 i = 0 ; ok && i < 4 ; i++)
02468     {
02469 
02470         if (m_RolloverState[i].Exists && (i == 0 || pSlice->ExistsOnLayerState[i]))
02471         {
02472             // hide other button layers and show this button layer
02473             ShowRolloverLayer(i);
02474             String_256 StateName = pSlice->name;
02475 
02476             if (i > 0)
02477                 StateName += m_RolloverState[i].Name;
02478 
02479             // make sure this named object is fully selected
02480             if (pSlice->IsNamedSlice)
02481             {
02482                 // do this by calling the select scan on it
02483                 SGNameItem* pItem = SliceHelper::LookupNameGalleryItem(pSlice->name);
02484                 if (pItem)
02485                 {
02486                     SelectScan scanner(pItem, SelectScan::SELECT);
02487                     scanner.Scan();
02488                 }
02489             }
02490 
02491             // export the graphic
02492             ok = ExportSliceGraphic(pSlice, pExportOptions, StateName);
02493         }
02494     }
02495 
02496     // restore layers to as they were
02497     ShowRolloverLayer(ORIGINAL_LAYERS);
02498 
02499     return ok;
02500 }
02501 
02502 
02503 /********************************************************************************************
02504 
02505 >   void OpSlice::ShowRolloverLayer(INT32 ShowLayer)
02506 
02507     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
02508     Created:    5/8/99
02509     Purpose:    Shows the layer number passed to it and hides the other of the rollover layers.
02510                 Pass it DEFAULT, MOUSE, CLICKED, SELECTED, ORIGINAL_LAYERS or ALL_LAYERS
02511 
02512 ********************************************************************************************/
02513 void OpSlice::ShowRolloverLayer(INT32 ShowLayer)
02514 {
02515     Spread* pSelSpread = Document::GetSelectedSpread();
02516     if (pSelSpread == NULL)
02517         return;
02518 
02519     Layer * pLayer = pSelSpread->FindFirstLayer();
02520     while (pLayer)
02521     {
02522         INT32 i = 0;
02523         for (i = 0; i < 4 ; i++)
02524         {
02525             if (pLayer->GetLayerID().CompareTo(m_RolloverState[i].Name) == 0)
02526             {
02527                 if (ShowLayer == ORIGINAL_LAYERS /* Restore all layers to starting visibilty*/)
02528                     pLayer->SetVisible(m_RolloverState[i].WasVisibleToStartWith);
02529                 else
02530                 if (ShowLayer == ALL_LAYERS /* show all layers at once */)
02531                     pLayer->SetVisible(TRUE);
02532                 else
02533                 if (i == ShowLayer)
02534                     pLayer->SetVisible(TRUE);
02535                 else
02536                     pLayer->SetVisible(FALSE);
02537             }
02538         }
02539 
02540         pLayer = pLayer->FindNextLayer();
02541     }
02542 }
02543 
02544 
02545 
02546 /********************************************************************************************
02547 
02548 >   void OpSlice::RemoveIlligalFileAndJavaChars(String_256 & Str)
02549 
02550     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
02551     Created:    12/8/99
02552     Purpose:    Replaces any illigal chars in the Str as far as filenames
02553                 and use as javascript variables for use in rollovers 
02554                 is concerned.
02555 
02556 ********************************************************************************************/
02557 void OpSlice::RemoveIlligalFileAndJavaChars(String_256 & Str)
02558 {
02559     INT32 i = 0;
02560 
02561     while (Str[i])
02562     {
02563         char stri = Str[i];
02564 
02565         if ((stri < 'a' || stri > 'z') && (stri < 'A' || stri > 'Z') && (stri < '0' || stri > '9')
02566             && (stri != '#' && stri != '$') )
02567         {
02568             *((TCHAR *) Str +i) = (TCHAR)'_';
02569         }
02570 
02571         i++;
02572     }
02573 }
02574 
02575 String_256 OpSlice::TurnUnderScoreIntoSpace(const String_256 & StartStr)
02576 {
02577     INT32 i = 0;
02578 
02579     String_256 Str = StartStr;
02580 
02581     while (Str[i])
02582     {
02583         char stri = Str[i];
02584 
02585         if (stri == '_')
02586         {
02587             *((TCHAR *) Str +i) = (TCHAR)' ';
02588         }
02589 
02590         i++;
02591     }
02592 
02593     return Str;
02594 }
02595 
02596 /********************************************************************************************
02597 
02598 >   void OpSlice::MarkEmptySlices(CList <CSlice *, CSlice *> * pMosaicList, DocRect &SelRect)
02599 
02600     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
02601     Created:    19/10/99
02602     Purpose:    What it is meant to do is check if the drawing has anything that is
02603                 visible within this slice. So if there is nothing visible don't
02604                 bother generating a graphic for it.
02605                 Any empty slices are set as empty in the list of slices.
02606                 Method used is to render the image to be exported as a 32bit graphic
02607                 and then check the alpha channel for anything non-transparent.
02608     Param       pMoasicList -   List of the slices
02609                 SelRect     -   The rect of the image being exported
02610     Returns     -
02611     Errors      Not putting a graphic into the HTML table may screw up the sizing
02612                 of cells in the table if it was relying on this cell to get the 
02613                 size information. So instead I re-use the shim graphic expanded to
02614                 that size (see the ExportHTML fn).
02615 ********************************************************************************************/
02616 void OpSlice::MarkEmptySlices(CList <CSlice *, CSlice *> * pMosaicList, DocRect &SelRect, BitmapExportOptions * pExportOptions)
02617 {
02618     // get the selection
02619     SelRange Sel(*(GetApplication()->FindSelection()));
02620 
02621     // set the range flags so it includes shadow and bevel manager nodes
02622     RangeControl rg = Sel.GetRangeControlFlags();
02623     rg.PromoteToParent = TRUE;
02624     rg.CrossLayer = TRUE;
02625     Sel.Range::SetRangeControl(rg);
02626     Sel.Update(FALSE);
02627 
02628     BOOL RenderedBmp = FALSE;
02629 
02630     OILBitmap* pOilBmp = NULL;
02631     UINT32 Width = 0;
02632     UINT32 Height = 0;
02633     
02634     POSITION ToDo = pMosaicList->GetHeadPosition();
02635 
02636     while (ToDo)
02637     {
02638         CSlice * pTopSlice = pMosaicList->GetNext(ToDo);
02639 
02640         // we will want to export all named slices
02641         // don't export any none-named slices that are blank
02642         // these are marked as empty
02643         if (!pTopSlice->IsNamedSlice)
02644         {
02645             // create the bmp of the selection if we haven't done so
02646             if (!RenderedBmp)
02647             {
02648                 SelectionState SelState;
02649                 SelState.Record();
02650 
02651                 // no selection implies exporting the lot
02652                 if (Sel.IsEmpty() || (pExportOptions && !pExportOptions->IsBackgroundTransparent()) )
02653                 {
02654                     // select everything
02655                     //NodeRenderableInk::SelectAllInRect(SelRect, Document::GetSelectedSpread());
02656                     // select everything
02657                     DocRect SpreadBounds = BaseBitmapFilter::GetSizeOfDrawing(Document::GetSelectedSpread()); // returns in spread co-ords ignoring silly layers
02658                     NodeRenderableInk::SelectAllInRect(SpreadBounds, Document::GetSelectedSpread());
02659 
02660                     SelRange NewSel(*(GetApplication()->FindSelection()));
02661                     // set the range flags so it includes shadow and bevel manager nodes
02662                     RangeControl rg = NewSel.GetRangeControlFlags();
02663                     rg.PromoteToParent = TRUE;
02664                     rg.CrossLayer = TRUE;
02665                     NewSel.Range::SetRangeControl(rg);
02666                     NewSel.Update(FALSE);
02667 
02668                     // render a bitmap of the entire image being exported (all slices)
02669                     pOilBmp = CBMPBits::RenderSelectionToBMP(&NewSel, 32, TRUE, &SelRect);
02670                 }
02671                 else
02672                 {
02673                     // render a bitmap of the entire image being exported (all slices)
02674                     pOilBmp = CBMPBits::RenderSelectionToBMP(&Sel, 32, TRUE, &SelRect);
02675                 }
02676 
02677                 SelState.Restore();
02678                 
02679                 if (!pOilBmp)
02680                     return;
02681 
02682                 Width = pOilBmp->GetWidth();
02683                 Height = pOilBmp->GetHeight();
02684 
02685                 RenderedBmp = TRUE; // since we only want to do this once!
02686 
02687                 /*
02688                 // add the bitmap to the bitmap list
02689                 KernelBitmap* PreConvOffscreenBitmap = new KernelBitmap(pOilBmp,TRUE);
02690                 KernelBitmap* copy1 = DIBUtil::CopyKernelBitmap(PreConvOffscreenBitmap,FALSE);  // FALSE to ensure OIL gets added to globalbmp list
02691                 OILBitmap* pOil1 = (OILBitmap*) copy1->GetActualBitmap();
02692                 pOil1->SetName(String_256("PreConvertedBitmap"));
02693                 copy1->Attach(Document::GetCurrent()->GetBitmapList());
02694                 delete PreConvOffscreenBitmap;
02695                 */
02696             }
02697 
02698             BOOL FoundABit = FALSE;
02699 
02700             // calculate sizes and start positions for the scan
02701 
02702             UINT32 x = (pTopSlice->left - SelRect.lox) * Width / (SelRect.hix - SelRect.lox);
02703             UINT32 y = (pTopSlice->top - SelRect.loy) * Height / (SelRect.hiy - SelRect.loy);
02704 
02705             UINT32 StartX = x;
02706 
02707             UINT32 EndX = min( Width, (pTopSlice->right - SelRect.lox) * Width / (SelRect.hix - SelRect.lox));
02708             UINT32 EndY = min(Height, (pTopSlice->bottom - SelRect.loy) * Height / (SelRect.hiy - SelRect.loy));
02709 
02710             TRACE( _T("marking slice "));
02711             TRACE(pTopSlice->name);
02712             TRACE( _T("\nfrom (%d,%d) to (%d,%d)\n"), x,y, EndX, EndY);
02713             Pixel32bpp Val;
02714 
02715             // scan this slices part of the bitmap
02716             if (pOilBmp)
02717                 while (!FoundABit && y < EndY)
02718                 {
02719                     x = StartX;
02720 
02721                     while (!FoundABit && x < EndX)
02722                     {
02723                         Val = pOilBmp->ReadPixel32bpp(x,y);
02724 
02725                         // check the alpha of each pixel in the 32bit bitmap of the slice
02726                         if (Val.Alpha != 255)
02727                             FoundABit = TRUE;
02728 
02729                         x++;
02730                     }
02731                     y++;
02732                 }
02733 
02734             // mark as empty
02735             if (!FoundABit)
02736             {
02737                 pTopSlice->IsEmpty = TRUE;
02738                 TRACE( _T("Is Empty\n"));
02739             }
02740         }
02741     }
02742 }
02743 
02744 /********************************************************************************************
02745 
02746 >   BOOL OpSlice::URLScan(String_256 * pLinkName, CList <CSlice *, CSlice *> * pMosaicList)
02747 
02748     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
02749     Created:    22/12/99
02750     Purpose:    Scans through the tree looking for URL tags.
02751                 If it finds one it looks for a set name on the same node.
02752                 If it finds a set name it scans the Mosaic list for the button with that set name
02753                 and records the URL as the link name for that button number
02754     Param       pMoasicList -   List of the slices
02755                 pLinkName   -   The dynamic array holding the URLs for each button
02756     Returns     TRUE if it ran ok
02757 ********************************************************************************************/
02758 BOOL OpSlice::URLScan(String_256 * pLinkName, CList <CSlice *, CSlice *> * pMosaicList)
02759 {
02760     Spread* pSpread = Document::GetSelectedSpread();
02761     if (pSpread == NULL || pLinkName == NULL || pMosaicList == NULL)
02762         return FALSE;
02763 
02764     Node * pNode = SliceHelper::FindNextOfClass(pSpread, pSpread, CC_RUNTIME_CLASS(AttrWebAddress));
02765     while (pNode)
02766     {
02767         String_256 URL = ((AttrWebAddress *)pNode)->Value.m_url.GetWebAddress(); // the URL set from the URL dlg
02768         TCHAR* pTargetFrame = ((AttrWebAddress *)pNode)->Value.m_pcFrame; // ptr to the frame string set from the URL dlg
02769 
02770         Node *pWix = pNode->FindParent()->FindFirstChild();
02771         while (pWix)
02772         {
02773             if (pWix->IsAnAttribute() && IS_A(pWix,TemplateAttribute))
02774                 break;
02775             pWix = pWix->FindNext();
02776         }
02777 
02778         if (pWix)
02779         {
02780             POSITION ToDo = pMosaicList->GetHeadPosition();
02781             String_256 ButtonName = ((TemplateAttribute *)pWix)->GetParam();
02782 
02783             // do the mundge
02784             RemoveIlligalFileAndJavaChars(ButtonName);
02785 
02786             while (ToDo)
02787             {
02788                 CSlice * pSlice = pMosaicList->GetNext(ToDo);
02789 
02790                 if (pSlice->IsNamedSlice && pSlice->ButtonNumber > 0 && ButtonName.CompareTo(pSlice->name) == 0)
02791                 {
02792                     // no dot in the URL? Perhaps they mean a file name? Make it URL.htm (or.html) for them
02793                     if (URL.FindNextChar('.') == -1)
02794                     {
02795                         URL += ".";
02796                         URL += m_HTMLext;
02797                     }
02798 
02799                     // set this as the link name
02800                     pLinkName[pSlice->ButtonNumber - 1] = URL;
02801 
02802                     // set the target frame
02803                     pSlice->pFrameText = pTargetFrame;
02804                     pSlice->HasURL = TRUE;
02805 
02806                     ToDo = NULL;
02807                 }
02808             }
02809         }
02810 
02811         pNode = SliceHelper::FindNextOfClass(pNode, pSpread, CC_RUNTIME_CLASS(AttrWebAddress));
02812     }
02813 
02814     return TRUE;
02815 }
02816 
02817 /********************************************************************************************
02818 
02819 >   BYTE * OpSlice::LoadFileIntoMemory(String_256 FileName, DWORD & Size)
02820 
02821     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
02822     Created:    18/2/00
02823     Purpose:    Creates a copy of the file in memory and says how big it is
02824     Param       Filename    -   The file to open
02825                 Size        -   Fills in this param with the size of the memory object created
02826     Returns     a ptr to the memory, or NULL if it failled
02827 ********************************************************************************************/
02828 BYTE * OpSlice::LoadFileIntoMemory(String_256 FileName, DWORD & Size)
02829 {
02830     Size = 0;
02831     CFile file (FileName, CFile::modeRead );
02832     DWORD BytesToRead = file.GetLength();
02833 
02834     if (!BytesToRead)
02835         return NULL;
02836 
02837     BYTE * pBits = new BYTE[BytesToRead + 1];
02838 
02839     if (!pBits)
02840         return NULL;
02841 
02842     Size = file.Read(pBits, BytesToRead) + 1;
02843 
02844     // set the last bit as zero so we can use string functions on the file!
02845     *(pBits + BytesToRead) = 0; 
02846 
02847     return pBits;
02848 }
02849 
02850 /********************************************************************************************
02851 
02852 >   BYTE * OpSlice::FindNextOccuranceOf(BYTE * pSearch, BYTE * pFrom)
02853 
02854     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
02855     Created:    18/2/00
02856     Purpose:    Finds the next occurance of a string in the other large 'string'.
02857                 Pass in lowercase and it will match with uppercase letters
02858     Param       pSearch     -   The shorter string being searched for
02859                 pFrom       -   The larger string to find it in
02860     Returns     a ptr to the memory where the search string was located nearest to the starting point,
02861                 or NULL if it wasn't found.
02862 ********************************************************************************************/
02863 BYTE * OpSlice::FindNextOccuranceOf(BYTE * pSearch, BYTE * pFrom)
02864 {
02865     ASSERT(pFrom);
02866     ASSERT(pSearch);
02867     INT32 i = 0;
02868     while (*pFrom)
02869     {
02870         i = 0;
02871         while (*(pSearch+i) == *(pFrom + i) || *(pSearch+i) == *(pFrom + i) + 32 /*+ 'a' - 'A'*/)
02872         {
02873             i++;
02874             if (*(pSearch + i) == 0)
02875                 return pFrom;
02876         }
02877         pFrom++;
02878     }
02879 
02880     return NULL;
02881 }
02882 
02883 
02884 BYTE * OpSlice::FindPreviousChar(char Search, BYTE * pFrom, BYTE * pLimit)
02885 {
02886     BOOL found = FALSE;
02887     while (pFrom >= pLimit && !found)
02888     {
02889         if ((char)*pFrom == Search)
02890             found = TRUE;
02891         else
02892             pFrom--;
02893     }
02894 
02895     return found ? pFrom : NULL;
02896 }
02897 /********************************************************************************************
02898 
02899 >   void OpSlice::WriteText(ofstream & f, BYTE * pData, INT32 NoOfBytes)
02900 
02901     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
02902     Created:    18/2/00
02903     Purpose:    There appeared to be a slight problem when using the write function to
02904                 output text to the ofstream that contained chars 10 & 13.
02905                 This function neatens this up cutting out 10,13 & 0 and putting a nice \n in 
02906                 the right places.
02907     Param       f           -   The output stream
02908                 pData       -   the string to output
02909                 NoOfBytes   -   Number of bytes to send to the stream
02910     Returns     
02911 ********************************************************************************************/
02912 void OpSlice::WriteText(ofstream & f, BYTE * pData, INT32 NoOfBytes)
02913 {
02914     while (NoOfBytes)
02915     {
02916         INT32 scan = 0;
02917         BYTE * pTemp = pData;
02918         while (NoOfBytes && *pTemp != 10 && *pTemp != 13 && *pTemp != 0)
02919         {
02920             scan++;
02921             pTemp++;
02922             NoOfBytes--;
02923         }
02924 
02925         f.write(pData, scan);
02926         if (*pTemp != 0)
02927             f << "\n";
02928 
02929         pData = pTemp;
02930 
02931         while (NoOfBytes && (*pData == 10 || *pData == 13 || *pData == 0))
02932         {
02933             pData++;
02934             NoOfBytes--;
02935         }
02936     }
02937 }
02938 
02939 /********************************************************************************************
02940 
02941 >   void OpSlice::FailledToExportHTML (const String_256 & file)
02942 
02943     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
02944     Created:    18/2/00
02945     Purpose:    Puts up an error msg saying that it could export the HTML
02946                 and marks it as unexported
02947     Param       file        -   The file it failled to export
02948     Returns     
02949 ********************************************************************************************/
02950 void OpSlice::FailledToExportHTML (const String_256 & file)
02951 {
02952     TCHAR prompt[256];
02953     if (!::LoadString( AfxGetResourceHandle(), _R(IDS_FAILED_EXPORT_HTML), prompt, 256 ) )
02954         camStrcpy( prompt, "%s?" );                             // in case cannot load
02955 
02956     // fill in the %s field with the filename
02957     TCHAR ErrorMsg[512];
02958     wsprintf( ErrorMsg, prompt, (LPCTSTR) file );
02959     Error::SetError( 0, ErrorMsg, 0 );
02960     SetNextMsgHelpContext(_R(IDM_OVERWRITE));
02961     InformLastError();
02962     m_ExportedHTMLOK = FALSE; // since we don't want to ask the user to view it if we didn't export it do we?
02963 }
02964 
02965 /********************************************************************************************
02966 
02967 >   BOOL SliceSaveFileDlg::IsValidFilename()
02968 
02969     Author:     Simon_Knight (Xara Group Ltd) <camelotdev@xara.com>
02970     Created:    18/2/00
02971     Purpose:    override for the virtual function in SaveFileDialog.
02972                 That had a message "file exists : replace or cancel?"
02973                 This extends that to a "file exists : replace, insert or cancel?"
02974                 for the insertion of HTML into existing HTML
02975     Param       
02976     Returns     
02977 ********************************************************************************************/
02978 BOOL SliceSaveFileDlg::IsValidFilename()
02979 {
02980     // Get the pathname
02981     CString FullPath = GetPathName();
02982     AppendExtension(&FullPath);
02983 
02984     // Webster - RanbirR 17/02/97
02985     // Save the file name with our Filter extension, for use in our Message Box.
02986 #ifdef WEBSTER
02987     CString FileName(FullPath);
02988 #endif //webster
02989 
02990     // if doesn't exist then thats fine
02991     if (_taccess( FullPath, 0 )) // requires io.h
02992     {
02993         //  WEBSTER-ranbirr-27/03/97
02994         // Remove the extension from the file. Webster - RanbirR 11\02\97.
02995     #ifdef WEBSTER
02996         RemoveFileExtension(&FileName);
02997     #endif //webster
02998         return TRUE;
02999     }
03000 
03001     // Added for Webster - Ranbir 11\02\97  
03002     // Removes the exstion from a file name.
03003 #ifdef WEBSTER
03004     RemoveFileExtension(&FileName);
03005 #endif //webster
03006 
03007     // Get the filename into a Path object
03008 #ifndef WEBSTER
03009     String_256 KernelFilename(FullPath);
03010     PathName FileMessage(KernelFilename);
03011     KernelFilename =  FileMessage.GetTruncatedPath(50);
03012 #endif //webster
03013     
03014     // Webster - RanbirR 17/02/97 
03015     // Use "FileName", since it contains the Filter extension.
03016 #ifdef WEBSTER
03017     String_256 KernelFilename(FileName);
03018     PathName FileMessage(KernelFilename);
03019     KernelFilename =  FileMessage.GetTruncatedPath(50);
03020 #endif //webster
03021 
03022     const TCHAR* Name;
03023     Name = (TCHAR*)KernelFilename;
03024 
03025     TCHAR prompt[256];
03026     if (!::LoadString( AfxGetResourceHandle(), _R(IDM_OVERWRITE_INJECT), prompt, 256 ) )
03027         camStrcpy( prompt, "%s?" );                             // in case cannot load
03028 
03029     // fill in the %s field with the filename
03030     TCHAR ErrorMsg[512];
03031     wsprintf( ErrorMsg, prompt, (const TCHAR*)Name );
03032     Error::SetError( 0, ErrorMsg, 0 );
03033     SetNextMsgHelpContext(_R(IDM_OVERWRITE_INJECT));
03034 
03035     // then ask the user
03036     ErrorInfo Info;
03037     Info.Button[0] = _R(IDB_OVERWRITE);
03038     Info.Button[1] = _R(IDS_INJECT);
03039     Info.Button[2] = _R(IDS_CANCEL);
03040     
03041     // This makes the cancel button the default one in this situation
03042     // as defaulting to replace is bad.
03043     Info.OK = Info.Cancel = 3;
03044 
03045     switch (AskQuestion( &Info ))
03046     {
03047         // if they cancel, then the name is not acceptable to them
03048         case _R(IDS_CANCEL):
03049             return FALSE;
03050 
03051         case _R(IDS_INJECT):
03052             m_Inject = TRUE;
03053         case _R(IDB_OVERWRITE):
03054         default:
03055             break;
03056     }
03057 
03058     return TRUE;
03059 }
03060 
03061 // shadows are not included in the bounds of the shape
03062 // due to latency in generating the bounds and you may want the entire set of buttons shadowed.
03063 // there are similar problems with bevels.
03064 // so this quick scan gets the "large" size which includes the full bevel and shadow and the
03065 // calling routine can use whichever best suits (sjk 7-4-00)
03066 DocRect OpSlice::ScanLargeSliceBounds(const String_256 & Name)
03067 {
03068     DocRect Ret;
03069     Ret.MakeEmpty();
03070 
03071     // scan each layer
03072     Node * pTop = Document::GetSelectedSpread();
03073     Node * pNode = NULL;
03074     Node * pParent = NULL;
03075 
03076     if (pTop)
03077     {
03078         // scan from the first layer all through the layers since they are brothers of this layer
03079         pNode = SliceHelper::FindNextOfClass(pTop, pTop, CC_RUNTIME_CLASS(TemplateAttribute));
03080 
03081         while (pNode)
03082         {
03083             if (Name.CompareTo(((TemplateAttribute *)pNode)->GetParam()) == 0)
03084             {
03085                 pParent = pNode->FindParent();
03086                 if (pParent->IsBounded())
03087                     Ret = Ret.Union(((NodeRenderableInk *)pParent)->GetBoundingRect(TRUE, FALSE));
03088             }
03089 
03090             pNode = SliceHelper::FindNextOfClass(pNode, pTop, CC_RUNTIME_CLASS(TemplateAttribute));
03091         }
03092     }
03093 
03094     return Ret;
03095 }
03096 
03097 // deflates any text stories in a slice to their visible bounds not the extending metrically worked out bounds
03098 void OpSlice::ScanTextStorySliceBounds(const String_256 & Name, DocRect & Bounds)
03099 {
03100     // scan each layer
03101     Node * pTop = Document::GetSelectedSpread();
03102     Node * pNode = NULL;
03103     Node * pParent = NULL;
03104     BOOL IncludesText = FALSE;
03105     DocRect TextModBounds;
03106 
03107     TextModBounds.MakeEmpty();
03108 
03109     if (pTop)
03110     {
03111         // scan from the first layer all through the layers since they are brothers of this layer
03112         pNode = SliceHelper::FindNextOfClass(pTop, pTop, CC_RUNTIME_CLASS(TemplateAttribute));
03113 
03114         while (pNode)
03115         {
03116             if (Name.CompareTo(((TemplateAttribute *)pNode)->GetParam()) == 0)
03117             {
03118                 pParent = pNode->FindParent();
03119 
03120                 if (IS_A(pParent,TextChar) || IS_A(pParent,TextStory))
03121                 {
03122                     IncludesText= TRUE;
03123 
03124                     // expand the rect by the bounding rect of the text story / text char
03125                     // taking the intersection of the Metric method of size with the Bounding rect render method
03126                     // The metric assures us that the overall bounds of the rect will not be outside the
03127                     // complete scope of the text. The bounding rect method expands for ascenders and descenders
03128                     // only where they appear but may be too large as it includes visible onscreen UI.
03129                     // intersecting these two will easily give the correct answer 99.9% of the time
03130                     // and always a safe answer.
03131                     DocRect Temp = SliceHelper::BoundingNodeSize(pParent);
03132                     Temp = Temp.Intersection(((NodeRenderableInk *)pParent)->GetBoundingRect());
03133                     TextModBounds = TextModBounds.Union(Temp);
03134                 }
03135                 else // union in the usual way
03136                     TextModBounds = TextModBounds.Union(SliceHelper::BoundingNodeSize(pParent));
03137             }
03138 
03139             pNode = SliceHelper::FindNextOfClass(pNode, pTop, CC_RUNTIME_CLASS(TemplateAttribute));
03140         }
03141 
03142         if (IncludesText)
03143             Bounds = TextModBounds;
03144     }
03145 }
03146 

Generated on Sat Nov 10 03:47:02 2007 for Camelot by  doxygen 1.4.4