Skip to content
This repository has been archived by the owner on Mar 11, 2024. It is now read-only.

use Snapshot API instead of cairo #64

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 33 additions & 52 deletions src/waveform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,19 @@

import Adw from "gi://Adw";
import GObject from "gi://GObject";
import Gdk from "gi://Gdk?version=4.0";
import Gtk from "gi://Gtk?version=4.0";
import Gst from "gi://Gst";

// @ts-expect-error This module doesn't import nicely
import Cairo from "cairo";
import Graphene from "gi://Graphene";

export enum WaveType {
Recorder,
Player,
}

const GUTTER = 4;
const LINE_WIDTH = 1;

export class APWaveForm extends Gtk.DrawingArea {
export class APWaveForm extends Gtk.Widget {
private _position: number;
private dragGesture?: Gtk.GestureDrag;
private hcId: number;
Expand Down Expand Up @@ -93,8 +91,6 @@ export class APWaveForm extends Gtk.DrawingArea {
this.queue_draw();
},
);

this.set_draw_func(this.drawFunc.bind(this));
}

get peaks(): number[] {
Expand Down Expand Up @@ -122,12 +118,10 @@ export class APWaveForm extends Gtk.DrawingArea {
this.emit("position-changed", this.position);
}

private drawFunc(
_: Gtk.DrawingArea,
ctx: Cairo.Context,
width: number,
height: number,
) {
vfunc_snapshot(snapshot: Gtk.Snapshot): void {
const height = this.get_height();
const width = this.get_width();

const peaks = this.peaks;
const vertiCenter = height / 2;
const horizCenter = width / 2;
Expand All @@ -140,23 +134,11 @@ export class APWaveForm extends Gtk.DrawingArea {

const leftColor = this.safeLookupColor("accent_color");

// Because the cairo module isn't real, we have to use these to ignore `any`.
// We keep them to the minimum possible scope to catch real errors.
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
ctx.setLineCap(Cairo.LineCap.SQUARE);
ctx.setAntialias(Cairo.Antialias.NONE);
ctx.setLineWidth(2);

this.setSourceRGBA(ctx, leftColor);

ctx.moveTo(horizCenter, vertiCenter - height);
ctx.lineTo(horizCenter, vertiCenter + height);
ctx.stroke();

ctx.setLineWidth(2);
/* eslint-enable @typescript-eslint/no-unsafe-call */
/* eslint-enable @typescript-eslint/no-unsafe-member-access */
const indicator = new Graphene.Rect({
origin: new Graphene.Point({ x: horizCenter, y: 0 }),
size: new Graphene.Size({ width: LINE_WIDTH, height }),
});
snapshot.append_color(leftColor, indicator);

// only draw the waveform for peaks inside the view
let invisible_peaks = 0;
Expand All @@ -166,7 +148,9 @@ export class APWaveForm extends Gtk.DrawingArea {
pointer = pointer + invisible_peaks;
}

for (const peak of peaks.slice(invisible_peaks / GUTTER)) {
// eslint-disable-next-line @typescript-eslint/no-for-in-array
for (const id in peaks.slice(invisible_peaks / GUTTER)) {
const peak = peaks.slice(invisible_peaks / GUTTER)[id];
// this shouldn't happen, but just in case
if (pointer < 0) {
pointer += GUTTER;
Expand All @@ -177,19 +161,24 @@ export class APWaveForm extends Gtk.DrawingArea {
break;
}

if (pointer > horizCenter) {
this.setSourceRGBA(ctx, rightColor);
} else {
this.setSourceRGBA(ctx, leftColor);
}

/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
ctx.moveTo(pointer, vertiCenter + peak * height);
ctx.lineTo(pointer, vertiCenter - peak * height);
ctx.stroke();
/* eslint-enable @typescript-eslint/no-unsafe-call */
/* eslint-enable @typescript-eslint/no-unsafe-member-access */
// only show 70% of the peaks. there are usually few peaks that are
// over 70% high, and those get clipped so that not much space is empty
const line_height = Math.max(peak * height * 0.7, 1);

const line = new Graphene.Rect({
origin: new Graphene.Point({
x: pointer,
y: Math.max(vertiCenter - line_height, 0),
}),
size: new Graphene.Size({
width: LINE_WIDTH,
height: Math.min(line_height * 2, height),
}),
});
snapshot.append_color(
pointer > horizCenter ? rightColor : leftColor,
line,
);

pointer += GUTTER;
}
Expand All @@ -207,14 +196,6 @@ export class APWaveForm extends Gtk.DrawingArea {
return this._position;
}

private setSourceRGBA(cr: Cairo.Context, rgba: Gdk.RGBA): void {
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
cr.setSourceRGBA(rgba.red, rgba.green, rgba.blue, rgba.alpha);
/* eslint-enable @typescript-eslint/no-unsafe-call */
/* eslint-enable @typescript-eslint/no-unsafe-member-access */
}

public destroy(): void {
Adw.StyleManager.get_default().disconnect(this.hcId);
this.peaks.length = 0;
Expand Down