]> Shamusworld >> Repos - architektonas/blob - src/drawingview.cpp
Major refactor of Architektonas: Jettisoning old cruft.
[architektonas] / src / drawingview.cpp
1 // drawingview.cpp
2 //
3 // Part of the Architektonas Project
4 // (C) 2011 Underground Software
5 // See the README and GPLv3 files for licensing and warranty information
6 //
7 // JLH = James L. Hammons <jlhamm@acm.org>
8 //
9 // Who  When        What
10 // ---  ----------  -------------------------------------------------------------
11 // JLH  03/22/2011  Created this file
12 //
13
14 // FIXED:
15 //
16 //
17 // STILL TO BE DONE:
18 //
19 //
20
21 // Uncomment this for debugging...
22 //#define DEBUG
23 //#define DEBUGFOO            // Various tool debugging...
24 //#define DEBUGTP                               // Toolpalette debugging...
25
26 #include "drawingview.h"
27
28 #include <stdint.h>
29 #include "mathconstants.h"
30
31 #include "arc.h"
32 #include "circle.h"
33 #include "dimension.h"
34 #include "line.h"
35
36
37 DrawingView::DrawingView(QWidget * parent/*= NULL*/): QWidget(parent),
38 //      scale(1.0), offsetX(-10), offsetY(-10), tool(TOOLSelect),
39 //      ptHighlight(-1), oldPtHighlight(-1), ptNextHighlight(-1), oldPtNextHighlight(-1),
40 //      polyFirstPoint(true)
41         scale(1.0), offsetX(-10), offsetY(-10),
42         document(Vector(0, 0)),
43         gridSpacing(32.0), collided(false)
44 {
45         setBackgroundRole(QPalette::Base);
46         setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
47
48 //      toolPalette = new ToolWindow();
49 //      CreateCursors();
50 //      setCursor(cur[TOOLSelect]);
51 //      setMouseTracking(true);
52
53         document.Add(new Line(Vector(5, 5), Vector(50, 40), &document));
54         document.Add(new Line(Vector(50, 40), Vector(10, 83), &document));
55         document.Add(new Line(Vector(10, 83), Vector(17, 2), &document));
56         document.Add(new Circle(Vector(100, 100), 36, &document));
57         document.Add(new Circle(Vector(50, 150), 49, &document));
58         document.Add(new Arc(Vector(300, 300), 32, PI / 4.0, PI * 1.3, &document)),
59         document.Add(new Arc(Vector(200, 200), 60, PI / 2.0, PI * 1.5, &document));
60         document.Add(new Dimension(Vector(5, 5), Vector(50, 40), &document));
61 }
62
63 QPoint DrawingView::GetAdjustedMousePosition(QMouseEvent * event)
64 {
65         // This is undoing the transform, e.g. going from client coords to local coords.
66         // In essence, the height - y is height + (y * -1), the (y * -1) term doing the
67         // conversion of the y-axis from increasing bottom to top.
68         return QPoint(offsetX + event->x(), offsetY + (size().height() - event->y()));
69 }
70
71 QPoint DrawingView::GetAdjustedClientPosition(int x, int y)
72 {
73         // VOODOO ALERT (ON Y COMPONENT!!!!) (eh?)
74         // No voodoo here, it's just grouped wrong to see it. It should be:
75         // -offsetY + (size.height() + (y * -1.0)) <-- this is wrong, offsetY should be positive
76         return QPoint(-offsetX + x, (size().height() - (-offsetY + y)) * +1.0);
77 }
78
79 void DrawingView::paintEvent(QPaintEvent * /*event*/)
80 {
81         QPainter painter(this);
82         painter.setRenderHint(QPainter::Antialiasing);
83
84 #if 0
85         painter.translate(QPoint(-offsetX, size.height() - (-offsetY)));
86         painter.scale(1.0, -1.0);
87 #else
88         QTransform transform;
89 //order of operations is important! N.B.: Can't use scaling other than 1.0, it
90 //causes lines to look strange (i.e., it scales the pen strokes too)
91 //      transform.translate(-offsetX, size().height() - (-offsetY));
92         transform.scale(1.0, -1.0);
93         transform.translate(-offsetX, -size().height() - offsetY);
94 //      transform.scale(0.25, 0.25);
95         painter.setTransform(transform);
96 #endif
97         Object::SetViewportHeight(size().height());
98
99         // Draw coordinate axes
100
101         painter.setPen(QPen(Qt::blue, 1.0, Qt::DotLine));
102         painter.drawLine(0, -16384, 0, 16384);
103         painter.drawLine(-16384, 0, 16384, 0);
104
105 // Maybe we can make the grid into a background brush instead, and let Qt deal
106 // with it???
107         // Draw grid
108
109 #if 0
110         painter.setPen(QPen(QColor(90, 90, 90), 1.0, Qt::DotLine));
111
112         //these two loops kill performance!
113         for(double x=0; x<size().width(); x+=gridSpacing*10.0)
114                 p.drawLine((int)x, -16384, (int)x, 16384);
115
116         for(double y=0; y<size().height(); y+=gridSpacing*10.0)
117                 p.drawLine(-16384, (int)y, 16384, (int)y);
118 #endif
119
120         painter.setPen(QPen(Qt::black, 1.0, Qt::SolidLine));
121
122         for(double x=0; x<size().width(); x+=gridSpacing)
123                 for(double y=0; y<size().height(); y+=gridSpacing)
124                         painter.drawPoint((int)x, (int)y);
125
126         // The top level document takes care of rendering for us...
127         document.Draw(&painter);
128 }
129
130 void DrawingView::mousePressEvent(QMouseEvent * event)
131 {
132         if (event->button() == Qt::LeftButton)
133         {
134                 QPoint pt = GetAdjustedMousePosition(event);
135                 Vector point(pt.x(), pt.y());
136
137                 collided = document.Collided(point);
138
139                 if (collided)
140                         update();       // Do an update if collided with at least *one* object in the document
141         }
142 }
143
144 void DrawingView::mouseMoveEvent(QMouseEvent * event)
145 {
146         QPoint pt = GetAdjustedMousePosition(event);
147         Vector point(pt.x(), pt.y());
148
149         // Grid processing...
150 #if 1
151         // This looks strange, but it's really quite simple: We want a point that's
152         // more than half-way to the next grid point to snap there while conversely
153         // we want a point that's less than half-way to to the next grid point then
154         // snap to the one before it. So we add half of the grid spacing to the
155         // point, then divide by it so that we can remove the fractional part, then
156         // multiply it back to get back to the correct answer.
157         point += gridSpacing / 2.0;                                     // *This* adds to Z!!!
158         point /= gridSpacing;
159         point.x = floor(point.x);//need to fix this for negative numbers...
160         point.y = floor(point.y);
161         point.z = 0;                                                            // Make *sure* Z doesn't go anywhere!!!
162         point *= gridSpacing;
163 #endif
164 //we should keep track of the last point here and only pass this down *if* the point
165 //changed...
166         document.PointerMoved(point);
167
168         if (document.NeedsUpdate())
169                 update();
170 }
171
172 void DrawingView::mouseReleaseEvent(QMouseEvent * event)
173 {
174         if (event->button() == Qt::LeftButton)
175         {
176                 document.PointerReleased();
177
178 //We need to update especially if nothing collided and the state needs to change. !!! FIX !!!
179 //could set it up to use the document's update function (assumes that all object updates
180 //are being reported correctly:
181 //              if (document.NeedsUpdate())
182 //              if (collided)
183                         update();       // Do an update if collided with at least *one* object in the document
184         }
185 }
186
187
188 #if 0
189 QSize DrawingView::minimumSizeHint() const
190 {
191         return QSize(50, 50);
192 }
193
194 QSize DrawingView::sizeHint() const
195 {
196         return QSize(400, 400);
197 }
198
199 void DrawingView::CreateCursors(void)
200 {
201         int hotx[8] = {  1,  1, 11, 15,  1,  1,  1,  1 };
202         int hoty[8] = {  1,  1, 11, 13,  1,  1,  1,  1 };
203
204         for(int i=0; i<8; i++)
205         {
206                 QString s;
207                 s.sprintf(":/res/cursor%u.png", i+1);
208                 QPixmap pmTmp(s);
209                 cur[i] = QCursor(pmTmp, hotx[i], hoty[i]);
210         }
211 }
212
213 /*
214 TODO:
215  o  Different colors for polys on selected points
216  o  Different colors for handles on non-selected polys
217  o  Line of sight (dashed, dotted) for off-curve points
218  o  Repaints for press/release of CTRL/SHIFT during point creation
219 */
220 void DrawingView::paintEvent(QPaintEvent * /*event*/)
221 {
222         QPainter p(this);
223 //hm, causes lockup
224 //      p.setRenderHint(QPainter::Antialiasing);
225 //Doesn't do crap!
226 //dc.SetBackground(*wxWHITE_BRUSH);
227
228 // Due to the screwiness of wxWidgets coord system, the origin is ALWAYS
229 // the upper left corner--regardless of axis orientation, etc...
230 //      int width, height;
231 //      dc.GetSize(&width, &height);
232         QSize winSize = size();
233
234 //      dc.SetDeviceOrigin(-offsetX, height - (-offsetY));
235 //      dc.SetAxisOrientation(true, true);
236         p.translate(QPoint(-offsetX, winSize.height() - (-offsetY)));
237         p.scale(1.0, -1.0);
238
239 // Scrolling can be done by using OffsetViewportOrgEx
240 // Scaling can be done by adjusting SetWindowExtEx (it's denominator of txform)
241 // you'd use: % = ViewportExt / WindowExt
242 // But it makes the window look like crap: fuggetuboutit.
243 // Instead, we have to scale EVERYTHING by hand. Crap!
244 // It's not *that* bad, but not as convenient either...
245
246 //      dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0xFF), 1, wxDOT)));
247 ////    dc.DrawLine(0, 0, 10, 10);
248         p.setPen(QPen(Qt::blue, 1.0, Qt::DotLine));
249
250     // Draw coordinate axes
251
252 //      dc.CrossHair(0, 0);
253         p.drawLine(0, -16384, 0, 16384);
254         p.drawLine(-16384, 0, 16384, 0);
255
256     // Draw points
257
258         for(int i=0; i<pts.GetNumPoints(); i++)
259         {
260                 if (i == ptHighlight)
261                 {
262 //                      dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));
263 ////                    SelectObject(hdc, hRedPen1);
264                         p.setPen(QPen(Qt::red, 1.0, Qt::SolidLine));
265
266                         if (pts.GetOnCurve(i))
267                         {
268                                 DrawSquareDotN(p, pts.GetX(i), pts.GetY(i), 7);
269                                 DrawSquareDotN(p, pts.GetX(i), pts.GetY(i), 9);
270                         }
271                         else
272                         {
273                                 DrawRoundDotN(p, pts.GetX(i), pts.GetY(i), 7);
274                                 DrawRoundDotN(p, pts.GetX(i), pts.GetY(i), 9);
275                         }
276                 }
277                 else if ((i == ptHighlight || i == ptNextHighlight) && tool == TOOLAddPt)
278                 {
279 //                      dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0xAF, 0x00), 1, wxSOLID)));
280 ////                    SelectObject(hdc, hGreenPen1);
281                         p.setPen(QPen(Qt::green, 1.0, Qt::SolidLine));
282
283                         if (pts.GetOnCurve(i))
284                         {
285                                 DrawSquareDotN(p, pts.GetX(i), pts.GetY(i), 7);
286                                 DrawSquareDotN(p, pts.GetX(i), pts.GetY(i), 9);
287                         }
288                         else
289                         {
290                                 DrawRoundDotN(p, pts.GetX(i), pts.GetY(i), 7);
291                                 DrawRoundDotN(p, pts.GetX(i), pts.GetY(i), 9);
292                         }
293                 }
294                 else
295                 {
296 //                      dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));
297 ////                    SelectObject(hdc, hBlackPen1);
298                         p.setPen(QPen(Qt::black, 1.0, Qt::SolidLine));
299
300                         if (pts.GetOnCurve(i))
301                                 DrawSquareDot(p, pts.GetX(i), pts.GetY(i));
302                         else
303                                 DrawRoundDot(p, pts.GetX(i), pts.GetY(i));
304                 }
305
306                 if (tool == TOOLDelPt && i == ptHighlight)
307                 {
308 #if 0
309                         dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));
310 //                      SelectObject(hdc, hRedPen1);
311 //                      MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5, NULL);
312 //                      LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) + 5);
313 //                      LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5);//Lameness!
314 //                      MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5, NULL);
315 //                      LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) - 5);
316 //                      LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5);//More lameness!!
317 #endif
318                         p.setPen(QPen(Qt::red, 1.0, Qt::SolidLine));
319                         p.drawLine(pts.GetX(i) - 5, pts.GetY(i) - 5, pts.GetX(i) + 5, pts.GetY(i) + 5);
320                         p.drawLine(pts.GetX(i) + 5, pts.GetY(i) - 5, pts.GetX(i) - 5, pts.GetY(i) + 5);
321                 }
322         }
323
324 ////            SelectObject(hdc, hBlackPen1);
325 //      dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));
326         p.setPen(QPen(Qt::black, 1.0, Qt::SolidLine));
327
328         // Draw curve formed by points
329
330         for(int poly=0; poly<pts.GetNumPolys(); poly++)
331         {
332                 if (pts.GetNumPoints(poly) > 2)
333                 {
334                         // Initial move...
335                         // If it's not on curve, then move to it, otherwise move to last point...
336
337                         int x, y;
338
339                         if (pts.GetOnCurve(poly, pts.GetNumPoints(poly) - 1))
340                                 x = (int)pts.GetX(poly, pts.GetNumPoints(poly) - 1), y = (int)pts.GetY(poly, pts.GetNumPoints(poly) - 1);
341                         else
342                                 x = (int)pts.GetX(poly, 0), y = (int)pts.GetY(poly, 0);
343
344                         for(int i=0; i<pts.GetNumPoints(poly); i++)
345                         {
346                                 if (pts.GetOnCurve(poly, i))
347 //                                      LineTo(hdc, pts.GetX(poly, i), pts.GetY(poly, i));
348                                 {
349                                         p.drawLine(x, y, pts.GetX(poly, i), pts.GetY(poly, i));
350                                         x = (int)pts.GetX(poly, i), y = (int)pts.GetY(poly, i);
351                                 }
352                                 else
353                                 {
354                                         uint32 prev = pts.GetPrev(poly, i), next = pts.GetNext(poly, i);
355                                         float px = pts.GetX(poly, prev), py = pts.GetY(poly, prev),
356                                                 nx = pts.GetX(poly, next), ny = pts.GetY(poly, next);
357
358                                         if (!pts.GetOnCurve(poly, prev))
359                                                 px = (px + pts.GetX(poly, i)) / 2.0f,
360                                                 py = (py + pts.GetY(poly, i)) / 2.0f;
361
362                                         if (!pts.GetOnCurve(poly, next))
363                                                 nx = (nx + pts.GetX(poly, i)) / 2.0f,
364                                                 ny = (ny + pts.GetY(poly, i)) / 2.0f;
365
366                                         Bezier(p, point(px, py), point(pts.GetX(poly, i), pts.GetY(poly, i)), point(nx, ny));
367                                         x = (int)nx, y = (int)ny;
368
369                                         if (pts.GetOnCurve(poly, next))
370                                                 i++;                                    // Following point is on curve, so move past it
371                                 }
372                         }
373                 }
374         }
375 }
376
377 void DrawingView::mousePressEvent(QMouseEvent * event)
378 {
379         if (event->button() == Qt::RightButton)
380         {
381                 toolPalette->move(event->globalPos());
382                 toolPalette->setVisible(true);
383                 setCursor(cur[TOOLSelect]);
384                 toolPalette->prevTool = TOOLSelect;
385         }
386         else if (event->button() == Qt::MidButton)
387         {
388                 setCursor(cur[2]);                                                      // Scrolling cursor
389         }
390         else if (event->button() == Qt::LeftButton)
391         {
392                 if (tool == TOOLScroll || tool == TOOLZoom)
393 ;//meh                  CaptureMouse();                                         // Make sure we capture the mouse when in scroll/zoom mode
394                 else if (tool == TOOLAddPt)             // "Add Point" tool
395                 {
396                         if (pts.GetNumPoints() > 0)
397                         {
398                                 QPoint pt = GetAdjustedMousePosition(event);
399                                 pts.InsertPoint(pts.GetNext(ptHighlight), pt.x(), pt.y(), ((event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier) ? false : true));
400                                 ptHighlight = ptNextHighlight;
401                                 update();
402                         }
403                 }
404                 else if (tool == TOOLAddPoly)   // "Add Poly" tool
405                 {
406 #ifdef DEBUGFOO
407 WriteLogMsg("Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts.GetNumPoints());
408 #endif
409                         if (polyFirstPoint)
410                         {
411                                 polyFirstPoint = false;
412                                 pts.AddNewPolyAtEnd();
413                         }
414
415                         QPoint pt = GetAdjustedMousePosition(event);
416 //printf("GetAdjustedMousePosition = %i, %i\n", pt.x(), pt.y());
417                         // Append a point to the end of the structure
418                         pts += IPoint(pt.x(), pt.y(), ((event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier) ? false : true));
419                         ptHighlight = pts.GetNumPoints() - 1;
420                         update();
421 #ifdef DEBUGFOO
422 WriteLogMsg(" --> [# polys: %u, # points: %u]\n", pts.GetNumPolys(), pts.GetNumPoints());
423 #endif
424                 }
425                 else if (tool == TOOLSelect || tool == TOOLPolySelect)
426                 {
427                         if (pts.GetNumPoints() > 0)
428                         {
429                                 pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight));
430 //printf("GetAdjustedClientPosition = %i, %i\n", pt.x(), pt.y());
431 //                              WarpPointer(pt.x, pt.y);
432                                 QCursor::setPos(mapToGlobal(pt));
433
434                                 if (event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier)
435                                 {
436                                         pts.SetOnCurve(ptHighlight, !pts.GetOnCurve(ptHighlight));
437                                         update();
438                                 }
439                         }
440                 }
441                 else if (tool == TOOLDelPt)
442                 {
443                         if (pts.GetNumPoints() > 0)
444 //Or could use:
445 //                      if (ptHighlight != -1)
446                         {
447 //This assumes that WM_MOUSEMOVE happens before this!
448 //The above commented out line should take care of this contingency... !!! FIX !!!
449                                 pts.DeletePoint(ptHighlight);
450                                 update();
451                         }
452                 }
453         }
454
455         event->accept();
456 }
457
458 void DrawingView::mouseMoveEvent(QMouseEvent * event)
459 {
460         if (event->buttons() == Qt::RightButton)
461         {
462                 ToolType newTool = toolPalette->FindSelectedTool();
463
464                 if (newTool != toolPalette->prevTool)
465                 {
466                         toolPalette->prevTool = newTool;
467                         toolPalette->repaint();
468                 }
469         }
470         else if (event->buttons() == Qt::MidButton)
471         {
472                 // Calc offset from previous point
473                 pt = event->pos();
474                 ptOffset = QPoint(pt.x() - ptPrevious.x(), pt.y() - ptPrevious.y());
475
476 // Then multiply it by the scaling factor. Whee!
477                 // This looks wacky because we're using screen coords for the offset...
478                 // Otherwise, we would subtract both offsets!
479                 offsetX -= ptOffset.x(), offsetY += ptOffset.y();
480                 update();
481                 ptPrevious = pt;
482         }
483         else if (event->buttons() == Qt::LeftButton)
484         {
485 #if 0
486                         if (tool == TOOLScroll)
487                         {
488                             // Extract current point from lParam/calc offset from previous point
489
490                                 pt = e.GetPosition();
491                                 ptOffset.x = pt.x - ptPrevious.x,
492                                 ptOffset.y = pt.y - ptPrevious.y;
493
494                                 // NOTE: OffsetViewportOrg operates in DEVICE UNITS...
495
496 //Seems there's no equivalent for this in wxWidgets...!
497 //!!! FIX !!!
498 //                              hdc = GetDC(hWnd);
499 //                              OffsetViewportOrgEx(hdc, ptOffset.x, ptOffset.y, NULL);
500 //                              ReleaseDC(hWnd, hdc);
501
502 // this shows that it works, so the logic above must be faulty...
503 // And it is. It should convert the coords first, then do the subtraction to figure the offset...
504 // Above: DONE
505 // Then multiply it by the scaling factor. Whee!
506                                 // This looks wacky because we're using screen coords for the offset...
507                                 // Otherwise, we would subtract both offsets!
508                                 offsetX -= ptOffset.x, offsetY += ptOffset.y;
509                                 Refresh();
510                         }
511                         else
512 #endif
513                         if (tool == TOOLAddPt || tool == TOOLAddPoly || tool == TOOLSelect)
514                         {
515                                 if (tool != TOOLAddPt || pts.GetNumPoints() > 0)//yecch.
516                                 {
517 //temporary, for testing. BTW, Select drag bug is here...!
518 #if 1
519                                         QPoint pt2 = GetAdjustedMousePosition(event);
520                                         pts.SetXY(ptHighlight, pt2.x(), pt2.y());
521                                         update();
522 #endif
523                                 }
524                         }
525                         else if (tool == TOOLPolySelect)
526                         {
527                                 if (pts.GetNumPoints() > 0)
528                                 {
529                                         QPoint pt2 = GetAdjustedMousePosition(event);
530                                         // Should also set onCurve here as well, depending on keystate
531 //Or should we?
532                                         pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x() - pts.GetX(ptHighlight), pt2.y() - pts.GetY(ptHighlight));
533                                         update();
534                                 }
535                         }
536         }
537         else if (event->buttons() == Qt::NoButton)
538         {
539                 // Moving, not dragging...
540                 if (tool == TOOLSelect || tool == TOOLDelPt || tool == TOOLAddPt
541                         || tool == TOOLPolySelect)// || tool == TOOLAddPoly)
542                 {
543                         QPoint pt2 = GetAdjustedMousePosition(event);
544                         double closest = 1.0e+99;
545
546                         for(int i=0; i<pts.GetNumPoints(); i++)
547                         {
548                                 double dist = ((pt2.x() - pts.GetX(i)) * (pt2.x() - pts.GetX(i)))
549                                         + ((pt2.y() - pts.GetY(i)) * (pt2.y() - pts.GetY(i)));
550
551                                 if (dist < closest)
552                                         closest = dist, ptHighlight = i;
553                         }
554
555                         if (ptHighlight != oldPtHighlight)
556                         {
557                                 oldPtHighlight = ptHighlight;
558                                 update();
559                         }
560
561                         // What follows here looks like voodoo, but is really simple. What we do is
562                         // check to see if the mouse point has a perpendicular intersection with any of
563                         // the line segments. If it does, calculate the length of the perpendicular
564                         // and choose the smallest length. If there is no perpendicular, then choose the
565                         // length of line connecting the closer of either the first endpoint or the
566                         // second and choose the smallest of those.
567
568                         // There is one bit of math that looks like voodoo to me ATM--will explain once
569                         // I understand it better (the calculation of the length of the perpendicular).
570
571                         if (pts.GetNumPoints() > 1 && tool == TOOLAddPt)
572                         {
573                                 double smallest = 1.0e+99;
574
575                                 for(int i=0; i<pts.GetNumPoints(); i++)
576                                 {
577                                         int32 p1x = pts.GetX(i), p1y = pts.GetY(i),
578                                                 p2x = pts.GetX(pts.GetNext(i)), p2y = pts.GetY(pts.GetNext(i));
579
580                                         vector ls(p2x, p2y, 0, p1x, p1y, 0), v1(pt2.x(), pt2.y(), 0, p1x, p1y, 0),
581                                                 v2(pt2.x(), pt2.y(), 0, p2x, p2y, 0);
582                                         double pp = ls.dot(v1) / ls.length(), dist;
583 // Geometric interpretation:
584 // pp is the paremeterized point on the vector ls where the perpendicular intersects ls.
585 // If pp < 0, then the perpendicular lies beyond the 1st endpoint. If pp > length of ls,
586 // then the perpendicular lies beyond the 2nd endpoint.
587
588                                         if (pp < 0.0)
589                                                 dist = v1.length();
590                                         else if (pp > ls.length())
591                                                 dist = v2.length();
592                                         else                                    // distance = ?Det?(ls, v1) / |ls|
593                                                 dist = fabs((ls.x * v1.y - v1.x * ls.y) / ls.length());
594
595 //The answer to the above looks like it might be found here:
596 //
597 //If the segment endpoints are s and e, and the point is p, then the test for the perpendicular
598 //intercepting the segment is equivalent to insisting that the two dot products {s-e}.{s-p} and
599 //{e-s}.{e-p} are both non-negative.  Perpendicular distance from the point to the segment is
600 //computed by first computing the area of the triangle the three points form, then dividing by the
601 //length of the segment.  Distances are done just by the Pythagorean theorem.  Twice the area of the
602 //triangle formed by three points is the determinant of the following matrix:
603 //
604 //sx sy 1
605 //ex ey 1
606 //px py 1
607 //
608 //By translating the start point to the origin, this can be rewritten as:
609 //By subtracting row 1 from all rows, you get the following:
610 //[because sx = sy = 0. you could leave out the -sx/y terms below. because we subtracted
611 // row 1 from all rows (including row 1) row 1 turns out to be zero. duh!]
612 //
613 //0         0         0
614 //(ex - sx) (ey - sy) 0
615 //(px - sx) (py - sy) 0
616 //
617 //which greatly simplifies the calculation of the determinant.
618
619                                         if (dist < smallest)
620                                                 smallest = dist, ptNextHighlight = pts.GetNext(i), ptHighlight = i;
621                                 }
622
623                                 if (ptNextHighlight != oldPtNextHighlight)
624                                 {
625                                         oldPtNextHighlight = ptNextHighlight;
626                                         update();
627                                 }
628                         }
629                 }
630
631                 ptPrevious = event->pos();
632         }
633
634         event->accept();
635 }
636
637 void DrawingView::mouseReleaseEvent(QMouseEvent * event)
638 {
639         if (event->button() == Qt::RightButton)
640         {
641                 ToolType newTool = toolPalette->FindSelectedTool();
642
643                 // We only change the tool if a new one was actually selected. Otherwise, we do nothing.
644                 if (newTool != TOOLNone)
645                 {
646                         tool = newTool;
647
648                         if (tool == TOOLScroll || tool == TOOLZoom || tool == TOOLAddPoly
649                                 || tool == TOOLDelPoly)
650                                 ptHighlight = -1;
651
652                         if (tool == TOOLAddPoly)
653                                 polyFirstPoint = true;
654                 }
655
656                 toolPalette->setVisible(false);
657                 setCursor(cur[tool]);
658                 // Just in case we changed highlighting style with the new tool...
659                 update();
660         }
661         else if (event->button() == Qt::MidButton)
662         {
663                 setCursor(cur[tool]);                                           // Restore previous cursor
664         }
665         else if (event->button() == Qt::LeftButton)
666         {
667 //              if (tool == TOOLScroll || tool == TOOLZoom)
668 //                      ReleaseMouse();
669 //this is prolly too much
670                 ((TTEdit *)qApp)->charWnd->MakePathFromPoints(&pts);
671                 ((TTEdit *)qApp)->charWnd->update();
672         }
673
674         event->accept();
675 }
676 #endif