zynaddsubfx

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

Fl_Osc_Slider.cpp (8082B)


      1 /*
      2   ZynAddSubFX - a software synthesizer
      3 
      4   Fl_Osc_Slider.cpp - OSC Based Slider
      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 #include <FL/Fl.H>
     13 #include "Fl_Osc_Slider.H"
     14 #include "Fl_Osc_Interface.h"
     15 #include "Fl_Osc_Pane.H"
     16 #include <cstdlib>
     17 #include <cstring>
     18 #include <cmath>
     19 #include <cassert>
     20 #include <sstream>
     21 #include "../Misc/Util.h"
     22 
     23 static double min__(double a, double b)
     24 {
     25     return a<b?a:b;
     26 }
     27 
     28 Fl_Osc_Slider::Fl_Osc_Slider(int X, int Y, int W, int H, const char *label)
     29     :Fl_Slider(X,Y,W,H,label), Fl_Osc_Widget(this), reset_value(0),
     30      cb_data(NULL, NULL), just_pushed(true)
     31 {
     32     //bounds(0.0f,1.0f);
     33     Fl_Slider::callback(Fl_Osc_Slider::_cb);
     34 }
     35 
     36 void Fl_Osc_Slider::init(std::string path_, char type_)
     37 {
     38     osc_type = type_;
     39     ext = path_;
     40     oscRegister(ext.c_str());
     41 }
     42 
     43 Fl_Osc_Slider::~Fl_Osc_Slider(void)
     44 {}
     45 
     46 void Fl_Osc_Slider::OSC_value(int v)
     47 {
     48     const float min_ = min__(minimum(), maximum());//flipped sliders
     49     Fl_Slider::value(v+min_+value()-floorf(value()));
     50 }
     51 
     52 void Fl_Osc_Slider::OSC_value(float v)
     53 {
     54     const float min_ = min__(minimum(), maximum());//flipped sliders
     55     Fl_Slider::value(v+min_);
     56 }
     57 
     58 void Fl_Osc_Slider::OSC_value(char v)
     59 {
     60     const float min_ = min__(minimum(), maximum());//flipped sliders
     61     Fl_Slider::value(v+min_+value()-floorf(value()));
     62 }
     63 
     64 void Fl_Osc_Slider::cb(void)
     65 {
     66     const float min_ = min__(minimum(), maximum());//flipped sliders
     67     const float val = Fl_Slider::value();
     68     if(osc_type == 'f')
     69         oscWrite(ext, "f", val-min_);
     70     else if(osc_type == 'i')
     71         oscWrite(ext, "i", (int)(val-min_));
     72     else {
     73         fprintf(stderr, "invalid `c' from slider %s%s, using `i'\n", loc.c_str(), ext.c_str());
     74         oscWrite(ext, "i", (int)(val-min_));
     75     }
     76     //OSC_value(val);
     77 
     78     if(cb_data.first)
     79         cb_data.first(this, cb_data.second);
     80 }
     81 
     82 void Fl_Osc_Slider::callback(Fl_Callback *cb, void *p)
     83 {
     84     cb_data.first = cb;
     85     cb_data.second = p;
     86 }
     87 
     88 #define MOD_MASK (FL_CTRL | FL_SHIFT)
     89 
     90 int Fl_Osc_Slider::handle(int ev, int X, int Y, int W, int H)
     91 {
     92     bool middle_mouse = (ev == FL_PUSH && Fl::event_state(FL_BUTTON2) && !Fl::event_shift());
     93     bool ctl_click    = (ev == FL_PUSH && Fl::event_state(FL_BUTTON3) && Fl::event_ctrl());
     94     bool shift_middle = (ev == FL_PUSH && Fl::event_state(FL_BUTTON2) && Fl::event_shift());
     95     if(middle_mouse || ctl_click) {
     96         printf("Trying to learn...\n");
     97         osc->write("/learn", "s", (loc+ext).c_str());
     98         return 1;
     99     } else if(shift_middle) {
    100         osc->write("/unlearn", "s", (loc+ext).c_str());
    101         return 1;
    102     }
    103 
    104     int handled;
    105     float rounded;
    106 
    107     const float range = maximum() - minimum();
    108     const float absrange = (range > 0 ? range : -range)+1;
    109     int old_mod_state;
    110     const float normal_step = range / W;
    111 
    112     switch (ev) {
    113         case FL_PUSH:
    114             just_pushed = true;
    115             mod_state = Fl::event_state() & MOD_MASK;
    116             slow_state = 0;
    117             start_pos = horizontal() ? Fl::event_x() : Fl::event_y();
    118             handled = mod_state ? 1 : Fl_Slider::handle(ev, X, Y, W, H);
    119             break;
    120         case FL_MOUSEWHEEL:
    121             mod_state = Fl::event_state() & MOD_MASK;
    122             if (Fl::event_buttons())
    123                 return 1;
    124             if (this == Fl::belowmouse() && Fl::e_dy != 0) {
    125                 int step_ = 1, divisor = 16;
    126 
    127                 switch (mod_state) {
    128                     case FL_SHIFT:
    129                         if (absrange > divisor * 8)
    130                             step_ = 8;
    131                     case FL_SHIFT | FL_CTRL:
    132                         break;
    133                     case FL_CTRL:
    134                         divisor = 128;
    135                         // fall through
    136                     default:
    137                         step_ = absrange / divisor;
    138                         if (step_ < 1)
    139                             step_ = 1;
    140                 }
    141                 int dy = minimum() <=  maximum() ? -Fl::e_dy : Fl::e_dy;
    142                 // Flip sense for vertical sliders.
    143                 dy = this->horizontal() ? dy : -dy;
    144                 handle_drag(clamp(value() + step_ * dy));
    145             }
    146             return 1;
    147         case FL_RELEASE:
    148             handled = Fl_Slider::handle(ev, X, Y, W, H);
    149             if (Fl::event_clicks() == 1) {
    150                 Fl::event_clicks(0);
    151                 value(reset_value);
    152             } else {
    153                 rounded = floorf(value() + 0.5);
    154                 value(clamp(rounded));
    155             }
    156             value_damage();
    157             do_callback();
    158             break;
    159         case FL_DRAG: {
    160             old_mod_state = mod_state;
    161             mod_state = Fl::event_state() & MOD_MASK;
    162             if (slow_state == 0 && mod_state == 0) {
    163                 int delta = (horizontal() ? Fl::event_x() : Fl::event_y())
    164                     - start_pos;
    165                 if (delta < -1 || delta > 1)
    166                     Fl::event_clicks(0);
    167                 return Fl_Slider::handle(ev, X, Y, W, H);
    168             }
    169 
    170             if (mod_state != 0) {
    171                 slow_state = 1;
    172             } else if (slow_state == 1)
    173                 slow_state = 2;
    174 
    175             if (just_pushed || old_mod_state != mod_state) {
    176                 just_pushed = false;
    177                 old_value = value();
    178                 start_pos = horizontal() ? Fl::event_x() : Fl::event_y();
    179                 if (slow_state == 1) {
    180                     denominator = 2.0;
    181                     float step_ = step();
    182                     if (step_ == 0) step_ = 1;
    183 
    184                     if (absrange / W / step_ > 32)
    185                         switch (mod_state) {
    186                             case FL_CTRL:
    187                                 denominator = 0.15;
    188                                 break;
    189                             case FL_SHIFT:
    190                                 denominator = 0.7;
    191                                 break;
    192                             case MOD_MASK:
    193                                 denominator = 3.0;
    194                                 break;
    195                         }
    196                     else if (mod_state & FL_SHIFT)
    197                         denominator = 5.0;
    198 
    199                     if (range < 0)
    200                         denominator *= -1;
    201                 }
    202             }
    203 
    204             int delta = (horizontal() ? Fl::event_x() : Fl::event_y())
    205                 - start_pos;
    206             if (delta < -1 || delta > 1)
    207                 Fl::event_clicks(0);
    208             float new_value;
    209             if (slow_state == 1) {
    210                 new_value = old_value + delta / denominator;
    211             } else {
    212                 new_value = old_value + delta * normal_step;
    213             }
    214             const float clamped_value = clamp(new_value);
    215             rounded = floor(clamped_value + 0.5);
    216             if (new_value != clamped_value) {
    217                 start_pos = horizontal() ? Fl::event_x() : Fl::event_y();
    218                 old_value = rounded;
    219                 if (slow_state == 2 &&
    220                     ((horizontal() &&
    221                       (Fl::event_x() < X || Fl::event_x() > X + W)) ||
    222                      (!horizontal() &&
    223                       (Fl::event_y() < Y || Fl::event_y() > Y + H))))
    224                     slow_state = 0;
    225             }
    226             value(rounded);
    227             value_damage();
    228             do_callback();
    229 
    230             handled = 1;
    231             break;
    232         }
    233         default:
    234             handled = Fl_Slider::handle(ev, X, Y, W, H);
    235     }
    236 
    237     return handled;
    238 }
    239 
    240 int Fl_Osc_Slider::handle(int ev) {
    241     return handle(ev,
    242                   x()+Fl::box_dx(box()),
    243                   y()+Fl::box_dy(box()),
    244                   w()-Fl::box_dw(box()),
    245                   h()-Fl::box_dh(box()));
    246 }
    247 
    248 void Fl_Osc_Slider::update(void)
    249 {
    250     oscWrite(ext, "");
    251 }
    252 
    253 void Fl_Osc_Slider::_cb(Fl_Widget *w, void *)
    254 {
    255     static_cast<Fl_Osc_Slider*>(w)->cb();
    256 }