2 // TTEDIT.CPP - The TrueType Editor
4 // (C) 2004 Underground Software
6 // JLH = James L. Hammons <jlhamm@acm.org>
9 // --- ---------- -------------------------------------------------------------
10 // JLH 08/28/2008 Created this file
11 // JLH 09/02/2008 Separated scrolling from dedicated tool to MMB drag
12 // JLH 03/13/2009 Converted from wxWidgets to Qt
21 // - Fix bug in Glyphpoints when dragging on an empty canvas or loading a font
22 // - Fix zooming, settings (ini)
23 // - Fix point adding bug 1: should be able to add points to empty canvas
24 // - Fix point adding bug 2: should be able to add point successfully to single
26 // - Add poly multi-select
27 // - Add point multi-select
31 // Uncomment this for debugging...
33 #define DEBUGFOO // Various tool debugging...
34 #define DEBUGTP // Toolpalette debugging...
36 #include "editwindow.h"
38 #include "graphicprimitives.h"
42 EditWindow::EditWindow(QWidget * parent/*=NULL*/): QWidget(parent),
43 scale(1.0), offsetX(-10), offsetY(-10), tool(TOOLSelect),
44 ptHighlight(-1), oldPtHighlight(-1), ptNextHighlight(-1), oldPtNextHighlight(-1),
47 setBackgroundRole(QPalette::Base);
48 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
50 toolPalette = new ToolWindow();
52 setCursor(cur[TOOLSelect]);
53 setMouseTracking(true);
56 QSize EditWindow::minimumSizeHint() const
61 QSize EditWindow::sizeHint() const
63 return QSize(400, 400);
66 void EditWindow::CreateCursors(void)
68 int hotx[8] = { 1, 1, 11, 15, 1, 1, 1, 1 };
69 int hoty[8] = { 1, 1, 11, 13, 1, 1, 1, 1 };
71 for(int i=0; i<8; i++)
74 s.sprintf(":/res/cursor%u.png", i+1);
76 cur[i] = QCursor(pmTmp, hotx[i], hoty[i]);
80 QPoint EditWindow::GetAdjustedMousePosition(QMouseEvent * event)
82 QSize winSize = size();
83 // This is undoing the transform, e.g. going from client coords to local coords.
84 // In essence, the height - y is height + (y * -1), the (y * -1) term doing the conversion
85 // of the y-axis from increasing bottom to top.
86 return QPoint(offsetX + event->x(), offsetY + (winSize.height() - event->y()));
89 QPoint EditWindow::GetAdjustedClientPosition(int x, int y)
91 QSize winSize = size();
93 // VOODOO ALERT (ON Y COMPONENT!!!!)
94 return QPoint(-offsetX + x, (winSize.height() - (-offsetY + y)) * +1.0);
97 void EditWindow::paintEvent(QPaintEvent * /*event*/)
101 // p.setRenderHint(QPainter::Antialiasing);
103 //dc.SetBackground(*wxWHITE_BRUSH);
105 // Due to the screwiness of wxWidgets coord system, the origin is ALWAYS
106 // the upper left corner--regardless of axis orientation, etc...
107 // int width, height;
108 // dc.GetSize(&width, &height);
109 QSize winSize = size();
111 // dc.SetDeviceOrigin(-offsetX, height - (-offsetY));
112 // dc.SetAxisOrientation(true, true);
113 p.translate(QPoint(-offsetX, winSize.height() - (-offsetY)));
116 // Scrolling can be done by using OffsetViewportOrgEx
117 // Scaling can be done by adjusting SetWindowExtEx (it's denominator of txform)
118 // you'd use: % = ViewportExt / WindowExt
119 // But it makes the window look like crap: fuggetuboutit.
120 // Instead, we have to scale EVERYTHING by hand. Crap!
121 // It's not *that* bad, but not as convenient either...
123 // dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0xFF), 1, wxDOT)));
124 //// dc.DrawLine(0, 0, 10, 10);
125 p.setPen(QPen(Qt::blue, 1.0, Qt::DotLine));
127 // Draw coordinate axes
129 // dc.CrossHair(0, 0);
130 p.drawLine(0, -16384, 0, 16384);
131 p.drawLine(-16384, 0, 16384, 0);
135 for(int i=0; i<pts.GetNumPoints(); i++)
137 if (i == ptHighlight)
139 // dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));
140 //// SelectObject(hdc, hRedPen1);
141 p.setPen(QPen(Qt::red, 1.0, Qt::SolidLine));
143 if (pts.GetOnCurve(i))
145 DrawSquareDotN(p, pts.GetX(i), pts.GetY(i), 7);
146 DrawSquareDotN(p, pts.GetX(i), pts.GetY(i), 9);
150 DrawRoundDotN(p, pts.GetX(i), pts.GetY(i), 7);
151 DrawRoundDotN(p, pts.GetX(i), pts.GetY(i), 9);
154 else if ((i == ptHighlight || i == ptNextHighlight) && tool == TOOLAddPt)
156 // dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0xAF, 0x00), 1, wxSOLID)));
157 //// SelectObject(hdc, hGreenPen1);
158 p.setPen(QPen(Qt::green, 1.0, Qt::SolidLine));
160 if (pts.GetOnCurve(i))
162 DrawSquareDotN(p, pts.GetX(i), pts.GetY(i), 7);
163 DrawSquareDotN(p, pts.GetX(i), pts.GetY(i), 9);
167 DrawRoundDotN(p, pts.GetX(i), pts.GetY(i), 7);
168 DrawRoundDotN(p, pts.GetX(i), pts.GetY(i), 9);
173 // dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));
174 //// SelectObject(hdc, hBlackPen1);
175 p.setPen(QPen(Qt::black, 1.0, Qt::SolidLine));
177 if (pts.GetOnCurve(i))
178 DrawSquareDot(p, pts.GetX(i), pts.GetY(i));
180 DrawRoundDot(p, pts.GetX(i), pts.GetY(i));
183 if (tool == TOOLDelPt && i == ptHighlight)
186 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));
187 // SelectObject(hdc, hRedPen1);
188 // MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5, NULL);
189 // LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) + 5);
190 // LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5);//Lameness!
191 // MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5, NULL);
192 // LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) - 5);
193 // LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5);//More lameness!!
195 p.setPen(QPen(Qt::red, 1.0, Qt::SolidLine));
196 p.drawLine(pts.GetX(i) - 5, pts.GetY(i) - 5, pts.GetX(i) + 5, pts.GetY(i) + 5);
197 p.drawLine(pts.GetX(i) + 5, pts.GetY(i) - 5, pts.GetX(i) - 5, pts.GetY(i) + 5);
201 //// SelectObject(hdc, hBlackPen1);
202 // dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));
203 p.setPen(QPen(Qt::black, 1.0, Qt::SolidLine));
205 // Draw curve formed by points
207 for(int poly=0; poly<pts.GetNumPolys(); poly++)
209 if (pts.GetNumPoints(poly) > 2)
212 // If it's not on curve, then move to it, otherwise move to last point...
216 if (pts.GetOnCurve(poly, pts.GetNumPoints(poly) - 1))
217 x = (int)pts.GetX(poly, pts.GetNumPoints(poly) - 1), y = (int)pts.GetY(poly, pts.GetNumPoints(poly) - 1);
219 x = (int)pts.GetX(poly, 0), y = (int)pts.GetY(poly, 0);
221 for(int i=0; i<pts.GetNumPoints(poly); i++)
223 if (pts.GetOnCurve(poly, i))
224 // LineTo(hdc, pts.GetX(poly, i), pts.GetY(poly, i));
226 p.drawLine(x, y, pts.GetX(poly, i), pts.GetY(poly, i));
227 x = (int)pts.GetX(poly, i), y = (int)pts.GetY(poly, i);
231 uint32 prev = pts.GetPrev(poly, i), next = pts.GetNext(poly, i);
232 float px = pts.GetX(poly, prev), py = pts.GetY(poly, prev),
233 nx = pts.GetX(poly, next), ny = pts.GetY(poly, next);
235 if (!pts.GetOnCurve(poly, prev))
236 px = (px + pts.GetX(poly, i)) / 2.0f,
237 py = (py + pts.GetY(poly, i)) / 2.0f;
239 if (!pts.GetOnCurve(poly, next))
240 nx = (nx + pts.GetX(poly, i)) / 2.0f,
241 ny = (ny + pts.GetY(poly, i)) / 2.0f;
243 Bezier(p, point(px, py), point(pts.GetX(poly, i), pts.GetY(poly, i)), point(nx, ny));
244 x = (int)nx, y = (int)ny;
246 if (pts.GetOnCurve(poly, next))
247 i++; // Following point is on curve, so move past it
254 void EditWindow::mousePressEvent(QMouseEvent * event)
256 if (event->button() == Qt::RightButton)
258 toolPalette->move(event->globalPos());
259 toolPalette->setVisible(true);
260 setCursor(cur[TOOLSelect]);
261 toolPalette->prevTool = TOOLSelect;
263 else if (event->button() == Qt::MidButton)
265 setCursor(cur[2]); // Scrolling cursor
267 else if (event->button() == Qt::LeftButton)
269 if (tool == TOOLScroll || tool == TOOLZoom)
270 ;//meh CaptureMouse(); // Make sure we capture the mouse when in scroll/zoom mode
271 else if (tool == TOOLAddPt) // "Add Point" tool
273 if (pts.GetNumPoints() > 0)
275 QPoint pt = GetAdjustedMousePosition(event);
276 pts.InsertPoint(pts.GetNext(ptHighlight), pt.x(), pt.y(), ((event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier) ? false : true));
277 ptHighlight = ptNextHighlight;
281 else if (tool == TOOLAddPoly) // "Add Poly" tool
284 WriteLogMsg("Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts.GetNumPoints());
288 polyFirstPoint = false;
289 pts.AddNewPolyAtEnd();
292 QPoint pt = GetAdjustedMousePosition(event);
293 //printf("GetAdjustedMousePosition = %i, %i\n", pt.x(), pt.y());
294 // Append a point to the end of the structure
295 pts += IPoint(pt.x(), pt.y(), ((event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier) ? false : true));
296 ptHighlight = pts.GetNumPoints() - 1;
299 WriteLogMsg(" --> [# polys: %u, # points: %u]\n", pts.GetNumPolys(), pts.GetNumPoints());
302 else if (tool == TOOLSelect || tool == TOOLPolySelect)
304 if (pts.GetNumPoints() > 0)
306 pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight));
307 //printf("GetAdjustedClientPosition = %i, %i\n", pt.x(), pt.y());
308 // WarpPointer(pt.x, pt.y);
309 QCursor::setPos(mapToGlobal(pt));
311 if (event->modifiers() == Qt::ShiftModifier || event->modifiers() == Qt::ControlModifier)
313 pts.SetOnCurve(ptHighlight, !pts.GetOnCurve(ptHighlight));
318 else if (tool == TOOLDelPt)
320 if (pts.GetNumPoints() > 0)
322 // if (ptHighlight != -1)
324 //This assumes that WM_MOUSEMOVE happens before this!
325 //The above commented out line should take care of this contingency... !!! FIX !!!
326 pts.DeletePoint(ptHighlight);
335 void EditWindow::mouseMoveEvent(QMouseEvent * event)
337 if (event->buttons() == Qt::RightButton)
339 ToolType newTool = toolPalette->FindSelectedTool();
341 if (newTool != toolPalette->prevTool)
343 toolPalette->prevTool = newTool;
344 toolPalette->repaint();
347 else if (event->buttons() == Qt::MidButton)
349 // Calc offset from previous point
351 ptOffset = QPoint(pt.x() - ptPrevious.x(), pt.y() - ptPrevious.y());
353 // Then multiply it by the scaling factor. Whee!
354 // This looks wacky because we're using screen coords for the offset...
355 // Otherwise, we would subtract both offsets!
356 offsetX -= ptOffset.x(), offsetY += ptOffset.y();
360 else if (event->buttons() == Qt::LeftButton)
363 if (tool == TOOLScroll)
365 // Extract current point from lParam/calc offset from previous point
367 pt = e.GetPosition();
368 ptOffset.x = pt.x - ptPrevious.x,
369 ptOffset.y = pt.y - ptPrevious.y;
371 // NOTE: OffsetViewportOrg operates in DEVICE UNITS...
373 //Seems there's no equivalent for this in wxWidgets...!
375 // hdc = GetDC(hWnd);
376 // OffsetViewportOrgEx(hdc, ptOffset.x, ptOffset.y, NULL);
377 // ReleaseDC(hWnd, hdc);
379 // this shows that it works, so the logic above must be faulty...
380 // And it is. It should convert the coords first, then do the subtraction to figure the offset...
382 // Then multiply it by the scaling factor. Whee!
383 // This looks wacky because we're using screen coords for the offset...
384 // Otherwise, we would subtract both offsets!
385 offsetX -= ptOffset.x, offsetY += ptOffset.y;
390 if (tool == TOOLAddPt || tool == TOOLAddPoly || tool == TOOLSelect)
392 if (tool != TOOLAddPt || pts.GetNumPoints() > 0)//yecch.
394 //temporary, for testing. BTW, Select drag bug is here...!
396 QPoint pt2 = GetAdjustedMousePosition(event);
397 pts.SetXY(ptHighlight, pt2.x(), pt2.y());
402 else if (tool == TOOLPolySelect)
404 if (pts.GetNumPoints() > 0)
406 QPoint pt2 = GetAdjustedMousePosition(event);
407 // Should also set onCurve here as well, depending on keystate
409 pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x() - pts.GetX(ptHighlight), pt2.y() - pts.GetY(ptHighlight));
414 else if (event->buttons() == Qt::NoButton)
416 // Moving, not dragging...
417 if (tool == TOOLSelect || tool == TOOLDelPt || tool == TOOLAddPt
418 || tool == TOOLPolySelect)// || tool == TOOLAddPoly)
420 QPoint pt2 = GetAdjustedMousePosition(event);
421 double closest = 1.0e+99;
423 for(int i=0; i<pts.GetNumPoints(); i++)
425 double dist = ((pt2.x() - pts.GetX(i)) * (pt2.x() - pts.GetX(i)))
426 + ((pt2.y() - pts.GetY(i)) * (pt2.y() - pts.GetY(i)));
429 closest = dist, ptHighlight = i;
432 if (ptHighlight != oldPtHighlight)
434 oldPtHighlight = ptHighlight;
438 // What follows here looks like voodoo, but is really simple. What we do is
439 // check to see if the mouse point has a perpendicular intersection with any of
440 // the line segments. If it does, calculate the length of the perpendicular
441 // and choose the smallest length. If there is no perpendicular, then choose the
442 // length of line connecting the closer of either the first endpoint or the
443 // second and choose the smallest of those.
445 // There is one bit of math that looks like voodoo to me ATM--will explain once
446 // I understand it better (the calculation of the length of the perpendicular).
448 if (pts.GetNumPoints() > 1 && tool == TOOLAddPt)
450 double smallest = 1.0e+99;
452 for(int i=0; i<pts.GetNumPoints(); i++)
454 int32 p1x = pts.GetX(i), p1y = pts.GetY(i),
455 p2x = pts.GetX(pts.GetNext(i)), p2y = pts.GetY(pts.GetNext(i));
457 vector ls(p2x, p2y, 0, p1x, p1y, 0), v1(pt2.x(), pt2.y(), 0, p1x, p1y, 0),
458 v2(pt2.x(), pt2.y(), 0, p2x, p2y, 0);
459 double pp = ls.dot(v1) / ls.length(), dist;
460 // Geometric interpretation:
461 // pp is the paremeterized point on the vector ls where the perpendicular intersects ls.
462 // If pp < 0, then the perpendicular lies beyond the 1st endpoint. If pp > length of ls,
463 // then the perpendicular lies beyond the 2nd endpoint.
467 else if (pp > ls.length())
469 else // distance = ?Det?(ls, v1) / |ls|
470 dist = fabs((ls.x * v1.y - v1.x * ls.y) / ls.length());
472 //The answer to the above looks like it might be found here:
474 //If the segment endpoints are s and e, and the point is p, then the test for the perpendicular
475 //intercepting the segment is equivalent to insisting that the two dot products {s-e}.{s-p} and
476 //{e-s}.{e-p} are both non-negative. Perpendicular distance from the point to the segment is
477 //computed by first computing the area of the triangle the three points form, then dividing by the
478 //length of the segment. Distances are done just by the Pythagorean theorem. Twice the area of the
479 //triangle formed by three points is the determinant of the following matrix:
485 //(???) By translating the start point to the origin, this can be rewritten as:
486 //By subtracting row 1 from all rows, you get the following:
489 //(ex - sx) (ey - sy) 0
490 //(px - sx) (py - sy) 0
492 //which greatly simplifies the calculation of the determinant.
495 smallest = dist, ptNextHighlight = pts.GetNext(i), ptHighlight = i;
498 if (ptNextHighlight != oldPtNextHighlight)
500 oldPtNextHighlight = ptNextHighlight;
506 ptPrevious = event->pos();
512 void EditWindow::mouseReleaseEvent(QMouseEvent * event)
514 if (event->button() == Qt::RightButton)
516 ToolType newTool = toolPalette->FindSelectedTool();
518 // We only change the tool if a new one was actually selected. Otherwise, we do nothing.
519 if (newTool != TOOLNone)
523 if (tool == TOOLScroll || tool == TOOLZoom || tool == TOOLAddPoly
524 || tool == TOOLDelPoly)
527 if (tool == TOOLAddPoly)
528 polyFirstPoint = true;
531 toolPalette->setVisible(false);
532 setCursor(cur[tool]);
533 // Just in case we changed highlighting style with the new tool...
536 else if (event->button() == Qt::MidButton)
538 setCursor(cur[tool]); // Restore previous cursor
540 else if (event->button() == Qt::LeftButton)
542 // if (tool == TOOLScroll || tool == TOOLZoom)
552 #include "editwindow.h"
553 #include "graphicprimitives.h"
554 #include "toolwindow.h"
559 BEGIN_EVENT_TABLE(TTEditWindow, wxWindow)
560 EVT_PAINT(TTEditWindow::OnPaint)
561 EVT_MOUSE_EVENTS(TTEditWindow::OnMouseEvent)
564 TTEditWindow::TTEditWindow(wxFrame * parent, const wxPoint &pos, const wxSize &size, long style):
565 wxWindow(parent, -1, pos, size, style | wxFULL_REPAINT_ON_RESIZE),
566 app(wxGetApp()), scale(1.0), offsetX(-10), offsetY(-10), tool(TOOLSelect),
567 ptHighlight(-1), oldPtHighlight(-1), ptNextHighlight(-1), oldPtNextHighlight(-1),
568 polyFirstPoint(true), bmp(NULL)
570 SetCursor(*(app.cur[tool]));
571 SetBackgroundColour(wxColour(0xFF, 0xFF, 0xFF));
574 s.Printf(_("Zoom: %.2f%%"), scale * 100.0);
575 parent->SetStatusText(s, 1);
578 TTEditWindow::~TTEditWindow(void)
584 void TTEditWindow::OnPaint(wxPaintEvent &e)
588 //dc.SetBackground(*wxWHITE_BRUSH);
590 // Due to the screwiness of wxWidgets coord system, the origin is ALWAYS
591 // the upper left corner--regardless of axis orientation, etc...
592 wxCoord width, height;
593 dc.GetSize(&width, &height);
595 dc.SetDeviceOrigin(-offsetX, height - (-offsetY));
596 dc.SetAxisOrientation(true, true);
598 // Scrolling can be done by using OffsetViewportOrgEx
599 // Scaling can be done by adjusting SetWindowExtEx (it's denominator of txform)
600 // you'd use: % = ViewportExt / WindowExt
601 // But it makes the window look like crap: fuggetuboutit.
602 // Instead, we have to scale EVERYTHING by hand. Crap!
603 // It's not *that* bad, but not as convenient either...
605 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0xFF), 1, wxDOT)));
606 // dc.DrawLine(0, 0, 10, 10);
608 // Draw coordinate axes
614 for(int i=0; i<pts.GetNumPoints(); i++)
616 if (i == ptHighlight)
618 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));
619 // SelectObject(hdc, hRedPen1);
621 if (pts.GetOnCurve(i))
623 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 7);
624 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 9);
628 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 7);
629 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 9);
632 else if ((i == ptHighlight || i == ptNextHighlight) && tool == TOOLAddPt)
634 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0xAF, 0x00), 1, wxSOLID)));
635 // SelectObject(hdc, hGreenPen1);
637 if (pts.GetOnCurve(i))
639 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 7);
640 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 9);
644 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 7);
645 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 9);
650 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));
651 // SelectObject(hdc, hBlackPen1);
653 if (pts.GetOnCurve(i))
654 DrawSquareDot(dc, pts.GetX(i), pts.GetY(i));
656 DrawRoundDot(dc, pts.GetX(i), pts.GetY(i));
659 if (tool == TOOLDelPt && i == ptHighlight)
661 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));
662 // SelectObject(hdc, hRedPen1);
663 // MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5, NULL);
664 // LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) + 5);
665 // LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5);//Lameness!
666 // MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5, NULL);
667 // LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) - 5);
668 // LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5);//More lameness!!
669 dc.DrawLine(pts.GetX(i) - 5, pts.GetY(i) - 5, pts.GetX(i) + 5, pts.GetY(i) + 5);
670 dc.DrawLine(pts.GetX(i) + 5, pts.GetY(i) - 5, pts.GetX(i) - 5, pts.GetY(i) + 5);
674 // SelectObject(hdc, hBlackPen1);
675 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));
677 // Draw curve formed by points
679 for(int poly=0; poly<pts.GetNumPolys(); poly++)
681 if (pts.GetNumPoints(poly) > 2)
684 // If it's not on curve, then move to it, otherwise move to last point...
688 if (pts.GetOnCurve(poly, pts.GetNumPoints(poly) - 1))
689 x = (wxCoord)pts.GetX(poly, pts.GetNumPoints(poly) - 1), y = (wxCoord)pts.GetY(poly, pts.GetNumPoints(poly) - 1);
691 x = (wxCoord)pts.GetX(poly, 0), y = (wxCoord)pts.GetY(poly, 0);
693 for(int i=0; i<pts.GetNumPoints(poly); i++)
695 if (pts.GetOnCurve(poly, i))
696 // LineTo(hdc, pts.GetX(poly, i), pts.GetY(poly, i));
698 dc.DrawLine(x, y, pts.GetX(poly, i), pts.GetY(poly, i));
699 x = (wxCoord)pts.GetX(poly, i), y = (wxCoord)pts.GetY(poly, i);
703 uint32 prev = pts.GetPrev(poly, i), next = pts.GetNext(poly, i);
704 float px = pts.GetX(poly, prev), py = pts.GetY(poly, prev),
705 nx = pts.GetX(poly, next), ny = pts.GetY(poly, next);
707 if (!pts.GetOnCurve(poly, prev))
708 px = (px + pts.GetX(poly, i)) / 2.0f,
709 py = (py + pts.GetY(poly, i)) / 2.0f;
711 if (!pts.GetOnCurve(poly, next))
712 nx = (nx + pts.GetX(poly, i)) / 2.0f,
713 ny = (ny + pts.GetY(poly, i)) / 2.0f;
715 Bezier(dc, point(px, py), point(pts.GetX(poly, i), pts.GetY(poly, i)), point(nx, ny));
716 x = (wxCoord)nx, y = (wxCoord)ny;
718 if (pts.GetOnCurve(poly, next))
719 i++; // Following point is on curve, so move past it
725 // SelectObject(hdc, oldPen); // Restore the stuff we disrupted...
726 dc.SetPen(wxNullPen);
727 // SelectObject(hdc, oldBrush);
728 // EndPaint(hWnd, &ps);
731 void TTEditWindow::OnMouseEvent(wxMouseEvent &e)
734 //printf("!!! This window %s focus...!\n", (HasCapture() ? "has" : "doesn't have"));
738 // Handle tool palette (NOTE: tool palette deals with RightUp event.)
740 wxPoint pt = ClientToScreen(e.GetPosition());
741 app.toolPalette->Move(pt);
742 app.toolPalette->Show(true);
743 SetCursor(*wxSTANDARD_CURSOR);
744 app.toolPalette->SetCursor(*wxSTANDARD_CURSOR);
745 app.toolPalette->prevTool = TOOLSelect;
746 app.toolPalette->Refresh(false);
749 else if (e.RightUp())
751 ToolType newTool = app.toolPalette->FindSelectedTool();//, oldTool = tool;
753 // We only change the tool if a new one was actually selected. Otherwise, we do nothing.
754 if (newTool != TOOLNone)
758 if (tool == TOOLScroll || tool == TOOLZoom || tool == TOOLAddPoly
759 || tool == TOOLDelPoly)
762 if (tool == TOOLAddPoly)
763 polyFirstPoint = true;
767 app.toolPalette->Show(false);
768 SetCursor(*(app.cur[tool]));
770 else if (e.LeftDown())
772 if (tool == TOOLScroll || tool == TOOLZoom)
773 CaptureMouse(); // Make sure we capture the mouse when in scroll/zoom mode
774 else if (tool == TOOLAddPt) // "Add Point" tool
776 if (pts.GetNumPoints() > 0)
778 wxPoint pt = GetAdjustedMousePosition(e);
779 pts.InsertPoint(pts.GetNext(ptHighlight), pt.x, pt.y, (e.ShiftDown() | e.ControlDown() ? false : true));
780 ptHighlight = ptNextHighlight;
784 else if (tool == TOOLAddPoly) // "Add Poly" tool
787 WriteLogMsg("Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts.GetNumPoints());
791 polyFirstPoint = false;
792 pts.AddNewPolyAtEnd();
795 wxPoint pt = GetAdjustedMousePosition(e);
796 // Append a point to the end of the structure
797 pts += IPoint(pt.x, pt.y, (e.ShiftDown() | e.ControlDown() ? false : true));
798 ptHighlight = pts.GetNumPoints() - 1;
801 WriteLogMsg(" --> [# polys: %u, # points: %u]\n", pts.GetNumPolys(), pts.GetNumPoints());
804 else if (tool == TOOLSelect || tool == TOOLPolySelect)
806 if (pts.GetNumPoints() > 0)
808 pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight));
809 WarpPointer(pt.x, pt.y);
811 if (e.ShiftDown() | e.ControlDown())
812 pts.SetOnCurve(ptHighlight, !pts.GetOnCurve(ptHighlight));
815 else if (tool == TOOLDelPt)
817 if (pts.GetNumPoints() > 0)
819 // if (ptHighlight != -1)
821 //This assumes that WM_MOUSEMOVE happens before this!
822 //The above commented out line should take care of this contingency... !!! FIX !!!
823 pts.DeletePoint(ptHighlight);
830 if (tool == TOOLScroll || tool == TOOLZoom)
833 else if (e.MiddleDown())
835 SetCursor(*(app.cur[2])); // Scrolling cursor
837 else if (e.MiddleUp())
839 SetCursor(*(app.cur[tool])); // Restore previous cursor
841 else if (e.Dragging())
845 ToolType newTool = app.toolPalette->FindSelectedTool();
847 if (newTool != app.toolPalette->prevTool)
849 app.toolPalette->prevTool = newTool;
850 app.toolPalette->Refresh(false);
855 else if (e.MiddleIsDown())
857 // Calc offset from previous point
858 pt = e.GetPosition();
859 ptOffset.x = pt.x - ptPrevious.x,
860 ptOffset.y = pt.y - ptPrevious.y;
862 // Then multiply it by the scaling factor. Whee!
863 // This looks wacky because we're using screen coords for the offset...
864 // Otherwise, we would subtract both offsets!
865 offsetX -= ptOffset.x, offsetY += ptOffset.y;
872 else if (e.LeftIsDown())
875 if (tool == TOOLScroll)
877 // Extract current point from lParam/calc offset from previous point
879 pt = e.GetPosition();
880 ptOffset.x = pt.x - ptPrevious.x,
881 ptOffset.y = pt.y - ptPrevious.y;
883 // NOTE: OffsetViewportOrg operates in DEVICE UNITS...
885 //Seems there's no equivalent for this in wxWidgets...!
887 // hdc = GetDC(hWnd);
888 // OffsetViewportOrgEx(hdc, ptOffset.x, ptOffset.y, NULL);
889 // ReleaseDC(hWnd, hdc);
891 // this shows that it works, so the logic above must be faulty...
892 // And it is. It should convert the coords first, then do the subtraction to figure the offset...
894 // Then multiply it by the scaling factor. Whee!
895 // This looks wacky because we're using screen coords for the offset...
896 // Otherwise, we would subtract both offsets!
897 offsetX -= ptOffset.x, offsetY += ptOffset.y;
902 if (tool == TOOLAddPt || tool == TOOLAddPoly || tool == TOOLSelect)
904 if (tool != TOOLAddPt || pts.GetNumPoints() > 0)//yecch.
906 //temporary, for testing. BTW, Select drag bug is here...!
908 wxPoint pt2 = GetAdjustedMousePosition(e);
909 pts.SetXY(ptHighlight, pt2.x, pt2.y);
914 else if (tool == TOOLPolySelect)
916 if (pts.GetNumPoints() > 0)
918 wxPoint pt2 = GetAdjustedMousePosition(e);
919 // Should also set onCurve here as well, depending on keystate
921 pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x - pts.GetX(ptHighlight), pt2.y - pts.GetY(ptHighlight));
931 // else // Moving, not dragging...
933 if (tool == TOOLSelect || tool == TOOLDelPt || tool == TOOLAddPt
934 || tool == TOOLPolySelect)// || tool == TOOLAddPoly)
936 wxPoint pt2 = GetAdjustedMousePosition(e);
937 double closest = 1.0e+99;
939 for(int i=0; i<pts.GetNumPoints(); i++)
941 double dist = ((pt2.x - pts.GetX(i)) * (pt2.x - pts.GetX(i)))
942 + ((pt2.y - pts.GetY(i)) * (pt2.y - pts.GetY(i)));
945 closest = dist, ptHighlight = i;
948 if (ptHighlight != oldPtHighlight)
950 oldPtHighlight = ptHighlight;
954 // What follows here looks like voodoo, but is really simple. What we do is
955 // check to see if the mouse point has a perpendicular intersection with any of
956 // the line segments. If it does, calculate the length of the perpendicular
957 // and choose the smallest length. If there is no perpendicular, then choose the
958 // length of line connecting the closer of either the first endpoint or the
959 // second and choose the smallest of those.
961 // There is one bit of math that looks like voodoo to me ATM--will explain once
962 // I understand it better (the calculation of the length of the perpendicular).
964 if (pts.GetNumPoints() > 1 && tool == TOOLAddPt)
966 double smallest = 1.0e+99;
968 for(int i=0; i<pts.GetNumPoints(); i++)
970 int32 p1x = pts.GetX(i), p1y = pts.GetY(i),
971 p2x = pts.GetX(pts.GetNext(i)), p2y = pts.GetY(pts.GetNext(i));
973 vector ls(p2x, p2y, 0, p1x, p1y, 0), v1(pt2.x, pt2.y, 0, p1x, p1y, 0),
974 v2(pt2.x, pt2.y, 0, p2x, p2y, 0);
975 double pp = ls.dot(v1) / ls.length(), dist;
976 // Geometric interpretation:
977 // pp is the paremeterized point on the vector ls where the perpendicular intersects ls.
978 // If pp < 0, then the perpendicular lies beyond the 1st endpoint. If pp > length of ls,
979 // then the perpendicular lies beyond the 2nd endpoint.
983 else if (pp > ls.length())
985 else // distance = ?Det?(ls, v1) / |ls|
986 dist = fabs((ls.x * v1.y - v1.x * ls.y) / ls.length());
988 //The answer to the above looks like it might be found here:
990 //If the segment endpoints are s and e, and the point is p, then the test for the perpendicular
991 //intercepting the segment is equivalent to insisting that the two dot products {s-e}.{s-p} and
992 //{e-s}.{e-p} are both non-negative. Perpendicular distance from the point to the segment is
993 //computed by first computing the area of the triangle the three points form, then dividing by the
994 //length of the segment. Distances are done just by the Pythagorean theorem. Twice the area of the
995 //triangle formed by three points is the determinant of the following matrix:
1001 //(???) By translating the start point to the origin, this can be rewritten as:
1002 //By subtracting row 1 from all rows, you get the following:
1005 //(ex - sx) (ey - sy) 0
1006 //(px - sx) (py - sy) 0
1008 //which greatly simplifies the calculation of the determinant.
1010 if (dist < smallest)
1011 smallest = dist, ptNextHighlight = pts.GetNext(i), ptHighlight = i;
1014 if (ptNextHighlight != oldPtNextHighlight)
1016 oldPtNextHighlight = ptNextHighlight;
1023 ptPrevious = e.GetPosition();
1027 wxPoint TTEditWindow::GetAdjustedMousePosition(wxMouseEvent &e)
1029 wxCoord width, height;
1030 wxClientDC dc(this);
1032 dc.GetSize(&width, &height);
1033 dc.SetDeviceOrigin(-offsetX, height - (-offsetY));
1034 dc.SetAxisOrientation(true, true);
1037 wxStatusBar * sb = ((wxFrame *)GetParent())->GetStatusBar();
1039 s.Printf("Logical mouse pos: %d, %d (%d, %d)", pt.x, pt.y, width, height);
1040 sb->SetStatusText(s);
1043 return e.GetLogicalPosition(dc);
1046 wxPoint TTEditWindow::GetAdjustedClientPosition(wxCoord x, wxCoord y)
1048 wxCoord width, height;
1049 wxClientDC dc(this);
1051 dc.GetSize(&width, &height);
1052 dc.SetDeviceOrigin(-offsetX, height - (-offsetY));
1053 dc.SetAxisOrientation(true, true);
1055 return wxPoint(dc.LogicalToDeviceX(x), dc.LogicalToDeviceY(y));
1064 LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
1076 MiscCenterWnd(hWnd, GetDesktopWindow());
1077 InitCommonControls();
1078 hStatusBar = CreateStatusWindow(WS_CHILD | WS_VISIBLE, statusBarTxt, hWnd, ID_STATUSBAR);
1083 // clean this crap up!
1084 // well, the only crappy thing here is using a POINT as an int array, but otherwise, this is OK
1085 wsprintf(strBuf, zoom, 1000);
1087 GetTextExtentPoint32(hdc, strBuf, lstrlen(strBuf), &sz);
1088 ReleaseDC(hWnd, hdc);
1089 zoomWndWidth = sz.cx;
1090 wsprintf(strBuf, zoom, 100);
1092 GetClientRect(hWnd, &rc1);
1093 pt.x = rc1.right - zoomWndWidth, pt.y = -1;
1094 SendMessage(hStatusBar, SB_SETPARTS, 2, (LPARAM)&pt);
1095 SendMessage(hStatusBar, SB_SETTEXT, (0 | SBT_NOBORDERS), (LPARAM)statusBarTxt);
1096 SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM)strBuf);
1098 hToolBar = CreateToolbarEx(hWnd, WS_CHILD | WS_BORDER | WS_VISIBLE | TBSTYLE_TOOLTIPS,
1099 IDR_TOOLBAR1, 3, hInst, IDB_TOOLBAR1, tbButtons, 4, 16, 16, 16, 16, sizeof(TBBUTTON));
1106 // The following can only be done because we use a private DC (using "CS_OWNDC")
1107 // (Is that true???)
1108 // Set the mapping to draw the character so it fits in the viewport...
1110 GetClientRect(hWnd, &rc1);
1111 GetClientRect(hStatusBar, &rc2);
1112 rc1.bottom -= rc2.bottom;
1113 SetMapMode(hdc, MM_ISOTROPIC);
1114 SetWindowExtEx(hdc, rc1.right, rc1.bottom, NULL);
1115 SetViewportExtEx(hdc, rc1.right, -rc1.bottom, NULL);
1116 SetViewportOrgEx(hdc, 0, rc1.bottom, NULL);
1117 ReleaseDC(hWnd, hdc);
1124 wpM.length = wpC.length = sizeof(WINDOWPLACEMENT);
1125 GetWindowPlacement(hMainWnd, &wpM);
1126 GetWindowPlacement(hCharWnd, &wpC);
1128 if (!IsWindowVisible(hCharWnd)) // Needed because Windows lies about visibility
1129 wpC.showCmd = SW_HIDE;
1132 GetViewportOrgEx(hdc, &ptVPM);
1133 ReleaseDC(hWnd, hdc);
1135 DestroyWindow(hWnd);
1145 case WM_NCLBUTTONDOWN:
1147 if (wParam == HTCAPTION)
1150 GetWindowRect(hMainWnd, &rc1);
1151 GetWindowRect(hCharWnd, &rc2);
1152 ptWinOffset.x = rc2.left - rc1.left;
1153 ptWinOffset.y = rc2.top - rc1.top;
1156 // Let Windows do its thing with this msg, or weird things will happen...
1158 DefWindowProc(hWnd, msgID, wParam, lParam);
1159 NCMouseDown = false;
1162 case WM_WINDOWPOSCHANGING:
1166 WINDOWPOS * wp = (WINDOWPOS *)lParam;
1168 if (wp->hwnd == hMainWnd && !(wp->flags & SWP_NOMOVE))
1169 SetWindowPos(hCharWnd, 0, wp->x + ptWinOffset.x, wp->y + ptWinOffset.y,
1170 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1173 return DefWindowProc(hWnd, msgID, wParam, lParam); // Seems this is needed... Bleah!
1177 hdc = BeginPaint(hWnd, &ps);
1179 // Scrolling can be done by using OffsetViewportOrgEx
1180 // Scaling can be done by adjusting SetWindowExtEx (it's denominator of txform)
1181 // you'd use: % = ViewportExt / WindowExt
1182 // But it makes the window look like crap: fuggetuboutit.
1183 // Instead, we have to scale EVERYTHING by hand. Crap!
1185 // Apparently, you *must* save the individual object types (pen, brush, etc.)
1187 HGDIOBJ oldPen = SelectObject(hdc, hBluePen1),
1188 oldBrush = SelectObject(hdc, hNullBrush);
1190 // Draw coordinate axes
1192 MoveToEx(hdc, 0, -32000, NULL);
1193 LineTo(hdc, 0, 32000);
1194 MoveToEx(hdc, -32000, 0, NULL);
1195 LineTo(hdc, 32000, 0);
1199 for(int i=0; i<pts.GetNumPoints(); i++)
1201 if (i == ptHighlight)
1203 SelectObject(hdc, hRedPen1);
1205 if (pts.GetOnCurve(i))
1207 DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 7);
1208 DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 9);
1212 DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 7);
1213 DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 9);
1216 else if ((i == ptHighlight || i == ptNextHighlight) && currentTool == TOOLAddPt)
1218 SelectObject(hdc, hGreenPen1);
1220 if (pts.GetOnCurve(i))
1222 DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 7);
1223 DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 9);
1227 DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 7);
1228 DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 9);
1233 SelectObject(hdc, hBlackPen1);
1235 if (pts.GetOnCurve(i))
1236 DrawSquareDot(hdc, pts.GetX(i), pts.GetY(i));
1238 DrawRoundDot(hdc, pts.GetX(i), pts.GetY(i));
1241 if (currentTool == TOOLDelPt && i == ptHighlight)
1243 SelectObject(hdc, hRedPen1);
1244 MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5, NULL);
1245 LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) + 5);
1246 LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5);//Lameness!
1247 MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5, NULL);
1248 LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) - 5);
1249 LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5);//More lameness!!
1253 SelectObject(hdc, hBlackPen1);
1255 // Draw curve formed by points
1257 for(int poly=0; poly<pts.GetNumPolys(); poly++)
1259 if (pts.GetNumPoints(poly) > 2)
1262 // If it's not on curve, then move to it, otherwise move to last point...
1264 if (pts.GetOnCurve(poly, pts.GetNumPoints(poly) - 1))
1265 MoveToEx(hdc, pts.GetX(poly, pts.GetNumPoints(poly) - 1), pts.GetY(poly, pts.GetNumPoints(poly) - 1), NULL);
1267 MoveToEx(hdc, pts.GetX(poly, 0), pts.GetY(poly, 0), NULL);
1269 for(int i=0; i<pts.GetNumPoints(poly); i++)
1271 if (pts.GetOnCurve(poly, i))
1272 LineTo(hdc, pts.GetX(poly, i), pts.GetY(poly, i));
1275 uint32 prev = pts.GetPrev(poly, i), next = pts.GetNext(poly, i);
1276 float px = pts.GetX(poly, prev), py = pts.GetY(poly, prev),
1277 nx = pts.GetX(poly, next), ny = pts.GetY(poly, next);
1279 if (!pts.GetOnCurve(poly, prev))
1280 px = (px + pts.GetX(poly, i)) / 2.0f,
1281 py = (py + pts.GetY(poly, i)) / 2.0f;
1283 if (!pts.GetOnCurve(poly, next))
1284 nx = (nx + pts.GetX(poly, i)) / 2.0f,
1285 ny = (ny + pts.GetY(poly, i)) / 2.0f;
1287 Bezier(hdc, point(px, py), point(pts.GetX(poly, i), pts.GetY(poly, i)), point(nx, ny));
1289 if (pts.GetOnCurve(poly, next))
1290 i++; // Following point is on curve, so move past it
1296 SelectObject(hdc, oldPen); // Restore the stuff we disrupted...
1297 SelectObject(hdc, oldBrush);
1298 EndPaint(hWnd, &ps);
1303 // Apparently this is needed since these windows don't update themselves.
1304 SendMessage(hStatusBar, msgID, wParam, lParam);
1305 SendMessage(hToolBar, msgID, wParam, lParam);
1307 // This is needed to make the 2nd status pane visible
1308 GetClientRect(hWnd, &rc1);
1309 pt.x = rc1.right - zoomWndWidth, pt.y = -1;
1310 SendMessage(hStatusBar, SB_SETPARTS, 2, (LPARAM)&pt);
1313 case WM_RBUTTONDOWN:
1316 SetWindowPos(hToolPalWnd, 0, pt.x, pt.y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
1317 SetFocus(hToolPalWnd);
1318 SetCapture(hToolPalWnd); // Ensure tool palette gets RButtonUp
1319 SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW))); // Tool pallete has "regular" cursor
1322 case WM_LBUTTONDOWN:
1326 if (currentTool == TOOLScroll || currentTool == TOOLZoom)
1327 SetCapture(hWnd); // Make sure we capture the mouse when in scroll/zoom mode
1328 else if (currentTool == TOOLAddPt) // "Add Point" tool
1330 if (pts.GetNumPoints() > 0)
1332 //Do we really need to put a cap on this???
1334 // if (pts.GetNumPoints() < 16)
1336 pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;
1338 DPtoLP(hdc, &pt, 1);
1339 pts.InsertPoint(pts.GetNext(ptHighlight), pt.x, pt.y, (wParam & (MK_SHIFT | MK_CONTROL) ? false : true));
1340 ptHighlight = ptNextHighlight;
1341 ReleaseDC(hWnd, hdc);
1342 InvalidateRect(hWnd, NULL, TRUE);
1346 else if (currentTool == TOOLAddPoly) // "Add Poly" tool
1349 wsprintf(strBuf, "Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts.GetNumPoints());
1350 WriteLogMsg(strBuf);
1354 polyFirstPoint = false;
1355 pts.AddNewPolyAtEnd();
1358 //Do we really need to put a cap on this???
1360 // if (pts.GetNumPoints() < 16)
1362 pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;
1364 DPtoLP(hdc, &pt, 1);
1365 ReleaseDC(hWnd, hdc);
1366 // Append a point to the end of the structure
1367 pts += IPoint(pt.x, pt.y, (wParam & (MK_SHIFT | MK_CONTROL) ? false : true));
1368 ptHighlight = pts.GetNumPoints() - 1;
1369 InvalidateRect(hWnd, NULL, TRUE);
1372 wsprintf(strBuf, " --> [# polys: %u, # points: %u]\xD\xA", pts.GetNumPolys(), pts.GetNumPoints());
1373 WriteLogMsg(strBuf);
1376 else if (currentTool == TOOLSelect || currentTool == TOOLPolySelect)
1378 if (pts.GetNumPoints() > 0)
1380 pt.x = pts.GetX(ptHighlight), pt.y = pts.GetY(ptHighlight);
1382 LPtoDP(hdc, &pt, 1);
1383 ClientToScreen(hWnd, &pt);
1384 SetCursorPos(pt.x, pt.y);
1385 ReleaseDC(hWnd, hdc);
1387 if (wParam & (MK_SHIFT | MK_CONTROL))
1388 pts.SetOnCurve(ptHighlight, !pts.GetOnCurve(ptHighlight));
1391 else if (currentTool == TOOLDelPt)
1393 if (pts.GetNumPoints() > 0)
1395 // if (ptHighlight != -1)
1397 //This assumes that WM_MOUSEMOVE happens before this!
1398 //The above commented out line should take care of this contingency... !!! FIX !!!
1399 pts.DeletePoint(ptHighlight);
1400 InvalidateRect(hWnd, NULL, TRUE);
1410 if (currentTool == TOOLScroll || currentTool == TOOLZoom)
1417 SetCursor(hCur[currentTool]);
1419 // Extract current point from lParam/calc offset from previous point
1421 pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;
1422 ptOffset.x = pt.x - ptPrevious.x,
1423 ptOffset.y = pt.y - ptPrevious.y;
1427 if (currentTool == TOOLScroll)
1429 // NOTE: OffsetViewportOrg operates in DEVICE UNITS...
1432 OffsetViewportOrgEx(hdc, ptOffset.x, ptOffset.y, NULL);
1433 ReleaseDC(hWnd, hdc);
1435 // this shows that it works, so the logic above must be faulty...
1436 // And it is. It should convert the coords first, then do the subtraction to figure the offset...
1438 // Then multiply it by the scaling factor. Whee!
1440 InvalidateRect(hWnd, NULL, TRUE);
1441 // SendMessage(hWnd, WM_PAINT, NULL, NULL);
1443 else if (currentTool == TOOLAddPt || currentTool == TOOLAddPoly || currentTool == TOOLSelect)
1445 if (currentTool != TOOLAddPt || pts.GetNumPoints() > 0)//yecch.
1448 pt2.x = pt.x, pt2.y = pt.y;
1449 // Should also set onCurve here as well, depending on keystate
1452 DPtoLP(hdc, &pt2, 1);
1453 pts.SetXY(ptHighlight, pt2.x, pt2.y);
1454 ReleaseDC(hWnd, hdc);
1455 InvalidateRect(hWnd, NULL, TRUE);
1458 else if (currentTool == TOOLPolySelect)
1460 if (pts.GetNumPoints() > 0)
1463 pt2.x = pt.x, pt2.y = pt.y;
1464 // Should also set onCurve here as well, depending on keystate
1467 DPtoLP(hdc, &pt2, 1);
1468 pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x - pts.GetX(ptHighlight), pt2.y - pts.GetY(ptHighlight));
1469 ReleaseDC(hWnd, hdc);
1470 InvalidateRect(hWnd, NULL, TRUE);
1476 if (currentTool == TOOLSelect || currentTool == TOOLDelPt || currentTool == TOOLAddPt
1477 || currentTool == TOOLPolySelect)// || currentTool == TOOLAddPoly)
1480 pt2.x = pt.x, pt2.y = pt.y;
1482 DPtoLP(hdc, &pt2, 1);
1483 ReleaseDC(hWnd, hdc);
1485 double closest = 1.0e+99;
1487 for(int i=0; i<pts.GetNumPoints(); i++)
1489 double dist = ((pt2.x - pts.GetX(i)) * (pt2.x - pts.GetX(i)))
1490 + ((pt2.y - pts.GetY(i)) * (pt2.y - pts.GetY(i)));
1493 closest = dist, ptHighlight = i;
1496 if (ptHighlight != oldPtHighlight)
1498 oldPtHighlight = ptHighlight;
1499 InvalidateRect(hWnd, NULL, TRUE);
1502 // What follows here looks like voodoo, but is really simple. What we do is
1503 // check to see if the mouse point has a perpendicular intersection with any of
1504 // the line segments. If it does, calculate the length of the perpendicular
1505 // and choose the smallest length. If there is no perpendicular, then choose the
1506 // length of line connecting the closer of either the first endpoint or the
1507 // second and choose the smallest of those.
1509 // There is one bit of math that looks like voodoo to me ATM--will explain once
1510 // I understand it better (the calculation of the length of the perpendicular).
1512 if (pts.GetNumPoints() > 1 && currentTool == TOOLAddPt)
1514 double smallest = 1.0e+99;
1516 for(int i=0; i<pts.GetNumPoints(); i++)
1518 int32 p1x = pts.GetX(i), p1y = pts.GetY(i),
1519 p2x = pts.GetX(pts.GetNext(i)), p2y = pts.GetY(pts.GetNext(i));
1521 vector ls(p2x, p2y, 0, p1x, p1y, 0), v1(pt2.x, pt2.y, 0, p1x, p1y, 0),
1522 v2(pt2.x, pt2.y, 0, p2x, p2y, 0);
1523 double pp = ls.dot(v1) / ls.length(), dist;
1524 // Geometric interpretation:
1525 // pp is the paremeterized point on the vector ls where the perpendicular intersects ls.
1526 // If pp < 0, then the perpendicular lies beyond the 1st endpoint. If pp > length of ls,
1527 // then the perpendicular lies beyond the 2nd endpoint.
1531 else if (pp > ls.length())
1533 else // distance = ?Det?(ls, v1) / |ls|
1534 dist = abs((ls.x * v1.y - v1.x * ls.y) / ls.length());
1536 //The answer to the above looks like it might be found here:
1538 //If the segment endpoints are s and e, and the point is p, then the test for the perpendicular
1539 //intercepting the segment is equivalent to insisting that the two dot products {s-e}.{s-p} and
1540 //{e-s}.{e-p} are both non-negative. Perpendicular distance from the point to the segment is
1541 //computed by first computing the area of the triangle the three points form, then dividing by the
1542 //length of the segment. Distances are done just by the Pythagorean theorem. Twice the area of the
1543 //triangle formed by three points is the determinant of the following matrix:
1549 //(???) By translating the start point to the origin, this can be rewritten as:
1550 //By subtracting row 1 from all rows, you get the following:
1553 //(ex - sx) (ey - sy) 0
1554 //(px - sx) (py - sy) 0
1556 //which greatly simplifies the calculation of the determinant.
1558 if (dist < smallest)
1559 smallest = dist, ptNextHighlight = pts.GetNext(i), ptHighlight = i;
1562 if (ptNextHighlight != oldPtNextHighlight)
1564 oldPtNextHighlight = ptNextHighlight;
1565 InvalidateRect(hWnd, NULL, TRUE);
1571 ptPrevious.x = pt.x, ptPrevious.y = pt.y;
1577 if (((NMHDR *)lParam)->code == TTN_NEEDTEXT)
1579 LoadString(hInst, ((TOOLTIPTEXT *)lParam)->hdr.idFrom + 0x80, toolTipTxt, 16);
1580 ((TOOLTIPTEXT *)lParam)->lpszText = toolTipTxt;
1587 statusBarTxt[0] = 0; // Clear status bar text
1588 uint16 flags = wParam >> 16; // Extract flags
1590 if (!(flags & MFT_SEPARATOR))
1592 uint16 id = wParam & 0xFFFF;
1594 if (flags & MF_POPUP)
1596 if (flags & MF_SYSMENU)
1599 id = IDM_FILEMENU + wParam;
1602 LoadString(hInst, id, statusBarTxt, 64);
1605 SendMessage(hStatusBar, SB_SETTEXT, 0 + SBT_NOBORDERS, (LPARAM)statusBarTxt);
1610 uint16 cmd = wParam & 0xFFFF;
1616 else if (cmd == IDM_OPEN)
1620 // movmov ofn.hwndOwner, eax, hMainWnd
1621 // mov ofn.Flags, OFN_PATHMUSTEXIST + OFN_FILEMUSTEXIST
1622 // invoke GetOpenFileName, ADDR ofn
1626 //szDMsg1a BYTE "Could not open the file (GetOpenFileName)...", 0
1627 //szDMsg1b BYTE "Open error!", 0
1628 //szDMsg1c BYTE "About to attempt to open file...", 0
1630 ////invoke MessageBox, hWnd, ADDR szDMsg1a, ADDR szDMsg1b, MB_ICONERROR or MB_OK
1631 //invoke MessageBox, hMainWnd, ADDR szDMsg1c, ADDR szFile, MB_ICONERROR or MB_OK
1632 // invoke LoadTTF, ADDR szFile
1635 // // <<< FILE OPEN CODE HERE >>>
1636 // or fFileStatus, NAMEDbit
1637 // and fFileStatus, NOT CHANGEDbit
1638 // call NewWindowName
1639 // mov eax, TRUE // return TRUE
1641 // //��������������������������������������
1642 //OpenError: invoke GetLastError
1643 // // <<< FILE OPEN ERROR CODE HERE >>>
1645 // zero eax // return FALSE
1648 else if (cmd == IDM_SAVEAS)
1650 // and fFileStatus, NOT NAMEDbit
1653 else if (cmd == IDM_SAVE)
1657 else if (cmd == IDM_ABOUT)
1658 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_ABOUT), hMainWnd, AboutProc, NULL);
1659 else if (cmd == IDM_EXIT)
1660 SendMessage(hWnd, WM_CLOSE, 0, 0);
1661 else if (cmd == ID_TBCHARWIN)
1663 ShowWindow(hCharWnd, (IsWindowVisible(hCharWnd) ? SW_HIDE : SW_SHOWNOACTIVATE));
1666 wpC.length = sizeof(WINDOWPLACEMENT);
1667 GetWindowPlacement(hCharWnd, &wpC);
1668 wsprintf(strBuf, "Char window showCmd = %08X...\n", wpC.showCmd);
1669 WriteLogMsg(strBuf);
1673 return DefWindowProc(hWnd, msgID, wParam, lParam);
1678 return DefWindowProc(hWnd, msgID, wParam, lParam);
1685 // Initialize TTF data
1687 void CreateNewDoc(void)
1692 // Save changes to document before quitting
1694 bool SaveChanges(void)
1702 // ABOUT Dialog WndProc
1704 BOOL CALLBACK AboutProc(HWND hDlg, UINT msgID, WPARAM wParam, LPARAM lParam)
1710 MiscCenterWnd(hDlg, hMainWnd);
1715 if (wParam == IDOK || wParam == IDCANCEL)
1716 EndDialog(hDlg, TRUE);
1728 // Character Window WndProc
1730 WndProcCW PROC STDCALL, hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
1732 mov eax, uMsg // pickup our message
1733 .IF (eax == WM_PAINT)
1734 mov eax, 0 // Non-sense... (placeholder!)
1735 // Scan conversion etc. goes here...
1736 .ELSEIF (eax == WM_LBUTTONDOWN)
1737 invoke SetCapture, hCharWnd
1738 .ELSEIF (eax == WM_LBUTTONUP)
1739 invoke ReleaseCapture
1740 invoke SetFocus, hMainWnd // Make sure the main wnd keeps focus!
1741 .ELSEIF (eax == WM_NCLBUTTONDOWN)
1742 invoke DefWindowProc, hWnd, uMsg, wParam, lParam // Let it do its thing
1743 invoke SetFocus, hMainWnd // Make sure the main wnd keeps focus!
1745 DefProc: invoke DefWindowProc, hWnd, uMsg, wParam, lParam
1752 // Character Window WndProc
1754 LRESULT CALLBACK WndProcCW(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
1759 return DefWindowProc(hWnd, msgID, wParam, lParam);
1766 // Function prototypes
1768 int32 FindSelectedTool(void);
1771 // Tool Palette WndProc
1773 LRESULT CALLBACK WndProcTP(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
1778 static uint32 prevTool = -1;
1784 hdc = BeginPaint(hWnd, &ps);
1785 HDC newDC = CreateCompatibleDC(NULL);
1786 SelectObject(newDC, hBMToolPal1);
1787 BitBlt(hdc, 0, 0, sizeTPBM.x, sizeTPBM.y, newDC, 0, 0, SRCCOPY);
1790 // This is crappy. Find some way to tighten this up!
1791 int32 tool = FindSelectedTool();
1795 newDC = CreateCompatibleDC(NULL);
1796 SelectObject(newDC, hBMToolPal1);
1797 //need ul corner of bitmap, ul corner of dest, width/height
1798 pt.x = sizeStamp.x * (tool & 0x03), pt.y = sizeStamp.y * (tool >> 2);
1799 BitBlt(hdc, pt.x, pt.y, sizeStamp.x, sizeStamp.y, newDC, pt.x, pt.y, NOTSRCCOPY);
1803 EndPaint(hWnd, &ps);
1808 int32 tool = FindSelectedTool();
1810 if (tool != prevTool)
1813 InvalidateRect(hWnd, NULL, FALSE);
1820 int32 tool = FindSelectedTool(), oldTool = currentTool;
1825 if (currentTool != TOOLSelect && currentTool != TOOLDelPt && currentTool != TOOLAddPt
1826 && currentTool != TOOLPolySelect)
1829 if (currentTool != oldTool)
1830 InvalidateRect(hMainWnd, NULL, TRUE);
1832 if (currentTool == TOOLAddPoly)
1836 polyFirstPoint = true;
1838 wsprintf(strBuf, "--> Selected poly tool, polyFirstPoint is %s\n", polyFirstPoint ? "true" : "false");
1839 WriteLogMsg(strBuf);
1844 ShowWindow(hToolPalWnd, SW_HIDE);
1845 SetFocus(hMainWnd); // Make sure the main wnd keeps focus!
1850 return DefWindowProc(hWnd, msgID, wParam, lParam);
1857 // Find which tool we're pointing at
1858 // Use: xcoord = mouse.x / (bmsize.x/4), ycoord = mouse.y / (bmsize.y/2)
1860 int32 FindSelectedTool(void)
1865 ScreenToClient(hToolPalWnd, &pt);
1867 uint32 x = (uint32)pt.x / sizeStamp.x, y = (uint32)pt.y / sizeStamp.y, tool = -1;
1874 // tool = -1; // 7 has no tool...
1882 // Misc center window
1884 void MiscCenterWnd(HWND hChild, HWND hParent)
1888 if (!GetWindowRect(hParent, &parent) || !GetWindowRect(hChild, &child))
1891 int32 x = parent.left + (((parent.right - parent.left) - (child.right - child.left)) / 2),
1892 y = parent.top + (((parent.bottom - parent.top) - (child.bottom - child.top)) / 2);
1896 else if (x > GetSystemMetrics(SM_CXFULLSCREEN) - (child.right - child.left))
1897 x = GetSystemMetrics(SM_CXFULLSCREEN) - (child.right - child.left);
1901 else if (y > GetSystemMetrics(SM_CYFULLSCREEN) - (child.bottom - child.top))
1902 y = GetSystemMetrics(SM_CYFULLSCREEN) - (child.bottom - child.top);
1904 SetWindowPos(hChild, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
1908 // Allow only one instance
1910 bool OnlyOneInstance(void)
1912 HWND window = FindWindow(className, NULL);
1917 ShowWindow(window, SW_SHOWNORMAL);
1918 SetWindowPos(window, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1924 // Load/Allocate all resources
1926 bool LoadResources(void)
1928 hCur[0] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR1));
1929 hCur[1] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR2));
1930 hCur[2] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR3));
1931 hCur[3] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR4));
1932 hCur[4] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR5));
1933 hCur[5] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR6));
1934 hCur[6] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR7));
1935 hCur[7] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR8));
1939 hBMToolPal1 = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_TOOLPAL1));
1940 GetObject(hBMToolPal1, sizeof(bm), &bm);
1944 sizeTPBM.x = bm.bmWidth, sizeTPBM.y = bm.bmHeight;
1945 sizeStamp.x = bm.bmWidth / 4, sizeStamp.y = bm.bmHeight / 2;
1947 hBluePen1 = CreatePen(PS_DOT, 1, 0x00FF0000);
1948 hRedPen1 = CreatePen(PS_SOLID, 1, 0x000000FF);
1949 hGreenPen1 = CreatePen(PS_SOLID, 1, 0x0000AF00);
1950 hBlackPen1 = CreatePen(PS_SOLID, 1, 0x00000000);
1952 LOGBRUSH lb = { BS_NULL, 0, 0 };
1954 hNullBrush = CreateBrushIndirect(&lb);
1960 // Deallocate all resources
1962 void DeallocateResources(void)
1964 DeleteObject(hBMToolPal1);
1965 DeleteObject(hBluePen1);
1966 DeleteObject(hRedPen1);
1967 DeleteObject(hGreenPen1);
1968 DeleteObject(hBlackPen1);
1969 DeleteObject(hNullBrush);
1973 // Save all application specific data, so we can pick up where we last left off...
1975 void SaveAppState(void)
1977 SetINIInt("Main", "flags", wpM.flags);
1978 SetINIInt("Main", "showCmd", wpM.showCmd);
1979 SetINIInt("Main", "x1", wpM.rcNormalPosition.left);
1980 SetINIInt("Main", "y1", wpM.rcNormalPosition.top);
1981 SetINIInt("Main", "x2", wpM.rcNormalPosition.right);
1982 SetINIInt("Main", "y2", wpM.rcNormalPosition.bottom);
1984 SetINIInt("Main", "vpx", ptVPM.x);
1985 SetINIInt("Main", "vpy", ptVPM.y);
1987 SetINIInt("Char", "flags", wpC.flags);
1988 SetINIInt("Char", "showCmd", wpC.showCmd);
1989 SetINIInt("Char", "x1", wpC.rcNormalPosition.left);
1990 SetINIInt("Char", "y1", wpC.rcNormalPosition.top);
1991 SetINIInt("Char", "x2", wpC.rcNormalPosition.right);
1992 SetINIInt("Char", "y2", wpC.rcNormalPosition.bottom);
1994 // Need to write out currently opened font, character looking at, other misc. crap
1995 // SetINIString("Main", "currentFile", pDoc->GetPathName());
1996 // SetINIInt("Main", "currentChar", pDoc->character_num);
2000 // Restore all application specific data previously saved
2002 bool RestoreAppState(void)
2007 wp.length = sizeof(WINDOWPLACEMENT);
2008 GetWindowPlacement(hMainWnd, &wp);
2010 wp.flags = GetINIInt("Main", "flags", wp.flags);
2011 wp.showCmd = GetINIInt("Main", "showCmd", wp.showCmd);
2012 wp.rcNormalPosition.left = GetINIInt("Main", "x1", wp.rcNormalPosition.left);
2013 wp.rcNormalPosition.top = GetINIInt("Main", "y1", wp.rcNormalPosition.top);
2014 wp.rcNormalPosition.right = GetINIInt("Main", "x2", wp.rcNormalPosition.right);
2015 wp.rcNormalPosition.bottom = GetINIInt("Main", "y2", wp.rcNormalPosition.bottom);
2017 SetWindowPlacement(hMainWnd, &wp);
2021 hdc = GetDC(hMainWnd);
2022 GetViewportOrgEx(hdc, &pt);
2024 pt.x = GetINIInt("Main", "vpx", pt.x);
2025 pt.y = GetINIInt("Main", "vpy", pt.y);
2027 SetViewportOrgEx(hdc, pt.x, pt.y, NULL);
2028 ReleaseDC(hMainWnd, hdc);
2030 GetWindowPlacement(hCharWnd, &wp);
2032 wp.flags = GetINIInt("Char", "flags", wp.flags);
2033 wp.showCmd = GetINIInt("Char", "showCmd", wp.showCmd);
2034 wp.rcNormalPosition.left = GetINIInt("Char", "x1", wp.rcNormalPosition.left);
2035 wp.rcNormalPosition.top = GetINIInt("Char", "y1", wp.rcNormalPosition.top);
2036 wp.rcNormalPosition.right = GetINIInt("Char", "x2", wp.rcNormalPosition.right);
2037 wp.rcNormalPosition.bottom = GetINIInt("Char", "y2", wp.rcNormalPosition.bottom);
2039 SetWindowPlacement(hCharWnd, &wp);
2041 if (wp.showCmd == SW_HIDE)
2042 SendMessage(hToolBar, TB_SETSTATE, ID_TBCHARWIN, MAKELONG(TBSTATE_ENABLED, 0));
2044 // CString lastFile = theApplicationObject.GetProfileString(version, "currentFile", "");
2045 // int lastChar = theApplicationObject.GetProfileInt(version, "currentChar", 0);
2046 // if (lastFile.GetLength())
2048 // // Attempt to restore the last session by open the last file used, etc...
2049 // if (!pDoc->m_myFont.Load(lastFile))
2051 // // Err, make sure you can support any allegations you make below, buddy!
2052 // AfxMessageBox("The last file opened with TTF Edit\n\rseems to have been moved or deleted.");
2056 // pDoc->m_myFont.SetGlyph(lastChar); // Set TTF object to last used char
2057 // pDoc->character_num = lastChar;
2058 // pDoc->SetPathName(lastFile);
2061 // pDoc->m_myFont.GetCharName(lastChar, name);
2062 // m_wndOwned.SetWindowText((char *)name);
2072 bool Initialization(void)
2076 if (!LoadResources())
2079 RtlFillMemory(&wcex, sizeof(WNDCLASSEX), 0);
2080 wcex.cbSize = sizeof(WNDCLASSEX);
2081 wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
2082 wcex.lpfnWndProc = WndProc;
2083 wcex.hInstance = hInst;
2084 wcex.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON));
2085 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
2086 wcex.lpszMenuName = MAKEINTRESOURCE(IDM_MENU);
2087 wcex.lpszClassName = className;
2088 wcex.hIconSm = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 16, 16, NULL);
2090 if (!RegisterClassEx(&wcex))
2093 hMainWnd = CreateWindowEx(NULL, className, className, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
2094 0, 0, 0x1A0, 0x180, NULL, NULL, hInst, NULL);
2099 ShowWindow(hMainWnd, nCmdShow);
2100 UpdateWindow(hMainWnd);
2102 // Character window creation
2104 wcex.lpfnWndProc = WndProcCW;
2105 wcex.lpszMenuName = NULL;
2106 wcex.lpszClassName = CNCharWin;
2107 wcex.hCursor = LoadCursor(NULL, IDC_ARROW); // Owned windows have "regular" cursors
2109 if (!RegisterClassEx(&wcex))
2112 hCharWnd = CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW, CNCharWin,
2113 curCharName, WS_POPUP | WS_CAPTION | WS_VISIBLE | WS_THICKFRAME,
2114 100, 100, 120, 120, hMainWnd, NULL, hInst, NULL);
2119 ShowWindow(hCharWnd, SW_SHOWNORMAL);
2120 UpdateWindow(hCharWnd);
2121 SetFocus(hMainWnd); // Make sure main wnd has focus!
2123 // Tool palette window creation
2125 wcex.lpfnWndProc = WndProcTP;
2126 wcex.lpszClassName = CNToolPal;
2128 if (!RegisterClassEx(&wcex))
2131 hToolPalWnd = CreateWindowEx(WS_EX_WINDOWEDGE, CNToolPal, NULL, WS_POPUP,
2132 0, 0, sizeTPBM.x, sizeTPBM.y, hMainWnd, NULL, hInst, NULL);
2137 // Note: A better way to handle this would be to have a sub that registers ALL
2138 // classes beforehand and passes a TRUE/FALSE back depending on whether or not
2139 // all the classes were able to be registered or not, THEN create the windows
2142 RestoreAppState(); // Restore app related stuff