Annotation of hatari/python-ui/dialogs.py, revision 1.1.1.13

1.1.1.13! root        1: #!/usr/bin/env python
1.1       root        2: #
                      3: # Classes for the Hatari UI dialogs
                      4: #
1.1.1.13! root        5: # Copyright (C) 2008-2019 by Eero Tamminen
1.1       root        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
1.1.1.13! root       18: import gi
        !            19: # use correct version of gtk
        !            20: gi.require_version('Gtk', '3.0')
        !            21: from gi.repository import Gtk
        !            22: from gi.repository import Gdk
        !            23: from gi.repository import GdkPixbuf
        !            24: from gi.repository import Pango
1.1       root       25: 
                     26: from uihelpers import UInfo, HatariTextInsert, create_table_dialog, \
                     27:      table_add_entry_row, table_add_widget_row, table_add_separator, \
1.1.1.13! root       28:      table_add_radio_rows, create_button, FselEntry, FselAndEjectFactory
1.1       root       29: 
                     30: 
                     31: # -----------------
                     32: # Dialog base class
                     33: 
                     34: class HatariUIDialog:
                     35:     def __init__(self, parent):
                     36:         "<any>Dialog(parent) -> object"
                     37:         self.parent = parent
                     38:         self.dialog = None
1.1.1.13! root       39: 
1.1       root       40:     def run(self):
                     41:         """run() -> response. Shows dialog and returns response,
                     42: subclasses overriding run() require also an argument."""
                     43:         response = self.dialog.run()
                     44:         self.dialog.hide()
                     45:         return response
                     46: 
                     47: 
                     48: # ---------------------------
                     49: # Note/Todo/Error/Ask dialogs
                     50: 
                     51: class NoteDialog(HatariUIDialog):
1.1.1.13! root       52:     button = Gtk.ButtonsType.OK
        !            53:     icontype = Gtk.MessageType.INFO
1.1       root       54:     textpattern = "\n%s"
                     55:     def run(self, text):
                     56:         "run(text), show message dialog with given text"
1.1.1.13! root       57:         dialog = Gtk.MessageDialog(self.parent,
        !            58:         Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
1.1.1.3   root       59:         self.icontype, self.button, self.textpattern % text)
1.1       root       60:         dialog.run()
                     61:         dialog.destroy()
                     62: 
                     63: class TodoDialog(NoteDialog):
                     64:     textpattern = "\nTODO: %s"
                     65: 
                     66: class ErrorDialog(NoteDialog):
1.1.1.13! root       67:     button = Gtk.ButtonsType.CLOSE
        !            68:     icontype = Gtk.MessageType.ERROR
1.1       root       69:     textpattern = "\nERROR: %s"
                     70: 
                     71: 
                     72: class AskDialog(HatariUIDialog):
                     73:     def run(self, text):
                     74:         "run(text) -> bool, show question dialog and return True if user OKed it"
1.1.1.13! root       75:         dialog = Gtk.MessageDialog(self.parent,
        !            76:         Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
        !            77:         Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, text)
1.1       root       78:         response = dialog.run()
                     79:         dialog.destroy()
1.1.1.13! root       80:         return (response == Gtk.ResponseType.YES)
1.1       root       81: 
                     82: 
                     83: # ---------------------------
                     84: # About dialog
                     85: 
                     86: class AboutDialog(HatariUIDialog):
                     87:     def __init__(self, parent):
1.1.1.13! root       88:         dialog = Gtk.AboutDialog()
1.1       root       89:         dialog.set_transient_for(parent)
                     90:         dialog.set_name(UInfo.name)
                     91:         dialog.set_version(UInfo.version)
1.1.1.5   root       92:         dialog.set_website("http://hatari.tuxfamily.org/")
1.1       root       93:         dialog.set_website_label("Hatari emulator www-site")
                     94:         dialog.set_authors(["Eero Tamminen"])
                     95:         dialog.set_artists(["The logo is from Hatari"])
1.1.1.13! root       96:         dialog.set_logo(GdkPixbuf.Pixbuf.new_from_file(UInfo.logo))
1.1       root       97:         dialog.set_translator_credits("translator-credits")
1.1.1.3   root       98:         dialog.set_copyright(UInfo.copyright)
1.1       root       99:         dialog.set_license("""
1.1.1.2   root      100: This software is licenced under GPL v2 or later.
1.1       root      101: 
                    102: You can see the whole license at:
                    103:     http://www.gnu.org/licenses/info/GPLv2.html""")
                    104:         self.dialog = dialog
                    105: 
                    106: 
                    107: # ---------------------------
                    108: # Input dialog
                    109: 
                    110: class InputDialog(HatariUIDialog):
                    111:     def __init__(self, parent):
1.1.1.13! root      112:         dialog = Gtk.Dialog("Key/mouse input", parent,
        !           113:             Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
        !           114:             ("Close", Gtk.ResponseType.CLOSE))
        !           115: 
        !           116:         entry = Gtk.Entry()
1.1       root      117:         entry.connect("activate", self._entry_cb)
                    118:         insert = create_button("Insert", self._entry_cb)
1.1.1.4   root      119:         insert.set_tooltip_text("Insert given text to Hatari window")
                    120:         enter = create_button("Enter key", self._enter_cb)
                    121:         enter.set_tooltip_text("Simulate Enter key press")
1.1       root      122: 
1.1.1.13! root      123:         hbox1 = Gtk.HBox()
        !           124:         hbox1.add(Gtk.Label(label="Text:"))
1.1       root      125:         hbox1.add(entry)
                    126:         hbox1.add(insert)
1.1.1.4   root      127:         hbox1.add(enter)
1.1       root      128:         dialog.vbox.add(hbox1)
                    129: 
1.1.1.13! root      130:         rclick = Gtk.Button("Right click")
1.1       root      131:         rclick.connect("pressed", self._rightpress_cb)
                    132:         rclick.connect("released", self._rightrelease_cb)
1.1.1.4   root      133:         rclick.set_tooltip_text("Simulate Atari right button press & release")
                    134:         dclick = create_button("Double click", self._doubleclick_cb)
                    135:         dclick.set_tooltip_text("Simulate Atari left button double-click")
1.1       root      136: 
1.1.1.13! root      137:         hbox2 = Gtk.HBox()
1.1       root      138:         hbox2.add(dclick)
1.1.1.4   root      139:         hbox2.add(rclick)
1.1       root      140:         dialog.vbox.add(hbox2)
                    141: 
                    142:         dialog.show_all()
                    143:         self.dialog = dialog
                    144:         self.entry = entry
1.1.1.13! root      145: 
1.1       root      146:     def _entry_cb(self, widget):
                    147:         text = self.entry.get_text()
                    148:         if text:
                    149:             HatariTextInsert(self.hatari, text)
                    150:             self.entry.set_text("")
                    151: 
