]> Shamusworld >> Repos - ttedit/blobdiff - src/editwindow.cpp
Added preview window to file loading dialog. :-)
[ttedit] / src / editwindow.cpp
old mode 100755 (executable)
new mode 100644 (file)
index f3cc70f..dac63c2
@@ -6,7 +6,7 @@
 // JLH = James L. Hammons <jlhamm@acm.org>
 //
 // Who  When        What
-// ---  ----------  -------------------------------------------------------------
+// ---  ----------  -----------------------------------------------------------
 // JLH  08/28/2008  Created this file
 // JLH  09/02/2008  Separated scrolling from dedicated tool to MMB drag
 // JLH  03/13/2009  Converted from wxWidgets to Qt
 #define DEBUGTP                                // Toolpalette debugging...
 
 #include "editwindow.h"
-//#include <QtGui>
-#include "graphicprimitives.h"
-#include "debug.h"
-#include "vector.h"
 #include "charwindow.h"
+#include "debug.h"
+#include "global.h"
+#include "mainwindow.h"
+#include "mathconstants.h"
 #include "ttedit.h"
+#include "vector.h"
+
 
 EditWindow::EditWindow(QWidget * parent/*= NULL*/): QWidget(parent),
-       scale(1.0), offsetX(-10), offsetY(-10), tool(TOOLSelect),
-       ptHighlight(-1), oldPtHighlight(-1), ptNextHighlight(-1), oldPtNextHighlight(-1),
-       polyFirstPoint(true)
+       tool(TOOLSelect), ptHighlight(-1), oldPtHighlight(-1), ptNextHighlight(-1),
+       oldPtNextHighlight(-1), polyFirstPoint(true), showRotationCenter(false),
+       haveZeroPoint(false), selectionInProgress(false)
 {
        setBackgroundRole(QPalette::Base);
        setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
@@ -53,48 +55,37 @@ EditWindow::EditWindow(QWidget * parent/*= NULL*/): QWidget(parent),
        CreateCursors();
        setCursor(cur[TOOLSelect]);
        setMouseTracking(true);
+       ClearSelection();
 }
 
+
 QSize EditWindow::minimumSizeHint() const
 {
        return QSize(50, 50);
 }
 
+
 QSize EditWindow::sizeHint() const
 {
        return QSize(400, 400);
 }
 
+
 void EditWindow::CreateCursors(void)
 {
-       int hotx[8] = {  1,  1, 11, 15,  1,  1,  1,  1 };
-       int hoty[8] = {  1,  1, 11, 13,  1,  1,  1,  1 };
+       int hotx[12] = {  1,  1, 1, 15,  1,  1,  1,  1,  1,  1,  1, 11 };
+       int hoty[12] = {  1,  1, 1, 13,  1,  1,  1,  1,  1,  1,  1, 11 };
+       char cursorName[12][48] = { "select", "select-poly", "select-multi", "zoom",
+               "add-point", "add-poly", "del-point", "del-poly", "rotate", "rotate",
+               "select", "scroll" };
 
-       for(int i=0; i<8; i++)
+       for(int i=0; i<12; i++)
        {
-               QString s;
-               s.sprintf(":/res/cursor%u.png", i+1);
-               QPixmap pmTmp(s);
+               QPixmap pmTmp(QString(":/res/cursor-%1.png").arg(cursorName[i]));
                cur[i] = QCursor(pmTmp, hotx[i], hoty[i]);
        }
 }
 
