home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 …ember: Reference Library / Apple Developer Reference Library (December 1999) (Disk 1).iso / pc / technical documentation / develop / develop issue 28 / develop issue 28 code / sketch / source / adts / elementhelpers.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-24  |  17.0 KB  |  678 lines

  1. /****************************************************************************
  2.  * 
  3.  * ElementHelpers.c
  4.  * 
  5.  * functions related to elements
  6.  * 
  7.  ****************************************************************************/
  8. #include <string.h>
  9.  
  10. #include "ElementHelpers.h" 
  11.  
  12. #include "Assertion.h"
  13. #include "DocumentADT.h"
  14. #include "ElementADT.h"
  15. #include "Structs.h"
  16. #include "StringUtils.h"
  17.  
  18. static Rect     CalculateGroupBounds            (ElementReference element);
  19. static Rect     CalculatePolygonBounds        (ElementReference element);
  20.  
  21. /*****************************************************************************
  22.  * 
  23.  * GetFirstSubElement
  24.  * 
  25.  * Retrieves the first element in an element’s sub-element list
  26.  * (skips the list header node). If the sub-element list is empty, NIL is
  27.  * returned.
  28.  *
  29.  *****************************************************************************/
  30. ElementReference GetFirstSubElement(ElementReference element)
  31. {
  32.     ElementList            sublist;
  33.     ElementReference    firstsub;
  34.     
  35.     firstsub = nil;
  36.  
  37.     sublist = GetElementSubElementList(element);
  38.     if (sublist != nil)
  39.         firstsub = GetFirstElement(sublist);
  40.     
  41.     return firstsub;
  42. }
  43.  
  44.  
  45.  
  46. /*****************************************************************************
  47.  * 
  48.  * GetElementByNumber
  49.  * 
  50.  * Recursively searches an element list looking for a specific element by an
  51.  * element number. 
  52.  * The element number is a unique number: no two elements in any list 
  53.  * in any document will have the same element number.
  54.  *
  55.  *****************************************************************************/
  56. ElementReference GetElementByNumber(ElementList list, unsigned long number)
  57. {
  58.     ElementReference    iterator;
  59.     ElementReference    element;
  60.     
  61.     element = nil;
  62.     
  63.     for (iterator = GetFirstElement(list); (iterator != nil) && (element == nil); iterator = GetNextElement(iterator))
  64.     {
  65.         if (GetElementNumber(iterator) == number)
  66.             element = iterator;
  67.         
  68.         if (element == nil)
  69.             if (GetFirstSubElement(iterator) != nil)
  70.                 element = GetElementByNumber(GetSubElementList(iterator), number);
  71.     }
  72.     
  73.     return element;
  74. }
  75.  
  76.  
  77. /*****************************************************************************
  78.  * 
  79.  * GetGroupElementBelongsTo
  80.  * 
  81.  * Returns the group that contains a specified element. If the element is at
  82.  * the root of the document's element list nil will be returned.
  83.  *
  84.  *****************************************************************************/
  85. ElementReference GetGroupElementBelongsTo(ElementList list, ElementReference element)
  86. {
  87.     ElementReference    groupElement        = nil;
  88.     
  89.     if (IsElementInList(list, element, &groupElement))                                                // this will recursively search the list and group elements.
  90.     {
  91.         if (groupElement == element)                                                                        // we found it at the root level, so return nil as advertised.  dsc
  92.             groupElement = nil;
  93.     }
  94.  
  95.     return groupElement;
  96. }
  97.  
  98.  
  99. /*****************************************************************************
  100.  * 
  101.  * IsElementInList
  102.  * 
  103.  *    This function recursively searches lists and Group elements for "element"
  104.  *
  105.  *    Returns :
  106.  *
  107.  *        true if found.
  108.  *        groupElement is set to == element for the deepest level
  109.  *        groupElement is set to the group owning the "element" for the next to deepest level
  110.  *        groupElement passes on the result from there on.
  111.  *
  112.  *   NOTE:  If there is only 1 level, and "element" is found, then "element"
  113.  *          is returned.  This is useful for GetGroupElementBelongsTo to then check it
  114.  *          and return nil as advertised.dsc
  115.  *
  116.  *****************************************************************************/
  117. Boolean IsElementInList(ElementList list, ElementReference element, ElementReference *groupElement)
  118. {
  119.     ElementType            elementType;
  120.     ElementReference    tempElement;
  121.     ElementReference    returnedElement    =    nil;
  122.     Boolean                foundIt                = false;
  123.     
  124.     *groupElement        = nil;
  125.     
  126.     tempElement        = GetFirstElement(list);                                                                        // get first element in list
  127.                 
  128.     if ((tempElement != nil) && (tempElement == element))                                                        // check the first element in the list.
  129.     {
  130.         *groupElement = tempElement;                                                                                    // this will flag the previous level to return that group as the result (or if at the root this will flag the root to then return nil).
  131.         foundIt = true;
  132.     }
  133.         
  134.     while ((tempElement != nil)  && (!foundIt))                                                                    // go until we the object or the end of the line
  135.     {
  136.         elementType = GetElementType(tempElement);
  137.  
  138.         if (elementType == kGroup)
  139.         {
  140.             if (IsElementInList(GetElementSubElementList(tempElement), element, &returnedElement))
  141.             {
  142.                 foundIt = true;
  143.                 
  144.                 if (element == returnedElement)                                                                        // need to flag so I know that at this level, this is the group element to pass back!
  145.                     *groupElement = tempElement;
  146.                 else
  147.                     *groupElement = returnedElement;                                                                    // pass on through this element with no changes 
  148.             }
  149.         }
  150.  
  151.         if (!foundIt)
  152.         {
  153.             tempElement = GetNextElement(tempElement);                                                            // move to the next element and try again
  154.             
  155.             if (tempElement == element)
  156.             {
  157.                 *groupElement = tempElement;                                                                            // this will flag the previous level to return that group as the result (or if at the root this will flag the root to then return nil).
  158.                 foundIt = true;
  159.             }
  160.         }
  161.     }    
  162.         
  163.     return foundIt;
  164. }
  165.  
  166. //----------------------------------------------------------------------------------
  167.  
  168. long
  169. CountElementsByClass(ElementList list, DescType objectClass)
  170. {
  171.     OSErr                    error         = noErr;
  172.     long                    numElements = 0L;
  173.  
  174.     ElementReference  element         = nil;
  175.     ElementType       elementType;
  176.     
  177.     if (objectClass == typeWildCard || objectClass == cGraphicObject)
  178.     {
  179.         numElements = CountElements(list);
  180.     }
  181.     else
  182.     {
  183.         ElementType    requestedType;
  184.         error = ConvertObjectClassToElementType(objectClass, &requestedType);
  185.         
  186.         element = GetFirstElement(list);
  187.         while (element != nil)
  188.         {
  189.             elementType = GetElementType(element);
  190.            if (requestedType == elementType)
  191.            {
  192.                numElements++;
  193.            }
  194.             element = GetNextElement(element);
  195.         }
  196.     }
  197.     
  198.     return numElements;
  199. }
  200.  
  201.  
  202. //----------------------------------------------------------------------------------
  203. // Note: This does not return the element's unique element number, but instead
  204. // it returns the index of that type of element: for instance
  205. // it returns 4 when the element is the 4th rectangle in a document
  206.  
  207. long
  208. GetIndexForElementType(DocumentReference document, ElementReference element, ElementType elementType)
  209. {
  210.     OSErr      error                         = noErr;
  211.     Boolean foundIt               = false;
  212.     
  213.     ElementList         list;
  214.     
  215.     ElementReference  iter;
  216.     ElementType            iterType;
  217.     
  218.     long                    index       = 0L;
  219.     long              numElements = 0L;
  220.     
  221.  
  222.     list = GetDocumentElementList(document);
  223.         
  224.     // First, how many elements of this type are there?
  225.     
  226.     iter = GetFirstElement(list);
  227.     while (iter != nil)
  228.     {
  229.         iterType = GetElementType(iter);
  230.  
  231.        if (elementType == typeWildCard || elementType == cGraphicObject || elementType == iterType)
  232.        {
  233.            numElements++;
  234.        }
  235.         iter = GetNextElement(iter);
  236.     }
  237.  
  238.     // Next, what is the index of the requested element and elementType or objectClass?
  239.     
  240.     iter = GetFirstElement(list);
  241.     while (iter != nil)
  242.     {
  243.         iterType = GetElementType(iter);
  244.  
  245.        if (elementType == typeWildCard || elementType == cGraphicObject || elementType == iterType)
  246.             index++;
  247.             
  248.         if (iter == element)
  249.             break;
  250.             
  251.         iter = GetNextElement(iter);
  252.     }
  253.         
  254.     if (iter != nil && iter == element)
  255.     {
  256.         index = numElements - index + 1;  // because element 1 is at the end of the list, not the beginning.
  257.     }
  258.     else
  259.     {
  260.         index = 0;    // This is an invalid number for an index, but technically -1, -2, etc. are valid
  261.     }                    // because -1 means the last element, -2 means next-to-last, etc. in AppleScript
  262.     
  263.     return index;
  264. }
  265.  
  266. //----------------------------------------------------------------------------------
  267. // Note: This does not return the element's unique element number, but instead
  268. // it returns the index of that type of element: for instance
  269. // it returns 4 when the element is the 4th rectangle in a document
  270.  
  271. long
  272. GetIndexForSubElementType(DocumentReference document, ElementReference element, ElementReference subElement, ElementType elementType)
  273. {
  274.     #pragma unused (document)
  275.  
  276.     OSErr      error                         = noErr;
  277.     Boolean foundIt               = false;
  278.     
  279.     ElementList         list             = GetSubElementList(element);
  280.     ElementReference  tempElement = nil;
  281.     
  282.     long                    index       = 0L;
  283.     long              numElements = 0L;
  284.     
  285.     // First, how many elements of this type are there?
  286.     
  287.     tempElement = GetFirstElement(list);
  288.     while (tempElement != nil)
  289.     {
  290.        if (elementType == typeWildCard || elementType == cGraphicObject || GetElementType(tempElement) == elementType)
  291.        {
  292.            numElements++;
  293.        }
  294.         tempElement = GetNextElement(tempElement);
  295.     }
  296.  
  297.     // Next, what is the index of the requested element and elementType?
  298.     
  299.     tempElement = GetFirstElement(list);
  300.     while (tempElement != nil)
  301.     {
  302.        if (elementType == typeWildCard || elementType == cGraphicObject || GetElementType(tempElement) == elementType)
  303.             index++;
  304.             
  305.         if (tempElement == subElement)
  306.             break;
  307.             
  308.         tempElement = GetNextElement(tempElement);
  309.     }
  310.         
  311.     if (tempElement != nil && tempElement == subElement)
  312.     {
  313.         index = numElements - index + 1;  // because element 1 is at the end of the list, not the beginning.
  314.     }
  315.     else
  316.     {
  317.         index = 0;    // This is an invalid number for an index, but technically -1, -2, etc. are valid
  318.     }                    // because -1 means the last element, -2 means next-to-last, etc. in AppleScript
  319.     
  320.     return index;
  321. }
  322.  
  323. //----------------------------------------------------------------------------------
  324.  
  325. OSErr
  326. FindElementByIndex(ElementList list, DescType objectClass, long index, ElementReference *element)
  327. {
  328.     OSErr    error                         = noErr;
  329.  
  330.     ElementReference  tempElement = nil;
  331.     ElementType            elementType;
  332.     ElementType            requestedType;
  333.     
  334.     long                    i            = 1L;
  335.     long                    numElements = 0L;
  336.     Boolean                foundIt      = false;
  337.     
  338.     *element = nil;
  339.         
  340.     if (objectClass == typeWildCard || objectClass == cGraphicObject)
  341.     {
  342.         numElements = CountElements(list);
  343.     }
  344.     else
  345.     {
  346.         numElements = CountElementsByClass(list, objectClass);
  347.         error = ConvertObjectClassToElementType(objectClass, &requestedType);
  348.     }
  349.     
  350.     // Negative indexes are offsets from the END of the element list:
  351.     // rectangle -1 is the last rectangle, rectangle -2 is the next to last rectangle, etc.
  352.  
  353.     if (index < 0)
  354.     {
  355.         index = numElements + 1 + index;        // convert offset from end of list to offset from beginning of list
  356.     }
  357.     
  358.     index = numElements - index + 1;  // because element 1 is at the end of the list, not the beginning.
  359.  
  360.     if (index < 1 || index > numElements)
  361.         error = errAEIllegalIndex;
  362.  
  363.     // Find the element of the requested type with the requested index
  364.     
  365.     if (error == noErr)
  366.     {
  367.         i = 1L;
  368.         tempElement = GetFirstElement(list);
  369.         
  370.         while (tempElement != nil)
  371.         { 
  372.             elementType = GetElementType(tempElement);
  373.             
  374.            if (objectClass == typeWildCard || objectClass == cGraphicObject)
  375.            {
  376.                if (i == index)
  377.                {
  378.                    foundIt = true;
  379.                    break;
  380.                }
  381.                i++;
  382.            }
  383.            else if (requestedType == elementType)
  384.            {
  385.                if (i == index)
  386.                {
  387.                    foundIt = true;
  388.                    break;
  389.                }
  390.                i++;
  391.            }
  392.             tempElement = GetNextElement(tempElement);
  393.         }
  394.     }
  395.     
  396.     // return the element, if found
  397.     
  398.     if (error == noErr)
  399.     {
  400.         if (foundIt)
  401.             *element = tempElement;
  402.         else
  403.             error = errAENoSuchObject;
  404.     }
  405.         
  406.     return error;
  407. }
  408.  
  409. //----------------------------------------------------------------------------------
  410.  
  411. ElementReference
  412. FindElementByUniqueID(ElementList list, long uniqueID)
  413. {
  414.     ElementReference  element         = nil;
  415.     Boolean                foundIt     = false;
  416.     
  417.     // Find the element of the requested ID
  418.  
  419.     element = GetFirstElement(list); 
  420.     
  421.     while (element != nil)
  422.     {
  423.         if (GetElementNumber(element) == uniqueID)
  424.         {
  425.             foundIt = true;
  426.             break;
  427.         }
  428.         element = GetNextElement(element);
  429.     }
  430.     
  431.     if (foundIt == false)
  432.         element = nil;
  433.         
  434.     return element;
  435. }
  436.  
  437. //----------------------------------------------------------------------------------
  438. // Convert AppleEvent class to elementType code
  439.  
  440. OSErr
  441. ConvertObjectClassToElementType(const DescType objectClass, ElementType *elementType)
  442. {
  443.     OSErr    error = noErr;
  444.  
  445.     switch (objectClass)
  446.     {            
  447.         case cOval:
  448.             *elementType = kQDOval;
  449.             break;
  450.         
  451.         case cPolygon:
  452.             *elementType = kQDPolygon;
  453.             break;
  454.         
  455.         case cRectangle:
  456.             *elementType = kQDRect;
  457.             break;
  458.         
  459.         case cRoundedRectangle:
  460.             *elementType = kQDRoundRect;
  461.             break;
  462.         
  463.         case cGraphicLine:
  464.             *elementType = kQDLine;
  465.             break;
  466.         
  467.         case cGraphicObject:
  468.         case typeWildCard:
  469.             *elementType = (ElementType) typeWildCard;
  470.             break;
  471.         
  472.         case cGroupedGraphic:
  473.             *elementType = kGroup;
  474.             break;
  475.         
  476.         default:
  477.             error = errAECantHandleClass;
  478.             break;
  479.     }
  480.  
  481.     return error;
  482. }
  483.  
  484. //----------------------------------------------------------------------------------
  485. // Convert an elementType code to AppleEvent class
  486.  
  487. OSErr
  488. ConvertElementTypeToObjectClass(const ElementType elementType, DescType *objectClass)
  489. {
  490.     OSErr    error = noErr;
  491.     
  492.     switch (elementType)
  493.     {
  494.         case kQDOval:
  495.             *objectClass = cOval;
  496.             break;
  497.         
  498.         case kQDPolygon:
  499.             *objectClass = cPolygon;
  500.             break;
  501.         
  502.         case kQDRect:
  503.             *objectClass = cRectangle;
  504.             break;
  505.         
  506.         case kQDRoundRect:
  507.             *objectClass = cRoundedRectangle;
  508.             break;
  509.         
  510.         case kQDLine:
  511.             *objectClass = cGraphicLine;
  512.             break;
  513.         
  514.         case kGroup:
  515.             *objectClass = cGroupedGraphic;
  516.             break;
  517.                 
  518.         case kUnknownElement:
  519.         default:
  520.             error = errAECantHandleClass;
  521.             break;
  522.     }
  523.  
  524.     return error;
  525. }
  526.  
  527. // ---------------------------------------------------------------------------
  528.  
  529. void PopulateElementWithDefaultData(ElementReference element)
  530. {
  531.     RGBColor black        = {0x0000, 0x0000, 0x0000};
  532.     RGBColor white     = {0xFFFF, 0xFFFF, 0xFFFF};
  533.     Point        ovalSize = { 20,  20};
  534.     Rect        bounds   = {  0,   0, 100,100};
  535.     Point    p1            = {  0,   0};
  536.     Point        p2       = {100, 100};
  537.     
  538.     SetElementBoundingBox(element, bounds);
  539.     
  540.     SetElementStrokePenHeight(element,     1);
  541.     SetElementStrokePenWidth(element,     1);
  542.  
  543.     SetElementStrokeColor(element, black);
  544.     SetElementFillColor(element, white);
  545.     
  546.     SetElementRoundRectOvalSize(element, ovalSize);
  547.     SetElementLineBeginPoint(element, p1);
  548.     SetElementLineEndPoint(element,   p2);
  549.  
  550. }
  551.  
  552. #pragma mark -
  553. /*****************************************************************************
  554.  * 
  555.  * CalculateElementBounds
  556.  * 
  557.  * Public function to get the bounds of both simple and complex objects
  558.  *
  559.  *****************************************************************************/
  560.  
  561. Rect CalculateElementBounds(ElementReference element)
  562. {
  563.     Rect    objectBounds;
  564.     Point p1;
  565.     Point p2;
  566.     
  567.     switch (GetElementType(element))
  568.     {
  569.         case kQDPolygon:
  570.                 objectBounds = CalculatePolygonBounds(element);
  571.                 break;
  572.         
  573.         case kQDRect:
  574.         case kQDRoundRect:
  575.         case kQDOval:
  576.                 objectBounds = GetElementBoundingBox(element);
  577.                 break;
  578.                     
  579.         case kQDLine:
  580.                 p1 = GetElementLineBeginPoint(element);
  581.                 p2 = GetElementLineEndPoint(element);
  582.                 
  583.                 objectBounds.top         = min(p1.v, p2.v);
  584.                 objectBounds.left     = min(p1.h, p2.h);
  585.                 objectBounds.bottom     = max(p1.v, p2.v);
  586.                 objectBounds.right     = max(p1.h, p2.h);
  587.                 break;
  588.                     
  589.         case kGroup:
  590.                 objectBounds = CalculateGroupBounds(element);
  591.                 break;
  592.  
  593.         default:
  594.                 Assert(kAssertAlways, "Unknown object in CalculateElementBounds");
  595.                 break;
  596.         }
  597.         
  598.     Assert(objectBounds.top  <= objectBounds.bottom, "IMAGING: CalculateElementBounds said that top is greater than bottom");
  599.     Assert(objectBounds.left <= objectBounds.right,  "IMAGING: CalculateElementBounds said that left is greater than right");
  600.  
  601.     return objectBounds;
  602. }
  603.  
  604. /*****************************************************************************
  605.  * 
  606.  * CalculateGroupBounds
  607.  * 
  608.  * walk the subElementList and Union all the visible elements bounding boxes together
  609.  * groupBounds being passed to this function should be set to an empty rectangle
  610.  * 
  611.  *****************************************************************************/
  612.  
  613. static Rect CalculateGroupBounds(ElementReference element)
  614. {
  615.     ElementReference    iterator;
  616.     Rect                    groupBounds    = {0, 0, 0, 0};
  617.     Rect                    objectBounds;
  618.     ElementList            list;
  619.  
  620.     list = GetSubElementList(element);
  621.         
  622.     for (iterator = GetFirstElement(list); iterator != nil; iterator = GetNextElement(iterator))
  623.     {
  624.         if (GetElementType(iterator) == kGroup)
  625.             objectBounds = CalculateGroupBounds(iterator);
  626.         else
  627.             objectBounds = CalculateElementBounds(iterator);
  628.             
  629.         if(EmptyRect(&groupBounds))
  630.             groupBounds = objectBounds;
  631.         else
  632.             UnionRect(&groupBounds, &objectBounds, &groupBounds);
  633.     }
  634.     
  635.     return groupBounds;
  636. }
  637.  
  638. /*****************************************************************************
  639.  * 
  640.  * CalculatePolygonBounds
  641.  *
  642.  * Polygons draw outside of their bounding box (go figure!) so we add the
  643.  * pen size to the right and bottom side of the bounding box
  644.  *
  645.  *****************************************************************************/
  646.  
  647. static Rect CalculatePolygonBounds(ElementReference element)
  648. {
  649.     Rect            objectBounds = {0, 0, 0, 0};
  650.     PolyHandle    polygon;
  651.     short            strokeWidth;
  652.     short            strokeHeight;
  653.             
  654.     polygon = GetElementPolygon(element);
  655.         
  656.     if (polygon != nil)
  657.     {
  658.         objectBounds = (**polygon).polyBBox;
  659.                         
  660.         strokeWidth = GetElementStrokePenWidth(element);
  661.         if(strokeWidth < 1)
  662.             strokeWidth = 1;
  663.         objectBounds.right  += strokeWidth;    
  664.  
  665.         
  666.         strokeHeight = GetElementStrokePenWidth(element);
  667.         if(strokeHeight < 1)
  668.             strokeHeight = 1;
  669.         objectBounds.bottom += strokeHeight;    
  670.     }
  671.     
  672.     return objectBounds;
  673. }
  674.  
  675.  
  676.  
  677.  
  678.