diff --git a/gtk2_ardour/cuebox_ui.cc b/gtk2_ardour/cuebox_ui.cc new file mode 100644 index 0000000000..e0911f86b4 --- /dev/null +++ b/gtk2_ardour/cuebox_ui.cc @@ -0,0 +1,347 @@ +/* + * Copyright (C) 2021 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "pbd/compose.h" +#include "pbd/convert.h" + +#include "ardour/region.h" +#include "ardour/triggerbox.h" + +#include "canvas/polygon.h" +#include "canvas/text.h" + +#include "gtkmm2ext/actions.h" +#include "gtkmm2ext/colors.h" +#include "gtkmm2ext/utils.h" + +#include "ardour_ui.h" +#include "gui_thread.h" +#include "cuebox_ui.h" +#include "public_editor.h" +#include "region_view.h" +#include "selection.h" +#include "timers.h" +#include "ui_config.h" +#include "utils.h" + +#include "pbd/i18n.h" + +using namespace ARDOUR; +using namespace ArdourCanvas; +using namespace Gtkmm2ext; +using namespace PBD; + +CueEntry::CueEntry (Item* item, uint64_t cue_index) + : ArdourCanvas::Rectangle (item) + , _cue_idx (cue_index) +{ + set_layout_sensitive(true); //why??? + + name = string_compose ("cue %1", _cue_idx); + + Event.connect (sigc::mem_fun (*this, &CueEntry::event_handler)); + + set_outline (false); + set_fill_color (UIConfiguration::instance().color ("theme:bg")); + + play_button = new ArdourCanvas::Rectangle (this); + play_button->set_outline (false); + play_button->set_fill(true); + play_button->name = string_compose ("playbutton %1", _cue_idx); + play_button->show (); + + play_shape = new ArdourCanvas::Polygon (play_button); + play_shape->name = string_compose ("playshape %1", _cue_idx); + play_shape->show (); + + name_button = new ArdourCanvas::Rectangle (this); + name_button->set_outline (true); + name_button->set_fill(false); + name_button->name = ("slot_selector_button"); + name_button->show (); + + name_text = new Text (name_button); + name_text->set_ignore_events (false); + name_text->show(); + + /* watch for change in theme */ + UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &CueEntry::ui_parameter_changed)); + ui_parameter_changed("color-file"); +} + +CueEntry::~CueEntry () +{ +} + +bool +CueEntry::event_handler (GdkEvent* ev) +{ + //for now, we fall thru to the cuebox for all events + switch (ev->type) { + case GDK_BUTTON_PRESS: + break; + case GDK_ENTER_NOTIFY: + break; + case GDK_LEAVE_NOTIFY: + break; + default: + break; + } + + return false; +} + +void +CueEntry::_size_allocate (ArdourCanvas::Rect const & alloc) +{ + Rectangle::_size_allocate (alloc); + + const Distance width = _rect.width(); + const Distance height = _rect.height(); + + play_button->set (ArdourCanvas::Rect (0, 0, height, height)); + name_button->set (ArdourCanvas::Rect (height, 0, width, height)); + + const double scale = UIConfiguration::instance().get_ui_scale(); + poly_margin = 2. * scale; + poly_size = height - 2*poly_margin; + shape_play_button (); + + float tleft = height; //make room for the play button + float twidth = name_button->width() - poly_margin*2; + + name_text->size_allocate (Rect(0, 0, width, height)); + name_text->set_position (Duple (tleft + poly_margin, poly_margin -0.5)); + name_text->clamp_width ( width - height ); + + //font scale may have changed. uiconfig 'embeds' the ui-scale in the font + name_text->set_font_description (UIConfiguration::instance().get_NormalFont()); +} + +void +CueEntry::render (Rect const & area, Cairo::RefPtr context) const +{ + Rectangle::render(area, context); +} + +void +CueEntry::shape_play_button () +{ + Points p; + + { + /* region exists; draw triangle to show that we can trigger */ + p.push_back (Duple (poly_margin, poly_margin)); + p.push_back (Duple (poly_margin, poly_size)); + p.push_back (Duple (poly_size, 0.5+poly_size / 2.)); + } + + play_shape->set (p); + + if (false /*ToDo*/) { + play_shape->set_outline (false); + play_shape->set_fill (true); + } else { + play_shape->set_outline (true); + play_shape->set_fill (false); + } +} + +void +CueEntry::ui_parameter_changed (std::string const& p) +{ + if (p == "color-file") { + set_fill_color (UIConfiguration::instance().color("theme:bg")); + + name_text->set_color (UIConfiguration::instance().color("neutral:foreground")); + + name_button->set_outline_color (UIConfiguration::instance().color("theme:bg")); + + play_button->set_outline_color (UIConfiguration::instance().color("theme:bg")); + play_button->set_fill_color (UIConfiguration::instance().color("theme:bg")); + + play_shape->set_outline_color (UIConfiguration::instance().color("neutral:midground")); + play_shape->set_fill_color (UIConfiguration::instance().color("neutral:midground")); + } +} + + + +/* ---------------------------- */ + +Gtkmm2ext::Bindings* CueBoxUI::bindings = 0; +Glib::RefPtr CueBoxUI::trigger_actions; + +CueBoxUI::CueBoxUI (ArdourCanvas::Item* parent) + : Rectangle (parent) +{ + set_layout_sensitive(true); //why??? + + set_fill_color (UIConfiguration::instance().color(X_("theme:bg"))); + set_fill (true); + + build (); +} + +CueBoxUI::~CueBoxUI () +{ +} + +void +CueBoxUI::setup_actions_and_bindings () +{ + load_bindings (); + register_actions (); +} + +void +CueBoxUI::load_bindings () +{ + bindings = Bindings::get_bindings (X_("Triggers")); +} + +void +CueBoxUI::register_actions () +{ +#if 0 + trigger_actions = ActionManager::create_action_group (bindings, X_("Triggers")); + + for (int32_t n = 0; n < CueBox::default_triggers_per_box; ++n) { + const std::string action_name = string_compose ("trigger-scene-%1", n); + const std::string display_name = string_compose (_("Scene %1"), n); + + ActionManager::register_toggle_action (trigger_actions, action_name.c_str(), display_name.c_str(), sigc::bind (sigc::ptr_fun (CueBoxUI::trigger_scene), n)); + } +#endif +} + +void +CueBoxUI::trigger_scene (uint64_t n) +{ + TriggerBox::scene_bang (n); +} + +void +CueBoxUI::build () +{ + // clear_items (true); + + _slots.clear (); + + for (int32_t n = 0; n < 8; ++n) { //ToDo + CueEntry* te = new CueEntry (this, n); + + _slots.push_back (te); + +// te->play_button->Event.connect (sigc::bind (sigc::mem_fun (*this, &CueBoxUI::trigger_scene), n)); +// te->name_text->Event.connect (sigc::bind (sigc::mem_fun (*this, &CueBoxUI::text_event), n)); + te->Event.connect (sigc::bind (sigc::mem_fun (*this, &CueBoxUI::event), n)); + } +} + +void +CueBoxUI::_size_allocate (ArdourCanvas::Rect const & alloc) +{ + Rectangle::_size_allocate (alloc); + + const float width = alloc.width(); + const float height = alloc.height(); + + const float slot_h = height / 8; //ToDo + + float ypos = 0; + for (auto & slot : _slots) { + slot->size_allocate (Rect(0, 0, width, slot_h)); + slot->set_position (Duple (0, ypos)); + ypos += slot_h; + slot->show(); + } + +} + +bool +CueBoxUI::text_event (GdkEvent *ev, uint64_t n) +{ + return false; +} + +bool +CueBoxUI::event (GdkEvent* ev, uint64_t n) +{ + switch (ev->type) { + case GDK_BUTTON_PRESS: + trigger_scene(n); + break; + case GDK_2BUTTON_PRESS: + break; + case GDK_BUTTON_RELEASE: + break; + default: + break; + } + + return false; +} + + +/* ------------ */ + +CueBoxWidget::CueBoxWidget (float w, float h) : FittedCanvasWidget(w,h) +{ + ui = new CueBoxUI (root()); + set_background_color (UIConfiguration::instance().color (X_("theme:bg"))); +} + +void +CueBoxWidget::on_map () +{ + FittedCanvasWidget::on_map (); +} + +void +CueBoxWidget::on_unmap () +{ + FittedCanvasWidget::on_unmap (); +} + + +/* ------------ */ + +CueBoxWindow::CueBoxWindow () +{ + CueBoxWidget* tbw = manage (new CueBoxWidget (-1., 8*16.)); + set_title (_("CueBox for XXXX")); + + set_default_size (-1., 8*16.); + add (*tbw); + tbw->show (); +} + +bool +CueBoxWindow::on_key_press_event (GdkEventKey* ev) +{ + Gtk::Window& main_window (ARDOUR_UI::instance()->main_window()); + return ARDOUR_UI_UTILS::relay_key_press (ev, &main_window); +} + +bool +CueBoxWindow::on_key_release_event (GdkEventKey* ev) +{ + Gtk::Window& main_window (ARDOUR_UI::instance()->main_window()); + return ARDOUR_UI_UTILS::relay_key_press (ev, &main_window); +} diff --git a/gtk2_ardour/cuebox_ui.h b/gtk2_ardour/cuebox_ui.h new file mode 100644 index 0000000000..f72b9b8f04 --- /dev/null +++ b/gtk2_ardour/cuebox_ui.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2021 Paul Davis + * Author: Ben Loftis 2021 + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __cuebox_ui_h__ +#define __cuebox_ui_h__ + +#include + +#include + +#include "pbd/properties.h" + +#include "ardour/triggerbox.h" + +#include "canvas/table.h" +#include "canvas/canvas.h" +#include "canvas/rectangle.h" + +#include "fitted_canvas_widget.h" + +namespace Gtk { +class FileChooserDialog; +class Menu; +} + +namespace Temporal { + struct BBT_Offset; +} + +namespace ArdourCanvas { + class Text; + class Polygon; +}; + +class CueEntry : public ArdourCanvas::Rectangle +{ + public: + CueEntry (ArdourCanvas::Item* item, uint64_t cue_index ); + ~CueEntry (); + + ArdourCanvas::Rectangle* play_button; + ArdourCanvas::Polygon* play_shape; + + ArdourCanvas::Rectangle* name_button; + ArdourCanvas::Text* name_text; + + void render (ArdourCanvas::Rect const & area, Cairo::RefPtr context) const; + + void _size_allocate (ArdourCanvas::Rect const &); + bool event_handler (GdkEvent*); + + private: + uint64_t _cue_idx; + + double poly_size; + double poly_margin; + + void shape_play_button (); + + void ui_parameter_changed (std::string const& p); +}; + + +class CueBoxUI : public ArdourCanvas::Rectangle +{ + public: + CueBoxUI (ArdourCanvas::Item* parent); + ~CueBoxUI (); + + void trigger_scene (uint64_t n); + + static Glib::RefPtr trigger_actions; + static void setup_actions_and_bindings (); + + void _size_allocate (ArdourCanvas::Rect const &); + + private: + + bool event (GdkEvent*, uint64_t); + bool text_event (GdkEvent*, uint64_t); + + typedef std::vector Slots; + Slots _slots; + + static Gtkmm2ext::Bindings* bindings; + static void load_bindings (); + static void register_actions (); + + void build (); +}; + +class CueBoxWidget : public FittedCanvasWidget +{ + public: + CueBoxWidget (float w, float h); + + void on_map (); + void on_unmap (); + + private: + CueBoxUI* ui; +}; + +/* XXX probably for testing only */ + +class CueBoxWindow : public Gtk::Window +{ + public: + CueBoxWindow (); + + bool on_key_press_event (GdkEventKey*); + bool on_key_release_event (GdkEventKey*); +}; + +#endif /* __cuebox_ui_h__ */ diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript index 5cd9c5bfcc..b08d3a20f6 100644 --- a/gtk2_ardour/wscript +++ b/gtk2_ardour/wscript @@ -72,6 +72,7 @@ gtk2_ardour_sources = [ 'control_point.cc', 'control_point_dialog.cc', 'control_slave_ui.cc', + 'cuebox_ui.cc', 'cursor_context.cc', 'curvetest.cc', 'debug.cc',