1 /* B.SEQuencer
2 * MIDI Step Sequencer LV2 Plugin
3 *
4 * Copyright (C) 2018, 2019 by Sven Jähnichen
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21 #ifndef SCALEEDITOR_HPP_
22 #define SCALEEDITOR_HPP_
23
24 #include <utility>
25 #include "definitions.h"
26 #include "BScale.hpp"
27 #include "ScaleMap.hpp"
28 #include "BWidgets/Widget.hpp"
29 #include "BWidgets/ValueWidget.hpp"
30 #include "BWidgets/HPianoRoll.hpp"
31 #include "BWidgets/Label.hpp"
32 #include "BWidgets/PopupListBox.hpp"
33 #include "BWidgets/TextButton.hpp"
34 #include "BWidgets/ImageIcon.hpp"
35
36 #ifdef LOCALEFILE
37 #include LOCALEFILE
38 #else
39 #include "Locale_EN.hpp"
40 #endif
41
42 class ScaleEditor : public BWidgets::ValueWidget
43 {
44 public:
45 ScaleEditor ();
46 ScaleEditor (const double x, const double y, const double width, const double height,
47 const std::string& name, const std::string& pluginPath,
48 const int mapNr, const ScaleMap& scaleMap, const BScale& scale);
49
50 virtual void resize (double width, double height) override;
51 void setScaleMap (const ScaleMap& scaleMap);
52 ScaleMap getScaleMap () const;
53 void setScale (const BScale& scale);
54 BScale getScale () const;
55 void setMapNr (const int nr);
56 int getMapNr () const;
57
58 protected:
59 void szScaleEditor ();
60 void updateAltSymbol (int nr);
61 static void symbolDragCallback (BEvents::Event* event);
62 static void symbolListboxValueChangedCallback (BEvents::Event* event);
63 static void noteListboxValueChangedCallback (BEvents::Event* event);
64 static void buttonClickCallback (BEvents::Event* event);
65 static void labelClickCallback (BEvents::Event* event);
66 static void labelMessageCallback (BEvents::Event* event);
67 static void pianoClickCallback (BEvents::Event* event);
68
69 BWidgets::Label nameLabel;
70 BWidgets::Label scaleNameLabel;
71 BWidgets::Label rowLabel;
72 BWidgets::Label symbolLabel;
73 BWidgets::Label noteLabel;
74 BWidgets::Label altSymbolLabel;
75 std::array<BWidgets::ImageIcon, ROWS> drumSymbol;
76 std::array<BWidgets::ImageIcon, ROWS>noteSymbol;
77 std::array<BWidgets::Label, ROWS> nrLabel;
78 std::array<BWidgets::PopupListBox, ROWS> nrSymbolListbox;
79 std::array<BWidgets::PopupListBox, ROWS> nrNoteListbox;
80 std::array<BWidgets::Label, ROWS> nrNoteLabel;
81 std::array<BWidgets::Label, ROWS> nrAltSymbolLabel;
82 BWidgets::HPianoRoll piano;
83 BWidgets::TextButton cancelButton;
84 BWidgets::TextButton applyButton;
85
86 int pianoRoot;
87 BScale scale;
88 ScaleMap scaleMap;
89 int mapNr;
90
91 double sz;
92
93 cairo_surface_t* bgSurface;
94
95 BColors::ColorSet txColors = {{{0.167, 0.37, 0.80, 1.0}, {0.33, 0.5, 0.85, 1.0}, {0.0, 0.0, 0.25, 1.0}, {0.0, 0.0, 0.0, 0.0}}};
96 BColors::ColorSet bgColors = {{{0.15, 0.15, 0.15, 1.0}, {0.3, 0.3, 0.3, 1.0}, {0.05, 0.05, 0.05, 1.0}, {0.0, 0.0, 0.0, 1.0}}};
97 BStyles::Border border = {{BColors::white, 1.0}, 0.0, 2.0, 0.0};
98 BStyles::Border menuBorder = {{BColors::darkgrey, 1.0}, 0.0, 0.0, 0.0};
99 BStyles::Border labelborder = {BStyles::noLine, 4.0, 0.0, 0.0};
100 BStyles::Fill scaleEditorBg = BStyles::blackFill;
101 BStyles::Fill menuBg = BStyles::Fill (BColors::Color (0.0, 0.0, 0.05, 1.0));
102 BStyles::Font ctLabelFont = BStyles::Font ("Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL, 12.0,
103 BStyles::TEXT_ALIGN_CENTER, BStyles::TEXT_VALIGN_MIDDLE);
104 BStyles::Font lfLabelFont = BStyles::Font ("Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL, 12.0,
105 BStyles::TEXT_ALIGN_LEFT, BStyles::TEXT_VALIGN_MIDDLE);
106 BStyles::StyleSet defaultStyles = {"default", {{"background", STYLEPTR (&BStyles::noFill)},
107 {"border", STYLEPTR (&BStyles::noBorder)}}};
108 BStyles::StyleSet labelStyles = {"labels", {{"background", STYLEPTR (&BStyles::noFill)},
109 {"border", STYLEPTR (&BStyles::noBorder)},
110 {"textcolors", STYLEPTR (&txColors)},
111 {"font", STYLEPTR (&ctLabelFont)}}};
112
113 BStyles::Theme theme = BStyles::Theme ({
114 defaultStyles,
115 {"scaleeditor", {{"background", STYLEPTR (&scaleEditorBg)},
116 {"border", STYLEPTR (&border)}}},
117 {"widget", {{"uses", STYLEPTR (&defaultStyles)}}},
118 {"ctlabel", {{"uses", STYLEPTR (&labelStyles)},
119 {"font", STYLEPTR (&ctLabelFont)}}},
120 {"lflabel", {{"uses", STYLEPTR (&labelStyles)},
121 {"font", STYLEPTR (&lfLabelFont)}}},
122 {"button", {{"font", STYLEPTR (&ctLabelFont)}}},
123 {"xsymbol", {{"uses", STYLEPTR (&defaultStyles)},
124 {"fgcolors", STYLEPTR (&BColors::whites)},
125 {"font", STYLEPTR (&ctLabelFont)}}},
126 {"menu", {{"border", STYLEPTR (&menuBorder)},
127 {"background", STYLEPTR (&menuBg)}}},
128 {"menu/item", {{"uses", STYLEPTR (&defaultStyles)},
129 {"border", STYLEPTR (&labelborder)},
130 {"textcolors", STYLEPTR (&BColors::whites)},
131 {"font", STYLEPTR (&lfLabelFont)}}},
132 {"menu/button", {{"border", STYLEPTR (&menuBorder)},
133 {"background", STYLEPTR (&menuBg)},
134 {"bgcolors", STYLEPTR (&bgColors)}}},
135 {"menu/listbox", {{"border", STYLEPTR (&menuBorder)},
136 {"background", STYLEPTR (&menuBg)}}},
137 {"menu/listbox/item", {{"uses", STYLEPTR (&defaultStyles)},
138 {"border", STYLEPTR (&labelborder)},
139 {"textcolors", STYLEPTR (&BColors::whites)},
140 {"font", STYLEPTR (&lfLabelFont)}}},
141 {"menu/listbox//button",{{"border", STYLEPTR (&menuBorder)},
142 {"background", STYLEPTR (&menuBg)},
143 {"bgcolors", STYLEPTR (&bgColors)}}}
144 });
145
146 };
147
ScaleEditor()148 ScaleEditor::ScaleEditor() : ScaleEditor (0, 0, 0, 0, "editor", "", 0, ScaleMap (), BScale (0, defaultScale)) {}
149
ScaleEditor(const double x,const double y,const double width,const double height,const std::string & name,const std::string & pluginPath,const int mapNr,const ScaleMap & scaleMap,const BScale & scale)150 ScaleEditor::ScaleEditor(const double x, const double y, const double width, const double height, const std::string& name,
151 const std::string& pluginPath, const int mapNr, const ScaleMap& scaleMap, const BScale& scale) :
152 BWidgets::ValueWidget (x, y, width, height, name, 0.0),
153 nameLabel (20, 60, 80, 20, "lflabel", BSEQUENCER_LABEL_SCALE_NAME ":"),
154 scaleNameLabel (120, 60, 320, 20, "lflabel", scaleMap.name),
155 rowLabel (20, 100, 80, 20, "lflabel", BSEQUENCER_LABEL_ROW),
156 symbolLabel (70, 100, 48, 20, "ctlabel", BSEQUENCER_LABEL_MODE),
157 noteLabel (148, 100, 80, 20, "ctlabel", BSEQUENCER_LABEL_NOTE),
158 altSymbolLabel (248, 100, 80, 20, "ctlabel", BSEQUENCER_LABEL_SYMBOL),
159 piano (50, 620, 260, 60, "widget", 0, 35),
160 cancelButton (60, 720, 60, 20, "button", BSEQUENCER_LABEL_CANCEL),
161 applyButton (240, 720, 60, 20, "button", BSEQUENCER_LABEL_APPLY),
162 pianoRoot (0), scale (scale), scaleMap (scaleMap), mapNr (mapNr),
163 sz (width / 360 < height / 760 ? width / 360 : height / 760)
164
165
166 {
167 setDraggable (true);
168 setFocusable (true); // Only to block underlying pads callback
169 setStacking (BWidgets::STACKING_CATCH);
170
171 bgSurface = cairo_image_surface_create_from_png ((pluginPath + "ScaleEditor.png").c_str());
172 scaleEditorBg.loadFillFromCairoSurface(bgSurface);
173
174 scaleNameLabel.setEditable (true);
175 scaleNameLabel.setCallbackFunction(BEvents::BUTTON_PRESS_EVENT, labelClickCallback);
176 scaleNameLabel.setCallbackFunction(BEvents::MESSAGE_EVENT, labelMessageCallback);
177
178 // Create note symbols (for nrListbox)
179 BScale sc = BScale(0, {CROMATICSCALE});
180 std::list<BItems::Item> noteNameItems;
181 for (int i = 0; i < 120; ++i)
182 {
183 int octave = (i / 12) - 1;
184 std::string strNote = std::to_string(i) + " (" + sc.getSymbol (i) + (octave != 0 ? std::to_string(octave) : "") + ")";
185 noteNameItems.push_back (BItems::Item (i, strNote));
186 }
187
188 // Init nr widgets
189 for (int i = 0; i < ROWS; ++i)
190 {
191
192 drumSymbol[i] = BWidgets::ImageIcon (0, 0, 48, 24, "widget", pluginPath + "DrumSymbol.png");
193 drumSymbol[i].rename ("widget");
194 drumSymbol[i].applyTheme (theme);
195 noteSymbol[i] = BWidgets::ImageIcon (0, 0, 48, 24, "widget", pluginPath + "NoteSymbol.png");
196 noteSymbol[i].rename ("widget");
197 noteSymbol[i].applyTheme (theme);
198
199 BItems::ItemList il;
200 il.push_back (BItems::Item (0, ¬eSymbol[i]));
201 il.push_back (BItems::Item (1, &drumSymbol[i]));
202
203 nrSymbolListbox[i] = BWidgets::PopupListBox (60, 580 - i * 30, 68, 24, 68, 68, "menu", il, 0);
204 nrSymbolListbox[i].setCallbackFunction(BEvents::VALUE_CHANGED_EVENT, symbolListboxValueChangedCallback);
205 nrSymbolListbox[i].rename ("menu");
206 nrSymbolListbox[i].applyTheme (theme);
207 add (nrSymbolListbox[i]);
208
209 nrLabel[i] = BWidgets::Label (20, 580 - i * 30, 30, 24, "lflabel", std::to_string (i + 1));
210 nrLabel[i].rename ("lflabel");
211 nrLabel[i].applyTheme (theme);
212 add (nrLabel[i]);
213
214 if (i >= 6) nrNoteListbox[i] = BWidgets::PopupListBox (148, 580 - i * 30, 80, 24, 80, 240, "menu", noteNameItems, 0);
215 else nrNoteListbox[i] = BWidgets::PopupListBox (148, 580 - i * 30, 80, 24, 0, -240, 80, 240, "menu", noteNameItems, 0);
216 nrNoteListbox[i].setCallbackFunction(BEvents::VALUE_CHANGED_EVENT, noteListboxValueChangedCallback);
217 nrNoteListbox[i].rename ("menu");
218 nrNoteListbox[i].applyTheme (theme);
219 add (nrNoteListbox[i]);
220
221 nrNoteLabel[i] = BWidgets::Label (148, 580 - i * 30, 80, 24, "ctlabel", "(" BSEQUENCER_LABEL_USES_SCALE ")");
222 nrNoteLabel[i].rename ("ctlabel");
223 nrNoteLabel[i].applyTheme (theme);
224 add (nrNoteLabel[i]);
225 nrNoteLabel[i].hide ();
226
227 nrAltSymbolLabel[i] = BWidgets::Label (248, 580 - i * 30, 80, 24, "ctlabel", "");
228 nrAltSymbolLabel[i].rename ("ctlabel");
229 nrAltSymbolLabel[i].setEditable (true);
230 nrAltSymbolLabel[i].setCallbackFunction(BEvents::BUTTON_PRESS_EVENT, labelClickCallback);
231 nrAltSymbolLabel[i].setCallbackFunction(BEvents::MESSAGE_EVENT, labelMessageCallback);
232 updateAltSymbol (i);
233 nrAltSymbolLabel[i].applyTheme (theme);
234 add (nrAltSymbolLabel[i]);
235 }
236
237 cancelButton.setCallbackFunction(BEvents::BUTTON_CLICK_EVENT, buttonClickCallback);
238 applyButton.setCallbackFunction(BEvents::BUTTON_CLICK_EVENT, buttonClickCallback);
239
240 piano.setKeysToggleable (true);
241 piano.setCallbackFunction(BEvents::BUTTON_PRESS_EVENT, pianoClickCallback);
242 piano.setCallbackFunction(BEvents::BUTTON_RELEASE_EVENT, pianoClickCallback);
243 piano.setCallbackFunction(BEvents::POINTER_DRAG_EVENT, pianoClickCallback);
244
245 setScale (scale);
246 setScaleMap (scaleMap);
247
248 nameLabel.applyTheme (theme);
249 scaleNameLabel.applyTheme (theme);
250 rowLabel.applyTheme (theme);
251 symbolLabel.applyTheme (theme);
252 noteLabel.applyTheme (theme);
253 altSymbolLabel.applyTheme (theme);
254 cancelButton.applyTheme (theme);
255 applyButton.applyTheme (theme);
256 piano.applyTheme (theme);
257 applyTheme (theme);
258
259 add (nameLabel);
260 add (scaleNameLabel);
261 add (rowLabel);
262 add (symbolLabel);
263 add (noteLabel);
264 add (altSymbolLabel);
265 add (cancelButton);
266 add (applyButton);
267 add (piano);
268
269 if (sz != 1.0) szScaleEditor();
270 }
271
resize(double width,double height)272 void ScaleEditor::resize (double width, double height)
273 {
274 double wf = width / 360;
275 double hf = height / 760;
276 double newsz = (wf < hf ? wf : hf);
277 if (sz != newsz)
278 {
279 sz = newsz;
280 szScaleEditor ();
281 }
282 }
283
szScaleEditor()284 void ScaleEditor::szScaleEditor ()
285 {
286 // Scale Fonts
287 ctLabelFont.setFontSize (12 * sz);
288 lfLabelFont.setFontSize (12 * sz);
289
290 // Scale background
291 cairo_surface_t* surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 360 * sz, 760 * sz);
292 cairo_t* cr = cairo_create (surface);
293 cairo_scale (cr, sz, sz);
294 cairo_set_source_surface(cr, bgSurface, 0, 0);
295 cairo_paint(cr);
296 scaleEditorBg.loadFillFromCairoSurface(surface);
297 cairo_destroy (cr);
298 cairo_surface_destroy (surface);
299
300 nameLabel.moveTo (20 * sz, 60 * sz); nameLabel.resize (80 * sz, 20 * sz);
301 scaleNameLabel.moveTo (120 * sz, 60 * sz); scaleNameLabel.resize(320 * sz, 20 * sz);
302 rowLabel.moveTo (20 * sz, 100 * sz); rowLabel.resize (80 * sz, 20 * sz);
303 symbolLabel.moveTo (70 * sz, 100 * sz); symbolLabel.resize (48 * sz, 20 * sz);
304 noteLabel.moveTo (148 * sz, 100 * sz); noteLabel.resize (80 * sz, 20 * sz);
305 altSymbolLabel.moveTo (248 * sz, 100 * sz); altSymbolLabel.resize (80 * sz, 20 * sz);
306 cancelButton.moveTo (60 * sz, 720 * sz); cancelButton.resize (60 * sz, 20 * sz);
307 applyButton.moveTo (240 * sz, 720 * sz); applyButton.resize (60 * sz, 20 * sz);
308 piano.moveTo (50 * sz, 620 * sz); piano.resize (260 * sz, 60 * sz);
309
310 for (int i = 0; i < ROWS; ++i)
311 {
312 nrLabel[i].moveTo (20 * sz, (580 - i * 30) * sz); nrLabel[i].resize (30 * sz, 24 * sz);
313 nrSymbolListbox[i].moveTo (60 * sz, (580 - i * 30) * sz); nrSymbolListbox[i].resize (68 * sz, 24 * sz);
314 nrSymbolListbox[i].resizeListBox (BUtilities::Point (68 * sz, 68 * sz));
315
316 nrNoteListbox[i].moveTo (148 * sz, (580 - i * 30) * sz ); nrNoteListbox[i].resize (80 * sz, 24 * sz);
317 nrNoteListbox[i].resizeListBox (BUtilities::Point (80 * sz, 240 * sz));
318 if (i < 6) nrNoteListbox[i].moveListBox(BUtilities::Point (0, -240 * sz));
319 nrNoteListbox[i].resizeListBoxItems (BUtilities::Point (80 * sz, 24 * sz));
320
321 nrNoteLabel[i].moveTo (148 * sz, (580 - i * 30) * sz); nrNoteLabel[i].resize (80 * sz, 24 * sz);
322 nrAltSymbolLabel[i].moveTo (248 * sz, (580 - i * 30) * sz); nrAltSymbolLabel[i].resize (80 * sz, 24 * sz);
323 }
324
325 nameLabel.applyTheme (theme);
326 scaleNameLabel.applyTheme (theme);
327 rowLabel.applyTheme (theme);
328 symbolLabel.applyTheme (theme);
329 noteLabel.applyTheme (theme);
330 altSymbolLabel.applyTheme (theme);
331 cancelButton.applyTheme (theme);
332 applyButton.applyTheme (theme);
333 piano.applyTheme (theme);
334
335 for (int i = 0; i < ROWS; ++i)
336 {
337 nrLabel[i].applyTheme (theme);
338 nrSymbolListbox[i].applyTheme (theme);
339 nrNoteListbox[i].applyTheme (theme);
340 nrNoteLabel[i].applyTheme (theme);
341 nrAltSymbolLabel[i].applyTheme (theme);
342 }
343
344 applyTheme (theme);
345 Widget::resize (360 * sz, 760 * sz);
346 }
347
setScaleMap(const ScaleMap & scaleMap)348 void ScaleEditor::setScaleMap (const ScaleMap& scaleMap)
349 {
350 this->scaleMap = scaleMap;
351
352 scaleNameLabel.setText(scaleMap.name);
353
354 // Set nr widgets
355 for (int i = 0; i < ROWS; ++i)
356 {
357 if (scaleMap.elements[i] & 0x0100)
358 {
359 nrSymbolListbox[i].setValue (1);
360 nrNoteLabel[i].hide ();
361 nrNoteListbox[i].setValue (scaleMap.elements[i] & 0x0FF);
362 nrNoteListbox[i].show ();
363 }
364
365 else
366 {
367 nrSymbolListbox[i].setValue (0);
368 nrNoteListbox[i].hide ();
369 nrNoteLabel[i].show ();
370 }
371
372 updateAltSymbol (i);
373 }
374 }
375
getScaleMap() const376 ScaleMap ScaleEditor::getScaleMap () const {return scaleMap;}
377
setScale(const BScale & scale)378 void ScaleEditor::setScale (const BScale& scale)
379 {
380 this->scale = scale;
381 for (int i = 0; i < ROWS; ++i) updateAltSymbol (i);
382
383 // Set piano
384 int pianoRoot = this->scale.getRoot() % 12;
385 if (pianoRoot < 6) pianoRoot +=12;
386 std::vector<bool> acKeys;
387 std::vector<bool> prKeys;
388
389 for (int i = 0; i < 36; ++i)
390 {
391 if ((i >= pianoRoot) && (i < pianoRoot + 12)) acKeys.push_back (true);
392 else acKeys.push_back (false);
393
394 if (this->scale.getElement (i/* + this->scale.getRoot()*/) != ENOTE) prKeys.push_back (true);
395 else prKeys.push_back (false);
396 }
397
398 piano.activateKeys (acKeys);
399 piano.pressKeys (prKeys);
400 }
401
getScale() const402 BScale ScaleEditor::getScale () const {return scale;}
403
setMapNr(const int nr)404 void ScaleEditor::setMapNr (const int nr) {mapNr = nr;}
405
getMapNr() const406 int ScaleEditor::getMapNr () const {return mapNr;}
407
updateAltSymbol(int nr)408 void ScaleEditor::updateAltSymbol (int nr)
409 {
410 std::string symbol;
411 if (scaleMap.altSymbols[nr] != "") symbol = scaleMap.altSymbols[nr];
412 else if (!(scaleMap.elements[nr] & 0x0100)) symbol = scale.getSymbol (scaleMap.elements[nr]);
413 nrAltSymbolLabel[nr].setText (symbol);
414 }
415
symbolListboxValueChangedCallback(BEvents::Event * event)416 void ScaleEditor::symbolListboxValueChangedCallback (BEvents::Event* event)
417 {
418 if ((!event) || (!event->getWidget()) || (!event->getWidget()->getParent())) return;
419
420 BWidgets::PopupListBox* listbox = (BWidgets::PopupListBox*)(event->getWidget());
421 ScaleEditor* scaleEditor = (ScaleEditor*)(listbox->getParent());
422 int nr = -1;
423 int value = ((BEvents::ValueChangedEvent*)event)->getValue ();
424
425 for (int i = 0; i < ROWS; ++i)
426 {
427 if (listbox == &(scaleEditor->nrSymbolListbox[i]))
428 {
429 nr = i;
430 break;
431 }
432 }
433
434 if (nr >= 0)
435 {
436 if (value)
437 {
438 scaleEditor->scaleMap.elements[nr] = ((int(scaleEditor->nrNoteListbox[nr].getValue())) | 0x0100);
439 scaleEditor->nrNoteListbox[nr].show ();
440 scaleEditor->nrNoteLabel[nr].hide ();
441 BWidgets::Label* l = (BWidgets::Label*) scaleEditor->nrNoteListbox[nr].getItem()->getWidget ();
442 if (l) scaleEditor->scaleMap.altSymbols[nr] = l->getText ();
443 scaleEditor->updateAltSymbol (nr);
444 }
445
446 else
447 {
448 scaleEditor->scaleMap.elements[nr] = 0; // Will be substituted by auto numbering later
449 scaleEditor->nrNoteListbox[nr].hide ();
450 scaleEditor->nrNoteLabel[nr].show ();
451 }
452
453 // Update auto numbering of scale map elements
454 for (int i = 0, count = 0; i < ROWS; ++i)
455 {
456 if (!(scaleEditor->scaleMap.elements[i] & 0x0100))
457 {
458 scaleEditor->scaleMap.elements[i] = count;
459 scaleEditor->scaleMap.altSymbols[i] = "";
460 ++count;
461 }
462 scaleEditor->updateAltSymbol (i);
463 }
464 }
465 }
466
noteListboxValueChangedCallback(BEvents::Event * event)467 void ScaleEditor::noteListboxValueChangedCallback (BEvents::Event* event)
468 {
469 if ((!event) || (!event->getWidget()) || (!event->getWidget()->getParent())) return;
470
471 BWidgets::PopupListBox* listbox = (BWidgets::PopupListBox*)(event->getWidget());
472 ScaleEditor* scaleEditor = (ScaleEditor*)(listbox->getParent());
473 int nr = -1;
474
475 for (int i = 0; i < ROWS; ++i)
476 {
477 if (listbox == &(scaleEditor->nrNoteListbox[i]))
478 {
479 nr = i;
480 break;
481 }
482 }
483
484 if ((nr >=0 ) && (scaleEditor->scaleMap.elements[nr] & 0x0100))
485 {
486 scaleEditor->scaleMap.elements[nr] = (((int)(scaleEditor->nrNoteListbox[nr].getValue())) | 0x0100);
487 BWidgets::Label* l = (BWidgets::Label*) scaleEditor->nrNoteListbox[nr].getItem()->getWidget ();
488 if (l) scaleEditor->scaleMap.altSymbols[nr] = l->getText ();
489 scaleEditor->updateAltSymbol (nr);
490 }
491 }
492
buttonClickCallback(BEvents::Event * event)493 void ScaleEditor::buttonClickCallback (BEvents::Event* event)
494 {
495 if ((event) && (event->getEventType() == BEvents::BUTTON_CLICK_EVENT) && (event->getWidget()))
496 {
497 BWidgets::TextButton* button = (BWidgets::TextButton*) event->getWidget();
498 if (button->getParent())
499 {
500 ScaleEditor* scaleEditor = (ScaleEditor*)(button->getParent());
501
502 if (button == &(scaleEditor->cancelButton)) scaleEditor->setValue (-1.0);
503 else if (button == &(scaleEditor->applyButton)) scaleEditor->setValue (1.0);
504 scaleEditor->postCloseRequest ();
505 }
506 }
507 }
508
labelClickCallback(BEvents::Event * event)509 void ScaleEditor::labelClickCallback (BEvents::Event* event)
510 {
511 if ((event) && (event->getEventType() == BEvents::BUTTON_PRESS_EVENT) && (event->getWidget()))
512 {
513 BWidgets::Label* label = (BWidgets::Label*) event->getWidget();
514 if (label->getParent ())
515 {
516 ScaleEditor* scaleEditor = (ScaleEditor*)(label->getParent());
517
518 // Switch off edit mode for all other editable labels
519 if (label == &scaleEditor->scaleNameLabel)
520 {
521 for (BWidgets::Label& l : scaleEditor->nrAltSymbolLabel)
522 {
523 if (l.getEditMode ()) l.applyEdit ();
524 }
525 }
526
527 else
528 {
529 if (scaleEditor->scaleNameLabel.getMainWindow ())
530 {
531 scaleEditor->scaleNameLabel.getMainWindow ()->getKeyGrabStack()->remove (&scaleEditor->scaleNameLabel);
532 }
533 scaleEditor->scaleNameLabel.setEditMode (false);
534 for (BWidgets::Label& l : scaleEditor->nrAltSymbolLabel)
535 {
536 if ((label != &l) && l.getEditMode ()) l.applyEdit ();
537 }
538 }
539 }
540 }
541 }
542
labelMessageCallback(BEvents::Event * event)543 void ScaleEditor::labelMessageCallback (BEvents::Event* event)
544 {
545 if ((event) && (event->getEventType() == BEvents::MESSAGE_EVENT) && (event->getWidget()))
546 {
547 BEvents::MessageEvent* me = (BEvents::MessageEvent*) event;
548
549 if (me->getName () == BWIDGETS_LABEL_TEXT_CHANGED_MESSAGE)
550 {
551 BWidgets::Label* label = (BWidgets::Label*) event->getWidget();
552 if (label->getParent ())
553 {
554 ScaleEditor* scaleEditor = (ScaleEditor*)(label->getParent());
555
556 if (label == &scaleEditor->scaleNameLabel) scaleEditor->scaleMap.name = scaleEditor->scaleNameLabel.getText ();
557
558 else for (size_t i = 0; i < ROWS; ++i)
559 {
560 BWidgets::Label* l = &scaleEditor->nrAltSymbolLabel[i];
561 if (label == l)
562 {
563 scaleEditor->scaleMap.altSymbols[i] = l->getText ();
564 break;
565 }
566 }
567 }
568 }
569 }
570 }
571
pianoClickCallback(BEvents::Event * event)572 void ScaleEditor::pianoClickCallback (BEvents::Event* event)
573 {
574 if ((event) && (event->getWidget()))
575 {
576 BWidgets::HPianoRoll* piano = (BWidgets::HPianoRoll*)(event->getWidget());
577 if (piano->getParent())
578 {
579 ScaleEditor* scaleEditor = (ScaleEditor*)(piano->getParent());
580 std::vector<bool> pressedKeys = piano->getPressedKeys();
581 BScale* scale = &(scaleEditor->scale);
582 int pianoRoot = scale->getRoot() % 12;
583 if (pianoRoot < 6) pianoRoot +=12;
584
585 // Build new BScale elementarray from piano
586 BScaleNotes newScaleNotes;
587 newScaleNotes.fill (ENOTE);
588 for (int i = 0, count = 0; i < 12; ++i)
589 {
590 if (pressedKeys[i + pianoRoot])
591 {
592 newScaleNotes[count] = i;
593 ++count;
594 }
595 }
596
597 // Something changed?
598 if (newScaleNotes != scale->getScale())
599 {
600 scale->setScale (newScaleNotes);
601
602 // Update auto numbering of scale map elements
603 for (int i = 0, count = 0; i < ROWS; ++i)
604 {
605 if (!(scaleEditor->scaleMap.elements[i] & 0x0100))
606 {
607 scaleEditor->scaleMap.elements[i] = count;
608 scaleEditor->scaleMap.altSymbols[i] = "";
609 ++count;
610 }
611 scaleEditor->updateAltSymbol (i);
612 }
613 }
614 }
615 }
616 }
617
618 #endif /* SCALEEDITOR_HPP_ */
619