1.1.1.4   root      152:     def _enter_cb(self, widget):
                    153:         self.hatari.insert_event("keypress 28") # Enter key scancode
                    154: 
1.1       root      155:     def _doubleclick_cb(self, widget):
                    156:         self.hatari.insert_event("doubleclick")
                    157: 
                    158:     def _rightpress_cb(self, widget):
1.1.1.4   root      159:         self.hatari.insert_event("rightdown")
1.1       root      160: 
                    161:     def _rightrelease_cb(self, widget):
1.1.1.4   root      162:         self.hatari.insert_event("rightup")
1.1       root      163: 
                    164:     def run(self, hatari):
                    165:         "run(hatari), do text/mouse click input"
                    166:         self.hatari = hatari
                    167:         self.dialog.run()
                    168:         self.dialog.hide()
                    169: 
                    170: 
                    171: # ---------------------------
                    172: # Quit and Save dialog
                    173: 
                    174: class QuitSaveDialog(HatariUIDialog):
                    175:     def __init__(self, parent):
1.1.1.13! root      176:         dialog = Gtk.Dialog("Quit and Save?", parent,
        !           177:             Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
        !           178:             ("Save changes",    Gtk.ResponseType.YES,
        !           179:              "Discard changes", Gtk.ResponseType.NO,
        !           180:              Gtk.STOCK_CANCEL,  Gtk.ResponseType.CANCEL))
        !           181:         dialog.vbox.add(Gtk.Label(label="You have unsaved configuration changes:"))
        !           182:         viewport = Gtk.Viewport()
        !           183:         viewport.add(Gtk.Label())
        !           184:         scrolledwindow = Gtk.ScrolledWindow()
        !           185:         scrolledwindow.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
1.1       root      186:         scrolledwindow.add(viewport)
                    187:         dialog.vbox.add(scrolledwindow)
                    188:         dialog.show_all()
                    189:         self.scrolledwindow = scrolledwindow
                    190:         self.viewport = viewport
                    191:         self.dialog = dialog
1.1.1.13! root      192: 
1.1       root      193:     def run(self, config):
                    194:         "run(config) -> False if canceled, True otherwise or if no changes"
                    195:         changes = []
                    196:         for key, value in config.get_changes():
                    197:             changes.append("%s = %s" % (key, str(value)))
                    198:         if not changes:
                    199:             return True
                    200:         child = self.viewport.get_child()
                    201:         child.set_text(config.get_path() + ":\n" + "\n".join(changes))
                    202:         width, height = child.get_size_request()
                    203:         if height < 320:
                    204:             self.scrolledwindow.set_size_request(width, height)
                    205:         else:
                    206:             self.scrolledwindow.set_size_request(-1, 320)
                    207:         self.viewport.show_all()
1.1.1.13! root      208: 
1.1       root      209:         response = self.dialog.run()
                    210:         self.dialog.hide()
1.1.1.13! root      211:         if response == Gtk.ResponseType.CANCEL:
1.1       root      212:             return False
1.1.1.13! root      213:         if response == Gtk.ResponseType.YES:
1.1       root      214:             config.save()
                    215:         return True
                    216: 
                    217: 
                    218: # ---------------------------
                    219: # Kill Hatari dialog
                    220: 
                    221: class KillDialog(HatariUIDialog):
                    222:     def __init__(self, parent):
1.1.1.13! root      223:         self.dialog = Gtk.MessageDialog(parent,
        !           224:         Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
        !           225:         Gtk.MessageType.QUESTION, Gtk.ButtonsType.OK_CANCEL,
1.1       root      226:         """\
                    227: Hatari emulator is already/still running and it needs to be terminated first. However, if it contains unsaved data, that will be lost.
                    228: 
                    229: Terminate Hatari anyway?""")
                    230: 
                    231:     def run(self, hatari):
                    232:         "run(hatari) -> True if Hatari killed, False if left running"
                    233:         if not hatari.is_running():
                    234:             return True
                    235:         # Hatari is running, OK to kill?
                    236:         response = self.dialog.run()
                    237:         self.dialog.hide()
1.1.1.13! root      238:         if response == Gtk.ResponseType.OK:
1.1       root      239:             hatari.kill()
                    240:             return True
                    241:         return False
                    242: 
1.1.1.13! root      243: 
1.1       root      244: # ---------------------------
                    245: # Reset Hatari dialog
                    246: 
                    247: class ResetDialog(HatariUIDialog):
                    248:     COLD = 1
                    249:     WARM = 2
                    250:     def __init__(self, parent):
1.1.1.13! root      251:         self.dialog = Gtk.Dialog("Reset Atari?", parent,
        !           252:             Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
1.1       root      253:             ("Cold reset", self.COLD, "Warm reset", self.WARM,
1.1.1.13! root      254:              Gtk.STOCK_CANCEL,  Gtk.ResponseType.CANCEL))
        !           255:         label = Gtk.Label(label="\nRebooting will lose changes in currently\nrunning Atari programs.\n\nReset anyway?\n")
1.1       root      256:         self.dialog.vbox.add(label)
                    257:         label.show()
                    258: 
                    259:     def run(self, hatari):
                    260:         "run(hatari) -> True if Hatari rebooted, False if canceled"
                    261:         if not hatari.is_running():
                    262:             return False
                    263:         # Hatari is running, how to reboot?
                    264:         response = self.dialog.run()
                    265:         self.dialog.hide()
                    266:         if response == self.COLD:
                    267:             hatari.trigger_shortcut("coldreset")
                    268:         elif response == self.WARM:
                    269:             hatari.trigger_shortcut("warmreset")
                    270:         else:
                    271:             return False
                    272:         return True
                    273: 
                    274: 
                    275: # ----------------------------------
                    276: # Floppy image dialog
                    277: 
1.1.1.3   root      278: class FloppyDialog(HatariUIDialog):
1.1       root      279:     def _create_dialog(self, config):
1.1.1.3   root      280:         table, self.dialog = create_table_dialog(self.parent, "Floppy images", 4, 2)
1.1.1.4   root      281:         factory = FselAndEjectFactory()
1.1.1.3   root      282: 
1.1       root      283:         row = 0
                    284:         self.floppy = []
                    285:         path = config.get_floppydir()
                    286:         for drive in ("A", "B"):
1.1.1.9   root      287:             label = "Disk %c image:" % drive
1.1.1.4   root      288:             fname = config.get_floppy(row)
1.1.1.13! root      289:             fsel, box = factory.get(label, path, fname, Gtk.FileChooserAction.OPEN)
        !           290:             table_add_widget_row(table, row, 0, label, box)
1.1.1.4   root      291:             self.floppy.append(fsel)
1.1       root      292:             row += 1
                    293: 
