]> Shamusworld >> Repos - ttedit/blobdiff - src/editwindow.cpp
Fixed a handful of bugs related to clicking and dragging
[ttedit] / src / editwindow.cpp
index 63e8b3f4a9e2e1674a804fdac3b627fbb52b49d4..ef3d585b2ddd4fd333c2c74759c3a43e3ccf9376 100755 (executable)
-//\r
-// TTEDIT.CPP - The TrueType Editor\r
-// by James L. Hammons\r
-// (C) 2004 Underground Software\r
-//\r
-// JLH = James L. Hammons <jlhamm@acm.org>\r
-//\r
-// Who  When        What\r
-// ---  ----------  -------------------------------------------------------------\r
-// JLH  08/28/2008  Created this file\r
-//\r
-\r
-// FIXED:\r
-//\r
-// STILL TO BE DONE:\r
-//\r
-// - Fix bug in Glyphpoints when dragging on an empty canvas or loading a font\r
-// - Fix scrolling, zooming, settings (ini)\r
-//\r
-\r
-// Uncomment this for debugging...\r
-#define DEBUG\r
-#define DEBUGFOO            // Various tool debugging...\r
-#define DEBUGTP                                // Toolpalette debugging...\r
-\r
-#include "editwindow.h"\r
-#include "bezier.h"\r
-#include "toolwindow.h"\r
-#include "debug.h"\r
-#include "vector.h"\r
-\r
-\r
-BEGIN_EVENT_TABLE(TTEditWindow, wxWindow)\r
-       EVT_PAINT(TTEditWindow::OnPaint)\r
-       EVT_MOUSE_EVENTS(TTEditWindow::OnMouseEvent)\r
-END_EVENT_TABLE()\r
-\r
-TTEditWindow::TTEditWindow(wxFrame * parent, const wxPoint &pos, const wxSize &size, long style):\r
-       wxWindow(parent, -1, pos, size, style | wxFULL_REPAINT_ON_RESIZE),\r
-       app(wxGetApp()), scale(1.0), offsetX(-10), offsetY(-10), tool(TOOLSelect),\r
-       ptHighlight(-1), oldPtHighlight(-1), ptNextHighlight(-1), oldPtNextHighlight(-1),\r
-       polyFirstPoint(true), bmp(NULL)\r
-{ \r
-       SetCursor(*(app.cur[tool]));\r
-       SetBackgroundColour(wxColour(0xFF, 0xFF, 0xFF));\r
-\r
-       wxString s;\r
-       s.Printf(_("Zoom: %.2f%%"), scale * 100.0);\r
-       parent->SetStatusText(s, 1);\r
-}\r
-\r
-TTEditWindow::~TTEditWindow(void)\r
-{\r
-       if (bmp)\r
-               delete bmp;\r
-}\r
-\r
-void TTEditWindow::OnPaint(wxPaintEvent &e)\r
-{\r
-       wxPaintDC dc(this);\r
-//Doesn't do crap!\r
-//dc.SetBackground(*wxWHITE_BRUSH);\r
-\r
-// Due to the screwiness of wxWidgets coord system, the origin is ALWAYS\r
-// the upper left corner--regardless of axis orientation, etc...\r
-       wxCoord width, height;\r
-       dc.GetSize(&width, &height);\r
-\r
-       dc.SetDeviceOrigin(-offsetX, height - (-offsetY));\r
-       dc.SetAxisOrientation(true, true);\r
-\r
-// Scrolling can be done by using OffsetViewportOrgEx\r
-// Scaling can be done by adjusting SetWindowExtEx (it's denominator of txform)\r
-// you'd use: % = ViewportExt / WindowExt\r
-// But it makes the window look like crap: fuggetuboutit.\r
-// Instead, we have to scale EVERYTHING by hand. Crap!\r
-// It's not *that* bad, but not as convenient either...\r
-\r
-       dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0xFF), 1, wxDOT)));\r
-//     dc.DrawLine(0, 0, 10, 10);\r
-\r
-    // Draw coordinate axes\r
-\r
-       dc.CrossHair(0, 0);\r
-\r
-    // Draw points\r
-\r
-       for(int i=0; i<pts.GetNumPoints(); i++)\r
-       {\r
-               if (i == ptHighlight)\r
-               {\r
-                       dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));\r
-//                     SelectObject(hdc, hRedPen1);\r
-\r
-                       if (pts.GetOnCurve(i))\r
-                       {\r
-                               DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 7);\r
-                               DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 9);\r
-                       }\r
-                       else\r
-                       {\r
-                               DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 7);\r
-                               DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 9);\r
-                       }\r
-               }\r
-               else if ((i == ptHighlight || i == ptNextHighlight) && tool == TOOLAddPt)\r
-               {\r
-                       dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0xAF, 0x00), 1, wxSOLID)));\r
-//                     SelectObject(hdc, hGreenPen1);\r
-\r
-                       if (pts.GetOnCurve(i))\r
-                       {\r
-                               DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 7);\r
-                               DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 9);\r
-                       }\r
-                       else\r
-                       {\r
-                               DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 7);\r
-                               DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 9);\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));\r
-//                     SelectObject(hdc, hBlackPen1);\r
-\r
-                       if (pts.GetOnCurve(i))\r
-                               DrawSquareDot(dc, pts.GetX(i), pts.GetY(i));\r
-                       else\r
-                               DrawRoundDot(dc, pts.GetX(i), pts.GetY(i));\r
-               }\r
-\r
-               if (tool == TOOLDelPt && i == ptHighlight)\r
-               {\r
-                       dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));\r
-//                     SelectObject(hdc, hRedPen1);\r
-//                     MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5, NULL);\r
-//                     LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) + 5);\r
-//                     LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5);//Lameness!\r
-//                     MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5, NULL);\r
-//                     LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) - 5);\r
-//                     LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5);//More lameness!!\r
-                       dc.DrawLine(pts.GetX(i) - 5, pts.GetY(i) - 5, pts.GetX(i) + 5, pts.GetY(i) + 5);\r
-                       dc.DrawLine(pts.GetX(i) + 5, pts.GetY(i) - 5, pts.GetX(i) - 5, pts.GetY(i) + 5);\r
-               }\r
-       }\r
-\r
-//             SelectObject(hdc, hBlackPen1);\r
-       dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));\r
-\r
-       // Draw curve formed by points\r
-\r
-       for(int poly=0; poly<pts.GetNumPolys(); poly++)\r
-       {\r
-               if (pts.GetNumPoints(poly) > 2)\r
-               {\r
-                       // Initial move...\r
-                       // If it's not on curve, then move to it, otherwise move to last point...\r
-\r
-                       wxCoord x, y;\r
-       \r
-                       if (pts.GetOnCurve(poly, pts.GetNumPoints(poly) - 1))\r
-                               x = (wxCoord)pts.GetX(poly, pts.GetNumPoints(poly) - 1), y = (wxCoord)pts.GetY(poly, pts.GetNumPoints(poly) - 1);\r
-                       else\r
-                               x = (wxCoord)pts.GetX(poly, 0), y = (wxCoord)pts.GetY(poly, 0);\r
-       \r
-                       for(int i=0; i<pts.GetNumPoints(poly); i++)\r
-                       {\r
-                               if (pts.GetOnCurve(poly, i))\r
-//                                     LineTo(hdc, pts.GetX(poly, i), pts.GetY(poly, i));\r
-                               {\r
-                                       dc.DrawLine(x, y, pts.GetX(poly, i), pts.GetY(poly, i));\r
-                                       x = (wxCoord)pts.GetX(poly, i), y = (wxCoord)pts.GetY(poly, i);\r
-                               }\r
-                               else\r
-                               {\r
-                                       uint32 prev = pts.GetPrev(poly, i), next = pts.GetNext(poly, i);\r
-                                       float px = pts.GetX(poly, prev), py = pts.GetY(poly, prev),\r
-                                               nx = pts.GetX(poly, next), ny = pts.GetY(poly, next);\r
-       \r
-                                       if (!pts.GetOnCurve(poly, prev))\r
-                                               px = (px + pts.GetX(poly, i)) / 2.0f,\r
-                                               py = (py + pts.GetY(poly, i)) / 2.0f;\r
-       \r
-                                       if (!pts.GetOnCurve(poly, next))\r
-                                               nx = (nx + pts.GetX(poly, i)) / 2.0f,\r
-                                               ny = (ny + pts.GetY(poly, i)) / 2.0f;\r
-       \r
-                                       Bezier(dc, point(px, py), point(pts.GetX(poly, i), pts.GetY(poly, i)), point(nx, ny));\r
-                                       x = (wxCoord)nx, y = (wxCoord)ny;\r
-       \r
-                                       if (pts.GetOnCurve(poly, next))\r
-                                               i++;                                    // Following point is on curve, so move past it\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-//             SelectObject(hdc, oldPen);                              // Restore the stuff we disrupted...\r
-       dc.SetPen(wxNullPen);\r
-//             SelectObject(hdc, oldBrush);\r
-//             EndPaint(hWnd, &ps);\r
-}\r
-\r
-void TTEditWindow::OnMouseEvent(wxMouseEvent &e)\r
-{\r
-#ifdef DEBUGTP\r
-//printf("!!! This window %s focus...!\n", (HasCapture() ? "has" : "doesn't have"));\r
-#endif\r
-       if (e.RightDown())\r
-       {\r
-               // Handle tool palette (NOTE: tool palette deals with RightUp event.)\r
-\r
-               wxPoint pt = ClientToScreen(e.GetPosition());\r
-               app.toolPalette->Move(pt);\r
-               app.toolPalette->Show(true);\r
-               SetCursor(*wxSTANDARD_CURSOR);\r
-               app.toolPalette->SetCursor(*wxSTANDARD_CURSOR);\r
-               app.toolPalette->prevTool = TOOLSelect;\r
-               app.toolPalette->Refresh(false);\r
-               CaptureMouse();\r
-       }\r
-       else if (e.RightUp())\r
-       {\r
-               ToolType newTool = app.toolPalette->FindSelectedTool();//, oldTool = tool;\r
-\r
-               // We only change the tool if a new one was actually selected. Otherwise, we do nothing.\r
-               if (newTool != TOOLNone)\r
-               {\r
-                       tool = newTool;\r
-\r
-                       if (tool == TOOLScroll || tool == TOOLZoom || tool == TOOLAddPoly\r
-                               || tool == TOOLDelPoly)\r
-                               ptHighlight = -1;\r
-\r
-                       if (tool == TOOLAddPoly)\r
-                               polyFirstPoint = true;\r
-               }\r
-\r
-               ReleaseMouse();\r
-               app.toolPalette->Show(false);\r
-               SetCursor(*(app.cur[tool]));\r
-       }\r
-       else if (e.LeftDown())\r
-       {\r
-               if (tool == TOOLScroll || tool == TOOLZoom)\r
-                       CaptureMouse();                                         // Make sure we capture the mouse when in scroll/zoom mode\r
-               else if (tool == TOOLAddPt)             // "Add Point" tool\r
-               {\r
-                       if (pts.GetNumPoints() > 0)\r
-                       {\r
-                               wxPoint pt = GetAdjustedMousePosition(e);\r
-                               pts.InsertPoint(pts.GetNext(ptHighlight), pt.x, pt.y, (e.ShiftDown() | e.ControlDown() ? false : true));\r
-                               ptHighlight = ptNextHighlight;\r
-                               Refresh();\r
-                       }\r
-               }\r
-               else if (tool == TOOLAddPoly)   // "Add Poly" tool\r
-               {\r
-#ifdef DEBUGFOO\r
-WriteLogMsg("Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts.GetNumPoints());\r
-#endif\r
-                       if (polyFirstPoint)\r
-                       {\r
-                               polyFirstPoint = false;\r
-                               pts.AddNewPolyAtEnd();\r
-                       }\r
-\r
-                       wxPoint pt = GetAdjustedMousePosition(e);\r
-                       // Append a point to the end of the structure\r
-                       pts += IPoint(pt.x, pt.y, (e.ShiftDown() | e.ControlDown() ? false : true));\r
-                       ptHighlight = pts.GetNumPoints() - 1;\r
-                       Refresh();\r
-#ifdef DEBUGFOO\r
-WriteLogMsg(" --> [# polys: %u, # points: %u]\n", pts.GetNumPolys(), pts.GetNumPoints());\r
-#endif\r
-               }\r
-               else if (tool == TOOLSelect || tool == TOOLPolySelect)\r
-               {\r
-                       if (pts.GetNumPoints() > 0)\r
-                       {\r
-                               pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight));\r
-                               WarpPointer(pt.x, pt.y);\r
-\r
-                               if (e.ShiftDown() | e.ControlDown())\r
-                                       pts.SetOnCurve(ptHighlight, !pts.GetOnCurve(ptHighlight));\r
-                       }\r
-               }\r
-               else if (tool == TOOLDelPt)\r
-               {\r
-                       if (pts.GetNumPoints() > 0)\r
-//Or could use:\r
-//                     if (ptHighlight != -1)\r
-                       {\r
-//This assumes that WM_MOUSEMOVE happens before this!\r
-//The above commented out line should take care of this contingency... !!! FIX !!!\r
-                               pts.DeletePoint(ptHighlight);\r
-                               Refresh();\r
-                       }\r
-               }\r
-       }\r
-       else if (e.LeftUp())\r
-       {\r
-//             mouseDown = false;\r
-\r
-               if (tool == TOOLScroll || tool == TOOLZoom)\r
-                       ReleaseMouse();\r
-       }\r
-       else if (e.Dragging())\r
-       {\r
-               if (e.RightIsDown())\r
-               {\r
-                       ToolType newTool = app.toolPalette->FindSelectedTool();\r
-\r
-                       if (newTool != app.toolPalette->prevTool)\r
-                       {\r
-                               app.toolPalette->prevTool = newTool;\r
-                               app.toolPalette->Refresh(false);\r
-                       }\r
-\r
-                       return;\r
-               }\r
-\r
-           // Extract current point from lParam/calc offset from previous point\r
-\r
-               pt = e.GetPosition();\r
-               ptOffset.x = pt.x - ptPrevious.x,\r
-               ptOffset.y = pt.y - ptPrevious.y;\r
-\r
-//             if (e.LeftIsDown())\r
-//             {\r
-                       if (tool == TOOLScroll)\r
-                       {\r
-                               // NOTE: OffsetViewportOrg operates in DEVICE UNITS...\r
-\r
-//Seems there's no equivalent for this in wxWidgets...!\r
-//!!! FIX !!!\r
-//                             hdc = GetDC(hWnd);\r
-//                             OffsetViewportOrgEx(hdc, ptOffset.x, ptOffset.y, NULL);\r
-//                             ReleaseDC(hWnd, hdc);\r
-\r
-// this shows that it works, so the logic above must be faulty...\r
-// And it is. It should convert the coords first, then do the subtraction to figure the offset...\r
-// Above: DONE\r
-// Then multiply it by the scaling factor. Whee!\r
-                               // This looks wacky because we're using screen coords for the offset...\r
-                               // Otherwise, we would subtract both offsets!\r
-                               offsetX -= ptOffset.x, offsetY += ptOffset.y;\r
-                               Refresh();\r
-                       }\r
-                       else if (tool == TOOLAddPt || tool == TOOLAddPoly || tool == TOOLSelect)\r
-                       {\r
-                               if (tool != TOOLAddPt || pts.GetNumPoints() > 0)//yecch.\r
-                               {\r
-//temporary, for testing. BTW, Select drag bug is here...!\r
-#if 0\r
-                                       wxPoint pt2 = GetAdjustedMousePosition(e);\r
-                                       pts.SetXY(ptHighlight, pt2.x, pt2.y);\r
-                                       Refresh();\r
-#endif\r
-                               }\r
-                       }\r
-                       else if (tool == TOOLPolySelect)\r
-                       {\r
-                               if (pts.GetNumPoints() > 0)\r
-                               {\r
-                                       wxPoint pt2 = GetAdjustedMousePosition(e);\r
-                                       // Should also set onCurve here as well, depending on keystate\r
-//Or should we?\r
-                                       pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x - pts.GetX(ptHighlight), pt2.y - pts.GetY(ptHighlight));\r
-                                       Refresh();\r
-                               }\r
-                       }\r
-//             }\r
-\r
-               ptPrevious = pt;\r
-       }\r
-       else if (e.Moving())\r
-       {\r
-//             else    // Moving, not dragging...\r
-//             {\r
-                       if (tool == TOOLSelect || tool == TOOLDelPt || tool == TOOLAddPt\r
-                               || tool == TOOLPolySelect)// || tool == TOOLAddPoly)\r
-                       {\r
-                               wxPoint pt2 = GetAdjustedMousePosition(e);\r
-                               double closest = 1.0e+99;\r
-\r
-                               for(int i=0; i<pts.GetNumPoints(); i++)\r
-                               {\r
-                                       double dist = ((pt2.x - pts.GetX(i)) * (pt2.x - pts.GetX(i)))\r
-                                               + ((pt2.y - pts.GetY(i)) * (pt2.y - pts.GetY(i)));\r
-\r
-                                       if (dist < closest)\r
-                                               closest = dist, ptHighlight = i;\r
-                               }\r
-\r
-                               if (ptHighlight != oldPtHighlight)\r
-                               {\r
-                                       oldPtHighlight = ptHighlight;\r
-                                       Refresh();\r
-                               }\r
-\r
-                               // What follows here looks like voodoo, but is really simple. What we do is\r
-                               // check to see if the mouse point has a perpendicular intersection with any of\r
-                               // the line segments. If it does, calculate the length of the perpendicular\r
-                               // and choose the smallest length. If there is no perpendicular, then choose the\r
-                               // length of line connecting the closer of either the first endpoint or the\r
-                               // second and choose the smallest of those.\r
-\r
-                               // There is one bit of math that looks like voodoo to me ATM--will explain once\r
-                               // I understand it better (the calculation of the length of the perpendicular).\r
-\r
-                               if (pts.GetNumPoints() > 1 && tool == TOOLAddPt)\r
-                               {\r
-                                       double smallest = 1.0e+99;\r
-\r
-                                       for(int i=0; i<pts.GetNumPoints(); i++)\r
-                                       {\r
-                                               int32 p1x = pts.GetX(i), p1y = pts.GetY(i),\r
-                                                       p2x = pts.GetX(pts.GetNext(i)), p2y = pts.GetY(pts.GetNext(i));\r
-\r
-                                               vector ls(p2x, p2y, 0, p1x, p1y, 0), v1(pt2.x, pt2.y, 0, p1x, p1y, 0),\r
-                                                       v2(pt2.x, pt2.y, 0, p2x, p2y, 0);\r
-                                               double pp = ls.dot(v1) / ls.length(), dist;\r
-// Geometric interpretation:\r
-// pp is the paremeterized point on the vector ls where the perpendicular intersects ls.\r
-// If pp < 0, then the perpendicular lies beyond the 1st endpoint. If pp > length of ls,\r
-// then the perpendicular lies beyond the 2nd endpoint.\r
-\r
-                                               if (pp < 0.0)\r
-                                                       dist = v1.length();\r
-                                               else if (pp > ls.length())\r
-                                                       dist = v2.length();\r
-                                               else                                    // distance = ?Det?(ls, v1) / |ls|\r
-                                                       dist = fabs((ls.x * v1.y - v1.x * ls.y) / ls.length());\r
-\r
-//The answer to the above looks like it might be found here:\r
-//\r
-//If the segment endpoints are s and e, and the point is p, then the test for the perpendicular\r
-//intercepting the segment is equivalent to insisting that the two dot products {s-e}.{s-p} and\r
-//{e-s}.{e-p} are both non-negative.  Perpendicular distance from the point to the segment is\r
-//computed by first computing the area of the triangle the three points form, then dividing by the\r
-//length of the segment.  Distances are done just by the Pythagorean theorem.  Twice the area of the\r
-//triangle formed by three points is the determinant of the following matrix:\r
-//\r
-//sx sy 1\r
-//ex ey 1\r
-//px py 1\r
-//\r
-//(???) By translating the start point to the origin, this can be rewritten as:\r
-//By subtracting row 1 from all rows, you get the following:\r
-//\r
-//0         0         0\r
-//(ex - sx) (ey - sy) 0\r
-//(px - sx) (py - sy) 0\r
-//\r
-//which greatly simplifies the calculation of the determinant.\r
-\r
-                                               if (dist < smallest)\r
-                                                       smallest = dist, ptNextHighlight = pts.GetNext(i), ptHighlight = i;\r
-                                       }\r
-\r
-                                       if (ptNextHighlight != oldPtNextHighlight)\r
-                                       {\r
-                                               oldPtNextHighlight = ptNextHighlight;\r
-                                               Refresh();\r
-                                       }\r
-                               }\r
-                       }\r
-//             }\r
-\r
-               ptPrevious = e.GetPosition();\r
-       }\r
-}\r
-\r
-wxPoint TTEditWindow::GetAdjustedMousePosition(wxMouseEvent &e)\r
-{\r
-       wxCoord width, height;\r
-       wxClientDC dc(this);\r
-\r
-       dc.GetSize(&width, &height);\r
-       dc.SetDeviceOrigin(-offsetX, height - (-offsetY));\r
-       dc.SetAxisOrientation(true, true);\r
-\r
-#if 0\r
-wxStatusBar * sb = ((wxFrame *)GetParent())->GetStatusBar();\r
-wxString s;\r
-s.Printf("Logical mouse pos: %d, %d (%d, %d)", pt.x, pt.y, width, height);\r
-sb->SetStatusText(s);\r
-#endif\r
-\r
-       return e.GetLogicalPosition(dc);\r
-}\r
-\r
-wxPoint TTEditWindow::GetAdjustedClientPosition(wxCoord x, wxCoord y)\r
-{\r
-       wxCoord width, height;\r
-       wxClientDC dc(this);\r
-\r
-       dc.GetSize(&width, &height);\r
-       dc.SetDeviceOrigin(-offsetX, height - (-offsetY));\r
-       dc.SetAxisOrientation(true, true);\r
-\r
-       return wxPoint(dc.LogicalToDeviceX(x), dc.LogicalToDeviceY(y));\r
-}\r
-\r
-//\r
-// Draw a round dot (5x5, centered on [x, y])\r
-//\r
-void TTEditWindow::DrawRoundDot(wxDC &dc, int32 x, int32 y)\r
-{\r
-       wxPoint pt[8];\r
-\r
-       pt[0].x = x - 1, pt[0].y = y - 2;\r
-       pt[1].x = x + 1, pt[1].y = y - 2;\r
-       pt[2].x = x + 2, pt[2].y = y - 1;\r
-       pt[3].x = x + 2, pt[3].y = y + 1;\r
-       pt[4].x = x + 1, pt[4].y = y + 2;\r
-       pt[5].x = x - 1, pt[5].y = y + 2;\r
-       pt[6].x = x - 2, pt[6].y = y + 1;\r
-       pt[7].x = x - 2, pt[7].y = y - 1;\r
-\r
-       dc.DrawPolygon(8, pt);\r
-}\r
-\r
-//\r
-// Draw a sqaure dot (5x5, centered on [x, y])\r
-//\r
-void TTEditWindow::DrawSquareDot(wxDC &dc, int32 x, int32 y)\r
-{\r
-       wxPoint pt[4];\r
-\r
-       pt[0].x = x - 2, pt[0].y = y - 2;\r
-       pt[1].x = x + 2, pt[1].y = y - 2;\r
-       pt[2].x = x + 2, pt[2].y = y + 2;\r
-       pt[3].x = x - 2, pt[3].y = y + 2;\r
-\r
-       dc.DrawPolygon(4, pt);\r
-}\r
-\r
-//\r
-// Draw a sqaure dot (nxn, centered on [x, y])\r
-//\r
-void TTEditWindow::DrawSquareDotN(wxDC &dc, int32 x, int32 y, uint32 n)\r
-{\r
-       wxPoint pt[4];\r
-       uint32 offset = (n - 1) / 2;\r
-\r
-       pt[0].x = x - offset, pt[0].y = y - offset;\r
-       pt[1].x = x + offset, pt[1].y = y - offset;\r
-       pt[2].x = x + offset, pt[2].y = y + offset;\r
-       pt[3].x = x - offset, pt[3].y = y + offset;\r
-\r
-       dc.DrawPolygon(4, pt);\r
-}\r
-\r
-//\r
-// Draw a round dot (nxn, centered on [x, y])\r
-//\r
-void TTEditWindow::DrawRoundDotN(wxDC &dc, int32 x, int32 y, uint32 n)\r
-{\r
-       dc.DrawCircle(x, y, (n / 2) + 1);\r
-}\r
-\r
-\r
-#if 0\r
-\r
-!!! OLD STUFF !!!\r
-\r
-\r
-LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)\r
-{\r
-       RECT rc1, rc2;\r
-       HDC hdc;\r
-       POINT pt, ptOffset;\r
-       SIZE sz;\r
-       PAINTSTRUCT ps;\r
-\r
-       switch (msgID)\r
-       {\r
-       case WM_CREATE:\r
-\r
-               MiscCenterWnd(hWnd, GetDesktopWindow());\r
-               InitCommonControls();\r
-               hStatusBar = CreateStatusWindow(WS_CHILD | WS_VISIBLE, statusBarTxt, hWnd, ID_STATUSBAR);\r
-\r
-               if (!hStatusBar)\r
-                       return -1;\r
-\r
-// clean this crap up!\r
-// well, the only crappy thing here is using a POINT as an int array, but otherwise, this is OK\r
-               wsprintf(strBuf, zoom, 1000);\r
-               hdc = GetDC(hWnd);\r
-               GetTextExtentPoint32(hdc, strBuf, lstrlen(strBuf), &sz);\r
-               ReleaseDC(hWnd, hdc);\r
-               zoomWndWidth = sz.cx;\r
-               wsprintf(strBuf, zoom, 100);\r
-\r
-               GetClientRect(hWnd, &rc1);\r
-               pt.x = rc1.right - zoomWndWidth, pt.y = -1;\r
-               SendMessage(hStatusBar, SB_SETPARTS, 2, (LPARAM)&pt);\r
-               SendMessage(hStatusBar, SB_SETTEXT, (0 | SBT_NOBORDERS), (LPARAM)statusBarTxt);\r
-               SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM)strBuf);\r
-\r
-               hToolBar = CreateToolbarEx(hWnd, WS_CHILD | WS_BORDER | WS_VISIBLE | TBSTYLE_TOOLTIPS,\r
-                       IDR_TOOLBAR1, 3, hInst, IDB_TOOLBAR1, tbButtons, 4, 16, 16, 16, 16, sizeof(TBBUTTON));\r
-\r
-               if (!hToolBar)\r
-                       return -1;\r
-\r
-               CreateNewDoc();\r
-\r
-// The following can only be done because we use a private DC (using "CS_OWNDC")\r
-// (Is that true???)\r
-// Set the mapping to draw the character so it fits in the viewport...\r
-               hdc = GetDC(hWnd);\r
-               GetClientRect(hWnd, &rc1);\r
-               GetClientRect(hStatusBar, &rc2);\r
-               rc1.bottom -= rc2.bottom;\r
-               SetMapMode(hdc, MM_ISOTROPIC);\r
-               SetWindowExtEx(hdc, rc1.right, rc1.bottom, NULL);\r
-               SetViewportExtEx(hdc, rc1.right, -rc1.bottom, NULL);\r
-               SetViewportOrgEx(hdc, 0, rc1.bottom, NULL);\r
-               ReleaseDC(hWnd, hdc);\r
-               break;\r
-\r
-       case WM_CLOSE:\r
-\r
-               if (SaveChanges())\r
-               {\r
-                       wpM.length = wpC.length = sizeof(WINDOWPLACEMENT);\r
-                       GetWindowPlacement(hMainWnd, &wpM);\r
-                       GetWindowPlacement(hCharWnd, &wpC);\r
-\r
-                       if (!IsWindowVisible(hCharWnd))         // Needed because Windows lies about visibility\r
-                               wpC.showCmd = SW_HIDE;\r
-\r
-                       hdc = GetDC(hWnd);\r
-                       GetViewportOrgEx(hdc, &ptVPM);\r
-                       ReleaseDC(hWnd, hdc);\r
-\r
-                       DestroyWindow(hWnd);\r
-               }\r
-\r
-               break;\r
-\r
-       case WM_DESTROY:\r
-\r
-               PostQuitMessage(0);\r
-               break;\r
-\r
-       case WM_NCLBUTTONDOWN:\r
-\r
-               if (wParam == HTCAPTION)\r
-               {\r
-                       NCMouseDown = true;\r
-                       GetWindowRect(hMainWnd, &rc1);\r
-                       GetWindowRect(hCharWnd, &rc2);\r
-                       ptWinOffset.x = rc2.left - rc1.left;\r
-                       ptWinOffset.y = rc2.top - rc1.top;\r
-               }\r
-                   \r
-               // Let Windows do its thing with this msg, or weird things will happen...\r
-\r
-               DefWindowProc(hWnd, msgID, wParam, lParam);\r
-               NCMouseDown = false;\r
-               break;\r
-\r
-       case WM_WINDOWPOSCHANGING:\r
-\r
-               if (NCMouseDown)\r
-               {\r
-                       WINDOWPOS * wp = (WINDOWPOS *)lParam;\r
-\r
-                       if (wp->hwnd == hMainWnd && !(wp->flags & SWP_NOMOVE))\r
-                               SetWindowPos(hCharWnd, 0, wp->x + ptWinOffset.x, wp->y + ptWinOffset.y,\r
-                                               0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);\r
-               }\r
-\r
-               return DefWindowProc(hWnd, msgID, wParam, lParam);      // Seems this is needed... Bleah!\r
-\r
-       case WM_PAINT:\r
-       {\r
-               hdc = BeginPaint(hWnd, &ps);\r
-\r
-// Scrolling can be done by using OffsetViewportOrgEx\r
-// Scaling can be done by adjusting SetWindowExtEx (it's denominator of txform)\r
-// you'd use: % = ViewportExt / WindowExt\r
-// But it makes the window look like crap: fuggetuboutit.\r
-// Instead, we have to scale EVERYTHING by hand. Crap!\r
-\r
-               // Apparently, you *must* save the individual object types (pen, brush, etc.)\r
-\r
-               HGDIOBJ oldPen = SelectObject(hdc, hBluePen1),\r
-                       oldBrush = SelectObject(hdc, hNullBrush);\r
-\r
-           // Draw coordinate axes\r
-\r
-               MoveToEx(hdc, 0, -32000, NULL);\r
-               LineTo(hdc, 0, 32000);\r
-               MoveToEx(hdc, -32000, 0, NULL);\r
-               LineTo(hdc, 32000, 0);\r
-\r
-           // Draw points\r
-\r
-               for(int i=0; i<pts.GetNumPoints(); i++)\r
-               {\r
-                       if (i == ptHighlight)\r
-                       {\r
-                               SelectObject(hdc, hRedPen1);\r
-\r
-                               if (pts.GetOnCurve(i))\r
-                               {\r
-                                       DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 7);\r
-                                       DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 9);\r
-                               }\r
-                               else\r
-                               {\r
-                                       DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 7);\r
-                                       DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 9);\r
-                               }\r
-                       }\r
-                       else if ((i == ptHighlight || i == ptNextHighlight) && currentTool == TOOLAddPt)\r
-                       {\r
-                               SelectObject(hdc, hGreenPen1);\r
-\r
-                               if (pts.GetOnCurve(i))\r
-                               {\r
-                                       DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 7);\r
-                                       DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 9);\r
-                               }\r
-                               else\r
-                               {\r
-                                       DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 7);\r
-                                       DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 9);\r
-                               }\r
-                       }\r
-                       else\r
-                       {\r
-                               SelectObject(hdc, hBlackPen1);\r
-\r
-                               if (pts.GetOnCurve(i))\r
-                                       DrawSquareDot(hdc, pts.GetX(i), pts.GetY(i));\r
-                               else\r
-                                       DrawRoundDot(hdc, pts.GetX(i), pts.GetY(i));\r
-                       }\r
-\r
-                       if (currentTool == TOOLDelPt && i == ptHighlight)\r
-                       {\r
-                               SelectObject(hdc, hRedPen1);\r
-                               MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5, NULL);\r
-                               LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) + 5);\r
-                               LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5);//Lameness!\r
-                               MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5, NULL);\r
-                               LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) - 5);\r
-                               LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5);//More lameness!!\r
-                       }\r
-               }\r
-\r
-               SelectObject(hdc, hBlackPen1);\r
-\r
-               // Draw curve formed by points\r
-\r
-               for(int poly=0; poly<pts.GetNumPolys(); poly++)\r
-               {\r
-                       if (pts.GetNumPoints(poly) > 2)\r
-                       {\r
-                               // Initial move...\r
-                               // If it's not on curve, then move to it, otherwise move to last point...\r
-       \r
-                               if (pts.GetOnCurve(poly, pts.GetNumPoints(poly) - 1))\r
-                                       MoveToEx(hdc, pts.GetX(poly, pts.GetNumPoints(poly) - 1), pts.GetY(poly, pts.GetNumPoints(poly) - 1), NULL);\r
-                               else\r
-                                       MoveToEx(hdc, pts.GetX(poly, 0), pts.GetY(poly, 0), NULL);\r
-       \r
-                               for(int i=0; i<pts.GetNumPoints(poly); i++)\r
-                               {\r
-                                       if (pts.GetOnCurve(poly, i))\r
-                                               LineTo(hdc, pts.GetX(poly, i), pts.GetY(poly, i));\r
-                                       else\r
-                                       {\r
-                                               uint32 prev = pts.GetPrev(poly, i), next = pts.GetNext(poly, i);\r
-                                               float px = pts.GetX(poly, prev), py = pts.GetY(poly, prev),\r
-                                                       nx = pts.GetX(poly, next), ny = pts.GetY(poly, next);\r
-       \r
-                                               if (!pts.GetOnCurve(poly, prev))\r
-                                                       px = (px + pts.GetX(poly, i)) / 2.0f,\r
-                                                       py = (py + pts.GetY(poly, i)) / 2.0f;\r
-       \r
-                                               if (!pts.GetOnCurve(poly, next))\r
-                                                       nx = (nx + pts.GetX(poly, i)) / 2.0f,\r
-                                                       ny = (ny + pts.GetY(poly, i)) / 2.0f;\r
-       \r
-                                               Bezier(hdc, point(px, py), point(pts.GetX(poly, i), pts.GetY(poly, i)), point(nx, ny));\r
-       \r
-                                               if (pts.GetOnCurve(poly, next))\r
-                                                       i++;                                    // Following point is on curve, so move past it\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-\r
-               SelectObject(hdc, oldPen);                              // Restore the stuff we disrupted...\r
-               SelectObject(hdc, oldBrush);\r
-               EndPaint(hWnd, &ps);\r
-               break;\r
-       }\r
-       case WM_SIZE:\r
-\r
-               // Apparently this is needed since these windows don't update themselves.\r
-               SendMessage(hStatusBar, msgID, wParam, lParam);\r
-               SendMessage(hToolBar, msgID, wParam, lParam);\r
-\r
-               // This is needed to make the 2nd status pane visible\r
-               GetClientRect(hWnd, &rc1);\r
-               pt.x = rc1.right - zoomWndWidth, pt.y = -1;\r
-               SendMessage(hStatusBar, SB_SETPARTS, 2, (LPARAM)&pt);\r
-               break;\r
-\r
-       case WM_RBUTTONDOWN:\r
-\r
-               GetCursorPos(&pt);\r
-               SetWindowPos(hToolPalWnd, 0, pt.x, pt.y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);\r
-               SetFocus(hToolPalWnd);\r
-               SetCapture(hToolPalWnd);                                // Ensure tool palette gets RButtonUp\r
-               SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)));        // Tool pallete has "regular" cursor\r
-               break;\r
-\r
-       case WM_LBUTTONDOWN:\r
-\r
-               mouseDown = true;\r
-\r
-               if (currentTool == TOOLScroll || currentTool == TOOLZoom)\r
-                       SetCapture(hWnd);                                       // Make sure we capture the mouse when in scroll/zoom mode\r
-               else if (currentTool == TOOLAddPt)              // "Add Point" tool\r
-               {\r
-                       if (pts.GetNumPoints() > 0)\r
-                       {\r
-//Do we really need to put a cap on this???\r
-//Maybe...\r
-//                             if (pts.GetNumPoints() < 16)\r
-//                             {\r
-                               pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;\r
-                               hdc = GetDC(hWnd);\r
-                               DPtoLP(hdc, &pt, 1);\r
-                               pts.InsertPoint(pts.GetNext(ptHighlight), pt.x, pt.y, (wParam & (MK_SHIFT | MK_CONTROL) ? false : true));\r
-                               ptHighlight = ptNextHighlight;\r
-                               ReleaseDC(hWnd, hdc);\r
-                               InvalidateRect(hWnd, NULL, TRUE);\r
-//                             }\r
-                       }\r
-               }\r
-               else if (currentTool == TOOLAddPoly)    // "Add Poly" tool\r
-               {\r
-#ifdef DEBUGFOO\r
-wsprintf(strBuf, "Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts.GetNumPoints());\r
-WriteLogMsg(strBuf);\r
-#endif\r
-                       if (polyFirstPoint)\r
-                       {\r
-                               polyFirstPoint = false;\r
-                               pts.AddNewPolyAtEnd();\r
-                       }\r
-\r
-//Do we really need to put a cap on this???\r
-//Maybe...\r
-//                     if (pts.GetNumPoints() < 16)\r
-//                     {\r
-                       pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;\r
-                       hdc = GetDC(hWnd);\r
-                       DPtoLP(hdc, &pt, 1);\r
-                       ReleaseDC(hWnd, hdc);\r
-                       // Append a point to the end of the structure\r
-                       pts += IPoint(pt.x, pt.y, (wParam & (MK_SHIFT | MK_CONTROL) ? false : true));\r
-ptHighlight = pts.GetNumPoints() - 1;\r
-                       InvalidateRect(hWnd, NULL, TRUE);\r
-//                     }\r
-#ifdef DEBUGFOO\r
-wsprintf(strBuf, " --> [# polys: %u, # points: %u]\xD\xA", pts.GetNumPolys(), pts.GetNumPoints());\r
-WriteLogMsg(strBuf);\r
-#endif\r
-               }\r
-               else if (currentTool == TOOLSelect || currentTool == TOOLPolySelect)\r
-               {\r
-                       if (pts.GetNumPoints() > 0)\r
-                       {\r
-                               pt.x = pts.GetX(ptHighlight), pt.y = pts.GetY(ptHighlight);\r
-                               hdc = GetDC(hWnd);\r
-                               LPtoDP(hdc, &pt, 1);\r
-                               ClientToScreen(hWnd, &pt);\r
-                               SetCursorPos(pt.x, pt.y);\r
-                               ReleaseDC(hWnd, hdc);\r
-\r
-                               if (wParam & (MK_SHIFT | MK_CONTROL))\r
-                                       pts.SetOnCurve(ptHighlight, !pts.GetOnCurve(ptHighlight));\r
-                       }\r
-               }\r
-               else if (currentTool == TOOLDelPt)\r
-               {\r
-                       if (pts.GetNumPoints() > 0)\r
-//Or could use:\r
-//                     if (ptHighlight != -1)\r
-                       {\r
-//This assumes that WM_MOUSEMOVE happens before this!\r
-//The above commented out line should take care of this contingency... !!! FIX !!!\r
-                               pts.DeletePoint(ptHighlight);\r
-                               InvalidateRect(hWnd, NULL, TRUE);\r
-                       }\r
-               }\r
-\r
-               break;\r
-\r
-       case WM_LBUTTONUP:\r
-\r
-               mouseDown = false;\r
-\r
-               if (currentTool == TOOLScroll || currentTool == TOOLZoom)\r
-                       ReleaseCapture();\r
-\r
-               break;\r
-\r
-       case WM_MOUSEMOVE:\r
-\r
-               SetCursor(hCur[currentTool]);\r
-\r
-           // Extract current point from lParam/calc offset from previous point\r
-\r
-               pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;\r
-               ptOffset.x = pt.x - ptPrevious.x,\r
-               ptOffset.y = pt.y - ptPrevious.y;\r
-\r
-               if (mouseDown)\r
-               {\r
-                       if (currentTool == TOOLScroll)\r
-                       {\r
-                               // NOTE: OffsetViewportOrg operates in DEVICE UNITS...\r
-\r
-                               hdc = GetDC(hWnd);\r
-                               OffsetViewportOrgEx(hdc, ptOffset.x, ptOffset.y, NULL);\r
-                               ReleaseDC(hWnd, hdc);\r
-\r
-// this shows that it works, so the logic above must be faulty...\r
-// And it is. It should convert the coords first, then do the subtraction to figure the offset...\r
-// Above: DONE\r
-// Then multiply it by the scaling factor. Whee!\r
-\r
-                               InvalidateRect(hWnd, NULL, TRUE);\r
-//                             SendMessage(hWnd, WM_PAINT, NULL, NULL);\r
-                       }\r
-                       else if (currentTool == TOOLAddPt || currentTool == TOOLAddPoly || currentTool == TOOLSelect)\r
-                       {\r
-                               if (currentTool != TOOLAddPt || pts.GetNumPoints() > 0)//yecch.\r
-                               {\r
-                                       POINT pt2;\r
-                                       pt2.x = pt.x, pt2.y = pt.y;\r
-                                       // Should also set onCurve here as well, depending on keystate\r
-//Or should we?\r
-                                       hdc = GetDC(hWnd);\r
-                                       DPtoLP(hdc, &pt2, 1);\r
-                                       pts.SetXY(ptHighlight, pt2.x, pt2.y);\r
-                                       ReleaseDC(hWnd, hdc);\r
-                                       InvalidateRect(hWnd, NULL, TRUE);\r
-                               }\r
-                       }\r
-                       else if (currentTool == TOOLPolySelect)\r
-                       {\r
-                               if (pts.GetNumPoints() > 0)\r
-                               {\r
-                                       POINT pt2;\r
-                                       pt2.x = pt.x, pt2.y = pt.y;\r
-                                       // Should also set onCurve here as well, depending on keystate\r
-//Or should we?\r
-                                       hdc = GetDC(hWnd);\r
-                                       DPtoLP(hdc, &pt2, 1);\r
-                                       pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x - pts.GetX(ptHighlight), pt2.y - pts.GetY(ptHighlight));\r
-                                       ReleaseDC(hWnd, hdc);\r
-                                       InvalidateRect(hWnd, NULL, TRUE);\r
-                               }\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       if (currentTool == TOOLSelect || currentTool == TOOLDelPt || currentTool == TOOLAddPt\r
-                               || currentTool == TOOLPolySelect)// || currentTool == TOOLAddPoly)\r
-                       {\r
-                               POINT pt2;\r
-                               pt2.x = pt.x, pt2.y = pt.y;\r
-                               hdc = GetDC(hWnd);\r
-                               DPtoLP(hdc, &pt2, 1);\r
-                               ReleaseDC(hWnd, hdc);\r
-\r
-                               double closest = 1.0e+99;\r
-\r
-                               for(int i=0; i<pts.GetNumPoints(); i++)\r
-                               {\r
-                                       double dist = ((pt2.x - pts.GetX(i)) * (pt2.x - pts.GetX(i)))\r
-                                               + ((pt2.y - pts.GetY(i)) * (pt2.y - pts.GetY(i)));\r
-\r
-                                       if (dist < closest)\r
-                                               closest = dist, ptHighlight = i;\r
-                               }\r
-\r
-                               if (ptHighlight != oldPtHighlight)\r
-                               {\r
-                                       oldPtHighlight = ptHighlight;\r
-                                       InvalidateRect(hWnd, NULL, TRUE);\r
-                               }\r
-\r
-                               // What follows here looks like voodoo, but is really simple. What we do is\r
-                               // check to see if the mouse point has a perpendicular intersection with any of\r
-                               // the line segments. If it does, calculate the length of the perpendicular\r
-                               // and choose the smallest length. If there is no perpendicular, then choose the\r
-                               // length of line connecting the closer of either the first endpoint or the\r
-                               // second and choose the smallest of those.\r
-\r
-                               // There is one bit of math that looks like voodoo to me ATM--will explain once\r
-                               // I understand it better (the calculation of the length of the perpendicular).\r
-\r
-                               if (pts.GetNumPoints() > 1 && currentTool == TOOLAddPt)\r
-                               {\r
-                                       double smallest = 1.0e+99;\r
-\r
-                                       for(int i=0; i<pts.GetNumPoints(); i++)\r
-                                       {\r
-                                               int32 p1x = pts.GetX(i), p1y = pts.GetY(i),\r
-                                                       p2x = pts.GetX(pts.GetNext(i)), p2y = pts.GetY(pts.GetNext(i));\r
-\r
-                                               vector ls(p2x, p2y, 0, p1x, p1y, 0), v1(pt2.x, pt2.y, 0, p1x, p1y, 0),\r
-                                                       v2(pt2.x, pt2.y, 0, p2x, p2y, 0);\r
-                                               double pp = ls.dot(v1) / ls.length(), dist;\r
-// Geometric interpretation:\r
-// pp is the paremeterized point on the vector ls where the perpendicular intersects ls.\r
-// If pp < 0, then the perpendicular lies beyond the 1st endpoint. If pp > length of ls,\r
-// then the perpendicular lies beyond the 2nd endpoint.\r
-\r
-                                               if (pp < 0.0)\r
-                                                       dist = v1.length();\r
-                                               else if (pp > ls.length())\r
-                                                       dist = v2.length();\r
-                                               else                                    // distance = ?Det?(ls, v1) / |ls|\r
-                                                       dist = abs((ls.x * v1.y - v1.x * ls.y) / ls.length());\r
-\r
-//The answer to the above looks like it might be found here:\r
-//\r
-//If the segment endpoints are s and e, and the point is p, then the test for the perpendicular\r
-//intercepting the segment is equivalent to insisting that the two dot products {s-e}.{s-p} and\r
-//{e-s}.{e-p} are both non-negative.  Perpendicular distance from the point to the segment is\r
-//computed by first computing the area of the triangle the three points form, then dividing by the\r
-//length of the segment.  Distances are done just by the Pythagorean theorem.  Twice the area of the\r
-//triangle formed by three points is the determinant of the following matrix:\r
-//\r
-//sx sy 1\r
-//ex ey 1\r
-//px py 1\r
-//\r
-//(???) By translating the start point to the origin, this can be rewritten as:\r
-//By subtracting row 1 from all rows, you get the following:\r
-//\r
-//0         0         0\r
-//(ex - sx) (ey - sy) 0\r
-//(px - sx) (py - sy) 0\r
-//\r
-//which greatly simplifies the calculation of the determinant.\r
-\r
-                                               if (dist < smallest)\r
-                                                       smallest = dist, ptNextHighlight = pts.GetNext(i), ptHighlight = i;\r
-                                       }\r
-\r
-                                       if (ptNextHighlight != oldPtNextHighlight)\r
-                                       {\r
-                                               oldPtNextHighlight = ptNextHighlight;\r
-                                               InvalidateRect(hWnd, NULL, TRUE);\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-\r
-               ptPrevious.x = pt.x, ptPrevious.y = pt.y;\r
-\r
-               break;\r
-\r
-       case WM_NOTIFY:\r
-\r
-               if (((NMHDR *)lParam)->code == TTN_NEEDTEXT)\r
-               {\r
-                       LoadString(hInst, ((TOOLTIPTEXT *)lParam)->hdr.idFrom + 0x80, toolTipTxt, 16);\r
-                       ((TOOLTIPTEXT *)lParam)->lpszText = toolTipTxt;\r
-               }\r
-\r
-               break;\r
-\r
-       case WM_MENUSELECT:\r
-       {\r
-               statusBarTxt[0] = 0;                                    // Clear status bar text\r
-               uint16 flags = wParam >> 16;                    // Extract flags\r
-\r
-               if (!(flags & MFT_SEPARATOR))\r
-               {\r
-                       uint16 id = wParam & 0xFFFF;\r
-\r
-                       if (flags & MF_POPUP)\r
-                       {\r
-                               if (flags & MF_SYSMENU)\r
-                                       id = IDS_SYSMENU;\r
-                               else\r
-                                       id = IDM_FILEMENU + wParam;\r
-                       }\r
-\r
-                       LoadString(hInst, id, statusBarTxt, 64);\r
-               }\r
-\r
-               SendMessage(hStatusBar, SB_SETTEXT, 0 + SBT_NOBORDERS, (LPARAM)statusBarTxt);\r
-               break;\r
-       }\r
-       case WM_COMMAND:\r
-       {\r
-               uint16 cmd = wParam & 0xFFFF;\r
-\r
-               if (cmd == IDM_NEW)\r
-               {\r
-//                   call   CmdIDM_NEW\r
-               }\r
-               else if (cmd == IDM_OPEN)\r
-               {\r
-//                   call   SaveChanges\r
-//                   .IF (eax)\r
-//                     movmov ofn.hwndOwner, eax, hMainWnd\r
-//                     mov    ofn.Flags, OFN_PATHMUSTEXIST + OFN_FILEMUSTEXIST\r
-//                     invoke GetOpenFileName, ADDR ofn\r
-//                     .IF (eax)\r
-////////\r
-//jmp @F\r
-//szDMsg1a     BYTE    "Could not open the file (GetOpenFileName)...", 0\r
-//szDMsg1b     BYTE    "Open error!", 0\r
-//szDMsg1c     BYTE    "About to attempt to open file...", 0\r
-//@@:\r
-////invoke MessageBox, hWnd, ADDR szDMsg1a, ADDR szDMsg1b, MB_ICONERROR or MB_OK\r
-//invoke MessageBox, hMainWnd, ADDR szDMsg1c, ADDR szFile, MB_ICONERROR or MB_OK\r
-//                       invoke LoadTTF, ADDR szFile\r
-//\r
-//////\r
-//                       // <<< FILE OPEN CODE HERE >>>\r
-//                       or     fFileStatus, NAMEDbit\r
-//                       and    fFileStatus, NOT CHANGEDbit\r
-//                       call   NewWindowName\r
-//                       mov    eax, TRUE      // return TRUE\r
-//                       jmp    Return\r
-//                       //��������������������������������������\r
-//OpenError:             invoke GetLastError\r
-//                       // <<< FILE OPEN ERROR CODE HERE >>>\r
-//                     .ENDIF\r
-//                     zero   eax      // return FALSE\r
-//                   .ENDIF\r
-               }\r
-               else if (cmd == IDM_SAVEAS)\r
-               {\r
-//                   and    fFileStatus, NOT NAMEDbit\r
-//                   call   CmdIDM_SAVE\r
-               }\r
-               else if (cmd == IDM_SAVE)\r
-               {\r
-//                   call   CmdIDM_SAVE\r
-               }\r
-               else if (cmd == IDM_ABOUT)\r
-                       DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_ABOUT), hMainWnd, AboutProc, NULL);\r
-               else if (cmd == IDM_EXIT)\r
-                       SendMessage(hWnd, WM_CLOSE, 0, 0);\r
-               else if (cmd == ID_TBCHARWIN)\r
-               {\r
-                       ShowWindow(hCharWnd, (IsWindowVisible(hCharWnd) ? SW_HIDE : SW_SHOWNOACTIVATE));\r
-\r
-#ifdef DEBUGFOO\r
-wpC.length = sizeof(WINDOWPLACEMENT);\r
-GetWindowPlacement(hCharWnd, &wpC);\r
-wsprintf(strBuf, "Char window showCmd = %08X...\n", wpC.showCmd);\r
-WriteLogMsg(strBuf);\r
-#endif\r
-               }\r
-               else\r
-                       return DefWindowProc(hWnd, msgID, wParam, lParam);\r
-\r
-               break;\r
-       }\r
-       default:\r
-               return DefWindowProc(hWnd, msgID, wParam, lParam);\r
-       }\r
-\r
-       return 0;\r
-}\r
-\r
-//\r
-// Initialize TTF data\r
-//\r
-void CreateNewDoc(void)\r
-{\r
-}\r
-\r
-//\r
-// Save changes to document before quitting\r
-//\r
-bool SaveChanges(void)\r
-{\r
-       return true;\r
-}\r
-\r
-\r
-\r
-//\r
-// ABOUT Dialog WndProc\r
-//\r
-BOOL CALLBACK AboutProc(HWND hDlg, UINT msgID, WPARAM wParam, LPARAM lParam)\r
-{\r
-       switch (msgID)\r
-       {\r
-       case WM_INITDIALOG:\r
-\r
-               MiscCenterWnd(hDlg, hMainWnd);\r
-               break;\r
-\r
-       case WM_COMMAND:\r
-\r
-               if (wParam == IDOK || wParam == IDCANCEL)\r
-                       EndDialog(hDlg, TRUE);\r
-\r
-               break;\r
-\r
-       default:\r
-               return FALSE;\r
-       }\r
-\r
-       return TRUE;\r
-}\r
-\r
-//\r
-// Character Window WndProc\r
-//\r
-WndProcCW      PROC  STDCALL, hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM\r
-\r
-               mov    eax, uMsg                // pickup our message\r
-               .IF (eax == WM_PAINT)\r
-                 mov    eax, 0                 // Non-sense... (placeholder!)\r
-// Scan conversion etc. goes here...\r
-               .ELSEIF (eax == WM_LBUTTONDOWN)\r
-                 invoke SetCapture, hCharWnd\r
-               .ELSEIF (eax == WM_LBUTTONUP)\r
-                 invoke ReleaseCapture\r
-                 invoke SetFocus, hMainWnd     // Make sure the main wnd keeps focus!\r
-               .ELSEIF (eax == WM_NCLBUTTONDOWN)\r
-                 invoke DefWindowProc, hWnd, uMsg, wParam, lParam // Let it do its thing\r
-                 invoke SetFocus, hMainWnd     // Make sure the main wnd keeps focus!\r
-               .ELSE\r
-DefProc:         invoke DefWindowProc, hWnd, uMsg, wParam, lParam\r
-               .ENDIF\r
-               ret\r
-\r
-WndProcCW      ENDP\r
-\r
-//\r
-// Character Window WndProc\r
-//\r
-LRESULT CALLBACK WndProcCW(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)\r
-{\r
-       switch (msgID)\r
-       {\r
-       default:\r
-               return DefWindowProc(hWnd, msgID, wParam, lParam);\r
-       }\r
-\r
-       return 0;\r
-}\r
-\r
-\r
-// Function prototypes\r
-\r
-int32 FindSelectedTool(void);\r
-\r
-//\r
-// Tool Palette WndProc\r
-//\r
-LRESULT CALLBACK WndProcTP(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)\r
-{\r
-       PAINTSTRUCT ps;\r
-       HDC hdc;\r
-       POINT pt;\r
-       static uint32 prevTool = -1;\r
-\r
-       switch (msgID)\r
-       {\r
-       case WM_PAINT:\r
-       {\r
-               hdc = BeginPaint(hWnd, &ps);\r
-               HDC newDC = CreateCompatibleDC(NULL);\r
-               SelectObject(newDC, hBMToolPal1);\r
-               BitBlt(hdc, 0, 0, sizeTPBM.x, sizeTPBM.y, newDC, 0, 0, SRCCOPY);\r
-               DeleteDC(newDC);\r
-\r
-// This is crappy. Find some way to tighten this up!\r
-               int32 tool = FindSelectedTool();\r
-\r
-               if (tool != -1)\r
-               {\r
-                       newDC = CreateCompatibleDC(NULL);\r
-                       SelectObject(newDC, hBMToolPal1);\r
-                   //need ul corner of bitmap, ul corner of dest, width/height\r
-                       pt.x = sizeStamp.x * (tool & 0x03), pt.y = sizeStamp.y * (tool >> 2);\r
-                       BitBlt(hdc, pt.x, pt.y, sizeStamp.x, sizeStamp.y, newDC, pt.x, pt.y, NOTSRCCOPY);\r
-                       DeleteDC(newDC);\r
-               }\r
-\r
-               EndPaint(hWnd, &ps);\r
-               break;\r
-       }\r
-       case WM_MOUSEMOVE:\r
-       {\r
-               int32 tool = FindSelectedTool();\r
-\r
-               if (tool != prevTool)\r
-               {\r
-                       prevTool = tool;\r
-                       InvalidateRect(hWnd, NULL, FALSE);\r
-               }\r
-\r
-               break;\r
-       }\r
-       case WM_RBUTTONUP:\r
-       {\r
-               int32 tool = FindSelectedTool(), oldTool = currentTool;\r
-\r
-               if (tool != -1)\r
-                       currentTool = tool;\r
-\r
-               if (currentTool != TOOLSelect && currentTool != TOOLDelPt && currentTool != TOOLAddPt\r
-                       && currentTool != TOOLPolySelect)\r
-                       ptHighlight = -1;\r
-\r
-               if (currentTool != oldTool)\r
-                       InvalidateRect(hMainWnd, NULL, TRUE);\r
-\r
-               if (currentTool == TOOLAddPoly)\r
-#ifdef DEBUGFOO\r
-{\r
-#endif\r
-                       polyFirstPoint = true;\r
-#ifdef DEBUGFOO\r
-wsprintf(strBuf, "--> Selected poly tool, polyFirstPoint is %s\n", polyFirstPoint ? "true" : "false");\r
-WriteLogMsg(strBuf);\r
-}\r
-#endif\r
-\r
-               ReleaseCapture();\r
-               ShowWindow(hToolPalWnd, SW_HIDE);\r
-               SetFocus(hMainWnd);                                             // Make sure the main wnd keeps focus!\r
-\r
-               break;\r
-       }\r
-       default:\r
-               return DefWindowProc(hWnd, msgID, wParam, lParam);\r
-       }\r
-\r
-       return 0;\r
-}\r
-\r
-//\r
-// Find which tool we're pointing at\r
-// Use: xcoord = mouse.x / (bmsize.x/4), ycoord = mouse.y / (bmsize.y/2)\r
-//\r
-int32 FindSelectedTool(void)\r
-{\r
-       POINT pt;\r
-               \r
-       GetCursorPos(&pt);\r
-       ScreenToClient(hToolPalWnd, &pt);\r
-\r
-       uint32 x = (uint32)pt.x / sizeStamp.x, y = (uint32)pt.y / sizeStamp.y, tool = -1;\r
-\r
-       if (x < 4 && y < 2)\r
-//     {\r
-               tool = (y * 4) + x;\r
-\r
-//             if (tool == 7)\r
-//                     tool = -1;                                                      // 7 has no tool...\r
-//     }\r
-\r
-       return tool;\r
-}\r
-\r
-\r
-//\r
-// Misc center window\r
-//\r
-void MiscCenterWnd(HWND hChild, HWND hParent)\r
-{\r
-       RECT parent, child;\r
-\r
-       if (!GetWindowRect(hParent, &parent) || !GetWindowRect(hChild, &child))\r
-               return;\r
-\r
-       int32 x = parent.left + (((parent.right - parent.left) - (child.right - child.left)) / 2),\r
-               y = parent.top + (((parent.bottom - parent.top) - (child.bottom - child.top)) / 2);\r
-\r
-       if (x < 0)\r
-               x = 0;\r
-       else if (x > GetSystemMetrics(SM_CXFULLSCREEN) - (child.right - child.left))\r
-               x = GetSystemMetrics(SM_CXFULLSCREEN) - (child.right - child.left);\r
-\r
-       if (y < 0)\r
-               y = 0;\r
-       else if (y > GetSystemMetrics(SM_CYFULLSCREEN) - (child.bottom - child.top))\r
-               y = GetSystemMetrics(SM_CYFULLSCREEN) - (child.bottom - child.top);\r
-\r
-       SetWindowPos(hChild, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);\r
-}\r
-\r
-//\r
-// Allow only one instance\r
-//\r
-bool OnlyOneInstance(void)\r
-{\r
-       HWND window = FindWindow(className, NULL);\r
-\r
-       if (window == NULL)\r
-               return true;\r
-\r
-       ShowWindow(window, SW_SHOWNORMAL);\r
-       SetWindowPos(window, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);\r
-\r
-       return false;\r
-}\r
-\r
-//\r
-// Load/Allocate all resources\r
-//\r
-bool LoadResources(void)\r
-{\r
-       hCur[0] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR1));\r
-       hCur[1] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR2));\r
-       hCur[2] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR3));\r
-       hCur[3] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR4));\r
-       hCur[4] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR5));\r
-       hCur[5] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR6));\r
-       hCur[6] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR7));\r
-       hCur[7] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR8));\r
-\r
-       BITMAP bm;\r
-\r
-       hBMToolPal1 = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_TOOLPAL1));\r
-       GetObject(hBMToolPal1, sizeof(bm), &bm);\r
-\r
-       // Set up sizes\r
-\r
-       sizeTPBM.x = bm.bmWidth, sizeTPBM.y = bm.bmHeight;\r
-       sizeStamp.x = bm.bmWidth / 4, sizeStamp.y = bm.bmHeight / 2;\r
-\r
-       hBluePen1 = CreatePen(PS_DOT, 1, 0x00FF0000);\r
-       hRedPen1 = CreatePen(PS_SOLID, 1, 0x000000FF);\r
-       hGreenPen1 = CreatePen(PS_SOLID, 1, 0x0000AF00);\r
-       hBlackPen1 = CreatePen(PS_SOLID, 1, 0x00000000);\r
-\r
-       LOGBRUSH lb = { BS_NULL, 0, 0 };\r
-\r
-       hNullBrush = CreateBrushIndirect(&lb);\r
-\r
-       return true;\r
-}\r
-\r
-//\r
-// Deallocate all resources\r
-//\r
-void DeallocateResources(void)\r
-{\r
-       DeleteObject(hBMToolPal1);\r
-       DeleteObject(hBluePen1);\r
-       DeleteObject(hRedPen1);\r
-       DeleteObject(hGreenPen1);\r
-       DeleteObject(hBlackPen1);\r
-       DeleteObject(hNullBrush);\r
-}\r
-\r
-//\r
-// Save all application specific data, so we can pick up where we last left off...\r
-//\r
-void SaveAppState(void)\r
-{\r
-       SetINIInt("Main", "flags", wpM.flags);\r
-       SetINIInt("Main", "showCmd", wpM.showCmd);\r
-       SetINIInt("Main", "x1", wpM.rcNormalPosition.left);\r
-       SetINIInt("Main", "y1", wpM.rcNormalPosition.top);\r
-       SetINIInt("Main", "x2", wpM.rcNormalPosition.right);\r
-       SetINIInt("Main", "y2", wpM.rcNormalPosition.bottom);\r
-\r
-       SetINIInt("Main", "vpx", ptVPM.x);\r
-       SetINIInt("Main", "vpy", ptVPM.y);\r
-\r
-       SetINIInt("Char", "flags", wpC.flags);\r
-       SetINIInt("Char", "showCmd", wpC.showCmd);\r
-       SetINIInt("Char", "x1", wpC.rcNormalPosition.left);\r
-       SetINIInt("Char", "y1", wpC.rcNormalPosition.top);\r
-       SetINIInt("Char", "x2", wpC.rcNormalPosition.right);\r
-       SetINIInt("Char", "y2", wpC.rcNormalPosition.bottom);\r
-\r
-       // Need to write out currently opened font, character looking at, other misc. crap\r
-//     SetINIString("Main", "currentFile", pDoc->GetPathName());\r
-//     SetINIInt("Main", "currentChar", pDoc->character_num);\r
-}\r
-\r
-//\r
-// Restore all application specific data previously saved\r
-//\r
-bool RestoreAppState(void)\r
-{\r
-       InitINIFile();\r
-\r
-       WINDOWPLACEMENT wp;\r
-       wp.length = sizeof(WINDOWPLACEMENT);\r
-       GetWindowPlacement(hMainWnd, &wp);\r
-\r
-       wp.flags = GetINIInt("Main", "flags", wp.flags);\r
-       wp.showCmd = GetINIInt("Main", "showCmd", wp.showCmd);\r
-       wp.rcNormalPosition.left = GetINIInt("Main", "x1", wp.rcNormalPosition.left);\r
-       wp.rcNormalPosition.top = GetINIInt("Main", "y1", wp.rcNormalPosition.top);\r
-       wp.rcNormalPosition.right = GetINIInt("Main", "x2", wp.rcNormalPosition.right);\r
-       wp.rcNormalPosition.bottom = GetINIInt("Main", "y2", wp.rcNormalPosition.bottom);\r
-\r
-       SetWindowPlacement(hMainWnd, &wp);\r
-\r
-       HDC hdc;\r
-       POINT pt;\r
-       hdc = GetDC(hMainWnd);\r
-       GetViewportOrgEx(hdc, &pt);\r
-\r
-       pt.x = GetINIInt("Main", "vpx", pt.x);\r
-       pt.y = GetINIInt("Main", "vpy", pt.y);\r
-\r
-       SetViewportOrgEx(hdc, pt.x, pt.y, NULL);\r
-       ReleaseDC(hMainWnd, hdc);\r
-\r
-       GetWindowPlacement(hCharWnd, &wp);\r
-\r
-       wp.flags = GetINIInt("Char", "flags", wp.flags);\r
-       wp.showCmd = GetINIInt("Char", "showCmd", wp.showCmd);\r
-       wp.rcNormalPosition.left = GetINIInt("Char", "x1", wp.rcNormalPosition.left);\r
-       wp.rcNormalPosition.top = GetINIInt("Char", "y1", wp.rcNormalPosition.top);\r
-       wp.rcNormalPosition.right = GetINIInt("Char", "x2", wp.rcNormalPosition.right);\r
-       wp.rcNormalPosition.bottom = GetINIInt("Char", "y2", wp.rcNormalPosition.bottom);\r
-\r
-       SetWindowPlacement(hCharWnd, &wp);\r
-\r
-       if (wp.showCmd == SW_HIDE)\r
-               SendMessage(hToolBar, TB_SETSTATE, ID_TBCHARWIN, MAKELONG(TBSTATE_ENABLED, 0));\r
-\r
-//  CString lastFile = theApplicationObject.GetProfileString(version, "currentFile", "");\r
-//  int lastChar = theApplicationObject.GetProfileInt(version, "currentChar", 0);\r
-//  if (lastFile.GetLength())\r
-//  {\r
-//    // Attempt to restore the last session by open the last file used, etc...\r
-//    if (!pDoc->m_myFont.Load(lastFile))\r
-//    {\r
-//      // Err, make sure you can support any allegations you make below, buddy!\r
-//      AfxMessageBox("The last file opened with TTF Edit\n\rseems to have been moved or deleted.");\r
-//    }\r
-//    else\r
-//    {\r
-//      pDoc->m_myFont.SetGlyph(lastChar);  // Set TTF object to last used char\r
-//      pDoc->character_num = lastChar;\r
-//      pDoc->SetPathName(lastFile);\r
-//\r
-//      BYTE name[512];\r
-//      pDoc->m_myFont.GetCharName(lastChar, name);\r
-//      m_wndOwned.SetWindowText((char *)name);\r
-//    }\r
-//  }\r
-\r
-       return true;\r
-}\r
-\r
-//\r
-// Initialization\r
-//\r
-bool Initialization(void)\r
-{\r
-       WNDCLASSEX wcex;\r
-\r
-       if (!LoadResources())\r
-               return false;\r
-\r
-       RtlFillMemory(&wcex, sizeof(WNDCLASSEX), 0);\r
-       wcex.cbSize = sizeof(WNDCLASSEX);\r
-       wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;\r
-       wcex.lpfnWndProc = WndProc;\r
-       wcex.hInstance = hInst;\r
-       wcex.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON));\r
-       wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);\r
-       wcex.lpszMenuName = MAKEINTRESOURCE(IDM_MENU);\r
-       wcex.lpszClassName = className;\r
-       wcex.hIconSm = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 16, 16, NULL);\r
-\r
-       if (!RegisterClassEx(&wcex))\r
-               return false;\r
-\r
-       hMainWnd = CreateWindowEx(NULL, className, className, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,\r
-               0, 0, 0x1A0, 0x180, NULL, NULL, hInst, NULL);\r
-\r
-       if (!hMainWnd)\r
-               return false;\r
-\r
-       ShowWindow(hMainWnd, nCmdShow);\r
-       UpdateWindow(hMainWnd);\r
-\r
-       // Character window creation\r
-\r
-       wcex.lpfnWndProc = WndProcCW;\r
-       wcex.lpszMenuName = NULL;\r
-       wcex.lpszClassName = CNCharWin;\r
-       wcex.hCursor = LoadCursor(NULL, IDC_ARROW);     // Owned windows have "regular" cursors\r
-\r
-       if (!RegisterClassEx(&wcex))\r
-               return false;\r
-\r
-       hCharWnd = CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW, CNCharWin,\r
-               curCharName, WS_POPUP | WS_CAPTION | WS_VISIBLE | WS_THICKFRAME,\r
-               100, 100, 120, 120, hMainWnd, NULL, hInst, NULL);\r
-\r
-       if (!hCharWnd)\r
-               return false;\r
-\r
-       ShowWindow(hCharWnd, SW_SHOWNORMAL);\r
-       UpdateWindow(hCharWnd);\r
-       SetFocus(hMainWnd);                                                     // Make sure main wnd has focus!\r
-\r
-       // Tool palette window creation\r
-\r
-       wcex.lpfnWndProc = WndProcTP;\r
-       wcex.lpszClassName = CNToolPal;\r
-\r
-       if (!RegisterClassEx(&wcex))\r
-               return false;\r
-\r
-       hToolPalWnd = CreateWindowEx(WS_EX_WINDOWEDGE, CNToolPal, NULL, WS_POPUP,\r
-               0, 0, sizeTPBM.x, sizeTPBM.y, hMainWnd, NULL, hInst, NULL);\r
-\r
-       if (!hToolPalWnd)\r
-               return false;\r
-\r
-// Note: A better way to handle this would be to have a sub that registers ALL\r
-//       classes beforehand and passes a TRUE/FALSE back depending on whether or not\r
-//       all the classes were able to be registered or not, THEN create the windows\r
-//       and controls...\r
-\r
-       RestoreAppState();                                                      // Restore app related stuff\r
-\r
-       return true;\r
-}\r
-\r
-#endif\r
+//
+// TTEDIT.CPP - The TrueType Editor
+// by James L. Hammons
+// (C) 2004 Underground Software
+//
+// 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
+//
+
+// FIXED:
+//
+// - Fixed scrolling
+//
+// STILL TO BE DONE:
+//
+// - Fix bug in Glyphpoints when dragging on an empty canvas or loading a font
+// - Fix zooming, settings (ini)
+// - Fix point adding bug 1: should be able to add points to empty canvas
+// - Fix point adding bug 2: should be able to add point successfully to single
+//   point on screen
+// - Add poly multi-select
+// - Add point multi-select
+// - Undo system
+//
+
+// Uncomment this for debugging...
+#define DEBUG
+#define DEBUGFOO            // Various tool debugging...
+#define DEBUGTP                                // Toolpalette debugging...
+
+#include "editwindow.h"
+#include "charwindow.h"
+#include "debug.h"
+#include "graphicprimitives.h"
+#include "mainwindow.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), showRotationCenter(false), haveZeroPoint(false)
+{
+       setBackgroundRole(QPalette::Base);
+       setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+
+       toolPalette = new ToolWindow();
+       CreateCursors();
+       setCursor(cur[TOOLSelect]);
+       setMouseTracking(true);
+}
+
+
+QSize EditWindow::minimumSizeHint() const
+{
+       return QSize(50, 50);
+}
+
+
+QSize EditWindow::sizeHint() const
+{
+       return QSize(400, 400);
+}
+
+
+void EditWindow::CreateCursors(void)
+{
+       int hotx[11] = {  1,  1, 11, 15,  1,  1,  1,  1,  1,  1,  1 };
+       int hoty[11] = {  1,  1, 11, 13,  1,  1,  1,  1,  1,  1,  1 };
+       char cursorName[11][48] = { "select", "select-poly", "scroll", "zoom", "add-point",
+               "add-poly", "del-point", "del-poly", "rotate", "rotate", "select" };
+
+       for(int i=0; i<11; i++)
+       {
+               QString s;
+               s.sprintf(":/res/cursor-%s.png", cursorName[i]);
+               QPixmap pmTmp(s);
+               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:
+ o  Different colors for polys on selected points
+ o  Different colors for handles on non-selected polys
+ o  Line of sight (dashed, dotted) for off-curve points
+ o  Repaints for press/release of CTRL/SHIFT during point creation
+*/
+void EditWindow::paintEvent(QPaintEvent * /*event*/)
+{
+       QPainter p(this);
+//hm, causes lockup (or does it???)
+       p.setRenderHint(QPainter::Antialiasing);
+
+       QSize winSize = size();
+
+       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...
+
+       p.setPen(QPen(Qt::blue, 1.0, Qt::DotLine));
+
+       // Draw coordinate axes
+
+       p.drawLine(0, -16384, 0, 16384);
+       p.drawLine(-16384, 0, 16384, 0);
+
+       // Draw rotation center (if active)
+
+       if (showRotationCenter)
+       {
+               p.setPen(QPen(Qt::red, 2.0, Qt::SolidLine));
+               p.drawLine(rotationCenter.x() + 7, rotationCenter.y(), rotationCenter.x() - 7, rotationCenter.y());
+               p.drawLine(rotationCenter.x(), rotationCenter.y() + 7, rotationCenter.x(), rotationCenter.y() - 7);
+       }
+
+       // Draw points
+
+       for(int i=0; i<pts.GetNumPoints(); i++)
+       {
+               if (i == ptHighlight)
+               {
+                       p.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);
+                       }
+                       else
+                       {
+                               DrawRoundDotN(p, pts.GetX(i), pts.GetY(i), 7);
+                               DrawRoundDotN(p, pts.GetX(i), pts.GetY(i), 9);
+                       }
+               }
+               else if ((i == ptHighlight || i == ptNextHighlight) && tool == TOOLAddPt)
+               {
+                       p.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);
+                       }
+                       else
+                       {
+                               DrawRoundDotN(p, pts.GetX(i), pts.GetY(i), 7);
+                               DrawRoundDotN(p, pts.GetX(i), pts.GetY(i), 9);
+                       }
+               }
+               else
+               {
+                       p.setPen(QPen(Qt::black, 1.0, Qt::SolidLine));
+
+                       if (pts.GetOnCurve(i))
+                               DrawSquareDot(p, pts.GetX(i), pts.GetY(i));
+                       else
+                               DrawRoundDot(p, pts.GetX(i), pts.GetY(i));
+               }
+
+               if (tool == TOOLDelPt && i == ptHighlight)
+               {
+                       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);
+               }
+       }
+
+       // Draw curve formed by points
+
+       p.setPen(QPen(Qt::black, 1.0, Qt::SolidLine));
+       DrawGlyph(p, pts);
+
+       if (haveZeroPoint)
+       {
+               // Rotation code
+               GlyphPoints rotated = pts;
+
+               if (tool == TOOLRotate)
+                       rotated.RotatePoints(rotationAngle, IPoint(rotationCenter.x(), rotationCenter.y()));
+               else if (tool == TOOLRotatePoly)
+               {
+                       uint16 poly = rotated.GetPolyForPointNumber(ptHighlight);
+                       rotated.RotatePolyAroundCentroid(poly, rotationAngle);
+               }
+
+               p.setPen(QPen(QColor(255, 0, 255), 1.0, Qt::SolidLine));
+               DrawGlyph(p, rotated);
+       }
+}
+
+
+void EditWindow::DrawGlyph(QPainter & p, GlyphPoints & glyph)
+{
+       for(int poly=0; poly<glyph.GetNumPolys(); poly++)
+       {
+               if (glyph.GetNumPoints(poly) < 3)
+                       continue;
+
+               // 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)));
+
+// Need to add separate color handling here for polys that are being manipulated...
+
+               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;
+                       }
+               }
+       }
+}
+
+
+void EditWindow::DrawGlyphPoly(QPainter & p, GlyphPoints & glyph, uint16 poly)
+{
+       // Sanity check
+       if (glyph.GetNumPoints(poly) < 3)
+               return;
+
+       // 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)));
+
+       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;
+               }
+       }
+}
+
+
+void EditWindow::mousePressEvent(QMouseEvent * event)
+{
+       if (event->button() == Qt::RightButton)
+       {
+               toolPalette->move(event->globalPos());
+               toolPalette->setVisible(true);
+               setCursor(cur[TOOLSelect]);
+               toolPalette->prevTool = TOOLSelect;
+       }
+       else if (event->button() == Qt::MidButton)
+       {
+               setCursor(cur[2]);                                                      // Scrolling cursor
+       }
+       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 == TOOLAddPt)             // "Add Point" tool
+               {
+                       QPoint pt = GetAdjustedMousePosition(event);
+                       IPoint pointToAdd(pt.x(), pt.y(), ((event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier) ? false : true));
+
+                       if (pts.GetNumPoints() < 2)
+                       {
+//                             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();
+               }
+               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);
+//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));
+                       ptHighlight = pts.GetNumPoints() - 1;
+                       update();
+#ifdef DEBUGFOO
+WriteLogMsg(" --> [# polys: %u, # points: %u]\n", pts.GetNumPolys(), pts.GetNumPoints());
+#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));
+
+                               if (event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier)
+                               {
+                                       pts.SetOnCurve(ptHighlight, !pts.GetOnCurve(ptHighlight));
+                                       update();
+                               }
+                       }
+               }
+               else if (tool == TOOLDelPt)
+               {
+                       if (pts.GetNumPoints() > 0)
+//Or could use:
+//                     if (ptHighlight != -1)
+                       {
+//This assumes that WM_MOUSEMOVE happens before this!
+//The above commented out line should take care of this contingency... !!! FIX !!!
+                               pts.DeletePoint(ptHighlight);
+                               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);
+                       showRotationCenter = true;
+                       haveZeroPoint = false;
+                       rotationAngle = 0;
+                       update();
+               }
+               else if (tool == TOOLRotatePoly)
+               {
+                       IPoint centroid = pts.GetPolyCentroid(pts.GetPolyForPointNumber(ptHighlight));
+                       rotationCenter = QPoint(centroid.x, centroid.y);
+                       showRotationCenter = true;
+                       pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight));
+                       QCursor::setPos(mapToGlobal(pt));
+                       rotationZeroPoint = QPoint(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));
+                       QCursor::setPos(mapToGlobal(pt));
+                       update();
+               }
+       }
+
+       event->accept();
+}
+
+
+void EditWindow::mouseMoveEvent(QMouseEvent * event)
+{
+       if (event->buttons() == Qt::RightButton)
+       {
+               ToolType newTool = toolPalette->FindSelectedTool();
+
+               if (newTool != toolPalette->prevTool)
+               {
+                       toolPalette->prevTool = newTool;
+                       toolPalette->repaint();
+               }
+       }
+       else if (event->buttons() == Qt::MidButton)
+       {
+               // Calc offset from previous point
+               pt = event->pos();
+               ptOffset = QPoint(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();
+               ptPrevious = pt;
+       }
+       else if (event->buttons() == Qt::LeftButton)
+       {
+               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;
+
+                       QPoint pt2 = GetAdjustedMousePosition(event);
+                       pts.SetXY(ptHighlight, pt2.x(), pt2.y());
+                       update();
+               }
+               else if (tool == TOOLPolySelect)
+               {
+                       if (pts.GetNumPoints() > 0)
+                       {
+                               QPoint pt2 = GetAdjustedMousePosition(event);
+                               // 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 == TOOLRotate || tool == TOOLRotatePoly)
+               {
+                       if (pts.GetNumPoints() > 0)
+                       {
+                               if (!haveZeroPoint)
+                               {
+                                       rotationZeroPoint = GetAdjustedMousePosition(event);
+                                       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 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 * 180.0 / 3.14159265358979323);
+                                       ((TTEdit *)qApp)->mainWindow->statusBar()->showMessage(s);
+                               }
+
+                               update();
+                       }
+               }
+       }
+       else if (event->buttons() == Qt::NoButton)
+       {
+               // Moving, not dragging...
+               if (tool == TOOLSelect || tool == TOOLDelPt || tool == TOOLAddPt
+                       || tool == TOOLPolySelect || tool == TOOLRotatePoly || tool == TOOLFlipWinding)
+               {
+                       QPoint pt2 = GetAdjustedMousePosition(event);
+                       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)));
+
+                               if (dist < closest)
+                                       closest = dist, ptHighlight = i;
+                       }
+
+                       if (ptHighlight != oldPtHighlight)
+                       {
+                               oldPtHighlight = ptHighlight;
+                               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.
+
+                       // 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)
+                       {
+                               double smallest = 1.0e+99;
+
+                               for(int i=0; i<pts.GetNumPoints(); i++)
+                               {
+                                       int32 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.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.
+
+                                       if (pp < 0.0)
+                                               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.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:
+//
+//sx sy 1
+//ex ey 1
+//px py 1
+//
+//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!]
+//
+//0         0         0
+//(ex - sx) (ey - sy) 0
+//(px - sx) (py - sy) 0
+//
+//which greatly simplifies the calculation of the determinant.
+
+                                       if (dist < smallest)
+                                               smallest = dist, ptNextHighlight = pts.GetNext(i), ptHighlight = i;
+                               }
+
+                               if (ptNextHighlight != oldPtNextHighlight)
+                               {
+                                       oldPtNextHighlight = ptNextHighlight;
+                                       update();
+                               }
+                       }
+               }
+
+               ptPrevious = event->pos();
+       }
+
+       event->accept();
+}
+
+
+void EditWindow::mouseReleaseEvent(QMouseEvent * event)
+{
+       if (event->button() == Qt::RightButton)
+       {
+               ToolType newTool = toolPalette->FindSelectedTool();
+
+               // We only change the tool if a new one was actually selected. Otherwise, we do nothing.
+               if (newTool != TOOLNone)
+               {
+                       tool = newTool;
+
+                       if (tool == TOOLScroll || tool == TOOLZoom || tool == TOOLAddPoly
+                               || tool == TOOLDelPoly)
+                               ptHighlight = -1;
+
+                       if (tool == TOOLAddPoly)
+                               polyFirstPoint = true;
+               }
+
+               toolPalette->setVisible(false);
+               setCursor(cur[tool]);
+               // Just in case we changed highlighting style with the new tool...
+               update();
+       }
+       else if (event->button() == Qt::MidButton)
+       {
+               setCursor(cur[tool]);                                           // Restore previous cursor
+       }
+       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 poly = pts.GetPolyForPointNumber(ptHighlight);
+                               pts.RotatePolyAroundCentroid(poly, rotationAngle);
+                       }
+
+                       update();
+                       ((TTEdit *)qApp)->mainWindow->statusBar()->showMessage("");
+               }
+
+//             if (tool == TOOLScroll || tool == TOOLZoom)
+//                     ReleaseMouse();
+//this is prolly too much
+               ((TTEdit *)qApp)->charWnd->MakePathFromPoints(&pts);
+               ((TTEdit *)qApp)->charWnd->update();
+
+       }
+
+       event->accept();
+}