Subversion Repositories DIN Is Noise

Rev

Rev 2105 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1787 jag 1
/*
1799 jag 2
* spinner2.h
2302 jag 3
* DIN Is Noise is copyright (c) 2006-2025 Jagannathan Sampath
1787 jag 4
* For more information, please visit http://dinisnoise.org/
5
*/
6
 
7
 
8
#ifndef __spinner22
9
#define __spinner22
10
 
11
#include "input.h"
12
#include "font.h"
13
#include "widget.h"
14
#include "label.h"
15
#include "arrow_button.h"
16
#include "checkbutton.h"
17
#include "field.h"
18
#include "utils.h"
19
#include "mouse_slider.h"
20
#include "tokenizer.h"
21
 
22
#include <string>
23
#include <typeinfo>
24
 
25
extern void abort_selectors ();
26
extern int SPACING;
27
extern const char spc;
28
extern char BUFFER[];
29
 
30
extern button& detach_from_menu (widget** wa, int n, int posx, int posy);
31
extern void attach_to_menu (widget** wa, int n);
32
 
33
template <typename T> struct spinner2 : widget, state_listener, change_listener<field>, typing_listener, mouse_slider_listener, nullt {
34
 
35
  template <typename Q> struct re_pre_lis : click_listener {
36
    spinner2<Q>& sp;
37
    click_listener* pre;
38
    re_pre_lis (spinner2<Q>& _sp, click_listener* _pre) : sp (_sp), pre (_pre) {}
39
    void clicked (button& b) {
40
      widget* w[] = {&sp};
41
      attach_to_menu (w, 1);
42
      LISTEN (sp.dec, pre)
43
      LISTEN (sp.inc, pre)
44
      if (sp.null) sp.set_value (0);
45
    }
46
  };
47
 
48
  template <typename Q> struct pre_lis : click_listener {
49
    spinner2<Q>& sp;
50
    click_listener *decl, *incl;
51
    pre_lis (spinner2<Q>& _sp, click_listener* _decl, click_listener* _incl) : sp (_sp), decl (_decl), incl (_incl) {}
52
    void clicked (button& b) {
53
      sp.dec.set_listener (decl);
54
      sp.inc.set_listener (incl);
55
      widget* wa [] = {&sp};
56
      button& b_close = detach_from_menu (wa, 1, sp.dec.posx, sp.lbl.posy);
57
      LISTEN (b_close, &sp.reprel);
58
      b.call_listener ();
59
    }
60
  };
61
 
62
  template <typename Q> struct dec_lis : click_listener {
63
    spinner2<Q>& sp;
64
    dec_lis (spinner2<Q>& _sp) : sp (_sp) {}
65
    void clicked (button& b) {sp.decrease ();}
66
  };
67
 
68
  template <typename Q> struct inc_lis : click_listener {
69
    spinner2<Q>& sp;
70
    inc_lis (spinner2<Q>& _sp) : sp (_sp) {}
71
    void clicked (button& b) {sp.increase ();}
72
  };
73
 
74
  template <typename Q> struct more_lis : click_listener {
75
    spinner2<Q>& sp;
76
    more_lis (spinner2<Q>& _sp) : sp (_sp) {}
77
    void clicked (button& b) {sp.toggle_delta();}
78
  };
79
 
80
  template <typename Q> struct delta_lis : change_listener<field> {
81
    spinner2<Q>* sp;
82
    delta_lis (spinner2<Q>* _sp = 0) : sp (_sp) {}
83
    void changed (field& f) {
84
      sp->delta0 = sp->delta = f;
85
      sp->call_listener (1, f);
86
    }
87
  };
88
 
89
  template <typename Q> struct variance_lis : change_listener<field> {
90
    spinner2<Q>* sp;
91
    variance_lis (spinner2<Q>* _sp = 0) : sp (_sp) {}
92
    void changed (field& f) {
93
      tokenizer tz (f.text);
94
      float mn, mx; tz >> mn >> mx;
95
      sp->variance.setrd (mn, mx);
1852 jag 96
      sp->set_pos (sp->posx, sp->posy);
1787 jag 97
      sp->call_listener (2, f);
98
    }
99
  };
100
 
101
  checkbutton lbl; // main label
102
 
103
  label backlbl; // back label, after field
104
  int draw_backlbl;
105
 
106
  // increase/decrease buttons
107
  arrow_button dec, inc;
1805 jag 108
  void updowndecinc () {
109
    dec.dir = arrow_button::down;
110
    inc.dir = arrow_button::up;
111
  }
112
 
1787 jag 113
  dec_lis<T> decl;
114
  inc_lis<T> incl;
115
  int dir; // < 0 = decrease, > 0 = increase
116
 
117
  // pre listeners so can detach from menu
118
  int pre;
119
  pre_lis<T> prel;
120
  re_pre_lis<T> reprel;
121
 
122
  // value
123
  field f_value;
124
  T value;
125
  T lastv;
126
 
127
  int draw_more;
128
  arrow_button more;
129
  more_lis<T> mol;
130
 
131
  label l_delta;
132
  field f_delta;
133
  delta_lis<T> dell;
134
 
135
  struct variancet {
136
    checkbutton cb;
137
    label lbl;
138
    field fld;
139
    variance_lis<T> lis;
140
    rnd<float> rd;
141
    int ui;
142
    variancet (spinner2<T>* sp = 0) : lis (sp) {
2084 jag 143
      lbl.set_text (" ~ ");
1787 jag 144
      fld.change_lsnr = &lis;
145
      fld.expr = 0;
146
      cb.set_text ("~");
147
      ui = 1;
148
    }
149
    void setrd (float s, float t) {
150
      // assume s,t in %
151
      s /= 100.0f;
152
      t /= 100.0f;
153
      rd.set (s, t);
154
    }
155
    void setfld () {
156
      int i = 100 * rd.min, j = 100 * rd.max;
157
      sprintf (BUFFER, "%d %d", i, j);
158
      fld.set_text (BUFFER);
159
    }
160
  } variance;
161
 
1957 jag 162
  T variedval () {
163
    return variance.rd () * value;
164
  }
165
 
1787 jag 166
  int limits;
167
  T lo, hi;
168
 
169
  void set_limits (T _lo, T _hi) {
170
    limits = 1;
171
    lo = _lo;
172
    hi = _hi;
173
  }
174
 
175
  change_listener<field> *lis[3]; // 0 - f_value, 1 - f_delta, 2 - variance.fld = null
176
 
177
  spinner2 (const std::string& _name = "unknown") :
178
  decl(*this), incl(*this),
179
  pre(1),
180
  prel (*this, &decl, &incl),
181
  reprel (*this, &prel),
182
  mol(*this),
183
  l_delta ("+-"),  dell(this), variance(this) {
184
 
185
#ifndef __WIDGET_MOVE__
186
    lbl.set_listener (this);
187
#endif
188
 
189
    widget* chld [] = {
190
      this,
191
      &dec,
192
      &inc,
193
      &f_value,
194
      &more,
195
      &l_delta,
196
      &f_delta,
197
      &variance.cb,
198
      &variance.lbl,
199
      &variance.fld
200
    };
201
    for (int i = 0; i < 10; ++i) lbl.add_child (chld[i]);
202
 
203
    dec.set_dir (arrow_button::left);
204
    inc.set_dir (arrow_button::right);
205
    inc.click_repeat = 1;
206
    dec.click_repeat = 1;
207
 
208
    dir = 1;
209
    draw_more = 1;
210
    more.set_dir (arrow_button::right);
211
 
212
    set_pre (pre);
213
 
214
    LISTEN (more,&mol)
215
 
216
    l_delta.hide ();
217
    f_delta.hide ();
218
 
219
    lastv = value = 0;
220
 
221
    f_value.change_lsnr = this;
222
    f_delta.change_lsnr = &dell;
223
 
224
 
1852 jag 225
    f_value.typing_lsnr = variance.fld.typing_lsnr = this;
1787 jag 226
 
227
    lis [0]=lis[1]=lis[2]=0;
228
 
229
    limits = 0;
230
    lo = hi = 0;
231
 
232
    // see field::call_listener ()
233
    const std::type_info& ti = typeid (T);
234
    std::string tn (ti.name());
235
    if (tn == "i")
236
      f_value.type = f_delta.type = "int";
237
    else if (tn == "f")
238
      f_value.type = f_delta.type = "double";
239
 
240
    draw_backlbl = 0;
241
 
2036 jag 242
    vary = &variance.cb;
1787 jag 243
 
244
  }
245
 
246
  void set_pos (int x, int y) {
247
    widget::set_pos (x, y);
248
    int i = 0;
249
    if (draw_more == 0 || variance.ui == 0) i = 1;
1838 jag 250
    widget* w [] = {&variance.cb, &lbl, &dec, &inc, &f_value, &more, &variance.lbl, &variance.fld, &l_delta, &f_delta, };
251
    int xshift [] = {0, 0, 0, -1, 1, -1, 0, 0, 5, 1};
1787 jag 252
    int lft [] = {0, 0, fnt.lift, fnt.lift, 0, fnt.lift, 0, 0, 0, 0};
253
    for (; i < 10; ++i) {
254
      x += xshift [i];
255
      widget* wi = w[i];
256
      wi->set_pos (x, y + lft[i]);
257
      advance_right (x, *wi, SPACING);
258
    }
259
    set_pos_backlbl ();
260
  }
261
 
262
  void set_pos_backlbl () {
263
    if (draw_backlbl) {
264
      widget* w = 0;
1838 jag 265
      if (f_delta.visible) w = &f_delta;
1787 jag 266
      else if (draw_more) w = &more;
267
      else w = &f_value;
268
      backlbl.set_pos (w->extents.right + SPACING, w->extents.bottom - fnt.lift);
269
    }
270
  }
271
 
272
  void update () {
273
    lbl.update ();
274
    backlbl.update ();
275
    l_delta.update ();
276
    f_value.update ();
277
    f_delta.update ();
278
    variance.cb.update ();
279
    variance.lbl.update ();
280
    variance.fld.update ();
281
    set_pos (posx, posy);
282
    inc.update ();
283
    dec.update ();
284
    more.update ();
285
  }
286
 
287
  void toggle_delta () {
288
    if (more.dir == arrow_button::right) {
289
      l_delta.show ();
290
      f_delta.show ();
291
      if (variance.ui) {
292
        variance.lbl.show ();
293
        variance.fld.show ();
294
      }
295
      more.set_dir (arrow_button::left);
296
    } else {
297
      l_delta.hide ();
298
      f_delta.hide ();
299
      if (variance.ui) {
300
        variance.lbl.hide ();
301
        variance.fld.hide ();
302
      }
303
      more.set_dir (arrow_button::right);
304
    }
305
    set_pos_backlbl ();
306
    abort_selectors ();
307
  }
308
 
2105 jag 309
  void change_value (int _dir, double scl = 1.0, int upd = 0) {
310
    dir = _dir;
311
    delta = scl * delta0;
312
    value += dir_delta ();
313
    if (limits) clamp<T>(lo, value, hi);
314
    if (pre == 0 || upd) {
315
      f_value = value;
316
      set_pos (posx, posy);
317
    }
318
    call_listener (0, f_value);
1787 jag 319
  }
320
 
2105 jag 321
  spinner2<T>& operator++ () {
322
    change_value (+1, 1, 1);
323
    return *this;
324
  }
325
 
326
  spinner2<T>& operator-- () {
327
    change_value (-1, 1, 1);
328
    return *this;
329
  }
330
 
1787 jag 331
  void increase () {
2105 jag 332
    change_value (+1, 1, 1);
1787 jag 333
  }
334
 
2105 jag 335
  void decrease () {
336
    change_value (-1, 1, 1);
1787 jag 337
  }
338
 
2105 jag 339
  void changed (field& f) {
1787 jag 340
 
2105 jag 341
    if (limits) {
342
      T v = f;
343
      if (clamp<T>(lo, v, hi)) f = v;
344
      value = v;
345
    } else
346
      value = f;
347
 
348
    delta = value - lastv;
349
    if (delta > 0) {
350
      dir = 1;
351
    } else {
352
      dir = -1;
353
      delta = -delta;
354
    }
355
    lastv = value;
356
 
357
    set_pos (posx, posy);
358
 
359
    call_listener (0, f);
360
 
361
  }
362
 
1787 jag 363
  void changed (checkbutton& cb) {
364
    if (orient == NONE) {
365
      cb.turn_off (0);
366
      if (mouse_slider0.active) cant_mouse_slide ();
367
    } else {
368
      if (cb.state) mouse_slider0.add (this); else mouse_slider0.remove (this);
369
      if (SHIFT == 0) activate_mouse_slider ();
370
    }
371
  }
372
 
373
  void call_listener (int i, field& f) {
374
    change_listener<field>* lisi = lis[i];
375
    if (lisi) lisi->changed (f);
376
  }
377
 
378
  void typing (field& f) {
379
    f.update ();
380
    set_pos (posx, posy);
381
  }
382
 
383
  void moused (int _dir, double scl) {
384
    change_value (_dir, scl);
385
  }
386
 
387
  void after_slide () {
388
    lbl.turn_off (DONT_CALL_LISTENER);
389
    set_delta (delta0 * mouse_slider0.scale.value);
2105 jag 390
    if (null)
391
      set_value (0);
392
    else {
393
      if (pre) set_value (value);
394
    }
1787 jag 395
  }
396
 
397
  void draw () {
398
    glColor3f (clr.r, clr.g, clr.b);
399
    widget* w [] = {&lbl, &dec, &inc, &f_value};
400
    for (int i = 0, j = 4; i < j; ++i) w[i]->draw ();
401
    if (variance.ui) variance.cb.draw ();
402
    if (draw_more) {
403
      more.draw ();
404
      if (more.dir == arrow_button::left) {
405
        l_delta.draw ();
406
        f_delta.draw ();
407
        if (variance.ui) {
408
          variance.lbl.draw ();
409
          variance.fld.draw ();
410
        }
411
      }
412
    }
413
    if (draw_backlbl) backlbl.draw ();
414
  }
415
 
416
  void set_value (T t) {
417
    value = t;
418
    lastv = value;
419
    f_value = value;
420
    set_pos (posx, posy);
421
  }
422
 
423
  void set_delta (T t) {
424
    delta0 = delta = t;
425
    f_delta = (T) delta0;
426
    set_pos (posx, posy);
427
  }
428
 
429
  void set_listener (change_listener<field>* _lis, int id = 0) {
430
    lis [id] = _lis;
431
  }
432
 
433
  void set_text (const std::string& l, const std::string& bl = "") {
434
    lbl.set_text (l);
435
    set_name (l);
436
    mouse_slider_listener::name = l;
437
    if (bl != "") {
438
      backlbl.set_text (bl);
439
      draw_backlbl = 1;
440
    }
441
  }
442
 
443
  void set_moveable (int m, int mc = 0, int* pmb = &lmb) {lbl.set_moveable (m, mc, pmb);}
444
 
445
  int handle_input () {
446
 
447
    int r = lbl.handle_input ();
448
    if (r) return r;
449
 
450
    if (variance.ui && variance.cb.handle_input()) return 1;
451
 
452
    int d1 = 0, i1 = 0, m1 = 0;
453
    d1 = dec.handle_input ();
454
    if (d1 == 0) {
455
      i1 = inc.handle_input ();
456
      if (i1 == 0)
457
        m1 = more.handle_input ();
458
    }
459
 
460
    int c = d1 | i1 | m1;
461
    if (c) return c;
462
 
463
    int s = f_value.handle_input ();
464
    if (s) return s;
465
 
466
    if (more.dir == arrow_button::left) {
467
      int fd = f_delta.handle_input ();
468
      if (fd) return fd;
469
      if (variance.ui) {
470
        if (variance.fld.handle_input()) return 1;
471
      }
472
    }
473
 
474
    return 0;
475
 
476
  }
477
 
478
  inline T dir_delta () {
479
    return dir * delta;
480
  }
481
 
482
  inline T operator() () {
483
    if (variance.cb.state) return ( variance.rd () * value ); else return value;
484
  }
485
 
486
  void set (const std::string& t, T d, T lmin, T lmax, change_listener<field>* l = 0, int _pre = 1) {
487
    set_text (t);
488
    set_delta (d);
489
    set_limits (lmin, lmax);
490
    set_listener (l);
491
    set_pre (_pre);
492
  }
493
 
494
  void set (const std::string& t, T d, change_listener<field>* l) {
495
    set_text (t);
496
    set_delta (d);
497
    set_listener (l);
498
  }
499
 
500
  void set (T d, T lmin, T lmax, change_listener<field>* l) {
501
    set_delta (d);
502
    set_limits (lmin, lmax);
503
    set_listener (l);
504
  }
505
 
506
  void set_pre (int _pre) {
507
    pre = _pre;
508
    if (pre) {
509
      LISTEN (dec,&prel)
510
      LISTEN (inc,&prel)
511
    } else {
512
      LISTEN (dec,&decl)
513
      LISTEN (inc,&incl)
514
    }
515
  }
516
 
517
};
518
 
1859 jag 519
template<> inline int spinner2<int>::operator() () {
520
  if (variance.cb.state) return ( variance.rd () * value + 0.5f); else return value;
521
}
522
 
1787 jag 523
template <typename T> ifstream& operator>> (ifstream& f, spinner2<T>& spn) {
524
 
525
  int state;
526
  float minn, maxx;
527
 
528
  f >> state >> minn >> maxx;
529
 
530
  spn.variance.cb.set_state (state, DONT_CALL_LISTENER);
531
  spn.variance.rd.set (minn, maxx);
532
  spn.variance.setfld ();
533
 
534
  return f;
535
 
536
}
537
 
538
template <typename T> ofstream& operator<< (ofstream& f, spinner2<T>& spn) {
539
  f << spn.variance.cb.state << spc << spn.variance.rd.min << spc << spn.variance.rd.max << spc;
540
  return f;
541
}
542
 
1852 jag 543
template <class P, class Q> Q getval (spinner2<P>& sp, Q& src) {
1849 jag 544
  typename spinner2<P>::variancet& var = sp.variance;
1852 jag 545
  if (var.cb.state)
546
    return var.rd () * src;
547
  else
548
    return src;
1849 jag 549
}
1787 jag 550
#endif