xref: /reactos/base/applications/mspaint/main.cpp (revision 4567e13e)
1 /*
2  * PROJECT:     PAINT for ReactOS
3  * LICENSE:     LGPL
4  * FILE:        base/applications/mspaint/main.cpp
5  * PURPOSE:     Initializing everything
6  * PROGRAMMERS: Benedikt Freisen
7  */
8 
9 /* INCLUDES *********************************************************/
10 
11 #include "precomp.h"
12 
13 /* FUNCTIONS ********************************************************/
14 
15 POINT start;
16 POINT last;
17 
18 ToolsModel toolsModel;
19 
20 SelectionModel selectionModel;
21 
22 LOGFONT lfTextFont;
23 HFONT hfontTextFont;
24 HWND hwndEditCtl;
25 LPTSTR textToolText = NULL;
26 int textToolTextMaxLen = 0;
27 
28 PaletteModel paletteModel;
29 
30 RegistrySettings registrySettings;
31 
32 ImageModel imageModel;
33 BOOL askBeforeEnlarging = FALSE;  // TODO: initialize from registry
34 
35 HWND hStatusBar;
36 CHOOSECOLOR choosecolor;
37 OPENFILENAME ofn;
38 OPENFILENAME sfn;
39 HICON hNontranspIcon;
40 HICON hTranspIcon;
41 
42 HCURSOR hCurFill;
43 HCURSOR hCurColor;
44 HCURSOR hCurZoom;
45 HCURSOR hCurPen;
46 HCURSOR hCurAirbrush;
47 
48 HWND hToolBtn[16];
49 
50 HINSTANCE hProgInstance;
51 
52 TCHAR filepathname[1000];
53 BOOL isAFile = FALSE;
54 int fileSize;
55 int fileHPPM = 2834;
56 int fileVPPM = 2834;
57 SYSTEMTIME fileTime;
58 
59 BOOL showGrid = FALSE;
60 BOOL showMiniature = FALSE;
61 
62 CMainWindow mainWindow;
63 CFullscreenWindow fullscreenWindow;
64 CMiniatureWindow miniature;
65 CToolBox toolBoxContainer;
66 CToolSettingsWindow toolSettingsWindow;
67 CPaletteWindow paletteWindow;
68 CScrollboxWindow scrollboxWindow;
69 CScrollboxWindow scrlClientWindow;
70 CSelectionWindow selectionWindow;
71 CImgAreaWindow imageArea;
72 CSizeboxWindow sizeboxLeftTop;
73 CSizeboxWindow sizeboxCenterTop;
74 CSizeboxWindow sizeboxRightTop;
75 CSizeboxWindow sizeboxLeftCenter;
76 CSizeboxWindow sizeboxRightCenter;
77 CSizeboxWindow sizeboxLeftBottom;
78 CSizeboxWindow sizeboxCenterBottom;
79 CSizeboxWindow sizeboxRightBottom;
80 CTextEditWindow textEditWindow;
81 
82 // get file name extension from filter string
83 static BOOL
84 FileExtFromFilter(LPTSTR pExt, LPCTSTR pTitle, OPENFILENAME *pOFN)
85 {
86     LPTSTR pchExt = pExt;
87     *pchExt = 0;
88 
89     DWORD nIndex = 1;
90     for (LPCTSTR pch = pOFN->lpstrFilter; *pch; ++nIndex)
91     {
92         pch += lstrlen(pch) + 1;
93         if (pOFN->nFilterIndex == nIndex)
94         {
95             for (++pch; *pch && *pch != _T(';'); ++pch)
96             {
97                 *pchExt++ = *pch;
98             }
99             *pchExt = 0;
100             CharLower(pExt);
101             return TRUE;
102         }
103         pch += lstrlen(pch) + 1;
104     }
105     return FALSE;
106 }
107 
108 // Hook procedure for OPENFILENAME to change the file name extension
109 static UINT_PTR APIENTRY
110 OFNHookProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
111 {
112     HWND hParent;
113     OFNOTIFY *pon;
114     switch (uMsg)
115     {
116     case WM_NOTIFY:
117         pon = (OFNOTIFY *)lParam;
118         if (pon->hdr.code == CDN_TYPECHANGE)
119         {
120             hParent = GetParent(hwnd);
121             TCHAR Path[MAX_PATH];
122             SendMessage(hParent, CDM_GETFILEPATH, SIZEOF(Path), (LPARAM)Path);
123             LPTSTR pchTitle = _tcsrchr(Path, _T('\\'));
124             if (pchTitle == NULL)
125                 pchTitle = _tcsrchr(Path, _T('/'));
126 
127             LPTSTR pch = _tcsrchr((pchTitle ? pchTitle : Path), _T('.'));
128             if (pch && pchTitle)
129             {
130                 pchTitle++;
131                 *pch = 0;
132                 FileExtFromFilter(pch, pchTitle, pon->lpOFN);
133                 SendMessage(hParent, CDM_SETCONTROLTEXT, 0x047c, (LPARAM)pchTitle);
134                 lstrcpyn(pon->lpOFN->lpstrFile, Path, SIZEOF(pon->lpOFN->lpstrFile));
135             }
136         }
137         break;
138     }
139     return 0;
140 }
141 
142 /* entry point */
143 
144 int WINAPI
145 _tWinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPTSTR lpszArgument, int nFunsterStil)
146 {
147     HWND hwnd;               /* This is the handle for our window */
148     MSG messages;            /* Here messages to the application are saved */
149 
150     HMENU menu;
151     HACCEL haccel;
152 
153     TCHAR sfnFilename[1000];
154     TCHAR sfnFiletitle[256];
155     TCHAR ofnFilename[1000];
156     TCHAR ofnFiletitle[256];
157     TCHAR miniaturetitle[100];
158     static int custColors[16] = { 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff,
159         0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff
160     };
161 
162     /* init font for text tool */
163     lfTextFont.lfHeight = 0;
164     lfTextFont.lfWidth = 0;
165     lfTextFont.lfEscapement = 0;
166     lfTextFont.lfOrientation = 0;
167     lfTextFont.lfWeight = FW_NORMAL;
168     lfTextFont.lfItalic = FALSE;
169     lfTextFont.lfUnderline = FALSE;
170     lfTextFont.lfStrikeOut = FALSE;
171     lfTextFont.lfCharSet = DEFAULT_CHARSET;
172     lfTextFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
173     lfTextFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
174     lfTextFont.lfQuality = DEFAULT_QUALITY;
175     lfTextFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
176     lstrcpy(lfTextFont.lfFaceName, _T(""));
177     hfontTextFont = CreateFontIndirect(&lfTextFont);
178 
179     hProgInstance = hThisInstance;
180 
181     /* initialize common controls library */
182     InitCommonControls();
183 
184     LoadString(hThisInstance, IDS_DEFAULTFILENAME, filepathname, SIZEOF(filepathname));
185     CPath pathFileName(filepathname);
186     pathFileName.StripPath();
187     CString strTitle;
188     strTitle.Format(IDS_WINDOWTITLE, (LPCTSTR)pathFileName);
189     LoadString(hThisInstance, IDS_MINIATURETITLE, miniaturetitle, SIZEOF(miniaturetitle));
190 
191     /* load settings from registry */
192     registrySettings.Load();
193     showMiniature = registrySettings.ShowThumbnail;
194     imageModel.Crop(registrySettings.BMPWidth, registrySettings.BMPHeight);
195 
196     /* create main window */
197     RECT mainWindowPos = {0, 0, 544, 375};	// FIXME: use equivalent of CW_USEDEFAULT for position
198     hwnd = mainWindow.Create(HWND_DESKTOP, mainWindowPos, strTitle, WS_OVERLAPPEDWINDOW);
199 
200     RECT fullscreenWindowPos = {0, 0, 100, 100};
201     fullscreenWindow.Create(HWND_DESKTOP, fullscreenWindowPos, NULL, WS_POPUPWINDOW | WS_MAXIMIZE);
202 
203     RECT miniaturePos = {(LONG) registrySettings.ThumbXPos, (LONG) registrySettings.ThumbYPos,
204                          (LONG) registrySettings.ThumbXPos + (LONG) registrySettings.ThumbWidth,
205                          (LONG) registrySettings.ThumbYPos + (LONG) registrySettings.ThumbHeight};
206     miniature.Create(hwnd, miniaturePos, miniaturetitle,
207                      WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME, WS_EX_PALETTEWINDOW);
208     miniature.ShowWindow(showMiniature ? SW_SHOW : SW_HIDE);
209 
210     /* loading and setting the window menu from resource */
211     menu = LoadMenu(hThisInstance, MAKEINTRESOURCE(ID_MENU));
212     SetMenu(hwnd, menu);
213     haccel = LoadAccelerators(hThisInstance, MAKEINTRESOURCE(800));
214 
215     /* preloading the draw transparent/nontransparent icons for later use */
216     hNontranspIcon =
217         (HICON) LoadImage(hThisInstance, MAKEINTRESOURCE(IDI_NONTRANSPARENT), IMAGE_ICON, 40, 30, LR_DEFAULTCOLOR);
218     hTranspIcon =
219         (HICON) LoadImage(hThisInstance, MAKEINTRESOURCE(IDI_TRANSPARENT), IMAGE_ICON, 40, 30, LR_DEFAULTCOLOR);
220 
221     hCurFill     = LoadIcon(hThisInstance, MAKEINTRESOURCE(IDC_FILL));
222     hCurColor    = LoadIcon(hThisInstance, MAKEINTRESOURCE(IDC_COLOR));
223     hCurZoom     = LoadIcon(hThisInstance, MAKEINTRESOURCE(IDC_ZOOM));
224     hCurPen      = LoadIcon(hThisInstance, MAKEINTRESOURCE(IDC_PEN));
225     hCurAirbrush = LoadIcon(hThisInstance, MAKEINTRESOURCE(IDC_AIRBRUSH));
226 
227     CreateWindowEx(0, _T("STATIC"), NULL, WS_CHILD | WS_VISIBLE | SS_ETCHEDHORZ, 0, 0, 5000, 2, hwnd, NULL,
228                    hThisInstance, NULL);
229 
230     RECT toolBoxContainerPos = {2, 2, 2 + 52, 2 + 350};
231     toolBoxContainer.Create(hwnd, toolBoxContainerPos, NULL, WS_CHILD | WS_VISIBLE);
232     /* creating the tool settings child window */
233     RECT toolSettingsWindowPos = {5, 208, 5 + 42, 208 + 140};
234     toolSettingsWindow.Create(toolBoxContainer.m_hWnd, toolSettingsWindowPos, NULL, WS_CHILD | WS_VISIBLE);
235 
236     /* creating the palette child window */
237     RECT paletteWindowPos = {56, 9, 56 + 255, 9 + 32};
238     paletteWindow.Create(hwnd, paletteWindowPos, NULL, WS_CHILD | WS_VISIBLE);
239 
240     /* creating the scroll box */
241     RECT scrollboxWindowPos = {56, 49, 56 + 472, 49 + 248};
242     scrollboxWindow.Create(hwnd, scrollboxWindowPos, NULL,
243                            WS_CHILD | WS_GROUP | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE, WS_EX_CLIENTEDGE);
244 
245     /* creating the status bar */
246     hStatusBar =
247         CreateWindowEx(0, STATUSCLASSNAME, NULL, SBARS_SIZEGRIP | WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hwnd,
248                        NULL, hThisInstance, NULL);
249     SendMessage(hStatusBar, SB_SETMINHEIGHT, 21, 0);
250 
251     RECT scrlClientWindowPos = {0, 0, 0 + 500, 0 + 500};
252     scrlClientWindow.Create(scrollboxWindow.m_hWnd, scrlClientWindowPos, NULL, WS_CHILD | WS_VISIBLE);
253 
254     /* create selection window (initially hidden) */
255     RECT selectionWindowPos = {350, 0, 350 + 100, 0 + 100};
256     selectionWindow.Create(scrlClientWindow.m_hWnd, selectionWindowPos, NULL, WS_CHILD | BS_OWNERDRAW);
257 
258     /* creating the window inside the scroll box, on which the image in hDrawingDC's bitmap is drawn */
259     RECT imageAreaPos = {3, 3, 3 + imageModel.GetWidth(), 3 + imageModel.GetHeight()};
260     imageArea.Create(scrlClientWindow.m_hWnd, imageAreaPos, NULL, WS_CHILD | WS_VISIBLE);
261 
262     if (__argc >= 2)
263     {
264         WIN32_FIND_DATAW find;
265         HANDLE hFind = FindFirstFileW(__targv[1], &find);
266         if (hFind != INVALID_HANDLE_VALUE)
267         {
268             FindClose(hFind);
269 
270             // check the file size
271             if (find.nFileSizeHigh || find.nFileSizeLow)
272             {
273                 // load it now
274                 HBITMAP bmNew = NULL;
275                 LoadDIBFromFile(&bmNew, __targv[1], &fileTime, &fileSize, &fileHPPM, &fileVPPM);
276                 if (bmNew)
277                 {
278                     // valid bitmap file
279                     GetFullPathName(__targv[1], SIZEOF(filepathname), filepathname, NULL);
280                     imageModel.Insert(bmNew);
281                     CPath pathFileName(filepathname);
282                     pathFileName.StripPath();
283 
284                     CString strTitle;
285                     strTitle.Format(IDS_WINDOWTITLE, (LPCTSTR)pathFileName);
286                     mainWindow.SetWindowText(strTitle);
287 
288                     imageModel.ClearHistory();
289 
290                     isAFile = TRUE;
291                     registrySettings.SetMostRecentFile(filepathname);
292                 }
293                 else
294                 {
295                     // cannot open and not empty
296                     CStringW strText;
297                     strText.Format(IDS_LOADERRORTEXT, __targv[1]);
298                     MessageBoxW(NULL, strText, NULL, MB_ICONERROR);
299                 }
300             }
301             else
302             {
303                 // open the empty file
304                 GetFullPathName(__targv[1], SIZEOF(filepathname), filepathname, NULL);
305                 CPath pathFileName(filepathname);
306                 pathFileName.StripPath();
307 
308                 CString strTitle;
309                 strTitle.Format(IDS_WINDOWTITLE, (LPCTSTR)pathFileName);
310                 mainWindow.SetWindowText(strTitle);
311 
312                 imageModel.ClearHistory();
313 
314                 isAFile = TRUE;
315                 registrySettings.SetMostRecentFile(filepathname);
316             }
317         }
318         else
319         {
320             // does not exist
321             CStringW strText;
322             strText.Format(IDS_LOADERRORTEXT, __targv[1]);
323             MessageBoxW(NULL, strText, NULL, MB_ICONERROR);
324         }
325     }
326 
327     /* initializing the CHOOSECOLOR structure for use with ChooseColor */
328     choosecolor.lStructSize    = sizeof(CHOOSECOLOR);
329     choosecolor.hwndOwner      = hwnd;
330     choosecolor.hInstance      = NULL;
331     choosecolor.rgbResult      = 0x00ffffff;
332     choosecolor.lpCustColors   = (COLORREF*) &custColors;
333     choosecolor.Flags          = 0;
334     choosecolor.lCustData      = 0;
335     choosecolor.lpfnHook       = NULL;
336     choosecolor.lpTemplateName = NULL;
337 
338     /* initializing the OPENFILENAME structure for use with GetOpenFileName and GetSaveFileName */
339     CopyMemory(ofnFilename, filepathname, sizeof(filepathname));
340     CString strImporters;
341     CSimpleArray<GUID> aguidFileTypesI;
342     CString strAllPictureFiles;
343     strAllPictureFiles.LoadString(hThisInstance, IDS_ALLPICTUREFILES);
344     CImage::GetImporterFilterString(strImporters, aguidFileTypesI, strAllPictureFiles, CImage::excludeDefaultLoad, _T('\0'));
345 //     CAtlStringW strAllFiles;
346 //     strAllFiles.LoadString(hThisInstance, IDS_ALLFILES);
347 //     strImporters = strAllFiles + CAtlStringW(_T("|*.*|")).Replace('|', '\0') + strImporters;
348     ZeroMemory(&ofn, sizeof(OPENFILENAME));
349     ofn.lStructSize    = sizeof(OPENFILENAME);
350     ofn.hwndOwner      = hwnd;
351     ofn.hInstance      = hThisInstance;
352     ofn.lpstrFilter    = strImporters;
353     ofn.lpstrFile      = ofnFilename;
354     ofn.nMaxFile       = SIZEOF(ofnFilename);
355     ofn.lpstrFileTitle = ofnFiletitle;
356     ofn.nMaxFileTitle  = SIZEOF(ofnFiletitle);
357     ofn.Flags          = OFN_HIDEREADONLY;
358 
359     CopyMemory(sfnFilename, filepathname, sizeof(filepathname));
360     CString strExporters;
361     CSimpleArray<GUID> aguidFileTypesE;
362     CImage::GetExporterFilterString(strExporters, aguidFileTypesE, NULL, CImage::excludeDefaultSave, _T('\0'));
363     ZeroMemory(&sfn, sizeof(OPENFILENAME));
364     sfn.lStructSize    = sizeof(OPENFILENAME);
365     sfn.hwndOwner      = hwnd;
366     sfn.hInstance      = hThisInstance;
367     sfn.lpstrFilter    = strExporters;
368     sfn.lpstrFile      = sfnFilename;
369     sfn.nMaxFile       = SIZEOF(sfnFilename);
370     sfn.lpstrFileTitle = sfnFiletitle;
371     sfn.nMaxFileTitle  = SIZEOF(sfnFiletitle);
372     sfn.Flags          = OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_EXPLORER | OFN_ENABLEHOOK;
373     sfn.lpfnHook       = OFNHookProc;
374 
375     /* creating the size boxes */
376     RECT sizeboxPos = {0, 0, 0 + 3, 0 + 3};
377     sizeboxLeftTop.Create(scrlClientWindow.m_hWnd, sizeboxPos, NULL, WS_CHILD | WS_VISIBLE);
378     sizeboxCenterTop.Create(scrlClientWindow.m_hWnd, sizeboxPos, NULL, WS_CHILD | WS_VISIBLE);
379     sizeboxRightTop.Create(scrlClientWindow.m_hWnd, sizeboxPos, NULL, WS_CHILD | WS_VISIBLE);
380     sizeboxLeftCenter.Create(scrlClientWindow.m_hWnd, sizeboxPos, NULL, WS_CHILD | WS_VISIBLE);
381     sizeboxRightCenter.Create(scrlClientWindow.m_hWnd, sizeboxPos, NULL, WS_CHILD | WS_VISIBLE);
382     sizeboxLeftBottom.Create(scrlClientWindow.m_hWnd, sizeboxPos, NULL, WS_CHILD | WS_VISIBLE);
383     sizeboxCenterBottom.Create(scrlClientWindow.m_hWnd, sizeboxPos, NULL, WS_CHILD | WS_VISIBLE);
384     sizeboxRightBottom.Create(scrlClientWindow.m_hWnd, sizeboxPos, NULL, WS_CHILD | WS_VISIBLE);
385     /* placing the size boxes around the image */
386     imageArea.SendMessage(WM_SIZE, 0, 0);
387 
388     /* by moving the window, the things in WM_SIZE are done */
389     mainWindow.SetWindowPlacement(&(registrySettings.WindowPlacement));
390 
391     /* creating the text editor window for the text tool */
392     RECT textEditWindowPos = {300, 0, 300 + 300, 0 + 200};
393     textEditWindow.Create(hwnd, textEditWindowPos, NULL, WS_OVERLAPPEDWINDOW);
394 
395     /* Make the window visible on the screen */
396     ShowWindow (hwnd, nFunsterStil);
397 
398     /* inform the system, that the main window accepts dropped files */
399     DragAcceptFiles(hwnd, TRUE);
400 
401     /* Run the message loop. It will run until GetMessage() returns 0 */
402     while (GetMessage(&messages, NULL, 0, 0))
403     {
404         TranslateAccelerator(hwnd, haccel, &messages);
405 
406         /* Translate virtual-key messages into character messages */
407         TranslateMessage(&messages);
408         /* Send message to WindowProcedure */
409         DispatchMessage(&messages);
410     }
411 
412     /* write back settings to registry */
413     registrySettings.ShowThumbnail = showMiniature;
414     registrySettings.BMPWidth = imageModel.GetWidth();
415     registrySettings.BMPHeight = imageModel.GetHeight();
416     registrySettings.Store();
417 
418     /* The program return-value is 0 - The value that PostQuitMessage() gave */
419     return messages.wParam;
420 }
421