Annotation of previous/python-ui/dialogs.py, revision 1.1.1.1

1.1       root        1: #!/usr/bin/env python
                      2: #
                      3: # Classes for the Hatari UI dialogs
                      4: #
                      5: # Copyright (C) 2008-2010 by Eero Tamminen <eerot at berlios>
                      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:      table_add_radio_rows, table_set_col_offset, 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:     button = gtk.BUTTONS_OK
                     51:     icontype = gtk.MESSAGE_INFO
                     52:     textpattern = "\n%s"
                     53:     def run(self, text):
                     54:         "run(text), show message dialog with given text"
                     55:         dialog = gtk.MessageDialog(self.parent,
                     56:         gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                     57:         self.icontype, self.button, self.textpattern % text)
                     58:         dialog.run()
                     59:         dialog.destroy()
                     60: 
                     61: class TodoDialog(NoteDialog):
                     62:     textpattern = "\nTODO: %s"
                     63: 
                     64: class ErrorDialog(NoteDialog):
                     65:     button = gtk.BUTTONS_CLOSE
                     66:     icontype = gtk.MESSAGE_ERROR
                     67:     textpattern = "\nERROR: %s"
                     68: 
                     69: 
                     70: class AskDialog(HatariUIDialog):
                     71:     def run(self, text):
                     72:         "run(text) -> bool, show question dialog and return True if user OKed it"
                     73:         dialog = gtk.MessageDialog(self.parent,
                     74:         gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                     75:         gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, text)
                     76:         response = dialog.run()
                     77:         dialog.destroy()
                     78:         return (response == gtk.RESPONSE_YES)
                     79: 
                     80: 
                     81: # ---------------------------
                     82: # About dialog
                     83: 
                     84: class AboutDialog(HatariUIDialog):
                     85:     def __init__(self, parent):
                     86:         dialog = gtk.AboutDialog()
                     87:         dialog.set_transient_for(parent)
                     88:         dialog.set_name(UInfo.name)
                     89:         dialog.set_version(UInfo.version)
                     90:         dialog.set_website("http://hatari.berlios.de/")
                     91:         dialog.set_website_label("Hatari emulator www-site")
                     92:         dialog.set_authors(["Eero Tamminen"])
                     93:         dialog.set_artists(["The logo is from Hatari"])
                     94:         dialog.set_logo(gtk.gdk.pixbuf_new_from_file(UInfo.logo))
                     95:         dialog.set_translator_credits("translator-credits")
                     96:         dialog.set_copyright(UInfo.copyright)
                     97:         dialog.set_license("""
                     98: This software is licenced under GPL v2 or later.
                     99: 
                    100: You can see the whole license at:
                    101:     http://www.gnu.org/licenses/info/GPLv2.html""")
                    102:         self.dialog = dialog
                    103: 
                    104: 
                    105: # ---------------------------
                    106: # Input dialog
                    107: 
                    108: class InputDialog(HatariUIDialog):
                    109:     def __init__(self, parent):
                    110:         dialog = gtk.Dialog("Key/mouse input", parent,
                    111:             gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                    112:             ("Close", gtk.RESPONSE_CLOSE))
                    113:         
                    114:         tips = gtk.Tooltips()
                    115:         entry = gtk.Entry()
                    116:         entry.connect("activate", self._entry_cb)
                    117:         insert = create_button("Insert", self._entry_cb)
                    118:         tips.set_tip(insert, "Insert text to Hatari window")
                    119: 
                    120:         hbox1 = gtk.HBox()
                    121:         hbox1.add(gtk.Label("Text:"))
                    122:         hbox1.add(entry)
                    123:         hbox1.add(insert)
                    124:         dialog.vbox.add(hbox1)
                    125: 
                    126:         rclick = gtk.Button("Rightclick")
                    127:         tips.set_tip(rclick, "Simulate Atari left button double-click")
                    128:         rclick.connect("pressed", self._rightpress_cb)
                    129:         rclick.connect("released", self._rightrelease_cb)
                    130:         dclick = create_button("Doubleclick", self._doubleclick_cb)
                    131:         tips.set_tip(dclick, "Simulate Atari rigth button click")
                    132: 
                    133:         hbox2 = gtk.HBox()
                    134:         hbox2.add(rclick)
                    135:         hbox2.add(dclick)
                    136:         dialog.vbox.add(hbox2)
                    137: 
                    138:         dialog.show_all()
                    139:         self.dialog = dialog
                    140:         self.entry = entry
                    141:     
                    142:     def _entry_cb(self, widget):
                    143:         text = self.entry.get_text()
                    144:         if text:
                    145:             HatariTextInsert(self.hatari, text)
                    146:             self.entry.set_text("")
                    147: 
                    148:     def _doubleclick_cb(self, widget):
                    149:         self.hatari.insert_event("doubleclick")
                    150: 
                    151:     def _rightpress_cb(self, widget):
                    152:         self.hatari.insert_event("rightpress")
                    153: 
                    154:     def _rightrelease_cb(self, widget):
                    155:         self.hatari.insert_event("rightrelease")
                    156: 
                    157:     def run(self, hatari):
                    158:         "run(hatari), do text/mouse click input"
                    159:         self.hatari = hatari
                    160:         self.dialog.run()
                    161:         self.dialog.hide()
                    162: 
                    163: 
                    164: # ---------------------------
                    165: # Quit and Save dialog
                    166: 
                    167: class QuitSaveDialog(HatariUIDialog):
                    168:     def __init__(self, parent):
                    169:         dialog = gtk.Dialog("Quit and Save?", parent,
                    170:             gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                    171:             ("Save changes",    gtk.RESPONSE_YES,
                    172:              "Discard changes", gtk.RESPONSE_NO,
                    173:              gtk.STOCK_CANCEL,  gtk.RESPONSE_CANCEL))
                    174:         dialog.vbox.add(gtk.Label("You have unsaved configuration changes:"))
                    175:         viewport = gtk.Viewport()
                    176:         viewport.add(gtk.Label())
                    177:         scrolledwindow = gtk.ScrolledWindow()
                    178:         scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
                    179:         scrolledwindow.add(viewport)
                    180:         dialog.vbox.add(scrolledwindow)
                    181:         dialog.show_all()
                    182:         self.scrolledwindow = scrolledwindow
                    183:         self.viewport = viewport
                    184:         self.dialog = dialog
                    185:         
                    186:     def run(self, config):
                    187:         "run(config) -> False if canceled, True otherwise or if no changes"
                    188:         changes = []
                    189:         for key, value in config.get_changes():
                    190:             changes.append("%s = %s" % (key, str(value)))
                    191:         if not changes:
                    192:             return True
                    193:         child = self.viewport.get_child()
                    194:         child.set_text(config.get_path() + ":\n" + "\n".join(changes))
                    195:         width, height = child.get_size_request()
                    196:         if height < 320:
                    197:             self.scrolledwindow.set_size_request(width, height)
                    198:         else:
                    199:             self.scrolledwindow.set_size_request(-1, 320)
                    200:         self.viewport.show_all()
                    201:         
                    202:         response = self.dialog.run()
                    203:         self.dialog.hide()
                    204:         if response == gtk.RESPONSE_CANCEL:
                    205:             return False
                    206:         if response == gtk.RESPONSE_YES:
                    207:             config.save()
                    208:         return True
                    209: 
                    210: 
                    211: # ---------------------------
                    212: # Kill Hatari dialog
                    213: 
                    214: class KillDialog(HatariUIDialog):
                    215:     def __init__(self, parent):
                    216:         self.dialog = gtk.MessageDialog(parent,
                    217:         gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                    218:         gtk.MESSAGE_QUESTION, gtk.BUTTONS_OK_CANCEL,
                    219:         """\
                    220: Hatari emulator is already/still running and it needs to be terminated first. However, if it contains unsaved data, that will be lost.
                    221: 
                    222: Terminate Hatari anyway?""")
                    223: 
                    224:     def run(self, hatari):
                    225:         "run(hatari) -> True if Hatari killed, False if left running"
                    226:         if not hatari.is_running():
                    227:             return True
                    228:         # Hatari is running, OK to kill?
                    229:         response = self.dialog.run()
                    230:         self.dialog.hide()
                    231:         if response == gtk.RESPONSE_OK:
                    232:             hatari.kill()
                    233:             return True
                    234:         return False
                    235: 
                    236:     
                    237: # ---------------------------
                    238: # Reset Hatari dialog
                    239: 
                    240: class ResetDialog(HatariUIDialog):
                    241:     COLD = 1
                    242:     WARM = 2
                    243:     def __init__(self, parent):
                    244:         self.dialog = gtk.Dialog("Reset Atari?", parent,
                    245:             gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                    246:             ("Cold reset", self.COLD, "Warm reset", self.WARM,
                    247:              gtk.STOCK_CANCEL,  gtk.RESPONSE_CANCEL))
                    248:         label = gtk.Label("\nRebooting will lose changes in currently\nrunning Atari programs.\n\nReset anyway?\n")
                    249:         self.dialog.vbox.add(label)
                    250:         label.show()
                    251: 
                    252:     def run(self, hatari):
                    253:         "run(hatari) -> True if Hatari rebooted, False if canceled"
                    254:         if not hatari.is_running():
                    255:             return False
                    256:         # Hatari is running, how to reboot?
                    257:         response = self.dialog.run()
                    258:         self.dialog.hide()
                    259:         if response == self.COLD:
                    260:             hatari.trigger_shortcut("coldreset")
                    261:         elif response == self.WARM:
                    262:             hatari.trigger_shortcut("warmreset")
                    263:         else:
                    264:             return False
                    265:         return True
                    266: 
                    267: 
                    268: # ----------------------------------
                    269: # Floppy image dialog
                    270: 
                    271: class FloppyDialog(HatariUIDialog):
                    272:     def _create_dialog(self, config):
                    273:         table, self.dialog = create_table_dialog(self.parent, "Floppy images", 4, 2)
                    274: 
                    275:         row = 0
                    276:         self.floppy = []
                    277:         path = config.get_floppydir()
                    278:         for drive in ("A", "B"):
                    279:             label = "Disk %c:" % drive
                    280:             fsel = gtk.FileChooserButton(label)
                    281:             # Hatari cannot access URIs
                    282:             fsel.set_local_only(True)
                    283:             fsel.set_width_chars(12)
                    284:             filename = config.get_floppy(row)
                    285:             if filename:
                    286:                 fsel.set_filename(filename)
                    287:             elif path:
                    288:                 fsel.set_current_folder(path)
                    289:             self.floppy.append(fsel)
                    290:             
                    291:             eject = create_button("Eject", self._eject, fsel)
                    292:             box = gtk.HBox()
                    293:             box.pack_start(fsel)
                    294:             box.pack_start(eject, False, False)
                    295:             table_add_widget_row(table, row, label, box)
                    296:             row += 1
                    297: 
                    298:         tips = gtk.Tooltips()
                    299: 
                    300:         protect = gtk.combo_box_new_text()
                    301:         for text in config.get_protection_types():
                    302:             protect.append_text(text)
                    303:         protect.set_active(config.get_floppy_protection())
                    304:         tips.set_tip(protect, "Write protect floppy image contents")
                    305:         table_add_widget_row(table, row, "Write protection:", protect)
                    306: 
                    307:         row += 1
                    308:         slowfdc = gtk.CheckButton("Slow floppy access")
                    309:         slowfdc.set_active(config.get_slowfdc())
                    310:         tips.set_tip(slowfdc, "May be required by some rare game/demo")
                    311:         table_add_widget_row(table, row, None, slowfdc)
                    312: 
                    313:         table.show_all()
                    314: 
                    315:         self.protect = protect
                    316:         self.slowfdc = slowfdc
                    317: 
                    318:     def _eject(self, widget, fsel):
                    319:         fsel.unselect_all()
                    320:     
                    321:     def run(self, config):
                    322:         "run(config), show disk image dialog"
                    323:         if not self.dialog:
                    324:             self._create_dialog(config)
                    325:         response = self.dialog.run()
                    326:         self.dialog.hide()
                    327:         
                    328:         if response == gtk.RESPONSE_APPLY:
                    329:             config.lock_updates()
                    330:             for drive in range(2):
                    331:                 config.set_floppy(drive, self.floppy[drive].get_filename())
                    332:             config.set_hd_protection(self.protect.get_active())
                    333:             config.set_slowfdc(self.slowfdc.get_active())
                    334:             config.flush_updates()
                    335: 
                    336: 
                    337: # ----------------------------------
                    338: # Hard disk dialog
                    339: 
                    340: class HardDiskDialog(HatariUIDialog):
                    341:     def _create_dialog(self, config):
                    342:         table, self.dialog = create_table_dialog(self.parent, "Hard disks", 4, 4, "Set and reboot")
                    343:         row = 0
                    344: 
                    345:         label = "ASCI HD image:"
                    346:         path = config.get_acsi_image()
                    347:         fsel, box = self._fsel_box(label, path, gtk.FILE_CHOOSER_ACTION_OPEN)
                    348:         table_add_widget_row(table, row, label, box, True)
                    349:         self.acsi = fsel
                    350:         row += 1
                    351: 
                    352:         label = "IDE HD master image:"
                    353:         path = config.get_idemaster_image()
                    354:         fsel, box = self._fsel_box(label, path, gtk.FILE_CHOOSER_ACTION_OPEN)
                    355:         table_add_widget_row(table, row, label, box, True)
                    356:         self.idemaster = fsel
                    357:         row += 1
                    358: 
                    359:         label = "IDE HD slave image:"
                    360:         path = config.get_ideslave_image()
                    361:         fsel, box = self._fsel_box(label, path, gtk.FILE_CHOOSER_ACTION_OPEN)
                    362:         table_add_widget_row(table, row, label, box, True)
                    363:         self.ideslave = fsel
                    364:         row += 1
                    365:         
                    366:         label = "GEMDOS drive directory:"
                    367:         path = config.get_gemdos_dir()
                    368:         fsel, box = self._fsel_box(label, path, gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
                    369:         table_add_widget_row(table, row, label, box, True)
                    370:         self.gemdos = fsel
                    371:         row += 1
                    372: 
                    373:         tips = gtk.Tooltips()
                    374: 
                    375:         protect = gtk.combo_box_new_text()
                    376:         for text in config.get_protection_types():
                    377:             protect.append_text(text)
                    378:         tips.set_tip(protect, "Write protect GEMDOS drive contents")
                    379:         table_add_widget_row(table, row, "Write protection:", protect)
                    380:         self.protect = protect
                    381: 
                    382:         table.show_all()
                    383: 
                    384:     def _eject(self, widget, fsel):
                    385:         fsel.unselect_all()
                    386: 
                    387:     def _fsel_box(self, label, path, action):
                    388:         fsel = gtk.FileChooserButton(label)
                    389:         # Hatari cannot access URIs
                    390:         fsel.set_local_only(True)
                    391:         fsel.set_width_chars(12)
                    392:         fsel.set_action(action)
                    393:         if path:
                    394:             fsel.set_filename(path)
                    395:         eject = create_button("Eject", self._eject, fsel)
                    396: 
                    397:         box = gtk.HBox()
                    398:         box.pack_start(fsel)
                    399:         box.pack_start(eject, False, False)
                    400:         return (fsel, box)
                    401:     
                    402:     def _get_config(self, config):
                    403:         path = config.get_gemdos_dir()
                    404:         if path:
                    405:             self.gemdos.set_filename(path)
                    406:         path = config.get_acsi_image()
                    407:         if path:
                    408:             self.acsi.set_filename(path)
                    409:         path = config.get_idemaster_image()
                    410:         if path:
                    411:             self.idemaster.set_filename(path)
                    412:         path = config.get_ideslave_image()
                    413:         if path:
                    414:             self.ideslave.set_filename(path)
                    415:         self.protect.set_active(config.get_hd_protection())
                    416:         
                    417:     def _set_config(self, config):
                    418:         config.lock_updates()
                    419:         config.set_gemdos_dir(self.gemdos.get_filename())
                    420:         config.set_acsi_image(self.acsi.get_filename())
                    421:         config.set_idemaster_image(self.idemaster.get_filename())
                    422:         config.set_ideslave_image(self.ideslave.get_filename())
                    423:         config.set_hd_protection(self.protect.get_active())
                    424:         config.flush_updates()
                    425: 
                    426:     def run(self, config):
                    427:         "run(config) -> bool, whether to reboot"
                    428:         if not self.dialog:
                    429:             self._create_dialog(config)
                    430: 
                    431:         self._get_config(config)
                    432:         response = self.dialog.run()
                    433:         self.dialog.hide()
                    434:         if response == gtk.RESPONSE_APPLY:
                    435:             self._set_config(config)
                    436:             return True
                    437:         return False
                    438: 
                    439: 
                    440: # ---------------------------
                    441: # Display dialog
                    442: 
                    443: class DisplayDialog(HatariUIDialog):
                    444: 
                    445:     def _create_dialog(self, config):
                    446:         tips = gtk.Tooltips()
                    447: 
                    448:         skip = gtk.combo_box_new_text()
                    449:         for text in config.get_frameskip_names():
                    450:             skip.append_text(text)
                    451:         skip.set_active(config.get_frameskip())
                    452:         tips.set_tip(skip, "Set how many frames are skipped")
                    453: 
                    454:         maxw, maxh = config.get_max_size()
                    455:         maxadjw = gtk.Adjustment(maxw, 320, 1280, 8, 40)
                    456:         maxadjh = gtk.Adjustment(maxh, 200,  960, 8, 40)
                    457:         scalew = gtk.HScale(maxadjw)
                    458:         scaleh = gtk.HScale(maxadjh)
                    459:         scalew.set_digits(0)
                    460:         scaleh.set_digits(0)
                    461:         tips.set_tip(scalew, "Preferred/maximum zoomed width")
                    462:         tips.set_tip(scaleh, "Preferred/maximum zoomed height")
                    463: 
                    464:         borders = gtk.CheckButton("ST/STE overscan borders")
                    465:         borders.set_active(config.get_borders())
                    466:         tips.set_tip(borders, "Whether to show ST/STE overscan borders in low/mid-rez. Visible border area is affected by max. zoom size")
                    467: 
                    468:         statusbar = gtk.CheckButton("Show statusbar")
                    469:         statusbar.set_active(config.get_statusbar())
                    470:         tips.set_tip(statusbar, "Whether to show statusbar with floppy leds etc")
                    471: 
                    472:         led = gtk.CheckButton("Show overlay led")
                    473:         led.set_active(config.get_led())
                    474:         tips.set_tip(led, "Whether to show overlay drive led when statusbar isn't visible")
                    475: 
                    476:         dialog = gtk.Dialog("Display settings", self.parent,
                    477:             gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                    478:             (gtk.STOCK_APPLY,  gtk.RESPONSE_APPLY,
                    479:              gtk.STOCK_CANCEL,  gtk.RESPONSE_CANCEL))
                    480: 
                    481:         dialog.vbox.add(gtk.Label("Frameskip:"))
                    482:         dialog.vbox.add(skip)
                    483:         dialog.vbox.add(gtk.Label("Max zoomed size:"))
                    484:         dialog.vbox.add(scalew)
                    485:         dialog.vbox.add(scaleh)
                    486:         dialog.vbox.add(borders)
                    487:         dialog.vbox.add(statusbar)
                    488:         dialog.vbox.add(led)
                    489:         dialog.vbox.show_all()
                    490: 
                    491:         self.dialog = dialog
                    492:         self.skip = skip
                    493:         self.maxw = maxadjw
                    494:         self.maxh = maxadjh
                    495:         self.borders = borders
                    496:         self.statusbar = statusbar
                    497:         self.led = led
                    498:  
                    499:     def run(self, config):
                    500:         "run(config), show display dialog"
                    501:         if not self.dialog:
                    502:             self._create_dialog(config)
                    503:         response = self.dialog.run()
                    504:         self.dialog.hide()
                    505:         if response == gtk.RESPONSE_APPLY:
                    506:             config.lock_updates()
                    507:             config.set_frameskip(self.skip.get_active())
                    508:             config.set_max_size(self.maxw.get_value(), self.maxh.get_value())
                    509:             config.set_borders(self.borders.get_active())
                    510:             config.set_statusbar(self.statusbar.get_active())
                    511:             config.set_led(self.led.get_active())
                    512:             config.flush_updates()
                    513: 
                    514: 
                    515: # ----------------------------------
                    516: # Joystick dialog
                    517: 
                    518: class JoystickDialog(HatariUIDialog):
                    519:     def _create_dialog(self, config):
                    520:         table, self.dialog = create_table_dialog(self.parent, "Joystick settings", 9, 2)
                    521:         
                    522:         joy = 0
                    523:         self.joy = []
                    524:         joytypes = config.get_joystick_types()
                    525:         for label in config.get_joystick_names():
                    526:             combo = gtk.combo_box_new_text()
                    527:             for text in joytypes:
                    528:                 combo.append_text(text)
                    529:             combo.set_active(config.get_joystick(joy))
                    530:             widget = table_add_widget_row(table, joy, "%s:" % label, combo)
                    531:             self.joy.append(widget)
                    532:             joy += 1
                    533: 
                    534:         table.show_all()
                    535:     
                    536:     def run(self, config):
                    537:         "run(config), show joystick dialog"
                    538:         if not self.dialog:
                    539:             self._create_dialog(config)
                    540:         response = self.dialog.run()
                    541:         self.dialog.hide()
                    542:         
                    543:         if response == gtk.RESPONSE_APPLY:
                    544:             config.lock_updates()
                    545:             for joy in range(6):
                    546:                 config.set_joystick(joy, self.joy[joy].get_active())
                    547:             config.flush_updates()
                    548: 
                    549: 
                    550: # ---------------------------------------
                    551: # Peripherals (midi,printer,rs232) dialog
                    552: 
                    553: class PeripheralDialog(HatariUIDialog):
                    554:     def _create_dialog(self, config):
                    555:         midi = gtk.CheckButton("Enable MIDI")
                    556:         midi.set_active(config.get_midi())
                    557: 
                    558:         printer = gtk.CheckButton("Enable printer output")
                    559:         printer.set_active(config.get_printer())
                    560: 
                    561:         rs232 = gtk.CheckButton("Enable RS232")
                    562:         rs232.set_active(config.get_rs232())
                    563: 
                    564:         dialog = gtk.Dialog("Peripherals", self.parent,
                    565:             gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                    566:             (gtk.STOCK_APPLY,  gtk.RESPONSE_APPLY,
                    567:              gtk.STOCK_CANCEL,  gtk.RESPONSE_CANCEL))
                    568:         dialog.vbox.add(midi)
                    569:         dialog.vbox.add(printer)
                    570:         dialog.vbox.add(rs232)
                    571:         dialog.vbox.show_all()
                    572: 
                    573:         self.dialog = dialog
                    574:         self.printer = printer
                    575:         self.rs232 = rs232
                    576:         self.midi = midi
                    577:     
                    578:     def run(self, config):
                    579:         "run(config), show peripherals dialog"
                    580:         if not self.dialog:
                    581:             self._create_dialog(config)
                    582:         response = self.dialog.run()
                    583:         self.dialog.hide()
                    584:         
                    585:         if response == gtk.RESPONSE_APPLY:
                    586:             config.lock_updates()
                    587:             config.set_midi(self.midi.get_active())
                    588:             config.set_printer(self.printer.get_active())
                    589:             config.set_rs232(self.rs232.get_active())
                    590:             config.flush_updates()
                    591: 
                    592: 
                    593: # ---------------------------------------
                    594: # Path dialog
                    595: 
                    596: class PathDialog(HatariUIDialog):
                    597:     def _create_dialog(self, config):
                    598:         paths = config.get_paths()
                    599:         table, self.dialog = create_table_dialog(self.parent, "File path settings", len(paths), 2)
                    600:         paths.sort()
                    601:         row = 0
                    602:         self.paths = []
                    603:         for (key, path, label) in paths:
                    604:             fsel = FselEntry(self.dialog, self._validate_fname, key)
                    605:             fsel.set_filename(path)
                    606:             self.paths.append((key, fsel))
                    607:             table_add_widget_row(table, row, label, fsel.get_container())
                    608:             row += 1
                    609:         table.show_all()
                    610:     
                    611:     def _validate_fname(self, key, fname):
                    612:         if key != "soundout":
                    613:             return True
                    614:         if fname.rsplit(".", 1)[-1].lower() in ("ym", "wav"):
                    615:             return True
                    616:         ErrorDialog(self.dialog).run("Sound output file name:\n\t%s\nneeds to end with '.ym' or '.wav'." % fname)
                    617:         return False
                    618:     
                    619:     def run(self, config):
                    620:         "run(config), show paths dialog"
                    621:         if not self.dialog:
                    622:             self._create_dialog(config)
                    623:         response = self.dialog.run()
                    624:         self.dialog.hide()
                    625: 
                    626:         if response == gtk.RESPONSE_APPLY:
                    627:             paths = []
                    628:             for key, fsel in self.paths:
                    629:                 paths.append((key, fsel.get_filename()))
                    630:             config.set_paths(paths)
                    631: 
                    632: 
                    633: # ---------------------------
                    634: # Sound dialog
                    635: 
                    636: class SoundDialog(HatariUIDialog):
                    637: 
                    638:     def _create_dialog(self, config):
                    639:         combo = gtk.combo_box_entry_new_text()
                    640:         for text in config.get_sound_values():
                    641:             combo.append_text(text)
                    642:         enabled, hz = config.get_sound()
                    643:         self.enabled = gtk.CheckButton("Sound enabled")
                    644:         self.enabled.set_active(enabled)
                    645:         combo.child.set_text(hz)
                    646:         box = gtk.HBox()
                    647:         box.pack_start(gtk.Label("Sound frequency:"), False, False)
                    648:         box.add(combo)
                    649:         self.sound = combo.child
                    650: 
                    651:         dialog = gtk.Dialog("Sound settings", self.parent,
                    652:             gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                    653:             (gtk.STOCK_APPLY,  gtk.RESPONSE_APPLY,
                    654:              gtk.STOCK_CANCEL,  gtk.RESPONSE_CANCEL))
                    655:         dialog.vbox.add(self.enabled)
                    656:         dialog.vbox.add(box)
                    657:         dialog.vbox.show_all()
                    658:         self.dialog = dialog
                    659: 
                    660:     def run(self, config):
                    661:         "run(config), show sound dialog"
                    662:         if not self.dialog:
                    663:             self._create_dialog(config)
                    664:         response = self.dialog.run()
                    665:         self.dialog.hide()
                    666:         if response == gtk.RESPONSE_APPLY:
                    667:             enabled = self.enabled.get_active()
                    668:             hz1 = self.sound.get_text()
                    669:             hz2 = config.set_sound(enabled, hz1)
                    670:             if hz2 != hz1:
                    671:                 self.sound.set_text(hz2)
                    672:         
                    673: 
                    674: # ---------------------------
                    675: # Trace settings dialog
                    676: 
                    677: class TraceDialog(HatariUIDialog):
                    678:     # you can get this list with:
                    679:     # hatari --trace help 2>&1|awk '/all$/{next} /^  [^-]/ {printf("\"%s\",\n", $1)}'
                    680:     tracepoints = [
                    681:         "video_sync",
                    682:         "video_res",
                    683:         "video_color",
                    684:         "video_border_v",
                    685:         "video_border_h",
                    686:         "video_addr",
                    687:         "video_hbl",
                    688:         "video_vbl",
                    689:         "video_ste",
                    690:         "mfp_exception",
                    691:         "mfp_start",
                    692:         "mfp_read",
                    693:         "mfp_write",
                    694:         "psg_write_reg",
                    695:         "psg_write_data",
                    696:         "cpu_pairing",
                    697:         "cpu_disasm",
                    698:         "cpu_exception",
                    699:         "int",
                    700:         "fdc",
                    701:         "ikbd_cmds",
                    702:         "ikbd_acia",
                    703:         "ikbd_exec",
                    704:         "blitter",
                    705:         "bios",
                    706:         "xbios",
                    707:         "gemdos",
                    708:         "vdi",
                    709:         "io_read",
                    710:         "io_write",
                    711:         "dmasound"
                    712:     ]
                    713:     def __init__(self, parent):
                    714:         self.savedpoints = "none"
                    715:         hbox1 = gtk.HBox()
                    716:         hbox1.add(create_button("Load", self._load_traces))
                    717:         hbox1.add(create_button("Clear", self._clear_traces))
                    718:         hbox1.add(create_button("Save", self._save_traces))
                    719:         hbox2 = gtk.HBox()
                    720:         vboxes = []
                    721:         for idx in (0,1,2):
                    722:             vboxes.append(gtk.VBox())
                    723:             hbox2.add(vboxes[idx])
                    724: 
                    725:         count = 0
                    726:         per_side = (len(self.tracepoints)+2)/3
                    727:         self.tracewidgets = {}
                    728:         for trace in self.tracepoints:
                    729:             name = trace.replace("_", "-")
                    730:             widget = gtk.CheckButton(name)
                    731:             self.tracewidgets[trace] = widget
                    732:             vboxes[count/per_side].pack_start(widget, False, True)
                    733:             count += 1
                    734:         
                    735:         dialog = gtk.Dialog("Trace settings", parent,
                    736:             gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                    737:             (gtk.STOCK_APPLY,  gtk.RESPONSE_APPLY,
                    738:              gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
                    739:         dialog.vbox.add(hbox1)
                    740:         dialog.vbox.add(gtk.Label("Select trace points:"))
                    741:         dialog.vbox.add(hbox2)
                    742:         dialog.vbox.show_all()
                    743:         self.dialog = dialog
                    744: 
                    745:     def _get_traces(self):
                    746:         traces = []
                    747:         for trace in self.tracepoints:
                    748:             if self.tracewidgets[trace].get_active():
                    749:                 traces.append(trace)
                    750:         if traces:
                    751:             return ",".join(traces)
                    752:         return "none"
                    753: 
                    754:     def _set_traces(self, tracepoints):
                    755:         self._clear_traces()
                    756:         for trace in tracepoints.split(","):
                    757:             if trace in self.tracewidgets:
                    758:                 self.tracewidgets[trace].set_active(True)
                    759:             else:
                    760:                 print "ERROR: unknown trace setting '%s'" % trace
                    761: 
                    762:     def _clear_traces(self, widget = None):
                    763:         for trace in self.tracepoints:
                    764:             self.tracewidgets[trace].set_active(False)
                    765: 
                    766:     def _load_traces(self, widget):
                    767:         # this doesn't load traces, just sets them from internal variable
                    768:         # that run method gets from caller and sets. It's up to caller
                    769:         # whether the saving or loading happens actually to disk
                    770:         self._set_traces(self.savedpoints)
                    771:     
                    772:     def _save_traces(self, widget):
                    773:         self.savedpoints = self._get_traces()
                    774: 
                    775:     def run(self, hatari, savedpoints):
                    776:         "run(hatari,tracepoints) -> tracepoints, caller saves tracepoints"
                    777:         self.savedpoints = savedpoints
                    778:         while 1:
                    779:             response = self.dialog.run()
                    780:             if response == gtk.RESPONSE_APPLY:
                    781:                 hatari.change_option("--trace %s" % self._get_traces())
                    782:             else:
                    783:                 self.dialog.hide()
                    784:                 return self.savedpoints
                    785: 
                    786: 
                    787: # ------------------------------------------
                    788: # Machine dialog for settings needing reboot
                    789: 
                    790: class MachineDialog(HatariUIDialog):
                    791:     def _machine_cb(self, widget, data):
                    792:         if not widget.get_active():
                    793:             return
                    794:         machine = data.lower()
                    795:         if machine == "ste" or machine == "st":
                    796:             self.clocks[0].set_active(True)
                    797:             self.cpulevel.set_active(0)
                    798:         elif machine == "falcon":
                    799:             self.clocks[1].set_active(True)
                    800:             self.cpulevel.set_active(3)
                    801:         elif machine == "tt":
                    802:             self.clocks[2].set_active(True)
                    803:             self.cpulevel.set_active(3)
                    804: 
                    805:     def _dsp_cb(self, widget, data):
                    806:         if not widget.get_active():
                    807:             return
                    808:         if not self.machines[3].get_active():
                    809:             NoteDialog(self.dialog).run("Only Falcon has DSP.")
                    810: 
                    811:     def _create_dialog(self, config):
                    812:         table, self.dialog = create_table_dialog(self.parent, "Machine configuration", 6, 4, "Set and reboot")
                    813:         
                    814:         row = 0
                    815:         self.machines = table_add_radio_rows(table, row, "Machine:",
                    816:                         config.get_machine_types(), self._machine_cb)
                    817:         row += 1
                    818: 
                    819:         self.dsps = table_add_radio_rows(table, row, "DSP type:",
                    820:                     config.get_dsp_types(), self._dsp_cb)
                    821:         row += 1
                    822: 
                    823:         # start next table column
                    824:         row = 0
                    825:         table_set_col_offset(table, 2)
                    826:         self.monitors = table_add_radio_rows(table, row, "Monitor:", config.get_monitor_types())
                    827:         row += 1
                    828: 
                    829:         self.clocks = table_add_radio_rows(table, row, "CPU clock:", config.get_cpuclock_types())
                    830:         row += 1
                    831: 
                    832:         # fullspan at bottom
                    833:         fullspan = True
                    834: 
                    835:         combo = gtk.combo_box_new_text()
                    836:         for text in config.get_cpulevel_types():
                    837:             combo.append_text(text)
                    838:         self.cpulevel = table_add_widget_row(table, row, "CPU type:", combo, fullspan)
                    839:         row += 1
                    840: 
                    841:         combo = gtk.combo_box_new_text()
                    842:         for text in config.get_memory_names():
                    843:             combo.append_text(text)
                    844:         self.memory = table_add_widget_row(table, row, "Memory:", combo, fullspan)
                    845:         row += 1
                    846:         
                    847:         label = "TOS image:"
                    848:         fsel = self._fsel(label, gtk.FILE_CHOOSER_ACTION_OPEN)
                    849:         self.tos = table_add_widget_row(table, row, label, fsel, fullspan)
                    850:         row += 1
                    851: 
                    852:         vbox = gtk.VBox()
                    853:         self.compatible = gtk.CheckButton("Compatible CPU")
                    854:         self.timerd = gtk.CheckButton("Patch Timer-D")
                    855:         vbox.add(self.compatible)
                    856:         vbox.add(self.timerd)
                    857:         table_add_widget_row(table, row, "Misc.:", vbox, fullspan)
                    858:         row += 1
                    859: 
                    860:         table.show_all()
                    861: 
                    862:     def _fsel(self, label, action):
                    863:         fsel = gtk.FileChooserButton(label)
                    864:         # Hatari cannot access URIs
                    865:         fsel.set_local_only(True)
                    866:         fsel.set_width_chars(12)
                    867:         fsel.set_action(action)
                    868:         return fsel
                    869:     
                    870:     def _get_config(self, config):
                    871:         self.machines[config.get_machine()].set_active(True)
                    872:         self.monitors[config.get_monitor()].set_active(True)
                    873:         self.clocks[config.get_cpuclock()].set_active(True)
                    874:         self.dsps[config.get_dsp()].set_active(True)
                    875:         self.cpulevel.set_active(config.get_cpulevel())
                    876:         self.memory.set_active(config.get_memory())
                    877:         tos = config.get_tos()
                    878:         if tos:
                    879:             self.tos.set_filename(tos)
                    880:         self.compatible.set_active(config.get_compatible())
                    881:         self.timerd.set_active(config.get_timerd())
                    882: 
                    883:     def _get_active_radio(self, radios):
                    884:         idx = 0
                    885:         for radio in radios:
                    886:             if radio.get_active():
                    887:                 return idx
                    888:             idx += 1
                    889:         
                    890:     def _set_config(self, config):
                    891:         config.lock_updates()
                    892:         config.set_machine(self._get_active_radio(self.machines))
                    893:         config.set_monitor(self._get_active_radio(self.monitors))
                    894:         config.set_cpuclock(self._get_active_radio(self.clocks))
                    895:         config.set_dsp(self._get_active_radio(self.dsps))
                    896:         config.set_cpulevel(self.cpulevel.get_active())
                    897:         config.set_memory(self.memory.get_active())
                    898:         config.set_tos(self.tos.get_filename())
                    899:         config.set_compatible(self.compatible.get_active())
                    900:         config.set_timerd(self.timerd.get_active())
                    901:         config.flush_updates()
                    902: 
                    903:     def run(self, config):
                    904:         "run(config) -> bool, whether to reboot"
                    905:         if not self.dialog:
                    906:             self._create_dialog(config)
                    907: 
                    908:         self._get_config(config)
                    909:         response = self.dialog.run()
                    910:         self.dialog.hide()
                    911:         if response == gtk.RESPONSE_APPLY:
                    912:             self._set_config(config)
                    913:             return True
                    914:         return False

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.