start on more structured code for step sequencer GUI

This commit is contained in:
Paul Davis 2018-11-05 23:39:37 -05:00
parent d37a61707b
commit ca869eda42
2 changed files with 233 additions and 141 deletions

View file

@ -42,12 +42,14 @@
#include "canvas/text.h"
#include "canvas/widget.h"
#include "gtkmm2ext/gui_thread.h"
#include "gtkmm2ext/utils.h"
#include "beatbox_gui.h"
#include "timers.h"
#include "ui_config.h"
using namespace PBD;
using namespace ARDOUR;
using namespace Gtkmm2ext;
using namespace ArdourCanvas;
@ -58,8 +60,6 @@ using std::endl;
const int _nsteps = 32;
const int _nrows = 8;
const double _step_dimen = 25;
const double _width = _step_dimen * _nsteps;
const double _height = _step_dimen * _nrows;
BBGUI::BBGUI (boost::shared_ptr<BeatBox> bb)
: ArdourDialog (_("BeatBox"))
@ -71,7 +71,6 @@ BBGUI::BBGUI (boost::shared_ptr<BeatBox> bb)
{
_canvas_viewport = new GtkCanvasViewport (horizontal_adjustment, vertical_adjustment);
_canvas_viewport->set_size_request (_width, _height + _step_dimen);
_canvas = _canvas_viewport->canvas();
_canvas->set_background_color (UIConfiguration::instance().color ("gtk_bright_color"));
@ -82,24 +81,15 @@ BBGUI::BBGUI (boost::shared_ptr<BeatBox> bb)
step_indicator_box = new ArdourCanvas::Container (no_scroll_group);
step_indicator_bg = new ArdourCanvas::Rectangle (step_indicator_box);
step_indicator_bg->set (Rect (0, 0, _width, _step_dimen));
step_indicator_bg->set_fill_color (UIConfiguration::instance().color ("gtk_lightest"));
step_indicator_bg->set_outline (false);
for (int n = 0; n < _nsteps; ++n) {
SequencerStepIndicator* ssi = new SequencerStepIndicator (step_indicator_box, n+1);
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());
}
v_scroll_group = new ScrollGroup (_canvas->root(), ScrollGroup::ScrollsVertically);
_canvas->add_scroller (*v_scroll_group);
_sequencer = new SequencerGrid (v_scroll_group);
_sequencer = new SequencerGrid (bbox->sequencer(), v_scroll_group);
_sequencer->set_position (Duple (0, _step_dimen));
_sequencer->set_fill_color (UIConfiguration::instance().color ("gtk_contrasting_indicator"));
_sequencer->Event.connect (sigc::mem_fun (*this, &BBGUI::grid_event));
srandom (time(0));
@ -120,6 +110,9 @@ BBGUI::BBGUI (boost::shared_ptr<BeatBox> bb)
export_as_region_button.signal_clicked.connect (sigc::mem_fun (*this, &BBGUI::export_as_region));
get_action_area()->pack_end (export_as_region_button);
PropertyChange pc;
sequencer_changed (pc);
show_all ();
}
@ -127,112 +120,6 @@ BBGUI::~BBGUI ()
{
}
bool
BBGUI::grid_event (GdkEvent* ev)
{
bool ret = false;
cerr << "grid event, type: " << event_type_string (ev->type);
switch (ev->type) {
case GDK_MOTION_NOTIFY:
ret = grid_motion_event (&ev->motion);
cerr << ' ' << ev->motion.x << ',' << ev->motion.y << " state " << show_gdk_event_state (ev->motion.state);
break;
case GDK_BUTTON_PRESS:
cerr << ' ' << ev->button.x << ',' << ev->button.y << " state " << show_gdk_event_state (ev->button.state);
ret = grid_button_press_event (&ev->button);
break;
case GDK_BUTTON_RELEASE:
cerr << ' ' << ev->button.x << ',' << ev->button.y << " state " << show_gdk_event_state (ev->button.state);
ret = grid_button_release_event (&ev->button);
break;
case GDK_SCROLL:
cerr << ' ' << ev->scroll.direction << show_gdk_event_state (ev->scroll.state);
ret = grid_scroll_event (&ev->scroll);
default:
break;
}
cerr << endl;
return ret;
}
bool
BBGUI::grid_motion_event (GdkEventMotion* ev)
{
return true;
}
bool
BBGUI::grid_button_press_event (GdkEventButton* ev)
{
set_grab_step (ev->x, ev->y);
grab_at = std::make_pair (ev->x, ev->y);
return true;
}
bool
BBGUI::grid_button_release_event (GdkEventButton* ev)
{
return true;
}
bool
BBGUI::grid_scroll_event (GdkEventScroll* ev)
{
int step = ev->x / _step_dimen;
int seq = ev->y / _step_dimen;
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;
}
if (ev->state & GDK_MOD1_MASK) {
cerr << "adjust pitch by " << amt << endl;
adjust_step_pitch (seq, step, amt);
} else {
cerr << "adjust velocity by " << amt << endl;
adjust_step_velocity (seq, step, amt);
}
return true;
}
void
BBGUI::set_grab_step (double x, double y)
{
int step = x / _step_dimen;
int seq = y / _step_dimen;
grab_step = std::make_pair (seq, step);
}
void
BBGUI::adjust_step_pitch (int seq, int step, int amt)
{
bbox->sequencer().adjust_step_pitch (seq, step, amt);
}
void
BBGUI::adjust_step_velocity (int seq, int step, int amt)
{
bbox->sequencer().adjust_step_velocity (seq, step, amt);
}
void
BBGUI::update ()
{
@ -376,15 +263,65 @@ BBGUI::export_as_region ()
boost::shared_ptr<Region> region = RegionFactory::create (src, plist, true);
}
SequencerGrid::SequencerGrid (Canvas *c)
: Rectangle (c)
void
BBGUI::sequencer_changed (PropertyChange const &)
{
set (Rect (0, 0, _width, _height));
const size_t nsteps = bbox->sequencer().nsteps();
const size_t nsequences = bbox->sequencer().nsequences();
_width = _step_dimen * nsteps;
_height = _step_dimen * nsequences;
/* height is 1 step_dimen larger to accomodate the "step indicator"
* line at the top
*/
_canvas_viewport->set_size_request (_width, _height + _step_dimen);
step_indicator_bg->set (Rect (0, 0, _width, _step_dimen));
step_indicator_box->clear (true); /* delete all existing step indicators */
/* indicator row */
for (size_t n = 0; n < nsteps; ++n) {
SequencerStepIndicator* ssi = new SequencerStepIndicator (step_indicator_box, n+1);
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 views, one per step per sequence */
for (size_t s = 0; s < nsequences; ++s) {
for (size_t n = 0; n < nsteps; ++n) {
StepView* sv = new StepView (*this, bbox->sequencer().sequence (s).step (n), v_scroll_group);
//sv->set (Rect (n * _step_dimen + 1, (s+1) * _step_dimen + 1, (n+1) * _step_dimen - 1, (s+2) * _step_dimen - 1));
sv->set_position (Duple (n * _step_dimen, (s+1) * _step_dimen));
sv->set (Rect (1, 1, _step_dimen - 2, _step_dimen - 2));
cerr << "step rect @ " << sv->get() << endl;
}
}
}
SequencerGrid::SequencerGrid (Item *p)
: Rectangle (p)
/**/
SequencerGrid::SequencerGrid (StepSequencer& s, Item *parent)
: Rectangle (parent)
, _sequencer (s)
{
PropertyChange pc;
sequencer_changed (pc);
}
void
SequencerGrid::sequencer_changed (PropertyChange const &)
{
const size_t nsteps = _sequencer.nsteps();
_width = _step_dimen * nsteps;
_height = _step_dimen * _sequencer.nsequences ();
set (Rect (0, 0, _width, _height));
}
@ -432,8 +369,6 @@ SequencerGrid::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context)
/* vertical bars for velocity */
Gtkmm2ext::set_source_rgba (context, UIConfiguration::instance().color ("gtk_somewhat_bright_indicator"));
for (int r = 0; r < _nrows; ++r) {
for (int c = 0; c < _nsteps; ++c) {
const double velocity = random() % 127 / 127.0;
@ -451,7 +386,11 @@ SequencerStepIndicator::SequencerStepIndicator (Item *p, int n)
set_outline (false);
text = new Text (this);
text->set (string_compose ("%1", n));
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));
@ -472,3 +411,122 @@ SequencerStepIndicator::render (Rect const & area, Cairo::RefPtr<Cairo::Context
Rectangle::render (area, context);
render_children (area, context);
}
StepView::StepView (BBGUI& bb, Step& s, ArdourCanvas::Item* parent)
: ArdourCanvas::Rectangle (parent)
, _step (s)
, bbgui (bb)
{
set_fill_color (UIConfiguration::instance().color ("gtk_bright_indicator"));
Event.connect (sigc::mem_fun (*this, &StepView::on_event));
_step.PropertyChanged.connect (step_connection, invalidator (*this), boost::bind (&StepView::step_changed, this, _1), gui_context());
}
void
StepView::step_changed (PropertyChange const &)
{
cerr << "Redraw for step @ " << _step.beat() << endl;
redraw ();
}
void
StepView::render (ArdourCanvas::Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
{
const double height = (_step_dimen - 2) * _step.velocity();
cerr << _step.beat() << " From V = " << _step.velocity() << " h = " << height << " area = " << area;
Rect r (1, height, _step_dimen - 2, _step_dimen - height);
r = item_to_window (r);
cerr << " draw " << r << endl;
context->rectangle (r.x1, r.y1, r.width(), r.height());
context->fill ();
}
bool
StepView::on_event (GdkEvent *ev)
{
bool ret = false;
switch (ev->type) {
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
StepView::motion_event (GdkEventMotion* ev)
{
return true;
}
bool
StepView::button_press_event (GdkEventButton* ev)
{
grab_at = std::make_pair (ev->x, ev->y);
return true;
}
bool
StepView::button_release_event (GdkEventButton* ev)
{
return true;
}
bool
StepView::scroll_event (GdkEventScroll* ev)
{
int step = ev->x / _step_dimen;
int seq = ev->y / _step_dimen;
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;
}
if (ev->state & GDK_MOD1_MASK) {
cerr << "adjust pitch by " << amt << endl;
adjust_step_pitch (amt);
} else {
cerr << "adjust velocity by " << amt << endl;
adjust_step_velocity (amt);
}
return true;
}
void
StepView::adjust_step_pitch (int amt)
{
_step.adjust_pitch (amt);
}
void
StepView::adjust_step_velocity (int amt)
{
_step.adjust_velocity (amt);
}

View file

@ -41,6 +41,10 @@
#include "widgets/ardour_dropdown.h"
#include "ardour_dialog.h"
namespace PBD {
class PropertyChange;
}
namespace ArdourCanvas {
class Grid;
class Item;
@ -53,14 +57,50 @@ class Widget;
namespace ARDOUR {
class BeatBox;
class Step;
class StepSequencer;
}
class BBGUI;
class StepView : public ArdourCanvas::Rectangle, public sigc::trackable {
public:
StepView (BBGUI&, ARDOUR::Step&, ArdourCanvas::Item*);
void render (ArdourCanvas::Rect const &, Cairo::RefPtr<Cairo::Context>) const;
bool on_event (GdkEvent*);
private:
ARDOUR::Step& _step;
BBGUI& bbgui;
std::pair<double,double> grab_at;
bool motion_event (GdkEventMotion*);
bool button_press_event (GdkEventButton*);
bool button_release_event (GdkEventButton*);
bool scroll_event (GdkEventScroll*);
void adjust_step_pitch (int amt);
void adjust_step_velocity (int amt);
void step_changed (PBD::PropertyChange const &);
PBD::ScopedConnection step_connection;
};
class SequencerGrid : public ArdourCanvas::Rectangle {
public:
SequencerGrid (ArdourCanvas::Canvas*);
SequencerGrid (ArdourCanvas::Item*);
SequencerGrid (ARDOUR::StepSequencer&, ArdourCanvas::Item* parent);
void render (ArdourCanvas::Rect const &, Cairo::RefPtr<Cairo::Context>) const;
private:
ARDOUR::StepSequencer& _sequencer;
std::vector<StepView*> step_views;
double _width;
double _height;
void sequencer_changed (PBD::PropertyChange const &);
};
class SequencerStepIndicator : public ArdourCanvas::Rectangle {
@ -77,12 +117,17 @@ class BBGUI : public ArdourDialog {
BBGUI (boost::shared_ptr<ARDOUR::BeatBox> bb);
~BBGUI ();
double width() const { return _width; }
double height() const { return _height; }
protected:
void on_map ();
void on_unmap ();
private:
boost::shared_ptr<ARDOUR::BeatBox> bbox;
double _width;
double _height;
Gtk::Adjustment horizontal_adjustment;
Gtk::Adjustment vertical_adjustment;
@ -113,18 +158,7 @@ class BBGUI : public ArdourDialog {
sigc::connection timer_connection;
bool grid_event (GdkEvent*);
bool grid_motion_event (GdkEventMotion*);
bool grid_button_press_event (GdkEventButton*);
bool grid_button_release_event (GdkEventButton*);
bool grid_scroll_event (GdkEventScroll*);
std::pair<int,int> grab_step;
std::pair<double,double> grab_at;
void set_grab_step (double x, double y);
void adjust_step_pitch (int seq, int step, int amt);
void adjust_step_velocity (int seq, int step, int amt);
void sequencer_changed (PBD::PropertyChange const &);
};
#endif /* __gtk2_ardour_beatbox_gui_h__ */