zynaddsubfx

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

commit 1865bfaa70ba82fc88da06731cc93cd55b72e190
parent c886f993c3e1a7c22f69a27abf7058c9f40dfb83
Author: Christopher A. Oliver <caowasteland@gmail.com>
Date:   Sat, 17 Oct 2015 02:53:32 -0400

Improved tipwins, sliders, and dials.

    1)   Add adjustable significant digits shown for tipwins.
    2)   Added "double click to reset" behavior to sliders and knobs.
    3)   Unified NTK and FLTK sliders.  OSC Value slider now inherits
         from OSC Slider, so generic slider behavior can go in just
         one place.

Diffstat:
Msrc/UI/Fl_Osc_DialF.cpp | 1+
Msrc/UI/Fl_Osc_Slider.H | 5+++--
Msrc/UI/Fl_Osc_Slider.cpp | 71++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/UI/Fl_Osc_VSlider.H | 26++++++++++++++++----------
Msrc/UI/Fl_Osc_VSlider.cpp | 101+++++++++++++++++++++++++++++++------------------------------------------------
Msrc/UI/TipWin.cpp | 13++++++++-----
Msrc/UI/TipWin.h | 5+++++
Msrc/UI/WidgetPDial.cpp | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Msrc/UI/WidgetPDial.h | 6++++++
9 files changed, 205 insertions(+), 109 deletions(-)

