1 /* B.Oops
2  * Glitch effect sequencer LV2 plugin
3  *
4  * Copyright (C) 2020 by Sven Jähnichen
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef OPTIONPHASER_HPP_
21 #define OPTIONPHASER_HPP_
22 
23 #include <new>
24 #include "OptionWidget.hpp"
25 #include "BWidgets/Label.hpp"
26 #include "DialRange.hpp"
27 
28 class OptionPhaser : public OptionWidget
29 {
30 public:
OptionPhaser()31 	OptionPhaser () : OptionPhaser (0.0, 0.0, 0.0, 0.0, "widget") {}
OptionPhaser(const double x,const double y,const double width,const double height,const std::string & name)32 	OptionPhaser (const double x, const double y, const double width, const double height, const std::string& name) :
33 		OptionWidget (x, y, width, height, name),
34 		loFreqLabel (10, 100, 60, 20, "ctlabel", BOOPS_LABEL_LOW_FREQ),
35 		hiFreqLabel (90, 100, 60, 20, "ctlabel", BOOPS_LABEL_HIGH_FREQ),
36 		modRateLabel (160, 100, 80, 20, "ctlabel", BOOPS_LABEL_MODULATION),
37 		modPhaseLabel (240, 100, 80, 20, "ctlabel", BOOPS_LABEL_STEREO_PHASE),
38 		stepsLabel (330, 100, 60, 20, "ctlabel", BOOPS_LABEL_STEPS),
39 		feedbackLabel (410, 100, 60, 20, "ctlabel", BOOPS_LABEL_FEEDBACK)
40 	{
41 		try
42 		{
43 			options[0] = new DialRange (10, 20, 60, 60, "pad0", 0.5, 0.0, 1.0, 0.0, BIDIRECTIONAL, "%1.0f", BOOPS_LABEL_HZ, [] (double x) {return 20.0 + 19980.0 * pow (x, 3.0);}, [] (double x) {return pow ((LIMIT (x, 20, 20000) - 20.0) / 19980.0, 1.0 / 3.0);});
44 			options[1] = new BWidgets::ValueWidget (0, 0, 0, 0, "widget", 0.0);
45 			options[2] = new DialRange (90, 20, 60, 60, "pad0", 0.5, 0.0, 1.0, 0.0, BIDIRECTIONAL, "%1.0f", BOOPS_LABEL_HZ, [] (double x) {return 20.0 + 19980.0 * pow (x, 3.0);}, [] (double x) {return pow ((LIMIT (x, 20, 20000) - 20.0) / 19980.0, 1.0 / 3.0);});
46 			options[3] = new BWidgets::ValueWidget (0, 0, 0, 0, "widget", 0.0);
47 			options[4] = new DialRange (170, 20, 60, 60, "pad0", 0.5, 0.0, 1.0, 0.0, BIDIRECTIONAL, "%1.2f", BOOPS_LABEL_HZ, [] (double x) {return 10.0 * pow (x, 3.0);}, [] (double x) {return pow (LIMIT (x, 0.0, 10.0) / 10.0, 1.0 / 3.0);});
48 			options[5] = new BWidgets::ValueWidget (0, 0, 0, 0, "widget", 0.0);
49 			options[6] = new DialRange (250, 20, 60, 60, "pad0", 0.5, 0.0, 1.0, 0.0, BIDIRECTIONAL, "%1.1f", "°", [] (double x) {return 360.0 * x;}, [] (double x) {return LIMIT (x, 0.0, 360.0) / 360.0;});
50 			options[7] = new BWidgets::ValueWidget (0, 0, 0, 0, "widget", 0.0);
51 			options[8] = new DialRange (410, 20, 60, 60, "pad0", 0.5, 0.0, 1.0, 0.0, BIDIRECTIONAL, "%1.2f", "", [] (double x) {return 2.0 * x - 1.0;}, [] (double x) {return (LIMIT (x, -1.0, 1.0) + 1.0) / 2.0;});
52 			options[9] = new BWidgets::ValueWidget (0, 0, 0, 0, "widget", 0.0);
53 			options[10] = new Dial (330, 20, 60, 60, "pad0", 0.5, 0.0, 1.0, 0.0, "%1.0f", "", [] (double x) {return floor (1.0 + LIMIT (x * 10.0, 0, 9));}, [] (double x) {return (LIMIT (x, 1.0, 10.0) - 0.99999) / 10.0;});
54 		}
55 		catch (std::bad_alloc& ba) {throw ba;}
56 
57 		for (int i = 0; i < 10; i += 2)
58 		{
59 			options[i]->setCallbackFunction (BEvents::VALUE_CHANGED_EVENT, valueChangedCallback);
60 			((DialRange*)options[i])->range.setCallbackFunction (BEvents::VALUE_CHANGED_EVENT, rangeChangedCallback);
61 			options[i + 1]->setCallbackFunction (BEvents::VALUE_CHANGED_EVENT, valueChangedCallback);
62 		}
63 		options[10]->setCallbackFunction (BEvents::VALUE_CHANGED_EVENT, valueChangedCallback);
64 
65 		add (loFreqLabel);
66 		add (hiFreqLabel);
67 		add (modRateLabel);
68 		add (modPhaseLabel);
69 		add (stepsLabel);
70 		add (feedbackLabel);
71 		for (int i = 0; i < 11; ++i) add (*options[i]);
72 	}
73 
OptionPhaser(const OptionPhaser & that)74 	OptionPhaser (const OptionPhaser& that) :
75 		OptionWidget (that),
76 		loFreqLabel (that.loFreqLabel), hiFreqLabel (that.hiFreqLabel),
77 		modRateLabel (that.modRateLabel), modPhaseLabel (that.modPhaseLabel),
78 		stepsLabel (that.stepsLabel), feedbackLabel (that.feedbackLabel)
79 	{
80 		add (loFreqLabel);
81 		add (hiFreqLabel);
82 		add (modRateLabel);
83 		add (modPhaseLabel);
84 		add (stepsLabel);
85 		add (feedbackLabel);
86 	}
87 
operator =(const OptionPhaser & that)88 	OptionPhaser& operator= (const OptionPhaser& that)
89 	{
90 		release (&loFreqLabel);
91 		release (&hiFreqLabel);
92 		release (&modRateLabel);
93 		release (&modPhaseLabel);
94 		release (&stepsLabel);
95 		release (&feedbackLabel);
96 		OptionWidget::operator= (that);
97 		loFreqLabel = that.loFreqLabel;
98 		hiFreqLabel = that.hiFreqLabel;
99 		modRateLabel = that.modRateLabel;
100 		modPhaseLabel = that.modPhaseLabel;
101 		stepsLabel = that.stepsLabel;
102 		feedbackLabel = that.feedbackLabel;
103 		add (loFreqLabel);
104 		add (hiFreqLabel);
105 		add (modRateLabel);
106 		add (modPhaseLabel);
107 		add (stepsLabel);
108 		add (feedbackLabel);
109 
110 		return *this;
111 	}
112 
clone() const113 	virtual Widget* clone () const override {return new OptionPhaser (*this);}
114 
applyTheme(BStyles::Theme & theme)115 	virtual void applyTheme (BStyles::Theme& theme) override {applyTheme (theme, name_);}
116 
applyTheme(BStyles::Theme & theme,const std::string & name)117 	virtual void applyTheme (BStyles::Theme& theme, const std::string& name) override
118 	{
119 		OptionWidget::applyTheme (theme, name);
120 		loFreqLabel.applyTheme (theme);
121 		hiFreqLabel.applyTheme (theme);
122 		modRateLabel.applyTheme (theme);
123 		modPhaseLabel.applyTheme (theme);
124 		feedbackLabel.applyTheme (theme);
125 	}
126 
valueChangedCallback(BEvents::Event * event)127 	static void valueChangedCallback(BEvents::Event* event)
128 	{
129 		if (!event) return;
130 		BWidgets::Widget* widget = event->getWidget ();
131 		if (!widget) return;
132 		OptionWidget* p = (OptionWidget*) widget->getParent();
133 		if (!p) return;
134 		BOopsGUI* ui = (BOopsGUI*) widget->getMainWindow();
135 		if (!ui) return;
136 
137 		// options[i + 1] changed ? Send to range
138 		for (int i = 0; i < 10; i += 2)
139 		{
140 			if (widget == p->getWidget(i + 1))
141 			{
142 				((DialRange*)p->getWidget(i))->range.setValue (((BWidgets::ValueWidget*)widget)->getValue());
143 				break;
144 			}
145 		}
146 
147 		// Forward all changed options to ui
148 		ui->optionChangedCallback (event);
149 	}
150 
rangeChangedCallback(BEvents::Event * event)151 	static void rangeChangedCallback(BEvents::Event* event)
152 	{
153 		if (!event) return;
154 		BWidgets::Widget* widget = event->getWidget ();
155 		if (!widget) return;
156 		DialRange* p = (DialRange*) widget->getParent();
157 		if (!p) return;
158 		OptionWidget* pp = (OptionWidget*) p->getParent();
159 		if (!pp) return;
160 
161 		// Send changed range to options[i + 1]
162 		for (int i = 0; i < 10; i += 2)
163 		{
164 			if ((p == (DialRange*)pp->getWidget(i)) && (widget == (BWidgets::Widget*)&p->range))
165 			{
166 				p->update();
167 				((BWidgets::ValueWidget*)pp->getWidget(i + 1))->setValue (p->range.getValue ());
168 			}
169 		}
170 	}
171 
172 protected:
173 	BWidgets::Label loFreqLabel;
174 	BWidgets::Label hiFreqLabel;
175 	BWidgets::Label modRateLabel;
176 	BWidgets::Label modPhaseLabel;
177 	BWidgets::Label stepsLabel;
178 	BWidgets::Label feedbackLabel;
179 };
180 
181 #endif /* OPTIONPHASER_HPP_ */
182