|
|
1.1 root 1: #!/usr/bin/env python
2: #
3: # Classes for the Hatari UI dialogs
4: #
5: # Copyright (C) 2008 by Eero Tamminen <[email protected]>
6: #
7: # This program is free software; you can redistribute it and/or modify
8: # it under the terms of the GNU General Public License as published by
9: # the Free Software Foundation; either version 2 of the License, or
10: # (at your option) any later version.
11: #
12: # This program is distributed in the hope that it will be useful,
13: # but WITHOUT ANY WARRANTY; without even the implied warranty of
14: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15: # GNU General Public License for more details.
16:
17: import os
18: # use correct version of pygtk/gtk
19: import pygtk
20: pygtk.require('2.0')
21: import gtk
22: import pango
23:
24: from uihelpers import UInfo, HatariTextInsert, create_table_dialog, \
25: table_add_entry_row, table_add_widget_row, table_add_separator, \
26: create_button, FselEntry
27:
28:
29: # -----------------
30: # Dialog base class
31:
32: class HatariUIDialog:
33: def __init__(self, parent):
34: "<any>Dialog(parent) -> object"
35: self.parent = parent
36: self.dialog = None
37:
38: def run(self):
39: """run() -> response. Shows dialog and returns response,
40: subclasses overriding run() require also an argument."""
41: response = self.dialog.run()
42: self.dialog.hide()
43: return response
44:
45:
46: # ---------------------------
47: # Note/Todo/Error/Ask dialogs
48:
49: class NoteDialog(HatariUIDialog):
50: icontype = gtk.MESSAGE_INFO
51: textpattern = "\n%s"
52: def run(self, text):
53: "run(text), show message dialog with given text"
54: dialog = gtk.MessageDialog(self.parent,
55: gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
56: self.icontype, gtk.BUTTONS_CLOSE, self.textpattern % text)
57: dialog.run()
58: dialog.destroy()
59:
60: class TodoDialog(NoteDialog):
61: textpattern = "\nTODO: %s"
62:
63: class ErrorDialog(NoteDialog):
64: icontype = gtk.MESSAGE_ERROR
65: textpattern = "\nERROR: %s"
66:
67:
68: class AskDialog(HatariUIDialog):
69: def run(self, text):
70: "run(text) -> bool, show question dialog and return True if user OKed it"
71: dialog = gtk.MessageDialog(self.parent,
72: gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
73: gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, text)
74: response = dialog.run()
75: dialog.destroy()
76: return (response == gtk.RESPONSE_YES)
77:
78:
79: # ---------------------------
80: # About dialog
81:
82: class AboutDialog(HatariUIDialog):
83: def __init__(self, parent):
84: dialog = gtk.AboutDialog()
85: dialog.set_transient_for(parent)
86: dialog.set_name(UInfo.name)
87: dialog.set_version(UInfo.version)
88: dialog.set_website("http://hatari.berlios.de/")
89: dialog.set_website_label("Hatari emulator www-site")
90: dialog.set_authors(["Eero Tamminen"])
91: dialog.set_artists(["The logo is from Hatari"])
92: dialog.set_logo(gtk.gdk.pixbuf_new_from_file(UInfo.logo))
93: dialog.set_translator_credits("translator-credits")
1.1.1.2 ! root 94: dialog.set_copyright("UI copyright (C) 2008-2009 by Eero Tamminen")
1.1 root 95: dialog.set_license("""
1.1.1.2 ! root 96: This software is licenced under GPL v2 or later.
1.1 root 97:
98: You can see the whole license at:
99: http://www.gnu.org/licenses/info/GPLv2.html""")
100: self.dialog = dialog
101:
102:
103: # ---------------------------
104: # Input dialog
105:
106: class InputDialog(HatariUIDialog):
107: def __init__(self, parent):
108: dialog = gtk.Dialog("Key/mouse input", parent,
109: gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
110: ("Close", gtk.RESPONSE_CLOSE))
111:
112: tips = gtk.Tooltips()
113: entry = gtk.Entry()
114: entry.connect("activate", self._entry_cb)
115: insert = create_button("Insert", self._entry_cb)
116: tips.set_tip(insert, "Insert text to Hatari window")
117:
118: hbox1 = gtk.HBox()
119: hbox1.add(gtk.Label("Text:"))
120: hbox1.add(entry)
121: hbox1.add(insert)
122: dialog.vbox.add(hbox1)
123:
124: rclick = gtk.Button("Rightclick")
125: tips.set_tip(rclick, "Simulate Atari left button double-click")
126: rclick.connect("pressed", self._rightpress_cb)
127: rclick.connect("released", self._rightrelease_cb)
128: dclick = create_button("Doubleclick", self._doubleclick_cb)
129: tips.set_tip(dclick, "Simulate Atari rigth button click")
130:
131: hbox2 = gtk.HBox()
132: hbox2.add(rclick)
133: hbox2.add(dclick)
134: dialog.vbox.add(hbox2)
135:
136: dialog.show_all()
137: self.dialog = dialog
138: self.entry = entry
139:
140: def _entry_cb(self, widget):
141: text = self.entry.get_text()
142: if text:
143: HatariTextInsert(self.hatari, text)
144: self.entry.set_text("")
145:
146: def _doubleclick_cb(self, widget):
147: self.hatari.insert_event("doubleclick")
148:
149: def _rightpress_cb(self, widget):
150: self.hatari.insert_event("rightpress")
151:
152: def _rightrelease_cb(self, widget):
153: self.hatari.insert_event("rightrelease")
154:
155: def run(self, hatari):
156: "run(hatari), do text/mouse click input"
157: self.hatari = hatari
158: self.dialog.run()
159: self.dialog.hide()
160:
161:
162: # ---------------------------
163: # Quit and Save dialog
164:
165: class QuitSaveDialog(HatariUIDialog):
166: def __init__(self, parent):
167: dialog = gtk.Dialog("Quit and Save?", parent,
168: gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
169: ("Save changes", gtk.RESPONSE_YES,
170: "Discard changes", gtk.RESPONSE_NO,
171: gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
172: dialog.vbox.add(gtk.Label("You have unsaved configuration changes:"))
173: viewport = gtk.Viewport()
174: viewport.add(gtk.Label())
175: scrolledwindow = gtk.ScrolledWindow()
176: scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
177: scrolledwindow.add(viewport)
178: dialog.vbox.add(scrolledwindow)
179: dialog.show_all()
180: self.scrolledwindow = scrolledwindow
181: self.viewport = viewport
182: self.dialog = dialog
183:
184: def run(self, config):
185: "run(config) -> False if canceled, True otherwise or if no changes"
186: changes = []
187: for key, value in config.get_changes():
188: changes.append("%s = %s" % (key, str(value)))
189: if not changes:
190: return True
191: child = self.viewport.get_child()
192: child.set_text(config.get_path() + ":\n" + "\n".join(changes))
193: width, height = child.get_size_request()
194: if height < 320:
195: self.scrolledwindow.set_size_request(width, height)
196: else:
197: self.scrolledwindow.set_size_request(-1, 320)
198: self.viewport.show_all()
199:
200: response = self.dialog.run()
201: self.dialog.hide()
202: if response == gtk.RESPONSE_CANCEL:
203: return False
204: if response == gtk.RESPONSE_YES:
205: config.save()
206: return True
207:
208:
209: # ---------------------------
210: # Kill Hatari dialog
211:
212: class KillDialog(HatariUIDialog):
213: def __init__(self, parent):
214: self.dialog = gtk.MessageDialog(parent,
215: gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
216: gtk.MESSAGE_QUESTION, gtk.BUTTONS_OK_CANCEL,
217: """\
218: Hatari emulator is already/still running and it needs to be terminated first. However, if it contains unsaved data, that will be lost.
219:
220: Terminate Hatari anyway?""")
221:
222: def run(self, hatari):
223: "run(hatari) -> True if Hatari killed, False if left running"
224: if not hatari.is_running():
225: return True
226: # Hatari is running, OK to kill?
227: response = self.dialog.run()
228: self.dialog.hide()
229: if response == gtk.RESPONSE_OK:
230: hatari.kill()
231: return True
232: return False
233:
234:
235: # ---------------------------
236: # Reset Hatari dialog
237:
238: class ResetDialog(HatariUIDialog):
239: COLD = 1
240: WARM = 2
241: def __init__(self, parent):
242: self.dialog = gtk.Dialog("Reset Atari?", parent,
243: gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
244: ("Cold reset", self.COLD, "Warm reset", self.WARM,
245: gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
246: label = gtk.Label("\nRebooting will lose changes in currently\nrunning Atari programs.\n\nReset anyway?\n")
247: self.dialog.vbox.add(label)
248: label.show()
249:
250: def run(self, hatari):
251: "run(hatari) -> True if Hatari rebooted, False if canceled"
252: if not hatari.is_running():
253: return False
254: # Hatari is running, how to reboot?
255: response = self.dialog.run()
256: self.dialog.hide()
257: if response == self.COLD:
258: hatari.trigger_shortcut("coldreset")
259: elif response == self.WARM:
260: hatari.trigger_shortcut("warmreset")
261: else:
262: return False
263: return True
264:
265:
266: # ----------------------------------
267: # Floppy image dialog
268:
269: class DiskDialog(HatariUIDialog):
270: def _create_dialog(self, config):
271: table, self.dialog = create_table_dialog(self.parent, "Floppy images", 9)
272:
273: row = 0
274: self.floppy = []
275: path = config.get_floppydir()
276: for drive in ("A", "B"):
277: label = "Disk %c:" % drive
278: fsel = gtk.FileChooserButton(label)
279: # Hatari cannot access URIs
280: fsel.set_local_only(True)
281: fsel.set_width_chars(12)
282: filename = config.get_floppy(row)
283: if filename:
284: fsel.set_filename(filename)
285: elif path:
286: fsel.set_current_folder(path)
287: self.floppy.append(fsel)
288:
289: eject = create_button("Eject", self._eject, fsel)
290: box = gtk.HBox()
291: box.pack_start(fsel)
292: box.pack_start(eject, False, False)
293: table_add_widget_row(table, row, label, box)
294: row += 1
295:
296: table.show_all()
297:
298: def _eject(self, widget, fsel):
299: fsel.unselect_all()
300:
301: def run(self, config):
302: "run(config), show disk image dialog"
303: if not self.dialog:
304: self._create_dialog(config)
305: response = self.dialog.run()
306: self.dialog.hide()
307:
308: if response == gtk.RESPONSE_APPLY:
309: config.lock_updates()
310: for drive in range(2):
311: config.set_floppy(drive, self.floppy[drive].get_filename())
312: config.flush_updates()
313:
314:
315: # ---------------------------
316: # Display dialog
317:
318: class DisplayDialog(HatariUIDialog):
319:
320: def _create_dialog(self, config):
321: tips = gtk.Tooltips()
322:
323: skip = gtk.combo_box_new_text()
324: for text in config.get_frameskip_names():
325: skip.append_text(text)
326: skip.set_active(config.get_frameskip())
327: tips.set_tip(skip, "Set how many frames are skipped")
328:
329: zoom = gtk.CheckButton("Zoom ST-low")
330: zoom.set_active(config.get_zoom())
331: tips.set_tip(zoom, "Whether to double ST-low resolution")
332:
333: borders = gtk.CheckButton("Borders")
334: borders.set_active(config.get_borders())
335: tips.set_tip(borders, "Whether to show overscan borders in low/mid-rez")
336:
337: spec512 = gtk.CheckButton("Spec512")
338: spec512.set_active(config.get_spec512threshold())
339: tips.set_tip(spec512, "Whether to support Spec512 (>16 colors at the same time)")
340:
341: statusbar = gtk.CheckButton("Statusbar")
342: statusbar.set_active(config.get_statusbar())
343: tips.set_tip(statusbar, "Whether to show statusbar with floppy leds etc")
344:
345: led = gtk.CheckButton("Overlay led")
346: led.set_active(config.get_led())
347: tips.set_tip(led, "Whether to show overlay drive led when statusbar isn't visible")
348:
349: dialog = gtk.Dialog("Display settings", self.parent,
350: gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
351: (gtk.STOCK_APPLY, gtk.RESPONSE_APPLY,
352: gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
353:
354: dialog.vbox.add(gtk.Label("Frameskip:"))
355: dialog.vbox.add(skip)
356: dialog.vbox.add(zoom)
357: dialog.vbox.add(borders)
358: dialog.vbox.add(spec512)
359: dialog.vbox.add(statusbar)
360: dialog.vbox.add(led)
361: dialog.vbox.show_all()
362:
363: self.dialog = dialog
364: self.skip = skip
365: self.zoom = zoom
366: self.borders = borders
367: self.spec512 = spec512
368: self.statusbar = statusbar
369: self.led = led
370:
371: def run(self, config):
372: "run(config), show display dialog"
373: if not self.dialog:
374: self._create_dialog(config)
375: response = self.dialog.run()
376: self.dialog.hide()
377: if response == gtk.RESPONSE_APPLY:
378: config.lock_updates()
379: config.set_frameskip(self.skip.get_active())
380: config.set_zoom(self.zoom.get_active())
381: config.set_borders(self.borders.get_active())
382: config.set_spec512threshold(self.spec512.get_active())
383: config.set_statusbar(self.statusbar.get_active())
384: config.set_led(self.led.get_active())
385: config.flush_updates()
386:
387:
388: # ----------------------------------
389: # Joystick dialog
390:
391: class JoystickDialog(HatariUIDialog):
392: def _create_dialog(self, config):
393: table, self.dialog = create_table_dialog(self.parent, "Joystick settings", 9)
394:
395: joy = 0
396: self.joy = []
397: joytypes = config.get_joystick_types()
398: for label in config.get_joystick_names():
399: combo = gtk.combo_box_new_text()
400: for text in joytypes:
401: combo.append_text(text)
402: combo.set_active(config.get_joystick(joy))
403: widget = table_add_widget_row(table, joy, "%s:" % label, combo)
404: self.joy.append(widget)
405: joy += 1
406:
407: table.show_all()
408:
409: def run(self, config):
410: "run(config), show joystick dialog"
411: if not self.dialog:
412: self._create_dialog(config)
413: response = self.dialog.run()
414: self.dialog.hide()
415:
416: if response == gtk.RESPONSE_APPLY:
417: config.lock_updates()
418: for joy in range(6):
419: config.set_joystick(joy, self.joy[joy].get_active())
420: config.flush_updates()
421:
422:
423: # ---------------------------------------
424: # Peripherals (midi,printer,rs232) dialog
425:
426: class PeripheralDialog(HatariUIDialog):
427: def _create_dialog(self, config):
428: midi = gtk.CheckButton("Enable MIDI")
429: midi.set_active(config.get_midi())
430:
431: printer = gtk.CheckButton("Enable printer output")
432: printer.set_active(config.get_printer())
433:
434: rs232 = gtk.CheckButton("Enable RS232")
435: rs232.set_active(config.get_rs232())
436:
437: dialog = gtk.Dialog("Peripherals", self.parent,
438: gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
439: (gtk.STOCK_APPLY, gtk.RESPONSE_APPLY,
440: gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
441: dialog.vbox.add(midi)
442: dialog.vbox.add(printer)
443: dialog.vbox.add(rs232)
444: dialog.vbox.show_all()
445:
446: self.dialog = dialog
447: self.printer = printer
448: self.rs232 = rs232
449: self.midi = midi
450:
451: def run(self, config):
452: "run(config), show peripherals dialog"
453: if not self.dialog:
454: self._create_dialog(config)
455: response = self.dialog.run()
456: self.dialog.hide()
457:
458: if response == gtk.RESPONSE_APPLY:
459: config.lock_updates()
460: config.set_midi(self.midi.get_active())
461: config.set_printer(self.printer.get_active())
462: config.set_rs232(self.rs232.get_active())
463: config.flush_updates()
464:
465:
466: # ---------------------------------------
467: # Path dialog
468:
469: class PathDialog(HatariUIDialog):
470: def _create_dialog(self, config):
471: paths = config.get_paths()
472: table, self.dialog = create_table_dialog(self.parent, "File path settings", len(paths))
473: paths.sort()
474: row = 0
475: self.paths = []
476: for (key, path, label) in paths:
477: fsel = FselEntry(self.dialog, self._validate_fname, key)
478: fsel.set_filename(path)
479: self.paths.append((key, fsel))
480: table_add_widget_row(table, row, label, fsel.get_container())
481: row += 1
482: table.show_all()
483:
484: def _validate_fname(self, key, fname):
485: if key != "soundout":
486: return True
487: if fname.rsplit(".", 1)[-1].lower() in ("ym", "wav"):
488: return True
489: ErrorDialog(self.dialog).run("Sound output file name:\n\t%s\nneeds to end with '.ym' or '.wav'." % fname)
490: return False
491:
492: def run(self, config):
493: "run(config), show paths dialog"
494: if not self.dialog:
495: self._create_dialog(config)
496: response = self.dialog.run()
497: self.dialog.hide()
498:
499: if response == gtk.RESPONSE_APPLY:
500: paths = []
501: for key, fsel in self.paths:
502: paths.append((key, fsel.get_filename()))
503: config.set_paths(paths)
504:
505:
506: # ---------------------------
507: # Sound dialog
508:
509: class SoundDialog(HatariUIDialog):
510:
511: def _create_dialog(self, config):
512: combo = gtk.combo_box_entry_new_text()
513: for text in config.get_sound_values():
514: combo.append_text(text)
515: enabled, hz = config.get_sound()
516: self.enabled = gtk.CheckButton("Sound enabled")
517: self.enabled.set_active(enabled)
518: combo.child.set_text(hz)
519: box = gtk.HBox()
520: box.pack_start(gtk.Label("Sound frequency:"), False, False)
521: box.add(combo)
522: self.sound = combo.child
523:
524: dialog = gtk.Dialog("Sound settings", self.parent,
525: gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
526: (gtk.STOCK_APPLY, gtk.RESPONSE_APPLY,
527: gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
528: dialog.vbox.add(self.enabled)
529: dialog.vbox.add(box)
530: dialog.vbox.show_all()
531: self.dialog = dialog
532:
533: def run(self, config):
534: "run(config), show sound dialog"
535: if not self.dialog:
536: self._create_dialog(config)
537: response = self.dialog.run()
538: self.dialog.hide()
539: if response == gtk.RESPONSE_APPLY:
540: enabled = self.enabled.get_active()
541: hz1 = self.sound.get_text()
542: hz2 = config.set_sound(enabled, hz1)
543: if hz2 != hz1:
544: self.sound.set_text(hz2)
545:
546:
547: # ---------------------------
548: # Trace settings dialog
549:
550: class TraceDialog(HatariUIDialog):
551: # you can get this list with:
552: # hatari --trace help 2>&1|awk '/all$/{next} /^ [^-]/ {printf("\"%s\",\n", $1)}'
553: tracepoints = [
554: "video_sync",
555: "video_res",
556: "video_color",
557: "video_border_v",
558: "video_border_h",
559: "video_addr",
560: "video_hbl",
561: "video_vbl",
562: "video_ste",
563: "mfp_exception",
564: "mfp_start",
565: "mfp_read",
566: "mfp_write",
567: "psg_write_reg",
568: "psg_write_data",
569: "cpu_pairing",
570: "cpu_disasm",
571: "cpu_exception",
572: "int",
573: "fdc",
574: "ikbd_cmds",
575: "ikbd_acia",
576: "ikbd_exec",
577: "blitter",
578: "bios",
579: "xbios",
580: "gemdos",
581: "vdi",
582: "io_read",
583: "io_write",
584: "dmasound"
585: ]
586: def __init__(self, parent):
587: self.savedpoints = "none"
588: hbox1 = gtk.HBox()
589: hbox1.add(create_button("Load", self._load_traces))
590: hbox1.add(create_button("Clear", self._clear_traces))
591: hbox1.add(create_button("Save", self._save_traces))
592: hbox2 = gtk.HBox()
593: vboxes = []
594: for idx in (0,1,2):
595: vboxes.append(gtk.VBox())
596: hbox2.add(vboxes[idx])
597:
598: count = 0
599: per_side = (len(self.tracepoints)+2)/3
600: self.tracewidgets = {}
601: for trace in self.tracepoints:
1.1.1.2 ! root 602: name = trace.replace("_", "-")
! 603: widget = gtk.CheckButton(name)
1.1 root 604: self.tracewidgets[trace] = widget
605: vboxes[count/per_side].pack_start(widget, False, True)
606: count += 1
607:
608: dialog = gtk.Dialog("Trace settings", parent,
609: gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
610: (gtk.STOCK_APPLY, gtk.RESPONSE_APPLY,
611: gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
612: dialog.vbox.add(hbox1)
613: dialog.vbox.add(gtk.Label("Select trace points:"))
614: dialog.vbox.add(hbox2)
615: dialog.vbox.show_all()
616: self.dialog = dialog
617:
618: def _get_traces(self):
619: traces = []
620: for trace in self.tracepoints:
621: if self.tracewidgets[trace].get_active():
622: traces.append(trace)
623: if traces:
624: return ",".join(traces)
625: return "none"
626:
627: def _set_traces(self, tracepoints):
628: self._clear_traces()
629: for trace in tracepoints.split(","):
630: if trace in self.tracewidgets:
631: self.tracewidgets[trace].set_active(True)
632: else:
633: print "ERROR: unknown trace setting '%s'" % trace
634:
635: def _clear_traces(self, widget = None):
636: for trace in self.tracepoints:
637: self.tracewidgets[trace].set_active(False)
638:
639: def _load_traces(self, widget):
640: # this doesn't load traces, just sets them from internal variable
641: # that run method gets from caller and sets. It's up to caller
642: # whether the saving or loading happens actually to disk
643: self._set_traces(self.savedpoints)
644:
645: def _save_traces(self, widget):
646: self.savedpoints = self._get_traces()
647:
648: def run(self, hatari, savedpoints):
649: "run(hatari,tracepoints) -> tracepoints, caller saves tracepoints"
650: self.savedpoints = savedpoints
651: while 1:
652: response = self.dialog.run()
653: if response == gtk.RESPONSE_APPLY:
654: hatari.change_option("--trace %s" % self._get_traces())
655: else:
656: self.dialog.hide()
657: return self.savedpoints
658:
659:
660: # ------------------------------------------
661: # Machine dialog for settings needing reboot
662:
663: class MachineDialog(HatariUIDialog):
664: def _create_dialog(self, config):
665: table, self.dialog = create_table_dialog(self.parent, "Machine configuration", 9, "Set and reboot")
666:
667: row = 0
668: combo = gtk.combo_box_new_text()
669: for text in config.get_machine_types():
670: combo.append_text(text)
671: self.machine = table_add_widget_row(table, row, "Machine type:", combo)
672: row += 1
673:
674: combo = gtk.combo_box_new_text()
675: for text in config.get_monitor_types():
676: combo.append_text(text)
677: self.monitor = table_add_widget_row(table, row, "Monitor type:", combo)
678: row += 1
679:
680: combo = gtk.combo_box_new_text()
681: for text in config.get_memory_names():
682: combo.append_text(text)
683: self.memory = table_add_widget_row(table, row, "Memory size:", combo)
684: row += 1
685:
686: label = "TOS image:"
687: fsel = self._fsel(label, gtk.FILE_CHOOSER_ACTION_OPEN)
688: self.tos = table_add_widget_row(table, row, label, fsel)
689: row += 1
690:
691: label = "Harddisk:"
692: fsel = self._fsel(label, gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
693: self.harddisk = table_add_widget_row(table, row, label, fsel)
694: row += 1
695:
696: widget = gtk.CheckButton("Use harddisk")
697: self.usehd = table_add_widget_row(table, row, None, widget)
698: row += 1
699:
700: widget = gtk.CheckButton("Compatible CPU")
701: self.compatible = table_add_widget_row(table, row, None, widget)
702: row += 1
703:
704: widget = gtk.CheckButton("Patch Timer-D")
705: self.timerd = table_add_widget_row(table, row, None, widget)
706: row += 1
707:
708: table.show_all()
709:
710: def _fsel(self, label, action):
711: fsel = gtk.FileChooserButton(label)
712: # Hatari cannot access URIs
713: fsel.set_local_only(True)
714: fsel.set_width_chars(12)
715: fsel.set_action(action)
716: return fsel
717:
718: def _get_config(self, config):
719: self.machine.set_active(config.get_machine())
720: self.monitor.set_active(config.get_monitor())
721: self.memory.set_active(config.get_memory())
722: tos = config.get_tos()
723: hd = config.get_harddisk()
724: usehd = config.get_use_harddisk()
725: if tos:
726: self.tos.set_filename(tos)
727: if hd:
728: self.harddisk.set_filename(hd)
729: if usehd:
730: self.usehd.set_active(usehd)
731: self.compatible.set_active(config.get_compatible())
732: self.timerd.set_active(config.get_timerd())
733:
734: def _set_config(self, config):
735: config.lock_updates()
736: config.set_machine(self.machine.get_active())
737: config.set_monitor(self.monitor.get_active())
738: config.set_memory(self.memory.get_active())
739: config.set_tos(self.tos.get_filename())
740: # usehd has to be before before harddisk
741: config.set_use_harddisk(self.usehd.get_active())
742: config.set_harddisk(self.harddisk.get_filename())
743: config.set_compatible(self.compatible.get_active())
744: config.set_timerd(self.timerd.get_active())
745: config.flush_updates()
746:
747: def run(self, config):
748: "run(config) -> bool, whether to reboot"
749: if not self.dialog:
750: self._create_dialog(config)
751:
752: self._get_config(config)
753: response = self.dialog.run()
754: self.dialog.hide()
755: if response == gtk.RESPONSE_APPLY:
756: self._set_config(config)
757: return True
758: return False
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.