-QPoint EditWindow::GetAdjustedMousePosition(QMouseEvent * event)
-{
-       QSize winSize = size();
-       // This is undoing the transform, e.g. going from client coords to local coords.
-       // In essence, the height - y is height + (y * -1), the (y * -1) term doing the
-       // conversion of the y-axis from increasing bottom to top.
-       return QPoint(offsetX + event->x(), offsetY + (winSize.height() - event->y()));
-}
-
-QPoint EditWindow::GetAdjustedClientPosition(int x, int y)
-{
-       QSize winSize = size();
-
-       // VOODOO ALERT (ON Y COMPONENT!!!!)
-       return QPoint(-offsetX + x, (winSize.height() - (-offsetY + y)) * +1.0);
-}
 
 /*
 TODO:
@@ -105,161 +96,270 @@ TODO:
 */
 void EditWindow::paintEvent(QPaintEvent * /*event*/)
 {
-       QPainter p(this);
-//hm, causes lockup (or does it???)
-       p.setRenderHint(QPainter::Antialiasing);
-//Doesn't do crap!
-//dc.SetBackground(*wxWHITE_BRUSH);
-
-// Due to the screwiness of wxWidgets coord system, the origin is ALWAYS
-// the upper left corner--regardless of axis orientation, etc...
-//     int width, height;
-//     dc.GetSize(&width, &height);
-       QSize winSize = size();
-
-//     dc.SetDeviceOrigin(-offsetX, height - (-offsetY));
-//     dc.SetAxisOrientation(true, true);
-       p.translate(QPoint(-offsetX, winSize.height() - (-offsetY)));
-       p.scale(1.0, -1.0);
-
-// Scrolling can be done by using OffsetViewportOrgEx
-// Scaling can be done by adjusting SetWindowExtEx (it's denominator of txform)
-// you'd use: % = ViewportExt / WindowExt
-// But it makes the window look like crap: fuggetuboutit.
-// Instead, we have to scale EVERYTHING by hand. Crap!
-// It's not *that* bad, but not as convenient either...
-
-//     dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0xFF), 1, wxDOT)));
-////   dc.DrawLine(0, 0, 10, 10);
-       p.setPen(QPen(Qt::blue, 1.0, Qt::DotLine));
-
-    // Draw coordinate axes
-
-//     dc.CrossHair(0, 0);
-       p.drawLine(0, -16384, 0, 16384);
-       p.drawLine(-16384, 0, 16384, 0);
-
-    // Draw points
+       QPainter qtp(this);
+       Painter painter(&qtp);
+       painter.SetRenderHint(QPainter::Antialiasing);
+
+       Global::viewportHeight = size().height();
+       Global::screenSize = Vector(size().width(), size().height());
+
+       // Draw coordinate axes
+
+       painter.SetPen(QPen(Qt::blue, 1.0, Qt::DotLine));
+       painter.DrawLine(0, -16384, 0, 16384);
+       painter.DrawLine(-16384, 0, 16384, 0);
+
+       // Draw rotation center (if active)
+
+       if (showRotationCenter)
+       {
+               painter.SetPen(QPen(Qt::red, 2.0, Qt::SolidLine));
+               painter.DrawLine(rotationCenter.x + 7, rotationCenter.y, rotationCenter.x - 7, rotationCenter.y);
+               painter.DrawLine(rotationCenter.x, rotationCenter.y + 7, rotationCenter.x, rotationCenter.y - 7);
+       }
+
+       // Draw points
 
        for(int i=0; i<pts.GetNumPoints(); i++)
        {
-               if (i == ptHighlight)
+               /*if (tool == TOOLMultiSelect)
+               {
+                       if (selectedPoints[i])
+                       {
+                               qtp.setPen(QPen(Qt::red, 1.0, Qt::SolidLine));
+                       }
+                       else
+                       {
+                               qtp.setPen(QPen(Qt::black, 1.0, Qt::SolidLine));
+                       }
+               }
+               else*/
+               if (((i == ptHighlight) && (tool != TOOLMultiSelect)) || ((tool == TOOLMultiSelect) && selectedPoints[i]))
                {
-//                     dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));
-////                   SelectObject(hdc, hRedPen1);
-                       p.setPen(QPen(Qt::red, 1.0, Qt::SolidLine));
+                       painter.SetPen(QPen(Qt::red, 1.0, Qt::SolidLine));
 
                        if (pts.GetOnCurve(i))
                        {
-                               DrawSquareDotN(p, pts.GetX(i), pts.GetY(i), 7);
-                               DrawSquareDotN(p, pts.GetX(i), pts.GetY(i), 9);
+                               painter.DrawSquareDotN(pts.GetXY(i), 7);
+                               painter.DrawSquareDotN(pts.GetXY(i), 9);
                        }
                        else
                        {
-                               DrawRoundDotN(p, pts.GetX(i), pts.GetY(i), 7);
-                               DrawRoundDotN(p, pts.GetX(i), pts.GetY(i), 9);
+                               painter.DrawRoundDotN(pts.GetXY(i), 7);
+                               painter.DrawRoundDotN(pts.GetXY(i), 9);
                        }
                }
                else if ((i == ptHighlight || i == ptNextHighlight) && tool == TOOLAddPt)
                {
-//                     dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0xAF, 0x00), 1, wxSOLID)));
-////                   SelectObject(hdc, hGreenPen1);
-                       p.setPen(QPen(Qt::green, 1.0, Qt::SolidLine));
+                       painter.SetPen(QPen(Qt::green, 1.0, Qt::SolidLine));
 
                        if (pts.GetOnCurve(i))
                        {
-                               DrawSquareDotN(p, pts.GetX(i), pts.GetY(i), 7);
-                               DrawSquareDotN(p, pts.GetX(i), pts.GetY(i), 9);
+                               painter.DrawSquareDotN(pts.GetXY(i), 7);
+                               painter.DrawSquareDotN(pts.GetXY(i), 9);
                        }
                        else
                        {
-                               DrawRoundDotN(p, pts.GetX(i), pts.GetY(i), 7);
-                               DrawRoundDotN(p, pts.GetX(i), pts.GetY(i), 9);
+                               painter.DrawRoundDotN(pts.GetXY(i), 7);
+                               painter.DrawRoundDotN(pts.GetXY(i), 9);
                        }
                }
                else
                {
-//                     dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));
-////                   SelectObject(hdc, hBlackPen1);
-                       p.setPen(QPen(Qt::black, 1.0, Qt::SolidLine));
+                       painter.SetPen(QPen(Qt::black, 1.0, Qt::SolidLine));
 
+#if 1
                        if (pts.GetOnCurve(i))
-                               DrawSquareDot(p, pts.GetX(i), pts.GetY(i));
+                               painter.DrawSquareDot(pts.GetXY(i));
                        else
-                               DrawRoundDot(p, pts.GetX(i), pts.GetY(i));
+                               painter.DrawRoundDot(pts.GetXY(i));
+#else
+                       (pts.GetOnCurve(i) ? DrawSquareDot(p, pts.GetX(i), pts.GetY(i))
+                               : DrawRoundDot(p, pts.GetX(i), pts.GetY(i)));
+#endif
                }
 
                if (tool == TOOLDelPt && i == ptHighlight)
                {
-#if 0
-                       dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));
-//                     SelectObject(hdc, hRedPen1);
-//                     MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5, NULL);
-//                     LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) + 5);
-//                     LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5);//Lameness!
-//                     MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5, NULL);
-//                     LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) - 5);
-//                     LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5);//More lameness!!
-#endif
-                       p.setPen(QPen(Qt::red, 1.0, Qt::SolidLine));
-                       p.drawLine(pts.GetX(i) - 5, pts.GetY(i) - 5, pts.GetX(i) + 5, pts.GetY(i) + 5);
-                       p.drawLine(pts.GetX(i) + 5, pts.GetY(i) - 5, pts.GetX(i) - 5, pts.GetY(i) + 5);
+                       painter.SetPen(QPen(Qt::red, 1.0, Qt::SolidLine));
+                       painter.DrawLine(pts.GetX(i) - 5, pts.GetY(i) - 5, pts.GetX(i) + 5, pts.GetY(i) + 5);
+                       painter.DrawLine(pts.GetX(i) + 5, pts.GetY(i) - 5, pts.GetX(i) - 5, pts.GetY(i) + 5);
                }
        }
 
