Skip to content

Commit

Permalink
rework iter display options to not include header
Browse files Browse the repository at this point in the history
  • Loading branch information
apple1417 committed Jan 20, 2024
1 parent aa9764e commit 707a403
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 62 deletions.
54 changes: 51 additions & 3 deletions src/bl3_mod_menu/options_setup.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import functools
from collections.abc import Sequence
from collections.abc import Iterator, Sequence
from dataclasses import dataclass
from typing import Any

Expand All @@ -9,6 +9,7 @@
BoolOption,
ButtonOption,
DropdownOption,
Game,
GroupedOption,
KeybindOption,
Mod,
Expand Down Expand Up @@ -187,6 +188,53 @@ def get_option_header() -> str:
)


def get_mod_options(mod: Mod) -> tuple[BaseOption, ...]:
"""
Gets the full list of mod options to display, including our custom header.
Args:
mod: The mod to get the options list of.
Returns:
A tuple of the options to display.
"""

def inner() -> Iterator[BaseOption]:
# Display the author and version in the title, if they're not the empty string
description_title = ""
if mod.author:
description_title += f"By {mod.author}"
if mod.author and mod.version:
description_title += " - "
if mod.version:
description_title += mod.version
description_title = description_title or "Description"

description = mod.description
if Game.get_current() not in mod.supported_games:
supported = [g.name for g in Game if g in mod.supported_games]
description = (
"<font color='#ffff00'>Incompatible Game!</font>\r"
"This mod supports: " + ", ".join(supported) + "\n\n" + description
)

yield ButtonOption(
"Description",
description=description,
description_title=description_title,
)

if not mod.enabling_locked:
yield BoolOption(
"Enabled",
mod.is_enabled,
on_change=lambda _, now_enabled: mod.enable() if now_enabled else mod.disable(),
)

yield from mod.iter_display_options()

return tuple(inner())


def open_options_menu(main_menu: UObject, mod: Mod) -> None:
"""
Opens the options menu for a particular mod.
Expand All @@ -199,7 +247,7 @@ def open_options_menu(main_menu: UObject, mod: Mod) -> None:
open_custom_options(
main_menu,
get_option_header(),
functools.partial(draw_options, options=tuple(mod.iter_display_options()), group_stack=[]),
functools.partial(draw_options, options=get_mod_options(mod), group_stack=[]),
)


Expand All @@ -220,7 +268,7 @@ def refresh_current_options_menu(options_menu: UObject, preserve_scroll: bool =
functools.partial(
draw_options,
options=(
tuple(option_info.cause.iter_display_options())
get_mod_options(option_info.cause)
if isinstance(option_info.cause, Mod)
else option_info.cause.children
),
Expand Down
30 changes: 30 additions & 0 deletions src/console_mod_menu/screens/mod.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,28 @@ def __post_init__(self) -> None:
def draw(self) -> None: # noqa: D102
draw_stack_header()

header = ""
if self.mod.author:
header += f"By {self.mod.author}"
if self.mod.author and self.mod.version:
header += " - "
if self.mod.version:
header += self.mod.version
draw(header)

draw(self.mod.get_status())
draw("")

if self.mod.description:
draw(self.mod.description)
draw("")

if not self.mod.enabling_locked:
if self.mod.is_enabled:
draw("[D] Disable")
else:
draw("[E] Enable")

self.drawn_options = []
self.draw_options_list(self.mod.iter_display_options(), [])

Expand All @@ -136,6 +158,14 @@ def handle_input(self, line: str) -> bool: # noqa: D102
if handle_standard_command_input(line):
return True

if not self.mod.enabling_locked:
if self.mod.is_enabled and line.lower() == "d":
self.mod.disable()
return True
if not self.mod.is_enabled and line.lower() == "e":
self.mod.enable()
return True

return self.handle_option_input(line)


Expand Down
76 changes: 17 additions & 59 deletions src/mods_base/mod.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,7 @@
from .command import AbstractCommand
from .hook import HookProtocol
from .keybinds import KeybindType
from .options import (
BaseOption,
BoolOption,
ButtonOption,
GroupedOption,
KeybindOption,
NestedOption,
)
from .options import BaseOption, GroupedOption, KeybindOption, NestedOption
from .settings import default_load_mod_settings, default_save_mod_settings


Expand Down Expand Up @@ -121,7 +114,9 @@ class Mod:
hooks: The mod's hooks. If not given, searches for them in instance variables.
commands: The mod's commands. If not given, searches for them in instance variables.
Attributes - Runtime:
Attributes - Enabling:
enabling_locked: If true, the mod cannot be enabled or disabled, it's locked in it's current
state. Set automatically, not available in constructor.
is_enabled: True if the mod is currently considered enabled. Not available in constructor.
auto_enable: True if to enable the mod on launch if it was also enabled last time.
on_enable: A no-arg callback to run on mod enable. Useful when constructing via dataclass.
Expand All @@ -144,6 +139,7 @@ class Mod:
hooks: Sequence[HookProtocol] = field(default=None) # type: ignore
commands: Sequence[AbstractCommand] = field(default=None) # type: ignore

enabling_locked: bool = field(init=False)
is_enabled: bool = field(default=False, init=False)
auto_enable: bool = True
on_enable: Callable[[], None] | None = None
Expand Down Expand Up @@ -194,11 +190,13 @@ def __post_init__(self) -> None:
for option in self.options:
option.mod = self

self.enabling_locked = Game.get_current() not in self.supported_games

def enable(self) -> None:
"""Called to enable the mod."""
if self.is_enabled:
if self.enabling_locked:
return
if Game.get_current() not in self.supported_games:
if self.is_enabled:
return

self.is_enabled = True
Expand All @@ -224,6 +222,8 @@ def disable(self, dont_update_setting: bool = False) -> None:
dont_update_setting: If true, prevents updating the enabled flag in the settings file.
Should be set for automated disables, and clear for manual ones.
"""
if self.enabling_locked:
return
if not self.is_enabled:
return

