コード例 #1
0
 def on_setting(self, key, _):
     if key in [
             "config_search",
             "game_list_uuid",
             "database_show_games",
             "database_show_adult",
             "database_show_unpublished",
     ]:
         # if key == "game_list_uuid":
         self.update_search()
         if len(self.items) > 0:
             self.select_item(None)
             self.select_item(0)
         else:
             # self.select_item(None)
             if LauncherSettings.get(PARENT_UUID):
                 LauncherSettings.set(PARENT_UUID, "")
                 LauncherConfig.load_default_config()
     elif key == "__config_refresh":
         self.update_search()
         self.select_item(None)
         old_parent_uuid = LauncherSettings.get(PARENT_UUID)
         if old_parent_uuid:
             LauncherSettings.set(PARENT_UUID, "")
             LauncherSettings.set(PARENT_UUID, old_parent_uuid)
     elif key == PARENT_UUID or key == "config_path":
         if not (LauncherSettings.get(PARENT_UUID)
                 or LauncherSettings.get("config_path")):
             self.select_item(None)
コード例 #2
0
    def update_search(self):
        search = LauncherSettings.get("config_search").strip().lower()
        print("search for", search)
        words = []
        special = []
        for word in search.split(" "):
            word = word.strip()
            if not word:
                continue
            if ":" in word[1:-1]:
                special.append(word)
            else:
                words.append(word)
        terms = GameNameUtil.extract_search_terms(" ".join(words))
        terms.update(special)

        database = Database.get_instance()

        try:
            have = int(LauncherSettings.get("database_show_games"))
        except ValueError:
            # default is show all downloadable and locally available games
            have = 1
        items = database.find_games_new(
            " ".join(terms),
            have=have,
            list_uuid=LauncherSettings.get("game_list_uuid"),
        )

        self.set_items(items)
コード例 #3
0
 def on_resize(self):
     width, height = self.get_size()
     # print("on_resize, size =", width, height)
     if self.is_maximized():
         if LauncherSettings.get("maximized") != "1":
             LauncherSettings.set("maximized", "1")
     else:
         if LauncherSettings.get("maximized") != "0":
             LauncherSettings.set("maximized", "0")
     if self.screenshots_panel is not None:
         available = width - 2 * 10 - self.game_info_panel.get_min_width()
         num_screenshots = int(
             (available - 22 + 22) / (Constants.SCREEN_SIZE[0] + 22))
         # print("Screenshots count:", num_screenshots)
         screenshots_panel_width = (
             (Constants.SCREEN_SIZE[0] + 22) * num_screenshots - 22 + 22)
         self.screenshots_panel.set_min_width(screenshots_panel_width)
     if width > CONFIGURATIONS_PANEL_WIDTH_THRESHOLD_2:
         configurations_width = (SCREENSHOT_WIDTH * 3 +
                                 SCREENSHOT_SPACING * 2 + MARGIN)
         self.configurations_panel.set_min_width(
             CONFIGURATIONS_PANEL_WIDTH_2)
     else:
         self.configurations_panel.set_min_width(
             CONFIGURATIONS_PANEL_WIDTH_1)
     super().on_resize()
