2 Copyright (C) 2016 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtkmm2ext/gui_thread.h"
23 #include "canvas/colors.h"
24 #include "canvas/rectangle.h"
25 #include "canvas/text.h"
33 #define Rect ArdourCanvas::Rect
36 using namespace ARDOUR;
40 using namespace ArdourSurface;
41 using namespace ArdourCanvas;
43 static double unselected_root_alpha = 0.5;
45 ScaleLayout::ScaleLayout (Push2& p, Session & s, std::string const & name)
46 : Push2Layout (p, s, name)
51 Pango::FontDescription fd ("Sans 10");
55 bg = new ArdourCanvas::Rectangle (this);
56 bg->set (Rect (0, 0, display_width(), display_height()));
57 bg->set_fill_color (p2.get_color (Push2::DarkBackground));
59 left_scroll_text = new Text (this);
60 left_scroll_text->set_font_description (fd);
61 left_scroll_text->set_position (Duple (10, 5));
62 left_scroll_text->set_color (p2.get_color (Push2::LightBackground));
64 close_text = new Text (this);
65 close_text->set_font_description (fd);
66 close_text->set_position (Duple (25, 5));
67 close_text->set_color (p2.get_color (Push2::LightBackground));
68 close_text->set (_("Close"));
70 right_scroll_text = new Text (this);
71 right_scroll_text->set_font_description (fd);
72 right_scroll_text->set_position (Duple (10 + (7 * Push2Canvas::inter_button_spacing()), 5));
73 right_scroll_text->set_color (p2.get_color (Push2::LightBackground));
75 Pango::FontDescription fd2 ("Sans 8");
76 inkey_text = new Text (this);
77 inkey_text->set_font_description (fd2);
78 inkey_text->set_position (Duple (10, 140));
79 inkey_text->set_color (p2.get_color (Push2::LightBackground));
80 inkey_text->set (_("InKey"));
82 chromatic_text = new Text (this);
83 chromatic_text->set_font_description (fd2);
84 chromatic_text->set_position (Duple (45, 140));
85 chromatic_text->set_color (p2.get_color (Push2::LightBackground));
86 chromatic_text->set (_("Chromatic"));
88 for (int n = 0; n < 8; ++n) {
90 /* text labels for root notes etc.*/
92 Text* t = new Text (this);
93 t->set_font_description (fd);
94 t->set_color (change_alpha (p2.get_color (Push2::LightBackground), unselected_root_alpha));
95 t->set_position (Duple (10 + (n * Push2Canvas::inter_button_spacing()), 5));
99 /* zeroth element is a dummy */
102 t->set (S_("Note|C"));
105 t->set (S_("Note|G"));
108 t->set (S_("Note|D"));
111 t->set (S_("Note|A"));
114 t->set (S_("Note|E"));
117 t->set (S_("Note|B"));
121 upper_text.push_back (t);
124 t->set_font_description (fd);
125 t->set_color (change_alpha (p2.get_color (Push2::LightBackground), unselected_root_alpha));
126 t->set_position (Duple (10 + (n*Push2Canvas::inter_button_spacing()), 140));
130 /* zeroth element is a dummy */
133 t->set (S_("Note|F"));
136 t->set (S_("Note|B\u266D/A\u266F"));
139 t->set (S_("Note|E\u266D/D\u266F"));
142 t->set (S_("Note|A\u266D/G\u266F"));
145 t->set (S_("Note|D\u266D/C\u266F"));
148 t->set (S_("Note|G\u266D/F\u266F"));
152 lower_text.push_back (t);
157 p2.ScaleChange.connect (p2_connections, invalidator (*this), boost::bind (&ScaleLayout::show_root_state, this), &p2);
160 ScaleLayout::~ScaleLayout ()
165 ScaleLayout::render (Rect const& area, Cairo::RefPtr<Cairo::Context> context) const
167 render_children (area, context);
171 ScaleLayout::button_upper (uint32_t n)
174 if (scale_menu->can_scroll_left()) {
175 scale_menu->scroll (Push2Menu::DirectionLeft, true);
177 p2.use_previous_layout ();
183 scale_menu->scroll (Push2Menu::DirectionRight, true);
219 p2.set_pad_scale (root, p2.root_octave(), p2.mode(), p2.in_key());
223 ScaleLayout::button_lower (uint32_t n)
226 p2.set_pad_scale (p2.scale_root(), p2.root_octave(), p2.mode(), !p2.in_key());
262 p2.set_pad_scale (root, p2.root_octave(), p2.mode(), p2.in_key());
266 ScaleLayout::button_up ()
268 scale_menu->scroll (Push2Menu::DirectionUp);
272 ScaleLayout::button_down ()
274 scale_menu->scroll (Push2Menu::DirectionDown);
278 ScaleLayout::button_left ()
280 scale_menu->scroll (Push2Menu::DirectionLeft);
284 ScaleLayout::button_right ()
286 scale_menu->scroll (Push2Menu::DirectionRight);
296 b = p2.button_by_id (Push2::Upper1);
297 b->set_color (Push2::LED::White);
298 b->set_state (Push2::LED::OneShot24th);
299 p2.write (b->state_msg());
301 b = p2.button_by_id (Push2::Upper8);
302 b->set_color (Push2::LED::White);
303 b->set_state (Push2::LED::OneShot24th);
304 p2.write (b->state_msg());
306 b = p2.button_by_id (Push2::Lower1);
307 b->set_color (Push2::LED::White);
308 b->set_state (Push2::LED::OneShot24th);
309 p2.write (b->state_msg());
311 /* all root buttons should be dimly lit */
313 Push2::ButtonID root_buttons[] = { Push2::Upper2, Push2::Upper3, Push2::Upper4, Push2::Upper5, Push2::Upper6, Push2::Upper7,
314 Push2::Lower2, Push2::Lower3, Push2::Lower4, Push2::Lower5, Push2::Lower6, Push2::Lower7, };
316 for (size_t n = 0; n < sizeof (root_buttons) / sizeof (root_buttons[0]); ++n) {
317 b = p2.button_by_id (root_buttons[n]);
319 b->set_color (Push2::LED::DarkGray);
320 b->set_state (Push2::LED::OneShot24th);
321 p2.write (b->state_msg());
330 ScaleLayout::strip_vpot (int n, int delta)
332 /* menu starts under the 2nd-from-left vpot */
338 if (last_vpot != n) {
339 uint32_t effective_column = n - 1;
340 uint32_t active = scale_menu->active ();
342 if (active / scale_menu->rows() != effective_column) {
343 /* knob turned is different than the current active column.
346 scale_menu->set_active (effective_column * scale_menu->rows()); /* top entry of that column */
350 /* new vpot, reset delta cnt */
355 if ((delta < 0 && vpot_delta_cnt > 0) || (delta > 0 && vpot_delta_cnt < 0)) {
356 /* direction changed, reset */
360 vpot_delta_cnt += delta;
363 /* this thins out vpot delta events so that we don't scroll so fast
367 const int vpot_slowdown_factor = 4;
369 if ((vpot_delta_cnt < 0) && (vpot_delta_cnt % vpot_slowdown_factor == 0)) {
370 scale_menu->scroll (Push2Menu::DirectionUp);
371 } else if (vpot_delta_cnt % vpot_slowdown_factor == 0) {
372 scale_menu->scroll (Push2Menu::DirectionDown);
377 ScaleLayout::build_scale_menu ()
381 /* must match in which enums are declared in push2.h
384 v.push_back ("Dorian");
385 v.push_back ("Ionian (Major)");
386 v.push_back ("Aeolian (Minor)");
387 v.push_back ("Harmonic Minor");
388 v.push_back ("MelodicMinor Asc.");
389 v.push_back ("MelodicMinor Desc.");
390 v.push_back ("Phrygian");
391 v.push_back ("Lydian");
392 v.push_back ("Mixolydian");
393 v.push_back ("Locrian");
394 v.push_back ("Pentatonic Major");
395 v.push_back ("Pentatonic Minor");
396 v.push_back ("Chromatic");
397 v.push_back ("Blues Scale");
398 v.push_back ("Neapolitan Minor");
399 v.push_back ("Neapolitan Major");
400 v.push_back ("Oriental");
401 v.push_back ("Double Harmonic");
402 v.push_back ("Enigmatic");
403 v.push_back ("Hirajoshi");
404 v.push_back ("Hungarian Minor");
405 v.push_back ("Hungarian Major");
406 v.push_back ("Kumoi");
407 v.push_back ("Iwato");
408 v.push_back ("Hindu");
409 v.push_back ("Spanish 8 Tone");
410 v.push_back ("Pelog");
411 v.push_back ("Hungarian Gypsy");
412 v.push_back ("Overtone");
413 v.push_back ("Leading Whole Tone");
414 v.push_back ("Arabian");
415 v.push_back ("Balinese");
416 v.push_back ("Gypsy");
417 v.push_back ("Mohammedan");
418 v.push_back ("Javanese");
419 v.push_back ("Persian");
420 v.push_back ("Algeria");
422 scale_menu = new Push2Menu (this, v);
423 scale_menu->Rearranged.connect (menu_connections, invalidator (*this), boost::bind (&ScaleLayout::menu_rearranged, this), &p2);
425 scale_menu->set_layout (6, 6);
426 scale_menu->set_text_color (p2.get_color (Push2::ParameterName));
427 scale_menu->set_active_color (p2.get_color (Push2::LightBackground));
429 Pango::FontDescription fd ("Sans Bold 8");
430 scale_menu->set_font_description (fd);
432 /* move menu into position so that its leftmost column is in the
433 * 2nd-from-left column of the display/button layout.
436 scale_menu->set_position (Duple (10 + Push2Canvas::inter_button_spacing(), 40));
438 /* listen for changes */
440 scale_menu->ActiveChanged.connect (menu_connections, invalidator (*this), boost::bind (&ScaleLayout::mode_changed, this), &p2);
444 ScaleLayout::show_root_state ()
447 /* don't do this stuff if we're not visible */
452 chromatic_text->set_color (change_alpha (chromatic_text->color(), unselected_root_alpha));
453 inkey_text->set_color (change_alpha (inkey_text->color(), 1.0));
455 inkey_text->set_color (change_alpha (chromatic_text->color(), unselected_root_alpha));
456 chromatic_text->set_color (change_alpha (inkey_text->color(), 1.0));
459 Pango::FontDescription fd_bold ("Sans Bold 10");
460 Pango::FontDescription fd ("Sans 10");
462 uint32_t highlight_text = 0;
463 vector<Text*>* none_text_array;
464 vector<Text*>* one_text_array;
467 switch (p2.scale_root()) {
470 none_text_array = &lower_text;
471 one_text_array = &upper_text;
476 none_text_array = &lower_text;
477 one_text_array = &upper_text;
482 none_text_array = &lower_text;
483 one_text_array = &upper_text;
488 none_text_array = &upper_text;
489 one_text_array = &lower_text;
494 none_text_array = &lower_text;
495 one_text_array = &upper_text;
500 none_text_array = &upper_text;
501 one_text_array = &lower_text;
506 none_text_array = &upper_text;
507 one_text_array = &lower_text;
512 none_text_array = &lower_text;
513 one_text_array = &upper_text;
518 none_text_array = &upper_text;
519 one_text_array = &lower_text;
524 none_text_array = &lower_text;
525 one_text_array = &upper_text;
530 none_text_array = &upper_text;
531 one_text_array = &lower_text;
536 none_text_array = &lower_text;
537 one_text_array = &upper_text;
542 if (none_text_array) {
544 for (uint32_t nn = 1; nn < 7; ++nn) {
545 (*none_text_array)[nn]->set_font_description (fd);
546 (*none_text_array)[nn]->set_color (change_alpha ((*none_text_array)[nn]->color(), unselected_root_alpha));
548 if (nn == highlight_text) {
549 (*one_text_array)[nn]->set_font_description (fd_bold);
550 (*one_text_array)[nn]->set_color (change_alpha ((*one_text_array)[nn]->color(), 1.0));
552 (*one_text_array)[nn]->set_font_description (fd);
553 (*one_text_array)[nn]->set_color (change_alpha ((*one_text_array)[nn]->color(), unselected_root_alpha));
559 Push2::Button* b = p2.button_by_id (bid);
561 if (b != root_button) {
563 /* turn the old one off (but not totally) */
564 root_button->set_color (Push2::LED::DarkGray);
565 root_button->set_state (Push2::LED::OneShot24th);
566 p2.write (root_button->state_msg());
572 /* turn the new one on */
573 root_button->set_color (Push2::LED::White);
574 root_button->set_state (Push2::LED::OneShot24th);
575 p2.write (root_button->state_msg());
579 scale_menu->set_active ((uint32_t) p2.mode ());
583 ScaleLayout::mode_changed ()
585 MusicalMode::Type m = (MusicalMode::Type) scale_menu->active();
586 p2.set_pad_scale (p2.scale_root(), p2.root_octave(), m, p2.in_key());
590 ScaleLayout::menu_rearranged ()
592 if (scale_menu->can_scroll_left()) {
593 left_scroll_text->set ("<");
596 left_scroll_text->set (string());
600 if (scale_menu->can_scroll_right()) {
601 right_scroll_text->set (">");
603 right_scroll_text->set (string());
608 ScaleLayout::update_cursor_buttons ()
613 b = p2.button_by_id (Push2::Up);
616 if (scale_menu->active() == 0) {
617 if (b->color_index() != Push2::LED::Black) {
618 b->set_color (Push2::LED::Black);
622 if (b->color_index() != Push2::LED::White) {
623 b->set_color (Push2::LED::White);
629 b->set_state (Push2::LED::OneShot24th);
630 p2.write (b->state_msg());
635 b = p2.button_by_id (Push2::Down);
638 if (scale_menu->active() == scale_menu->items() - 1) {
639 if (b->color_index() != Push2::LED::Black) {
640 b->set_color (Push2::LED::Black);
644 if (b->color_index() != Push2::LED::White) {
645 b->set_color (Push2::LED::White);
651 b->set_color (Push2::LED::OneShot24th);
652 p2.write (b->state_msg());
657 b = p2.button_by_id (Push2::Left);
660 if (scale_menu->active() < scale_menu->rows()) {
661 if (b->color_index() != Push2::LED::Black) {
662 b->set_color (Push2::LED::Black);
666 if (b->color_index() != Push2::LED::White) {
667 b->set_color (Push2::LED::White);
673 b->set_color (Push2::LED::OneShot24th);
674 p2.write (b->state_msg());
679 b = p2.button_by_id (Push2::Right);
682 if (scale_menu->active() > (scale_menu->items() - scale_menu->rows())) {
683 if (b->color_index() != Push2::LED::Black) {
684 b->set_color (Push2::LED::Black);
688 if (b->color_index() != Push2::LED::White) {
689 b->set_color (Push2::LED::White);
696 b->set_color (Push2::LED::OneShot24th);
697 p2.write (b->state_msg());