Expand Down Expand Up @@ -263,39 +263,10 @@ def iter_display_options(self) -> Iterator[BaseOption]:
Yields:
Options, in the order they should be displayed.
"""
compatible_game = Game.get_current() in self.supported_games

if not compatible_game:
yield ButtonOption(
"Incompatible Game!",
description=f"This mod is incompatible with {Game.get_current().name}!",
)

# Displat the author and version in the title, if they're not the empty string
description_title = ""
if self.author:
description_title += f"By {self.author}"
if self.author and self.version:
description_title += " - "
if self.version:
description_title += self.version

yield ButtonOption(
"Description",
description=self.description,
description_title=description_title or "Description",
)
if compatible_game:
yield BoolOption(
"Enabled",
self.is_enabled,
on_change=lambda _, now_enabled: self.enable() if now_enabled else self.disable(),
)

if any(not opt.is_hidden for opt in self.options) > 0:
if any(not opt.is_hidden for opt in self.options):
yield GroupedOption("Options", self.options)

if any(not kb.is_hidden for kb in self.keybinds) > 0:
if any(not kb.is_hidden for kb in self.keybinds):
yield GroupedOption(
"Keybinds",
[KeybindOption.from_keybind(bind) for bind in self.keybinds],
Expand All @@ -316,21 +287,8 @@ class Library(Mod):
def __post_init__(self) -> None:
super().__post_init__()

if Game.get_current() in self.supported_games:
# Enable if not already locked due to an incompatible game
if not self.enabling_locked:
self.enable()

def disable(self, dont_update_setting: bool = False) -> None:
"""No-op to prevent the library from being disabled."""

def iter_display_options(self) -> Iterator[BaseOption]:
"""Custom display options, which remove the enabled switch."""
seen_enabled = False
for option in super().iter_display_options():
if (
not seen_enabled
and option.identifier == "Enabled"
and isinstance(option, BoolOption)
):
seen_enabled = True
continue
yield option
# And then lock
self.enabling_locked = True

0 comments on commit 707a403

Please sign in to comment.