blob: bef21a8673eb61168f1ec0adc48fec071b7c1536 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
// SPDX-License-Identifier: GPL-2.0-or-later
/**
* @file
* Action Accel
* A simple tracker for accelerator keys associated to an action
*
* Authors:
* Rafael Siejakowski <rs@rs-math.net>
*
* Copyright (C) 2022 the Authors.
*
* Released under GNU GPL v2+, read the file 'COPYING' for more information.
*/
#ifndef ACTION_ACCEL_H_SEEN
#define ACTION_ACCEL_H_SEEN
#include <gdk/gdk.h>
#include <glibmm/ustring.h>
#include <gtkmm.h>
#include <set>
#include <sigc++/sigc++.h>
#include <vector>
namespace Inkscape {
namespace Util {
/** Gtk::AccelKey but with equality and less-than operators */
class AcceleratorKey : public Gtk::AccelKey
{
public:
bool operator==(AcceleratorKey const &other) const
{
return (get_key() == other.get_key()) && (get_mod() == other.get_mod());
}
bool operator<(AcceleratorKey const &other) const
{
return (get_key() < other.get_key()) || (get_key() == other.get_key()
&& get_mod() < other.get_mod());
}
AcceleratorKey(Gtk::AccelKey const &ak) : Gtk::AccelKey{ak} {};
};
/**
* \brief The ActionAccel class stores the keyboard shortcuts for a given action
* and automatically keeps track of changes in the keybindings.
*
* Additionally, a signal is emitted when the keybindings for the action change.
*
* In order to create an ActionAccel object, one must pass a Glib::ustring containing the
* action name to the constructor. The object will automatically observe the
* keybindings for that action, so you always get up-to-date keyboard shortcuts.
* To check if a given key event triggers one of these keybindings, use `isTriggeredBy()`.
*
* Typical usage example:
* \code{.cpp}
auto accel = Inkscape::Util::ActionAccel("doc.undo");
GdkEventKey *key = get_from_somewhere();
if (accel.isTriggeredBy(key)) {
... // do stuff
}
accel.connectModified( []() { // This code will run when the user changes
// the keybindings for this action.
} );
\endcode
*/
class ActionAccel
{
private:
sigc::signal<void ()> _we_changed; ///< Emitted when the keybindings for the action are changed
sigc::connection _prefs_changed; ///< To listen to changes to the keyboard shortcuts
Glib::ustring _action; ///< Name of the action
std::set<AcceleratorKey> _accels; ///< Stores the accelerator keys for the action
/** Queries and updates the stored shortcuts, returning true if they have changed. */
bool _query();
/** Runs when the keyboard shortcut settings have changed */
void _onShortcutsModified();
public:
/**
* @brief Construct an ActionAccel object which will keep track of keybindings for a given action.
* @param action_name - the name of the action to hold and observe the keybindings of.
*/
ActionAccel(Glib::ustring action_name);
~ActionAccel();
/**
* @brief Returns all keyboard shortcuts for the action.
* @return a vector containing a Gtk::AccelKey for each of the keybindings present for the action.
*/
std::vector<Gtk::AccelKey> getKeys() const
{
return std::vector<Gtk::AccelKey>(_accels.begin(), _accels.end());
}
/**
* @brief Connects a void callback which will run whenever the keybindings for the action change.
* At the time when the callback runs, the values stored in the ActionAccel object will have
* already been updated. This means that the new keybindings can be queried by the callback.
* @param slot - the sigc::slot representing the callback function.
* @return the resulting sigc::connection.
*/
sigc::connection connectModified(sigc::slot<void ()> const &slot) { return _we_changed.connect(slot); }
/**
* @brief Checks whether a given key event triggers this action.
* @param key - a pointer to a GdkEventKey struct containing key event data.
* @return true if one of the keyboard shortcuts for the action is triggered by the passed event,
* false otherwise.
*/
bool isTriggeredBy(GdkEventKey *key) const;
};
} // namespace Util
} // namespace Inkscape
#endif // ACTION_ACCEL_H_SEEN
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
|