Files
gti_radiostudio/icons.py
T
nickmin 89fb7010fb v0.5 — cleanup orphan code, add MIDI master volume learn, fix turn-deck crashes
- Remove vestigial lufs_meter_widget.py and debug_audio.py
- Delete unused WaveformWidget/WaveformMonitor classes, dead stubs, duplicate code
- Fix turn-mode deck crashes (deck3/deck4 missing from engine.decks, uninitialized manual_elapsed/duration)
- Replace raw print() with logging in main.py
- Add master_volume MIDI learn signal + settings popup entry
- Bump version to 0.5
2026-05-14 22:25:10 +10:00

346 lines
13 KiB
Python

# icons.py -- QPainter-drawn icons for Radio Panel
#
# Each function takes (color: str) and returns a QIcon painted at 24x24.
# All icons are simple geometric shapes -- clean, broadcast-console look.
from PySide6.QtGui import QPainter, QColor, QPen, QBrush, QPixmap, QIcon, QPainterPath
from PySide6.QtCore import Qt, QRectF, QPointF
_S = 24
def _make_icon(paint_fn, color: str) -> QIcon:
pix = QPixmap(_S, _S)
pix.fill(Qt.transparent)
p = QPainter(pix)
p.setRenderHint(QPainter.Antialiasing)
paint_fn(p, QRectF(2, 2, _S - 4, _S - 4), QColor(color))
p.end()
return QIcon(pix)
# ── Transport Icons ────────────────────────────────────────────────
def icon_play(color: str = "#00ff41") -> QIcon:
def paint(p, r, c):
p.setPen(Qt.NoPen)
p.setBrush(c)
path = QPainterPath()
path.moveTo(r.left(), r.top())
path.lineTo(r.right(), r.center().y())
path.lineTo(r.left(), r.bottom())
path.closeSubpath()
p.drawPath(path)
return _make_icon(paint, color)
def icon_pause(color: str = "#ffffff") -> QIcon:
def paint(p, r, c):
p.setPen(Qt.NoPen)
p.setBrush(c)
w = r.width() * 0.32
p.drawRect(QRectF(r.left(), r.top(), w, r.height()))
p.drawRect(QRectF(r.right() - w, r.top(), w, r.height()))
return _make_icon(paint, color)
def icon_stop(color: str = "#ff4444") -> QIcon:
def paint(p, r, c):
p.setPen(Qt.NoPen)
p.setBrush(c)
margin = r.width() * 0.18
p.drawRect(r.adjusted(margin, margin, -margin, -margin))
return _make_icon(paint, color)
def icon_skip_start(color: str = "#ffffff") -> QIcon:
def paint(p, r, c):
p.setPen(Qt.NoPen)
p.setBrush(c)
w = r.width() * 0.35
# Two triangles pointing left
path = QPainterPath()
path.moveTo(r.right(), r.top())
path.lineTo(r.left(), r.center().y())
path.lineTo(r.right(), r.bottom())
path.closeSubpath()
p.drawPath(path)
path2 = QPainterPath()
path2.moveTo(r.center().x(), r.top())
path2.lineTo(r.left(), r.center().y())
path2.lineTo(r.center().x(), r.bottom())
path2.closeSubpath()
p.drawPath(path2)
return _make_icon(paint, color)
def icon_skip_end(color: str = "#ffffff") -> QIcon:
def paint(p, r, c):
p.setPen(Qt.NoPen)
p.setBrush(c)
path = QPainterPath()
path.moveTo(r.left(), r.top())
path.lineTo(r.right(), r.center().y())
path.lineTo(r.left(), r.bottom())
path.closeSubpath()
p.drawPath(path)
path2 = QPainterPath()
path2.moveTo(r.center().x(), r.top())
path2.lineTo(r.right(), r.center().y())
path2.lineTo(r.center().x(), r.bottom())
path2.closeSubpath()
p.drawPath(path2)
return _make_icon(paint, color)
def icon_skip_back(color: str = "#aaaaaa") -> QIcon:
def paint(p, r, c):
p.setPen(Qt.NoPen)
p.setBrush(c)
path = QPainterPath()
path.moveTo(r.right() * 0.7, r.top())
path.lineTo(r.left(), r.center().y())
path.lineTo(r.right() * 0.7, r.bottom())
path.closeSubpath()
p.drawPath(path)
# Vertical bar
bar_w = r.width() * 0.12
p.drawRect(QRectF(r.right() - bar_w, r.top(), bar_w, r.height()))
return _make_icon(paint, color)
def icon_skip_forward(color: str = "#aaaaaa") -> QIcon:
def paint(p, r, c):
p.setPen(Qt.NoPen)
p.setBrush(c)
path = QPainterPath()
path.moveTo(r.left() + r.width() * 0.3, r.top())
path.lineTo(r.right(), r.center().y())
path.lineTo(r.left() + r.width() * 0.3, r.bottom())
path.closeSubpath()
p.drawPath(path)
bar_w = r.width() * 0.12
p.drawRect(QRectF(r.left(), r.top(), bar_w, r.height()))
return _make_icon(paint, color)
def icon_eject(color: str = "#ff4444") -> QIcon:
def paint(p, r, c):
pen = QPen(c, r.width() * 0.12)
pen.setCapStyle(Qt.RoundCap)
p.setPen(pen)
p.setBrush(Qt.NoBrush)
# Upward triangle
mid_x = r.center().x()
path = QPainterPath()
path.moveTo(r.left() + r.width() * 0.2, r.center().y() + r.height() * 0.1)
path.lineTo(mid_x, r.top() + r.height() * 0.2)
path.lineTo(r.right() - r.width() * 0.2, r.center().y() + r.height() * 0.1)
p.drawPath(path)
# Horizontal line
p.drawLine(QPointF(r.left() + r.width() * 0.2, r.bottom() - r.height() * 0.1),
QPointF(r.right() - r.width() * 0.2, r.bottom() - r.height() * 0.1))
return _make_icon(paint, color)
# ── Action Icons ───────────────────────────────────────────────────
def icon_plus(color: str = "#00ff41") -> QIcon:
def paint(p, r, c):
pen = QPen(c, r.width() * 0.12)
pen.setCapStyle(Qt.RoundCap)
p.setPen(pen)
p.setBrush(Qt.NoBrush)
mid = r.center()
p.drawLine(QPointF(mid.x(), r.top()), QPointF(mid.x(), r.bottom()))
p.drawLine(QPointF(r.left(), mid.y()), QPointF(r.right(), mid.y()))
return _make_icon(paint, color)
def icon_delete(color: str = "#ff4444") -> QIcon:
def paint(p, r, c):
pen = QPen(c, r.width() * 0.12)
pen.setCapStyle(Qt.RoundCap)
p.setPen(pen)
p.setBrush(Qt.NoBrush)
p.drawLine(QPointF(r.left(), r.top()), QPointF(r.right(), r.bottom()))
p.drawLine(QPointF(r.right(), r.top()), QPointF(r.left(), r.bottom()))
return _make_icon(paint, color)
def icon_save(color: str = "#aaaaaa") -> QIcon:
def paint(p, r, c):
pen = QPen(c, r.width() * 0.12)
pen.setCapStyle(Qt.RoundCap)
p.setPen(pen)
p.setBrush(Qt.NoBrush)
# Arrow down into tray
mid_x = r.center().x()
p.drawLine(QPointF(mid_x, r.top()), QPointF(mid_x, r.bottom() - r.height() * 0.15))
# Arrow head
p.drawLine(QPointF(mid_x - r.width() * 0.25, r.bottom() - r.height() * 0.4),
QPointF(mid_x, r.bottom() - r.height() * 0.15))
p.drawLine(QPointF(mid_x + r.width() * 0.25, r.bottom() - r.height() * 0.4),
QPointF(mid_x, r.bottom() - r.height() * 0.15))
# Tray bottom line
p.drawLine(QPointF(r.left(), r.bottom()), QPointF(r.right(), r.bottom()))
return _make_icon(paint, color)
def icon_load(color: str = "#aaaaaa") -> QIcon:
def paint(p, r, c):
pen = QPen(c, r.width() * 0.12)
pen.setCapStyle(Qt.RoundCap)
p.setPen(pen)
p.setBrush(Qt.NoBrush)
# Arrow up from tray
mid_x = r.center().x()
p.drawLine(QPointF(mid_x, r.bottom()), QPointF(mid_x, r.top() + r.height() * 0.15))
p.drawLine(QPointF(mid_x - r.width() * 0.25, r.top() + r.height() * 0.35),
QPointF(mid_x, r.top() + r.height() * 0.1))
p.drawLine(QPointF(mid_x + r.width() * 0.25, r.top() + r.height() * 0.35),
QPointF(mid_x, r.top() + r.height() * 0.1))
p.drawLine(QPointF(r.left(), r.bottom()), QPointF(r.right(), r.bottom()))
return _make_icon(paint, color)
def icon_export(color: str = "#aaaaaa") -> QIcon:
def paint(p, r, c):
pen = QPen(c, r.width() * 0.12)
pen.setCapStyle(Qt.RoundCap)
p.setPen(pen)
p.setBrush(Qt.NoBrush)
# Box
margin = r.width() * 0.15
p.drawRect(r.adjusted(margin, margin, -margin, -margin))
# Arrow out of box (top-right)
p.drawLine(QPointF(r.right() - margin, r.top() + margin),
QPointF(r.right(), r.top()))
p.drawLine(QPointF(r.right() - r.width() * 0.3, r.top()),
QPointF(r.right(), r.top()))
p.drawLine(QPointF(r.right(), r.top() + r.height() * 0.3),
QPointF(r.right(), r.top()))
return _make_icon(paint, color)
def icon_mute(color: str = "#ff4444") -> QIcon:
def paint(p, r, c):
pen = QPen(c, r.width() * 0.12)
pen.setCapStyle(Qt.RoundCap)
p.setPen(pen)
p.setBrush(Qt.NoBrush)
# Speaker body
cx = r.left() + r.width() * 0.3
p.drawLine(QPointF(cx, r.top() + r.height() * 0.25),
QPointF(cx, r.bottom() - r.height() * 0.25))
p.drawLine(QPointF(cx, r.top() + r.height() * 0.25),
QPointF(r.left() + r.width() * 0.5, r.center().y() - r.height() * 0.15))
p.drawLine(QPointF(cx, r.bottom() - r.height() * 0.25),
QPointF(r.left() + r.width() * 0.5, r.center().y() + r.height() * 0.15))
p.drawLine(QPointF(r.left() + r.width() * 0.2, r.center().y() - r.height() * 0.15),
QPointF(r.left() + r.width() * 0.5, r.center().y() - r.height() * 0.15))
p.drawLine(QPointF(r.left() + r.width() * 0.2, r.center().y() + r.height() * 0.15),
QPointF(r.left() + r.width() * 0.5, r.center().y() + r.height() * 0.15))
# X over speaker
x = r.right() - r.width() * 0.2
y1 = r.top() + r.height() * 0.2
y2 = r.bottom() - r.height() * 0.2
p.drawLine(QPointF(x, y1), QPointF(r.right() - r.width() * 0.05, y2))
p.drawLine(QPointF(r.right() - r.width() * 0.05, y1), QPointF(x, y2))
return _make_icon(paint, color)
def icon_solo(color: str = "#ffaa00") -> QIcon:
def paint(p, r, c):
p.setPen(Qt.NoPen)
p.setBrush(c)
# Circle with "S"
center = r.center()
radius = min(r.width(), r.height()) * 0.45
p.drawEllipse(center, radius, radius)
# S letter (white)
pen = QPen(QColor("#000000"), r.width() * 0.12)
pen.setCapStyle(Qt.RoundCap)
p.setPen(pen)
p.setBrush(Qt.NoBrush)
path = QPainterPath()
path.moveTo(r.left() + r.width() * 0.45, r.top() + r.height() * 0.3)
path.cubicTo(
r.left() + r.width() * 0.7, r.top() + r.height() * 0.15,
r.right() - r.width() * 0.25, r.top() + r.height() * 0.35,
r.left() + r.width() * 0.55, r.top() + r.height() * 0.5
)
path.cubicTo(
r.left() + r.width() * 0.3, r.top() + r.height() * 0.65,
r.right() - r.width() * 0.15, r.top() + r.height() * 0.7,
r.left() + r.width() * 0.45, r.bottom() - r.height() * 0.2
)
p.drawPath(path)
return _make_icon(paint, color)
def icon_cog(color: str = "#aaaaaa") -> QIcon:
def paint(p, r, c):
pen = QPen(c, r.width() * 0.1)
pen.setCapStyle(Qt.RoundCap)
p.setPen(pen)
p.setBrush(Qt.NoBrush)
# Outer circle (gear ring)
cx, cy = r.center().x(), r.center().y()
outer_r = min(r.width(), r.height()) * 0.42
inner_r = outer_r * 0.6
# Draw gear teeth (6 bumps)
import math
p.setBrush(QColor(c))
for i in range(6):
angle = i * 60 - 30
a_rad = math.radians(angle)
bx = cx + outer_r * math.cos(a_rad)
by = cy + outer_r * math.sin(a_rad)
tooth = QPainterPath()
tw = r.width() * 0.12
th = r.width() * 0.18
tooth.addRect(bx - tw/2, by - th/2, tw, th)
p.drawRect(bx - tw/2, by - th/2, tw, th)
# Center circle
p.setPen(Qt.NoPen)
p.setBrush(QColor(c))
p.drawEllipse(QPointF(cx, cy), inner_r, inner_r)
# Inner hole
p.setBrush(QColor("#000000"))
p.drawEllipse(QPointF(cx, cy), inner_r * 0.55, inner_r * 0.55)
return _make_icon(paint, color)
def icon_theme(color: str = "#00ff41") -> QIcon:
def paint(p, r, c):
p.setPen(Qt.NoPen)
# Draw 4 coloured quadrants
mid = r.center()
colors = [QColor("#00ff41"), QColor("#ffaa00"),
QColor("#00aaff"), QColor("#ff4444")]
for i, col in enumerate(colors):
path = QPainterPath()
if i == 0:
path.moveTo(mid)
path.arcTo(r, 0, 90)
path.closeSubpath()
elif i == 1:
path.moveTo(mid)
path.arcTo(r, 270, 90)
path.closeSubpath()
elif i == 2:
path.moveTo(mid)
path.arcTo(r, 180, 90)
path.closeSubpath()
else:
path.moveTo(mid)
path.arcTo(r, 90, 90)
path.closeSubpath()
p.setBrush(col)
p.drawPath(path)
# White circle in centre
p.setBrush(QColor("#ffffff"))
p.drawEllipse(mid, r.width() * 0.15, r.height() * 0.15)
return _make_icon(paint, color)