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