[SCRIPT] Updated
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,3 @@
|
||||
from .service import MaterialService
|
||||
|
||||
__all__ = ["MaterialService"]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,11 @@
|
||||
import os
|
||||
import ignis
|
||||
from ignis.utils import Utils
|
||||
|
||||
|
||||
MATERIAL_CACHE_DIR = f"{ignis.CACHE_DIR}/material" # type: ignore
|
||||
|
||||
TEMPLATES = Utils.get_current_dir() + "/templates"
|
||||
SAMPLE_WALL = Utils.get_current_dir() + "/sample_wall.png"
|
||||
|
||||
os.makedirs(MATERIAL_CACHE_DIR, exist_ok=True)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.1 MiB |
@@ -0,0 +1,127 @@
|
||||
#!/usr/bin/python
|
||||
import os
|
||||
import asyncio
|
||||
from gi.repository import GLib # type: ignore
|
||||
from jinja2 import Template
|
||||
from PIL import Image
|
||||
from materialyoucolor.quantize import QuantizeCelebi
|
||||
from materialyoucolor.hct import Hct
|
||||
from materialyoucolor.scheme.scheme_tonal_spot import SchemeTonalSpot
|
||||
from materialyoucolor.dynamiccolor.material_dynamic_colors import MaterialDynamicColors
|
||||
from materialyoucolor.score.score import Score
|
||||
|
||||
from ignis.utils import Utils
|
||||
from ignis.app import IgnisApp
|
||||
from ignis.base_service import BaseService
|
||||
from ignis.services.wallpaper import CACHE_WALLPAPER_PATH
|
||||
from ignis.options import options
|
||||
from user_options import user_options
|
||||
|
||||
from .constants import MATERIAL_CACHE_DIR, TEMPLATES, SAMPLE_WALL
|
||||
from .util import rgba_to_hex, calculate_optimal_size
|
||||
|
||||
app = IgnisApp.get_default()
|
||||
|
||||
|
||||
class MaterialService(BaseService):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
if not os.path.exists(CACHE_WALLPAPER_PATH):
|
||||
self.__on_colors_not_found()
|
||||
if user_options.material.colors == {}:
|
||||
self.__on_colors_not_found()
|
||||
|
||||
user_options.material.connect_option(
|
||||
"dark_mode", lambda: self.generate_colors(CACHE_WALLPAPER_PATH)
|
||||
)
|
||||
|
||||
def __on_colors_not_found(self) -> None:
|
||||
options.wallpaper.set_wallpaper_path(SAMPLE_WALL)
|
||||
self.generate_colors(SAMPLE_WALL)
|
||||
asyncio.create_task(Utils.exec_sh_async("hyprctl reload"))
|
||||
|
||||
def get_colors_from_img(self, path: str, dark_mode: bool) -> dict[str, str]:
|
||||
image = Image.open(path)
|
||||
wsize, hsize = image.size
|
||||
wsize_new, hsize_new = calculate_optimal_size(wsize, hsize, 128)
|
||||
if wsize_new < wsize or hsize_new < hsize:
|
||||
image = image.resize((wsize_new, hsize_new), Image.Resampling.BICUBIC) # type: ignore
|
||||
|
||||
pixel_len = image.width * image.height
|
||||
image_data = image.getdata()
|
||||
pixel_array = [image_data[_] for _ in range(0, pixel_len, 1)]
|
||||
|
||||
colors = QuantizeCelebi(pixel_array, 128)
|
||||
argb = Score.score(colors)[0]
|
||||
|
||||
hct = Hct.from_int(argb)
|
||||
scheme = SchemeTonalSpot(hct, dark_mode, 0.0)
|
||||
|
||||
material_colors = {}
|
||||
for color in vars(MaterialDynamicColors).keys():
|
||||
color_name = getattr(MaterialDynamicColors, color)
|
||||
if hasattr(color_name, "get_hct"):
|
||||
rgba = color_name.get_hct(scheme).to_rgba()
|
||||
material_colors[color] = rgba_to_hex(rgba)
|
||||
|
||||
return material_colors
|
||||
|
||||
def generate_colors(self, path: str) -> None:
|
||||
colors = self.get_colors_from_img(path, user_options.material.dark_mode)
|
||||
dark_colors = self.get_colors_from_img(path, True)
|
||||
user_options.material.colors = colors
|
||||
self.__render_templates(colors, dark_colors)
|
||||
asyncio.create_task(self.__setup(path))
|
||||
|
||||
def __render_templates(self, colors: dict, dark_colors: dict) -> None:
|
||||
for template in os.listdir(TEMPLATES):
|
||||
self.render_template(
|
||||
colors=colors,
|
||||
dark_mode=user_options.material.dark_mode,
|
||||
input_file=f"{TEMPLATES}/{template}",
|
||||
output_file=f"{MATERIAL_CACHE_DIR}/{template}",
|
||||
)
|
||||
|
||||
for template in os.listdir(TEMPLATES):
|
||||
self.render_template(
|
||||
colors=dark_colors,
|
||||
dark_mode=True,
|
||||
input_file=f"{TEMPLATES}/{template}",
|
||||
output_file=f"{MATERIAL_CACHE_DIR}/dark_{template}",
|
||||
)
|
||||
|
||||
def render_template(
|
||||
self,
|
||||
colors: dict,
|
||||
input_file: str,
|
||||
output_file: str,
|
||||
dark_mode: bool | None = None,
|
||||
) -> None:
|
||||
if dark_mode is None:
|
||||
colors["dark_mode"] = str(user_options.material.dark_mode).lower()
|
||||
else:
|
||||
colors["dark_mode"] = str(dark_mode).lower()
|
||||
with open(input_file) as file:
|
||||
template_rendered = Template(file.read()).render(colors)
|
||||
|
||||
with open(output_file, "w") as file:
|
||||
file.write(template_rendered)
|
||||
|
||||
async def __reload_gtk_theme(self) -> None:
|
||||
THEME_CMD = "gsettings set org.gnome.desktop.interface gtk-theme {}"
|
||||
COLOR_SCHEME_CMD = "gsettings set org.gnome.desktop.interface color-scheme {}"
|
||||
await Utils.exec_sh_async(THEME_CMD.format("Adwaita"))
|
||||
await Utils.exec_sh_async(THEME_CMD.format("Material"))
|
||||
await Utils.exec_sh_async(COLOR_SCHEME_CMD.format("default"))
|
||||
await Utils.exec_sh_async(COLOR_SCHEME_CMD.format("prefer-dark"))
|
||||
await Utils.exec_sh_async(COLOR_SCHEME_CMD.format("default"))
|
||||
|
||||
async def __setup(self, image_path: str) -> None:
|
||||
try:
|
||||
await Utils.exec_sh_async("pkill -SIGUSR1 kitty")
|
||||
except GLib.Error:
|
||||
...
|
||||
options.wallpaper.set_wallpaper_path(image_path)
|
||||
app.reload_css()
|
||||
await self.__reload_gtk_theme()
|
||||
@@ -0,0 +1,7 @@
|
||||
$primary = rgb({{ primary | replace("#", "") }})
|
||||
$surface = rgb({{ surface | replace("#", "") }})
|
||||
$onSurface = rgb({{ onSurface | replace("#", "") }})
|
||||
|
||||
$primaryHex = #{{ primary }}
|
||||
$surfaceHex = #{{ surface }}
|
||||
$onSurfaceHex = #{{ onSurface }}
|
||||
@@ -0,0 +1,23 @@
|
||||
foreground {{ onBackground }}
|
||||
background {{ background }}
|
||||
cursor {{ primaryFixed }}
|
||||
|
||||
# Base 8 Colors (0-7)
|
||||
color0 {{ surfaceContainerLowest }}
|
||||
color1 {{ error }}
|
||||
color2 {{ primary }}
|
||||
color3 {{ tertiary }}
|
||||
color4 {{ primaryContainer }}
|
||||
color5 {{ secondaryFixedDim }}
|
||||
color6 {{ tertiaryFixed }}
|
||||
color7 {{ onSurface }}
|
||||
|
||||
# Bright (Bold) Variants (8–15)
|
||||
color8 {{ outlineVariant }}
|
||||
color9 {{ errorContainer }}
|
||||
color10 {{ primaryContainer }}
|
||||
color11 {{ tertiaryContainer }}
|
||||
color12 {{ secondaryContainer }}
|
||||
color13 {{ onSecondaryFixedVariant }}
|
||||
color14 {{ onTertiaryFixedVariant }}
|
||||
color15 {{ onSurfaceVariant }}
|
||||
@@ -0,0 +1,55 @@
|
||||
$primary_paletteKeyColor: {{ primary_paletteKeyColor }};
|
||||
$secondary_paletteKeyColor: {{ secondary_paletteKeyColor }};
|
||||
$tertiary_paletteKeyColor: {{ tertiary_paletteKeyColor }};
|
||||
$neutral_paletteKeyColor: {{ neutral_paletteKeyColor }};
|
||||
$neutral_variant_paletteKeyColor: {{ neutral_variant_paletteKeyColor }};
|
||||
$background: {{ background }};
|
||||
$onBackground: {{ onBackground }};
|
||||
$surface: {{ surface }};
|
||||
$surfaceDim: {{ surfaceDim }};
|
||||
$surfaceBright: {{ surfaceBright }};
|
||||
$surfaceContainerLowest: {{ surfaceContainerLowest }};
|
||||
$surfaceContainerLow: {{ surfaceContainerLow }};
|
||||
$surfaceContainer: {{ surfaceContainer }};
|
||||
$surfaceContainerHigh: {{ surfaceContainerHigh }};
|
||||
$surfaceContainerHighest: {{ surfaceContainerHighest }};
|
||||
$onSurface: {{ onSurface }};
|
||||
$surfaceVariant: {{ surfaceVariant }};
|
||||
$onSurfaceVariant: {{ onSurfaceVariant }};
|
||||
$inverseSurface: {{ inverseSurface }};
|
||||
$inverseOnSurface: {{ inverseOnSurface }};
|
||||
$outline: {{ outline }};
|
||||
$outlineVariant: {{ outlineVariant }};
|
||||
$shadow: {{ shadow }};
|
||||
$scrim: {{ scrim }};
|
||||
$surfaceTint: {{ surfaceTint }};
|
||||
$primary: {{ primary }};
|
||||
$onPrimary: {{ onPrimary }};
|
||||
$primaryContainer: {{ primaryContainer }};
|
||||
$onPrimaryContainer: {{ onPrimaryContainer }};
|
||||
$inversePrimary: {{ inversePrimary }};
|
||||
$secondary: {{ secondary }};
|
||||
$onSecondary: {{ onSecondary }};
|
||||
$secondaryContainer: {{ secondaryContainer }};
|
||||
$onSecondaryContainer: {{ onSecondaryContainer }};
|
||||
$tertiary: {{ tertiary }};
|
||||
$onTertiary: {{ onTertiary }};
|
||||
$tertiaryContainer: {{ tertiaryContainer }};
|
||||
$onTertiaryContainer: {{ onTertiaryContainer }};
|
||||
$error: {{ error }};
|
||||
$onError: {{ onError }};
|
||||
$errorContainer: {{ errorContainer }};
|
||||
$onErrorContainer: {{ onErrorContainer }};
|
||||
$primaryFixed: {{ primaryFixed }};
|
||||
$primaryFixedDim: {{ primaryFixedDim }};
|
||||
$onPrimaryFixed: {{ onPrimaryFixed }};
|
||||
$onPrimaryFixedVariant: {{ onPrimaryFixedVariant }};
|
||||
$secondaryFixed: {{ secondaryFixed }};
|
||||
$secondaryFixedDim: {{ secondaryFixedDim }};
|
||||
$onSecondaryFixed: {{ onSecondaryFixed }};
|
||||
$onSecondaryFixedVariant: {{ onSecondaryFixedVariant }};
|
||||
$tertiaryFixed: {{ tertiaryFixed }};
|
||||
$tertiaryFixedDim: {{ tertiaryFixedDim }};
|
||||
$onTertiaryFixed: {{ onTertiaryFixed }};
|
||||
$onTertiaryFixedVariant: {{ onTertiaryFixedVariant }};
|
||||
$darkmode: {{ dark_mode }};
|
||||
@@ -0,0 +1,50 @@
|
||||
@define-color accent_color {{ primary }};
|
||||
@define-color accent_bg_color {{ primary }};
|
||||
@define-color accent_fg_color {{ surface }};
|
||||
@define-color destructive_color {{ errorContainer }};
|
||||
@define-color destructive_bg_color {{ errorContainer }};
|
||||
@define-color destructive_fg_color {{ onSurface }};
|
||||
@define-color success_color {{ tertiary }};
|
||||
@define-color success_bg_color {{ tertiary }};
|
||||
@define-color success_fg_color {{ onSurface }};
|
||||
@define-color warning_color {{ secondary }};
|
||||
@define-color warning_bg_color {{ secondary }};
|
||||
@define-color warning_fg_color {{ onSurface }};
|
||||
@define-color error_color {{ errorContainer }};
|
||||
@define-color error_bg_color {{ errorContainer }};
|
||||
@define-color error_fg_color {{ onSurface }};
|
||||
@define-color window_bg_color {{ surface }};
|
||||
@define-color window_fg_color {{ onSurface }};
|
||||
@define-color view_bg_color {{ surface }};
|
||||
@define-color view_fg_color {{ onSurface }};
|
||||
@define-color headerbar_bg_color {{ surface }};
|
||||
@define-color headerbar_fg_color {{ onSurface }};
|
||||
@define-color headerbar_border_color {{ outline }};
|
||||
@define-color headerbar_backdrop_color {{ surface }};
|
||||
@define-color headerbar_shade_color {{ outline }};
|
||||
@define-color sidebar_bg_color {{ surfaceContainer }};
|
||||
@define-color sidebar_fg_color {{ onSurface }};
|
||||
@define-color sidebar_backdrop_color {{ surfaceContainer }};
|
||||
@define-color card_bg_color {{ surfaceContainer }};
|
||||
@define-color card_fg_color {{ onSurface }};
|
||||
@define-color card_shade_color rgba(0, 0, 0, 0.07);
|
||||
@define-color thumbnail_bg_color {{ surface }};
|
||||
@define-color thumbnail_fg_color {{ onSurface }};
|
||||
@define-color dialog_bg_color {{ surface }};
|
||||
@define-color dialog_fg_color {{ onSurface }};
|
||||
@define-color popover_bg_color {{ surfaceContainer }};
|
||||
@define-color popover_fg_color {{ onSurface }};
|
||||
@define-color shade_color rgba(0, 0, 0, 0.36);
|
||||
@define-color scrollbar_outline_color {{ outline }};
|
||||
|
||||
.navigation-sidebar {
|
||||
background-color: {{ surfaceContainer }};
|
||||
}
|
||||
|
||||
switch:checked {
|
||||
background-color: {{ primary }};
|
||||
}
|
||||
|
||||
switch:checked slider {
|
||||
background-color: {{ onPrimary }};
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
# ---------------------SETTINGS---------------------------#
|
||||
daemonize
|
||||
show-failed-attempts
|
||||
clock
|
||||
screenshot
|
||||
ignore-empty-password
|
||||
indicator
|
||||
font=JetBrainsMono
|
||||
indicator-radius=200
|
||||
indicator-thickness=20
|
||||
|
||||
|
||||
#----------------------EFFECTS----------------------------#
|
||||
effect-blur=9x5
|
||||
effect-vignette=0.5:0.5
|
||||
|
||||
#--------------------INPUT IGNORE-------------------------#
|
||||
grace-no-mouse
|
||||
grace-no-touch
|
||||
|
||||
|
||||
#--------------------DATE & TIME--------------------------#
|
||||
datestr=%a,%e %B
|
||||
timestr=%H:%M
|
||||
fade-in=0.2
|
||||
|
||||
|
||||
#----------------------COLORS-----------------------------#
|
||||
bs-hl-color={{ error }}
|
||||
inside-color=#FFFFFF00
|
||||
ring-color=#FFFFFF00
|
||||
line-color=#FFFFFF00
|
||||
separator-color=#FFFFFF00
|
||||
key-hl-color={{ primaryFixedDim }}
|
||||
text-color={{ primaryFixedDim }}
|
||||
text-caps-lock-color={{ tertiary }}
|
||||
|
||||
ring-clear-color=#FFFFFF00
|
||||
text-clear-color={{ onTertiary }}
|
||||
inside-clear-color={{ tertiary }}
|
||||
line-clear-color=#FFFFFF00
|
||||
|
||||
ring-ver-color=#FFFFFF00
|
||||
text-ver-color={{ onSecondary }}
|
||||
inside-ver-color={{ secondary }}
|
||||
line-ver-color=#FFFFFF00
|
||||
|
||||
ring-wrong-color=#FFFFFF00
|
||||
text-wrong-color={{ onError }}
|
||||
inside-wrong-color={{ error }}
|
||||
line-wrong-color=#FFFFFF00
|
||||
@@ -0,0 +1,18 @@
|
||||
import math
|
||||
|
||||
|
||||
def rgba_to_hex(rgba: list) -> str:
|
||||
return "#{:02x}{:02x}{:02x}".format(*rgba)
|
||||
|
||||
|
||||
def calculate_optimal_size(width: int, height: int, bitmap_size: int) -> tuple:
|
||||
image_area = width * height
|
||||
bitmap_area = bitmap_size**2
|
||||
scale = math.sqrt(bitmap_area / image_area) if image_area > bitmap_area else 1
|
||||
new_width = round(width * scale)
|
||||
new_height = round(height * scale)
|
||||
if new_width == 0:
|
||||
new_width = 1
|
||||
if new_height == 0:
|
||||
new_height = 1
|
||||
return new_width, new_height
|
||||
Reference in New Issue
Block a user