23
23
24
24
import Adw from "gi://Adw" ;
25
25
import GObject from "gi://GObject" ;
26
- import Gdk from "gi://Gdk?version=4.0" ;
27
26
import Gtk from "gi://Gtk?version=4.0" ;
28
27
import Gst from "gi://Gst" ;
29
-
30
- // @ts -expect-error This module doesn't import nicely
31
- import Cairo from "cairo" ;
28
+ import Graphene from "gi://Graphene" ;
32
29
33
30
export enum WaveType {
34
31
Recorder ,
35
32
Player ,
36
33
}
37
34
38
35
const GUTTER = 4 ;
36
+ const LINE_WIDTH = 1 ;
39
37
40
- export class APWaveForm extends Gtk . DrawingArea {
38
+ export class APWaveForm extends Gtk . Widget {
41
39
private _position : number ;
42
40
private dragGesture ?: Gtk . GestureDrag ;
43
41
private hcId : number ;
@@ -93,8 +91,6 @@ export class APWaveForm extends Gtk.DrawingArea {
93
91
this . queue_draw ( ) ;
94
92
} ,
95
93
) ;
96
-
97
- this . set_draw_func ( this . drawFunc . bind ( this ) ) ;
98
94
}
99
95
100
96
get peaks ( ) : number [ ] {
@@ -122,12 +118,10 @@ export class APWaveForm extends Gtk.DrawingArea {
122
118
this . emit ( "position-changed" , this . position ) ;
123
119
}
124
120
125
- private drawFunc (
126
- _ : Gtk . DrawingArea ,
127
- ctx : Cairo . Context ,
128
- width : number ,
129
- height : number ,
130
- ) {
121
+ vfunc_snapshot ( snapshot : Gtk . Snapshot ) : void {
122
+ const height = this . get_height ( ) ;
123
+ const width = this . get_width ( ) ;
124
+
131
125
const peaks = this . peaks ;
132
126
const vertiCenter = height / 2 ;
133
127
const horizCenter = width / 2 ;
@@ -140,23 +134,17 @@ export class APWaveForm extends Gtk.DrawingArea {
140
134
141
135
const leftColor = this . safeLookupColor ( "accent_color" ) ;
142
136
143
- // Because the cairo module isn't real, we have to use these to ignore `any`.
144
- // We keep them to the minimum possible scope to catch real errors.
145
- /* eslint-disable @typescript-eslint/no-unsafe-call */
146
- /* eslint-disable @typescript-eslint/no-unsafe-member-access */
147
- ctx . setLineCap ( Cairo . LineCap . SQUARE ) ;
148
- ctx . setAntialias ( Cairo . Antialias . NONE ) ;
149
- ctx . setLineWidth ( 2 ) ;
150
-
151
- this . setSourceRGBA ( ctx , leftColor ) ;
152
-
153
- ctx . moveTo ( horizCenter , vertiCenter - height ) ;
154
- ctx . lineTo ( horizCenter , vertiCenter + height ) ;
155
- ctx . stroke ( ) ;
137
+ // Clip the snapshot to the widget area.
138
+ // Turns out the DrawingArea was automatically doing that for us
139
+ snapshot . push_clip (
140
+ new Graphene . Rect ( { size : new Graphene . Size ( { width, height } ) } ) ,
141
+ ) ;
156
142
157
- ctx . setLineWidth ( 2 ) ;
158
- /* eslint-enable @typescript-eslint/no-unsafe-call */
159
- /* eslint-enable @typescript-eslint/no-unsafe-member-access */
143
+ const indicator = new Graphene . Rect ( {
144
+ origin : new Graphene . Point ( { x : horizCenter , y : 0 } ) ,
145
+ size : new Graphene . Size ( { width : LINE_WIDTH , height } ) ,
146
+ } ) ;
147
+ snapshot . append_color ( leftColor , indicator ) ;
160
148
161
149
// only draw the waveform for peaks inside the view
162
150
let invisible_peaks = 0 ;
@@ -166,7 +154,9 @@ export class APWaveForm extends Gtk.DrawingArea {
166
154
pointer = pointer + invisible_peaks ;
167
155
}
168
156
169
- for ( const peak of peaks . slice ( invisible_peaks / GUTTER ) ) {
157
+ // eslint-disable-next-line @typescript-eslint/no-for-in-array
158
+ for ( const id in peaks . slice ( invisible_peaks / GUTTER ) ) {
159
+ const peak = peaks . slice ( invisible_peaks / GUTTER ) [ id ] ;
170
160
// this shouldn't happen, but just in case
171
161
if ( pointer < 0 ) {
172
162
pointer += GUTTER ;
@@ -177,22 +167,29 @@ export class APWaveForm extends Gtk.DrawingArea {
177
167
break ;
178
168
}
179
169
180
- if ( pointer > horizCenter ) {
181
- this . setSourceRGBA ( ctx , rightColor ) ;
182
- } else {
183
- this . setSourceRGBA ( ctx , leftColor ) ;
184
- }
185
-
186
- /* eslint-disable @typescript-eslint/no-unsafe-call */
187
- /* eslint-disable @typescript-eslint/no-unsafe-member-access */
188
- ctx . moveTo ( pointer , vertiCenter + peak * height ) ;
189
- ctx . lineTo ( pointer , vertiCenter - peak * height ) ;
190
- ctx . stroke ( ) ;
191
- /* eslint-enable @typescript-eslint/no-unsafe-call */
192
- /* eslint-enable @typescript-eslint/no-unsafe-member-access */
170
+ // only show 70% of the peaks. there are usually few peaks that are
171
+ // over 70% high, and those get clipped so that not much space is empty
172
+ const line_height = Math . max ( peak * height * 0.7 , 1 ) ;
173
+
174
+ const line = new Graphene . Rect ( {
175
+ origin : new Graphene . Point ( {
176
+ x : pointer ,
177
+ y : vertiCenter - line_height ,
178
+ } ) ,
179
+ size : new Graphene . Size ( {
180
+ width : LINE_WIDTH ,
181
+ height : line_height * 2 ,
182
+ } ) ,
183
+ } ) ;
184
+ snapshot . append_color (
185
+ pointer > horizCenter ? rightColor : leftColor ,
186
+ line ,
187
+ ) ;
193
188
194
189
pointer += GUTTER ;
195
190
}
191
+
192
+ snapshot . pop ( ) ;
196
193
}
197
194
198
195
set position ( pos : number ) {
@@ -207,14 +204,6 @@ export class APWaveForm extends Gtk.DrawingArea {
207
204
return this . _position ;
208
205
}
209
206
210
- private setSourceRGBA ( cr : Cairo . Context , rgba : Gdk . RGBA ) : void {
211
- /* eslint-disable @typescript-eslint/no-unsafe-call */
212
- /* eslint-disable @typescript-eslint/no-unsafe-member-access */
213
- cr . setSourceRGBA ( rgba . red , rgba . green , rgba . blue , rgba . alpha ) ;
214
- /* eslint-enable @typescript-eslint/no-unsafe-call */
215
- /* eslint-enable @typescript-eslint/no-unsafe-member-access */
216
- }
217
-
218
207
public destroy ( ) : void {
219
208
Adw . StyleManager . get_default ( ) . disconnect ( this . hcId ) ;
220
209
this . peaks . length = 0 ;
0 commit comments