コード例 #4
0
ファイル: gamedriver.py プロジェクト: hroncok/fs-uae-launcher
    def update_environment_with_centering_info(self, env):
        # FIXME: does not really belong here (dependency loop)
        from launcher.launcher_config import LauncherConfig
        from launcher.launcher_settings import LauncherSettings
        width = (LauncherConfig.get("window_width")
                 or LauncherSettings.get("window_width"))
        height = (LauncherConfig.get("window_height")
                  or LauncherSettings.get("window_height"))
        try:
            width = int(width)
        except:
            width = 960
        try:
            height = int(height)
        except:
            height = 540
        from launcher.ui.launcherwindow import LauncherWindow
        if LauncherWindow.current() is None:
            return

        main_w, main_h = LauncherWindow.current().get_size()
        main_x, main_y = LauncherWindow.current().get_position()

        x = main_x + (main_w - width) // 2
        y = main_y + (main_h - height) // 2

        # FIXME: REMOVE
        env["FSGS_WINDOW_X"] = str(x)
        env["FSGS_WINDOW_Y"] = str(y)

        # FIXME: REMOVE
        env["SDL_VIDEO_WINDOW_POS"] = str("{0},{1}".format(x, y))

        env["FSGS_WINDOW_CENTER"] = "{0},{1}".format(main_x + main_w // 2,
                                                     main_y + main_h // 2)
コード例 #5
0
 def update_info(self, value=None):
     if LauncherSettings.get("fullscreen") != "1":
         self.set_text("")
         return
     if value is None:
         value = LauncherSettings.get("monitor")
     x, y, w, h = GameDriver.screen_rect_for_monitor(value)
     # index = GameRunner.screen_index_for_monitor(value)
     refresh_rate = GameDriver.screen_refresh_rate_for_monitor(value)
     assume_refresh_rate = LauncherSettings.get("assume_refresh_rate")
     if assume_refresh_rate:
         refresh_rate_override = " (OVERRIDING {})".format(refresh_rate)
         try:
             refresh_rate = float(assume_refresh_rate)
         except ValueError:
             refresh_rate = 0.0
     else:
         refresh_rate_override = ""
     if x or y:
         pos_str = " ({}, {})".format(x, y)
     else:
         pos_str = ""
     self.set_text(
         "{}x{}{} @ {}Hz{}".format(
             w, h, pos_str, refresh_rate, refresh_rate_override
         )
     )
コード例 #6
0
    def __init__(self, database):
        self.database = database
        database_cursor = self.database.cursor()

        database_cursor.execute(
            "SELECT uuid, update_stamp, have, id FROM game "
            "WHERE uuid IS NOT NULL")
        self.existing_games = {}
        for row in database_cursor:
            self.existing_games[row[0]] = row[1], row[2], row[3]
        database_cursor.execute(
            "SELECT uuid, update_stamp, have, id FROM game_variant")
        self.existing_variants = {}
        for row in database_cursor:
            self.existing_variants[row[0]] = row[1], row[2], row[3]

        self.file_stamps = FileDatabase.get_instance().get_last_event_stamps()
        cached_file_stamps = self.database.get_last_file_event_stamps()
        self.added_files = (self.file_stamps["last_file_insert"] !=
                            cached_file_stamps["last_file_insert"])
        self.deleted_files = (self.file_stamps["last_file_delete"] !=
                              cached_file_stamps["last_file_delete"])
        # print(LauncherSettings.get(Option.DATABASE_LOCKER),
        #         cached_file_stamps["database_locker"])
        # assert 0
        if (LauncherSettings.get(Option.DATABASE_LOCKER) !=
                cached_file_stamps["database_locker"]):
            # Assume that files could be deleted or removed...
            if LauncherSettings.get(Option.DATABASE_LOCKER) == "0":
                self.deleted_files = True
            else:
                self.added_files = True
コード例 #7
0
ファイル: FSUAE.py プロジェクト: jelmer/fs-uae-debian
    def center_window(cls, args, env):
        # FIXME: does not really belong here (dependency loop)
        from launcher.launcher_config import LauncherConfig
        from launcher.launcher_settings import LauncherSettings
        width = (LauncherConfig.get("window_width")
                 or LauncherSettings.get("window_width"))
        height = (LauncherConfig.get("window_height")
                  or LauncherSettings.get("window_height"))
        try:
            width = int(width)
        except:
            width = 960
        try:
            height = int(height)
        except:
            height = 540
        from launcher.ui.launcher_window import LauncherWindow
        if LauncherWindow.current() is None:
            return

        main_w, main_h = LauncherWindow.current().get_size()
        main_x, main_y = LauncherWindow.current().get_position()

        x = main_x + (main_w - width) // 2
        y = main_y + (main_h - height) // 2

        # FIXME: re-implement without wx
        # if windows:
        #     import wx
        #    y += wx.SystemSettings_GetMetric(wx.SYS_CAPTION_Y)

        env[str("SDL_VIDEO_WINDOW_POS")] = str("{0},{1}".format(x, y))
        args.append("--window-x={0}".format(x))
        args.append("--window-y={0}".format(y))
コード例 #8
0
ファイル: FSUAE.py プロジェクト: glaubitz/fs-uae-debian
    def center_window(cls, args, env):
        # FIXME: does not really belong here (dependency loop)
        from launcher.launcher_config import LauncherConfig
        from launcher.launcher_settings import LauncherSettings
        width = (LauncherConfig.get("window_width") or
                 LauncherSettings.get("window_width"))
        height = (LauncherConfig.get("window_height") or
                  LauncherSettings.get("window_height"))
        try:
            width = int(width)
        except:
            width = 960
        try:
            height = int(height)
        except:
            height = 540
        from launcher.ui.launcher_window import LauncherWindow
        if LauncherWindow.current() is None:
            return

        main_w, main_h = LauncherWindow.current().get_size()
        main_x, main_y = LauncherWindow.current().get_position()

        x = main_x + (main_w - width) // 2
        y = main_y + (main_h - height) // 2

        # FIXME: re-implement without wx
        # if windows:
        #     import wx
        #    y += wx.SystemSettings_GetMetric(wx.SYS_CAPTION_Y)

        env[str("SDL_VIDEO_WINDOW_POS")] = str("{0},{1}".format(x, y))
        args.append("--window-x={0}".format(x))
        args.append("--window-y={0}".format(y))
コード例 #9
0
    def load_settings(cls):
        if cls.settings_loaded:
            return
        cls.settings_loaded = True

        settings = Settings.instance()
        settings.load()
        path = settings.path
        # path = app.get_settings_path()
        print("loading last config from " + repr(path))
        if not os.path.exists(path):
            print("settings file does not exist")
        # noinspection PyArgumentList
        cp = ConfigParser(interpolation=None)
        try:
            cp.read([path])
        except Exception as e:
            print(repr(e))
            return

        for key in LauncherSettings.old_keys:
            if app.settings.get(key):
                print("[SETTINGS] Removing old key", key)
                app.settings.set(key, "")

        if fsgs.config.add_from_argv():
            print("[CONFIG] Configuration specified via command line")
            # Prevent the launcher from loading the last used game
            LauncherSettings.set("parent_uuid", "")
        elif LauncherSettings.get("config_path"):
            if LauncherConfig.load_file(LauncherSettings.get("config_path")):
                print("[CONFIG] Loaded last configuration file")
            else:
                print("[CONFIG] Failed to load last configuration file")
                LauncherConfig.load_default_config()
        else:
            pass
            # config = {}
            # try:
            #     keys = cp.options("config")
            # except NoSectionError:
            #     keys = []
            # for key in keys:
            #     config[key] = fs.from_utf8_str(cp.get("config", key))
            # for key, value in config.items():
            #     print("loaded", key, value)
            #     fsgs.config.values[key] = value

        # Argument --new-config[=<platform>]
        new_config = "--new-config" in sys.argv
        new_config_platform = None
        for platform_id in PLATFORM_IDS:
            if "--new-config=" + platform_id in sys.argv:
                new_config = True
                new_config_platform = platform_id
        if new_config:
            LauncherConfig.load_default_config(platform=new_config_platform)
            # Prevent the launcher from loading the last used game
            LauncherSettings.set("parent_uuid", "")
コード例 #10
0
    def load_settings(cls):
        if cls.settings_loaded:
            return
        cls.settings_loaded = True

        settings = Settings.instance()
        settings.load()
        path = settings.path
        # path = app.get_settings_path()
        print("loading last config from " + repr(path))
        if not os.path.exists(path):
            print("settings file does not exist")
        # noinspection PyArgumentList
        cp = ConfigParser(interpolation=None)
        try:
            cp.read([path])
        except Exception as e:
            print(repr(e))
            return

        for key in LauncherSettings.old_keys:
            if app.settings.get(key):
                print("[SETTINGS] Removing old key", key)
                app.settings.set(key, "")

        if fsgs.config.add_from_argv():
            print("[CONFIG] Configuration specified via command line")
            # Prevent the launcher from loading the last used game
            LauncherSettings.set("parent_uuid", "")
        elif LauncherSettings.get("config_path"):
            if LauncherConfig.load_file(LauncherSettings.get("config_path")):
                print("[CONFIG] Loaded last configuration file")
            else:
                print("[CONFIG] Failed to load last configuration file")
                LauncherConfig.load_default_config()
        else:
            pass
            # config = {}
            # try:
            #     keys = cp.options("config")
            # except NoSectionError:
            #     keys = []
            # for key in keys:
            #     config[key] = fs.from_utf8_str(cp.get("config", key))
            # for key, value in config.items():
            #     print("loaded", key, value)
            #     fsgs.config.values[key] = value

        # Argument --new-config[=<platform>]
        new_config = "--new-config" in sys.argv
        new_config_platform = None
        for platform_id in PLATFORM_IDS:
            if "--new-config=" + platform_id in sys.argv:
                new_config = True
                new_config_platform = platform_id
        if new_config:
            LauncherConfig.load_default_config(platform=new_config_platform)
            # Prevent the launcher from loading the last used game
            LauncherSettings.set("parent_uuid", "")
コード例 #11
0
 def get_preferred_joysticks(cls):
     prefs = []
     if LauncherSettings.get("primary_joystick"):
         prefs.append(
             Device.create_cmp_id(LauncherSettings.get("primary_joystick")))
     if LauncherSettings.get("secondary_joystick"):
         prefs.append(
             Device.create_cmp_id(
                 LauncherSettings.get("secondary_joystick")))
     return prefs
コード例 #12
0
 def _check_platform(self, platform_option):
     if LauncherSettings.get(platform_option) == "1":
         return True
     if platform_option in [Option.AMIGA_DATABASE, Option.CD32_DATABASE,
                            Option.CDTV_DATABASE]:
         if LauncherSettings.get(platform_option) != "0":
             return True
         return False
     if openretro and platform_option in OPENRETRO_DEFAULT_DATABASES:
         if LauncherSettings.get(platform_option) == "0":
             return False
         return True
     return False
コード例 #13
0
 def get_preferred_joysticks(cls):
     prefs = []
     if LauncherSettings.get("primary_joystick"):
         prefs.append(
             Device.create_cmp_id(LauncherSettings.get("primary_joystick"))
         )
     if LauncherSettings.get("secondary_joystick"):
         prefs.append(
             Device.create_cmp_id(
                 LauncherSettings.get("secondary_joystick")
             )
         )
     return prefs
コード例 #14
0
    def create_menu(self):
        menu = fsui.PopupMenu()

        if LauncherSettings.get(Option.DATABASE_AUTH):
            menu.add_item(gettext("Update Game Database"),
                          self.on_update_game_database)
        menu.add_item(gettext("Update File Database"),
                      self.on_update_file_database)

        menu.add_separator()

        menu.add_item(gettext("ADF Creator"), self.on_adf_creator)
        menu.add_item(gettext("HDF Creator"), self.on_hdf_creator)
        if LauncherSettings.get(Option.NETPLAY_FEATURE) != "0":
            menu.add_item(gettext("Net Play"), self.on_net_play)

        menu.add_separator()
        menu.add_item(
            gettext("Import Kickstarts") + "...", self.on_import_kickstarts)
        menu.add_item(
            gettext("Amiga Forever Import") + "...", self.on_import_kickstarts)

        menu.add_separator()
        self.add_user_menu_content(menu)

        menu.add_separator()
        # menu.add_item(
        #         gettext("Kickstarts & ROMs"), self.on_import_kickstarts)

        if LauncherSettings.get(Option.LAUNCHER_SETUP_WIZARD_FEATURE):
            menu.add_item(
                gettext("Setup Wizard") + "...", self.on_setup_wizard)

        menu.add_preferences_item(gettext("Settings"), self.on_settings_button)

        menu.add_separator()
        menu.add_item(
            gettext("About {name}").format(name="OpenRetro.org"),
            self.on_what_is_this,
        )
        if fsgs_module.product == "OpenRetro":
            app_name = "OpenRetro Launcher"
        else:
            app_name = "FS-UAE Launcher"
        menu.add_about_item(
            gettext("About {name}").format(name=app_name), self.on_about)

        menu.add_separator()
        menu.add_about_item(gettext("Quit"), self.on_quit)
        return menu
コード例 #15
0
 def update_title(self):
     if Skin.fws():
         # Just want to keep "FS-UAE Launcher" in the title
         return
     auth = LauncherSettings.get(Option.DATABASE_AUTH)
     if auth:
         username = LauncherSettings.get(Option.DATABASE_USERNAME)
         login_info = username
     else:
         login_info = gettext("Not logged in")
     app_name = "{} Launcher".format(Product.base_name)
     title = "{} {} ({})".format(app_name,
                                 Application.instance().version, login_info)
     self.set_title(title)
コード例 #16
0
    def __init__(self, parent):
        StatusElement.__init__(self, parent)
        self.error_icon = Image("launcher:res/16/error.png")
        self.warning_icon = Image("launcher:res/16/warning_3.png")
        self.notice_icon = Image("launcher:res/16/information.png")
        self.icons = [
            self.error_icon,
            self.warning_icon,
            self.notice_icon,
        ]
        self.coordinates = []
        self.warnings = []
        self.game_notice = ""
        self.variant_notice = ""
        self.variant_warning = ""
        self.variant_error = ""
        self.joy_emu_conflict = ""
        self.using_joy_emu = False
        self.kickstart_file = ""
        self.x_kickstart_file_sha1 = ""
        self.update_available = ""
        self.__error = ""
        self.x_missing_files = ""
        self.download_page = ""
        self.download_file = ""
        self.amiga_model = ""
        self.amiga_model_calculated = ""
        self.chip_memory = ""
        self.chip_memory_calculated = 0
        self.outdated_plugins = []
        self.custom_config = set()
        self.custom_uae_config = set()
        self.settings_config_keys = set()

        plugin_manager = PluginManager.instance()
        for plugin in plugin_manager.plugins():
            if plugin.outdated:
                self.outdated_plugins.append(plugin.name)

        ConfigBehavior(self, [
            "x_game_notice", "x_variant_notice", "x_variant_warning",
            "x_variant_error", "x_joy_emu_conflict", "amiga_model",
            "x_kickstart_file_sha1", "kickstart_file", "download_page",
            "download_file", "x_missing_files", "__error",
            "chip_memory", "jit_compiler"])
        SettingsBehavior(self, ["__update_available"])

        LauncherConfig.add_listener(self)
        for key in JOYSTICK_KEYS:
            self.on_config(key, LauncherConfig.get(key))
        for key in LauncherConfig.keys():
            if LauncherConfig.is_custom_uae_option(key):
                self.on_config(key, LauncherConfig.get(key))
            elif LauncherConfig.is_custom_option(key):
                self.on_config(key, LauncherConfig.get(key))

        LauncherSettings.add_listener(self)
        for key in LauncherSettings.keys():
            if LauncherConfig.is_config_only_option(key):
                self.on_setting(key, LauncherSettings.get(key))
コード例 #17
0
    def __init__(self, parent):
        # fsui.VerticalItemView.__init__(self, parent)
        fsui.ItemChoice.__init__(self, parent)

        self.parent_uuid = ""
        self.items = []  # type: list [dict]
        # self.last_variants = LastVariants()

        self.icon = fsui.Image("launcher:/data/fsuae_config_16.png")
        self.adf_icon = fsui.Image("launcher:/data/adf_game_16.png")
        self.ipf_icon = fsui.Image("launcher:/data/ipf_game_16.png")
        self.cd_icon = fsui.Image("launcher:/data/cd_game_16.png")
        self.hd_icon = fsui.Image("launcher:/data/hd_game_16.png")
        # self.missing_icon = fsui.Image(
        #     "launcher:/data/missing_game_16.png")
        self.missing_icon = fsui.Image("launcher:/data/16x16/delete_grey.png")
        self.missing_color = fsui.Color(0xA8, 0xA8, 0xA8)

        self.blank_icon = fsui.Image("launcher:/data/16x16/blank.png")
        self.bullet_icon = fsui.Image("launcher:/data/16x16/bullet.png")

        self.manual_download_icon = fsui.Image(
            "launcher:/data/16x16/arrow_down_yellow.png")
        self.auto_download_icon = fsui.Image(
            "launcher:/data/16x16/arrow_down_green.png")

        self.up_icon = fsui.Image("launcher:/data/16x16/thumb_up_mod.png")
        self.down_icon = fsui.Image("launcher:/data/16x16/thumb_down_mod.png")
        self.fav_icon = fsui.Image("launcher:/data/rating_fav_16.png")

        LauncherSettings.add_listener(self)
        self.on_setting("parent_uuid", LauncherSettings.get("parent_uuid"))
コード例 #18
0
 def _check_platform(self, platform_option):
     if LauncherSettings.get(platform_option) == "1":
         return True
     if platform_option in [
         Option.AMIGA_DATABASE,
         Option.CD32_DATABASE,
         Option.CDTV_DATABASE,
     ]:
         if LauncherSettings.get(platform_option) != "0":
             return True
         return False
     if openretro and platform_option in OPENRETRO_DEFAULT_DATABASES:
         if LauncherSettings.get(platform_option) == "0":
             return False
         return True
     return False
コード例 #19
0
    def finish(self):
        database_cursor = self.database.cursor()

        # variants left in this list must now be deleted
        for row in self.existing_variants.values():
            variant_id = row[2]
            database_cursor.execute("DELETE FROM game_variant WHERE id = ?",
                                    (variant_id, ))

        # games left in this list must now be deleted
        for row in self.existing_games.values():
            game_id = row[2]
            database_cursor.execute("DELETE FROM game WHERE id = ?",
                                    (game_id, ))

        database_cursor.execute(
            "SELECT count(*) FROM game WHERE uuid IS NOT NULL "
            "AND (have IS NULL OR have != (SELECT coalesce(max(have), 0) "
            "FROM game_variant WHERE game_uuid = game.uuid))")
        update_rows = database_cursor.fetchone()[0]
        print(update_rows, "game entries need update for have field")
        if update_rows > 0:
            database_cursor.execute(
                "UPDATE game SET have = (SELECT coalesce(max(have), 0) FROM "
                "game_variant WHERE game_uuid = game.uuid) WHERE uuid IS NOT "
                "NULL AND (have IS NULL OR have != (SELECT coalesce(max("
                "have), 0) FROM game_variant WHERE game_uuid = game.uuid))")
        # FIXME: Remove this line?
        FileDatabase.get_instance().get_last_event_stamps()
        self.file_stamps["database_locker"] = LauncherSettings.get(
            Option.DATABASE_LOCKER)
        self.database.update_last_file_event_stamps(self.file_stamps)
コード例 #20
0
    def config_startup_scan(cls):
        if cls._config_scanned:
            return
        cls._config_scanned = True

        configs_dir = FSGSDirectories.get_configurations_dir()
        print("config_startup_scan", configs_dir)
        print(LauncherSettings.settings)

        settings_mtime = LauncherSettings.get("configurations_dir_mtime")
        dir_mtime = cls.get_dir_mtime_str(configs_dir)
        if settings_mtime == dir_mtime + "+" + str(Database.VERSION):
            print("... mtime not changed", settings_mtime, dir_mtime)
            return

        database = Database.get_instance()
        file_database = FileDatabase.get_instance()

        print("... database.find_local_configurations")
        local_configs = Database.get_instance().find_local_configurations()
        print("... walk configs_dir")
        for dir_path, dir_names, file_names in os.walk(configs_dir):
            for file_name in file_names:
                if not file_name.endswith(".fs-uae"):
                    continue
                path = Paths.join(dir_path, file_name)
                if path in local_configs:
                    local_configs[path] = None
                    # already exists in database
                    continue
                name, ext = os.path.splitext(file_name)
                # search = ConfigurationScanner.create_configuration_search(
                # name)
                scanner = ConfigurationScanner()
                print("[startup] adding config", path)
                file_database.delete_file(path=path)
                with open(path, "rb") as f:
                    sha1 = hashlib.sha1(f.read()).hexdigest()
                file_database.add_file(path=path, sha1=sha1)

                game_id = database.add_configuration(
                    path=path, name=scanner.create_configuration_name(name)
                )
                database.update_game_search_terms(
                    game_id, scanner.create_search_terms(name)
                )

        for path, config_id in local_configs.items():
            if config_id is not None:
                print("[startup] removing configuration", path)
                database.delete_game(id=config_id)
                file_database.delete_file(path=path)
        print("... commit")
        database.commit()

        LauncherSettings.set(
            "configurations_dir_mtime",
            cls.get_dir_mtime_str(configs_dir) + "+" + str(Database.VERSION),
        )
コード例 #21
0
 def _check_platform(self, platform_option):
     if LauncherSettings.get(platform_option) == "1":
         return True
     if Product.includes_amiga() and platform_option in [
             Option.AMIGA_DATABASE,
             Option.CD32_DATABASE,
             Option.CDTV_DATABASE,
     ]:
         if LauncherSettings.get(platform_option) != "0":
             return True
         return False
     if (Product.is_openretro()
             and platform_option in OPENRETRO_DEFAULT_DATABASES):
         if LauncherSettings.get(platform_option) == "0":
             return False
         return True
     return False
コード例 #22
0
 def _update_game_database(self, database_name, game_database):
     game_database_client = GameDatabaseClient(game_database)
     synchronizer = GameDatabaseSynchronizer(
         self.context, game_database_client, on_status=self.on_status,
         stop_check=self.stop_check, platform_id=database_name)
     synchronizer.username = "******"
     synchronizer.password = LauncherSettings.get("database_auth")
     synchronizer.synchronize()
コード例 #23
0
    def config_startup_scan(cls):
        if cls._config_scanned:
            return
        cls._config_scanned = True

        configs_dir = FSGSDirectories.get_configurations_dir()
        print("config_startup_scan", configs_dir)
        print(LauncherSettings.settings)

        settings_mtime = LauncherSettings.get("configurations_dir_mtime")
        dir_mtime = cls.get_dir_mtime_str(configs_dir)
        if settings_mtime == dir_mtime + "+" + str(Database.VERSION):
            print("... mtime not changed", settings_mtime, dir_mtime)
            return

        database = Database.get_instance()
        file_database = FileDatabase.get_instance()

        print("... database.find_local_configurations")
        local_configs = Database.get_instance().find_local_configurations()
        print("... walk configs_dir")
        for dir_path, dir_names, file_names in os.walk(configs_dir):
            for file_name in file_names:
                if not file_name.endswith(".fs-uae"):
                    continue
                path = Paths.join(dir_path, file_name)
                if path in local_configs:
                    local_configs[path] = None
                    # already exists in database
                    continue
                name, ext = os.path.splitext(file_name)
                # search = ConfigurationScanner.create_configuration_search(
                # name)
                scanner = ConfigurationScanner()
                print("[startup] adding config", path)
                file_database.delete_file(path=path)
                with open(path, "rb") as f:
                    sha1 = hashlib.sha1(f.read()).hexdigest()
                file_database.add_file(path=path, sha1=sha1)

                game_id = database.add_configuration(
                    path=path, name=scanner.create_configuration_name(name))
                database.update_game_search_terms(
                    game_id, scanner.create_search_terms(name))

        for path, config_id in local_configs.items():
            if config_id is not None:
                print("[startup] removing configuration", path)
                database.delete_game(id=config_id)
                file_database.delete_file(path=path)
        print("... commit")
        database.commit()

        LauncherSettings.set(
            "configurations_dir_mtime",
            cls.get_dir_mtime_str(configs_dir) + "+" + str(Database.VERSION),
        )
コード例 #24
0
ファイル: scanner.py プロジェクト: bopopescu/fs-uae-debian
    def _scan_thread(cls, database):
        if cls.scan_for_files:
            scanner = FileScanner(
                cls.paths,
                cls.purge_other_dirs,
                on_status=cls.on_status,
                stop_check=cls.stop_check,
            )
            scanner.scan()
            if cls.stop_check():
                return

        # if cls.scan_for_configs or
        # if cls.update_game_database:
        scanner = ConfigurationScanner(cls.paths,
                                       on_status=cls.on_status,
                                       stop_check=cls.stop_check)
        scanner.scan(database)

        if cls.update_game_database:

            context = SynchronizerContext()

            synchronizer = MetaSynchronizer(context,
                                            on_status=cls.on_status,
                                            stop_check=cls.stop_check)
            synchronizer.synchronize()

            synchronizer = GameRatingSynchronizer(
                context,
                database,
                on_status=cls.on_status,
                stop_check=cls.stop_check,
            )
            synchronizer.username = "******"
            synchronizer.password = LauncherSettings.get("database_auth")
            synchronizer.synchronize()

            synchronizer = ListsSynchronizer(context,
                                             on_status=cls.on_status,
                                             stop_check=cls.stop_check)
            synchronizer.synchronize()

            scanner = GameScanner(
                context,
                cls.paths,
                on_status=cls.on_status,
                stop_check=cls.stop_check,
            )
            scanner.update_game_database()

        scanner = GameScanner(None,
                              cls.paths,
                              on_status=cls.on_status,
                              stop_check=cls.stop_check)
        scanner.scan(database)
コード例 #25
0
    def _scan_thread(cls, database):
        if cls.scan_for_files:
            scanner = FileScanner(
                cls.paths,
                cls.purge_other_dirs,
                on_status=cls.on_status,
                stop_check=cls.stop_check,
            )
            scanner.scan()
            if cls.stop_check():
                return

        # if cls.scan_for_configs or
        # if cls.update_game_database:
        scanner = ConfigurationScanner(
            cls.paths, on_status=cls.on_status, stop_check=cls.stop_check
        )
        scanner.scan(database)

        if cls.update_game_database:

            context = SynchronizerContext()

            synchronizer = MetaSynchronizer(
                context, on_status=cls.on_status, stop_check=cls.stop_check
            )
            synchronizer.synchronize()

            synchronizer = GameRatingSynchronizer(
                context,
                database,
                on_status=cls.on_status,
                stop_check=cls.stop_check,
            )
            synchronizer.username = "******"
            synchronizer.password = LauncherSettings.get("database_auth")
            synchronizer.synchronize()

            synchronizer = ListsSynchronizer(
                context, on_status=cls.on_status, stop_check=cls.stop_check
            )
            synchronizer.synchronize()

            scanner = GameScanner(
                context,
                cls.paths,
                on_status=cls.on_status,
                stop_check=cls.stop_check,
            )
            scanner.update_game_database()

        scanner = GameScanner(
            None, cls.paths, on_status=cls.on_status, stop_check=cls.stop_check
        )
        scanner.scan(database)
コード例 #26
0
    def update_environment_with_centering_info(self, env):
        # FIXME: does not really belong here (dependency loop)
        from launcher.launcher_config import LauncherConfig
        from launcher.launcher_settings import LauncherSettings

        width = LauncherConfig.get("window_width") or LauncherSettings.get(
            "window_width"
        )
        height = LauncherConfig.get("window_height") or LauncherSettings.get(
            "window_height"
        )
        try:
            width = int(width)
        except:
            width = 960
        try:
            height = int(height)
        except:
            height = 540
        from launcher.ui.launcherwindow import LauncherWindow

        if LauncherWindow.current() is None:
            return

        main_w, main_h = LauncherWindow.current().get_size()
        main_x, main_y = LauncherWindow.current().get_position()

        x = main_x + (main_w - width) // 2
        y = main_y + (main_h - height) // 2

        # FIXME: REMOVE
        env["FSGS_WINDOW_X"] = str(x)
        env["FSGS_WINDOW_Y"] = str(y)

        # FIXME: REMOVE
        env["SDL_VIDEO_WINDOW_POS"] = str("{0},{1}".format(x, y))
        env["FSGS_WINDOW_POS"] = str("{0},{1}".format(x, y))

        env["FSGS_WINDOW_CENTER"] = "{0},{1}".format(
            main_x + main_w // 2, main_y + main_h // 2
        )
コード例 #27
0
 def _update_game_database(self, database_name, game_database):
     game_database_client = GameDatabaseClient(game_database)
     synchronizer = GameDatabaseSynchronizer(
         self.context,
         game_database_client,
         on_status=self.on_status,
         stop_check=self.stop_check,
         platform_id=database_name,
     )
     synchronizer.username = "******"
     synchronizer.password = LauncherSettings.get("database_auth")
     synchronizer.synchronize()
コード例 #28
0
    def __init__(self, database):
        self.database = database
        database_cursor = self.database.cursor()

        database_cursor.execute(
            "SELECT uuid, update_stamp, have, id FROM game "
            "WHERE uuid IS NOT NULL"
        )
        self.existing_games = {}
        for row in database_cursor:
            self.existing_games[row[0]] = row[1], row[2], row[3]
        database_cursor.execute(
            "SELECT uuid, update_stamp, have, id FROM game_variant"
        )
        self.existing_variants = {}
        for row in database_cursor:
            self.existing_variants[row[0]] = row[1], row[2], row[3]

        self.file_stamps = FileDatabase.get_instance().get_last_event_stamps()
        cached_file_stamps = self.database.get_last_file_event_stamps()
        self.added_files = (
            self.file_stamps["last_file_insert"]
            != cached_file_stamps["last_file_insert"]
        )
        self.deleted_files = (
            self.file_stamps["last_file_delete"]
            != cached_file_stamps["last_file_delete"]
        )
        # print(LauncherSettings.get(Option.DATABASE_LOCKER),
        #         cached_file_stamps["database_locker"])
        # assert 0
        if (
            LauncherSettings.get(Option.DATABASE_LOCKER)
            != cached_file_stamps["database_locker"]
        ):
            # Assume that files could be deleted or removed...
            if LauncherSettings.get(Option.DATABASE_LOCKER) == "0":
                self.deleted_files = True
            else:
                self.added_files = True
コード例 #29
0
 def __init__(self, parent, names):
     parent.__settings_enable_behavior = self
     self._parent = weakref.ref(parent)
     self._names = set(names)
     LauncherSettings.add_listener(self)
     try:
         parent.destroyed.connect(self.on_parent_destroyed)
     except AttributeError:
         print("WARNING: SettingsBehavior without remove_listener "
               "implementation")
     for name in names:
         # Broadcast initial value
         self.on_setting(name, LauncherSettings.get(name))
コード例 #30
0
 def __init__(self, parent, names):
     parent.__settings_enable_behavior = self
     self._parent = weakref.ref(parent)
     self._names = set(names)
     LauncherSettings.add_listener(self)
     try:
         parent.destroyed.connect(self.on_parent_destroyed)
     except AttributeError:
         print("WARNING: SettingsBehavior without remove_listener "
               "implementation")
     for name in names:
         # Broadcast initial value
         self.on_setting(name, LauncherSettings.get(name))
コード例 #31
0
 def add_user_menu_content(self, menu):
     if LauncherSettings.get(Option.DATABASE_AUTH):
         # menu.add_item(_("Log In / Register"), self.on_log_in)
         # menu.add_item(gettext("Update Game Database"),
         #               self.on_game_database_refresh)
         if is_locker_enabled():
             menu.add_item(
                 gettext("Upload Files to OpenRetro Locker"),
                 self.on_upload_locker_files,
             )
             # menu.add_separator()
         menu.add_item(gettext("Log Out"), self.on_log_out)
     else:
         menu.add_item(gettext("Log In / Register"), self.on_log_in)
コード例 #32
0
    def update_widgets(self):
        value = LauncherSettings.get("video_sync")
        vblank = value in ["1", "auto", "full", "vblank"]
        full = value in ["1", "auto", "full"]

        # self.full_sync_checkbox.enable(vblank)
        self.sync_method_group.label.enable(vblank)
        self.sync_method_group.widget.enable(vblank)
        self.sync_method_group.help_button.enable(vblank)
        self.sync_method_label.enable(vblank)
        # self.smooth_label.enable(vblank)
        self.low_latency_group.label.enable(full)
        self.low_latency_group.widget.enable(full)
        self.low_latency_group.help_button.enable(full)
コード例 #33
0
    def update_widgets(self):
        value = LauncherSettings.get("video_sync")
        vblank = value in ["1", "auto", "full", "vblank"]
        full = value in ["1", "auto", "full"]

        # self.full_sync_checkbox.enable(vblank)
        self.sync_method_group.label.enable(vblank)
        self.sync_method_group.widget.enable(vblank)
        self.sync_method_group.help_button.enable(vblank)
        self.sync_method_label.enable(vblank)
        # self.smooth_label.enable(vblank)
        self.low_latency_group.label.enable(full)
        self.low_latency_group.widget.enable(full)
        self.low_latency_group.help_button.enable(full)
コード例 #34
0
    def load_settings(cls):
        if cls.settings_loaded:
            return
        cls.settings_loaded = True

        settings = Settings.instance()
        settings.load()
        path = settings.path
        # path = app.get_settings_path()
        print("loading last config from " + repr(path))
        if not os.path.exists(path):
            print("settings file does not exist")
        # noinspection PyArgumentList
        cp = ConfigParser(interpolation=None)
        try:
            cp.read([path])
        except Exception as e:
            print(repr(e))
            return

        for key in LauncherSettings.old_keys:
            if app.settings.get(key):
                print("[SETTINGS] Removing old key", key)
                app.settings.set(key, "")

        if fsgs.config.add_from_argv():
            print("[CONFIG] Configuration specified via command line")
            # Prevent the launcher from loading the last used game
            LauncherSettings.set("parent_uuid", "")
        elif LauncherSettings.get("config_path"):
            if LauncherConfig.load_file(LauncherSettings.get("config_path")):
                print("[CONFIG] Loaded last configuration file")
            else:
                print("[CONFIG] Failed to load last configuration file")
                LauncherConfig.load_default_config()

            pass
コード例 #35
0
 def update_info(self, value=None):
     if LauncherSettings.get("fullscreen") != "1":
         self.set_text("")
         return
     if value is None:
         value = LauncherSettings.get("monitor")
     x, y, w, h = GameRunner.screen_rect_for_monitor(value)
     # index = GameRunner.screen_index_for_monitor(value)
     refresh_rate = GameRunner.screen_refresh_rate_for_monitor(value)
     assume_refresh_rate = LauncherSettings.get("assume_refresh_rate")
     if assume_refresh_rate:
         refresh_rate_override = " (OVERRIDING {})".format(refresh_rate)
         try:
             refresh_rate = float(assume_refresh_rate)
         except ValueError:
             refresh_rate = 0.0
     else:
         refresh_rate_override = ""
     if x or y:
         pos_str = " ({}, {})".format(x, y)
     else:
         pos_str = ""
     self.set_text("{}x{}{} @ {}Hz{}".format(
         w, h, pos_str, refresh_rate, refresh_rate_override))
コード例 #36
0
    def __init__(self, parent):
        fsui.Choice.__init__(self, parent)
        # FIXME: include in () what language is currently the automatic one

        selected_language = LauncherSettings.get("language")
        k = 0
        selected_index = 0
        for label, language_key, icon_name in LANGUAGE_ITEMS:
            self.add_item(label, fsui.Image(
                "workspace:res/16/flag-{0}.png".format(icon_name)))
            if language_key == selected_language:
                selected_index = k
            k += 1
        if selected_index > 0:
            self.set_index(selected_index)
コード例 #37
0
    def kickstart_startup_scan(cls):
        if cls._kickstart_scanned:
            return
        cls._kickstart_scanned = True

        print("kickstart_startup_scan")
        kickstarts_dir = FSGSDirectories.get_kickstarts_dir()
        if LauncherSettings.get(
            "kickstarts_dir_mtime"
        ) == cls.get_dir_mtime_str(kickstarts_dir):
            print("... mtime not changed")
        else:
            file_database = FileDatabase.get_instance()
            print("... database.find_local_roms")
            local_roms = file_database.find_local_roms()
            print("... walk kickstarts_dir")
            for dir_path, dir_names, file_names in os.walk(kickstarts_dir):
                for file_name in file_names:
                    if not file_name.lower().endswith(
                        ".rom"
                    ) and not file_name.lower().endswith(".bin"):
                        continue
                    path = Paths.join(dir_path, file_name)
                    if path in local_roms:
                        local_roms[path] = None
                        # already exists in database
                        continue
                    print("[startup] adding kickstart", path)
                    ROMManager.add_rom_to_database(path, file_database)
            print(local_roms)
            for path, file_id in local_roms.items():
                if file_id is not None:
                    print("[startup] removing kickstart", path)
                    file_database.delete_file(id=file_id)
            print("... commit")
            file_database.commit()
            LauncherSettings.set(
                "kickstarts_dir_mtime", cls.get_dir_mtime_str(kickstarts_dir)
            )

        amiga = Amiga.get_model_config("A500")
        for sha1 in amiga["kickstarts"]:
            if fsgs.file.find_by_sha1(sha1=sha1):
                break
        else:
            file_database = FileDatabase.get_instance()
            cls.amiga_forever_kickstart_scan()
            file_database.commit()
コード例 #38
0
    def __init__(self, parent):
        fsui.Choice.__init__(self, parent)
        # FIXME: include in () what language is currently the automatic one

        selected_language = LauncherSettings.get("language")
        k = 0
        selected_index = 0
        for label, language_key, icon_name in LANGUAGE_ITEMS:
            self.add_item(
                label,
                fsui.Image("workspace:res/16/flag-{0}.png".format(icon_name)))
            if language_key == selected_language:
                selected_index = k
            k += 1
        if selected_index > 0:
            self.set_index(selected_index)
コード例 #39
0
    def kickstart_startup_scan(cls):
        if cls._kickstart_scanned:
            return
        cls._kickstart_scanned = True

        print("kickstart_startup_scan")
        kickstarts_dir = FSGSDirectories.get_kickstarts_dir()
        if LauncherSettings.get("kickstarts_dir_mtime") == \
                cls.get_dir_mtime_str(kickstarts_dir):
            print("... mtime not changed")
        else:
            file_database = FileDatabase.get_instance()
            print("... database.find_local_roms")
            local_roms = file_database.find_local_roms()
            print("... walk kickstarts_dir")
            for dir_path, dir_names, file_names in os.walk(kickstarts_dir):
                for file_name in file_names:
                    if not file_name.lower().endswith(".rom") and not \
                            file_name.lower().endswith(".bin"):
                        continue
                    path = Paths.join(dir_path, file_name)
                    if path in local_roms:
                        local_roms[path] = None
                        # already exists in database
                        continue
                    print("[startup] adding kickstart", path)
                    ROMManager.add_rom_to_database(path, file_database)
            print(local_roms)
            for path, file_id in local_roms.items():
                if file_id is not None:
                    print("[startup] removing kickstart", path)
                    file_database.delete_file(id=file_id)
            print("... commit")
            file_database.commit()
            LauncherSettings.set(
                "kickstarts_dir_mtime",
                cls.get_dir_mtime_str(kickstarts_dir))

        amiga = Amiga.get_model_config("A500")
        for sha1 in amiga["kickstarts"]:
            if fsgs.file.find_by_sha1(sha1=sha1):
                break
        else:
            file_database = FileDatabase.get_instance()
            cls.amiga_forever_kickstart_scan()
            file_database.commit()
コード例 #40
0
 def on_remove_button(self):
     path = self.list_view.get_item(self.list_view.get_index())
     search_path = LauncherSettings.get("search_path")
     search_path = [x.strip() for x in search_path.split(";") if x.strip()]
     for i in range(len(search_path)):
         if search_path[i].startswith("-"):
             if path == search_path[i][1:]:
                 # Already removed.
                 break
         else:
             if search_path[i] == path:
                 search_path.remove(search_path[i])
                 break
     default_paths = FSGSDirectories.get_default_search_path()
     if path in default_paths:
         search_path.append("-" + path)
     LauncherSettings.set("search_path", ";".join(search_path))
コード例 #41
0
        def observe(observer, scheduler):
            print(" -- new listener")
            # def listener(key, value):
            #     if key ==
            #     observer.on_next(value)

            # Broadcast initial value
            observer.on_next(LauncherSettings.get(key))
            listener = SettingListener(key, observer)
            # HACK, BECAUSE LauncherSettings do not keep ref
            SettingObservable.listeners.append(listener)
            LauncherSettings.add_listener(listener)

            def dispose():
                SettingObservable.listeners.remove(listener)
                LauncherSettings.remove_listener(listener)

            return Disposable(dispose)
コード例 #42
0
 def on_add_button(self):
     search_path = LauncherSettings.get("search_path")
     search_path = [x.strip() for x in search_path.split(";") if x.strip()]
     path = fsui.pick_directory(parent=self.get_window())
     if path:
         for i in range(len(search_path)):
             if search_path[i].startswith("-"):
                 if path == search_path[i][1:]:
                     search_path.remove(search_path[i])
                     break
             else:
                 if search_path[i] == path:
                     # Already added.
                     break
         else:
             default_paths = FSGSDirectories.get_default_search_path()
             if path not in default_paths:
                 search_path.append(path)
         LauncherSettings.set("search_path", ";".join(search_path))
コード例 #43
0
ファイル: paths.py プロジェクト: EdwardBetts/fs-uae-launcher
 def expand_path(cls, path, default_dir=None):
     if path and path[0] == "$":
         cmp_path = path.upper().replace("\\", "/")
         if cmp_path.startswith("$BASE/"):
             return cls.join(cls.get_base_dir(), path[6:])
         if cmp_path.startswith("$CONFIG/"):
             # FIXME: dependency loop, have FS-UAE Launcher register
             # this prefix with this class instead
             from launcher.launcher_settings import LauncherSettings
             config_path = LauncherSettings.get("config_path")
             if config_path:
                 return cls.join(os.path.dirname(config_path), path[8:])
         if cmp_path.startswith("$HOME/"):
             return cls.join(cls.get_home_dir(), path[6:])
         # FIXME: $base_dir is deprecated
         if cmp_path.startswith("$BASE_DIR/"):
             return cls.join(cls.get_base_dir(), path[10:])
     elif not os.path.isabs(path) and default_dir is not None:
         return os.path.join(default_dir, path)
     return path
コード例 #44
0
ファイル: paths.py プロジェクト: jelmer/fs-uae-debian
 def expand_path(cls, path, default_dir=None):
     if path and path[0] == "$":
         cmp_path = path.upper().replace("\\", "/")
         if cmp_path.startswith("$BASE/"):
             return cls.join(cls.get_base_dir(), path[6:])
         if cmp_path.startswith("$CONFIG/"):
             # FIXME: dependency loop, have FS-UAE Launcher register
             # this prefix with this class instead
             from launcher.launcher_settings import LauncherSettings
             config_path = LauncherSettings.get("config_path")
             if config_path:
                 return cls.join(os.path.dirname(config_path), path[8:])
         if cmp_path.startswith("$HOME/"):
             return cls.join(cls.get_home_dir(), path[6:])
         # FIXME: $base_dir is deprecated
         if cmp_path.startswith("$BASE_DIR/"):
             return cls.join(cls.get_base_dir(), path[10:])
     elif not os.path.isabs(path) and default_dir is not None:
         return os.path.join(default_dir, path)
     return path
コード例 #45
0
    def finish(self):
        database_cursor = self.database.cursor()

        # variants left in this list must now be deleted
        for row in self.existing_variants.values():
            variant_id = row[2]
            database_cursor.execute(
                "DELETE FROM game_variant WHERE id = ?", (variant_id,)
            )

        # games left in this list must now be deleted
        for row in self.existing_games.values():
            game_id = row[2]
            database_cursor.execute(
                "DELETE FROM game WHERE id = ?", (game_id,)
            )

        database_cursor.execute(
            "SELECT count(*) FROM game WHERE uuid IS NOT NULL "
            "AND (have IS NULL OR have != (SELECT coalesce(max(have), 0) "
            "FROM game_variant WHERE game_uuid = game.uuid))"
        )
        update_rows = database_cursor.fetchone()[0]
        print(update_rows, "game entries need update for have field")
        if update_rows > 0:
            database_cursor.execute(
                "UPDATE game SET have = (SELECT coalesce(max(have), 0) FROM "
                "game_variant WHERE game_uuid = game.uuid) WHERE uuid IS NOT "
                "NULL AND (have IS NULL OR have != (SELECT coalesce(max("
                "have), 0) FROM game_variant WHERE game_uuid = game.uuid))"
            )
        # FIXME: Remove this line?
        FileDatabase.get_instance().get_last_event_stamps()
        self.file_stamps["database_locker"] = LauncherSettings.get(
            Option.DATABASE_LOCKER
        )
        self.database.update_last_file_event_stamps(self.file_stamps)
コード例 #46
0
 def get_search_path(cls):
     paths = FSGSDirectories.get_default_search_path()
     search_path = LauncherSettings.get("search_path")
     for p in search_path.split(";"):
         p = p.strip()
         if not p:
             continue
         elif p[0] == "-":
             p = p[1:]
             if p in paths:
                 paths.remove(p)
         else:
             if p not in paths:
                 paths.append(p)
     # The Configurations dir is always scanned on startup (whenever
     # modification time has changed). If we don't include it here too
     # always, the result will be that the configs sometimes appear (on
     # startup) and disappear (on scan).
     if not FSGSDirectories.get_configurations_dir() in paths:
         paths.append(FSGSDirectories.get_configurations_dir())
     # Likewise, we force the Kickstarts directory to always be scanned.
     if not FSGSDirectories.get_kickstarts_dir() in paths:
         paths.append(FSGSDirectories.get_kickstarts_dir())
     return paths
コード例 #47
0
    def start_local_game_amiga(cls):
        # make sure x_kickstart_file is initialized
        LauncherConfig.set_kickstart_from_model()

        # if not Config.get("x_kickstart_file"):  # or not \
        #     #  os.path.exists(Config.get("kickstart_file")):
        #     fsui.show_error(
        #         gettext("No kickstart found for this model. Use the 'Import "
        #                 "Kickstarts' function from the menu."))
        #     return
        cs = Amiga.get_model_config(
            LauncherConfig.get("amiga_model"))["ext_roms"]
        if len(cs) > 0:
            # extended kickstart ROM is needed
            if not LauncherConfig.get("x_kickstart_ext_file"):
                fsui.show_error(
                    gettext("No extended kickstart found for this model. "
                            "Try 'scan' function."))
                return

        config = LauncherConfig.copy()
        prepared_config = cls.prepare_config(config)

        model = LauncherConfig.get("amiga_model")
        if model.startswith("CD32"):
            platform = "CD32"
        elif model == "CDTV":
            platform = "CDTV"
        else:
            platform = "Amiga"
        name = LauncherSettings.get("config_name")
        uuid = LauncherConfig.get("x_game_uuid")

        from fsgs.SaveStateHandler import SaveStateHandler
        save_state_handler = SaveStateHandler(fsgs, name, platform, uuid)

        from fsgs.amiga.LaunchHandler import LaunchHandler
        launch_handler = LaunchHandler(fsgs, name, prepared_config,
                                       save_state_handler)

        from .ui.launcher_window import LauncherWindow
        task = AmigaLaunchTask(launch_handler)
        # dialog = LaunchDialog(MainWindow.instance, launch_handler)
        dialog = LaunchDialog(
            LauncherWindow.current(), gettext("Launching FS-UAE"), task)
        dialog.show()

        def on_show_license_information(license_text):
            unused(license_text)
            # FIXME: don't depend on wx here
            # noinspection PyUnresolvedReferences
            # import wx
            # license_dialog = wx.MessageDialog(
            #     dialog, license_text, _("Terms of Use"),
            #     wx.OK | wx.CANCEL | wx.CENTRE)
            # license_dialog.CenterOnParent()
            # result = license_dialog.ShowModal()
            # return result == wx.ID_OK
            # FIXME
            return True

        fsgs.file.on_show_license_information = on_show_license_information

        LauncherConfig.set("__running", "1")
        task.start()
コード例 #48
0
    def __init__(self, parent):
        super().__init__(parent)
        icon = fsui.Icon("video-settings", "pkg:workspace")
        gettext("Video Synchronization Settings")
        title = gettext("Synchronization")
        subtitle = gettext("Synchronize FS-UAE with your display for "
                           "smooth video")
        self.add_header(icon, title, subtitle)

        label = fsui.MultiLineLabel(
            self,
            gettext(
                "Enabling the following option will synchronize the emulation "
                "to the display when the emulation refresh rate matches the"
                "screen refresh rate."), 640)
        self.layout.add(label, fill=True, margin_top=0)
        self.video_sync_group = self.add_option("video_sync")

        self.low_latency_group = self.add_option("low_latency_vsync")

        # label = fsui.MultiLineLabel(self, gettext(
        #     "Enabling the following option will prevent tearing from "
        #     "occurring, but will also use more CPU. Input latency "
        #     "may become slightly higher."), 640)
        # self.layout.add(label, fill=True, margin_top=0)
        # self.vblank_checkbox = fsui.HeadingCheckBox(self, gettext(
        #     "Synchronize buffer swaps with display (prevents tearing)"))
        # self.layout.add(self.vblank_checkbox, margin_top=20)

        self.sync_method_label = fsui.MultiLineLabel(
            self,
            gettext("Depending on your OS and OpenGL drivers, synchronizing "
                    "can use needlessly much CPU (esp. applies to "
                    "Linux). You can experiment with different sync methods "
                    "to improve performance."), 640)
        self.layout.add(self.sync_method_label, fill=True, margin_top=20)
        self.sync_method_group = self.add_option("video_sync_method")

        # self.smooth_label = fsui.MultiLineLabel(self, gettext(
        #     "In order to get really smooth Amiga graphics, you need to "
        #     "enable the following option, and also make sure your display "
        #     "is running at 50Hz (for PAL) or 60Hz (for NTSC)."), 640)
        # self.layout.add(self.smooth_label, fill=True, margin_top=20)
        # self.full_sync_checkbox = fsui.HeadingCheckBox(self, gettext(
        #     "Also synchronize emulation with display when possible "
        #     "(smooth scrolling)"))
        # self.layout.add(self.full_sync_checkbox, margin_top=20)

        self.layout.add_spacer(0, expand=True)

        hori_layout = fsui.HorizontalLayout()
        self.layout.add(hori_layout, fill=True, margin_top=10)
        hori_layout.add(
            fsui.ImageView(self,
                           fsui.Image("launcher:res/16x16/world_link.png")))
        label = fsui.URLLabel(
            self, gettext("How to achieve perfectly smooth scrolling"),
            "https://fs-uae.net/perfectly-smooth-scrolling")
        hori_layout.add(label, margin_left=6)

        text = gettext(
            "Synchronizing with the display can in some cases cause "
            "increased stuttering and low frame rates (esp. in some Linux "
            "desktop environments with compositing enabled).")
        link = (" <a href='https://fs-uae.net/video-synchronization-issues'>"
                "{0}</a>.".format(gettext("Read more")))

        label = fsui.MultiLineLabel(self, text + link, min_width=640)
        self.layout.add(label, fill=True, margin_top=20)

        LauncherSettings.add_listener(self)
        for key in ["video_sync"]:
            self.on_setting(key, LauncherSettings.get(key))
コード例 #49
0
 def has_close_buttons(self):
     return LauncherSettings.get(Option.LAUNCHER_CLOSE_BUTTONS) == "1"
コード例 #50
0
    def __init__(self, parent, index=0):
        PagedDialog.__init__(
            self,
            parent,
            "{} - {} Launcher".format(gettext("Settings"), fsgs.product),
        )

        # FIXME: remove this once the dialog uses Window as base class
        # self.setAttribute(Qt.WA_DeleteOnClose, True)

        # self.add_page(
        #     # gettext("Appearance"), LanguageSettingsPage,
        #     gettext("Language"), LanguageSettingsPage,
        #     fsui.Icon("language-settings", "pkg:workspace"))
        self.add_page(
            gettext("Common"),
            LanguageSettingsPage,
            fsui.Icon("language-settings", "pkg:workspace"),
            bold=True,
        )
        self.add_page(
            gettext("Controllers"),
            JoystickSettingsPage,
            fsui.Icon("gamepad", "pkg:workspace"),
        )
        self.add_page(
            gettext("Plugins"),
            PluginsSettingsPage,
            fsui.Icon("settings", "pkg:workspace"),
        )
        self.add_page(
            gettext("Directories"),
            DirectoriesSettingsPage,
            fsui.Icon("folder", "pkg:launcher"),
        )
        self.add_page(
            gettext("Advanced"),
            AdvancedSettingsPage,
            fsui.Icon("settings", "pkg:workspace"),
        )
        self.add_page(
            "FS-UAE",
            FSUAESettingsPage,
            fsui.Icon("fs-uae", "pkg:launcher"),
            bold=True,
        )
        self.add_page(
            gettext("Keyboard"),
            KeyboardSettingsPage,
            fsui.Icon("keyboard-settings", "pkg:workspace"),
        )
        self.add_page(
            gettext("Mouse"),
            MouseSettingsPage,
            fsui.Icon("mouse-settings", "pkg:workspace"),
        )
        self.add_page(
            gettext("Audio"),
            AudioSettingsPage,
            fsui.Icon("audio-settings", "pkg:workspace"),
        )
        self.add_page(
            gettext("Video"),
            VideoSettingsPage,
            fsui.Icon("video-settings", "pkg:workspace"),
        )
        self.add_page(
            gettext("Advanced Video"),
            AdvancedVideoSettingsPage,
            fsui.Icon("video-settings", "pkg:workspace"),
        )
        # self.add_page(
        #     gettext("Synchronization"), VideoSyncSettingsPage,
        #     fsui.Icon("video-settings", "pkg:workspace"))
        # self.add_page(
        #     gettext("Filters & Scaling"), FilterSettingsPage,
        #     fsui.Icon("video-settings", "pkg:workspace"))
        # self.add_page(gettext("OpenGL Settings"), OpenGLSettingsPage)
        # if Settings.get("database_feature") == "1":
        # self.add_page(
        #     gettext("Logging"), LoggingSettingsPage,
        #     fsui.Icon("settings", "pkg:workspace"))
        self.add_page(
            "{} Launcher".format(fsgs.product),
            LauncherSettingsPage,
            fsui.Icon("fs-uae-launcher", "pkg:launcher"),
            bold=True,
        )
        self.add_page(
            gettext("File Database"),
            ScanSettingsPage,
            fsui.Icon("indexing-settings", "pkg:workspace"),
        )
        self.add_page(
            gettext("Game Database"),
            GameDatabaseSettingsPage,
            fsui.Icon("database-settings", "pkg:workspace"),
        )
        if fsgs.openretro or settings.get(Option.PLATFORMS_FEATURE) == "1":
            self.add_page(
                gettext("Game Platforms"),
                GamePlatformsSettingsPage,
                fsui.Icon("database-settings", "pkg:workspace"),
            )
        # self.add_page(gettext("Custom Settings"), CustomSettingsPage)
        if LauncherSettings.get(Option.NETPLAY_FEATURE) != "0":
            self.add_page(
                gettext("Net Play"),
                NetplaySettingsPage,
                fsui.Icon("netplay-settings", "pkg:workspace"),
            )
        self.add_page(
            "WHDLoad", WHDLoadSettingsPage, fsui.Icon("hd", "pkg:launcher")
        )
        # self.add_page(
        #     gettext("Experimental Features"), ExperimentalFeaturesPage,
        #     fsui.Icon("settings", "pkg:workspace"))
        # self.add_page(
        #     gettext("Maintenance"), MaintenanceSettingsPage,
        #     fsui.Icon("maintenance", "pkg:workspace"))
        self.add_page(
            "{} Arcade".format(fsgs.product),
            ArcadeSettingsPage,
            fsui.Icon("fs-uae-arcade", "pkg:launcher"),
            bold=True,
        )

        # Old texts
        # gettext("Video Synchronization")
        # gettext("Synchronization")
        gettext("Advanced")

        last_index = self.get_page_index_by_title(
            LauncherSettings.get("last_settings_page")
        )
        index = last_index or index
        self.list_view.set_index(index)

        defaults_button = fsui.Button(self, gettext("Reset to Defaults"))
        defaults_button.activated.connect(self.__defaults_activated)
        self.button_layout.insert(0, defaults_button, fill=True)

        defaults_label = fsui.Label(
            self, gettext("Choices marked with (*) is the default setting")
        )
        self.button_layout.insert(1, defaults_label, margin_left=20)

        self.set_size((940, 560))
        # self.center_on_parent()

        self.closed.connect(self.__closed)
        self.page_changed.connect(self.__page_changed)
コード例 #51
0
    def __init__(self, parent):
        fsui.Panel.__init__(self, parent)
        Skin.set_background_color(self)
        self.layout = fsui.HorizontalLayout()

        vert_layout = fsui.VerticalLayout()
        self.layout.add(vert_layout, fill=True, expand=True)

        hor_layout = fsui.HorizontalLayout()
        vert_layout.add(hor_layout, fill=True)

        label_stand_in = fsui.Panel(self)
        tw, th = label_stand_in.measure_text("Games")
        label_stand_in.set_min_height(th)
        hor_layout.add(label_stand_in, margin_top=10, margin_bottom=10)

        hor_layout.add(NewButton(self), margin_left=10, margin_right=10)

        game_list_selector = GameListSelector(self)
        game_list_selector.set_min_width(250)
        game_list_selector.setMaximumWidth(250)
        game_list_selector.changed.connect(self.on_game_list_changed)
        hor_layout.add(game_list_selector, expand=False, margin_left=10)

        self.text_field = fsui.TextField(
            self, LauncherSettings.get("config_search"))
        self.text_field.on_changed = self.on_search_changed
        if VariantsBrowser.use_horizontal_layout():
            # window is big enough to use fixed size
            # self.text_field.set_min_width(210)
            self.text_field.set_min_width(229)
            hor_layout.add(
                self.text_field, expand=False, margin=10, margin_top=0,
                margin_bottom=0)
        else:
            hor_layout.add(
                self.text_field, expand=True, margin=10, margin_top=0,
                margin_bottom=0)

        # self.refresh_button = IconButton(self, "refresh_button.png")
        # self.refresh_button.set_tooltip(
        #     gettext("Refresh Game Configurations from Online Database"))
        # self.refresh_button.activated.connect(self.on_refresh_button)
        # hor_layout.add(
        #     self.refresh_button, margin=10, margin_top=0, margin_bottom=0)

        self.configurations_browser = ConfigurationsBrowser(self)

        vert_layout.add(
            self.configurations_browser, fill=True, expand=3, margin=10)

        self.variants_panel = fsui.Panel(self)
        vert_layout.add(self.variants_panel, fill=True, expand=False,
                        margin=10, margin_top=20)

        self.variants_panel.layout = fsui.HorizontalLayout()
        self.variants_browser = VariantsBrowser(self.variants_panel)
        # Do not use fill=True with the default OS X theme at least,
        # if you do the item will be rendered with the old Aqua look
        self.variants_panel.layout.add(
            self.variants_browser, fill=False, expand=True)

        # for rating in [1, 4, 5]:
        #     button = RatingButton(self.variants_panel, rating)
        #     self.variants_panel.layout.add(button, margin_left=5, fill=True)

        self.variants_panel.layout.add(
            RatingChoice(self.variants_panel), margin_left=5, fill=True)

        self.config_panel = fsui.Panel(self)
        vert_layout.add(self.config_panel, fill=True, expand=False,
                        margin_bottom=10, margin_top=20)

        self.config_panel.layout = fsui.VerticalLayout()
        self.config_group = ConfigGroup(self.config_panel, new_button=False)
        self.config_panel.layout.add(self.config_group, fill=True, expand=True)

        LauncherSettings.add_listener(self)
        self.on_setting("parent_uuid", LauncherSettings.get("parent_uuid"))
コード例 #52
0
    def save_config():
        print("SaveButton.save_config")
        database = Database.get_instance()

        name = LauncherSettings.get("config_name").strip()
        if not name:
            print("no config_name")
            # FIXME: notify user
            return

        file_name = name + ".fs-uae"
        path = os.path.join(FSGSDirectories.get_configurations_dir(),
                            file_name)
        with io.open(path, "w", encoding="UTF-8") as f:
            f.write("# FS-UAE configuration saved by FS-UAE Launcher\n")
            f.write("# Last saved: {0}\n".format(
                datetime.datetime.today().strftime("%Y-%m-%d %H:%M:%S")))
            f.write("\n[fs-uae]\n")
            keys = sorted(fsgs.config.values.keys())
            for key in keys:
                value = LauncherConfig.get(key)
                if key.startswith("__"):
                    continue
                if key in LauncherConfig.no_save_keys_set:
                    continue
                # elif key == "joystick_port_2_mode" and value == "nothing":
                #     continue
                # elif key == "joystick_port_3_mode" and value == "nothing":
                #     continue
                if value == LauncherConfig.default_config.get(key, ""):
                    continue
                if value:
                    f.write("{0} = {1}\n".format(key, value))

        # scanner = ConfigurationScanner()
        # search = ConfigurationScanner.create_configuration_search(name)
        # name = scanner.create_configuration_name(name)
        # print("adding", path)
        # # deleting the path from the database first in case it already exists
        # database.delete_configuration(path=path)
        # database.delete_file(path=path)
        # database.add_file(path=path)
        # database.add_configuration(
        #     path=path, uuid="", name=name, scan=0, search=search)

        file_database = FileDatabase.get_instance()
        scanner = ConfigurationScanner()
        print("[save config] adding config", path)
        file_database.delete_file(path=path)
        with open(path, "rb") as f:
            sha1 = hashlib.sha1(f.read()).hexdigest()
        file_database.add_file(path=path, sha1=sha1)

        game_id = database.add_configuration(
            path=path, name=scanner.create_configuration_name(name))
        database.update_game_search_terms(game_id,
                                          scanner.create_search_terms(name))

        database.commit()
        file_database.commit()

        LauncherSettings.set("__config_refresh", str(time.time()))
        # Settings.set("config_changed", "0")
        LauncherConfig.set("__changed", "0")
コード例 #53
0
 def get(key):
     return LauncherSettings.get(key)
コード例 #54
0
ファイル: savebutton.py プロジェクト: glaubitz/fs-uae-debian
    def save_config():
        print("SaveButton.save_config")
        database = Database.get_instance()

        name = LauncherSettings.get("config_name").strip()
        if not name:
            print("no config_name")
            # FIXME: notify user
            return

        file_name = name + ".fs-uae"
        path = os.path.join(
            FSGSDirectories.get_configurations_dir(), file_name)
        with io.open(path, "w", encoding="UTF-8") as f:
            f.write("# FS-UAE configuration saved by FS-UAE Launcher\n")
            f.write("# Last saved: {0}\n".format(
                    datetime.datetime.today().strftime("%Y-%m-%d %H:%M:%S")))
            f.write("\n[fs-uae]\n")
            keys = sorted(fsgs.config.values.keys())
            for key in keys:
                value = LauncherConfig.get(key)
                if key.startswith("__"):
                    continue
                if key in LauncherConfig.no_save_keys_set:
                    continue
                # elif key == "joystick_port_2_mode" and value == "nothing":
                #     continue
                # elif key == "joystick_port_3_mode" and value == "nothing":
                #     continue
                if value == LauncherConfig.default_config.get(key, ""):
                    continue
                if value:
                    f.write("{0} = {1}\n".format(key, value))

        # scanner = ConfigurationScanner()
        # search = ConfigurationScanner.create_configuration_search(name)
        # name = scanner.create_configuration_name(name)
        # print("adding", path)
        # # deleting the path from the database first in case it already exists
        # database.delete_configuration(path=path)
        # database.delete_file(path=path)
        # database.add_file(path=path)
        # database.add_configuration(
        #     path=path, uuid="", name=name, scan=0, search=search)

        file_database = FileDatabase.get_instance()
        scanner = ConfigurationScanner()
        print("[save config] adding config", path)
        file_database.delete_file(path=path)
        with open(path, "rb") as f:
            sha1 = hashlib.sha1(f.read()).hexdigest()
        file_database.add_file(path=path, sha1=sha1)

        game_id = database.add_game(
            path=path, name=scanner.create_configuration_name(name))
        database.update_game_search_terms(
            game_id, scanner.create_search_terms(name))

        database.commit()
        file_database.commit()

        LauncherSettings.set("__config_refresh", str(time.time()))
        # Settings.set("config_changed", "0")
        LauncherConfig.set("__changed", "0")
コード例 #55
0
    def __init__(self, parent):
        super().__init__(parent)
        icon = fsui.Icon("video-settings", "pkg:workspace")
        gettext("Video Synchronization Settings")
        title = gettext("Synchronization")
        subtitle = gettext("Synchronize FS-UAE with your display for "
                           "smooth video")
        self.add_header(icon, title, subtitle)

        label = fsui.MultiLineLabel(self, gettext(
            "Enabling the following option will synchronize the emulation "
            "to the display when the emulation refresh rate matches the"
            "screen refresh rate."), 640)
        self.layout.add(label, fill=True, margin_top=0)
        self.video_sync_group = self.add_option("video_sync")

        self.low_latency_group = self.add_option("low_latency_vsync")

        # label = fsui.MultiLineLabel(self, gettext(
        #     "Enabling the following option will prevent tearing from "
        #     "occurring, but will also use more CPU. Input latency "
        #     "may become slightly higher."), 640)
        # self.layout.add(label, fill=True, margin_top=0)
        # self.vblank_checkbox = fsui.HeadingCheckBox(self, gettext(
        #     "Synchronize buffer swaps with display (prevents tearing)"))
        # self.layout.add(self.vblank_checkbox, margin_top=20)

        self.sync_method_label = fsui.MultiLineLabel(self, gettext(
            "Depending on your OS and OpenGL drivers, synchronizing "
            "can use needlessly much CPU (esp. applies to "
            "Linux). You can experiment with different sync methods "
            "to improve performance."), 640)
        self.layout.add(self.sync_method_label, fill=True, margin_top=20)
        self.sync_method_group = self.add_option("video_sync_method")

        # self.smooth_label = fsui.MultiLineLabel(self, gettext(
        #     "In order to get really smooth Amiga graphics, you need to "
        #     "enable the following option, and also make sure your display "
        #     "is running at 50Hz (for PAL) or 60Hz (for NTSC)."), 640)
        # self.layout.add(self.smooth_label, fill=True, margin_top=20)
        # self.full_sync_checkbox = fsui.HeadingCheckBox(self, gettext(
        #     "Also synchronize emulation with display when possible "
        #     "(smooth scrolling)"))
        # self.layout.add(self.full_sync_checkbox, margin_top=20)

        self.layout.add_spacer(0, expand=True)

        hori_layout = fsui.HorizontalLayout()
        self.layout.add(hori_layout, fill=True, margin_top=10)
        hori_layout.add(fsui.ImageView(self, fsui.Image(
            "launcher:res/16/world_link.png")))
        label = fsui.URLLabel(self, gettext(
            "How to achieve perfectly smooth scrolling"),
                              "http://fs-uae.net/perfectly-smooth-scrolling")
        hori_layout.add(label, margin_left=6)

        text = gettext(
            "Synchronizing with the display can in some cases cause "
            "increased stuttering and low frame rates (esp. in some Linux "
            "desktop environments with compositing enabled).")
        link = (" <a href='https://fs-uae.net/video-synchronization-issues'>"
                "{0}</a>.".format(gettext("Read more")))

        label = fsui.MultiLineLabel(self, text + link, min_width=640)
        self.layout.add(label, fill=True, margin_top=20)

        LauncherSettings.add_listener(self)
        for key in ["video_sync"]:
            self.on_setting(key, LauncherSettings.get(key))
コード例 #56
0
    def create_group(
        cls, parent, name, description=None, help_button=True, thin=False
    ):
        group = fsui.Group(parent)
        group.layout = fsui.HorizontalLayout()
        if thin:
            thin_layout = fsui.VerticalLayout()
            thin_layout.add(group.layout, fill=True)
        option = Option.get(name)
        if description == "":
            description = gettext(option["description"])
        if description:
            group.label = fsui.Label(group, description + ":")
            group.layout.add(group.label, margin_right=10)
            group.layout.add(OverrideWarning(group, name), margin_right=10)

        if thin:
            group.layout = fsui.HorizontalLayout()
            if description:
                thin_layout.add(group.layout, fill=True, margin_top=6)
            else:
                thin_layout.add(group.layout, fill=True, margin_top=0)

        choice_values = []

        if description:
            default_tmpl = "{0} (*)"
            # default_tmpl = "Default - {0}"
        else:
            default_tmpl = "{0} (*)"
            # default_tmpl = "Default - {0}"

        if option["type"].lower() == "boolean":
            if option["default"] == "1":
                default_desc = gettext(default_tmpl).format(gettext("On"))
            elif option["default"] == "0":
                default_desc = gettext(default_tmpl).format(gettext("Off"))
            else:
                default_desc = gettext("Default")
            choice_values.append(("", default_desc))
            choice_values.append(("1", gettext("On")))
            choice_values.append(("0", gettext("Off")))

        elif option["type"].lower() == "choice":
            for i, value in enumerate(option["values"]):
                if option["default"] == value[0]:
                    default_desc = gettext(default_tmpl).format(
                        gettext(value[1])
                    )
                    break
            else:
                default_desc = gettext("Default")
            choice_values.append(("", default_desc))
            for option in option["values"]:
                choice_values.append((option[0], gettext(option[1])))

        elif option["type"].lower() == "string":

            def on_changed():
                val = text_field.get_text()
                LauncherSettings.set(name, val.strip())

            text_field = fsui.TextField(group)
            # text_field.set_min_width(400)
            text_field.set_text(LauncherSettings.get(name))
            text_field.on_changed = on_changed
            group.layout.add(text_field, expand=True)

        elif (
            option["type"].lower() == "integer"
            and "min" in option
            and "max" in option
        ):
            current = LauncherSettings.get(name)

            if name == Option.LAUNCHER_FONT_SIZE:
                font = app.qapplication.font()
                Option.get(Option.LAUNCHER_FONT_SIZE)[
                    "default"
                ] = font.pointSize()

            current_int = int(option["default"])
            if current:
                try:
                    current_int = int(current)
                except ValueError:
                    pass
            current_int = max(option["min"], min(option["max"], current_int))
            check_box = fsui.CheckBox(group, gettext("Default"))
            spin_ctrl = fsui.SpinCtrl(
                group, option["min"], option["max"], current_int
            )
            if current == "":
                check_box.check()
                spin_ctrl.disable()

            def on_checkbox():
                if check_box.is_checked():
                    spin_ctrl.set_value(int(option["default"]))
                    spin_ctrl.disable()
                    LauncherSettings.set(name, "")
                else:
                    spin_ctrl.enable()

            check_box.on_changed = on_checkbox

            def on_spin():
                val = spin_ctrl.get_value()
                val = max(option["min"], min(option["max"], val))
                LauncherSettings.set(name, str(val))

            spin_ctrl.on_changed = on_spin
            group.layout.add_spacer(0, expand=True)
            group.layout.add(check_box)
            group.layout.add(spin_ctrl, margin_left=10)

        if choice_values:

            def on_changed():
                index = choice.get_index()
                LauncherSettings.set(name, choice_values[index][0])

            choice_labels = [x[1] for x in choice_values]
            choice = fsui.Choice(group, choice_labels)
            current = LauncherSettings.get(name)
            for i, value in enumerate(choice_values):
                if current == value[0]:
                    choice.set_index(i)
                    break
            choice.on_changed = on_changed
            if thin:
                group.layout.add(choice, expand=True)
            else:
                group.layout.add_spacer(0, expand=True)
                group.layout.add(choice)
            group.widget = choice

        if help_button:
            option_url = "https://fs-uae.net/docs/options/" + name.replace(
                "_", "-"
            )
            group.help_button = HelpButton(parent, option_url)
            group.layout.add(group.help_button, margin_left=10)

        if thin:
            group.layout = thin_layout
        return group