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()