expand the test used to decide if we need to make copies when uncombining a compound...
[ardour.git] / libs / widgets / binding_proxy.cc
1 /*
2  * Copyright (C) 2006 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2017-2019 Robin Gareus <robin@gareus.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19
20 #include <string>
21 #include <climits>
22 #include <iostream>
23
24 #include "pbd/controllable.h"
25 #include "gtkmm2ext/gui_thread.h"
26 #include "gtkmm2ext/keyboard.h"
27 #include "widgets/binding_proxy.h"
28 #include "widgets/popup.h"
29
30 #include "pbd/i18n.h"
31
32 using namespace std;
33 using namespace PBD;
34 using namespace Gtkmm2ext;
35 using namespace ArdourWidgets;
36
37 guint BindingProxy::bind_button = 2;
38 guint BindingProxy::bind_statemask = Gdk::CONTROL_MASK;
39
40 BindingProxy::BindingProxy (boost::shared_ptr<Controllable> c)
41         : prompter (0),
42           controllable (c)
43 {
44         if (c) {
45                 c->DropReferences.connect (
46                                 _controllable_going_away_connection, invalidator (*this),
47                                 boost::bind (&BindingProxy::set_controllable, this, boost::shared_ptr<Controllable> ()),
48                                 gui_context());
49         }
50 }
51
52 BindingProxy::BindingProxy ()
53         : prompter (0)
54 {
55 }
56
57 BindingProxy::~BindingProxy ()
58 {
59         if (prompter) {
60                 delete prompter;
61         }
62 }
63
64 void
65 BindingProxy::set_controllable (boost::shared_ptr<Controllable> c)
66 {
67         learning_finished ();
68         controllable = c;
69
70         _controllable_going_away_connection.disconnect ();
71         if (c) {
72                 c->DropReferences.connect (
73                                 _controllable_going_away_connection, invalidator (*this),
74                                 boost::bind (&BindingProxy::set_controllable, this, boost::shared_ptr<Controllable> ()),
75                                 gui_context());
76         }
77 }
78
79 void
80 BindingProxy::set_bind_button_state (guint button, guint statemask)
81 {
82         bind_button = button;
83         bind_statemask = statemask;
84 }
85
86 bool
87 BindingProxy::is_bind_action (GdkEventButton *ev)
88 {
89         return (Keyboard::modifier_state_equals (ev->state, bind_statemask) && ev->button == bind_button );
90 }
91
92 bool
93 BindingProxy::button_press_handler (GdkEventButton *ev)
94 {
95         if ( controllable && is_bind_action(ev) ) {
96                 if (Controllable::StartLearning (controllable)) {
97                         string prompt = _("operate controller now");
98                         if (prompter == 0) {
99                                 prompter = new PopUp (Gtk::WIN_POS_MOUSE, 30000, false);
100                                 prompter->signal_unmap_event().connect (mem_fun (*this, &BindingProxy::prompter_hiding));
101                         }
102                         prompter->set_text (prompt);
103                         prompter->touch (); // shows popup
104                         controllable->LearningFinished.connect_same_thread (learning_connection, boost::bind (&BindingProxy::learning_finished, this));
105                 }
106                 return true;
107         }
108
109         return false;
110 }
111
112 void
113 BindingProxy::learning_finished ()
114 {
115         learning_connection.disconnect ();
116         if (prompter) {
117                 prompter->touch (); // hides popup
118         }
119 }
120
121 bool
122 BindingProxy::prompter_hiding (GdkEventAny* /*ev*/)
123 {
124         learning_connection.disconnect ();
125         if (controllable) {
126                 Controllable::StopLearning (controllable);
127         }
128         return false;
129 }