Optimize automation-event process splitting
[ardour.git] / gtk2_ardour / port_matrix.h
index dc863ad26b6c66757b208245937fc2bfd708389d..09c334b5efe7222f3e5bb570f08e0e6e26e0b378 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2002-2007 Paul Davis 
+    Copyright (C) 2002-2009 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
 
 */
 
-#ifndef __ardour_ui_port_matrix_h__
-#define __ardour_ui_port_matrix_h__
+#ifndef __gtk_ardour_port_matrix_h__
+#define __gtk_ardour_port_matrix_h__
 
+#include <list>
 #include <gtkmm/box.h>
-#include <gtkmm/checkbutton.h>
+#include <gtkmm/scrollbar.h>
 #include <gtkmm/table.h>
-#include <gtkmm/frame.h>
-#include <gtkmm/eventbox.h>
-#include <gtkmm/scrolledwindow.h>
+#include <gtkmm/label.h>
+#include <gtkmm/checkbutton.h>
+#include <gtkmm/notebook.h>
+#include <boost/shared_ptr.hpp>
+
+#include "ardour/bundle.h"
+#include "ardour/types.h"
+#include "ardour/session_handle.h"
 
-#include "ardour_dialog.h"
+#include "port_group.h"
+#include "port_matrix_types.h"
+
+/** The `port matrix' UI.  This is a widget which lets the user alter
+ *  associations between one set of ports and another.  e.g. to connect
+ *  things together.
+ *
+ *  It is made up of a body, PortMatrixBody, which is rendered using cairo,
+ *  and some scrollbars and other stuff.  All of this is arranged inside the
+ *  Table that we inherit from.
+ */
 
 namespace ARDOUR {
-       class Session;
-       class IO;
-       class PortInsert;
+       class Bundle;
+}
+
+namespace Gtk {
+       namespace Menu_Helpers {
+               class MenuList;
+       }
 }
 
-class PortMatrix;
+class PortMatrixBody;
 
-/// A list of port names, grouped by some aspect of their type e.g. busses, tracks, system
-class PortGroup
+class PortMatrix : public Gtk::Table, public ARDOUR::SessionHandlePtr
 {
-  public:
-       /** PortGroup constructor.
-        * @param n Name.
-        * @param p Port name prefix.
-        * @param v true if group should be visible in the UI, otherwise false.
-        */
-       PortGroup (std::string const & n, std::string const & p, bool v) : name (n), prefix (p), visible (v) {}
+public:
+       PortMatrix (Gtk::Window*, ARDOUR::Session *, ARDOUR::DataType);
+       ~PortMatrix ();
 
-       void add (std::string const & p);
+       void set_type (ARDOUR::DataType);
 
-       std::string name; ///< name for the group
-       std::string prefix; ///< prefix (before colon) e.g. "ardour:"
-       std::vector<std::string> ports; ///< port names
-       bool visible; ///< true if the group is visible in the UI
-};
+       ARDOUR::DataType type () const {
+               return _type;
+       }
 
-/// The UI for a PortGroup
-class PortGroupUI
-{
-  public:
-       PortGroupUI (PortMatrix&, PortGroup&);
-
-       Gtk::Widget& get_table ();
-       Gtk::Widget& get_visibility_checkbutton ();
-       std::pair<int, int> unit_size () const;
-       PortGroup& port_group () { return _port_group; }
-       void setup_visibility ();
-
-  private:
-       void port_checkbutton_toggled (Gtk::CheckButton*, int, int);
-       void visibility_checkbutton_toggled ();
-
-       PortMatrix& _port_matrix; ///< the PortMatrix that we are working for
-       PortGroup& _port_group; ///< the PortGroup that we are representing
-       bool _ignore_check_button_toggle;
-       Gtk::Table _table;
-       Gtk::EventBox _table_box;
-       std::vector<std::vector<Gtk::CheckButton* > > _port_checkbuttons;
-       Gtk::CheckButton _visibility_checkbutton;
-};
+       void disassociate_all ();
+       void setup_scrollbars ();
+       void popup_menu (ARDOUR::BundleChannel, ARDOUR::BundleChannel, uint32_t);
 
