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
17 // - Fix bug in Glyphpoints when dragging on an empty canvas or loading a font
18 // - Fix scrolling, zooming, settings (ini)
21 // Uncomment this for debugging...
23 #define DEBUGFOO // Various tool debugging...
24 #define DEBUGTP // Toolpalette debugging...
26 #include "editwindow.h"
27 #include "graphicprimitives.h"
28 #include "toolwindow.h"
33 BEGIN_EVENT_TABLE(TTEditWindow, wxWindow)
34 EVT_PAINT(TTEditWindow::OnPaint)
35 EVT_MOUSE_EVENTS(TTEditWindow::OnMouseEvent)
38 TTEditWindow::TTEditWindow(wxFrame * parent, const wxPoint &pos, const wxSize &size, long style):
39 wxWindow(parent, -1, pos, size, style | wxFULL_REPAINT_ON_RESIZE),
40 app(wxGetApp()), scale(1.0), offsetX(-10), offsetY(-10), tool(TOOLSelect),
41 ptHighlight(-1), oldPtHighlight(-1), ptNextHighlight(-1), oldPtNextHighlight(-1),
42 polyFirstPoint(true), bmp(NULL)
44 SetCursor(*(app.cur[tool]));
45 SetBackgroundColour(wxColour(0xFF, 0xFF, 0xFF));
48 s.Printf(_("Zoom: %.2f%%"), scale * 100.0);
49 parent->SetStatusText(s, 1);
52 TTEditWindow::~TTEditWindow(void)
58 void TTEditWindow::OnPaint(wxPaintEvent &e)
62 //dc.SetBackground(*wxWHITE_BRUSH);
64 // Due to the screwiness of wxWidgets coord system, the origin is ALWAYS
65 // the upper left corner--regardless of axis orientation, etc...
66 wxCoord width, height;
67 dc.GetSize(&width, &height);
69 dc.SetDeviceOrigin(-offsetX, height - (-offsetY));
70 dc.SetAxisOrientation(true, true);
72 // Scrolling can be done by using OffsetViewportOrgEx
73 // Scaling can be done by adjusting SetWindowExtEx (it's denominator of txform)
74 // you'd use: % = ViewportExt / WindowExt
75 // But it makes the window look like crap: fuggetuboutit.
76 // Instead, we have to scale EVERYTHING by hand. Crap!
77 // It's not *that* bad, but not as convenient either...
79 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0xFF), 1, wxDOT)));
80 // dc.DrawLine(0, 0, 10, 10);
82 // Draw coordinate axes
88 for(int i=0; i<pts.GetNumPoints(); i++)
92 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));
93 // SelectObject(hdc, hRedPen1);
95 if (pts.GetOnCurve(i))
97 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 7);
98 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 9);
102 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 7);
103 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 9);
106 else if ((i == ptHighlight || i == ptNextHighlight) && tool == TOOLAddPt)
108 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0xAF, 0x00), 1, wxSOLID)));
109 // SelectObject(hdc, hGreenPen1);
111 if (pts.GetOnCurve(i))
113 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 7);
114 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 9);
118 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 7);
119 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 9);
124 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));
125 // SelectObject(hdc, hBlackPen1);
127 if (pts.GetOnCurve(i))
128 DrawSquareDot(dc, pts.GetX(i), pts.GetY(i));
130 DrawRoundDot(dc, pts.GetX(i), pts.GetY(i));
133 if (tool == TOOLDelPt && i == ptHighlight)
135 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));
136 // SelectObject(hdc, hRedPen1);
137 // MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5, NULL);
138 // LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) + 5);
139 // LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5);//Lameness!
140 // MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5, NULL);
141 // LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) - 5);
142 // LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5);//More lameness!!
143 dc.DrawLine(pts.GetX(i) - 5, pts.GetY(i) - 5, pts.GetX(i) + 5, pts.GetY(i) + 5);
144 dc.DrawLine(pts.GetX(i) + 5, pts.GetY(i) - 5, pts.GetX(i) - 5, pts.GetY(i) + 5);
148 // SelectObject(hdc, hBlackPen1);
149 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));
151 // Draw curve formed by points
153 for(int poly=0; poly<pts.GetNumPolys(); poly++)
155 if (pts.GetNumPoints(poly) > 2)
158 // If it's not on curve, then move to it, otherwise move to last point...
162 if (pts.GetOnCurve(poly, pts.GetNumPoints(poly) - 1))
163 x = (wxCoord)pts.GetX(poly, pts.GetNumPoints(poly) - 1), y = (wxCoord)pts.GetY(poly, pts.GetNumPoints(poly) - 1);
165 x = (wxCoord)pts.GetX(poly, 0), y = (wxCoord)pts.GetY(poly, 0);
167 for(int i=0; i<pts.GetNumPoints(poly); i++)
169 if (pts.GetOnCurve(poly, i))
170 // LineTo(hdc, pts.GetX(poly, i), pts.GetY(poly, i));
172 dc.DrawLine(x, y, pts.GetX(poly, i), pts.GetY(poly, i));
173 x = (wxCoord)pts.GetX(poly, i), y = (wxCoord)pts.GetY(poly, i);
177 uint32 prev = pts.GetPrev(poly, i), next = pts.GetNext(poly, i);
178 float px = pts.GetX(poly, prev), py = pts.GetY(poly, prev),
179 nx = pts.GetX(poly, next), ny = pts.GetY(poly, next);
181 if (!pts.GetOnCurve(poly, prev))
182 px = (px + pts.GetX(poly, i)) / 2.0f,
183 py = (py + pts.GetY(poly, i)) / 2.0f;
185 if (!pts.GetOnCurve(poly, next))
186 nx = (nx + pts.GetX(poly, i)) / 2.0f,
187 ny = (ny + pts.GetY(poly, i)) / 2.0f;
189 Bezier(dc, point(px, py), point(pts.GetX(poly, i), pts.GetY(poly, i)), point(nx, ny));
190 x = (wxCoord)nx, y = (wxCoord)ny;
192 if (pts.GetOnCurve(poly, next))
193 i++; // Following point is on curve, so move past it
199 // SelectObject(hdc, oldPen); // Restore the stuff we disrupted...
200 dc.SetPen(wxNullPen);
201 // SelectObject(hdc, oldBrush);
202 // EndPaint(hWnd, &ps);
205 void TTEditWindow::OnMouseEvent(wxMouseEvent &e)
208 //printf("!!! This window %s focus...!\n", (HasCapture() ? "has" : "doesn't have"));
212 // Handle tool palette (NOTE: tool palette deals with RightUp event.)
214 wxPoint pt = ClientToScreen(e.GetPosition());
215 app.toolPalette->Move(pt);
216 app.toolPalette->Show(true);
217 SetCursor(*wxSTANDARD_CURSOR);
218 app.toolPalette->SetCursor(*wxSTANDARD_CURSOR);
219 app.toolPalette->prevTool = TOOLSelect;
220 app.toolPalette->Refresh(false);
223 else if (e.RightUp())
225 ToolType newTool = app.toolPalette->FindSelectedTool();//, oldTool = tool;
227 // We only change the tool if a new one was actually selected. Otherwise, we do nothing.
228 if (newTool != TOOLNone)
232 if (tool == TOOLScroll || tool == TOOLZoom || tool == TOOLAddPoly
233 || tool == TOOLDelPoly)
236 if (tool == TOOLAddPoly)
237 polyFirstPoint = true;
241 app.toolPalette->Show(false);
242 SetCursor(*(app.cur[tool]));
244 else if (e.LeftDown())
246 if (tool == TOOLScroll || tool == TOOLZoom)
247 CaptureMouse(); // Make sure we capture the mouse when in scroll/zoom mode
248 else if (tool == TOOLAddPt) // "Add Point" tool
250 if (pts.GetNumPoints() > 0)
252 wxPoint pt = GetAdjustedMousePosition(e);
253 pts.InsertPoint(pts.GetNext(ptHighlight), pt.x, pt.y, (e.ShiftDown() | e.ControlDown() ? false : true));
254 ptHighlight = ptNextHighlight;
258 else if (tool == TOOLAddPoly) // "Add Poly" tool
261 WriteLogMsg("Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts.GetNumPoints());
265 polyFirstPoint = false;
266 pts.AddNewPolyAtEnd();
269 wxPoint pt = GetAdjustedMousePosition(e);
270 // Append a point to the end of the structure
271 pts += IPoint(pt.x, pt.y, (e.ShiftDown() | e.ControlDown() ? false : true));
272 ptHighlight = pts.GetNumPoints() - 1;
275 WriteLogMsg(" --> [# polys: %u, # points: %u]\n", pts.GetNumPolys(), pts.GetNumPoints());
278 else if (tool == TOOLSelect || tool == TOOLPolySelect)
280 if (pts.GetNumPoints() > 0)
282 pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight));
283 WarpPointer(pt.x, pt.y);
285 if (e.ShiftDown() | e.ControlDown())
286 pts.SetOnCurve(ptHighlight, !pts.GetOnCurve(ptHighlight));
289 else if (tool == TOOLDelPt)
291 if (pts.GetNumPoints() > 0)
293 // if (ptHighlight != -1)
295 //This assumes that WM_MOUSEMOVE happens before this!
296 //The above commented out line should take care of this contingency... !!! FIX !!!
297 pts.DeletePoint(ptHighlight);
304 // mouseDown = false;
306 if (tool == TOOLScroll || tool == TOOLZoom)
309 else if (e.Dragging())
313 ToolType newTool = app.toolPalette->FindSelectedTool();
315 if (newTool != app.toolPalette->prevTool)
317 app.toolPalette->prevTool = newTool;
318 app.toolPalette->Refresh(false);
324 if (e.MiddleIsDown())
326 // Calc offset from previous point
327 pt = e.GetPosition();
328 ptOffset.x = pt.x - ptPrevious.x,
329 ptOffset.y = pt.y - ptPrevious.y;
331 // Then multiply it by the scaling factor. Whee!
332 // This looks wacky because we're using screen coords for the offset...
333 // Otherwise, we would subtract both offsets!
334 offsetX -= ptOffset.x, offsetY += ptOffset.y;
340 // if (e.LeftIsDown())
343 if (tool == TOOLScroll)
345 // Extract current point from lParam/calc offset from previous point
347 pt = e.GetPosition();
348 ptOffset.x = pt.x - ptPrevious.x,
349 ptOffset.y = pt.y - ptPrevious.y;
351 // NOTE: OffsetViewportOrg operates in DEVICE UNITS...
353 //Seems there's no equivalent for this in wxWidgets...!
355 // hdc = GetDC(hWnd);
356 // OffsetViewportOrgEx(hdc, ptOffset.x, ptOffset.y, NULL);
357 // ReleaseDC(hWnd, hdc);
359 // this shows that it works, so the logic above must be faulty...
360 // And it is. It should convert the coords first, then do the subtraction to figure the offset...
362 // Then multiply it by the scaling factor. Whee!
363 // This looks wacky because we're using screen coords for the offset...
364 // Otherwise, we would subtract both offsets!
365 offsetX -= ptOffset.x, offsetY += ptOffset.y;
370 if (tool == TOOLAddPt || tool == TOOLAddPoly || tool == TOOLSelect)
372 if (tool != TOOLAddPt || pts.GetNumPoints() > 0)//yecch.
374 //temporary, for testing. BTW, Select drag bug is here...!
376 wxPoint pt2 = GetAdjustedMousePosition(e);
377 pts.SetXY(ptHighlight, pt2.x, pt2.y);
382 else if (tool == TOOLPolySelect)
384 if (pts.GetNumPoints() > 0)
386 wxPoint pt2 = GetAdjustedMousePosition(e);
387 // Should also set onCurve here as well, depending on keystate
389 pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x - pts.GetX(ptHighlight), pt2.y - pts.GetY(ptHighlight));
399 // else // Moving, not dragging...
401 if (tool == TOOLSelect || tool == TOOLDelPt || tool == TOOLAddPt
402 || tool == TOOLPolySelect)// || tool == TOOLAddPoly)
404 wxPoint pt2 = GetAdjustedMousePosition(e);
405 double closest = 1.0e+99;
407 for(int i=0; i<pts.GetNumPoints(); i++)
409 double dist = ((pt2.x - pts.GetX(i)) * (pt2.x - pts.GetX(i)))
410 + ((pt2.y - pts.GetY(i)) * (pt2.y - pts.GetY(i)));
413 closest = dist, ptHighlight = i;
416 if (ptHighlight != oldPtHighlight)
418 oldPtHighlight = ptHighlight;
422 // What follows here looks like voodoo, but is really simple. What we do is
423 // check to see if the mouse point has a perpendicular intersection with any of
424 // the line segments. If it does, calculate the length of the perpendicular
425 // and choose the smallest length. If there is no perpendicular, then choose the
426 // length of line connecting the closer of either the first endpoint or the
427 // second and choose the smallest of those.
429 // There is one bit of math that looks like voodoo to me ATM--will explain once
430 // I understand it better (the calculation of the length of the perpendicular).
432 if (pts.GetNumPoints() > 1 && tool == TOOLAddPt)
434 double smallest = 1.0e+99;
436 for(int i=0; i<pts.GetNumPoints(); i++)
438 int32 p1x = pts.GetX(i), p1y = pts.GetY(i),
439 p2x = pts.GetX(pts.GetNext(i)), p2y = pts.GetY(pts.GetNext(i));
441 vector ls(p2x, p2y, 0, p1x, p1y, 0), v1(pt2.x, pt2.y, 0, p1x, p1y, 0),
442 v2(pt2.x, pt2.y, 0, p2x, p2y, 0);
443 double pp = ls.dot(v1) / ls.length(), dist;
444 // Geometric interpretation:
445 // pp is the paremeterized point on the vector ls where the perpendicular intersects ls.
446 // If pp < 0, then the perpendicular lies beyond the 1st endpoint. If pp > length of ls,
447 // then the perpendicular lies beyond the 2nd endpoint.
451 else if (pp > ls.length())
453 else // distance = ?Det?(ls, v1) / |ls|
454 dist = fabs((ls.x * v1.y - v1.x * ls.y) / ls.length());
456 //The answer to the above looks like it might be found here:
458 //If the segment endpoints are s and e, and the point is p, then the test for the perpendicular
459 //intercepting the segment is equivalent to insisting that the two dot products {s-e}.{s-p} and
460 //{e-s}.{e-p} are both non-negative. Perpendicular distance from the point to the segment is
461 //computed by first computing the area of the triangle the three points form, then dividing by the
462 //length of the segment. Distances are done just by the Pythagorean theorem. Twice the area of the
463 //triangle formed by three points is the determinant of the following matrix:
469 //(???) By translating the start point to the origin, this can be rewritten as:
470 //By subtracting row 1 from all rows, you get the following:
473 //(ex - sx) (ey - sy) 0
474 //(px - sx) (py - sy) 0
476 //which greatly simplifies the calculation of the determinant.
479 smallest = dist, ptNextHighlight = pts.GetNext(i), ptHighlight = i;
482 if (ptNextHighlight != oldPtNextHighlight)
484 oldPtNextHighlight = ptNextHighlight;
491 ptPrevious = e.GetPosition();
495 wxPoint TTEditWindow::GetAdjustedMousePosition(wxMouseEvent &e)
497 wxCoord width, height;
500 dc.GetSize(&width, &height);
501 dc.SetDeviceOrigin(-offsetX, height - (-offsetY));
502 dc.SetAxisOrientation(true, true);
505 wxStatusBar * sb = ((wxFrame *)GetParent())->GetStatusBar();
507 s.Printf("Logical mouse pos: %d, %d (%d, %d)", pt.x, pt.y, width, height);
508 sb->SetStatusText(s);
511 return e.GetLogicalPosition(dc);
514 wxPoint TTEditWindow::GetAdjustedClientPosition(wxCoord x, wxCoord y)
516 wxCoord width, height;
519 dc.GetSize(&width, &height);
520 dc.SetDeviceOrigin(-offsetX, height - (-offsetY));
521 dc.SetAxisOrientation(true, true);
523 return wxPoint(dc.LogicalToDeviceX(x), dc.LogicalToDeviceY(y));
532 LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
544 MiscCenterWnd(hWnd, GetDesktopWindow());
545 InitCommonControls();
546 hStatusBar = CreateStatusWindow(WS_CHILD | WS_VISIBLE, statusBarTxt, hWnd, ID_STATUSBAR);
551 // clean this crap up!
552 // well, the only crappy thing here is using a POINT as an int array, but otherwise, this is OK
553 wsprintf(strBuf, zoom, 1000);
555 GetTextExtentPoint32(hdc, strBuf, lstrlen(strBuf), &sz);
556 ReleaseDC(hWnd, hdc);
557 zoomWndWidth = sz.cx;
558 wsprintf(strBuf, zoom, 100);
560 GetClientRect(hWnd, &rc1);
561 pt.x = rc1.right - zoomWndWidth, pt.y = -1;
562 SendMessage(hStatusBar, SB_SETPARTS, 2, (LPARAM)&pt);
563 SendMessage(hStatusBar, SB_SETTEXT, (0 | SBT_NOBORDERS), (LPARAM)statusBarTxt);
564 SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM)strBuf);
566 hToolBar = CreateToolbarEx(hWnd, WS_CHILD | WS_BORDER | WS_VISIBLE | TBSTYLE_TOOLTIPS,
567 IDR_TOOLBAR1, 3, hInst, IDB_TOOLBAR1, tbButtons, 4, 16, 16, 16, 16, sizeof(TBBUTTON));
574 // The following can only be done because we use a private DC (using "CS_OWNDC")
576 // Set the mapping to draw the character so it fits in the viewport...
578 GetClientRect(hWnd, &rc1);
579 GetClientRect(hStatusBar, &rc2);
580 rc1.bottom -= rc2.bottom;
581 SetMapMode(hdc, MM_ISOTROPIC);
582 SetWindowExtEx(hdc, rc1.right, rc1.bottom, NULL);
583 SetViewportExtEx(hdc, rc1.right, -rc1.bottom, NULL);
584 SetViewportOrgEx(hdc, 0, rc1.bottom, NULL);
585 ReleaseDC(hWnd, hdc);
592 wpM.length = wpC.length = sizeof(WINDOWPLACEMENT);
593 GetWindowPlacement(hMainWnd, &wpM);
594 GetWindowPlacement(hCharWnd, &wpC);
596 if (!IsWindowVisible(hCharWnd)) // Needed because Windows lies about visibility
597 wpC.showCmd = SW_HIDE;
600 GetViewportOrgEx(hdc, &ptVPM);
601 ReleaseDC(hWnd, hdc);
613 case WM_NCLBUTTONDOWN:
615 if (wParam == HTCAPTION)
618 GetWindowRect(hMainWnd, &rc1);
619 GetWindowRect(hCharWnd, &rc2);
620 ptWinOffset.x = rc2.left - rc1.left;
621 ptWinOffset.y = rc2.top - rc1.top;
624 // Let Windows do its thing with this msg, or weird things will happen...
626 DefWindowProc(hWnd, msgID, wParam, lParam);
630 case WM_WINDOWPOSCHANGING:
634 WINDOWPOS * wp = (WINDOWPOS *)lParam;
636 if (wp->hwnd == hMainWnd && !(wp->flags & SWP_NOMOVE))
637 SetWindowPos(hCharWnd, 0, wp->x + ptWinOffset.x, wp->y + ptWinOffset.y,
638 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
641 return DefWindowProc(hWnd, msgID, wParam, lParam); // Seems this is needed... Bleah!
645 hdc = BeginPaint(hWnd, &ps);
647 // Scrolling can be done by using OffsetViewportOrgEx
648 // Scaling can be done by adjusting SetWindowExtEx (it's denominator of txform)
649 // you'd use: % = ViewportExt / WindowExt
650 // But it makes the window look like crap: fuggetuboutit.
651 // Instead, we have to scale EVERYTHING by hand. Crap!
653 // Apparently, you *must* save the individual object types (pen, brush, etc.)
655 HGDIOBJ oldPen = SelectObject(hdc, hBluePen1),
656 oldBrush = SelectObject(hdc, hNullBrush);
658 // Draw coordinate axes
660 MoveToEx(hdc, 0, -32000, NULL);
661 LineTo(hdc, 0, 32000);
662 MoveToEx(hdc, -32000, 0, NULL);
663 LineTo(hdc, 32000, 0);
667 for(int i=0; i<pts.GetNumPoints(); i++)
669 if (i == ptHighlight)
671 SelectObject(hdc, hRedPen1);
673 if (pts.GetOnCurve(i))
675 DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 7);
676 DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 9);
680 DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 7);
681 DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 9);
684 else if ((i == ptHighlight || i == ptNextHighlight) && currentTool == TOOLAddPt)
686 SelectObject(hdc, hGreenPen1);
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);
701 SelectObject(hdc, hBlackPen1);
703 if (pts.GetOnCurve(i))
704 DrawSquareDot(hdc, pts.GetX(i), pts.GetY(i));
706 DrawRoundDot(hdc, pts.GetX(i), pts.GetY(i));
709 if (currentTool == TOOLDelPt && i == ptHighlight)
711 SelectObject(hdc, hRedPen1);
712 MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5, NULL);
713 LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) + 5);
714 LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5);//Lameness!
715 MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5, NULL);
716 LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) - 5);
717 LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5);//More lameness!!
721 SelectObject(hdc, hBlackPen1);
723 // Draw curve formed by points
725 for(int poly=0; poly<pts.GetNumPolys(); poly++)
727 if (pts.GetNumPoints(poly) > 2)
730 // If it's not on curve, then move to it, otherwise move to last point...
732 if (pts.GetOnCurve(poly, pts.GetNumPoints(poly) - 1))
733 MoveToEx(hdc, pts.GetX(poly, pts.GetNumPoints(poly) - 1), pts.GetY(poly, pts.GetNumPoints(poly) - 1), NULL);
735 MoveToEx(hdc, pts.GetX(poly, 0), pts.GetY(poly, 0), NULL);
737 for(int i=0; i<pts.GetNumPoints(poly); i++)
739 if (pts.GetOnCurve(poly, i))
740 LineTo(hdc, pts.GetX(poly, i), pts.GetY(poly, i));
743 uint32 prev = pts.GetPrev(poly, i), next = pts.GetNext(poly, i);
744 float px = pts.GetX(poly, prev), py = pts.GetY(poly, prev),
745 nx = pts.GetX(poly, next), ny = pts.GetY(poly, next);
747 if (!pts.GetOnCurve(poly, prev))
748 px = (px + pts.GetX(poly, i)) / 2.0f,
749 py = (py + pts.GetY(poly, i)) / 2.0f;
751 if (!pts.GetOnCurve(poly, next))
752 nx = (nx + pts.GetX(poly, i)) / 2.0f,
753 ny = (ny + pts.GetY(poly, i)) / 2.0f;
755 Bezier(hdc, point(px, py), point(pts.GetX(poly, i), pts.GetY(poly, i)), point(nx, ny));
757 if (pts.GetOnCurve(poly, next))
758 i++; // Following point is on curve, so move past it
764 SelectObject(hdc, oldPen); // Restore the stuff we disrupted...
765 SelectObject(hdc, oldBrush);
771 // Apparently this is needed since these windows don't update themselves.
772 SendMessage(hStatusBar, msgID, wParam, lParam);
773 SendMessage(hToolBar, msgID, wParam, lParam);
775 // This is needed to make the 2nd status pane visible
776 GetClientRect(hWnd, &rc1);
777 pt.x = rc1.right - zoomWndWidth, pt.y = -1;
778 SendMessage(hStatusBar, SB_SETPARTS, 2, (LPARAM)&pt);
784 SetWindowPos(hToolPalWnd, 0, pt.x, pt.y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
785 SetFocus(hToolPalWnd);
786 SetCapture(hToolPalWnd); // Ensure tool palette gets RButtonUp
787 SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW))); // Tool pallete has "regular" cursor
794 if (currentTool == TOOLScroll || currentTool == TOOLZoom)
795 SetCapture(hWnd); // Make sure we capture the mouse when in scroll/zoom mode
796 else if (currentTool == TOOLAddPt) // "Add Point" tool
798 if (pts.GetNumPoints() > 0)
800 //Do we really need to put a cap on this???
802 // if (pts.GetNumPoints() < 16)
804 pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;
807 pts.InsertPoint(pts.GetNext(ptHighlight), pt.x, pt.y, (wParam & (MK_SHIFT | MK_CONTROL) ? false : true));
808 ptHighlight = ptNextHighlight;
809 ReleaseDC(hWnd, hdc);
810 InvalidateRect(hWnd, NULL, TRUE);
814 else if (currentTool == TOOLAddPoly) // "Add Poly" tool
817 wsprintf(strBuf, "Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts.GetNumPoints());
822 polyFirstPoint = false;
823 pts.AddNewPolyAtEnd();
826 //Do we really need to put a cap on this???
828 // if (pts.GetNumPoints() < 16)
830 pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;
833 ReleaseDC(hWnd, hdc);
834 // Append a point to the end of the structure
835 pts += IPoint(pt.x, pt.y, (wParam & (MK_SHIFT | MK_CONTROL) ? false : true));
836 ptHighlight = pts.GetNumPoints() - 1;
837 InvalidateRect(hWnd, NULL, TRUE);
840 wsprintf(strBuf, " --> [# polys: %u, # points: %u]\xD\xA", pts.GetNumPolys(), pts.GetNumPoints());
844 else if (currentTool == TOOLSelect || currentTool == TOOLPolySelect)
846 if (pts.GetNumPoints() > 0)
848 pt.x = pts.GetX(ptHighlight), pt.y = pts.GetY(ptHighlight);
851 ClientToScreen(hWnd, &pt);
852 SetCursorPos(pt.x, pt.y);
853 ReleaseDC(hWnd, hdc);
855 if (wParam & (MK_SHIFT | MK_CONTROL))
856 pts.SetOnCurve(ptHighlight, !pts.GetOnCurve(ptHighlight));
859 else if (currentTool == TOOLDelPt)
861 if (pts.GetNumPoints() > 0)
863 // if (ptHighlight != -1)
865 //This assumes that WM_MOUSEMOVE happens before this!
866 //The above commented out line should take care of this contingency... !!! FIX !!!
867 pts.DeletePoint(ptHighlight);
868 InvalidateRect(hWnd, NULL, TRUE);
878 if (currentTool == TOOLScroll || currentTool == TOOLZoom)
885 SetCursor(hCur[currentTool]);
887 // Extract current point from lParam/calc offset from previous point
889 pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;
890 ptOffset.x = pt.x - ptPrevious.x,
891 ptOffset.y = pt.y - ptPrevious.y;
895 if (currentTool == TOOLScroll)
897 // NOTE: OffsetViewportOrg operates in DEVICE UNITS...
900 OffsetViewportOrgEx(hdc, ptOffset.x, ptOffset.y, NULL);
901 ReleaseDC(hWnd, hdc);
903 // this shows that it works, so the logic above must be faulty...
904 // And it is. It should convert the coords first, then do the subtraction to figure the offset...
906 // Then multiply it by the scaling factor. Whee!
908 InvalidateRect(hWnd, NULL, TRUE);
909 // SendMessage(hWnd, WM_PAINT, NULL, NULL);
911 else if (currentTool == TOOLAddPt || currentTool == TOOLAddPoly || currentTool == TOOLSelect)
913 if (currentTool != TOOLAddPt || pts.GetNumPoints() > 0)//yecch.
916 pt2.x = pt.x, pt2.y = pt.y;
917 // Should also set onCurve here as well, depending on keystate
920 DPtoLP(hdc, &pt2, 1);
921 pts.SetXY(ptHighlight, pt2.x, pt2.y);
922 ReleaseDC(hWnd, hdc);
923 InvalidateRect(hWnd, NULL, TRUE);
926 else if (currentTool == TOOLPolySelect)
928 if (pts.GetNumPoints() > 0)
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.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x - pts.GetX(ptHighlight), pt2.y - pts.GetY(ptHighlight));
937 ReleaseDC(hWnd, hdc);
938 InvalidateRect(hWnd, NULL, TRUE);
944 if (currentTool == TOOLSelect || currentTool == TOOLDelPt || currentTool == TOOLAddPt
945 || currentTool == TOOLPolySelect)// || currentTool == TOOLAddPoly)
948 pt2.x = pt.x, pt2.y = pt.y;
950 DPtoLP(hdc, &pt2, 1);
951 ReleaseDC(hWnd, hdc);
953 double closest = 1.0e+99;
955 for(int i=0; i<pts.GetNumPoints(); i++)
957 double dist = ((pt2.x - pts.GetX(i)) * (pt2.x - pts.GetX(i)))
958 + ((pt2.y - pts.GetY(i)) * (pt2.y - pts.GetY(i)));
961 closest = dist, ptHighlight = i;
964 if (ptHighlight != oldPtHighlight)
966 oldPtHighlight = ptHighlight;
967 InvalidateRect(hWnd, NULL, TRUE);
970 // What follows here looks like voodoo, but is really simple. What we do is
971 // check to see if the mouse point has a perpendicular intersection with any of
972 // the line segments. If it does, calculate the length of the perpendicular
973 // and choose the smallest length. If there is no perpendicular, then choose the
974 // length of line connecting the closer of either the first endpoint or the
975 // second and choose the smallest of those.
977 // There is one bit of math that looks like voodoo to me ATM--will explain once
978 // I understand it better (the calculation of the length of the perpendicular).
980 if (pts.GetNumPoints() > 1 && currentTool == TOOLAddPt)
982 double smallest = 1.0e+99;
984 for(int i=0; i<pts.GetNumPoints(); i++)
986 int32 p1x = pts.GetX(i), p1y = pts.GetY(i),
987 p2x = pts.GetX(pts.GetNext(i)), p2y = pts.GetY(pts.GetNext(i));
989 vector ls(p2x, p2y, 0, p1x, p1y, 0), v1(pt2.x, pt2.y, 0, p1x, p1y, 0),
990 v2(pt2.x, pt2.y, 0, p2x, p2y, 0);
991 double pp = ls.dot(v1) / ls.length(), dist;
992 // Geometric interpretation:
993 // pp is the paremeterized point on the vector ls where the perpendicular intersects ls.
994 // If pp < 0, then the perpendicular lies beyond the 1st endpoint. If pp > length of ls,
995 // then the perpendicular lies beyond the 2nd endpoint.
999 else if (pp > ls.length())
1001 else // distance = ?Det?(ls, v1) / |ls|
1002 dist = abs((ls.x * v1.y - v1.x * ls.y) / ls.length());
1004 //The answer to the above looks like it might be found here:
1006 //If the segment endpoints are s and e, and the point is p, then the test for the perpendicular
1007 //intercepting the segment is equivalent to insisting that the two dot products {s-e}.{s-p} and
1008 //{e-s}.{e-p} are both non-negative. Perpendicular distance from the point to the segment is
1009 //computed by first computing the area of the triangle the three points form, then dividing by the
1010 //length of the segment. Distances are done just by the Pythagorean theorem. Twice the area of the
1011 //triangle formed by three points is the determinant of the following matrix:
1017 //(???) By translating the start point to the origin, this can be rewritten as:
1018 //By subtracting row 1 from all rows, you get the following:
1021 //(ex - sx) (ey - sy) 0
1022 //(px - sx) (py - sy) 0
1024 //which greatly simplifies the calculation of the determinant.
1026 if (dist < smallest)
1027 smallest = dist, ptNextHighlight = pts.GetNext(i), ptHighlight = i;
1030 if (ptNextHighlight != oldPtNextHighlight)
1032 oldPtNextHighlight = ptNextHighlight;
1033 InvalidateRect(hWnd, NULL, TRUE);
1039 ptPrevious.x = pt.x, ptPrevious.y = pt.y;
1045 if (((NMHDR *)lParam)->code == TTN_NEEDTEXT)
1047 LoadString(hInst, ((TOOLTIPTEXT *)lParam)->hdr.idFrom + 0x80, toolTipTxt, 16);
1048 ((TOOLTIPTEXT *)lParam)->lpszText = toolTipTxt;
1055 statusBarTxt[0] = 0; // Clear status bar text
1056 uint16 flags = wParam >> 16; // Extract flags
1058 if (!(flags & MFT_SEPARATOR))
1060 uint16 id = wParam & 0xFFFF;
1062 if (flags & MF_POPUP)
1064 if (flags & MF_SYSMENU)
1067 id = IDM_FILEMENU + wParam;
1070 LoadString(hInst, id, statusBarTxt, 64);
1073 SendMessage(hStatusBar, SB_SETTEXT, 0 + SBT_NOBORDERS, (LPARAM)statusBarTxt);
1078 uint16 cmd = wParam & 0xFFFF;
1084 else if (cmd == IDM_OPEN)
1088 // movmov ofn.hwndOwner, eax, hMainWnd
1089 // mov ofn.Flags, OFN_PATHMUSTEXIST + OFN_FILEMUSTEXIST
1090 // invoke GetOpenFileName, ADDR ofn
1094 //szDMsg1a BYTE "Could not open the file (GetOpenFileName)...", 0
1095 //szDMsg1b BYTE "Open error!", 0
1096 //szDMsg1c BYTE "About to attempt to open file...", 0
1098 ////invoke MessageBox, hWnd, ADDR szDMsg1a, ADDR szDMsg1b, MB_ICONERROR or MB_OK
1099 //invoke MessageBox, hMainWnd, ADDR szDMsg1c, ADDR szFile, MB_ICONERROR or MB_OK
1100 // invoke LoadTTF, ADDR szFile
1103 // // <<< FILE OPEN CODE HERE >>>
1104 // or fFileStatus, NAMEDbit
1105 // and fFileStatus, NOT CHANGEDbit
1106 // call NewWindowName
1107 // mov eax, TRUE // return TRUE
1109 // //��������������������������������������
1110 //OpenError: invoke GetLastError
1111 // // <<< FILE OPEN ERROR CODE HERE >>>
1113 // zero eax // return FALSE
1116 else if (cmd == IDM_SAVEAS)
1118 // and fFileStatus, NOT NAMEDbit
1121 else if (cmd == IDM_SAVE)
1125 else if (cmd == IDM_ABOUT)
1126 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_ABOUT), hMainWnd, AboutProc, NULL);
1127 else if (cmd == IDM_EXIT)
1128 SendMessage(hWnd, WM_CLOSE, 0, 0);
1129 else if (cmd == ID_TBCHARWIN)
1131 ShowWindow(hCharWnd, (IsWindowVisible(hCharWnd) ? SW_HIDE : SW_SHOWNOACTIVATE));
1134 wpC.length = sizeof(WINDOWPLACEMENT);
1135 GetWindowPlacement(hCharWnd, &wpC);
1136 wsprintf(strBuf, "Char window showCmd = %08X...\n", wpC.showCmd);
1137 WriteLogMsg(strBuf);
1141 return DefWindowProc(hWnd, msgID, wParam, lParam);
1146 return DefWindowProc(hWnd, msgID, wParam, lParam);
1153 // Initialize TTF data
1155 void CreateNewDoc(void)
1160 // Save changes to document before quitting
1162 bool SaveChanges(void)
1170 // ABOUT Dialog WndProc
1172 BOOL CALLBACK AboutProc(HWND hDlg, UINT msgID, WPARAM wParam, LPARAM lParam)
1178 MiscCenterWnd(hDlg, hMainWnd);
1183 if (wParam == IDOK || wParam == IDCANCEL)
1184 EndDialog(hDlg, TRUE);
1196 // Character Window WndProc
1198 WndProcCW PROC STDCALL, hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
1200 mov eax, uMsg // pickup our message
1201 .IF (eax == WM_PAINT)
1202 mov eax, 0 // Non-sense... (placeholder!)
1203 // Scan conversion etc. goes here...
1204 .ELSEIF (eax == WM_LBUTTONDOWN)
1205 invoke SetCapture, hCharWnd
1206 .ELSEIF (eax == WM_LBUTTONUP)
1207 invoke ReleaseCapture
1208 invoke SetFocus, hMainWnd // Make sure the main wnd keeps focus!
1209 .ELSEIF (eax == WM_NCLBUTTONDOWN)
1210 invoke DefWindowProc, hWnd, uMsg, wParam, lParam // Let it do its thing
1211 invoke SetFocus, hMainWnd // Make sure the main wnd keeps focus!
1213 DefProc: invoke DefWindowProc, hWnd, uMsg, wParam, lParam
1220 // Character Window WndProc
1222 LRESULT CALLBACK WndProcCW(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
1227 return DefWindowProc(hWnd, msgID, wParam, lParam);
1234 // Function prototypes
1236 int32 FindSelectedTool(void);
1239 // Tool Palette WndProc
1241 LRESULT CALLBACK WndProcTP(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
1246 static uint32 prevTool = -1;
1252 hdc = BeginPaint(hWnd, &ps);
1253 HDC newDC = CreateCompatibleDC(NULL);
1254 SelectObject(newDC, hBMToolPal1);
1255 BitBlt(hdc, 0, 0, sizeTPBM.x, sizeTPBM.y, newDC, 0, 0, SRCCOPY);
1258 // This is crappy. Find some way to tighten this up!
1259 int32 tool = FindSelectedTool();
1263 newDC = CreateCompatibleDC(NULL);
1264 SelectObject(newDC, hBMToolPal1);
1265 //need ul corner of bitmap, ul corner of dest, width/height
1266 pt.x = sizeStamp.x * (tool & 0x03), pt.y = sizeStamp.y * (tool >> 2);
1267 BitBlt(hdc, pt.x, pt.y, sizeStamp.x, sizeStamp.y, newDC, pt.x, pt.y, NOTSRCCOPY);
1271 EndPaint(hWnd, &ps);
1276 int32 tool = FindSelectedTool();
1278 if (tool != prevTool)
1281 InvalidateRect(hWnd, NULL, FALSE);
1288 int32 tool = FindSelectedTool(), oldTool = currentTool;
1293 if (currentTool != TOOLSelect && currentTool != TOOLDelPt && currentTool != TOOLAddPt
1294 && currentTool != TOOLPolySelect)
1297 if (currentTool != oldTool)
1298 InvalidateRect(hMainWnd, NULL, TRUE);
1300 if (currentTool == TOOLAddPoly)
1304 polyFirstPoint = true;
1306 wsprintf(strBuf, "--> Selected poly tool, polyFirstPoint is %s\n", polyFirstPoint ? "true" : "false");
1307 WriteLogMsg(strBuf);
1312 ShowWindow(hToolPalWnd, SW_HIDE);
1313 SetFocus(hMainWnd); // Make sure the main wnd keeps focus!
1318 return DefWindowProc(hWnd, msgID, wParam, lParam);
1325 // Find which tool we're pointing at
1326 // Use: xcoord = mouse.x / (bmsize.x/4), ycoord = mouse.y / (bmsize.y/2)
1328 int32 FindSelectedTool(void)
1333 ScreenToClient(hToolPalWnd, &pt);
1335 uint32 x = (uint32)pt.x / sizeStamp.x, y = (uint32)pt.y / sizeStamp.y, tool = -1;
1342 // tool = -1; // 7 has no tool...
1350 // Misc center window
1352 void MiscCenterWnd(HWND hChild, HWND hParent)
1356 if (!GetWindowRect(hParent, &parent) || !GetWindowRect(hChild, &child))
1359 int32 x = parent.left + (((parent.right - parent.left) - (child.right - child.left)) / 2),
1360 y = parent.top + (((parent.bottom - parent.top) - (child.bottom - child.top)) / 2);
1364 else if (x > GetSystemMetrics(SM_CXFULLSCREEN) - (child.right - child.left))
1365 x = GetSystemMetrics(SM_CXFULLSCREEN) - (child.right - child.left);
1369 else if (y > GetSystemMetrics(SM_CYFULLSCREEN) - (child.bottom - child.top))
1370 y = GetSystemMetrics(SM_CYFULLSCREEN) - (child.bottom - child.top);
1372 SetWindowPos(hChild, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
1376 // Allow only one instance
1378 bool OnlyOneInstance(void)
1380 HWND window = FindWindow(className, NULL);
1385 ShowWindow(window, SW_SHOWNORMAL);
1386 SetWindowPos(window, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1392 // Load/Allocate all resources
1394 bool LoadResources(void)
1396 hCur[0] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR1));
1397 hCur[1] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR2));
1398 hCur[2] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR3));
1399 hCur[3] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR4));
1400 hCur[4] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR5));
1401 hCur[5] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR6));
1402 hCur[6] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR7));
1403 hCur[7] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR8));
1407 hBMToolPal1 = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_TOOLPAL1));
1408 GetObject(hBMToolPal1, sizeof(bm), &bm);
1412 sizeTPBM.x = bm.bmWidth, sizeTPBM.y = bm.bmHeight;
1413 sizeStamp.x = bm.bmWidth / 4, sizeStamp.y = bm.bmHeight / 2;
1415 hBluePen1 = CreatePen(PS_DOT, 1, 0x00FF0000);
1416 hRedPen1 = CreatePen(PS_SOLID, 1, 0x000000FF);
1417 hGreenPen1 = CreatePen(PS_SOLID, 1, 0x0000AF00);
1418 hBlackPen1 = CreatePen(PS_SOLID, 1, 0x00000000);
1420 LOGBRUSH lb = { BS_NULL, 0, 0 };
1422 hNullBrush = CreateBrushIndirect(&lb);
1428 // Deallocate all resources
1430 void DeallocateResources(void)
1432 DeleteObject(hBMToolPal1);
1433 DeleteObject(hBluePen1);
1434 DeleteObject(hRedPen1);
1435 DeleteObject(hGreenPen1);
1436 DeleteObject(hBlackPen1);
1437 DeleteObject(hNullBrush);
1441 // Save all application specific data, so we can pick up where we last left off...
1443 void SaveAppState(void)
1445 SetINIInt("Main", "flags", wpM.flags);
1446 SetINIInt("Main", "showCmd", wpM.showCmd);
1447 SetINIInt("Main", "x1", wpM.rcNormalPosition.left);
1448 SetINIInt("Main", "y1", wpM.rcNormalPosition.top);
1449 SetINIInt("Main", "x2", wpM.rcNormalPosition.right);
1450 SetINIInt("Main", "y2", wpM.rcNormalPosition.bottom);
1452 SetINIInt("Main", "vpx", ptVPM.x);
1453 SetINIInt("Main", "vpy", ptVPM.y);
1455 SetINIInt("Char", "flags", wpC.flags);
1456 SetINIInt("Char", "showCmd", wpC.showCmd);
1457 SetINIInt("Char", "x1", wpC.rcNormalPosition.left);
1458 SetINIInt("Char", "y1", wpC.rcNormalPosition.top);
1459 SetINIInt("Char", "x2", wpC.rcNormalPosition.right);
1460 SetINIInt("Char", "y2", wpC.rcNormalPosition.bottom);
1462 // Need to write out currently opened font, character looking at, other misc. crap
1463 // SetINIString("Main", "currentFile", pDoc->GetPathName());
1464 // SetINIInt("Main", "currentChar", pDoc->character_num);
1468 // Restore all application specific data previously saved
1470 bool RestoreAppState(void)
1475 wp.length = sizeof(WINDOWPLACEMENT);
1476 GetWindowPlacement(hMainWnd, &wp);
1478 wp.flags = GetINIInt("Main", "flags", wp.flags);
1479 wp.showCmd = GetINIInt("Main", "showCmd", wp.showCmd);
1480 wp.rcNormalPosition.left = GetINIInt("Main", "x1", wp.rcNormalPosition.left);
1481 wp.rcNormalPosition.top = GetINIInt("Main", "y1", wp.rcNormalPosition.top);
1482 wp.rcNormalPosition.right = GetINIInt("Main", "x2", wp.rcNormalPosition.right);
1483 wp.rcNormalPosition.bottom = GetINIInt("Main", "y2", wp.rcNormalPosition.bottom);
1485 SetWindowPlacement(hMainWnd, &wp);
1489 hdc = GetDC(hMainWnd);
1490 GetViewportOrgEx(hdc, &pt);
1492 pt.x = GetINIInt("Main", "vpx", pt.x);
1493 pt.y = GetINIInt("Main", "vpy", pt.y);
1495 SetViewportOrgEx(hdc, pt.x, pt.y, NULL);
1496 ReleaseDC(hMainWnd, hdc);
1498 GetWindowPlacement(hCharWnd, &wp);
1500 wp.flags = GetINIInt("Char", "flags", wp.flags);
1501 wp.showCmd = GetINIInt("Char", "showCmd", wp.showCmd);
1502 wp.rcNormalPosition.left = GetINIInt("Char", "x1", wp.rcNormalPosition.left);
1503 wp.rcNormalPosition.top = GetINIInt("Char", "y1", wp.rcNormalPosition.top);
1504 wp.rcNormalPosition.right = GetINIInt("Char", "x2", wp.rcNormalPosition.right);
1505 wp.rcNormalPosition.bottom = GetINIInt("Char", "y2", wp.rcNormalPosition.bottom);
1507 SetWindowPlacement(hCharWnd, &wp);
1509 if (wp.showCmd == SW_HIDE)
1510 SendMessage(hToolBar, TB_SETSTATE, ID_TBCHARWIN, MAKELONG(TBSTATE_ENABLED, 0));
1512 // CString lastFile = theApplicationObject.GetProfileString(version, "currentFile", "");
1513 // int lastChar = theApplicationObject.GetProfileInt(version, "currentChar", 0);
1514 // if (lastFile.GetLength())
1516 // // Attempt to restore the last session by open the last file used, etc...
1517 // if (!pDoc->m_myFont.Load(lastFile))
1519 // // Err, make sure you can support any allegations you make below, buddy!
1520 // AfxMessageBox("The last file opened with TTF Edit\n\rseems to have been moved or deleted.");
1524 // pDoc->m_myFont.SetGlyph(lastChar); // Set TTF object to last used char
1525 // pDoc->character_num = lastChar;
1526 // pDoc->SetPathName(lastFile);
1529 // pDoc->m_myFont.GetCharName(lastChar, name);
1530 // m_wndOwned.SetWindowText((char *)name);
1540 bool Initialization(void)
1544 if (!LoadResources())
1547 RtlFillMemory(&wcex, sizeof(WNDCLASSEX), 0);
1548 wcex.cbSize = sizeof(WNDCLASSEX);
1549 wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
1550 wcex.lpfnWndProc = WndProc;
1551 wcex.hInstance = hInst;
1552 wcex.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON));
1553 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1554 wcex.lpszMenuName = MAKEINTRESOURCE(IDM_MENU);
1555 wcex.lpszClassName = className;
1556 wcex.hIconSm = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 16, 16, NULL);
1558 if (!RegisterClassEx(&wcex))
1561 hMainWnd = CreateWindowEx(NULL, className, className, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
1562 0, 0, 0x1A0, 0x180, NULL, NULL, hInst, NULL);
1567 ShowWindow(hMainWnd, nCmdShow);
1568 UpdateWindow(hMainWnd);
1570 // Character window creation
1572 wcex.lpfnWndProc = WndProcCW;
1573 wcex.lpszMenuName = NULL;
1574 wcex.lpszClassName = CNCharWin;
1575 wcex.hCursor = LoadCursor(NULL, IDC_ARROW); // Owned windows have "regular" cursors
1577 if (!RegisterClassEx(&wcex))
1580 hCharWnd = CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW, CNCharWin,
1581 curCharName, WS_POPUP | WS_CAPTION | WS_VISIBLE | WS_THICKFRAME,
1582 100, 100, 120, 120, hMainWnd, NULL, hInst, NULL);
1587 ShowWindow(hCharWnd, SW_SHOWNORMAL);
1588 UpdateWindow(hCharWnd);
1589 SetFocus(hMainWnd); // Make sure main wnd has focus!
1591 // Tool palette window creation
1593 wcex.lpfnWndProc = WndProcTP;
1594 wcex.lpszClassName = CNToolPal;
1596 if (!RegisterClassEx(&wcex))
1599 hToolPalWnd = CreateWindowEx(WS_EX_WINDOWEDGE, CNToolPal, NULL, WS_POPUP,
1600 0, 0, sizeTPBM.x, sizeTPBM.y, hMainWnd, NULL, hInst, NULL);
1605 // Note: A better way to handle this would be to have a sub that registers ALL
1606 // classes beforehand and passes a TRUE/FALSE back depending on whether or not
1607 // all the classes were able to be registered or not, THEN create the windows
1610 RestoreAppState(); // Restore app related stuff