1 /*
2  *  Prefs_Be.i - Global preferences, Be specific stuff
3  *
4  *  Frodo (C) 1994-1997,2002 Christian Bauer
5  */
6 
7 #include <InterfaceKit.h>
8 #include <StorageKit.h>
9 #include <Path.h>
10 
11 
12 // Special colors
13 const rgb_color light_color = {255, 255, 255, 0};
14 const rgb_color fill_color = {216, 216, 216, 0};
15 const rgb_color dark_color = {184, 184, 184, 0};
16 
17 
18 // Window thread messages
19 const uint32 MSG_OK = 'okok';
20 const uint32 MSG_CANCEL = 'cncl';
21 const uint32 MSG_SPRITES_ON = 'spon';
22 const uint32 MSG_SPRITE_COLLISIONS = 'scol';
23 const uint32 MSG_JOYSTICK_1_ON = 'joy1';
24 const uint32 MSG_JOYSTICK_2_ON = 'joy2';
25 const uint32 MSG_JOYSTICK_SWAP = 'jswp';
26 const uint32 MSG_LIMIT_SPEED = 'lmit';
27 const uint32 MSG_FAST_RESET = 'frst';
28 const uint32 MSG_CIA_IRQ_HACK = 'cirq';
29 const uint32 MSG_SID_FILTERS = 'filt';
30 const uint32 MSG_DOUBLE_SCAN = 'dbls';
31 const uint32 MSG_MAP_SLASH = 'mpsl';
32 const uint32 MSG_EMUL_1541_PROC = '15pr';
33 const uint32 MSG_DRVTYPE_8 = 'drt8';
34 const uint32 MSG_DRVTYPE_9 = 'drt9';
35 const uint32 MSG_DRVTYPE_10 = 'drt:';
36 const uint32 MSG_DRVTYPE_11 = 'drt;';
37 const uint32 MSG_GETDRIVE_8 = 'gtd8';
38 const uint32 MSG_GETDRIVE_9 = 'gtd9';
39 const uint32 MSG_GETDRIVE_10 = 'gtd:';
40 const uint32 MSG_GETDRIVE_11 = 'gtd;';
41 const uint32 MSG_DRIVE_PANEL_RETURNED = 'gdr8';
42 const uint32 MSG_SID_TYPE = 'sidt';
43 const uint32 MSG_REU_SIZE = 'reus';
44 const uint32 MSG_DISPLAY_TYPE = 'dspt';
45 
46 const uint32 MSG_OPEN = 'open';
47 const uint32 MSG_SAVE = 'save';
48 const uint32 MSG_SAVE_AS = 'svas';
49 const uint32 MSG_REVERT = 'rvrt';
50 const uint32 MSG_OPEN_PANEL_RETURNED = 'oprt';
51 const uint32 MSG_SAVE_PANEL_RETURNED = 'svrt';
52 
53 
54 /*
55  *  Preferences window class
56  */
57 
58 class NumberControl;
59 class PathControl;
60 
61 class PrefsWindow : public BWindow {
62 public:
63 	PrefsWindow(Prefs *p, bool start, char *path);
64 	virtual void MessageReceived(BMessage *msg);
65 	virtual bool QuitRequested(void);
66 	virtual bool FilterKeyDown(uint32 *aChar, BView **target);
67 
68 private:
69 	BCheckBox *make_checkbox(BRect frame, char *label, uint32 what, BView *parent);
70 	NumberControl *make_number_entry(BRect frame, char *label_text, BView *parent);
71 	BPopUpMenu *make_drvtype_popup(BRect frame, uint32 what, BView *parent);
72 	PathControl *make_path_entry(BRect frame, char *label, BView *parent);
73 	BPopUpMenu *make_sidtype_popup(BRect frame, char *label_text, uint32 what, BView *parent);
74 	BPopUpMenu *make_reusize_popup(BRect frame, char *label_text, uint32 what, BView *parent);
75 	BPopUpMenu *make_disptype_popup(BRect frame, char *label_text, uint32 what, BView *parent);
76 	void set_values(void);
77 	void get_values(void);
78 	void ghost_controls(void);
79 
80 	Prefs *prefs;
81 
82 	BMessenger this_messenger;
83 	BFilePanel *open_panel;		// For opening prefs
84 	BFilePanel *save_panel;		// For saving prefs
85 	BFilePanel *file_panel;		// For D64/T64 drives
86 	BFilePanel *dir_panel;		// For directory drives
87 	int panel_drive_num;		// Drive number (0..3) of the file panel
88 
89 	BButton *g_ok;
90 	BButton *g_cancel;
91 	NumberControl *g_normal_cycles;
92 	NumberControl *g_bad_line_cycles;
93 	NumberControl *g_cia_cycles;
94 	NumberControl *g_floppy_cycles;
95 	NumberControl *g_skip_frames;
96 	BPopUpMenu *g_drive_type[4];
97 	PathControl *g_drive_path[4];
98 	BPopUpMenu *g_sid_type;
99 	BPopUpMenu *g_reu_size;
100 	BPopUpMenu *g_display_type;
101 	BCheckBox *g_sprites_on;
102 	BCheckBox *g_sprite_collisions;
103 	BCheckBox *g_joystick_1_on;
104 	BCheckBox *g_joystick_2_on;
105 	BCheckBox *g_joystick_swap;
106 	BCheckBox *g_limit_speed;
107 	BCheckBox *g_fast_reset;
108 	BCheckBox *g_cia_irq_hack;
109 	BCheckBox *g_sid_filters;
110 	BCheckBox *g_double_scan;
111 	BCheckBox *g_map_slash;
112 	BCheckBox *g_emul_1541_proc;
113 
114 	char *prefs_path;
115 	bool startup;
116 };
117 
118 
119 /*
120  *  Start preferences editor (asynchronously)
121  *  startup = false: Send MSG_PREFS_DONE to application on close
122  *  startup = true : Send MSG_STARTUP to application on close if not canceled,
123  *                   B_QUIT_REQUESTED otherwise
124  *  prefs_name points to the file name of the preferences (which may be changed)
125  */
126 
ShowEditor(bool startup,char * prefs_name)127 bool Prefs::ShowEditor(bool startup, char *prefs_name)
128 {
129 	PrefsWindow *win = new PrefsWindow(this, startup, prefs_name);
130 	win->Show();
131 	return true;
132 }
133 
134 
135 /*
136  *  Number-only BTextControl
137  */
138 
139 // Class definition
140 class NumberControl : public BTextControl {
141 public:
142 	NumberControl(BRect frame, float divider, const char *name, const char *label, const char *text, BMessage *message);
143 	void SetValue(long value);
144 	long Value(void);
145 };
146 
147 // Constructor: Allow only digits
NumberControl(BRect frame,float divider,const char * name,const char * label,const char * text,BMessage * message)148 NumberControl::NumberControl(BRect frame, float divider, const char *name, const char *label, const char *text, BMessage *message)
149  : BTextControl(frame, name, label, text, message, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE)
150 {
151 	SetDivider(divider);
152 	for (int c=0; c<256; c++)
153 		if (!isdigit(c) && c != B_BACKSPACE && c != B_LEFT_ARROW && c != B_RIGHT_ARROW)
154 			((BTextView *)ChildAt(0))->DisallowChar(c);
155 }
156 
157 // Set integer value
SetValue(long value)158 void NumberControl::SetValue(long value)
159 {
160 	char str[32];
161 	sprintf(str, "%ld", value);
162 	SetText(str);
163 }
164 
165 // Get integer value
Value(void)166 long NumberControl::Value(void)
167 {
168 	return atol(Text());
169 }
170 
171 
172 /*
173  *  Path-entry BTextControl
174  */
175 
176 // Class definition
177 class PathControl : public BTextControl {
178 public:
179 	PathControl(BRect frame, float divider, const char *name, const char *label, const char *text, BMessage *message);
180 	virtual void MessageReceived(BMessage *msg);
181 };
182 
183 // Constructor: Disable some keys
PathControl(BRect frame,float divider,const char * name,const char * label,const char * text,BMessage * message)184 PathControl::PathControl(BRect frame, float divider, const char *name, const char *label, const char *text, BMessage *message)
185  : BTextControl(frame, name, label, text, message, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE)
186 {
187 	SetDivider(divider);
188 	for (int c=0; c<' '; c++)
189 		if (c != B_BACKSPACE && c != B_LEFT_ARROW && c != B_RIGHT_ARROW)
190 			((BTextView *)ChildAt(0))->DisallowChar(c);
191 }
192 
193 // Message received: Look out for dropped refs
MessageReceived(BMessage * msg)194 void PathControl::MessageReceived(BMessage *msg)
195 {
196 	if (msg->what == B_SIMPLE_DATA) {
197 		entry_ref the_ref;
198 		BEntry the_entry;
199 
200 		// First look for refs
201 		if (msg->FindRef("refs", &the_ref) == B_NO_ERROR) {
202 			if (the_entry.SetTo(&the_ref) == B_NO_ERROR) {
203 				BPath the_path;
204 				the_entry.GetPath(&the_path);
205 				SetText(the_path.Path());
206 			}
207 		} else
208 			BTextControl::MessageReceived(msg);
209 
210 		MakeFocus();
211 	} else
212 		BTextControl::MessageReceived(msg);
213 }
214 
215 
216 /*
217  *  Open preferences window
218  */
219 
PrefsWindow(Prefs * p,bool start,char * path)220 PrefsWindow::PrefsWindow(Prefs *p, bool start, char *path) : BWindow(BRect(0, 0, 400, 349), "Frodo Preferences", B_TITLED_WINDOW, B_NOT_CLOSABLE | B_NOT_RESIZABLE | B_NOT_ZOOMABLE), this_messenger(this)
221 {
222 	int i;
223 	prefs = p;
224 	startup = start;
225 	prefs_path = path;
226 
227 	// Move window to right position
228 	Lock();
229 	MoveTo(80, 80);
230 
231 	// Set up menus
232 	BMenuBar *bar = new BMenuBar(Bounds(), "");
233 	BMenu *menu = new BMenu("Preferences");
234 	BMenuItem *item;
235 	menu->AddItem(item = new BMenuItem("About Frodo" B_UTF8_ELLIPSIS, new BMessage(B_ABOUT_REQUESTED)));
236 	item->SetTarget(be_app);
237 	menu->AddItem(new BSeparatorItem);
238 	menu->AddItem(new BMenuItem("Open" B_UTF8_ELLIPSIS, new BMessage(MSG_OPEN), 'O'));
239 	menu->AddItem(new BMenuItem("Save", new BMessage(MSG_SAVE), 'S'));
240 	menu->AddItem(new BMenuItem("Save As" B_UTF8_ELLIPSIS, new BMessage(MSG_SAVE_AS), 'A'));
241 	menu->AddItem(new BMenuItem("Revert", new BMessage(MSG_REVERT)));
242 	menu->AddItem(new BSeparatorItem);
243 	menu->AddItem(item = new BMenuItem("Quit Frodo", new BMessage(B_QUIT_REQUESTED), 'Q'));
244 	item->SetTarget(be_app);
245 	bar->AddItem(menu);
246 	AddChild(bar);
247 	SetKeyMenuBar(bar);
248 	int mbar_height = bar->Frame().bottom + 1;
249 
250 	// Resize window to fit menu bar
251 	ResizeBy(0, mbar_height);
252 
253 	// Light gray background
254 	BRect b = Bounds();
255 	BView *top = new BView(BRect(0, mbar_height, b.right, b.bottom), "top", B_FOLLOW_NONE, B_WILL_DRAW);
256 	AddChild(top);
257 	top->SetViewColor(fill_color);
258 
259 	// Checkboxes
260 	g_sprites_on = make_checkbox(BRect(10, 10, 160, 21), "Sprite display", MSG_SPRITES_ON, top);
261 	g_sprite_collisions = make_checkbox(BRect(10, 25, 160, 36), "Sprite collisions", MSG_SPRITE_COLLISIONS, top);
262 	g_joystick_1_on = make_checkbox(BRect(10, 40, 160, 51), "Joystick on port 1", MSG_JOYSTICK_1_ON, top);
263 	g_joystick_2_on = make_checkbox(BRect(10, 55, 160, 66), "Joystick on port 2", MSG_JOYSTICK_2_ON, top);
264 	g_joystick_swap = make_checkbox(BRect(10, 70, 160, 81), "Swap joysticks", MSG_JOYSTICK_SWAP, top);
265 	g_limit_speed = make_checkbox(BRect(10, 85, 160, 96), "Limit speed", MSG_LIMIT_SPEED, top);
266 	g_fast_reset = make_checkbox(BRect(10, 100, 160, 111), "Fast reset", MSG_FAST_RESET, top);
267 	g_cia_irq_hack = make_checkbox(BRect(10, 115, 160, 126), "Clear CIA ICR on write", MSG_CIA_IRQ_HACK, top);
268 	g_sid_filters = make_checkbox(BRect(10, 130, 160, 141), "SID filters", MSG_SID_FILTERS, top);
269 	g_double_scan = make_checkbox(BRect(10, 145, 160, 156), "Doublescan lines", MSG_DOUBLE_SCAN, top);
270 
271 	// Number entry fields
272 	g_normal_cycles = make_number_entry(BRect(160, 10, 390, 26), "Cycles per line (CPU)", top);
273 	g_bad_line_cycles = make_number_entry(BRect(160, 30, 390, 46), "Cycles per Bad Line (CPU)", top);
274 	g_cia_cycles = make_number_entry(BRect(160, 50, 390, 66), "Cycles per line (CIA)", top);
275 	g_floppy_cycles = make_number_entry(BRect(160, 70, 390, 86), "Cycles per line (1541)", top);
276 	g_skip_frames = make_number_entry(BRect(160, 90, 390, 106), "Draw every n-th frame", top);
277 
278 	// Popup fields
279 	g_display_type = make_disptype_popup(BRect(160, 110, 390, 126), "Display type", MSG_DISPLAY_TYPE, top);
280 	g_sid_type = make_sidtype_popup(BRect(160, 130, 390, 146), "SID emulation type", MSG_SID_TYPE, top);
281 	g_reu_size = make_reusize_popup(BRect(160, 150, 390, 166), "REU size", MSG_REU_SIZE, top);
282 
283 	// Prepare on/off pictures for file panel buttons
284 	BView *view = new BView(BRect(0, 0, 19, 15), "", B_FOLLOW_NONE, 0);
285 	AddChild(view);
286 	view->SetViewColor(fill_color);
287 
288 	view->BeginPicture(new BPicture);
289 	view->SetHighColor(fill_color);
290 	view->FillRect(BRect(0, 0, 19, 15));
291 	view->SetHighColor(light_color);
292 	view->StrokeRect(BRect(0, 0, 18, 0));
293 	view->StrokeRect(BRect(0, 0, 0, 14));
294 	view->SetHighColor(dark_color);
295 	view->StrokeRect(BRect(0, 15, 19, 15));
296 	view->StrokeRect(BRect(19, 0, 19, 15));
297 	view->SetFont(be_plain_font);
298 	view->SetHighColor(0, 0, 0);
299 	view->SetLowColor(fill_color);
300 	view->MovePenTo(7, 11);
301 	view->DrawString("B");
302 	BPicture *on = view->EndPicture();
303 
304 	view->BeginPicture(new BPicture);
305 	view->SetHighColor(dark_color);
306 	view->FillRect(BRect(0, 0, 19, 15));
307 	view->SetHighColor(128, 128, 128);
308 	view->StrokeRect(BRect(0, 0, 18, 0));
309 	view->StrokeRect(BRect(0, 0, 0, 14));
310 	view->SetHighColor(light_color);
311 	view->StrokeRect(BRect(0, 15, 19, 15));
312 	view->StrokeRect(BRect(19, 0, 19, 15));
313 	view->SetFont(be_plain_font);
314 	view->SetHighColor(0, 0, 0);
315 	view->SetLowColor(dark_color);
316 	view->MovePenTo(7, 11);
317 	view->DrawString("B");
318 	BPicture *off = view->EndPicture();
319 
320 	RemoveChild(view);
321 	delete view;
322 
323 	// Drive settings
324 	BBox *drvbox = new BBox(BRect(10, 173, 390, 304));
325 	top->AddChild(drvbox);
326 	drvbox->SetViewColor(fill_color);
327 	drvbox->SetLowColor(fill_color);
328 	drvbox->SetLabel("Drives");
329 
330 	for (i=0; i<4; i++) {
331 		char str[4];
332 		sprintf(str, "%d", i+8);
333 		g_drive_path[i] = make_path_entry(BRect(10, 14+i*20, 299, 30+i*20), str, drvbox);
334 		drvbox->AddChild(new BPictureButton(BRect(304, 16+i*20, 323, 31+i*20), "", new BPicture(*on), new BPicture(*off), new BMessage(MSG_GETDRIVE_8 + i)));
335 		g_drive_type[i] = make_drvtype_popup(BRect(329, 14+i*20, 373, 30+i*20), MSG_DRVTYPE_8 + i, drvbox);
336 	}
337 
338 	g_map_slash = make_checkbox(BRect(10, 94, 300, 110), "Map '/'<->'\\' in filenames", MSG_MAP_SLASH, drvbox);
339 	g_emul_1541_proc = make_checkbox(BRect(10, 109, 300, 125), "Enable 1541 processor emulation", MSG_EMUL_1541_PROC, drvbox);
340 
341 	// "OK" button
342 	top->AddChild(g_ok = new BButton(BRect(20, 315, 90, 340), "", startup ? "Start" : "OK", new BMessage(MSG_OK)));
343 	SetDefaultButton(g_ok);
344 
345 	// "Cancel" button
346 	top->AddChild(g_cancel = new BButton(BRect(b.right-90, 315, b.right-20, 340), "", startup ? "Quit" : "Cancel", new BMessage(MSG_CANCEL)));
347 
348 	// Set the values of all controls to reflect the preferences
349 	set_values();
350 	g_normal_cycles->MakeFocus();
351 
352 	// Create file panels
353 	open_panel = new BFilePanel(B_OPEN_PANEL, &this_messenger, NULL, 0, false, new BMessage(MSG_OPEN_PANEL_RETURNED));
354 	open_panel->Window()->SetTitle("Frodo: Open preferences");
355 	save_panel = new BFilePanel(B_SAVE_PANEL, &this_messenger, NULL, 0, false, new BMessage(MSG_SAVE_PANEL_RETURNED));
356 	save_panel->Window()->SetTitle("Frodo: Save preferences");
357 	file_panel = new BFilePanel(B_OPEN_PANEL, &this_messenger, NULL, 0, false, new BMessage(MSG_DRIVE_PANEL_RETURNED));
358 	file_panel->SetPanelDirectory(&AppDirectory);
359 	dir_panel = new BFilePanel(B_OPEN_PANEL, &this_messenger, NULL, B_DIRECTORY_NODE, false, new BMessage(MSG_DRIVE_PANEL_RETURNED));
360 	dir_panel->SetPanelDirectory(&AppDirectory);
361 	dir_panel->Window()->SetTitle("Frodo: Select directory");
362 	dir_panel->SetButtonLabel(B_DEFAULT_BUTTON, "Select");
363 
364 	Unlock();
365 }
366 
367 
368 /*
369  *  Create checkbox
370  */
371 
make_checkbox(BRect frame,char * label,uint32 what,BView * parent)372 BCheckBox *PrefsWindow::make_checkbox(BRect frame, char *label, uint32 what, BView *parent)
373 {
374 	BCheckBox *checkbox = new BCheckBox(frame, "", label, new BMessage(what));
375 	parent->AddChild(checkbox);
376 	return checkbox;
377 }
378 
379 
380 /*
381  *  Create number entry field
382  */
383 
make_number_entry(BRect frame,char * label_text,BView * parent)384 NumberControl *PrefsWindow::make_number_entry(BRect frame, char *label_text, BView *parent)
385 {
386 	NumberControl *num = new NumberControl(frame, frame.right-frame.left-55, "", label_text, NULL, NULL);
387 	parent->AddChild(num);
388 
389 	num->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_RIGHT);
390 	num->SetFont(be_plain_font);
391 	num->ChildAt(0)->SetFont(be_plain_font);
392 
393 	return num;
394 }
395 
396 
397 /*
398  *  Create drive type popup menu
399  */
400 
make_drvtype_popup(BRect frame,uint32 what,BView * parent)401 BPopUpMenu *PrefsWindow::make_drvtype_popup(BRect frame, uint32 what, BView *parent)
402 {
403 	BPopUpMenu *popup = new BPopUpMenu("drive_type popup", true, true);
404 	popup->AddItem(new BMenuItem("Dir", new BMessage(what)));
405 	popup->AddItem(new BMenuItem("D64", new BMessage(what)));
406 	popup->AddItem(new BMenuItem("T64", new BMessage(what)));
407 	popup->SetTargetForItems(this);
408 	BMenuField *menu_field = new BMenuField(frame, "drive_type", NULL, popup);
409 	menu_field->SetDivider(0);
410 	parent->AddChild(menu_field);
411 	return popup;
412 }
413 
414 
415 /*
416  *  Create path entry field
417  */
418 
make_path_entry(BRect frame,char * label,BView * parent)419 PathControl *PrefsWindow::make_path_entry(BRect frame, char *label, BView *parent)
420 {
421 	PathControl *path = new PathControl(frame, 16, "", label, NULL, NULL);
422 	parent->AddChild(path);
423 
424 	path->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
425 	path->SetFont(be_plain_font);
426 	path->ChildAt(0)->SetFont(be_plain_font);
427 	((BTextView *)(path->ChildAt(0)))->SetMaxBytes(255);
428 
429 	return path;
430 }
431 
432 
433 /*
434  *  Create display type popup
435  */
436 
make_disptype_popup(BRect frame,char * label_text,uint32 what,BView * parent)437 BPopUpMenu *PrefsWindow::make_disptype_popup(BRect frame, char *label_text, uint32 what, BView *parent)
438 {
439 	BPopUpMenu *popup = new BPopUpMenu("display_type popup", true, true);
440 	popup->AddItem(new BMenuItem("Window", new BMessage(what)));
441 	popup->AddItem(new BMenuItem("Screen", new BMessage(what)));
442 	popup->SetTargetForItems(this);
443 	BMenuField *menu_field = new BMenuField(frame, "display_type", label_text, popup);
444 	menu_field->SetDivider(frame.Width()-55);
445 	menu_field->SetAlignment(B_ALIGN_RIGHT);
446 	parent->AddChild(menu_field);
447 	return popup;
448 }
449 
450 
451 /*
452  *  Create SID type popup
453  */
454 
make_sidtype_popup(BRect frame,char * label_text,uint32 what,BView * parent)455 BPopUpMenu *PrefsWindow::make_sidtype_popup(BRect frame, char *label_text, uint32 what, BView *parent)
456 {
457 	BPopUpMenu *popup = new BPopUpMenu("sid_type popup", true, true);
458 	popup->AddItem(new BMenuItem("None", new BMessage(what)));
459 	popup->AddItem(new BMenuItem("Digital", new BMessage(what)));
460 	popup->SetTargetForItems(this);
461 	BMenuField *menu_field = new BMenuField(frame, "sid_type", label_text, popup);
462 	menu_field->SetDivider(frame.Width()-55);
463 	menu_field->SetAlignment(B_ALIGN_RIGHT);
464 	parent->AddChild(menu_field);
465 	return popup;
466 }
467 
468 
469 /*
470  *  Create REU size popup
471  */
472 
make_reusize_popup(BRect frame,char * label_text,uint32 what,BView * parent)473 BPopUpMenu *PrefsWindow::make_reusize_popup(BRect frame, char *label_text, uint32 what, BView *parent)
474 {
475 	BPopUpMenu *popup = new BPopUpMenu("reu_size popup", true, true);
476 	popup->AddItem(new BMenuItem("None", new BMessage(what)));
477 	popup->AddItem(new BMenuItem("128K", new BMessage(what)));
478 	popup->AddItem(new BMenuItem("256K", new BMessage(what)));
479 	popup->AddItem(new BMenuItem("512K", new BMessage(what)));
480 	popup->SetTargetForItems(this);
481 	BMenuField *menu_field = new BMenuField(frame, "reu_size", label_text, popup);
482 	menu_field->SetDivider(frame.Width()-55);
483 	menu_field->SetAlignment(B_ALIGN_RIGHT);
484 	parent->AddChild(menu_field);
485 	return popup;
486 }
487 
488 
489 /*
490  *  Set the values of the controls
491  */
492 
set_values(void)493 void PrefsWindow::set_values(void)
494 {
495 	prefs->Check();
496 
497 	g_normal_cycles->SetValue(prefs->NormalCycles);
498 	g_bad_line_cycles->SetValue(prefs->BadLineCycles);
499 	g_cia_cycles->SetValue(prefs->CIACycles);
500 	g_floppy_cycles->SetValue(prefs->FloppyCycles);
501 	g_skip_frames->SetValue(prefs->SkipFrames);
502 
503 	for (int i=0; i<4; i++) {
504 		g_drive_type[i]->ItemAt(prefs->DriveType[i])->SetMarked(true);
505 		g_drive_path[i]->SetText(prefs->DrivePath[i]);
506 	}
507 
508 	g_sid_type->ItemAt(prefs->SIDType)->SetMarked(true);
509 	g_reu_size->ItemAt(prefs->REUSize)->SetMarked(true);
510 	g_display_type->ItemAt(prefs->DisplayType)->SetMarked(true);
511 
512 	g_sprites_on->SetValue(prefs->SpritesOn ? B_CONTROL_ON : B_CONTROL_OFF);
513 	g_sprite_collisions->SetValue(prefs->SpriteCollisions ? B_CONTROL_ON : B_CONTROL_OFF);
514 	g_joystick_1_on->SetValue(prefs->Joystick1On ? B_CONTROL_ON : B_CONTROL_OFF);
515 	g_joystick_2_on->SetValue(prefs->Joystick2On ? B_CONTROL_ON : B_CONTROL_OFF);
516 	g_joystick_swap->SetValue(prefs->JoystickSwap ? B_CONTROL_ON : B_CONTROL_OFF);
517 	g_limit_speed->SetValue(prefs->LimitSpeed ? B_CONTROL_ON : B_CONTROL_OFF);
518 	g_fast_reset->SetValue(prefs->FastReset ? B_CONTROL_ON : B_CONTROL_OFF);
519 	g_cia_irq_hack->SetValue(prefs->CIAIRQHack ? B_CONTROL_ON : B_CONTROL_OFF);
520 	g_sid_filters->SetValue(prefs->SIDFilters ? B_CONTROL_ON : B_CONTROL_OFF);
521 	g_double_scan->SetValue(prefs->DoubleScan ? B_CONTROL_ON : B_CONTROL_OFF);
522 
523 	g_map_slash->SetValue(prefs->MapSlash ? B_CONTROL_ON : B_CONTROL_OFF);
524 	g_emul_1541_proc->SetValue(prefs->Emul1541Proc ? B_CONTROL_ON : B_CONTROL_OFF);
525 
526 	ghost_controls();
527 }
528 
529 
530 /*
531  *  Get the values of the controls
532  */
533 
get_values(void)534 void PrefsWindow::get_values(void)
535 {
536 	prefs->NormalCycles = g_normal_cycles->Value();
537 	prefs->BadLineCycles = g_bad_line_cycles->Value();
538 	prefs->CIACycles = g_cia_cycles->Value();
539 	prefs->FloppyCycles = g_floppy_cycles->Value();
540 	prefs->SkipFrames = g_skip_frames->Value();
541 
542 	for (int i=0; i<4; i++)
543 		strcpy(prefs->DrivePath[i], g_drive_path[i]->Text());
544 
545 	prefs->Check();
546 }
547 
548 
549 /*
550  *  Enable/disable certain controls
551  */
552 
ghost_controls(void)553 void PrefsWindow::ghost_controls(void)
554 {
555 	g_normal_cycles->SetEnabled(!IsFrodoSC);
556 	g_bad_line_cycles->SetEnabled(!IsFrodoSC);
557 	g_cia_cycles->SetEnabled(!IsFrodoSC);
558 	g_floppy_cycles->SetEnabled(!IsFrodoSC);
559 	g_cia_irq_hack->SetEnabled(!IsFrodoSC);
560 	g_double_scan->SetEnabled(prefs->DisplayType == DISPTYPE_SCREEN);
561 }
562 
563 
564 /*
565  *  Message from controls/menus received
566  */
567 
MessageReceived(BMessage * msg)568 void PrefsWindow::MessageReceived(BMessage *msg)
569 {
570 	switch (msg->what) {
571 		case MSG_OK:
572 			get_values();
573 			if (startup)
574 				be_app->PostMessage(MSG_STARTUP);
575 			else {
576 				BMessage msg(MSG_PREFS_DONE);
577 				msg.AddBool("canceled", false);
578 				msg.AddPointer("prefs", prefs);
579 				be_app->PostMessage(&msg);
580 			}
581 			PostMessage(B_QUIT_REQUESTED);
582 			break;
583 
584 		case MSG_CANCEL:
585 			if (startup)
586 				be_app->PostMessage(B_QUIT_REQUESTED);
587 			else {
588 				BMessage msg(MSG_PREFS_DONE);
589 				msg.AddBool("canceled", true);
590 				msg.AddPointer("prefs", prefs);
591 				be_app->PostMessage(&msg);
592 			}
593 			PostMessage(B_QUIT_REQUESTED);
594 			break;
595 
596 		case MSG_SPRITES_ON:
597 			prefs->SpritesOn = !prefs->SpritesOn;
598 			break;
599 
600 		case MSG_SPRITE_COLLISIONS:
601 			prefs->SpriteCollisions = !prefs->SpriteCollisions;
602 			break;
603 
604 		case MSG_JOYSTICK_1_ON:
605 			prefs->Joystick1On = !prefs->Joystick1On;
606 			break;
607 
608 		case MSG_JOYSTICK_2_ON:
609 			prefs->Joystick2On = !prefs->Joystick2On;
610 			break;
611 
612 		case MSG_JOYSTICK_SWAP:
613 			prefs->JoystickSwap = !prefs->JoystickSwap;
614 			break;
615 
616 		case MSG_LIMIT_SPEED:
617 			prefs->LimitSpeed = !prefs->LimitSpeed;
618 			break;
619 
620 		case MSG_FAST_RESET:
621 			prefs->FastReset = !prefs->FastReset;
622 			break;
623 
624 		case MSG_CIA_IRQ_HACK:
625 			prefs->CIAIRQHack = !prefs->CIAIRQHack;
626 			break;
627 
628 		case MSG_SID_FILTERS:
629 			prefs->SIDFilters = !prefs->SIDFilters;
630 			break;
631 
632 		case MSG_DOUBLE_SCAN:
633 			prefs->DoubleScan = !prefs->DoubleScan;
634 			break;
635 
636 		case MSG_SID_TYPE:
637 			prefs->SIDType = msg->FindInt32("index");
638 			break;
639 
640 		case MSG_REU_SIZE:
641 			prefs->REUSize = msg->FindInt32("index");
642 			break;
643 
644 		case MSG_DISPLAY_TYPE:
645 			prefs->DisplayType = msg->FindInt32("index");
646 			g_double_scan->SetEnabled(prefs->DisplayType == DISPTYPE_SCREEN);
647 			break;
648 
649 		case MSG_MAP_SLASH:
650 			prefs->MapSlash = !prefs->MapSlash;
651 			break;
652 
653 		case MSG_EMUL_1541_PROC:
654 			prefs->Emul1541Proc = !prefs->Emul1541Proc;
655 			break;
656 
657 		case MSG_DRVTYPE_8:
658 		case MSG_DRVTYPE_9:
659 		case MSG_DRVTYPE_10:
660 		case MSG_DRVTYPE_11:
661 			prefs->DriveType[msg->what & 3] = msg->FindInt32("index");
662 			break;
663 
664 		case MSG_GETDRIVE_8:
665 		case MSG_GETDRIVE_9:
666 		case MSG_GETDRIVE_10:
667 		case MSG_GETDRIVE_11:
668 			panel_drive_num = msg->what & 3;
669 			file_panel->Hide();
670 			dir_panel->Hide();
671 			if (prefs->DriveType[panel_drive_num] == DRVTYPE_D64) {
672 				file_panel->Window()->SetTitle("Frodo: Select disk image file");
673 				file_panel->Show();
674 			} else if (prefs->DriveType[panel_drive_num] == DRVTYPE_T64) {
675 				file_panel->Window()->SetTitle("Frodo: Select archive file");
676 				file_panel->Show();
677 			} else
678 				dir_panel->Show();
679 			break;
680 
681 		case MSG_DRIVE_PANEL_RETURNED:	{	// Drive path file panel returned
682 			entry_ref the_ref;
683 			BEntry the_entry;
684 			if (msg->FindRef("refs", &the_ref) == B_NO_ERROR)
685 				if (the_entry.SetTo(&the_ref) == B_NO_ERROR) {
686 					BPath the_path;
687 					the_entry.GetPath(&the_path);
688 					strncpy(prefs->DrivePath[panel_drive_num], the_path.Path(), 255);
689 					prefs->DrivePath[panel_drive_num][255] = 0;
690 					set_values();
691 				}
692 			break;
693 		}
694 
695 		case MSG_OPEN:
696 			open_panel->Show();
697 			break;
698 
699 		case MSG_OPEN_PANEL_RETURNED: {	// Open file panel returned
700 			get_values();	// Useful if Load() is unsuccessful
701 
702 			entry_ref the_ref;
703 			BEntry the_entry;
704 			if (msg->FindRef("refs", &the_ref) == B_NO_ERROR)
705 				if (the_entry.SetTo(&the_ref) == B_NO_ERROR)
706 					if (the_entry.IsFile()) {
707 						BPath the_path;
708 						the_entry.GetPath(&the_path);
709 						strncpy(prefs_path, the_path.Path(), 1023);
710 						prefs_path[1023] = 0;
711 						prefs->Load(prefs_path);
712 						set_values();
713 					}
714 		}
715 
716 		case MSG_SAVE:
717 			get_values();
718 			prefs->Save(prefs_path);
719 			break;
720 
721 		case MSG_SAVE_AS:
722 			save_panel->Show();
723 			break;
724 
725 		case MSG_SAVE_PANEL_RETURNED: {	// Save file panel returned
726 			entry_ref the_ref;
727 			BEntry the_entry;
728 			if (msg->FindRef("directory", &the_ref) == B_NO_ERROR)
729 				if (the_entry.SetTo(&the_ref) == B_NO_ERROR) {
730 					BPath the_path;
731 					the_entry.GetPath(&the_path);
732 					strncpy(prefs_path, the_path.Path(), 1023);
733 					strncat(prefs_path, "/", 1023);
734 					strncat(prefs_path, msg->FindString("name"), 1023);
735 					prefs_path[1023] = 0;
736 					get_values();
737 					if (!prefs->Save(prefs_path))
738 						ShowRequester("Couldn't save preferences.", "Too bad");
739 				}
740 			break;
741 		}
742 
743 		case MSG_REVERT:
744 			get_values();	// Useful if Load() is unsuccessful
745 			prefs->Load(prefs_path);
746 			set_values();
747 			break;
748 
749 		default:
750 			BWindow::MessageReceived(msg);
751 	}
752 }
753 
754 
755 /*
756  *  Intercept ESC key (works as clicking the Cancel button)
757  */
758 
FilterKeyDown(uint32 * aChar,BView ** target)759 bool PrefsWindow::FilterKeyDown(uint32 *aChar, BView **target)
760 {
761 	if (*aChar == B_ESCAPE) {
762 		// Flash Cancel button
763 		g_cancel->SetValue(B_CONTROL_ON);
764 		snooze(100000.0);
765 		PostMessage(MSG_CANCEL);
766 	}
767 	return true;
768 }
769 
770 
771 /*
772  *  Quit requested
773  */
774 
QuitRequested(void)775 bool PrefsWindow::QuitRequested(void)
776 {
777 	delete open_panel;
778 	delete save_panel;
779 	delete file_panel;
780 	delete dir_panel;
781 	return true;
782 }
783