dotfiles/.local/bin/hypranimator.py
2025-05-28 18:33:04 +02:00

168 lines
6.2 KiB
Python

import gi
import matplotlib
matplotlib.use('GTK3Agg')
from matplotlib.figure import Figure
from matplotlib.backends.backend_gtk3agg import FigureCanvasGTK3Agg as FigureCanvas
from gi.repository import Gtk, Gdk, GLib
import pyperclip
import time
class AnimationConfigurator(Gtk.Window):
def __init__(self):
super().__init__(title="Hyprland Animation Configurator")
self.set_default_size(600, 600)
self.curves = {
"default": (0.25, 0.25, 0.75, 0.75),
"soft": (0.25, 0.8, 0.25, 1),
"jellyFast": (0.25, 1.1, 0.4, 1.2),
"bounce": (0.34, 1.56, 0.64, 1.0),
"snappy": (0.45, 1.8, 0.4, 1),
"smoothOut": (0.3, 1, 0.6, 1),
}
self.styles = ["slide", "popin", "gnomed", "fade", "slidefade", "slidevert", "slidefadevert"]
main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
main_box.set_margin_top(10)
main_box.set_margin_bottom(10)
main_box.set_margin_start(10)
main_box.set_margin_end(10)
# Dropdown de curvas
self.curve_combo = Gtk.ComboBoxText()
for name in self.curves:
self.curve_combo.append_text(name)
self.curve_combo.set_active(0)
self.curve_combo.connect("changed", self.update_curve)
main_box.pack_start(Gtk.Label(label="Curva Bézier"), False, False, 0)
main_box.pack_start(self.curve_combo, False, False, 0)
# Slider de velocidad
self.speed_adjustment = Gtk.Adjustment(5, 1, 20, 1, 0, 0)
self.speed_slider = Gtk.Scale(orientation=Gtk.Orientation.HORIZONTAL, adjustment=self.speed_adjustment)
self.speed_slider.set_digits(0)
main_box.pack_start(Gtk.Label(label="Velocidad (ds: 1ds = 100ms)"), False, False, 0)
main_box.pack_start(self.speed_slider, False, False, 0)
# Dropdown de estilo
self.style_combo = Gtk.ComboBoxText()
for s in self.styles:
self.style_combo.append_text(s)
self.style_combo.set_active(3) # 'fade'
main_box.pack_start(Gtk.Label(label="Estilo"), False, False, 0)
main_box.pack_start(self.style_combo, False, False, 0)
# Preview Bézier con matplotlib
self.figure = Figure(figsize=(4, 2))
self.ax = self.figure.add_subplot(111)
self.canvas = FigureCanvas(self.figure)
self.update_curve() # inicializa la curva
main_box.pack_start(self.canvas, True, True, 0)
# Botón para generar línea
self.output_label = Gtk.Label(label="")
gen_button = Gtk.Button(label="Copiar línea de configuración")
gen_button.connect("clicked", self.copy_line)
main_box.pack_start(gen_button, False, False, 5)
main_box.pack_start(self.output_label, False, False, 5)
# Botones para previews
preview_buttons = Gtk.Box(spacing=10)
fade_button = Gtk.Button(label="Previsualizar fade")
fade_button.connect("clicked", self.run_fade_preview)
slide_button = Gtk.Button(label="Previsualizar slide")
slide_button.connect("clicked", self.run_slide_preview)
preview_buttons.pack_start(fade_button, True, True, 0)
preview_buttons.pack_start(slide_button, True, True, 0)
main_box.pack_start(preview_buttons, False, False, 10)
# Área de previsualización
self.preview_area = Gtk.Fixed()
self.preview_box = Gtk.EventBox()
self.preview_box.set_size_request(100, 50)
self.preview_box.override_background_color(Gtk.StateFlags.NORMAL, Gdk.RGBA(0.2, 0.6, 1.0, 1.0))
self.preview_area.put(self.preview_box, -110, 0)
main_box.pack_start(self.preview_area, True, True, 0)
self.add(main_box)
self.show_all()
def bezier_point(self, t, p0, p1, p2, p3):
return (
(1 - t)**3 * p0 + 3 * (1 - t)**2 * t * p1 + 3 * (1 - t) * t**2 * p2 + t**3 * p3
)
def update_curve(self, *_):
name = self.curve_combo.get_active_text()
if not name:
return
x1, y1, x2, y2 = self.curves[name]
ts = [t / 100 for t in range(101)]
xs = [self.bezier_point(t, 0, x1, x2, 1) for t in ts]
ys = [self.bezier_point(t, 0, y1, y2, 1) for t in ts]
self.ax.clear()
self.ax.plot(xs, ys)
self.ax.set_title(f"Curva: {name}")
self.canvas.draw()
def copy_line(self, *_):
curve = self.curve_combo.get_active_text()
speed = int(self.speed_slider.get_value())
style = self.style_combo.get_active_text()
line = f"animation = windows, 1, {speed}, {curve}, {style}"
pyperclip.copy(line)
self.output_label.set_text(f"Copiado: {line}")
def run_fade_preview(self, *_):
name = self.curve_combo.get_active_text()
_, y1, y2, _ = 0, *self.curves[name][1:3], 1
duration = int(self.speed_slider.get_value()) * 100
steps = 60
interval = duration / steps
t = 0
def update():
nonlocal t
t += 1 / steps
if t > 1:
t = 1
alpha = self.bezier_point(t, 0, y1, y2, 1)
self.preview_box.override_background_color(Gtk.StateFlags.NORMAL, Gdk.RGBA(0.2, 0.6, 1.0, alpha))
return t < 1
self.preview_box.override_background_color(Gtk.StateFlags.NORMAL, Gdk.RGBA(0.2, 0.6, 1.0, 0))
GLib.timeout_add(int(interval), update)
def run_slide_preview(self, *_):
name = self.curve_combo.get_active_text()
x1, _, x2, _ = self.curves[name]
duration = int(self.speed_slider.get_value()) * 100
steps = 60
interval = duration / steps
width = self.preview_area.get_allocated_width()
end_x = (width - 100) // 2
t = 0
def update():
nonlocal t
t += 1 / steps
if t > 1:
t = 1
x = self.bezier_point(t, -110, x1 * end_x, x2 * end_x, end_x)
self.preview_area.move(self.preview_box, int(x), 0)
return t < 1
self.preview_area.move(self.preview_box, -110, 0)
GLib.timeout_add(int(interval), update)
def main():
win = AnimationConfigurator()
Gtk.main()
if __name__ == "__main__":
main()