1.1.1.13! root      294:         protect = Gtk.ComboBoxText()
1.1.1.3   root      295:         for text in config.get_protection_types():
                    296:             protect.append_text(text)
                    297:         protect.set_active(config.get_floppy_protection())
1.1.1.4   root      298:         protect.set_tooltip_text("Write protect floppy image contents")
1.1.1.13! root      299:         table_add_widget_row(table, row, 0, "Write protection:", protect)
1.1.1.9   root      300:         row += 1
1.1.1.3   root      301: 
1.1.1.13! root      302:         ds = Gtk.CheckButton("Double sided drives")
1.1.1.9   root      303:         ds.set_active(config.get_doublesided())
                    304:         ds.set_tooltip_text("Whether drives are double or single sided. Can affect behavior of some games")
1.1.1.13! root      305:         table_add_widget_row(table, row, 0, None, ds)
1.1.1.9   root      306:         row += 1
1.1.1.13! root      307: 
        !           308:         driveb = Gtk.CheckButton("Drive B connected")
1.1.1.9   root      309:         driveb.set_active(config.get_floppy_drives()[1])
                    310:         driveb.set_tooltip_text("Wheter drive B is connected. Can affect behavior of some demos & games")
1.1.1.13! root      311:         table_add_widget_row(table, row, 0, None, driveb)
1.1.1.3   root      312:         row += 1
1.1.1.9   root      313: 
1.1.1.13! root      314:         fastfdc = Gtk.CheckButton("Fast floppy access")
1.1.1.5   root      315:         fastfdc.set_active(config.get_fastfdc())
1.1.1.6   root      316:         fastfdc.set_tooltip_text("Can cause incompatibilities with some games/demos")
1.1.1.13! root      317:         table_add_widget_row(table, row, 0, None, fastfdc)
1.1.1.3   root      318: 
1.1       root      319:         table.show_all()
                    320: 
1.1.1.3   root      321:         self.protect = protect
1.1.1.5   root      322:         self.fastfdc = fastfdc
1.1.1.9   root      323:         self.driveb = driveb
                    324:         self.ds = ds
1.1.1.13! root      325: 
1.1       root      326:     def run(self, config):
                    327:         "run(config), show disk image dialog"
                    328:         if not self.dialog:
                    329:             self._create_dialog(config)
                    330:         response = self.dialog.run()
                    331:         self.dialog.hide()
1.1.1.13! root      332: 
        !           333:         if response == Gtk.ResponseType.APPLY:
1.1       root      334:             config.lock_updates()
                    335:             for drive in range(2):
                    336:                 config.set_floppy(drive, self.floppy[drive].get_filename())
1.1.1.4   root      337:             config.set_floppy_protection(self.protect.get_active())
1.1.1.9   root      338:             config.set_doublesided(self.ds.get_active())
1.1.1.5   root      339:             config.set_fastfdc(self.fastfdc.get_active())
1.1.1.9   root      340:             drives = (config.get_floppy_drives()[0], self.driveb.get_active())
                    341:             config.set_floppy_drives(drives)
1.1       root      342:             config.flush_updates()
                    343: 
1.1.1.3   root      344: 
                    345: # ----------------------------------
                    346: # Hard disk dialog
                    347: 
                    348: class HardDiskDialog(HatariUIDialog):
                    349:     def _create_dialog(self, config):
                    350:         table, self.dialog = create_table_dialog(self.parent, "Hard disks", 4, 4, "Set and reboot")
1.1.1.4   root      351:         factory = FselAndEjectFactory()
1.1.1.3   root      352: 
1.1.1.4   root      353:         row = 0
1.1.1.3   root      354:         label = "ASCI HD image:"
                    355:         path = config.get_acsi_image()
1.1.1.13! root      356:         fsel, box = factory.get(label, None, path, Gtk.FileChooserAction.OPEN)
        !           357:         table_add_widget_row(table, row, 0, label, box, True)
1.1.1.3   root      358:         self.acsi = fsel
                    359:         row += 1
                    360: 
                    361:         label = "IDE HD master image:"
                    362:         path = config.get_idemaster_image()
1.1.1.13! root      363:         fsel, box = factory.get(label, None, path, Gtk.FileChooserAction.OPEN)
        !           364:         table_add_widget_row(table, row, 0, label, box, True)
1.1.1.3   root      365:         self.idemaster = fsel
                    366:         row += 1
                    367: 
                    368:         label = "IDE HD slave image:"
                    369:         path = config.get_ideslave_image()
1.1.1.13! root      370:         fsel, box = factory.get(label, None, path, Gtk.FileChooserAction.OPEN)
        !           371:         table_add_widget_row(table, row, 0, label, box, True)
1.1.1.3   root      372:         self.ideslave = fsel
                    373:         row += 1
1.1.1.10  root      374: 
1.1.1.13! root      375:         table_add_widget_row(table, row, 0, " ", Gtk.HSeparator(), True)
1.1.1.10  root      376:         row += 1
                    377: 
1.1.1.3   root      378:         label = "GEMDOS drive directory:"
1.1.1.10  root      379:         path = config.get_hd_dir()
1.1.1.13! root      380:         fsel, box = factory.get(label, None, path, Gtk.FileChooserAction.SELECT_FOLDER)
        !           381:         table_add_widget_row(table, row, 0, label, box, True)
1.1.1.10  root      382:         self.hddir = fsel
                    383:         row += 1
                    384: 
1.1.1.13! root      385:         hddrive = Gtk.ComboBoxText()
1.1.1.10  root      386:         for text in config.get_hd_drives():
                    387:             hddrive.append_text(text)
                    388:         hddrive.set_tooltip_text("Whether GEMDOS HD emulation uses fixed drive letter, or first free drive letter after ASCI & IDE drives (detection unreliable)")
1.1.1.13! root      389:         table_add_widget_row(table, row, 0, "GEMDOS HD drive:", hddrive)
1.1.1.10  root      390:         self.hddrive = hddrive
1.1.1.3   root      391:         row += 1
                    392: 
1.1.1.13! root      393:         protect = Gtk.ComboBoxText()
1.1.1.3   root      394:         for text in config.get_protection_types():
                    395:             protect.append_text(text)
1.1.1.9   root      396:         protect.set_tooltip_text("Whether/how to write protect (GEMDOS HD) emulation files, 'auto' means using host files' own properties")
1.1.1.13! root      397:         table_add_widget_row(table, row, 0, "Write protection:", protect)
1.1.1.3   root      398:         self.protect = protect
1.1.1.9   root      399:         row += 1
1.1.1.13! root      400: 
        !           401:         lower = Gtk.ComboBoxText()
