[CONSOLE][CONCFG][CONSRV] Provide support for specified additional TrueType fonts...
[reactos.git] / 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 IN UINT CurrentCodePage)
77 {
78 LIST_CTL ListCtl;
79 HKEY hKey;
80 DWORD dwIndex, dwSize, dwType;
81 UINT CodePage;
82 WCHAR szValueName[MAX_VALUE_NAME];
83
84 // #define REGSTR_PATH_CODEPAGE TEXT("System\\CurrentControlSet\\Control\\Nls\\CodePage")
85 /* Open the Nls\CodePage key */
86 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
87 L"System\\CurrentControlSet\\Control\\Nls\\CodePage",
88 0,
89 KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
90 &hKey) != ERROR_SUCCESS)
91 {
92 return;
93 }
94
95 ListCtl.hWndList = GetDlgItem(hDlg, IDL_CODEPAGE);
96 ListCtl.GetCount = List_GetCount;
97 ListCtl.GetData = List_GetData;
98
99 /* Enumerate all the available code pages on the system */
100 dwSize = ARRAYSIZE(szValueName);
101 dwIndex = 0;
102 while (RegEnumValueW(hKey, dwIndex, szValueName, &dwSize,
103 NULL, &dwType, NULL, NULL) == ERROR_SUCCESS) // != ERROR_NO_MORE_ITEMS
104 {
105 /* Ignore these parameters, prepare for next iteration */
106 dwSize = ARRAYSIZE(szValueName);
107 ++dwIndex;
108
109 /* Check the value type validity */
110 if (dwType != REG_SZ)
111 continue;
112
113 /*
114 * Add the code page into the list.
115 * If _wtol fails and returns 0, the code page is considered invalid
116 * (and indeed this value corresponds to the CP_ACP alias too).
117 */
118 CodePage = (UINT)_wtol(szValueName);
119 if (CodePage == 0) continue;
120 AddCodePage(&ListCtl, CodePage);
121 }
122
123 RegCloseKey(hKey);
124
125 /* Add the special UTF-7 (CP_UTF7 65000) and UTF-8 (CP_UTF8 65001) code pages */
126 AddCodePage(&ListCtl, CP_UTF7);
127 AddCodePage(&ListCtl, CP_UTF8);
128
129 /* Find and select the current code page in the sorted list */
130 if (BisectListSortedByValue(&ListCtl, CurrentCodePage, &CodePage, FALSE) == CB_ERR ||
131 CodePage == CB_ERR)
132 {
133 /* Not found, select the first element */
134 CodePage = 0;
135 }
136 SendMessageW(ListCtl.hWndList, CB_SETCURSEL, (WPARAM)CodePage, 0);
137 }
138
139 static VOID
140 UpdateDialogElements(
141 IN HWND hDlg,
142 IN PCONSOLE_STATE_INFO pConInfo)
143 {
144 /* Update the cursor size */
145 if (pConInfo->CursorSize <= 25)
146 {
147 /* Small cursor */
148 CheckRadioButton(hDlg, IDC_RADIO_SMALL_CURSOR, IDC_RADIO_LARGE_CURSOR, IDC_RADIO_SMALL_CURSOR);
149 // CheckDlgButton(hDlg, IDC_RADIO_SMALL_CURSOR , BST_CHECKED);
150 // CheckDlgButton(hDlg, IDC_RADIO_MEDIUM_CURSOR, BST_UNCHECKED);
151 // CheckDlgButton(hDlg, IDC_RADIO_LARGE_CURSOR , BST_UNCHECKED);
152 }
153 else if (pConInfo->CursorSize <= 50)
154 {
155 /* Medium cursor */
156 CheckRadioButton(hDlg, IDC_RADIO_SMALL_CURSOR, IDC_RADIO_LARGE_CURSOR, IDC_RADIO_MEDIUM_CURSOR);
157 // CheckDlgButton(hDlg, IDC_RADIO_SMALL_CURSOR , BST_UNCHECKED);
158 // CheckDlgButton(hDlg, IDC_RADIO_MEDIUM_CURSOR, BST_CHECKED);
159 // CheckDlgButton(hDlg, IDC_RADIO_LARGE_CURSOR , BST_UNCHECKED);
160 }
161 else /* if (pConInfo->CursorSize <= 100) */
162 {
163 /* Large cursor */
164 CheckRadioButton(hDlg, IDC_RADIO_SMALL_CURSOR, IDC_RADIO_LARGE_CURSOR, IDC_RADIO_LARGE_CURSOR);
165 // CheckDlgButton(hDlg, IDC_RADIO_SMALL_CURSOR , BST_UNCHECKED);
166 // CheckDlgButton(hDlg, IDC_RADIO_MEDIUM_CURSOR, BST_UNCHECKED);
167 // CheckDlgButton(hDlg, IDC_RADIO_LARGE_CURSOR , BST_CHECKED);
168 }
169
170 /* Update the number of history buffers */
171 SendDlgItemMessageW(hDlg, IDC_UPDOWN_NUM_BUFFER, UDM_SETRANGE, 0, MAKELONG(999, 1));
172 SetDlgItemInt(hDlg, IDC_EDIT_NUM_BUFFER, pConInfo->NumberOfHistoryBuffers, FALSE);
173
174 /* Update the history buffer size */
175 SendDlgItemMessageW(hDlg, IDC_UPDOWN_BUFFER_SIZE, UDM_SETRANGE, 0, MAKELONG(999, 1));
176 SetDlgItemInt(hDlg, IDC_EDIT_BUFFER_SIZE, pConInfo->HistoryBufferSize, FALSE);
177
178 /* Update discard duplicates */
179 CheckDlgButton(hDlg, IDC_CHECK_DISCARD_DUPLICATES,
180 pConInfo->HistoryNoDup ? BST_CHECKED : BST_UNCHECKED);
181
182 /* Update full/window screen state */
183 if (pConInfo->FullScreen)
184 {
185 CheckRadioButton(hDlg, IDC_RADIO_DISPLAY_WINDOW, IDC_RADIO_DISPLAY_FULL, IDC_RADIO_DISPLAY_FULL);
186 // CheckDlgButton(hDlg, IDC_RADIO_DISPLAY_WINDOW, BST_UNCHECKED);
187 // CheckDlgButton(hDlg, IDC_RADIO_DISPLAY_FULL , BST_CHECKED);
188 }
189 else
190 {
191 CheckRadioButton(hDlg, IDC_RADIO_DISPLAY_WINDOW, IDC_RADIO_DISPLAY_FULL, IDC_RADIO_DISPLAY_WINDOW);
192 // CheckDlgButton(hDlg, IDC_RADIO_DISPLAY_WINDOW, BST_CHECKED);
193 // CheckDlgButton(hDlg, IDC_RADIO_DISPLAY_FULL , BST_UNCHECKED);
194 }
195
196 /* Update "Quick-edit" state */
197 CheckDlgButton(hDlg, IDC_CHECK_QUICK_EDIT,
198 pConInfo->QuickEdit ? BST_CHECKED : BST_UNCHECKED);
199
200 /* Update "Insert mode" state */
201 CheckDlgButton(hDlg, IDC_CHECK_INSERT_MODE,
202 pConInfo->InsertMode ? BST_CHECKED : BST_UNCHECKED);
203 }
204
205 INT_PTR
206 CALLBACK
207 OptionsProc(HWND hDlg,
208 UINT uMsg,
209 WPARAM wParam,
210 LPARAM lParam)
211 {
212 switch (uMsg)
213 {
214 case WM_INITDIALOG:
215 {
216 BuildCodePageList(hDlg, ConInfo->CodePage);
217 UpdateDialogElements(hDlg, ConInfo);
218 return TRUE;
219 }
220
221 case WM_NOTIFY:
222 {
223 LPPSHNOTIFY lppsn = (LPPSHNOTIFY)lParam;
224
225 if (lppsn->hdr.code == UDN_DELTAPOS)
226 {
227 LPNMUPDOWN lpnmud = (LPNMUPDOWN)lParam;
228
229 if (lppsn->hdr.idFrom == IDC_UPDOWN_BUFFER_SIZE)
230 {
231 lpnmud->iPos = min(max(lpnmud->iPos + lpnmud->iDelta, 1), 999);
232 ConInfo->HistoryBufferSize = lpnmud->iPos;
233 PropSheet_Changed(GetParent(hDlg), hDlg);
234 }
235 else if (lppsn->hdr.idFrom == IDC_UPDOWN_NUM_BUFFER)
236 {
237 lpnmud->iPos = min(max(lpnmud->iPos + lpnmud->iDelta, 1), 999);
238 ConInfo->NumberOfHistoryBuffers = lpnmud->iPos;
239 PropSheet_Changed(GetParent(hDlg), hDlg);
240 }
241 }
242 else if (lppsn->hdr.code == PSN_APPLY)
243 {
244 ApplyConsoleInfo(hDlg);
245 return TRUE;
246 }
247 break;
248 }
249
250 case WM_COMMAND:
251 {
252 if (HIWORD(wParam) == BN_CLICKED)
253 {
254 switch (LOWORD(wParam))
255 {
256 case IDC_RADIO_SMALL_CURSOR:
257 {
258 ConInfo->CursorSize = 25;
259 PropSheet_Changed(GetParent(hDlg), hDlg);
260 break;
261 }
262 case IDC_RADIO_MEDIUM_CURSOR:
263 {
264 ConInfo->CursorSize = 50;
265 PropSheet_Changed(GetParent(hDlg), hDlg);
266 break;
267 }
268 case IDC_RADIO_LARGE_CURSOR:
269 {
270 ConInfo->CursorSize = 100;
271 PropSheet_Changed(GetParent(hDlg), hDlg);
272 break;
273 }
274 case IDC_RADIO_DISPLAY_WINDOW:
275 {
276 ConInfo->FullScreen = FALSE;
277 PropSheet_Changed(GetParent(hDlg), hDlg);
278 break;
279 }
280 case IDC_RADIO_DISPLAY_FULL:
281 {
282 ConInfo->FullScreen = TRUE;
283 PropSheet_Changed(GetParent(hDlg), hDlg);
284 break;
285 }
286 case IDC_CHECK_QUICK_EDIT:
287 {
288 ConInfo->QuickEdit = (IsDlgButtonChecked(hDlg, IDC_CHECK_QUICK_EDIT) == BST_CHECKED); // BST_UNCHECKED or BST_INDETERMINATE => FALSE
289 PropSheet_Changed(GetParent(hDlg), hDlg);
290 break;
291 }
292 case IDC_CHECK_INSERT_MODE:
293 {
294 ConInfo->InsertMode = (IsDlgButtonChecked(hDlg, IDC_CHECK_INSERT_MODE) == BST_CHECKED); // BST_UNCHECKED or BST_INDETERMINATE => FALSE
295 PropSheet_Changed(GetParent(hDlg), hDlg);
296 break;
297 }
298 case IDC_CHECK_DISCARD_DUPLICATES:
299 {
300 ConInfo->HistoryNoDup = (IsDlgButtonChecked(hDlg, IDC_CHECK_DISCARD_DUPLICATES) == BST_CHECKED); // BST_UNCHECKED or BST_INDETERMINATE => FALSE
301 PropSheet_Changed(GetParent(hDlg), hDlg);
302 break;
303 }
304 }
305 }
306 else
307 if (HIWORD(wParam) == EN_KILLFOCUS)
308 {
309 switch (LOWORD(wParam))
310 {
311 case IDC_EDIT_BUFFER_SIZE:
312 {
313 DWORD sizeBuff;
314
315 sizeBuff = GetDlgItemInt(hDlg, IDC_EDIT_BUFFER_SIZE, NULL, FALSE);
316 sizeBuff = min(max(sizeBuff, 1), 999);
317
318 ConInfo->HistoryBufferSize = sizeBuff;
319 PropSheet_Changed(GetParent(hDlg), hDlg);
320 break;
321 }
322 case IDC_EDIT_NUM_BUFFER:
323 {
324 DWORD numBuff;
325
326 numBuff = GetDlgItemInt(hDlg, IDC_EDIT_NUM_BUFFER, NULL, FALSE);
327 numBuff = min(max(numBuff, 1), 999);
328
329 ConInfo->NumberOfHistoryBuffers = numBuff;
330 PropSheet_Changed(GetParent(hDlg), hDlg);
331 break;
332 }
333 }
334 }
335 else
336 // (HIWORD(wParam) == CBN_KILLFOCUS)
337 if ((HIWORD(wParam) == CBN_SELCHANGE || HIWORD(wParam) == CBN_SELENDOK) &&
338 (LOWORD(wParam) == IDL_CODEPAGE))
339 {
340 HWND hWndList = GetDlgItem(hDlg, IDL_CODEPAGE);
341 INT iItem;
342 UINT CodePage;
343
344 iItem = (INT)SendMessageW(hWndList, CB_GETCURSEL, 0, 0);
345 if (iItem == CB_ERR)
346 break;
347
348 CodePage = (UINT)SendMessageW(hWndList, CB_GETITEMDATA, iItem, 0);
349 if (CodePage == CB_ERR)
350 break;
351
352 /* If the user validated a different code page... */
353 if ((HIWORD(wParam) == CBN_SELENDOK) && (CodePage != ConInfo->CodePage))
354 {
355 /* ... update the code page, notify the siblings and change the property sheet state */
356 ConInfo->CodePage = CodePage;
357 // PropSheet_QuerySiblings(GetParent(hDlg), IDL_CODEPAGE, 0);
358 ResetFontPreview(&FontPreview);
359 PropSheet_Changed(GetParent(hDlg), hDlg);
360 }
361 }
362
363 break;
364 }
365
366 default:
367 break;
368 }
369
370 return FALSE;
371 }