-////           SelectObject(hdc, hBlackPen1);
-//     dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));
-       p.setPen(QPen(Qt::black, 1.0, Qt::SolidLine));
+       // Draw highlighted point on poly add tool
+       if (tool == TOOLAddPoly)
+       {
+               painter.SetPen(QPen(Qt::red, 1.0, Qt::SolidLine));
+
+               if (addPointOnCurve)
+               {
+                       painter.DrawSquareDotN(addPoint, 7);
+                       painter.DrawSquareDotN(addPoint, 9);
+               }
+               else
+               {
+                       painter.DrawRoundDotN(addPoint, 7);
+                       painter.DrawRoundDotN(addPoint, 9);
+               }
+       }
 
        // Draw curve formed by points
 
-       for(int poly=0; poly<pts.GetNumPolys(); poly++)
+       painter.SetPen(QPen(Qt::black, 1.0, Qt::SolidLine));
+       DrawGlyph(painter, pts);
+
+       if (haveZeroPoint)
        {
-               if (pts.GetNumPoints(poly) > 2)
+               // Rotation code
+               GlyphPoints rotated = pts;
+
+               if (tool == TOOLRotate)
+                       rotated.RotatePoints(rotationAngle, IPoint(rotationCenter.x, rotationCenter.y));
+               else if (tool == TOOLRotatePoly)
                {
-                       // Initial move...
-                       // If it's not on curve, then move to it, otherwise move to last point...
+                       uint16_t poly = rotated.GetPolyForPointNumber(ptHighlight);
+                       rotated.RotatePolyAroundCentroid(poly, rotationAngle);
+               }
 
-                       int x, y;
+               painter.SetPen(QPen(QColor(255, 0, 255), 1.0, Qt::SolidLine));
+               DrawGlyph(painter, rotated);
+       }
 
-                       if (pts.GetOnCurve(poly, pts.GetNumPoints(poly) - 1))
-                               x = (int)pts.GetX(poly, pts.GetNumPoints(poly) - 1), y = (int)pts.GetY(poly, pts.GetNumPoints(poly) - 1);
-                       else
-                               x = (int)pts.GetX(poly, 0), y = (int)pts.GetY(poly, 0);
+       if (selectionInProgress)
+       {
+               painter.SetPen(QPen(QColor(255, 127, 0, 255)));
+               painter.SetBrush(QBrush(QColor(255, 127, 0, 100)));
+               painter.DrawRect(selection);
+       }
+}
 
