colortheme builder wip
This commit is contained in:
parent
d8ffaea25a
commit
e5f9c4410b
9 changed files with 689 additions and 1289 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -20,4 +20,6 @@ firefox_config.txt
|
|||
test/
|
||||
lang/
|
||||
test.py
|
||||
download/
|
||||
download/
|
||||
theme.json
|
||||
test.json
|
|
@ -6,6 +6,40 @@ from PIL import Image, ImageTk
|
|||
import download_main
|
||||
from gui_starfield import StarField
|
||||
from json_main import save_package
|
||||
from theme_ctk_auto import generate_theme_json
|
||||
|
||||
def apply_theme(app, col_background, col_theme, is_dark):
|
||||
|
||||
if is_dark:
|
||||
set_default_color_theme("dark-blue")
|
||||
set_appearance_mode("dark")
|
||||
else:
|
||||
set_default_color_theme("blue")
|
||||
set_appearance_mode("white")
|
||||
|
||||
generate_theme_json(col_theme, is_dark)
|
||||
set_default_color_theme("./theme.json")
|
||||
|
||||
# # Apply background color to the app
|
||||
# app.configure(bg=f"#{col_background[0]:02x}{col_background[1]:02x}{col_background[2]:02x}")
|
||||
|
||||
# # Customize individual widget colors
|
||||
# CLabel.set_default("bg", f"#{col_background[0]:02x}{col_background[1]:02x}{col_background[2]:02x}")
|
||||
# CLabel.set_default("fg", f"#{col_theme[0]:02x}{col_theme[1]:02x}{col_theme[2]:02x}")
|
||||
|
||||
# CButton.set_default("bg", f"#{col_theme[0]:02x}{col_theme[1]:02x}{col_theme[2]:02x}")
|
||||
# CButton.set_default("fg", f"#{col_background[0]:02x}{col_background[1]:02x}{col_background[2]:02x}")
|
||||
|
||||
# CCombobox.set_default("bg", f"#{col_theme[0]:02x}{col_theme[1]:02x}{col_theme[2]:02x}")
|
||||
# CCombobox.set_default("fg", f"#{col_background[0]:02x}{col_background[1]:02x}{col_background[2]:02x}")
|
||||
|
||||
# # Set dark mode specific configurations
|
||||
# if is_dark:
|
||||
# # Example: Set dark mode specific configurations
|
||||
# CLabel.set_default("font", ("Arial", 12, "bold"))
|
||||
# CButton.set_default("font", ("Arial", 12, "bold"))
|
||||
# # Add more configurations as needed for dark mode
|
||||
|
||||
|
||||
def run_installer(download_folder_tmp, col_background, col_theme, col_isDark):
|
||||
global visible_widgets, tab_combobox # Declare tab_combobox as a global variable
|
||||
|
@ -17,14 +51,10 @@ def run_installer(download_folder_tmp, col_background, col_theme, col_isDark):
|
|||
app.minsize(width=800, height=600)
|
||||
app.maxsize(width=800, height=600)
|
||||
|
||||
app.isDark = col_isDark
|
||||
|
||||
if app.isDark:
|
||||
set_default_color_theme("dark-blue")
|
||||
set_appearance_mode("dark")
|
||||
|
||||
app.resizable(False, False)
|
||||
|
||||
apply_theme(app, col_background, col_theme, col_isDark)
|
||||
|
||||
def print_ahoj():
|
||||
spitfire_source_info = {
|
||||
"url": "https://downloads.sourceforge.net/project/spitfire-browser/nightly/components/Browser/win-bin-nighty.zip",
|
||||
|
@ -47,7 +77,7 @@ def run_installer(download_folder_tmp, col_background, col_theme, col_isDark):
|
|||
|
||||
def display_star_field(container):
|
||||
global star_field
|
||||
star_field = StarField(container, 400, 600, app.isDark)
|
||||
star_field = StarField(container, 400, 600, col_isDark)
|
||||
star_field.canvas.pack(side="left", fill="y")
|
||||
|
||||
def create_widgets_for_current_tab():
|
||||
|
|
140
src/init_win.py
Normal file
140
src/init_win.py
Normal file
|
@ -0,0 +1,140 @@
|
|||
import os
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
import requests
|
||||
import zipfile
|
||||
import certifi
|
||||
import ssl
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
def get_temp_folder():
|
||||
# Get the current user's temporary directory
|
||||
temp_dir = tempfile.gettempdir()
|
||||
|
||||
# Create a subdirectory inside the temporary directory
|
||||
user_temp_folder = os.path.join(temp_dir, 'SpitfireBrowserTmp')
|
||||
|
||||
# Create the directory if it doesn't exist
|
||||
if not os.path.exists(user_temp_folder):
|
||||
os.makedirs(user_temp_folder)
|
||||
|
||||
return user_temp_folder
|
||||
|
||||
|
||||
def download_file(url, destination, progress_callback=None, label_callback=None):
|
||||
response = requests.get(url, stream=True)
|
||||
total_size = int(response.headers.get('content-length', 0))
|
||||
block_size = 8192
|
||||
current_size = 0
|
||||
with open(destination, 'wb') as out_file:
|
||||
for buffer in response.iter_content(block_size):
|
||||
if not buffer:
|
||||
break
|
||||
out_file.write(buffer)
|
||||
current_size += len(buffer)
|
||||
if progress_callback:
|
||||
progress_callback(current_size, total_size)
|
||||
if label_callback:
|
||||
label_callback("Downloading")
|
||||
|
||||
if label_callback:
|
||||
label_callback("Download Complete")
|
||||
|
||||
|
||||
def extract_zip(zip_file, extract_path, label_callback=None):
|
||||
with zipfile.ZipFile(zip_file, 'r') as zip_ref:
|
||||
zip_ref.extractall(extract_path)
|
||||
|
||||
if label_callback:
|
||||
label_callback("Extracting")
|
||||
|
||||
|
||||
def download_gtk_dlls(download_path, dll_url, dll_files, progress_callback=None, label_callback=None):
|
||||
for dll_file in dll_files:
|
||||
file_url = dll_url + dll_file
|
||||
|
||||
if not os.path.exists(os.path.join(download_path, dll_file)):
|
||||
download_file(file_url, os.path.join(download_path, dll_file), progress_callback, label_callback)
|
||||
|
||||
# Check if the downloaded file is a zip file, extract it, and remove the zip file
|
||||
if dll_file.endswith('.zip'):
|
||||
extract_path = os.path.join(download_path, dll_file.replace('.zip', ''))
|
||||
extract_zip(os.path.join(download_path, dll_file), extract_path, label_callback)
|
||||
os.remove(os.path.join(download_path, dll_file))
|
||||
|
||||
|
||||
def set_path_variable(download_path):
|
||||
|
||||
current = subprocess.run("echo %Path%", stdout=subprocess.PIPE, shell=True, text=True)
|
||||
|
||||
output_string = str(current.stdout).strip() + ';' + download_path
|
||||
|
||||
# Split the output_string into individual elements
|
||||
elements = output_string.split(';')
|
||||
|
||||
# Remove duplicates
|
||||
unique_elements = list(set(elements))
|
||||
|
||||
# Join the unique elements back together
|
||||
output_string_unique = ';'.join(unique_elements)
|
||||
|
||||
# Refresh the system environment variables
|
||||
subprocess.run("SETX Path " + output_string_unique, shell=True)
|
||||
|
||||
print(f"Added PATH: {output_string_unique}")
|
||||
|
||||
|
||||
def get_deps_win():
|
||||
|
||||
download_path = get_temp_folder()
|
||||
|
||||
dll_url = 'https://downloads.sourceforge.net/project/spitfire-browser/nightly/components/GTK4/'
|
||||
|
||||
# Check if all required files are already present
|
||||
dll_files = [
|
||||
'libs.zip'
|
||||
]
|
||||
|
||||
# Get the names of the folders corresponding to ".zip" files
|
||||
zip_folders = [filename.replace('.zip', '') for filename in dll_files if filename.endswith('.zip')]
|
||||
|
||||
# Check if all corresponding folders exist
|
||||
all_folders_exist = all(os.path.exists(os.path.join(download_path, folder)) for folder in zip_folders)
|
||||
|
||||
if not all_folders_exist:
|
||||
root = tk.Tk()
|
||||
root.title("Preparing for first start")
|
||||
root.geometry("240x120")
|
||||
|
||||
progress_var = tk.DoubleVar()
|
||||
progress = ttk.Progressbar(root, variable=progress_var, length=200)
|
||||
progress.grid(row=0, column=0, padx=20, pady=20)
|
||||
|
||||
label_var = tk.StringVar()
|
||||
label = tk.Label(root, textvariable=label_var)
|
||||
label.grid(row=1, column=0, padx=20, pady=10)
|
||||
|
||||
def update_progress_bar(current_size, total_size):
|
||||
progress_value = (current_size / total_size) * 100
|
||||
progress_var.set(progress_value)
|
||||
root.update_idletasks()
|
||||
|
||||
def update_label(new_label):
|
||||
label_var.set(new_label)
|
||||
root.update_idletasks()
|
||||
|
||||
def start_download():
|
||||
download_gtk_dlls(download_path, dll_url, dll_files, update_progress_bar, update_label)
|
||||
set_path_variable(download_path)
|
||||
|
||||
for zip_folder in zip_folders:
|
||||
set_path_variable(os.path.join(download_path, zip_folder))
|
||||
|
||||
root.destroy()
|
||||
return download_path
|
||||
|
||||
root.after(100, start_download)
|
||||
root.mainloop()
|
||||
else:
|
||||
return download_path
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
import json_main
|
||||
|
||||
def install_all_packages(data):
|
||||
|
|
|
@ -3,12 +3,12 @@ import sys
|
|||
def main():
|
||||
# do an OS specific precheck
|
||||
if sys.platform == 'win32':
|
||||
from main_win import run_init_win
|
||||
run_init_win()
|
||||
from main_win import main_win
|
||||
main_win()
|
||||
return
|
||||
|
||||
from gui_main import run_installer
|
||||
run_installer(".")
|
||||
run_installer("./tmp",(10, 10, 10),(0, 120, 215),true)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
157
src/main_win.py
157
src/main_win.py
|
@ -1,147 +1,14 @@
|
|||
import os
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
import requests
|
||||
import zipfile
|
||||
import certifi
|
||||
import ssl
|
||||
import subprocess
|
||||
import tempfile
|
||||
from init_win import get_deps_win
|
||||
from theme_win import get_theme_win
|
||||
from gui_main import run_installer
|
||||
|
||||
def get_temp_folder():
|
||||
# Get the current user's temporary directory
|
||||
temp_dir = tempfile.gettempdir()
|
||||
def main_win():
|
||||
dow_path = "./tmp"
|
||||
col_background = None
|
||||
col_theme = None
|
||||
is_dark = None
|
||||
|
||||
dow_path = get_deps_win()
|
||||
col_background, col_theme, is_dark = get_theme_win()
|
||||
|
||||
# Create a subdirectory inside the temporary directory
|
||||
user_temp_folder = os.path.join(temp_dir, 'SpitfireBrowserTmp')
|
||||
|
||||
# Create the directory if it doesn't exist
|
||||
if not os.path.exists(user_temp_folder):
|
||||
os.makedirs(user_temp_folder)
|
||||
|
||||
return user_temp_folder
|
||||
|
||||
|
||||
def download_file(url, destination, progress_callback=None, label_callback=None):
|
||||
response = requests.get(url, stream=True)
|
||||
total_size = int(response.headers.get('content-length', 0))
|
||||
block_size = 8192
|
||||
current_size = 0
|
||||
with open(destination, 'wb') as out_file:
|
||||
for buffer in response.iter_content(block_size):
|
||||
if not buffer:
|
||||
break
|
||||
out_file.write(buffer)
|
||||
current_size += len(buffer)
|
||||
if progress_callback:
|
||||
progress_callback(current_size, total_size)
|
||||
if label_callback:
|
||||
label_callback("Downloading")
|
||||
|
||||
if label_callback:
|
||||
label_callback("Download Complete")
|
||||
|
||||
|
||||
def extract_zip(zip_file, extract_path, label_callback=None):
|
||||
with zipfile.ZipFile(zip_file, 'r') as zip_ref:
|
||||
zip_ref.extractall(extract_path)
|
||||
|
||||
if label_callback:
|
||||
label_callback("Extracting")
|
||||
|
||||
|
||||
def download_gtk_dlls(download_path, dll_url, dll_files, progress_callback=None, label_callback=None):
|
||||
for dll_file in dll_files:
|
||||
file_url = dll_url + dll_file
|
||||
|
||||
if not os.path.exists(os.path.join(download_path, dll_file)):
|
||||
download_file(file_url, os.path.join(download_path, dll_file), progress_callback, label_callback)
|
||||
|
||||
# Check if the downloaded file is a zip file, extract it, and remove the zip file
|
||||
if dll_file.endswith('.zip'):
|
||||
extract_path = os.path.join(download_path, dll_file.replace('.zip', ''))
|
||||
extract_zip(os.path.join(download_path, dll_file), extract_path, label_callback)
|
||||
os.remove(os.path.join(download_path, dll_file))
|
||||
|
||||
|
||||
def set_path_variable(download_path):
|
||||
|
||||
current = subprocess.run("echo %Path%", stdout=subprocess.PIPE, shell=True, text=True)
|
||||
|
||||
output_string = str(current.stdout).strip() + ';' + download_path
|
||||
|
||||
# Split the output_string into individual elements
|
||||
elements = output_string.split(';')
|
||||
|
||||
# Remove duplicates
|
||||
unique_elements = list(set(elements))
|
||||
|
||||
# Join the unique elements back together
|
||||
output_string_unique = ';'.join(unique_elements)
|
||||
|
||||
# Refresh the system environment variables
|
||||
subprocess.run("SETX Path " + output_string_unique, shell=True)
|
||||
|
||||
print(f"Added PATH: {output_string_unique}")
|
||||
|
||||
|
||||
def run_init_win():
|
||||
|
||||
download_path = get_temp_folder()
|
||||
|
||||
dll_url = 'https://downloads.sourceforge.net/project/spitfire-browser/nightly/components/GTK4/'
|
||||
|
||||
# Check if all required files are already present
|
||||
dll_files = [
|
||||
'libs.zip'
|
||||
]
|
||||
|
||||
# Get the names of the folders corresponding to ".zip" files
|
||||
zip_folders = [filename.replace('.zip', '') for filename in dll_files if filename.endswith('.zip')]
|
||||
|
||||
# Check if all corresponding folders exist
|
||||
all_folders_exist = all(os.path.exists(os.path.join(download_path, folder)) for folder in zip_folders)
|
||||
|
||||
if not all_folders_exist:
|
||||
root = tk.Tk()
|
||||
root.title("Preparing for first start")
|
||||
root.geometry("240x120")
|
||||
|
||||
progress_var = tk.DoubleVar()
|
||||
progress = ttk.Progressbar(root, variable=progress_var, length=200)
|
||||
progress.grid(row=0, column=0, padx=20, pady=20)
|
||||
|
||||
label_var = tk.StringVar()
|
||||
label = tk.Label(root, textvariable=label_var)
|
||||
label.grid(row=1, column=0, padx=20, pady=10)
|
||||
|
||||
def update_progress_bar(current_size, total_size):
|
||||
progress_value = (current_size / total_size) * 100
|
||||
progress_var.set(progress_value)
|
||||
root.update_idletasks()
|
||||
|
||||
def update_label(new_label):
|
||||
label_var.set(new_label)
|
||||
root.update_idletasks()
|
||||
|
||||
def start_download():
|
||||
download_gtk_dlls(download_path, dll_url, dll_files, update_progress_bar, update_label)
|
||||
set_path_variable(download_path)
|
||||
|
||||
for zip_folder in zip_folders:
|
||||
set_path_variable(os.path.join(download_path, zip_folder))
|
||||
|
||||
root.destroy()
|
||||
|
||||
|
||||
# Run your main application function
|
||||
|
||||
# Run your main application function
|
||||
from gui_main import run_installer
|
||||
run_installer(download_path)
|
||||
|
||||
root.after(100, start_download)
|
||||
root.mainloop()
|
||||
else:
|
||||
from gui_main import run_installer
|
||||
run_installer(download_path)
|
||||
run_installer(dow_path, col_background, col_theme, is_dark)
|
428
src/theme_ctk_auto.py
Normal file
428
src/theme_ctk_auto.py
Normal file
|
@ -0,0 +1,428 @@
|
|||
import json
|
||||
|
||||
def rgb_to_hex(rgb):
|
||||
"""
|
||||
Convert RGB color values to hex color code.
|
||||
|
||||
Args:
|
||||
- rgb (tuple): RGB color represented as a tuple of three integers (R, G, B).
|
||||
|
||||
Returns:
|
||||
- str: Hex color code.
|
||||
"""
|
||||
if not isinstance(rgb, tuple) or len(rgb) != 3:
|
||||
raise ValueError("Input color must be a tuple of three integers (R, G, B).")
|
||||
|
||||
hex_color = "#{:02x}{:02x}{:02x}".format(*rgb)
|
||||
return hex_color.upper()
|
||||
|
||||
def adjust_brightness_based_on_luminance(color, adjustment_percent):
|
||||
"""
|
||||
Adjust the brightness of a color based on its luminance.
|
||||
|
||||
Args:
|
||||
- color (tuple): RGB color represented as a tuple of three integers (R, G, B).
|
||||
- adjustment_percent (float): Percentage by which to adjust the brightness.
|
||||
Positive values make the color lighter, negative values make it darker.
|
||||
|
||||
Returns:
|
||||
- tuple: Adjusted RGB color represented as a tuple of three integers (R, G, B).
|
||||
"""
|
||||
# Validate input color
|
||||
if not isinstance(color, tuple) or len(color) != 3:
|
||||
raise ValueError("Input color must be a tuple of three integers (R, G, B).")
|
||||
|
||||
# Calculate luminance using the formula: 0.299 * R + 0.587 * G + 0.114 * B
|
||||
luminance = 0.299 * color[0] + 0.587 * color[1] + 0.114 * color[2]
|
||||
|
||||
# Determine whether the color is dark or light
|
||||
is_dark = luminance < 128 # Assuming a luminance threshold of 128 for darkness
|
||||
|
||||
# Adjust brightness based on luminance
|
||||
adjustment_factor = -adjustment_percent if is_dark else adjustment_percent
|
||||
adjusted_color = tuple(max(0, min(int(value * (1 + adjustment_factor / 100)), 255)) for value in color)
|
||||
|
||||
return rgb_to_hex(adjusted_color)
|
||||
|
||||
def generate_theme_json(col_theme, is_dark):
|
||||
# Define colors based on is_dark
|
||||
if is_dark:
|
||||
bg_color = ["gray17", "gray20"]
|
||||
text_color = ["gray10", "#DCE4EE"]
|
||||
|
||||
else:
|
||||
bg_color = ["gray86", "gray20"]
|
||||
text_color = ["#111111", "#000000"]
|
||||
|
||||
|
||||
fg_color = col_theme
|
||||
combo_box_col = col_theme
|
||||
|
||||
bg_col_theme = adjust_brightness_based_on_luminance(col_theme, 20)
|
||||
disabled_col_theme = adjust_brightness_based_on_luminance(col_theme, -30)
|
||||
|
||||
|
||||
# Generate theme dictionary
|
||||
theme_data = {
|
||||
"CTk": {
|
||||
"fg_color": text_color
|
||||
},
|
||||
"CTkToplevel": {
|
||||
"fg_color": text_color
|
||||
},
|
||||
"CTkFrame": {
|
||||
"corner_radius": 6,
|
||||
"border_width": 0,
|
||||
"fg_color": bg_color,
|
||||
"top_fg_color": [
|
||||
"gray81",
|
||||
"gray20"
|
||||
],
|
||||
"border_color": [
|
||||
"gray65",
|
||||
"gray28"
|
||||
]
|
||||
},
|
||||
"CTkButton": {
|
||||
"corner_radius": 6,
|
||||
"border_width": 0,
|
||||
"fg_color": [
|
||||
"#3B8ED0",
|
||||
"#1F6AA5"
|
||||
],
|
||||
"hover_color": bg_col_theme,
|
||||
"border_color": [
|
||||
"#3E454A",
|
||||
"#949A9F"
|
||||
],
|
||||
"text_color": text_color,
|
||||
"text_color_disabled": [
|
||||
"gray74",
|
||||
"gray60"
|
||||
]
|
||||
},
|
||||
"CTkLabel": {
|
||||
"corner_radius": 0,
|
||||
"fg_color": "transparent",
|
||||
"text_color": text_color,
|
||||
"text_color_disabled": text_color
|
||||
},
|
||||
"CTkEntry": {
|
||||
"corner_radius": 6,
|
||||
"border_width": 2,
|
||||
"fg_color": [
|
||||
"#F9F9FA",
|
||||
"#343638"
|
||||
],
|
||||
"border_color": [
|
||||
"#979DA2",
|
||||
"#565B5E"
|
||||
],
|
||||
"text_color": text_color,
|
||||
"placeholder_text_color": [
|
||||
"gray52",
|
||||
"gray62"
|
||||
]
|
||||
},
|
||||
"CTkCheckBox": {
|
||||
"corner_radius": 6,
|
||||
"border_width": 3,
|
||||
"fg_color": [
|
||||
"#3B8ED0",
|
||||
"#1F6AA5"
|
||||
],
|
||||
"border_color": [
|
||||
"#3E454A",
|
||||
"#949A9F"
|
||||
],
|
||||
"hover_color": [
|
||||
"#3B8ED0",
|
||||
"#1F6AA5"
|
||||
],
|
||||
"checkmark_color": [
|
||||
"#DCE4EE",
|
||||
"gray90"
|
||||
],
|
||||
"text_color": text_color,
|
||||
"text_color_disabled": [
|
||||
"gray60",
|
||||
"gray45"
|
||||
]
|
||||
},
|
||||
"CTkSwitch": {
|
||||
"corner_radius": 1000,
|
||||
"border_width": 3,
|
||||
"button_length": 0,
|
||||
"fg_color": [
|
||||
"#939BA2",
|
||||
"#4A4D50"
|
||||
],
|
||||
"progress_color": [
|
||||
"#3B8ED0",
|
||||
"#1F6AA5"
|
||||
],
|
||||
"button_color": [
|
||||
"gray36",
|
||||
"#D5D9DE"
|
||||
],
|
||||
"button_hover_color": [
|
||||
"gray20",
|
||||
"gray100"
|
||||
],
|
||||
"text_color": text_color,
|
||||
"text_color_disabled": [
|
||||
"gray60",
|
||||
"gray45"
|
||||
]
|
||||
},
|
||||
"CTkRadioButton": {
|
||||
"corner_radius": 1000,
|
||||
"border_width_checked": 6,
|
||||
"border_width_unchecked": 3,
|
||||
"fg_color": [
|
||||
"#3B8ED0",
|
||||
"#1F6AA5"
|
||||
],
|
||||
"border_color": [
|
||||
"#3E454A",
|
||||
"#949A9F"
|
||||
],
|
||||
"hover_color": bg_col_theme,
|
||||
"text_color": text_color,
|
||||
"text_color_disabled": [
|
||||
"gray60",
|
||||
"gray45"
|
||||
]
|
||||
},
|
||||
"CTkProgressBar": {
|
||||
"corner_radius": 1000,
|
||||
"border_width": 0,
|
||||
"fg_color": [
|
||||
"#939BA2",
|
||||
"#4A4D50"
|
||||
],
|
||||
"progress_color": [
|
||||
"#3B8ED0",
|
||||
"#1F6AA5"
|
||||
],
|
||||
"border_color": [
|
||||
"gray",
|
||||
"gray"
|
||||
]
|
||||
},
|
||||
"CTkSlider": {
|
||||
"corner_radius": 1000,
|
||||
"button_corner_radius": 1000,
|
||||
"border_width": 6,
|
||||
"button_length": 0,
|
||||
"fg_color": [
|
||||
"#939BA2",
|
||||
"#4A4D50"
|
||||
],
|
||||
"progress_color": [
|
||||
"gray40",
|
||||
"#AAB0B5"
|
||||
],
|
||||
"button_color": [
|
||||
"#3B8ED0",
|
||||
"#1F6AA5"
|
||||
],
|
||||
"button_hover_color": [
|
||||
"#36719F",
|
||||
"#144870"
|
||||
]
|
||||
},
|
||||
"CTkOptionMenu": {
|
||||
"corner_radius": 6,
|
||||
"fg_color": [
|
||||
"#3B8ED0",
|
||||
"#1F6AA5"
|
||||
],
|
||||
"button_color": col_theme,
|
||||
"button_hover_color": [
|
||||
"#27577D",
|
||||
"#203A4F"
|
||||
],
|
||||
"text_color": [
|
||||
"#DCE4EE",
|
||||
"#DCE4EE"
|
||||
],
|
||||
"text_color_disabled": [
|
||||
"gray74",
|
||||
"gray60"
|
||||
]
|
||||
},
|
||||
"CTkComboBox": {
|
||||
"corner_radius": 6,
|
||||
"border_width": 2,
|
||||
"fg_color": [
|
||||
"#F9F9FA",
|
||||
"#343638"
|
||||
],
|
||||
"border_color": [
|
||||
"#979DA2",
|
||||
"#565B5E"
|
||||
],
|
||||
"button_color": [
|
||||
"#979DA2",
|
||||
"#565B5E"
|
||||
],
|
||||
"button_hover_color": [
|
||||
"#6E7174",
|
||||
"#7A848D"
|
||||
],
|
||||
"text_color": text_color,
|
||||
"text_color_disabled": [
|
||||
"gray50",
|
||||
"gray45"
|
||||
]
|
||||
},
|
||||
"CTkScrollbar": {
|
||||
"corner_radius": 1000,
|
||||
"border_spacing": 4,
|
||||
"fg_color": "transparent",
|
||||
"button_color": [
|
||||
"gray55",
|
||||
"gray41"
|
||||
],
|
||||
"button_hover_color": [
|
||||
"gray40",
|
||||
"gray53"
|
||||
]
|
||||
},
|
||||
"CTkSegmentedButton": {
|
||||
"corner_radius": 6,
|
||||
"border_width": 2,
|
||||
"fg_color": [
|
||||
"#979DA2",
|
||||
"gray29"
|
||||
],
|
||||
"selected_color": [
|
||||
"#3B8ED0",
|
||||
"#1F6AA5"
|
||||
],
|
||||
"selected_hover_color": [
|
||||
"#36719F",
|
||||
"#144870"
|
||||
],
|
||||
"unselected_color": [
|
||||
"#979DA2",
|
||||
"gray29"
|
||||
],
|
||||
"unselected_hover_color": [
|
||||
"gray70",
|
||||
"gray41"
|
||||
],
|
||||
"text_color": [
|
||||
"#DCE4EE",
|
||||
"#DCE4EE"
|
||||
],
|
||||
"text_color_disabled": [
|
||||
"gray74",
|
||||
"gray60"
|
||||
]
|
||||
},
|
||||
"CTkTextbox": {
|
||||
"corner_radius": 6,
|
||||
"border_width": 0,
|
||||
"fg_color": [
|
||||
"#F9F9FA",
|
||||
"#1D1E1E"
|
||||
],
|
||||
"border_color": [
|
||||
"#979DA2",
|
||||
"#565B5E"
|
||||
],
|
||||
"text_color": text_color,
|
||||
"scrollbar_button_color": [
|
||||
"gray55",
|
||||
"gray41"
|
||||
],
|
||||
"scrollbar_button_hover_color": [
|
||||
"gray40",
|
||||
"gray53"
|
||||
]
|
||||
},
|
||||
"CTkScrollableFrame": {
|
||||
"label_fg_color": [
|
||||
"gray78",
|
||||
"gray23"
|
||||
]
|
||||
},
|
||||
"DropdownMenu": {
|
||||
"fg_color": [
|
||||
"gray90",
|
||||
"gray20"
|
||||
],
|
||||
"hover_color": [
|
||||
"gray75",
|
||||
"gray28"
|
||||
],
|
||||
"text_color": [
|
||||
"gray10",
|
||||
"gray90"
|
||||
]
|
||||
},
|
||||
"CTkFont": {
|
||||
"macOS": {
|
||||
"family": "SF Display",
|
||||
"size": 13,
|
||||
"weight": "normal"
|
||||
},
|
||||
"Windows": {
|
||||
"family": "Roboto",
|
||||
"size": 13,
|
||||
"weight": "normal"
|
||||
},
|
||||
"Linux": {
|
||||
"family": "Roboto",
|
||||
"size": 13,
|
||||
"weight": "normal"
|
||||
}
|
||||
},
|
||||
"provenance": {
|
||||
"theme name": "Blue",
|
||||
"theme author": "Tom Schimansky",
|
||||
"date created": "Aug 17 2023 10:47:28",
|
||||
"last modified by": "Clive Bostock",
|
||||
"last modified": "Aug 17 2023 10:47:28",
|
||||
"created with": "CTk Theme Builder v2.4.0",
|
||||
"keystone colour": None,
|
||||
"harmony method": None,
|
||||
"harmony differential": None
|
||||
}
|
||||
}
|
||||
|
||||
# Add provenance information
|
||||
theme_data["provenance"] = {
|
||||
"theme name": "Custom",
|
||||
"theme author": "Your Name",
|
||||
"date created": "Current Date",
|
||||
"last modified by": "Your Name",
|
||||
"last modified": "Current Date",
|
||||
"created with": "Python Theme Generator",
|
||||
"keystone colour": None,
|
||||
"harmony method": None,
|
||||
"harmony differential": None
|
||||
}
|
||||
|
||||
with open("./theme.json", "w") as json_file:
|
||||
json.dump(theme_data, json_file, indent=2)
|
||||
|
||||
# Example use
|
||||
# # Add provenance information
|
||||
# theme_data["provenance"] = {
|
||||
# "theme name": "Custom",
|
||||
# "theme author": "Your Name",
|
||||
# "date created": "Current Date",
|
||||
# "last modified by": "Your Name",
|
||||
# "last modified": "Current Date",
|
||||
# "created with": "Python Theme Generator",
|
||||
# "keystone colour": None,
|
||||
# "harmony method": None,
|
||||
# "harmony differential": None
|
||||
# }
|
||||
|
||||
# # Save the theme data to theme.json
|
||||
# with open("theme.json", "w") as json_file:
|
||||
# json.dump(theme_data, json_file, indent=2)
|
181
src/theme_win.py
181
src/theme_win.py
|
@ -1,120 +1,71 @@
|
|||
import ctypes
|
||||
import winreg
|
||||
|
||||
def get_system_color(index):
|
||||
return ctypes.windll.user32.GetSysColor(index)
|
||||
def get_registry_color_value(key_path, value_name):
|
||||
try:
|
||||
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path)
|
||||
value, _ = winreg.QueryValueEx(key, value_name)
|
||||
winreg.CloseKey(key)
|
||||
return value
|
||||
except Exception as e:
|
||||
print(f"Error accessing registry: {e}")
|
||||
return None
|
||||
|
||||
def color_value_to_rgb(color_value):
|
||||
blue = color_value & 255
|
||||
green = (color_value >> 8) & 255
|
||||
red = (color_value >> 16) & 255
|
||||
return red, green, blue
|
||||
def parse_registry_color_value(value):
|
||||
try:
|
||||
# Convert dword value to RGB format
|
||||
rgb_value = (value & 0xFF, (value >> 8) & 0xFF, (value >> 16) & 0xFF)
|
||||
return rgb_value
|
||||
except Exception as e:
|
||||
print(f"Error parsing registry color value: {e}")
|
||||
return None
|
||||
|
||||
def main():
|
||||
# System color indexes
|
||||
color_indexes = {
|
||||
1: "Scrollbar",
|
||||
2: "Background",
|
||||
3: "ActiveCaption",
|
||||
4: "InactiveCaption",
|
||||
5: "Menu",
|
||||
6: "Window",
|
||||
7: "WindowFrame",
|
||||
8: "MenuText",
|
||||
9: "WindowText",
|
||||
10: "CaptionText",
|
||||
11: "ActiveBorder",
|
||||
12: "InactiveBorder",
|
||||
13: "AppWorkspace",
|
||||
14: "Highlight",
|
||||
15: "HighlightText",
|
||||
16: "BtnFace",
|
||||
17: "BtnShadow",
|
||||
18: "GrayText",
|
||||
19: "BtnText",
|
||||
20: "InactiveCaptionText",
|
||||
21: "BtnHighlight",
|
||||
22: "3dDarkShadow",
|
||||
23: "3dLight",
|
||||
24: "InfoText",
|
||||
25: "InfoWindow",
|
||||
26: "HotLight",
|
||||
27: "GradientActiveCaption",
|
||||
28: "GradientInactiveCaption",
|
||||
29: "MenuHighlight",
|
||||
30: "MenuBar"
|
||||
}
|
||||
# Get and print system colors in RGB format
|
||||
for index, name in color_indexes.items():
|
||||
color_value = get_system_color(index)
|
||||
rgb_color = color_value_to_rgb(color_value)
|
||||
print(f"{name}: RGB{rgb_color}")
|
||||
def get_dark_mode():
|
||||
# Registry key and value for dark mode
|
||||
dark_mode_entry = ("Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", "AppsUseLightTheme")
|
||||
|
||||
# Get and print dark mode value from the registry
|
||||
dark_mode_value = get_registry_color_value(*dark_mode_entry)
|
||||
if dark_mode_value is not None:
|
||||
is_dark = dark_mode_value == 0
|
||||
# print(f"Dark Mode: {'Enabled' if is_dark else 'Disabled'}")
|
||||
|
||||
return is_dark
|
||||
|
||||
return None
|
||||
|
||||
def get_theme_win():
|
||||
# Registry keys and values
|
||||
registry_entries = [
|
||||
("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Accent", "AccentColorMenu"),
|
||||
("Software\\Microsoft\\Windows\\DWM", "AccentColor"),
|
||||
]
|
||||
|
||||
is_dark = get_dark_mode()
|
||||
col_theme = None
|
||||
|
||||
black_rgb = (10, 10, 10)
|
||||
white_rgb = (245, 245, 245)
|
||||
col_background = black_rgb if is_dark else white_rgb
|
||||
|
||||
# Get and print colors from the registry
|
||||
for key_path, value_name in registry_entries:
|
||||
registry_value = get_registry_color_value(key_path, value_name)
|
||||
if registry_value is not None:
|
||||
rgb_color = parse_registry_color_value(registry_value)
|
||||
if rgb_color is not None:
|
||||
|
||||
if value_name == "AccentColorMenu" and rgb_color is not None:
|
||||
col_theme = rgb_color
|
||||
|
||||
if value_name == "AccentColor" and rgb_color is not None:
|
||||
col_theme = rgb_color
|
||||
|
||||
return col_background, col_theme, is_dark
|
||||
|
||||
# Example use
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
|
||||
# run 1
|
||||
# PS C:\msys64\home\Blazek_M\Launcher> python.exe .\src\theme_win.py
|
||||
# Scrollbar: RGB(0, 0, 0)
|
||||
# Background: RGB(209, 180, 153)
|
||||
# ActiveCaption: RGB(219, 205, 191)
|
||||
# InactiveCaption: RGB(240, 240, 240)
|
||||
# Menu: RGB(255, 255, 255)
|
||||
# Window: RGB(100, 100, 100)
|
||||
# WindowFrame: RGB(0, 0, 0)
|
||||
# MenuText: RGB(0, 0, 0)
|
||||
# WindowText: RGB(0, 0, 0)
|
||||
# CaptionText: RGB(180, 180, 180)
|
||||
# ActiveBorder: RGB(252, 247, 244)
|
||||
# InactiveBorder: RGB(171, 171, 171)
|
||||
# AppWorkspace: RGB(215, 120, 0)
|
||||
# Highlight: RGB(255, 255, 255)
|
||||
# HighlightText: RGB(240, 240, 240)
|
||||
# BtnFace: RGB(160, 160, 160)
|
||||
# BtnShadow: RGB(109, 109, 109)
|
||||
# GrayText: RGB(0, 0, 0)
|
||||
# BtnText: RGB(0, 0, 0)
|
||||
# InactiveCaptionText: RGB(255, 255, 255)
|
||||
# BtnHighlight: RGB(105, 105, 105)
|
||||
# 3dDarkShadow: RGB(227, 227, 227)
|
||||
# 3dLight: RGB(0, 0, 0)
|
||||
# InfoText: RGB(225, 255, 255)
|
||||
# InfoWindow: RGB(0, 0, 0)
|
||||
# HotLight: RGB(204, 102, 0)
|
||||
# GradientActiveCaption: RGB(234, 209, 185)
|
||||
# GradientInactiveCaption: RGB(242, 228, 215)
|
||||
# MenuHighlight: RGB(255, 153, 51)
|
||||
# MenuBar: RGB(240, 240, 240)
|
||||
|
||||
# run 2
|
||||
# PS C:\msys64\home\Blazek_M\Launcher> python.exe .\src\theme_win.py
|
||||
# Scrollbar: RGB(0, 0, 0)
|
||||
# Background: RGB(209, 180, 153)
|
||||
# ActiveCaption: RGB(219, 205, 191)
|
||||
# InactiveCaption: RGB(240, 240, 240)
|
||||
# Menu: RGB(255, 255, 255)
|
||||
# Window: RGB(100, 100, 100)
|
||||
# WindowFrame: RGB(0, 0, 0)
|
||||
# MenuText: RGB(0, 0, 0)
|
||||
# WindowText: RGB(0, 0, 0)
|
||||
# CaptionText: RGB(180, 180, 180)
|
||||
# ActiveBorder: RGB(252, 247, 244)
|
||||
# InactiveBorder: RGB(171, 171, 171)
|
||||
# AppWorkspace: RGB(215, 120, 0)
|
||||
# Highlight: RGB(255, 255, 255)
|
||||
# HighlightText: RGB(240, 240, 240)
|
||||
# BtnFace: RGB(160, 160, 160)
|
||||
# BtnShadow: RGB(109, 109, 109)
|
||||
# GrayText: RGB(0, 0, 0)
|
||||
# BtnText: RGB(0, 0, 0)
|
||||
# InactiveCaptionText: RGB(255, 255, 255)
|
||||
# BtnHighlight: RGB(105, 105, 105)
|
||||
# 3dDarkShadow: RGB(227, 227, 227)
|
||||
# 3dLight: RGB(0, 0, 0)
|
||||
# InfoText: RGB(225, 255, 255)
|
||||
# InfoWindow: RGB(0, 0, 0)
|
||||
# HotLight: RGB(204, 102, 0)
|
||||
# GradientActiveCaption: RGB(234, 209, 185)
|
||||
# GradientInactiveCaption: RGB(242, 228, 215)
|
||||
# MenuHighlight: RGB(255, 153, 51)
|
||||
# MenuBar: RGB(240, 240, 240)
|
||||
col_background, col_theme, is_dark = get_theme_win()
|
||||
print(f"---------------")
|
||||
print(f"Background Color: RGB{col_background}")
|
||||
print(f"Theme Color: RGB{col_theme}")
|
||||
print(f"Dark Mode: {'Enabled' if is_dark else 'Disabled'}")
|
||||
|
|
Reference in a new issue