1 /*
2  *  Prefs_WIN32.i - Global preferences, WIN32 specific stuff
3  *
4  *  Frodo (C) 1994-1997,2002 Christian Bauer
5  *  WIN32 code by J. Richard Sladkey <jrs@world.std.com>
6  */
7 
8 #include <commctrl.h>
9 #include "resource.h"
10 
11 Prefs *Prefs::edit_prefs;
12 char *Prefs::edit_prefs_name;
13 HWND Prefs::hDlg;
14 
15 #define STANDARD_PAGE	0
16 #define WIN32_PAGE	1
17 
ShowEditor(bool,char * prefs_name)18 bool Prefs::ShowEditor(bool /* startup */, char *prefs_name)
19 {
20 	edit_prefs = this;
21 	edit_prefs_name = prefs_name;
22 
23 	PROPSHEETPAGE psp[2];
24 
25 	// Set up standard preferences property page.
26 	psp[0].dwSize = sizeof(PROPSHEETPAGE);
27 	psp[0].dwFlags = PSP_HASHELP;
28 	psp[0].hInstance = hInstance;
29 	psp[0].pszTemplate = MAKEINTRESOURCE(IDD_PREFERENCES_STANDARD);
30 	psp[0].pszIcon = NULL;
31 	psp[0].pfnDlgProc = StandardDialogProc;
32 	psp[0].pszTitle = NULL;
33 	psp[0].lParam = 0;
34 	psp[0].pfnCallback = NULL;
35 
36 	// Set up WIN32 preferences property page.
37 	psp[1].dwSize = sizeof(PROPSHEETPAGE);
38 	psp[1].dwFlags = PSP_HASHELP;
39 	psp[1].hInstance = hInstance;
40 	psp[1].pszTemplate = MAKEINTRESOURCE(IDD_PREFERENCES_WIN32);
41 	psp[1].pszIcon = NULL;
42 	psp[1].pfnDlgProc = WIN32DialogProc;
43 	psp[1].pszTitle = NULL;
44 	psp[1].lParam = 0;
45 	psp[1].pfnCallback = NULL;
46 
47 	// Setup property sheet.
48 	PROPSHEETHEADER psh;
49 	psh.dwSize = sizeof(PROPSHEETHEADER);
50 	psh.dwFlags = PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW;
51 	psh.hwndParent = hwnd;
52 	psh.hInstance = hInstance;
53 	psh.pszIcon = NULL;
54 	psh.pszCaption = "Preferences";
55 	psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
56 	psh.nStartPage = 0;
57 	psh.ppsp = psp;
58 	psh.pfnCallback = NULL;
59 
60 	int result = PropertySheet(&psh);
61 
62 	if (result == -1)
63 		return FALSE;
64 	return result;
65 }
66 
StandardDialogProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)67 BOOL CALLBACK Prefs::StandardDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
68 {
69 	return edit_prefs->DialogProc(STANDARD_PAGE, hDlg, message, wParam, lParam);
70 }
71 
WIN32DialogProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)72 BOOL CALLBACK Prefs::WIN32DialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
73 {
74 	return edit_prefs->DialogProc(WIN32_PAGE, hDlg, message, wParam, lParam);
75 }
76 
DialogProc(int page,HWND hDlg_arg,UINT message,WPARAM wParam,LPARAM lParam)77 BOOL Prefs::DialogProc(int page, HWND hDlg_arg, UINT message, WPARAM wParam, LPARAM lParam)
78 {
79 	hDlg = hDlg_arg;
80 
81 	switch (message) {
82 
83 	case WM_INITDIALOG:
84 		SetupControls(page);
85 		SetValues(page);
86 		return TRUE;
87 
88 	case WM_COMMAND:
89 		switch (LOWORD(wParam)) {
90 
91 		case IDC_BROWSE8:
92 			BrowseForDevice(IDC_DEVICE8);
93 			break;
94 
95 		case IDC_BROWSE9:
96 			BrowseForDevice(IDC_DEVICE9);
97 			break;
98 
99 		case IDC_BROWSE10:
100 			BrowseForDevice(IDC_DEVICE10);
101 			break;
102 
103 		case IDC_BROWSE11:
104 			BrowseForDevice(IDC_DEVICE11);
105 			break;
106 
107 		}
108 		return TRUE;
109 
110 	case WM_NOTIFY:
111 		{
112 			NMHDR *pnmhdr = (NMHDR *) lParam;
113 			switch (pnmhdr->code) {
114 
115 			case PSN_KILLACTIVE:
116 				SetWindowLong(hDlg, DWL_MSGRESULT, FALSE);
117 				break;
118 
119 			case PSN_APPLY:
120 				GetValues(page);
121 				break;
122 
123 			case PSN_HELP:
124 				PostMessage(hwnd, WM_COMMAND, ID_HELP_SETTINGS, 0);
125 				break;
126 			}
127 		}
128 		return TRUE;
129 	}
130 
131 	return FALSE;
132 }
133 
134 #define SetupSpin(id, upper, lower) SendMessage(GetDlgItem(hDlg, id), UDM_SETRANGE, 0, MAKELONG(upper, lower))
135 #define SetupSpinIncrement(id, increment) (udaccel.nSec = 0, udaccel.nInc = increment, SendMessage(GetDlgItem(hDlg, id), UDM_SETACCEL, 1, (LPARAM) &udaccel))
136 #define SetupComboClear(id) SendMessage(GetDlgItem(hDlg, id), CB_RESETCONTENT, 0, 0)
137 #define SetupComboAdd(id, string) SendMessage(GetDlgItem(hDlg, id), CB_ADDSTRING, 0, (LPARAM) string)
138 
SetupControls(int page)139 void Prefs::SetupControls(int page)
140 {
141 	UDACCEL udaccel;
142 	switch (page) {
143 
144 	case STANDARD_PAGE:
145 		SetupSpin(IDC_NORMAL_SPIN, 200, 1);
146 		SetupSpin(IDC_BADLINES_SPIN, 200, 1);
147 		SetupSpin(IDC_CIA_SPIN, 200, 1);
148 		SetupSpin(IDC_FLOPPY_SPIN, 200, 1);
149 		SetupSpin(IDC_DRAWEVERY_SPIN, 10, 1);
150 		SetupComboClear(IDC_REUSIZE);
151 		SetupComboAdd(IDC_REUSIZE, "None");
152 		SetupComboAdd(IDC_REUSIZE, "128k");
153 		SetupComboAdd(IDC_REUSIZE, "256k");
154 		SetupComboAdd(IDC_REUSIZE, "512k");
155 		break;
156 
157 	case WIN32_PAGE:
158 		SetupComboClear(IDC_VIEWPORT);
159 		SetupComboAdd(IDC_VIEWPORT, "Default");
160 		SetupComboAdd(IDC_VIEWPORT, "320x200");
161 		SetupComboAdd(IDC_VIEWPORT, "336x216");
162 		SetupComboAdd(IDC_VIEWPORT, "384x272");
163 		SetupComboClear(IDC_DISPLAYMODE);
164 		SetupComboAdd(IDC_DISPLAYMODE, "Default");
165 		{
166 			C64Display *TheDisplay = TheApp->TheC64->TheDisplay;
167 			int n = TheDisplay->GetNumDisplayModes();
168 			const C64Display::DisplayMode *modes =
169 				TheDisplay->GetDisplayModes();
170 			for (int i = 0; i < n; i++) {
171 				char mode[64];
172 				sprintf(mode, "%dx%dx%d%s",
173 					modes[i].x, modes[i].y, modes[i].depth,
174 					modes[i].modex ? " (ModeX)" : "");
175 				SetupComboAdd(IDC_DISPLAYMODE, mode);
176 			}
177 		}
178 		SetupSpin(IDC_SCALINGNUMERATOR_SPIN, 16, 1);
179 		SetupSpin(IDC_SCALINGDENOMINATOR_SPIN, 4, 1);
180 		SetupSpin(IDC_LATENCYMIN_SPIN, 1000, 20);
181 		SetupSpinIncrement(IDC_LATENCYMIN_SPIN, 20);
182 		SetupSpin(IDC_LATENCYMAX_SPIN, 1000, 20);
183 		SetupSpinIncrement(IDC_LATENCYMAX_SPIN, 20);
184 		SetupSpin(IDC_LATENCYAVG_SPIN, 1000, 20);
185 		SetupSpinIncrement(IDC_LATENCYAVG_SPIN, 20);
186 		break;
187 	}
188 }
189 
190 #define SetText(id, val) SetDlgItemText(hDlg, id, val)
191 #define SetInteger(id, val) SetDlgItemInt(hDlg, id, val, FALSE)
192 #define SetCheckBox(id, val) CheckDlgButton(hDlg, id, (val) ? BST_CHECKED : BST_UNCHECKED)
193 #define SetCombo(id, val) SendMessage(GetDlgItem(hDlg, id), CB_SELECTSTRING, 0, (LPARAM) val)
194 
SetValues(int page)195 void Prefs::SetValues(int page)
196 {
197 	const char *str;
198 	switch (page) {
199 
200 	case STANDARD_PAGE:
201 		SetText(IDC_DEVICE8, DrivePath[0]);
202 		SetText(IDC_DEVICE9, DrivePath[1]);
203 		SetText(IDC_DEVICE10, DrivePath[2]);
204 		SetText(IDC_DEVICE11, DrivePath[3]);
205 
206 		SetInteger(IDC_NORMAL, NormalCycles);
207 		SetInteger(IDC_BADLINES, BadLineCycles);
208 		SetInteger(IDC_CIA, CIACycles);
209 		SetInteger(IDC_FLOPPY, FloppyCycles);
210 		SetInteger(IDC_DRAWEVERY, SkipFrames);
211 		switch (REUSize) {
212 		case REU_NONE: str = "None"; break;
213 		case REU_128K: str = "128k"; break;
214 		case REU_256K: str = "256k"; break;
215 		case REU_512K: str = "512k"; break;
216 		}
217 		SetCombo(IDC_REUSIZE, str);
218 
219 		SetCheckBox(IDC_LIMITSPEED, LimitSpeed);
220 		SetCheckBox(IDC_SPRITES, SpritesOn);
221 		SetCheckBox(IDC_SPRITECOLLISIONS, SpriteCollisions);
222 		SetCheckBox(IDC_JOYSTICK1, Joystick1On);
223 		SetCheckBox(IDC_JOYSTICK2, Joystick2On);
224 		SetCheckBox(IDC_SWAPJOYSTICKS, JoystickSwap);
225 		SetCheckBox(IDC_FASTRESET, FastReset);
226 		SetCheckBox(IDC_CIAIRQHACK, CIAIRQHack);
227 		SetCheckBox(IDC_MAPSLASH, MapSlash);
228 		SetCheckBox(IDC_SIDEMULATION, SIDType == SIDTYPE_DIGITAL);
229 		SetCheckBox(IDC_SIDFILTERS, SIDFilters);
230 		SetCheckBox(IDC_1541EMULATION, Emul1541Proc);
231 		break;
232 
233 	case WIN32_PAGE:
234 		SetCheckBox(IDC_FULLSCREEN, DisplayType == DISPTYPE_SCREEN);
235 		SetCheckBox(IDC_SYSTEMMEMORY, SystemMemory);
236 		SetCheckBox(IDC_ALWAYSCOPY, AlwaysCopy);
237 		SetText(IDC_VIEWPORT, ViewPort);
238 		SetText(IDC_DISPLAYMODE, DisplayMode);
239 
240 		SetCheckBox(IDC_HIDECURSOR, HideCursor);
241 		SetCheckBox(IDC_SYSTEMKEYS, SystemKeys);
242 		SetInteger(IDC_SCALINGNUMERATOR, ScalingNumerator);
243 		SetInteger(IDC_SCALINGDENOMINATOR, ScalingDenominator);
244 
245 		SetCheckBox(IDC_DIRECTSOUND, DirectSound);
246 		SetCheckBox(IDC_EXCLUSIVESOUND, ExclusiveSound);
247 		SetInteger(IDC_LATENCYMIN, LatencyMin);
248 		SetInteger(IDC_LATENCYMAX, LatencyMax);
249 		SetInteger(IDC_LATENCYAVG, LatencyAvg);
250 
251 		SetCheckBox(IDC_AUTOPAUSE, AutoPause);
252 		SetCheckBox(IDC_PREFSATSTARTUP, PrefsAtStartup);
253 		SetCheckBox(IDC_SHOWLEDS, ShowLEDs);
254 		break;
255 	}
256 }
257 
258 #define GetCheckBox(id, val) (val = IsDlgButtonChecked(hDlg, id) == BST_CHECKED)
259 #define GetInteger(id, val) (val = GetDlgItemInt(hDlg, id, NULL, FALSE))
260 #define GetText(id, val) GetDlgItemText(hDlg, id, val, sizeof(val))
261 
GetValues(int page)262 void Prefs::GetValues(int page)
263 {
264 	BOOL temp;
265 	char str[256];
266 	switch (page) {
267 
268 	case STANDARD_PAGE:
269 		GetText(IDC_DEVICE8, DrivePath[0]);
270 		GetText(IDC_DEVICE9, DrivePath[1]);
271 		GetText(IDC_DEVICE10, DrivePath[2]);
272 		GetText(IDC_DEVICE11, DrivePath[3]);
273 
274 		GetInteger(IDC_NORMAL, NormalCycles);
275 		GetInteger(IDC_BADLINES, BadLineCycles);
276 		GetInteger(IDC_CIA, CIACycles);
277 		GetInteger(IDC_FLOPPY, FloppyCycles);
278 		GetInteger(IDC_DRAWEVERY, SkipFrames);
279 		GetText(IDC_REUSIZE, str);
280 		if (strcmp(str, "None") == 0)
281 			REUSize = REU_NONE;
282 		else if (strcmp(str, "128k") == 0)
283 			REUSize = REU_128K;
284 		else if (strcmp(str, "256k") == 0)
285 			REUSize = REU_256K;
286 		else if (strcmp(str, "512k") == 0)
287 			REUSize = REU_512K;
288 
289 		GetCheckBox(IDC_LIMITSPEED, LimitSpeed);
290 		GetCheckBox(IDC_SPRITES, SpritesOn);
291 		GetCheckBox(IDC_SPRITECOLLISIONS, SpriteCollisions);
292 		GetCheckBox(IDC_JOYSTICK1, Joystick1On);
293 		GetCheckBox(IDC_JOYSTICK2, Joystick2On);
294 		GetCheckBox(IDC_SWAPJOYSTICKS, JoystickSwap);
295 		GetCheckBox(IDC_FASTRESET, FastReset);
296 		GetCheckBox(IDC_CIAIRQHACK, CIAIRQHack);
297 		GetCheckBox(IDC_MAPSLASH, MapSlash);
298 		GetCheckBox(IDC_SIDEMULATION, temp);
299 		SIDType = temp ? SIDTYPE_DIGITAL : SIDTYPE_NONE;
300 		GetCheckBox(IDC_SIDFILTERS, SIDFilters);
301 		GetCheckBox(IDC_1541EMULATION, Emul1541Proc);
302 		break;
303 
304 	case WIN32_PAGE:
305 		GetCheckBox(IDC_FULLSCREEN, temp);
306 		DisplayType = temp ? DISPTYPE_SCREEN : DISPTYPE_WINDOW;
307 		GetCheckBox(IDC_SYSTEMMEMORY, SystemMemory);
308 		GetCheckBox(IDC_ALWAYSCOPY, AlwaysCopy);
309 		GetText(IDC_VIEWPORT, ViewPort);
310 		GetText(IDC_DISPLAYMODE, DisplayMode);
311 
312 		GetCheckBox(IDC_HIDECURSOR, HideCursor);
313 		GetCheckBox(IDC_SYSTEMKEYS, SystemKeys);
314 		GetInteger(IDC_SCALINGNUMERATOR, ScalingNumerator);
315 		GetInteger(IDC_SCALINGDENOMINATOR, ScalingDenominator);
316 
317 		GetCheckBox(IDC_DIRECTSOUND, DirectSound);
318 		GetCheckBox(IDC_EXCLUSIVESOUND, ExclusiveSound);
319 		GetInteger(IDC_LATENCYMIN, LatencyMin);
320 		GetInteger(IDC_LATENCYMAX, LatencyMax);
321 		GetInteger(IDC_LATENCYAVG, LatencyAvg);
322 
323 		GetCheckBox(IDC_AUTOPAUSE, AutoPause);
324 		GetCheckBox(IDC_PREFSATSTARTUP, PrefsAtStartup);
325 		GetCheckBox(IDC_SHOWLEDS, ShowLEDs);
326 		break;
327 	}
328 
329 	for (int i = 0; i < 4; i++) {
330 		DriveType[i] = DRVTYPE_DIR;
331 		int length = strlen(DrivePath[i]);
332 		if (length >= 4) {
333 			char *suffix = DrivePath[i] + length - 4;
334 			if (stricmp(suffix, ".t64") == 0)
335 				DriveType[i] = DRVTYPE_T64;
336 			else if (stricmp(suffix, ".d64") == 0)
337 				DriveType[i] = DRVTYPE_D64;
338 		}
339 	}
340 }
341 
BrowseForDevice(int id)342 void Prefs::BrowseForDevice(int id)
343 {
344 	char filename[256];
345 	GetDlgItemText(hDlg, id, filename, sizeof(filename));
346 	OPENFILENAME ofn;
347 	memset(&ofn, 0, sizeof(ofn));
348 	ofn.lStructSize = sizeof(ofn);
349 	ofn.hwndOwner = hDlg;
350 	ofn.hInstance = hInstance;
351 	ofn.lpstrFilter =
352 		"All Files (*.*)\0*.*\0"
353 		"All C64 Files (*.d64;*.t64)\0*.d64;*.t64\0"
354 		"D64 Files (*.d64)\0*.d64\0"
355 		"T64 Files (*.t64)\0*.t64\0"
356 		;
357 	ofn.lpstrCustomFilter = NULL;
358 	ofn.nMaxCustFilter = 0;
359 	ofn.nFilterIndex = 1;
360 	ofn.lpstrFile = filename;
361 	ofn.nMaxFile = sizeof(filename);
362 	ofn.lpstrFileTitle = NULL;
363 	ofn.nMaxFileTitle = 0;
364 	ofn.lpstrInitialDir = NULL;
365 	ofn.lpstrTitle = "Set Device";
366 	ofn.Flags = OFN_EXPLORER | OFN_HIDEREADONLY | OFN_NOTESTFILECREATE |
367 		OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | OFN_SHAREAWARE;
368 	ofn.nFileOffset = 0;
369 	ofn.nFileExtension = 0;
370 	ofn.lpstrDefExt = NULL;
371 	ofn.lpfnHook = NULL;
372 	ofn.lpTemplateName = NULL;
373 	BOOL result = GetOpenFileName(&ofn);
374 	if (result) {
375 		const char *ext = filename + ofn.nFileExtension;
376 		if (stricmp(ext, "d64") != 0 && stricmp(ext, "t64") != 0)
377 			filename[ofn.nFileOffset - 1] = '\0';
378 		char cwd[256];
379 		GetCurrentDirectory(sizeof(cwd), cwd);
380 		int cwd_len = strlen(cwd);
381 		if (cwd_len > 0 && cwd[cwd_len - 1] != '\\') {
382 			strcat(cwd, "\\");
383 			cwd_len++;
384 		}
385 		if (strnicmp(filename, cwd, cwd_len) == 0)
386 			SetDlgItemText(hDlg, id, filename + cwd_len);
387 		else
388 			SetDlgItemText(hDlg, id, filename);
389 	}
390 }
391