4 #include "pbd/convert.h"
6 #include "gtkmm2ext/actions.h"
7 #include "gtkmm2ext/bindings.h"
8 #include "gtkmm2ext/keyboard.h"
15 using namespace Gtkmm2ext
;
17 uint32_t Bindings::_ignored_state
= 0;
19 MouseButton::MouseButton (uint32_t state
, uint32_t keycode
)
21 uint32_t ignore
= Bindings::ignored_state();
23 if (gdk_keyval_is_upper (keycode
) && gdk_keyval_is_lower (keycode
)) {
24 /* key is not subject to case, so ignore SHIFT
26 ignore
|= GDK_SHIFT_MASK
;
29 _val
= (state
& ~ignore
);
35 MouseButton::make_button (const string
& str
, MouseButton
& b
)
39 if (str
.find ("Primary") != string::npos
) {
40 s
|= Keyboard::PrimaryModifier
;
43 if (str
.find ("Secondary") != string::npos
) {
44 s
|= Keyboard::SecondaryModifier
;
47 if (str
.find ("Tertiary") != string::npos
) {
48 s
|= Keyboard::TertiaryModifier
;
51 if (str
.find ("Level4") != string::npos
) {
52 s
|= Keyboard::Level4Modifier
;
55 string::size_type lastmod
= str
.find_last_of ('-');
56 uint32_t button_number
;
58 if (lastmod
== string::npos
) {
59 button_number
= PBD::atoi (str
);
61 button_number
= PBD::atoi (str
.substr (lastmod
+1));
64 b
= MouseButton (s
, button_number
);
69 MouseButton::name () const
75 if (s
& Keyboard::PrimaryModifier
) {
78 if (s
& Keyboard::SecondaryModifier
) {
84 if (s
& Keyboard::TertiaryModifier
) {
90 if (s
& Keyboard::Level4Modifier
) {
102 snprintf (buf
, sizeof (buf
), "%u", button());
108 KeyboardKey::KeyboardKey (uint32_t state
, uint32_t keycode
)
110 uint32_t ignore
= Bindings::ignored_state();
112 if (gdk_keyval_is_upper (keycode
) && gdk_keyval_is_lower (keycode
)) {
113 /* key is not subject to case, so ignore SHIFT
115 ignore
|= GDK_SHIFT_MASK
;
118 _val
= (state
& ~ignore
);
125 KeyboardKey::name () const
131 if (s
& Keyboard::PrimaryModifier
) {
134 if (s
& Keyboard::SecondaryModifier
) {
140 if (s
& Keyboard::TertiaryModifier
) {
146 if (s
& Keyboard::Level4Modifier
) {
157 str
+= gdk_keyval_name (key());
163 KeyboardKey::make_key (const string
& str
, KeyboardKey
& k
)
167 if (str
.find ("Primary") != string::npos
) {
168 s
|= Keyboard::PrimaryModifier
;
171 if (str
.find ("Secondary") != string::npos
) {
172 s
|= Keyboard::SecondaryModifier
;
175 if (str
.find ("Tertiary") != string::npos
) {
176 s
|= Keyboard::TertiaryModifier
;
179 if (str
.find ("Level4") != string::npos
) {
180 s
|= Keyboard::Level4Modifier
;
183 string::size_type lastmod
= str
.find_last_of ('-');
186 if (lastmod
== string::npos
) {
187 keyval
= gdk_keyval_from_name (str
.c_str());
189 keyval
= gdk_keyval_from_name (str
.substr (lastmod
+1).c_str());
192 if (keyval
== GDK_VoidSymbol
) {
196 k
= KeyboardKey (s
, keyval
);
200 Bindings::Bindings ()
205 Bindings::~Bindings()
210 Bindings::set_action_map (ActionMap
& am
)
213 press_bindings
.clear ();
214 release_bindings
.clear ();
218 Bindings::activate (KeyboardKey kb
, Operation op
)
224 kbm
= &press_bindings
;
227 kbm
= &release_bindings
;
231 KeybindingMap::iterator k
= kbm
->find (kb
);
233 if (k
== kbm
->end()) {
234 /* no entry for this key in the state map */
240 k
->second
->activate ();
245 Bindings::add (KeyboardKey kb
, Operation op
, RefPtr
<Action
> what
)
251 kbm
= &press_bindings
;
254 kbm
= &release_bindings
;
258 KeybindingMap::iterator k
= kbm
->find (kb
);
260 if (k
== kbm
->end()) {
261 pair
<KeyboardKey
,RefPtr
<Action
> > newpair (kb
, what
);
262 kbm
->insert (newpair
);
263 cerr
<< "Bindings added " << kb
.key() << " w/ " << kb
.state() << " => " << what
->get_name() << endl
;
270 Bindings::remove (KeyboardKey kb
, Operation op
)
276 kbm
= &press_bindings
;
279 kbm
= &release_bindings
;
283 KeybindingMap::iterator k
= kbm
->find (kb
);
285 if (k
!= kbm
->end()) {
291 Bindings::activate (MouseButton bb
, Operation op
)
293 MouseButtonBindingMap
* bbm
;
297 bbm
= &button_press_bindings
;
300 bbm
= &button_release_bindings
;
304 MouseButtonBindingMap::iterator b
= bbm
->find (bb
);
306 if (b
== bbm
->end()) {
307 /* no entry for this key in the state map */
313 b
->second
->activate ();
318 Bindings::add (MouseButton bb
, Operation op
, RefPtr
<Action
> what
)
320 MouseButtonBindingMap
* bbm
;
324 bbm
= &button_press_bindings
;
327 bbm
= &button_release_bindings
;
331 MouseButtonBindingMap::iterator b
= bbm
->find (bb
);
333 if (b
== bbm
->end()) {
334 pair
<MouseButton
,RefPtr
<Action
> > newpair (bb
, what
);
335 bbm
->insert (newpair
);
336 cerr
<< "Bindings added mouse button " << bb
.button() << " w/ " << bb
.state() << " => " << what
->get_name() << endl
;
343 Bindings::remove (MouseButton bb
, Operation op
)
345 MouseButtonBindingMap
* bbm
;
349 bbm
= &button_press_bindings
;
352 bbm
= &button_release_bindings
;
356 MouseButtonBindingMap::iterator b
= bbm
->find (bb
);
358 if (b
!= bbm
->end()) {
364 Bindings::save (const string
& path
)
367 XMLNode
* root
= new XMLNode (X_("Bindings"));
368 tree
.set_root (root
);
372 if (!tree
.write (path
)) {
373 ::unlink (path
.c_str());
381 Bindings::save (XMLNode
& root
)
383 XMLNode
* presses
= new XMLNode (X_("Press"));
384 root
.add_child_nocopy (*presses
);
386 for (KeybindingMap::iterator k
= press_bindings
.begin(); k
!= press_bindings
.end(); ++k
) {
388 child
= new XMLNode (X_("Binding"));
389 child
->add_property (X_("key"), k
->first
.name());
390 string ap
= k
->second
->get_accel_path();
391 child
->add_property (X_("action"), ap
.substr (ap
.find ('/') + 1));
392 presses
->add_child_nocopy (*child
);
395 for (MouseButtonBindingMap::iterator k
= button_press_bindings
.begin(); k
!= button_press_bindings
.end(); ++k
) {
397 child
= new XMLNode (X_("Binding"));
398 child
->add_property (X_("button"), k
->first
.name());
399 string ap
= k
->second
->get_accel_path();
400 child
->add_property (X_("action"), ap
.substr (ap
.find ('/') + 1));
401 presses
->add_child_nocopy (*child
);
404 XMLNode
* releases
= new XMLNode (X_("Release"));
405 root
.add_child_nocopy (*releases
);
407 for (KeybindingMap::iterator k
= release_bindings
.begin(); k
!= release_bindings
.end(); ++k
) {
409 child
= new XMLNode (X_("Binding"));
410 child
->add_property (X_("key"), k
->first
.name());
411 string ap
= k
->second
->get_accel_path();
412 child
->add_property (X_("action"), ap
.substr (ap
.find ('/') + 1));
413 releases
->add_child_nocopy (*child
);
416 for (MouseButtonBindingMap::iterator k
= button_release_bindings
.begin(); k
!= button_release_bindings
.end(); ++k
) {
418 child
= new XMLNode (X_("Binding"));
419 child
->add_property (X_("button"), k
->first
.name());
420 string ap
= k
->second
->get_accel_path();
421 child
->add_property (X_("action"), ap
.substr (ap
.find ('/') + 1));
422 releases
->add_child_nocopy (*child
);
428 Bindings::load (const string
& path
)
436 if (!tree
.read (path
)) {
440 press_bindings
.clear ();
441 release_bindings
.clear ();
443 XMLNode
& root (*tree
.root());
444 const XMLNodeList
& children (root
.children());
446 for (XMLNodeList::const_iterator i
= children
.begin(); i
!= children
.end(); ++i
) {
454 Bindings::load (const XMLNode
& node
)
456 if (node
.name() == X_("Press") || node
.name() == X_("Release")) {
460 if (node
.name() == X_("Press")) {
466 const XMLNodeList
& children (node
.children());
468 for (XMLNodeList::const_iterator p
= children
.begin(); p
!= children
.end(); ++p
) {
474 ap
= (*p
)->property ("action");
475 kp
= (*p
)->property ("key");
476 bp
= (*p
)->property ("button");
478 if (!ap
|| (!kp
&& !bp
)) {
485 act
= action_map
->find_action (ap
->value());
489 string::size_type slash
= ap
->value().find ('/');
490 if (slash
!= string::npos
) {
491 string group
= ap
->value().substr (0, slash
);
492 string action
= ap
->value().substr (slash
+1);
493 act
= ActionManager::get_action (group
.c_str(), action
.c_str());
503 if (!KeyboardKey::make_key (kp
->value(), k
)) {
509 if (!MouseButton::make_button (bp
->value(), b
)) {
519 ActionMap::find_action (const string
& name
)
521 _ActionMap::iterator a
= actions
.find (name
);
523 if (a
!= actions
.end()) {
527 return RefPtr
<Action
>();
531 ActionMap::register_action (const char* path
,
532 const char* name
, const char* label
, sigc::slot
<void> sl
)
536 RefPtr
<Action
> act
= Action::create (name
, label
);
538 act
->signal_activate().connect (sl
);
544 actions
.insert (_ActionMap::value_type (fullpath
, act
));
549 ActionMap::register_radio_action (const char* path
, Gtk::RadioAction::Group
& rgroup
,
550 const char* name
, const char* label
,
551 sigc::slot
<void,GtkAction
*> sl
,
556 RefPtr
<Action
> act
= RadioAction::create (rgroup
, name
, label
);
557 RefPtr
<RadioAction
> ract
= RefPtr
<RadioAction
>::cast_dynamic(act
);
558 ract
->property_value() = value
;
560 act
->signal_activate().connect (sigc::bind (sl
, act
->gobj()));
566 actions
.insert (_ActionMap::value_type (fullpath
, act
));
571 ActionMap::register_toggle_action (const char* path
,
572 const char* name
, const char* label
, sigc::slot
<void> sl
)
576 RefPtr
<Action
> act
= ToggleAction::create (name
, label
);
578 act
->signal_activate().connect (sl
);
584 actions
.insert (_ActionMap::value_type (fullpath
, act
));