-/// A list of PortGroups
-class PortGroupList : public std::list<PortGroup*>
-{
-  public:
-       enum Mask {
-               BUSS = 0x1,
-               TRACK = 0x2,
-               SYSTEM = 0x4,
-               OTHER = 0x8
+       int min_height_divisor () const {
+               return _min_height_divisor;
+       }
+       void set_min_height_divisor (int f) {
+               _min_height_divisor = f;
+       }
+
+       enum Arrangement {
+               TOP_TO_RIGHT,  ///< column labels on top, row labels to the right
+               LEFT_TO_BOTTOM ///< row labels to the left, column labels on the bottom
        };
 
-       PortGroupList (ARDOUR::Session &, ARDOUR::DataType, bool, Mask);
 
-       void refresh ();
-       int n_visible_ports () const;
-       std::string get_port_by_index (int, bool with_prefix = true) const;
-       void set_type (ARDOUR::DataType);
-       void set_offer_inputs (bool);
-       
-  private:
-       ARDOUR::Session& _session;
-       ARDOUR::DataType _type;
-       bool _offer_inputs;
+       /** @return Arrangement in use */
+       Arrangement arrangement () const {
+               return _arrangement;
+       }
 
-       PortGroup buss;
-       PortGroup track;
-       PortGroup system;
-       PortGroup other;
-};
+       bool show_only_bundles () const {
+               return _show_only_bundles;
+       }
 
+       PortGroupList const * columns () const;
+       boost::shared_ptr<const PortGroup> visible_columns () const;
 
-/// A widget which provides a set of rotated text labels
-class RotatedLabelSet : public Gtk::Widget {
-  public:
-       RotatedLabelSet (PortGroupList&);
-       virtual ~RotatedLabelSet ();
-
-       void set_angle (int);
-       void set_base_width (int);
-       void update_visibility ();
-       
-  protected:
-       virtual void on_size_request (Gtk::Requisition*);
-       virtual void on_size_allocate (Gtk::Allocation&);
-       virtual void on_realize ();
-       virtual void on_unrealize ();
-       virtual bool on_expose_event (GdkEventExpose*);
-
-       Glib::RefPtr<Gdk::Window> _gdk_window;
-
-  private:
-       std::pair<int, int> setup_layout (std::string const &);
-
-       PortGroupList& _port_group_list; ///< list of ports to display
-       int _angle_degrees; ///< label rotation angle in degrees
-       double _angle_radians; ///< label rotation angle in radians
-       int _base_width; ///< width of labels; see set_base_width() for more details
-       Glib::RefPtr<Pango::Context> _pango_context;
-       Glib::RefPtr<Pango::Layout> _pango_layout;
-       Glib::RefPtr<Gdk::GC> _gc;
-       Gdk::Color _fg_colour;
-       Gdk::Color _bg_colour;
-};
+       /** @return index into the _ports array for the list which is displayed as columns */
+       int column_index () const {
+               return _column_index;
+       }
 
+       PortGroupList const * rows () const;
+       boost::shared_ptr<const PortGroup> visible_rows () const;
 
-class PortMatrix : public Gtk::VBox {
-  public:
-       PortMatrix (ARDOUR::Session&, ARDOUR::DataType, bool, PortGroupList::Mask);
-       ~PortMatrix ();
+       /** @return index into the _ports array for the list which is displayed as rows */
+       int row_index () const {
+               return _row_index;
+       }
 
-       void redisplay ();
+       PortGroupList const * ports (int d) const {
+               return &_ports[d];
+       }
+
+       boost::shared_ptr<const PortGroup> visible_ports (int d) const;
+
+       void init ();
+       void setup ();
+       virtual void setup_ports (int) = 0;
+       void setup_all_ports ();
+
+       std::pair<uint32_t, uint32_t> max_size () const;
+
+       bool should_show (ARDOUR::DataType) const;
+       uint32_t count_of_our_type (ARDOUR::ChanCount) const;
+       uint32_t count_of_our_type_min_1 (ARDOUR::ChanCount) const;
+
+       PortMatrixNode::State get_association (PortMatrixNode) const;
+
+       void flip ();
+       bool key_press (GdkEventKey *);
+
+       /** @param c Channels; where c[0] is from _ports[0] and c[1] is from _ports[1].
+        *  @param s New state.
+        */
+       virtual void set_state (ARDOUR::BundleChannel c[2], bool s) = 0;
+
+       /** @param c Channels; where c[0] is from _ports[0] and c[1] is from _ports[1].
+        *  @return state
+        */
+       virtual PortMatrixNode::State get_state (ARDOUR::BundleChannel c[2]) const = 0;
+       virtual bool list_is_global (int) const = 0;
+
+       virtual bool can_add_channels (boost::shared_ptr<ARDOUR::Bundle>) const;
+       virtual void add_channel (boost::shared_ptr<ARDOUR::Bundle>, ARDOUR::DataType);
+       virtual bool can_remove_channels (boost::shared_ptr<ARDOUR::Bundle>) const;
+       virtual void remove_channel (ARDOUR::BundleChannel);
+       virtual void remove_all_channels (boost::weak_ptr<ARDOUR::Bundle>);
+       virtual bool can_rename_channels (boost::shared_ptr<ARDOUR::Bundle>) const {
+               return false;
+       }
+       virtual void rename_channel (ARDOUR::BundleChannel) {}
+       virtual std::string disassociation_verb () const = 0;
+       virtual std::string channel_noun () const;
 
        enum Result {
                Cancelled,
@@ -160,43 +163,75 @@ class PortMatrix : public Gtk::VBox {
 
        sigc::signal<void, Result> Finished;
 
-       void set_type (ARDOUR::DataType);
-       void set_offer_inputs (bool);
-       bool offering_input() const { return _offer_inputs; }
-
-       virtual void set_state (int, std::string const &, bool) = 0;
-       virtual bool get_state (int, std::string const &) const = 0;
-       virtual uint32_t n_rows () const = 0;
-       virtual uint32_t maximum_rows () const = 0;
-       virtual uint32_t minimum_rows () const = 0;
-       virtual std::string row_name (int) const = 0;
-       virtual void add_row () = 0;
-       virtual void remove_row (int) = 0;
-       virtual std::string row_descriptor () const = 0;
-
-  protected:
-
-       bool _offer_inputs;
-
-  private:
-       PortGroupList _port_group_list;
+       static bool bundle_with_channels (boost::shared_ptr<ARDOUR::Bundle>);
+
+protected:
+
+       /** We have two port group lists.  One will be presented on the rows of the matrix,
+           the other on the columns.  The PortMatrix chooses the arrangement based on which has
+           more ports in it.  Subclasses must fill these two lists with the port groups that they
+           wish to present.  The PortMatrix will arrange its layout such that signal flow is vaguely
+           from left to right as you go from list 0 to list 1.  Hence subclasses which deal with
+           inputs and outputs should put outputs in list 0 and inputs in list 1. */
+       PortGroupList _ports[2];
+
+private:
+
+       void hscroll_changed ();
+       void vscroll_changed ();
+       void routes_changed ();
+       void reconnect_to_routes ();
+       void select_arrangement ();
+       void add_channel_proxy (boost::weak_ptr<ARDOUR::Bundle>, ARDOUR::DataType);
+       void remove_channel_proxy (boost::weak_ptr<ARDOUR::Bundle>, uint32_t);
+       void rename_channel_proxy (boost::weak_ptr<ARDOUR::Bundle>, uint32_t);
+       void disassociate_all_on_channel (boost::weak_ptr<ARDOUR::Bundle>, uint32_t, int);
+       void disassociate_all_on_bundle (boost::weak_ptr<ARDOUR::Bundle>, int);
+       void setup_global_ports ();
+        void setup_global_ports_proxy ();
+       void toggle_show_only_bundles ();
+       bool on_scroll_event (GdkEventScroll *);
+       boost::shared_ptr<ARDOUR::IO> io_from_bundle (boost::shared_ptr<ARDOUR::Bundle>) const;
+       void setup_notebooks ();
+       void remove_notebook_pages (Gtk::Notebook &);
+       void notebook_page_selected (GtkNotebookPage *, guint);
+       void route_processors_changed (ARDOUR::RouteProcessorChange);
+       void body_dimensions_changed ();
+       void session_going_away ();
+       void add_remove_option (Gtk::Menu_Helpers::MenuList &, boost::weak_ptr<ARDOUR::Bundle>, int);
+       void add_disassociate_option (Gtk::Menu_Helpers::MenuList &, boost::weak_ptr<ARDOUR::Bundle>, int, int);
+       void port_connected_or_disconnected ();
+       void update_tab_highlighting ();
+       std::pair<int, int> check_flip () const;
+       bool can_flip () const;
+
+       Gtk::Window* _parent;
+
+       /** port type that we are working with, or NIL if we are working with all of them */
        ARDOUR::DataType _type;
-       std::vector<PortGroupUI*> _port_group_ui;
-       std::vector<Gtk::EventBox*> _row_labels[2];
-       Gtk::VBox* _row_labels_vbox[2];
-       RotatedLabelSet _column_labels;
-       Gtk::HBox _overall_hbox;
-       Gtk::VBox _side_vbox[2];
-       Gtk::HBox _port_group_hbox;
-       Gtk::ScrolledWindow _scrolled_window;
-       Gtk::Label* _side_vbox_pad[2];
-       Gtk::HBox _visibility_checkbutton_box;
-
-       void setup ();
-       void clear ();
-       void setup_dimensions ();
-       bool row_label_button_pressed (GdkEventButton*, int);
-       void reset_visibility ();
+       PBD::ScopedConnectionList _route_connections;
+       PBD::ScopedConnectionList _changed_connections;
+       PBD::ScopedConnectionList _bundle_changed_connections;
+
+       PortMatrixBody* _body;
+       Gtk::HScrollbar _hscroll;
+       Gtk::VScrollbar _vscroll;
+       Gtk::Notebook _vnotebook;
+       Gtk::Notebook _hnotebook;
+       Gtk::Label _vlabel;
+       Gtk::Label _hlabel;
+       Gtk::VBox _vbox;
+       Gtk::HBox _hbox;
+       Gtk::Label _hspacer;
+       Gtk::Label _vspacer;
+       Gtk::Menu* _menu;
+       Arrangement _arrangement;
+       int _row_index;
+       int _column_index;
+       int _min_height_divisor;
+       bool _show_only_bundles;
+       bool _inhibit_toggle_show_only_bundles;
+       bool _ignore_notebook_page_selected;
 };
 
 #endif