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 / EDITOR1.C < prev    next >
C/C++ Source or Header  |  1991-12-30  |  33KB  |  1,301 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: editor.c,v 1.24 90/02/05 16:16:53 linton Exp $ */
  24.  
  25. /*
  26.  * implements class Editor.
  27.  */
  28.  
  29. #include "dialogbox.h"
  30. #include "drawing.h"
  31. #include "drawingview.h"
  32. #include "editor.h"
  33. #include "history.h"
  34. #include "idraw.h"
  35. #include "listchange.h"
  36. #include "listselectn.h"
  37. #include "rubbands.h"
  38. #include "slellipses.h"
  39. #include "sllines.h"
  40. #include "slpolygons.h"
  41. #include "slsplines.h"
  42. #include "sltext.h"
  43. #include "state.h"
  44. #include "textedit.h"
  45. #include "version.h"
  46. #include <InterViews/event.h>
  47. #include <InterViews/transformer.h>
  48. #include <InterViews/Graphic/util.h>
  49. #include <stdio.h>
  50.  
  51. void Editor::HandleSelect (Event& e) {
  52.     Selection* pick = drawing->PickSelectionIntersecting(e.x, e.y);
  53.     if (!e.shift) {        /* replacing previous Selections */
  54.     drawingview->EraseHandles();
  55.     if (pick != nil) {
  56.         drawing->Select(pick);
  57.     } else {
  58.         RubberRect* rubberrect =
  59.         new RubberRect(nil, nil, e.x, e.y, e.x, e.y);
  60.         drawingview->Manipulate(e, rubberrect, UpEvent, false);
  61.         Coord l, b, r, t;
  62.         rubberrect->GetCurrent(l, b, r, t);
  63.         delete rubberrect;
  64.  
  65.         SelectionList* picklist= drawing->PickSelectionsWithin(l, b, r, t);
  66.         drawing->Select(picklist);
  67.         delete picklist;
  68.     }
  69.     } else {            /* extending Selections */
  70.     if (pick != nil) {
  71.         drawingview->ErasePickedHandles(pick);
  72.         drawing->Extend(pick);
  73.     } else {
  74.         RubberRect* rubberrect =
  75.         new RubberRect(nil, nil, e.x, e.y, e.x, e.y);
  76.         drawingview->Manipulate(e, rubberrect, UpEvent, false);
  77.         Coord l, b, r, t;
  78.         rubberrect->GetCurrent(l, b, r, t);
  79.         delete rubberrect;
  80.  
  81.         SelectionList* picklist= drawing->PickSelectionsWithin(l, b, r, t);
  82.         drawingview->ErasePickedHandles(picklist);
  83.         drawing->Extend(picklist);
  84.         delete picklist;
  85.     }
  86.     }
  87.     drawingview->DrawHandles();
  88. }
  89.  
  90. /*
  91.  * HandleMove lets the user manipulate a sliding rectangle enclosing
  92.  * the Selections and moves them the same way when the user releases
  93.  * the button.
  94.  */
  95.  
  96. void Editor::HandleMove (Event& e) {
  97.     Selection* pick = drawing->PickSelectionIntersecting(e.x, e.y);
  98.     if (pick != nil) {
  99.     drawingview->EraseUngraspedHandles(pick);
  100.     drawing->Grasp(pick);
  101.     drawingview->DrawHandles();
  102.  
  103.     Coord l, b, r, t;
  104.     drawing->GetBox(l, b, r, t);
  105.     state->Constrain(e.x, e.y);
  106.     SlidingRect* slidingrect =
  107.         new SlidingRect(nil, nil, l, b, r, t, e.x, e.y);
  108.     drawingview->Manipulate(e, slidingrect, UpEvent);
  109.     Coord nl, nb, nr, nt;
  110.     slidingrect->GetCurrent(nl, nb, nr, nt);
  111.     delete slidingrect;
  112.  
  113.     if (nl != l || nb != b) {
  114.         float x0, y0, x1, y1;
  115.         Transformer t;
  116.         drawing->GetPictureTT(t);
  117.         t.InvTransform(float(l), float(b), x0, y0);
  118.         t.InvTransform(float(nl), float(nb), x1, y1);
  119.         Do(new MoveChange(drawing, drawingview, x1 - x0, y1 - y0));
  120.     }
  121.     }
  122. }
  123.  
  124. /*
  125.  * HandleScale lets the user manipulate a scaling rectangle enclosing
  126.  * the picked Selection and scales the Selections to the new scale
  127.  * when the user releases the button.
  128.  */
  129.  
  130. void Editor::HandleScale (Event& e) {
  131.     Selection* pick = drawing->PickSelectionIntersecting(e.x, e.y);
  132.     if (pick != nil) {
  133.     drawingview->EraseUngraspedHandles(pick);
  134.     drawing->Grasp(pick);
  135.     drawingview->DrawHandles();
  136.  
  137.     float l, b, r, t;
  138.     pick->GetBounds(l, b, r, t);
  139.     float cx, cy;
  140.     pick->GetCenter(cx, cy);
  141.     ScalingRect* scalingrect =
  142.         new ScalingRect(nil, nil, round(l), round(b), round(r), round(t),
  143.                 round(cx), round(cy));
  144.     drawingview->Manipulate(e, scalingrect, UpEvent);
  145.     float scale = scalingrect->CurrentScaling();
  146.     delete scalingrect;
  147.  
  148.     if (scale != 0) {
  149.         Do(new ScaleChange(drawing, drawingview, scale, scale));
  150.     }
  151.     }
  152. }
  153.  
  154. /*
  155.  * HandleStretch lets the user manipulate a stretching rectangle
  156.  * enclosing the picked Selection and stretches the Selections the
  157.  * same way when the user releases the button.
  158.  */
  159.  
  160. void Editor::HandleStretch (Event& e) {
  161.     Selection* pick = drawing->PickSelectionIntersecting(e.x, e.y);
  162.     if (pick != nil) {
  163.     drawingview->EraseUngraspedHandles(pick);
  164.     drawing->Grasp(pick);
  165.     drawingview->DrawHandles();
  166.  
  167.     float l, b, r, t;
  168.     pick->GetBounds(l, b, r, t);
  169.     IStretchingRect* istretchingrect = new
  170.         IStretchingRect(nil, nil, round(l), round(b), round(r), round(t));
  171.     drawingview->Manipulate(e, istretchingrect, UpEvent);
  172.     float stretch = istretchingrect->CurrentStretching();
  173.     Alignment side = istretchingrect->CurrentSide(drawing->GetLandscape());
  174.     delete istretchingrect;
  175.  
  176.     if (stretch != 0) {
  177.         Do(new StretchChange(drawing, drawingview, stretch, side));
  178.     }
  179.     }
  180. }
  181.  
  182. /*
  183.  * HandleRotate lets the user manipulate a rotating rectangle
  184.  * enclosing the picked Selection and rotates the Selections the same
  185.  * way when the user releases the button.
  186.  */
  187.  
  188. void Editor::HandleRotate (Event& e) {
  189.     Selection* pick = drawing->PickSelectionIntersecting(e.x, e.y);
  190.     if (pick != nil) {
  191.     drawingview->EraseUngraspedHandles(pick);
  192.     drawing->Grasp(pick);
  193.     drawingview->DrawHandles();
  194.  
  195.     Coord l, b, r, t;
  196.     pick->GetBox(l, b, r, t);
  197.     float cx, cy;
  198.     pick->GetCenter(cx, cy);
  199.     state->Constrain(e.x, e.y);
  200.     RotatingRect* rotatingrect =
  201.         new RotatingRect(nil, nil, l, b, r, t, round(cx), round(cy),
  202.                  e.x, e.y);
  203.     drawingview->Manipulate(e, rotatingrect, UpEvent);
  204.     float angle = rotatingrect->CurrentAngle();
  205.     delete rotatingrect;
  206.  
  207.     if (angle != 0) {
  208.         Do(new RotateChange(drawing, drawingview, angle));
  209.     }
  210.     }
  211. }
  212.  
  213. /*
  214.  * HandleReshape lets the user reshape an already existing Selection
  215.  * and replaces the Selection with the reshaped Selection.  Text
  216.  * Selections "reshape" themselves using different code below.
  217.  */
  218.  
  219. void Editor::HandleReshape (Event& e) {
  220.     Selection* pick = drawing->PickSelectionShapedBy(e.x, e.y);
  221.     if (pick != nil) {
  222.     drawingview->EraseHandles();
  223.     drawing->Select(pick);
  224.     drawingview->DrawHandles();
  225.     Selection* reshapedpick = nil;
  226.     if (pick->IsA(TEXTSELECTION)) {
  227.         int len;
  228.         const char* text = ((TextSelection*) pick)->GetOriginal(len);
  229.         TextEdit* textedit = new TextEdit(text, len);
  230.         drawingview->EraseHandles();
  231.         drawingview->Edit(e, textedit, pick);
  232.         text = textedit->GetText(len);
  233.         reshapedpick = new TextSelection(text, len, pick);
  234.         delete textedit;
  235.     } else {
  236.         Rubberband* shape = pick->CreateShape(e.x, e.y);
  237.         drawingview->Manipulate(e, shape, UpEvent);
  238.         reshapedpick = pick->GetReshapedCopy();
  239.     }
  240.     if (reshapedpick != nil) {
  241.         Do(new ReplaceChange(drawing, drawingview, pick, reshapedpick));
  242.     }
  243.     }
  244. }
  245.  
  246. /*
  247.  * HandleMagnify lets the user manipulate a rubber rectangle and
  248.  * expands the given area to fill the view.
  249.  */
  250.  
  251. void Editor::HandleMagnify (Event& e) {
  252.     RubberRect* rubberrect = NewRubberRectOrSquare(e);
  253.     drawingview->Manipulate(e, rubberrect, UpEvent, false);
  254.     Coord fx, fy;
  255.     rubberrect->GetCurrent(fx, fy, e.x, e.y);
  256.     delete rubberrect;
  257.  
  258.     drawingview->Magnify(fx, fy, e.x, e.y);
  259. }
  260.  
  261. /*
  262.  * HandleText lets the user type some text and creates a new
  263.  * TextSelection when the user finishes typing the text.  It must
  264.  * clear the selection list because DrawingView will redraw the
  265.  * handles obscured by the TextEdit if the list's not empty.
  266.  */
  267.  
  268. void Editor::HandleText (Event& e) {
  269.     drawingview->EraseHandles();
  270.     drawing->Clear();
  271.     TextEdit* textedit = new TextEdit;
  272.     drawingview->Edit(e, textedit);
  273.     int len;
  274.     const char* text = textedit->GetText(len);
  275.     if (len > 0) {
  276.     drawing->Select(new TextSelection(text, len, state->GetTextGS()));
  277.     Do(new AddChange(drawing, drawingview));
  278.     }
  279.     delete textedit;
  280. }
  281.  
  282. /*
  283.  * HandleLine lets the user manipulate a rubber line and creates
  284.  * a LineSelection when the user releases the button.
  285.  */
  286.  
  287. void Editor::HandleLine (Event& e) {
  288.     drawingview->EraseHandles();
  289.     state->Constrain(e.x, e.y);
  290.     RubberLine* rubberline = NewRubberLineOrAxis(e);
  291.     drawingview->Manipulate(e, rubberline, UpEvent);
  292.     Coord x0, y0, x1, y1;
  293.     rubberline->GetCurrent(x0, y0, x1, y1);
  294.     delete rubberline;
  295.  
  296.     if (x0 != x1 || y0 != y1) {
  297.     drawing->Select(
  298.         new LineSelection(x0, y0, x1, y1, state->GetGraphicGS())
  299.     );
  300.     Do(new AddChange(drawing, drawingview));
  301.     }
  302. }
  303.  
  304. /*
  305.  * HandleMultiLine lets the user draw a series of connected lines and
  306.  * creates a MultiLineSelection when the user presses the middle
  307.  * button.
  308.  */
  309.  
  310. void Editor::HandleMultiLine (Event& e) {
  311.     Coord* x;
  312.     Coord* y;
  313.     int n;
  314.  
  315.     drawingview->EraseHandles();
  316.     InputVertices(e, x, y, n);
  317.  
  318.     if (n != 2 || x[0] != x[1] || y[0] != y[1]) {
  319.     drawing->Select(
  320.         new MultiLineSelection(x, y, n, state->GetGraphicGS())
  321.     );
  322.     Do(new AddChange(drawing, drawingview));
  323.     }
  324. }
  325.  
  326. /*
  327.  * HandleBSpline lets the user draw a series of connected lines and
  328.  * creates a BSplineSelection when the user presses the middle button.
  329.  */
  330.  
  331. void Editor::HandleBSpline (Event& e) {
  332.     Coord* x;
  333.     Coord* y;
  334.     int n;
  335.  
  336.     drawingview->EraseHandles();
  337.     InputVertices(e, x, y, n);
  338.  
  339.     if (n != 2 || x[0] != x[1] || y[0] != y[1]) {
  340.     drawing->Select(
  341.         new BSplineSelection(x, y, n, state->GetGraphicGS())
  342.     );
  343.     Do(new AddChange(drawing, drawingview));
  344.     }
  345. }
  346.  
  347. /*
  348.  * HandleEllipse lets the user manipulate a rubber ellipse and creates
  349.  * an EllipseSelection when the user releases the button.
  350.  */
  351.  
  352. void Editor::HandleEllipse (Event& e) {
  353.     drawingview->EraseHandles();
  354.     state->Constrain(e.x, e.y);
  355.     RubberEllipse* rubberellipse = NewRubberEllipseOrCircle(e);
  356.     drawingview->Manipulate(e, rubberellipse, UpEvent);
  357.     Coord cx, cy, rx, ry;
  358.     int xr, yr;
  359.     rubberellipse->GetCurrent(cx, cy, rx, ry);
  360.     rubberellipse->CurrentRadii(xr, yr);
  361.     delete rubberellipse;
  362.  
  363.     if (xr > 0 || yr > 0) {
  364.     drawing->Select(
  365.         new EllipseSelection(cx, cy, xr, yr, state->GetGraphicGS())
  366.             );
  367.     Do(new AddChange(drawing, drawingview));
  368.     }
  369. }
  370.  
  371. /*
  372.  * HandleRect lets the user manipulate a rubber rectangle and creates
  373.  * a RectSelection when the user releases the button.
  374.  */
  375.  
  376. void Editor::HandleRect (Event& e) {
  377.     drawingview->EraseHandles();
  378.     state->Constrain(e.x, e.y);
  379.     RubberRect* rubberrect = NewRubberRectOrSquare(e);
  380.     drawingview->Manipulate(e, rubberrect, UpEvent);
  381.     Coord l, b, r, t;
  382.     rubberrect->GetCurrent(l, b, r, t);
  383.     delete rubberrect;
  384.  
  385.     if (l != r || b != t) {
  386.     drawing->Select(new RectSelection(l, b, r, t, state->GetGraphicGS()));
  387.     Do(new AddChange(drawing, drawingview));
  388.     }
  389. }
  390.  
  391. /*
  392.  * HandlePolygon lets the user draw a series of connected lines and
  393.  * creates a PolygonSelection when the user presses the middle button.
  394.  */
  395.  
  396. void Editor::HandlePolygon (Event& e) {
  397.     Coord* x;
  398.     Coord* y;
  399.     int n;
  400.  
  401.     drawingview->EraseHandles();
  402.     InputVertices(e, x, y, n);
  403.  
  404.     if (n != 2 || x[0] != x[1] || y[0] != y[1]) {
  405.     drawing->Select(new PolygonSelection(x, y, n, state->GetGraphicGS()));
  406.     Do(new AddChange(drawing, drawingview));
  407.     }
  408. }
  409.  
  410. /*
  411.  * HandleClosedBSpline lets the user draw a series of connected lines
  412.  * and creates a ClosedBSplineSelection when the user presses the
  413.  * middle button.
  414.  */
  415.  
  416. void Editor::HandleClosedBSpline (Event& e) {
  417.     Coord* x;
  418.     Coord* y;
  419.     int n;
  420.  
  421.     drawingview->EraseHandles();
  422.     InputVertices(e, x, y, n);
  423.  
  424.     if (n != 2 || x[0] != x[1] || y[0] != y[1]) {
  425.     drawing->Select(
  426.         new ClosedBSplineSelection(x, y, n, state->GetGraphicGS())
  427.     );
  428.     Do(new AddChange(drawing, drawingview));
  429.     }
  430. }
  431.  
  432. /*
  433.  * New offers to write an unsaved drawing and creates a new empty
  434.  * drawing if the save succeeds or the user refuses the offer.
  435.  */
  436.  
  437. void Editor::New () {
  438.     boolean successful = OfferToSave();
  439.     if (successful) {
  440.     drawing->ClearPicture();
  441.     Reset(nil);
  442.     }
  443. }
  444.  
  445. /*
  446.  * Revert rereads the drawing from its file.  It asks for confirmation
  447.  * before reverting an unsaved drawing.
  448.  */
  449.  
  450. void Editor::Revert () {
  451.     const char* name = state->GetDrawingName();
  452.     if (name != nil) {
  453.     char response = revertdialog->Confirm();
  454.     if (response == 'y') {
  455.         boolean successful = drawing->ReadPicture(name, state);
  456.         if (successful) {
  457.         Reset(name);
  458.         } else {
  459.         savecurdialog->
  460.             SetWarning("couldn't revert! (file nonexistent?)");
  461.         Open();
  462.         }
  463.     }
  464.     }
  465. }
  466.  
  467. /*
  468.  * Open reads a drawing from the given file.  If it fails, it calls
  469.  * the interactive Open to ask the user to type another name.
  470.  */
  471.  
  472. void Editor::Open (const char* name) {
  473.     boolean successful = drawing->ReadPicture(name, state);
  474.     if (successful) {
  475.     Reset(name);
  476.     } else {
  477.     opendialog->SetTitle("Open failed!");
  478.     Open();
  479.     }
  480. }
  481.  
  482. /*
  483.  * Open prompts for a file name and reads a drawing from that file.
  484.  * It offers to save an unsaved drawing and it keeps trying to read a
  485.  * drawing until it succeeds or the user cancels the command.
  486.  */
  487.  
  488. void Editor::Open () {
  489.     boolean successful = OfferToSave();
  490.     if (successful) {
  491.     const char* name = nil;
  492.     for (;;) {
  493.         name = opendialog->Find();
  494.         if (name == nil) {
  495.         break;
  496.         }
  497.         boolean successful = drawing->ReadPicture(name, state);
  498.         if (successful) {
  499.         Reset(name);
  500.         break;
  501.         } else {
  502.         opendialog->SetTitle("Open failed!");
  503.         }
  504.     }
  505.     }
  506. }
  507.  
  508. /*
  509.  * Save writes the drawing to the file it was read from unless there's
  510.  * no file or it can't write the drawing to that file, in which case
  511.  * it hands the job off to SaveAs.
  512.  */
  513.  
  514. void Editor::Save () {
  515.     const char* name = state->GetDrawingName();
  516.     if (name == nil) {
  517.     SaveAs();
  518.     } else if (state->GetModifStatus() == ReadOnly) {
  519.     saveasdialog->SetTitle("Can't save in read-only file!");
  520.     SaveAs();
  521.     } else {
  522.     boolean successful = drawing->WritePicture(name, state);
  523.     if (successful) {
  524.         state->SetModifStatus(Unmodified);
  525.         state->UpdateViews();
  526.     } else {
  527.         saveasdialog->SetTitle("Couldn't save!");
  528.         SaveAs();
  529.     }
  530.     }
  531. }
  532.  
  533. /*
  534.  * SaveAs prompts for a file name and writes the drawing to that file.
  535.  * It asks for confirmation before overwriting an already existing
  536.  * file and it keeps trying to write the drawing until it succeeds or
  537.  * the user cancels the command.
  538.  */
  539.  
  540. void Editor::SaveAs () {
  541.     const char* name = nil;
  542.     for (;;) {
  543.     name = saveasdialog->Find();
  544.     if (name == nil) {
  545.         break;
  546.     }
  547.     if (drawing->Exists(name)) {
  548.         overwritedialog->SetWarning("a drawing named ", name);
  549.         char response = overwritedialog->Confirm();
  550.         if (response != 'y') {
  551.         break;
  552.         }
  553.     }
  554.     boolean successful = drawing->WritePicture(name, state);
  555.     if (successful) {
  556.         state->SetDrawingName(name);
  557.         state->SetModifStatus(Unmodified);
  558.         state->UpdateViews();
  559.         break;
  560.     } else {
  561.         saveasdialog->SetTitle("Couldn't save!");
  562.     }
  563.     }
  564.     saveasdialog->SetTitle("");
  565. }
  566.  
  567. /*
  568.  * Print prompts for a print command and writes the drawing through a
  569.  * pipe to that command's standard input.  It keeps trying to print
  570.  * the drawing until it succeeds or the user cancels the command.
  571.  */
  572.  
  573. void Editor::Print () {
  574.     if (state->GetModifStatus() == Modified) {
  575.     savecurdialog->SetWarning("a broken pipe signal won't be caught");
  576.     }
  577.     boolean successful = OfferToSave();
  578.     if (successful) {
  579.     char* cmd = nil;
  580.     for (;;) {
  581.         delete cmd;
  582.         cmd = printdialog->Edit(nil);
  583.         if (cmd == nil) {
  584.         break;
  585.         }
  586.         boolean successful = drawing->PrintPicture(cmd, state);
  587.         if (successful) {
  588.         break;
  589.         } else {
  590.         printdialog->SetWarning("couldn't execute ", cmd);
  591.         }
  592.     }
  593.     delete cmd;
  594.     }
  595. }
  596.  
  597. /*
  598.  * Quit offers to save an unsaved drawing and tells Idraw to quit
  599.  * running if the save succeeds or the user refuses the offer.
  600.  */
  601.  
  602. void Editor::Quit (Event& e) {
  603.     boolean successful = OfferToSave();
  604.     if (successful) {
  605.     e.target = nil;
  606.     }
  607. }
  608.  
  609. /*
  610.  * Checkpoint writes an unsaved drawing to a temporary filename.  The
  611.  * program currently calls Checkpoint only when an X error occurs.
  612.  */
  613.  
  614. void Editor::Checkpoint () {
  615.     if (state->GetModifStatus() == Modified) {
  616.     char* path = tempnam("./", "idraw");
  617.     boolean successful = drawing->WritePicture(path, state);
  618.     if (successful) {
  619.         fprintf(stderr, "saved drawing as \"%s\"\n", path);
  620.     } else {
  621.         fprintf(stderr, "sorry, couldn't save drawing as \"%s\"\n", path);
  622.     }
  623.     delete path;
  624.     } else {
  625.     fprintf(stderr, "drawing was unmodified, didn't save it\n");
  626.     }
  627. }
  628.  
  629. /*
  630.  * Undo undoes the last change made to the drawing.  Undo does nothing
  631.  * if all stored changes have been undone.
  632.  */
  633.  
  634. void Editor::Undo () {
  635.     history->Undo();
  636. }
  637.  
  638. /*
  639.  * Redo redoes the last undone change made to the drawing, i.e., it
  640.  * undoes an Undo.  Redo does nothing if it follows a Do.
  641.  */
  642.  
  643. void Editor::Redo () {
  644.     history->Redo();
  645. }
  646.  
  647. /*
  648.  * Cut removes the Selections and writes them to the clipboard file,
  649.  * overwriting whatever was there previously.
  650.  */
  651.  
  652. void Editor::Cut () {
  653.     Do(new CutChange(drawing, drawingview));
  654. }
  655.  
  656. /*
  657.  * Copy copies the Selections and writes them to the clipboard file,
  658.  * overwriting whatever was there previously.
  659.  */
  660.  
  661. void Editor::Copy () {
  662.     Do(new CopyChange(drawing, drawingview));
  663. }
  664.  
  665. /*
  666.  * Paste reads new Selections from the clipboard file and appends them
  667.  * to the drawing.
  668.  */
  669.  
  670. void Editor::Paste () {
  671.     Do(new PasteChange(drawing, drawingview, state));
  672. }
  673.  
  674. /*
  675.  * Duplicate duplicates the Selections and appends the new Selections
  676.  * to the drawing.
  677.  */
  678.  
  679. void Editor::Duplicate () {
  680.     Do(new DuplicateChange(drawing, drawingview));
  681. }
  682.  
  683. /*
  684.  * Delete deletes all of the Selections.
  685.  */
  686.  
  687. void Editor::Delete () {
  688.     Do(new DeleteChange(drawing, drawingview));
  689. }
  690.  
  691. /*
  692.  * SelectAll selects all of the Selections in the drawing.
  693.  */
  694.  
  695. void Editor::SelectAll () {
  696.     drawing->SelectAll();
  697.     drawingview->DrawHandles();
  698. }
  699.  
  700. /*
  701.  * FlipHorizontal flips the Selections horizontally by scaling them by
  702.  * -1 along the x axis about their centers.
  703.  */
  704.  
  705. void Editor::FlipHorizontal () {
  706.     Do(new ScaleChange(drawing, drawingview, -1, 1));
  707. }
  708.  
  709. /*
  710.  * FlipVertical flips the Selections vertically by scaling them by -1
  711.  * along the y axis about their centers.
  712.  */
  713.  
  714. void Editor::FlipVertical () {
  715.     Do(new ScaleChange(drawing, drawingview, 1, -1));
  716. }
  717.  
  718. /*
  719.  * _90Clockwise rotates the Selections 90 degrees clockwise about
  720.  * their centers.
  721.  */
  722.  
  723. void Editor::_90Clockwise () {
  724.     Do(new RotateChange(drawing, drawingview, -90.));
  725. }
  726.  
  727. /*
  728.  * _90CounterCW rotates the Selections 90 degrees counter-clockwise
  729.  * about their centers.
  730.  */
  731.  
  732. void Editor::_90CounterCW () {
  733.     Do(new RotateChange(drawing, drawingview, 90.));
  734. }
  735.  
  736. /*
  737.  * PreciseMove prompts the user for the x and y movement in units of
  738.  * points or pixels and moves the Selections that far.
  739.  */
  740.  
  741. void Editor::PreciseMove () {
  742.     char* movement = nil;
  743.     for (;;) {
  744.     delete movement;
  745.     movement = precmovedialog->Edit(nil);
  746.     if (movement == nil) {
  747.         break;
  748.     }
  749.     float xdisp, ydisp;
  750.     char unit;
  751.     if (sscanf(movement, "%f %f p%c", &xdisp, &ydisp, &unit) == 3) {
  752.         if (xdisp != 0 || ydisp != 0) {
  753.         if (unit != 'i') {
  754.             xdisp *= points;
  755.             ydisp *= points;
  756.         }
  757.         Do(new MoveChange(drawing, drawingview, xdisp, ydisp));
  758.         }
  759.         break;
  760.     } else {
  761.         precmovedialog->SetWarning("couldn't parse ", movement);
  762.     }
  763.     }
  764.     delete movement;
  765. }
  766.  
  767. /*
  768.  * PreciseScale prompts the user for the x and y scales and scales the
  769.  * Selections that much about their centers.
  770.  */
  771.  
  772. void Editor::PreciseScale () {
  773.     char* scaling = nil;
  774.     for (;;) {
  775.     delete scaling;
  776.     scaling = precscaledialog->Edit(nil);
  777.     if (scaling == nil) {
  778.         break;
  779.     }
  780.     float xscale, yscale;
  781.     if (sscanf(scaling, "%f %f", &xscale, &yscale) == 2) {
  782.         if (xscale !=0 && yscale != 0) {
  783.         Do(new ScaleChange(drawing, drawingview, xscale, yscale));
  784.         }
  785.         break;
  786.     } else {
  787.         precscaledialog->SetWarning("couldn't parse ", scaling);
  788.     }
  789.     }
  790.     delete scaling;
  791. }
  792.  
  793. /*
  794.  * PreciseRotate prompts the user for the angle and rotates the
  795.  * Selections that many degrees about their centers.
  796.  */
  797.  
  798. void Editor::PreciseRotate () {
  799.     char* rotation = nil;
  800.     for (;;) {
  801.     delete rotation;
  802.     rotation = precrotdialog->Edit(nil);
  803.     if (rotation == nil) {
  804.         break;
  805.     }
  806.     float angle;
  807.     if (sscanf(rotation, "%f", &angle) == 1) {
  808.         if (angle != 0) {
  809.         Do(new RotateChange(drawing, drawingview, angle));
  810.         }
  811.         break;
  812.     } else {
  813.         precrotdialog->SetWarning("couldn't parse ", rotation);
  814.     }
  815.     }
  816.     delete rotation;
  817. }
  818.  
  819. /*
  820.  * Group groups the Selections together.
  821.  */
  822.  
  823. void Editor::Group () {
  824.     Do(new GroupChange(drawing, drawingview));
  825. }
  826.  
  827. /*
  828.  * Ungroup ungroups each PictSelection into its component Selections.
  829.  */
  830.  
  831. void Editor::Ungroup () {
  832.     Do(new UngroupChange(drawing, drawingview));
  833. }
  834.  
  835. /*
  836.  * BringToFront brings the Selections to the front of the drawing.
  837.  */
  838.  
  839. void Editor::BringToFront () {
  840.     Do(new BringToFrontChange(drawing, drawingview));
  841. }
  842.  
  843. /*
  844.  * SendToBack sends the Selections to the back of the drawing.
  845.  */
  846.  
  847. void Editor::SendToBack () {
  848.     Do(new SendToBackChange(drawing, drawingview));
  849. }
  850.  
  851. /*
  852.  * NumberOfGraphics counts the number of graphics in the drawing and
  853.  * displays the count.
  854.  */
  855.  
  856. void Editor::NumberOfGraphics () {
  857.     int num = drawing->GetNumberOfGraphics();
  858.     if (num == 1) {
  859.     numberofdialog->SetMessage("The selections contain 1 graphic.");
  860.     } else {
  861.     char buf[50];
  862.     sprintf(buf, "The selections contain %d graphics.", num);
  863.     numberofdialog->SetMessage(buf);
  864.     }
  865.     numberofdialog->Display();
  866. }
  867.  
  868. /*
  869.  * SetBrush sets the Selections' brush and updates the views to
  870.  * display the new current brush.
  871.  */
  872.  
  873. void Editor::SetBrush (IBrush* brush) {
  874.     state->SetBrush(brush);
  875.     state->UpdateViews();
  876.     Do(new SetBrushChange(drawing, drawingview, brush));
  877. }
  878.  
  879. /*
  880.  * SetFgColor sets the Selections' foreground color and updates the
  881.  * views to display the new current foreground color.
  882.  */
  883.  
  884. void Editor::SetFgColor (IColor* fg) {
  885.     state->SetFgColor(fg);
  886.     state->UpdateViews();
  887.     Do(new SetFgColorChange(drawing, drawingview, fg));
  888. }
  889.  
  890. /*
  891.  * SetBgColor sets the Selections' background color and updates the
  892.  * views to display the new current background color.
  893.  */
  894.  
  895. void Editor::SetBgColor (IColor* bg) {
  896.     state->SetBgColor(bg);
  897.     state->UpdateViews();
  898.     Do(new SetBgColorChange(drawing, drawingview, bg));
  899. }
  900.  
  901. /*
  902.  * SetFont sets the Selections' font and updates the views to display
  903.  * the new current font.
  904.  */
  905.  
  906. void Editor::SetFont (IFont* font) {
  907.     state->SetFont(font);
  908.     state->UpdateViews();
  909.     Do(new SetFontChange(drawing, drawingview, font));
  910. }
  911.  
  912. /*
  913.  * SetPattern sets the Selections' pattern and updates the views to
  914.  * display the new current pattern.
  915.  */
  916.  
  917. void Editor::SetPattern (IPattern* pattern) {
  918.     state->SetPattern(pattern);
  919.     state->UpdateViews();
  920.     Do(new SetPatternChange(drawing, drawingview, pattern));
  921. }
  922.  
  923. /*
  924.  * AlignLeftSides aligns the rest of the Selections's left sides with
  925.  * the first Selection's left side.
  926.  */
  927.  
  928. void Editor::AlignLeftSides () {
  929.     Do(new AlignChange(drawing, drawingview, Left, Left));
  930. }
  931.  
  932. /*
  933.  * AlignRightSides aligns the rest of the Selections' right sides with
  934.  * the first Selection's right side.
  935.  */
  936.  
  937. void Editor::AlignRightSides () {
  938.     Do(new AlignChange(drawing, drawingview, Right, Right));
  939. }
  940.  
  941. /*
  942.  * AlignBottomSides aligns the rest of the Selections' bottom sides
  943.  * with the first Selection's bottom side.
  944.  */
  945.  
  946. void Editor::AlignBottoms () {
  947.     Do(new AlignChange(drawing, drawingview, Bottom, Bottom));
  948. }
  949.  
  950. /*
  951.  * AlignTopSides aligns the rest of the Selections' top sides with the
  952.  * first Selection's top side.
  953.  */
  954.  
  955. void Editor::AlignTops () {
  956.     Do(new AlignChange(drawing, drawingview, Top, Top));
  957. }
  958.  
  959. /*
  960.  * AlignVertCenters aligns the rest of the Selections' vertical
  961.  * centers with the first Selection's vertical center.
  962.  */
  963.  
  964. void Editor::AlignVertCenters () {
  965.     Do(new AlignChange(drawing, drawingview, VertCenter, VertCenter));
  966. }
  967.  
  968. /*
  969.  * AlignHorizCenters aligns the rest of the Selections' horizontal
  970.  * centers with the first Selection's horizontal center.
  971.  */
  972.  
  973. void Editor::AlignHorizCenters () {
  974.     Do(new AlignChange(drawing, drawingview, HorizCenter, HorizCenter));
  975. }
  976.  
  977. /*
  978.  * AlignCenters aligns the rest of the Selections' centers with the
  979.  * first Selection's center.
  980.  */
  981.  
  982. void Editor::AlignCenters () {
  983.     Do(new AlignChange(drawing, drawingview, Center, Center));
  984. }
  985.  
  986. /*
  987.  * AlignLeftToRight aligns each Selection's left side with its
  988.  * predecessor's right side.
  989.  */
  990.  
  991. void Editor::AlignLeftToRight () {
  992.     Do(new AlignChange(drawing, drawingview, Right, Left));
  993. }
  994.  
  995. /*
  996.  * AlignRightToLeft aligns each Selection's right side with its
  997.  * predecessor's left side.
  998.  */
  999.  
  1000. void Editor::AlignRightToLeft () {
  1001.     Do(new AlignChange(drawing, drawingview, Left, Right));
  1002. }
  1003.  
  1004. /*
  1005.  * AlignBottomToTop aligns each Selection's bottom side with its
  1006.  * predecessor's top side.
  1007.  */
  1008.  
  1009. void Editor::AlignBottomToTop () {
  1010.     Do(new AlignChange(drawing, drawingview, Top, Bottom));
  1011. }
  1012.  
  1013. /*
  1014.  * AlignTopToBottom aligns each Selection's top side with its
  1015.  * predecessor's bottom side.
  1016.  */
  1017.  
  1018. void Editor::AlignTopToBottom () {
  1019.     Do(new AlignChange(drawing, drawingview, Bottom, Top));
  1020. }
  1021.  
  1022. /*
  1023.  * AlignToGrid aligns the Selections' lower left corners with the
  1024.  * closest grid point.
  1025.  */
  1026.  
  1027. void Editor::AlignToGrid () {
  1028.     Do(new AlignToGridChange(drawing, drawingview));
  1029. }
  1030.  
  1031. /*
  1032.  * Reduce reduces the drawing's magnification by a factor of two.
  1033.  */
  1034.  
  1035. void Editor::Reduce () {
  1036.     drawingview->Reduce();
  1037. }
  1038.  
  1039. /*
  1040.  * Enlarge enlarges the drawing's magnification by a factor of two.
  1041.  */
  1042.  
  1043. void Editor::Enlarge () {
  1044.     drawingview->Enlarge();
  1045. }
  1046.  
  1047. /*
  1048.  * NormalSize resets the drawing's magnification.
  1049.  */
  1050.  
  1051. void Editor::NormalSize () {
  1052.     drawingview->NormalSize();
  1053. }
  1054.  
  1055. /*
  1056.  * ReduceToFit reduces the drawing's magnification enough to fit all
  1057.  * of the drawing in the window.
  1058.  */
  1059.  
  1060. void Editor::ReduceToFit () {
  1061.     drawingview->ReduceToFit();
  1062. }
  1063.  
  1064. /*
  1065.  * CenterPage scrolls the drawing so its center coincidences with the
  1066.  * window's center.
  1067.  */
  1068.  
  1069. void Editor::CenterPage () {
  1070.     drawingview->CenterPage();
  1071. }
  1072.  
  1073. /*
  1074.  * RedrawPage redraws the drawing without moving the view.
  1075.  */
  1076.  
  1077. void Editor::RedrawPage () {
  1078.     drawingview->Draw();
  1079. }
  1080.  
  1081. /*
  1082.  * GriddingOnOff toggles the grid's constraint on or off.
  1083.  */
  1084.  
  1085. void Editor::GriddingOnOff () {
  1086.     state->SetGridGravity(!state->GetGridGravity());
  1087.     state->UpdateViews();
  1088. }
  1089.  
  1090. /*
  1091.  * GridVisibleInvisible toggles the grid's visibility on or off.
  1092.  */
  1093.  
  1094. void Editor::GridVisibleInvisible () {
  1095.     state->SetGridVisibility(!state->GetGridVisibility());
  1096.     drawingview->Draw();
  1097. }
  1098.  
  1099. /*
  1100.  * GridSpacing prompts the user for the new grid spacing in units of
  1101.  * points or pixels.
  1102.  */
  1103.  
  1104. void Editor::GridSpacing () {
  1105.     static char oldspacing[50];
  1106.     sprintf(oldspacing, "%lg", state->GetGridSpacing());
  1107.     char* spacing = nil;
  1108.     for (;;) {
  1109.     delete spacing;
  1110.     spacing = spacingdialog->Edit(oldspacing);
  1111.     if (spacing == nil) {
  1112.         break;
  1113.     }
  1114.     float s;
  1115.     char unit;
  1116.     if (sscanf(spacing, "%f p%c", &s, &unit) == 2) {
  1117.         if (s > 0.) {
  1118.         state->SetGridSpacing(s, (unit == 'i'));
  1119.         if (state->GetGridVisibility() == true) {
  1120.             drawingview->Update();
  1121.         }
  1122.         }
  1123.         break;
  1124.     } else {
  1125.         spacingdialog->SetWarning("couldn't parse ", spacing);
  1126.     }
  1127.     }
  1128.     delete spacing;
  1129. }
  1130.  
  1131. /*
  1132.  * Orientation toggles the page between portrait and landscape
  1133.  * orientations.
  1134.  */
  1135.  
  1136. void Editor::Orientation () {
  1137.     state->ToggleOrientation();
  1138.     drawingview->Update();
  1139. }
  1140.  
  1141. /*
  1142.  * ShowVersion displays idraw's version level and author.
  1143.  */
  1144.  
  1145. void Editor::ShowVersion () {
  1146.     versiondialog->Display();
  1147. }
  1148.  
  1149. /*
  1150.  * Do performs a change to the drawing and updates the drawing's
  1151.  * modification status if it was unmodified.
  1152.  */
  1153.  
  1154. void Editor::Do (ChangeNode* changenode) {
  1155.     switch (state->GetModifStatus()) {
  1156.     case Unmodified:
  1157.     history->Do(changenode);
  1158.     state->SetModifStatus(Modified);
  1159.     state->UpdateViews();
  1160.     break;
  1161.     default:
  1162.     history->Do(changenode);
  1163.     break;
  1164.     }
  1165. }
  1166.  
  1167. /*
  1168.  * InputVertices lets the user keep drawing a series of connected
  1169.  * lines until the user presses a button other than the left button.
  1170.  * It returns the vertices inputted by the user.
  1171.  */
  1172.  
  1173. void Editor::InputVertices (Event& e, Coord*& xret, Coord*& yret, int& nret) {
  1174.     const int INITIALSIZE = 100;
  1175.     static int sizebuffers = 0;
  1176.     static RubberLine** rubberlines = nil;
  1177.     static Coord* x = nil;
  1178.     static Coord* y = nil;
  1179.     if (INITIALSIZE > sizebuffers) {
  1180.     sizebuffers = INITIALSIZE;
  1181.     rubberlines = new RubberLine*[sizebuffers];
  1182.     x = new Coord[sizebuffers];
  1183.     y = new Coord[sizebuffers];
  1184.     }
  1185.  
  1186.     int n = 0;
  1187.     state->Constrain(e.x, e.y);
  1188.     rubberlines[0] = nil;
  1189.     x[0] = e.x;
  1190.     y[0] = e.y;
  1191.     ++n;
  1192.  
  1193.     while (e.button == LEFTMOUSE) {
  1194.     rubberlines[n] = NewRubberLineOrAxis(e);
  1195.     e.eventType = UpEvent;
  1196.     drawingview->Manipulate(e, rubberlines[n], DownEvent, true, false);
  1197.     Coord dummy;
  1198.     rubberlines[n]->GetCurrent(dummy, dummy, e.x, e.y);
  1199.     x[n] = e.x;
  1200.     y[n] = e.y;
  1201.     ++n;
  1202.  
  1203.     if (n == sizebuffers) {
  1204.         RubberLine** oldrubberlines = rubberlines;
  1205.         Coord* oldx = x;
  1206.         Coord* oldy = y;
  1207.         sizebuffers += INITIALSIZE/2;
  1208.         rubberlines = new RubberLine*[sizebuffers];
  1209.         x = new Coord[sizebuffers];
  1210.         y = new Coord[sizebuffers];
  1211.         memmove(rubberlines, oldrubberlines, n * sizeof(RubberLine*));
  1212.         memmove(x, oldx, n * sizeof(Coord));
  1213.         memmove(y, oldy, n * sizeof(Coord));
  1214.         delete oldrubberlines;
  1215.         delete oldx;
  1216.         delete oldy;
  1217.     }
  1218.     }
  1219.  
  1220.     xret = x;
  1221.     yret = y;
  1222.     nret = n;
  1223.     for (int i = 1; i < n; i++) {
  1224.     rubberlines[i]->Erase();
  1225.     delete rubberlines[i];
  1226.     }
  1227. }
  1228.  
  1229. /*
  1230.  * NewRubberLineOrAxis creates and returns a new RubberLine or a new
  1231.  * RubberAxis depending on whether the shift key's being depressed.
  1232.  */
  1233.  
  1234. RubberLine* Editor::NewRubberLineOrAxis (Event& e) {
  1235.     return (!e.shift ? 
  1236.         new RubberLine(nil, nil, e.x, e.y, e.x, e.y) :
  1237.         new RubberAxis(nil, nil, e.x, e.y, e.x, e.y));
  1238. }
  1239.  
  1240. /*
  1241.  * NewRubberEllipseOrCircle creates and returns a new RubberEllipse or
  1242.  * a new RubberCircle depending on the shift key's state.
  1243.  */
  1244.  
  1245. RubberEllipse* Editor::NewRubberEllipseOrCircle (Event& e) {
  1246.     return (!e.shift ?
  1247.         new RubberEllipse(nil, nil, e.x, e.y, e.x, e.y) :
  1248.         new RubberCircle(nil, nil, e.x, e.y, e.x, e.y));
  1249. }
  1250.  
  1251. /*
  1252.  * NewRubberRectOrSquare creates and returns a new RubberRect or a new
  1253.  * RubberSquare depending on whether the shift key's being depressed.
  1254.  */
  1255.  
  1256. RubberRect* Editor::NewRubberRectOrSquare (Event& e) {
  1257.     return (!e.shift ? 
  1258.         new RubberRect(nil, nil, e.x, e.y, e.x, e.y) :
  1259.         new RubberSquare(nil, nil, e.x, e.y, e.x, e.y));
  1260. }
  1261.  
  1262. /*
  1263.  * OfferToSave returns true if it saves an unsaved drawing or the user
  1264.  * refuses the offer or no changes need to be saved.
  1265.  */
  1266.  
  1267. boolean Editor::OfferToSave () {
  1268.     boolean successful = false;
  1269.     if (state->GetModifStatus() == Modified) {
  1270.     char response = savecurdialog->Confirm();
  1271.     if (response == 'y') {
  1272.         Save();
  1273.         if (state->GetModifStatus() == Unmodified) {
  1274.         successful = true;
  1275.         }
  1276.     } else if (response == 'n') {
  1277.         successful = true;
  1278.     }
  1279.     } else {
  1280.     successful = true;
  1281.     }
  1282.     return successful;
  1283. }
  1284.  
  1285. /*
  1286.  * Reset redraws the view, clears the history, and resets state
  1287.  * information about the drawing's name and its modification status.
  1288.  */
  1289.  
  1290. void Editor::Reset (const char* name) {
  1291.     history->Clear();
  1292.     state->SetDrawingName(name);
  1293.     if (name != nil && !drawing->Writable(name)) {
  1294.     state->SetModifStatus(ReadOnly);
  1295.     } else {
  1296.     state->SetModifStatus(Unmodified);
  1297.     }
  1298.     state->UpdateViews();
  1299.     drawingview->Update();
  1300. }
  1301.