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: 28 июн. 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 CtlButton::metadata = { "CtlButton", &CtlWidget::metadata };
29 
CtlButton(CtlRegistry * src,LSPButton * widget)30         CtlButton::CtlButton(CtlRegistry *src, LSPButton *widget): CtlWidget(src, widget)
31         {
32             pClass          = &metadata;
33             fValue          = 0.0f;
34             fDflValue       = 0.0f;
35             bValueSet       = false;
36             pPort           = NULL;
37         }
38 
~CtlButton()39         CtlButton::~CtlButton()
40         {
41             sEditable.destroy();
42         }
43 
slot_change(LSPWidget * sender,void * ptr,void * data)44         status_t CtlButton::slot_change(LSPWidget *sender, void *ptr, void *data)
45         {
46             CtlButton *_this    = static_cast<CtlButton *>(ptr);
47             if (_this != NULL)
48                 _this->submit_value();
49             return STATUS_OK;
50         }
51 
next_value(bool down)52         float CtlButton::next_value(bool down)
53         {
54             const port_t *mdata = (pPort != NULL) ? pPort->metadata() : NULL;
55             if (mdata == NULL)
56                 return (fValue >= 0.5f) ? 0.0f : 1.0f;
57 
58             // Analyze event
59             if (down)
60             {
61                 if (mdata->unit == U_ENUM)
62                     return (bValueSet) ? fDflValue : fValue;
63 //                if (!IS_TRIGGER_PORT(mdata))
64 //                    return fValue;
65             }
66 
67             // Get minimum and maximum
68             float min   = (mdata->flags & F_LOWER) ? mdata->min : 0.0;
69             float max   = (mdata->flags & F_UPPER) ? mdata->max : min + 1.0f;
70             float step  = (mdata->flags & F_STEP) ? mdata->step : 1.0;
71             if ((mdata->unit == U_ENUM) && (mdata->items != NULL))
72             {
73                 if (bValueSet)
74                     return fDflValue;
75 
76                 max     = mdata->min + list_size(mdata->items) - 1.0f;
77             }
78 
79             float value = fValue + step;
80             if (value > max)
81                 value = min;
82             else if (value < min)
83                 value = max;
84 
85             return value;
86         }
87 
submit_value()88         void CtlButton::submit_value()
89         {
90             LSPButton *btn = widget_cast<LSPButton>(pWidget);
91             if (btn == NULL)
92                 return;
93             lsp_trace("button is down=%s", (btn->is_down()) ? "true" : "false");
94 
95             float value     = next_value(btn->is_down());
96             if (value == fValue)
97             {
98                 if (bValueSet)
99                     btn->set_down(value == fDflValue);
100                 return;
101             }
102 
103             if (pPort != NULL)
104             {
105                 lsp_trace("Setting %s = %f", pPort->id(), value);
106                 pPort->set_value(value);
107                 pPort->notify_all();
108             }
109         }
110 
commit_value(float value)111         void CtlButton::commit_value(float value)
112         {
113             lsp_trace("commit value=%f", value);
114             LSPButton *btn = widget_cast<LSPButton>(pWidget);
115             if (btn == NULL)
116                 return;
117 
118             const port_t *mdata = (pPort != NULL) ? pPort->metadata() : NULL;
119 
120             if (mdata != NULL)
121             {
122                 fValue      = value;
123 
124                 float min   = (mdata->flags & F_LOWER) ? mdata->min : 0.0;
125                 float max   = (mdata->flags & F_UPPER) ? mdata->max : min + 1.0f;
126 
127                 if (mdata->unit == U_ENUM)
128                 {
129                     if (bValueSet)
130                         btn->set_down(fValue == fDflValue);
131                     else
132                         btn->set_down(false);
133                 }
134                 else if (!IS_TRIGGER_PORT(mdata))
135                     btn->set_down(fabs(value - max) < fabs(value - min));
136 //                else if (fValue == max)
137 //                    btn->set_down(true);
138 //                else
139 //                    btn->set_down(false);
140             }
141             else
142             {
143                 fValue      = (value >= 0.5f) ? 1.0f : 0.0f;
144                 btn->set_down(fValue >= 0.5f);
145             }
146         }
147 
init()148         void CtlButton::init()
149         {
150             CtlWidget::init();
151 
152             LSPButton *btn = widget_cast<LSPButton>(pWidget);
153             if (btn == NULL)
154                 return;
155 
156             // Initialize color controllers
157             sColor.init_hsl(pRegistry, btn, btn->color(), A_COLOR, A_HUE_ID, A_SAT_ID, A_LIGHT_ID);
158             sTextColor.init_basic(pRegistry, btn, btn->font()->color(), A_TEXT_COLOR);
159 
160             // Bind slots
161             btn->slots()->bind(LSPSLOT_CHANGE, slot_change, this);
162             sEditable.init(pRegistry, this);
163         }
164 
set(const char * name,const char * value)165         void CtlButton::set(const char *name, const char *value)
166         {
167             LSPButton *btn = widget_cast<LSPButton>(pWidget);
168             if (btn != NULL)
169                 set_lc_attr(A_TEXT, btn->title(), name, value);
170 
171             CtlWidget::set(name, value);
172         }
173 
set(widget_attribute_t att,const char * value)174         void CtlButton::set(widget_attribute_t att, const char *value)
175         {
176             LSPButton *btn = widget_cast<LSPButton>(pWidget);
177 
178             switch (att)
179             {
180                 case A_ID:
181                     BIND_PORT(pRegistry, pPort, value);
182                     break;
183                 case A_SIZE:
184                     if (btn != NULL)
185                         PARSE_INT(value, btn->set_min_size(__, __));
186                     break;
187                 case A_WIDTH:
188                     if (btn != NULL)
189                         PARSE_INT(value, btn->set_min_width(__));
190                     break;
191                 case A_HEIGHT:
192                     if (btn != NULL)
193                         PARSE_INT(value, btn->set_min_height(__));
194                     break;
195                 case A_VALUE:
196                     bValueSet = true;
197                     PARSE_FLOAT(value, fDflValue = __);
198                     commit_value(fDflValue);
199                     fDflValue = fValue;
200                     break;
201                 case A_LED:
202                     if (btn != NULL)
203                         PARSE_BOOL(value, btn->set_led(__));
204                     break;
205                 case A_EDITABLE:
206                     BIND_EXPR(sEditable, value);
207                     break;
208                 case A_FONT_SIZE:
209                     if (btn != NULL)
210                         PARSE_INT(value, btn->font()->set_size(__));
211                     break;
212                 default:
213                 {
214                     sColor.set(att, value);
215                     sTextColor.set(att, value);
216                     CtlWidget::set(att, value);
217                     break;
218                 }
219             }
220         }
221 
notify(CtlPort * port)222         void CtlButton::notify(CtlPort *port)
223         {
224             CtlWidget::notify(port);
225 
226             if (port == pPort)
227                 commit_value(pPort->get_value());
228 
229             // Trigger expressions
230             trigger_expr();
231         }
232 
trigger_expr()233         void CtlButton::trigger_expr()
234         {
235             LSPButton *btn = widget_cast<LSPButton>(pWidget);
236             if (btn == NULL)
237                 return;
238 
239             if (sEditable.valid())
240                 btn->set_editable(sEditable.evaluate() >= 0.5f);
241         }
242 
end()243         void CtlButton::end()
244         {
245             if (pWidget != NULL)
246             {
247                 LSPButton *btn = widget_cast<LSPButton>(pWidget);
248                 if (btn == NULL)
249                     return;
250 
251                 if (pPort != NULL)
252                 {
253                     const port_t *mdata = pPort->metadata();
254                     if (mdata != NULL)
255                     {
256                         if (IS_TRIGGER_PORT(mdata))
257                             btn->set_trigger();
258                         else if (mdata->unit != U_ENUM)
259                             btn->set_toggle();
260                         else if (bValueSet)
261                             btn->set_toggle();
262                     }
263 
264                     commit_value(pPort->get_value());
265                 }
266                 else
267                     commit_value(fValue);
268             }
269 
270             trigger_expr();
271 
272             CtlWidget::end();
273         }
274 
275     } /* namespace ctl */
276 } /* namespace lsp */
277