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 CtlMarker::metadata = { "CtlMarker", &CtlWidget::metadata };
29 
CtlMarker(CtlRegistry * src,LSPMarker * mark)30         CtlMarker::CtlMarker(CtlRegistry *src, LSPMarker *mark): CtlWidget(src, mark)
31         {
32             pClass          = &metadata;
33             pPort           = NULL;
34             fTransparency   = 0.0f;
35         }
36 
~CtlMarker()37         CtlMarker::~CtlMarker()
38         {
39         }
40 
slot_change(LSPWidget * sender,void * ptr,void * data)41         status_t CtlMarker::slot_change(LSPWidget *sender, void *ptr, void *data)
42         {
43             CtlMarker *_this    = static_cast<CtlMarker *>(ptr);
44             if (_this != NULL)
45                 _this->submit_values();
46             return STATUS_OK;
47         }
48 
slot_graph_resize(LSPWidget * sender,void * ptr,void * data)49         status_t CtlMarker::slot_graph_resize(LSPWidget *sender, void *ptr, void *data)
50         {
51             CtlMarker *_this    = static_cast<CtlMarker *>(ptr);
52             if (_this != NULL)
53                 _this->trigger_expr();
54             return STATUS_OK;
55         }
56 
submit_values()57         void CtlMarker::submit_values()
58         {
59             if (pPort == NULL)
60                 return;
61             LSPMarker *mark   = widget_cast<LSPMarker>(pWidget);
62             if (mark == NULL)
63                 return;
64 
65             if (mark->editable())
66             {
67                 float v = mark->value();
68                 if (v == pPort->get_value())
69                     return;
70 
71                 pPort->set_value(v);
72                 pPort->notify_all();
73             }
74         }
75 
init()76         void CtlMarker::init()
77         {
78             CtlWidget::init();
79             if (pWidget == NULL)
80                 return;
81 
82             LSPMarker *mark   = widget_cast<LSPMarker>(pWidget);
83             if (mark == NULL)
84                 return;
85 
86             // Initialize color controllers
87             sColor.init_hsl(pRegistry, mark, mark->color(), A_COLOR, A_HUE_ID, A_SAT_ID, A_LIGHT_ID);
88 
89             // Bind slots
90             mark->slots()->bind(LSPSLOT_CHANGE, slot_change, this);
91             mark->slots()->bind(LSPSLOT_RESIZE_PARENT, slot_graph_resize, this);
92 
93             sAngle.init(pRegistry, this);
94             sDX.init(pRegistry, this);
95             sDY.init(pRegistry, this);
96             sValue.init(pRegistry, this);
97         }
98 
set(widget_attribute_t att,const char * value)99         void CtlMarker::set(widget_attribute_t att, const char *value)
100         {
101             LSPMarker *mark = widget_cast<LSPMarker>(pWidget);
102 
103             switch (att)
104             {
105                 case A_ID:
106                     if (mark != NULL)
107                         BIND_PORT(pRegistry, pPort, value);
108                     break;
109                 case A_VALUE:
110                     BIND_EXPR(sValue, value);
111                     break;
112                 case A_OFFSET:
113                     if (mark != NULL)
114                         PARSE_FLOAT(value, mark->set_offset(__));
115                     break;
116                 case A_ANGLE:
117                     BIND_EXPR(sAngle, value);
118                     break;
119                 case A_DX:
120                     BIND_EXPR(sDX, value);
121                     break;
122                 case A_DY:
123                     BIND_EXPR(sDY, value);
124                     break;
125                 case A_SMOOTH:
126                     if (mark != NULL)
127                         PARSE_BOOL(value, mark->set_smooth(__));
128                     break;
129                 case A_FILL:
130                     PARSE_FLOAT(value, fTransparency = __);
131                     break;
132                 case A_BASIS:
133                     if (mark != NULL)
134                         PARSE_INT(value, mark->set_basis_id(__));
135                     break;
136                 case A_PARALLEL:
137                     if (mark != NULL)
138                         PARSE_INT(value, mark->set_parallel_id(__));
139                     break;
140                 case A_WIDTH:
141                     if (mark != NULL)
142                         PARSE_INT(value, mark->set_width(__));
143                     break;
144                 case A_CENTER:
145                     if (mark != NULL)
146                         PARSE_INT(value, mark->set_center(__));
147                     break;
148                 case A_BORDER:
149                     if (mark != NULL)
150                         PARSE_INT(value, mark->set_border(__));
151                     break;
152                 case A_EDITABLE:
153                     if (mark != NULL)
154                         PARSE_BOOL(value, mark->set_editable(__));
155                     break;
156                 case A_MIN:
157                     if (mark != NULL)
158                         PARSE_FLOAT(value, mark->set_minimum(__));
159                     break;
160                 case A_MAX:
161                     if (mark != NULL)
162                         PARSE_FLOAT(value, mark->set_maximum(__));
163                     break;
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 CtlMarker::end()
175         {
176             if (pPort != NULL)
177                 notify(pPort);
178             sColor.set_alpha(fTransparency);
179 
180             LSPMarker *mark = widget_cast<LSPMarker>(pWidget);
181             if ((mark != NULL) && (mark->editable()))
182             {
183                 const port_t *p = (pPort != NULL) ? pPort->metadata() : NULL;
184                 if (p != NULL)
185                 {
186                     if (p->flags & F_LOWER)
187                         mark->set_minimum(p->min);
188                     if (p->flags & F_UPPER)
189                         mark->set_maximum(p->max);
190                 }
191             }
192 
193             trigger_expr();
194 
195             CtlWidget::end();
196         }
197 
eval_expr(CtlExpression * expr)198         float CtlMarker::eval_expr(CtlExpression *expr)
199         {
200             LSPMarker *mark   = widget_cast<LSPMarker>(pWidget);
201             if (mark == NULL)
202                 return 0.0f;
203 
204             LSPGraph *g = mark->graph();
205             if (g == NULL)
206                 return 0.0f;
207 
208             expr->params()->clear();
209             expr->params()->set_int("_g_width", g->width());
210             expr->params()->set_int("_g_height", g->height());
211             expr->params()->set_int("_a_width", g->area_width());
212             expr->params()->set_int("_a_height", g->area_height());
213 
214             return expr->evaluate();
215         }
216 
trigger_expr()217         void CtlMarker::trigger_expr()
218         {
219             LSPMarker *mark   = widget_cast<LSPMarker>(pWidget);
220             if (mark == NULL)
221                 return;
222 
223             if (sAngle.valid())
224             {
225                 float angle = eval_expr(&sAngle);
226                 mark->set_angle(angle * M_PI);
227             }
228 
229             if (sValue.valid())
230             {
231                 float value = eval_expr(&sValue);
232                 mark->set_value(value);
233             }
234 
235             if (sDX.valid())
236             {
237                 float dx = eval_expr(&sDX);
238                 if (sDY.valid())
239                 {
240                     float dy = eval_expr(&sDY);
241                     mark->set_direction(dx, dy);
242                 }
243                 else
244                     mark->set_dir_x(dx);
245             }
246             else if (sDY.valid())
247             {
248                 float dy = eval_expr(&sDY);
249                 mark->set_dir_y(dy);
250             }
251         }
252 
notify(CtlPort * port)253         void CtlMarker::notify(CtlPort *port)
254         {
255             CtlWidget::notify(port);
256 
257             if (pPort == port)
258             {
259                 LSPMarker *mark = widget_cast<LSPMarker>(pWidget);
260                 if (mark != NULL)
261                     mark->set_value(pPort->get_value());
262             }
263 
264             trigger_expr();
265         }
266     } /* namespace ctl */
267 } /* namespace lsp */
268