xref: /reactos/base/applications/mspaint/main.cpp (revision f5200e6c)
1 /*
2  * PROJECT:    PAINT for ReactOS
3  * LICENSE:    LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
4  * PURPOSE:    Initializing everything
5  * COPYRIGHT:  Copyright 2015 Benedikt Freisen <b.freisen@gmx.net>
6  */
7 
8 #include "precomp.h"
9 
10 POINT g_ptStart, g_ptEnd;
11 BOOL g_askBeforeEnlarging = FALSE;  // TODO: initialize from registry
12 HINSTANCE g_hinstExe = NULL;
13 TCHAR g_szFileName[MAX_LONG_PATH] = { 0 };
14 BOOL g_isAFile = FALSE;
15 BOOL g_imageSaved = FALSE;
16 BOOL g_showGrid = FALSE;
17 
18 CMainWindow mainWindow;
19 
20 /* FUNCTIONS ********************************************************/
21 
22 // get file name extension from filter string
23 static BOOL
24 FileExtFromFilter(LPTSTR pExt, OPENFILENAME *pOFN)
25 {
26     LPTSTR pchExt = pExt;
27     *pchExt = 0;
28 
29     DWORD nIndex = 1;
30     for (LPCTSTR pch = pOFN->lpstrFilter; *pch; ++nIndex)
31     {
32         pch += lstrlen(pch) + 1;
33         if (pOFN->nFilterIndex == nIndex)
34         {
35             for (++pch; *pch && *pch != _T(';'); ++pch)
36             {
37                 *pchExt++ = *pch;
38             }
39             *pchExt = 0;
40             CharLower(pExt);
41             return TRUE;
42         }
43         pch += lstrlen(pch) + 1;
44     }
45     return FALSE;
46 }
47 
48 // Hook procedure for OPENFILENAME to change the file name extension
49 static UINT_PTR APIENTRY
50 OFNHookProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
51 {
52     HWND hParent;
53     OFNOTIFY *pon;
54     switch (uMsg)
55     {
56     case WM_NOTIFY:
57         pon = (OFNOTIFY *)lParam;
58         if (pon->hdr.code == CDN_TYPECHANGE)
59         {
60             hParent = GetParent(hwnd);
61             TCHAR Path[MAX_PATH];
62             SendMessage(hParent, CDM_GETFILEPATH, _countof(Path), (LPARAM)Path);
63             FileExtFromFilter(PathFindExtension(Path), pon->lpOFN);
64             SendMessage(hParent, CDM_SETCONTROLTEXT, 0x047c, (LPARAM)PathFindFileName(Path));
65             lstrcpyn(pon->lpOFN->lpstrFile, Path, pon->lpOFN->nMaxFile);
66         }
67         break;
68     }
69     return 0;
70 }
71 
72 BOOL CMainWindow::GetOpenFileName(IN OUT LPTSTR pszFile, INT cchMaxFile)
73 {
74     static OPENFILENAME ofn = { 0 };
75     static CString strFilter;
76 
77     if (ofn.lStructSize == 0)
78     {
79         // The "All Files" item text
80         CString strAllPictureFiles;
81         strAllPictureFiles.LoadString(g_hinstExe, IDS_ALLPICTUREFILES);
82 
83         // Get the import filter
84         CSimpleArray<GUID> aguidFileTypesI;
85         CImage::GetImporterFilterString(strFilter, aguidFileTypesI, strAllPictureFiles,
86                                         CImage::excludeDefaultLoad, _T('\0'));
87 
88         // Initializing the OPENFILENAME structure for GetOpenFileName
89         ZeroMemory(&ofn, sizeof(ofn));
90         ofn.lStructSize = sizeof(ofn);
91         ofn.hwndOwner   = m_hWnd;
92         ofn.hInstance   = g_hinstExe;
93         ofn.lpstrFilter = strFilter;
94         ofn.Flags       = OFN_EXPLORER | OFN_HIDEREADONLY;
95         ofn.lpstrDefExt = L"png";
96     }
97 
98     ofn.lpstrFile = pszFile;
99     ofn.nMaxFile  = cchMaxFile;
100     return ::GetOpenFileName(&ofn);
101 }
102 
103 BOOL CMainWindow::GetSaveFileName(IN OUT LPTSTR pszFile, INT cchMaxFile)
104 {
105     static OPENFILENAME sfn = { 0 };
106     static CString strFilter;
107 
108     if (sfn.lStructSize == 0)
109     {
110         // Get the export filter
111         CSimpleArray<GUID> aguidFileTypesE;
112         CImage::GetExporterFilterString(strFilter, aguidFileTypesE, NULL,
113                                         CImage::excludeDefaultSave, _T('\0'));
114 
115         // Initializing the OPENFILENAME structure for GetSaveFileName
116         ZeroMemory(&sfn, sizeof(sfn));
117         sfn.lStructSize = sizeof(sfn);
118         sfn.hwndOwner   = m_hWnd;
119         sfn.hInstance   = g_hinstExe;
120         sfn.lpstrFilter = strFilter;
121         sfn.Flags       = OFN_EXPLORER | OFN_OVERWRITEPROMPT | OFN_ENABLEHOOK;
122         sfn.lpfnHook    = OFNHookProc;
123         sfn.lpstrDefExt = L"png";
124 
125         LPWSTR pchDotExt = PathFindExtensionW(pszFile);
126         if (*pchDotExt == UNICODE_NULL)
127         {
128             // Choose PNG
129             wcscat(pszFile, L".png");
130             for (INT i = 0; i < aguidFileTypesE.GetSize(); ++i)
131             {
132                 if (aguidFileTypesE[i] == Gdiplus::ImageFormatPNG)
133                 {
134                     sfn.nFilterIndex = i + 1;
135                     break;
136                 }
137             }
138         }
139     }
140 
141     sfn.lpstrFile = pszFile;
142     sfn.nMaxFile  = cchMaxFile;
143     return ::GetSaveFileName(&sfn);
144 }
145 
146 BOOL CMainWindow::ChooseColor(IN OUT COLORREF *prgbColor)
147 {
148     static CHOOSECOLOR choosecolor = { 0 };
149     static COLORREF custColors[16] =
150     {
151         0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff,
152         0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff
153     };
154 
155     if (choosecolor.lStructSize == 0)
156     {
157         // Initializing the CHOOSECOLOR structure for ChooseColor
158         ZeroMemory(&choosecolor, sizeof(choosecolor));
159         choosecolor.lStructSize  = sizeof(choosecolor);
160         choosecolor.hwndOwner    = m_hWnd;
161         choosecolor.lpCustColors = custColors;
162     }
163 
164     choosecolor.Flags = CC_RGBINIT;
165     choosecolor.rgbResult = *prgbColor;
166     if (!::ChooseColor(&choosecolor))
167         return FALSE;
168 
169     *prgbColor = choosecolor.rgbResult;
170     return TRUE;
171 }
172 
173 HWND CMainWindow::DoCreate()
174 {
175     ::LoadString(g_hinstExe, IDS_DEFAULTFILENAME, g_szFileName, _countof(g_szFileName));
176 
177     CString strTitle;
178     strTitle.Format(IDS_WINDOWTITLE, PathFindFileName(g_szFileName));
179 
180     RECT& rc = registrySettings.WindowPlacement.rcNormalPosition;
181     return Create(HWND_DESKTOP, rc, strTitle, WS_OVERLAPPEDWINDOW, WS_EX_ACCEPTFILES);
182 }
183 
184 // entry point
185 INT WINAPI
186 _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, INT nCmdShow)
187 {
188 #ifdef _DEBUG
189     // Report any memory leaks on exit
190     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
191 #endif
192 
193     g_hinstExe = hInstance;
194 
195     // Initialize common controls library
196     INITCOMMONCONTROLSEX iccx;
197     iccx.dwSize = sizeof(iccx);
198     iccx.dwICC = ICC_STANDARD_CLASSES | ICC_USEREX_CLASSES | ICC_BAR_CLASSES;
199     InitCommonControlsEx(&iccx);
200 
201     // Load settings from registry
202     registrySettings.Load(nCmdShow);
203 
204     // Create the main window
205     if (!mainWindow.DoCreate())
206     {
207         MessageBox(NULL, TEXT("Failed to create main window."), NULL, MB_ICONERROR);
208         return 1;
209     }
210 
211     // Initialize imageModel
212     imageModel.Crop(registrySettings.BMPWidth, registrySettings.BMPHeight);
213     if (__argc >= 2)
214         DoLoadImageFile(mainWindow, __targv[1], TRUE);
215     imageModel.ClearHistory();
216 
217     // Make the window visible on the screen
218     mainWindow.ShowWindow(registrySettings.WindowPlacement.showCmd);
219 
220     // Load the access keys
221     HACCEL hAccel = ::LoadAccelerators(hInstance, MAKEINTRESOURCE(800));
222 
223     // The message loop
224     MSG msg;
225     while (::GetMessage(&msg, NULL, 0, 0))
226     {
227         if (fontsDialog.IsWindow() && fontsDialog.IsDialogMessage(&msg))
228             continue;
229 
230         if (::TranslateAccelerator(mainWindow, hAccel, &msg))
231             continue;
232 
233         ::TranslateMessage(&msg);
234         ::DispatchMessage(&msg);
235     }
236 
237     // Unload the access keys
238     ::DestroyAcceleratorTable(hAccel);
239 
240     // Write back settings to registry
241     registrySettings.Store();
242 
243     // Return the value that PostQuitMessage() gave
244     return (INT)msg.wParam;
245 }
246