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 / DRAWINGV.C < prev    next >
C/C++ Source or Header  |  1992-02-05  |  12KB  |  430 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: drawingview.c,v 1.16 89/10/09 14:47:51 linton Exp $
  24. // implements class DrawingView.
  25.  
  26. #include "drawingview.h"
  27. #include "istring.h"
  28. #include "listselectn.h"
  29. #include "page.h"
  30. #include "slpict.h"
  31. #include "state.h"
  32. #include "tedit.h"
  33. #include <InterViews/Graphic/damage.h>
  34. #include <InterViews/event.h>
  35. #include <InterViews/painter.h>
  36. #include <InterViews/perspective.h>
  37. #include <InterViews/rubband.h>
  38. #include <InterViews/sensor.h>
  39. #include <InterViews/shape.h>
  40. #include <math.h>
  41.  
  42. // DrawingView caches its canvas' contents if possible to speed up
  43. // redrawing after expose events.
  44.  
  45. static const int PAD = 0;    // we don't want any padding around graphic
  46.  
  47. DrawingView::DrawingView (Page* p) : (updownEvents, p, PAD, Center, Binary) {
  48.     damage = nil;
  49.     gs = nil;
  50.     page = p;
  51.     rasterxor = nil;
  52.     sl = nil;
  53.     state = nil;
  54.     textedit = nil;
  55.     tools = nil;
  56.     SetCanvasType(CanvasSaveContents);
  57. }
  58.  
  59. // Free storage allocated to store members.
  60.  
  61. DrawingView::~DrawingView () {
  62.     delete damage;
  63.     Unref(rasterxor);
  64. }
  65.  
  66. // Define access functions to set members' values.  Only Idraw sets
  67. // their values.
  68.  
  69. void DrawingView::SetSelectionList (SelectionList* slist) {
  70.     sl = slist;
  71. }
  72.  
  73. void DrawingView::SetState (State* s) {
  74.     state = s;
  75. }
  76.  
  77. void DrawingView::SetTools (Interactor* t) {
  78.     tools = t;
  79. }
  80.  
  81. // Draw draws the entire view.  Draw calls Check for its side effect
  82. // of flushing any redraws caused by a dialog box's removal before
  83. // drawing the view.
  84.  
  85. void DrawingView::Draw () {
  86.     if (graphic != nil) {
  87.     Graphic* backup = graphic;
  88.     graphic = nil;
  89.     Check();
  90.     graphic = backup;
  91.  
  92.     GraphicBlock::Draw();
  93.     damage->Reset();
  94.     ResetAllHandles();
  95.     RedrawHandles();
  96.     RedrawTextEditor();
  97.     }
  98. }
  99.  
  100. // Handle delegates input events to the tools.
  101.  
  102. void DrawingView::Handle (Event& e) {
  103.     tools->Handle(e);
  104. }
  105.  
  106. // Manipulate lets the user manipulate the Rubberband with the mouse
  107. // until a specified event occurs.
  108.  
  109. void DrawingView::Manipulate (Event& e, Rubberband* rubberband, int et,
  110. boolean constrain, boolean erase) {
  111.     rubberband->SetPainter(rasterxor);
  112.     rubberband->SetCanvas(canvas);
  113.     Listen(allEvents);
  114.     while (e.eventType != et) {
  115.     if (e.eventType == MotionEvent) {
  116.         rubberband->Track(e.x, e.y);
  117.     }
  118.     Read(e);
  119.     if (constrain) {
  120.         page->Constrain(e.x, e.y);
  121.     }
  122.     }
  123.     Listen(input);
  124.     if (erase) {
  125.     rubberband->Erase();
  126.     }
  127. }
  128.  
  129. // Edit lets the user enter text into the drawing.
  130.  
  131. void DrawingView::Edit (Event& e, TextEdit* textedit, Graphic* gs) {
  132.     StartTextEditing(e, textedit, gs);
  133.  
  134.     textedit->Grasp(e);
  135.     Listen(allEvents);
  136.     while (textedit->Editing(e)) {
  137.     Read(e);
  138.     }
  139.     UnRead(e);
  140.     Listen(input);
  141.  
  142.     EndTextEditing();
  143. }
  144.  
  145. // DrawHandles tells all the Selections to draw their handles unless
  146. // they've already been drawn.
  147.  
  148. void DrawingView::DrawHandles () {
  149.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  150.     sl->GetCur()->GetSelection()->DrawHandles(rasterxor, canvas);
  151.     }
  152. }
  153.  
  154. // RedrawHandles tells all the Selections to redraw their handles
  155. // whether or not they've already been drawn.
  156.  
  157. void DrawingView::RedrawHandles () {
  158.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  159.     sl->GetCur()->GetSelection()->RedrawHandles(rasterxor, canvas);
  160.     }
  161. }
  162.  
  163. // EraseHandles tells all the Selections to erase their handles unless
  164. // they've already been erased.
  165.  
  166. void DrawingView::EraseHandles () {
  167.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  168.     sl->GetCur()->GetSelection()->EraseHandles(rasterxor, canvas);
  169.     }
  170. }
  171.  
  172. // EraseExcessHandles erases the excess Selections' handles if it
  173. // doesn't find the Selections in the current SelectionList.
  174.  
  175. void DrawingView::EraseExcessHandles (SelectionList* newsl) {
  176.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  177.     Selection* oldselection = sl->GetCur()->GetSelection();
  178.     if (!newsl->Find(oldselection)) {
  179.         oldselection->EraseHandles(rasterxor, canvas);
  180.     }
  181.     }
  182. }
  183.  
  184. // ErasePickedHandles erases the picked Selection's handles if it
  185. // finds the picked Selection in the SelectionList.
  186.  
  187. void DrawingView::ErasePickedHandles (Selection* pick) {
  188.     if (sl->Find(pick)) {
  189.     sl->GetCur()->GetSelection()->EraseHandles(rasterxor, canvas);
  190.     }
  191. }
  192.  
  193. // ErasePickedHandles erases the picked Selections' handles if it
  194. // finds the picked Selections in the SelectionList.
  195.  
  196. void DrawingView::ErasePickedHandles (SelectionList* pl) {
  197.     for (pl->First(); !pl->AtEnd(); pl->Next()) {
  198.     Selection* pick = pl->GetCur()->GetSelection();
  199.     if (sl->Find(pick)) {
  200.         sl->GetCur()->GetSelection()->EraseHandles(rasterxor, canvas);
  201.     }
  202.     }
  203. }
  204.  
  205. // EraseUngraspedHandles erases all of the handles only if the
  206. // SelectionList does not already include the picked Selection.
  207.  
  208. void DrawingView::EraseUngraspedHandles (Selection* pick) {
  209.     if (!sl->Find(pick)) {
  210.     EraseHandles();
  211.     }
  212. }
  213.  
  214. // ResetAllHandles resets all of the handles because the Selections
  215. // may have moved out from under their handles.
  216.  
  217. void DrawingView::ResetAllHandles () {
  218.     PictSelection* picture = page->GetPicture();
  219.     for (picture->First(); !picture->AtEnd(); picture->Next()) {
  220.     Selection* s = picture->GetCurrent();
  221.     s->ResetHandles();
  222.     }
  223. }
  224.  
  225. // Added adds the Selections to the list of Selections in the drawing
  226. // to be drawn for the first time.
  227.  
  228. void DrawingView::Added () {
  229.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  230.         damage->Added(sl->GetCur()->GetSelection());
  231.     }
  232. }
  233.  
  234. // Damaged adds the areas covered by the selected Selections
  235. // (including their handles, too) to the list of damaged areas in the
  236. // drawing to be repaired.
  237.  
  238. void DrawingView::Damaged () {
  239.     BoxObj box;
  240.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  241.     sl->GetCur()->GetSelection()->GetPaddedBox(box);
  242.         damage->Incur(box);
  243.     }
  244. }
  245.  
  246. // Repair repairs the drawing's damaged areas and then redraws the
  247. // Selections' handles.  The damaged areas must have included all the
  248. // handles for RedrawHandles to work correctly.
  249.  
  250. void DrawingView::Repair () {
  251.     if (damage->Incurred()) {
  252.     damage->Repair();
  253.     RedrawHandles();
  254.     }
  255. }
  256.  
  257. // Magnify magnifies the given area to fill the view.
  258.  
  259. void DrawingView::Magnify (Coord l, Coord b, Coord r, Coord t) {
  260.     Perspective np;
  261.     np = *GetPerspective();
  262.     np.curx += min(l, r);
  263.     np.cury += min(b, t);
  264.     np.curwidth = max(abs(r - l), 1);
  265.     np.curheight = max(abs(t - b), 1);
  266.     Adjust(np);
  267. }
  268.  
  269. // Reduce reduces the drawing's magnification by a factor of two.
  270.  
  271. void DrawingView::Reduce () {
  272.     SetMagnification(GetMagnification() / 2);
  273. }
  274.  
  275. // Enlarge enlarges the drawing's magnification by a factor of two.
  276.  
  277. void DrawingView::Enlarge () {
  278.     SetMagnification(2 * GetMagnification());
  279. }
  280.  
  281. // NormalSize resets the drawing's magnification.
  282.  
  283. void DrawingView::NormalSize () {
  284.     SetMagnification(1.);
  285. }
  286.  
  287. // ReduceToFit reduces the drawing's magnification enough to fit all
  288. // of the drawing in the window.
  289.  
  290. void DrawingView::ReduceToFit () {
  291.     Perspective np;
  292.     np = *GetPerspective();
  293.     np.curx = np.x0;
  294.     np.cury = np.y0;
  295.     np.curwidth = np.width;
  296.     np.curheight = np.height;
  297.     Adjust(np);
  298. }
  299.  
  300. // CenterPage recenters the drawing over the window's center.
  301.  
  302. void DrawingView::CenterPage () {
  303.     register Perspective* p = perspective;
  304.     Coord left, bottom, right, top;
  305.  
  306.     page->Center(mag, xmax/2, ymax/2);
  307.  
  308.     GetGraphicBox(left, bottom, right, top);
  309.     x0 = left;
  310.     y0 = bottom;
  311.     p->width = right - left + 2*pad;
  312.     p->height = top - bottom + 2*pad;
  313.     p->curwidth = xmax + 1;
  314.     p->curheight = ymax + 1;
  315.     p->curx = (p->width - p->curwidth)/2;
  316.     p->cury = (p->height - p->curheight)/2;
  317.     p->Update();
  318.     Draw();
  319. }
  320.  
  321. // Reconfig gives output the page's background color, creates a
  322. // painter for drawing the rubberbands, and asks for the smallest
  323. // possible canvas if the user wants a small window.
  324.  
  325. void DrawingView::Reconfig () {
  326.     Color* bg = page->GetBackgroundColor();
  327.     if (output->GetBgColor() != bg) {
  328.     Painter* copy = new Painter(output);
  329.     copy->Reference();
  330.     Unref(output);
  331.     output = copy;
  332.     output->SetColors(output->GetFgColor(), bg);
  333.     }
  334.     if (rasterxor == nil) {
  335.     rasterxor = new Painter(output);
  336.     rasterxor->Reference();
  337.     }
  338.     if (strcmp(GetAttribute("small"), "true") == 0) {
  339.     shape->width = 0;
  340.     shape->height = 0;
  341.     }
  342.     GraphicBlock::Reconfig();
  343. }
  344.  
  345. // Redraw draws a rectangular subpart of the view.
  346.  
  347. void DrawingView::Redraw (Coord l, Coord b, Coord r, Coord t) {
  348.     if (graphic != nil) {
  349.     GraphicBlock::Redraw(l, b, r, t);
  350.     rasterxor->Clip(canvas, l, b, r, t);
  351.     for (sl->First(); !sl->AtEnd(); sl->Next()) {
  352.         Selection* selection = sl->GetCur()->GetSelection();
  353.         selection->RedrawUnclippedHandles(rasterxor, canvas);
  354.     }
  355.     rasterxor->NoClip();
  356.     RedrawTextEditor();
  357.     }
  358. }
  359.  
  360. // Resize recreates damage in case canvas changed its value.
  361.  
  362. void DrawingView::Resize () {
  363.     GraphicBlock::Resize();
  364.     delete damage;
  365.     damage = new Damage(canvas, output, graphic);
  366.     ResetAllHandles();
  367. }
  368.  
  369. // LimitMagnification limits the factor by which DrawingView may scale
  370. // the view of the drawing to avoid torturing the X server.  In
  371. // addition, LimitMagnification updates State's stored magnification.
  372. // Alternatively, State could have attached itself to DrawingView's
  373. // perspective if it was an Interactor like MagnifView.
  374.  
  375. float DrawingView::LimitMagnification (float desired) {
  376.     const float MIN = 1./8.;
  377.     const float MAX = 16.;
  378.     if (desired < MIN) {
  379.     desired = MIN;
  380.     } else if (desired > MAX) {
  381.     desired = MAX;
  382.     }
  383.     state->SetMagnif(desired);
  384.     return desired;
  385. }
  386.  
  387. // StartTextEditing stores the textedit and draws it on the canvas.
  388.  
  389. void DrawingView::StartTextEditing (
  390.     Event& e, TextEdit* textedit, Graphic* gs
  391. ) {
  392.     DrawingView::textedit = textedit;
  393.     DrawingView::gs = gs;
  394.  
  395.     page->Constrain(e.x, e.y);
  396.     if (gs != nil) {
  397.     state->SetTextGS(gs, output);
  398.     } else {
  399.     state->SetTextGS(e.x, e.y, output);
  400.     }
  401.     textedit->Redraw(
  402.     state->GetTextPainter(), canvas, state->GetLineHt(), false
  403.     );
  404. }
  405.  
  406. // EndTextEditing marks the area damaged by the textedit for later
  407. // repair and forgets it has a textedit.
  408.  
  409. void DrawingView::EndTextEditing () {
  410.     Coord xmin, ymin, xmax, ymax;
  411.     textedit->Bounds(xmin, ymin, xmax, ymax);
  412.     damage->Incur(xmin, ymin, xmax, ymax);
  413.     gs = nil;
  414.     textedit = nil;
  415. }
  416.  
  417. // RedrawTextEdit redraws the textedit on the canvas after a Resize or
  418. // other asynchronous window event.
  419.  
  420. void DrawingView::RedrawTextEditor () {
  421.     if (textedit != nil) {
  422.     if (gs != nil) {
  423.         state->SetTextGS(gs, output);
  424.     }
  425.     textedit->Redraw(
  426.         state->GetTextPainter(), canvas, state->GetLineHt(), true
  427.     );
  428.     }
  429. }
  430.