1.1.1.9   root      402:         for text in config.get_hd_cases():
                    403:             lower.append_text(text)
                    404:         lower.set_tooltip_text("What to do with names of files created by Atari programs through GEMDOS HD emulation")
1.1.1.13! root      405:         table_add_widget_row(table, row, 0, "File names:", lower)
1.1.1.9   root      406:         self.lower = lower
1.1.1.3   root      407: 
                    408:         table.show_all()
1.1.1.13! root      409: 
1.1.1.3   root      410:     def _get_config(self, config):
                    411:         path = config.get_acsi_image()
                    412:         if path:
                    413:             self.acsi.set_filename(path)
                    414:         path = config.get_idemaster_image()
                    415:         if path:
                    416:             self.idemaster.set_filename(path)
                    417:         path = config.get_ideslave_image()
                    418:         if path:
                    419:             self.ideslave.set_filename(path)
1.1.1.10  root      420:         path = config.get_hd_dir()
                    421:         if path:
                    422:             self.hddir.set_filename(path)
                    423:         self.hddrive.set_active(config.get_hd_drive())
1.1.1.3   root      424:         self.protect.set_active(config.get_hd_protection())
1.1.1.9   root      425:         self.lower.set_active(config.get_hd_case())
                    426: 
1.1.1.3   root      427:     def _set_config(self, config):
                    428:         config.lock_updates()
                    429:         config.set_acsi_image(self.acsi.get_filename())
                    430:         config.set_idemaster_image(self.idemaster.get_filename())
                    431:         config.set_ideslave_image(self.ideslave.get_filename())
1.1.1.10  root      432:         config.set_hd_dir(self.hddir.get_filename())
                    433:         config.set_hd_drive(self.hddrive.get_active())
1.1.1.3   root      434:         config.set_hd_protection(self.protect.get_active())
1.1.1.9   root      435:         config.set_hd_case(self.lower.get_active())
1.1.1.3   root      436:         config.flush_updates()
                    437: 
                    438:     def run(self, config):
                    439:         "run(config) -> bool, whether to reboot"
                    440:         if not self.dialog:
                    441:             self._create_dialog(config)
                    442: 
                    443:         self._get_config(config)
                    444:         response = self.dialog.run()
                    445:         self.dialog.hide()
1.1.1.13! root      446:         if response == Gtk.ResponseType.APPLY:
1.1.1.3   root      447:             self._set_config(config)
                    448:             return True
                    449:         return False
                    450: 
                    451: 
1.1       root      452: # ---------------------------
                    453: # Display dialog
                    454: 
                    455: class DisplayDialog(HatariUIDialog):
                    456: 
                    457:     def _create_dialog(self, config):
                    458: 
1.1.1.13! root      459:         skip = Gtk.ComboBoxText()
1.1       root      460:         for text in config.get_frameskip_names():
                    461:             skip.append_text(text)
                    462:         skip.set_active(config.get_frameskip())
1.1.1.9   root      463:         skip.set_tooltip_text("Set how many frames are skipped to speed up emulation")
                    464: 
1.1.1.13! root      465:         slow = Gtk.ComboBoxText()
1.1.1.9   root      466:         for text in config.get_slowdown_names():
                    467:             slow.append_text(text)
                    468:         slow.set_active(0)
                    469:         slow.set_tooltip_text("VBL wait multiplier to slow down emulation. Breaks sound and large enough slowdown causes mouse clicks not to work.")
1.1       root      470: 
1.1.1.3   root      471:         maxw, maxh = config.get_max_size()
1.1.1.6   root      472:         topw, toph = config.get_desktop_size()
1.1.1.13! root      473:         maxadjw = Gtk.Adjustment(maxw, 320, topw, 8, 40)
        !           474:         maxadjh = Gtk.Adjustment(maxh, 200, toph, 8, 40)
        !           475:         scalew = Gtk.HScale(adjustment=maxadjw)
        !           476:         scaleh = Gtk.HScale(adjustment=maxadjh)
1.1.1.3   root      477:         scalew.set_digits(0)
                    478:         scaleh.set_digits(0)
1.1.1.4   root      479:         scalew.set_tooltip_text("Preferred/maximum zoomed width")
                    480:         scaleh.set_tooltip_text("Preferred/maximum zoomed height")
                    481: 
1.1.1.13! root      482:         force_max = Gtk.CheckButton("Force max resolution (Falcon)")
1.1.1.7   root      483:         force_max.set_active(config.get_force_max())
                    484:         force_max.set_tooltip_text("Whether to force maximum resolution to help recording videos of demos which do resolution changes")
                    485: 
1.1.1.13! root      486:         desktop = Gtk.CheckButton("Keep desktop resolution, scales")
1.1.1.4   root      487:         desktop.set_active(config.get_desktop())
1.1.1.13! root      488:         desktop.set_tooltip_text("Whether to keep screen resolution in fullscreen. With SDL1, only applies to Falcon/TT and scales Atari screen by an integer factor. Avoids potential monitor res switch delay & sound skips")
1.1.1.7   root      489: 
1.1.1.13! root      490:         desktop_st = Gtk.CheckButton("Keep desktop resolution, NO scaling")
1.1.1.7   root      491:         desktop_st.set_active(config.get_desktop_st())
1.1.1.13! root      492:         desktop_st.set_tooltip_text("SDL1 / ST & STE only. Whether to keep screen resolution in fullscreen. Avoids potential monitor res switch delay & sound skips")
1.1       root      493: 
1.1.1.13! root      494:         borders = Gtk.CheckButton("Atari screen borders")
1.1       root      495:         borders.set_active(config.get_borders())
1.1.1.7   root      496:         borders.set_tooltip_text("Whether to show overscan borders in ST/STE low/mid-rez or in Falcon color resolutions. Visible border area is affected by max. zoom size")
1.1       root      497: 
1.1.1.13! root      498:         statusbar = Gtk.CheckButton("Show statusbar")
1.1       root      499:         statusbar.set_active(config.get_statusbar())
1.1.1.4   root      500:         statusbar.set_tooltip_text("Whether to show statusbar with floppy leds etc")
1.1       root      501: 
1.1.1.13! root      502:         led = Gtk.CheckButton("Show overlay led")
1.1       root      503:         led.set_active(config.get_led())
1.1.1.4   root      504:         led.set_tooltip_text("Whether to show overlay drive led when statusbar isn't visible")
                    505: 
1.1.1.13! root      506:         crop = Gtk.CheckButton("Remove statusbar from screen capture")
1.1.1.4   root      507:         crop.set_active(config.get_crop())
                    508:         crop.set_tooltip_text("Whether to crop statusbar from screenshots and video recordings")