-                       for(int i=0; i<pts.GetNumPoints(poly); i++)
-                       {
-                               if (pts.GetOnCurve(poly, i))
-//                                     LineTo(hdc, pts.GetX(poly, i), pts.GetY(poly, i));
-                               {
-                                       p.drawLine(x, y, pts.GetX(poly, i), pts.GetY(poly, i));
-                                       x = (int)pts.GetX(poly, i), y = (int)pts.GetY(poly, i);
-                               }
-                               else
-                               {
-                                       uint32 prev = pts.GetPrev(poly, i), next = pts.GetNext(poly, i);
-                                       float px = pts.GetX(poly, prev), py = pts.GetY(poly, prev),
-                                               nx = pts.GetX(poly, next), ny = pts.GetY(poly, next);
 
-                                       if (!pts.GetOnCurve(poly, prev))
-                                               px = (px + pts.GetX(poly, i)) / 2.0f,
-                                               py = (py + pts.GetY(poly, i)) / 2.0f;
+void EditWindow::DrawGlyph(Painter & p, GlyphPoints & glyph)
+{
+       for(int poly=0; poly<glyph.GetNumPolys(); poly++)
+       {
+#if 0
+               if (glyph.GetNumPoints(poly) < 3)
+                       continue;
 
-                                       if (!pts.GetOnCurve(poly, next))
-                                               nx = (nx + pts.GetX(poly, i)) / 2.0f,
-                                               ny = (ny + pts.GetY(poly, i)) / 2.0f;
+               // Initial move: If our start point is on curve, then go to it. Otherwise,
+               // check previous point. If it's on curve, go to it otherwise go the
+               // midpoint between start point and previous (since it's between two curve
+               // control points).
+               IPoint pt = (glyph.GetOnCurve(poly, 0)
+                       ? glyph.GetPoint(poly, 0) : (glyph.GetPrevOnCurve(poly, 0)
+                               ? glyph.GetPrevPoint(poly, 0) : glyph.GetMidpointToPrev(poly, 0)));
 
-                                       Bezier(p, point(px, py), point(pts.GetX(poly, i), pts.GetY(poly, i)), point(nx, ny));
-                                       x = (int)nx, y = (int)ny;
+// Need to add separate color handling here for polys that are being manipulated...
 
-                                       if (pts.GetOnCurve(poly, next))
-                                               i++;                                    // Following point is on curve, so move past it
-                               }
+               for(int i=0; i<glyph.GetNumPoints(poly); i++)
+               {
+                       // If this point and then next are both on curve, we have a line...
+                       if (glyph.GetOnCurve(poly, i) && glyph.GetNextOnCurve(poly, i))
+                       {
+                               IPoint pt2 = glyph.GetNextPoint(poly, i);
+                               p.drawLine(pt.x, pt.y, pt2.x, pt2.y);
+                               pt = pt2;
+                       }
+                       else
+                       {
+                               // Skip point if it's on curve (start of curve--it's already
+                               // been plotted so we don't need to handle it...)
+                               if (glyph.GetOnCurve(poly, i))
+                                       continue;
+
+                               // We are now guaranteed that we are sitting on a curve control point
+                               // (off curve). Figure the extent of the curve: If the following is a
+                               // curve control point, then use the midpoint to it otherwise go to
+                               // the next point since it's on curve.
+                               IPoint pt2 = (glyph.GetNextOnCurve(poly, i)
+                                       ? glyph.GetNextPoint(poly, i) : glyph.GetMidpointToNext(poly, i));
+
+                               Bezier(p, pt, glyph.GetPoint(poly, i), pt2);
+                               pt = pt2;
                        }
                }
+#else
+               DrawGlyphPoly(p, glyph, poly);
+#endif
+       }
+}
+
+
+/*
+So, to make it draw the point the pointer is pointing at, we need to do something. Either patch the GlyphPoints to handle it, or insert the point into the GlyphPoints and delete it if the user changes tools. Either way, need
+to change the color of the line(s) drawn to the point to signal to the user
+that it isn't finalized until they click the button.
+*/
+void EditWindow::DrawGlyphPoly(Painter & p, GlyphPoints & glyph, uint16_t poly)
+{
+       // Sanity check
+       if (glyph.GetNumPoints(poly) < 3)
+               return;
+
+       IPoint p1 = glyph.GetPrevPoint(poly, 0);
+       IPoint p2 = glyph.GetPoint(poly, 0);
+
+       // Inject the new poly point into the current polygon
+       if ((tool == TOOLAddPoly) && (poly == (glyph.GetNumPolys() - 1)))
+       {
+               p1 = IPoint(addPoint.x, addPoint.y, addPointOnCurve);
+       }
+
+       for(int i=0; i<glyph.GetNumPoints(poly); i++)
+       {
+               IPoint p3 = glyph.GetNextPoint(poly, i);
+
+               if ((tool == TOOLAddPoly) && (poly == (glyph.GetNumPolys() - 1))
+                       && (i == (glyph.GetNumPoints(poly) - 1)))
+               {
+                       p3 = IPoint(addPoint.x, addPoint.y, addPointOnCurve);
+                       p.SetPen(QPen(Qt::green, 1.0, Qt::SolidLine));
+                       DrawGlyphSegment(p, p1, p2, p3);
+                       p1 = p2;
+                       p2 = p3;
+                       p3 = glyph.GetNextPoint(poly, i);
+               }
+
+               DrawGlyphSegment(p, p1, p2, p3);
+
+               p1 = p2;
+               p2 = p3;
+       }
+}
+
+
+//
+// Draw a glyph segment given 3 points
+//
+void EditWindow::DrawGlyphSegment(Painter & p, IPoint p1, IPoint p2, IPoint p3)
+{
+       if (p2.onCurve)
+       {
+               // Skip drawing if the middle point is on curve and the last is off
+               if (p3.onCurve)
+                       p.DrawLine(p2, p3);
+       }
+       else
+       {
+               // The middle point is off curve, and so we need to draw a Bezier curve.
+               // Also, depending on whether or not the previous or follow points are
+               // off curve, we need to draw to the midpoints if so.
+               IPoint mid12 = IPoint((p1.x + p2.x) / 2, (p1.y + p2.y) / 2);
+               IPoint mid23 = IPoint((p2.x + p3.x) / 2, (p2.y + p3.y) / 2);
+               p.DrawBezier((p1.onCurve ? p1 : mid12), p2, (p3.onCurve ? p3 : mid23));
        }
 }
 
+
+void EditWindow::ClearSelection(void)
+{
+       for(int i=0; i<65536; i++)
+               selectedPoints[i] = false;
+}
+
+
 void EditWindow::mousePressEvent(QMouseEvent * event)
 {
        if (event->button() == Qt::RightButton)
@@ -271,22 +371,48 @@ void EditWindow::mousePressEvent(QMouseEvent * event)
        }
        else if (event->button() == Qt::MidButton)
        {
-               setCursor(cur[2]);                                                      // Scrolling cursor
+               // Scrolling cursor
+               setCursor(cur[11]);
+               ptPrevious = Vector(event->x(), event->y());
+               ptPrevious /= Global::zoom;
        }
        else if (event->button() == Qt::LeftButton)
        {
                if (tool == TOOLScroll || tool == TOOLZoom)
 ;//meh                 CaptureMouse();                                         // Make sure we capture the mouse when in scroll/zoom mode
+               else if (tool == TOOLMultiSelect)
+               {
+//                     QPoint pt = GetAdjustedMousePosition(event);
+                       Vector pt = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
+                       selectionInProgress = true;
+                       selection.setTopLeft(QPoint(pt.x, pt.y));
+                       selection.setBottomRight(QPoint(pt.x, pt.y));
+               }
                else if (tool == TOOLAddPt)             // "Add Point" tool
                {
-                       if (pts.GetNumPoints() > 0)
+//                     QPoint pt = GetAdjustedMousePosition(event);
+                       Vector pt = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
+                       IPoint pointToAdd(pt.x, pt.y, ((event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier) ? false : true));
+
+                       if (pts.GetNumPoints() < 2)
                        {
-                               QPoint pt = GetAdjustedMousePosition(event);
-                               pts.InsertPoint(pts.GetNext(ptHighlight), pt.x(), pt.y(), ((event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier) ? false : true));
+//                             pts += IPoint(pt.x(), pt.y(), ((event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier) ? false : true));
+                               pts += pointToAdd;
+                               ptHighlight = pts.GetNumPoints() - 1;
+                       }
+                       else
+                       {
+//                             QPoint pt = GetAdjustedMousePosition(event);
+//                             pts.InsertPoint(pts.GetNext(ptHighlight), pt.x(), pt.y(), ((event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier) ? false : true));
+                               pts.InsertPoint(pts.GetNext(ptHighlight), pointToAdd);
                                ptHighlight = ptNextHighlight;
-                               update();
+//                             update();
                        }
+
+                       update();
                }
+// Moved to mouse up routine, so we can slide the point around
+#if 0
                else if (tool == TOOLAddPoly)   // "Add Poly" tool
                {
 #ifdef DEBUGFOO
@@ -298,24 +424,27 @@ WriteLogMsg("Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts.
                                pts.AddNewPolyAtEnd();
                        }
 
-                       QPoint pt = GetAdjustedMousePosition(event);
+//                     QPoint pt = GetAdjustedMousePosition(event);
+                       Vector pt = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
 //printf("GetAdjustedMousePosition = %i, %i\n", pt.x(), pt.y());
                        // Append a point to the end of the structure
-                       pts += IPoint(pt.x(), pt.y(), ((event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier) ? false : true));
+                       pts += IPoint(pt.x, pt.y, ((event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier) ? false : true));
                        ptHighlight = pts.GetNumPoints() - 1;
                        update();
 #ifdef DEBUGFOO
 WriteLogMsg(" --> [# polys: %u, # points: %u]\n", pts.GetNumPolys(), pts.GetNumPoints());
 #endif
                }
+#endif
                else if (tool == TOOLSelect || tool == TOOLPolySelect)
                {
                        if (pts.GetNumPoints() > 0)
                        {
-                               pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight));
-//printf("GetAdjustedClientPosition = %i, %i\n", pt.x(), pt.y());
-//                             WarpPointer(pt.x, pt.y);
-                               QCursor::setPos(mapToGlobal(pt));
+//                             pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight));
+                               Vector pt = Painter::CartesianToQtCoords(Vector(pts.GetX(ptHighlight), pts.GetY(ptHighlight)));
+//printf("GetAdjustedClientPosition = %lf, %lf\n", pt.x, pt.y);
+                               QPoint warp(pt.x, pt.y);
+                               QCursor::setPos(mapToGlobal(warp));
 
                                if (event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier)
                                {
@@ -336,11 +465,46 @@ WriteLogMsg(" --> [# polys: %u, # points: %u]\n", pts.GetNumPolys(), pts.GetNumP
                                update();
                        }
                }
+               else if (tool == TOOLRotate)
+               {
+                       // I think what's needed here is to keep the initial mouse click,
+                       // paint the rotation center, then use the 1st mouse move event to
+                       // establish the rotation "zero line", which becomes the line of
+                       // reference to all subsequent mouse moves.
+//                     rotationCenter = GetAdjustedMousePosition(event);
+                       rotationCenter = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
+                       showRotationCenter = true;
+                       haveZeroPoint = false;
+                       rotationAngle = 0;
+                       update();
+               }
+               else if (tool == TOOLRotatePoly)
+               {
+                       IPoint centroid = pts.GetPolyCentroid(pts.GetPolyForPointNumber(ptHighlight));
+                       rotationCenter = Vector(centroid.x, centroid.y);
+                       showRotationCenter = true;
+//                     pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight));
+                       Vector pt = Painter::CartesianToQtCoords(Vector(pts.GetX(ptHighlight), pts.GetY(ptHighlight)));
+                       QCursor::setPos(mapToGlobal(QPoint(pt.x, pt.y)));
+                       rotationZeroPoint = Vector(pts.GetX(ptHighlight), pts.GetY(ptHighlight));
+                       haveZeroPoint = true;
+                       rotationAngle = 0;
+                       update();
+               }
+               else if (tool == TOOLFlipWinding)
+               {
+                       pts.InvertPolyDrawSequence(pts.GetPolyForPointNumber(ptHighlight));
+//                     pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight));
+                       Vector pt = Painter::CartesianToQtCoords(Vector(pts.GetX(ptHighlight), pts.GetY(ptHighlight)));
+                       QCursor::setPos(mapToGlobal(QPoint(pt.x, pt.y)));
+                       update();
+               }
        }
 
        event->accept();
 }
 
