home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / i / iv26_w_3.zip / EXAMPLES / IDRAW / DRAWING.C < prev    next >
C/C++ Source or Header  |  1992-01-30  |  27KB  |  916 lines

  1. /*
  2.  * Copyright (c) 1987, 1988, 1989 Stanford University
  3.  *
  4.  * Permission to use, copy, modify, distribute, and sell this software and its
  5.  * documentation for any purpose is hereby granted without fee, provided
  6.  * that the above copyright notice appear in all copies and that both that
  7.  * copyright notice and this permission notice appear in supporting
  8.  * documentation, and that the name of Stanford not be used in advertising or
  9.  * publicity pertaining to distribution of the software without specific,
  10.  * written prior permission.  Stanford makes no representations about
  11.  * the suitability of this software for any purpose.  It is provided "as is"
  12.  * without express or implied warranty.
  13.  *
  14.  * STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
  16.  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  18.  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  19.  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  20.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  21.  */
  22.  
  23. // $Header: drawing.c,v 1.19 90/01/11 22:11:12 dunwoody Exp $
  24. // implements class Drawing.
  25.  
  26. #include "drawing.h"
  27. #include "ipaint.h"
  28. #include "istring.h"
  29. #include "listboolean.h"
  30. #include "listcenter.h"
  31. #include "listgroup.h"
  32. #include "listibrush.h"
  33. #include "listicolor.h"
  34. #include "listifont.h"
  35. #include "listipattern.h"
  36. #include "listselectn.h"
  37. #include "page.h"
  38. #include "slpict.h"
  39. #include <InterViews/Graphic/polygons.h>
  40. #include <InterViews/transformer.h>
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include <io.h>
  44. #include <sys/types.h>
  45. #ifdef XD88
  46. //#include <sys/unistd.h>
  47. #endif
  48. //#include <sys/file.h>            /* define constants for access call */
  49.  
  50. // Drawing creates the page, selection list, and clipboard filename.
  51.  
  52. Drawing::Drawing (double w, double h, double b) {
  53.     const char* home = (home = getenv("HOME")) ? home : ".";
  54.     const char* name = "clipboard";
  55.     clipfilename = new char[strlen(home) + 1 + strlen(name) + 1];
  56.     strcpy(clipfilename, home);
  57.     strcat(clipfilename, "\\");
  58.     strcat(clipfilename, name);
  59.     page = new Page(w, h, b);
  60.     picture = page->GetPicture();
  61.     sl = new SelectionList;
  62. }
  63.  
  64. // ~Drawing frees storage allocated for the clipboard filename, page,
  65. // and selection list.
  66.  
  67. Drawing::~Drawing () {
  68.     delete clipfilename;
  69.     delete page;
  70.     delete sl;
  71. }
  72.  
  73. // Define access functions to return attributes.
  74.  
  75. boolean Drawing::GetLandscape () {
  76.     Transformer* t = page->GetTransformer();
  77.     return t ? t->Rotated90() : false;
  78. }
  79.  
  80. Page* Drawing::GetPage () {
  81.     return page;
  82. }
  83.  
  84. void Drawing::GetPictureTT (Transformer& t) {
  85.     picture->TotalTransformation(t);
  86. }
  87.  
  88. SelectionList* Drawing::GetSelectionList () {
  89.     return sl;
  90. }
  91.  
  92. // Writable returns true only if the given drawing is writable.
  93.  
  94. boolean Drawing::Writable (const char* path) {
  95.     return (access(path, 02) >= 0);
  96. }
  97.  
  98. // Exists returns true only if the drawing already exists.
  99.  
  100. boolean Drawing::Exists (const char* path) {
  101.     return (access(path, 00) >= 0);
  102. }
  103.  
  104. // ClearPicture deletes the old picture and creates a new empty
  105. // picture.
  106.  
  107. void Drawing::ClearPicture () {
  108.     sl->DeleteAll();
  109.     page->SetPicture(nil);
  110.     picture = page->GetPicture();
  111. }
  112.  
  113. // ReadPicture reads a new picture and replaces the old picture with
  114. // the new picture if the read succeeds.
  115.  
  116. boolean Drawing::ReadPicture (const char* path, State* state) {
  117.     boolean successful = false;
  118.     if (path != nil) {
  119.     FILE* stream = fopen(path, "r");
  120.     if (stream != nil) {
  121.         PictSelection* newpic = new PictSelection(stream, state);
  122.         fclose(stream);
  123.         if (newpic->Valid()) {
  124.         sl->DeleteAll();
  125.         page->SetPicture(newpic);
  126.         picture = page->GetPicture();
  127.         successful = true;
  128.         } else {
  129.         delete newpic;
  130.         fprintf(stderr, "Drawing: input error in reading %s\n", path);
  131.         }
  132.     }
  133.     }
  134.     return successful;
  135. }
  136.  
  137. // PrintPicture prints the current picture by writing it through a
  138. // pipe to a print command.
  139.  
  140. boolean Drawing::PrintPicture (const char* cmd, State* state) {
  141.     boolean successful = false;
  142.     if (cmd != nil) {
  143. //    FILE* stream = popen(cmd, "w");
  144. //    if (stream != nil) {
  145. //        successful = picture->WritePicture(stream, state, true);
  146. //        pclose(stream);
  147. //    }
  148.     }
  149.     return successful;
  150. }
  151.  
  152. // WritePicture writes the current picture to a file.
  153.  
  154. boolean Drawing::WritePicture (const char* path, State* state) {
  155.     boolean successful = false;
  156.     if (path != nil) {
  157.     FILE* stream = fopen(path, "w");
  158.     if (stream != nil) {
  159.         successful = picture->WritePicture(stream, state, true);
  160.         fclose(stream);
  161.     }
  162.     }
  163.     return successful;
  164. }
  165.  
  166. // ReadClipboard returns copies of the Selections within the clipboard
  167. // file in a newly allocated list.
  168.  
  169. SelectionList* Drawing::ReadClipboard (State* state) {
  170.     SelectionList* sl = new SelectionList;
  171.     FILE* stream = fopen(clipfilename, "r");
  172.     if (stream != nil) {
  173.     PictSelection* newpic = new PictSelection(stream, state);
  174.     fclose(stream);
  175.     if (newpic->Valid()) {
  176.         newpic->Propagate();
  177.         for (newpic->First(); !newpic->AtEnd(); newpic->RemoveCur()) {
  178.         Selection* child = (Selection*) newpic->GetCurrent();
  179.         sl->Append(new SelectionNode(child));
  180.         }
  181.     }
  182.     delete newpic;
  183.     } else {
  184.     fprintf(stderr, "Drawing: can't open %s\n", clipfilename);
  185.     }
  186.     return sl;
  187. }
  188.  
  189. // WriteClipboard writes the picked Selections to the clipboard file,
  190. // overwriting its previous contents.
  191.  
  192. void Drawing::WriteClipboard () {
  193.     FILE* stream = fopen(clipfilename, "w");
  194.     if (stream != nil) {
  195.     PictSelection* newpic = new PictSelection;
  196.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  197.         Graphic* copy = sl->GetCur()->GetSelection()->Copy();
  198.         newpic->Append(copy);
  199.     }
  200.     newpic->WritePicture(stream, nil, false);
  201.     fclose(stream);
  202.     delete newpic;
  203.     } else {
  204.     fprintf(stderr, "Drawing: can't open %s\n", clipfilename);
  205.     }
  206. }
  207.  
  208. // GetBox gets the smallest box bounding all the Selections.
  209.  
  210. void Drawing::GetBox (Coord& l, Coord& b, Coord& r, Coord& t) {
  211.     BoxObj btotal;
  212.     BoxObj bselection;
  213.  
  214.     if (sl->Size() >= 1) {
  215.     sl->First()->GetSelection()->GetBox(btotal);
  216.     for (sl->Next(); !sl->AtEnd(); sl->Next()) {
  217.         sl->GetCur()->GetSelection()->GetBox(bselection);
  218.         btotal = btotal + bselection;
  219.     }
  220.     l = btotal.left;
  221.     b = btotal.bottom;
  222.     r = btotal.right;
  223.     t = btotal.top;
  224.     }
  225. }
  226.  
  227. // GetBrush returns the Selections' brush attributes in a newly
  228. // allocated list.
  229.  
  230. IBrushList* Drawing::GetBrush () {
  231.     IBrushList* brushlist = new IBrushList;
  232.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  233.     IBrush* brush = (IBrush*) sl->GetCur()->GetSelection()->GetBrush();
  234.     brushlist->Append(new IBrushNode(brush));
  235.     }
  236.     return brushlist;
  237. }
  238.  
  239. // GetCenter returns the Selections' centers in a newly allocated
  240. // list.  It converts the centers from window coordinates to picture
  241. // coordinates because only these coordinates will remain constant.
  242.  
  243. CenterList* Drawing::GetCenter () {
  244.     CenterList* centerlist = new CenterList;
  245.     Transformer t;
  246.     picture->TotalTransformation(t);
  247.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  248.     float wincx, wincy, cx, cy;
  249.  
  250.     sl->GetCur()->GetSelection()->GetCenter(wincx, wincy);
  251.     t.InvTransform(wincx, wincy, cx, cy);
  252.     centerlist->Append(new CenterNode(cx, cy));
  253.     }
  254.     return centerlist;
  255. }
  256.  
  257. // GetChildren returns the Selections and their children, if any, in a
  258. // newly allocated list.
  259.  
  260. GroupList* Drawing::GetChildren () {
  261.     GroupList* grouplist = new GroupList;
  262.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  263.     PictSelection* parent = (PictSelection*) sl->GetCur()->GetSelection();
  264.     boolean haschildren = parent->HasChildren();
  265.     SelectionList* children = new SelectionList;
  266.     if (haschildren) {
  267.         for (parent->First(); !parent->AtEnd(); parent->Next()) {
  268.         Selection* child = parent->GetCurrent();
  269.         children->Append(new SelectionNode(child));
  270.         }
  271.     }
  272.     grouplist->Append(new GroupNode(parent, haschildren, children));
  273.     delete children;
  274.     }
  275.     return grouplist;
  276. }
  277.  
  278. // GetFgColor returns the Selections' FgColor attributes in a newly
  279. // allocated list.
  280.  
  281. IColorList* Drawing::GetFgColor () {
  282.     IColorList* fgcolorlist = new IColorList;
  283.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  284.     IColor* fgcolor = (IColor*) sl->GetCur()->GetSelection()->GetFgColor();
  285.     fgcolorlist->Append(new IColorNode(fgcolor));
  286.     }
  287.     return fgcolorlist;
  288. }
  289.  
  290. // GetBgColor returns the Selections' BgColor attributes in a newly
  291. // allocated list.
  292.  
  293. IColorList* Drawing::GetBgColor () {
  294.     IColorList* bgcolorlist = new IColorList;
  295.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  296.     IColor* bgcolor = (IColor*) sl->GetCur()->GetSelection()->GetBgColor();
  297.     bgcolorlist->Append(new IColorNode(bgcolor));
  298.     }
  299.     return bgcolorlist;
  300. }
  301.  
  302. // GetDuplicates duplicates the Selections, offsets them by one grid
  303. // spacing, and returns them in a newly allocated list.
  304.  
  305. SelectionList* Drawing::GetDuplicates () {
  306.     int offset = round(page->GetGridSpacing() * points);
  307.     SelectionList* duplicates = new SelectionList;
  308.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  309.     Selection* dup = (Selection*) sl->GetCur()->GetSelection()->Copy();
  310.     dup->Translate(offset, offset);
  311.     duplicates->Append(new SelectionNode(dup));
  312.     }
  313.     return duplicates;
  314. }
  315.  
  316. // GetFillBg returns the Selections' fillbg attributes in a newly
  317. // allocated list.
  318.  
  319. booleanList* Drawing::GetFillBg () {
  320.     booleanList* fillbglist = new booleanList;
  321.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  322.     boolean fillbg = sl->GetCur()->GetSelection()->BgFilled();
  323.     fillbglist->Append(new booleanNode(fillbg)); 
  324.     }
  325.     return fillbglist;
  326. }
  327.  
  328. // GetFont returns the Selections' Font attributes in a newly
  329. // allocated list.
  330.  
  331. IFontList* Drawing::GetFont () {
  332.     IFontList* fontlist = new IFontList;
  333.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  334.     IFont* font = (IFont*) sl->GetCur()->GetSelection()->GetFont();
  335.     fontlist->Append(new IFontNode(font));
  336.     }
  337.     return fontlist;
  338. }
  339.  
  340. // GetNumberOfGraphics returns the number of graphics in the
  341. // Selections.
  342.  
  343. int Drawing::GetNumberOfGraphics () {
  344.     int num = 0;
  345.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  346.     Selection* s = sl->GetCur()->GetSelection();
  347.     if (s->HasChildren()) {
  348.         num += NumberOfGraphics((PictSelection*) s);
  349.     } else {
  350.         ++num;
  351.     }
  352.     }
  353.     return num;
  354. }
  355.  
  356. // GetParent returns the Selections and their new parent in a newly
  357. // allocated list if there are enough Selections to form a Group.
  358.  
  359. GroupList* Drawing::GetParent () {
  360.     GroupList* grouplist = new GroupList;
  361.     if (sl->Size() >= 2) {
  362.     PictSelection* parent = new PictSelection;
  363.     boolean haschildren = true;
  364.     grouplist->Append(new GroupNode(parent, haschildren, sl));
  365.     }
  366.     return grouplist;
  367. }
  368.  
  369. // GetPattern returns the Selections' Pattern attributes in a newly
  370. // allocated list.
  371.  
  372. IPatternList* Drawing::GetPattern () {
  373.     IPatternList* patternlist = new IPatternList;
  374.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  375.     IPattern* pattern =
  376.         (IPattern*) sl->GetCur()->GetSelection()->GetPattern();
  377.     patternlist->Append(new IPatternNode(pattern));
  378.     }
  379.     return patternlist;
  380. }
  381.  
  382. // GetPrevs returns the Selections' predecessors within the picture in
  383. // a newly allocated list.
  384.  
  385. SelectionList* Drawing::GetPrevs () {
  386.     SelectionList* prevlist = new SelectionList;
  387.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  388.     picture->SetCurrent(sl->GetCur()->GetSelection());
  389.     Selection* prev = picture->Prev();
  390.     prevlist->Append(new SelectionNode(prev));
  391.     }
  392.     return prevlist;
  393. }
  394.  
  395. // GetSelections returns the Selections in a newly allocated list.
  396.  
  397. SelectionList* Drawing::GetSelections () {
  398.     SelectionList* newsl = new SelectionList;
  399.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  400.     Selection* s = sl->GetCur()->GetSelection();
  401.     newsl->Append(new SelectionNode(s));
  402.     }
  403.     return newsl;
  404. }
  405.  
  406. // PickSelectionIntersecting returns the last Selection intersecting a
  407. // box around the given point.
  408.  
  409. Selection* Drawing::PickSelectionIntersecting (Coord x, Coord y) {
  410.     const int SLOP = 2;
  411.     BoxObj pickpoint(x - SLOP, y - SLOP, x + SLOP, y + SLOP);
  412.     return picture->LastSelectionIntersecting(pickpoint);
  413. }
  414.  
  415. // PickSelectionShapedBy returns the last Selection shaped by a point
  416. // close to the given point.
  417.  
  418. Selection* Drawing::PickSelectionShapedBy (Coord x, Coord y) {
  419.     const float SLOP = 6.;
  420.     for (picture->Last(); !picture->AtEnd(); picture->Prev()) {
  421.     Selection* pick = picture->GetCurrent();
  422.     if (pick->ShapedBy(x, y, SLOP)) {
  423.         return pick;
  424.     }
  425.     }
  426.     return nil;
  427. }
  428.  
  429. // PickSelectionsWithin returns all the Selections within the given
  430. // box.
  431.  
  432. SelectionList* Drawing::PickSelectionsWithin (Coord l, Coord b, Coord r,
  433. Coord t) {
  434.     Selection** picks = nil;
  435.     int numpicks = picture->SelectionsWithin(BoxObj(l, b, r, t), picks);
  436.     SelectionList* picklist = new SelectionList;
  437.     for (int i = 0; i < numpicks; i++) {
  438.     picklist->Append(new SelectionNode(picks[i]));
  439.     }
  440.     delete picks;
  441.     return picklist;
  442. }
  443.  
  444. // Clear empties the SelectionList.
  445.  
  446. void Drawing::Clear () {
  447.     sl->DeleteAll();
  448. }
  449.  
  450. // Extend extends the SelectionList to include the picked Selection
  451. // unless it's already there, in which case it removes the Selection.
  452.  
  453. void Drawing::Extend (Selection* pick) {
  454.     if (!sl->Find(pick)) {
  455.     sl->Append(new SelectionNode(pick));
  456.     } else {
  457.     sl->DeleteCur();
  458.     }
  459. }
  460.  
  461. // Extend extends the SelectionList to include the picked Selections
  462. // unless they're already there, in which case it removes them.
  463.  
  464. void Drawing::Extend (SelectionList* picklist) {
  465.     for (picklist->First(); !picklist->AtEnd(); picklist->Next()) {
  466.     Selection* pick = picklist->GetCur()->GetSelection();
  467.     Extend(pick);
  468.     }
  469. }
  470.  
  471. // Grasp selects the picked Selection only if the SelectionList does
  472. // not already include it.
  473.  
  474. void Drawing::Grasp (Selection* pick) {
  475.     if (!sl->Find(pick)) {
  476.     Select(pick);
  477.     }
  478. }
  479.  
  480. // Select selects the picked Selection.
  481.  
  482. void Drawing::Select (Selection* pick) {
  483.     sl->DeleteAll();
  484.     sl->Append(new SelectionNode(pick));
  485. }
  486.  
  487. // Select selects the picked Selections.
  488.  
  489. void Drawing::Select (SelectionList* picklist) {
  490.     sl->DeleteAll();
  491.     for (picklist->First(); !picklist->AtEnd(); picklist->Next()) {
  492.     Selection* pick = picklist->GetCur()->GetSelection();
  493.     sl->Append(new SelectionNode(pick));
  494.     }
  495. }
  496.  
  497. // SelectAll selects all of the Selections in the picture.
  498.  
  499. void Drawing::SelectAll () {
  500.     sl->DeleteAll();
  501.     for (picture->First(); !picture->AtEnd(); picture->Next()) {
  502.     Selection* pick = picture->GetCurrent();
  503.     sl->Append(new SelectionNode(pick));
  504.     }
  505. }
  506.  
  507. // Move translates the Selections.
  508.  
  509. void Drawing::Move (float xdisp, float ydisp) {
  510.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  511.     Selection* s = sl->GetCur()->GetSelection();
  512.     s->Translate(xdisp, ydisp);
  513.     }
  514. }
  515.  
  516. // Scale scales the Selections about their centers.
  517.  
  518. void Drawing::Scale (float xscale, float yscale) {
  519.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  520.     Selection* s = sl->GetCur()->GetSelection();
  521.     float cx, cy;
  522.     s->GetCenter(cx, cy);
  523.     s->Scale(xscale, yscale, cx, cy);
  524.     }
  525. }
  526.  
  527. // Stretch stretches the Selections while keeping the given side
  528. // fixed.
  529.  
  530. void Drawing::Stretch (float stretch, Alignment side) {
  531.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  532.     Selection* s = sl->GetCur()->GetSelection();
  533.     float l, b, r, t;
  534.     s->GetBounds(l, b, r, t);
  535.     switch (side) {
  536.     case Left:
  537.         s->Scale(stretch, 1, r, t);
  538.         break;
  539.     case Bottom:
  540.         s->Scale(1, stretch, r, t);
  541.         break;
  542.     case Right:
  543.         s->Scale(stretch, 1, l, b);
  544.         break;
  545.     case Top:
  546.         s->Scale(1, stretch, l, b);
  547.         break;
  548.     default:
  549.         fprintf(stderr, "inappropriate enum passed to Drawing::Stretch\n");
  550.         break;
  551.     }
  552.     }
  553. }
  554.  
  555. // Rotate rotates the Selections about their centers.
  556.  
  557. void Drawing::Rotate (float angle) {
  558.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  559.     Selection* s = sl->GetCur()->GetSelection();
  560.     float cx, cy;
  561.     s->GetCenter(cx, cy);
  562.     s->Rotate(angle, cx, cy);
  563.     }
  564. }
  565.  
  566. // Align either aligns up all of the Selections or abuts all of them
  567. // side to side, depending on whether the moving Selection's side or
  568. // center aligns with the fixed Selection's same side or center.
  569.  
  570. void Drawing::Align (Alignment falign, Alignment malign) {
  571.     if (falign == malign) {
  572.     Selection* stays = sl->First()->GetSelection();
  573.     for (sl->Next(); !sl->AtEnd(); sl->Next()) {
  574.         Selection* moves = sl->GetCur()->GetSelection();
  575.         stays->Align(falign, moves, malign);
  576.     }
  577.     } else {
  578.     Selection* stays = sl->First()->GetSelection();
  579.     for (sl->Next(); !sl->AtEnd(); sl->Next()) {
  580.         Selection* moves = sl->GetCur()->GetSelection();
  581.         stays->Align(falign, moves, malign);
  582.         stays = moves;
  583.     }
  584.     }
  585. }
  586.  
  587. // AlignToGrid aligns the Selections' lower left corners to the
  588. // nearest grid point.
  589.  
  590. void Drawing::AlignToGrid () {
  591.     boolean gravity = page->GetGridGravity();
  592.     page->SetGridGravity(true);
  593.     Transformer t;
  594.     picture->TotalTransformation(t);
  595.  
  596.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  597.     Selection* s = sl->GetCur()->GetSelection();
  598.     float l, b, dummy;
  599.     s->GetBounds(l, b, dummy, dummy);
  600.     Coord nl = round(l);
  601.     Coord nb = round(b);
  602.     page->Constrain(nl, nb);
  603.     float x0, y0, x1, y1;
  604.     t.InvTransform(l, b, x0, y0);
  605.     t.InvTransform(float(nl), float(nb), x1, y1);
  606.     s->Translate(x1 - x0, y1 - y0);
  607.     }
  608.  
  609.     page->SetGridGravity(gravity);
  610. }
  611.  
  612. // SetBrush sets the Selections' brush attributes with the given brush
  613. // attribute.
  614.  
  615. void Drawing::SetBrush (IBrush* brush) {
  616.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  617.     sl->GetCur()->GetSelection()->SetBrush(brush);
  618.     }
  619. }
  620.  
  621. // SetBrush sets each Selection's brush attribute with the
  622. // corresponding brush attribute in the provided list.
  623.  
  624. void Drawing::SetBrush (IBrushList* brushlist) {
  625.     for (sl->First(), brushlist->First(); !sl->AtEnd() && !brushlist->AtEnd();
  626.      sl->Next(), brushlist->Next())
  627.     {
  628.     IBrush* brush = brushlist->GetCur()->GetBrush();
  629.     sl->GetCur()->GetSelection()->SetBrush(brush);
  630.     }
  631. }
  632.  
  633. // SetCenter centers each of the Selections over the corresponding
  634. // position in the provided list.  It expects the passed postions to
  635. // in picture coordinates, not window coordinates.
  636.  
  637. void Drawing::SetCenter (CenterList* centerlist) {
  638.     Transformer t;
  639.     picture->TotalTransformation(t);
  640.     for (sl->First(), centerlist->First();
  641.      !sl->AtEnd() && !centerlist->AtEnd();
  642.      sl->Next(), centerlist->Next())
  643.     {
  644.     float winoldcx, winoldcy, oldcx, oldcy;
  645.     float newcx = centerlist->GetCur()->GetCx();
  646.     float newcy = centerlist->GetCur()->GetCy();
  647.     Selection* s = sl->GetCur()->GetSelection();
  648.  
  649.     s->GetCenter(winoldcx, winoldcy);
  650.     t.InvTransform(winoldcx, winoldcy, oldcx, oldcy);
  651.     s->Translate(newcx - oldcx, newcy - oldcy);
  652.     }
  653. }
  654.  
  655. // SetFgColor sets the Selections' foreground color attributes with
  656. // the given color attribute.
  657.  
  658. void Drawing::SetFgColor (IColor* fgcolor) {
  659.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  660.     Selection* s = sl->GetCur()->GetSelection();
  661.     IColor* bgcolor = (IColor*) s->GetBgColor();
  662.     s->SetColors(fgcolor, bgcolor);
  663.     }
  664. }
  665.  
  666. // SetFgColor sets the Selections' foreground color attributes with
  667. // the corresponding color attributes in the provided list.
  668.  
  669. void Drawing::SetFgColor (IColorList* fgcolorlist) {
  670.     for (sl->First(), fgcolorlist->First();
  671.      !sl->AtEnd() && !fgcolorlist->AtEnd();
  672.      sl->Next(), fgcolorlist->Next())
  673.     {
  674.     Selection* s = sl->GetCur()->GetSelection();
  675.     IColor* fgcolor = fgcolorlist->GetCur()->GetColor();
  676.     IColor* bgcolor = (IColor*) s->GetBgColor();
  677.     s->SetColors(fgcolor, bgcolor);
  678.     }
  679. }
  680.  
  681. // SetBgColor sets the Selections' background color attributes with
  682. // the given color attribute.
  683.  
  684. void Drawing::SetBgColor (IColor* bgcolor) {
  685.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  686.     Selection* s = sl->GetCur()->GetSelection();
  687.     IColor* fgcolor = (IColor*) s->GetFgColor();
  688.     s->SetColors(fgcolor, bgcolor);
  689.     }
  690. }
  691.  
  692. // SetBgColor sets the Selections' background color attributes with
  693. // the corresponding color attributes in the provided list.
  694.  
  695. void Drawing::SetBgColor (IColorList* bgcolorlist) {
  696.     for (sl->First(), bgcolorlist->First();
  697.      !sl->AtEnd() && !bgcolorlist->AtEnd();
  698.      sl->Next(), bgcolorlist->Next())
  699.     {
  700.     Selection* s = sl->GetCur()->GetSelection();
  701.     IColor* fgcolor = (IColor*) s->GetFgColor();
  702.     IColor* bgcolor = bgcolorlist->GetCur()->GetColor();
  703.     s->SetColors(fgcolor, bgcolor);
  704.     }
  705. }
  706.  
  707. // SetFillBg sets the Selections' fillbg attributes with the given
  708. // fillbg attribute.
  709.  
  710. void Drawing::SetFillBg (boolean fillbg) {
  711.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  712.     sl->GetCur()->GetSelection()->FillBg(fillbg);
  713.     }
  714. }
  715.  
  716. // SetFillBg sets each Selection's fillbg attribute with the
  717. // corresponding fillbg attribute in the provided list.
  718.  
  719. void Drawing::SetFillBg (booleanList* fillbglist) {
  720.     for (sl->First(), fillbglist->First();
  721.      !sl->AtEnd() && !fillbglist->AtEnd();
  722.      sl->Next(), fillbglist->Next())
  723.     {
  724.     boolean fillbg = fillbglist->GetCur()->GetBoolean();
  725.     sl->GetCur()->GetSelection()->FillBg(fillbg);
  726.     }
  727. }
  728.  
  729. // SetFont sets the Selections' font attributes with the given font
  730. // attribute.
  731.  
  732. void Drawing::SetFont (IFont* font) {
  733.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  734.     Selection* s = sl->GetCur()->GetSelection();
  735.     s->SetFont(font);
  736.     }
  737. }
  738.  
  739. // SetFont sets each Selection's font attribute with the corresponding
  740. // font attribute in the provided list.
  741.  
  742. void Drawing::SetFont (IFontList* fontlist) {
  743.     for (sl->First(), fontlist->First(); !sl->AtEnd() && !fontlist->AtEnd();
  744.      sl->Next(), fontlist->Next())
  745.     {
  746.     IFont* font = fontlist->GetCur()->GetFont();
  747.     Selection* s = sl->GetCur()->GetSelection();
  748.     s->SetFont(font);
  749.     }
  750. }
  751.  
  752. // SetPattern sets the Selections' pattern attributes with the given
  753. // pattern attribute.
  754.  
  755. void Drawing::SetPattern (IPattern* pattern) {
  756.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  757.     sl->GetCur()->GetSelection()->SetPattern(pattern);
  758.     }
  759. }
  760.  
  761. // SetPattern sets each Selection's pattern attribute with the
  762. // corresponding pattern attribute in the provided list.
  763.  
  764. void Drawing::SetPattern (IPatternList* patternlist) {
  765.     for (sl->First(), patternlist->First();
  766.      !sl->AtEnd() && !patternlist->AtEnd();
  767.      sl->Next(), patternlist->Next())
  768.     {
  769.     IPattern* pattern = patternlist->GetCur()->GetPattern();
  770.     sl->GetCur()->GetSelection()->SetPattern(pattern);
  771.     }
  772. }
  773.  
  774. // Append appends the Selections to the picture.
  775.  
  776. void Drawing::Append () {
  777.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  778.     Selection* s = sl->GetCur()->GetSelection();
  779.     picture->Append(s);
  780.     }
  781. }
  782.  
  783. // Group groups each parent's children, if any, under their parent and
  784. // returns the resulting Selections in the SelectionList.
  785.  
  786. void Drawing::Group (GroupList* grouplist) {
  787.     if (grouplist->Size() >= 1) {
  788.     sl->DeleteAll();
  789.     for (grouplist->First(); !grouplist->AtEnd(); grouplist->Next()) {
  790.         GroupNode* gn = grouplist->GetCur();
  791.         PictSelection* parent = gn->GetParent();
  792.         boolean haschildren = gn->GetHasChildren();
  793.         SelectionList* children = gn->GetChildren();
  794.         SelectionList* childrengs = gn->GetChildrenGS();
  795.         if (haschildren) {
  796.         for (children->First(), childrengs->First();
  797.              !children->AtEnd() && !childrengs->AtEnd();
  798.              children->Next(), childrengs->Next())
  799.         {
  800.             Graphic* child = children->GetCur()->GetSelection();
  801.             Graphic* childgs = childrengs->GetCur()->GetSelection();
  802.             *child = *childgs;
  803.             picture->SetCurrent(child);
  804.             picture->Remove(child);
  805.             parent->Append(child);
  806.         }
  807.         picture->InsertBeforeCur(parent);
  808.         }
  809.         sl->Append(new SelectionNode(parent));
  810.     }
  811.     Sort();
  812.     }
  813. }
  814.  
  815. // InsertAfterPrev inserts each Selection after its corresponding
  816. // predecessor in the provided list.
  817.  
  818. void Drawing::InsertAfterPrev (SelectionList* prevlist) {
  819.     for (sl->First(), prevlist->First(); !sl->AtEnd() && !prevlist->AtEnd();
  820.      sl->Next(), prevlist->Next())
  821.     {
  822.     Selection* prev = prevlist->GetCur()->GetSelection();
  823.     picture->SetCurrent(prev);
  824.     Selection* s = sl->GetCur()->GetSelection();
  825.     picture->InsertAfterCur(s);
  826.     }
  827. }
  828.  
  829. // Prepend prepends the Selections to the picture.
  830.  
  831. void Drawing::Prepend () {
  832.     for (sl->Last(); !sl->AtEnd(); sl->Prev()) {
  833.     Selection* s = sl->GetCur()->GetSelection();
  834.     picture->Prepend(s);
  835.     }
  836. }
  837.  
  838. // Remove removes the Selections from the picture.
  839.  
  840. void Drawing::Remove () {
  841.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  842.     Selection* s = sl->GetCur()->GetSelection();
  843.     picture->Remove(s);
  844.     }
  845. }
  846.  
  847. // Replace replaces a Selection in the picture with a Selection not in it.
  848.  
  849. void Drawing::Replace (Selection* replacee, Selection* replacer) {
  850.     picture->SetCurrent(replacee);
  851.     picture->Remove(replacee);
  852.     picture->InsertBeforeCur(replacer);
  853. }
  854.  
  855. // Sort sorts the Selections so they occur in the same order as they
  856. // do in the picture.
  857.  
  858. void Drawing::Sort () {
  859.     if (sl->Size() >= 2) {
  860.     for (picture->First(); !picture->AtEnd(); picture->Next()) {
  861.         Selection* g = picture->GetCurrent();
  862.         if (sl->Find(g)) {
  863.         SelectionNode* s = sl->GetCur();
  864.         sl->RemoveCur();
  865.         sl->Append(s);
  866.         }
  867.     }
  868.     }
  869. }
  870.  
  871. // Ungroup replaces all Selections which contain children with their
  872. // children and returns the resulting Selections in the SelectionList.
  873.  
  874. void Drawing::Ungroup (GroupList* grouplist) {
  875.     if (grouplist->Size() >= 1) {
  876.     sl->DeleteAll();
  877.     for (grouplist->First(); !grouplist->AtEnd(); grouplist->Next()) {
  878.         GroupNode* gn = grouplist->GetCur();
  879.         PictSelection* parent = gn->GetParent();
  880.         boolean haschildren = gn->GetHasChildren();
  881.         SelectionList* children = gn->GetChildren();
  882.         if (haschildren) {
  883.         parent->Propagate();
  884.         picture->SetCurrent(parent);
  885.         for (children->First(); !children->AtEnd(); children->Next()) {
  886.             Selection* child = children->GetCur()->GetSelection();
  887.             parent->Remove(child);
  888.             picture->InsertBeforeCur(child);
  889.             sl->Append(new SelectionNode(child));
  890.         }
  891.         picture->Remove(parent);
  892.         } else {
  893.         sl->Append(new SelectionNode(parent));
  894.         }
  895.     }
  896.     Sort();
  897.     }
  898. }
  899.  
  900. // NumberOfGraphics returns the number of graphics in the picture,
  901. // calling itself recursively to count the number of graphics in
  902. // subpictures.
  903.  
  904. int Drawing::NumberOfGraphics (PictSelection* picture) {
  905.     int num = 0;
  906.     for (picture->First(); !picture->AtEnd(); picture->Next()) {
  907.     Selection* s = picture->GetCurrent();
  908.     if (s->HasChildren()) {
  909.         num += NumberOfGraphics((PictSelection*) s);
  910.     } else {
  911.         ++num;
  912.     }
  913.     }
  914.     return num;
  915. }
  916.