Files
wehub-resource-sync ead81af521
CI / go (push) Waiting to run
CI / build (darwin, macos-14) (push) Waiting to run
CI / build (windows, windows-2025) (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Failing after 0s
chore: import upstream snapshot with attribution
2026-07-13 12:31:13 +08:00

134 lines
4.5 KiB
QML

// Crisp, font-independent media transport icons drawn with Canvas2D.
//
// Shapes: "prev", "play", "pause", "next", "stop". The icon fills a square
// bounded by implicitWidth x implicitHeight (default 14 x 14) and is centred
// inside that square. Color follows the active theme.
import QtQuick
Item {
id: root
property string shape: "play"
property color color: "#d4be98"
property real size: 14
implicitWidth: size
implicitHeight: size
onShapeChanged: canvas.requestPaint()
onColorChanged: canvas.requestPaint()
Canvas {
id: canvas
anchors.fill: parent
antialiasing: true
onPaint: {
const ctx = getContext("2d");
ctx.reset();
const w = width, h = height;
const s = Math.min(w, h);
// Inset so strokes/triangle tips don't clip on the canvas edge.
const pad = Math.max(1, Math.round(s * 0.12));
const x0 = (w - s) / 2 + pad;
const y0 = (h - s) / 2 + pad;
const sz = s - pad * 2;
ctx.fillStyle = root.color;
ctx.strokeStyle = root.color;
ctx.lineJoin = "round";
ctx.lineCap = "round";
switch (root.shape) {
case "prev": drawPrev(ctx, x0, y0, sz); break;
case "next": drawNext(ctx, x0, y0, sz); break;
case "pause": drawPause(ctx, x0, y0, sz); break;
case "stop": drawStop(ctx, x0, y0, sz); break;
case "play":
default: drawPlay(ctx, x0, y0, sz); break;
}
}
function triangleRight(ctx, x, y, w, h) {
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(x + w, y + h / 2);
ctx.lineTo(x, y + h);
ctx.closePath();
ctx.fill();
}
function triangleLeft(ctx, x, y, w, h) {
ctx.beginPath();
ctx.moveTo(x + w, y);
ctx.lineTo(x, y + h / 2);
ctx.lineTo(x + w, y + h);
ctx.closePath();
ctx.fill();
}
function drawPlay(ctx, x0, y0, sz) {
// Narrow the triangle to 92% of width for balance; full height, centered.
const w = sz * 0.92;
triangleRight(ctx, x0 + (sz - w) / 2, y0, w, sz);
}
function drawPause(ctx, x0, y0, sz) {
const barW = Math.max(2, Math.round(sz * 0.28));
const gap = Math.max(2, Math.round(sz * 0.18));
const totalW = barW * 2 + gap;
const left = x0 + (sz - totalW) / 2;
ctx.fillRect(left, y0, barW, sz);
ctx.fillRect(left + barW + gap, y0, barW, sz);
}
function drawStop(ctx, x0, y0, sz) {
const side = sz * 0.86;
const inset = (sz - side) / 2;
ctx.fillRect(x0 + inset, y0 + inset, side, side);
}
function drawPrev(ctx, x0, y0, sz) {
// Vertical bar + left-pointing double triangle.
const barW = Math.max(1.5, sz * 0.14);
ctx.fillRect(x0, y0, barW, sz);
// Two stacked triangles forming the doubled arrow.
const tStart = x0 + barW + Math.max(1, sz * 0.06);
const tSpan = (x0 + sz) - tStart;
const tHalf = tSpan / 2;
ctx.beginPath();
ctx.moveTo(tStart, y0 + sz / 2);
ctx.lineTo(tStart + tHalf, y0);
ctx.lineTo(tStart + tHalf, y0 + sz);
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.moveTo(tStart + tHalf, y0 + sz / 2);
ctx.lineTo(tStart + tSpan, y0);
ctx.lineTo(tStart + tSpan, y0 + sz);
ctx.closePath();
ctx.fill();
}
function drawNext(ctx, x0, y0, sz) {
// Right-pointing double triangle + trailing vertical bar.
const barW = Math.max(1.5, sz * 0.14);
const barX = x0 + sz - barW;
ctx.fillRect(barX, y0, barW, sz);
const tEnd = barX - Math.max(1, sz * 0.06);
const tSpan = tEnd - x0;
const tHalf = tSpan / 2;
ctx.beginPath();
ctx.moveTo(x0, y0);
ctx.lineTo(x0 + tHalf, y0 + sz / 2);
ctx.lineTo(x0, y0 + sz);
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.moveTo(x0 + tHalf, y0);
ctx.lineTo(tEnd, y0 + sz / 2);
ctx.lineTo(x0 + tHalf, y0 + sz);
ctx.closePath();
ctx.fill();
}
}
}