1.1       root      509: 
1.1.1.13! root      510:         dialog = Gtk.Dialog("Display settings", self.parent,
        !           511:             Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
        !           512:             (Gtk.STOCK_APPLY,  Gtk.ResponseType.APPLY,
        !           513:              Gtk.STOCK_CANCEL,  Gtk.ResponseType.CANCEL))
1.1       root      514: 
1.1.1.13! root      515:         dialog.vbox.add(Gtk.Label(label="Max zoomed size:"))
1.1.1.3   root      516:         dialog.vbox.add(scalew)
                    517:         dialog.vbox.add(scaleh)
1.1.1.7   root      518:         dialog.vbox.add(force_max)
1.1.1.4   root      519:         dialog.vbox.add(desktop)
1.1.1.7   root      520:         dialog.vbox.add(desktop_st)
1.1       root      521:         dialog.vbox.add(borders)
1.1.1.13! root      522:         dialog.vbox.add(Gtk.Label(label="Frameskip:"))
1.1.1.9   root      523:         dialog.vbox.add(skip)
1.1.1.13! root      524:         dialog.vbox.add(Gtk.Label(label="Slowdown:"))
1.1.1.9   root      525:         dialog.vbox.add(slow)
1.1       root      526:         dialog.vbox.add(statusbar)
                    527:         dialog.vbox.add(led)
1.1.1.4   root      528:         dialog.vbox.add(crop)
1.1       root      529:         dialog.vbox.show_all()
                    530: 
                    531:         self.dialog = dialog
                    532:         self.skip = skip
1.1.1.9   root      533:         self.slow = slow
1.1.1.3   root      534:         self.maxw = maxadjw
                    535:         self.maxh = maxadjh
1.1.1.7   root      536:         self.force_max = force_max
1.1.1.4   root      537:         self.desktop = desktop
1.1.1.7   root      538:         self.desktop_st = desktop_st
1.1       root      539:         self.borders = borders
                    540:         self.statusbar = statusbar
                    541:         self.led = led
1.1.1.4   root      542:         self.crop = crop
1.1.1.13! root      543: 
1.1       root      544:     def run(self, config):
                    545:         "run(config), show display dialog"
                    546:         if not self.dialog:
                    547:             self._create_dialog(config)
                    548:         response = self.dialog.run()
                    549:         self.dialog.hide()
1.1.1.13! root      550:         if response == Gtk.ResponseType.APPLY:
1.1       root      551:             config.lock_updates()
                    552:             config.set_frameskip(self.skip.get_active())
1.1.1.9   root      553:             config.set_slowdown(self.slow.get_active())
1.1.1.3   root      554:             config.set_max_size(self.maxw.get_value(), self.maxh.get_value())
1.1.1.7   root      555:             config.set_force_max(self.force_max.get_active())
1.1.1.4   root      556:             config.set_desktop(self.desktop.get_active())
1.1.1.7   root      557:             config.set_desktop_st(self.desktop_st.get_active())
1.1       root      558:             config.set_borders(self.borders.get_active())
                    559:             config.set_statusbar(self.statusbar.get_active())
                    560:             config.set_led(self.led.get_active())
1.1.1.4   root      561:             config.set_crop(self.crop.get_active())
1.1       root      562:             config.flush_updates()
                    563: 
                    564: 
                    565: # ----------------------------------
                    566: # Joystick dialog
                    567: 
                    568: class JoystickDialog(HatariUIDialog):
                    569:     def _create_dialog(self, config):
1.1.1.3   root      570:         table, self.dialog = create_table_dialog(self.parent, "Joystick settings", 9, 2)
1.1.1.13! root      571: 
1.1       root      572:         joy = 0
                    573:         self.joy = []
                    574:         joytypes = config.get_joystick_types()
                    575:         for label in config.get_joystick_names():
1.1.1.13! root      576:             combo = Gtk.ComboBoxText()
1.1       root      577:             for text in joytypes:
                    578:                 combo.append_text(text)
                    579:             combo.set_active(config.get_joystick(joy))
1.1.1.13! root      580:             widget = table_add_widget_row(table, joy, 0, "%s:" % label, combo)
1.1       root      581:             self.joy.append(widget)
                    582:             joy += 1
                    583: 
                    584:         table.show_all()
1.1.1.13! root      585: 
1.1       root      586:     def run(self, config):
                    587:         "run(config), show joystick dialog"
                    588:         if not self.dialog:
                    589:             self._create_dialog(config)
                    590:         response = self.dialog.run()
                    591:         self.dialog.hide()
1.1.1.13! root      592: 
        !           593:         if response == Gtk.ResponseType.APPLY:
1.1       root      594:             config.lock_updates()
                    595:             for joy in range(6):
                    596:                 config.set_joystick(joy, self.joy[joy].get_active())
                    597:             config.flush_updates()
                    598: 
                    599: 
                    600: # ---------------------------------------
                    601: # Peripherals (midi,printer,rs232) dialog
                    602: 
                    603: class PeripheralDialog(HatariUIDialog):
                    604:     def _create_dialog(self, config):
1.1.1.13! root      605:         midi = Gtk.CheckButton("Enable MIDI")
1.1       root      606:         midi.set_active(config.get_midi())
                    607: 
1.1.1.13! root      608:         printer = Gtk.CheckButton("Enable printer output")
1.1       root      609:         printer.set_active(config.get_printer())
                    610: 
1.1.1.13! root      611:         rs232 = Gtk.CheckButton("Enable MFP RS232 (ST/MegaST/STE/MegaSTE/TT)")
1.1       root      612:         rs232.set_active(config.get_rs232())
                    613: 
1.1.1.13! root      614:         sccb = Gtk.CheckButton("Enable SCC-B RS232 output (MegaSTE/TT/Falcon")
        !           615:         sccb.set_active(config.get_sccb())
        !           616: 
        !           617:         dialog = Gtk.Dialog("Peripherals", self.parent,
        !           618:             Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
        !           619:             (Gtk.STOCK_APPLY,  Gtk.ResponseType.APPLY,
        !           620:              Gtk.STOCK_CANCEL,  Gtk.ResponseType.CANCEL))
1.1       root      621:         dialog.vbox.add(midi)
                    622:         dialog.vbox.add(printer)
                    623:         dialog.vbox.add(rs232)
1.1.1.13! root      624:         dialog.vbox.add(sccb)
1.1       root      625:         dialog.vbox.show_all()
                    626: 
                    627:         self.dialog = dialog
                    628:         self.printer = printer
                    629:         self.rs232 = rs232
1.1.1.13! root      630:         self.sccb = sccb
1.1       root      631:         self.midi = midi
1.1.1.13! root      632: 
1.1       root      633:     def run(self, config):
                    634:         "run(config), show peripherals dialog"
                    635:         if not self.dialog:
                    636:             self._create_dialog(config)
                    637:         response = self.dialog.run()
                    638:         self.dialog.hide()
