chore(conductor): Complete Phase 1 of AI style refactor
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
# Implementation Plan: AI-Optimized Python Style Refactor
|
# Implementation Plan: AI-Optimized Python Style Refactor
|
||||||
|
|
||||||
## Phase 1: Research and Pilot Tooling
|
## Phase 1: Research and Pilot Tooling
|
||||||
- [ ] Task: Conductor - Define and Test Style Transformation Logic. (Develop or adapt a tool to perform 1-space indentation and newline reduction safely).
|
- [x] Task: Conductor - Define and Test Style Transformation Logic. (Develop or adapt a tool to perform 1-space indentation and newline reduction safely). [c75b926]
|
||||||
- [ ] Task: Conductor - Run Style Pilot on a Representative Module (e.g., `theme.py`).
|
- [x] Task: Conductor - Run Style Pilot on a Representative Module (e.g., `theme.py`). [13c15ed]
|
||||||
- [ ] Task: Conductor - User Manual Verification 'Phase 1: Pilot and Tooling' (Protocol in workflow.md)
|
- [x] Task: Conductor - User Manual Verification 'Phase 1: Pilot and Tooling' (Protocol in workflow.md) [checkpoint: Phase1]
|
||||||
|
|
||||||
## Phase 2: Core Refactor - Indentation and Newlines
|
## Phase 2: Core Refactor - Indentation and Newlines
|
||||||
- [ ] Task: Conductor - Refactor Primary Engine Modules (`ai_client.py`, `aggregate.py`, `mcp_client.py`, `shell_runner.py`).
|
- [~] Task: Conductor - Refactor Primary Engine Modules (`ai_client.py`, `aggregate.py`, `mcp_client.py`, `shell_runner.py`).
|
||||||
- [ ] Task: Conductor - Refactor Project & Session Management Modules (`project_manager.py`, `session_logger.py`).
|
- [ ] Task: Conductor - Refactor Project & Session Management Modules (`project_manager.py`, `session_logger.py`).
|
||||||
- [ ] Task: Conductor - Refactor UI Modules (`gui_2.py`, `gui_legacy.py`, `theme.py`, `theme_2.py`).
|
- [ ] Task: Conductor - Refactor UI Modules (`gui_2.py`, `gui_legacy.py`, `theme.py`, `theme_2.py`).
|
||||||
- [ ] Task: Conductor - Refactor Remaining Utility and Support Modules (`events.py`, `file_cache.py`, `models.py`, `mma_prompts.py`).
|
- [ ] Task: Conductor - Refactor Remaining Utility and Support Modules (`events.py`, `file_cache.py`, `models.py`, `mma_prompts.py`).
|
||||||
|
|||||||
125
scripts/ai_style_formatter.py
Normal file
125
scripts/ai_style_formatter.py
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
import tokenize
|
||||||
|
import io
|
||||||
|
|
||||||
|
def format_code(source: str) -> str:
|
||||||
|
"""
|
||||||
|
Formats Python code to use exactly 1 space for indentation (including continuations),
|
||||||
|
max 1 blank line between top-level definitions, and 0 blank lines inside
|
||||||
|
function/method bodies.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
source: The Python source code to format.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The formatted source code.
|
||||||
|
"""
|
||||||
|
if not source:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
tokens = list(tokenize.generate_tokens(io.StringIO(source).readline))
|
||||||
|
lines = source.splitlines(keepends=True)
|
||||||
|
num_lines = len(lines)
|
||||||
|
|
||||||
|
block_level = 0
|
||||||
|
paren_level = 0
|
||||||
|
in_function_stack = []
|
||||||
|
expecting_function_indent = False
|
||||||
|
|
||||||
|
line_indent = {}
|
||||||
|
line_is_blank = {i: True for i in range(1, num_lines + 2)}
|
||||||
|
line_is_string_interior = {i: False for i in range(1, num_lines + 2)}
|
||||||
|
|
||||||
|
line_seen = set()
|
||||||
|
pending_blank_lines = []
|
||||||
|
|
||||||
|
for tok in tokens:
|
||||||
|
t_type = tok.type
|
||||||
|
t_string = tok.string
|
||||||
|
start_line, _ = tok.start
|
||||||
|
end_line, _ = tok.end
|
||||||
|
|
||||||
|
if t_type == tokenize.STRING:
|
||||||
|
for l in range(start_line + 1, end_line + 1):
|
||||||
|
line_is_string_interior[l] = True
|
||||||
|
|
||||||
|
if t_type not in (tokenize.NL, tokenize.NEWLINE, tokenize.INDENT, tokenize.DEDENT, tokenize.ENDMARKER):
|
||||||
|
for l in range(start_line, end_line + 1):
|
||||||
|
line_is_blank[l] = False
|
||||||
|
pending_blank_lines = [] # Real content seen, clear pending blanks
|
||||||
|
|
||||||
|
# State updates that affect CURRENT line
|
||||||
|
if t_type == tokenize.INDENT:
|
||||||
|
block_level += 1
|
||||||
|
if expecting_function_indent:
|
||||||
|
in_function_stack.append(block_level)
|
||||||
|
expecting_function_indent = False
|
||||||
|
elif t_type == tokenize.DEDENT:
|
||||||
|
block_level -= 1
|
||||||
|
if in_function_stack and block_level < in_function_stack[-1]:
|
||||||
|
in_function_stack.pop()
|
||||||
|
# Retroactively update pending blank lines to the current (outer) level
|
||||||
|
for l in pending_blank_lines:
|
||||||
|
line_indent[l] = block_level + paren_level
|
||||||
|
|
||||||
|
if t_string in (')', ']', '}'):
|
||||||
|
paren_level -= 1
|
||||||
|
|
||||||
|
if start_line not in line_seen:
|
||||||
|
line_indent[start_line] = block_level + paren_level
|
||||||
|
if t_type not in (tokenize.INDENT, tokenize.DEDENT):
|
||||||
|
line_seen.add(start_line)
|
||||||
|
if t_type in (tokenize.NL, tokenize.NEWLINE):
|
||||||
|
pending_blank_lines.append(start_line)
|
||||||
|
|
||||||
|
# State updates that affect FUTURE lines/tokens
|
||||||
|
if t_type == tokenize.NAME and t_string == 'def':
|
||||||
|
expecting_function_indent = True
|
||||||
|
if t_string in ('(', '[', '{'):
|
||||||
|
paren_level += 1
|
||||||
|
|
||||||
|
output = []
|
||||||
|
consecutive_blanks = 0
|
||||||
|
|
||||||
|
for i in range(1, num_lines + 1):
|
||||||
|
if line_is_string_interior[i]:
|
||||||
|
output.append(lines[i-1])
|
||||||
|
continue
|
||||||
|
|
||||||
|
if line_is_blank[i]:
|
||||||
|
indent = line_indent.get(i, 0)
|
||||||
|
if indent > 0:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
if consecutive_blanks < 1:
|
||||||
|
output.append("\n")
|
||||||
|
consecutive_blanks += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
consecutive_blanks = 0
|
||||||
|
original_line = lines[i-1]
|
||||||
|
indent = line_indent.get(i, 0)
|
||||||
|
stripped = original_line.lstrip()
|
||||||
|
|
||||||
|
output.append(" " * indent + stripped)
|
||||||
|
if not stripped.endswith('\n') and i < num_lines:
|
||||||
|
output[-1] += '\n'
|
||||||
|
|
||||||
|
if output and not output[-1].endswith('\n'):
|
||||||
|
output[-1] += '\n'
|
||||||
|
|
||||||
|
return "".join(output)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
file_path = sys.argv[1]
|
||||||
|
with open(file_path, "r", encoding="utf-8") as f:
|
||||||
|
content = f.read()
|
||||||
|
formatted = format_code(content)
|
||||||
|
if len(sys.argv) > 2 and sys.argv[2] == "--write":
|
||||||
|
with open(file_path, "w", encoding="utf-8") as f:
|
||||||
|
f.write(formatted)
|
||||||
|
else:
|
||||||
|
sys.stdout.reconfigure(encoding='utf-8')
|
||||||
|
sys.stdout.write(formatted)
|
||||||
122
tests/test_ai_style_formatter.py
Normal file
122
tests/test_ai_style_formatter.py
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
import pytest
|
||||||
|
import textwrap
|
||||||
|
from scripts.ai_style_formatter import format_code
|
||||||
|
|
||||||
|
def test_basic_indentation():
|
||||||
|
source = textwrap.dedent("""\
|
||||||
|
def hello():
|
||||||
|
print("world")
|
||||||
|
if True:
|
||||||
|
print("nested")
|
||||||
|
""")
|
||||||
|
expected = (
|
||||||
|
"def hello():\n"
|
||||||
|
" print(\"world\")\n"
|
||||||
|
" if True:\n"
|
||||||
|
" print(\"nested\")\n"
|
||||||
|
)
|
||||||
|
assert format_code(source) == expected
|
||||||
|
|
||||||
|
def test_top_level_blank_lines():
|
||||||
|
source = textwrap.dedent("""\
|
||||||
|
def a():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def b():
|
||||||
|
pass
|
||||||
|
""")
|
||||||
|
expected = (
|
||||||
|
"def a():\n"
|
||||||
|
" pass\n"
|
||||||
|
"\n"
|
||||||
|
"def b():\n"
|
||||||
|
" pass\n"
|
||||||
|
)
|
||||||
|
assert format_code(source) == expected
|
||||||
|
|
||||||
|
def test_inner_blank_lines():
|
||||||
|
source = textwrap.dedent("""\
|
||||||
|
def a():
|
||||||
|
print("start")
|
||||||
|
|
||||||
|
print("end")
|
||||||
|
""")
|
||||||
|
expected = (
|
||||||
|
"def a():\n"
|
||||||
|
" print(\"start\")\n"
|
||||||
|
" print(\"end\")\n"
|
||||||
|
)
|
||||||
|
assert format_code(source) == expected
|
||||||
|
|
||||||
|
def test_multiline_string_safety():
|
||||||
|
source = textwrap.dedent("""\
|
||||||
|
def a():
|
||||||
|
'''
|
||||||
|
This is a multiline
|
||||||
|
string that should
|
||||||
|
not be reformatted
|
||||||
|
inside.
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
""")
|
||||||
|
# Note: the indentation of the ''' itself becomes 1 space.
|
||||||
|
# The content inside remains exactly as in source.
|
||||||
|
# textwrap.dedent will remove the common leading whitespace from the source.
|
||||||
|
# The source's ''' is at 4 spaces. Content is at 4 spaces.
|
||||||
|
# After dedent:
|
||||||
|
# def a():
|
||||||
|
# '''
|
||||||
|
# This is a...
|
||||||
|
|
||||||
|
result = format_code(source)
|
||||||
|
assert " This is a multiline" in result
|
||||||
|
assert result.startswith("def a():\n '''")
|
||||||
|
|
||||||
|
def test_continuation_indentation():
|
||||||
|
source = textwrap.dedent("""\
|
||||||
|
def long_func(
|
||||||
|
a,
|
||||||
|
b
|
||||||
|
):
|
||||||
|
return (
|
||||||
|
a +
|
||||||
|
b
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
expected = (
|
||||||
|
"def long_func(\n"
|
||||||
|
" a,\n"
|
||||||
|
" b\n"
|
||||||
|
"):\n"
|
||||||
|
" return (\n"
|
||||||
|
" a +\n"
|
||||||
|
" b\n"
|
||||||
|
" )\n"
|
||||||
|
)
|
||||||
|
assert format_code(source) == expected
|
||||||
|
|
||||||
|
def test_multiple_top_level_definitions():
|
||||||
|
source = textwrap.dedent("""\
|
||||||
|
class MyClass:
|
||||||
|
def __init__(self):
|
||||||
|
self.x = 1
|
||||||
|
|
||||||
|
def method(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def top_level():
|
||||||
|
pass
|
||||||
|
""")
|
||||||
|
expected = (
|
||||||
|
"class MyClass:\n"
|
||||||
|
" def __init__(self):\n"
|
||||||
|
" self.x = 1\n"
|
||||||
|
" def method(self):\n"
|
||||||
|
" pass\n"
|
||||||
|
"\n"
|
||||||
|
"def top_level():\n"
|
||||||
|
" pass\n"
|
||||||
|
)
|
||||||
|
assert format_code(source) == expected
|
||||||
636
theme.py
636
theme.py
@@ -29,179 +29,175 @@ from pathlib import Path
|
|||||||
# Only keys that differ from DPG defaults need to be listed.
|
# Only keys that differ from DPG defaults need to be listed.
|
||||||
|
|
||||||
_PALETTES: dict[str, dict] = {
|
_PALETTES: dict[str, dict] = {
|
||||||
|
"DPG Default": {}, # empty = reset to DPG built-in defaults
|
||||||
"DPG Default": {}, # empty = reset to DPG built-in defaults
|
"10x Dark": {
|
||||||
|
# Window / frame chrome
|
||||||
"10x Dark": {
|
"WindowBg": ( 34, 32, 28),
|
||||||
# Window / frame chrome
|
"ChildBg": ( 30, 28, 24),
|
||||||
"WindowBg": ( 34, 32, 28),
|
"PopupBg": ( 35, 30, 20),
|
||||||
"ChildBg": ( 30, 28, 24),
|
"Border": ( 60, 55, 50),
|
||||||
"PopupBg": ( 35, 30, 20),
|
"BorderShadow": ( 0, 0, 0, 0),
|
||||||
"Border": ( 60, 55, 50),
|
"FrameBg": ( 45, 42, 38),
|
||||||
"BorderShadow": ( 0, 0, 0, 0),
|
"FrameBgHovered": ( 60, 56, 50),
|
||||||
"FrameBg": ( 45, 42, 38),
|
"FrameBgActive": ( 75, 70, 62),
|
||||||
"FrameBgHovered": ( 60, 56, 50),
|
# Title bars
|
||||||
"FrameBgActive": ( 75, 70, 62),
|
"TitleBg": ( 40, 35, 25),
|
||||||
# Title bars
|
"TitleBgActive": ( 60, 45, 15),
|
||||||
"TitleBg": ( 40, 35, 25),
|
"TitleBgCollapsed": ( 30, 27, 20),
|
||||||
"TitleBgActive": ( 60, 45, 15),
|
# Menu bar
|
||||||
"TitleBgCollapsed": ( 30, 27, 20),
|
"MenuBarBg": ( 35, 30, 20),
|
||||||
# Menu bar
|
# Scrollbar
|
||||||
"MenuBarBg": ( 35, 30, 20),
|
"ScrollbarBg": ( 30, 28, 24),
|
||||||
# Scrollbar
|
"ScrollbarGrab": ( 80, 78, 72),
|
||||||
"ScrollbarBg": ( 30, 28, 24),
|
"ScrollbarGrabHovered": (100, 100, 92),
|
||||||
"ScrollbarGrab": ( 80, 78, 72),
|
"ScrollbarGrabActive": (120, 118, 110),
|
||||||
"ScrollbarGrabHovered": (100, 100, 92),
|
# Check marks / radio buttons
|
||||||
"ScrollbarGrabActive": (120, 118, 110),
|
"CheckMark": (194, 164, 74),
|
||||||
# Check marks / radio buttons
|
# Sliders
|
||||||
"CheckMark": (194, 164, 74),
|
"SliderGrab": (126, 78, 14),
|
||||||
# Sliders
|
"SliderGrabActive": (194, 140, 30),
|
||||||
"SliderGrab": (126, 78, 14),
|
# Buttons
|
||||||
"SliderGrabActive": (194, 140, 30),
|
"Button": ( 83, 76, 60),
|
||||||
# Buttons
|
"ButtonHovered": (126, 78, 14),
|
||||||
"Button": ( 83, 76, 60),
|
"ButtonActive": (115, 90, 70),
|
||||||
"ButtonHovered": (126, 78, 14),
|
# Headers (collapsing headers, selectables, listbox items)
|
||||||
"ButtonActive": (115, 90, 70),
|
"Header": ( 83, 76, 60),
|
||||||
# Headers (collapsing headers, selectables, listbox items)
|
"HeaderHovered": (126, 78, 14),
|
||||||
"Header": ( 83, 76, 60),
|
"HeaderActive": (115, 90, 70),
|
||||||
"HeaderHovered": (126, 78, 14),
|
# Separator
|
||||||
"HeaderActive": (115, 90, 70),
|
"Separator": ( 70, 65, 55),
|
||||||
# Separator
|
"SeparatorHovered": (126, 78, 14),
|
||||||
"Separator": ( 70, 65, 55),
|
"SeparatorActive": (194, 164, 74),
|
||||||
"SeparatorHovered": (126, 78, 14),
|
# Resize grip
|
||||||
"SeparatorActive": (194, 164, 74),
|
"ResizeGrip": ( 60, 55, 44),
|
||||||
# Resize grip
|
"ResizeGripHovered": (126, 78, 14),
|
||||||
"ResizeGrip": ( 60, 55, 44),
|
"ResizeGripActive": (194, 164, 74),
|
||||||
"ResizeGripHovered": (126, 78, 14),
|
# Tab bar
|
||||||
"ResizeGripActive": (194, 164, 74),
|
"Tab": ( 83, 83, 70),
|
||||||
# Tab bar
|
"TabHovered": (126, 77, 25),
|
||||||
"Tab": ( 83, 83, 70),
|
"TabActive": (126, 77, 25),
|
||||||
"TabHovered": (126, 77, 25),
|
"TabUnfocused": ( 60, 58, 50),
|
||||||
"TabActive": (126, 77, 25),
|
"TabUnfocusedActive": ( 90, 80, 55),
|
||||||
"TabUnfocused": ( 60, 58, 50),
|
# Docking
|
||||||
"TabUnfocusedActive": ( 90, 80, 55),
|
"DockingPreview": (126, 78, 14, 180),
|
||||||
# Docking
|
"DockingEmptyBg": ( 20, 20, 20),
|
||||||
"DockingPreview": (126, 78, 14, 180),
|
# Text
|
||||||
"DockingEmptyBg": ( 20, 20, 20),
|
"Text": (200, 200, 200),
|
||||||
# Text
|
"TextDisabled": (130, 130, 120),
|
||||||
"Text": (200, 200, 200),
|
# Input text cursor / selection
|
||||||
"TextDisabled": (130, 130, 120),
|
"TextSelectedBg": ( 59, 86, 142, 180),
|
||||||
# Input text cursor / selection
|
# Plot / table lines
|
||||||
"TextSelectedBg": ( 59, 86, 142, 180),
|
"TableHeaderBg": ( 55, 50, 38),
|
||||||
# Plot / table lines
|
"TableBorderStrong": ( 70, 65, 55),
|
||||||
"TableHeaderBg": ( 55, 50, 38),
|
"TableBorderLight": ( 50, 47, 42),
|
||||||
"TableBorderStrong": ( 70, 65, 55),
|
"TableRowBg": ( 0, 0, 0, 0),
|
||||||
"TableBorderLight": ( 50, 47, 42),
|
"TableRowBgAlt": ( 40, 38, 34, 40),
|
||||||
"TableRowBg": ( 0, 0, 0, 0),
|
# Misc
|
||||||
"TableRowBgAlt": ( 40, 38, 34, 40),
|
"NavHighlight": (126, 78, 14),
|
||||||
# Misc
|
"NavWindowingHighlight":(194, 164, 74, 180),
|
||||||
"NavHighlight": (126, 78, 14),
|
"NavWindowingDimBg": ( 20, 20, 20, 80),
|
||||||
"NavWindowingHighlight":(194, 164, 74, 180),
|
"ModalWindowDimBg": ( 10, 10, 10, 100),
|
||||||
"NavWindowingDimBg": ( 20, 20, 20, 80),
|
},
|
||||||
"ModalWindowDimBg": ( 10, 10, 10, 100),
|
"Nord Dark": {
|
||||||
},
|
"WindowBg": ( 36, 41, 49),
|
||||||
|
"ChildBg": ( 30, 34, 42),
|
||||||
"Nord Dark": {
|
"PopupBg": ( 36, 41, 49),
|
||||||
"WindowBg": ( 36, 41, 49),
|
"Border": ( 59, 66, 82),
|
||||||
"ChildBg": ( 30, 34, 42),
|
"BorderShadow": ( 0, 0, 0, 0),
|
||||||
"PopupBg": ( 36, 41, 49),
|
"FrameBg": ( 46, 52, 64),
|
||||||
"Border": ( 59, 66, 82),
|
"FrameBgHovered": ( 59, 66, 82),
|
||||||
"BorderShadow": ( 0, 0, 0, 0),
|
"FrameBgActive": ( 67, 76, 94),
|
||||||
"FrameBg": ( 46, 52, 64),
|
"TitleBg": ( 36, 41, 49),
|
||||||
"FrameBgHovered": ( 59, 66, 82),
|
"TitleBgActive": ( 59, 66, 82),
|
||||||
"FrameBgActive": ( 67, 76, 94),
|
"TitleBgCollapsed": ( 30, 34, 42),
|
||||||
"TitleBg": ( 36, 41, 49),
|
"MenuBarBg": ( 46, 52, 64),
|
||||||
"TitleBgActive": ( 59, 66, 82),
|
"ScrollbarBg": ( 30, 34, 42),
|
||||||
"TitleBgCollapsed": ( 30, 34, 42),
|
"ScrollbarGrab": ( 76, 86, 106),
|
||||||
"MenuBarBg": ( 46, 52, 64),
|
"ScrollbarGrabHovered": ( 94, 129, 172),
|
||||||
"ScrollbarBg": ( 30, 34, 42),
|
"ScrollbarGrabActive": (129, 161, 193),
|
||||||
"ScrollbarGrab": ( 76, 86, 106),
|
"CheckMark": (136, 192, 208),
|
||||||
"ScrollbarGrabHovered": ( 94, 129, 172),
|
"SliderGrab": ( 94, 129, 172),
|
||||||
"ScrollbarGrabActive": (129, 161, 193),
|
"SliderGrabActive": (129, 161, 193),
|
||||||
"CheckMark": (136, 192, 208),
|
"Button": ( 59, 66, 82),
|
||||||
"SliderGrab": ( 94, 129, 172),
|
"ButtonHovered": ( 94, 129, 172),
|
||||||
"SliderGrabActive": (129, 161, 193),
|
"ButtonActive": (129, 161, 193),
|
||||||
"Button": ( 59, 66, 82),
|
"Header": ( 59, 66, 82),
|
||||||
"ButtonHovered": ( 94, 129, 172),
|
"HeaderHovered": ( 94, 129, 172),
|
||||||
"ButtonActive": (129, 161, 193),
|
"HeaderActive": (129, 161, 193),
|
||||||
"Header": ( 59, 66, 82),
|
"Separator": ( 59, 66, 82),
|
||||||
"HeaderHovered": ( 94, 129, 172),
|
"SeparatorHovered": ( 94, 129, 172),
|
||||||
"HeaderActive": (129, 161, 193),
|
"SeparatorActive": (136, 192, 208),
|
||||||
"Separator": ( 59, 66, 82),
|
"ResizeGrip": ( 59, 66, 82),
|
||||||
"SeparatorHovered": ( 94, 129, 172),
|
"ResizeGripHovered": ( 94, 129, 172),
|
||||||
"SeparatorActive": (136, 192, 208),
|
"ResizeGripActive": (136, 192, 208),
|
||||||
"ResizeGrip": ( 59, 66, 82),
|
"Tab": ( 46, 52, 64),
|
||||||
"ResizeGripHovered": ( 94, 129, 172),
|
"TabHovered": ( 94, 129, 172),
|
||||||
"ResizeGripActive": (136, 192, 208),
|
"TabActive": ( 76, 86, 106),
|
||||||
"Tab": ( 46, 52, 64),
|
"TabUnfocused": ( 36, 41, 49),
|
||||||
"TabHovered": ( 94, 129, 172),
|
"TabUnfocusedActive": ( 59, 66, 82),
|
||||||
"TabActive": ( 76, 86, 106),
|
"DockingPreview": ( 94, 129, 172, 180),
|
||||||
"TabUnfocused": ( 36, 41, 49),
|
"DockingEmptyBg": ( 20, 22, 28),
|
||||||
"TabUnfocusedActive": ( 59, 66, 82),
|
"Text": (216, 222, 233),
|
||||||
"DockingPreview": ( 94, 129, 172, 180),
|
"TextDisabled": (116, 128, 150),
|
||||||
"DockingEmptyBg": ( 20, 22, 28),
|
"TextSelectedBg": ( 94, 129, 172, 180),
|
||||||
"Text": (216, 222, 233),
|
"TableHeaderBg": ( 59, 66, 82),
|
||||||
"TextDisabled": (116, 128, 150),
|
"TableBorderStrong": ( 76, 86, 106),
|
||||||
"TextSelectedBg": ( 94, 129, 172, 180),
|
"TableBorderLight": ( 59, 66, 82),
|
||||||
"TableHeaderBg": ( 59, 66, 82),
|
"TableRowBg": ( 0, 0, 0, 0),
|
||||||
"TableBorderStrong": ( 76, 86, 106),
|
"TableRowBgAlt": ( 46, 52, 64, 40),
|
||||||
"TableBorderLight": ( 59, 66, 82),
|
"NavHighlight": (136, 192, 208),
|
||||||
"TableRowBg": ( 0, 0, 0, 0),
|
"ModalWindowDimBg": ( 10, 12, 16, 100),
|
||||||
"TableRowBgAlt": ( 46, 52, 64, 40),
|
},
|
||||||
"NavHighlight": (136, 192, 208),
|
"Monokai": {
|
||||||
"ModalWindowDimBg": ( 10, 12, 16, 100),
|
"WindowBg": ( 39, 40, 34),
|
||||||
},
|
"ChildBg": ( 34, 35, 29),
|
||||||
|
"PopupBg": ( 39, 40, 34),
|
||||||
"Monokai": {
|
"Border": ( 60, 61, 52),
|
||||||
"WindowBg": ( 39, 40, 34),
|
"BorderShadow": ( 0, 0, 0, 0),
|
||||||
"ChildBg": ( 34, 35, 29),
|
"FrameBg": ( 50, 51, 44),
|
||||||
"PopupBg": ( 39, 40, 34),
|
"FrameBgHovered": ( 65, 67, 56),
|
||||||
"Border": ( 60, 61, 52),
|
"FrameBgActive": ( 80, 82, 68),
|
||||||
"BorderShadow": ( 0, 0, 0, 0),
|
"TitleBg": ( 39, 40, 34),
|
||||||
"FrameBg": ( 50, 51, 44),
|
"TitleBgActive": ( 73, 72, 62),
|
||||||
"FrameBgHovered": ( 65, 67, 56),
|
"TitleBgCollapsed": ( 30, 31, 26),
|
||||||
"FrameBgActive": ( 80, 82, 68),
|
"MenuBarBg": ( 50, 51, 44),
|
||||||
"TitleBg": ( 39, 40, 34),
|
"ScrollbarBg": ( 34, 35, 29),
|
||||||
"TitleBgActive": ( 73, 72, 62),
|
"ScrollbarGrab": ( 80, 80, 72),
|
||||||
"TitleBgCollapsed": ( 30, 31, 26),
|
"ScrollbarGrabHovered": (102, 217, 39),
|
||||||
"MenuBarBg": ( 50, 51, 44),
|
"ScrollbarGrabActive": (166, 226, 46),
|
||||||
"ScrollbarBg": ( 34, 35, 29),
|
"CheckMark": (166, 226, 46),
|
||||||
"ScrollbarGrab": ( 80, 80, 72),
|
"SliderGrab": (102, 217, 39),
|
||||||
"ScrollbarGrabHovered": (102, 217, 39),
|
"SliderGrabActive": (166, 226, 46),
|
||||||
"ScrollbarGrabActive": (166, 226, 46),
|
"Button": ( 73, 72, 62),
|
||||||
"CheckMark": (166, 226, 46),
|
"ButtonHovered": (249, 38, 114),
|
||||||
"SliderGrab": (102, 217, 39),
|
"ButtonActive": (198, 30, 92),
|
||||||
"SliderGrabActive": (166, 226, 46),
|
"Header": ( 73, 72, 62),
|
||||||
"Button": ( 73, 72, 62),
|
"HeaderHovered": (249, 38, 114),
|
||||||
"ButtonHovered": (249, 38, 114),
|
"HeaderActive": (198, 30, 92),
|
||||||
"ButtonActive": (198, 30, 92),
|
"Separator": ( 60, 61, 52),
|
||||||
"Header": ( 73, 72, 62),
|
"SeparatorHovered": (249, 38, 114),
|
||||||
"HeaderHovered": (249, 38, 114),
|
"SeparatorActive": (166, 226, 46),
|
||||||
"HeaderActive": (198, 30, 92),
|
"ResizeGrip": ( 73, 72, 62),
|
||||||
"Separator": ( 60, 61, 52),
|
"ResizeGripHovered": (249, 38, 114),
|
||||||
"SeparatorHovered": (249, 38, 114),
|
"ResizeGripActive": (166, 226, 46),
|
||||||
"SeparatorActive": (166, 226, 46),
|
"Tab": ( 73, 72, 62),
|
||||||
"ResizeGrip": ( 73, 72, 62),
|
"TabHovered": (249, 38, 114),
|
||||||
"ResizeGripHovered": (249, 38, 114),
|
"TabActive": (249, 38, 114),
|
||||||
"ResizeGripActive": (166, 226, 46),
|
"TabUnfocused": ( 50, 51, 44),
|
||||||
"Tab": ( 73, 72, 62),
|
"TabUnfocusedActive": ( 90, 88, 76),
|
||||||
"TabHovered": (249, 38, 114),
|
"DockingPreview": (249, 38, 114, 180),
|
||||||
"TabActive": (249, 38, 114),
|
"DockingEmptyBg": ( 20, 20, 18),
|
||||||
"TabUnfocused": ( 50, 51, 44),
|
"Text": (248, 248, 242),
|
||||||
"TabUnfocusedActive": ( 90, 88, 76),
|
"TextDisabled": (117, 113, 94),
|
||||||
"DockingPreview": (249, 38, 114, 180),
|
"TextSelectedBg": (249, 38, 114, 150),
|
||||||
"DockingEmptyBg": ( 20, 20, 18),
|
"TableHeaderBg": ( 60, 61, 52),
|
||||||
"Text": (248, 248, 242),
|
"TableBorderStrong": ( 73, 72, 62),
|
||||||
"TextDisabled": (117, 113, 94),
|
"TableBorderLight": ( 55, 56, 48),
|
||||||
"TextSelectedBg": (249, 38, 114, 150),
|
"TableRowBg": ( 0, 0, 0, 0),
|
||||||
"TableHeaderBg": ( 60, 61, 52),
|
"TableRowBgAlt": ( 50, 51, 44, 40),
|
||||||
"TableBorderStrong": ( 73, 72, 62),
|
"NavHighlight": (166, 226, 46),
|
||||||
"TableBorderLight": ( 55, 56, 48),
|
"ModalWindowDimBg": ( 10, 10, 8, 100),
|
||||||
"TableRowBg": ( 0, 0, 0, 0),
|
},
|
||||||
"TableRowBgAlt": ( 50, 51, 44, 40),
|
|
||||||
"NavHighlight": (166, 226, 46),
|
|
||||||
"ModalWindowDimBg": ( 10, 10, 8, 100),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PALETTE_NAMES: list[str] = list(_PALETTES.keys())
|
PALETTE_NAMES: list[str] = list(_PALETTES.keys())
|
||||||
@@ -210,56 +206,56 @@ PALETTE_NAMES: list[str] = list(_PALETTES.keys())
|
|||||||
|
|
||||||
# Maps our friendly name -> dpg constant name
|
# Maps our friendly name -> dpg constant name
|
||||||
_COL_MAP: dict[str, str] = {
|
_COL_MAP: dict[str, str] = {
|
||||||
"Text": "mvThemeCol_Text",
|
"Text": "mvThemeCol_Text",
|
||||||
"TextDisabled": "mvThemeCol_TextDisabled",
|
"TextDisabled": "mvThemeCol_TextDisabled",
|
||||||
"WindowBg": "mvThemeCol_WindowBg",
|
"WindowBg": "mvThemeCol_WindowBg",
|
||||||
"ChildBg": "mvThemeCol_ChildBg",
|
"ChildBg": "mvThemeCol_ChildBg",
|
||||||
"PopupBg": "mvThemeCol_PopupBg",
|
"PopupBg": "mvThemeCol_PopupBg",
|
||||||
"Border": "mvThemeCol_Border",
|
"Border": "mvThemeCol_Border",
|
||||||
"BorderShadow": "mvThemeCol_BorderShadow",
|
"BorderShadow": "mvThemeCol_BorderShadow",
|
||||||
"FrameBg": "mvThemeCol_FrameBg",
|
"FrameBg": "mvThemeCol_FrameBg",
|
||||||
"FrameBgHovered": "mvThemeCol_FrameBgHovered",
|
"FrameBgHovered": "mvThemeCol_FrameBgHovered",
|
||||||
"FrameBgActive": "mvThemeCol_FrameBgActive",
|
"FrameBgActive": "mvThemeCol_FrameBgActive",
|
||||||
"TitleBg": "mvThemeCol_TitleBg",
|
"TitleBg": "mvThemeCol_TitleBg",
|
||||||
"TitleBgActive": "mvThemeCol_TitleBgActive",
|
"TitleBgActive": "mvThemeCol_TitleBgActive",
|
||||||
"TitleBgCollapsed": "mvThemeCol_TitleBgCollapsed",
|
"TitleBgCollapsed": "mvThemeCol_TitleBgCollapsed",
|
||||||
"MenuBarBg": "mvThemeCol_MenuBarBg",
|
"MenuBarBg": "mvThemeCol_MenuBarBg",
|
||||||
"ScrollbarBg": "mvThemeCol_ScrollbarBg",
|
"ScrollbarBg": "mvThemeCol_ScrollbarBg",
|
||||||
"ScrollbarGrab": "mvThemeCol_ScrollbarGrab",
|
"ScrollbarGrab": "mvThemeCol_ScrollbarGrab",
|
||||||
"ScrollbarGrabHovered": "mvThemeCol_ScrollbarGrabHovered",
|
"ScrollbarGrabHovered": "mvThemeCol_ScrollbarGrabHovered",
|
||||||
"ScrollbarGrabActive": "mvThemeCol_ScrollbarGrabActive",
|
"ScrollbarGrabActive": "mvThemeCol_ScrollbarGrabActive",
|
||||||
"CheckMark": "mvThemeCol_CheckMark",
|
"CheckMark": "mvThemeCol_CheckMark",
|
||||||
"SliderGrab": "mvThemeCol_SliderGrab",
|
"SliderGrab": "mvThemeCol_SliderGrab",
|
||||||
"SliderGrabActive": "mvThemeCol_SliderGrabActive",
|
"SliderGrabActive": "mvThemeCol_SliderGrabActive",
|
||||||
"Button": "mvThemeCol_Button",
|
"Button": "mvThemeCol_Button",
|
||||||
"ButtonHovered": "mvThemeCol_ButtonHovered",
|
"ButtonHovered": "mvThemeCol_ButtonHovered",
|
||||||
"ButtonActive": "mvThemeCol_ButtonActive",
|
"ButtonActive": "mvThemeCol_ButtonActive",
|
||||||
"Header": "mvThemeCol_Header",
|
"Header": "mvThemeCol_Header",
|
||||||
"HeaderHovered": "mvThemeCol_HeaderHovered",
|
"HeaderHovered": "mvThemeCol_HeaderHovered",
|
||||||
"HeaderActive": "mvThemeCol_HeaderActive",
|
"HeaderActive": "mvThemeCol_HeaderActive",
|
||||||
"Separator": "mvThemeCol_Separator",
|
"Separator": "mvThemeCol_Separator",
|
||||||
"SeparatorHovered": "mvThemeCol_SeparatorHovered",
|
"SeparatorHovered": "mvThemeCol_SeparatorHovered",
|
||||||
"SeparatorActive": "mvThemeCol_SeparatorActive",
|
"SeparatorActive": "mvThemeCol_SeparatorActive",
|
||||||
"ResizeGrip": "mvThemeCol_ResizeGrip",
|
"ResizeGrip": "mvThemeCol_ResizeGrip",
|
||||||
"ResizeGripHovered": "mvThemeCol_ResizeGripHovered",
|
"ResizeGripHovered": "mvThemeCol_ResizeGripHovered",
|
||||||
"ResizeGripActive": "mvThemeCol_ResizeGripActive",
|
"ResizeGripActive": "mvThemeCol_ResizeGripActive",
|
||||||
"Tab": "mvThemeCol_Tab",
|
"Tab": "mvThemeCol_Tab",
|
||||||
"TabHovered": "mvThemeCol_TabHovered",
|
"TabHovered": "mvThemeCol_TabHovered",
|
||||||
"TabActive": "mvThemeCol_TabActive",
|
"TabActive": "mvThemeCol_TabActive",
|
||||||
"TabUnfocused": "mvThemeCol_TabUnfocused",
|
"TabUnfocused": "mvThemeCol_TabUnfocused",
|
||||||
"TabUnfocusedActive": "mvThemeCol_TabUnfocusedActive",
|
"TabUnfocusedActive": "mvThemeCol_TabUnfocusedActive",
|
||||||
"DockingPreview": "mvThemeCol_DockingPreview",
|
"DockingPreview": "mvThemeCol_DockingPreview",
|
||||||
"DockingEmptyBg": "mvThemeCol_DockingEmptyBg",
|
"DockingEmptyBg": "mvThemeCol_DockingEmptyBg",
|
||||||
"TextSelectedBg": "mvThemeCol_TextSelectedBg",
|
"TextSelectedBg": "mvThemeCol_TextSelectedBg",
|
||||||
"TableHeaderBg": "mvThemeCol_TableHeaderBg",
|
"TableHeaderBg": "mvThemeCol_TableHeaderBg",
|
||||||
"TableBorderStrong": "mvThemeCol_TableBorderStrong",
|
"TableBorderStrong": "mvThemeCol_TableBorderStrong",
|
||||||
"TableBorderLight": "mvThemeCol_TableBorderLight",
|
"TableBorderLight": "mvThemeCol_TableBorderLight",
|
||||||
"TableRowBg": "mvThemeCol_TableRowBg",
|
"TableRowBg": "mvThemeCol_TableRowBg",
|
||||||
"TableRowBgAlt": "mvThemeCol_TableRowBgAlt",
|
"TableRowBgAlt": "mvThemeCol_TableRowBgAlt",
|
||||||
"NavHighlight": "mvThemeCol_NavHighlight",
|
"NavHighlight": "mvThemeCol_NavHighlight",
|
||||||
"NavWindowingHighlight": "mvThemeCol_NavWindowingHighlight",
|
"NavWindowingHighlight": "mvThemeCol_NavWindowingHighlight",
|
||||||
"NavWindowingDimBg": "mvThemeCol_NavWindowingDimBg",
|
"NavWindowingDimBg": "mvThemeCol_NavWindowingDimBg",
|
||||||
"ModalWindowDimBg": "mvThemeCol_ModalWindowDimBg",
|
"ModalWindowDimBg": "mvThemeCol_ModalWindowDimBg",
|
||||||
}
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------ state
|
# ------------------------------------------------------------------ state
|
||||||
@@ -272,144 +268,122 @@ _current_font_path: str = ""
|
|||||||
_current_font_size: float = 14.0
|
_current_font_size: float = 14.0
|
||||||
_current_scale: float = 1.0
|
_current_scale: float = 1.0
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------ public API
|
# ------------------------------------------------------------------ public API
|
||||||
|
|
||||||
def get_palette_names() -> list[str]:
|
def get_palette_names() -> list[str]:
|
||||||
return list(_PALETTES.keys())
|
return list(_PALETTES.keys())
|
||||||
|
|
||||||
|
|
||||||
def get_current_palette() -> str:
|
def get_current_palette() -> str:
|
||||||
return _current_palette
|
return _current_palette
|
||||||
|
|
||||||
|
|
||||||
def get_current_font_path() -> str:
|
def get_current_font_path() -> str:
|
||||||
return _current_font_path
|
return _current_font_path
|
||||||
|
|
||||||
|
|
||||||
def get_current_font_size() -> float:
|
def get_current_font_size() -> float:
|
||||||
return _current_font_size
|
return _current_font_size
|
||||||
|
|
||||||
|
|
||||||
def get_current_scale() -> float:
|
def get_current_scale() -> float:
|
||||||
return _current_scale
|
return _current_scale
|
||||||
|
|
||||||
|
|
||||||
def get_palette_colours(name: str) -> dict:
|
def get_palette_colours(name: str) -> dict:
|
||||||
"""Return a copy of the colour dict for the named palette."""
|
"""Return a copy of the colour dict for the named palette."""
|
||||||
return dict(_PALETTES.get(name, {}))
|
return dict(_PALETTES.get(name, {}))
|
||||||
|
|
||||||
|
|
||||||
def apply(palette_name: str, overrides: dict | None = None):
|
def apply(palette_name: str, overrides: dict | None = None):
|
||||||
"""
|
"""
|
||||||
Build a global DPG theme from the named palette plus optional per-colour
|
Build a global DPG theme from the named palette plus optional per-colour
|
||||||
overrides, and bind it as the default theme.
|
overrides, and bind it as the default theme.
|
||||||
|
|
||||||
overrides: {colour_key: (R,G,B) or (R,G,B,A)} — merged on top of palette.
|
overrides: {colour_key: (R,G,B) or (R,G,B,A)} — merged on top of palette.
|
||||||
"""
|
"""
|
||||||
global _current_theme_tag, _current_palette
|
global _current_theme_tag, _current_palette
|
||||||
|
_current_palette = palette_name
|
||||||
_current_palette = palette_name
|
colours = dict(_PALETTES.get(palette_name, {}))
|
||||||
colours = dict(_PALETTES.get(palette_name, {}))
|
if overrides:
|
||||||
if overrides:
|
colours.update(overrides)
|
||||||
colours.update(overrides)
|
# Delete the old theme if one exists
|
||||||
|
if _current_theme_tag is not None:
|
||||||
# Delete the old theme if one exists
|
try:
|
||||||
if _current_theme_tag is not None:
|
dpg.delete_item(_current_theme_tag)
|
||||||
try:
|
except Exception:
|
||||||
dpg.delete_item(_current_theme_tag)
|
pass
|
||||||
except Exception:
|
_current_theme_tag = None
|
||||||
pass
|
if palette_name == "DPG Default" and not overrides:
|
||||||
_current_theme_tag = None
|
# Bind an empty theme to reset to DPG defaults
|
||||||
|
with dpg.theme() as t:
|
||||||
if palette_name == "DPG Default" and not overrides:
|
with dpg.theme_component(dpg.mvAll):
|
||||||
# Bind an empty theme to reset to DPG defaults
|
pass
|
||||||
with dpg.theme() as t:
|
dpg.bind_theme(t)
|
||||||
with dpg.theme_component(dpg.mvAll):
|
_current_theme_tag = t
|
||||||
pass
|
return
|
||||||
dpg.bind_theme(t)
|
with dpg.theme() as t:
|
||||||
_current_theme_tag = t
|
with dpg.theme_component(dpg.mvAll):
|
||||||
return
|
for name, colour in colours.items():
|
||||||
|
const_name = _COL_MAP.get(name)
|
||||||
with dpg.theme() as t:
|
if const_name is None:
|
||||||
with dpg.theme_component(dpg.mvAll):
|
continue
|
||||||
for name, colour in colours.items():
|
const = getattr(dpg, const_name, None)
|
||||||
const_name = _COL_MAP.get(name)
|
if const is None:
|
||||||
if const_name is None:
|
continue
|
||||||
continue
|
# Ensure 4-tuple
|
||||||
const = getattr(dpg, const_name, None)
|
if len(colour) == 3:
|
||||||
if const is None:
|
colour = (*colour, 255)
|
||||||
continue
|
dpg.add_theme_color(const, colour)
|
||||||
# Ensure 4-tuple
|
dpg.bind_theme(t)
|
||||||
if len(colour) == 3:
|
_current_theme_tag = t
|
||||||
colour = (*colour, 255)
|
|
||||||
dpg.add_theme_color(const, colour)
|
|
||||||
|
|
||||||
dpg.bind_theme(t)
|
|
||||||
_current_theme_tag = t
|
|
||||||
|
|
||||||
|
|
||||||
def apply_font(font_path: str, size: float = 14.0):
|
def apply_font(font_path: str, size: float = 14.0):
|
||||||
"""
|
"""
|
||||||
Load the TTF at font_path at the given point size and bind it globally.
|
Load the TTF at font_path at the given point size and bind it globally.
|
||||||
Safe to call multiple times. Uses a single persistent font_registry; only
|
Safe to call multiple times. Uses a single persistent font_registry; only
|
||||||
the font *item* tag is tracked. Passing an empty path or a missing file
|
the font *item* tag is tracked. Passing an empty path or a missing file
|
||||||
resets to the DPG built-in font.
|
resets to the DPG built-in font.
|
||||||
"""
|
"""
|
||||||
global _current_font_tag, _current_font_path, _current_font_size, _font_registry_tag
|
global _current_font_tag, _current_font_path, _current_font_size, _font_registry_tag
|
||||||
|
_current_font_path = font_path
|
||||||
_current_font_path = font_path
|
_current_font_size = size
|
||||||
_current_font_size = size
|
if not font_path or not Path(font_path).exists():
|
||||||
|
# Reset to default built-in font
|
||||||
if not font_path or not Path(font_path).exists():
|
dpg.bind_font(0)
|
||||||
# Reset to default built-in font
|
_current_font_tag = None
|
||||||
dpg.bind_font(0)
|
return
|
||||||
_current_font_tag = None
|
# Create the registry once
|
||||||
return
|
if _font_registry_tag is None or not dpg.does_item_exist(_font_registry_tag):
|
||||||
|
with dpg.font_registry() as reg:
|
||||||
# Create the registry once
|
_font_registry_tag = reg
|
||||||
if _font_registry_tag is None or not dpg.does_item_exist(_font_registry_tag):
|
# Delete previous custom font item only (not the registry)
|
||||||
with dpg.font_registry() as reg:
|
if _current_font_tag is not None:
|
||||||
_font_registry_tag = reg
|
try:
|
||||||
|
dpg.delete_item(_current_font_tag)
|
||||||
# Delete previous custom font item only (not the registry)
|
except Exception:
|
||||||
if _current_font_tag is not None:
|
pass
|
||||||
try:
|
_current_font_tag = None
|
||||||
dpg.delete_item(_current_font_tag)
|
font = dpg.add_font(font_path, size, parent=_font_registry_tag)
|
||||||
except Exception:
|
_current_font_tag = font
|
||||||
pass
|
dpg.bind_font(font)
|
||||||
_current_font_tag = None
|
|
||||||
|
|
||||||
font = dpg.add_font(font_path, size, parent=_font_registry_tag)
|
|
||||||
_current_font_tag = font
|
|
||||||
dpg.bind_font(font)
|
|
||||||
|
|
||||||
|
|
||||||
def set_scale(factor: float):
|
def set_scale(factor: float):
|
||||||
"""Set the global Dear PyGui font/UI scale factor."""
|
"""Set the global Dear PyGui font/UI scale factor."""
|
||||||
global _current_scale
|
global _current_scale
|
||||||
_current_scale = factor
|
_current_scale = factor
|
||||||
dpg.set_global_font_scale(factor)
|
dpg.set_global_font_scale(factor)
|
||||||
|
|
||||||
|
|
||||||
def save_to_config(config: dict):
|
def save_to_config(config: dict):
|
||||||
"""Persist theme settings into the config dict under [theme]."""
|
"""Persist theme settings into the config dict under [theme]."""
|
||||||
config.setdefault("theme", {})
|
config.setdefault("theme", {})
|
||||||
config["theme"]["palette"] = _current_palette
|
config["theme"]["palette"] = _current_palette
|
||||||
config["theme"]["font_path"] = _current_font_path
|
config["theme"]["font_path"] = _current_font_path
|
||||||
config["theme"]["font_size"] = _current_font_size
|
config["theme"]["font_size"] = _current_font_size
|
||||||
config["theme"]["scale"] = _current_scale
|
config["theme"]["scale"] = _current_scale
|
||||||
|
|
||||||
|
|
||||||
def load_from_config(config: dict):
|
def load_from_config(config: dict):
|
||||||
"""Read [theme] from config and apply everything."""
|
"""Read [theme] from config and apply everything."""
|
||||||
t = config.get("theme", {})
|
t = config.get("theme", {})
|
||||||
palette = t.get("palette", "DPG Default")
|
palette = t.get("palette", "DPG Default")
|
||||||
font_path = t.get("font_path", "")
|
font_path = t.get("font_path", "")
|
||||||
font_size = float(t.get("font_size", 14.0))
|
font_size = float(t.get("font_size", 14.0))
|
||||||
scale = float(t.get("scale", 1.0))
|
scale = float(t.get("scale", 1.0))
|
||||||
|
apply(palette)
|
||||||
apply(palette)
|
if font_path:
|
||||||
if font_path:
|
apply_font(font_path, font_size)
|
||||||
apply_font(font_path, font_size)
|
set_scale(scale)
|
||||||
set_scale(scale)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user