Ejemplo n.º 1
0
    def ShowConfiguration(self) -> None:
        inputBox = TextInputBox("Configure Console Command", self.Command)

        def OnSubmit(msg: str) -> None:
            if len(msg) != 0:
                self.Command = msg
            self.OnFinishConfiguration()

        inputBox.OnSubmit = OnSubmit  # type: ignore
        inputBox.Show()
Ejemplo n.º 2
0
class PresetManager:
    Option: Options.Hidden
    PresetList: List[Preset]
    CheatList: List[ABCCheat]

    _NewPreset: ClassVar[OptionBoxButton] = OptionBoxButton(
        "Create New Preset")
    _OpenPresetFile: ClassVar[OptionBoxButton] = OptionBoxButton(
        "Open Settings File",
        ("Useful for reordering or sharing presets."
         " The game will have to be restarted for changes to apply."))
    _EditPreset: ClassVar[OptionBoxButton] = OptionBoxButton("Configure")
    _RenamePreset: ClassVar[OptionBoxButton] = OptionBoxButton("Rename")
    _DeletePreset: ClassVar[OptionBoxButton] = OptionBoxButton("Delete")
    _Yes: ClassVar[OptionBoxButton] = OptionBoxButton("Yes")
    _No: ClassVar[OptionBoxButton] = OptionBoxButton("No")

    _ConfigureBox: OptionBox
    _ButtonPresetMap: Dict[str, Preset]

    _CurrentPreset: Optional[Preset]
    _PresetActionBox: OptionBox
    _ConfirmDeleteBox: OptionBox

    _RenameBox: TextInputBox

    def __init__(self, Option: Options.Hidden, CheatList: List[ABCCheat]):
        self.Option = Option
        self.CheatList = CheatList

        # Move legacy presets into the option
        legacy_path = os.path.join(os.path.dirname(__file__), "Presets.json")
        try:
            loaded_data = []
            with open(legacy_path) as file:
                loaded_data = json.load(file)
            os.remove(legacy_path)
            self.Option.CurrentValue = loaded_data
        except (FileNotFoundError, json.JSONDecodeError):
            pass

        self.LoadPresets()

        self._ConfigureBox = OptionBox(
            Title="Configure Presets",
            Caption="Select the preset you want to configure",
            Tooltip=OptionBox.CreateTooltipString(EscMessage="Exit"),
            Buttons=(
                self._NewPreset,
                self._OpenPresetFile,
            ),
        )
        self._ConfigureBox.OnPress = self._SelectSpecificPreset  # type: ignore
        self._UpdateConfigureBox()

        self._CurrentPreset = None

        # These two dialog boxes are mostly the constant, we'll just update their title as needed
        self._PresetActionBox = OptionBox(
            Title="Selected 'PRESET NAME'",
            Caption="Select the action to perform on this preset",
            Tooltip=OptionBox.CreateTooltipString(EscMessage="Back"),
            Buttons=(self._EditPreset, self._RenamePreset, self._DeletePreset),
        )
        self._PresetActionBox.OnPress = self._SelectPresetAction  # type: ignore
        self._PresetActionBox.OnCancel = self.StartConfiguring  # type: ignore

        self._ConfirmDeleteBox = OptionBox(
            Title="Delete 'PRESET NAME'",
            Caption="Are you sure you want to delete this preset?",
            Tooltip=OptionBox.CreateTooltipString(EscMessage="Back"),
            Buttons=(self._No, self._Yes),
        )
        self._ConfirmDeleteBox.OnPress = self._OnConfirmDelete  # type: ignore
        self._ConfirmDeleteBox.OnCancel = lambda: self._OnConfirmDelete(
            None)  # type: ignore

        self._RenameBox = TextInputBox("Rename 'PRESET NAME'")
        self._RenameBox.OnSubmit = self._OnPresetRename  # type: ignore

    def LoadPresets(self) -> None:
        self.PresetList = []
        for idx, current_dict in enumerate(self.Option.CurrentValue):
            name: str = f"Preset {idx}"
            settings: Dict[str, str] = {}

            if "Name" in current_dict:
                name = html.escape(str(current_dict["Name"]))

            if "Settings" in current_dict and isinstance(
                    current_dict["Settings"], dict):
                settings = current_dict["Settings"]
                # Sanity-check the data
                for cheat in self.CheatList:
                    if cheat.Name in settings:
                        value = settings[cheat.Name]
                        # We don't really care what this value is for regular cheats, but better to
                        #  keep it consistent
                        if not isinstance(cheat, ABCCycleableCheat):
                            value = "Run"
                        settings[cheat.Name] = value

            current_preset = Preset(name, settings, self.CheatList)
            current_preset.OnFinishConfiguring = self._OnFinishConfiguringPreset  # type: ignore
            self.PresetList.append(current_preset)

        # If there are no valid presets then still add the first one
        if len(self.PresetList) == 0:
            new_preset = Preset("Preset 1", {}, self.CheatList)
            new_preset.OnFinishConfiguring = self._OnFinishConfiguringPreset  # type: ignore
            self.PresetList.append(new_preset)

    def SavePresets(self) -> None:
        data = []
        for preset in self.PresetList:
            data.append({
                "Name": html.unescape(preset.Name),
                "Settings": preset.GetSettings()
            })

        self.Option.CurrentValue = data
        self.SaveOptions()

    def StartConfiguring(self) -> None:
        self._UpdateConfigureBox()
        self._ConfigureBox.Show()

    # The next four functions should be overwritten by the main mod
    def AddKeybind(self, Name: str) -> None:
        raise NotImplementedError

    def RenameKeybind(self, OldName: str, NewName: str) -> None:
        raise NotImplementedError

    def RemoveKeybind(self, Name: str) -> None:
        raise NotImplementedError

    def SaveOptions(self) -> None:
        raise NotImplementedError

    def _OnFinishConfiguringPreset(self) -> None:
        self.SavePresets()
        self.StartConfiguring()

    def _UpdateConfigureBox(self) -> None:
        button_list = []
        self._ButtonPresetMap = {}
        for preset in self.PresetList:
            button = OptionBoxButton(html.unescape(preset.Name))
            button_list.append(button)
            self._ButtonPresetMap[button.Name] = preset

        button_list += [
            self._NewPreset,
            self._OpenPresetFile,
        ]

        self._ConfigureBox.Buttons = button_list
        self._ConfigureBox.Update()

    def _SelectSpecificPreset(self, button: OptionBoxButton) -> None:
        if button == self._NewPreset:
            # Get a new default name that's at least the size of the list + 1, or the largest
            #  existing default name + 1
            # This makes renaming or deleting cheats still add a somewhat logical name
            max_val = len(self.PresetList)
            for preset in self.PresetList:
                val: int
                try:
                    val = int(preset.Name.split(" ")[-1])
                except ValueError:
                    continue
                if val > max_val:
                    max_val = val
            name = f"Preset {max_val + 1}"

            new_preset = Preset(name, {}, self.CheatList)
            new_preset.OnFinishConfiguring = self._OnFinishConfiguringPreset  # type: ignore
            self.PresetList.append(new_preset)

            self.AddKeybind(name)

            self.SavePresets()
        elif button == self._OpenPresetFile:
            settings_path = os.path.join(os.path.dirname(__file__),
                                         "settings.json")
            os.startfile(settings_path)

        if button.Name in self._ButtonPresetMap:
            self._CurrentPreset = self._ButtonPresetMap[button.Name]
            self._PresetActionBox.Title = f"Selected '{self._CurrentPreset.Name}'"
            self._PresetActionBox.Update()
            self._PresetActionBox.Show()
            return

        self.StartConfiguring()

    def _SelectPresetAction(self, button: OptionBoxButton) -> None:
        if self._CurrentPreset is None:
            raise RuntimeError("Current Preset is None")
        if button == self._EditPreset:
            self._CurrentPreset.StartConfiguring()
            self._CurrentPreset = None
        elif button == self._RenamePreset:
            self._RenameBox.Title = f"Rename '{self._CurrentPreset.Name}'"
            self._RenameBox.DefaultMessage = self._CurrentPreset.Name
            self._RenameBox.Show()
        elif button == self._DeletePreset:
            self._ConfirmDeleteBox.Title = f"Delete '{self._CurrentPreset.Name}'"
            self._ConfirmDeleteBox.Update()
            self._ConfirmDeleteBox.Show()

    def _OnPresetRename(self, msg: str) -> None:
        if self._CurrentPreset is None:
            raise RuntimeError("Current Preset is None")

        if len(msg) > 0:
            self.RenameKeybind(self._CurrentPreset.Name, msg)

            self._ButtonPresetMap[msg] = self._ButtonPresetMap[
                self._CurrentPreset.Name]
            del self._ButtonPresetMap[self._CurrentPreset.Name]

            self._CurrentPreset.UpdateName(msg)
            self.SavePresets()
            self._UpdateConfigureBox()

        self._PresetActionBox.Title = f"Selected '{self._CurrentPreset.Name}'"
        self._PresetActionBox.Update()
        self._PresetActionBox.Show(self._RenamePreset)

    def _OnConfirmDelete(self, button: Optional[OptionBoxButton]) -> None:
        if self._CurrentPreset is None:
            raise RuntimeError("Current Preset is None")
        if button == self._Yes:
            self.PresetList.remove(self._CurrentPreset)
            self.RemoveKeybind(self._CurrentPreset.Name)
            self._CurrentPreset = None
            self.SavePresets()
            self.StartConfiguring()
        else:
            self._PresetActionBox.Show()