+
 void EditWindow::mouseMoveEvent(QMouseEvent * event)
 {
        if (event->buttons() == Qt::RightButton)
@@ -356,83 +520,119 @@ void EditWindow::mouseMoveEvent(QMouseEvent * event)
        else if (event->buttons() == Qt::MidButton)
        {
                // Calc offset from previous point
-               pt = event->pos();
-               ptOffset = QPoint(pt.x() - ptPrevious.x(), pt.y() - ptPrevious.y());
+               Vector pt(event->x(), event->y());
+               pt /= Global::zoom;
+               ptOffset = Vector(pt.x - ptPrevious.x, -(pt.y - ptPrevious.y));
 
 // Then multiply it by the scaling factor. Whee!
                // This looks wacky because we're using screen coords for the offset...
                // Otherwise, we would subtract both offsets!
-               offsetX -= ptOffset.x(), offsetY += ptOffset.y();
-               update();
+//             offsetX -= ptOffset.x, offsetY += ptOffset.y;
+               Global::origin -= ptOffset;
                ptPrevious = pt;
+               update();
        }
        else if (event->buttons() == Qt::LeftButton)
        {
-#if 0
-                       if (tool == TOOLScroll)
-                       {
-                           // Extract current point from lParam/calc offset from previous point
-
-                               pt = e.GetPosition();
-                               ptOffset.x = pt.x - ptPrevious.x,
-                               ptOffset.y = pt.y - ptPrevious.y;
-
-                               // NOTE: OffsetViewportOrg operates in DEVICE UNITS...
+               if (tool == TOOLAddPt || tool == TOOLAddPoly || tool == TOOLSelect)
+               {
+                       // Bail out if we have the select tool and no points yet...
+                       if ((tool == TOOLSelect) && (pts.GetNumPoints() == 0))
+                               return;
 
-//Seems there's no equivalent for this in wxWidgets...!
-//!!! FIX !!!
-//                             hdc = GetDC(hWnd);
-//                             OffsetViewportOrgEx(hdc, ptOffset.x, ptOffset.y, NULL);
-//                             ReleaseDC(hWnd, hdc);
+//                     QPoint pt2 = GetAdjustedMousePosition(event);
+                       Vector pt2 = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
 
-// this shows that it works, so the logic above must be faulty...
-// And it is. It should convert the coords first, then do the subtraction to figure the offset...
-// Above: DONE
-// Then multiply it by the scaling factor. Whee!
-                               // This looks wacky because we're using screen coords for the offset...
-                               // Otherwise, we would subtract both offsets!
-                               offsetX -= ptOffset.x, offsetY += ptOffset.y;
-                               Refresh();
+                       if (tool != TOOLSelect)
+                       {
+                               addPoint = pt2;
+                               ptHighlight = -1;
+                               // Prolly should move this to the key handlers below...
+//now we do! :-D
+//                             addPointOnCurve = ((event->modifiers() == Qt::ShiftModifier) || (event->modifiers() == Qt::ControlModifier) ? false : true);
                        }
                        else
-#endif
-                       if (tool == TOOLAddPt || tool == TOOLAddPoly || tool == TOOLSelect)
+                               pts.SetXY(ptHighlight, pt2.x, pt2.y);
+
+                       update();
+               }
+               else if (tool == TOOLPolySelect)
+               {
+                       if (pts.GetNumPoints() > 0)
                        {
-                               if (tool != TOOLAddPt || pts.GetNumPoints() > 0)//yecch.
-                               {
-//temporary, for testing. BTW, Select drag bug is here...!
-#if 1
-                                       QPoint pt2 = GetAdjustedMousePosition(event);
-                                       pts.SetXY(ptHighlight, pt2.x(), pt2.y());
-                                       update();
-#endif
-                               }
+//                             QPoint pt2 = GetAdjustedMousePosition(event);
+                               Vector pt2 = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
+                               // Should also set onCurve here as well, depending on keystate
+//Or should we?
+//Would be nice, but we'd need to trap the keyPressEvent() as well, otherwise pressing/releasing
+//the hotkey would show no change until the user moved their mouse.
+                               pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x - pts.GetX(ptHighlight), pt2.y - pts.GetY(ptHighlight));
+                               update();
                        }
-                       else if (tool == TOOLPolySelect)
+               }
+               else if (tool == TOOLRotate || tool == TOOLRotatePoly)
+               {
+                       if (pts.GetNumPoints() > 0)
                        {
-                               if (pts.GetNumPoints() > 0)
+                               if (!haveZeroPoint)
                                {
-                                       QPoint pt2 = GetAdjustedMousePosition(event);
-                                       // Should also set onCurve here as well, depending on keystate
-//Or should we?
-                                       pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x() - pts.GetX(ptHighlight), pt2.y() - pts.GetY(ptHighlight));
-                                       update();
+//                                     rotationZeroPoint = GetAdjustedMousePosition(event);
+                                       rotationZeroPoint = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
+                                       haveZeroPoint = true;
                                }
+                               else
+                               {
+                                       // Figure out the angle between the "zero" vector and the
+                                       // current one, then rotate all points relative to the
+                                       // "zero" vector (done by paint())
+//                                     QPoint currentPoint = GetAdjustedMousePosition(event);
+                                       Vector currentPoint = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
+                                       Vector v1(rotationZeroPoint.x, rotationZeroPoint.y, 0,
+                                               rotationCenter.x, rotationCenter.y, 0);
+                                       Vector v2(currentPoint.x, currentPoint.y, 0,
+                                               rotationCenter.x, rotationCenter.y, 0);
+//                                     rotationAngle = v1.Angle(v2);
+                                       rotationAngle = v2.Angle(v1);
+
+                                       QString s;
+                                       s.sprintf("%.3f degrees", rotationAngle * RADIANS_TO_DEGREES);
+                                       Global::mainWindow->statusBar()->showMessage(s);
+                               }
+
+                               update();
                        }
+               }
+               else if (tool == TOOLMultiSelect)
+               {
+//                     QPoint pt = GetAdjustedMousePosition(event);
+                       Vector pt = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
+                       selection.setBottomRight(QPoint(pt.x, pt.y));
+
+                       for(int i=0; i<pts.GetNumPoints(); i++)
+                       {
+                               if (selection.contains(QPoint(pts.GetX(i), pts.GetY(i))))
+                                       selectedPoints[i] = true;
+                               else
+                                       selectedPoints[i] = false;
+                       }
+
+                       update();
+               }
        }
        else if (event->buttons() == Qt::NoButton)
        {
                // Moving, not dragging...
                if (tool == TOOLSelect || tool == TOOLDelPt || tool == TOOLAddPt
-                       || tool == TOOLPolySelect)// || tool == TOOLAddPoly)
+                       || tool == TOOLPolySelect || tool == TOOLRotatePoly || tool == TOOLFlipWinding)
                {
-                       QPoint pt2 = GetAdjustedMousePosition(event);
+//                     QPoint pt2 = GetAdjustedMousePosition(event);
+                       Vector pt2 = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
                        double closest = 1.0e+99;
 
                        for(int i=0; i<pts.GetNumPoints(); i++)
                        {
-                               double dist = ((pt2.x() - pts.GetX(i)) * (pt2.x() - pts.GetX(i)))
-                                       + ((pt2.y() - pts.GetY(i)) * (pt2.y() - pts.GetY(i)));
+                               double dist = ((pt2.x - pts.GetX(i)) * (pt2.x - pts.GetX(i)))
+                                       + ((pt2.y - pts.GetY(i)) * (pt2.y - pts.GetY(i)));
 
                                if (dist < closest)
                                        closest = dist, ptHighlight = i;
@@ -444,15 +644,17 @@ void EditWindow::mouseMoveEvent(QMouseEvent * event)
                                update();
                        }
 
-                       // What follows here looks like voodoo, but is really simple. What we do is
-                       // check to see if the mouse point has a perpendicular intersection with any of
-                       // the line segments. If it does, calculate the length of the perpendicular
-                       // and choose the smallest length. If there is no perpendicular, then choose the
-                       // length of line connecting the closer of either the first endpoint or the
-                       // second and choose the smallest of those.
+                       // What follows here looks like voodoo, but is really simple. What
+                       // we do is check to see if the mouse point has a perpendicular
+                       // intersection with any of the line segments. If it does,
+                       // calculate the length of the perpendicular and choose the
+                       // smallest length. If there is no perpendicular, then choose the
+                       // length of line connecting the closer of either the first
+                       // endpoint or the second and choose the smallest of those.
 
-                       // There is one bit of math that looks like voodoo to me ATM--will explain once
-                       // I understand it better (the calculation of the length of the perpendicular).
+                       // There is one bit of math that looks like voodoo to me ATM--will
+                       // explain once I understand it better (the calculation of the
+                       // length of the perpendicular).
 
                        if (pts.GetNumPoints() > 1 && tool == TOOLAddPt)
                        {
@@ -460,32 +662,36 @@ void EditWindow::mouseMoveEvent(QMouseEvent * event)
 
                                for(int i=0; i<pts.GetNumPoints(); i++)
                                {
-                                       int32 p1x = pts.GetX(i), p1y = pts.GetY(i),
+                                       int32_t p1x = pts.GetX(i), p1y = pts.GetY(i),
                                                p2x = pts.GetX(pts.GetNext(i)), p2y = pts.GetY(pts.GetNext(i));
 
-                                       vector ls(p2x, p2y, 0, p1x, p1y, 0), v1(pt2.x(), pt2.y(), 0, p1x, p1y, 0),
-                                               v2(pt2.x(), pt2.y(), 0, p2x, p2y, 0);
-                                       double pp = ls.dot(v1) / ls.length(), dist;
+                                       Vector ls(p2x, p2y, 0, p1x, p1y, 0),
+                                               v1(pt2.x, pt2.y, 0, p1x, p1y, 0),
+                                               v2(pt2.x, pt2.y, 0, p2x, p2y, 0);
+                                       double pp = ls.Dot(v1) / ls.Magnitude(), dist;
 // Geometric interpretation:
-// pp is the paremeterized point on the vector ls where the perpendicular intersects ls.
-// If pp < 0, then the perpendicular lies beyond the 1st endpoint. If pp > length of ls,
-// then the perpendicular lies beyond the 2nd endpoint.
+// pp is the paremeterized point on the vector ls where the perpendicular
+// intersects ls. If pp < 0, then the perpendicular lies beyond the 1st
+// endpoint. If pp > length of ls, then the perpendicular lies beyond the 2nd
+// endpoint.
 
                                        if (pp < 0.0)
-                                               dist = v1.length();
-                                       else if (pp > ls.length())
-                                               dist = v2.length();
+                                               dist = v1.Magnitude();
+                                       else if (pp > ls.Magnitude())
+                                               dist = v2.Magnitude();
                                        else                                    // distance = ?Det?(ls, v1) / |ls|
-                                               dist = fabs((ls.x * v1.y - v1.x * ls.y) / ls.length());
+                                               dist = fabs((ls.x * v1.y - v1.x * ls.y) / ls.Magnitude());
 
 //The answer to the above looks like it might be found here:
 //
-//If the segment endpoints are s and e, and the point is p, then the test for the perpendicular
-//intercepting the segment is equivalent to insisting that the two dot products {s-e}.{s-p} and
-//{e-s}.{e-p} are both non-negative.  Perpendicular distance from the point to the segment is
-//computed by first computing the area of the triangle the three points form, then dividing by the
-//length of the segment.  Distances are done just by the Pythagorean theorem.  Twice the area of the
-//triangle formed by three points is the determinant of the following matrix:
+//If the segment endpoints are s and e, and the point is p, then the test for
+//the perpendicular intercepting the segment is equivalent to insisting that
+//the two dot products {s-e}.{s-p} and {e-s}.{e-p} are both non-negative.
+//Perpendicular distance from the point to the segment is computed by first
+//computing the area of the triangle the three points form, then dividing by
+//the length of the segment.  Distances are done just by the Pythagorean
+//theorem. Twice the area of the triangle formed by three points is the
+//determinant of the following matrix:
 //
 //sx sy 1
 //ex ey 1
@@ -493,8 +699,9 @@ void EditWindow::mouseMoveEvent(QMouseEvent * event)
 //
 //By translating the start point to the origin, this can be rewritten as:
 //By subtracting row 1 from all rows, you get the following:
-//[because sx = sy = 0. you could leave out the -sx/y terms below. because we subtracted
-// row 1 from all rows (including row 1) row 1 turns out to be zero. duh!]
+//[because sx = sy = 0. you could leave out the -sx/y terms below. because we
+//subtracted row 1 from all rows (including row 1) row 1 turns out to be zero.
+//duh!]
 //
 //0         0         0
 //(ex - sx) (ey - sy) 0
@@ -514,12 +721,19 @@ void EditWindow::mouseMoveEvent(QMouseEvent * event)
                        }
                }
 
-               ptPrevious = event->pos();
+               ptPrevious = Vector(event->x(), event->y());
+               addPoint = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
+//handled by real key handlers now...
+//             addPointOnCurve = ((event->modifiers() == Qt::ShiftModifier) || (event->modifiers() == Qt::ControlModifier) ? false : true);
+
+               if (tool == TOOLAddPoly)
+                       update();
        }
 
        event->accept();
 }
 