1.1.1.13! root      639: 
        !           640:         if response == Gtk.ResponseType.APPLY:
1.1       root      641:             config.lock_updates()
                    642:             config.set_midi(self.midi.get_active())
                    643:             config.set_printer(self.printer.get_active())
                    644:             config.set_rs232(self.rs232.get_active())
1.1.1.13! root      645:             config.set_sccb(self.sccb.get_active())
1.1       root      646:             config.flush_updates()
                    647: 
                    648: 
                    649: # ---------------------------------------
                    650: # Path dialog
                    651: 
                    652: class PathDialog(HatariUIDialog):
                    653:     def _create_dialog(self, config):
                    654:         paths = config.get_paths()
1.1.1.3   root      655:         table, self.dialog = create_table_dialog(self.parent, "File path settings", len(paths), 2)
1.1       root      656:         paths.sort()
                    657:         row = 0
                    658:         self.paths = []
                    659:         for (key, path, label) in paths:
                    660:             fsel = FselEntry(self.dialog, self._validate_fname, key)
                    661:             fsel.set_filename(path)
                    662:             self.paths.append((key, fsel))
1.1.1.13! root      663:             table_add_widget_row(table, row, 0, label, fsel.get_container())
1.1       root      664:             row += 1
                    665:         table.show_all()
1.1.1.13! root      666: 
1.1       root      667:     def _validate_fname(self, key, fname):
                    668:         if key != "soundout":
                    669:             return True
                    670:         if fname.rsplit(".", 1)[-1].lower() in ("ym", "wav"):
                    671:             return True
                    672:         ErrorDialog(self.dialog).run("Sound output file name:\n\t%s\nneeds to end with '.ym' or '.wav'." % fname)
                    673:         return False
1.1.1.13! root      674: 
1.1       root      675:     def run(self, config):
                    676:         "run(config), show paths dialog"
                    677:         if not self.dialog:
                    678:             self._create_dialog(config)
                    679:         response = self.dialog.run()
                    680:         self.dialog.hide()
                    681: 
1.1.1.13! root      682:         if response == Gtk.ResponseType.APPLY:
1.1       root      683:             paths = []
                    684:             for key, fsel in self.paths:
                    685:                 paths.append((key, fsel.get_filename()))
                    686:             config.set_paths(paths)
                    687: 
                    688: 
                    689: # ---------------------------
                    690: # Sound dialog
                    691: 
                    692: class SoundDialog(HatariUIDialog):
                    693: 
                    694:     def _create_dialog(self, config):
1.1.1.6   root      695:         enabled, curhz = config.get_sound()
                    696: 
1.1.1.13! root      697:         self.enabled = Gtk.CheckButton("Sound enabled")
1.1       root      698:         self.enabled.set_active(enabled)
1.1.1.6   root      699: 
1.1.1.13! root      700:         hz = Gtk.ComboBoxText()
1.1.1.6   root      701:         for text in config.get_sound_values():
                    702:             hz.append_text(text)
                    703:         hz.set_active(curhz)
                    704:         self.hz = hz
                    705: 
1.1.1.13! root      706:         ymmixer = Gtk.ComboBoxText()
1.1.1.6   root      707:         for text in config.get_ymmixer_types():
                    708:             ymmixer.append_text(text)
                    709:         ymmixer.set_active(config.get_ymmixer())
                    710:         self.ymmixer = ymmixer
                    711: 
1.1.1.13! root      712:         adj = Gtk.Adjustment(config.get_bufsize(), 0, 110, 10, 10, 10)
        !           713:         bufsize = Gtk.HScale(adjustment=adj)
1.1.1.9   root      714:         bufsize.set_digits(0)
                    715:         bufsize.set_tooltip_text("0 = use default value. In some situations, SDL default may cause large (~0.5s) sound delay at lower frequency.  If you have this problem, try with e.g. 20 ms, otherwise keep at 0.")
                    716:         self.bufsize = bufsize
                    717: 
1.1.1.13! root      718:         self.sync = Gtk.CheckButton("Emulation speed synched to sound output")
1.1.1.9   root      719:         self.sync.set_tooltip_text("Constantly adjust emulation screen update rate to match sound output. Can help if you suffer from sound buffer under/overflow.")
                    720:         self.sync.set_active(config.get_sync())
                    721: 
1.1.1.13! root      722:         self.mic = Gtk.CheckButton("Enable (Falcon) microphone")
1.1.1.6   root      723:         self.mic.set_active(config.get_mic())
1.1       root      724: 
1.1.1.13! root      725:         dialog = Gtk.Dialog("Sound settings", self.parent,
        !           726:             Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
        !           727:             (Gtk.STOCK_APPLY,  Gtk.ResponseType.APPLY,
        !           728:              Gtk.STOCK_CANCEL,  Gtk.ResponseType.CANCEL))
1.1       root      729:         dialog.vbox.add(self.enabled)
1.1.1.13! root      730:         dialog.vbox.add(Gtk.Label(label="Sound frequency:"))
1.1.1.6   root      731:         dialog.vbox.add(hz)
1.1.1.13! root      732:         dialog.vbox.add(Gtk.Label(label="YM voices mixing method:"))
1.1.1.6   root      733:         dialog.vbox.add(ymmixer)
1.1.1.13! root      734:         dialog.vbox.add(Gtk.Label(label="SDL sound buffer size (ms):"))
1.1.1.9   root      735:         dialog.vbox.add(bufsize)
                    736:         dialog.vbox.add(self.sync)
1.1.1.6   root      737:         dialog.vbox.add(self.mic)
1.1       root      738:         dialog.vbox.show_all()
                    739:         self.dialog = dialog
                    740: 
                    741:     def run(self, config):
                    742:         "run(config), show sound dialog"
                    743:         if not self.dialog:
                    744:             self._create_dialog(config)
                    745:         response = self.dialog.run()
                    746:         self.dialog.hide()
1.1.1.13! root      747:         if response == Gtk.ResponseType.APPLY:
1.1.1.6   root      748:             config.lock_updates()
                    749:             config.set_mic(self.mic.get_active())
1.1.1.9   root      750:             config.set_sync(self.sync.get_active())
                    751:             config.set_bufsize(self.bufsize.get_value())
1.1.1.6   root      752:             config.set_ymmixer(self.ymmixer.get_active())
1.1       root      753:             enabled = self.enabled.get_active()
1.1.1.6   root      754:             hz = self.hz.get_active()
                    755:             config.set_sound(enabled, hz)
                    756:             config.flush_updates()
