[MSPAINT] Fix interpretation of command line (#707)
[reactos.git] / base / applications / mspaint / main.cpp
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 }