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
20 // - Fix bug in Glyphpoints when dragging on an empty canvas or loading a font
21 // - Fix zooming, settings (ini)
22 // - Fix point adding bug 1: should be able to add points to empty canvas
23 // - Fix point adding bug 2: should be able to add point successfully to single
25 // - Add poly multi-select
26 // - Add point multi-select
29 // Uncomment this for debugging...
31 #define DEBUGFOO // Various tool debugging...
32 #define DEBUGTP // Toolpalette debugging...
34 #include "editwindow.h"
35 #include "graphicprimitives.h"
36 #include "toolwindow.h"
41 BEGIN_EVENT_TABLE(TTEditWindow, wxWindow)
42 EVT_PAINT(TTEditWindow::OnPaint)
43 EVT_MOUSE_EVENTS(TTEditWindow::OnMouseEvent)
46 TTEditWindow::TTEditWindow(wxFrame * parent, const wxPoint &pos, const wxSize &size, long style):
47 wxWindow(parent, -1, pos, size, style | wxFULL_REPAINT_ON_RESIZE),
48 app(wxGetApp()), scale(1.0), offsetX(-10), offsetY(-10), tool(TOOLSelect),
49 ptHighlight(-1), oldPtHighlight(-1), ptNextHighlight(-1), oldPtNextHighlight(-1),
50 polyFirstPoint(true), bmp(NULL)
52 SetCursor(*(app.cur[tool]));
53 SetBackgroundColour(wxColour(0xFF, 0xFF, 0xFF));
56 s.Printf(_("Zoom: %.2f%%"), scale * 100.0);
57 parent->SetStatusText(s, 1);
60 TTEditWindow::~TTEditWindow(void)
66 void TTEditWindow::OnPaint(wxPaintEvent &e)
70 //dc.SetBackground(*wxWHITE_BRUSH);
72 // Due to the screwiness of wxWidgets coord system, the origin is ALWAYS
73 // the upper left corner--regardless of axis orientation, etc...
74 wxCoord width, height;
75 dc.GetSize(&width, &height);
77 dc.SetDeviceOrigin(-offsetX, height - (-offsetY));
78 dc.SetAxisOrientation(true, true);
80 // Scrolling can be done by using OffsetViewportOrgEx
81 // Scaling can be done by adjusting SetWindowExtEx (it's denominator of txform)
82 // you'd use: % = ViewportExt / WindowExt
83 // But it makes the window look like crap: fuggetuboutit.
84 // Instead, we have to scale EVERYTHING by hand. Crap!
85 // It's not *that* bad, but not as convenient either...
87 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0xFF), 1, wxDOT)));
88 // dc.DrawLine(0, 0, 10, 10);
90 // Draw coordinate axes
96 for(int i=0; i<pts.GetNumPoints(); i++)
100 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));
101 // SelectObject(hdc, hRedPen1);
103 if (pts.GetOnCurve(i))
105 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 7);
106 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 9);
110 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 7);
111 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 9);
114 else if ((i == ptHighlight || i == ptNextHighlight) && tool == TOOLAddPt)
116 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0xAF, 0x00), 1, wxSOLID)));
117 // SelectObject(hdc, hGreenPen1);
119 if (pts.GetOnCurve(i))
121 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 7);
122 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 9);
126 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 7);
127 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 9);
132 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));
133 // SelectObject(hdc, hBlackPen1);
135 if (pts.GetOnCurve(i))
136 DrawSquareDot(dc, pts.GetX(i), pts.GetY(i));
138 DrawRoundDot(dc, pts.GetX(i), pts.GetY(i));
141 if (tool == TOOLDelPt && i == ptHighlight)
143 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));
144 // SelectObject(hdc, hRedPen1);
145 // MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5, NULL);
146 // LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) + 5);
147 // LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5);//Lameness!
148 // MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5, NULL);
149 // LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) - 5);
150 // LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5);//More lameness!!
151 dc.DrawLine(pts.GetX(i) - 5, pts.GetY(i) - 5, pts.GetX(i) + 5, pts.GetY(i) + 5);
152 dc.DrawLine(pts.GetX(i) + 5, pts.GetY(i) - 5, pts.GetX(i) - 5, pts.GetY(i) + 5);
156 // SelectObject(hdc, hBlackPen1);
157 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));
159 // Draw curve formed by points
161 for(int poly=0; poly<pts.GetNumPolys(); poly++)
163 if (pts.GetNumPoints(poly) > 2)
166 // If it's not on curve, then move to it, otherwise move to last point...
170 if (pts.GetOnCurve(poly, pts.GetNumPoints(poly) - 1))
171 x = (wxCoord)pts.GetX(poly, pts.GetNumPoints(poly) - 1), y = (wxCoord)pts.GetY(poly, pts.GetNumPoints(poly) - 1);
173 x = (wxCoord)pts.GetX(poly, 0), y = (wxCoord)pts.GetY(poly, 0);
175 for(int i=0; i<pts.GetNumPoints(poly); i++)
177 if (pts.GetOnCurve(poly, i))
178 // LineTo(hdc, pts.GetX(poly, i), pts.GetY(poly, i));
180 dc.DrawLine(x, y, pts.GetX(poly, i), pts.GetY(poly, i));
181 x = (wxCoord)pts.GetX(poly, i), y = (wxCoord)pts.GetY(poly, i);
185 uint32 prev = pts.GetPrev(poly, i), next = pts.GetNext(poly, i);
186 float px = pts.GetX(poly, prev), py = pts.GetY(poly, prev),
187 nx = pts.GetX(poly, next), ny = pts.GetY(poly, next);
189 if (!pts.GetOnCurve(poly, prev))
190 px = (px + pts.GetX(poly, i)) / 2.0f,
191 py = (py + pts.GetY(poly, i)) / 2.0f;
193 if (!pts.GetOnCurve(poly, next))
194 nx = (nx + pts.GetX(poly, i)) / 2.0f,
195 ny = (ny + pts.GetY(poly, i)) / 2.0f;
197 Bezier(dc, point(px, py), point(pts.GetX(poly, i), pts.GetY(poly, i)), point(nx, ny));
198 x = (wxCoord)nx, y = (wxCoord)ny;
200 if (pts.GetOnCurve(poly, next))
201 i++; // Following point is on curve, so move past it
207 // SelectObject(hdc, oldPen); // Restore the stuff we disrupted...
208 dc.SetPen(wxNullPen);
209 // SelectObject(hdc, oldBrush);
210 // EndPaint(hWnd, &ps);
213 void TTEditWindow::OnMouseEvent(wxMouseEvent &e)
216 //printf("!!! This window %s focus...!\n", (HasCapture() ? "has" : "doesn't have"));
220 // Handle tool palette (NOTE: tool palette deals with RightUp event.)
222 wxPoint pt = ClientToScreen(e.GetPosition());
223 app.toolPalette->Move(pt);
224 app.toolPalette->Show(true);
225 SetCursor(*wxSTANDARD_CURSOR);
226 app.toolPalette->SetCursor(*wxSTANDARD_CURSOR);
227 app.toolPalette->prevTool = TOOLSelect;
228 app.toolPalette->Refresh(false);
231 else if (e.RightUp())
233 ToolType newTool = app.toolPalette->FindSelectedTool();//, oldTool = tool;
235 // We only change the tool if a new one was actually selected. Otherwise, we do nothing.
236 if (newTool != TOOLNone)
240 if (tool == TOOLScroll || tool == TOOLZoom || tool == TOOLAddPoly
241 || tool == TOOLDelPoly)
244 if (tool == TOOLAddPoly)
245 polyFirstPoint = true;
249 app.toolPalette->Show(false);
250 SetCursor(*(app.cur[tool]));
252 else if (e.LeftDown())
254 if (tool == TOOLScroll || tool == TOOLZoom)
255 CaptureMouse(); // Make sure we capture the mouse when in scroll/zoom mode
256 else if (tool == TOOLAddPt) // "Add Point" tool
258 if (pts.GetNumPoints() > 0)
260 wxPoint pt = GetAdjustedMousePosition(e);
261 pts.InsertPoint(pts.GetNext(ptHighlight), pt.x, pt.y, (e.ShiftDown() | e.ControlDown() ? false : true));
262 ptHighlight = ptNextHighlight;
266 else if (tool == TOOLAddPoly) // "Add Poly" tool
269 WriteLogMsg("Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts.GetNumPoints());
273 polyFirstPoint = false;
274 pts.AddNewPolyAtEnd();
277 wxPoint pt = GetAdjustedMousePosition(e);
278 // Append a point to the end of the structure
279 pts += IPoint(pt.x, pt.y, (e.ShiftDown() | e.ControlDown() ? false : true));
280 ptHighlight = pts.GetNumPoints() - 1;
283 WriteLogMsg(" --> [# polys: %u, # points: %u]\n", pts.GetNumPolys(), pts.GetNumPoints());
286 else if (tool == TOOLSelect || tool == TOOLPolySelect)
288 if (pts.GetNumPoints() > 0)
290 pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight));
291 WarpPointer(pt.x, pt.y);
293 if (e.ShiftDown() | e.ControlDown())
294 pts.SetOnCurve(ptHighlight, !pts.GetOnCurve(ptHighlight));
297 else if (tool == TOOLDelPt)
299 if (pts.GetNumPoints() > 0)
301 // if (ptHighlight != -1)
303 //This assumes that WM_MOUSEMOVE happens before this!
304 //The above commented out line should take care of this contingency... !!! FIX !!!
305 pts.DeletePoint(ptHighlight);
312 if (tool == TOOLScroll || tool == TOOLZoom)
315 else if (e.MiddleDown())
317 SetCursor(*(app.cur[2])); // Scrolling cursor
319 else if (e.MiddleUp())
321 SetCursor(*(app.cur[tool])); // Restore previous cursor
323 else if (e.Dragging())
327 ToolType newTool = app.toolPalette->FindSelectedTool();
329 if (newTool != app.toolPalette->prevTool)
331 app.toolPalette->prevTool = newTool;
332 app.toolPalette->Refresh(false);
337 else if (e.MiddleIsDown())
339 // Calc offset from previous point
340 pt = e.GetPosition();
341 ptOffset.x = pt.x - ptPrevious.x,
342 ptOffset.y = pt.y - ptPrevious.y;
344 // Then multiply it by the scaling factor. Whee!
345 // This looks wacky because we're using screen coords for the offset...
346 // Otherwise, we would subtract both offsets!
347 offsetX -= ptOffset.x, offsetY += ptOffset.y;
354 else if (e.LeftIsDown())
357 if (tool == TOOLScroll)
359 // Extract current point from lParam/calc offset from previous point
361 pt = e.GetPosition();
362 ptOffset.x = pt.x - ptPrevious.x,
363 ptOffset.y = pt.y - ptPrevious.y;
365 // NOTE: OffsetViewportOrg operates in DEVICE UNITS...
367 //Seems there's no equivalent for this in wxWidgets...!
369 // hdc = GetDC(hWnd);
370 // OffsetViewportOrgEx(hdc, ptOffset.x, ptOffset.y, NULL);
371 // ReleaseDC(hWnd, hdc);
373 // this shows that it works, so the logic above must be faulty...
374 // And it is. It should convert the coords first, then do the subtraction to figure the offset...
376 // Then multiply it by the scaling factor. Whee!
377 // This looks wacky because we're using screen coords for the offset...
378 // Otherwise, we would subtract both offsets!
379 offsetX -= ptOffset.x, offsetY += ptOffset.y;
384 if (tool == TOOLAddPt || tool == TOOLAddPoly || tool == TOOLSelect)
386 if (tool != TOOLAddPt || pts.GetNumPoints() > 0)//yecch.
388 //temporary, for testing. BTW, Select drag bug is here...!
390 wxPoint pt2 = GetAdjustedMousePosition(e);
391 pts.SetXY(ptHighlight, pt2.x, pt2.y);
396 else if (tool == TOOLPolySelect)
398 if (pts.GetNumPoints() > 0)
400 wxPoint pt2 = GetAdjustedMousePosition(e);
401 // Should also set onCurve here as well, depending on keystate
403 pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x - pts.GetX(ptHighlight), pt2.y - pts.GetY(ptHighlight));
413 // else // Moving, not dragging...
415 if (tool == TOOLSelect || tool == TOOLDelPt || tool == TOOLAddPt
416 || tool == TOOLPolySelect)// || tool == TOOLAddPoly)
418 wxPoint pt2 = GetAdjustedMousePosition(e);
419 double closest = 1.0e+99;
421 for(int i=0; i<pts.GetNumPoints(); i++)
423 double dist = ((pt2.x - pts.GetX(i)) * (pt2.x - pts.GetX(i)))
424 + ((pt2.y - pts.GetY(i)) * (pt2.y - pts.GetY(i)));
427 closest = dist, ptHighlight = i;
430 if (ptHighlight != oldPtHighlight)
432 oldPtHighlight = ptHighlight;
436 // What follows here looks like voodoo, but is really simple. What we do is
437 // check to see if the mouse point has a perpendicular intersection with any of
438 // the line segments. If it does, calculate the length of the perpendicular
439 // and choose the smallest length. If there is no perpendicular, then choose the
440 // length of line connecting the closer of either the first endpoint or the
441 // second and choose the smallest of those.
443 // There is one bit of math that looks like voodoo to me ATM--will explain once
444 // I understand it better (the calculation of the length of the perpendicular).
446 if (pts.GetNumPoints() > 1 && tool == TOOLAddPt)
448 double smallest = 1.0e+99;
450 for(int i=0; i<pts.GetNumPoints(); i++)
452 int32 p1x = pts.GetX(i), p1y = pts.GetY(i),
453 p2x = pts.GetX(pts.GetNext(i)), p2y = pts.GetY(pts.GetNext(i));
455 vector ls(p2x, p2y, 0, p1x, p1y, 0), v1(pt2.x, pt2.y, 0, p1x, p1y, 0),
456 v2(pt2.x, pt2.y, 0, p2x, p2y, 0);
457 double pp = ls.dot(v1) / ls.length(), dist;
458 // Geometric interpretation:
459 // pp is the paremeterized point on the vector ls where the perpendicular intersects ls.
460 // If pp < 0, then the perpendicular lies beyond the 1st endpoint. If pp > length of ls,
461 // then the perpendicular lies beyond the 2nd endpoint.
465 else if (pp > ls.length())
467 else // distance = ?Det?(ls, v1) / |ls|
468 dist = fabs((ls.x * v1.y - v1.x * ls.y) / ls.length());
470 //The answer to the above looks like it might be found here:
472 //If the segment endpoints are s and e, and the point is p, then the test for the perpendicular
473 //intercepting the segment is equivalent to insisting that the two dot products {s-e}.{s-p} and
474 //{e-s}.{e-p} are both non-negative. Perpendicular distance from the point to the segment is
475 //computed by first computing the area of the triangle the three points form, then dividing by the
476 //length of the segment. Distances are done just by the Pythagorean theorem. Twice the area of the
477 //triangle formed by three points is the determinant of the following matrix:
483 //(???) By translating the start point to the origin, this can be rewritten as:
484 //By subtracting row 1 from all rows, you get the following:
487 //(ex - sx) (ey - sy) 0
488 //(px - sx) (py - sy) 0
490 //which greatly simplifies the calculation of the determinant.
493 smallest = dist, ptNextHighlight = pts.GetNext(i), ptHighlight = i;
496 if (ptNextHighlight != oldPtNextHighlight)
498 oldPtNextHighlight = ptNextHighlight;
505 ptPrevious = e.GetPosition();
509 wxPoint TTEditWindow::GetAdjustedMousePosition(wxMouseEvent &e)
511 wxCoord width, height;
514 dc.GetSize(&width, &height);
515 dc.SetDeviceOrigin(-offsetX, height - (-offsetY));
516 dc.SetAxisOrientation(true, true);
519 wxStatusBar * sb = ((wxFrame *)GetParent())->GetStatusBar();
521 s.Printf("Logical mouse pos: %d, %d (%d, %d)", pt.x, pt.y, width, height);
522 sb->SetStatusText(s);
525 return e.GetLogicalPosition(dc);
528 wxPoint TTEditWindow::GetAdjustedClientPosition(wxCoord x, wxCoord y)
530 wxCoord width, height;
533 dc.GetSize(&width, &height);
534 dc.SetDeviceOrigin(-offsetX, height - (-offsetY));
535 dc.SetAxisOrientation(true, true);
537 return wxPoint(dc.LogicalToDeviceX(x), dc.LogicalToDeviceY(y));
546 LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
558 MiscCenterWnd(hWnd, GetDesktopWindow());
559 InitCommonControls();
560 hStatusBar = CreateStatusWindow(WS_CHILD | WS_VISIBLE, statusBarTxt, hWnd, ID_STATUSBAR);
565 // clean this crap up!
566 // well, the only crappy thing here is using a POINT as an int array, but otherwise, this is OK
567 wsprintf(strBuf, zoom, 1000);
569 GetTextExtentPoint32(hdc, strBuf, lstrlen(strBuf), &sz);
570 ReleaseDC(hWnd, hdc);
571 zoomWndWidth = sz.cx;
572 wsprintf(strBuf, zoom, 100);
574 GetClientRect(hWnd, &rc1);
575 pt.x = rc1.right - zoomWndWidth, pt.y = -1;
576 SendMessage(hStatusBar, SB_SETPARTS, 2, (LPARAM)&pt);
577 SendMessage(hStatusBar, SB_SETTEXT, (0 | SBT_NOBORDERS), (LPARAM)statusBarTxt);
578 SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM)strBuf);
580 hToolBar = CreateToolbarEx(hWnd, WS_CHILD | WS_BORDER | WS_VISIBLE | TBSTYLE_TOOLTIPS,
581 IDR_TOOLBAR1, 3, hInst, IDB_TOOLBAR1, tbButtons, 4, 16, 16, 16, 16, sizeof(TBBUTTON));
588 // The following can only be done because we use a private DC (using "CS_OWNDC")
590 // Set the mapping to draw the character so it fits in the viewport...
592 GetClientRect(hWnd, &rc1);
593 GetClientRect(hStatusBar, &rc2);
594 rc1.bottom -= rc2.bottom;
595 SetMapMode(hdc, MM_ISOTROPIC);
596 SetWindowExtEx(hdc, rc1.right, rc1.bottom, NULL);
597 SetViewportExtEx(hdc, rc1.right, -rc1.bottom, NULL);
598 SetViewportOrgEx(hdc, 0, rc1.bottom, NULL);
599 ReleaseDC(hWnd, hdc);
606 wpM.length = wpC.length = sizeof(WINDOWPLACEMENT);
607 GetWindowPlacement(hMainWnd, &wpM);
608 GetWindowPlacement(hCharWnd, &wpC);
610 if (!IsWindowVisible(hCharWnd)) // Needed because Windows lies about visibility
611 wpC.showCmd = SW_HIDE;
614 GetViewportOrgEx(hdc, &ptVPM);
615 ReleaseDC(hWnd, hdc);
627 case WM_NCLBUTTONDOWN:
629 if (wParam == HTCAPTION)
632 GetWindowRect(hMainWnd, &rc1);
633 GetWindowRect(hCharWnd, &rc2);
634 ptWinOffset.x = rc2.left - rc1.left;
635 ptWinOffset.y = rc2.top - rc1.top;
638 // Let Windows do its thing with this msg, or weird things will happen...
640 DefWindowProc(hWnd, msgID, wParam, lParam);
644 case WM_WINDOWPOSCHANGING:
648 WINDOWPOS * wp = (WINDOWPOS *)lParam;
650 if (wp->hwnd == hMainWnd && !(wp->flags & SWP_NOMOVE))
651 SetWindowPos(hCharWnd, 0, wp->x + ptWinOffset.x, wp->y + ptWinOffset.y,
652 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
655 return DefWindowProc(hWnd, msgID, wParam, lParam); // Seems this is needed... Bleah!
659 hdc = BeginPaint(hWnd, &ps);
661 // Scrolling can be done by using OffsetViewportOrgEx
662 // Scaling can be done by adjusting SetWindowExtEx (it's denominator of txform)
663 // you'd use: % = ViewportExt / WindowExt
664 // But it makes the window look like crap: fuggetuboutit.
665 // Instead, we have to scale EVERYTHING by hand. Crap!
667 // Apparently, you *must* save the individual object types (pen, brush, etc.)
669 HGDIOBJ oldPen = SelectObject(hdc, hBluePen1),
670 oldBrush = SelectObject(hdc, hNullBrush);
672 // Draw coordinate axes
674 MoveToEx(hdc, 0, -32000, NULL);
675 LineTo(hdc, 0, 32000);
676 MoveToEx(hdc, -32000, 0, NULL);
677 LineTo(hdc, 32000, 0);
681 for(int i=0; i<pts.GetNumPoints(); i++)
683 if (i == ptHighlight)
685 SelectObject(hdc, hRedPen1);
687 if (pts.GetOnCurve(i))
689 DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 7);
690 DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 9);
694 DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 7);
695 DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 9);
698 else if ((i == ptHighlight || i == ptNextHighlight) && currentTool == TOOLAddPt)
700 SelectObject(hdc, hGreenPen1);
702 if (pts.GetOnCurve(i))
704 DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 7);
705 DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 9);
709 DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 7);
710 DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 9);
715 SelectObject(hdc, hBlackPen1);
717 if (pts.GetOnCurve(i))
718 DrawSquareDot(hdc, pts.GetX(i), pts.GetY(i));
720 DrawRoundDot(hdc, pts.GetX(i), pts.GetY(i));
723 if (currentTool == TOOLDelPt && i == ptHighlight)
725 SelectObject(hdc, hRedPen1);
726 MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5, NULL);
727 LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) + 5);
728 LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5);//Lameness!
729 MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5, NULL);
730 LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) - 5);
731 LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5);//More lameness!!
735 SelectObject(hdc, hBlackPen1);
737 // Draw curve formed by points
739 for(int poly=0; poly<pts.GetNumPolys(); poly++)
741 if (pts.GetNumPoints(poly) > 2)
744 // If it's not on curve, then move to it, otherwise move to last point...
746 if (pts.GetOnCurve(poly, pts.GetNumPoints(poly) - 1))
747 MoveToEx(hdc, pts.GetX(poly, pts.GetNumPoints(poly) - 1), pts.GetY(poly, pts.GetNumPoints(poly) - 1), NULL);
749 MoveToEx(hdc, pts.GetX(poly, 0), pts.GetY(poly, 0), NULL);
751 for(int i=0; i<pts.GetNumPoints(poly); i++)
753 if (pts.GetOnCurve(poly, i))
754 LineTo(hdc, pts.GetX(poly, i), pts.GetY(poly, i));
757 uint32 prev = pts.GetPrev(poly, i), next = pts.GetNext(poly, i);
758 float px = pts.GetX(poly, prev), py = pts.GetY(poly, prev),
759 nx = pts.GetX(poly, next), ny = pts.GetY(poly, next);
761 if (!pts.GetOnCurve(poly, prev))
762 px = (px + pts.GetX(poly, i)) / 2.0f,
763 py = (py + pts.GetY(poly, i)) / 2.0f;
765 if (!pts.GetOnCurve(poly, next))
766 nx = (nx + pts.GetX(poly, i)) / 2.0f,
767 ny = (ny + pts.GetY(poly, i)) / 2.0f;
769 Bezier(hdc, point(px, py), point(pts.GetX(poly, i), pts.GetY(poly, i)), point(nx, ny));
771 if (pts.GetOnCurve(poly, next))
772 i++; // Following point is on curve, so move past it
778 SelectObject(hdc, oldPen); // Restore the stuff we disrupted...
779 SelectObject(hdc, oldBrush);
785 // Apparently this is needed since these windows don't update themselves.
786 SendMessage(hStatusBar, msgID, wParam, lParam);
787 SendMessage(hToolBar, msgID, wParam, lParam);
789 // This is needed to make the 2nd status pane visible
790 GetClientRect(hWnd, &rc1);
791 pt.x = rc1.right - zoomWndWidth, pt.y = -1;
792 SendMessage(hStatusBar, SB_SETPARTS, 2, (LPARAM)&pt);
798 SetWindowPos(hToolPalWnd, 0, pt.x, pt.y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
799 SetFocus(hToolPalWnd);
800 SetCapture(hToolPalWnd); // Ensure tool palette gets RButtonUp
801 SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW))); // Tool pallete has "regular" cursor
808 if (currentTool == TOOLScroll || currentTool == TOOLZoom)
809 SetCapture(hWnd); // Make sure we capture the mouse when in scroll/zoom mode
810 else if (currentTool == TOOLAddPt) // "Add Point" tool
812 if (pts.GetNumPoints() > 0)
814 //Do we really need to put a cap on this???
816 // if (pts.GetNumPoints() < 16)
818 pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;
821 pts.InsertPoint(pts.GetNext(ptHighlight), pt.x, pt.y, (wParam & (MK_SHIFT | MK_CONTROL) ? false : true));
822 ptHighlight = ptNextHighlight;
823 ReleaseDC(hWnd, hdc);
824 InvalidateRect(hWnd, NULL, TRUE);
828 else if (currentTool == TOOLAddPoly) // "Add Poly" tool
831 wsprintf(strBuf, "Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts.GetNumPoints());
836 polyFirstPoint = false;
837 pts.AddNewPolyAtEnd();
840 //Do we really need to put a cap on this???
842 // if (pts.GetNumPoints() < 16)
844 pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;
847 ReleaseDC(hWnd, hdc);
848 // Append a point to the end of the structure
849 pts += IPoint(pt.x, pt.y, (wParam & (MK_SHIFT | MK_CONTROL) ? false : true));
850 ptHighlight = pts.GetNumPoints() - 1;
851 InvalidateRect(hWnd, NULL, TRUE);
854 wsprintf(strBuf, " --> [# polys: %u, # points: %u]\xD\xA", pts.GetNumPolys(), pts.GetNumPoints());
858 else if (currentTool == TOOLSelect || currentTool == TOOLPolySelect)
860 if (pts.GetNumPoints() > 0)
862 pt.x = pts.GetX(ptHighlight), pt.y = pts.GetY(ptHighlight);
865 ClientToScreen(hWnd, &pt);
866 SetCursorPos(pt.x, pt.y);
867 ReleaseDC(hWnd, hdc);
869 if (wParam & (MK_SHIFT | MK_CONTROL))
870 pts.SetOnCurve(ptHighlight, !pts.GetOnCurve(ptHighlight));
873 else if (currentTool == TOOLDelPt)
875 if (pts.GetNumPoints() > 0)
877 // if (ptHighlight != -1)
879 //This assumes that WM_MOUSEMOVE happens before this!
880 //The above commented out line should take care of this contingency... !!! FIX !!!
881 pts.DeletePoint(ptHighlight);
882 InvalidateRect(hWnd, NULL, TRUE);
892 if (currentTool == TOOLScroll || currentTool == TOOLZoom)
899 SetCursor(hCur[currentTool]);
901 // Extract current point from lParam/calc offset from previous point
903 pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;
904 ptOffset.x = pt.x - ptPrevious.x,
905 ptOffset.y = pt.y - ptPrevious.y;
909 if (currentTool == TOOLScroll)
911 // NOTE: OffsetViewportOrg operates in DEVICE UNITS...
914 OffsetViewportOrgEx(hdc, ptOffset.x, ptOffset.y, NULL);
915 ReleaseDC(hWnd, hdc);
917 // this shows that it works, so the logic above must be faulty...
918 // And it is. It should convert the coords first, then do the subtraction to figure the offset...
920 // Then multiply it by the scaling factor. Whee!
922 InvalidateRect(hWnd, NULL, TRUE);
923 // SendMessage(hWnd, WM_PAINT, NULL, NULL);
925 else if (currentTool == TOOLAddPt || currentTool == TOOLAddPoly || currentTool == TOOLSelect)
927 if (currentTool != TOOLAddPt || pts.GetNumPoints() > 0)//yecch.
930 pt2.x = pt.x, pt2.y = pt.y;
931 // Should also set onCurve here as well, depending on keystate
934 DPtoLP(hdc, &pt2, 1);
935 pts.SetXY(ptHighlight, pt2.x, pt2.y);
936 ReleaseDC(hWnd, hdc);
937 InvalidateRect(hWnd, NULL, TRUE);
940 else if (currentTool == TOOLPolySelect)
942 if (pts.GetNumPoints() > 0)
945 pt2.x = pt.x, pt2.y = pt.y;
946 // Should also set onCurve here as well, depending on keystate
949 DPtoLP(hdc, &pt2, 1);
950 pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x - pts.GetX(ptHighlight), pt2.y - pts.GetY(ptHighlight));
951 ReleaseDC(hWnd, hdc);
952 InvalidateRect(hWnd, NULL, TRUE);
958 if (currentTool == TOOLSelect || currentTool == TOOLDelPt || currentTool == TOOLAddPt
959 || currentTool == TOOLPolySelect)// || currentTool == TOOLAddPoly)
962 pt2.x = pt.x, pt2.y = pt.y;
964 DPtoLP(hdc, &pt2, 1);
965 ReleaseDC(hWnd, hdc);
967 double closest = 1.0e+99;
969 for(int i=0; i<pts.GetNumPoints(); i++)
971 double dist = ((pt2.x - pts.GetX(i)) * (pt2.x - pts.GetX(i)))
972 + ((pt2.y - pts.GetY(i)) * (pt2.y - pts.GetY(i)));
975 closest = dist, ptHighlight = i;
978 if (ptHighlight != oldPtHighlight)
980 oldPtHighlight = ptHighlight;
981 InvalidateRect(hWnd, NULL, TRUE);
984 // What follows here looks like voodoo, but is really simple. What we do is
985 // check to see if the mouse point has a perpendicular intersection with any of
986 // the line segments. If it does, calculate the length of the perpendicular
987 // and choose the smallest length. If there is no perpendicular, then choose the
988 // length of line connecting the closer of either the first endpoint or the
989 // second and choose the smallest of those.
991 // There is one bit of math that looks like voodoo to me ATM--will explain once
992 // I understand it better (the calculation of the length of the perpendicular).
994 if (pts.GetNumPoints() > 1 && currentTool == TOOLAddPt)
996 double smallest = 1.0e+99;
998 for(int i=0; i<pts.GetNumPoints(); i++)
1000 int32 p1x = pts.GetX(i), p1y = pts.GetY(i),
1001 p2x = pts.GetX(pts.GetNext(i)), p2y = pts.GetY(pts.GetNext(i));
1003 vector ls(p2x, p2y, 0, p1x, p1y, 0), v1(pt2.x, pt2.y, 0, p1x, p1y, 0),
1004 v2(pt2.x, pt2.y, 0, p2x, p2y, 0);
1005 double pp = ls.dot(v1) / ls.length(), dist;
1006 // Geometric interpretation:
1007 // pp is the paremeterized point on the vector ls where the perpendicular intersects ls.
1008 // If pp < 0, then the perpendicular lies beyond the 1st endpoint. If pp > length of ls,
1009 // then the perpendicular lies beyond the 2nd endpoint.
1013 else if (pp > ls.length())
1015 else // distance = ?Det?(ls, v1) / |ls|
1016 dist = abs((ls.x * v1.y - v1.x * ls.y) / ls.length());
1018 //The answer to the above looks like it might be found here:
1020 //If the segment endpoints are s and e, and the point is p, then the test for the perpendicular
1021 //intercepting the segment is equivalent to insisting that the two dot products {s-e}.{s-p} and
1022 //{e-s}.{e-p} are both non-negative. Perpendicular distance from the point to the segment is
1023 //computed by first computing the area of the triangle the three points form, then dividing by the
1024 //length of the segment. Distances are done just by the Pythagorean theorem. Twice the area of the
1025 //triangle formed by three points is the determinant of the following matrix:
1031 //(???) By translating the start point to the origin, this can be rewritten as:
1032 //By subtracting row 1 from all rows, you get the following:
1035 //(ex - sx) (ey - sy) 0
1036 //(px - sx) (py - sy) 0
1038 //which greatly simplifies the calculation of the determinant.
1040 if (dist < smallest)
1041 smallest = dist, ptNextHighlight = pts.GetNext(i), ptHighlight = i;
1044 if (ptNextHighlight != oldPtNextHighlight)
1046 oldPtNextHighlight = ptNextHighlight;
1047 InvalidateRect(hWnd, NULL, TRUE);
1053 ptPrevious.x = pt.x, ptPrevious.y = pt.y;
1059 if (((NMHDR *)lParam)->code == TTN_NEEDTEXT)
1061 LoadString(hInst, ((TOOLTIPTEXT *)lParam)->hdr.idFrom + 0x80, toolTipTxt, 16);
1062 ((TOOLTIPTEXT *)lParam)->lpszText = toolTipTxt;
1069 statusBarTxt[0] = 0; // Clear status bar text
1070 uint16 flags = wParam >> 16; // Extract flags
1072 if (!(flags & MFT_SEPARATOR))
1074 uint16 id = wParam & 0xFFFF;
1076 if (flags & MF_POPUP)
1078 if (flags & MF_SYSMENU)
1081 id = IDM_FILEMENU + wParam;
1084 LoadString(hInst, id, statusBarTxt, 64);
1087 SendMessage(hStatusBar, SB_SETTEXT, 0 + SBT_NOBORDERS, (LPARAM)statusBarTxt);
1092 uint16 cmd = wParam & 0xFFFF;
1098 else if (cmd == IDM_OPEN)
1102 // movmov ofn.hwndOwner, eax, hMainWnd
1103 // mov ofn.Flags, OFN_PATHMUSTEXIST + OFN_FILEMUSTEXIST
1104 // invoke GetOpenFileName, ADDR ofn
1108 //szDMsg1a BYTE "Could not open the file (GetOpenFileName)...", 0
1109 //szDMsg1b BYTE "Open error!", 0
1110 //szDMsg1c BYTE "About to attempt to open file...", 0
1112 ////invoke MessageBox, hWnd, ADDR szDMsg1a, ADDR szDMsg1b, MB_ICONERROR or MB_OK
1113 //invoke MessageBox, hMainWnd, ADDR szDMsg1c, ADDR szFile, MB_ICONERROR or MB_OK
1114 // invoke LoadTTF, ADDR szFile
1117 // // <<< FILE OPEN CODE HERE >>>
1118 // or fFileStatus, NAMEDbit
1119 // and fFileStatus, NOT CHANGEDbit
1120 // call NewWindowName
1121 // mov eax, TRUE // return TRUE
1123 // //��������������������������������������
1124 //OpenError: invoke GetLastError
1125 // // <<< FILE OPEN ERROR CODE HERE >>>
1127 // zero eax // return FALSE
1130 else if (cmd == IDM_SAVEAS)
1132 // and fFileStatus, NOT NAMEDbit
1135 else if (cmd == IDM_SAVE)
1139 else if (cmd == IDM_ABOUT)
1140 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_ABOUT), hMainWnd, AboutProc, NULL);
1141 else if (cmd == IDM_EXIT)
1142 SendMessage(hWnd, WM_CLOSE, 0, 0);
1143 else if (cmd == ID_TBCHARWIN)
1145 ShowWindow(hCharWnd, (IsWindowVisible(hCharWnd) ? SW_HIDE : SW_SHOWNOACTIVATE));
1148 wpC.length = sizeof(WINDOWPLACEMENT);
1149 GetWindowPlacement(hCharWnd, &wpC);
1150 wsprintf(strBuf, "Char window showCmd = %08X...\n", wpC.showCmd);
1151 WriteLogMsg(strBuf);
1155 return DefWindowProc(hWnd, msgID, wParam, lParam);
1160 return DefWindowProc(hWnd, msgID, wParam, lParam);
1167 // Initialize TTF data
1169 void CreateNewDoc(void)
1174 // Save changes to document before quitting
1176 bool SaveChanges(void)
1184 // ABOUT Dialog WndProc
1186 BOOL CALLBACK AboutProc(HWND hDlg, UINT msgID, WPARAM wParam, LPARAM lParam)
1192 MiscCenterWnd(hDlg, hMainWnd);
1197 if (wParam == IDOK || wParam == IDCANCEL)
1198 EndDialog(hDlg, TRUE);
1210 // Character Window WndProc
1212 WndProcCW PROC STDCALL, hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
1214 mov eax, uMsg // pickup our message
1215 .IF (eax == WM_PAINT)
1216 mov eax, 0 // Non-sense... (placeholder!)
1217 // Scan conversion etc. goes here...
1218 .ELSEIF (eax == WM_LBUTTONDOWN)
1219 invoke SetCapture, hCharWnd
1220 .ELSEIF (eax == WM_LBUTTONUP)
1221 invoke ReleaseCapture
1222 invoke SetFocus, hMainWnd // Make sure the main wnd keeps focus!
1223 .ELSEIF (eax == WM_NCLBUTTONDOWN)
1224 invoke DefWindowProc, hWnd, uMsg, wParam, lParam // Let it do its thing
1225 invoke SetFocus, hMainWnd // Make sure the main wnd keeps focus!
1227 DefProc: invoke DefWindowProc, hWnd, uMsg, wParam, lParam
1234 // Character Window WndProc
1236 LRESULT CALLBACK WndProcCW(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
1241 return DefWindowProc(hWnd, msgID, wParam, lParam);
1248 // Function prototypes
1250 int32 FindSelectedTool(void);
1253 // Tool Palette WndProc
1255 LRESULT CALLBACK WndProcTP(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
1260 static uint32 prevTool = -1;
1266 hdc = BeginPaint(hWnd, &ps);
1267 HDC newDC = CreateCompatibleDC(NULL);
1268 SelectObject(newDC, hBMToolPal1);
1269 BitBlt(hdc, 0, 0, sizeTPBM.x, sizeTPBM.y, newDC, 0, 0, SRCCOPY);
1272 // This is crappy. Find some way to tighten this up!
1273 int32 tool = FindSelectedTool();
1277 newDC = CreateCompatibleDC(NULL);
1278 SelectObject(newDC, hBMToolPal1);
1279 //need ul corner of bitmap, ul corner of dest, width/height
1280 pt.x = sizeStamp.x * (tool & 0x03), pt.y = sizeStamp.y * (tool >> 2);
1281 BitBlt(hdc, pt.x, pt.y, sizeStamp.x, sizeStamp.y, newDC, pt.x, pt.y, NOTSRCCOPY);
1285 EndPaint(hWnd, &ps);
1290 int32 tool = FindSelectedTool();
1292 if (tool != prevTool)
1295 InvalidateRect(hWnd, NULL, FALSE);
1302 int32 tool = FindSelectedTool(), oldTool = currentTool;
1307 if (currentTool != TOOLSelect && currentTool != TOOLDelPt && currentTool != TOOLAddPt
1308 && currentTool != TOOLPolySelect)
1311 if (currentTool != oldTool)
1312 InvalidateRect(hMainWnd, NULL, TRUE);
1314 if (currentTool == TOOLAddPoly)
1318 polyFirstPoint = true;
1320 wsprintf(strBuf, "--> Selected poly tool, polyFirstPoint is %s\n", polyFirstPoint ? "true" : "false");
1321 WriteLogMsg(strBuf);
1326 ShowWindow(hToolPalWnd, SW_HIDE);
1327 SetFocus(hMainWnd); // Make sure the main wnd keeps focus!
1332 return DefWindowProc(hWnd, msgID, wParam, lParam);
1339 // Find which tool we're pointing at
1340 // Use: xcoord = mouse.x / (bmsize.x/4), ycoord = mouse.y / (bmsize.y/2)
1342 int32 FindSelectedTool(void)
1347 ScreenToClient(hToolPalWnd, &pt);
1349 uint32 x = (uint32)pt.x / sizeStamp.x, y = (uint32)pt.y / sizeStamp.y, tool = -1;
1356 // tool = -1; // 7 has no tool...
1364 // Misc center window
1366 void MiscCenterWnd(HWND hChild, HWND hParent)
1370 if (!GetWindowRect(hParent, &parent) || !GetWindowRect(hChild, &child))
1373 int32 x = parent.left + (((parent.right - parent.left) - (child.right - child.left)) / 2),
1374 y = parent.top + (((parent.bottom - parent.top) - (child.bottom - child.top)) / 2);
1378 else if (x > GetSystemMetrics(SM_CXFULLSCREEN) - (child.right - child.left))
1379 x = GetSystemMetrics(SM_CXFULLSCREEN) - (child.right - child.left);
1383 else if (y > GetSystemMetrics(SM_CYFULLSCREEN) - (child.bottom - child.top))
1384 y = GetSystemMetrics(SM_CYFULLSCREEN) - (child.bottom - child.top);
1386 SetWindowPos(hChild, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
1390 // Allow only one instance
1392 bool OnlyOneInstance(void)
1394 HWND window = FindWindow(className, NULL);
1399 ShowWindow(window, SW_SHOWNORMAL);
1400 SetWindowPos(window, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1406 // Load/Allocate all resources
1408 bool LoadResources(void)
1410 hCur[0] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR1));
1411 hCur[1] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR2));
1412 hCur[2] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR3));
1413 hCur[3] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR4));
1414 hCur[4] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR5));
1415 hCur[5] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR6));
1416 hCur[6] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR7));
1417 hCur[7] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR8));
1421 hBMToolPal1 = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_TOOLPAL1));
1422 GetObject(hBMToolPal1, sizeof(bm), &bm);
1426 sizeTPBM.x = bm.bmWidth, sizeTPBM.y = bm.bmHeight;
1427 sizeStamp.x = bm.bmWidth / 4, sizeStamp.y = bm.bmHeight / 2;
1429 hBluePen1 = CreatePen(PS_DOT, 1, 0x00FF0000);
1430 hRedPen1 = CreatePen(PS_SOLID, 1, 0x000000FF);
1431 hGreenPen1 = CreatePen(PS_SOLID, 1, 0x0000AF00);
1432 hBlackPen1 = CreatePen(PS_SOLID, 1, 0x00000000);
1434 LOGBRUSH lb = { BS_NULL, 0, 0 };
1436 hNullBrush = CreateBrushIndirect(&lb);
1442 // Deallocate all resources
1444 void DeallocateResources(void)
1446 DeleteObject(hBMToolPal1);
1447 DeleteObject(hBluePen1);
1448 DeleteObject(hRedPen1);
1449 DeleteObject(hGreenPen1);
1450 DeleteObject(hBlackPen1);
1451 DeleteObject(hNullBrush);
1455 // Save all application specific data, so we can pick up where we last left off...
1457 void SaveAppState(void)
1459 SetINIInt("Main", "flags", wpM.flags);
1460 SetINIInt("Main", "showCmd", wpM.showCmd);
1461 SetINIInt("Main", "x1", wpM.rcNormalPosition.left);
1462 SetINIInt("Main", "y1", wpM.rcNormalPosition.top);
1463 SetINIInt("Main", "x2", wpM.rcNormalPosition.right);
1464 SetINIInt("Main", "y2", wpM.rcNormalPosition.bottom);
1466 SetINIInt("Main", "vpx", ptVPM.x);
1467 SetINIInt("Main", "vpy", ptVPM.y);
1469 SetINIInt("Char", "flags", wpC.flags);
1470 SetINIInt("Char", "showCmd", wpC.showCmd);
1471 SetINIInt("Char", "x1", wpC.rcNormalPosition.left);
1472 SetINIInt("Char", "y1", wpC.rcNormalPosition.top);
1473 SetINIInt("Char", "x2", wpC.rcNormalPosition.right);
1474 SetINIInt("Char", "y2", wpC.rcNormalPosition.bottom);
1476 // Need to write out currently opened font, character looking at, other misc. crap
1477 // SetINIString("Main", "currentFile", pDoc->GetPathName());
1478 // SetINIInt("Main", "currentChar", pDoc->character_num);
1482 // Restore all application specific data previously saved
1484 bool RestoreAppState(void)
1489 wp.length = sizeof(WINDOWPLACEMENT);
1490 GetWindowPlacement(hMainWnd, &wp);
1492 wp.flags = GetINIInt("Main", "flags", wp.flags);
1493 wp.showCmd = GetINIInt("Main", "showCmd", wp.showCmd);
1494 wp.rcNormalPosition.left = GetINIInt("Main", "x1", wp.rcNormalPosition.left);
1495 wp.rcNormalPosition.top = GetINIInt("Main", "y1", wp.rcNormalPosition.top);
1496 wp.rcNormalPosition.right = GetINIInt("Main", "x2", wp.rcNormalPosition.right);
1497 wp.rcNormalPosition.bottom = GetINIInt("Main", "y2", wp.rcNormalPosition.bottom);
1499 SetWindowPlacement(hMainWnd, &wp);
1503 hdc = GetDC(hMainWnd);
1504 GetViewportOrgEx(hdc, &pt);
1506 pt.x = GetINIInt("Main", "vpx", pt.x);
1507 pt.y = GetINIInt("Main", "vpy", pt.y);
1509 SetViewportOrgEx(hdc, pt.x, pt.y, NULL);
1510 ReleaseDC(hMainWnd, hdc);
1512 GetWindowPlacement(hCharWnd, &wp);
1514 wp.flags = GetINIInt("Char", "flags", wp.flags);
1515 wp.showCmd = GetINIInt("Char", "showCmd", wp.showCmd);
1516 wp.rcNormalPosition.left = GetINIInt("Char", "x1", wp.rcNormalPosition.left);
1517 wp.rcNormalPosition.top = GetINIInt("Char", "y1", wp.rcNormalPosition.top);
1518 wp.rcNormalPosition.right = GetINIInt("Char", "x2", wp.rcNormalPosition.right);
1519 wp.rcNormalPosition.bottom = GetINIInt("Char", "y2", wp.rcNormalPosition.bottom);
1521 SetWindowPlacement(hCharWnd, &wp);
1523 if (wp.showCmd == SW_HIDE)
1524 SendMessage(hToolBar, TB_SETSTATE, ID_TBCHARWIN, MAKELONG(TBSTATE_ENABLED, 0));
1526 // CString lastFile = theApplicationObject.GetProfileString(version, "currentFile", "");
1527 // int lastChar = theApplicationObject.GetProfileInt(version, "currentChar", 0);
1528 // if (lastFile.GetLength())
1530 // // Attempt to restore the last session by open the last file used, etc...
1531 // if (!pDoc->m_myFont.Load(lastFile))
1533 // // Err, make sure you can support any allegations you make below, buddy!
1534 // AfxMessageBox("The last file opened with TTF Edit\n\rseems to have been moved or deleted.");
1538 // pDoc->m_myFont.SetGlyph(lastChar); // Set TTF object to last used char
1539 // pDoc->character_num = lastChar;
1540 // pDoc->SetPathName(lastFile);
1543 // pDoc->m_myFont.GetCharName(lastChar, name);
1544 // m_wndOwned.SetWindowText((char *)name);
1554 bool Initialization(void)
1558 if (!LoadResources())
1561 RtlFillMemory(&wcex, sizeof(WNDCLASSEX), 0);
1562 wcex.cbSize = sizeof(WNDCLASSEX);
1563 wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
1564 wcex.lpfnWndProc = WndProc;
1565 wcex.hInstance = hInst;
1566 wcex.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON));
1567 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1568 wcex.lpszMenuName = MAKEINTRESOURCE(IDM_MENU);
1569 wcex.lpszClassName = className;
1570 wcex.hIconSm = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 16, 16, NULL);
1572 if (!RegisterClassEx(&wcex))
1575 hMainWnd = CreateWindowEx(NULL, className, className, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
1576 0, 0, 0x1A0, 0x180, NULL, NULL, hInst, NULL);
1581 ShowWindow(hMainWnd, nCmdShow);
1582 UpdateWindow(hMainWnd);
1584 // Character window creation
1586 wcex.lpfnWndProc = WndProcCW;
1587 wcex.lpszMenuName = NULL;
1588 wcex.lpszClassName = CNCharWin;
1589 wcex.hCursor = LoadCursor(NULL, IDC_ARROW); // Owned windows have "regular" cursors
1591 if (!RegisterClassEx(&wcex))
1594 hCharWnd = CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW, CNCharWin,
1595 curCharName, WS_POPUP | WS_CAPTION | WS_VISIBLE | WS_THICKFRAME,
1596 100, 100, 120, 120, hMainWnd, NULL, hInst, NULL);
1601 ShowWindow(hCharWnd, SW_SHOWNORMAL);
1602 UpdateWindow(hCharWnd);
1603 SetFocus(hMainWnd); // Make sure main wnd has focus!
1605 // Tool palette window creation
1607 wcex.lpfnWndProc = WndProcTP;
1608 wcex.lpszClassName = CNToolPal;
1610 if (!RegisterClassEx(&wcex))
1613 hToolPalWnd = CreateWindowEx(WS_EX_WINDOWEDGE, CNToolPal, NULL, WS_POPUP,
1614 0, 0, sizeTPBM.x, sizeTPBM.y, hMainWnd, NULL, hInst, NULL);
1619 // Note: A better way to handle this would be to have a sub that registers ALL
1620 // classes beforehand and passes a TRUE/FALSE back depending on whether or not
1621 // all the classes were able to be registered or not, THEN create the windows
1624 RestoreAppState(); // Restore app related stuff