+
 void EditWindow::mouseReleaseEvent(QMouseEvent * event)
 {
        if (event->button() == Qt::RightButton)
@@ -550,12 +764,107 @@ void EditWindow::mouseReleaseEvent(QMouseEvent * event)
        }
        else if (event->button() == Qt::LeftButton)
        {
+               if (showRotationCenter)
+               {
+                       showRotationCenter = false;
+                       haveZeroPoint = false;
+
+                       if (tool == TOOLRotate)
+                               pts.RotatePoints(rotationAngle, IPoint(rotationCenter.x, rotationCenter.y));
+                       else
+                       {
+                               uint16_t poly = pts.GetPolyForPointNumber(ptHighlight);
+                               pts.RotatePolyAroundCentroid(poly, rotationAngle);
+                       }
+
+                       update();
+                       Global::mainWindow->statusBar()->showMessage("");
+               }
+
 //             if (tool == TOOLScroll || tool == TOOLZoom)
 //                     ReleaseMouse();
 //this is prolly too much
-               ((TTEdit *)qApp)->charWnd->MakePathFromPoints(&pts);
-               ((TTEdit *)qApp)->charWnd->update();
+               Global::charWnd->MakePathFromPoints(&pts);
+               Global::charWnd->update();
+
+               if (tool == TOOLMultiSelect)
+               {
+                       selectionInProgress = false;
+                       update();
+               }
+               else if (tool == TOOLAddPoly)   // "Add Poly" tool
+               {
+#ifdef DEBUGFOO
+WriteLogMsg("Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts.GetNumPoints());
+#endif
+                       if (polyFirstPoint)
+                       {
+                               polyFirstPoint = false;
+                               pts.AddNewPolyAtEnd();
+                       }
+
+//                     QPoint pt = GetAdjustedMousePosition(event);
+                       Vector pt = Painter::QtToCartesianCoords(Vector(event->x(), event->y()));
+//printf("GetAdjustedMousePosition = %i, %i\n", pt.x(), pt.y());
+                       // Append a point to the end of the structure
+                       pts += IPoint(pt.x, pt.y, addPointOnCurve);
+//                     ptHighlight = pts.GetNumPoints() - 1;
+                       update();
+#ifdef DEBUGFOO
+WriteLogMsg(" --> [# polys: %u, # points: %u]\n", pts.GetNumPolys(), pts.GetNumPoints());
+#endif
+               }
        }
 
        event->accept();
 }
