[CONSOLE.CPL]: Minor code refactoring:
[reactos.git] / reactos / dll / cpl / console / options.c
1 /*
2 * PROJECT: ReactOS Console Configuration DLL
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/cpl/console/options.c
5 * PURPOSE: Options dialog
6 * PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org)
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 */
9
10 #include "console.h"
11
12 #define NDEBUG
13 #include <debug.h>
14
15 #define MAX_VALUE_NAME 16383
16
17
18 static INT
19 List_GetCount(IN PLIST_CTL ListCtl)
20 {
21 return (INT)SendMessageW(ListCtl->hWndList, CB_GETCOUNT, 0, 0);
22 }
23
24 static ULONG_PTR
25 List_GetData(IN PLIST_CTL ListCtl, IN INT Index)
26 {
27 return (ULONG_PTR)SendMessageW(ListCtl->hWndList, CB_GETITEMDATA, (WPARAM)Index, 0);
28 }
29
30 static VOID
31 AddCodePage(
32 IN PLIST_CTL ListCtl,
33 IN UINT CodePage)
34 {
35 UINT iItem, iDupItem;
36 CPINFOEXW CPInfo;
37
38 /*
39 * Add only valid code pages, that is:
40 * - If the CodePage is one of the reserved (alias) values:
41 * CP_ACP == 0 ; CP_OEMCP == 1 ; CP_MACCP == 2 ; CP_THREAD_ACP == 3 ;
42 * or the deprecated CP_SYMBOL == 42 (see http://archives.miloush.net/michkap/archive/2005/11/08/490495.html)
43 * it is considered invalid.
44 * - If IsValidCodePage() fails because the code page is listed but
45 * not installed on the system, it is also considered invalid.
46 */
47 if (CodePage == CP_ACP || CodePage == CP_OEMCP || CodePage == CP_MACCP ||
48 CodePage == CP_THREAD_ACP || CodePage == CP_SYMBOL || !IsValidCodePage(CodePage))
49 {
50 return;
51 }
52
53 /* Retrieve the code page display name */
54 if (!GetCPInfoExW(CodePage, 0, &CPInfo))
55 {
56 /* We failed, just use the code page value as its name */
57 // _ultow(CodePage, CPInfo.CodePageName, 10);
58 StringCchPrintfW(CPInfo.CodePageName, ARRAYSIZE(CPInfo.CodePageName), L"%lu", CodePage);
59 }
60
61 /* Add the code page into the list, sorted by code page value. Avoid any duplicates. */
62 iDupItem = CB_ERR;
63 iItem = BisectListSortedByValue(ListCtl, CodePage, &iDupItem, TRUE);
64 if (iItem == CB_ERR)
65 iItem = 0;
66 if (iDupItem != CB_ERR)
67 return;
68 iItem = (UINT)SendMessageW(ListCtl->hWndList, CB_INSERTSTRING, iItem, (LPARAM)CPInfo.CodePageName);
69 if (iItem != CB_ERR && iItem != CB_ERRSPACE)
70 iItem = SendMessageW(ListCtl->hWndList, CB_SETITEMDATA, iItem, CodePage);
71 }
72
73 static VOID
74 BuildCodePageList(
75 IN HWND hDlg)
76 {
77 LIST_CTL ListCtl;
78 HKEY hKey;
79 DWORD dwIndex, dwSize, dwType;
80 UINT CodePage;
81 WCHAR szValueName[MAX_VALUE_NAME];
82
83 // #define REGSTR_PATH_CODEPAGE TEXT("System\\CurrentControlSet\\Control\\Nls\\CodePage")
84 /* Open the Nls\CodePage key */
85 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
86 L"System\\CurrentControlSet\\Control\\Nls\\CodePage",
87 0,
88 KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
89 &hKey) != ERROR_SUCCESS)
90 {
91 return;
92 }
93
94 ListCtl.hWndList = GetDlgItem(hDlg, IDL_CODEPAGE);
95 ListCtl.GetCount = List_GetCount;
96 ListCtl.GetData = List_GetData;
97
98 /* Enumerate all the available code pages on the system */
99 dwSize = ARRAYSIZE(szValueName);
100 dwIndex = 0;
101 while (RegEnumValueW(hKey, dwIndex, szValueName, &dwSize,
102 NULL, &dwType, NULL, NULL) == ERROR_SUCCESS) // != ERROR_NO_MORE_ITEMS
103 {
104 /* Ignore these parameters, prepare for next iteration */
105 dwSize = ARRAYSIZE(szValueName);
106 ++dwIndex;
107
108 /* Check the value type validity */
109 if (dwType != REG_SZ)
110 continue;
111
112 /*
113 * Add the code page into the list.
114 * If _wtol fails and returns 0, the code page is considered invalid
115 * (and indeed this value corresponds to the CP_ACP alias too).
116 */
117 CodePage = (UINT)_wtol(szValueName);
118 if (CodePage == 0) continue;
119 AddCodePage(&ListCtl, CodePage);
120 }
121
122 RegCloseKey(hKey);
123
124 /* Add the special UTF-7 (CP_UTF7 65000) and UTF-8 (CP_UTF8 65001) code pages */
125 AddCodePage(&ListCtl, CP_UTF7);
126 AddCodePage(&ListCtl, CP_UTF8);
127
128 /* Find and select the current code page in the sorted list */
129 if (BisectListSortedByValue(&ListCtl, ConInfo->CodePage, &CodePage, FALSE) == CB_ERR ||
130 CodePage == CB_ERR)
131 {
132 /* Not found, select the first element */
133 CodePage = 0;
134 }
135 SendMessageW(ListCtl.hWndList, CB_SETCURSEL, (WPARAM)CodePage, 0);
136 }
137
138 static VOID
139 UpdateDialogElements(HWND hwndDlg, PCONSOLE_STATE_INFO pConInfo)
140 {
141 HWND hDlgCtrl;
142
143 /* Update cursor size */
144 if (pConInfo->CursorSize <= 25)
145 {
146 /* Small cursor */
147 hDlgCtrl = GetDlgItem(hwndDlg, IDC_RADIO_SMALL_CURSOR);
148 SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
149
150 hDlgCtrl = GetDlgItem(hwndDlg, IDC_RADIO_MEDIUM_CURSOR);
151 SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_UNCHECKED, 0);
152 hDlgCtrl = GetDlgItem(hwndDlg, IDC_RADIO_LARGE_CURSOR);
153 SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_UNCHECKED, 0);
154 }
155 else if (pConInfo->CursorSize <= 50)
156 {
157 hDlgCtrl = GetDlgItem(hwndDlg, IDC_RADIO_MEDIUM_CURSOR);
158 SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
159
160 hDlgCtrl = GetDlgItem(hwndDlg, IDC_RADIO_SMALL_CURSOR);
161 SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_UNCHECKED, 0);
162 hDlgCtrl = GetDlgItem(hwndDlg, IDC_RADIO_LARGE_CURSOR);
163 SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_UNCHECKED, 0);
164 }
165 else /* if (pConInfo->CursorSize <= 100) */
166 {
167 hDlgCtrl = GetDlgItem(hwndDlg, IDC_RADIO_LARGE_CURSOR);
168 SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
169
170 hDlgCtrl = GetDlgItem(hwndDlg, IDC_RADIO_SMALL_CURSOR);
171 SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_UNCHECKED, 0);
172 hDlgCtrl = GetDlgItem(hwndDlg, IDC_RADIO_MEDIUM_CURSOR);
173 SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_UNCHECKED, 0);
174 }
175
176 /* Update num buffers */
177 hDlgCtrl = GetDlgItem(hwndDlg, IDC_UPDOWN_NUM_BUFFER);
178 SendMessageW(hDlgCtrl, UDM_SETRANGE, 0, MAKELONG(999, 1));
179 SetDlgItemInt(hwndDlg, IDC_EDIT_NUM_BUFFER, pConInfo->NumberOfHistoryBuffers, FALSE);
180
181 /* Update buffer size */
182 hDlgCtrl = GetDlgItem(hwndDlg, IDC_UPDOWN_BUFFER_SIZE);
183 SendMessageW(hDlgCtrl, UDM_SETRANGE, 0, MAKELONG(999, 1));
184 SetDlgItemInt(hwndDlg, IDC_EDIT_BUFFER_SIZE, pConInfo->HistoryBufferSize, FALSE);
185
186 /* Update discard duplicates */
187 CheckDlgButton(hwndDlg, IDC_CHECK_DISCARD_DUPLICATES,
188 pConInfo->HistoryNoDup ? BST_CHECKED : BST_UNCHECKED);
189
190 /* Update full/window screen */
191 if (pConInfo->FullScreen)
192 {
193 hDlgCtrl = GetDlgItem(hwndDlg, IDC_RADIO_DISPLAY_FULL);
194 SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
195
196 hDlgCtrl = GetDlgItem(hwndDlg, IDC_RADIO_DISPLAY_WINDOW);
197 SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_UNCHECKED, 0);
198 }
199 else
200 {
201 hDlgCtrl = GetDlgItem(hwndDlg, IDC_RADIO_DISPLAY_WINDOW);
202 SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
203
204 hDlgCtrl = GetDlgItem(hwndDlg, IDC_RADIO_DISPLAY_FULL);
205 SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)BST_UNCHECKED, 0);
206 }
207
208 /* Update quick edit */
209 CheckDlgButton(hwndDlg, IDC_CHECK_QUICK_EDIT,
210 pConInfo->QuickEdit ? BST_CHECKED : BST_UNCHECKED);
211
212 /* Update insert mode */
213 CheckDlgButton(hwndDlg, IDC_CHECK_INSERT_MODE,
214 pConInfo->InsertMode ? BST_CHECKED : BST_UNCHECKED);
215 }
216
217 INT_PTR
218 CALLBACK
219 OptionsProc(HWND hwndDlg,
220 UINT uMsg,
221 WPARAM wParam,
222 LPARAM lParam)
223 {
224 switch (uMsg)
225 {
226 case WM_INITDIALOG:
227 {
228 BuildCodePageList(hwndDlg);
229 UpdateDialogElements(hwndDlg, ConInfo);
230 return TRUE;
231 }
232
233 case WM_NOTIFY:
234 {
235 LPPSHNOTIFY lppsn = (LPPSHNOTIFY)lParam;
236
237 if (lppsn->hdr.code == UDN_DELTAPOS)
238 {
239 LPNMUPDOWN lpnmud = (LPNMUPDOWN)lParam;
240
241 if (lppsn->hdr.idFrom == IDC_UPDOWN_BUFFER_SIZE)
242 {
243 lpnmud->iPos = min(max(lpnmud->iPos + lpnmud->iDelta, 1), 999);
244 ConInfo->HistoryBufferSize = lpnmud->iPos;
245 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
246 }
247 else if (lppsn->hdr.idFrom == IDC_UPDOWN_NUM_BUFFER)
248 {
249 lpnmud->iPos = min(max(lpnmud->iPos + lpnmud->iDelta, 1), 999);
250 ConInfo->NumberOfHistoryBuffers = lpnmud->iPos;
251 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
252 }
253 }
254 else if (lppsn->hdr.code == PSN_APPLY)
255 {
256 ApplyConsoleInfo(hwndDlg);
257 return TRUE;
258 }
259 break;
260 }
261
262 case WM_COMMAND:
263 {
264 LRESULT lResult;
265
266 switch (LOWORD(wParam))
267 {
268 case IDC_RADIO_SMALL_CURSOR:
269 {
270 ConInfo->CursorSize = 25;
271 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
272 break;
273 }
274 case IDC_RADIO_MEDIUM_CURSOR:
275 {
276 ConInfo->CursorSize = 50;
277 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
278 break;
279 }
280 case IDC_RADIO_LARGE_CURSOR:
281 {
282 ConInfo->CursorSize = 100;
283 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
284 break;
285 }
286 case IDC_RADIO_DISPLAY_WINDOW:
287 {
288 ConInfo->FullScreen = FALSE;
289 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
290 break;
291 }
292 case IDC_RADIO_DISPLAY_FULL:
293 {
294 ConInfo->FullScreen = TRUE;
295 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
296 break;
297 }
298 case IDC_CHECK_QUICK_EDIT:
299 {
300 lResult = SendMessageW((HWND)lParam, BM_GETCHECK, 0, 0);
301 if (lResult == BST_CHECKED)
302 {
303 ConInfo->QuickEdit = FALSE;
304 SendMessageW((HWND)lParam, BM_SETCHECK, (WPARAM)BST_UNCHECKED, 0);
305 }
306 else if (lResult == BST_UNCHECKED)
307 {
308 ConInfo->QuickEdit = TRUE;
309 SendMessageW((HWND)lParam, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
310 }
311 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
312 break;
313 }
314 case IDC_CHECK_INSERT_MODE:
315 {
316 lResult = SendMessageW((HWND)lParam, BM_GETCHECK, 0, 0);
317 if (lResult == BST_CHECKED)
318 {
319 ConInfo->InsertMode = FALSE;
320 SendMessageW((HWND)lParam, BM_SETCHECK, (WPARAM)BST_UNCHECKED, 0);
321 }
322 else if (lResult == BST_UNCHECKED)
323 {
324 ConInfo->InsertMode = TRUE;
325 SendMessageW((HWND)lParam, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
326 }
327 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
328 break;
329 }
330 case IDC_CHECK_DISCARD_DUPLICATES:
331 {
332 lResult = SendMessageW((HWND)lParam, BM_GETCHECK, 0, 0);
333 if (lResult == BST_CHECKED)
334 {
335 ConInfo->HistoryNoDup = FALSE;
336 SendMessageW((HWND)lParam, BM_SETCHECK, (WPARAM)BST_UNCHECKED, 0);
337 }
338 else if (lResult == BST_UNCHECKED)
339 {
340 ConInfo->HistoryNoDup = TRUE;
341 SendMessageW((HWND)lParam, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
342 }
343 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
344 break;
345 }
346 case IDC_EDIT_BUFFER_SIZE:
347 {
348 if (HIWORD(wParam) == EN_KILLFOCUS)
349 {
350 DWORD sizeBuff;
351
352 sizeBuff = GetDlgItemInt(hwndDlg, IDC_EDIT_BUFFER_SIZE, NULL, FALSE);
353 sizeBuff = min(max(sizeBuff, 1), 999);
354
355 ConInfo->HistoryBufferSize = sizeBuff;
356 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
357 }
358 break;
359 }
360 case IDC_EDIT_NUM_BUFFER:
361 {
362 if (HIWORD(wParam) == EN_KILLFOCUS)
363 {
364 DWORD numBuff;
365
366 numBuff = GetDlgItemInt(hwndDlg, IDC_EDIT_NUM_BUFFER, NULL, FALSE);
367 numBuff = min(max(numBuff, 1), 999);
368
369 ConInfo->NumberOfHistoryBuffers = numBuff;
370 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
371 }
372 break;
373 }
374 case IDL_CODEPAGE:
375 {
376 if (HIWORD(wParam) == CBN_SELENDOK)
377 {
378 INT iItem;
379 UINT CodePage;
380
381 iItem = (INT)SendMessageW((HWND)lParam, CB_GETCURSEL, 0, 0);
382 if (iItem != CB_ERR)
383 {
384 CodePage = (UINT)SendMessageW((HWND)lParam, CB_GETITEMDATA, iItem, 0);
385 if (CodePage != CB_ERR)
386 {
387 ConInfo->CodePage = CodePage;
388 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
389 }
390 }
391 }
392 break;
393 }
394 default:
395 break;
396 }
397 break;
398 }
399
400 default:
401 break;
402 }
403
404 return FALSE;
405 }