2 // TTEDIT.CPP - The TrueType Editor
\r
3 // by James L. Hammons
\r
4 // (C) 2004 Underground Software
\r
6 // JLH = James L. Hammons <jlhamm@acm.org>
\r
9 // --- ---------- -------------------------------------------------------------
\r
10 // JLH 04/10/2002 Created this file
\r
11 // JLH 05/10/2004 Translated file from ASM to CPP
\r
12 // JLH 05/14/2004 Added rudimentary editing capability to tool palette tools
\r
13 // JLH 11/18/2006 Initial port to Linux
\r
16 // STILL TO BE DONE:
\r
18 // - Fix bug in Glyphpoints when dragging on an empty canvas or loading a font
\r
19 // - Fix scrolling, zooming, settings (ini)
\r
20 // - Finish conversion to wxWidgets for cross-platform portability
\r
21 // - Fix problem with owned window causing main window refresh problems
\r
22 // (ironically enough, it doesn't seem to be a problem anymore...)
\r
25 // Uncomment this for debugging...
\r
27 #define DEBUGFOO // Various tool debugging...
\r
31 #include "tte_res.h"
\r
33 #include "registry.h"
\r
35 #include "glyphpoints.h"
\r
40 #include "ttedit.h" // Usually not necessary, but here we are...
\r
41 #include <wx/confbase.h>
\r
42 #include <wx/fileconf.h>
\r
43 #include <wx/image.h>
\r
45 #include "res/ttedit.xpm" // *nix only, but small enough to not matter
\r
46 #include "res/toolpal1.xpm" // Docs say this is portable... Let's see!
\r
47 #include "res/cur1.xpm"
\r
48 #include "res/cur2.xpm"
\r
49 #include "res/cur3.xpm"
\r
50 #include "res/cur4.xpm"
\r
51 #include "res/cur5.xpm"
\r
52 #include "res/cur6.xpm"
\r
53 #include "res/cur7.xpm"
\r
54 #include "res/cur8.xpm"
\r
55 #include "res/tool1.xpm"
\r
56 #include "res/tool2.xpm"
\r
57 #include "res/tool3.xpm"
\r
62 #define TOOLSelect 0x00 // The "selection" tool
\r
63 #define TOOLPolySelect 0x01 // Polygon selection tool
\r
64 #define TOOLScroll 0x02 // Scroll window tool
\r
65 #define TOOLZoom 0x03 // Zoom window tool
\r
66 #define TOOLAddPt 0x04 // Add point tool
\r
67 #define TOOLAddPoly 0x05 // Polygon creation tool
\r
68 #define TOOLDelPt 0x06 // Delete point tool
\r
69 #define TOOLDelPoly 0x07 // Delete polygon tool
\r
72 // Function and Procedure Prototypes
\r
74 //BOOL CALLBACK AboutProc(HWND, UINT, WPARAM, LPARAM);
\r
75 //void MiscCenterWnd(HWND, HWND);
\r
76 //bool OnlyOneInstance(void);
\r
77 void CreateResources(void);
\r
78 bool Initialization(void);
\r
79 void DeallocateResources(void);
\r
80 void SaveAppState(void);
\r
81 void DrawRoundDot(wxDC &, int32, int32);
\r
82 void DrawSquareDot(wxDC &, int32, int32);
\r
83 void DrawRoundDotN(wxDC &, int32, int32, uint32);
\r
84 void DrawSquareDotN(wxDC &, int32, int32, uint32);
\r
85 void CreateNewDoc(void);
\r
86 bool SaveChanges(void);
\r
88 // Global constant data
\r
90 //const char className[] = "TTEDIT";
\r
91 //const char CNCharWin[] = "US_CHARWIN";
\r
92 //const char CNToolPal[] = "US_TOOLPALETTE";
\r
93 //const char CNStatus[] = "msctls_statusbar32";
\r
94 const char filter[] = "Font Files (*.TTF)\0*.TTF\0All Files (*.*)\0*.*\0";
\r
95 const char defExt[] = "ttf";
\r
96 //const char mtitle[] = "Character Window!";
\r
97 const char zoom[] = "Zoom: %u%%";
\r
99 /*const TBBUTTON tbButtons[4] = {
\r
100 { 0, ID_TBLEFT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0 },
\r
101 { 1, ID_TBRIGHT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0 },
\r
102 { 0, 0, 0, TBSTYLE_SEP, 0, 0 },
\r
103 { 2, ID_TBCHARWIN, TBSTATE_ENABLED | TBSTATE_CHECKED, TBSTYLE_CHECK, 0, 0 }
\r
108 // U N I N I T I A L I Z E D D A T A
\r
111 szSaveChanges SBYTE "Save changes to the following file?", 0Ah, 0Ah
\r
112 szFile SBYTE MAX_PATH DUP (0)
\r
113 szWindowName SBYTE (MAX_PATH + 10h) DUP (0)
\r
114 fScaleFactor REAL4 1.0 // Window scaling factor
\r
120 //HWND hMainWnd, hStatusBar, hToolBar, hCharWnd, hToolPalWnd;
\r
121 char statusBarTxt[64];
\r
122 char toolTipTxt[16];
\r
128 //HBITMAP hBMToolPal1;
\r
129 //HPEN hRedPen1, hBluePen1, hGreenPen1, hBlackPen1;
\r
130 //HBRUSH hNullBrush;
\r
132 //POINT sizeStamp, sizeTPBM, ptPrevious;
\r
133 //PTSTRUCT aPts[16];
\r
134 //uint32 numPts = 0;
\r
136 int32 ptHighlight = -1, oldPtHighlight = -1, ptNextHighlight = -1, oldPtNextHighlight = -1;
\r
137 int32 currentTool = TOOLSelect; // Current tool is "selection" tool
\r
138 bool mouseDown = false; // Mouse down flag
\r
140 //POINT ptWinOffset;
\r
141 uint32 zoomWndWidth;
\r
142 bool polyFirstPoint = true;
\r
144 char curCharName[] = "Own3d W1nd0w"; // Need to make this a buffer w/default
\r
146 //WINDOWPLACEMENT wpM, wpC;
\r
151 IMPLEMENT_APP(TTEditApp) // Run the main application loop
\r
153 bool TTEditApp::OnInit()
\r
155 wxLog * logTarget = new wxLogStderr();//fopen("!ttedit_log.txt", "wb"));
\r
156 wxLog::SetActiveTarget(logTarget);
\r
161 // Initialize all the top-level window members to NULL.
\r
164 toolPalette = NULL;
\r
168 mainFrame = new TTEditFrame(NULL, _("TTEdit"), wxPoint(155, 165), wxSize(300, 300),
\r
169 wxDEFAULT_FRAME_STYLE | wxFULL_REPAINT_ON_RESIZE);
\r
170 // wxMINIMIZE_BOX | wxRESIZE_BOX | wxMAXIMIZE_BOX | | wxSYSTEM_MENU | wxCAPTION);
\r
172 charWin = new CharWindow(NULL);//, _T("Own3d W1nd0w"), wxDefaultPosition, wxDefaultSize);
\r
173 toolPalette = new ToolWindow(mainFrame, _(""), wxDefaultPosition, wxDefaultSize,
\r
174 wxNO_BORDER | wxFRAME_NO_TASKBAR);
\r
179 int TTEditApp::OnExit()
\r
188 BEGIN_EVENT_TABLE(TTEditFrame, wxFrame)
\r
189 EVT_MENU(IDM_OPEN, TTEditFrame::OnOpen)
\r
190 EVT_MENU(IDM_EXIT, TTEditFrame::OnExit)
\r
191 EVT_MENU(IDM_ABOUT, TTEditFrame::OnAbout)
\r
192 EVT_CLOSE(TTEditFrame::OnCloseWindow)
\r
195 TTEditFrame::TTEditFrame(wxFrame * parent, const wxString &title, const wxPoint &pos,
\r
196 const wxSize &size, long style): wxFrame(parent, -1, title, pos, size, style), app(wxGetApp())
\r
198 // Initialize child subwindow members (and hopefully avoid subtle bugs)
\r
201 SetIcon(wxICON(ttedit));
\r
202 // CreateStatusBar(2); // Create 2 panes
\r
203 int widths[2] = { -1, 100 };
\r
204 wxStatusBar * sb = CreateStatusBar(2, 0); // Create 2 panes
\r
205 sb->SetStatusWidths(2, widths);
\r
206 wxToolBar * tb = CreateToolBar();
\r
212 wxBitmap tool1(tool1_xpm);
\r
213 wxBitmap tool2(tool2_xpm);
\r
214 wxBitmap tool3(tool3_xpm);
\r
216 tb->AddTool(ID_TBLEFT, _("Prev char"), tool1, _("Go to prev char"), wxITEM_NORMAL);
\r
217 tb->AddTool(ID_TBRIGHT, _("Next char"), tool2, _("Go to next char"), wxITEM_NORMAL);
\r
218 tb->AddTool(ID_TBCHARWIN, _("Char Wnd"), tool3, _("Toggle char window"), wxITEM_NORMAL);
\r
222 // Create a menu bar for the frame
\r
223 menuBar = new wxMenuBar;
\r
224 wxMenu * menu1 = new wxMenu;
\r
225 menu1->Append(IDM_NEW, _("&New\tCtrl+N"), _("Create a new font."));
\r
226 menu1->Append(IDM_OPEN, _("&Open...\tCtrl+O"), _("Opens an existing font."));
\r
227 menu1->Append(IDM_SAVE, _("&Save\tCtrl+S"), _("Save the current font."));
\r
228 menu1->Append(IDM_SAVEAS, _("Save &As..."), _("Save the current font under a different name."));
\r
229 menu1->AppendSeparator();
\r
230 menu1->Append(IDM_EXIT, _("E&xit\tAlt+X"), _("Quits the TTEdit program."));
\r
231 menuBar->Append(menu1, _("&File"));
\r
232 wxMenu * menu2 = new wxMenu;
\r
233 menu2->Append(IDM_HELPTOPICS, _("&Help Topics"), _("Displays the Help contents and index."));
\r
234 menu2->AppendSeparator();
\r
235 menu2->Append(IDM_ABOUT, _("&About TTEdit"), _("Displays information about TTEdit."));
\r
236 menuBar->Append(menu2, _("&Help"));
\r
237 SetMenuBar(menuBar);
\r
239 // Create child subwindows
\r
240 mainWindow = new TTEditWindow(this);
\r
242 Centre(wxBOTH); // Centre frame on the screen
\r
243 Show(true); // Show the frame
\r
246 TTEditFrame::~TTEditFrame()
\r
250 void TTEditFrame::OnOpen(wxCommandEvent &e)
\r
252 wxFileDialog fd(this, _("Choose a font to load"), _(""), _(""), _("TTF files (*.ttf)|*.ttf|All files (*.*)|*.*"), wxOPEN);
\r
254 if (fd.ShowModal() != wxID_OK)
\r
257 // Hmm. The font object is causing a massive crash... (gdb says it's in "Load")
\r
258 if (app.font.Load((char *)fd.GetPath().c_str()) != true)
\r
260 wxMessageDialog dlg(NULL, _("Load font failed!"), _("Houston, we have a problem..."), wxOK | wxICON_ERROR);
\r
264 //Huzzah! It works! Now just need scaling, scrolling, etc...
\r
265 // pts = app.font.GetGlyphPoints(45);
\r
268 void TTEditFrame::OnAbout(wxCommandEvent &e)
\r
270 wxMessageDialog dlg(NULL, _("TrueType Edit v1.0.0\n\nA handy tool for editing TrueType fonts!\nby James \"Shamus\" Hammons\n(C) 2006 Underground Software"), _("About TrueType Edit"), wxOK | wxICON_INFORMATION);
\r
274 void TTEditFrame::OnExit(wxCommandEvent &e)
\r
276 wxGetApp().toolPalette->Destroy();
\r
280 void TTEditFrame::OnCloseWindow(wxCloseEvent &e)
\r
282 wxGetApp().toolPalette->Destroy();
\r
286 BEGIN_EVENT_TABLE(TTEditWindow, wxWindow)
\r
287 EVT_PAINT(TTEditWindow::OnPaint)
\r
288 EVT_MOUSE_EVENTS(TTEditWindow::OnMouseEvent)
\r
291 TTEditWindow::TTEditWindow(wxFrame * parent, const wxPoint &pos, const wxSize &size, long style):
\r
292 wxWindow(parent, -1, pos, size, style), app(wxGetApp())
\r
296 offsetX = offsetY = -10;
\r
298 SetCursor(*cur[currentTool]);
\r
299 SetBackgroundColour(wxColour(0xFF, 0xFF, 0xFF));
\r
302 s.Printf(_("Zoom: %.2f%%"), scale * 100.0);
\r
303 parent->SetStatusText(s, 1);
\r
306 TTEditWindow::~TTEditWindow(void)
\r
312 void TTEditWindow::OnPaint(wxPaintEvent &e)
\r
314 /* wxPaintDC dc(this);
\r
316 // Insert your drawing code here.
\r
319 bmp = new wxBitmap(field_width * x_cell * X_UNIT + 1, field_height * y_cell * Y_UNIT + 1);
\r
324 memDC.SelectObject(*bmp);
\r
325 DrawField(&memDC, 0, 0, field_width - 1, field_height - 1);
\r
326 memDC.SelectObject(wxNullBitmap);
\r
333 memDC.SelectObject(* bmp);
\r
334 dc.Blit(0, 0, field_width * x_cell * X_UNIT + 1, field_height * y_cell * Y_UNIT + 1,
\r
335 &memDC, 0, 0, wxCOPY);
\r
336 memDC.SelectObject(wxNullBitmap);
\r
339 DrawField(&dc, 0, 0, field_width - 1, field_height - 1);*/
\r
341 wxPaintDC dc(this);
\r
343 //dc.SetBackground(*wxWHITE_BRUSH);
\r
345 // Due to the screwiness of wxWidgets coord system, the origin is ALWAYS
\r
346 // the upper left corner--regardless of axis orientation, etc...
\r
347 wxCoord width, height;
\r
348 dc.GetSize(&width, &height);
\r
350 dc.SetDeviceOrigin(-offsetX, height - (-offsetY));
\r
351 dc.SetAxisOrientation(true, true);
\r
353 // Scrolling can be done by using OffsetViewportOrgEx
\r
354 // Scaling can be done by adjusting SetWindowExtEx (it's denominator of txform)
\r
355 // you'd use: % = ViewportExt / WindowExt
\r
356 // But it makes the window look like crap: fuggetuboutit.
\r
357 // Instead, we have to scale EVERYTHING by hand. Crap!
\r
358 // It's not *that* bad, but not as convenient either...
\r
360 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0xFF), 1, wxDOT)));
\r
361 // dc.DrawLine(0, 0, 10, 10);
\r
363 // Draw coordinate axes
\r
365 dc.CrossHair(0, 0);
\r
369 for(int i=0; i<pts.GetNumPoints(); i++)
\r
371 if (i == ptHighlight)
\r
373 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));
\r
374 // SelectObject(hdc, hRedPen1);
\r
376 if (pts.GetOnCurve(i))
\r
378 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 7);
\r
379 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 9);
\r
383 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 7);
\r
384 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 9);
\r
387 else if ((i == ptHighlight || i == ptNextHighlight) && currentTool == TOOLAddPt)
\r
389 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0xAF, 0x00), 1, wxSOLID)));
\r
390 // SelectObject(hdc, hGreenPen1);
\r
392 if (pts.GetOnCurve(i))
\r
394 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 7);
\r
395 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 9);
\r
399 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 7);
\r
400 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 9);
\r
405 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));
\r
406 // SelectObject(hdc, hBlackPen1);
\r
408 if (pts.GetOnCurve(i))
\r
409 DrawSquareDot(dc, pts.GetX(i), pts.GetY(i));
\r
411 DrawRoundDot(dc, pts.GetX(i), pts.GetY(i));
\r
414 if (currentTool == TOOLDelPt && i == ptHighlight)
\r
416 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));
\r
417 // SelectObject(hdc, hRedPen1);
\r
418 // MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5, NULL);
\r
419 // LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) + 5);
\r
420 // LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5);//Lameness!
\r
421 // MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5, NULL);
\r
422 // LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) - 5);
\r
423 // LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5);//More lameness!!
\r
424 dc.DrawLine(pts.GetX(i) - 5, pts.GetY(i) - 5, pts.GetX(i) + 5, pts.GetY(i) + 5);
\r
425 dc.DrawLine(pts.GetX(i) + 5, pts.GetY(i) - 5, pts.GetX(i) - 5, pts.GetY(i) + 5);
\r
429 // SelectObject(hdc, hBlackPen1);
\r
430 dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));
\r
432 // Draw curve formed by points
\r
434 for(int poly=0; poly<pts.GetNumPolys(); poly++)
\r
436 if (pts.GetNumPoints(poly) > 2)
\r
439 // If it's not on curve, then move to it, otherwise move to last point...
\r
443 if (pts.GetOnCurve(poly, pts.GetNumPoints(poly) - 1))
\r
444 x = (wxCoord)pts.GetX(poly, pts.GetNumPoints(poly) - 1), y = (wxCoord)pts.GetY(poly, pts.GetNumPoints(poly) - 1);
\r
446 x = (wxCoord)pts.GetX(poly, 0), y = (wxCoord)pts.GetY(poly, 0);
\r
448 for(int i=0; i<pts.GetNumPoints(poly); i++)
\r
450 if (pts.GetOnCurve(poly, i))
\r
451 // LineTo(hdc, pts.GetX(poly, i), pts.GetY(poly, i));
\r
453 dc.DrawLine(x, y, pts.GetX(poly, i), pts.GetY(poly, i));
\r
454 x = (wxCoord)pts.GetX(poly, i), y = (wxCoord)pts.GetY(poly, i);
\r
458 uint32 prev = pts.GetPrev(poly, i), next = pts.GetNext(poly, i);
\r
459 float px = pts.GetX(poly, prev), py = pts.GetY(poly, prev),
\r
460 nx = pts.GetX(poly, next), ny = pts.GetY(poly, next);
\r
462 if (!pts.GetOnCurve(poly, prev))
\r
463 px = (px + pts.GetX(poly, i)) / 2.0f,
\r
464 py = (py + pts.GetY(poly, i)) / 2.0f;
\r
466 if (!pts.GetOnCurve(poly, next))
\r
467 nx = (nx + pts.GetX(poly, i)) / 2.0f,
\r
468 ny = (ny + pts.GetY(poly, i)) / 2.0f;
\r
470 Bezier(dc, point(px, py), point(pts.GetX(poly, i), pts.GetY(poly, i)), point(nx, ny));
\r
471 x = (wxCoord)nx, y = (wxCoord)ny;
\r
473 if (pts.GetOnCurve(poly, next))
\r
474 i++; // Following point is on curve, so move past it
\r
480 // SelectObject(hdc, oldPen); // Restore the stuff we disrupted...
\r
481 dc.SetPen(wxNullPen);
\r
482 // SelectObject(hdc, oldBrush);
\r
483 // EndPaint(hWnd, &ps);
\r
486 void TTEditWindow::OnMouseEvent(wxMouseEvent &e)
\r
490 wxPoint pt = ClientToScreen(e.GetPosition());
\r
491 wxGetApp().toolPalette->Move(pt);
\r
492 wxGetApp().toolPalette->Show(true);
\r
493 wxGetApp().toolPalette->SetFocus();
\r
494 wxGetApp().toolPalette->CaptureMouse();
\r
495 SetCursor(*wxSTANDARD_CURSOR);
\r
497 else if (e.LeftDown())
\r
499 if (currentTool == TOOLScroll || currentTool == TOOLZoom)
\r
500 CaptureMouse(); // Make sure we capture the mouse when in scroll/zoom mode
\r
501 else if (currentTool == TOOLAddPt) // "Add Point" tool
\r
503 if (pts.GetNumPoints() > 0)
\r
505 wxPoint pt = GetAdjustedMousePosition(e);
\r
506 pts.InsertPoint(pts.GetNext(ptHighlight), pt.x, pt.y, (e.ShiftDown() | e.ControlDown() ? false : true));
\r
507 ptHighlight = ptNextHighlight;
\r
511 else if (currentTool == TOOLAddPoly) // "Add Poly" tool
\r
514 WriteLogMsg("Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts.GetNumPoints());
\r
516 if (polyFirstPoint)
\r
518 polyFirstPoint = false;
\r
519 pts.AddNewPolyAtEnd();
\r
522 wxPoint pt = GetAdjustedMousePosition(e);
\r
523 // Append a point to the end of the structure
\r
524 pts += IPoint(pt.x, pt.y, (e.ShiftDown() | e.ControlDown() ? false : true));
\r
525 ptHighlight = pts.GetNumPoints() - 1;
\r
528 WriteLogMsg(" --> [# polys: %u, # points: %u]\n", pts.GetNumPolys(), pts.GetNumPoints());
\r
531 else if (currentTool == TOOLSelect || currentTool == TOOLPolySelect)
\r
533 if (pts.GetNumPoints() > 0)
\r
535 pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight));
\r
536 WarpPointer(pt.x, pt.y);
\r
538 if (e.ShiftDown() | e.ControlDown())
\r
539 pts.SetOnCurve(ptHighlight, !pts.GetOnCurve(ptHighlight));
\r
542 else if (currentTool == TOOLDelPt)
\r
544 if (pts.GetNumPoints() > 0)
\r
546 // if (ptHighlight != -1)
\r
548 //This assumes that WM_MOUSEMOVE happens before this!
\r
549 //The above commented out line should take care of this contingency... !!! FIX !!!
\r
550 pts.DeletePoint(ptHighlight);
\r
555 else if (e.LeftUp())
\r
557 // mouseDown = false;
\r
559 if (currentTool == TOOLScroll || currentTool == TOOLZoom)
\r
560 // ReleaseCapture();
\r
563 else if (e.Dragging())
\r
565 //Do this here? Needed? SetCursor(hCur[currentTool]);
\r
567 // Extract current point from lParam/calc offset from previous point
\r
569 pt = e.GetPosition();
\r
570 ptOffset.x = pt.x - ptPrevious.x,
\r
571 ptOffset.y = pt.y - ptPrevious.y;
\r
573 // if (e.LeftIsDown())
\r
575 if (currentTool == TOOLScroll)
\r
577 // NOTE: OffsetViewportOrg operates in DEVICE UNITS...
\r
579 //Seems there's no equivalent for this in wxWidgets...!
\r
581 // hdc = GetDC(hWnd);
\r
582 // OffsetViewportOrgEx(hdc, ptOffset.x, ptOffset.y, NULL);
\r
583 // ReleaseDC(hWnd, hdc);
\r
585 // this shows that it works, so the logic above must be faulty...
\r
586 // And it is. It should convert the coords first, then do the subtraction to figure the offset...
\r
588 // Then multiply it by the scaling factor. Whee!
\r
589 // This looks wacky because we're using screen coords for the offset...
\r
590 // Otherwise, we would subtract both offsets!
\r
591 offsetX -= ptOffset.x, offsetY += ptOffset.y;
\r
594 else if (currentTool == TOOLAddPt || currentTool == TOOLAddPoly || currentTool == TOOLSelect)
\r
596 if (currentTool != TOOLAddPt || pts.GetNumPoints() > 0)//yecch.
\r
598 wxPoint pt2 = GetAdjustedMousePosition(e);
\r
599 pts.SetXY(ptHighlight, pt2.x, pt2.y);
\r
603 else if (currentTool == TOOLPolySelect)
\r
605 if (pts.GetNumPoints() > 0)
\r
607 wxPoint pt2 = GetAdjustedMousePosition(e);
\r
608 // Should also set onCurve here as well, depending on keystate
\r
610 pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x - pts.GetX(ptHighlight), pt2.y - pts.GetY(ptHighlight));
\r
618 else if (e.Moving())
\r
620 // else // Moving, not dragging...
\r
622 if (currentTool == TOOLSelect || currentTool == TOOLDelPt || currentTool == TOOLAddPt
\r
623 || currentTool == TOOLPolySelect)// || currentTool == TOOLAddPoly)
\r
625 wxPoint pt2 = GetAdjustedMousePosition(e);
\r
626 double closest = 1.0e+99;
\r
628 for(int i=0; i<pts.GetNumPoints(); i++)
\r
630 double dist = ((pt2.x - pts.GetX(i)) * (pt2.x - pts.GetX(i)))
\r
631 + ((pt2.y - pts.GetY(i)) * (pt2.y - pts.GetY(i)));
\r
633 if (dist < closest)
\r
634 closest = dist, ptHighlight = i;
\r
637 if (ptHighlight != oldPtHighlight)
\r
639 oldPtHighlight = ptHighlight;
\r
643 // What follows here looks like voodoo, but is really simple. What we do is
\r
644 // check to see if the mouse point has a perpendicular intersection with any of
\r
645 // the line segments. If it does, calculate the length of the perpendicular
\r
646 // and choose the smallest length. If there is no perpendicular, then choose the
\r
647 // length of line connecting the closer of either the first endpoint or the
\r
648 // second and choose the smallest of those.
\r
650 // There is one bit of math that looks like voodoo to me ATM--will explain once
\r
651 // I understand it better (the calculation of the length of the perpendicular).
\r
653 if (pts.GetNumPoints() > 1 && currentTool == TOOLAddPt)
\r
655 double smallest = 1.0e+99;
\r
657 for(int i=0; i<pts.GetNumPoints(); i++)
\r
659 int32 p1x = pts.GetX(i), p1y = pts.GetY(i),
\r
660 p2x = pts.GetX(pts.GetNext(i)), p2y = pts.GetY(pts.GetNext(i));
\r
662 vector ls(p2x, p2y, 0, p1x, p1y, 0), v1(pt2.x, pt2.y, 0, p1x, p1y, 0),
\r
663 v2(pt2.x, pt2.y, 0, p2x, p2y, 0);
\r
664 double pp = ls.dot(v1) / ls.length(), dist;
\r
665 // Geometric interpretation:
\r
666 // pp is the paremeterized point on the vector ls where the perpendicular intersects ls.
\r
667 // If pp < 0, then the perpendicular lies beyond the 1st endpoint. If pp > length of ls,
\r
668 // then the perpendicular lies beyond the 2nd endpoint.
\r
671 dist = v1.length();
\r
672 else if (pp > ls.length())
\r
673 dist = v2.length();
\r
674 else // distance = ?Det?(ls, v1) / |ls|
\r
675 dist = fabs((ls.x * v1.y - v1.x * ls.y) / ls.length());
\r
677 //The answer to the above looks like it might be found here:
\r
679 //If the segment endpoints are s and e, and the point is p, then the test for the perpendicular
\r
680 //intercepting the segment is equivalent to insisting that the two dot products {s-e}.{s-p} and
\r
681 //{e-s}.{e-p} are both non-negative. Perpendicular distance from the point to the segment is
\r
682 //computed by first computing the area of the triangle the three points form, then dividing by the
\r
683 //length of the segment. Distances are done just by the Pythagorean theorem. Twice the area of the
\r
684 //triangle formed by three points is the determinant of the following matrix:
\r
690 //(???) By translating the start point to the origin, this can be rewritten as:
\r
691 //By subtracting row 1 from all rows, you get the following:
\r
694 //(ex - sx) (ey - sy) 0
\r
695 //(px - sx) (py - sy) 0
\r
697 //which greatly simplifies the calculation of the determinant.
\r
699 if (dist < smallest)
\r
700 smallest = dist, ptNextHighlight = pts.GetNext(i), ptHighlight = i;
\r
703 if (ptNextHighlight != oldPtNextHighlight)
\r
705 oldPtNextHighlight = ptNextHighlight;
\r
712 ptPrevious = e.GetPosition();
\r
717 wxPoint TTEditWindow::GetAdjustedMousePosition(wxMouseEvent &e)
\r
719 wxCoord width, height;
\r
720 wxClientDC dc(this);
\r
722 dc.GetSize(&width, &height);
\r
723 dc.SetDeviceOrigin(-offsetX, height - (-offsetY));
\r
724 dc.SetAxisOrientation(true, true);
\r
726 /*wxStatusBar * sb = ((wxFrame *)GetParent())->GetStatusBar();
\r
728 s.Printf("Logical mouse pos: %d, %d (%d, %d)", pt.x, pt.y, width, height);
\r
729 sb->SetStatusText(s);//*/
\r
731 return e.GetLogicalPosition(dc);
\r
734 wxPoint TTEditWindow::GetAdjustedClientPosition(wxCoord x, wxCoord y)
\r
736 wxCoord width, height;
\r
737 wxClientDC dc(this);
\r
739 dc.GetSize(&width, &height);
\r
740 dc.SetDeviceOrigin(-offsetX, height - (-offsetY));
\r
741 dc.SetAxisOrientation(true, true);
\r
743 return wxPoint(dc.LogicalToDeviceX(x), dc.LogicalToDeviceY(y));
\r
748 void CreateResources(void)
\r
750 // This is a sucky way to create cursors, but at least it's cross-platform...
\r
751 // NOTE: Need to fix hotspots on a few... !!! FIX !!!
\r
753 wxBitmap cursorBM1(cur1_xpm);
\r
754 wxImage cursorImage1 = cursorBM1.ConvertToImage();
\r
755 cursorImage1.SetMaskFromImage(cursorImage1, 0xFF, 0xFF, 0xFF);
\r
756 cur[0] = new wxCursor(cursorImage1);
\r
758 wxBitmap cursorBM2(cur2_xpm);
\r
759 wxImage cursorImage2 = cursorBM2.ConvertToImage();
\r
760 cursorImage2.SetMaskFromImage(cursorImage2, 0xFF, 0xFF, 0xFF);
\r
761 cur[1] = new wxCursor(cursorImage2);
\r
763 wxBitmap cursorBM3(cur3_xpm);
\r
764 wxImage cursorImage3 = cursorBM3.ConvertToImage();
\r
765 cursorImage3.SetMaskFromImage(cursorImage3, 0xFF, 0xFF, 0xFF);
\r
766 cur[2] = new wxCursor(cursorImage3);
\r
768 wxBitmap cursorBM4(cur4_xpm);
\r
769 wxImage cursorImage4 = cursorBM4.ConvertToImage();
\r
770 cursorImage4.SetMaskFromImage(cursorImage4, 0xFF, 0xFF, 0xFF);
\r
771 cur[3] = new wxCursor(cursorImage4);
\r
773 wxBitmap cursorBM5(cur5_xpm);
\r
774 wxImage cursorImage5 = cursorBM5.ConvertToImage();
\r
775 cursorImage5.SetMaskFromImage(cursorImage5, 0xFF, 0xFF, 0xFF);
\r
776 cur[4] = new wxCursor(cursorImage5);
\r
778 wxBitmap cursorBM6(cur6_xpm);
\r
779 wxImage cursorImage6 = cursorBM6.ConvertToImage();
\r
780 cursorImage6.SetMaskFromImage(cursorImage6, 0xFF, 0xFF, 0xFF);
\r
781 cur[5] = new wxCursor(cursorImage6);
\r
783 wxBitmap cursorBM7(cur7_xpm);
\r
784 wxImage cursorImage7 = cursorBM7.ConvertToImage();
\r
785 cursorImage7.SetMaskFromImage(cursorImage7, 0xFF, 0xFF, 0xFF);
\r
786 cur[6] = new wxCursor(cursorImage7);
\r
788 wxBitmap cursorBM8(cur8_xpm);
\r
789 wxImage cursorImage8 = cursorBM8.ConvertToImage();
\r
790 cursorImage8.SetMaskFromImage(cursorImage8, 0xFF, 0xFF, 0xFF);
\r
791 cur[7] = new wxCursor(cursorImage8);
\r
795 // Draw a round dot (5x5, centered on [x, y])
\r
797 void DrawRoundDot(wxDC &dc, int32 x, int32 y)
\r
801 pt[0].x = x - 1, pt[0].y = y - 2;
\r
802 pt[1].x = x + 1, pt[1].y = y - 2;
\r
803 pt[2].x = x + 2, pt[2].y = y - 1;
\r
804 pt[3].x = x + 2, pt[3].y = y + 1;
\r
805 pt[4].x = x + 1, pt[4].y = y + 2;
\r
806 pt[5].x = x - 1, pt[5].y = y + 2;
\r
807 pt[6].x = x - 2, pt[6].y = y + 1;
\r
808 pt[7].x = x - 2, pt[7].y = y - 1;
\r
810 dc.DrawPolygon(8, pt);
\r
814 // Draw a sqaure dot (5x5, centered on [x, y])
\r
816 void DrawSquareDot(wxDC &dc, int32 x, int32 y)
\r
820 pt[0].x = x - 2, pt[0].y = y - 2;
\r
821 pt[1].x = x + 2, pt[1].y = y - 2;
\r
822 pt[2].x = x + 2, pt[2].y = y + 2;
\r
823 pt[3].x = x - 2, pt[3].y = y + 2;
\r
825 dc.DrawPolygon(4, pt);
\r
829 // Draw a sqaure dot (nxn, centered on [x, y])
\r
831 void DrawSquareDotN(wxDC &dc, int32 x, int32 y, uint32 n)
\r
834 uint32 offset = (n - 1) / 2;
\r
836 pt[0].x = x - offset, pt[0].y = y - offset;
\r
837 pt[1].x = x + offset, pt[1].y = y - offset;
\r
838 pt[2].x = x + offset, pt[2].y = y + offset;
\r
839 pt[3].x = x - offset, pt[3].y = y + offset;
\r
841 dc.DrawPolygon(4, pt);
\r
845 // Draw a round dot (nxn, centered on [x, y])
\r
847 void DrawRoundDotN(wxDC &dc, int32 x, int32 y, uint32 n)
\r
849 dc.DrawCircle(x, y, (n / 2) + 1);
\r
853 BEGIN_EVENT_TABLE(CharWindow, wxWindow)
\r
854 // EVT_PAINT(CharWindow::OnPaint)
\r
855 // EVT_MOUSE_EVENTS(CharWindow::OnMouseEvent)
\r
858 CharWindow::CharWindow(wxFrame * parent, const wxPoint &pos, const wxSize &size, long style):
\r
859 wxWindow(parent, -1, pos, size, style)
\r
863 CharWindow::~CharWindow()
\r
868 BEGIN_EVENT_TABLE(ToolWindow, wxWindow)
\r
869 EVT_PAINT(ToolWindow::OnPaint)
\r
870 EVT_MOUSE_EVENTS(ToolWindow::OnMouseEvent)
\r
873 ToolWindow::ToolWindow(wxFrame * parent, const wxString &title, const wxPoint &pos,
\r
874 const wxSize &size, long style): wxFrame(parent, -1, title, pos, size, style)
\r
875 //ToolWindow::ToolWindow(wxFrame * parent, const wxPoint &pos, const wxSize &size, long style):
\r
876 // wxWindow(parent, -1, pos, size, style)
\r
878 bmp = new wxBitmap(toolpal1_xpm);
\r
883 sizeTPBM.x = bmp->GetWidth(), sizeTPBM.y = bmp->GetHeight();
\r
884 sizeStamp.x = sizeTPBM.x / 4, sizeStamp.y = sizeTPBM.y / 2;
\r
886 SetSize(10, 10, sizeTPBM.x, sizeTPBM.y);
\r
890 ToolWindow::~ToolWindow()
\r
894 void ToolWindow::OnPaint(wxPaintEvent &e)
\r
896 wxPaintDC dc(this);
\r
899 memDC.SelectObject(*bmp);
\r
900 dc.Blit(0, 0, sizeTPBM.x, sizeTPBM.y, &memDC, 0, 0, wxCOPY);
\r
902 int32 tool = FindSelectedTool();
\r
906 //need ul corner of bitmap, ul corner of dest, width/height
\r
907 wxPoint pt(sizeStamp.x * (tool & 0x03), sizeStamp.y * (tool >> 2));
\r
908 dc.Blit(pt.x, pt.y, sizeStamp.x, sizeStamp.y, &memDC, pt.x, pt.y, wxSRC_INVERT);
\r
911 memDC.SelectObject(wxNullBitmap);
\r
914 void ToolWindow::OnMouseEvent(wxMouseEvent &e)
\r
919 int32 tool = FindSelectedTool();
\r
921 if (tool != prevTool)
\r
930 int32 tool = FindSelectedTool(), oldTool = currentTool;
\r
933 currentTool = tool;
\r
935 if (currentTool != TOOLSelect && currentTool != TOOLDelPt && currentTool != TOOLAddPt
\r
936 && currentTool != TOOLPolySelect)
\r
939 if (currentTool != oldTool)
\r
942 if (currentTool == TOOLAddPoly)
\r
946 polyFirstPoint = true;
\r
948 sprintf(strBuf, "--> Selected poly tool, polyFirstPoint is %s\n", polyFirstPoint ? "true" : "false");
\r
949 WriteLogMsg(strBuf);
\r
955 wxGetApp().mainFrame->mainWindow->SetCursor(*cur[currentTool]);
\r
956 wxGetApp().mainFrame->mainWindow->SetFocus(); // Make sure the main wnd keeps focus!
\r
961 // Find which tool we're pointing at
\r
962 // Use: xcoord = mouse.x / (bmsize.x/4), ycoord = mouse.y / (bmsize.y/2)
\r
964 int32 ToolWindow::FindSelectedTool(void)
\r
966 wxPoint pt = ScreenToClient(wxGetMousePosition());
\r
967 uint32 x = (uint32)pt.x / sizeStamp.x, y = (uint32)pt.y / sizeStamp.y, tool = (uint32)-1;
\r
969 if (x < 4 && y < 2)
\r
970 tool = (y * 4) + x;
\r
977 LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
\r
981 POINT pt, ptOffset;
\r
989 MiscCenterWnd(hWnd, GetDesktopWindow());
\r
990 InitCommonControls();
\r
991 hStatusBar = CreateStatusWindow(WS_CHILD | WS_VISIBLE, statusBarTxt, hWnd, ID_STATUSBAR);
\r
996 // clean this crap up!
\r
997 // well, the only crappy thing here is using a POINT as an int array, but otherwise, this is OK
\r
998 wsprintf(strBuf, zoom, 1000);
\r
1000 GetTextExtentPoint32(hdc, strBuf, lstrlen(strBuf), &sz);
\r
1001 ReleaseDC(hWnd, hdc);
\r
1002 zoomWndWidth = sz.cx;
\r
1003 wsprintf(strBuf, zoom, 100);
\r
1005 GetClientRect(hWnd, &rc1);
\r
1006 pt.x = rc1.right - zoomWndWidth, pt.y = -1;
\r
1007 SendMessage(hStatusBar, SB_SETPARTS, 2, (LPARAM)&pt);
\r
1008 SendMessage(hStatusBar, SB_SETTEXT, (0 | SBT_NOBORDERS), (LPARAM)statusBarTxt);
\r
1009 SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM)strBuf);
\r
1011 hToolBar = CreateToolbarEx(hWnd, WS_CHILD | WS_BORDER | WS_VISIBLE | TBSTYLE_TOOLTIPS,
\r
1012 IDR_TOOLBAR1, 3, hInst, IDB_TOOLBAR1, tbButtons, 4, 16, 16, 16, 16, sizeof(TBBUTTON));
\r
1019 // The following can only be done because we use a private DC (using "CS_OWNDC")
\r
1020 // (Is that true???)
\r
1021 // Set the mapping to draw the character so it fits in the viewport...
\r
1022 hdc = GetDC(hWnd);
\r
1023 GetClientRect(hWnd, &rc1);
\r
1024 GetClientRect(hStatusBar, &rc2);
\r
1025 rc1.bottom -= rc2.bottom;
\r
1026 SetMapMode(hdc, MM_ISOTROPIC);
\r
1027 SetWindowExtEx(hdc, rc1.right, rc1.bottom, NULL);
\r
1028 SetViewportExtEx(hdc, rc1.right, -rc1.bottom, NULL);
\r
1029 SetViewportOrgEx(hdc, 0, rc1.bottom, NULL);
\r
1030 ReleaseDC(hWnd, hdc);
\r
1035 if (SaveChanges())
\r
1037 wpM.length = wpC.length = sizeof(WINDOWPLACEMENT);
\r
1038 GetWindowPlacement(hMainWnd, &wpM);
\r
1039 GetWindowPlacement(hCharWnd, &wpC);
\r
1041 if (!IsWindowVisible(hCharWnd)) // Needed because Windows lies about visibility
\r
1042 wpC.showCmd = SW_HIDE;
\r
1044 hdc = GetDC(hWnd);
\r
1045 GetViewportOrgEx(hdc, &ptVPM);
\r
1046 ReleaseDC(hWnd, hdc);
\r
1048 DestroyWindow(hWnd);
\r
1055 PostQuitMessage(0);
\r
1058 case WM_NCLBUTTONDOWN:
\r
1060 if (wParam == HTCAPTION)
\r
1062 NCMouseDown = true;
\r
1063 GetWindowRect(hMainWnd, &rc1);
\r
1064 GetWindowRect(hCharWnd, &rc2);
\r
1065 ptWinOffset.x = rc2.left - rc1.left;
\r
1066 ptWinOffset.y = rc2.top - rc1.top;
\r
1069 // Let Windows do its thing with this msg, or weird things will happen...
\r
1071 DefWindowProc(hWnd, msgID, wParam, lParam);
\r
1072 NCMouseDown = false;
\r
1075 case WM_WINDOWPOSCHANGING:
\r
1079 WINDOWPOS * wp = (WINDOWPOS *)lParam;
\r
1081 if (wp->hwnd == hMainWnd && !(wp->flags & SWP_NOMOVE))
\r
1082 SetWindowPos(hCharWnd, 0, wp->x + ptWinOffset.x, wp->y + ptWinOffset.y,
\r
1083 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
\r
1086 return DefWindowProc(hWnd, msgID, wParam, lParam); // Seems this is needed... Bleah!
\r
1090 hdc = BeginPaint(hWnd, &ps);
\r
1092 // Scrolling can be done by using OffsetViewportOrgEx
\r
1093 // Scaling can be done by adjusting SetWindowExtEx (it's denominator of txform)
\r
1094 // you'd use: % = ViewportExt / WindowExt
\r
1095 // But it makes the window look like crap: fuggetuboutit.
\r
1096 // Instead, we have to scale EVERYTHING by hand. Crap!
\r
1098 // Apparently, you *must* save the individual object types (pen, brush, etc.)
\r
1100 HGDIOBJ oldPen = SelectObject(hdc, hBluePen1),
\r
1101 oldBrush = SelectObject(hdc, hNullBrush);
\r
1103 // Draw coordinate axes
\r
1105 MoveToEx(hdc, 0, -32000, NULL);
\r
1106 LineTo(hdc, 0, 32000);
\r
1107 MoveToEx(hdc, -32000, 0, NULL);
\r
1108 LineTo(hdc, 32000, 0);
\r
1112 for(int i=0; i<pts.GetNumPoints(); i++)
\r
1114 if (i == ptHighlight)
\r
1116 SelectObject(hdc, hRedPen1);
\r
1118 if (pts.GetOnCurve(i))
\r
1120 DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 7);
\r
1121 DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 9);
\r
1125 DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 7);
\r
1126 DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 9);
\r
1129 else if ((i == ptHighlight || i == ptNextHighlight) && currentTool == TOOLAddPt)
\r
1131 SelectObject(hdc, hGreenPen1);
\r
1133 if (pts.GetOnCurve(i))
\r
1135 DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 7);
\r
1136 DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 9);
\r
1140 DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 7);
\r
1141 DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 9);
\r
1146 SelectObject(hdc, hBlackPen1);
\r
1148 if (pts.GetOnCurve(i))
\r
1149 DrawSquareDot(hdc, pts.GetX(i), pts.GetY(i));
\r
1151 DrawRoundDot(hdc, pts.GetX(i), pts.GetY(i));
\r
1154 if (currentTool == TOOLDelPt && i == ptHighlight)
\r
1156 SelectObject(hdc, hRedPen1);
\r
1157 MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5, NULL);
\r
1158 LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) + 5);
\r
1159 LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) - 5);//Lameness!
\r
1160 MoveToEx(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5, NULL);
\r
1161 LineTo(hdc, pts.GetX(i) + 5, pts.GetY(i) - 5);
\r
1162 LineTo(hdc, pts.GetX(i) - 5, pts.GetY(i) + 5);//More lameness!!
\r
1166 SelectObject(hdc, hBlackPen1);
\r
1168 // Draw curve formed by points
\r
1170 for(int poly=0; poly<pts.GetNumPolys(); poly++)
\r
1172 if (pts.GetNumPoints(poly) > 2)
\r
1174 // Initial move...
\r
1175 // If it's not on curve, then move to it, otherwise move to last point...
\r
1177 if (pts.GetOnCurve(poly, pts.GetNumPoints(poly) - 1))
\r
1178 MoveToEx(hdc, pts.GetX(poly, pts.GetNumPoints(poly) - 1), pts.GetY(poly, pts.GetNumPoints(poly) - 1), NULL);
\r
1180 MoveToEx(hdc, pts.GetX(poly, 0), pts.GetY(poly, 0), NULL);
\r
1182 for(int i=0; i<pts.GetNumPoints(poly); i++)
\r
1184 if (pts.GetOnCurve(poly, i))
\r
1185 LineTo(hdc, pts.GetX(poly, i), pts.GetY(poly, i));
\r
1188 uint32 prev = pts.GetPrev(poly, i), next = pts.GetNext(poly, i);
\r
1189 float px = pts.GetX(poly, prev), py = pts.GetY(poly, prev),
\r
1190 nx = pts.GetX(poly, next), ny = pts.GetY(poly, next);
\r
1192 if (!pts.GetOnCurve(poly, prev))
\r
1193 px = (px + pts.GetX(poly, i)) / 2.0f,
\r
1194 py = (py + pts.GetY(poly, i)) / 2.0f;
\r
1196 if (!pts.GetOnCurve(poly, next))
\r
1197 nx = (nx + pts.GetX(poly, i)) / 2.0f,
\r
1198 ny = (ny + pts.GetY(poly, i)) / 2.0f;
\r
1200 Bezier(hdc, point(px, py), point(pts.GetX(poly, i), pts.GetY(poly, i)), point(nx, ny));
\r
1202 if (pts.GetOnCurve(poly, next))
\r
1203 i++; // Following point is on curve, so move past it
\r
1209 SelectObject(hdc, oldPen); // Restore the stuff we disrupted...
\r
1210 SelectObject(hdc, oldBrush);
\r
1211 EndPaint(hWnd, &ps);
\r
1216 // Apparently this is needed since these windows don't update themselves.
\r
1217 SendMessage(hStatusBar, msgID, wParam, lParam);
\r
1218 SendMessage(hToolBar, msgID, wParam, lParam);
\r
1220 // This is needed to make the 2nd status pane visible
\r
1221 GetClientRect(hWnd, &rc1);
\r
1222 pt.x = rc1.right - zoomWndWidth, pt.y = -1;
\r
1223 SendMessage(hStatusBar, SB_SETPARTS, 2, (LPARAM)&pt);
\r
1226 case WM_RBUTTONDOWN:
\r
1228 GetCursorPos(&pt);
\r
1229 SetWindowPos(hToolPalWnd, 0, pt.x, pt.y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
\r
1230 SetFocus(hToolPalWnd);
\r
1231 SetCapture(hToolPalWnd); // Ensure tool palette gets RButtonUp
\r
1232 SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW))); // Tool pallete has "regular" cursor
\r
1235 case WM_LBUTTONDOWN:
\r
1239 if (currentTool == TOOLScroll || currentTool == TOOLZoom)
\r
1240 SetCapture(hWnd); // Make sure we capture the mouse when in scroll/zoom mode
\r
1241 else if (currentTool == TOOLAddPt) // "Add Point" tool
\r
1243 if (pts.GetNumPoints() > 0)
\r
1245 //Do we really need to put a cap on this???
\r
1247 // if (pts.GetNumPoints() < 16)
\r
1249 pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;
\r
1250 hdc = GetDC(hWnd);
\r
1251 DPtoLP(hdc, &pt, 1);
\r
1252 pts.InsertPoint(pts.GetNext(ptHighlight), pt.x, pt.y, (wParam & (MK_SHIFT | MK_CONTROL) ? false : true));
\r
1253 ptHighlight = ptNextHighlight;
\r
1254 ReleaseDC(hWnd, hdc);
\r
1255 InvalidateRect(hWnd, NULL, TRUE);
\r
1259 else if (currentTool == TOOLAddPoly) // "Add Poly" tool
\r
1262 wsprintf(strBuf, "Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts.GetNumPoints());
\r
1263 WriteLogMsg(strBuf);
\r
1265 if (polyFirstPoint)
\r
1267 polyFirstPoint = false;
\r
1268 pts.AddNewPolyAtEnd();
\r
1271 //Do we really need to put a cap on this???
\r
1273 // if (pts.GetNumPoints() < 16)
\r
1275 pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;
\r
1276 hdc = GetDC(hWnd);
\r
1277 DPtoLP(hdc, &pt, 1);
\r
1278 ReleaseDC(hWnd, hdc);
\r
1279 // Append a point to the end of the structure
\r
1280 pts += IPoint(pt.x, pt.y, (wParam & (MK_SHIFT | MK_CONTROL) ? false : true));
\r
1281 ptHighlight = pts.GetNumPoints() - 1;
\r
1282 InvalidateRect(hWnd, NULL, TRUE);
\r
1285 wsprintf(strBuf, " --> [# polys: %u, # points: %u]\xD\xA", pts.GetNumPolys(), pts.GetNumPoints());
\r
1286 WriteLogMsg(strBuf);
\r
1289 else if (currentTool == TOOLSelect || currentTool == TOOLPolySelect)
\r
1291 if (pts.GetNumPoints() > 0)
\r
1293 pt.x = pts.GetX(ptHighlight), pt.y = pts.GetY(ptHighlight);
\r
1294 hdc = GetDC(hWnd);
\r
1295 LPtoDP(hdc, &pt, 1);
\r
1296 ClientToScreen(hWnd, &pt);
\r
1297 SetCursorPos(pt.x, pt.y);
\r
1298 ReleaseDC(hWnd, hdc);
\r
1300 if (wParam & (MK_SHIFT | MK_CONTROL))
\r
1301 pts.SetOnCurve(ptHighlight, !pts.GetOnCurve(ptHighlight));
\r
1304 else if (currentTool == TOOLDelPt)
\r
1306 if (pts.GetNumPoints() > 0)
\r
1308 // if (ptHighlight != -1)
\r
1310 //This assumes that WM_MOUSEMOVE happens before this!
\r
1311 //The above commented out line should take care of this contingency... !!! FIX !!!
\r
1312 pts.DeletePoint(ptHighlight);
\r
1313 InvalidateRect(hWnd, NULL, TRUE);
\r
1319 case WM_LBUTTONUP:
\r
1321 mouseDown = false;
\r
1323 if (currentTool == TOOLScroll || currentTool == TOOLZoom)
\r
1328 case WM_MOUSEMOVE:
\r
1330 SetCursor(hCur[currentTool]);
\r
1332 // Extract current point from lParam/calc offset from previous point
\r
1334 pt.x = lParam & 0xFFFF, pt.y = lParam >> 16;
\r
1335 ptOffset.x = pt.x - ptPrevious.x,
\r
1336 ptOffset.y = pt.y - ptPrevious.y;
\r
1340 if (currentTool == TOOLScroll)
\r
1342 // NOTE: OffsetViewportOrg operates in DEVICE UNITS...
\r
1344 hdc = GetDC(hWnd);
\r
1345 OffsetViewportOrgEx(hdc, ptOffset.x, ptOffset.y, NULL);
\r
1346 ReleaseDC(hWnd, hdc);
\r
1348 // this shows that it works, so the logic above must be faulty...
\r
1349 // And it is. It should convert the coords first, then do the subtraction to figure the offset...
\r
1351 // Then multiply it by the scaling factor. Whee!
\r
1353 InvalidateRect(hWnd, NULL, TRUE);
\r
1354 // SendMessage(hWnd, WM_PAINT, NULL, NULL);
\r
1356 else if (currentTool == TOOLAddPt || currentTool == TOOLAddPoly || currentTool == TOOLSelect)
\r
1358 if (currentTool != TOOLAddPt || pts.GetNumPoints() > 0)//yecch.
\r
1361 pt2.x = pt.x, pt2.y = pt.y;
\r
1362 // Should also set onCurve here as well, depending on keystate
\r
1364 hdc = GetDC(hWnd);
\r
1365 DPtoLP(hdc, &pt2, 1);
\r
1366 pts.SetXY(ptHighlight, pt2.x, pt2.y);
\r
1367 ReleaseDC(hWnd, hdc);
\r
1368 InvalidateRect(hWnd, NULL, TRUE);
\r
1371 else if (currentTool == TOOLPolySelect)
\r
1373 if (pts.GetNumPoints() > 0)
\r
1376 pt2.x = pt.x, pt2.y = pt.y;
\r
1377 // Should also set onCurve here as well, depending on keystate
\r
1379 hdc = GetDC(hWnd);
\r
1380 DPtoLP(hdc, &pt2, 1);
\r
1381 pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x - pts.GetX(ptHighlight), pt2.y - pts.GetY(ptHighlight));
\r
1382 ReleaseDC(hWnd, hdc);
\r
1383 InvalidateRect(hWnd, NULL, TRUE);
\r
1389 if (currentTool == TOOLSelect || currentTool == TOOLDelPt || currentTool == TOOLAddPt
\r
1390 || currentTool == TOOLPolySelect)// || currentTool == TOOLAddPoly)
\r
1393 pt2.x = pt.x, pt2.y = pt.y;
\r
1394 hdc = GetDC(hWnd);
\r
1395 DPtoLP(hdc, &pt2, 1);
\r
1396 ReleaseDC(hWnd, hdc);
\r
1398 double closest = 1.0e+99;
\r
1400 for(int i=0; i<pts.GetNumPoints(); i++)
\r
1402 double dist = ((pt2.x - pts.GetX(i)) * (pt2.x - pts.GetX(i)))
\r
1403 + ((pt2.y - pts.GetY(i)) * (pt2.y - pts.GetY(i)));
\r
1405 if (dist < closest)
\r
1406 closest = dist, ptHighlight = i;
\r
1409 if (ptHighlight != oldPtHighlight)
\r
1411 oldPtHighlight = ptHighlight;
\r
1412 InvalidateRect(hWnd, NULL, TRUE);
\r
1415 // What follows here looks like voodoo, but is really simple. What we do is
\r
1416 // check to see if the mouse point has a perpendicular intersection with any of
\r
1417 // the line segments. If it does, calculate the length of the perpendicular
\r
1418 // and choose the smallest length. If there is no perpendicular, then choose the
\r
1419 // length of line connecting the closer of either the first endpoint or the
\r
1420 // second and choose the smallest of those.
\r
1422 // There is one bit of math that looks like voodoo to me ATM--will explain once
\r
1423 // I understand it better (the calculation of the length of the perpendicular).
\r
1425 if (pts.GetNumPoints() > 1 && currentTool == TOOLAddPt)
\r
1427 double smallest = 1.0e+99;
\r
1429 for(int i=0; i<pts.GetNumPoints(); i++)
\r
1431 int32 p1x = pts.GetX(i), p1y = pts.GetY(i),
\r
1432 p2x = pts.GetX(pts.GetNext(i)), p2y = pts.GetY(pts.GetNext(i));
\r
1434 vector ls(p2x, p2y, 0, p1x, p1y, 0), v1(pt2.x, pt2.y, 0, p1x, p1y, 0),
\r
1435 v2(pt2.x, pt2.y, 0, p2x, p2y, 0);
\r
1436 double pp = ls.dot(v1) / ls.length(), dist;
\r
1437 // Geometric interpretation:
\r
1438 // pp is the paremeterized point on the vector ls where the perpendicular intersects ls.
\r
1439 // If pp < 0, then the perpendicular lies beyond the 1st endpoint. If pp > length of ls,
\r
1440 // then the perpendicular lies beyond the 2nd endpoint.
\r
1443 dist = v1.length();
\r
1444 else if (pp > ls.length())
\r
1445 dist = v2.length();
\r
1446 else // distance = ?Det?(ls, v1) / |ls|
\r
1447 dist = abs((ls.x * v1.y - v1.x * ls.y) / ls.length());
\r
1449 //The answer to the above looks like it might be found here:
\r
1451 //If the segment endpoints are s and e, and the point is p, then the test for the perpendicular
\r
1452 //intercepting the segment is equivalent to insisting that the two dot products {s-e}.{s-p} and
\r
1453 //{e-s}.{e-p} are both non-negative. Perpendicular distance from the point to the segment is
\r
1454 //computed by first computing the area of the triangle the three points form, then dividing by the
\r
1455 //length of the segment. Distances are done just by the Pythagorean theorem. Twice the area of the
\r
1456 //triangle formed by three points is the determinant of the following matrix:
\r
1462 //(???) By translating the start point to the origin, this can be rewritten as:
\r
1463 //By subtracting row 1 from all rows, you get the following:
\r
1466 //(ex - sx) (ey - sy) 0
\r
1467 //(px - sx) (py - sy) 0
\r
1469 //which greatly simplifies the calculation of the determinant.
\r
1471 if (dist < smallest)
\r
1472 smallest = dist, ptNextHighlight = pts.GetNext(i), ptHighlight = i;
\r
1475 if (ptNextHighlight != oldPtNextHighlight)
\r
1477 oldPtNextHighlight = ptNextHighlight;
\r
1478 InvalidateRect(hWnd, NULL, TRUE);
\r
1484 ptPrevious.x = pt.x, ptPrevious.y = pt.y;
\r
1490 if (((NMHDR *)lParam)->code == TTN_NEEDTEXT)
\r
1492 LoadString(hInst, ((TOOLTIPTEXT *)lParam)->hdr.idFrom + 0x80, toolTipTxt, 16);
\r
1493 ((TOOLTIPTEXT *)lParam)->lpszText = toolTipTxt;
\r
1498 case WM_MENUSELECT:
\r
1500 statusBarTxt[0] = 0; // Clear status bar text
\r
1501 uint16 flags = wParam >> 16; // Extract flags
\r
1503 if (!(flags & MFT_SEPARATOR))
\r
1505 uint16 id = wParam & 0xFFFF;
\r
1507 if (flags & MF_POPUP)
\r
1509 if (flags & MF_SYSMENU)
\r
1512 id = IDM_FILEMENU + wParam;
\r
1515 LoadString(hInst, id, statusBarTxt, 64);
\r
1518 SendMessage(hStatusBar, SB_SETTEXT, 0 + SBT_NOBORDERS, (LPARAM)statusBarTxt);
\r
1523 uint16 cmd = wParam & 0xFFFF;
\r
1525 if (cmd == IDM_NEW)
\r
1527 // call CmdIDM_NEW
\r
1529 else if (cmd == IDM_OPEN)
\r
1531 // call SaveChanges
\r
1533 // movmov ofn.hwndOwner, eax, hMainWnd
\r
1534 // mov ofn.Flags, OFN_PATHMUSTEXIST + OFN_FILEMUSTEXIST
\r
1535 // invoke GetOpenFileName, ADDR ofn
\r
1539 //szDMsg1a BYTE "Could not open the file (GetOpenFileName)...", 0
\r
1540 //szDMsg1b BYTE "Open error!", 0
\r
1541 //szDMsg1c BYTE "About to attempt to open file...", 0
\r
1543 ////invoke MessageBox, hWnd, ADDR szDMsg1a, ADDR szDMsg1b, MB_ICONERROR or MB_OK
\r
1544 //invoke MessageBox, hMainWnd, ADDR szDMsg1c, ADDR szFile, MB_ICONERROR or MB_OK
\r
1545 // invoke LoadTTF, ADDR szFile
\r
1548 // // <<< FILE OPEN CODE HERE >>>
\r
1549 // or fFileStatus, NAMEDbit
\r
1550 // and fFileStatus, NOT CHANGEDbit
\r
1551 // call NewWindowName
\r
1552 // mov eax, TRUE // return TRUE
\r
1554 // //ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
\r
1555 //OpenError: invoke GetLastError
\r
1556 // // <<< FILE OPEN ERROR CODE HERE >>>
\r
1558 // zero eax // return FALSE
\r
1561 else if (cmd == IDM_SAVEAS)
\r
1563 // and fFileStatus, NOT NAMEDbit
\r
1564 // call CmdIDM_SAVE
\r
1566 else if (cmd == IDM_SAVE)
\r
1568 // call CmdIDM_SAVE
\r
1570 else if (cmd == IDM_ABOUT)
\r
1571 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_ABOUT), hMainWnd, AboutProc, NULL);
\r
1572 else if (cmd == IDM_EXIT)
\r
1573 SendMessage(hWnd, WM_CLOSE, 0, 0);
\r
1574 else if (cmd == ID_TBCHARWIN)
\r
1576 ShowWindow(hCharWnd, (IsWindowVisible(hCharWnd) ? SW_HIDE : SW_SHOWNOACTIVATE));
\r
1579 wpC.length = sizeof(WINDOWPLACEMENT);
\r
1580 GetWindowPlacement(hCharWnd, &wpC);
\r
1581 wsprintf(strBuf, "Char window showCmd = %08X...\n", wpC.showCmd);
\r
1582 WriteLogMsg(strBuf);
\r
1586 return DefWindowProc(hWnd, msgID, wParam, lParam);
\r
1591 return DefWindowProc(hWnd, msgID, wParam, lParam);
\r
1598 // Initialize TTF data
\r
1600 void CreateNewDoc(void)
\r
1605 // Save changes to document before quitting
\r
1607 bool SaveChanges(void)
\r
1615 // ABOUT Dialog WndProc
\r
1617 BOOL CALLBACK AboutProc(HWND hDlg, UINT msgID, WPARAM wParam, LPARAM lParam)
\r
1621 case WM_INITDIALOG:
\r
1623 MiscCenterWnd(hDlg, hMainWnd);
\r
1628 if (wParam == IDOK || wParam == IDCANCEL)
\r
1629 EndDialog(hDlg, TRUE);
\r
1641 // Character Window WndProc
\r
1643 WndProcCW PROC STDCALL, hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
\r
1645 mov eax, uMsg // pickup our message
\r
1646 .IF (eax == WM_PAINT)
\r
1647 mov eax, 0 // Non-sense... (placeholder!)
\r
1648 // Scan conversion etc. goes here...
\r
1649 .ELSEIF (eax == WM_LBUTTONDOWN)
\r
1650 invoke SetCapture, hCharWnd
\r
1651 .ELSEIF (eax == WM_LBUTTONUP)
\r
1652 invoke ReleaseCapture
\r
1653 invoke SetFocus, hMainWnd // Make sure the main wnd keeps focus!
\r
1654 .ELSEIF (eax == WM_NCLBUTTONDOWN)
\r
1655 invoke DefWindowProc, hWnd, uMsg, wParam, lParam // Let it do its thing
\r
1656 invoke SetFocus, hMainWnd // Make sure the main wnd keeps focus!
\r
1658 DefProc: invoke DefWindowProc, hWnd, uMsg, wParam, lParam
\r
1665 // Character Window WndProc
\r
1667 LRESULT CALLBACK WndProcCW(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
\r
1672 return DefWindowProc(hWnd, msgID, wParam, lParam);
\r
1679 // Function prototypes
\r
1681 int32 FindSelectedTool(void);
\r
1684 // Tool Palette WndProc
\r
1686 LRESULT CALLBACK WndProcTP(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
\r
1691 static uint32 prevTool = -1;
\r
1697 hdc = BeginPaint(hWnd, &ps);
\r
1698 HDC newDC = CreateCompatibleDC(NULL);
\r
1699 SelectObject(newDC, hBMToolPal1);
\r
1700 BitBlt(hdc, 0, 0, sizeTPBM.x, sizeTPBM.y, newDC, 0, 0, SRCCOPY);
\r
1703 // This is crappy. Find some way to tighten this up!
\r
1704 int32 tool = FindSelectedTool();
\r
1708 newDC = CreateCompatibleDC(NULL);
\r
1709 SelectObject(newDC, hBMToolPal1);
\r
1710 //need ul corner of bitmap, ul corner of dest, width/height
\r
1711 pt.x = sizeStamp.x * (tool & 0x03), pt.y = sizeStamp.y * (tool >> 2);
\r
1712 BitBlt(hdc, pt.x, pt.y, sizeStamp.x, sizeStamp.y, newDC, pt.x, pt.y, NOTSRCCOPY);
\r
1716 EndPaint(hWnd, &ps);
\r
1719 case WM_MOUSEMOVE:
\r
1721 int32 tool = FindSelectedTool();
\r
1723 if (tool != prevTool)
\r
1726 InvalidateRect(hWnd, NULL, FALSE);
\r
1731 case WM_RBUTTONUP:
\r
1733 int32 tool = FindSelectedTool(), oldTool = currentTool;
\r
1736 currentTool = tool;
\r
1738 if (currentTool != TOOLSelect && currentTool != TOOLDelPt && currentTool != TOOLAddPt
\r
1739 && currentTool != TOOLPolySelect)
\r
1742 if (currentTool != oldTool)
\r
1743 InvalidateRect(hMainWnd, NULL, TRUE);
\r
1745 if (currentTool == TOOLAddPoly)
\r
1749 polyFirstPoint = true;
\r
1751 wsprintf(strBuf, "--> Selected poly tool, polyFirstPoint is %s\n", polyFirstPoint ? "true" : "false");
\r
1752 WriteLogMsg(strBuf);
\r
1757 ShowWindow(hToolPalWnd, SW_HIDE);
\r
1758 SetFocus(hMainWnd); // Make sure the main wnd keeps focus!
\r
1763 return DefWindowProc(hWnd, msgID, wParam, lParam);
\r
1770 // Find which tool we're pointing at
\r
1771 // Use: xcoord = mouse.x / (bmsize.x/4), ycoord = mouse.y / (bmsize.y/2)
\r
1773 int32 FindSelectedTool(void)
\r
1777 GetCursorPos(&pt);
\r
1778 ScreenToClient(hToolPalWnd, &pt);
\r
1780 uint32 x = (uint32)pt.x / sizeStamp.x, y = (uint32)pt.y / sizeStamp.y, tool = -1;
\r
1782 if (x < 4 && y < 2)
\r
1784 tool = (y * 4) + x;
\r
1787 // tool = -1; // 7 has no tool...
\r
1795 // Misc center window
\r
1797 void MiscCenterWnd(HWND hChild, HWND hParent)
\r
1799 RECT parent, child;
\r
1801 if (!GetWindowRect(hParent, &parent) || !GetWindowRect(hChild, &child))
\r
1804 int32 x = parent.left + (((parent.right - parent.left) - (child.right - child.left)) / 2),
\r
1805 y = parent.top + (((parent.bottom - parent.top) - (child.bottom - child.top)) / 2);
\r
1809 else if (x > GetSystemMetrics(SM_CXFULLSCREEN) - (child.right - child.left))
\r
1810 x = GetSystemMetrics(SM_CXFULLSCREEN) - (child.right - child.left);
\r
1814 else if (y > GetSystemMetrics(SM_CYFULLSCREEN) - (child.bottom - child.top))
\r
1815 y = GetSystemMetrics(SM_CYFULLSCREEN) - (child.bottom - child.top);
\r
1817 SetWindowPos(hChild, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
1821 // Allow only one instance
\r
1823 bool OnlyOneInstance(void)
\r
1825 HWND window = FindWindow(className, NULL);
\r
1827 if (window == NULL)
\r
1830 ShowWindow(window, SW_SHOWNORMAL);
\r
1831 SetWindowPos(window, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
\r
1837 // Load/Allocate all resources
\r
1839 bool LoadResources(void)
\r
1841 hCur[0] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR1));
\r
1842 hCur[1] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR2));
\r
1843 hCur[2] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR3));
\r
1844 hCur[3] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR4));
\r
1845 hCur[4] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR5));
\r
1846 hCur[5] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR6));
\r
1847 hCur[6] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR7));
\r
1848 hCur[7] = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR8));
\r
1852 hBMToolPal1 = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_TOOLPAL1));
\r
1853 GetObject(hBMToolPal1, sizeof(bm), &bm);
\r
1857 sizeTPBM.x = bm.bmWidth, sizeTPBM.y = bm.bmHeight;
\r
1858 sizeStamp.x = bm.bmWidth / 4, sizeStamp.y = bm.bmHeight / 2;
\r
1860 hBluePen1 = CreatePen(PS_DOT, 1, 0x00FF0000);
\r
1861 hRedPen1 = CreatePen(PS_SOLID, 1, 0x000000FF);
\r
1862 hGreenPen1 = CreatePen(PS_SOLID, 1, 0x0000AF00);
\r
1863 hBlackPen1 = CreatePen(PS_SOLID, 1, 0x00000000);
\r
1865 LOGBRUSH lb = { BS_NULL, 0, 0 };
\r
1867 hNullBrush = CreateBrushIndirect(&lb);
\r
1873 // Deallocate all resources
\r
1875 void DeallocateResources(void)
\r
1877 DeleteObject(hBMToolPal1);
\r
1878 DeleteObject(hBluePen1);
\r
1879 DeleteObject(hRedPen1);
\r
1880 DeleteObject(hGreenPen1);
\r
1881 DeleteObject(hBlackPen1);
\r
1882 DeleteObject(hNullBrush);
\r
1886 // Save all application specific data, so we can pick up where we last left off...
\r
1888 void SaveAppState(void)
\r
1890 SetINIInt("Main", "flags", wpM.flags);
\r
1891 SetINIInt("Main", "showCmd", wpM.showCmd);
\r
1892 SetINIInt("Main", "x1", wpM.rcNormalPosition.left);
\r
1893 SetINIInt("Main", "y1", wpM.rcNormalPosition.top);
\r
1894 SetINIInt("Main", "x2", wpM.rcNormalPosition.right);
\r
1895 SetINIInt("Main", "y2", wpM.rcNormalPosition.bottom);
\r
1897 SetINIInt("Main", "vpx", ptVPM.x);
\r
1898 SetINIInt("Main", "vpy", ptVPM.y);
\r
1900 SetINIInt("Char", "flags", wpC.flags);
\r
1901 SetINIInt("Char", "showCmd", wpC.showCmd);
\r
1902 SetINIInt("Char", "x1", wpC.rcNormalPosition.left);
\r
1903 SetINIInt("Char", "y1", wpC.rcNormalPosition.top);
\r
1904 SetINIInt("Char", "x2", wpC.rcNormalPosition.right);
\r
1905 SetINIInt("Char", "y2", wpC.rcNormalPosition.bottom);
\r
1907 // Need to write out currently opened font, character looking at, other misc. crap
\r
1908 // SetINIString("Main", "currentFile", pDoc->GetPathName());
\r
1909 // SetINIInt("Main", "currentChar", pDoc->character_num);
\r
1913 // Restore all application specific data previously saved
\r
1915 bool RestoreAppState(void)
\r
1919 WINDOWPLACEMENT wp;
\r
1920 wp.length = sizeof(WINDOWPLACEMENT);
\r
1921 GetWindowPlacement(hMainWnd, &wp);
\r
1923 wp.flags = GetINIInt("Main", "flags", wp.flags);
\r
1924 wp.showCmd = GetINIInt("Main", "showCmd", wp.showCmd);
\r
1925 wp.rcNormalPosition.left = GetINIInt("Main", "x1", wp.rcNormalPosition.left);
\r
1926 wp.rcNormalPosition.top = GetINIInt("Main", "y1", wp.rcNormalPosition.top);
\r
1927 wp.rcNormalPosition.right = GetINIInt("Main", "x2", wp.rcNormalPosition.right);
\r
1928 wp.rcNormalPosition.bottom = GetINIInt("Main", "y2", wp.rcNormalPosition.bottom);
\r
1930 SetWindowPlacement(hMainWnd, &wp);
\r
1934 hdc = GetDC(hMainWnd);
\r
1935 GetViewportOrgEx(hdc, &pt);
\r
1937 pt.x = GetINIInt("Main", "vpx", pt.x);
\r
1938 pt.y = GetINIInt("Main", "vpy", pt.y);
\r
1940 SetViewportOrgEx(hdc, pt.x, pt.y, NULL);
\r
1941 ReleaseDC(hMainWnd, hdc);
\r
1943 GetWindowPlacement(hCharWnd, &wp);
\r
1945 wp.flags = GetINIInt("Char", "flags", wp.flags);
\r
1946 wp.showCmd = GetINIInt("Char", "showCmd", wp.showCmd);
\r
1947 wp.rcNormalPosition.left = GetINIInt("Char", "x1", wp.rcNormalPosition.left);
\r
1948 wp.rcNormalPosition.top = GetINIInt("Char", "y1", wp.rcNormalPosition.top);
\r
1949 wp.rcNormalPosition.right = GetINIInt("Char", "x2", wp.rcNormalPosition.right);
\r
1950 wp.rcNormalPosition.bottom = GetINIInt("Char", "y2", wp.rcNormalPosition.bottom);
\r
1952 SetWindowPlacement(hCharWnd, &wp);
\r
1954 if (wp.showCmd == SW_HIDE)
\r
1955 SendMessage(hToolBar, TB_SETSTATE, ID_TBCHARWIN, MAKELONG(TBSTATE_ENABLED, 0));
\r
1957 // CString lastFile = theApplicationObject.GetProfileString(version, "currentFile", "");
\r
1958 // int lastChar = theApplicationObject.GetProfileInt(version, "currentChar", 0);
\r
1959 // if (lastFile.GetLength())
\r
1961 // // Attempt to restore the last session by open the last file used, etc...
\r
1962 // if (!pDoc->m_myFont.Load(lastFile))
\r
1964 // // Err, make sure you can support any allegations you make below, buddy!
\r
1965 // AfxMessageBox("The last file opened with TTF Edit\n\rseems to have been moved or deleted.");
\r
1969 // pDoc->m_myFont.SetGlyph(lastChar); // Set TTF object to last used char
\r
1970 // pDoc->character_num = lastChar;
\r
1971 // pDoc->SetPathName(lastFile);
\r
1973 // BYTE name[512];
\r
1974 // pDoc->m_myFont.GetCharName(lastChar, name);
\r
1975 // m_wndOwned.SetWindowText((char *)name);
\r
1985 bool Initialization(void)
\r
1989 if (!LoadResources())
\r
1992 RtlFillMemory(&wcex, sizeof(WNDCLASSEX), 0);
\r
1993 wcex.cbSize = sizeof(WNDCLASSEX);
\r
1994 wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
\r
1995 wcex.lpfnWndProc = WndProc;
\r
1996 wcex.hInstance = hInst;
\r
1997 wcex.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON));
\r
1998 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
\r
1999 wcex.lpszMenuName = MAKEINTRESOURCE(IDM_MENU);
\r
2000 wcex.lpszClassName = className;
\r
2001 wcex.hIconSm = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 16, 16, NULL);
\r
2003 if (!RegisterClassEx(&wcex))
\r
2006 hMainWnd = CreateWindowEx(NULL, className, className, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
\r
2007 0, 0, 0x1A0, 0x180, NULL, NULL, hInst, NULL);
\r
2012 ShowWindow(hMainWnd, nCmdShow);
\r
2013 UpdateWindow(hMainWnd);
\r
2015 // Character window creation
\r
2017 wcex.lpfnWndProc = WndProcCW;
\r
2018 wcex.lpszMenuName = NULL;
\r
2019 wcex.lpszClassName = CNCharWin;
\r
2020 wcex.hCursor = LoadCursor(NULL, IDC_ARROW); // Owned windows have "regular" cursors
\r
2022 if (!RegisterClassEx(&wcex))
\r
2025 hCharWnd = CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW, CNCharWin,
\r
2026 curCharName, WS_POPUP | WS_CAPTION | WS_VISIBLE | WS_THICKFRAME,
\r
2027 100, 100, 120, 120, hMainWnd, NULL, hInst, NULL);
\r
2032 ShowWindow(hCharWnd, SW_SHOWNORMAL);
\r
2033 UpdateWindow(hCharWnd);
\r
2034 SetFocus(hMainWnd); // Make sure main wnd has focus!
\r
2036 // Tool palette window creation
\r
2038 wcex.lpfnWndProc = WndProcTP;
\r
2039 wcex.lpszClassName = CNToolPal;
\r
2041 if (!RegisterClassEx(&wcex))
\r
2044 hToolPalWnd = CreateWindowEx(WS_EX_WINDOWEDGE, CNToolPal, NULL, WS_POPUP,
\r
2045 0, 0, sizeTPBM.x, sizeTPBM.y, hMainWnd, NULL, hInst, NULL);
\r
2050 // Note: A better way to handle this would be to have a sub that registers ALL
\r
2051 // classes beforehand and passes a TRUE/FALSE back depending on whether or not
\r
2052 // all the classes were able to be registered or not, THEN create the windows
\r
2053 // and controls...
\r
2055 RestoreAppState(); // Restore app related stuff
\r