diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2016-07-10 08:37:45 -0400 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2016-09-27 14:59:30 -0500 |
commit | 86578ea0cc1daef464953fdb80820d40a8167f78 (patch) | |
tree | b1f626a0e11f5db70516c59cba9837664a0e953c /libs | |
parent | b37531e04f1f8786ffcc8599759aa93411d42c1b (diff) |
push2: first somewhat operational versions of menus
Diffstat (limited to 'libs')
-rw-r--r-- | libs/surfaces/push2/buttons.cc | 22 | ||||
-rw-r--r-- | libs/surfaces/push2/menu.cc | 218 | ||||
-rw-r--r-- | libs/surfaces/push2/menu.h | 66 | ||||
-rw-r--r-- | libs/surfaces/push2/push2.cc | 105 | ||||
-rw-r--r-- | libs/surfaces/push2/push2.h | 18 | ||||
-rw-r--r-- | libs/surfaces/push2/wscript | 1 |
6 files changed, 418 insertions, 12 deletions
diff --git a/libs/surfaces/push2/buttons.cc b/libs/surfaces/push2/buttons.cc index 6925517f68..8e916d126f 100644 --- a/libs/surfaces/push2/buttons.cc +++ b/libs/surfaces/push2/buttons.cc @@ -193,7 +193,7 @@ Push2::build_maps () MAKE_WHITE_BUTTON_PRESS (Left, 44, &Push2::button_left); MAKE_WHITE_BUTTON_PRESS (Repeat, 56, &Push2::button_repeat); MAKE_WHITE_BUTTON (Accent, 57); - MAKE_WHITE_BUTTON (Scale, 58); + MAKE_WHITE_BUTTON_PRESS (Scale, 58, &Push2::button_scale_press); MAKE_WHITE_BUTTON_PRESS (Layout, 31, &Push2::button_layout_press); MAKE_WHITE_BUTTON (Note, 50); MAKE_WHITE_BUTTON (Session, 51); @@ -608,3 +608,23 @@ Push2::button_octave_up () build_pad_table (); } } + +void +Push2::button_layout_press () +{ + if (percussion) { + set_percussive_mode (false); + } else { + set_percussive_mode (true); + } +} + +void +Push2::button_scale_press () +{ + if (current_menu != scale_menu) { + show_scale_menu (); + } else { + cancel_menu (); + } +} diff --git a/libs/surfaces/push2/menu.cc b/libs/surfaces/push2/menu.cc new file mode 100644 index 0000000000..583c0a235c --- /dev/null +++ b/libs/surfaces/push2/menu.cc @@ -0,0 +1,218 @@ +/* + Copyright (C) 2016 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <cairomm/context.h> +#include <cairomm/surface.h> +#include <pangomm/layout.h> + +#include "push2.h" +#include "gui.h" + +using namespace ARDOUR; +using namespace std; +using namespace PBD; +using namespace Glib; +using namespace ArdourSurface; + +#include "i18n.h" +#include "menu.h" + +Push2Menu::Push2Menu (Cairo::RefPtr<Cairo::Context> context) + : _dirty (true) +{ + Pango::FontDescription fd2 ("Sans 10"); + + { + Glib::RefPtr<Pango::Layout> throwaway = Pango::Layout::create (context); + throwaway->set_font_description (fd2); + throwaway->set_text (X_("Hg")); /* ascender + descender) */ + int h, w; + throwaway->get_pixel_size (w, h); + baseline = h; + nrows = Push2::rows / baseline; + } + + for (int n = 0; n < 8; ++n) { + columns[n].layout = Pango::Layout::create (context); + columns[n].layout->set_font_description (fd2); + columns[n].top = -1; + columns[n].active = -1; + } +} + +void +Push2Menu::fill_column (int col, vector<string> v) +{ + if (col < 0 || col > 7) { + return; + } + + columns[col].text = v; + + if (v.empty()) { + columns[col].active = -1; + } else { + columns[col].active = 0; + } + + set_text (col, 0); + + _dirty = true; +} + +void +Push2Menu::set_text (int col, int top_row) +{ + if (top_row > (int) columns[col].text.size() - nrows || top_row < 0) { + return; + } + + if (top_row == columns[col].top) { + return; + } + + vector<string>::iterator s = columns[col].text.begin(); + s += top_row; + + string rows; + + while (true) { + rows += *s; + ++s; + if (s != columns[col].text.end()) { + rows += '\n'; + } else { + break; + } + } + + columns[col].layout->set_text (rows); + columns[col].top = top_row; + + _dirty = true; +} + +void +Push2Menu::scroll (int col, int dir) +{ + if (dir > 0) { + set_text (col, columns[col].top + 1); + } else { + set_text (col, columns[col].top - 1); + } +} + +void +Push2Menu::set_active (int col, int index) +{ + if (col < 0 || col > 7) { + return; + } + + if (index < 0 || index > (int) columns[col].text.size()) { + return; + } + + columns[col].active = index; + + ActiveChanged (); /* emit signal */ + + _dirty = true; +} + +void +Push2Menu::step_active (int col, int dir) +{ + if (col < 0 || col > 7) { + return; + } + + if (columns[col].text.empty()) { + return; + } + + + if (dir < 0) { + if (columns[col].active == -1) { + columns[col].active = 0; + } else { + columns[col].active = columns[col].active - 1; + if (columns[col].active < 0) { + columns[col].active = columns[col].text.size() - 1; + } + } + } else { + if (columns[col].active == -1) { + columns[col].active = 0; + } else { + columns[col].active = columns[col].active + 1; + if (columns[col].active >= (int) columns[col].text.size()) { + columns[col].active = 0; + } + } + } + + if (columns[col].active < nrows/2) { + set_text (col, 0); + } else { + set_text (col, columns[col].active - (nrows/2) + 1); + } + + _dirty = true; +} + +int +Push2Menu::get_active (int col) +{ + if (col < 0 || col > 7) { + return -1; + } + + return columns[col].active; +} + +void +Push2Menu::redraw (Cairo::RefPtr<Cairo::Context> context) const +{ + for (int n = 0; n < 8; ++n) { + + /* Active: move to column/now, draw background indicator + for active row. + */ + + const double x = 10.0 + (n * 120.0); + const double y = 2.0; + + if (columns[n].active >= 0) { + int effective_row = columns[n].active - columns[n].top; + context->rectangle (x, y + (effective_row * baseline), 120.0, baseline); + context->set_source_rgb (1.0, 1.0, 1.0); + context->fill (); + } + + /* now draw all the text, in one go */ + + context->move_to (x, y); + context->set_source_rgb (0.23, 0.0, 0.349); + columns[n].layout->update_from_cairo_context (context); + columns[n].layout->show_in_cairo_context (context); + + } + + _dirty = false; +} diff --git a/libs/surfaces/push2/menu.h b/libs/surfaces/push2/menu.h new file mode 100644 index 0000000000..a76bba170d --- /dev/null +++ b/libs/surfaces/push2/menu.h @@ -0,0 +1,66 @@ +/* + Copyright (C) 2016 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __ardour_push2_menu_h__ +#define __ardour_push2_menu_h__ + +#include <cairomm/context.h> +#include <cairomm/surface.h> +#include <pangomm/layout.h> + +#include "pbd/signals.h" + +namespace ArdourSurface { + +class Push2Menu { + public: + Push2Menu (Cairo::RefPtr<Cairo::Context>); + + void redraw (Cairo::RefPtr<Cairo::Context>) const; + bool dirty () const { return _dirty; } + + void fill_column (int col, std::vector<std::string>); + void set_active (int col, int index); + void step_active (int col, int dir); + int get_active (int col); + + PBD::Signal0<void> ActiveChanged; + PBD::Signal0<void> Selected; + + private: + struct Column { + std::vector<std::string> text; + Glib::RefPtr<Pango::Layout> layout; + int top; + int active; + }; + + Column columns[8]; + + void scroll (int col, int dir); + void set_text (int col, int top); + + int nrows; + double baseline; + + mutable bool _dirty; +}; + +} // namespace + +#endif /* __ardour_push2_menu_h__ */ diff --git a/libs/surfaces/push2/push2.cc b/libs/surfaces/push2/push2.cc index d4fe17bbd0..d2e4be3fde 100644 --- a/libs/surfaces/push2/push2.cc +++ b/libs/surfaces/push2/push2.cc @@ -44,6 +44,7 @@ #include "push2.h" #include "gui.h" +#include "menu.h" using namespace ARDOUR; using namespace std; @@ -132,6 +133,8 @@ Push2::Push2 (ARDOUR::Session& s) , _in_key (true) , octave_shift (0) , percussion (false) + , current_menu (0) + , drawn_menu (0) { context = Cairo::Context::create (frame_buffer); tc_clock_layout = Pango::Layout::create (context); @@ -159,6 +162,7 @@ Push2::Push2 (ARDOUR::Session& s) build_pad_table (); build_maps (); + build_scale_menu (); if (open ()) { throw failed_constructor (); @@ -340,7 +344,7 @@ Push2::init_buttons (bool startup) ButtonID buttons[] = { Mute, Solo, Master, Up, Right, Left, Down, Note, Session, Mix, AddTrack, Delete, Undo, Metronome, Shift, Select, Play, RecordEnable, Automate, Repeat, Note, Session, DoubleLoop, - Quantize, Duplicate, Browse, PageRight, PageLeft, OctaveUp, OctaveDown, Layout + Quantize, Duplicate, Browse, PageRight, PageLeft, OctaveUp, OctaveDown, Layout, Scale }; for (size_t n = 0; n < sizeof (buttons) / sizeof (buttons[0]); ++n) { @@ -376,7 +380,7 @@ Push2::init_buttons (bool startup) ButtonID off_buttons[] = { TapTempo, Setup, User, Stop, Convert, New, FixedLength, Fwd32ndT, Fwd32nd, Fwd16thT, Fwd16th, Fwd8thT, Fwd8th, Fwd4trT, Fwd4tr, - Accent, Scale, Note, Session, }; + Accent, Note, Session, }; for (size_t n = 0; n < sizeof (off_buttons) / sizeof (off_buttons[0]); ++n) { Button* b = id_button_map[off_buttons[n]]; @@ -516,6 +520,22 @@ Push2::redraw () } } + if (current_menu) { + if (current_menu->dirty() || drawn_menu != current_menu) { + /* fill background */ + context->set_source_rgb (0.764, 0.882, 0.882); + context->rectangle (0, 0, 960, 160); + context->fill (); + /* now menu */ + current_menu->redraw (context); + drawn_menu = current_menu; + return true; + } + return false; + } else { + drawn_menu = 0; + } + if (session) { framepos_t audible = session->audible_frame(); Timecode::Time TC; @@ -1492,6 +1512,11 @@ Push2::mute_change (int n) void Push2::strip_vpot (int n, int delta) { + if (current_menu) { + current_menu->step_active (n, delta); + return; + } + if (stripable[n]) { boost::shared_ptr<AutomationControl> ac = stripable[n]->gain_control(); if (ac) { @@ -1503,6 +1528,10 @@ Push2::strip_vpot (int n, int delta) void Push2::strip_vpot_touch (int n, bool touching) { + if (current_menu) { + return; + } + if (stripable[n]) { boost::shared_ptr<AutomationControl> ac = stripable[n]->gain_control(); if (ac) { @@ -1977,11 +2006,71 @@ Push2::set_percussive_mode (bool yn) } void -Push2::button_layout_press () +Push2::set_menu (Push2Menu* m) { - if (percussion) { - set_percussive_mode (false); - } else { - set_percussive_mode (true); - } + current_menu = m; + drawn_menu = 0; +} + +void +Push2::build_scale_menu () +{ + vector<string> v; + + scale_menu = new Push2Menu (context); + + v.push_back ("Dorian"); + v.push_back ("IonianMajor"); + v.push_back ("Minor"); + v.push_back ("HarmonicMinor"); + v.push_back ("MelodicMinorAscending"); + v.push_back ("MelodicMinorDescending"); + v.push_back ("Phrygian"); + v.push_back ("Lydian"); + v.push_back ("Mixolydian"); + v.push_back ("Aeolian"); + v.push_back ("Locrian"); + v.push_back ("PentatonicMajor"); + v.push_back ("PentatonicMinor"); + v.push_back ("Chromatic"); + v.push_back ("BluesScale"); + v.push_back ("NeapolitanMinor"); + v.push_back ("NeapolitanMajor"); + v.push_back ("Oriental"); + v.push_back ("DoubleHarmonic"); + v.push_back ("Enigmatic"); + v.push_back ("Hirajoshi"); + v.push_back ("HungarianMinor"); + v.push_back ("HungarianMajor"); + v.push_back ("Kumoi"); + v.push_back ("Iwato"); + v.push_back ("Hindu"); + v.push_back ("Spanish8Tone"); + v.push_back ("Pelog"); + v.push_back ("HungarianGypsy"); + v.push_back ("Overtone"); + v.push_back ("LeadingWholeTone"); + v.push_back ("Arabian"); + v.push_back ("Balinese"); + v.push_back ("Gypsy"); + v.push_back ("Mohammedan"); + v.push_back ("Javanese"); + v.push_back ("Persian"); + v.push_back ("Algeria"); + + scale_menu->fill_column (0, v); + + v.clear (); +} + +void +Push2::show_scale_menu () +{ + set_menu (scale_menu); +} + +void +Push2::cancel_menu () +{ + set_menu (0); } diff --git a/libs/surfaces/push2/push2.h b/libs/surfaces/push2/push2.h index d1655d1d60..4ced88b67f 100644 --- a/libs/surfaces/push2/push2.h +++ b/libs/surfaces/push2/push2.h @@ -71,6 +71,7 @@ public: }; class P2GUI; +class Push2Menu; class Push2 : public ARDOUR::ControlProtocol , public AbstractUI<Push2Request> @@ -107,6 +108,9 @@ class Push2 : public ARDOUR::ControlProtocol int root_octave() const { return _root_octave; } bool in_key() const { return _in_key; } + static const int cols; + static const int rows; + private: libusb_device_handle *handle; uint8_t frame_header[16]; @@ -124,8 +128,6 @@ class Push2 : public ARDOUR::ControlProtocol ModifierState modifier_state; - static const int cols; - static const int rows; static const int pixels_per_row; void do_request (Push2Request*); @@ -460,6 +462,7 @@ class Push2 : public ARDOUR::ControlProtocol void button_octave_up (); void button_octave_down (); void button_layout_press (); + void button_scale_press (); void start_shift (); void end_shift (); @@ -536,8 +539,17 @@ class Push2 : public ARDOUR::ControlProtocol bool percussion; void set_percussive_mode (bool); -}; + /* menus */ + Push2Menu* current_menu; + Push2Menu* drawn_menu; + Push2Menu* scale_menu; + + void build_scale_menu (); + void set_menu (Push2Menu*); + void show_scale_menu (); + void cancel_menu (); +}; } /* namespace */ diff --git a/libs/surfaces/push2/wscript b/libs/surfaces/push2/wscript index b69d4a22ce..409311e0f5 100644 --- a/libs/surfaces/push2/wscript +++ b/libs/surfaces/push2/wscript @@ -27,6 +27,7 @@ def build(bld): leds.cc gui.cc mode.cc + menu.cc ''' obj.export_includes = ['.'] obj.defines = [ 'PACKAGE="ardour_push2"' ] |