feat: Add VLC skin core files
- theme.xml: Main skin definition with Apple-style interface - 500x225 layout with 20px margins - Close/minimize buttons only (no maximize) - Time slider, volume control, playback controls - Shuffle, repeat all, repeat one support - Video and playlist windows - Fullscreen controller - generate_assets_v3.py: Python script to generate PNG assets - Superellipse rounded corners (Apple squircle) - 44px touch targets per Apple HIG - Blue hover tint (#007AFF) - Gray secondary icons (#8E8E93) - Disabled states support - fonts/: Liberation Sans (Bold and Regular) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
87e7ea770f
commit
db0c1ecb11
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,564 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
AppleVLC Skin v3 - Diseño Apple con capacidades reales de VLC Skins2
|
||||
- PNG con canal alpha REAL (no alphacolor)
|
||||
- Iconos SF Symbols limpios
|
||||
- Colores Apple HIG
|
||||
- Touch targets 44px mínimo
|
||||
"""
|
||||
|
||||
from PIL import Image, ImageDraw
|
||||
import math
|
||||
import os
|
||||
|
||||
# === PALETA APPLE HIG ===
|
||||
APPLE = {
|
||||
# Primarios
|
||||
'blue': (0, 122, 255, 255),
|
||||
'red': (255, 59, 48, 255),
|
||||
'green': (52, 199, 89, 255),
|
||||
'orange': (255, 149, 0, 255),
|
||||
|
||||
# Grises - Light Mode
|
||||
'label': (0, 0, 0, 255),
|
||||
'secondary': (60, 60, 67, 255),
|
||||
'tertiary': (60, 60, 67, 153),
|
||||
'quaternary': (60, 60, 67, 46),
|
||||
|
||||
# Iconos secundarios - gris más claro para jerarquía
|
||||
'icon_secondary': (142, 142, 147, 255), # #8E8E93 - Apple systemGray
|
||||
|
||||
# Fondos
|
||||
'bg_primary': (242, 242, 247, 255),
|
||||
'bg_secondary': (255, 255, 255, 255),
|
||||
'fill': (120, 120, 128, 51),
|
||||
|
||||
# Controles ventana macOS
|
||||
'win_close': (255, 95, 87, 255),
|
||||
'win_min': (255, 189, 46, 255),
|
||||
'win_max': (39, 201, 63, 255),
|
||||
|
||||
# Separadores
|
||||
'separator': (60, 60, 67, 73),
|
||||
|
||||
# Sombra
|
||||
'shadow': (0, 0, 0, 40),
|
||||
}
|
||||
|
||||
IMG_DIR = 'images'
|
||||
|
||||
|
||||
def superellipse_mask(width, height, n=4.5, padding=0):
|
||||
"""Crea máscara con superelipse (squircle Apple) con alpha real."""
|
||||
img = Image.new('L', (width, height), 0) # Máscara en escala de grises
|
||||
draw = ImageDraw.Draw(img)
|
||||
|
||||
cx, cy = width / 2, height / 2
|
||||
rx, ry = width / 2 - padding, height / 2 - padding
|
||||
|
||||
points = []
|
||||
for i in range(200):
|
||||
t = 2 * math.pi * i / 200
|
||||
cos_t, sin_t = math.cos(t), math.sin(t)
|
||||
x = cx + abs(cos_t) ** (2/n) * rx * (1 if cos_t >= 0 else -1)
|
||||
y = cy + abs(sin_t) ** (2/n) * ry * (1 if sin_t >= 0 else -1)
|
||||
points.append((x, y))
|
||||
|
||||
draw.polygon(points, fill=255)
|
||||
return img
|
||||
|
||||
|
||||
def create_background():
|
||||
"""Fondo limpio con esquinas superelipse y borde sutil."""
|
||||
w, h = 500, 225 # +20px en cada borde
|
||||
|
||||
# Fondo transparente
|
||||
img = Image.new('RGBA', (w, h), (0, 0, 0, 0))
|
||||
|
||||
# Fondo principal con color Apple
|
||||
base = Image.new('RGBA', (w, h), APPLE['bg_primary'])
|
||||
mask = superellipse_mask(w, h, n=5, padding=1)
|
||||
|
||||
# Aplicar máscara superelipse
|
||||
img.paste(base, (0, 0), mask)
|
||||
|
||||
# Borde sutil 1px para definición
|
||||
border_color = (200, 200, 200, 180)
|
||||
border_mask = superellipse_mask(w, h, n=5, padding=0)
|
||||
inner_mask = superellipse_mask(w, h, n=5, padding=2)
|
||||
|
||||
for y in range(h):
|
||||
for x in range(w):
|
||||
if border_mask.getpixel((x, y)) > 128 and inner_mask.getpixel((x, y)) < 128:
|
||||
img.putpixel((x, y), border_color)
|
||||
|
||||
img.save(f'{IMG_DIR}/background.png')
|
||||
print('✓ background.png (con borde sutil)')
|
||||
|
||||
|
||||
def create_video_background():
|
||||
"""Fondo para ventana con video - más grande."""
|
||||
w, h = 640, 480 # Tamaño para video 16:9 + controles
|
||||
|
||||
img = Image.new('RGBA', (w, h), (0, 0, 0, 0))
|
||||
base = Image.new('RGBA', (w, h), APPLE['bg_primary'])
|
||||
mask = superellipse_mask(w, h, n=5, padding=1)
|
||||
img.paste(base, (0, 0), mask)
|
||||
|
||||
# Borde sutil
|
||||
border_color = (200, 200, 200, 180)
|
||||
border_mask = superellipse_mask(w, h, n=5, padding=0)
|
||||
inner_mask = superellipse_mask(w, h, n=5, padding=2)
|
||||
|
||||
for y in range(h):
|
||||
for x in range(w):
|
||||
if border_mask.getpixel((x, y)) > 128 and inner_mask.getpixel((x, y)) < 128:
|
||||
img.putpixel((x, y), border_color)
|
||||
|
||||
img.save(f'{IMG_DIR}/background_video.png')
|
||||
print('✓ background_video.png (640x480)')
|
||||
|
||||
|
||||
def create_playlist_background():
|
||||
"""Fondo para área de playlist."""
|
||||
w, h = 300, 200
|
||||
|
||||
img = Image.new('RGBA', (w, h), (0, 0, 0, 0))
|
||||
draw = ImageDraw.Draw(img)
|
||||
# Fondo ligeramente más oscuro para contraste
|
||||
draw.rounded_rectangle([0, 0, w-1, h-1], radius=8,
|
||||
fill=(230, 230, 235, 255), outline=(200, 200, 200, 180))
|
||||
img.save(f'{IMG_DIR}/playlist_bg.png')
|
||||
print('✓ playlist_bg.png')
|
||||
|
||||
|
||||
def create_playlist_items():
|
||||
"""Items de playlist: seleccionado, hover, normal."""
|
||||
w, h = 280, 24
|
||||
|
||||
# Item normal (transparente)
|
||||
normal = Image.new('RGBA', (w, h), (0, 0, 0, 0))
|
||||
normal.save(f'{IMG_DIR}/playlist_item.png')
|
||||
|
||||
# Item seleccionado (azul Apple)
|
||||
selected = Image.new('RGBA', (w, h), (0, 0, 0, 0))
|
||||
draw = ImageDraw.Draw(selected)
|
||||
draw.rounded_rectangle([2, 2, w-3, h-3], radius=6, fill=(0, 122, 255, 255))
|
||||
selected.save(f'{IMG_DIR}/playlist_selected.png')
|
||||
|
||||
# Item hover
|
||||
hover = Image.new('RGBA', (w, h), (0, 0, 0, 0))
|
||||
draw = ImageDraw.Draw(hover)
|
||||
draw.rounded_rectangle([2, 2, w-3, h-3], radius=6, fill=(0, 122, 255, 40))
|
||||
hover.save(f'{IMG_DIR}/playlist_hover.png')
|
||||
|
||||
print('✓ playlist_*.png (items)')
|
||||
|
||||
|
||||
def draw_icon(draw, bounds, icon_type, color, stroke=2.5):
|
||||
"""Dibuja iconos estilo SF Symbols."""
|
||||
x1, y1, x2, y2 = bounds
|
||||
cx, cy = (x1 + x2) / 2, (y1 + y2) / 2
|
||||
w, h = x2 - x1, y2 - y1
|
||||
m = w * 0.22 # margen
|
||||
|
||||
if icon_type == 'play':
|
||||
pts = [(x1 + m + 3, y1 + m), (x2 - m, cy), (x1 + m + 3, y2 - m)]
|
||||
draw.polygon(pts, fill=color)
|
||||
|
||||
elif icon_type == 'pause':
|
||||
bw = w * 0.16
|
||||
gap = w * 0.1
|
||||
for dx in [-1, 1]:
|
||||
bx = cx + dx * (gap + bw/2) - bw/2
|
||||
draw.rounded_rectangle([bx, y1+m, bx+bw, y2-m], radius=2, fill=color)
|
||||
|
||||
elif icon_type == 'stop':
|
||||
draw.rounded_rectangle([x1+m+2, y1+m+2, x2-m-2, y2-m-2], radius=3, fill=color)
|
||||
|
||||
elif icon_type == 'prev':
|
||||
# Barra + triángulo
|
||||
bw = 4
|
||||
draw.rectangle([x1+m, y1+m+2, x1+m+bw, y2-m-2], fill=color)
|
||||
pts = [(x2-m, y1+m+2), (x1+m+bw+3, cy), (x2-m, y2-m-2)]
|
||||
draw.polygon(pts, fill=color)
|
||||
|
||||
elif icon_type == 'next':
|
||||
bw = 4
|
||||
draw.rectangle([x2-m-bw, y1+m+2, x2-m, y2-m-2], fill=color)
|
||||
pts = [(x1+m, y1+m+2), (x2-m-bw-3, cy), (x1+m, y2-m-2)]
|
||||
draw.polygon(pts, fill=color)
|
||||
|
||||
elif icon_type == 'volume':
|
||||
# Altavoz
|
||||
sw = w * 0.3
|
||||
draw.polygon([
|
||||
(x1+m, cy-4), (x1+m+sw*0.4, cy-4), (x1+m+sw, cy-10),
|
||||
(x1+m+sw, cy+10), (x1+m+sw*0.4, cy+4), (x1+m, cy+4)
|
||||
], fill=color)
|
||||
# Ondas
|
||||
for i, offset in enumerate([8, 14]):
|
||||
draw.arc([x1+m+sw+2+i*5, cy-offset, x1+m+sw+10+i*6, cy+offset],
|
||||
-50, 50, fill=color, width=int(stroke))
|
||||
|
||||
elif icon_type == 'mute':
|
||||
sw = w * 0.3
|
||||
draw.polygon([
|
||||
(x1+m, cy-4), (x1+m+sw*0.4, cy-4), (x1+m+sw, cy-10),
|
||||
(x1+m+sw, cy+10), (x1+m+sw*0.4, cy+4), (x1+m, cy+4)
|
||||
], fill=color)
|
||||
# X
|
||||
xstart = x2 - m - 10
|
||||
draw.line([xstart, cy-6, xstart+10, cy+6], fill=APPLE['red'], width=int(stroke))
|
||||
draw.line([xstart, cy+6, xstart+10, cy-6], fill=APPLE['red'], width=int(stroke))
|
||||
|
||||
elif icon_type == 'shuffle':
|
||||
# Flechas cruzadas
|
||||
draw.line([x1+m, y2-m-3, x2-m-5, y1+m+3], fill=color, width=int(stroke))
|
||||
draw.line([x1+m, y1+m+3, x2-m-5, y2-m-3], fill=color, width=int(stroke))
|
||||
# Puntas
|
||||
aw = 5
|
||||
draw.polygon([(x2-m, y1+m), (x2-m-aw, y1+m), (x2-m, y1+m+aw)], fill=color)
|
||||
draw.polygon([(x2-m, y2-m), (x2-m-aw, y2-m), (x2-m, y2-m-aw)], fill=color)
|
||||
|
||||
elif icon_type == 'repeat':
|
||||
# Rectángulo con flechas
|
||||
draw.rounded_rectangle([x1+m, y1+m+3, x2-m, y2-m-3], radius=5,
|
||||
outline=color, width=int(stroke))
|
||||
aw = 5
|
||||
# Flecha derecha
|
||||
ax = x2 - m - 8
|
||||
draw.polygon([(ax, y1+m+3-aw), (ax+aw, y1+m+3), (ax, y1+m+3+aw)], fill=color)
|
||||
# Flecha izquierda
|
||||
ax = x1 + m + 8
|
||||
draw.polygon([(ax, y2-m-3-aw), (ax-aw, y2-m-3), (ax, y2-m-3+aw)], fill=color)
|
||||
|
||||
elif icon_type == 'fullscreen':
|
||||
aw = 8
|
||||
sw = int(stroke)
|
||||
# Esquina superior izquierda
|
||||
draw.line([x1+m, y1+m, x1+m+aw, y1+m], fill=color, width=sw)
|
||||
draw.line([x1+m, y1+m, x1+m, y1+m+aw], fill=color, width=sw)
|
||||
# Esquina inferior derecha
|
||||
draw.line([x2-m, y2-m, x2-m-aw, y2-m], fill=color, width=sw)
|
||||
draw.line([x2-m, y2-m, x2-m, y2-m-aw], fill=color, width=sw)
|
||||
|
||||
elif icon_type == 'playlist':
|
||||
# Tres líneas con bullets
|
||||
for i in range(3):
|
||||
y = y1 + m + i * 8 + 2
|
||||
draw.ellipse([x1+m, y, x1+m+4, y+4], fill=color)
|
||||
draw.rectangle([x1+m+8, y+1, x2-m, y+3], fill=color)
|
||||
|
||||
elif icon_type == 'equalizer':
|
||||
# Barras verticales de ecualizador
|
||||
bar_w = 4
|
||||
heights = [0.5, 0.8, 0.6, 0.9, 0.4]
|
||||
gap = (w - 2*m - len(heights)*bar_w) / (len(heights) - 1)
|
||||
for i, h_ratio in enumerate(heights):
|
||||
bx = x1 + m + i * (bar_w + gap)
|
||||
bar_h = (h - 2*m) * h_ratio
|
||||
by = y2 - m - bar_h
|
||||
draw.rounded_rectangle([bx, by, bx + bar_w, y2 - m], radius=2, fill=color)
|
||||
|
||||
elif icon_type == 'ab_loop':
|
||||
# Letras A-B con flecha circular
|
||||
# A
|
||||
draw.polygon([(x1+m+2, y2-m-2), (x1+m+8, y1+m+2), (x1+m+14, y2-m-2)], outline=color, width=int(stroke))
|
||||
draw.line([x1+m+5, cy+2, x1+m+11, cy+2], fill=color, width=int(stroke))
|
||||
# B
|
||||
draw.line([x2-m-12, y1+m+2, x2-m-12, y2-m-2], fill=color, width=int(stroke))
|
||||
draw.arc([x2-m-14, y1+m+2, x2-m-4, cy], -90, 90, fill=color, width=int(stroke))
|
||||
draw.arc([x2-m-14, cy, x2-m-4, y2-m-2], -90, 90, fill=color, width=int(stroke))
|
||||
|
||||
elif icon_type == 'speed':
|
||||
# Velocímetro / gauge
|
||||
draw.arc([x1+m, y1+m+2, x2-m, y2-m+6], 200, 340, fill=color, width=int(stroke)+1)
|
||||
# Aguja
|
||||
draw.line([cx, cy+2, cx+6, y1+m+6], fill=color, width=int(stroke))
|
||||
|
||||
|
||||
def create_button(name, icon_type, color, size=44, with_disabled=False):
|
||||
"""Crea botón con 3 estados - hover azul Apple."""
|
||||
states = ['up', 'over', 'down']
|
||||
if with_disabled:
|
||||
states.append('disabled')
|
||||
|
||||
for state in states:
|
||||
img = Image.new('RGBA', (size, size), (0, 0, 0, 0))
|
||||
draw = ImageDraw.Draw(img)
|
||||
|
||||
if state == 'disabled':
|
||||
# Estado disabled - muy tenue
|
||||
icon_color = (180, 180, 180, 100)
|
||||
else:
|
||||
# Fondo circular con tinte azul Apple en hover
|
||||
if state == 'over':
|
||||
draw.ellipse([2, 2, size-3, size-3], fill=(0, 122, 255, 30))
|
||||
elif state == 'down':
|
||||
draw.ellipse([2, 2, size-3, size-3], fill=(0, 122, 255, 50))
|
||||
|
||||
alpha = 255 if state == 'up' else 230 if state == 'over' else 200
|
||||
icon_color = (*color[:3], alpha)
|
||||
|
||||
draw_icon(draw, (0, 0, size, size), icon_type, icon_color)
|
||||
img.save(f'{IMG_DIR}/{name}_{state}.png')
|
||||
|
||||
print(f'✓ {name}_*.png' + (' (con disabled)' if with_disabled else ''))
|
||||
|
||||
|
||||
def create_window_buttons():
|
||||
"""Botones de ventana macOS."""
|
||||
buttons = [
|
||||
('win_close', APPLE['win_close'], 'x'),
|
||||
('win_min', APPLE['win_min'], '-'),
|
||||
('win_max', APPLE['win_max'], '+'),
|
||||
]
|
||||
|
||||
for name, color, symbol in buttons:
|
||||
for state in ['up', 'over', 'down']:
|
||||
size = 14
|
||||
img = Image.new('RGBA', (size, size), (0, 0, 0, 0))
|
||||
draw = ImageDraw.Draw(img)
|
||||
|
||||
# Color según estado
|
||||
alpha = 255 if state != 'down' else 200
|
||||
c = (*color[:3], alpha)
|
||||
|
||||
draw.ellipse([0, 0, size-1, size-1], fill=c)
|
||||
|
||||
# Símbolo en hover
|
||||
if state == 'over':
|
||||
sc = (60, 0, 0, 200) if symbol == 'x' else (60, 50, 0, 200) if symbol == '-' else (0, 60, 0, 200)
|
||||
if symbol == 'x':
|
||||
draw.line([4, 4, 9, 9], fill=sc, width=2)
|
||||
draw.line([4, 9, 9, 4], fill=sc, width=2)
|
||||
elif symbol == '-':
|
||||
draw.line([4, 6, 9, 6], fill=sc, width=2)
|
||||
else:
|
||||
draw.line([4, 6, 9, 6], fill=sc, width=2)
|
||||
draw.line([6, 4, 6, 9], fill=sc, width=2)
|
||||
|
||||
img.save(f'{IMG_DIR}/{name}_{state}.png')
|
||||
|
||||
print('✓ win_*.png')
|
||||
|
||||
|
||||
def create_volume_slider():
|
||||
"""Slider de volumen limpio sin sombras."""
|
||||
vol_w, vol_h = 80, 4 # Track compacto
|
||||
|
||||
# Track volumen - gris visible
|
||||
track = Image.new('RGBA', (vol_w, vol_h), (0, 0, 0, 0))
|
||||
draw = ImageDraw.Draw(track)
|
||||
draw.rounded_rectangle([0, 0, vol_w-1, vol_h-1], radius=2, fill=(0, 0, 0, 80))
|
||||
track.save(f'{IMG_DIR}/vol_slider_track.png')
|
||||
|
||||
# Knob volumen - 18px limpio sin sombra
|
||||
knob_size = 18
|
||||
for state in ['up', 'over', 'down']:
|
||||
knob = Image.new('RGBA', (knob_size, knob_size), (0, 0, 0, 0))
|
||||
draw = ImageDraw.Draw(knob)
|
||||
|
||||
# Círculo blanco limpio con borde definido
|
||||
if state == 'up':
|
||||
c = (255, 255, 255, 255)
|
||||
border = (200, 200, 200, 255)
|
||||
elif state == 'over':
|
||||
c = (248, 248, 248, 255)
|
||||
border = (180, 180, 180, 255)
|
||||
else:
|
||||
c = (235, 235, 235, 255)
|
||||
border = (160, 160, 160, 255)
|
||||
|
||||
draw.ellipse([1, 1, knob_size-2, knob_size-2], fill=c, outline=border)
|
||||
|
||||
knob.save(f'{IMG_DIR}/vol_knob_{state}.png')
|
||||
|
||||
print('✓ vol_slider_*.png (limpio, 18px knob)')
|
||||
|
||||
|
||||
def create_repeat_one_icons():
|
||||
"""Icono Repeat One (repetir una canción) - hover visible."""
|
||||
size = 44
|
||||
|
||||
for checked in [False, True]:
|
||||
for state in ['up', 'over', 'down']:
|
||||
img = Image.new('RGBA', (size, size), (0, 0, 0, 0))
|
||||
draw = ImageDraw.Draw(img)
|
||||
|
||||
# Color - azul activo, gris secundario inactivo
|
||||
base = APPLE['blue'][:3] if checked else APPLE['icon_secondary'][:3]
|
||||
alpha = 255 if state == 'up' else 230 if state == 'over' else 200
|
||||
color = (*base, alpha)
|
||||
|
||||
# Fondo hover - MÁS VISIBLE
|
||||
if state == 'over':
|
||||
draw.ellipse([4, 4, size-5, size-5], fill=(0, 0, 0, 35))
|
||||
elif state == 'down':
|
||||
draw.ellipse([4, 4, size-5, size-5], fill=(0, 0, 0, 55))
|
||||
|
||||
# Dibujar icono repeat con "1"
|
||||
m = 10
|
||||
# Rectángulo con flechas
|
||||
draw.rounded_rectangle([m, m+3, size-m, size-m-3], radius=5,
|
||||
outline=color, width=2)
|
||||
# Flecha derecha
|
||||
aw = 4
|
||||
ax = size - m - 6
|
||||
draw.polygon([(ax, m+3-aw), (ax+aw, m+3), (ax, m+3+aw)], fill=color)
|
||||
# Flecha izquierda
|
||||
ax = m + 6
|
||||
draw.polygon([(ax, size-m-3-aw), (ax-aw, size-m-3), (ax, size-m-3+aw)], fill=color)
|
||||
|
||||
# Número "1" en el centro
|
||||
# Dibujar línea vertical para el "1"
|
||||
cx, cy = size // 2, size // 2
|
||||
draw.line([cx, cy-5, cx, cy+5], fill=color, width=2)
|
||||
draw.line([cx-2, cy-3, cx, cy-5], fill=color, width=2)
|
||||
|
||||
suffix = 'on' if checked else 'off'
|
||||
img.save(f'{IMG_DIR}/repeat1_{suffix}_{state}.png')
|
||||
|
||||
print('✓ repeat1_*.png (repeat one)')
|
||||
|
||||
|
||||
def create_slider():
|
||||
"""Slider estilo Apple Music con track grueso."""
|
||||
track_w, track_h = 400, 8 # 8px para mejor visibilidad
|
||||
num_frames = 400
|
||||
|
||||
# Track (fondo gris visible)
|
||||
track = Image.new('RGBA', (track_w, track_h), (0, 0, 0, 0))
|
||||
draw = ImageDraw.Draw(track)
|
||||
draw.rounded_rectangle([0, 0, track_w-1, track_h-1], radius=4,
|
||||
fill=(0, 0, 0, 70))
|
||||
track.save(f'{IMG_DIR}/slider_track.png')
|
||||
|
||||
# SliderBackground: imagen con N frames horizontales para progreso
|
||||
num_frames = 50
|
||||
frame_w = track_w
|
||||
total_w = frame_w * num_frames
|
||||
|
||||
fill = Image.new('RGBA', (total_w, track_h), (0, 0, 0, 0))
|
||||
draw = ImageDraw.Draw(fill)
|
||||
apple_blue = APPLE['blue']
|
||||
|
||||
for i in range(num_frames):
|
||||
x_start = i * frame_w
|
||||
progress_w = int((i / (num_frames - 1)) * (frame_w - 1)) if i > 0 else 0
|
||||
|
||||
if progress_w >= 4:
|
||||
draw.rounded_rectangle(
|
||||
[x_start, 0, x_start + progress_w, track_h - 1],
|
||||
radius=4, fill=apple_blue
|
||||
)
|
||||
elif progress_w > 0:
|
||||
draw.rectangle(
|
||||
[x_start, 0, x_start + progress_w, track_h - 1],
|
||||
fill=apple_blue
|
||||
)
|
||||
|
||||
fill.save(f'{IMG_DIR}/slider_fill.png')
|
||||
print(f' → slider_fill.png ({num_frames} frames, 8px track)')
|
||||
|
||||
# Knob - círculo blanco limpio sin sombra
|
||||
knob_size = 20
|
||||
for state in ['up', 'over', 'down']:
|
||||
knob = Image.new('RGBA', (knob_size, knob_size), (0, 0, 0, 0))
|
||||
draw = ImageDraw.Draw(knob)
|
||||
|
||||
# Círculo blanco principal - sin sombra
|
||||
if state == 'up':
|
||||
c = (255, 255, 255, 255)
|
||||
border = (210, 210, 210, 255)
|
||||
elif state == 'over':
|
||||
c = (248, 248, 248, 255)
|
||||
border = (190, 190, 190, 255)
|
||||
else:
|
||||
c = (235, 235, 235, 255)
|
||||
border = (170, 170, 170, 255)
|
||||
|
||||
# Círculo con borde definido
|
||||
draw.ellipse([1, 1, knob_size-2, knob_size-2], fill=c, outline=border)
|
||||
|
||||
knob.save(f'{IMG_DIR}/slider_knob_{state}.png')
|
||||
|
||||
print('✓ slider_*.png (limpio, 20px knob)')
|
||||
|
||||
|
||||
def create_checkboxes():
|
||||
"""Checkboxes para shuffle/repeat - hover azul Apple."""
|
||||
for name, icon in [('shuffle', 'shuffle'), ('repeat', 'repeat')]:
|
||||
for checked in [False, True]:
|
||||
for state in ['up', 'over', 'down']:
|
||||
size = 44
|
||||
img = Image.new('RGBA', (size, size), (0, 0, 0, 0))
|
||||
draw = ImageDraw.Draw(img)
|
||||
|
||||
# Color - azul activo, gris inactivo
|
||||
base = APPLE['blue'][:3] if checked else APPLE['icon_secondary'][:3]
|
||||
alpha = 255 if state == 'up' else 230 if state == 'over' else 200
|
||||
color = (*base, alpha)
|
||||
|
||||
# Hover con tinte azul Apple
|
||||
if state == 'over':
|
||||
draw.ellipse([4, 4, size-5, size-5], fill=(0, 122, 255, 25))
|
||||
elif state == 'down':
|
||||
draw.ellipse([4, 4, size-5, size-5], fill=(0, 122, 255, 45))
|
||||
|
||||
draw_icon(draw, (6, 6, size-6, size-6), icon, color, stroke=2.5)
|
||||
|
||||
suffix = 'on' if checked else 'off'
|
||||
img.save(f'{IMG_DIR}/{name}_{suffix}_{state}.png')
|
||||
|
||||
print('✓ shuffle/repeat_*.png (hover azul)')
|
||||
|
||||
|
||||
def main():
|
||||
os.makedirs(IMG_DIR, exist_ok=True)
|
||||
|
||||
print('\n🍎 AppleVLC v8 - Assets completos...\n')
|
||||
|
||||
# Fondos
|
||||
create_background()
|
||||
create_video_background()
|
||||
create_playlist_background()
|
||||
create_playlist_items()
|
||||
|
||||
# Reproducción - Play/Pause 48px azul (protagonista)
|
||||
create_button('play', 'play', APPLE['blue'][:3], 48, with_disabled=True)
|
||||
create_button('pause', 'pause', APPLE['blue'][:3], 48)
|
||||
|
||||
# Iconos SECUNDARIOS con estados disabled
|
||||
create_button('stop', 'stop', APPLE['icon_secondary'][:3], 44, with_disabled=True)
|
||||
create_button('prev', 'prev', APPLE['icon_secondary'][:3], 44, with_disabled=True)
|
||||
create_button('next', 'next', APPLE['icon_secondary'][:3], 44, with_disabled=True)
|
||||
create_button('playlist', 'playlist', APPLE['icon_secondary'][:3], 44)
|
||||
|
||||
# Audio
|
||||
create_button('volume', 'volume', APPLE['icon_secondary'][:3], 44)
|
||||
create_button('mute', 'mute', APPLE['icon_secondary'][:3], 44)
|
||||
|
||||
# Otros controles
|
||||
create_button('fullscreen', 'fullscreen', APPLE['icon_secondary'][:3], 44)
|
||||
create_button('equalizer', 'equalizer', APPLE['icon_secondary'][:3], 44)
|
||||
create_button('ab_loop', 'ab_loop', APPLE['icon_secondary'][:3], 44)
|
||||
create_button('speed', 'speed', APPLE['icon_secondary'][:3], 44)
|
||||
|
||||
# Ventana macOS
|
||||
create_window_buttons()
|
||||
|
||||
# Sliders
|
||||
create_slider()
|
||||
create_volume_slider()
|
||||
|
||||
# Checkboxes
|
||||
create_checkboxes()
|
||||
create_repeat_one_icons()
|
||||
|
||||
print('\n✅ Assets v8 - Video, playlist, disabled states')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -0,0 +1,371 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Theme PUBLIC "-//VideoLAN//DTD VLC Skins V2.0//EN"
|
||||
"http://www.videolan.org/vlc/skins2-0.dtd">
|
||||
|
||||
<Theme version="2.0" tooltipfont="font_small" magnet="15" alpha="255" movealpha="180">
|
||||
|
||||
<ThemeInfo name="AppleVLC" author="Claude Code" email="" webpage=""/>
|
||||
|
||||
<!-- BITMAPS - PNG con canal alpha real -->
|
||||
<Bitmap id="bg" file="images/background.png" alphacolor="#FF00FF"/>
|
||||
|
||||
<Bitmap id="play_up" file="images/play_up.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="play_down" file="images/play_down.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="play_over" file="images/play_over.png" alphacolor="#FF00FF"/>
|
||||
|
||||
<Bitmap id="pause_up" file="images/pause_up.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="pause_down" file="images/pause_down.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="pause_over" file="images/pause_over.png" alphacolor="#FF00FF"/>
|
||||
|
||||
<Bitmap id="stop_up" file="images/stop_up.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="stop_down" file="images/stop_down.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="stop_over" file="images/stop_over.png" alphacolor="#FF00FF"/>
|
||||
|
||||
<Bitmap id="prev_up" file="images/prev_up.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="prev_down" file="images/prev_down.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="prev_over" file="images/prev_over.png" alphacolor="#FF00FF"/>
|
||||
|
||||
<Bitmap id="next_up" file="images/next_up.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="next_down" file="images/next_down.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="next_over" file="images/next_over.png" alphacolor="#FF00FF"/>
|
||||
|
||||
<Bitmap id="volume_up" file="images/volume_up.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="volume_down" file="images/volume_down.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="volume_over" file="images/volume_over.png" alphacolor="#FF00FF"/>
|
||||
|
||||
<Bitmap id="mute_up" file="images/mute_up.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="mute_down" file="images/mute_down.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="mute_over" file="images/mute_over.png" alphacolor="#FF00FF"/>
|
||||
|
||||
<Bitmap id="fullscreen_up" file="images/fullscreen_up.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="fullscreen_down" file="images/fullscreen_down.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="fullscreen_over" file="images/fullscreen_over.png" alphacolor="#FF00FF"/>
|
||||
|
||||
<Bitmap id="playlist_up" file="images/playlist_up.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="playlist_down" file="images/playlist_down.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="playlist_over" file="images/playlist_over.png" alphacolor="#FF00FF"/>
|
||||
|
||||
<Bitmap id="win_close_up" file="images/win_close_up.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="win_close_down" file="images/win_close_down.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="win_close_over" file="images/win_close_over.png" alphacolor="#FF00FF"/>
|
||||
|
||||
<Bitmap id="win_min_up" file="images/win_min_up.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="win_min_down" file="images/win_min_down.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="win_min_over" file="images/win_min_over.png" alphacolor="#FF00FF"/>
|
||||
|
||||
<Bitmap id="win_max_up" file="images/win_max_up.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="win_max_down" file="images/win_max_down.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="win_max_over" file="images/win_max_over.png" alphacolor="#FF00FF"/>
|
||||
|
||||
<Bitmap id="slider_track" file="images/slider_track.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="slider_fill" file="images/slider_fill.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="slider_knob_up" file="images/slider_knob_up.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="slider_knob_down" file="images/slider_knob_down.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="slider_knob_over" file="images/slider_knob_over.png" alphacolor="#FF00FF"/>
|
||||
|
||||
<Bitmap id="shuffle_off_up" file="images/shuffle_off_up.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="shuffle_off_down" file="images/shuffle_off_down.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="shuffle_off_over" file="images/shuffle_off_over.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="shuffle_on_up" file="images/shuffle_on_up.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="shuffle_on_down" file="images/shuffle_on_down.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="shuffle_on_over" file="images/shuffle_on_over.png" alphacolor="#FF00FF"/>
|
||||
|
||||
<Bitmap id="repeat_off_up" file="images/repeat_off_up.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="repeat_off_down" file="images/repeat_off_down.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="repeat_off_over" file="images/repeat_off_over.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="repeat_on_up" file="images/repeat_on_up.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="repeat_on_down" file="images/repeat_on_down.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="repeat_on_over" file="images/repeat_on_over.png" alphacolor="#FF00FF"/>
|
||||
|
||||
<Bitmap id="repeat1_off_up" file="images/repeat1_off_up.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="repeat1_off_down" file="images/repeat1_off_down.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="repeat1_off_over" file="images/repeat1_off_over.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="repeat1_on_up" file="images/repeat1_on_up.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="repeat1_on_down" file="images/repeat1_on_down.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="repeat1_on_over" file="images/repeat1_on_over.png" alphacolor="#FF00FF"/>
|
||||
|
||||
<Bitmap id="vol_slider_track" file="images/vol_slider_track.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="vol_knob_up" file="images/vol_knob_up.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="vol_knob_down" file="images/vol_knob_down.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="vol_knob_over" file="images/vol_knob_over.png" alphacolor="#FF00FF"/>
|
||||
|
||||
<Bitmap id="equalizer_up" file="images/equalizer_up.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="equalizer_down" file="images/equalizer_down.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="equalizer_over" file="images/equalizer_over.png" alphacolor="#FF00FF"/>
|
||||
|
||||
<Bitmap id="ab_loop_up" file="images/ab_loop_up.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="ab_loop_down" file="images/ab_loop_down.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="ab_loop_over" file="images/ab_loop_over.png" alphacolor="#FF00FF"/>
|
||||
|
||||
<Bitmap id="speed_up" file="images/speed_up.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="speed_down" file="images/speed_down.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="speed_over" file="images/speed_over.png" alphacolor="#FF00FF"/>
|
||||
|
||||
<!-- Video y Playlist backgrounds -->
|
||||
<Bitmap id="bg_video" file="images/background_video.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="playlist_bg" file="images/playlist_bg.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="playlist_item" file="images/playlist_item.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="playlist_selected" file="images/playlist_selected.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="playlist_hover" file="images/playlist_hover.png" alphacolor="#FF00FF"/>
|
||||
|
||||
<!-- Estados disabled -->
|
||||
<Bitmap id="play_disabled" file="images/play_disabled.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="stop_disabled" file="images/stop_disabled.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="prev_disabled" file="images/prev_disabled.png" alphacolor="#FF00FF"/>
|
||||
<Bitmap id="next_disabled" file="images/next_disabled.png" alphacolor="#FF00FF"/>
|
||||
|
||||
<!-- FUENTES -->
|
||||
<Font id="font_title" file="fonts/LiberationSans-Bold.ttf" size="13"/>
|
||||
<Font id="font_body" file="fonts/LiberationSans-Regular.ttf" size="11"/>
|
||||
<Font id="font_small" file="fonts/LiberationSans-Regular.ttf" size="10"/>
|
||||
|
||||
<!-- VENTANA PRINCIPAL -->
|
||||
<Window id="mainWindow" x="0" y="0" visible="true" dragdrop="true">
|
||||
<Layout id="mainLayout" width="500" height="225"
|
||||
minwidth="500" maxwidth="500" minheight="225" maxheight="225">
|
||||
|
||||
<!-- Fondo con action="move" para arrastrar ventana -->
|
||||
<Image id="background" x="0" y="0" image="bg" action="move"/>
|
||||
|
||||
<!-- Controles ventana macOS - solo cerrar y minimizar -->
|
||||
<Button id="closeBtn" x="24" y="24"
|
||||
up="win_close_up" down="win_close_down" over="win_close_over"
|
||||
action="vlc.quit()" tooltiptext="Cerrar"/>
|
||||
<Button id="minBtn" x="44" y="24"
|
||||
up="win_min_up" down="win_min_down" over="win_min_over"
|
||||
action="vlc.minimize()" tooltiptext="Minimizar"/>
|
||||
|
||||
<!-- Título - padding extra para scroll sin cortar -->
|
||||
<Text id="trackTitle" x="72" y="22" width="280"
|
||||
font="font_title" color="#000000" scrolling="auto"
|
||||
text=" $N "/>
|
||||
|
||||
<!-- Tiempo actual / duración -->
|
||||
<Text id="timeDisplay" x="370" y="22" width="110"
|
||||
font="font_body" color="#3C3C43"
|
||||
text="$T / $D" alignment="right"/>
|
||||
|
||||
<!-- Info audio: bitrate y sample rate -->
|
||||
<Text id="audioInfo" x="370" y="38" width="110"
|
||||
font="font_small" color="#8E8E93"
|
||||
text="$B kb/s · $S kHz" alignment="right"/>
|
||||
|
||||
<!-- Slider de progreso - 8px track -->
|
||||
<Image id="sliderBg" x="30" y="70" image="slider_track"/>
|
||||
<Slider id="timeSlider" x="30" y="63"
|
||||
up="slider_knob_up" down="slider_knob_down" over="slider_knob_over"
|
||||
points="(0,10),(440,10)" thickness="20"
|
||||
value="time" tooltiptext="$T / $D"/>
|
||||
|
||||
|
||||
<!-- Controles secundarios izquierda -->
|
||||
<Button id="stopBtn" x="30" y="100"
|
||||
up="stop_up" down="stop_down" over="stop_over"
|
||||
action="vlc.stop()" tooltiptext="Detener"/>
|
||||
|
||||
<Button id="playlistBtn" x="76" y="100"
|
||||
up="playlist_up" down="playlist_down" over="playlist_over"
|
||||
action="playlistWindow.show()" tooltiptext="Lista"/>
|
||||
|
||||
<!-- Controles principales centrados -->
|
||||
<Checkbox id="shuffleBtn" x="130" y="100"
|
||||
up1="shuffle_off_up" down1="shuffle_off_down" over1="shuffle_off_over"
|
||||
up2="shuffle_on_up" down2="shuffle_on_down" over2="shuffle_on_over"
|
||||
action1="playlist.setRandom(true)" action2="playlist.setRandom(false)"
|
||||
state="playlist.isRandom" tooltiptext1="Aleatorio" tooltiptext2="Aleatorio activo"/>
|
||||
|
||||
<Button id="prevBtn" x="176" y="100"
|
||||
up="prev_up" down="prev_down" over="prev_over"
|
||||
action="playlist.previous()" tooltiptext="Anterior"/>
|
||||
|
||||
<Button id="playBtn" x="226" y="98" visible="not vlc.isPlaying"
|
||||
up="play_up" down="play_down" over="play_over"
|
||||
action="vlc.play()" tooltiptext="Reproducir"/>
|
||||
<Button id="pauseBtn" x="226" y="98" visible="vlc.isPlaying"
|
||||
up="pause_up" down="pause_down" over="pause_over"
|
||||
action="vlc.pause()" tooltiptext="Pausar"/>
|
||||
|
||||
<Button id="nextBtn" x="274" y="100"
|
||||
up="next_up" down="next_down" over="next_over"
|
||||
action="playlist.next()" tooltiptext="Siguiente"/>
|
||||
|
||||
<!-- Repeat Loop -->
|
||||
<Checkbox id="repeatBtn" x="320" y="100"
|
||||
up1="repeat_off_up" down1="repeat_off_down" over1="repeat_off_over"
|
||||
up2="repeat_on_up" down2="repeat_on_down" over2="repeat_on_over"
|
||||
action1="playlist.setLoop(true)" action2="playlist.setLoop(false)"
|
||||
state="playlist.isLoop" tooltiptext1="Repetir todo" tooltiptext2="Repetir todo activo"/>
|
||||
|
||||
<!-- Repeat One -->
|
||||
<Checkbox id="repeat1Btn" x="364" y="100"
|
||||
up1="repeat1_off_up" down1="repeat1_off_down" over1="repeat1_off_over"
|
||||
up2="repeat1_on_up" down2="repeat1_on_down" over2="repeat1_on_over"
|
||||
action1="playlist.setRepeat(true)" action2="playlist.setRepeat(false)"
|
||||
state="playlist.isRepeat" tooltiptext1="Repetir una" tooltiptext2="Repetir una activo"/>
|
||||
|
||||
<!-- Fullscreen -->
|
||||
<Button id="fullscreenBtn" x="420" y="100"
|
||||
up="fullscreen_up" down="fullscreen_down" over="fullscreen_over"
|
||||
action="vlc.fullscreen()" tooltiptext="Pantalla completa"/>
|
||||
|
||||
<!-- Fila inferior: Volumen + controles extra -->
|
||||
<Button id="volumeBtn" x="30" y="158" visible="not vlc.isMute"
|
||||
up="volume_up" down="volume_down" over="volume_over"
|
||||
action="vlc.mute()" tooltiptext="Volumen: $V%"/>
|
||||
<Button id="muteBtn" x="30" y="158" visible="vlc.isMute"
|
||||
up="mute_up" down="mute_down" over="mute_over"
|
||||
action="vlc.mute()" tooltiptext="Silenciado"/>
|
||||
|
||||
<Image id="volTrackBg" x="76" y="172" image="vol_slider_track"/>
|
||||
<Slider id="volumeSlider" x="76" y="165"
|
||||
up="vol_knob_up" down="vol_knob_down" over="vol_knob_over"
|
||||
points="(0,9),(80,9)" thickness="18"
|
||||
value="volume" tooltiptext="Volumen: $V%"/>
|
||||
|
||||
<Button id="eqBtn" x="170" y="158"
|
||||
up="equalizer_up" down="equalizer_down" over="equalizer_over"
|
||||
action="dialogs.popup()" tooltiptext="Ecualizador"/>
|
||||
|
||||
<Button id="abLoopBtn" x="216" y="158"
|
||||
up="ab_loop_up" down="ab_loop_down" over="ab_loop_over"
|
||||
action="dialogs.popup()" tooltiptext="Loop A-B"/>
|
||||
|
||||
<Button id="speedBtn" x="262" y="158"
|
||||
up="speed_up" down="speed_down" over="speed_over"
|
||||
action="dialogs.popup()" tooltiptext="Velocidad"/>
|
||||
|
||||
</Layout>
|
||||
</Window>
|
||||
|
||||
<!-- FULLSCREEN CONTROLLER - Aparece en pantalla completa -->
|
||||
<Window id="fullscreenController" x="0" y="0" visible="true" dragdrop="false">
|
||||
<Layout id="fsLayout" width="500" height="80"
|
||||
minwidth="500" maxwidth="500" minheight="80" maxheight="80">
|
||||
|
||||
<!-- Fondo semi-transparente -->
|
||||
<Image id="fsBg" x="0" y="0" image="bg" action="none"/>
|
||||
|
||||
<!-- Tiempo -->
|
||||
<Text id="fsTime" x="20" y="10" width="100"
|
||||
font="font_body" color="#000000"
|
||||
text="$T / $D"/>
|
||||
|
||||
<!-- Slider tiempo -->
|
||||
<Image id="fsSliderBg" x="20" y="35" image="slider_track"/>
|
||||
<Slider id="fsTimeSlider" x="20" y="27"
|
||||
up="slider_knob_up" down="slider_knob_down" over="slider_knob_over"
|
||||
points="(0,11),(460,11)" thickness="22"
|
||||
value="time" tooltiptext="$T / $D"/>
|
||||
|
||||
<!-- Controles centrados -->
|
||||
<Button id="fsPrevBtn" x="160" y="55"
|
||||
up="prev_up" down="prev_down" over="prev_over"
|
||||
action="playlist.previous()" tooltiptext="Anterior"/>
|
||||
|
||||
<Button id="fsPlayBtn" x="210" y="53" visible="not vlc.isPlaying"
|
||||
up="play_up" down="play_down" over="play_over"
|
||||
action="vlc.play()" tooltiptext="Reproducir"/>
|
||||
<Button id="fsPauseBtn" x="210" y="53" visible="vlc.isPlaying"
|
||||
up="pause_up" down="pause_down" over="pause_over"
|
||||
action="vlc.pause()" tooltiptext="Pausar"/>
|
||||
|
||||
<Button id="fsNextBtn" x="260" y="55"
|
||||
up="next_up" down="next_down" over="next_over"
|
||||
action="playlist.next()" tooltiptext="Siguiente"/>
|
||||
|
||||
<!-- Volumen -->
|
||||
<Button id="fsVolBtn" x="420" y="55" visible="not vlc.isMute"
|
||||
up="volume_up" down="volume_down" over="volume_over"
|
||||
action="vlc.mute()" tooltiptext="$V%"/>
|
||||
|
||||
<!-- Salir fullscreen -->
|
||||
<Button id="fsExitBtn" x="460" y="55"
|
||||
up="fullscreen_up" down="fullscreen_down" over="fullscreen_over"
|
||||
action="vlc.fullscreen()" tooltiptext="Salir pantalla completa"/>
|
||||
|
||||
</Layout>
|
||||
</Window>
|
||||
|
||||
<!-- VIDEO WINDOW - Ventana con área de video -->
|
||||
<Window id="videoWindow" x="0" y="0" visible="true" dragdrop="true">
|
||||
<Layout id="videoLayout" width="640" height="480"
|
||||
minwidth="320" maxwidth="1920" minheight="240" maxheight="1080">
|
||||
|
||||
<!-- Fondo -->
|
||||
<Image id="videoBg" x="0" y="0" image="bg_video" action="move"/>
|
||||
|
||||
<!-- Área de video -->
|
||||
<Video id="videoArea" x="10" y="40" width="620" height="360"
|
||||
autoresize="false"/>
|
||||
|
||||
<!-- Controles ventana -->
|
||||
<Button id="vidCloseBtn" x="16" y="14"
|
||||
up="win_close_up" down="win_close_down" over="win_close_over"
|
||||
action="videoWindow.hide()" tooltiptext="Cerrar"/>
|
||||
|
||||
<!-- Título -->
|
||||
<Text id="vidTitle" x="50" y="12" width="500"
|
||||
font="font_title" color="#000000" scrolling="auto"
|
||||
text=" $N "/>
|
||||
|
||||
<!-- Controles inferiores -->
|
||||
<Image id="vidSliderBg" x="20" y="415" image="slider_track"/>
|
||||
<Slider id="vidTimeSlider" x="20" y="408"
|
||||
up="slider_knob_up" down="slider_knob_down" over="slider_knob_over"
|
||||
points="(0,10),(600,10)" thickness="20"
|
||||
value="time" tooltiptext="$T / $D"/>
|
||||
|
||||
<Button id="vidPrevBtn" x="220" y="440"
|
||||
up="prev_up" down="prev_down" over="prev_over"
|
||||
action="playlist.previous()" tooltiptext="Anterior"/>
|
||||
|
||||
<Button id="vidPlayBtn" x="270" y="438" visible="not vlc.isPlaying"
|
||||
up="play_up" down="play_down" over="play_over"
|
||||
action="vlc.play()" tooltiptext="Reproducir"/>
|
||||
<Button id="vidPauseBtn" x="270" y="438" visible="vlc.isPlaying"
|
||||
up="pause_up" down="pause_down" over="pause_over"
|
||||
action="vlc.pause()" tooltiptext="Pausar"/>
|
||||
|
||||
<Button id="vidNextBtn" x="320" y="440"
|
||||
up="next_up" down="next_down" over="next_over"
|
||||
action="playlist.next()" tooltiptext="Siguiente"/>
|
||||
|
||||
<Button id="vidFullBtn" x="590" y="440"
|
||||
up="fullscreen_up" down="fullscreen_down" over="fullscreen_over"
|
||||
action="vlc.fullscreen()" tooltiptext="Pantalla completa"/>
|
||||
|
||||
<Text id="vidTime" x="20" y="445" width="100"
|
||||
font="font_body" color="#000000"
|
||||
text="$T / $D"/>
|
||||
|
||||
</Layout>
|
||||
</Window>
|
||||
|
||||
<!-- PLAYLIST WINDOW - Ventana de playlist -->
|
||||
<Window id="playlistWindow" x="450" y="0" visible="false" dragdrop="true">
|
||||
<Layout id="playlistLayout" width="320" height="400"
|
||||
minwidth="250" maxwidth="500" minheight="200" maxheight="800">
|
||||
|
||||
<!-- Fondo -->
|
||||
<Image id="plBg" x="0" y="0" image="playlist_bg" action="move"/>
|
||||
|
||||
<!-- Controles ventana -->
|
||||
<Button id="plCloseBtn" x="12" y="10"
|
||||
up="win_close_up" down="win_close_down" over="win_close_over"
|
||||
action="playlistWindow.hide()" tooltiptext="Cerrar"/>
|
||||
|
||||
<!-- Título -->
|
||||
<Text id="plTitle" x="40" y="8" width="200"
|
||||
font="font_title" color="#000000"
|
||||
text="Playlist"/>
|
||||
|
||||
<!-- Lista de reproducción -->
|
||||
<Playtree id="playtree" x="10" y="35" width="300" height="355"
|
||||
font="font_body" fgcolor="#000000" selcolor="#FFFFFF"
|
||||
playcolor="#007AFF" bgcolor1="#F2F2F7" bgcolor2="#E5E5EA"
|
||||
flat="false"/>
|
||||
|
||||
</Layout>
|
||||
</Window>
|
||||
|
||||
</Theme>
|
||||
Loading…
Reference in New Issue