diff --git a/src/UI/Fl_Osc_DialF.cpp b/src/UI/Fl_Osc_DialF.cpp @@ -39,6 +39,7 @@ void Fl_Osc_DialF::init(const char *path) ext = path; loc = pane->base; oscRegister(path); + integer_step = false; }; Fl_Osc_DialF::~Fl_Osc_DialF(void) diff --git a/src/UI/Fl_Osc_Slider.H b/src/UI/Fl_Osc_Slider.H @@ -5,7 +5,6 @@ class Fl_Osc_Slider:public Fl_Slider, public Fl_Osc_Widget { - public: Fl_Osc_Slider(int X, int Y, int W, int H, const char *label = NULL); // string name, @@ -22,10 +21,12 @@ class Fl_Osc_Slider:public Fl_Slider, public Fl_Osc_Widget void callback(Fl_Callback *cb, void *p = NULL); //MIDI Learn - int handle(int); + int handle(int ev, int X, int Y, int W, int H); + int handle(int ev); void cb(void); static void _cb(Fl_Widget *w, void *); + float reset_value; private: char osc_type; std::pair<Fl_Callback*, void*> cb_data; diff --git a/src/UI/Fl_Osc_Slider.cpp b/src/UI/Fl_Osc_Slider.cpp @@ -7,6 +7,7 @@ #include <cmath> #include <cassert> #include <sstream> +#include "../Misc/Util.h" static double min__(double a, double b) { @@ -14,7 +15,8 @@ static double min__(double a, double b) } Fl_Osc_Slider::Fl_Osc_Slider(int X, int Y, int W, int H, const char *label) - :Fl_Slider(X,Y,W,H,label), Fl_Osc_Widget(this), cb_data(NULL, NULL) + :Fl_Slider(X,Y,W,H,label), Fl_Osc_Widget(this), reset_value(0), + cb_data(NULL, NULL) { //bounds(0.0f,1.0f); Fl_Slider::callback(Fl_Osc_Slider::_cb); @@ -72,7 +74,7 @@ void Fl_Osc_Slider::callback(Fl_Callback *cb, void *p) cb_data.second = p; } -int Fl_Osc_Slider::handle(int ev) +int Fl_Osc_Slider::handle(int ev, int X, int Y, int W, int H) { bool middle_mouse = (ev == FL_PUSH && Fl::event_state(FL_BUTTON2) && !Fl::event_shift()); bool ctl_click = (ev == FL_PUSH && Fl::event_state(FL_BUTTON1) && Fl::event_ctrl()); @@ -85,7 +87,70 @@ int Fl_Osc_Slider::handle(int ev) osc->write("/unlearn", "s", (loc+ext).c_str()); return 1; } - return Fl_Slider::handle(ev); + + int handled, rounded; + bool reset_requested = false; + switch (ev) { + case FL_MOUSEWHEEL: + if (this == Fl::belowmouse() && Fl::e_dy != 0) { + int step = 1, divisor = 16; + switch (Fl::event_state() & ( FL_CTRL | FL_SHIFT)) { + case FL_SHIFT: + step = 8; + case FL_SHIFT | FL_CTRL: + break; + case FL_CTRL: + divisor = 128; + default: + step = (fabs(maximum() - minimum()) + 1) / divisor; + if (step < 1) + step = 1; + } + int dy = minimum() <= maximum() ? Fl::e_dy : -Fl::e_dy; + handle_drag(clamp(value() + step * dy)); + } + return 1; + case FL_RELEASE: + rounded = value() + 0.5; + value(limit((double)rounded,minimum(),maximum())); + if (Fl::event_clicks() == 1) { + Fl::event_clicks(0); + reset_requested = true; + } + } + + if (!Fl::event_shift()) { + handled = Fl_Slider::handle(ev, X, Y, W, H); + if (reset_requested) { + value(reset_value); + value_damage(); + if (this->when() != 0) + do_callback(); + } + return handled; + } + + // Slow down the drag. + // Handy if the slider has a large delta bigger than a mouse quantum. + // Somewhat tricky to use with OSC feedback. + // To change direction of movement, one must reclick the handle. + int old_value = value(); + handled = Fl_Slider::handle(ev, X, Y, W, H); + int delta = value() - old_value; + if (ev == FL_DRAG && (delta < -1 || delta > 1)) { + value(old_value + (delta > 0 ? 1 : -1)); + value_damage(); + do_callback(); + } + return handled; +} + +int Fl_Osc_Slider::handle(int ev) { + return handle(ev, + x()+Fl::box_dx(box()), + y()+Fl::box_dy(box()), + w()-Fl::box_dw(box()), + h()-Fl::box_dh(box())); } void Fl_Osc_Slider::update(void) diff --git a/src/UI/Fl_Osc_VSlider.H b/src/UI/Fl_Osc_VSlider.H @@ -1,29 +1,35 @@ #pragma once #include <FL/Fl_Value_Slider.H> -#include "Fl_Osc_Widget.H" +#include "Fl_Osc_Slider.H" #include <string> -class Fl_Osc_VSlider:public Fl_Value_Slider, public Fl_Osc_Widget +class Fl_Osc_VSlider:public Fl_Osc_Slider { public: Fl_Osc_VSlider(int X, int Y, int W, int H, const char *label = NULL); virtual ~Fl_Osc_VSlider(void); - void OSC_value(char); - void OSC_value(int); - void OSC_value(float); - void init(std::string, char type = 'i'); + Fl_Font textfont_; + Fl_Fontsize textsize_; + Fl_Color textcolor_; + void init(std::string, char type = 'i'); //Refetch parameter information - void update(void); - void callback(Fl_Callback *cb, void *p = NULL); //MIDI Learn int handle(int); - void cb(void); - static void _cb(Fl_Widget *w, void *); + // Value Slider add-ins. + Fl_Font textfont() const {return textfont_;} + void textfont(Fl_Font s) {textfont_ = s;} + Fl_Fontsize textsize() const {return textsize_;} + void textsize(Fl_Fontsize s) {textsize_ = s;} + Fl_Color textcolor() const {return textcolor_;} + void textcolor(Fl_Color s) {textcolor_ = s;} + + protected: + void draw(void); private: char osc_type; std::pair<Fl_Callback*, void*> cb_data; diff --git a/src/UI/Fl_Osc_VSlider.cpp b/src/UI/Fl_Osc_VSlider.cpp @@ -1,4 +1,5 @@ #include <FL/Fl.H> +#include <FL/fl_draw.H> #include "Fl_Osc_VSlider.H" #include "Fl_Osc_Interface.h" #include "Fl_Osc_Pane.H" @@ -9,82 +10,60 @@ #include <sstream> Fl_Osc_VSlider::Fl_Osc_VSlider(int X, int Y, int W, int H, const char *label) - :Fl_Value_Slider(X,Y,W,H,label), Fl_Osc_Widget(this), cb_data(NULL, NULL) + :Fl_Osc_Slider(X,Y,W,H,label), cb_data(NULL, NULL) { //bounds(0.0f,1.0f); - Fl_Slider::callback(Fl_Osc_VSlider::_cb); -} - -void Fl_Osc_VSlider::init(std::string path_, char type_) -{ - osc_type = type_; - ext = path_; - oscRegister(ext.c_str()); + Fl_Slider::callback(Fl_Osc_Slider::_cb); + textfont_ = FL_HELVETICA; + textsize_ = 10; + textcolor_ = FL_FOREGROUND_COLOR; } Fl_Osc_VSlider::~Fl_Osc_VSlider(void) {} -void Fl_Osc_VSlider::OSC_value(char v) -{ - Fl_Slider::value(v+minimum()+fmodf(value(), 1.0f)); -} - -void Fl_Osc_VSlider::OSC_value(int v) -{ - Fl_Slider::value(v+minimum()+fmodf(value(), 1.0f)); -} - -void Fl_Osc_VSlider::OSC_value(float v) +void Fl_Osc_VSlider::init(std::string path_, char type_) { - Fl_Slider::value(v+minimum()); + Fl_Osc_Slider::init(path_, type_); } -void Fl_Osc_VSlider::cb(void) -{ - const float val = Fl_Slider::value(); - if(osc_type == 'f') - oscWrite(ext, "f", val-minimum()); - else if(osc_type == 'i') - oscWrite(ext, "i", (int)(val-minimum())); - else { - fprintf(stderr, "invalid `c' from vslider %s%s, using `i'\n", loc.c_str(), ext.c_str()); - oscWrite(ext, "i", (int)(val-minimum())); +void Fl_Osc_VSlider::draw() { + int sxx = x(), syy = y(), sww = w(), shh = h(); + int bxx = x(), byy = y(), bww = w(), bhh = h(); + if (horizontal()) { + bww = 35; sxx += 35; sww -= 35; + } else { + syy += 25; bhh = 25; shh -= 25; } - //OSC_value(val); - - if(cb_data.first) - cb_data.first(this, cb_data.second); -} - -void Fl_Osc_VSlider::callback(Fl_Callback *cb, void *p) -{ - cb_data.first = cb; - cb_data.second = p; + if (damage()&FL_DAMAGE_ALL) draw_box(box(),sxx,syy,sww,shh,color()); + Fl_Osc_Slider::draw(sxx+Fl::box_dx(box()), + syy+Fl::box_dy(box()), + sww-Fl::box_dw(box()), + shh-Fl::box_dh(box())); + draw_box(box(),bxx,byy,bww,bhh,color()); + char buf[128]; + format(buf); + fl_font(textfont(), textsize()); + fl_color(active_r() ? textcolor() : fl_inactive(textcolor())); + fl_draw(buf, bxx, byy, bww, bhh, FL_ALIGN_CLIP); } int Fl_Osc_VSlider::handle(int ev) { - bool middle_mouse = (ev == FL_PUSH && Fl::event_state(FL_BUTTON2) && !Fl::event_shift()); - bool ctl_click = (ev == FL_PUSH && Fl::event_state(FL_BUTTON1) && Fl::event_ctrl()); - bool shift_middle = (ev == FL_PUSH && Fl::event_state(FL_BUTTON2) && Fl::event_shift()); - if(middle_mouse || ctl_click) { - printf("Trying to learn...\n"); - osc->write("/learn", "s", (loc+ext).c_str()); - return 1; - } else if(shift_middle) { - osc->write("/unlearn", "s", (loc+ext).c_str()); - return 1; + if (ev == FL_PUSH && Fl::visible_focus()) { + Fl::focus(this); + redraw(); + } + int sxx = x(), syy = y(), sww = w(), shh = h(); + if (horizontal()) { + sxx += 35; sww -= 35; + } else { + syy += 25; shh -= 25; } - return Fl_Value_Slider::handle(ev); -} - -void Fl_Osc_VSlider::update(void) -{ - oscWrite(ext, ""); -} -void Fl_Osc_VSlider::_cb(Fl_Widget *w, void *) -{ - static_cast<Fl_Osc_VSlider*>(w)->cb(); + return Fl_Osc_Slider::handle(ev, + sxx+Fl::box_dx(box()), + syy+Fl::box_dy(box()), + sww-Fl::box_dw(box()), + shh-Fl::box_dh(box())); } diff --git a/src/UI/TipWin.cpp b/src/UI/TipWin.cpp @@ -1,18 +1,21 @@ #include <cstdio> -#include <iostream> #include <cmath> -#include <string> #include <FL/Fl_Tooltip.H> -#include <FL/Fl_Menu_Window.H> #include <FL/fl_draw.H> #include "TipWin.h" -TipWin::TipWin():Fl_Menu_Window(1, 1) +TipWin::TipWin(void):Fl_Menu_Window(1, 1) { + strcpy(format, "%0.2f"); set_override(); end(); } +void TipWin::setRounding(unsigned int digits) +{ + format[3] = "0123456789"[digits < 9 ? digits : 9]; +} + void TipWin::draw() { //setup window @@ -29,7 +32,7 @@ void TipWin::showValue(float f) { //convert the value to a string char tmp[10]; - snprintf(tmp, 9, "%.2f", f); + snprintf(tmp, 9, format, f); tip = tmp; textmode = false; diff --git a/src/UI/TipWin.h b/src/UI/TipWin.h @@ -1,4 +1,7 @@ #ifndef TIPWIN_H +#include <string> +#include <FL/Fl_Menu_Window.H> +#include <FL/Fl_Tooltip.H> #define TIPWIN_H using namespace std; @@ -10,11 +13,13 @@ class TipWin:public Fl_Menu_Window void showValue(float f); void setText(const char *c); void showText(); + void setRounding(unsigned int digits = 0); private: void redraw(); const char *getStr() const; string tip; string text; bool textmode; + char format[6]; }; #endif diff --git a/src/UI/WidgetPDial.cpp b/src/UI/WidgetPDial.cpp @@ -1,16 +1,9 @@ // generated by Fast Light User Interface Designer (fluid) version 1.0107f -#include "WidgetPDial.h" -#include <cstdio> -#include <iostream> #include <cmath> -#include <string> -#include <FL/Fl_Tooltip.H> #include <FL/fl_draw.H> -#include <FL/Fl_Group.H> -#include <FL/Fl_Menu_Window.H> #include "../Misc/Util.h" -#include "TipWin.h" +#include "WidgetPDial.h" //Copyright (c) 2003-2005 Nasca Octavian Paul //License: GNU GPL version 2 or later @@ -18,15 +11,15 @@ //static int numobj = 0; WidgetPDial::WidgetPDial(int x, int y, int w, int h, const char *label) - :Fl_Dial(x, y, w, h, label), oldvalue(0.0f), pos(false), textset(false), - value_offset(0.0), value_scale(1.0) + :Fl_Dial(x, y, w, h, label), reset_value(0), integer_step(true), + oldvalue(0.0f), pos(false), textset(false), value_offset(0.0), + value_scale(1.0) { //cout << "[" << label << "] There are now " << ++numobj << endl; Fl_Group *save = Fl_Group::current(); tipwin = new TipWin(); tipwin->hide(); Fl_Group::current(save); - value_offset=0; } WidgetPDial::~WidgetPDial() @@ -35,26 +28,45 @@ WidgetPDial::~WidgetPDial() delete tipwin; } -int WidgetPDial::handle(int event) +void WidgetPDial::setRounding(unsigned int digits) { -//#ifdef NTK_GUI -// return Fl_Dial::handle( event ); -//#else - double dragsize, min = minimum(), max = maximum(); - int my; + tipwin->setRounding(digits); +} +int WidgetPDial::handle(int event) +{ + double dragsize, min = minimum(), max = maximum(), result; + int dy; + + if (event == FL_RELEASE && Fl::event_clicks() == 1) { + Fl::event_clicks(0); + value(reset_value); + value_damage(); + if (this->when() != 0) + do_callback(); + return 1; + } + switch(event) { case FL_PUSH: + if (integer_step) + setRounding(0); + else if (Fl::event_shift()) + setRounding(4); + else + setRounding(Fl::event_button1() ? 2 : 3); oldvalue = value(); + old_y = Fl::event_y(); case FL_DRAG: getPos(); - my = -(Fl::event_y() - y() - h() / 2); + dy = old_y - Fl::event_y(); - dragsize = 200.0f; - if(Fl::event_state(FL_BUTTON1) == 0) - dragsize *= 10; + if (Fl::event_shift()) + dragsize = 20000.0f; + else + dragsize = Fl::event_button1() ? 200.0f : 2000.0f; - value(limit(oldvalue + my / dragsize * (max - min), min, max)); + value(limit(oldvalue + dy / dragsize * (max - min), min, max)); tipwin->showValue(transform(value())); value_damage(); if(this->when() != 0) @@ -63,13 +75,27 @@ int WidgetPDial::handle(int event) case FL_MOUSEWHEEL: if (Fl::belowmouse() != this) return 1; - my = - Fl::event_dy(); - - dragsize = 200.0f; - if(Fl::event_state(FL_CTRL) != 0) - dragsize *= 10; + dy = - Fl::event_dy(); + + if (integer_step) { + setRounding(0); + result = (int)(value() + dy * (Fl::event_ctrl() ? 1 : 8)); + } else { + float dragsize; + if (Fl::event_shift()) { + dragsize = 10000.0; + setRounding(4); + } else if (Fl::event_ctrl()) { + dragsize = 1000.0; + setRounding(3); + } else { + dragsize = 100.0; + setRounding(2); + } + result = value() + dy / dragsize * (max - min); + } + value(limit(result, min, max)); - value(limit(value() + my / dragsize * (max - min), min, max)); tipwin->showValue(transform(value())); value_damage(); if(this->when() != 0) @@ -85,6 +111,10 @@ int WidgetPDial::handle(int event) resetPos(); break; case FL_RELEASE: + if (integer_step) { + int rounded = value() + 0.5; + value(limit((double)rounded,min,max)); + } tipwin->hide(); resetPos(); if(this->when() == 0) diff --git a/src/UI/WidgetPDial.h b/src/UI/WidgetPDial.h @@ -3,6 +3,7 @@ #ifndef WIDGETPDIAL_h #define WIDGETPDIAL_h #include <FL/Fl_Dial.H> +#include "TipWin.h" class WidgetPDial:public Fl_Dial @@ -16,10 +17,15 @@ class WidgetPDial:public Fl_Dial void tooltip(const char *c); void set_transform(float scale = 1.0, float offset = 0.0); float transform(float x); + void setRounding(unsigned int digits = 0); + float reset_value; + protected: + bool integer_step; private: void getPos(); void resetPos(); double oldvalue; + int old_y; bool pos; bool textset; class TipWin * tipwin;