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
30 // Uncomment this for debugging...
32 #define DEBUGFOO // Various tool debugging...
33 #define DEBUGTP // Toolpalette debugging...
35 #include "editwindow.h"
36 #include "graphicprimitives.h"
37 #include "toolwindow.h"
42 BEGIN_EVENT_TABLE(TTEditWindow, wxWindow)
43 EVT_PAINT(TTEditWindow::OnPaint)
44 EVT_MOUSE_EVENTS(TTEditWindow::OnMouseEvent)
47 TTEditWindow::TTEditWindow(wxFrame * parent, const wxPoint &pos, const wxSize &size, long style):
48 wxWindow(parent, -1, pos, size, style | wxFULL_REPAINT_ON_RESIZE),
49 app(wxGetApp()), scale(1.0), offsetX(-10), offsetY(-10), tool(TOOLSelect),
50 ptHighlight(-1), oldPtHighlight(-1), ptNextHighlight(-1), oldPtNextHighlight(-1),
51 polyFirstPoint(true), bmp(NULL)
53 SetCursor(*(app.cur[tool]));
54 SetBackgroundColour(wxColour(0xFF, 0xFF, 0xFF));
57 s.Printf(_("Zoom: %.2f%%"), scale * 100.0);
58 parent->SetStatusText(s, 1);
61 TTEditWindow::~TTEditWindow(void)
67 void TTEditWindow::OnPaint(wxPaintEvent &e)
71 //dc.SetBackground(*wxWHITE_BRUSH);
73 // Due to the screwiness of wxWidgets coord system, the origin is ALWAYS
74 // the upper left corner--regardless of axis orientation, etc...
75 wxCoord width, height;
76 dc.GetSize(&width, &height);
78 dc.SetDeviceOrigin(-offsetX, height - (-offsetY));
79 dc.SetAxisOrientation(true, true);
81 // Scrolling can be done by using OffsetViewportOrgEx
82 // Scaling can be done by adjusting SetWindowExtEx (it's denominator of txform)
83 // you'd use: % = ViewportExt / WindowExt
84 // But it makes the window look like crap: fuggetuboutit.
85 // Instead, we have to scale EVERYTHING by hand. Crap!
86 // It's not *that* bad, but not as convenient either...
88 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0xFF), 1, wxDOT)));
89 // dc.DrawLine(0, 0, 10, 10);
91 // Draw coordinate axes
97 for(int i=0; i<pts.GetNumPoints(); i++)
101 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));
102 // SelectObject(hdc, hRedPen1);
104 if (pts.GetOnCurve(i))
106 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 7);
107 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 9);
111 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 7);
112 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 9);
115 else if ((i == ptHighlight || i == ptNextHighlight) && tool == TOOLAddPt)
117 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0xAF, 0x00), 1, wxSOLID)));
118 // SelectObject(hdc, hGreenPen1);
120 if (pts.GetOnCurve(i))
122 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 7);
123 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 9);
127 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 7);
128 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 9);
133 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));
134 // SelectObject(hdc, hBlackPen1);
136 if (pts.GetOnCurve(i))
137 DrawSquareDot(dc, pts.GetX(i), pts.GetY(i));
139 DrawRoundDot(dc, pts.GetX(i), pts.GetY(i));
142 if (tool == TOOLDelPt && i == ptHighlight)
144 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));
145 // SelectObject(hdc, hRedPen1);
146 // MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5, NULL);
147 // LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) + 5);
148 // LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5);//Lameness!
149 // MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5, NULL);
150 // LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) - 5);
151 // LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5);//More lameness!!
152 dc.DrawLine(pts.GetX(i) - 5, pts.GetY(i) - 5, pts.GetX(i) + 5, pts.GetY(i) + 5);
153 dc.DrawLine(pts.GetX(i) + 5, pts.GetY(i) - 5, pts.GetX(i) - 5, pts.GetY(i) + 5);
157 // SelectObject(hdc, hBlackPen1);
158 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));
160 // Draw curve formed by points
162 for(int poly=0; poly<pts.GetNumPolys(); poly++)
164 if (pts.GetNumPoints(poly) > 2)
167 // If it's not on curve, then move to it, otherwise move to last point...
171 if (pts.GetOnCurve(poly, pts.GetNumPoints(poly) - 1))
172 x = (wxCoord)pts.GetX(poly, pts.GetNumPoints(poly) - 1), y = (wxCoord)pts.GetY(poly, pts.GetNumPoints(poly) - 1);
174 x = (wxCoord)pts.GetX(poly, 0), y = (wxCoord)pts.GetY(poly, 0);
176 for(int i=0; i<pts.GetNumPoints(poly); i++)
178 if (pts.GetOnCurve(poly, i))
179 // LineTo(hdc, pts.GetX(poly, i), pts.GetY(poly, i));
181 dc.DrawLine(x, y, pts.GetX(poly, i), pts.GetY(poly, i));
182 x = (wxCoord)pts.GetX(poly, i), y = (wxCoord)pts.GetY(poly, i);
186 uint32 prev = pts.GetPrev(poly, i), next = pts.GetNext(poly, i);
187 float px = pts.GetX(poly, prev), py = pts.GetY(poly, prev),
188 nx = pts.GetX(poly, next), ny = pts.GetY(poly, next);
190 if (!pts.GetOnCurve(poly, prev))
191 px = (px + pts.GetX(poly, i)) / 2.0f,
192 py = (py + pts.GetY(poly, i)) / 2.0f;
194 if (!pts.GetOnCurve(poly, next))
195 nx = (nx + pts.GetX(poly, i)) / 2.0f,
196 ny = (ny + pts.GetY(poly, i)) / 2.0f;
198 Bezier(dc, point(px, py), point(pts.GetX(poly, i), pts.GetY(poly, i)), point(nx, ny));
199 x = (wxCoord)nx, y = (wxCoord)ny;
201 if (pts.GetOnCurve(poly, next))
202 i++; // Following point is on curve, so move past it
208 // SelectObject(hdc, oldPen); // Restore the stuff we disrupted...
209 dc.SetPen(wxNullPen);
210 // SelectObject(hdc, oldBrush);
211 // EndPaint(hWnd, &ps);
214 void TTEditWindow::OnMouseEvent(wxMouseEvent &e)
217 //printf("!!! This window %s focus...!\n", (HasCapture() ? "has" : "doesn't have"));
221 // Handle tool palette (NOTE: tool palette deals with RightUp event.)
223 wxPoint pt = ClientToScreen(e.GetPosition());
224 app.toolPalette->Move(pt);
225 app.toolPalette->Show(true);
226 SetCursor(*wxSTANDARD_CURSOR);
227 app.toolPalette->SetCursor(*wxSTANDARD_CURSOR);
228 app.toolPalette->prevTool = TOOLSelect;
229 app.toolPalette->Refresh(false);
232 else if (e.RightUp())
234 ToolType newTool = app.toolPalette->FindSelectedTool();//, oldTool = tool;
236 // We only change the tool if a new one was actually selected. Otherwise, we do nothing.
237 if (newTool != TOOLNone)
241 if (tool == TOOLScroll || tool == TOOLZoom || tool == TOOLAddPoly
242 || tool == TOOLDelPoly)
245 if (tool == TOOLAddPoly)
246 polyFirstPoint = true;
250 app.toolPalette->Show(false);
251 SetCursor(*(app.cur[tool]));
253 else if (e.LeftDown())
255 if (tool == TOOLScroll || tool == TOOLZoom)
256 CaptureMouse(); // Make sure we capture the mouse when in scroll/zoom mode
257 else if (tool == TOOLAddPt) // "Add Point" tool
259 if (pts.GetNumPoints() > 0)
261 wxPoint pt = GetAdjustedMousePosition(e);
262 pts.InsertPoint(pts.GetNext(ptHighlight), pt.x, pt.y, (e.ShiftDown() | e.ControlDown() ? false : true));
263 ptHighlight = ptNextHighlight;
267 else if (tool == TOOLAddPoly) // "Add Poly" tool
270 WriteLogMsg("Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts.GetNumPoints());
274 polyFirstPoint = false;
275 pts.AddNewPolyAtEnd();
278 wxPoint pt = GetAdjustedMousePosition(e);
279 // Append a point to the end of the structure
280 pts += IPoint(pt.x, pt.y, (e.ShiftDown() | e.ControlDown() ? false : true));
281 ptHighlight = pts.GetNumPoints() - 1;
284 WriteLogMsg(" --> [# polys: %u, # points: %u]\n", pts.GetNumPolys(), pts.GetNumPoints());
287 else if (tool == TOOLSelect || tool == TOOLPolySelect)
289 if (pts.GetNumPoints() > 0)
291 pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight));
292 WarpPointer(pt.x, pt.y);
294 if (e.ShiftDown() | e.ControlDown())
295 pts.SetOnCurve(ptHighlight, !pts.GetOnCurve(ptHighlight));
298 else if (tool == TOOLDelPt)
300 if (pts.GetNumPoints() > 0)
302 // if (ptHighlight != -1)
304 //This assumes that WM_MOUSEMOVE happens before this!
305 //The above commented out line should take care of this contingency... !!! FIX !!!
306 pts.DeletePoint(ptHighlight);
313 if (tool == TOOLScroll || tool == TOOLZoom)
316 else if (e.MiddleDown())
318 SetCursor(*(app.cur[2])); // Scrolling cursor
320 else if (e.MiddleUp())
322 SetCursor(*(app.cur[tool])); // Restore previous cursor
324 else if (e.Dragging())
328 ToolType newTool = app.toolPalette->FindSelectedTool();
330 if (newTool != app.toolPalette->prevTool)
332 app.toolPalette->prevTool = newTool;
333 app.toolPalette->Refresh(false);
338 else if (e.MiddleIsDown())
340 // Calc offset from previous point
341 pt = e.GetPosition();
342 ptOffset.x = pt.x - ptPrevious.x,
343 ptOffset.y = pt.y - ptPrevious.y;
345 // Then multiply it by the scaling factor. Whee!
346 // This looks wacky because we're using screen coords for the offset...
347 // Otherwise, we would subtract both offsets!
348 offsetX -= ptOffset.x, offsetY += ptOffset.y;
355 else if (e.LeftIsDown())
358 if (tool == TOOLScroll)
360 // Extract current point from lParam/calc offset from previous point
362 pt = e.GetPosition();
363 ptOffset.x = pt.x - ptPrevious.x,
364 ptOffset.y = pt.y - ptPrevious.y;
366 // NOTE: OffsetViewportOrg operates in DEVICE UNITS...
368 //Seems there's no equivalent for this in wxWidgets...!
370 // hdc = GetDC(hWnd);
371 // OffsetViewportOrgEx(hdc, ptOffset.x, ptOffset.y, NULL);
372 // ReleaseDC(hWnd, hdc);
374 // this shows that it works, so the logic above must be faulty...
375 // And it is. It should convert the coords first, then do the subtraction to figure the offset...
377 // Then multiply it by the scaling factor. Whee!
378 // This looks wacky because we're using screen coords for the offset...
379 // Otherwise, we would subtract both offsets!
380 offsetX -= ptOffset.x, offsetY += ptOffset.y;
385 if (tool == TOOLAddPt || tool == TOOLAddPoly || tool == TOOLSelect)
387 if (tool != TOOLAddPt || pts.GetNumPoints() > 0)//yecch.
389 //temporary, for testing. BTW, Select drag bug is here...!
391 wxPoint pt2 = GetAdjustedMousePosition(e);
392 pts.SetXY(ptHighlight, pt2.x, pt2.y);
397 else if (tool == TOOLPolySelect)
399 if (pts.GetNumPoints() > 0)
401 wxPoint pt2 = GetAdjustedMousePosition(e);
402 // Should also set onCurve here as well, depending on keystate
404 pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x - pts.GetX(ptHighlight), pt2.y - pts.GetY(ptHighlight));
414 // else // Moving, not dragging...
416 if (tool == TOOLSelect || tool == TOOLDelPt || tool == TOOLAddPt
417 || tool == TOOLPolySelect)// || tool == TOOLAddPoly)
419 wxPoint pt2 = GetAdjustedMousePosition(e);
420 double closest = 1.0e+99;
422 for(int i=0; i<pts.GetNumPoints(); i++)
424 double dist = ((pt2.x - pts.GetX(i)) * (pt2.x - pts.GetX(i)))
425 + ((pt2.y - pts.GetY(i)) * (pt2.y - pts.GetY(i)));
428 closest = dist, ptHighlight = i;
431 if (ptHighlight != oldPtHighlight)
433 oldPtHighlight = ptHighlight;
437 // What follows here looks like voodoo, but is really simple. What we do is
438 // check to see if the mouse point has a perpendicular intersection with any of
439 // the line segments. If it does, calculate the length of the perpendicular
440 // and choose the smallest length. If there is no perpendicular, then choose the
441 // length of line connecting the closer of either the first endpoint or the
442 // second and choose the smallest of those.
444 // There is one bit of math that looks like voodoo to me ATM--will explain once
445 // I understand it better (the calculation of the length of the perpendicular).
447 if (pts.GetNumPoints() > 1 && tool == TOOLAddPt)
449 double smallest = 1.0e+99;
451 for(int i=0; i<pts.GetNumPoints(); i++)
453 int32 p1x = pts.GetX(i), p1y = pts.GetY(i),
454 p2x = pts.GetX(pts.GetNext(i)), p2y = pts.GetY(pts.GetNext(i));
456 vector ls(p2x, p2y, 0, p1x, p1y, 0), v1(pt2.x, pt2.y, 0, p1x, p1y, 0),
457 v2(pt2.x, pt2.y, 0, p2x, p2y, 0);
458 double pp = ls.dot(v1) / ls.length(), dist;
459 // Geometric interpretation:
460 // pp is the paremeterized point on the vector ls where the perpendicular intersects ls.
461 // If pp < 0, then the perpendicular lies beyond the 1st endpoint. If pp > length of ls,
462 // then the perpendicular lies beyond the 2nd endpoint.
466 else if (pp > ls.length())
468 else // distance = ?Det?(ls, v1) / |ls|
469 dist = fabs((ls.x * v1.y - v1.x * ls.y) / ls.length());
471 //The answer to the above looks like it might be found here:
473 //If the segment endpoints are s and e, and the point is p, then the test for the perpendicular
474 //intercepting the segment is equivalent to insisting that the two dot products {s-e}.{s-p} and
475 //{e-s}.{e-p} are both non-negative. Perpendicular distance from the point to the segment is
476 //computed by first computing the area of the triangle the three points form, then dividing by the
477 //length of the segment. Distances are done just by the Pythagorean theorem. Twice the area of the
478 //triangle formed by three points is the determinant of the following matrix:
484 //(???) By translating the start point to the origin, this can be rewritten as:
485 //By subtracting row 1 from all rows, you get the following:
488 //(ex - sx) (ey - sy) 0
489 //(px - sx) (py - sy) 0
491 //which greatly simplifies the calculation of the determinant.
494 smallest = dist, ptNextHighlight = pts.GetNext(i), ptHighlight = i;
497 if (ptNextHighlight != oldPtNextHighlight)
499 oldPtNextHighlight = ptNextHighlight;
506 ptPrevious = e.GetPosition();
510 wxPoint TTEditWindow::GetAdjustedMousePosition(wxMouseEvent &e)
512 wxCoord width, height;
515 dc.GetSize(&width, &height);
516 dc.SetDeviceOrigin(-offsetX, height - (-offsetY));
517 dc.SetAxisOrientation(true, true);
520 wxStatusBar * sb = ((wxFrame *)GetParent())->GetStatusBar();
522 s.Printf("Logical mouse pos: %d, %d (%d, %d)", pt.x, pt.y, width, height);
523 sb->SetStatusText(s);
526 return e.GetLogicalPosition(dc);
529 wxPoint TTEditWindow::GetAdjustedClientPosition(wxCoord x, wxCoord y)
531 wxCoord width, height;
534 dc.GetSize(&width, &height);
535 dc.SetDeviceOrigin(-offsetX, height - (-offsetY));
536 dc.SetAxisOrientation(true, true);
538 return wxPoint(dc.LogicalToDeviceX(x), dc.LogicalToDeviceY(y));
547 LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
559 MiscCenterWnd(hWnd, GetDesktopWindow());
560 InitCommonControls();
561 hStatusBar = CreateStatusWindow(WS_CHILD | WS_VISIBLE, statusBarTxt, hWnd, ID_STATUSBAR);
566 // clean this crap up!
567 // well, the only crappy thing here is using a POINT as an int array, but otherwise, this is OK
568 wsprintf(strBuf, zoom, 1000);
570 GetTextExtentPoint32(hdc, strBuf, lstrlen(strBuf), &sz);
571 ReleaseDC(hWnd, hdc);
572 zoomWndWidth = sz.cx;
573 wsprintf(strBuf, zoom, 100);
575 GetClientRect(hWnd, &rc1);
576 pt.x = rc1.right - zoomWndWidth, pt.y = -1;
577 SendMessage(hStatusBar, SB_SETPARTS, 2, (LPARAM)&pt);
578 SendMessage(hStatusBar, SB_SETTEXT, (0 | SBT_NOBORDERS), (LPARAM)statusBarTxt);
579 SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM)strBuf);
581 hToolBar = CreateToolbarEx(hWnd, WS_CHILD | WS_BORDER | WS_VISIBLE | TBSTYLE_TOOLTIPS,
582 IDR_TOOLBAR1, 3, hInst, IDB_TOOLBAR1, tbButtons, 4, 16, 16, 16, 16, sizeof(TBBUTTON));
589 // The following can only be done because we use a private DC (using "CS_OWNDC")
591 // Set the mapping to draw the character so it fits in the viewport...
593 GetClientRect(hWnd, &rc1);
594 GetClientRect(hStatusBar, &rc2);
595 rc1.bottom -= rc2.bottom;
596 SetMapMode(hdc, MM_ISOTROPIC);
597 SetWindowExtEx(hdc, rc1.right, rc1.bottom, NULL);
598 SetViewportExtEx(hdc, rc1.right, -rc1.bottom, NULL);
599 SetViewportOrgEx(hdc, 0, rc1.bottom, NULL);
600 ReleaseDC(hWnd, hdc);
607 wpM.length = wpC.length = sizeof(WINDOWPLACEMENT);
608 GetWindowPlacement(hMainWnd, &wpM);
609 GetWindowPlacement(hCharWnd, &wpC);
611 if (!IsWindowVisible(hCharWnd)) // Needed because Windows lies about visibility
612 wpC.showCmd = SW_HIDE;
615 GetViewportOrgEx(hdc, &ptVPM);
616 ReleaseDC(hWnd, hdc);
628 case WM_NCLBUTTONDOWN:
630 if (wParam == HTCAPTION)
633 GetWindowRect(hMainWnd, &rc1);
634 GetWindowRect(hCharWnd, &rc2);
635 ptWinOffset.x = rc2.left - rc1.left;
636 ptWinOffset.y = rc2.top - rc1.top;
639 // Let Windows do its thing with this msg, or weird things will happen...
641 DefWindowProc(hWnd, msgID, wParam, lParam);
645 case WM_WINDOWPOSCHANGING:
649 WINDOWPOS * wp = (WINDOWPOS *)lParam;
651 if (wp->hwnd == hMainWnd && !(wp->flags & SWP_NOMOVE))
652 SetWindowPos(hCharWnd, 0, wp->x + ptWinOffset.x, wp->y + ptWinOffset.y,
653 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
656 return DefWindowProc(hWnd, msgID, wParam, lParam); // Seems this is needed... Bleah!
660 hdc = BeginPaint(hWnd, &ps);
662 // Scrolling can be done by using OffsetViewportOrgEx
663 // Scaling can be done by adjusting SetWindowExtEx (it's denominator of txform)
664 // you'd use: % = ViewportExt / WindowExt
665 // But it makes the window look like crap: fuggetuboutit.
666 // Instead, we have to scale EVERYTHING by hand. Crap!
668 // Apparently, you *must* save the individual object types (pen, brush, etc.)
670 HGDIOBJ oldPen = SelectObject(hdc, hBluePen1),
671 oldBrush = SelectObject(hdc, hNullBrush);
673 // Draw coordinate axes
675 MoveToEx(hdc, 0, -32000, NULL);
676 LineTo(hdc, 0, 32000);
677 MoveToEx(hdc, -32000, 0, NULL);
678 LineTo(hdc, 32000, 0);
682 for(int i=0; i<pts.GetNumPoints(); i++)
684 if (i == ptHighlight)
686 SelectObject(hdc, hRedPen1);
688 if (pts.GetOnCurve(i))
690 DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 7);
691 DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 9);
695 DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 7);
696 DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 9);
699 else if ((i == ptHighlight || i == ptNextHighlight) && currentTool == TOOLAddPt)
701 SelectObject(hdc, hGreenPen1);
703 if (pts.GetOnCurve(i))
705 DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 7);
706 DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 9);
710 DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 7);
711 DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 9);
716 SelectObject(hdc, hBlackPen1);
718 if (pts.GetOnCurve(i))
719 DrawSquareDot(hdc, pts.GetX(i), pts.GetY(i));
721 DrawRoundDot(hdc, pts.GetX(i), pts.GetY(i));
724 if (currentTool == TOOLDelPt && i == ptHighlight)
726 SelectObject(hdc, hRedPen1);
727 MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5, NULL);
728 LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) + 5);
729 LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5);//Lameness!
730 MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5, NULL);
731 LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) - 5);
732 LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5);//More lameness!!
736 SelectObject(hdc, hBlackPen1);
738 // Draw curve formed by points
740 for(int poly=0; poly<pts.GetNumPolys(); poly++)
742 if (pts.GetNumPoints(poly) > 2)
745 // If it's not on curve, then move to it, otherwise move to last point...
747 if (pts.GetOnCurve(poly, pts.GetNumPoints(poly) - 1))
748 MoveToEx(hdc, pts.GetX(poly, pts.GetNumPoints(poly) - 1), pts.GetY(poly, pts.GetNumPoints(poly) - 1), NULL);
750 MoveToEx(hdc, pts.GetX(poly, 0), pts.GetY(poly, 0), NULL);
752 for(int i=0; i<pts.GetNumPoints(poly); i++)
754 if (pts.GetOnCurve(poly, i))
755 LineTo(hdc, pts.GetX(poly, i), pts.GetY(poly, i));
758 uint32 prev = pts.GetPrev(poly, i), next = pts.GetNext(poly, i);
759 float px = pts.GetX(poly, prev), py = pts.GetY(poly, prev),
760 nx = pts.GetX(poly, next), ny = pts.GetY(poly, next);
762 if (!pts.GetOnCurve(poly, prev))
763 px = (px + pts.GetX(poly, i)) / 2.0f,
764 py = (py + pts.GetY(poly, i)) / 2.0f;
766 if (!pts.GetOnCurve(poly, next))
767 nx = (nx + pts.GetX(poly, i)) / 2.0f,
768 ny = (ny + pts.GetY(poly, i)) / 2.0f;
770 Bezier(hdc, point(px, py), point(pts.GetX(poly, i), pts.GetY(poly, i)), point(nx, ny));
772 if (pts.GetOnCurve(poly, next))
773 i++; // Following point is on curve, so move past it
779 SelectObject(hdc, oldPen); // Restore the stuff we disrupted...
780 SelectObject(hdc, oldBrush);
786 // Apparently this is needed since these windows don't update themselves.
787 SendMessage(hStatusBar, msgID, wParam, lParam);
788 SendMessage(hToolBar, msgID, wParam, lParam);
790 // This is needed to make the 2nd status pane visible
791 GetClientRect(hWnd, &rc1);
792 pt.x = rc1.right - zoomWndWidth, pt.y = -1;
793 SendMessage(hStatusBar, SB_SETPARTS, 2, (LPARAM)&pt);
799 SetWindowPos(hToolPalWnd, 0, pt.x, pt.y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
800 SetFocus(hToolPalWnd);
801 SetCapture(hToolPalWnd); // Ensure tool palette gets RButtonUp
802 SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW))); // Tool pallete has "regular" cursor
809 if (currentTool == TOOLScroll || currentTool == TOOLZoom)
810 SetCapture(hWnd); // Make sure we capture the mouse when in scroll/zoom mode
811 else if (currentTool == TOOLAddPt) // "Add Point" tool
813 if (pts.GetNumPoints() > 0)
815 //Do we really need to put a cap on this???
817 // if (pts.GetNumPoints() < 16)
819 pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;
822 pts.InsertPoint(pts.GetNext(ptHighlight), pt.x, pt.y, (wParam & (MK_SHIFT | MK_CONTROL) ? false : true));
823 ptHighlight = ptNextHighlight;
824 ReleaseDC(hWnd, hdc);
825 InvalidateRect(hWnd, NULL, TRUE);
829 else if (currentTool == TOOLAddPoly) // "Add Poly" tool
832 wsprintf(strBuf, "Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts.GetNumPoints());
837 polyFirstPoint = false;
838 pts.AddNewPolyAtEnd();
841 //Do we really need to put a cap on this???
843 // if (pts.GetNumPoints() < 16)
845 pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;
848 ReleaseDC(hWnd, hdc);
849 // Append a point to the end of the structure
850 pts += IPoint(pt.x, pt.y, (wParam & (MK_SHIFT | MK_CONTROL) ? false : true));
851 ptHighlight = pts.GetNumPoints() - 1;
852 InvalidateRect(hWnd, NULL, TRUE);
855 wsprintf(strBuf, " --> [# polys: %u, # points: %u]\xD\xA", pts.GetNumPolys(), pts.GetNumPoints());
859 else if (currentTool == TOOLSelect || currentTool == TOOLPolySelect)
861 if (pts.GetNumPoints() > 0)
863 pt.x = pts.GetX(ptHighlight), pt.y = pts.GetY(ptHighlight);
866 ClientToScreen(hWnd, &pt);
867 SetCursorPos(pt.x, pt.y);
868 ReleaseDC(hWnd, hdc);
870 if (wParam & (MK_SHIFT | MK_CONTROL))
871 pts.SetOnCurve(ptHighlight, !pts.GetOnCurve(ptHighlight));
874 else if (currentTool == TOOLDelPt)
876 if (pts.GetNumPoints() > 0)
878 // if (ptHighlight != -1)
880 //This assumes that WM_MOUSEMOVE happens before this!
881 //The above commented out line should take care of this contingency... !!! FIX !!!
882 pts.DeletePoint(ptHighlight);
883 InvalidateRect(hWnd, NULL, TRUE);
893 if (currentTool == TOOLScroll || currentTool == TOOLZoom)
900 SetCursor(hCur[currentTool]);
902 // Extract current point from lParam/calc offset from previous point
904 pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;
905 ptOffset.x = pt.x - ptPrevious.x,
906 ptOffset.y = pt.y - ptPrevious.y;
910 if (currentTool == TOOLScroll)
912 // NOTE: OffsetViewportOrg operates in DEVICE UNITS...
915 OffsetViewportOrgEx(hdc, ptOffset.x, ptOffset.y, NULL);
916 ReleaseDC(hWnd, hdc);
918 // this shows that it works, so the logic above must be faulty...
919 // And it is. It should convert the coords first, then do the subtraction to figure the offset...
921 // Then multiply it by the scaling factor. Whee!
923 InvalidateRect(hWnd, NULL, TRUE);
924 // SendMessage(hWnd, WM_PAINT, NULL, NULL);
926 else if (currentTool == TOOLAddPt || currentTool == TOOLAddPoly || currentTool == TOOLSelect)
928 if (currentTool != TOOLAddPt || pts.GetNumPoints() > 0)//yecch.
931 pt2.x = pt.x, pt2.y = pt.y;
932 // Should also set onCurve here as well, depending on keystate
935 DPtoLP(hdc, &pt2, 1);
936 pts.SetXY(ptHighlight, pt2.x, pt2.y);
937 ReleaseDC(hWnd, hdc);
938 InvalidateRect(hWnd, NULL, TRUE);
941 else if (currentTool == TOOLPolySelect)
943 if (pts.GetNumPoints() > 0)
946 pt2.x = pt.x, pt2.y = pt.y;
947 // Should also set onCurve here as well, depending on keystate
950 DPtoLP(hdc, &pt2, 1);
951 pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x - pts.GetX(ptHighlight), pt2.y - pts.GetY(ptHighlight));
952 ReleaseDC(hWnd, hdc);
953 InvalidateRect(hWnd, NULL, TRUE);
959 if (currentTool == TOOLSelect || currentTool == TOOLDelPt || currentTool == TOOLAddPt
960 || currentTool == TOOLPolySelect)// || currentTool == TOOLAddPoly)
963 pt2.x = pt.x, pt2.y = pt.y;
965 DPtoLP(hdc, &pt2, 1);
966 ReleaseDC(hWnd, hdc);
968 double closest = 1.0e+99;
970 for(int i=0; i<pts.GetNumPoints(); i++)
972 double dist = ((pt2.x - pts.GetX(i)) * (pt2.x - pts.GetX(i)))
973 + ((pt2.y - pts.GetY(i)) * (pt2.y - pts.GetY(i)));
976 closest = dist, ptHighlight = i;
979 if (ptHighlight != oldPtHighlight)
981 oldPtHighlight = ptHighlight;
982 InvalidateRect(hWnd, NULL, TRUE);
985 // What follows here looks like voodoo, but is really simple. What we do is
986 // check to see if the mouse point has a perpendicular intersection with any of
987 // the line segments. If it does, calculate the length of the perpendicular
988 // and choose the smallest length. If there is no perpendicular, then choose the
989 // length of line connecting the closer of either the first endpoint or the
990 // second and choose the smallest of those.
992 // There is one bit of math that looks like voodoo to me ATM--will explain once
993 // I understand it better (the calculation of the length of the perpendicular).
995 if (pts.GetNumPoints() > 1 && currentTool == TOOLAddPt)
997 double smallest = 1.0e+99;
999 for(int i=0; i<pts.GetNumPoints(); i++)
1001 int32 p1x = pts.GetX(i), p1y = pts.GetY(i),
1002 p2x = pts.GetX(pts.GetNext(i)), p2y = pts.GetY(pts.GetNext(i));
1004 vector ls(p2x, p2y, 0, p1x, p1y, 0), v1(pt2.x, pt2.y, 0, p1x, p1y, 0),
1005 v2(pt2.x, pt2.y, 0, p2x, p2y, 0);
1006 double pp = ls.dot(v1) / ls.length(), dist;
1007 // Geometric interpretation:
1008 // pp is the paremeterized point on the vector ls where the perpendicular intersects ls.
1009 // If pp < 0, then the perpendicular lies beyond the 1st endpoint. If pp > length of ls,
1010 // then the perpendicular lies beyond the 2nd endpoint.
1014 else if (pp > ls.length())
1016 else // distance = ?Det?(ls, v1) / |ls|
1017 dist = abs((ls.x * v1.y - v1.x * ls.y) / ls.length());
1019 //The answer to the above looks like it might be found here:
1021 //If the segment endpoints are s and e, and the point is p, then the test for the perpendicular
1022 //intercepting the segment is equivalent to insisting that the two dot products {s-e}.{s-p} and
1023 //{e-s}.{e-p} are both non-negative. Perpendicular distance from the point to the segment is
1024 //computed by first computing the area of the triangle the three points form, then dividing by the
1025 //length of the segment. Distances are done just by the Pythagorean theorem. Twice the area of the
1026 //triangle formed by three points is the determinant of the following matrix:
1032 //(???) By translating the start point to the origin, this can be rewritten as:
1033 //By subtracting row 1 from all rows, you get the following:
1036 //(ex - sx) (ey - sy) 0
1037 //(px - sx) (py - sy) 0
1039 //which greatly simplifies the calculation of the determinant.
1041 if (dist < smallest)
1042 smallest = dist, ptNextHighlight = pts.GetNext(i), ptHighlight = i;
1045 if (ptNextHighlight != oldPtNextHighlight)
1047 oldPtNextHighlight = ptNextHighlight;
1048 InvalidateRect(hWnd, NULL, TRUE);
1054 ptPrevious.x = pt.x, ptPrevious.y = pt.y;
1060 if (((NMHDR *)lParam)->code == TTN_NEEDTEXT)
1062 LoadString(hInst, ((TOOLTIPTEXT *)lParam)->hdr.idFrom + 0x80, toolTipTxt, 16);
1063 ((TOOLTIPTEXT *)lParam)->lpszText = toolTipTxt;
1070 statusBarTxt[0] = 0; // Clear status bar text
1071 uint16 flags = wParam >> 16; // Extract flags
1073 if (!(flags & MFT_SEPARATOR))
1075 uint16 id = wParam & 0xFFFF;
1077 if (flags & MF_POPUP)
1079 if (flags & MF_SYSMENU)
1082 id = IDM_FILEMENU + wParam;
1085 LoadString(hInst, id, statusBarTxt, 64);
1088 SendMessage(hStatusBar, SB_SETTEXT, 0 + SBT_NOBORDERS, (LPARAM)statusBarTxt);
1093 uint16 cmd = wParam & 0xFFFF;
1099 else if (cmd == IDM_OPEN)
1103 // movmov ofn.hwndOwner, eax, hMainWnd
1104 // mov ofn.Flags, OFN_PATHMUSTEXIST + OFN_FILEMUSTEXIST
1105 // invoke GetOpenFileName, ADDR ofn
1109 //szDMsg1a BYTE "Could not open the file (GetOpenFileName)...", 0
1110 //szDMsg1b BYTE "Open error!", 0
1111 //szDMsg1c BYTE "About to attempt to open file...", 0
1113 ////invoke MessageBox, hWnd, ADDR szDMsg1a, ADDR szDMsg1b, MB_ICONERROR or MB_OK
1114 //invoke MessageBox, hMainWnd, ADDR szDMsg1c, ADDR szFile, MB_ICONERROR or MB_OK
1115 // invoke LoadTTF, ADDR szFile
1118 // // <<< FILE OPEN CODE HERE >>>
1119 // or fFileStatus, NAMEDbit
1120 // and fFileStatus, NOT CHANGEDbit
1121 // call NewWindowName
1122 // mov eax, TRUE // return TRUE
1124 // //��������������������������������������
1125 //OpenError: invoke GetLastError
1126 // // <<< FILE OPEN ERROR CODE HERE >>>
1128 // zero eax // return FALSE
1131 else if (cmd == IDM_SAVEAS)
1133 // and fFileStatus, NOT NAMEDbit
1136 else if (cmd == IDM_SAVE)
1140 else if (cmd == IDM_ABOUT)
1141 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_ABOUT), hMainWnd, AboutProc, NULL);
1142 else if (cmd == IDM_EXIT)
1143 SendMessage(hWnd, WM_CLOSE, 0, 0);
1144 else if (cmd == ID_TBCHARWIN)
1146 ShowWindow(hCharWnd, (IsWindowVisible(hCharWnd) ? SW_HIDE : SW_SHOWNOACTIVATE));
1149 wpC.length = sizeof(WINDOWPLACEMENT);
1150 GetWindowPlacement(hCharWnd, &wpC);
1151 wsprintf(strBuf, "Char window showCmd = %08X...\n", wpC.showCmd);
1152 WriteLogMsg(strBuf);
1156 return DefWindowProc(hWnd, msgID, wParam, lParam);
1161 return DefWindowProc(hWnd, msgID, wParam, lParam);
1168 // Initialize TTF data
1170 void CreateNewDoc(void)
1175 // Save changes to document before quitting
1177 bool SaveChanges(void)
1185 // ABOUT Dialog WndProc
1187 BOOL CALLBACK AboutProc(HWND hDlg, UINT msgID, WPARAM wParam, LPARAM lParam)
1193 MiscCenterWnd(hDlg, hMainWnd);
1198 if (wParam == IDOK || wParam == IDCANCEL)
1199 EndDialog(hDlg, TRUE);
1211 // Character Window WndProc
1213 WndProcCW PROC STDCALL, hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
1215 mov eax, uMsg // pickup our message
1216 .IF (eax == WM_PAINT)
1217 mov eax, 0 // Non-sense... (placeholder!)
1218 // Scan conversion etc. goes here...
1219 .ELSEIF (eax == WM_LBUTTONDOWN)
1220 invoke SetCapture, hCharWnd
1221 .ELSEIF (eax == WM_LBUTTONUP)
1222 invoke ReleaseCapture
1223 invoke SetFocus, hMainWnd // Make sure the main wnd keeps focus!
1224 .ELSEIF (eax == WM_NCLBUTTONDOWN)
1225 invoke DefWindowProc, hWnd, uMsg, wParam, lParam // Let it do its thing
1226 invoke SetFocus, hMainWnd // Make sure the main wnd keeps focus!
1228 DefProc: invoke DefWindowProc, hWnd, uMsg, wParam, lParam
1235 // Character Window WndProc
1237 LRESULT CALLBACK WndProcCW(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
1242 return DefWindowProc(hWnd, msgID, wParam, lParam);
1249 // Function prototypes
1251 int32 FindSelectedTool(void);
1254 // Tool Palette WndProc
1256 LRESULT CALLBACK WndProcTP(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
1261 static uint32 prevTool = -1;
1267 hdc = BeginPaint(hWnd, &ps);
1268 HDC newDC = CreateCompatibleDC(NULL);
1269 SelectObject(newDC, hBMToolPal1);
1270 BitBlt(hdc, 0, 0, sizeTPBM.x, sizeTPBM.y, newDC, 0, 0, SRCCOPY);
1273 // This is crappy. Find some way to tighten this up!
1274 int32 tool = FindSelectedTool();
1278 newDC = CreateCompatibleDC(NULL);
1279 SelectObject(newDC, hBMToolPal1);
1280 //need ul corner of bitmap, ul corner of dest, width/height
1281 pt.x = sizeStamp.x * (tool & 0x03), pt.y = sizeStamp.y * (tool >> 2);
1282 BitBlt(hdc, pt.x, pt.y, sizeStamp.x, sizeStamp.y, newDC, pt.x, pt.y, NOTSRCCOPY);
1286 EndPaint(hWnd, &ps);
1291 int32 tool = FindSelectedTool();
1293 if (tool != prevTool)
1296 InvalidateRect(hWnd, NULL, FALSE);
1303 int32 tool = FindSelectedTool(), oldTool = currentTool;
1308 if (currentTool != TOOLSelect && currentTool != TOOLDelPt && currentTool != TOOLAddPt
1309 && currentTool != TOOLPolySelect)
1312 if (currentTool != oldTool)
1313 InvalidateRect(hMainWnd, NULL, TRUE);
1315 if (currentTool == TOOLAddPoly)
1319 polyFirstPoint = true;
1321 wsprintf(strBuf, "--> Selected poly tool, polyFirstPoint is %s\n", polyFirstPoint ? "true" : "false");
1322 WriteLogMsg(strBuf);
1327 ShowWindow(hToolPalWnd, SW_HIDE);
1328 SetFocus(hMainWnd); // Make sure the main wnd keeps focus!
1333 return DefWindowProc(hWnd, msgID, wParam, lParam);
1340 // Find which tool we're pointing at
1341 // Use: xcoord = mouse.x / (bmsize.x/4), ycoord = mouse.y / (bmsize.y/2)
1343 int32 FindSelectedTool(void)
1348 ScreenToClient(hToolPalWnd, &pt);
1350 uint32 x = (uint32)pt.x / sizeStamp.x, y = (uint32)pt.y / sizeStamp.y, tool = -1;
1357 // tool = -1; // 7 has no tool...
1365 // Misc center window
1367 void MiscCenterWnd(HWND hChild, HWND hParent)
1371 if (!GetWindowRect(hParent, &parent) || !GetWindowRect(hChild, &child))
1374 int32 x = parent.left + (((parent.right - parent.left) - (child.right - child.left)) / 2),
1375 y = parent.top + (((parent.bottom - parent.top) - (child.bottom - child.top)) / 2);
1379 else if (x > GetSystemMetrics(SM_CXFULLSCREEN) - (child.right - child.left))
1380 x = GetSystemMetrics(SM_CXFULLSCREEN) - (child.right - child.left);
1384 else if (y > GetSystemMetrics(SM_CYFULLSCREEN) - (child.bottom - child.top))
1385 y = GetSystemMetrics(SM_CYFULLSCREEN) - (child.bottom - child.top);
1387 SetWindowPos(hChild, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
1391 // Allow only one instance
1393 bool OnlyOneInstance(void)
1395 HWND window = FindWindow(className, NULL);
1400 ShowWindow(window, SW_SHOWNORMAL);
1401 SetWindowPos(window, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1407 // Load/Allocate all resources
1409 bool LoadResources(void)
1411 hCur[0] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR1));
1412 hCur[1] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR2));
1413 hCur[2] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR3));
1414 hCur[3] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR4));
1415 hCur[4] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR5));
1416 hCur[5] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR6));
1417 hCur[6] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR7));
1418 hCur[7] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR8));
1422 hBMToolPal1 = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_TOOLPAL1));
1423 GetObject(hBMToolPal1, sizeof(bm), &bm);
1427 sizeTPBM.x = bm.bmWidth, sizeTPBM.y = bm.bmHeight;
1428 sizeStamp.x = bm.bmWidth / 4, sizeStamp.y = bm.bmHeight / 2;
1430 hBluePen1 = CreatePen(PS_DOT, 1, 0x00FF0000);
1431 hRedPen1 = CreatePen(PS_SOLID, 1, 0x000000FF);
1432 hGreenPen1 = CreatePen(PS_SOLID, 1, 0x0000AF00);
1433 hBlackPen1 = CreatePen(PS_SOLID, 1, 0x00000000);
1435 LOGBRUSH lb = { BS_NULL, 0, 0 };
1437 hNullBrush = CreateBrushIndirect(&lb);
1443 // Deallocate all resources
1445 void DeallocateResources(void)
1447 DeleteObject(hBMToolPal1);
1448 DeleteObject(hBluePen1);
1449 DeleteObject(hRedPen1);
1450 DeleteObject(hGreenPen1);
1451 DeleteObject(hBlackPen1);
1452 DeleteObject(hNullBrush);
1456 // Save all application specific data, so we can pick up where we last left off...
1458 void SaveAppState(void)
1460 SetINIInt("Main", "flags", wpM.flags);
1461 SetINIInt("Main", "showCmd", wpM.showCmd);
1462 SetINIInt("Main", "x1", wpM.rcNormalPosition.left);
1463 SetINIInt("Main", "y1", wpM.rcNormalPosition.top);
1464 SetINIInt("Main", "x2", wpM.rcNormalPosition.right);
1465 SetINIInt("Main", "y2", wpM.rcNormalPosition.bottom);
1467 SetINIInt("Main", "vpx", ptVPM.x);
1468 SetINIInt("Main", "vpy", ptVPM.y);
1470 SetINIInt("Char", "flags", wpC.flags);
1471 SetINIInt("Char", "showCmd", wpC.showCmd);
1472 SetINIInt("Char", "x1", wpC.rcNormalPosition.left);
1473 SetINIInt("Char", "y1", wpC.rcNormalPosition.top);
1474 SetINIInt("Char", "x2", wpC.rcNormalPosition.right);
1475 SetINIInt("Char", "y2", wpC.rcNormalPosition.bottom);
1477 // Need to write out currently opened font, character looking at, other misc. crap
1478 // SetINIString("Main", "currentFile", pDoc->GetPathName());
1479 // SetINIInt("Main", "currentChar", pDoc->character_num);
1483 // Restore all application specific data previously saved
1485 bool RestoreAppState(void)
1490 wp.length = sizeof(WINDOWPLACEMENT);
1491 GetWindowPlacement(hMainWnd, &wp);
1493 wp.flags = GetINIInt("Main", "flags", wp.flags);
1494 wp.showCmd = GetINIInt("Main", "showCmd", wp.showCmd);
1495 wp.rcNormalPosition.left = GetINIInt("Main", "x1", wp.rcNormalPosition.left);
1496 wp.rcNormalPosition.top = GetINIInt("Main", "y1", wp.rcNormalPosition.top);
1497 wp.rcNormalPosition.right = GetINIInt("Main", "x2", wp.rcNormalPosition.right);
1498 wp.rcNormalPosition.bottom = GetINIInt("Main", "y2", wp.rcNormalPosition.bottom);
1500 SetWindowPlacement(hMainWnd, &wp);
1504 hdc = GetDC(hMainWnd);
1505 GetViewportOrgEx(hdc, &pt);
1507 pt.x = GetINIInt("Main", "vpx", pt.x);
1508 pt.y = GetINIInt("Main", "vpy", pt.y);
1510 SetViewportOrgEx(hdc, pt.x, pt.y, NULL);
1511 ReleaseDC(hMainWnd, hdc);
1513 GetWindowPlacement(hCharWnd, &wp);
1515 wp.flags = GetINIInt("Char", "flags", wp.flags);
1516 wp.showCmd = GetINIInt("Char", "showCmd", wp.showCmd);
1517 wp.rcNormalPosition.left = GetINIInt("Char", "x1", wp.rcNormalPosition.left);
1518 wp.rcNormalPosition.top = GetINIInt("Char", "y1", wp.rcNormalPosition.top);
1519 wp.rcNormalPosition.right = GetINIInt("Char", "x2", wp.rcNormalPosition.right);
1520 wp.rcNormalPosition.bottom = GetINIInt("Char", "y2", wp.rcNormalPosition.bottom);
1522 SetWindowPlacement(hCharWnd, &wp);
1524 if (wp.showCmd == SW_HIDE)
1525 SendMessage(hToolBar, TB_SETSTATE, ID_TBCHARWIN, MAKELONG(TBSTATE_ENABLED, 0));
1527 // CString lastFile = theApplicationObject.GetProfileString(version, "currentFile", "");
1528 // int lastChar = theApplicationObject.GetProfileInt(version, "currentChar", 0);
1529 // if (lastFile.GetLength())
1531 // // Attempt to restore the last session by open the last file used, etc...
1532 // if (!pDoc->m_myFont.Load(lastFile))
1534 // // Err, make sure you can support any allegations you make below, buddy!
1535 // AfxMessageBox("The last file opened with TTF Edit\n\rseems to have been moved or deleted.");
1539 // pDoc->m_myFont.SetGlyph(lastChar); // Set TTF object to last used char
1540 // pDoc->character_num = lastChar;
1541 // pDoc->SetPathName(lastFile);
1544 // pDoc->m_myFont.GetCharName(lastChar, name);
1545 // m_wndOwned.SetWindowText((char *)name);
1555 bool Initialization(void)
1559 if (!LoadResources())
1562 RtlFillMemory(&wcex, sizeof(WNDCLASSEX), 0);
1563 wcex.cbSize = sizeof(WNDCLASSEX);
1564 wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
1565 wcex.lpfnWndProc = WndProc;
1566 wcex.hInstance = hInst;
1567 wcex.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON));
1568 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1569 wcex.lpszMenuName = MAKEINTRESOURCE(IDM_MENU);
1570 wcex.lpszClassName = className;
1571 wcex.hIconSm = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 16, 16, NULL);
1573 if (!RegisterClassEx(&wcex))
1576 hMainWnd = CreateWindowEx(NULL, className, className, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
1577 0, 0, 0x1A0, 0x180, NULL, NULL, hInst, NULL);
1582 ShowWindow(hMainWnd, nCmdShow);
1583 UpdateWindow(hMainWnd);
1585 // Character window creation
1587 wcex.lpfnWndProc = WndProcCW;
1588 wcex.lpszMenuName = NULL;
1589 wcex.lpszClassName = CNCharWin;
1590 wcex.hCursor = LoadCursor(NULL, IDC_ARROW); // Owned windows have "regular" cursors
1592 if (!RegisterClassEx(&wcex))
1595 hCharWnd = CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW, CNCharWin,
1596 curCharName, WS_POPUP | WS_CAPTION | WS_VISIBLE | WS_THICKFRAME,
1597 100, 100, 120, 120, hMainWnd, NULL, hInst, NULL);
1602 ShowWindow(hCharWnd, SW_SHOWNORMAL);
1603 UpdateWindow(hCharWnd);
1604 SetFocus(hMainWnd); // Make sure main wnd has focus!
1606 // Tool palette window creation
1608 wcex.lpfnWndProc = WndProcTP;
1609 wcex.lpszClassName = CNToolPal;
1611 if (!RegisterClassEx(&wcex))
1614 hToolPalWnd = CreateWindowEx(WS_EX_WINDOWEDGE, CNToolPal, NULL, WS_POPUP,
1615 0, 0, sizeTPBM.x, sizeTPBM.y, hMainWnd, NULL, hInst, NULL);
1620 // Note: A better way to handle this would be to have a sub that registers ALL
1621 // classes beforehand and passes a TRUE/FALSE back depending on whether or not
1622 // all the classes were able to be registered or not, THEN create the windows
1625 RestoreAppState(); // Restore app related stuff