1 /**
2  * File name: top_bar.cpp
3  * Project: Geonkick (A kick synthesizer)
4  *
5  * Copyright (C) 2018 Iurie Nistor (http://iuriepage.wordpress.com)
6  *
7  * This file is part of Geonkick.
8  *
9  * GeonKick is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  */
23 
24 #include <cmath> // for std::fabs() from redkite/RkTransition.h
25 #include "top_bar.h"
26 #include "geonkick_button.h"
27 #include "preset_browser_model.h"
28 #include "preset_browser_view.h"
29 #include "ViewState.h"
30 #include "kit_model.h"
31 #include "percussion_model.h"
32 #include "MidiKeyWidget.h"
33 
34 #include <RkLabel.h>
35 #include <RkButton.h>
36 #include <RkTransition.h>
37 #include <RkContainer.h>
38 
39 RK_DECLARE_IMAGE_RC(separator);
40 RK_DECLARE_IMAGE_RC(logo);
41 RK_DECLARE_IMAGE_RC(open);
42 RK_DECLARE_IMAGE_RC(open_hover);
43 RK_DECLARE_IMAGE_RC(save);
44 RK_DECLARE_IMAGE_RC(save_hover);
45 RK_DECLARE_IMAGE_RC(export);
46 RK_DECLARE_IMAGE_RC(export_hover);
47 RK_DECLARE_IMAGE_RC(reset);
48 RK_DECLARE_IMAGE_RC(reset_hover);
49 RK_DECLARE_IMAGE_RC(reset_active);
50 RK_DECLARE_IMAGE_RC(play);
51 RK_DECLARE_IMAGE_RC(play_pressed);
52 RK_DECLARE_IMAGE_RC(play_hover);
53 RK_DECLARE_IMAGE_RC(layer1);
54 RK_DECLARE_IMAGE_RC(layer2);
55 RK_DECLARE_IMAGE_RC(layer3);
56 RK_DECLARE_IMAGE_RC(layer1_disabled);
57 RK_DECLARE_IMAGE_RC(layer2_disabled);
58 RK_DECLARE_IMAGE_RC(layer3_disabled);
59 RK_DECLARE_IMAGE_RC(layer1_hover);
60 RK_DECLARE_IMAGE_RC(layer2_hover);
61 RK_DECLARE_IMAGE_RC(layer3_hover);
62 RK_DECLARE_IMAGE_RC(tune_checkbox_on);
63 RK_DECLARE_IMAGE_RC(tune_checkbox_off);
64 RK_DECLARE_IMAGE_RC(tune_checkbox_hover);
65 RK_DECLARE_IMAGE_RC(topmenu_controls_active);
66 RK_DECLARE_IMAGE_RC(topmenu_controls_hover);
67 RK_DECLARE_IMAGE_RC(topmenu_controls_off);
68 RK_DECLARE_IMAGE_RC(topmenu_midi_off);
69 RK_DECLARE_IMAGE_RC(topmenu_midi_active);
70 RK_DECLARE_IMAGE_RC(topmenu_midi_hover);
71 #ifndef GEONKICK_SINGLE
72 RK_DECLARE_IMAGE_RC(topmenu_kit_active);
73 RK_DECLARE_IMAGE_RC(topmenu_kit_hover);
74 RK_DECLARE_IMAGE_RC(topmenu_kit_off);
75 #endif // GEONKICK_SINGLE
76 RK_DECLARE_IMAGE_RC(topmenu_presets_active);
77 RK_DECLARE_IMAGE_RC(topmenu_presets_hover);
78 RK_DECLARE_IMAGE_RC(topmenu_presets_off);
79 RK_DECLARE_IMAGE_RC(topmenu_samples_active);
80 RK_DECLARE_IMAGE_RC(topmenu_samples_hover);
81 RK_DECLARE_IMAGE_RC(topmenu_samples_off);
82 
TopBar(GeonkickWidget * parent,KitModel * model)83 TopBar::TopBar(GeonkickWidget *parent, KitModel *model)
84         : GeonkickWidget(parent)
85         , kitModel{model}
86         , openFileButton{nullptr}
87         , saveFileButton{nullptr}
88         , exportFileButton{nullptr}
89         , presetNameLabel{nullptr}
90         , layer1Button{nullptr}
91         , layer2Button{nullptr}
92         , layer3Button{nullptr}
93         , controlsButton{nullptr}
94         , midiKeyButton{nullptr}
95 #ifndef GEONKICK_SINGLE
96         , kitButton{nullptr}
97 #endif // GEONKICK_SINGLE
98         , presetsButton{nullptr}
99         , samplesButton{nullptr}
100 {
101         setFixedSize({parent->width(), 30});
102         auto mainLayout = new RkContainer(this);
103         mainLayout->setSize(size());
104 
105         auto logo = new RkLabel(this);
106         RkImage image(62, 10, RK_IMAGE_RC(logo));
107         logo->setSize(image.width(), image.height());
108         logo->setBackgroundColor(68, 68, 70);
109         logo->setImage(image);
110         logo->show();
111         mainLayout->addWidget(logo);
112         addSeparator(mainLayout, 10);
113 
114         openFileButton = new GeonkickButton(this);
115         openFileButton->show();
116         openFileButton->setSize(26, 10);
117         openFileButton->setType(RkButton::ButtonType::ButtonCheckable);
118         openFileButton->setImage(RkImage(openFileButton->size(), RK_IMAGE_RC(open)),
119                                  RkButton::State::Unpressed);
120         openFileButton->setImage(RkImage(openFileButton->size(), RK_IMAGE_RC(open_hover)),
121                                  RkButton::State::UnpressedHover);
122         openFileButton->setImage(RkImage(openFileButton->size(), RK_IMAGE_RC(open_hover)),
123                                  RkButton::State::Pressed);
__anon175a8eb20102()124         RK_ACT_BINDL(openFileButton, pressed, RK_ACT_ARGS(), [=](){openFileButton->setPressed(false);
125                                                               action openFile();});
126         mainLayout->addWidget(openFileButton);
127         addSeparator(mainLayout, 10);
128 
129         saveFileButton = new GeonkickButton(this);
130         saveFileButton->setSize(23, 10);
131         saveFileButton->setType(RkButton::ButtonType::ButtonCheckable);
132         saveFileButton->setImage(RkImage(saveFileButton->size(), RK_IMAGE_RC(save)),
133                                  RkButton::State::Unpressed);
134         saveFileButton->setImage(RkImage(saveFileButton->size(), RK_IMAGE_RC(save_hover)),
135                                  RkButton::State::UnpressedHover);
136         saveFileButton->setImage(RkImage(saveFileButton->size(), RK_IMAGE_RC(save_hover)),
137                                  RkButton::State::Pressed);
__anon175a8eb20202()138         RK_ACT_BINDL(saveFileButton, pressed, RK_ACT_ARGS(), [=](){saveFileButton->setPressed(false);
139                                                              action saveFile();});
140         mainLayout->addWidget(saveFileButton);
141         addSeparator(mainLayout, 10);
142 
143         exportFileButton = new GeonkickButton(this);
144         exportFileButton->setSize(29, 10);
145         saveFileButton->setType(RkButton::ButtonType::ButtonCheckable);
146         exportFileButton->setImage(RkImage(exportFileButton->size(), RK_IMAGE_RC(export)),
147                                  RkButton::State::Unpressed);
148         exportFileButton->setImage(RkImage(exportFileButton->size(), RK_IMAGE_RC(export_hover)),
149                                  RkButton::State::UnpressedHover);
150         exportFileButton->setImage(RkImage(exportFileButton->size(), RK_IMAGE_RC(export_hover)),
151                                 RkButton::State::Pressed);
__anon175a8eb20302()152         RK_ACT_BINDL(exportFileButton, pressed, RK_ACT_ARGS(), [=](){exportFileButton->setPressed(false);
153                                                                action openExport();});
154         mainLayout->addWidget(exportFileButton);
155         addSeparator(mainLayout, 10);
156 
157 	auto playButton = new RkButton(this);
158         playButton->setType(RkButton::ButtonType::ButtonPush);
159         playButton->setSize(43, 18);
160         playButton->setImage(RkImage(playButton->size(), RK_IMAGE_RC(play)),
161                              RkButton::State::Unpressed);
162         playButton->setImage(RkImage(playButton->size(), RK_IMAGE_RC(play_hover)),
163                              RkButton::State::UnpressedHover);
164         playButton->setImage(RkImage(playButton->size(), RK_IMAGE_RC(play_pressed)),
165                              RkButton::State::Pressed);
166         RK_ACT_BIND(playButton, pressed, RK_ACT_ARGS(), kitModel->api(), playKick());
167 	playButton->show();
168         mainLayout->addWidget(playButton);
169         addSeparator(mainLayout, 10);
170 
171         createLyersButtons(mainLayout);
172         addSeparator(mainLayout, 10);
173 
174         auto resetButton = new RkButton(this);
175         resetButton->setSize(33, 18);
176         resetButton->setType(RkButton::ButtonType::ButtonPush);
177         resetButton->setImage(RkImage(resetButton->size(), RK_IMAGE_RC(reset)),
178                               RkButton::State::Unpressed);
179         resetButton->setImage(RkImage(resetButton->size(), RK_IMAGE_RC(reset_hover)),
180                               RkButton::State::UnpressedHover);
181         resetButton->setImage(RkImage(resetButton->size(), RK_IMAGE_RC(reset_active)),
182                               RkButton::State::Pressed);
183         resetButton->show();
184         RK_ACT_BIND(resetButton, pressed, RK_ACT_ARGS(), this, resetToDefault());
185         mainLayout->addWidget(resetButton);
186 
187         addSeparator(mainLayout, 10);
188 
189         tuneCheckbox = new GeonkickButton(this);
190         tuneCheckbox->setCheckable(true);
191         tuneCheckbox->setFixedSize(33, 18);
192         tuneCheckbox->setImage(RkImage(tuneCheckbox->size(), RK_IMAGE_RC(tune_checkbox_off)),
193                                RkButton::State::Unpressed);
194         tuneCheckbox->setImage(RkImage(tuneCheckbox->size(), RK_IMAGE_RC(tune_checkbox_on)),
195                                RkButton::State::Pressed);
196         tuneCheckbox->setImage(RkImage(tuneCheckbox->size(), RK_IMAGE_RC(tune_checkbox_hover)),
197                                RkButton::State::PressedHover);
198         tuneCheckbox->setImage(RkImage(tuneCheckbox->size(), RK_IMAGE_RC(tune_checkbox_hover)),
199                                RkButton::State::UnpressedHover);
200         tuneCheckbox->show();
201         RK_ACT_BIND(tuneCheckbox, toggled, RK_ACT_ARGS(bool b), kitModel->api(),
202 		    tuneAudioOutput(kitModel->api()->currentPercussion(), b));
203         mainLayout->addWidget(tuneCheckbox);
204         addSeparator(mainLayout, 10);
205 
206         presetNameLabel = new RkLabel(this);
207         presetNameLabel->setBackgroundColor(background());
208         presetNameLabel->setTextColor({210, 226, 226, 140});
209         auto font = presetNameLabel->font();
210         font.setSize(10);
211         presetNameLabel->setFont(font);
212         presetNameLabel->setSize(80, 30);
213         presetNameLabel->show();
214         mainLayout->addWidget(presetNameLabel);
215 
216         addSeparator(mainLayout);
217         midiKeyButton = new GeonkickButton(this);
218         midiKeyButton->setTextColor({200, 200, 200});
219         midiKeyButton->setType(RkButton::ButtonType::ButtonUncheckable);
220         midiKeyButton->setSize(36, 20);
221         midiKeyButton->setImage(RkImage(midiKeyButton->size(), RK_IMAGE_RC(topmenu_midi_off)),
222                                 RkButton::State::Unpressed);
223         midiKeyButton->setImage(RkImage(midiKeyButton->size(), RK_IMAGE_RC(topmenu_midi_active)),
224                                 RkButton::State::Pressed);
225         midiKeyButton->setImage(RkImage(midiKeyButton->size(), RK_IMAGE_RC(topmenu_midi_hover)),
226                                 RkButton::State::UnpressedHover);
227         RK_ACT_BIND(midiKeyButton, toggled,
228                     RK_ACT_ARGS(bool pressed),
229                     this,
230                     showMidiPopup());
231         mainLayout->addWidget(midiKeyButton);
232 
233         // Controls button
234         addSeparator(mainLayout);
235         controlsButton = new GeonkickButton(this);
236         controlsButton->setPressed(viewState()->getMainView() == ViewState::View::Controls);
237         controlsButton->setFixedSize(54, 20);
238         controlsButton->setImage(RkImage(controlsButton->size(), RK_IMAGE_RC(topmenu_controls_off)),
239                                RkButton::State::Unpressed);
240         controlsButton->setImage(RkImage(controlsButton->size(), RK_IMAGE_RC(topmenu_controls_active)),
241                                RkButton::State::Pressed);
242         controlsButton->setImage(RkImage(controlsButton->size(), RK_IMAGE_RC(topmenu_controls_hover)),
243                                RkButton::State::UnpressedHover);
244         controlsButton->show();
245         mainLayout->addWidget(controlsButton);
246         RK_ACT_BIND(controlsButton, pressed, RK_ACT_ARGS(),
247                     viewState(), setMainView(ViewState::View::Controls));
248         RK_ACT_BIND(viewState(), mainViewChanged, RK_ACT_ARGS(ViewState::View view),
249                     controlsButton, setPressed(view == ViewState::View::Controls));
250 
251 #ifndef GEONKICK_SINGLE
252         // Kit button
253         addSeparator(mainLayout);
254         kitButton = new GeonkickButton(this);
255         kitButton->setPressed(viewState()->getMainView() == ViewState::View::Kit);
256         kitButton->setFixedSize(54, 20);
257         kitButton->setImage(RkImage(kitButton->size(), RK_IMAGE_RC(topmenu_kit_off)),
258                                RkButton::State::Unpressed);
259         kitButton->setImage(RkImage(kitButton->size(), RK_IMAGE_RC(topmenu_kit_active)),
260                                RkButton::State::Pressed);
261         kitButton->setImage(RkImage(kitButton->size(), RK_IMAGE_RC(topmenu_kit_hover)),
262                                RkButton::State::UnpressedHover);
263         kitButton->show();
264         RK_ACT_BIND(kitButton, pressed, RK_ACT_ARGS(),
265                     viewState(), setMainView(ViewState::View::Kit));
266         RK_ACT_BIND(viewState(), mainViewChanged, RK_ACT_ARGS(ViewState::View view),
267                     kitButton, setPressed(view == ViewState::View::Kit));
268         mainLayout->addWidget(kitButton);
269 #endif // GEONKICK_SINGLE
270 
271         // Presets button
272         addSeparator(mainLayout);
273         presetsButton = new GeonkickButton(this);
274         presetsButton->setPressed(viewState()->getMainView() == ViewState::View::Presets);
275         presetsButton->setFixedSize(54, 20);
276         presetsButton->setImage(RkImage(presetsButton->size(), RK_IMAGE_RC(topmenu_presets_off)),
277                                RkButton::State::Unpressed);
278         presetsButton->setImage(RkImage(presetsButton->size(), RK_IMAGE_RC(topmenu_presets_active)),
279                                RkButton::State::Pressed);
280         presetsButton->setImage(RkImage(presetsButton->size(), RK_IMAGE_RC(topmenu_presets_hover)),
281                                RkButton::State::UnpressedHover);
282         presetsButton->show();
283         RK_ACT_BIND(presetsButton, pressed, RK_ACT_ARGS(),
284                     viewState(), setMainView(ViewState::View::Presets));
285         RK_ACT_BIND(viewState(), mainViewChanged, RK_ACT_ARGS(ViewState::View view),
286                     presetsButton, setPressed(view == ViewState::View::Presets));
287         mainLayout->addWidget(presetsButton);
288 
289         // Samples button
290         addSeparator(mainLayout);
291         samplesButton = new GeonkickButton(this);
292         samplesButton->setPressed(viewState()->getMainView() == ViewState::View::Samples);
293         samplesButton->setFixedSize(54, 20);
294         samplesButton->setImage(RkImage(samplesButton->size(), RK_IMAGE_RC(topmenu_samples_off)),
295                                RkButton::State::Unpressed);
296         samplesButton->setImage(RkImage(samplesButton->size(), RK_IMAGE_RC(topmenu_samples_active)),
297                                RkButton::State::Pressed);
298         samplesButton->setImage(RkImage(samplesButton->size(), RK_IMAGE_RC(topmenu_samples_hover)),
299                                RkButton::State::UnpressedHover);
300         samplesButton->show();
301         RK_ACT_BIND(samplesButton, pressed, RK_ACT_ARGS(),
302                     viewState(), setMainView(ViewState::View::Samples));
303         RK_ACT_BIND(viewState(), mainViewChanged, RK_ACT_ARGS(ViewState::View view),
304                     samplesButton, setPressed(view == ViewState::View::Samples));
305         mainLayout->addWidget(samplesButton);
306 
307         RK_ACT_BIND(kitModel, modelUpdated, RK_ACT_ARGS(), this, updateGui());
308         RK_ACT_BINDL(kitModel, percussionUpdated, RK_ACT_ARGS(PercussionModel* model),
__anon175a8eb20402(PercussionModel* model) 309                      [=](PercussionModel* model) {
310                              if (model->isSelected())
311                                      updateGui();
312                      } );
313         updateGui();
314 }
315 
addSeparator(RkContainer * mainLayout,int width)316 void TopBar::addSeparator(RkContainer *mainLayout, int width)
317 {
318         mainLayout->addSpace(width);
319         auto separator = new RkLabel(this);
320         separator->setSize(2, 21);
321         separator->setBackgroundColor(68, 68, 70);
322         separator->setImage(RkImage(separator->size(), RK_IMAGE_RC(separator)));
323         separator->show();
324         mainLayout->addWidget(separator);
325         mainLayout->addSpace(width);
326 }
327 
createLyersButtons(RkContainer * mainLayout)328 void TopBar::createLyersButtons(RkContainer *mainLayout)
329 {
330         layer1Button = new GeonkickButton(this);
331         layer1Button->setBackgroundColor(background());
332         layer1Button->setSize(24, 18);
333         layer1Button->setImage(RkImage(layer1Button->size(), RK_IMAGE_RC(layer1_disabled)),
334                                RkButton::State::Unpressed);
335         layer1Button->setImage(RkImage(layer1Button->size(), RK_IMAGE_RC(layer1)),
336                                RkButton::State::Pressed);
337         layer1Button->setImage(RkImage(layer1Button->size(), RK_IMAGE_RC(layer1_hover)),
338                                RkButton::State::PressedHover);
339         layer1Button->setImage(RkImage(layer1Button->size(), RK_IMAGE_RC(layer1_hover)),
340                                RkButton::State::UnpressedHover);
341 
342         layer1Button->setCheckable(true);
343         mainLayout->addWidget(layer1Button);
344         mainLayout->addSpace(2);
345 
346         layer2Button = new GeonkickButton(this);
347         layer2Button->setBackgroundColor(background());
348         layer2Button->setSize(24, 18);
349         layer2Button->setImage(RkImage(layer2Button->size(), RK_IMAGE_RC(layer2_disabled)),
350                                RkButton::State::Unpressed);
351         layer2Button->setImage(RkImage(layer2Button->size(), RK_IMAGE_RC(layer2)),
352                                RkButton::State::Pressed);
353         layer2Button->setImage(RkImage(layer2Button->size(), RK_IMAGE_RC(layer2_hover)),
354                                RkButton::State::PressedHover);
355         layer2Button->setImage(RkImage(layer2Button->size(), RK_IMAGE_RC(layer2_hover)),
356                                RkButton::State::UnpressedHover);
357 
358         layer2Button->setCheckable(true);
359         mainLayout->addWidget(layer2Button);
360         mainLayout->addSpace(2);
361 
362         layer3Button = new GeonkickButton(this);
363         layer3Button->setBackgroundColor(background());
364         layer3Button->setSize(24, 18);
365         layer3Button->setImage(RkImage(layer3Button->size(), RK_IMAGE_RC(layer3_disabled)),
366                                RkButton::State::Unpressed);
367         layer3Button->setImage(RkImage(layer3Button->size(), RK_IMAGE_RC(layer3)),
368                                RkButton::State::Pressed);
369         layer3Button->setImage(RkImage(layer3Button->size(), RK_IMAGE_RC(layer3_hover)),
370                                RkButton::State::PressedHover);
371         layer3Button->setImage(RkImage(layer3Button->size(), RK_IMAGE_RC(layer3_hover)),
372                                RkButton::State::UnpressedHover);
373 
374         layer3Button->setCheckable(true);
375         mainLayout->addWidget(layer3Button);
376 
377         RK_ACT_BIND(layer1Button, toggled, RK_ACT_ARGS(bool b),
378                     kitModel->api(), enbaleLayer(GeonkickApi::Layer::Layer1, b));
379         RK_ACT_BIND(layer3Button, toggled, RK_ACT_ARGS(bool b),
380                     kitModel->api(), enbaleLayer(GeonkickApi::Layer::Layer3, b));
381         RK_ACT_BIND(layer2Button, toggled, RK_ACT_ARGS(bool b),
382                     kitModel->api(), enbaleLayer(GeonkickApi::Layer::Layer2, b));
383 }
384 
setPresetName(const std::string & name)385 void TopBar::setPresetName(const std::string &name)
386 {
387         if (name.size() > 20) {
388                 std::string preset = name;
389                 preset.resize(15);
390                 preset += "...";
391                 presetNameLabel->setText(preset);
392         } else {
393                 presetNameLabel->setText(name);
394         }
395 }
396 
updateGui()397 void TopBar::updateGui()
398 {
399         auto api = kitModel->api();
400         layer1Button->setPressed(api->isLayerEnabled(GeonkickApi::Layer::Layer1));
401         layer2Button->setPressed(api->isLayerEnabled(GeonkickApi::Layer::Layer2));
402         layer3Button->setPressed(api->isLayerEnabled(GeonkickApi::Layer::Layer3));
403         tuneCheckbox->setPressed(api->isAudioOutputTuned(api->currentPercussion()));
404         setPresetName(kitModel->currentPercussion()->name());
405         midiKeyButton->setText(MidiKeyWidget::midiKeyToNote(kitModel->currentPercussion()->key()));
406 }
407 
showMidiPopup()408 void TopBar::showMidiPopup()
409 {
410         auto midiPopup = new MidiKeyWidget(dynamic_cast<GeonkickWidget*>(getTopWidget()),
411                                            kitModel->currentPercussion());
412         midiPopup->setPosition(midiKeyButton->x() - 170, y() + 35);
413         RK_ACT_BIND(midiPopup,
414                     isAboutToClose,
415                     RK_ACT_ARGS(),
416                     midiKeyButton,
417                     setPressed(false));
418         midiPopup->show();
419 }
420