1.1.1.13! root      757: 
1.1       root      758: 
                    759: # ---------------------------
                    760: # Trace settings dialog
                    761: 
                    762: class TraceDialog(HatariUIDialog):
                    763:     # you can get this list with:
                    764:     # hatari --trace help 2>&1|awk '/all$/{next} /^  [^-]/ {printf("\"%s\",\n", $1)}'
                    765:     tracepoints = [
                    766:         "video_sync",
                    767:         "video_res",
                    768:         "video_color",
                    769:         "video_border_v",
                    770:         "video_border_h",
                    771:         "video_addr",
                    772:         "video_hbl",
                    773:         "video_vbl",
                    774:         "video_ste",
                    775:         "mfp_exception",
                    776:         "mfp_start",
                    777:         "mfp_read",
                    778:         "mfp_write",
1.1.1.4   root      779:         "psg_read",
                    780:         "psg_write",
1.1       root      781:         "cpu_pairing",
                    782:         "cpu_disasm",
                    783:         "cpu_exception",
                    784:         "int",
                    785:         "fdc",
1.1.1.8   root      786:         "acia",
1.1       root      787:         "ikbd_cmds",
                    788:         "ikbd_acia",
                    789:         "ikbd_exec",
                    790:         "blitter",
                    791:         "bios",
                    792:         "xbios",
                    793:         "gemdos",
                    794:         "vdi",
1.1.1.4   root      795:         "aes",
1.1       root      796:         "io_read",
                    797:         "io_write",
1.1.1.4   root      798:         "dmasound",
                    799:         "crossbar",
                    800:         "videl",
                    801:         "dsp_host_interface",
                    802:         "dsp_host_command",
                    803:         "dsp_host_ssi",
                    804:         "dsp_interrupt",
                    805:         "dsp_disasm",
1.1.1.8   root      806:         "dsp_disasm_reg",
                    807:         "dsp_disasm_mem",
                    808:         "dsp_state",
                    809:         "dsp_symbols",
                    810:         "cpu_symbols",
1.1.1.9   root      811:         "nvram",
                    812:         "scsi_cmd",
                    813:         "natfeats",
1.1.1.10  root      814:         "keymap",
                    815:         "midi",
                    816:         "ide",
1.1.1.11  root      817:         "os_base",
                    818:         "scsidrv"
1.1       root      819:     ]
                    820:     def __init__(self, parent):
1.1.1.6   root      821:         self.savedpoints = None
1.1.1.13! root      822:         hbox1 = Gtk.HBox()
1.1       root      823:         hbox1.add(create_button("Load", self._load_traces))
                    824:         hbox1.add(create_button("Clear", self._clear_traces))
                    825:         hbox1.add(create_button("Save", self._save_traces))
1.1.1.13! root      826:         hbox2 = Gtk.HBox()
1.1       root      827:         vboxes = []
1.1.1.4   root      828:         for idx in (0,1,2,3):
1.1.1.13! root      829:             vboxes.append(Gtk.VBox())
1.1       root      830:             hbox2.add(vboxes[idx])
                    831: 
                    832:         count = 0
1.1.1.13! root      833:         per_side = (len(self.tracepoints)+3)//4
1.1       root      834:         self.tracewidgets = {}
                    835:         for trace in self.tracepoints:
