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