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