1 /*
2  * Copyright (C) 2010-2019 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2017 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 #ifndef __libgtkmm2ext_bindings_h__
21 #define __libgtkmm2ext_bindings_h__
22 
23 #include <map>
24 #include <vector>
25 #include <list>
26 
27 #include <stdint.h>
28 
29 #include <gdk/gdkkeysyms.h>
30 #include <gtkmm/action.h>
31 #include <gtkmm/radioaction.h>
32 #include <gtkmm/toggleaction.h>
33 
34 #include "pbd/signals.h"
35 
36 #include "gtkmm2ext/visibility.h"
37 
38 class XMLNode;
39 class XMLProperty;
40 
41 namespace Gtkmm2ext {
42 
43 class LIBGTKMM2EXT_API KeyboardKey
44 {
45   public:
KeyboardKey()46 	KeyboardKey () {
47 		_val = GDK_VoidSymbol;
48 	}
49 
50 	KeyboardKey (uint32_t state, uint32_t keycode);
51 
null_key()52 	static KeyboardKey null_key() { return KeyboardKey (0, 0); }
53 
state()54 	uint32_t state() const { return _val >> 32; }
key()55 	uint32_t key() const { return _val & 0xffffffff; }
56 
57 	bool operator<(const KeyboardKey& other) const {
58 		return _val < other._val;
59 	}
60 
61 	bool operator==(const KeyboardKey& other) const {
62 		return _val == other._val;
63 	}
64 
65 	std::string name() const;
66 	std::string native_name() const;
67 	std::string native_short_name() const;
68 	static bool make_key (const std::string&, KeyboardKey&);
69 
70 	std::string display_label() const;
71 
72   private:
73 	uint64_t _val;
74 };
75 
76 class LIBGTKMM2EXT_API MouseButton {
77   public:
MouseButton()78 	MouseButton () {
79 		_val = ~0ULL;
80 	}
81 
82 	MouseButton (uint32_t state, uint32_t button_number);
state()83 	uint32_t state() const { return _val >> 32; }
button()84 	uint32_t button() const { return _val & 0xffff; }
85 
86 	bool operator<(const MouseButton& other) const {
87 		return _val < other._val;
88 	}
89 
90 	bool operator==(const MouseButton& other) const {
91 		return _val == other._val;
92 	}
93 
94 	std::string name() const;
95 	static bool make_button (const std::string&, MouseButton&);
96 
97   private:
98 	uint64_t _val;
99 };
100 
101 class LIBGTKMM2EXT_API Bindings;
102 
103 class LIBGTKMM2EXT_API Bindings {
104   public:
105 	enum Operation {
106 		Press,
107 		Release
108 	};
109 
110 	struct ActionInfo {
ActionInfoActionInfo111 		ActionInfo (std::string const& name) : action_name (name) {}
ActionInfoActionInfo112 		ActionInfo (std::string const& name, std::string const& grp) : action_name (name), group_name (grp) {}
113 
114 		std::string action_name;
115 		std::string group_name; /* may be empty */
116 		mutable Glib::RefPtr<Gtk::Action> action;
117 	};
118 	typedef std::map<KeyboardKey,ActionInfo> KeybindingMap;
119 
120 	Bindings (std::string const& name);
121 	~Bindings ();
122 
name()123 	std::string const& name() const { return _name; }
124 
125 	void reassociate ();
126 	void associate ();
127 	void dissociate ();
128 
129 	bool empty() const;
130 	bool empty_keys () const;
131 	bool empty_mouse () const;
132 
133 	bool add (KeyboardKey, Operation, std::string const&, XMLProperty const*, bool can_save = false);
134 	bool replace (KeyboardKey, Operation, std::string const& action_name, bool can_save = true);
135 	bool remove (Operation, std::string const& action_name, bool can_save = false);
136 
137 	bool activate (KeyboardKey, Operation);
138 
139 	void add (MouseButton, Operation, std::string const&, XMLProperty const*);
140 	void remove (MouseButton, Operation);
141 	bool activate (MouseButton, Operation);
142 
143 	bool is_bound (KeyboardKey const&, Operation, std::string* path = 0) const;
144 	std::string bound_name (KeyboardKey const&, Operation) const;
145 	bool is_registered (Operation op, std::string const& action_name) const;
146 
147 	KeyboardKey get_binding_for_action (Glib::RefPtr<Gtk::Action>, Operation& op);
148 
149 	bool load (XMLNode const& node);
150 	void load_operation (XMLNode const& node);
151 	void save (XMLNode& root);
152 	void save_as_html (std::ostream&, bool) const;
153 
154 	/* used for editing bindings */
155 	void get_all_actions (std::vector<std::string>& paths,
156 	                      std::vector<std::string>& labels,
157 	                      std::vector<std::string>& tooltips,
158 	                      std::vector<std::string>& keys,
159 	                      std::vector<Glib::RefPtr<Gtk::Action> >& actions);
160 
161 	/* all bindings currently in existence, as grouped into Bindings */
reset_bindings()162 	static void reset_bindings () { bindings.clear (); }
163 	static std::list<Bindings*> bindings;
164 	static Bindings* get_bindings (std::string const & name);
165 	static void associate_all ();
166 	static void save_all_bindings_as_html (std::ostream&);
167 
168 	static PBD::Signal1<void,Bindings*> BindingsChanged;
169 
170   private:
171 	std::string  _name;
172 	KeybindingMap press_bindings;
173 	KeybindingMap release_bindings;
174 
175 	typedef std::map<MouseButton,ActionInfo> MouseButtonBindingMap;
176 	MouseButtonBindingMap button_press_bindings;
177 	MouseButtonBindingMap button_release_bindings;
178 
179 	void push_to_gtk (KeyboardKey, Glib::RefPtr<Gtk::Action>);
180 
181 	KeybindingMap& get_keymap (Operation op);
182 	const KeybindingMap& get_keymap (Operation op) const;
183 	MouseButtonBindingMap& get_mousemap (Operation op);
184 
185 	/* GTK has the following position a Gtk::Action:
186 	 *
187 	 *  accel_path: <Actions>/GroupName/ActionName
188 	 *  name: ActionName
189 	 *
190 	 * We want proper namespacing and we're not interested in
191 	 * the silly <Actions> "extra" namespace. So in Ardour:
192 	 *
193 	 * accel_path: <Actions>/GroupName/ActionName
194 	 * name: GroupName/ActionName
195 	 *
196 	 * This (static) method returns the "ardour" name for the action.
197 	 */
198 	static std::string ardour_action_name (Glib::RefPtr<Gtk::Action>);
199 
200 };
201 
202 } // namespace
203 
204 std::ostream& operator<<(std::ostream& out, Gtkmm2ext::KeyboardKey const & k);
205 
206 #endif /* __libgtkmm2ext_bindings_h__ */
207