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