Add game logo files and enhance home view layout with grid and button components
This commit is contained in:
parent
9154f8ed3e
commit
d62820dd80
10
agentm/assets/game_logos/doapp.txt
Normal file
10
agentm/assets/game_logos/doapp.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
██████╗ ███████╗ █████╗ ██████╗ ██████╗ ██████╗ █████╗ ██╗ ██╗██╗ ██╗███████╗
|
||||||
|
██╔══██╗██╔════╝██╔══██╗██╔══██╗ ██╔═══██╗██╔══██╗ ██╔══██╗██║ ██║██║ ██║██╔════╝
|
||||||
|
██║ ██║█████╗ ███████║██║ ██║ ██║ ██║██████╔╝ ███████║██║ ██║██║ ██║█████╗
|
||||||
|
██║ ██║██╔══╝ ██╔══██║██║ ██║ ██║ ██║██╔══██╗ ██╔══██║██║ ██║╚██╗ ██╔╝██╔══╝
|
||||||
|
██████╔╝███████╗██║ ██║██████╔╝ ╚██████╔╝██║ ██║ ██║ ██║███████╗██║ ╚████╔╝ ███████╗
|
||||||
|
╚═════╝ ╚══════╝╚═╝ ╚═╝╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═══╝ ╚══════╝
|
||||||
|
|
||||||
|
|
||||||
10
agentm/assets/game_logos/kof98umh.txt
Normal file
10
agentm/assets/game_logos/kof98umh.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
████████╗██╗ ██╗███████╗ ██╗ ██╗██╗███╗ ██╗ ██████╗ ██████╗ ███████╗ ███████╗██╗ ██████╗ ██╗ ██╗████████╗███████╗██████╗ ███████╗
|
||||||
|
╚══██╔══╝██║ ██║██╔════╝ ██║ ██╔╝██║████╗ ██║██╔════╝ ██╔═══██╗██╔════╝ ██╔════╝██║██╔════╝ ██║ ██║╚══██╔══╝██╔════╝██╔══██╗██╔════╝
|
||||||
|
██║ ███████║█████╗ █████╔╝ ██║██╔██╗ ██║██║ ███╗ ██║ ██║█████╗ █████╗ ██║██║ ███╗███████║ ██║ █████╗ ██████╔╝███████╗
|
||||||
|
██║ ██╔══██║██╔══╝ ██╔═██╗ ██║██║╚██╗██║██║ ██║ ██║ ██║██╔══╝ ██╔══╝ ██║██║ ██║██╔══██║ ██║ ██╔══╝ ██╔══██╗╚════██║
|
||||||
|
██║ ██║ ██║███████╗ ██║ ██╗██║██║ ╚████║╚██████╔╝ ╚██████╔╝██║ ██║ ██║╚██████╔╝██║ ██║ ██║ ███████╗██║ ██║███████║
|
||||||
|
╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚══════╝
|
||||||
|
|
||||||
|
|
||||||
10
agentm/assets/game_logos/mvsc.txt
Normal file
10
agentm/assets/game_logos/mvsc.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
███╗ ███╗ █████╗ ██████╗ ██╗ ██╗███████╗██╗ ██╗ ██╗███████╗ ██████╗ █████╗ ██████╗ ██████╗ ██████╗ ███╗ ███╗
|
||||||
|
████╗ ████║██╔══██╗██╔══██╗██║ ██║██╔════╝██║ ██║ ██║██╔════╝ ██╔════╝██╔══██╗██╔══██╗██╔════╝██╔═══██╗████╗ ████║
|
||||||
|
██╔████╔██║███████║██████╔╝██║ ██║█████╗ ██║ ██║ ██║███████╗ ██║ ███████║██████╔╝██║ ██║ ██║██╔████╔██║
|
||||||
|
██║╚██╔╝██║██╔══██║██╔══██╗╚██╗ ██╔╝██╔══╝ ██║ ╚██╗ ██╔╝╚════██║ ██║ ██╔══██║██╔═══╝ ██║ ██║ ██║██║╚██╔╝██║
|
||||||
|
██║ ╚═╝ ██║██║ ██║██║ ██║ ╚████╔╝ ███████╗███████╗ ╚████╔╝ ███████║██╗ ╚██████╗██║ ██║██║ ╚██████╗╚██████╔╝██║ ╚═╝ ██║
|
||||||
|
╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═══╝ ╚══════╝╚══════╝ ╚═══╝ ╚══════╝╚═╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝
|
||||||
|
|
||||||
|
|
||||||
10
agentm/assets/game_logos/samsh5sp.txt
Normal file
10
agentm/assets/game_logos/samsh5sp.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
███████╗ █████╗ ███╗ ███╗██╗ ██╗██████╗ █████╗ ██╗ ███████╗██╗ ██╗ ██████╗ ██████╗ ██████╗ ██╗ ██╗███╗ ██╗ ██╗ ██╗
|
||||||
|
██╔════╝██╔══██╗████╗ ████║██║ ██║██╔══██╗██╔══██╗██║ ██╔════╝██║ ██║██╔═══██╗██╔══██╗██╔═══██╗██║ ██║████╗ ██║ ██║ ██║
|
||||||
|
███████╗███████║██╔████╔██║██║ ██║██████╔╝███████║██║ ███████╗███████║██║ ██║██║ ██║██║ ██║██║ █╗ ██║██╔██╗ ██║ ██║ ██║
|
||||||
|
╚════██║██╔══██║██║╚██╔╝██║██║ ██║██╔══██╗██╔══██║██║ ╚════██║██╔══██║██║ ██║██║ ██║██║ ██║██║███╗██║██║╚██╗██║ ╚██╗ ██╔╝
|
||||||
|
███████║██║ ██║██║ ╚═╝ ██║╚██████╔╝██║ ██║██║ ██║██║ ███████║██║ ██║╚██████╔╝██████╔╝╚██████╔╝╚███╔███╔╝██║ ╚████║ ╚████╔╝
|
||||||
|
╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══╝╚══╝ ╚═╝ ╚═══╝ ╚═══╝
|
||||||
|
|
||||||
|
|
||||||
10
agentm/assets/game_logos/sfiii3n.txt
Normal file
10
agentm/assets/game_logos/sfiii3n.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
███████╗████████╗██████╗ ███████╗███████╗████████╗ ███████╗██╗ ██████╗ ██╗ ██╗████████╗███████╗██████╗ ██╗██╗██╗
|
||||||
|
██╔════╝╚══██╔══╝██╔══██╗██╔════╝██╔════╝╚══██╔══╝ ██╔════╝██║██╔════╝ ██║ ██║╚══██╔══╝██╔════╝██╔══██╗ ██║██║██║
|
||||||
|
███████╗ ██║ ██████╔╝█████╗ █████╗ ██║ █████╗ ██║██║ ███╗███████║ ██║ █████╗ ██████╔╝ ██║██║██║
|
||||||
|
╚════██║ ██║ ██╔══██╗██╔══╝ ██╔══╝ ██║ ██╔══╝ ██║██║ ██║██╔══██║ ██║ ██╔══╝ ██╔══██╗ ██║██║██║
|
||||||
|
███████║ ██║ ██║ ██║███████╗███████╗ ██║ ██║ ██║╚██████╔╝██║ ██║ ██║ ███████╗██║ ██║ ██║██║██║
|
||||||
|
╚══════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝ ╚═╝╚═╝╚═╝
|
||||||
|
|
||||||
|
|
||||||
10
agentm/assets/game_logos/soulclbr.txt
Normal file
10
agentm/assets/game_logos/soulclbr.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
███████╗ ██████╗ ██╗ ██╗██╗ ██████╗ █████╗ ██╗ ██╗██████╗ ██╗ ██╗██████╗
|
||||||
|
██╔════╝██╔═══██╗██║ ██║██║ ██╔════╝██╔══██╗██║ ██║██╔══██╗██║ ██║██╔══██╗
|
||||||
|
███████╗██║ ██║██║ ██║██║ ██║ ███████║██║ ██║██████╔╝██║ ██║██████╔╝
|
||||||
|
╚════██║██║ ██║██║ ██║██║ ██║ ██╔══██║██║ ██║██╔══██╗██║ ██║██╔══██╗
|
||||||
|
███████║╚██████╔╝╚██████╔╝███████╗ ╚██████╗██║ ██║███████╗██║██████╔╝╚██████╔╝██║ ██║
|
||||||
|
╚══════╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚═╝╚═════╝ ╚═════╝ ╚═╝ ╚═╝
|
||||||
|
|
||||||
|
|
||||||
10
agentm/assets/game_logos/tektagt.txt
Normal file
10
agentm/assets/game_logos/tektagt.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
████████╗███████╗██╗ ██╗██╗ ██╗███████╗███╗ ██╗ ████████╗ █████╗ ██████╗ ████████╗ ██████╗ ██╗ ██╗██████╗ ███╗ ██╗ █████╗ ███╗ ███╗███████╗███╗ ██╗████████╗
|
||||||
|
╚══██╔══╝██╔════╝██║ ██╔╝██║ ██╔╝██╔════╝████╗ ██║ ╚══██╔══╝██╔══██╗██╔════╝ ╚══██╔══╝██╔═══██╗██║ ██║██╔══██╗████╗ ██║██╔══██╗████╗ ████║██╔════╝████╗ ██║╚══██╔══╝
|
||||||
|
██║ █████╗ █████╔╝ █████╔╝ █████╗ ██╔██╗ ██║ ██║ ███████║██║ ███╗ ██║ ██║ ██║██║ ██║██████╔╝██╔██╗ ██║███████║██╔████╔██║█████╗ ██╔██╗ ██║ ██║
|
||||||
|
██║ ██╔══╝ ██╔═██╗ ██╔═██╗ ██╔══╝ ██║╚██╗██║ ██║ ██╔══██║██║ ██║ ██║ ██║ ██║██║ ██║██╔══██╗██║╚██╗██║██╔══██║██║╚██╔╝██║██╔══╝ ██║╚██╗██║ ██║
|
||||||
|
██║ ███████╗██║ ██╗██║ ██╗███████╗██║ ╚████║ ██║ ██║ ██║╚██████╔╝ ██║ ╚██████╔╝╚██████╔╝██║ ██║██║ ╚████║██║ ██║██║ ╚═╝ ██║███████╗██║ ╚████║ ██║
|
||||||
|
╚═╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═══╝ ╚═╝
|
||||||
|
|
||||||
|
|
||||||
10
agentm/assets/game_logos/umk3.txt
Normal file
10
agentm/assets/game_logos/umk3.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
███╗ ███╗ ██████╗ ██████╗ ████████╗ █████╗ ██╗ ██╗ ██╗ ██████╗ ███╗ ███╗██████╗ █████╗ ████████╗ ██████╗
|
||||||
|
████╗ ████║██╔═══██╗██╔══██╗╚══██╔══╝██╔══██╗██║ ██║ ██╔╝██╔═══██╗████╗ ████║██╔══██╗██╔══██╗╚══██╔══╝ ╚════██╗
|
||||||
|
██╔████╔██║██║ ██║██████╔╝ ██║ ███████║██║ █████╔╝ ██║ ██║██╔████╔██║██████╔╝███████║ ██║ █████╔╝
|
||||||
|
██║╚██╔╝██║██║ ██║██╔══██╗ ██║ ██╔══██║██║ ██╔═██╗ ██║ ██║██║╚██╔╝██║██╔══██╗██╔══██║ ██║ ╚═══██╗
|
||||||
|
██║ ╚═╝ ██║╚██████╔╝██║ ██║ ██║ ██║ ██║███████╗ ██║ ██╗╚██████╔╝██║ ╚═╝ ██║██████╔╝██║ ██║ ██║ ██████╔╝
|
||||||
|
╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝
|
||||||
|
|
||||||
|
|
||||||
10
agentm/assets/game_logos/xmvsf.txt
Normal file
10
agentm/assets/game_logos/xmvsf.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
██╗ ██╗ ███╗ ███╗███████╗███╗ ██╗ ██╗ ██╗███████╗ ███████╗████████╗██████╗ ███████╗███████╗████████╗ ███████╗██╗ ██████╗ ██╗ ██╗████████╗███████╗██████╗
|
||||||
|
╚██╗██╔╝ ████╗ ████║██╔════╝████╗ ██║ ██║ ██║██╔════╝ ██╔════╝╚══██╔══╝██╔══██╗██╔════╝██╔════╝╚══██╔══╝ ██╔════╝██║██╔════╝ ██║ ██║╚══██╔══╝██╔════╝██╔══██╗
|
||||||
|
╚███╔╝█████╗██╔████╔██║█████╗ ██╔██╗ ██║ ██║ ██║███████╗ ███████╗ ██║ ██████╔╝█████╗ █████╗ ██║ █████╗ ██║██║ ███╗███████║ ██║ █████╗ ██████╔╝
|
||||||
|
██╔██╗╚════╝██║╚██╔╝██║██╔══╝ ██║╚██╗██║ ╚██╗ ██╔╝╚════██║ ╚════██║ ██║ ██╔══██╗██╔══╝ ██╔══╝ ██║ ██╔══╝ ██║██║ ██║██╔══██║ ██║ ██╔══╝ ██╔══██╗
|
||||||
|
██╔╝ ██╗ ██║ ╚═╝ ██║███████╗██║ ╚████║ ╚████╔╝ ███████║ ███████║ ██║ ██║ ██║███████╗███████╗ ██║ ██║ ██║╚██████╔╝██║ ██║ ██║ ███████╗██║ ██║
|
||||||
|
╚═╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═══╝ ╚═══╝ ╚══════╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝
|
||||||
|
|
||||||
|
|
||||||
@ -1,7 +1,13 @@
|
|||||||
# agentm/main.py
|
import subprocess
|
||||||
|
|
||||||
from agentm.app import AgentMApp
|
from agentm.app import AgentMApp
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
# Run the generate_theme_css module silently
|
||||||
|
subprocess.run(
|
||||||
|
["python", "-m", "agentm.theme.generate_theme_css", "--silent"],
|
||||||
|
check=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# Launch the app
|
||||||
app = AgentMApp()
|
app = AgentMApp()
|
||||||
app.run()
|
app.run()
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
from agentm.theme.palette import get_theme
|
import sys
|
||||||
from pathlib import Path
|
|
||||||
import re
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
from agentm.theme.palette import get_theme
|
||||||
|
|
||||||
|
# Check for --silent in command-line arguments
|
||||||
|
silent = "--silent" in sys.argv
|
||||||
|
|
||||||
# Load dark theme instance
|
# Load dark theme instance
|
||||||
theme = get_theme("dark")
|
theme = get_theme("dark")
|
||||||
@ -16,14 +20,16 @@ template = template_path.read_text()
|
|||||||
# Find all placeholders like {{FOREGROUND}}, {{BACKGROUND}}, etc.
|
# Find all placeholders like {{FOREGROUND}}, {{BACKGROUND}}, etc.
|
||||||
tokens = set(re.findall(r"{{\s*([A-Z0-9_]+)\s*}}", template))
|
tokens = set(re.findall(r"{{\s*([A-Z0-9_]+)\s*}}", template))
|
||||||
|
|
||||||
# Replace them with actual values from theme
|
# Replace tokens
|
||||||
for token in tokens:
|
for token in tokens:
|
||||||
value = getattr(theme, token, None)
|
value = getattr(theme, token, None)
|
||||||
if value is not None:
|
if value is not None:
|
||||||
template = template.replace(f"{{{{{token}}}}}", value)
|
template = template.replace(f"{{{{{token}}}}}", value)
|
||||||
else:
|
elif not silent:
|
||||||
print(f"⚠️ Warning: Theme token '{token}' not found in ThemeManager")
|
print(f"⚠️ Warning: Theme token '{token}' not found in ThemeManager")
|
||||||
|
|
||||||
# Write final output
|
# Write final output
|
||||||
output_path.write_text(template)
|
output_path.write_text(template)
|
||||||
print(f"✅ Synced themed CSS written to: {output_path}")
|
|
||||||
|
if not silent:
|
||||||
|
print(f"✅ Synced themed CSS written to: {output_path}")
|
||||||
|
|||||||
@ -14,7 +14,7 @@ Screen {
|
|||||||
|
|
||||||
/* === Headers === */
|
/* === Headers === */
|
||||||
|
|
||||||
# Header, .header {
|
# .header {
|
||||||
# dock: top;
|
# dock: top;
|
||||||
# height: 3;
|
# height: 3;
|
||||||
# content-align: center middle;
|
# content-align: center middle;
|
||||||
@ -31,10 +31,13 @@ Button {
|
|||||||
background: {{SURFACE_10}};
|
background: {{SURFACE_10}};
|
||||||
color: {{ACCENT}};
|
color: {{ACCENT}};
|
||||||
border: solid {{ACCENT}};
|
border: solid {{ACCENT}};
|
||||||
padding: 1 2;
|
padding: 1;
|
||||||
margin: 1;
|
margin: 0;
|
||||||
content-align: center middle;
|
content-align: center middle;
|
||||||
text-style: bold;
|
text-style: bold;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 3;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
Button:hover {
|
Button:hover {
|
||||||
@ -47,6 +50,42 @@ Button:focus {
|
|||||||
border: solid {{ACCENT}};
|
border: solid {{ACCENT}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Button:disabled {
|
||||||
|
background: {{DISABLED_BG}};
|
||||||
|
color: {{DISABLED}};
|
||||||
|
border: solid {{DISABLED_BORDER}};
|
||||||
|
text-style: dim;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === Grid Layout === */
|
||||||
|
|
||||||
|
.rom_grid {
|
||||||
|
grid-size: 5;
|
||||||
|
grid-gutter: 1;
|
||||||
|
padding: 0 1; /* Was: 1 2 */
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
align-horizontal: center;
|
||||||
|
align-vertical: middle;
|
||||||
|
height: auto; /* Ensure it can grow */
|
||||||
|
}
|
||||||
|
|
||||||
|
#rom_grid_scroll {
|
||||||
|
max-height: 30vh; /* was: height: 40vh */
|
||||||
|
overflow-y: auto;
|
||||||
|
scrollbar-gutter: stable;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
border-bottom: solid {{BORDER}};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Optionally ensure the parent container scrolls properly */
|
||||||
|
#game_content_layout {
|
||||||
|
height: auto;
|
||||||
|
width: 100%;
|
||||||
|
padding: 1 2;
|
||||||
|
}
|
||||||
|
|
||||||
/* === Inputs === */
|
/* === Inputs === */
|
||||||
|
|
||||||
Input {
|
Input {
|
||||||
@ -115,7 +154,7 @@ Input:focus {
|
|||||||
content-align: center middle;
|
content-align: center middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* === Game Layout === */
|
/* === Layout === */
|
||||||
|
|
||||||
.centered_layout {
|
.centered_layout {
|
||||||
layout: vertical;
|
layout: vertical;
|
||||||
@ -125,30 +164,6 @@ Input:focus {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rom_rows_container {
|
|
||||||
layout: vertical;
|
|
||||||
align-horizontal: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game_card {
|
|
||||||
width: auto;
|
|
||||||
height: auto;
|
|
||||||
max-width: 60;
|
|
||||||
margin: 1;
|
|
||||||
padding: 1;
|
|
||||||
background: {{SURFACE_10}};
|
|
||||||
color: {{ACCENT}};
|
|
||||||
border: solid {{BORDER}};
|
|
||||||
content-align: center middle;
|
|
||||||
text-style: bold;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game_card:hover {
|
|
||||||
background: {{SURFACE_20}};
|
|
||||||
color: {{ACCENT_HOVER}};
|
|
||||||
}
|
|
||||||
|
|
||||||
Static {
|
Static {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
@ -157,47 +172,16 @@ Horizontal {
|
|||||||
content-align: center middle;
|
content-align: center middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.game_card:focus {
|
|
||||||
background: {{SURFACE_20}};
|
|
||||||
border: solid {{ACCENT}};
|
|
||||||
}
|
|
||||||
|
|
||||||
.game_card:disabled {
|
|
||||||
background: {{SURFACE_10}};
|
|
||||||
color: {{BORDER}};
|
|
||||||
}
|
|
||||||
|
|
||||||
.game_card_clicked {
|
|
||||||
background: {{ACCENT}};
|
|
||||||
color: {{BACKGROUND}};
|
|
||||||
}
|
|
||||||
|
|
||||||
.offset_card {
|
|
||||||
width: 11;
|
|
||||||
height: auto;
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rom_row {
|
|
||||||
layout: horizontal;
|
|
||||||
align-horizontal: center;
|
|
||||||
align-vertical: middle;
|
|
||||||
padding: 1 2;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info_confirm_row {
|
.info_confirm_row {
|
||||||
layout: horizontal;
|
|
||||||
width: 100%;
|
|
||||||
height: auto;
|
height: auto;
|
||||||
padding: 1 2;
|
padding: 0 0;
|
||||||
align-vertical: top;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#confirm_button {
|
#confirm_button {
|
||||||
width: 20%;
|
width: 100%; /* Take full width of its container */
|
||||||
height: auto;
|
min-width: 20; /* Increase minimum width if needed */
|
||||||
content-align: center middle;
|
max-width: 100%; /* Optional: avoid oversizing */
|
||||||
}
|
}
|
||||||
|
|
||||||
.confirm_button:hover {
|
.confirm_button:hover {
|
||||||
@ -205,21 +189,30 @@ Horizontal {
|
|||||||
color: {{BACKGROUND}};
|
color: {{BACKGROUND}};
|
||||||
}
|
}
|
||||||
|
|
||||||
Button:disabled {
|
|
||||||
background: {{DISABLED_BG}};
|
|
||||||
color: {{DISABLED}};
|
|
||||||
border: solid {{DISABLED_BORDER}};
|
|
||||||
text-style: dim;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game_info {
|
.game_info {
|
||||||
padding: 1 2;
|
padding: 0 1;
|
||||||
|
margin: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-right: 1;
|
|
||||||
color: {{ACCENT}};
|
color: {{ACCENT}};
|
||||||
}
|
}
|
||||||
|
|
||||||
#game_info_box {
|
#game_info_box {
|
||||||
width: 80%;
|
width: 80%;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
max-height: 50vh; /* Adjusted for better visibility */
|
||||||
|
padding: 1;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Button.game_button {
|
||||||
|
min-height: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
#confirm_button_container {
|
||||||
|
width: 20%;
|
||||||
|
min-width: 20;
|
||||||
|
align-vertical: middle;
|
||||||
|
align-horizontal: center;
|
||||||
|
height: 100%;
|
||||||
|
padding-left: 1;
|
||||||
|
}
|
||||||
@ -14,7 +14,7 @@ Screen {
|
|||||||
|
|
||||||
/* === Headers === */
|
/* === Headers === */
|
||||||
|
|
||||||
# Header, .header {
|
# .header {
|
||||||
# dock: top;
|
# dock: top;
|
||||||
# height: 3;
|
# height: 3;
|
||||||
# content-align: center middle;
|
# content-align: center middle;
|
||||||
@ -31,10 +31,13 @@ Button {
|
|||||||
background: #282828;
|
background: #282828;
|
||||||
color: #ed7d3a;
|
color: #ed7d3a;
|
||||||
border: solid #ed7d3a;
|
border: solid #ed7d3a;
|
||||||
padding: 1 2;
|
padding: 1;
|
||||||
margin: 1;
|
margin: 0;
|
||||||
content-align: center middle;
|
content-align: center middle;
|
||||||
text-style: bold;
|
text-style: bold;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 3;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
Button:hover {
|
Button:hover {
|
||||||
@ -47,6 +50,42 @@ Button:focus {
|
|||||||
border: solid #ed7d3a;
|
border: solid #ed7d3a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Button:disabled {
|
||||||
|
background: #444444;
|
||||||
|
color: #999999;
|
||||||
|
border: solid #666666;
|
||||||
|
text-style: dim;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === Grid Layout === */
|
||||||
|
|
||||||
|
.rom_grid {
|
||||||
|
grid-size: 5;
|
||||||
|
grid-gutter: 1;
|
||||||
|
padding: 0 1; /* Was: 1 2 */
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
align-horizontal: center;
|
||||||
|
align-vertical: middle;
|
||||||
|
height: auto; /* Ensure it can grow */
|
||||||
|
}
|
||||||
|
|
||||||
|
#rom_grid_scroll {
|
||||||
|
max-height: 30vh; /* was: height: 40vh */
|
||||||
|
overflow-y: auto;
|
||||||
|
scrollbar-gutter: stable;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
border-bottom: solid #3a9bed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Optionally ensure the parent container scrolls properly */
|
||||||
|
#game_content_layout {
|
||||||
|
height: auto;
|
||||||
|
width: 100%;
|
||||||
|
padding: 1 2;
|
||||||
|
}
|
||||||
|
|
||||||
/* === Inputs === */
|
/* === Inputs === */
|
||||||
|
|
||||||
Input {
|
Input {
|
||||||
@ -115,7 +154,7 @@ Input:focus {
|
|||||||
content-align: center middle;
|
content-align: center middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* === Game Layout === */
|
/* === Layout === */
|
||||||
|
|
||||||
.centered_layout {
|
.centered_layout {
|
||||||
layout: vertical;
|
layout: vertical;
|
||||||
@ -125,30 +164,6 @@ Input:focus {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rom_rows_container {
|
|
||||||
layout: vertical;
|
|
||||||
align-horizontal: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game_card {
|
|
||||||
width: auto;
|
|
||||||
height: auto;
|
|
||||||
max-width: 60;
|
|
||||||
margin: 1;
|
|
||||||
padding: 1;
|
|
||||||
background: #282828;
|
|
||||||
color: #ed7d3a;
|
|
||||||
border: solid #3a9bed;
|
|
||||||
content-align: center middle;
|
|
||||||
text-style: bold;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game_card:hover {
|
|
||||||
background: #3f3f3f;
|
|
||||||
color: rgb(236, 194, 169);
|
|
||||||
}
|
|
||||||
|
|
||||||
Static {
|
Static {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
@ -157,47 +172,16 @@ Horizontal {
|
|||||||
content-align: center middle;
|
content-align: center middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.game_card:focus {
|
|
||||||
background: #3f3f3f;
|
|
||||||
border: solid #ed7d3a;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game_card:disabled {
|
|
||||||
background: #282828;
|
|
||||||
color: #3a9bed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game_card_clicked {
|
|
||||||
background: #ed7d3a;
|
|
||||||
color: #0e0e0e;
|
|
||||||
}
|
|
||||||
|
|
||||||
.offset_card {
|
|
||||||
width: 11;
|
|
||||||
height: auto;
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rom_row {
|
|
||||||
layout: horizontal;
|
|
||||||
align-horizontal: center;
|
|
||||||
align-vertical: middle;
|
|
||||||
padding: 1 2;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info_confirm_row {
|
.info_confirm_row {
|
||||||
layout: horizontal;
|
|
||||||
width: 100%;
|
|
||||||
height: auto;
|
height: auto;
|
||||||
padding: 1 2;
|
padding: 0 0;
|
||||||
align-vertical: top;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#confirm_button {
|
#confirm_button {
|
||||||
width: 20%;
|
width: 100%; /* Take full width of its container */
|
||||||
height: auto;
|
min-width: 20; /* Increase minimum width if needed */
|
||||||
content-align: center middle;
|
max-width: 100%; /* Optional: avoid oversizing */
|
||||||
}
|
}
|
||||||
|
|
||||||
.confirm_button:hover {
|
.confirm_button:hover {
|
||||||
@ -205,21 +189,30 @@ Horizontal {
|
|||||||
color: #0e0e0e;
|
color: #0e0e0e;
|
||||||
}
|
}
|
||||||
|
|
||||||
Button:disabled {
|
|
||||||
background: #444444;
|
|
||||||
color: #999999;
|
|
||||||
border: solid #666666;
|
|
||||||
text-style: dim;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game_info {
|
.game_info {
|
||||||
padding: 1 2;
|
padding: 0 1;
|
||||||
|
margin: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-right: 1;
|
|
||||||
color: #ed7d3a;
|
color: #ed7d3a;
|
||||||
}
|
}
|
||||||
|
|
||||||
#game_info_box {
|
#game_info_box {
|
||||||
width: 80%;
|
width: 80%;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
max-height: 50vh; /* Adjusted for better visibility */
|
||||||
|
padding: 1;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Button.game_button {
|
||||||
|
min-height: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
#confirm_button_container {
|
||||||
|
width: 20%;
|
||||||
|
min-width: 20;
|
||||||
|
align-vertical: middle;
|
||||||
|
align-horizontal: center;
|
||||||
|
height: 100%;
|
||||||
|
padding-left: 1;
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
from textual.screen import Screen
|
from textual.screen import Screen
|
||||||
from textual.widgets import Static, Button
|
from textual.widgets import Static, Button
|
||||||
from textual.containers import Vertical, Horizontal, HorizontalScroll
|
from textual.containers import Vertical, Horizontal, VerticalScroll, Grid
|
||||||
from textual.message import Message
|
from textual.message import Message
|
||||||
from textual.reactive import reactive
|
from textual.reactive import reactive
|
||||||
from textual.widget import Widget
|
from textual.widget import Widget
|
||||||
@ -8,18 +8,12 @@ from rich.panel import Panel
|
|||||||
from rich.console import Group
|
from rich.console import Group
|
||||||
from rich.table import Table
|
from rich.table import Table
|
||||||
from rich.rule import Rule
|
from rich.rule import Rule
|
||||||
from rich.markup import escape
|
from rich.text import Text
|
||||||
from PIL import Image, ImageFilter
|
|
||||||
import os
|
|
||||||
|
|
||||||
from rich_pixels import Pixels
|
|
||||||
from rich_pixels._renderer import HalfcellRenderer
|
|
||||||
|
|
||||||
from agentm.utils.logger import log_with_caller
|
from agentm.utils.logger import log_with_caller
|
||||||
from agentm.logic.roms import get_verified_roms, GAME_FILES
|
from agentm.logic.roms import get_verified_roms, GAME_FILES
|
||||||
from agentm.theme.palette import get_theme
|
from agentm.theme.palette import get_theme
|
||||||
from agentm.components.footer import AgentMFooter
|
from agentm.components.footer import AgentMFooter
|
||||||
from agentm.components.game_image_preview import GameImagePreview
|
|
||||||
|
|
||||||
palette = get_theme()
|
palette = get_theme()
|
||||||
|
|
||||||
@ -37,30 +31,19 @@ class ProgressWidget(Widget):
|
|||||||
return f"[bold {palette.ACCENT}]{self.message}[/]"
|
return f"[bold {palette.ACCENT}]{self.message}[/]"
|
||||||
|
|
||||||
|
|
||||||
|
class GameCardButton(Button):
|
||||||
class GameAccordion(Static):
|
def __init__(self, metadata: dict, parent_view):
|
||||||
def __init__(self, title: str, rom_file: str, metadata: dict, parent_view):
|
|
||||||
super().__init__(
|
|
||||||
id=f"accordion_{rom_file.replace('.', '_').replace('-', '_')}",
|
|
||||||
classes="game_card"
|
|
||||||
)
|
|
||||||
|
|
||||||
self.title = title
|
|
||||||
self.rom_file = rom_file
|
|
||||||
self.metadata = metadata
|
self.metadata = metadata
|
||||||
self.parent_view = parent_view
|
self.parent_view = parent_view
|
||||||
|
safe_id = metadata["rom_file"].replace(".", "_").replace("-", "_")
|
||||||
|
label = Text(metadata["title"], style=f"bold {palette.ACCENT}")
|
||||||
|
|
||||||
self.title_label = Static(
|
super().__init__(
|
||||||
f"[b {palette.ACCENT}]{escape(self.title.upper())}[/]\n",
|
label=label,
|
||||||
classes="game_title",
|
id=f"game_btn_{safe_id}",
|
||||||
markup=True
|
classes="game_button"
|
||||||
)
|
)
|
||||||
|
self.styles.min_height = 3 # Ensures buttons stay visible even in constrained space
|
||||||
self.image_path = os.path.abspath(self.metadata.get("image_path", ""))
|
|
||||||
|
|
||||||
def compose(self):
|
|
||||||
yield self.title_label
|
|
||||||
yield GameImagePreview(image_path=self.image_path)
|
|
||||||
|
|
||||||
async def on_click(self):
|
async def on_click(self):
|
||||||
await self.display_info()
|
await self.display_info()
|
||||||
@ -68,19 +51,19 @@ class GameAccordion(Static):
|
|||||||
|
|
||||||
async def display_info(self):
|
async def display_info(self):
|
||||||
meta = self.metadata
|
meta = self.metadata
|
||||||
log_with_caller("debug", f"Showing shared info for {self.rom_file}")
|
|
||||||
|
|
||||||
table = Table.grid(expand=True)
|
table = Table.grid(padding=(0, 1))
|
||||||
table.add_column(ratio=1)
|
table.add_column("Key", style="bold underline", no_wrap=True)
|
||||||
table.add_column()
|
table.add_column("Value", style=palette.ACCENT, overflow="fold")
|
||||||
table.add_row("[b]Title:[/b]", meta['title'])
|
|
||||||
table.add_row("[b]Game ID:[/b]", meta['game_id'])
|
|
||||||
table.add_row("[b]Difficulty:[/b]", f"{meta.get('difficulty_min')} - {meta.get('difficulty_max')}")
|
|
||||||
table.add_row("[b]Characters:[/b]", ", ".join(meta.get("characters", [])))
|
|
||||||
table.add_row("[b]Keywords:[/b]", ", ".join(meta.get("keywords", [])))
|
|
||||||
table.add_row("[b]SHA256:[/b]", meta["sha256"])
|
|
||||||
|
|
||||||
self.parent_view.shared_info_box.update(
|
table.add_row("Title", meta["title"])
|
||||||
|
table.add_row("Game ID", meta["game_id"])
|
||||||
|
table.add_row("Difficulty", f"{meta.get('difficulty_min')} - {meta.get('difficulty_max')}")
|
||||||
|
table.add_row("Characters", ", ".join(meta.get("characters", [])))
|
||||||
|
table.add_row("Keywords", ", ".join(meta.get("keywords", [])))
|
||||||
|
table.add_row("SHA256", meta["sha256"])
|
||||||
|
|
||||||
|
self.parent_view.shared_info_content.update(
|
||||||
Panel(Group(table, Rule(style="dim")), title="Game Info", border_style=palette.BORDER, expand=True)
|
Panel(Group(table, Rule(style="dim")), title="Game Info", border_style=palette.BORDER, expand=True)
|
||||||
)
|
)
|
||||||
self.parent_view.shared_confirm_button.label = f"✅ Confirm {meta['title']}"
|
self.parent_view.shared_confirm_button.label = f"✅ Confirm {meta['title']}"
|
||||||
@ -88,13 +71,12 @@ class GameAccordion(Static):
|
|||||||
self.parent_view.selected_game = meta
|
self.parent_view.selected_game = meta
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class HomeView(Screen):
|
class HomeView(Screen):
|
||||||
BINDINGS = [("escape", "app.quit", "Quit")]
|
BINDINGS = [("escape", "app.quit", "Quit")]
|
||||||
|
|
||||||
def highlight_selected(self, selected_widget: GameAccordion):
|
def highlight_selected(self, selected_widget: GameCardButton):
|
||||||
for card in self.rom_scroll_row.children:
|
for card in self.rom_grid.children:
|
||||||
if isinstance(card, GameAccordion):
|
if isinstance(card, GameCardButton):
|
||||||
card.remove_class("game_card_clicked")
|
card.remove_class("game_card_clicked")
|
||||||
selected_widget.add_class("game_card_clicked")
|
selected_widget.add_class("game_card_clicked")
|
||||||
|
|
||||||
@ -125,7 +107,6 @@ class HomeView(Screen):
|
|||||||
id="loading_container"
|
id="loading_container"
|
||||||
)
|
)
|
||||||
|
|
||||||
# This will be the main container we later modify
|
|
||||||
self.dynamic_container = Vertical(self.loading_container, id="dynamic_content")
|
self.dynamic_container = Vertical(self.loading_container, id="dynamic_content")
|
||||||
|
|
||||||
yield Vertical(
|
yield Vertical(
|
||||||
@ -148,7 +129,7 @@ class HomeView(Screen):
|
|||||||
|
|
||||||
for idx, rom in enumerate(verified_roms, start=1):
|
for idx, rom in enumerate(verified_roms, start=1):
|
||||||
self.app.call_from_thread(
|
self.app.call_from_thread(
|
||||||
lambda title=rom['title'], idx=idx: setattr(
|
lambda title=rom["title"], idx=idx: setattr(
|
||||||
self.progress_text, "message",
|
self.progress_text, "message",
|
||||||
f"Processing {title} ({idx}/{total})"
|
f"Processing {title} ({idx}/{total})"
|
||||||
)
|
)
|
||||||
@ -161,49 +142,56 @@ class HomeView(Screen):
|
|||||||
async def display_verified_roms(self, verified_roms):
|
async def display_verified_roms(self, verified_roms):
|
||||||
log_with_caller("info", f"ROM verification complete. Total: {len(verified_roms)}")
|
log_with_caller("info", f"ROM verification complete. Total: {len(verified_roms)}")
|
||||||
|
|
||||||
self.shared_info_box = Static(
|
self.shared_info_content = Static(
|
||||||
Panel(
|
Panel(
|
||||||
"[dim]Select a Game From Above to Start[/dim]",
|
"[dim]Select a Game From the Grid Below to Start[/dim]",
|
||||||
title="Game Info",
|
title="Game Info",
|
||||||
border_style=palette.BORDER,
|
border_style=palette.BORDER,
|
||||||
expand=True
|
expand=True
|
||||||
),
|
),
|
||||||
id="game_info_box",
|
id="info_panel_static"
|
||||||
classes="game_info",
|
|
||||||
expand=True
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.shared_info_box = VerticalScroll(
|
||||||
|
self.shared_info_content,
|
||||||
|
id="game_info_box",
|
||||||
|
classes="game_info"
|
||||||
|
)
|
||||||
|
self.shared_info_box.styles.height = 7 # Around 5 visible rows
|
||||||
|
|
||||||
self.shared_confirm_button = Button(
|
self.shared_confirm_button = Button(
|
||||||
"✅ Confirm",
|
"✅ Confirm",
|
||||||
id="confirm_button",
|
id="confirm_button",
|
||||||
classes="confirm_button",
|
classes="confirm_button",
|
||||||
disabled=True
|
disabled=True
|
||||||
)
|
)
|
||||||
self.rom_scroll_row = HorizontalScroll(id="rom_scroll_row", classes="rom_row")
|
|
||||||
|
self.rom_grid = Grid(id="rom_grid", classes="rom_grid")
|
||||||
|
self.rom_grid.styles.grid_columns = ["1fr"] * 5
|
||||||
|
self.rom_grid.styles.grid_gap = (0, 1)
|
||||||
|
self.rom_grid.styles.width = "100%"
|
||||||
|
|
||||||
|
rom_grid_scroll = VerticalScroll(self.rom_grid, id="rom_grid_scroll")
|
||||||
|
rom_grid_scroll.styles.max_height = "30vh"
|
||||||
|
|
||||||
new_content = Vertical(
|
new_content = Vertical(
|
||||||
self.rom_scroll_row,
|
rom_grid_scroll,
|
||||||
Horizontal(
|
Horizontal(
|
||||||
self.shared_info_box,
|
self.shared_info_box,
|
||||||
self.shared_confirm_button,
|
Vertical(self.shared_confirm_button, id="confirm_button_container"),
|
||||||
id="info_row",
|
id="info_row",
|
||||||
classes="info_confirm_row"
|
classes="info_confirm_row"
|
||||||
)
|
),
|
||||||
|
id="game_content_layout",
|
||||||
|
classes="game_content_layout"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Replace loading content with new UI below logo and welcome
|
|
||||||
dynamic_container = self.query_one("#dynamic_content")
|
dynamic_container = self.query_one("#dynamic_content")
|
||||||
await dynamic_container.remove_children()
|
await dynamic_container.remove_children()
|
||||||
await dynamic_container.mount(new_content)
|
await dynamic_container.mount(new_content)
|
||||||
|
|
||||||
# Populate games
|
|
||||||
for rom in verified_roms:
|
for rom in verified_roms:
|
||||||
await self.rom_scroll_row.mount(GameAccordion(
|
await self.rom_grid.mount(GameCardButton(metadata=rom, parent_view=self))
|
||||||
title=rom["title"],
|
|
||||||
rom_file=rom["rom_file"],
|
|
||||||
metadata=rom,
|
|
||||||
parent_view=self
|
|
||||||
))
|
|
||||||
|
|
||||||
|
|
||||||
async def on_button_pressed(self, event: Button.Pressed) -> None:
|
async def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||||
if event.button.id == "confirm_button" and self.selected_game:
|
if event.button.id == "confirm_button" and self.selected_game:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user