2 DeScratch - Scratches Removing Filter
3 Plugin for Avisynth 2.5
4 Copyright (c)2003-2016 Alexander G. Balakhnin aka Fizick
5 bag@hotmail.ru http://avisynth.org.ru
7 This program is FREE software under GPL licence v2.
9 This plugin removes vertical scratches from digitized films.
10 Reworked for cin5 by GG. 03/2018, from the laws of Fizick's
17 #include "descratch.h"
19 REGISTER_PLUGIN(DeScratchMain)
21 DeScratchMain::DeScratchMain(PluginServer *server)
22 : PluginVClient(server)
31 DeScratchMain::~DeScratchMain()
41 const char* DeScratchMain::plugin_title() { return N_("DeScratch"); }
42 int DeScratchMain::is_realtime() { return 1; }
44 void DeScratchConfig::reset()
63 DeScratchConfig::DeScratchConfig()
68 DeScratchConfig::~DeScratchConfig()
72 int DeScratchConfig::equivalent(DeScratchConfig &that)
74 return threshold == that.threshold &&
75 asymmetry == that.asymmetry &&
76 min_width == that.min_width &&
77 max_width == that.max_width &&
78 min_len == that.min_len &&
79 max_len == that.max_len &&
80 max_angle == that.max_angle &&
81 blur_len == that.blur_len &&
82 gap_len == that.gap_len &&
83 mode_y == that.mode_y &&
84 mode_u == that.mode_u &&
85 mode_v == that.mode_v &&
87 ffade == that.ffade &&
88 border == that.border;
90 void DeScratchConfig::copy_from(DeScratchConfig &that)
92 threshold = that.threshold;
93 asymmetry = that.asymmetry;
94 min_width = that.min_width;
95 max_width = that.max_width;
96 min_len = that.min_len;
97 max_len = that.max_len;
98 max_angle = that.max_angle;
99 blur_len = that.blur_len;
100 gap_len = that.gap_len;
101 mode_y = that.mode_y;
102 mode_u = that.mode_u;
103 mode_v = that.mode_v;
106 border = that.border;
109 void DeScratchConfig::interpolate(DeScratchConfig &prev, DeScratchConfig &next,
110 int64_t prev_frame, int64_t next_frame, int64_t current_frame)
115 LOAD_CONFIGURATION_MACRO(DeScratchMain, DeScratchConfig)
117 void DeScratchMain::save_data(KeyFrame *keyframe)
120 // cause data to be stored directly in text
121 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
123 output.tag.set_title("DESCRATCH");
124 output.tag.set_property("THRESHOLD", config.threshold);
125 output.tag.set_property("ASYMMETRY", config.asymmetry);
126 output.tag.set_property("MIN_WIDTH", config.min_width);
127 output.tag.set_property("MAX_WIDTH", config.max_width);
128 output.tag.set_property("MIN_LEN", config.min_len);
129 output.tag.set_property("MAX_LEN", config.max_len);
130 output.tag.set_property("MAX_ANGLE", config.max_angle);
131 output.tag.set_property("BLUR_LEN", config.blur_len);
132 output.tag.set_property("GAP_LEN", config.gap_len);
133 output.tag.set_property("MODE_Y", config.mode_y);
134 output.tag.set_property("MODE_U", config.mode_u);
135 output.tag.set_property("MODE_V", config.mode_v);
136 output.tag.set_property("MARK", config.mark);
137 output.tag.set_property("FFADE", config.ffade);
138 output.tag.set_property("BORDER", config.border);
140 output.tag.set_title("/DESCRATCH");
142 output.append_newline();
143 output.terminate_string();
146 void DeScratchMain::read_data(KeyFrame *keyframe)
149 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
153 while( !(result = input.read_tag()) ) {
154 if(input.tag.title_is("DESCRATCH")) {
155 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
156 config.asymmetry = input.tag.get_property("ASYMMETRY", config.asymmetry);
157 config.min_width = input.tag.get_property("MIN_WIDTH", config.min_width);
158 config.max_width = input.tag.get_property("MAX_WIDTH", config.max_width);
159 config.min_len = input.tag.get_property("MIN_LEN", config.min_len);
160 config.max_len = input.tag.get_property("MAX_LEN", config.max_len);
161 config.max_angle = input.tag.get_property("MAX_ANGLE", config.max_angle);
162 config.blur_len = input.tag.get_property("BLUR_LEN", config.blur_len);
163 config.gap_len = input.tag.get_property("GAP_LEN", config.gap_len);
164 config.mode_y = input.tag.get_property("MODE_Y", config.mode_y);
165 config.mode_u = input.tag.get_property("MODE_U", config.mode_u);
166 config.mode_v = input.tag.get_property("MODE_V", config.mode_v);
167 config.mark = input.tag.get_property("MARK", config.mark);
168 config.ffade = input.tag.get_property("FFADE", config.ffade);
169 config.border = input.tag.get_property("BORDER", config.border);
174 void DeScratchMain::get_extrems_plane(int comp, int thresh)
176 uint8_t **rows = blurry->get_rows();
177 int d = config.max_width, d1 = d+1, wd = src_w - d1;
178 int bpp = 3, dsz = d * bpp;
179 int asym = config.asymmetry;
180 if( thresh > 0 ) { // black (low value) scratches
181 for( int y=0; y<src_h; ++y ) {
182 uint8_t *ip = inf + y*src_w;
184 for( ; x<d1; ++x ) *ip++ = SD_NULL;
185 uint8_t *dp = rows[y] + x*bpp + comp;
186 for( ; x<wd; ++x,dp+=bpp ) {
187 uint8_t *lp = dp-dsz, *rp = dp+dsz;
188 *ip++ = (lp[0]-*dp) > thresh && (rp[0]-*dp) > thresh &&
189 (abs(lp[-bpp]-rp[+bpp]) <= asym) &&
190 ((lp[0]-lp[+bpp]) + (rp[0]-rp[-bpp]) >
191 (lp[-bpp]-lp[0]) + (rp[bpp]-rp[0])) ?
192 SD_EXTREM : SD_NULL; // sharp extremum found
194 for( ; x<src_w; ++x ) *ip++ = SD_NULL;
197 else { // white (high value) scratches
198 for( int y=0; y<src_h; ++y ) {
199 uint8_t *ip = inf + y*src_w;
201 for( ; x<d1; ++x ) *ip++ = SD_NULL;
202 uint8_t *dp = rows[y] + x*bpp + comp;
203 for( ; x<wd; ++x,dp+=bpp ) {
204 uint8_t *lp = dp-dsz, *rp = dp+dsz;
205 *ip++ = (lp[0]-*dp) < thresh && (rp[0]-*dp) < thresh &&
206 (abs(lp[-bpp]-rp[+bpp]) <= asym) &&
207 ((lp[0]-lp[+bpp]) + (rp[0]-rp[-bpp]) <
208 (lp[-bpp]-lp[0]) + (rp[bpp]-rp[0])) ?
209 SD_EXTREM : SD_NULL; // sharp extremum found
211 for( ; x<src_w; ++x ) *ip++ = SD_NULL;
217 void DeScratchMain::remove_min_extrems_plane(int comp, int thresh)
219 uint8_t **rows = blurry->get_rows();
220 int d = config.min_width, d1 = d+1, wd = src_w - d1;
221 int bpp = 3, dsz = d * bpp;
222 int asym = config.asymmetry;
223 if( thresh > 0 ) { // black (low value) scratches
224 for( int y=0; y<src_h; ++y ) {
225 uint8_t *ip = inf + y*src_w;
226 uint8_t *dp = rows[y] + d1*bpp + comp;
227 for( int x=d1; x<wd; ++x,++ip,dp+=bpp ) {
228 if( *ip != SD_EXTREM ) continue;
229 uint8_t *lp = dp-dsz, *rp = dp+dsz;
230 if( (lp[0]-*dp) > thresh && (rp[0]-*dp) > thresh &&
231 (abs(lp[-bpp]-rp[+bpp]) <= asym) &&
232 ((lp[0]-lp[+bpp]) + (rp[0]-rp[-bpp]) >
233 (lp[-bpp]-lp[0]) + (rp[bpp]-rp[0])) )
234 *ip = SD_NULL; // sharp extremum found
238 else { // white (high value) scratches
239 for( int y=0; y<src_h; ++y ) {
240 uint8_t *ip = inf + y*src_w;
241 uint8_t *dp = rows[y] + d1*bpp + comp;
242 for( int x=d1; x<wd; ++x,++ip,dp+=bpp ) {
243 if( *ip != SD_EXTREM ) continue;
244 uint8_t *lp = dp-dsz, *rp = dp+dsz;
245 if( (lp[0]-*dp) < thresh && (rp[0]-*dp) < thresh &&
246 (abs(lp[-bpp]-rp[+bpp]) <= asym) &&
247 ((lp[0]-lp[+bpp]) + (rp[0]-rp[-bpp]) <
248 (lp[-bpp]-lp[0]) + (rp[bpp]-rp[0])) )
249 *ip = SD_NULL; // sharp extremum found
255 void DeScratchMain::close_gaps()
257 int len = config.gap_len * src_h / 100;
258 for( int y=len; y<src_h; ++y ) {
259 uint8_t *ip = inf + y*src_w;
260 for( int x=0; x<src_w; ++x,++ip ) {
261 if( *ip != SD_EXTREM ) continue;
262 uint8_t *bp = ip; // expand to previous lines in range
263 for( int i=len; --i>0; ) *(bp-=src_w) = SD_EXTREM;
268 void DeScratchMain::test_scratches()
271 int min_len = config.min_len * src_h / 100;
272 int max_len = config.max_len * src_h / 100;
273 int maxwidth = config.max_width*2 + 1;
274 int maxangle = config.max_angle;
276 for( int y=0; y<src_h; ++y ) {
277 for( int x=2; x<w2; ++x ) {
278 int ofs = y*src_w + x; // offset of first candidate
279 if( inf[ofs] != SD_EXTREM ) continue;
280 int ctr = ofs+1, nctr = ctr; // centered to inf for maxwidth=3
281 int hy = src_h - y, len;
282 for( len=0; len<hy; ++len ) { // cycle along inf
283 uint8_t *ip = inf + ctr;
284 int n = 0; // number good points in row
285 if( maxwidth >= 3 ) {
286 if( ip[-2] == SD_EXTREM ) { ip[-2] = SD_TESTED; nctr = ctr-2; ++n; }
287 if( ip[+2] == SD_EXTREM ) { ip[+2] = SD_TESTED; nctr = ctr+2; ++n; }
289 if( ip[-1] == SD_EXTREM ) { ip[-1] = SD_TESTED; nctr = ctr-1; ++n; }
290 if( ip[+1] == SD_EXTREM ) { ip[+1] = SD_TESTED; nctr = ctr+1; ++n; }
291 if( ip[+0] == SD_EXTREM ) { ip[+0] = SD_TESTED; nctr = ctr+0; ++n; }
292 // end of points tests, check result for row:
293 // check gap and angle, if no points or big angle, it is end of inf
294 if( !n || abs(nctr%src_w - x) >= maxwidth+len*maxangle/57 ) break;
295 ctr = nctr + src_w; // new center for next row test
297 int mask = len >= min_len && len <= max_len ? SD_GOOD : SD_REJECT;
298 ctr = ofs+1; nctr = ctr; // pass2
299 for( len=0; len<hy; ++len ) { // cycle along inf
300 uint8_t *ip = inf + ctr;
301 int n = 0; // number good points in row
302 if( maxwidth >= 3 ) {
303 if( ip[-2] == SD_TESTED ) { ip[-2] = mask; nctr = ctr-2; ++n; }
304 if( ip[+2] == SD_TESTED ) { ip[+2] = mask; nctr = ctr+2; ++n; }
306 if( ip[-1] == SD_TESTED ) { ip[-1] = mask; nctr = ctr-1; ++n; }
307 if( ip[+1] == SD_TESTED ) { ip[+1] = mask; nctr = ctr+1; ++n; }
308 if( ip[+0] == SD_TESTED ) { ip[+0] = mask; nctr = ctr+0; ++n; }
309 // end of points tests, check result for row:
310 // check gap and angle, if no points or big angle, it is end of inf
311 if( !n || abs(nctr%src_w - x) >= maxwidth+len*maxangle/57 ) break;
312 ctr = nctr + src_w; // new center for next row test
318 void DeScratchMain::mark_scratches_plane(int comp, int mask, int value)
320 int bpp = 3, dst_w = dst->get_w(), dst_h = dst->get_h();
321 uint8_t **rows = dst->get_rows();
322 for( int y=0; y<dst_h; ++y ) {
323 uint8_t *dp = rows[y] + comp;
324 uint8_t *ip = inf + y*src_w;
325 for( int x=0; x<dst_w; ++x,++ip,dp+=bpp ) {
326 if( *ip == mask ) *dp = value;
331 void DeScratchMain::remove_scratches_plane(int comp)
333 int r = config.max_width;
334 int fade = (config.ffade * 1024) / 100; // norm 2^10
335 int fade1 = 1024 - fade;
337 uint8_t **src_rows = src->get_rows();
338 uint8_t **dst_rows = dst->get_rows();
339 uint8_t **blur_rows = blurry->get_rows();
340 int bpp = 3, margin = r+config.border+2, wm = src_w-margin;
341 float nrm = 1. / 1024.f, nrm2r = nrm / (2*r*bpp);
343 for( int y=0; y<src_h; ++y ) {
345 uint8_t *inp = src_rows[y] + comp;
346 uint8_t *out = dst_rows[y] + comp;
347 uint8_t *blur = blur_rows[y] + comp;
348 for( int x=margin; x<wm; ++x ) {
349 uint8_t *dp = ip + x;
350 if( (dp[+0]&SD_GOOD) && !(dp[-1]&SD_GOOD) ) left = x;
351 if( left!=0 && (dp[+0]&SD_GOOD) && !(dp[+1]&SD_GOOD) ) { // the inf, left/right
353 int ctr = (left + right) / 2; // the inf center
354 int ls = ctr - r, rs = ctr + r;
355 int lt = ls - config.border - 1, rt = rs + config.border + 1;
356 lt *= bpp; ls *= bpp; rs *= bpp; rt *= bpp; // component index
357 for( int i=ls; i<=rs; i+=bpp ) { // across the inf
358 int lv = inp[i] + blur[lt] - blur[i];
359 int rv = inp[i] + blur[rt] - blur[i];
360 lv = fade*lv + fade1*inp[lt];
361 rv = fade*rv + fade1*inp[rt];
362 int v = nrm2r*(lv*(rs-i) + rv*(i-ls));
363 out[i] = CLIP(v,0,255);
365 for( int i=lt; i<ls; i+=bpp ) { // at left border
366 int lv = inp[i] + blur[lt] - blur[i];
367 int v = nrm*(fade*lv + fade1*inp[lt]);
368 out[i] = CLIP(v,0,255);
370 for( int i=rt; i>rs; i-=bpp ) { // at right border
371 int rv = inp[i] + blur[rt] - blur[i];
372 int v = nrm*(fade*rv + fade1*inp[rt]);
373 out[i] = CLIP(v,0,255);
382 void DeScratchMain::pass(int comp, int thresh)
384 // pass for current plane and current sign
385 get_extrems_plane(comp, thresh);
386 if( config.min_width > 1 )
387 remove_min_extrems_plane(comp, thresh);
391 int value = config.threshold > 0 ? 0 : 255;
392 mark_scratches_plane(comp, SD_GOOD, value);
393 mark_scratches_plane(comp, SD_REJECT, 127);
396 remove_scratches_plane(comp);
399 void DeScratchMain::blur(int scale)
401 int tw = src_w, th = (src_h / scale) & ~1;
403 (tmp_frame->get_w() != tw || tmp_frame->get_h() != th) ) {
404 delete tmp_frame; tmp_frame = 0;
407 tmp_frame = new VFrame(tw, th, BC_YUV888);
410 (blurry->get_w() != src_w || blurry->get_h() != src_h) ) {
411 delete blurry; blurry = 0;
414 blurry = new VFrame(src_w, src_h, BC_YUV888);
416 overlay_frame->overlay(tmp_frame, src,
417 0,0,src_w,src_h, 0,0,tw,th, 1.f, TRANSFER_NORMAL, LINEAR_LINEAR);
418 overlay_frame->overlay(blurry, tmp_frame,
419 0,0,tw,th, 0,0,src_w,src_h, 1.f, TRANSFER_NORMAL, CUBIC_CUBIC);
422 void DeScratchMain::copy(int comp)
424 uint8_t **src_rows = src->get_rows();
425 uint8_t **dst_rows = dst->get_rows();
426 for( int y=0; y<src_h; ++y ) {
427 uint8_t *sp = src_rows[y] + comp, *dp = dst_rows[y] + comp;
428 for( int x=0; x<src_w; ++x,sp+=3,dp+=3 ) *sp = *dp;
432 void DeScratchMain::plane_pass(int comp, int mode)
434 int threshold = config.threshold;
435 if( comp != 0 ) threshold /= 2; // fakey UV scaling
438 pass(comp, threshold);
440 case MODE_HIGH: // fall thru
441 threshold = -threshold;
442 case MODE_LOW: // fall thru
443 pass(comp, threshold);
448 int DeScratchMain::process_realtime(VFrame *input, VFrame *output)
450 load_configuration();
451 src_w = input->get_w();
452 src_h = input->get_h();
453 if( src_w >= 2*config.max_width+3 ) {
454 if( !overlay_frame ) {
455 int cpus = PluginClient::smp + 1;
456 if( cpus > 8 ) cpus = 8;
457 overlay_frame = new OverlayFrame(cpus);
459 if( src && (src->get_w() != src_w || src->get_h() != src_h) ) {
462 if( !src ) src = new VFrame(src_w, src_h, BC_YUV888);
463 src->transfer_from(input);
464 if( dst && (dst->get_w() != src_w || dst->get_h() != src_h) ) {
467 if( !dst ) dst = new VFrame(src_w, src_h, BC_YUV888);
469 int sz = src_w * src_h;
470 if( sz_inf != sz ) { delete [] inf; inf = 0; }
471 if( !inf ) inf = new uint8_t[sz_inf=sz];
472 blur(config.blur_len + 1);
473 plane_pass(0, config.mode_y);
474 plane_pass(1, config.mode_u);
475 plane_pass(2, config.mode_v);
476 output->transfer_from(dst);
481 void DeScratchMain::update_gui()
483 if( !thread ) return;
484 DeScratchWindow *window = (DeScratchWindow *)thread->get_window();
485 window->lock_window("DeScratchMain::update_gui");
486 if( load_configuration() )
487 window->update_gui();
488 window->unlock_window();
491 NEW_WINDOW_MACRO(DeScratchMain, DeScratchWindow)
494 DeScratchWindow::DeScratchWindow(DeScratchMain *plugin)
495 : PluginClientWindow(plugin, 512, 256, 512, 256, 0)
497 this->plugin = plugin;
500 DeScratchWindow::~DeScratchWindow()
504 void DeScratchWindow::create_objects()
507 plugin->load_configuration();
508 DeScratchConfig &config = plugin->config;
511 add_tool(title = new BC_Title(x, y, _("DeScratch:")));
512 y += title->get_h() + 5;
513 int x1 = x, x2 = get_w()/2;
514 add_tool(title = new BC_Title(x1=x, y, _("threshold:")));
515 x1 += title->get_w()+16;
516 add_tool(threshold = new DeScratchISlider(this, x1, y, x2-x1-10, 0,64, &config.threshold));
517 add_tool(title = new BC_Title(x1=x2, y, _("asymmetry:")));
518 x1 += title->get_w()+16;
519 add_tool(asymmetry = new DeScratchISlider(this, x1, y, get_w()-x1-15, 0,64, &config.asymmetry));
520 y += threshold->get_h() + 10;
522 add_tool(title = new BC_Title(x1=x, y, _("Mode:")));
523 x1 += title->get_w()+16;
524 add_tool(title = new BC_Title(x1, y, _("y:")));
525 int w1 = title->get_w()+16;
526 add_tool(y_mode = new DeScratchMode(this, (x1+=w1), y, &config.mode_y));
527 y_mode->create_objects(); x1 += y_mode->get_w()+16;
528 add_tool(title = new BC_Title(x1, y, _("u:")));
529 add_tool(u_mode = new DeScratchMode(this, (x1+=w1), y, &config.mode_u));
530 u_mode->create_objects(); x1 += u_mode->get_w()+16;
531 add_tool(title = new BC_Title(x1, y, _("v:")));
532 add_tool(v_mode = new DeScratchMode(this, (x1+=w1), y, &config.mode_v));
533 v_mode->create_objects();
534 y += y_mode->get_h() + 10;
536 add_tool(title = new BC_Title(x1=x, y, _("width:")));
537 w1 = title->get_w()+16; x1 += w1;
538 add_tool(title = new BC_Title(x1, y, _("min:")));
539 x1 += title->get_w()+16;
540 add_tool(min_width = new DeScratchISlider(this, x1, y, x2-x1-10, 0,16, &config.min_width));
541 add_tool(title = new BC_Title(x1=x2, y, _("max:")));
542 x1 += title->get_w()+16;
543 add_tool(max_width = new DeScratchISlider(this, x1, y, get_w()-x1-15, 0,16, &config.max_width));
544 y += min_width->get_h() + 10;
546 add_tool(title = new BC_Title(x1=x, y, _("len:")));
547 w1 = title->get_w()+16; x1 += w1;
548 add_tool(title = new BC_Title(x1, y, _("min:")));
549 x1 += title->get_w()+16;
550 add_tool(min_len = new DeScratchFSlider(this, x1, y, x2-x1-10, 0.0,100.0, &config.min_len));
551 add_tool(title = new BC_Title(x1=x2, y, _("max:")));
552 x1 += title->get_w()+16;
553 add_tool(max_len = new DeScratchFSlider(this, x1, y, get_w()-x1-15, 0.0,100.0, &config.max_len));
554 y += min_len->get_h() + 10;
556 add_tool(title = new BC_Title(x1=x, y, _("len:")));
557 w1 = title->get_w()+16; x1 += w1;
558 add_tool(title = new BC_Title(x1, y, _("blur:")));
559 x1 += title->get_w()+16;
560 add_tool(blur_len = new DeScratchISlider(this, x1, y, x2-x1-10, 0,16, &config.blur_len));
561 add_tool(title = new BC_Title(x1=x2, y, _("gap:")));
562 x1 += title->get_w()+16;
563 add_tool(gap_len = new DeScratchFSlider(this, x1, y, get_w()-x1-15, 0.0,100.0, &config.gap_len));
564 y += blur_len->get_h() + 10;
566 add_tool(title = new BC_Title(x1=x, y, _("max angle:")));
567 w1 = title->get_w()+16; x1 += w1;
568 add_tool(max_angle = new DeScratchFSlider(this, x1, y, x2-x1-10, 0.0,90.0, &config.max_angle));
569 add_tool(title = new BC_Title(x1=x2, y, _("fade:")));
570 x1 += title->get_w()+16;
571 add_tool(ffade = new DeScratchFSlider(this, x1, y, get_w()-x1-15, 0.0,100.0, &config.ffade));
572 y += max_angle->get_h() + 10;
574 add_tool(title = new BC_Title(x1=x, y, _("border:")));
575 x1 += title->get_w()+16;
576 add_tool(border = new DeScratchISlider(this, x1, y, x2-x1-10, 0,16, &config.border));
577 add_tool(mark = new DeScratchMark(this, x1=x2, y));
578 w1 = DeScratchReset::calculate_w(this, _("Reset"));
579 add_tool(reset = new DeScratchReset(this, get_w()-w1-15, y));
584 void DeScratchWindow::update_gui()
586 DeScratchConfig &config = plugin->config;
587 y_mode->update(config.mode_y);
588 u_mode->update(config.mode_u);
589 v_mode->update(config.mode_v);
590 min_width->update(config.min_width);
591 max_width->update(config.max_width);
592 min_len->update(config.min_len);
593 max_len->update(config.max_len);
594 blur_len->update(config.blur_len);
595 gap_len->update(config.gap_len);
596 max_angle->update(config.max_angle);
597 ffade->update(config.ffade);
598 mark->update(config.mark);
602 DeScratchModeItem::DeScratchModeItem(DeScratchMode *popup, int type, const char *text)
609 DeScratchModeItem::~DeScratchModeItem()
613 int DeScratchModeItem::handle_event()
616 return popup->handle_event();
619 DeScratchMode::DeScratchMode(DeScratchWindow *win, int x, int y, int *value)
620 : BC_PopupMenu(x, y, 64, "", 1)
626 DeScratchMode::~DeScratchMode()
630 void DeScratchMode::create_objects()
632 add_item(new DeScratchModeItem(this, MODE_NONE, _("None")));
633 add_item(new DeScratchModeItem(this, MODE_LOW, _("Low")));
634 add_item(new DeScratchModeItem(this, MODE_HIGH, _("High")));
635 add_item(new DeScratchModeItem(this, MODE_ALL, _("All")));
639 int DeScratchMode::handle_event()
641 win->plugin->send_configure_change();
645 void DeScratchMode::update(int v)
647 set_value(*value = v);
650 void DeScratchMode::set_value(int v)
652 int i = total_items();
653 while( --i >= 0 && ((DeScratchModeItem*)get_item(i))->type != v );
654 if( i >= 0 ) set_text(get_item(i)->get_text());
657 DeScratchISlider::DeScratchISlider(DeScratchWindow *win,
658 int x, int y, int w, int min, int max, int *output)
659 : BC_ISlider(x, y, 0, w, w, min, max, *output)
662 this->output = output;
665 DeScratchISlider::~DeScratchISlider()
669 int DeScratchISlider::handle_event()
671 *output = get_value();
672 win->plugin->send_configure_change();
676 DeScratchFSlider::DeScratchFSlider(DeScratchWindow *win,
677 int x, int y, int w, float min, float max, float *output)
678 : BC_FSlider(x, y, 0, w, w, min, max, *output)
681 this->output = output;
684 DeScratchFSlider::~DeScratchFSlider()
688 int DeScratchFSlider::handle_event()
690 *output = get_value();
691 win->plugin->send_configure_change();
695 DeScratchMark::DeScratchMark(DeScratchWindow *win, int x, int y)
696 : BC_CheckBox(x, y, &win->plugin->config.mark, _("Mark"))
701 DeScratchMark::~DeScratchMark()
705 int DeScratchMark::handle_event()
707 int ret = BC_CheckBox::handle_event();
708 win->plugin->send_configure_change();
712 DeScratchReset::DeScratchReset(DeScratchWindow *win, int x, int y)
713 : BC_GenericButton(x, y, _("Reset"))
718 int DeScratchReset::handle_event()
720 win->plugin->config.reset();
722 win->plugin->send_configure_change();