1.1.1.2   root      836:             name = trace.replace("_", "-")
1.1.1.13! root      837:             widget = Gtk.CheckButton(name)
1.1       root      838:             self.tracewidgets[trace] = widget
1.1.1.13! root      839:             vboxes[count//per_side].pack_start(widget, False, True, 0)
1.1       root      840:             count += 1
1.1.1.13! root      841: 
        !           842:         dialog = Gtk.Dialog("Trace settings", parent,
        !           843:             Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
        !           844:             (Gtk.STOCK_APPLY,  Gtk.ResponseType.APPLY,
        !           845:              Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE))
1.1       root      846:         dialog.vbox.add(hbox1)
1.1.1.13! root      847:         dialog.vbox.add(Gtk.Label(label="Select trace points:"))
1.1       root      848:         dialog.vbox.add(hbox2)
                    849:         dialog.vbox.show_all()
                    850:         self.dialog = dialog
                    851: 
                    852:     def _get_traces(self):
                    853:         traces = []
                    854:         for trace in self.tracepoints:
                    855:             if self.tracewidgets[trace].get_active():
                    856:                 traces.append(trace)
                    857:         if traces:
                    858:             return ",".join(traces)
                    859:         return "none"
                    860: 
                    861:     def _set_traces(self, tracepoints):
                    862:         self._clear_traces()
1.1.1.6   root      863:         if not tracepoints:
                    864:             return
1.1       root      865:         for trace in tracepoints.split(","):
                    866:             if trace in self.tracewidgets:
                    867:                 self.tracewidgets[trace].set_active(True)
                    868:             else:
1.1.1.4   root      869:                 print("ERROR: unknown trace setting '%s'" % trace)
1.1       root      870: 
                    871:     def _clear_traces(self, widget = None):
                    872:         for trace in self.tracepoints:
                    873:             self.tracewidgets[trace].set_active(False)
                    874: 
                    875:     def _load_traces(self, widget):
                    876:         # this doesn't load traces, just sets them from internal variable
                    877:         # that run method gets from caller and sets. It's up to caller
                    878:         # whether the saving or loading happens actually to disk
                    879:         self._set_traces(self.savedpoints)
1.1.1.13! root      880: 
1.1       root      881:     def _save_traces(self, widget):
                    882:         self.savedpoints = self._get_traces()
                    883: 
                    884:     def run(self, hatari, savedpoints):
                    885:         "run(hatari,tracepoints) -> tracepoints, caller saves tracepoints"
                    886:         self.savedpoints = savedpoints
                    887:         while 1:
                    888:             response = self.dialog.run()
1.1.1.13! root      889:             if response == Gtk.ResponseType.APPLY:
1.1       root      890:                 hatari.change_option("--trace %s" % self._get_traces())
                    891:             else:
                    892:                 self.dialog.hide()
                    893:                 return self.savedpoints
                    894: 
                    895: 
                    896: # ------------------------------------------
                    897: # Machine dialog for settings needing reboot
                    898: 
                    899: class MachineDialog(HatariUIDialog):
1.1.1.3   root      900:     def _machine_cb(self, widget, data):
                    901:         if not widget.get_active():
                    902:             return
                    903:         machine = data.lower()
                    904:         if machine == "ste" or machine == "st":
                    905:             self.clocks[0].set_active(True)
                    906:             self.cpulevel.set_active(0)
                    907:         elif machine == "falcon":
                    908:             self.clocks[1].set_active(True)
1.1.1.4   root      909:             self.dsps[2].set_active(True)
1.1.1.3   root      910:             self.cpulevel.set_active(3)
                    911:         elif machine == "tt":
                    912:             self.clocks[2].set_active(True)
                    913:             self.cpulevel.set_active(3)
                    914: 
1.1       root      915:     def _create_dialog(self, config):
1.1.1.3   root      916:         table, self.dialog = create_table_dialog(self.parent, "Machine configuration", 6, 4, "Set and reboot")
1.1.1.13! root      917: 
        !           918:         col = 0
1.1.1.3   root      919:         row = 0
1.1.1.13! root      920:         self.machines = table_add_radio_rows(table, row, col, "Machine:",
1.1.1.3   root      921:                         config.get_machine_types(), self._machine_cb)
                    922:         row += 1
1.1       root      923: 
1.1.1.13! root      924:         self.dsps = table_add_radio_rows(table, row, col, "DSP type:", config.get_dsp_types())
1.1.1.3   root      925:         row += 1
                    926: 
                    927:         # start next table column
1.1.1.13! root      928:         col = 2
1.1       root      929:         row = 0
1.1.1.13! root      930:         self.monitors = table_add_radio_rows(table, row, col, "Monitor:", config.get_monitor_types())
1.1       root      931:         row += 1
1.1.1.3   root      932: 
1.1.1.13! root      933:         self.clocks = table_add_radio_rows(table, row, col, "CPU clock:", config.get_cpuclock_types())
1.1.1.3   root      934:         row += 1
                    935: 
                    936:         # fullspan at bottom
                    937:         fullspan = True
                    938: 
1.1.1.13! root      939:         combo = Gtk.ComboBoxText()
1.1.1.3   root      940:         for text in config.get_cpulevel_types():
1.1       root      941:             combo.append_text(text)
1.1.1.13! root      942:         self.cpulevel = table_add_widget_row(table, row, col, "CPU type:", combo, fullspan)
1.1       root      943:         row += 1
1.1.1.3   root      944: 
1.1.1.13! root      945:         combo = Gtk.ComboBoxText()
1.1       root      946:         for text in config.get_memory_names():
                    947:             combo.append_text(text)
1.1.1.13! root      948:         self.memory = table_add_widget_row(table, row, col, "Memory:", combo, fullspan)
1.1       root      949:         row += 1
1.1.1.10  root      950: 
1.1.1.13! root      951:         self.ttram = Gtk.Adjustment(config.get_ttram(), 0, 260, 4, 4, 4)
        !           952:         ttram = Gtk.HScale(adjustment=self.ttram)
1.1.1.10  root      953:         ttram.set_digits(0)
                    954:         ttram.set_tooltip_text("TT-RAM needs Falcon/TT with WinUAE CPU core and implies 32-bit addressing.  0 = disabled, 24-bit addressing.")
1.1.1.13! root      955:         table_add_widget_row(table, row, col, "TT-RAM", ttram, fullspan)
1.1.1.10  root      956:         row += 1
1.1.1.13! root      957: 
1.1       root      958:         label = "TOS image:"
1.1.1.13! root      959:         fsel = self._fsel(label, Gtk.FileChooserAction.OPEN)
        !           960:         self.tos = table_add_widget_row(table, row, col, label, fsel, fullspan)
1.1       root      961:         row += 1
                    962: 
1.1.1.13! root      963:         vbox = Gtk.VBox()
        !           964:         self.compatible = Gtk.CheckButton("Compatible CPU")
        !           965:         self.timerd = Gtk.CheckButton("Patch Timer-D")
1.1.1.9   root      966:         self.compatible.set_tooltip_text("Needed for overscan and other timing sensitive things to work correctly")
                    967:         self.timerd.set_tooltip_text("Improves ST/STE emulation performance, but some rare demos/games don't work with this")
1.1.1.3   root      968:         vbox.add(self.compatible)
                    969:         vbox.add(self.timerd)
1.1.1.13! root      970:         table_add_widget_row(table, row, col, "Misc.:", vbox, fullspan)
1.1       root      971:         row += 1
                    972: 
                    973:         table.show_all()
                    974: 
                    975:     def _fsel(self, label, action):
1.1.1.13! root      976:         fsel = Gtk.FileChooserButton(label)
1.1       root      977:         # Hatari cannot access URIs
                    978:         fsel.set_local_only(True)
                    979:         fsel.set_width_chars(12)
                    980:         fsel.set_action(action)
                    981:         return fsel
1.1.1.13! root      982: 
1.1       root      983:     def _get_config(self, config):
1.1.1.3   root      984:         self.machines[config.get_machine()].set_active(True)
                    985:         self.monitors[config.get_monitor()].set_active(True)
                    986:         self.clocks[config.get_cpuclock()].set_active(True)
                    987:         self.dsps[config.get_dsp()].set_active(True)
                    988:         self.cpulevel.set_active(config.get_cpulevel())
1.1       root      989:         self.memory.set_active(config.get_memory())
1.1.1.10  root      990:         self.ttram.set_value(config.get_ttram())
1.1       root      991:         tos = config.get_tos()
                    992:         if tos:
                    993:             self.tos.set_filename(tos)
                    994:         self.compatible.set_active(config.get_compatible())
                    995:         self.timerd.set_active(config.get_timerd())
                    996: 
1.1.1.3   root      997:     def _get_active_radio(self, radios):
                    998:         idx = 0
                    999:         for radio in radios:
                   1000:             if radio.get_active():
                   1001:                 return idx
                   1002:             idx += 1
1.1.1.13! root     1003: 
1.1       root     1004:     def _set_config(self, config):
                   1005:         config.lock_updates()
1.1.1.3   root     1006:         config.set_machine(self._get_active_radio(self.machines))
                   1007:         config.set_monitor(self._get_active_radio(self.monitors))
                   1008:         config.set_cpuclock(self._get_active_radio(self.clocks))
                   1009:         config.set_dsp(self._get_active_radio(self.dsps))
                   1010:         config.set_cpulevel(self.cpulevel.get_active())
1.1       root     1011:         config.set_memory(self.memory.get_active())
1.1.1.10  root     1012:         config.set_ttram(self.ttram.get_value())
1.1       root     1013:         config.set_tos(self.tos.get_filename())
                   1014:         config.set_compatible(self.compatible.get_active())
                   1015:         config.set_timerd(self.timerd.get_active())
                   1016:         config.flush_updates()
                   1017: 
                   1018:     def run(self, config):
                   1019:         "run(config) -> bool, whether to reboot"
                   1020:         if not self.dialog:
                   1021:             self._create_dialog(config)
                   1022: 
                   1023:         self._get_config(config)
                   1024:         response = self.dialog.run()
                   1025:         self.dialog.hide()
1.1.1.13! root     1026:         if response == Gtk.ResponseType.APPLY:
1.1       root     1027:             self._set_config(config)
                   1028:             return True
                   1029:         return False

unix.superglobalmegacorp.com

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