stole the settings menu from my Berry IDE lol
This commit is contained in:
59
src/settings_store.py
Normal file
59
src/settings_store.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from textual.app import App
|
||||
from pathlib import Path
|
||||
import os
|
||||
import configparser
|
||||
from typing import Any
|
||||
|
||||
|
||||
class ConfigHandler:
|
||||
def __init__(self, app: App):
|
||||
self.app: App = app
|
||||
self.config: configparser.ConfigParser = configparser.ConfigParser()
|
||||
|
||||
self.plugin_defined_settings = {}
|
||||
self.config_dir: str = self.ensure_hidden_config_dir()
|
||||
self.load_settings()
|
||||
|
||||
def ensure_hidden_config_dir(self):
|
||||
config_dir = Path.home() / ".termdaw"
|
||||
config_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
return config_dir
|
||||
|
||||
def get(self, section: str, option: str):
|
||||
if not self.config.has_section(section):
|
||||
self.config.add_section(section)
|
||||
if not self.config.has_option(section, option):
|
||||
self.set(section, option, "0")
|
||||
return "0"
|
||||
|
||||
return self.config.get(section, option, fallback=None)
|
||||
|
||||
def set(self, section: str, option: str, new_value: str):
|
||||
if not self.config.has_section(section):
|
||||
self.config.add_section(section)
|
||||
self.config.set(section, option, new_value)
|
||||
|
||||
self.write_settings()
|
||||
|
||||
def apply_settings(self):
|
||||
self.app.theme = self.get("appearance", "colour_theme")
|
||||
|
||||
def write_settings(self):
|
||||
with open(self.config_dir / "config.ini", "w") as configfile:
|
||||
self.config.write(configfile)
|
||||
|
||||
def load_settings(self):
|
||||
if os.path.isfile(self.config_dir / "config.ini"):
|
||||
self.config.read(self.config_dir / "config.ini")
|
||||
return
|
||||
|
||||
self.config["config"] = {
|
||||
"version": "1"
|
||||
}
|
||||
self.config["appearance"] = {
|
||||
"colour_theme": "textual-dark"
|
||||
}
|
||||
|
||||
with open(self.config_dir / "config.ini", "w") as configfile:
|
||||
self.config.write(configfile)
|
||||
@@ -9,9 +9,12 @@ from ui.widgets.timeline import Timeline, TimelineRow
|
||||
from ui.widgets.project_settings import ProjectSettings
|
||||
from ui.widgets.channel import Channel
|
||||
from ui.widgets.context_menu import ContextMenu, NoSelectStatic
|
||||
from ui.widgets.chunk_types.audio import AudioChunk, Chunk
|
||||
from ui.screens.settings import SettingsScreen
|
||||
|
||||
from project import ProjectChannel, Project, ChunkType
|
||||
from ui.widgets.chunk_types.audio import AudioChunk, Chunk
|
||||
from settings_store import ConfigHandler
|
||||
|
||||
|
||||
|
||||
class AppUI(App):
|
||||
@@ -23,6 +26,8 @@ class AppUI(App):
|
||||
self.last_zoom_level = self.zoom_level
|
||||
self.project = project
|
||||
|
||||
self.config_handler = ConfigHandler(self)
|
||||
|
||||
self.open_project_path = None
|
||||
self.first_tab_click = True # stupid events firing when the app is first composed :/
|
||||
|
||||
@@ -135,6 +140,9 @@ class AppUI(App):
|
||||
)
|
||||
), callback=callback)
|
||||
|
||||
case "Settings":
|
||||
self.push_screen(SettingsScreen())
|
||||
|
||||
case _:
|
||||
self.notify("Sorry, that isn't implemented yet... ;-;", severity="warning")
|
||||
|
||||
@@ -176,3 +184,7 @@ class AppUI(App):
|
||||
yield Timeline()
|
||||
yield ProjectSettings()
|
||||
yield Footer()
|
||||
|
||||
def on_mount(self):
|
||||
# load config into the UI
|
||||
self.config_handler.apply_settings()
|
||||
93
src/ui/screens/settings.py
Normal file
93
src/ui/screens/settings.py
Normal file
@@ -0,0 +1,93 @@
|
||||
from textual.screen import ModalScreen
|
||||
from textual.widgets import Label, Select, TabbedContent, TabPane, Switch, Input, Rule, Static
|
||||
from textual.containers import Vertical, HorizontalGroup, VerticalGroup, VerticalScroll
|
||||
from textual.binding import Binding
|
||||
|
||||
|
||||
class SettingsScreen(ModalScreen):
|
||||
border_title = "Settings"
|
||||
DEFAULT_CSS = """
|
||||
SettingsScreen {
|
||||
align: center middle;
|
||||
|
||||
#window {
|
||||
border: panel $primary;
|
||||
background: $background;
|
||||
width: 65%;
|
||||
height: 65%;
|
||||
padding: 1;
|
||||
}
|
||||
|
||||
TabPane {
|
||||
padding: 1;
|
||||
}
|
||||
|
||||
Rule {
|
||||
color: $boost;
|
||||
}
|
||||
|
||||
.thingy {
|
||||
margin-top: 2;
|
||||
text-style: bold;
|
||||
}
|
||||
|
||||
.setting {
|
||||
padding: 0 2;
|
||||
content-align: center middle;
|
||||
margin-bottom: 1;
|
||||
|
||||
.setting-name {
|
||||
text-style: bold;
|
||||
}
|
||||
|
||||
.setting-desc {
|
||||
text-style: dim;
|
||||
width: 100%;
|
||||
min-width: 30;
|
||||
}
|
||||
|
||||
VerticalGroup {
|
||||
width: 50%;
|
||||
min-width: 20;
|
||||
margin-right: 1;
|
||||
}
|
||||
|
||||
Select, Input {
|
||||
max-width: 30;
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
BINDINGS = [
|
||||
Binding("escape", "close", "Close")
|
||||
]
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def action_close(self):
|
||||
self.dismiss()
|
||||
|
||||
def on_select_changed(self, event: Select.Changed):
|
||||
if event.select.id == "colour-theme":
|
||||
self.app.theme = event.value
|
||||
self.app.config_handler.set("appearance", "colour_theme", str(event.value))
|
||||
|
||||
def compose(self):
|
||||
with Vertical(id="window") as window:
|
||||
window.border_title = "Settings"
|
||||
with TabbedContent():
|
||||
with TabPane("Appearance"):
|
||||
with VerticalScroll():
|
||||
with HorizontalGroup(classes="setting"):
|
||||
with VerticalGroup():
|
||||
yield Label("Colour Theme", classes="setting-name")
|
||||
yield Label("Colour theme used for the entire Berry app. You can get more themes with plugins!", classes="setting-desc")
|
||||
|
||||
yield Select.from_values(
|
||||
(theme_name for theme_name in self.app._registered_themes.keys() if theme_name != "textual-ansi"),
|
||||
allow_blank=False,
|
||||
id="colour-theme",
|
||||
value=self.app.theme
|
||||
)
|
||||
Reference in New Issue
Block a user