diff --git a/gtk2_ardour/beatbox_gui.cc b/gtk2_ardour/beatbox_gui.cc index 1b7873950b..50efae9429 100644 --- a/gtk2_ardour/beatbox_gui.cc +++ b/gtk2_ardour/beatbox_gui.cc @@ -44,6 +44,7 @@ #include "gtkmm2ext/gui_thread.h" #include "gtkmm2ext/utils.h" +#include "gtkmm2ext/colors.h" #include "beatbox_gui.h" #include "timers.h" @@ -76,12 +77,11 @@ BBGUI::BBGUI (boost::shared_ptr bb) { _canvas_viewport = new GtkCanvasViewport (horizontal_adjustment, vertical_adjustment); _canvas = _canvas_viewport->canvas(); - _canvas->set_background_color (UIConfiguration::instance().color ("gtk_bright_color")); + _canvas->set_background_color (UIConfiguration::instance().color ("gtk_bases")); _canvas->use_nsglview (); _sequencer = new SequencerGrid (bbox->sequencer(), _canvas); _sequencer->set_position (Duple (0, _step_dimen)); - _sequencer->set_fill_color (UIConfiguration::instance().color ("gtk_contrasting_indicator")); srandom (time(0)); @@ -135,28 +135,7 @@ BBGUI::mode_clicked (SequencerGrid::Mode m) void BBGUI::update () { - update_sequencer (); -} - -void -BBGUI::update_sequencer () -{ - Timecode::BBT_Time bbt; - - if (!bbox->running()) { - /* do something */ - return; - } -#if 0 - bbt = bbox->get_last_time (); - - int current_switch_column = (bbt.bars - 1) * bbox->meter_beats (); - current_switch_column += bbt.beats - 1; - - for (SwitchRows::iterator sr = switch_rows.begin(); sr != switch_rows.end(); ++sr) { - (*sr)->update (current_switch_column); - } -#endif + _sequencer->update (); } void @@ -301,10 +280,6 @@ SequencerGrid::SequencerGrid (StepSequencer& s, Canvas* c) no_scroll_group = new ArdourCanvas::Container (_canvas->root()); step_indicator_box = new ArdourCanvas::Container (no_scroll_group); - step_indicator_bg = new ArdourCanvas::Rectangle (step_indicator_box); - step_indicator_bg->set_fill_color (UIConfiguration::instance().color ("gtk_lightest")); - step_indicator_bg->set_outline (false); - v_scroll_group = new ScrollGroup (_canvas->root(), ScrollGroup::ScrollsVertically); _canvas->add_scroller (*v_scroll_group); v_scroll_group->add (this); @@ -318,6 +293,28 @@ SequencerGrid::SequencerGrid (StepSequencer& s, Canvas* c) } } +void +SequencerGrid::update () +{ + bool running = true; + size_t step = _sequencer.last_step (); + + if (!running) { + for (StepIndicators::iterator s = step_indicators.begin(); s != step_indicators.end(); ++s) { + (*s)->set_current (false); + } + } else { + size_t n = 0; + for (StepIndicators::iterator s = step_indicators.begin(); s != step_indicators.end(); ++s, ++n) { + if (n == step) { + (*s)->set_current (true); + } else { + (*s)->set_current (false); + } + } + } +} + void SequencerGrid::sequencer_changed (PropertyChange const &) { @@ -329,21 +326,28 @@ SequencerGrid::sequencer_changed (PropertyChange const &) set (Rect (0, 0, _width, _height)); - step_indicator_bg->set (Rect (0, 0, _width, _step_dimen)); step_indicator_box->clear (true); /* delete all existing step indicators */ + step_indicators.clear (); + + step_indicator_bg = new ArdourCanvas::Rectangle (step_indicator_box); + step_indicator_bg->set_fill_color (HSV (UIConfiguration::instance().color ("gtk_bases")).lighter (0.1)); + step_indicator_bg->set_outline (false); + step_indicator_bg->set (Rect (0, 0, _width, _step_dimen)); /* indicator row */ for (size_t n = 0; n < nsteps; ++n) { - SequencerStepIndicator* ssi = new SequencerStepIndicator (step_indicator_box, n+1); + SequencerStepIndicator* ssi = new SequencerStepIndicator (*this, step_indicator_box, n); ssi->set (Rect (n * _step_dimen, 0, (n+1) * _step_dimen, _step_dimen)); ssi->set_position (Duple (n * _step_dimen, 0.0)); ssi->set_fill_color (random()); + step_indicators.push_back (ssi); } + /* step views, one per step per sequence */ clear (true); - _step_views.clear (); + step_views.clear (); for (size_t s = 0; s < nsequences; ++s) { for (size_t n = 0; n < nsteps; ++n) { @@ -351,7 +355,7 @@ SequencerGrid::sequencer_changed (PropertyChange const &) /* sequence row is 1-row down ... because of the step indicator row */ sv->set_position (Duple (n * _step_dimen, (s+1) * _step_dimen)); sv->set (Rect (1, 1, _step_dimen - 2, _step_dimen - 2)); - _step_views.push_back (sv); + step_views.push_back (sv); } } } @@ -361,7 +365,7 @@ SequencerGrid::set_mode (Mode m) { _mode = m; - for (StepViews::iterator s = _step_views.begin(); s != _step_views.end(); ++s) { + for (StepViews::iterator s = step_views.begin(); s != step_views.end(); ++s) { (*s)->view_mode_changed (); } @@ -391,7 +395,7 @@ SequencerGrid::render (Rect const & area, Cairo::RefPtr context) for (int n = 0; n < _nrows; ++n) { double x = 0; double y = n * _step_dimen; - Duple start = Duple (x, y).translate (_position).translate (Duple (0.5, 0.5)); + Duple start = item_to_window (Duple (x, y).translate (Duple (0.5, 0.5))); context->move_to (start.x, start.y); context->line_to (start.x + _width, start.y); @@ -403,7 +407,7 @@ SequencerGrid::render (Rect const & area, Cairo::RefPtr context) for (int n = 0; n < _nsteps; ++n) { double x = n * _step_dimen; double y = 0; - Duple start = Duple (x, y).translate (_position).translate (Duple (0.5, 0.5)); + Duple start = item_to_window (Duple (x, y).translate (Duple (0.5, 0.5))); context->move_to (start.x, start.y); context->line_to (start.x, start.y + _height); @@ -413,21 +417,27 @@ SequencerGrid::render (Rect const & area, Cairo::RefPtr context) render_children (area, context); } -SequencerStepIndicator::SequencerStepIndicator (Item *p, int n) +Gtkmm2ext::Color SequencerStepIndicator::other_color = Gtkmm2ext::Color (0); +Gtkmm2ext::Color SequencerStepIndicator::current_color = Gtkmm2ext::Color (0); +Gtkmm2ext::Color SequencerStepIndicator::other_text_color = Gtkmm2ext::Color (0); +Gtkmm2ext::Color SequencerStepIndicator::current_text_color = Gtkmm2ext::Color (0); +int SequencerStepIndicator::dragging = 0; + +SequencerStepIndicator::SequencerStepIndicator (SequencerGrid& s, Item *p, size_t n) : Rectangle (p) + , grid (s) + , number (n) { + if (current_color == 0) { /* zero alpha? not set */ + other_color = UIConfiguration::instance().color ("gtk_bases"); + current_color = UIConfiguration::instance().color ("gtk_bright_color"); + other_text_color = contrasting_text_color (other_color); + current_text_color = contrasting_text_color (current_color); + } + set_fill (false); set_outline (false); - text = new Text (this); - if (n == 7) { - text->set ("\u21a9"); - } else { - text->set (string_compose ("%1", n)); - } - text->set_font_description (UIConfiguration::instance ().get_SmallFont ()); - text->set_position (Duple ((_step_dimen/2.0) - (text->width()/2.0), 5.0)); - poly = new Polygon (this); Points points; points.push_back (Duple (0.0, 0.0)); @@ -436,7 +446,144 @@ SequencerStepIndicator::SequencerStepIndicator (Item *p, int n) points.push_back (Duple (_step_dimen/2.0, _step_dimen)); points.push_back (Duple (0.0, _step_dimen/2.0)); poly->set (points); - poly->set_fill_color (Gtkmm2ext::color_at_alpha (random(), 0.4)); + poly->set_fill_color (current_color); + poly->set_ignore_events (true); + + text = new Text (this); + + set_text (); + + text->set_font_description (UIConfiguration::instance ().get_SmallFont ()); + text->set_position (Duple ((_step_dimen/2.0) - (text->width()/2.0), 5.0)); + text->set_color (other_text_color); + text->set_ignore_events (true); + + Event.connect (sigc::mem_fun (*this, &SequencerStepIndicator::on_event)); +} + +void +SequencerStepIndicator::set_text () +{ + StepSequence& sequence = grid.sequencer().sequence (number / grid.sequencer().nsteps()); + + if (number == sequence.end_step()) { + text->set ("\u21a9"); + } else if (number == sequence.start_step()) { + text->set ("\u21aa"); + } else { + text->set (string_compose ("%1", number+1)); + } +} + +bool +SequencerStepIndicator::on_event (GdkEvent* ev) +{ + bool ret = false; + + switch (ev->type) { + case GDK_ENTER_NOTIFY: + switch (dragging) { + case 1: /* end */ + text->set ("\u21a9"); + poly->set_outline_color (current_color); + break; + case -1: + text->set ("\u21aa"); + poly->set_outline_color (current_color); + break; + default: + text->set (string_compose ("%1", number+1)); + poly->set_outline_color (other_color); + } + break; + case GDK_LEAVE_NOTIFY: + if (dragging) { + text->set (string_compose ("%1", number+1)); + poly->set_outline_color (other_color); + } + break; + case GDK_MOTION_NOTIFY: + ret = motion_event (&ev->motion); + break; + case GDK_BUTTON_PRESS: + ret = button_press_event (&ev->button); + break; + case GDK_BUTTON_RELEASE: + ret = button_release_event (&ev->button); + break; + case GDK_SCROLL: + ret = scroll_event (&ev->scroll); + default: + break; + } + + return ret; +} + +bool +SequencerStepIndicator::motion_event (GdkEventMotion* ev) +{ + //const double distance = last_motion.second - ev->y; + + last_motion = std::make_pair (ev->x, ev->y); + return true; +} + +bool +SequencerStepIndicator::button_press_event (GdkEventButton* ev) +{ + StepSequence& sequence = grid.sequencer().sequence (number / grid.sequencer().nsteps()); + + if (number == sequence.end_step()) { + dragging = 1; + } else if (number == sequence.start_step()) { + dragging = -1; + } + + return true; +} + +bool +SequencerStepIndicator::button_release_event (GdkEventButton* ev) +{ + dragging = 0; + return true; +} + +bool +SequencerStepIndicator::scroll_event (GdkEventScroll* ev) +{ + int amt = 0; + + switch (ev->direction) { + case GDK_SCROLL_UP: + amt = 1; + break; + case GDK_SCROLL_LEFT: + amt = -1; + break; + case GDK_SCROLL_RIGHT: + amt = 1; + break; + case GDK_SCROLL_DOWN: + amt = -1; + break; + } + + return true; +} + + +void +SequencerStepIndicator::set_current (bool yn) +{ + if (yn) { + poly->set_fill_color (current_color); + text->set_color (current_text_color); + } else { + poly->set_fill_color (other_color); + text->set_color (other_text_color); + } } void @@ -446,6 +593,9 @@ SequencerStepIndicator::render (Rect const & area, Cairo::RefPtrset_fill_color (contrasting_text_color (fill_color())); + set_fill_color (off_fill_color); + set_outline_color (UIConfiguration::instance().color ("gtk_bright_color")); + set_outline (false); + + text->set_color (contrasting_text_color (fill_color())); text->set_font_description (UIConfiguration::instance ().get_SmallFont ()); text->hide (); @@ -466,56 +623,79 @@ StepView::StepView (SequencerGrid& sg, Step& s, ArdourCanvas::Item* parent) void StepView::view_mode_changed () { - cerr << "view mode changed\n"; - if (_seq.mode() == SequencerGrid::Octave) { - cerr << "octave\n"; - - text->show (); - if (_step.octave_shift() >= 0) { - text->set (string_compose ("+%1", _step.octave_shift())); - } else { - text->set (string_compose ("%1", _step.octave_shift())); - } - - const double w = text->width(); - const double h = text->height(); - - cerr << "put octave text " << text->text() << " dimen " << w << " x " << h << " @ " << Duple (_step_dimen/2 - (w/2), _step_dimen/2 - (h/2)) << endl; - - text->set_position (Duple (_step_dimen/2 - (w/2), _step_dimen/2 - (h/2))); - + set_octave_text (); } else if (_seq.mode() == SequencerGrid::Group) { - text->set (std::string()); - text->show (); + set_group_text (); } else { text->hide (); } } +void +StepView::set_group_text () +{ + text->hide (); +} + +void +StepView::set_octave_text () +{ + if (_step.octave_shift() > 0) { + text->set (string_compose ("+%1", _step.octave_shift())); + text->show (); + } else if (_step.octave_shift() == 0) { + text->hide (); + } else { + text->set (string_compose ("%1", _step.octave_shift())); + text->show (); + } + + if (text->self_visible()) { + const double w = text->width(); + const double h = text->height(); + text->set_position (Duple (_step_dimen/2 - (w/2), _step_dimen/2 - (h/2))); + } +} + void StepView::step_changed (PropertyChange const &) { + if (_seq.mode() == SequencerGrid::Octave) { + set_octave_text (); + } + + if (_step.velocity()) { + set_fill_color (on_fill_color); + } else { + set_fill_color (off_fill_color); + } + redraw (); } void StepView::render (ArdourCanvas::Rect const & area, Cairo::RefPtr context) const { + Rectangle::render (area, context); + if (_seq.mode() == SequencerGrid::Velocity) { const double height = (_step_dimen - 4) * _step.velocity(); const Duple origin = item_to_window (Duple (0, 0)); + set_source_rgba (context, outline_color()); context->rectangle (origin.x + 2, origin.y + (_step_dimen - height - 2), _step_dimen - 4, height); context->fill (); } else if (_seq.mode() == SequencerGrid::Pitch) { const double height = (_step_dimen - 4) * (_step.note() / 128.0); const Duple origin = item_to_window (Duple (0, 0)); + set_source_rgba (context, outline_color()); context->rectangle (origin.x + 2, origin.y + (_step_dimen - height - 2), _step_dimen - 4, height); context->fill (); } else if (_seq.mode() == SequencerGrid::Duration) { const Step::DurationRatio d (_step.duration()); const double height = ((_step_dimen - 4.0) * d.numerator()) / d.denominator(); const Duple origin = item_to_window (Duple (0, 0)); + set_source_rgba (context, outline_color()); context->rectangle (origin.x + 2, origin.y + (_step_dimen - height - 2), _step_dimen - 4, height); context->fill (); } @@ -560,13 +740,10 @@ StepView::motion_event (GdkEventMotion* ev) const double distance = last_motion.second - ev->y; if ((ev->state & GDK_MOD1_MASK) || _seq.mode() == SequencerGrid::Pitch) { - cerr << "adjust pitch by " << distance << endl; adjust_step_pitch (distance); } else if (_seq.mode() == SequencerGrid::Velocity) { - cerr << "adjust velocity by " << distance << endl; adjust_step_velocity (distance); } else if (_seq.mode() == SequencerGrid::Duration) { - cerr << "adjust duration by " << Step::DurationRatio (distance, 32) << endl; adjust_step_duration (Step::DurationRatio (distance, 32)); /* adjust by 1/32 of the sequencer step size */ } else if (_seq.mode() == SequencerGrid::Octave) { adjust_step_octave (distance); @@ -598,16 +775,14 @@ StepView::button_release_event (GdkEventButton* ev) if (fabs (last_motion.second - grab_at.second) < 4) { /* just a click */ - cerr << "just a click! " << last_motion.first << " grab at " << grab_at.first << endl; - if (_seq.mode() == SequencerGrid::Velocity) { - _step.set_velocity (1.0); - } else if (_seq.mode() == SequencerGrid::Octave) { - if (ev->button == 1) { - adjust_step_octave (1); - } else if (ev->button == 3) { - adjust_step_octave (-1); + if (_step.velocity()) { + _step.set_velocity (0.0); + } else { + _step.set_velocity (0.9); } + } else if (_seq.mode() == SequencerGrid::Octave) { + _step.set_octave_shift (0); } } } diff --git a/gtk2_ardour/beatbox_gui.h b/gtk2_ardour/beatbox_gui.h index 86e75159b1..0faf7c439d 100644 --- a/gtk2_ardour/beatbox_gui.h +++ b/gtk2_ardour/beatbox_gui.h @@ -79,7 +79,6 @@ class StepView : public ArdourCanvas::Rectangle, public sigc::trackable { SequencerGrid& _seq; ArdourCanvas::Text* text; bool grabbed; - bool grab_motion; std::pair grab_at; std::pair last_motion; @@ -97,7 +96,43 @@ class StepView : public ArdourCanvas::Rectangle, public sigc::trackable { void step_changed (PBD::PropertyChange const &); PBD::ScopedConnection step_connection; - void make_text (); + void set_octave_text (); + void set_group_text (); + + static Gtkmm2ext::Color on_fill_color; + static Gtkmm2ext::Color off_fill_color; +}; + +class SequencerStepIndicator : public ArdourCanvas::Rectangle { + public: + SequencerStepIndicator (SequencerGrid&, ArdourCanvas::Item *, size_t n); + void render (ArdourCanvas::Rect const &, Cairo::RefPtr) const; + bool on_event (GdkEvent*); + + void set_current (bool); + + private: + SequencerGrid& grid; + size_t number; + ArdourCanvas::Polygon* poly; + ArdourCanvas::Text* text; + + std::pair grab_at; + std::pair last_motion; + + static int dragging; + + bool motion_event (GdkEventMotion*); + bool button_press_event (GdkEventButton*); + bool button_release_event (GdkEventButton*); + bool scroll_event (GdkEventScroll*); + + void set_text (); + + static Gtkmm2ext::Color current_color; + static Gtkmm2ext::Color other_color; + static Gtkmm2ext::Color current_text_color; + static Gtkmm2ext::Color other_text_color; }; class SequencerGrid : public ArdourCanvas::Rectangle, public sigc::trackable { @@ -112,15 +147,20 @@ class SequencerGrid : public ArdourCanvas::Rectangle, public sigc::trackable { SequencerGrid (ARDOUR::StepSequencer&, ArdourCanvas::Canvas*); + ARDOUR::StepSequencer& sequencer() const { return _sequencer; } + Mode mode() const { return _mode; } void set_mode (Mode m); void render (ArdourCanvas::Rect const &, Cairo::RefPtr) const; + void update (); private: ARDOUR::StepSequencer& _sequencer; typedef std::vector StepViews; - StepViews _step_views; + StepViews step_views; + typedef std::vector StepIndicators; + StepIndicators step_indicators; double _width; double _height; Mode _mode; @@ -134,15 +174,6 @@ class SequencerGrid : public ArdourCanvas::Rectangle, public sigc::trackable { PBD::ScopedConnection sequencer_connection; }; -class SequencerStepIndicator : public ArdourCanvas::Rectangle { - public: - SequencerStepIndicator (ArdourCanvas::Item *, int n); - void render (ArdourCanvas::Rect const &, Cairo::RefPtr) const; - private: - ArdourCanvas::Polygon* poly; - ArdourCanvas::Text* text; -}; - class BBGUI : public ArdourDialog { public: BBGUI (boost::shared_ptr bb);