]> Shamusworld >> Repos - ttedit/blob - src/ttedit.cpp
Move main repo to trunk.
[ttedit] / src / ttedit.cpp
1 //\r
2 // TTEDIT.CPP - The TrueType Editor\r
3 // by James L. Hammons\r
4 // (C) 2004 Underground Software\r
5 //\r
6 // JLH = James L. Hammons <jlhamm@acm.org>\r
7 //\r
8 // Who  When        What\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
14 //\r
15 \r
16 // STILL TO BE DONE:\r
17 //\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
23 //\r
24 \r
25 // Uncomment this for debugging...\r
26 #define DEBUG\r
27 #define DEBUGFOO            // Various tool debugging...\r
28 \r
29 #include <math.h>\r
30 #include "types.h"\r
31 #include "tte_res.h"\r
32 #include "ttf.h"\r
33 #include "registry.h"\r
34 #include "bezier.h"\r
35 #include "glyphpoints.h"\r
36 #include "vector.h"\r
37 #ifdef DEBUG\r
38 #include "debug.h"\r
39 #endif\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
44 \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
58 \r
59 //\r
60 // E Q U A T E S\r
61 //\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
70 \r
71 //\r
72 // Function and Procedure Prototypes\r
73 //\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
87 \r
88 // Global constant data\r
89 \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
98 \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
104 };*/\r
105 \r
106 \r
107 //\r
108 // U N I N I T I A L I Z E D    D A T A\r
109 //\r
110 /*\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
115 \r
116 */\r
117 \r
118 //HINSTANCE hInst;\r
119 int nCmdShow;\r
120 //HWND hMainWnd, hStatusBar, hToolBar, hCharWnd, hToolPalWnd;\r
121 char statusBarTxt[64];\r
122 char toolTipTxt[16];\r
123 char strBuf[1024];\r
124 \r
125 //HCURSOR hCur[8];\r
126 wxCursor * cur[8];\r
127 \r
128 //HBITMAP hBMToolPal1;\r
129 //HPEN hRedPen1, hBluePen1, hGreenPen1, hBlackPen1;\r
130 //HBRUSH hNullBrush;\r
131 \r
132 //POINT sizeStamp, sizeTPBM, ptPrevious;\r
133 //PTSTRUCT aPts[16];\r
134 //uint32 numPts = 0;\r
135 GlyphPoints pts;\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
139 bool NCMouseDown;\r
140 //POINT ptWinOffset;\r
141 uint32 zoomWndWidth;\r
142 bool polyFirstPoint = true;\r
143 \r
144 char curCharName[] = "Own3d W1nd0w";                    // Need to make this a buffer w/default\r
145 \r
146 //WINDOWPLACEMENT wpM, wpC;\r
147 //POINT ptVPM;\r
148 \r
149 \r
150 \r
151 IMPLEMENT_APP(TTEditApp)                                                // Run the main application loop\r
152 \r
153 bool TTEditApp::OnInit()\r
154 {\r
155         wxLog * logTarget = new wxLogStderr();//fopen("!ttedit_log.txt", "wb"));\r
156         wxLog::SetActiveTarget(logTarget);\r
157 #ifdef DEBUG\r
158         OpenDebugLog();\r
159 #endif\r
160 \r
161         // Initialize all the top-level window members to NULL.\r
162         mainFrame = NULL;\r
163         charWin = NULL;\r
164         toolPalette = NULL;\r
165 \r
166         CreateResources();\r
167 \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
171 \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
175 \r
176         return true;\r
177 }\r
178 \r
179 int TTEditApp::OnExit()\r
180 {\r
181 #ifdef DEBUG\r
182         CloseDebugLog();\r
183 #endif\r
184 \r
185         return 0;\r
186 }\r
187 \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
193 END_EVENT_TABLE()\r
194 \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
197 {\r
198         // Initialize child subwindow members (and hopefully avoid subtle bugs)\r
199         mainWindow = NULL;\r
200 \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
207 \r
208         if (tb != NULL)\r
209         {\r
210                 // Create buttons\r
211 \r
212                 wxBitmap tool1(tool1_xpm);\r
213                 wxBitmap tool2(tool2_xpm);\r
214                 wxBitmap tool3(tool3_xpm);\r
215 \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
219                 tb->Realize();\r
220         }\r
221 \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
238 \r
239         // Create child subwindows\r
240         mainWindow = new TTEditWindow(this);\r
241 \r
242         Centre(wxBOTH);                                                         // Centre frame on the screen\r
243         Show(true);                                                                     // Show the frame\r
244 }\r
245 \r
246 TTEditFrame::~TTEditFrame()\r
247 {\r
248 }\r
249 \r
250 void TTEditFrame::OnOpen(wxCommandEvent &e)\r
251 {\r
252         wxFileDialog fd(this, _("Choose a font to load"), _(""), _(""), _("TTF files (*.ttf)|*.ttf|All files (*.*)|*.*"), wxOPEN);\r
253 \r
254         if (fd.ShowModal() != wxID_OK)\r
255             return;\r
256 \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
259         {\r
260                 wxMessageDialog dlg(NULL, _("Load font failed!"), _("Houston, we have a problem..."), wxOK | wxICON_ERROR);\r
261                 dlg.ShowModal();\r
262         }\r
263 \r
264 //Huzzah! It works! Now just need scaling, scrolling, etc...\r
265 //      pts = app.font.GetGlyphPoints(45);\r
266 }\r
267 \r
268 void TTEditFrame::OnAbout(wxCommandEvent &e)\r
269 {\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
271         dlg.ShowModal();\r
272 }\r
273 \r
274 void TTEditFrame::OnExit(wxCommandEvent &e)\r
275 {\r
276         wxGetApp().toolPalette->Destroy();\r
277         this->Destroy();\r
278 }\r
279 \r
280 void TTEditFrame::OnCloseWindow(wxCloseEvent &e)\r
281 {\r
282         wxGetApp().toolPalette->Destroy();\r
283         this->Destroy();\r
284 }\r
285 \r
286 BEGIN_EVENT_TABLE(TTEditWindow, wxWindow)\r
287         EVT_PAINT(TTEditWindow::OnPaint)\r
288         EVT_MOUSE_EVENTS(TTEditWindow::OnMouseEvent)\r
289 END_EVENT_TABLE()\r
290 \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
293\r
294         bmp = NULL;\r
295         scale = 1.0;\r
296         offsetX = offsetY = -10;\r
297 \r
298         SetCursor(*cur[currentTool]);\r
299         SetBackgroundColour(wxColour(0xFF, 0xFF, 0xFF));\r
300 \r
301         wxString s;\r
302         s.Printf(_("Zoom: %.2f%%"), scale * 100.0);\r
303         parent->SetStatusText(s, 1);\r
304 }\r
305 \r
306 TTEditWindow::~TTEditWindow(void)\r
307 {\r
308         if (bmp)\r
309                 delete bmp;\r
310 }\r
311 \r
312 void TTEditWindow::OnPaint(wxPaintEvent &e)\r
313 {\r
314 /*      wxPaintDC dc(this);\r
315 \r
316         // Insert your drawing code here.\r
317         if (!bmp)\r
318         {\r
319                 bmp = new wxBitmap(field_width * x_cell * X_UNIT + 1, field_height * y_cell * Y_UNIT + 1);\r
320 \r
321                 if (bmp)\r
322                 {\r
323                         wxMemoryDC memDC;\r
324                         memDC.SelectObject(*bmp);\r
325                         DrawField(&memDC, 0, 0, field_width - 1, field_height - 1);\r
326                         memDC.SelectObject(wxNullBitmap);\r
327                 }\r
328         }\r
329 \r
330         if (bmp)\r
331         {\r
332                 wxMemoryDC memDC;\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
337         }\r
338         else\r
339                 DrawField(&dc, 0, 0, field_width - 1, field_height - 1);*/\r
340 \r
341         wxPaintDC dc(this);\r
342 //Doesn't do crap!\r
343 //dc.SetBackground(*wxWHITE_BRUSH);\r
344 \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
349 \r
350         dc.SetDeviceOrigin(-offsetX, height - (-offsetY));\r
351         dc.SetAxisOrientation(true, true);\r
352 \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
359 \r
360         dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0xFF), 1, wxDOT)));\r
361 //      dc.DrawLine(0, 0, 10, 10);\r
362 \r
363     // Draw coordinate axes\r
364 \r
365         dc.CrossHair(0, 0);\r
366 \r
367     // Draw points\r
368 \r
369         for(int i=0; i<pts.GetNumPoints(); i++)\r
370         {\r
371                 if (i == ptHighlight)\r
372                 {\r
373                         dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0xFF, 0x00, 0x00), 1, wxSOLID)));\r
374 //                      SelectObject(hdc, hRedPen1);\r
375 \r
376                         if (pts.GetOnCurve(i))\r
377                         {\r
378                                 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 7);\r
379                                 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 9);\r
380                         }\r
381                         else\r
382                         {\r
383                                 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 7);\r
384                                 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 9);\r
385                         }\r
386                 }\r
387                 else if ((i == ptHighlight || i == ptNextHighlight) && currentTool == TOOLAddPt)\r
388                 {\r
389                         dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0xAF, 0x00), 1, wxSOLID)));\r
390 //                      SelectObject(hdc, hGreenPen1);\r
391 \r
392                         if (pts.GetOnCurve(i))\r
393                         {\r
394                                 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 7);\r
395                                 DrawSquareDotN(dc, pts.GetX(i), pts.GetY(i), 9);\r
396                         }\r
397                         else\r
398                         {\r
399                                 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 7);\r
400                                 DrawRoundDotN(dc, pts.GetX(i), pts.GetY(i), 9);\r
401                         }\r
402                 }\r
403                 else\r
404                 {\r
405                         dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));\r
406 //                      SelectObject(hdc, hBlackPen1);\r
407 \r
408                         if (pts.GetOnCurve(i))\r
409                                 DrawSquareDot(dc, pts.GetX(i), pts.GetY(i));\r
410                         else\r
411                                 DrawRoundDot(dc, pts.GetX(i), pts.GetY(i));\r
412                 }\r
413 \r
414                 if (currentTool == TOOLDelPt && i == ptHighlight)\r
415                 {\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
426                 }\r
427         }\r
428 \r
429 //              SelectObject(hdc, hBlackPen1);\r
430         dc.SetPen(*(wxThePenList->FindOrCreatePen(wxColour(0x00, 0x00, 0x00), 1, wxSOLID)));\r
431 \r
432         // Draw curve formed by points\r
433 \r
434         for(int poly=0; poly<pts.GetNumPolys(); poly++)\r
435         {\r
436                 if (pts.GetNumPoints(poly) > 2)\r
437                 {\r
438                         // Initial move...\r
439                         // If it's not on curve, then move to it, otherwise move to last point...\r
440 \r
441                         wxCoord x, y;\r
442         \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
445                         else\r
446                                 x = (wxCoord)pts.GetX(poly, 0), y = (wxCoord)pts.GetY(poly, 0);\r
447         \r
448                         for(int i=0; i<pts.GetNumPoints(poly); i++)\r
449                         {\r
450                                 if (pts.GetOnCurve(poly, i))\r
451 //                                      LineTo(hdc, pts.GetX(poly, i), pts.GetY(poly, i));\r
452                                 {\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
455                                 }\r
456                                 else\r
457                                 {\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
461         \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
465         \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
469         \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
472         \r
473                                         if (pts.GetOnCurve(poly, next))\r
474                                                 i++;                                    // Following point is on curve, so move past it\r
475                                 }\r
476                         }\r
477                 }\r
478         }\r
479 \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
484 }\r
485 \r
486 void TTEditWindow::OnMouseEvent(wxMouseEvent &e)\r
487 {\r
488         if (e.RightDown())\r
489         {\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
496         }\r
497         else if (e.LeftDown())\r
498         {\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
502                 {\r
503                         if (pts.GetNumPoints() > 0)\r
504                         {\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
508                                 Refresh();\r
509                         }\r
510                 }\r
511                 else if (currentTool == TOOLAddPoly)    // "Add Poly" tool\r
512                 {\r
513 #ifdef DEBUGFOO\r
514 WriteLogMsg("Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts.GetNumPoints());\r
515 #endif\r
516                         if (polyFirstPoint)\r
517                         {\r
518                                 polyFirstPoint = false;\r
519                                 pts.AddNewPolyAtEnd();\r
520                         }\r
521 \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
526                         Refresh();\r
527 #ifdef DEBUGFOO\r
528 WriteLogMsg(" --> [# polys: %u, # points: %u]\n", pts.GetNumPolys(), pts.GetNumPoints());\r
529 #endif\r
530                 }\r
531                 else if (currentTool == TOOLSelect || currentTool == TOOLPolySelect)\r
532                 {\r
533                         if (pts.GetNumPoints() > 0)\r
534                         {\r
535                                 pt = GetAdjustedClientPosition(pts.GetX(ptHighlight), pts.GetY(ptHighlight));\r
536                                 WarpPointer(pt.x, pt.y);\r
537 \r
538                                 if (e.ShiftDown() | e.ControlDown())\r
539                                         pts.SetOnCurve(ptHighlight, !pts.GetOnCurve(ptHighlight));\r
540                         }\r
541                 }\r
542                 else if (currentTool == TOOLDelPt)\r
543                 {\r
544                         if (pts.GetNumPoints() > 0)\r
545 //Or could use:\r
546 //                      if (ptHighlight != -1)\r
547                         {\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
551                                 Refresh();\r
552                         }\r
553                 }\r
554         }\r
555         else if (e.LeftUp())\r
556         {\r
557 //              mouseDown = false;\r
558 \r
559                 if (currentTool == TOOLScroll || currentTool == TOOLZoom)\r
560 //                      ReleaseCapture();\r
561                         ReleaseMouse();\r
562         }\r
563         else if (e.Dragging())\r
564         {\r
565 //Do this here? Needed?         SetCursor(hCur[currentTool]);\r
566 \r
567             // Extract current point from lParam/calc offset from previous point\r
568 \r
569                 pt = e.GetPosition();\r
570                 ptOffset.x = pt.x - ptPrevious.x,\r
571                 ptOffset.y = pt.y - ptPrevious.y;\r
572 \r
573 //              if (e.LeftIsDown())\r
574 //              {\r
575                         if (currentTool == TOOLScroll)\r
576                         {\r
577                                 // NOTE: OffsetViewportOrg operates in DEVICE UNITS...\r
578 \r
579 //Seems there's no equivalent for this in wxWidgets...!\r
580 //!!! FIX !!!\r
581 //                              hdc = GetDC(hWnd);\r
582 //                              OffsetViewportOrgEx(hdc, ptOffset.x, ptOffset.y, NULL);\r
583 //                              ReleaseDC(hWnd, hdc);\r
584 \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
587 // Above: DONE\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
592                                 Refresh();\r
593                         }\r
594                         else if (currentTool == TOOLAddPt || currentTool == TOOLAddPoly || currentTool == TOOLSelect)\r
595                         {\r
596                                 if (currentTool != TOOLAddPt || pts.GetNumPoints() > 0)//yecch.\r
597                                 {\r
598                                         wxPoint pt2 = GetAdjustedMousePosition(e);\r
599                                         pts.SetXY(ptHighlight, pt2.x, pt2.y);\r
600                                         Refresh();\r
601                                 }\r
602                         }\r
603                         else if (currentTool == TOOLPolySelect)\r
604                         {\r
605                                 if (pts.GetNumPoints() > 0)\r
606                                 {\r
607                                         wxPoint pt2 = GetAdjustedMousePosition(e);\r
608                                         // Should also set onCurve here as well, depending on keystate\r
609 //Or should we?\r
610                                         pts.OffsetPoly(pts.GetPoly(ptHighlight), pt2.x - pts.GetX(ptHighlight), pt2.y - pts.GetY(ptHighlight));\r
611                                         Refresh();\r
612                                 }\r
613                         }\r
614 //              }\r
615 \r
616                 ptPrevious = pt;\r
617         }\r
618         else if (e.Moving())\r
619         {\r
620 //              else    // Moving, not dragging...\r
621 //              {\r
622                         if (currentTool == TOOLSelect || currentTool == TOOLDelPt || currentTool == TOOLAddPt\r
623                                 || currentTool == TOOLPolySelect)// || currentTool == TOOLAddPoly)\r
624                         {\r
625                                 wxPoint pt2 = GetAdjustedMousePosition(e);\r
626                                 double closest = 1.0e+99;\r
627 \r
628                                 for(int i=0; i<pts.GetNumPoints(); i++)\r
629                                 {\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
632 \r
633                                         if (dist < closest)\r
634                                                 closest = dist, ptHighlight = i;\r
635                                 }\r
636 \r
637                                 if (ptHighlight != oldPtHighlight)\r
638                                 {\r
639                                         oldPtHighlight = ptHighlight;\r
640                                         Refresh();\r
641                                 }\r
642 \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
649 \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
652 \r
653                                 if (pts.GetNumPoints() > 1 && currentTool == TOOLAddPt)\r
654                                 {\r
655                                         double smallest = 1.0e+99;\r
656 \r
657                                         for(int i=0; i<pts.GetNumPoints(); i++)\r
658                                         {\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
661 \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
669 \r
670                                                 if (pp < 0.0)\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
676 \r
677 //The answer to the above looks like it might be found here:\r
678 //\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
685 //\r
686 //sx sy 1\r
687 //ex ey 1\r
688 //px py 1\r
689 //\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
692 //\r
693 //0         0         0\r
694 //(ex - sx) (ey - sy) 0\r
695 //(px - sx) (py - sy) 0\r
696 //\r
697 //which greatly simplifies the calculation of the determinant.\r
698 \r
699                                                 if (dist < smallest)\r
700                                                         smallest = dist, ptNextHighlight = pts.GetNext(i), ptHighlight = i;\r
701                                         }\r
702 \r
703                                         if (ptNextHighlight != oldPtNextHighlight)\r
704                                         {\r
705                                                 oldPtNextHighlight = ptNextHighlight;\r
706                                                 Refresh();\r
707                                         }\r
708                                 }\r
709                         }\r
710 //              }\r
711 \r
712                 ptPrevious = e.GetPosition();\r
713         }\r
714 }\r
715 \r
716 \r
717 wxPoint TTEditWindow::GetAdjustedMousePosition(wxMouseEvent &e)\r
718 {\r
719         wxCoord width, height;\r
720         wxClientDC dc(this);\r
721 \r
722         dc.GetSize(&width, &height);\r
723         dc.SetDeviceOrigin(-offsetX, height - (-offsetY));\r
724         dc.SetAxisOrientation(true, true);\r
725 \r
726 /*wxStatusBar * sb = ((wxFrame *)GetParent())->GetStatusBar();\r
727 wxString s;\r
728 s.Printf("Logical mouse pos: %d, %d (%d, %d)", pt.x, pt.y, width, height);\r
729 sb->SetStatusText(s);//*/\r
730 \r
731         return e.GetLogicalPosition(dc);\r
732 }\r
733 \r
734 wxPoint TTEditWindow::GetAdjustedClientPosition(wxCoord x, wxCoord y)\r
735 {\r
736         wxCoord width, height;\r
737         wxClientDC dc(this);\r
738 \r
739         dc.GetSize(&width, &height);\r
740         dc.SetDeviceOrigin(-offsetX, height - (-offsetY));\r
741         dc.SetAxisOrientation(true, true);\r
742 \r
743         return wxPoint(dc.LogicalToDeviceX(x), dc.LogicalToDeviceY(y));\r
744 }\r
745 \r
746 //\r
747 \r
748 void CreateResources(void)\r
749 {\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
752 \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
757 \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
762 \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
767 \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
772 \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
777 \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
782 \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
787 \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
792 }\r
793 \r
794 //\r
795 // Draw a round dot (5x5, centered on [x, y])\r
796 //\r
797 void DrawRoundDot(wxDC &dc, int32 x, int32 y)\r
798 {\r
799         wxPoint pt[8];\r
800 \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
809 \r
810         dc.DrawPolygon(8, pt);\r
811 }\r
812 \r
813 //\r
814 // Draw a sqaure dot (5x5, centered on [x, y])\r
815 //\r
816 void DrawSquareDot(wxDC &dc, int32 x, int32 y)\r
817 {\r
818         wxPoint pt[4];\r
819 \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
824 \r
825         dc.DrawPolygon(4, pt);\r
826 }\r
827 \r
828 //\r
829 // Draw a sqaure dot (nxn, centered on [x, y])\r
830 //\r
831 void DrawSquareDotN(wxDC &dc, int32 x, int32 y, uint32 n)\r
832 {\r
833         wxPoint pt[4];\r
834         uint32 offset = (n - 1) / 2;\r
835 \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
840 \r
841         dc.DrawPolygon(4, pt);\r
842 }\r
843 \r
844 //\r
845 // Draw a round dot (nxn, centered on [x, y])\r
846 //\r
847 void DrawRoundDotN(wxDC &dc, int32 x, int32 y, uint32 n)\r
848 {\r
849         dc.DrawCircle(x, y, (n / 2) + 1);\r
850 }\r
851 \r
852 \r
853 BEGIN_EVENT_TABLE(CharWindow, wxWindow)\r
854 //      EVT_PAINT(CharWindow::OnPaint)\r
855 //      EVT_MOUSE_EVENTS(CharWindow::OnMouseEvent)\r
856 END_EVENT_TABLE()\r
857 \r
858 CharWindow::CharWindow(wxFrame * parent, const wxPoint &pos, const wxSize &size, long style):\r
859         wxWindow(parent, -1, pos, size, style)\r
860 {\r
861\r
862 \r
863 CharWindow::~CharWindow()\r
864 {\r
865 }\r
866 \r
867 \r
868 BEGIN_EVENT_TABLE(ToolWindow, wxWindow)\r
869         EVT_PAINT(ToolWindow::OnPaint)\r
870         EVT_MOUSE_EVENTS(ToolWindow::OnMouseEvent)\r
871 END_EVENT_TABLE()\r
872 \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
877 {\r
878         bmp = new wxBitmap(toolpal1_xpm);\r
879         prevTool = -1;\r
880 \r
881         // Set up sizes\r
882 \r
883         sizeTPBM.x = bmp->GetWidth(), sizeTPBM.y = bmp->GetHeight();\r
884         sizeStamp.x = sizeTPBM.x / 4, sizeStamp.y = sizeTPBM.y / 2;\r
885 \r
886         SetSize(10, 10, sizeTPBM.x, sizeTPBM.y);\r
887         Show(false);\r
888 }\r
889 \r
890 ToolWindow::~ToolWindow()\r
891 {\r
892 }\r
893 \r
894 void ToolWindow::OnPaint(wxPaintEvent &e)\r
895 {\r
896         wxPaintDC dc(this);\r
897 \r
898         wxMemoryDC memDC;\r
899         memDC.SelectObject(*bmp);\r
900         dc.Blit(0, 0, sizeTPBM.x, sizeTPBM.y, &memDC, 0, 0, wxCOPY);\r
901 \r
902         int32 tool = FindSelectedTool();\r
903 \r
904         if (tool != -1)\r
905         {\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
909         }\r
910 \r
911         memDC.SelectObject(wxNullBitmap);\r
912 }\r
913 \r
914 void ToolWindow::OnMouseEvent(wxMouseEvent &e)\r
915 {\r
916 //      if (e.Moving())\r
917         if (e.Dragging())\r
918         {\r
919                 int32 tool = FindSelectedTool();\r
920 \r
921                 if (tool != prevTool)\r
922                 {\r
923                         prevTool = tool;\r
924                         Refresh(false);\r
925                 }\r
926         }\r
927 \r
928         if (e.RightUp())\r
929         {\r
930                 int32 tool = FindSelectedTool(), oldTool = currentTool;\r
931 \r
932                 if (tool != -1)\r
933                         currentTool = tool;\r
934 \r
935                 if (currentTool != TOOLSelect && currentTool != TOOLDelPt && currentTool != TOOLAddPt\r
936                         && currentTool != TOOLPolySelect)\r
937                         ptHighlight = -1;\r
938 \r
939                 if (currentTool != oldTool)\r
940                         Refresh(false);\r
941 \r
942                 if (currentTool == TOOLAddPoly)\r
943 #ifdef DEBUGFOO\r
944 {\r
945 #endif\r
946                         polyFirstPoint = true;\r
947 #ifdef DEBUGFOO\r
948 sprintf(strBuf, "--> Selected poly tool, polyFirstPoint is %s\n", polyFirstPoint ? "true" : "false");\r
949 WriteLogMsg(strBuf);\r
950 }\r
951 #endif\r
952 \r
953                 ReleaseMouse();\r
954                 Show(false);\r
955                 wxGetApp().mainFrame->mainWindow->SetCursor(*cur[currentTool]);\r
956                 wxGetApp().mainFrame->mainWindow->SetFocus();   // Make sure the main wnd keeps focus!\r
957         }\r
958 }\r
959 \r
960 //\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
963 //\r
964 int32 ToolWindow::FindSelectedTool(void)\r
965 {\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
968 \r
969         if (x < 4 && y < 2)\r
970                 tool = (y * 4) + x;\r
971 \r
972         return tool;\r
973 }\r
974 \r
975 \r
976 /*\r
977 LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)\r
978 {\r
979         RECT rc1, rc2;\r
980         HDC hdc;\r
981         POINT pt, ptOffset;\r
982         SIZE sz;\r
983         PAINTSTRUCT ps;\r
984 \r
985         switch (msgID)\r
986         {\r
987         case WM_CREATE:\r
988 \r
989                 MiscCenterWnd(hWnd, GetDesktopWindow());\r
990                 InitCommonControls();\r
991                 hStatusBar = CreateStatusWindow(WS_CHILD | WS_VISIBLE, statusBarTxt, hWnd, ID_STATUSBAR);\r
992 \r
993                 if (!hStatusBar)\r
994                         return -1;\r
995 \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
999                 hdc = GetDC(hWnd);\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
1004 \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
1010 \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
1013 \r
1014                 if (!hToolBar)\r
1015                         return -1;\r
1016 \r
1017                 CreateNewDoc();\r
1018 \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
1031                 break;\r
1032 \r
1033         case WM_CLOSE:\r
1034 \r
1035                 if (SaveChanges())\r
1036                 {\r
1037                         wpM.length = wpC.length = sizeof(WINDOWPLACEMENT);\r
1038                         GetWindowPlacement(hMainWnd, &wpM);\r
1039                         GetWindowPlacement(hCharWnd, &wpC);\r
1040 \r
1041                         if (!IsWindowVisible(hCharWnd))         // Needed because Windows lies about visibility\r
1042                                 wpC.showCmd = SW_HIDE;\r
1043 \r
1044                         hdc = GetDC(hWnd);\r
1045                         GetViewportOrgEx(hdc, &ptVPM);\r
1046                         ReleaseDC(hWnd, hdc);\r
1047 \r
1048                         DestroyWindow(hWnd);\r
1049                 }\r
1050 \r
1051                 break;\r
1052 \r
1053         case WM_DESTROY:\r
1054 \r
1055                 PostQuitMessage(0);\r
1056                 break;\r
1057 \r
1058         case WM_NCLBUTTONDOWN:\r
1059 \r
1060                 if (wParam == HTCAPTION)\r
1061                 {\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
1067                 }\r
1068                     \r
1069                 // Let Windows do its thing with this msg, or weird things will happen...\r
1070 \r
1071                 DefWindowProc(hWnd, msgID, wParam, lParam);\r
1072                 NCMouseDown = false;\r
1073                 break;\r
1074 \r
1075         case WM_WINDOWPOSCHANGING:\r
1076 \r
1077                 if (NCMouseDown)\r
1078                 {\r
1079                         WINDOWPOS * wp = (WINDOWPOS *)lParam;\r
1080 \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
1084                 }\r
1085 \r
1086                 return DefWindowProc(hWnd, msgID, wParam, lParam);      // Seems this is needed... Bleah!\r
1087 \r
1088         case WM_PAINT:\r
1089         {\r
1090                 hdc = BeginPaint(hWnd, &ps);\r
1091 \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
1097 \r
1098                 // Apparently, you *must* save the individual object types (pen, brush, etc.)\r
1099 \r
1100                 HGDIOBJ oldPen = SelectObject(hdc, hBluePen1),\r
1101                         oldBrush = SelectObject(hdc, hNullBrush);\r
1102 \r
1103             // Draw coordinate axes\r
1104 \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
1109 \r
1110             // Draw points\r
1111 \r
1112                 for(int i=0; i<pts.GetNumPoints(); i++)\r
1113                 {\r
1114                         if (i == ptHighlight)\r
1115                         {\r
1116                                 SelectObject(hdc, hRedPen1);\r
1117 \r
1118                                 if (pts.GetOnCurve(i))\r
1119                                 {\r
1120                                         DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 7);\r
1121                                         DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 9);\r
1122                                 }\r
1123                                 else\r
1124                                 {\r
1125                                         DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 7);\r
1126                                         DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 9);\r
1127                                 }\r
1128                         }\r
1129                         else if ((i == ptHighlight || i == ptNextHighlight) && currentTool == TOOLAddPt)\r
1130                         {\r
1131                                 SelectObject(hdc, hGreenPen1);\r
1132 \r
1133                                 if (pts.GetOnCurve(i))\r
1134                                 {\r
1135                                         DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 7);\r
1136                                         DrawSquareDotN(hdc, pts.GetX(i), pts.GetY(i), 9);\r
1137                                 }\r
1138                                 else\r
1139                                 {\r
1140                                         DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 7);\r
1141                                         DrawRoundDotN(hdc, pts.GetX(i), pts.GetY(i), 9);\r
1142                                 }\r
1143                         }\r
1144                         else\r
1145                         {\r
1146                                 SelectObject(hdc, hBlackPen1);\r
1147 \r
1148                                 if (pts.GetOnCurve(i))\r
1149                                         DrawSquareDot(hdc, pts.GetX(i), pts.GetY(i));\r
1150                                 else\r
1151                                         DrawRoundDot(hdc, pts.GetX(i), pts.GetY(i));\r
1152                         }\r
1153 \r
1154                         if (currentTool == TOOLDelPt && i == ptHighlight)\r
1155                         {\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
1163                         }\r
1164                 }\r
1165 \r
1166                 SelectObject(hdc, hBlackPen1);\r
1167 \r
1168                 // Draw curve formed by points\r
1169 \r
1170                 for(int poly=0; poly<pts.GetNumPolys(); poly++)\r
1171                 {\r
1172                         if (pts.GetNumPoints(poly) > 2)\r
1173                         {\r
1174                                 // Initial move...\r
1175                                 // If it's not on curve, then move to it, otherwise move to last point...\r
1176         \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
1179                                 else\r
1180                                         MoveToEx(hdc, pts.GetX(poly, 0), pts.GetY(poly, 0), NULL);\r
1181         \r
1182                                 for(int i=0; i<pts.GetNumPoints(poly); i++)\r
1183                                 {\r
1184                                         if (pts.GetOnCurve(poly, i))\r
1185                                                 LineTo(hdc, pts.GetX(poly, i), pts.GetY(poly, i));\r
1186                                         else\r
1187                                         {\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
1191         \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
1195         \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
1199         \r
1200                                                 Bezier(hdc, point(px, py), point(pts.GetX(poly, i), pts.GetY(poly, i)), point(nx, ny));\r
1201         \r
1202                                                 if (pts.GetOnCurve(poly, next))\r
1203                                                         i++;                                    // Following point is on curve, so move past it\r
1204                                         }\r
1205                                 }\r
1206                         }\r
1207                 }\r
1208 \r
1209                 SelectObject(hdc, oldPen);                              // Restore the stuff we disrupted...\r
1210                 SelectObject(hdc, oldBrush);\r
1211                 EndPaint(hWnd, &ps);\r
1212                 break;\r
1213         }\r
1214         case WM_SIZE:\r
1215 \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
1219 \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
1224                 break;\r
1225 \r
1226         case WM_RBUTTONDOWN:\r
1227 \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
1233                 break;\r
1234 \r
1235         case WM_LBUTTONDOWN:\r
1236 \r
1237                 mouseDown = true;\r
1238 \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
1242                 {\r
1243                         if (pts.GetNumPoints() > 0)\r
1244                         {\r
1245 //Do we really need to put a cap on this???\r
1246 //Maybe...\r
1247 //                              if (pts.GetNumPoints() < 16)\r
1248 //                              {\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
1256 //                              }\r
1257                         }\r
1258                 }\r
1259                 else if (currentTool == TOOLAddPoly)    // "Add Poly" tool\r
1260                 {\r
1261 #ifdef DEBUGFOO\r
1262 wsprintf(strBuf, "Adding point... # polys: %u, # points: %u", pts.GetNumPolys(), pts.GetNumPoints());\r
1263 WriteLogMsg(strBuf);\r
1264 #endif\r
1265                         if (polyFirstPoint)\r
1266                         {\r
1267                                 polyFirstPoint = false;\r
1268                                 pts.AddNewPolyAtEnd();\r
1269                         }\r
1270 \r
1271 //Do we really need to put a cap on this???\r
1272 //Maybe...\r
1273 //                      if (pts.GetNumPoints() < 16)\r
1274 //                      {\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
1283 //                      }\r
1284 #ifdef DEBUGFOO\r
1285 wsprintf(strBuf, " --> [# polys: %u, # points: %u]\xD\xA", pts.GetNumPolys(), pts.GetNumPoints());\r
1286 WriteLogMsg(strBuf);\r
1287 #endif\r
1288                 }\r
1289                 else if (currentTool == TOOLSelect || currentTool == TOOLPolySelect)\r
1290                 {\r
1291                         if (pts.GetNumPoints() > 0)\r
1292                         {\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
1299 \r
1300                                 if (wParam & (MK_SHIFT | MK_CONTROL))\r
1301                                         pts.SetOnCurve(ptHighlight, !pts.GetOnCurve(ptHighlight));\r
1302                         }\r
1303                 }\r
1304                 else if (currentTool == TOOLDelPt)\r
1305                 {\r
1306                         if (pts.GetNumPoints() > 0)\r
1307 //Or could use:\r
1308 //                      if (ptHighlight != -1)\r
1309                         {\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
1314                         }\r
1315                 }\r
1316 \r
1317                 break;\r
1318 \r
1319         case WM_LBUTTONUP:\r
1320 \r
1321                 mouseDown = false;\r
1322 \r
1323                 if (currentTool == TOOLScroll || currentTool == TOOLZoom)\r
1324                         ReleaseCapture();\r
1325 \r
1326                 break;\r
1327 \r
1328         case WM_MOUSEMOVE:\r
1329 \r
1330                 SetCursor(hCur[currentTool]);\r
1331 \r
1332             // Extract current point from lParam/calc offset from previous point\r
1333 \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
1337 \r
1338                 if (mouseDown)\r
1339                 {\r
1340                         if (currentTool == TOOLScroll)\r
1341                         {\r
1342                                 // NOTE: OffsetViewportOrg operates in DEVICE UNITS...\r
1343 \r
1344                                 hdc = GetDC(hWnd);\r
1345                                 OffsetViewportOrgEx(hdc, ptOffset.x, ptOffset.y, NULL);\r
1346                                 ReleaseDC(hWnd, hdc);\r
1347 \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
1350 // Above: DONE\r
1351 // Then multiply it by the scaling factor. Whee!\r
1352 \r
1353                                 InvalidateRect(hWnd, NULL, TRUE);\r
1354 //                              SendMessage(hWnd, WM_PAINT, NULL, NULL);\r
1355                         }\r
1356                         else if (currentTool == TOOLAddPt || currentTool == TOOLAddPoly || currentTool == TOOLSelect)\r
1357                         {\r
1358                                 if (currentTool != TOOLAddPt || pts.GetNumPoints() > 0)//yecch.\r
1359                                 {\r
1360                                         POINT pt2;\r
1361                                         pt2.x = pt.x, pt2.y = pt.y;\r
1362                                         // Should also set onCurve here as well, depending on keystate\r
1363 //Or should we?\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
1369                                 }\r
1370                         }\r
1371                         else if (currentTool == TOOLPolySelect)\r
1372                         {\r
1373                                 if (pts.GetNumPoints() > 0)\r
1374                                 {\r
1375                                         POINT pt2;\r
1376                                         pt2.x = pt.x, pt2.y = pt.y;\r
1377                                         // Should also set onCurve here as well, depending on keystate\r
1378 //Or should we?\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
1384                                 }\r
1385                         }\r
1386                 }\r
1387                 else\r
1388                 {\r
1389                         if (currentTool == TOOLSelect || currentTool == TOOLDelPt || currentTool == TOOLAddPt\r
1390                                 || currentTool == TOOLPolySelect)// || currentTool == TOOLAddPoly)\r
1391                         {\r
1392                                 POINT pt2;\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
1397 \r
1398                                 double closest = 1.0e+99;\r
1399 \r
1400                                 for(int i=0; i<pts.GetNumPoints(); i++)\r
1401                                 {\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
1404 \r
1405                                         if (dist < closest)\r
1406                                                 closest = dist, ptHighlight = i;\r
1407                                 }\r
1408 \r
1409                                 if (ptHighlight != oldPtHighlight)\r
1410                                 {\r
1411                                         oldPtHighlight = ptHighlight;\r
1412                                         InvalidateRect(hWnd, NULL, TRUE);\r
1413                                 }\r
1414 \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
1421 \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
1424 \r
1425                                 if (pts.GetNumPoints() > 1 && currentTool == TOOLAddPt)\r
1426                                 {\r
1427                                         double smallest = 1.0e+99;\r
1428 \r
1429                                         for(int i=0; i<pts.GetNumPoints(); i++)\r
1430                                         {\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
1433 \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
1441 \r
1442                                                 if (pp < 0.0)\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
1448 \r
1449 //The answer to the above looks like it might be found here:\r
1450 //\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
1457 //\r
1458 //sx sy 1\r
1459 //ex ey 1\r
1460 //px py 1\r
1461 //\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
1464 //\r
1465 //0         0         0\r
1466 //(ex - sx) (ey - sy) 0\r
1467 //(px - sx) (py - sy) 0\r
1468 //\r
1469 //which greatly simplifies the calculation of the determinant.\r
1470 \r
1471                                                 if (dist < smallest)\r
1472                                                         smallest = dist, ptNextHighlight = pts.GetNext(i), ptHighlight = i;\r
1473                                         }\r
1474 \r
1475                                         if (ptNextHighlight != oldPtNextHighlight)\r
1476                                         {\r
1477                                                 oldPtNextHighlight = ptNextHighlight;\r
1478                                                 InvalidateRect(hWnd, NULL, TRUE);\r
1479                                         }\r
1480                                 }\r
1481                         }\r
1482                 }\r
1483 \r
1484                 ptPrevious.x = pt.x, ptPrevious.y = pt.y;\r
1485 \r
1486                 break;\r
1487 \r
1488         case WM_NOTIFY:\r
1489 \r
1490                 if (((NMHDR *)lParam)->code == TTN_NEEDTEXT)\r
1491                 {\r
1492                         LoadString(hInst, ((TOOLTIPTEXT *)lParam)->hdr.idFrom + 0x80, toolTipTxt, 16);\r
1493                         ((TOOLTIPTEXT *)lParam)->lpszText = toolTipTxt;\r
1494                 }\r
1495 \r
1496                 break;\r
1497 \r
1498         case WM_MENUSELECT:\r
1499         {\r
1500                 statusBarTxt[0] = 0;                                    // Clear status bar text\r
1501                 uint16 flags = wParam >> 16;                    // Extract flags\r
1502 \r
1503                 if (!(flags & MFT_SEPARATOR))\r
1504                 {\r
1505                         uint16 id = wParam & 0xFFFF;\r
1506 \r
1507                         if (flags & MF_POPUP)\r
1508                         {\r
1509                                 if (flags & MF_SYSMENU)\r
1510                                         id = IDS_SYSMENU;\r
1511                                 else\r
1512                                         id = IDM_FILEMENU + wParam;\r
1513                         }\r
1514 \r
1515                         LoadString(hInst, id, statusBarTxt, 64);\r
1516                 }\r
1517 \r
1518                 SendMessage(hStatusBar, SB_SETTEXT, 0 + SBT_NOBORDERS, (LPARAM)statusBarTxt);\r
1519                 break;\r
1520         }\r
1521         case WM_COMMAND:\r
1522         {\r
1523                 uint16 cmd = wParam & 0xFFFF;\r
1524 \r
1525                 if (cmd == IDM_NEW)\r
1526                 {\r
1527 //                    call   CmdIDM_NEW\r
1528                 }\r
1529                 else if (cmd == IDM_OPEN)\r
1530                 {\r
1531 //                    call   SaveChanges\r
1532 //                    .IF (eax)\r
1533 //                      movmov ofn.hwndOwner, eax, hMainWnd\r
1534 //                      mov    ofn.Flags, OFN_PATHMUSTEXIST + OFN_FILEMUSTEXIST\r
1535 //                      invoke GetOpenFileName, ADDR ofn\r
1536 //                      .IF (eax)\r
1537 ////////\r
1538 //jmp @F\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
1542 //@@:\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
1546 //\r
1547 //////\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
1553 //                        jmp    Return\r
1554 //                        //ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\r
1555 //OpenError:              invoke GetLastError\r
1556 //                        // <<< FILE OPEN ERROR CODE HERE >>>\r
1557 //                      .ENDIF\r
1558 //                      zero   eax      // return FALSE\r
1559 //                    .ENDIF\r
1560                 }\r
1561                 else if (cmd == IDM_SAVEAS)\r
1562                 {\r
1563 //                    and    fFileStatus, NOT NAMEDbit\r
1564 //                    call   CmdIDM_SAVE\r
1565                 }\r
1566                 else if (cmd == IDM_SAVE)\r
1567                 {\r
1568 //                    call   CmdIDM_SAVE\r
1569                 }\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
1575                 {\r
1576                         ShowWindow(hCharWnd, (IsWindowVisible(hCharWnd) ? SW_HIDE : SW_SHOWNOACTIVATE));\r
1577 \r
1578 #ifdef DEBUGFOO\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
1583 #endif\r
1584                 }\r
1585                 else\r
1586                         return DefWindowProc(hWnd, msgID, wParam, lParam);\r
1587 \r
1588                 break;\r
1589         }\r
1590         default:\r
1591                 return DefWindowProc(hWnd, msgID, wParam, lParam);\r
1592         }\r
1593 \r
1594         return 0;\r
1595 }\r
1596 \r
1597 //\r
1598 // Initialize TTF data\r
1599 //\r
1600 void CreateNewDoc(void)\r
1601 {\r
1602 }\r
1603 \r
1604 //\r
1605 // Save changes to document before quitting\r
1606 //\r
1607 bool SaveChanges(void)\r
1608 {\r
1609         return true;\r
1610 }\r
1611 \r
1612 \r
1613 \r
1614 //\r
1615 // ABOUT Dialog WndProc\r
1616 //\r
1617 BOOL CALLBACK AboutProc(HWND hDlg, UINT msgID, WPARAM wParam, LPARAM lParam)\r
1618 {\r
1619         switch (msgID)\r
1620         {\r
1621         case WM_INITDIALOG:\r
1622 \r
1623                 MiscCenterWnd(hDlg, hMainWnd);\r
1624                 break;\r
1625 \r
1626         case WM_COMMAND:\r
1627 \r
1628                 if (wParam == IDOK || wParam == IDCANCEL)\r
1629                         EndDialog(hDlg, TRUE);\r
1630 \r
1631                 break;\r
1632 \r
1633         default:\r
1634                 return FALSE;\r
1635         }\r
1636 \r
1637         return TRUE;\r
1638 }\r
1639 \r
1640 //\r
1641 // Character Window WndProc\r
1642 //\r
1643 WndProcCW       PROC  STDCALL, hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM\r
1644 \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
1657                 .ELSE\r
1658 DefProc:          invoke DefWindowProc, hWnd, uMsg, wParam, lParam\r
1659                 .ENDIF\r
1660                 ret\r
1661 \r
1662 WndProcCW       ENDP\r
1663 \r
1664 //\r
1665 // Character Window WndProc\r
1666 //\r
1667 LRESULT CALLBACK WndProcCW(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)\r
1668 {\r
1669         switch (msgID)\r
1670         {\r
1671         default:\r
1672                 return DefWindowProc(hWnd, msgID, wParam, lParam);\r
1673         }\r
1674 \r
1675         return 0;\r
1676 }\r
1677 \r
1678 \r
1679 // Function prototypes\r
1680 \r
1681 int32 FindSelectedTool(void);\r
1682 \r
1683 //\r
1684 // Tool Palette WndProc\r
1685 //\r
1686 LRESULT CALLBACK WndProcTP(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)\r
1687 {\r
1688         PAINTSTRUCT ps;\r
1689         HDC hdc;\r
1690         POINT pt;\r
1691         static uint32 prevTool = -1;\r
1692 \r
1693         switch (msgID)\r
1694         {\r
1695         case WM_PAINT:\r
1696         {\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
1701                 DeleteDC(newDC);\r
1702 \r
1703 // This is crappy. Find some way to tighten this up!\r
1704                 int32 tool = FindSelectedTool();\r
1705 \r
1706                 if (tool != -1)\r
1707                 {\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
1713                         DeleteDC(newDC);\r
1714                 }\r
1715 \r
1716                 EndPaint(hWnd, &ps);\r
1717                 break;\r
1718         }\r
1719         case WM_MOUSEMOVE:\r
1720         {\r
1721                 int32 tool = FindSelectedTool();\r
1722 \r
1723                 if (tool != prevTool)\r
1724                 {\r
1725                         prevTool = tool;\r
1726                         InvalidateRect(hWnd, NULL, FALSE);\r
1727                 }\r
1728 \r
1729                 break;\r
1730         }\r
1731         case WM_RBUTTONUP:\r
1732         {\r
1733                 int32 tool = FindSelectedTool(), oldTool = currentTool;\r
1734 \r
1735                 if (tool != -1)\r
1736                         currentTool = tool;\r
1737 \r
1738                 if (currentTool != TOOLSelect && currentTool != TOOLDelPt && currentTool != TOOLAddPt\r
1739                         && currentTool != TOOLPolySelect)\r
1740                         ptHighlight = -1;\r
1741 \r
1742                 if (currentTool != oldTool)\r
1743                         InvalidateRect(hMainWnd, NULL, TRUE);\r
1744 \r
1745                 if (currentTool == TOOLAddPoly)\r
1746 #ifdef DEBUGFOO\r
1747 {\r
1748 #endif\r
1749                         polyFirstPoint = true;\r
1750 #ifdef DEBUGFOO\r
1751 wsprintf(strBuf, "--> Selected poly tool, polyFirstPoint is %s\n", polyFirstPoint ? "true" : "false");\r
1752 WriteLogMsg(strBuf);\r
1753 }\r
1754 #endif\r
1755 \r
1756                 ReleaseCapture();\r
1757                 ShowWindow(hToolPalWnd, SW_HIDE);\r
1758                 SetFocus(hMainWnd);                                             // Make sure the main wnd keeps focus!\r
1759 \r
1760                 break;\r
1761         }\r
1762         default:\r
1763                 return DefWindowProc(hWnd, msgID, wParam, lParam);\r
1764         }\r
1765 \r
1766         return 0;\r
1767 }\r
1768 \r
1769 //\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
1772 //\r
1773 int32 FindSelectedTool(void)\r
1774 {\r
1775         POINT pt;\r
1776                 \r
1777         GetCursorPos(&pt);\r
1778         ScreenToClient(hToolPalWnd, &pt);\r
1779 \r
1780         uint32 x = (uint32)pt.x / sizeStamp.x, y = (uint32)pt.y / sizeStamp.y, tool = -1;\r
1781 \r
1782         if (x < 4 && y < 2)\r
1783 //      {\r
1784                 tool = (y * 4) + x;\r
1785 \r
1786 //              if (tool == 7)\r
1787 //                      tool = -1;                                                      // 7 has no tool...\r
1788 //      }\r
1789 \r
1790         return tool;\r
1791 }\r
1792 \r
1793 \r
1794 //\r
1795 // Misc center window\r
1796 //\r
1797 void MiscCenterWnd(HWND hChild, HWND hParent)\r
1798 {\r
1799         RECT parent, child;\r
1800 \r
1801         if (!GetWindowRect(hParent, &parent) || !GetWindowRect(hChild, &child))\r
1802                 return;\r
1803 \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
1806 \r
1807         if (x < 0)\r
1808                 x = 0;\r
1809         else if (x > GetSystemMetrics(SM_CXFULLSCREEN) - (child.right - child.left))\r
1810                 x = GetSystemMetrics(SM_CXFULLSCREEN) - (child.right - child.left);\r
1811 \r
1812         if (y < 0)\r
1813                 y = 0;\r
1814         else if (y > GetSystemMetrics(SM_CYFULLSCREEN) - (child.bottom - child.top))\r
1815                 y = GetSystemMetrics(SM_CYFULLSCREEN) - (child.bottom - child.top);\r
1816 \r
1817         SetWindowPos(hChild, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);\r
1818 }\r
1819 \r
1820 //\r
1821 // Allow only one instance\r
1822 //\r
1823 bool OnlyOneInstance(void)\r
1824 {\r
1825         HWND window = FindWindow(className, NULL);\r
1826 \r
1827         if (window == NULL)\r
1828                 return true;\r
1829 \r
1830         ShowWindow(window, SW_SHOWNORMAL);\r
1831         SetWindowPos(window, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);\r
1832 \r
1833         return false;\r
1834 }\r
1835 \r
1836 //\r
1837 // Load/Allocate all resources\r
1838 //\r
1839 bool LoadResources(void)\r
1840 {\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
1849 \r
1850         BITMAP bm;\r
1851 \r
1852         hBMToolPal1 = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_TOOLPAL1));\r
1853         GetObject(hBMToolPal1, sizeof(bm), &bm);\r
1854 \r
1855         // Set up sizes\r
1856 \r
1857         sizeTPBM.x = bm.bmWidth, sizeTPBM.y = bm.bmHeight;\r
1858         sizeStamp.x = bm.bmWidth / 4, sizeStamp.y = bm.bmHeight / 2;\r
1859 \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
1864 \r
1865         LOGBRUSH lb = { BS_NULL, 0, 0 };\r
1866 \r
1867         hNullBrush = CreateBrushIndirect(&lb);\r
1868 \r
1869         return true;\r
1870 }\r
1871 \r
1872 //\r
1873 // Deallocate all resources\r
1874 //\r
1875 void DeallocateResources(void)\r
1876 {\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
1883 }\r
1884 \r
1885 //\r
1886 // Save all application specific data, so we can pick up where we last left off...\r
1887 //\r
1888 void SaveAppState(void)\r
1889 {\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
1896 \r
1897         SetINIInt("Main", "vpx", ptVPM.x);\r
1898         SetINIInt("Main", "vpy", ptVPM.y);\r
1899 \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
1906 \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
1910 }\r
1911 \r
1912 //\r
1913 // Restore all application specific data previously saved\r
1914 //\r
1915 bool RestoreAppState(void)\r
1916 {\r
1917         InitINIFile();\r
1918 \r
1919         WINDOWPLACEMENT wp;\r
1920         wp.length = sizeof(WINDOWPLACEMENT);\r
1921         GetWindowPlacement(hMainWnd, &wp);\r
1922 \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
1929 \r
1930         SetWindowPlacement(hMainWnd, &wp);\r
1931 \r
1932         HDC hdc;\r
1933         POINT pt;\r
1934         hdc = GetDC(hMainWnd);\r
1935         GetViewportOrgEx(hdc, &pt);\r
1936 \r
1937         pt.x = GetINIInt("Main", "vpx", pt.x);\r
1938         pt.y = GetINIInt("Main", "vpy", pt.y);\r
1939 \r
1940         SetViewportOrgEx(hdc, pt.x, pt.y, NULL);\r
1941         ReleaseDC(hMainWnd, hdc);\r
1942 \r
1943         GetWindowPlacement(hCharWnd, &wp);\r
1944 \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
1951 \r
1952         SetWindowPlacement(hCharWnd, &wp);\r
1953 \r
1954         if (wp.showCmd == SW_HIDE)\r
1955                 SendMessage(hToolBar, TB_SETSTATE, ID_TBCHARWIN, MAKELONG(TBSTATE_ENABLED, 0));\r
1956 \r
1957 //  CString lastFile = theApplicationObject.GetProfileString(version, "currentFile", "");\r
1958 //  int lastChar = theApplicationObject.GetProfileInt(version, "currentChar", 0);\r
1959 //  if (lastFile.GetLength())\r
1960 //  {\r
1961 //    // Attempt to restore the last session by open the last file used, etc...\r
1962 //    if (!pDoc->m_myFont.Load(lastFile))\r
1963 //    {\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
1966 //    }\r
1967 //    else\r
1968 //    {\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
1972 //\r
1973 //      BYTE name[512];\r
1974 //      pDoc->m_myFont.GetCharName(lastChar, name);\r
1975 //      m_wndOwned.SetWindowText((char *)name);\r
1976 //    }\r
1977 //  }\r
1978 \r
1979         return true;\r
1980 }\r
1981 \r
1982 //\r
1983 // Initialization\r
1984 //\r
1985 bool Initialization(void)\r
1986 {\r
1987         WNDCLASSEX wcex;\r
1988 \r
1989         if (!LoadResources())\r
1990                 return false;\r
1991 \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
2002 \r
2003         if (!RegisterClassEx(&wcex))\r
2004                 return false;\r
2005 \r
2006         hMainWnd = CreateWindowEx(NULL, className, className, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,\r
2007                 0, 0, 0x1A0, 0x180, NULL, NULL, hInst, NULL);\r
2008 \r
2009         if (!hMainWnd)\r
2010                 return false;\r
2011 \r
2012         ShowWindow(hMainWnd, nCmdShow);\r
2013         UpdateWindow(hMainWnd);\r
2014 \r
2015         // Character window creation\r
2016 \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
2021 \r
2022         if (!RegisterClassEx(&wcex))\r
2023                 return false;\r
2024 \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
2028 \r
2029         if (!hCharWnd)\r
2030                 return false;\r
2031 \r
2032         ShowWindow(hCharWnd, SW_SHOWNORMAL);\r
2033         UpdateWindow(hCharWnd);\r
2034         SetFocus(hMainWnd);                                                     // Make sure main wnd has focus!\r
2035 \r
2036         // Tool palette window creation\r
2037 \r
2038         wcex.lpfnWndProc = WndProcTP;\r
2039         wcex.lpszClassName = CNToolPal;\r
2040 \r
2041         if (!RegisterClassEx(&wcex))\r
2042                 return false;\r
2043 \r
2044         hToolPalWnd = CreateWindowEx(WS_EX_WINDOWEDGE, CNToolPal, NULL, WS_POPUP,\r
2045                 0, 0, sizeTPBM.x, sizeTPBM.y, hMainWnd, NULL, hInst, NULL);\r
2046 \r
2047         if (!hToolPalWnd)\r
2048                 return false;\r
2049 \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
2054 \r
2055         RestoreAppState();                                                      // Restore app related stuff\r
2056 \r
2057         return true;\r
2058 }\r
2059 \r
2060 */\r
2061 \r