zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

WidgetPDial.cpp (7812B)


      1 /*
      2   ZynAddSubFX - a software synthesizer
      3 
      4   WidgetPDial.cpp - Fl_Dial With Custom Behavior
      5   Copyright (C) 2016 Mark McCurry
      6 
      7   This program is free software; you can redistribute it and/or
      8   modify it under the terms of the GNU General Public License
      9   as published by the Free Software Foundation; either version 2
     10   of the License, or (at your option) any later version.
     11 */
     12 // generated by Fast Light User Interface Designer (fluid) version 1.0107f
     13 
     14 #include <cmath>
     15 #include <FL/fl_draw.H>
     16 #include "../Misc/Util.h"
     17 #include "WidgetPDial.h"
     18 //Copyright (c) 2003-2005 Nasca Octavian Paul
     19 //License: GNU GPL version 2 or later
     20 
     21 
     22 //static int numobj = 0;
     23 
     24 static float identity(float value)
     25 {
     26     return value;
     27 }
     28 
     29 WidgetPDial::WidgetPDial(int x, int y, int w, int h, const char *label)
     30     :Fl_Dial(x, y, w, h, label), reset_value(0), integer_step(true),
     31      use_rounding(false),  oldvalue(0.0f), pos(false), textset(false),
     32      transform(identity)
     33 {
     34     //cout << "[" << label << "] There are now " << ++numobj << endl;
     35     Fl_Group *save = Fl_Group::current();
     36     tipwin = new TipWin();
     37     tipwin->hide();
     38     Fl_Group::current(save);
     39 }
     40 
     41 WidgetPDial::~WidgetPDial()
     42 {
     43     //cout << "There are now " << --numobj << endl;
     44     delete tipwin;
     45 }
     46 
     47 void WidgetPDial::set_rounding(unsigned int digits)
     48 {
     49     tipwin->set_rounding(digits);
     50 }
     51 
     52 #define MOD_MASK (FL_CTRL | FL_SHIFT)
     53 
     54 int WidgetPDial::handle(int event)
     55 {
     56     double dragsize, min = minimum(), max = maximum(), result;
     57     int dy;
     58 
     59     if (event == FL_RELEASE && Fl::event_clicks() == 1) {
     60         Fl::event_clicks(0);
     61         value(reset_value);
     62         tipwin->hide();
     63         value_damage();
     64         if (this->when() != 0)
     65             do_callback();
     66         return 1;
     67     }
     68 
     69     int old_mod_state;
     70 
     71     switch(event) {
     72         case FL_PUSH:
     73             mod_state = Fl::event_state() & MOD_MASK;
     74             if (!use_rounding) {
     75                 if (integer_step)
     76                     set_rounding(0);
     77                 else if (mod_state == MOD_MASK)
     78                     set_rounding(5);
     79                 else if (mod_state == FL_SHIFT)
     80                     set_rounding(4);
     81                 else
     82                     set_rounding((Fl::event_button3() || mod_state & FL_CTRL)
     83                                  ? 3 : 2);
     84             }
     85             oldvalue = value();
     86             old_y = Fl::event_y();
     87             // fall through
     88         case FL_DRAG:
     89             getPos();
     90             old_mod_state = mod_state;
     91             mod_state = Fl::event_state() & MOD_MASK;
     92             if (old_mod_state != mod_state) {
     93                 oldvalue = value();
     94                 old_y = Fl::event_y();
     95                 if (!use_rounding) {
     96                     if (integer_step)
     97                         set_rounding(0);
     98                     else if (mod_state == MOD_MASK)
     99                         set_rounding(5);
    100                     else if (mod_state == FL_SHIFT)
    101                         set_rounding(4);
    102                     else
    103                         set_rounding((Fl::event_button3() ||
    104                                       mod_state & FL_CTRL)
    105                                      ? 3 : 2);
    106                 }
    107                 break;
    108             }
    109             dy = old_y - Fl::event_y();
    110             if (dy < -1 || dy > 1)
    111                 Fl::event_clicks(0);
    112 
    113             if (!integer_step && mod_state == MOD_MASK)
    114                 dragsize = 200000.0f;
    115             else if (!integer_step && mod_state == FL_SHIFT)
    116                 dragsize = 20000.0f;
    117             else
    118                 dragsize = (Fl::event_button3() || mod_state & MOD_MASK)
    119                     ? 1000.0f : 200.0f;
    120 
    121             value(clamp(oldvalue + dy / dragsize * (max - min)));
    122             tipwin->showValue(transform(value()));
    123             value_damage();
    124             if(this->when() != 0)
    125                 do_callback();
    126             return 1;
    127         case FL_MOUSEWHEEL:
    128             if (Fl::event_buttons() || Fl::belowmouse() != this)
    129                 return 1;
    130             mod_state = Fl::event_state() & MOD_MASK;
    131             dy = - Fl::event_dy();
    132 
    133             if (integer_step) {
    134                 if (!use_rounding) set_rounding(0);
    135                 result = (int)(value() +
    136                                dy * ((Fl::event_ctrl() ||
    137                                       Fl::event_shift()) ? 1 : 8));
    138             } else {
    139                 float dragsize;
    140                 if (mod_state == MOD_MASK) {
    141                     dragsize = 100000.0;
    142                     if (!use_rounding) set_rounding(5);
    143                 } else if (mod_state == FL_SHIFT) {
    144                     dragsize = 10000.0;
    145                     if (!use_rounding) set_rounding(4);
    146                 } else if (mod_state == FL_CTRL) {
    147                     dragsize = 1000.0;
    148                     if (!use_rounding) set_rounding(3);
    149                 } else {
    150                     dragsize = 100.0;
    151                     if (!use_rounding) set_rounding(2);
    152                 }
    153                 result = value() + dy / dragsize * (max - min);
    154             }
    155             value(clamp(result));
    156 
    157             tipwin->showValue(transform(value()));
    158             value_damage();
    159             if(this->when() != 0)
    160                 do_callback();
    161             return 1;
    162         case FL_ENTER:
    163             getPos();
    164             tipwin->showText();
    165             return 1;
    166         case FL_HIDE:
    167         case FL_LEAVE:
    168             tipwin->hide();
    169             resetPos();
    170             break;
    171         case FL_RELEASE:
    172             if (integer_step) {
    173                 float rounded = floorf(value() + 0.5);
    174                 value(clamp(rounded));
    175             }
    176             tipwin->hide();
    177             resetPos();
    178             if(this->when() == 0)
    179                 do_callback();
    180             return 1;
    181     }
    182     return 0;
    183 //#endif
    184 }
    185 
    186 void WidgetPDial::draw()
    187 {
    188 #ifdef NTK_GUI
    189     box( FL_NO_BOX );
    190 
    191     Fl_Dial::draw();
    192 
    193     return;
    194 #else
    195     const int cx = x(), cy = y(), sx = w(), sy = h();
    196     const double a1 = angle1(), a2 = angle2();
    197     const double val = (value() - minimum()) / (maximum() - minimum());
    198     // even radius produces less artifacts if no antialiasing is avail
    199     const int rad = (sx > sy ? sy : sx) &~1;
    200 
    201     /* clears the button background */
    202     pdialcolor(160, 160, 160);
    203     fl_pie(cx - 2, cy - 2, rad + 4, rad + 4, 0, 360);
    204 
    205     /* dark outline */
    206     fl_color(60, 60, 60);
    207     fl_pie(cx - 1, cy - 1, rad + 2, rad + 2, 0, 360);
    208 
    209     /* Draws the button faceplate, min/max */
    210     pdialcolor(110, 110, 115);
    211     fl_pie(cx, cy, rad, rad, 270 - a2, 270 - a1);
    212 
    213     /* knob center */
    214     if (rad > 8) {
    215         pdialcolor(140, 140, 145);
    216         fl_pie(cx + 4, cy + 4, rad - 8, rad - 8, 0, 360);
    217     }
    218 
    219     /* value circle */
    220     double a = -(a2 - a1) * val - a1;
    221     fl_line_style(0, 2, 0);
    222     pdialcolor(0, 200, 0);
    223     fl_arc(cx + 1, cy + 1, rad - 2, rad - 2, a - 90, a1 - 180);
    224     fl_line_style(0);
    225 
    226     /* draw value line */
    227     int ll = rad/4;
    228     if (ll < 2) ll = 2;
    229 
    230     fl_push_matrix();
    231 
    232     fl_translate(cx + rad / 2, cy + rad / 2);
    233     fl_rotate(a - 90.0f);
    234 
    235     fl_translate(rad / 2, 0);
    236 
    237     fl_begin_polygon();
    238     pdialcolor(0, 0, 0);
    239     fl_vertex(-ll, 0);
    240     fl_vertex(0, 0);
    241     fl_end_polygon();
    242 
    243     fl_pop_matrix();
    244 
    245 #endif
    246 }
    247 
    248 void WidgetPDial::pdialcolor(int r, int g, int b)
    249 {
    250     if(active_r())
    251         fl_color(r, g, b);
    252     else
    253         fl_color(160 - (160 - r) / 3, 160 - (160 - b) / 3, 160 - (160 - b) / 3);
    254 }
    255 
    256 void WidgetPDial::tooltip(const char *c)
    257 {
    258     tipwin->setText(c);
    259     textset = true;
    260 }
    261 
    262 void WidgetPDial::getPos()
    263 {
    264     if(!pos) {
    265         tipwin->position(Fl::event_x_root(), Fl::event_y_root() + 20);
    266         pos = true;
    267     }
    268 }
    269 
    270 void WidgetPDial::resetPos()
    271 {
    272     pos = false;
    273 }
    274 
    275 void WidgetPDial::set_transform(float (*transformer)(float))
    276 {
    277     transform = transformer;
    278     use_rounding = true;
    279 }