+
+
+void EditWindow::keyPressEvent(QKeyEvent * event)
+{
+       // We do this here because of the ptHighlight nonsense. If we're in
+       // the add poly tool, we'll never see this if it's under the 'sanity'
+       // check (which is needed for the arrow key shite, but still...)
+       if ((event->key() == Qt::Key_Shift) || (event->key() == Qt::Key_Control))
+       {
+               addPointOnCurve = false;
+               update();
+       }
+
+       // Sanity checking...
+       if (ptHighlight == -1)
+               return;
+
+       if (event->key() == Qt::Key_Up)
+       {
+               pts.SetXY(ptHighlight, pts.GetX(ptHighlight), pts.GetY(ptHighlight) + 1);
+       }
+       else if (event->key() == Qt::Key_Down)
+               pts.SetXY(ptHighlight, pts.GetX(ptHighlight), pts.GetY(ptHighlight) - 1);
+       else if (event->key() == Qt::Key_Right)
+               pts.SetXY(ptHighlight, pts.GetX(ptHighlight) + 1, pts.GetY(ptHighlight));
+       else if (event->key() == Qt::Key_Left)
+               pts.SetXY(ptHighlight, pts.GetX(ptHighlight) - 1, pts.GetY(ptHighlight));
+       else
+               return;
+
+//Not need but you need to call the base class for some reason??
+//     event->accept();
+       update();
+       Global::charWnd->MakePathFromPoints(&pts);
+       Global::charWnd->update();
+}
+
+
+void EditWindow::keyReleaseEvent(QKeyEvent * event)
+{
+       if ((event->key() == Qt::Key_Shift) || (event->key() == Qt::Key_Control))
+       {
+               addPointOnCurve = true;
+       }
+       else
+               return;
+
+       update();
+}
+