1 /*
2  * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/>
3  *           (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com>
4  *
5  * This file is part of lsp-plugins
6  * Created on: 27 июл. 2017 г.
7  *
8  * lsp-plugins is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * any later version.
12  *
13  * lsp-plugins is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <ui/ctl/ctl.h>
23 
24 namespace lsp
25 {
26     namespace ctl
27     {
28         const ctl_class_t CtlDot::metadata = { "CtlDot", &CtlWidget::metadata };
29 
CtlDot(CtlRegistry * src,LSPDot * dot)30         CtlDot::CtlDot(CtlRegistry *src, LSPDot *dot): CtlWidget(src, dot)
31         {
32             pClass          = &metadata;
33             pTop            = NULL;
34             pLeft           = NULL;
35             pScroll         = NULL;
36             nFlags          = 0;
37             fTop            = 0.0f;
38             fLeft           = 0.0f;
39             bEditable       = false;
40         }
41 
~CtlDot()42         CtlDot::~CtlDot()
43         {
44         }
45 
init()46         void CtlDot::init()
47         {
48             CtlWidget::init();
49             if (pWidget == NULL)
50                 return;
51 
52             LSPDot *dot   = static_cast<LSPDot *>(pWidget);
53 
54             // Initialize color controllers
55             sColor.init_hsl(pRegistry, dot, dot->color(), A_COLOR, A_HUE_ID, A_SAT_ID, A_LIGHT_ID);
56 
57             // Bind slots
58             dot->slots()->bind(LSPSLOT_CHANGE, slot_change, this);
59         }
60 
slot_change(LSPWidget * sender,void * ptr,void * data)61         status_t CtlDot::slot_change(LSPWidget *sender, void *ptr, void *data)
62         {
63             CtlDot *_this       = static_cast<CtlDot *>(ptr);
64             if (_this != NULL)
65                 _this->submit_values();
66             return STATUS_OK;
67         }
68 
submit_values()69         void CtlDot::submit_values()
70         {
71             LSPDot *dot   = widget_cast<LSPDot>(pWidget);
72             if (dot == NULL)
73                 return;
74 
75             if (dot->x_editable())
76                 submit_value(pLeft, dot->x_value());
77             if (dot->y_editable())
78                 submit_value(pTop, dot->y_value());
79             if (dot->z_editable())
80             {
81                 const port_t *p = pScroll->metadata();
82                 float value = dot->z_value();
83 
84                 if ((p != NULL) && (is_log_rule(p)))
85                 {
86                     float min = fabs(p->min);
87 
88                     min = (min < GAIN_AMP_M_120_DB) ? logf(GAIN_AMP_M_80_DB) : logf(min);
89                     value = (value < min) ? p->min : expf(value);
90 
91                 }
92 
93                 submit_value(pScroll, value);
94             }
95         }
96 
submit_value(CtlPort * port,float value)97         void CtlDot::submit_value(CtlPort *port, float value)
98         {
99             if (port == NULL)
100                 return;
101             if (value == port->get_value())
102                 return;
103 
104             port->set_value(value);
105             port->notify_all();
106         }
107 
set(widget_attribute_t att,const char * value)108         void CtlDot::set(widget_attribute_t att, const char *value)
109         {
110             LSPDot *dot = widget_cast<LSPDot>(pWidget);
111 
112             switch (att)
113             {
114                 case A_VPOS:
115                     PARSE_FLOAT(value, fTop = __);
116                     break;
117                 case A_HPOS:
118                     PARSE_FLOAT(value, fLeft = __);
119                     break;
120                 case A_SIZE:
121                     if (dot != NULL)
122                         PARSE_INT(value, dot->set_size(__));
123                     break;
124                 case A_BORDER:
125                     if (dot != NULL)
126                         PARSE_INT(value, dot->set_border(__));
127                     break;
128                 case A_PADDING:
129                     if (dot != NULL)
130                         PARSE_INT(value, dot->set_padding(__));
131                     break;
132 
133                 case A_BASIS:
134                     if (dot != NULL)
135                         PARSE_INT(value, dot->set_basis_id(__));
136                     break;
137                 case A_PARALLEL:
138                     if (dot != NULL)
139                         PARSE_INT(value, dot->set_parallel_id(__));
140                     break;
141                 case A_CENTER:
142                     if (dot != NULL)
143                         PARSE_INT(value, dot->set_center_id(__));
144                     break;
145 
146                 case A_SCROLL_ID:
147                     BIND_PORT(pRegistry, pScroll, value);
148                     break;
149                 case A_VPOS_ID:
150                     BIND_PORT(pRegistry, pTop, value);
151                     break;
152                 case A_HPOS_ID:
153                     BIND_PORT(pRegistry, pLeft, value);
154                     break;
155 
156                 case A_EDITABLE:
157                     PARSE_BOOL(value, bEditable = __);
158                     break;
159                 case A_LED:
160                     if (dot != NULL)
161                         PARSE_BOOL(value, dot->set_highlight(__));
162                     break;
163 
164                 default:
165                 {
166                     bool set = sColor.set(att, value);
167                     if (!set)
168                         CtlWidget::set(att, value);
169                     break;
170                 }
171             }
172         }
173 
end()174         void CtlDot::end()
175         {
176             CtlWidget::end();
177 
178             // Get widget
179             LSPDot *dot   = widget_cast<LSPDot>(pWidget);
180             if (dot == NULL)
181                 return;
182 
183             // Tune parameters
184             const port_t *p = NULL;
185 
186             if (pLeft != NULL)
187             {
188                 dot->set_x_editable(bEditable);
189                 fLeft = pLeft->get_value();
190 
191                 p = pLeft->metadata();
192                 if (p != NULL)
193                 {
194                     if (p->flags & F_LOWER)
195                         dot->set_x_minimum(p->min);
196                     if (p->flags & F_UPPER)
197                         dot->set_x_maximum(p->max);
198                     if (p->flags & F_STEP)
199                         dot->set_x_step(p->step);
200                 }
201             }
202             else
203             {
204                 dot->set_x_minimum(fLeft);
205                 dot->set_x_maximum(fLeft);
206                 dot->set_x_value(fLeft);
207             }
208 
209             if (pTop != NULL)
210             {
211                 dot->set_y_editable(bEditable);
212                 fTop = pTop->get_value();
213 
214                 p = pTop->metadata();
215                 if (p != NULL)
216                 {
217                     if (p->flags & F_LOWER)
218                         dot->set_y_minimum(p->min);
219                     if (p->flags & F_UPPER)
220                         dot->set_y_maximum(p->max);
221                     if (p->flags & F_STEP)
222                         dot->set_y_step(p->step);
223                 }
224             }
225             else
226             {
227                 dot->set_y_minimum(fTop);
228                 dot->set_y_maximum(fTop);
229                 dot->set_y_value(fTop);
230             }
231 
232             if (pScroll != NULL)
233             {
234                 dot->set_z_editable(bEditable);
235                 p = pScroll->metadata();
236 
237                 if (p != NULL)
238                 {
239                     float min, max;
240                     if (is_log_rule(p))
241                     {
242                         min = fabs(p->min);
243                         max = fabs(p->max);
244 
245                         min = (min < GAIN_AMP_M_80_DB) ? logf(GAIN_AMP_M_80_DB) - p->step : logf(min);
246                         max = (max < GAIN_AMP_M_80_DB) ? logf(GAIN_AMP_M_80_DB) - p->step : logf(max);
247                     }
248                     else
249                     {
250                         min = p->min;
251                         max = p->max;
252                     }
253 
254                     if (p->flags & F_LOWER)
255                         dot->set_z_minimum(min);
256                     if (p->flags & F_UPPER)
257                         dot->set_z_maximum(max);
258                     if (p->flags & F_STEP)
259                     {
260                         dot->set_z_tiny_step(p->step);
261                         dot->set_z_step(p->step * 10.0f);
262                         dot->set_z_big_step(p->step * 100.0f);
263                     }
264                 }
265             }
266 
267             // Update mouse pointer for dot
268             if (dot->x_editable() && dot->y_editable())
269                 dot->set_cursor(MP_DRAG);
270             else if (dot->x_editable())
271                 dot->set_cursor(MP_HSIZE);
272             else if (dot->y_editable())
273                 dot->set_cursor(MP_VSIZE);
274             else
275                 dot->set_cursor(MP_DEFAULT);
276 
277             notify(pLeft);
278             notify(pTop);
279             notify(pScroll);
280         }
281 
notify(CtlPort * port)282         void CtlDot::notify(CtlPort *port)
283         {
284             CtlWidget::notify(port);
285 
286             LSPDot *dot = widget_cast<LSPDot>(pWidget);
287             if (dot == NULL)
288                 return;
289 
290             if ((pLeft != NULL) && (port == pLeft))
291             {
292                 fLeft   = pLeft->get_value();
293                 dot->set_x_value(fLeft);
294             }
295             if ((pTop != NULL) && (port == pTop))
296             {
297                 fTop    = pTop->get_value();
298                 dot->set_y_value(fTop);
299             }
300             if ((pScroll != NULL) && (port == pScroll))
301             {
302                 const port_t *p = pScroll->metadata();
303                 float min;
304                 float value = pScroll->get_value();
305 
306                 if (is_log_rule(p))
307                 {
308                     min = fabs(p->min);
309 //                    max = fabs(p->max);
310 
311                     min = (min < GAIN_AMP_M_80_DB) ? logf(GAIN_AMP_M_80_DB) - p->step : logf(min);
312 //                    max = (max < GAIN_AMP_M_80_DB) ? logf(GAIN_AMP_M_80_DB) - p->step : logf(max);
313 
314                     value = (value < GAIN_AMP_M_80_DB) ? min : logf(value);
315                 }
316 
317                 dot->set_z_value(value);
318             }
319         }
320     } /* namespace ctl */
321 } /* namespace lsp */
322