|
| 1 | +import CGtk |
| 2 | + |
| 3 | +/// `GtkGesture` is the base class for gesture recognition. |
| 4 | +/// |
| 5 | +/// Although `GtkGesture` is quite generalized to serve as a base for |
| 6 | +/// multi-touch gestures, it is suitable to implement single-touch and |
| 7 | +/// pointer-based gestures (using the special %NULL `GdkEventSequence` |
| 8 | +/// value for these). |
| 9 | +/// |
| 10 | +/// The number of touches that a `GtkGesture` need to be recognized is |
| 11 | +/// controlled by the [property@Gtk.Gesture:n-points] property, if a |
| 12 | +/// gesture is keeping track of less or more than that number of sequences, |
| 13 | +/// it won't check whether the gesture is recognized. |
| 14 | +/// |
| 15 | +/// As soon as the gesture has the expected number of touches, it will check |
| 16 | +/// regularly if it is recognized, the criteria to consider a gesture as |
| 17 | +/// "recognized" is left to `GtkGesture` subclasses. |
| 18 | +/// |
| 19 | +/// A recognized gesture will then emit the following signals: |
| 20 | +/// |
| 21 | +/// - [signal@Gtk.Gesture::begin] when the gesture is recognized. |
| 22 | +/// - [signal@Gtk.Gesture::update], whenever an input event is processed. |
| 23 | +/// - [signal@Gtk.Gesture::end] when the gesture is no longer recognized. |
| 24 | +/// |
| 25 | +/// ## Event propagation |
| 26 | +/// |
| 27 | +/// In order to receive events, a gesture needs to set a propagation phase |
| 28 | +/// through [method@Gtk.EventController.set_propagation_phase]. |
| 29 | +/// |
| 30 | +/// In the capture phase, events are propagated from the toplevel down |
| 31 | +/// to the target widget, and gestures that are attached to containers |
| 32 | +/// above the widget get a chance to interact with the event before it |
| 33 | +/// reaches the target. |
| 34 | +/// |
| 35 | +/// In the bubble phase, events are propagated up from the target widget |
| 36 | +/// to the toplevel, and gestures that are attached to containers above |
| 37 | +/// the widget get a chance to interact with events that have not been |
| 38 | +/// handled yet. |
| 39 | +/// |
| 40 | +/// ## States of a sequence |
| 41 | +/// |
| 42 | +/// Whenever input interaction happens, a single event may trigger a cascade |
| 43 | +/// of `GtkGesture`s, both across the parents of the widget receiving the |
| 44 | +/// event and in parallel within an individual widget. It is a responsibility |
| 45 | +/// of the widgets using those gestures to set the state of touch sequences |
| 46 | +/// accordingly in order to enable cooperation of gestures around the |
| 47 | +/// `GdkEventSequence`s triggering those. |
| 48 | +/// |
| 49 | +/// Within a widget, gestures can be grouped through [method@Gtk.Gesture.group]. |
| 50 | +/// Grouped gestures synchronize the state of sequences, so calling |
| 51 | +/// [method@Gtk.Gesture.set_state] on one will effectively propagate |
| 52 | +/// the state throughout the group. |
| 53 | +/// |
| 54 | +/// By default, all sequences start out in the %GTK_EVENT_SEQUENCE_NONE state, |
| 55 | +/// sequences in this state trigger the gesture event handler, but event |
| 56 | +/// propagation will continue unstopped by gestures. |
| 57 | +/// |
| 58 | +/// If a sequence enters into the %GTK_EVENT_SEQUENCE_DENIED state, the gesture |
| 59 | +/// group will effectively ignore the sequence, letting events go unstopped |
| 60 | +/// through the gesture, but the "slot" will still remain occupied while |
| 61 | +/// the touch is active. |
| 62 | +/// |
| 63 | +/// If a sequence enters in the %GTK_EVENT_SEQUENCE_CLAIMED state, the gesture |
| 64 | +/// group will grab all interaction on the sequence, by: |
| 65 | +/// |
| 66 | +/// - Setting the same sequence to %GTK_EVENT_SEQUENCE_DENIED on every other |
| 67 | +/// gesture group within the widget, and every gesture on parent widgets |
| 68 | +/// in the propagation chain. |
| 69 | +/// - Emitting [signal@Gtk.Gesture::cancel] on every gesture in widgets |
| 70 | +/// underneath in the propagation chain. |
| 71 | +/// - Stopping event propagation after the gesture group handles the event. |
| 72 | +/// |
| 73 | +/// Note: if a sequence is set early to %GTK_EVENT_SEQUENCE_CLAIMED on |
| 74 | +/// %GDK_TOUCH_BEGIN/%GDK_BUTTON_PRESS (so those events are captured before |
| 75 | +/// reaching the event widget, this implies %GTK_PHASE_CAPTURE), one similar |
| 76 | +/// event will be emulated if the sequence changes to %GTK_EVENT_SEQUENCE_DENIED. |
| 77 | +/// This way event coherence is preserved before event propagation is unstopped |
| 78 | +/// again. |
| 79 | +/// |
| 80 | +/// Sequence states can't be changed freely. |
| 81 | +/// See [method@Gtk.Gesture.set_state] to know about the possible |
| 82 | +/// lifetimes of a `GdkEventSequence`. |
| 83 | +/// |
| 84 | +/// ## Touchpad gestures |
| 85 | +/// |
| 86 | +/// On the platforms that support it, `GtkGesture` will handle transparently |
| 87 | +/// touchpad gesture events. The only precautions users of `GtkGesture` should |
| 88 | +/// do to enable this support are: |
| 89 | +/// |
| 90 | +/// - If the gesture has %GTK_PHASE_NONE, ensuring events of type |
| 91 | +/// %GDK_TOUCHPAD_SWIPE and %GDK_TOUCHPAD_PINCH are handled by the `GtkGesture` |
| 92 | +public class Gesture: EventController { |
| 93 | + |
| 94 | + public override func registerSignals() { |
| 95 | + super.registerSignals() |
| 96 | + |
| 97 | + let handler0: |
| 98 | + @convention(c) (UnsafeMutableRawPointer, OpaquePointer, UnsafeMutableRawPointer) -> Void = |
| 99 | + { _, value1, data in |
| 100 | + SignalBox1<OpaquePointer>.run(data, value1) |
| 101 | + } |
| 102 | + |
| 103 | + addSignal(name: "begin", handler: gCallback(handler0)) { |
| 104 | + [weak self] (param0: OpaquePointer) in |
| 105 | + guard let self = self else { return } |
| 106 | + self.begin?(self, param0) |
| 107 | + } |
| 108 | + |
| 109 | + let handler1: |
| 110 | + @convention(c) (UnsafeMutableRawPointer, OpaquePointer, UnsafeMutableRawPointer) -> Void = |
| 111 | + { _, value1, data in |
| 112 | + SignalBox1<OpaquePointer>.run(data, value1) |
| 113 | + } |
| 114 | + |
| 115 | + addSignal(name: "cancel", handler: gCallback(handler1)) { |
| 116 | + [weak self] (param0: OpaquePointer) in |
| 117 | + guard let self = self else { return } |
| 118 | + self.cancel?(self, param0) |
| 119 | + } |
| 120 | + |
| 121 | + let handler2: |
| 122 | + @convention(c) (UnsafeMutableRawPointer, OpaquePointer, UnsafeMutableRawPointer) -> Void = |
| 123 | + { _, value1, data in |
| 124 | + SignalBox1<OpaquePointer>.run(data, value1) |
| 125 | + } |
| 126 | + |
| 127 | + addSignal(name: "end", handler: gCallback(handler2)) { |
| 128 | + [weak self] (param0: OpaquePointer) in |
| 129 | + guard let self = self else { return } |
| 130 | + self.end?(self, param0) |
| 131 | + } |
| 132 | + |
| 133 | + let handler3: |
| 134 | + @convention(c) ( |
| 135 | + UnsafeMutableRawPointer, OpaquePointer, GtkEventSequenceState, |
| 136 | + UnsafeMutableRawPointer |
| 137 | + ) -> Void = |
| 138 | + { _, value1, value2, data in |
| 139 | + SignalBox2<OpaquePointer, GtkEventSequenceState>.run(data, value1, value2) |
| 140 | + } |
| 141 | + |
| 142 | + addSignal(name: "sequence-state-changed", handler: gCallback(handler3)) { |
| 143 | + [weak self] (param0: OpaquePointer, param1: GtkEventSequenceState) in |
| 144 | + guard let self = self else { return } |
| 145 | + self.sequenceStateChanged?(self, param0, param1) |
| 146 | + } |
| 147 | + |
| 148 | + let handler4: |
| 149 | + @convention(c) (UnsafeMutableRawPointer, OpaquePointer, UnsafeMutableRawPointer) -> Void = |
| 150 | + { _, value1, data in |
| 151 | + SignalBox1<OpaquePointer>.run(data, value1) |
| 152 | + } |
| 153 | + |
| 154 | + addSignal(name: "update", handler: gCallback(handler4)) { |
| 155 | + [weak self] (param0: OpaquePointer) in |
| 156 | + guard let self = self else { return } |
| 157 | + self.update?(self, param0) |
| 158 | + } |
| 159 | + |
| 160 | + let handler5: |
| 161 | + @convention(c) (UnsafeMutableRawPointer, OpaquePointer, UnsafeMutableRawPointer) -> Void = |
| 162 | + { _, value1, data in |
| 163 | + SignalBox1<OpaquePointer>.run(data, value1) |
| 164 | + } |
| 165 | + |
| 166 | + addSignal(name: "notify::n-points", handler: gCallback(handler5)) { |
| 167 | + [weak self] (param0: OpaquePointer) in |
| 168 | + guard let self = self else { return } |
| 169 | + self.notifyNPoints?(self, param0) |
| 170 | + } |
| 171 | + } |
| 172 | + |
| 173 | + /// Emitted when the gesture is recognized. |
| 174 | + /// |
| 175 | + /// This means the number of touch sequences matches |
| 176 | + /// [property@Gtk.Gesture:n-points]. |
| 177 | + /// |
| 178 | + /// Note: These conditions may also happen when an extra touch |
| 179 | + /// (eg. a third touch on a 2-touches gesture) is lifted, in that |
| 180 | + /// situation @sequence won't pertain to the current set of active |
| 181 | + /// touches, so don't rely on this being true. |
| 182 | + public var begin: ((Gesture, OpaquePointer) -> Void)? |
| 183 | + |
| 184 | + /// Emitted whenever a sequence is cancelled. |
| 185 | + /// |
| 186 | + /// This usually happens on active touches when |
| 187 | + /// [method@Gtk.EventController.reset] is called on @gesture |
| 188 | + /// (manually, due to grabs...), or the individual @sequence |
| 189 | + /// was claimed by parent widgets' controllers (see |
| 190 | + /// [method@Gtk.Gesture.set_sequence_state]). |
| 191 | + /// |
| 192 | + /// @gesture must forget everything about @sequence as in |
| 193 | + /// response to this signal. |
| 194 | + public var cancel: ((Gesture, OpaquePointer) -> Void)? |
| 195 | + |
| 196 | + /// Emitted when @gesture either stopped recognizing the event |
| 197 | + /// sequences as something to be handled, or the number of touch |
| 198 | + /// sequences became higher or lower than [property@Gtk.Gesture:n-points]. |
| 199 | + /// |
| 200 | + /// Note: @sequence might not pertain to the group of sequences that |
| 201 | + /// were previously triggering recognition on @gesture (ie. a just |
| 202 | + /// pressed touch sequence that exceeds [property@Gtk.Gesture:n-points]). |
| 203 | + /// This situation may be detected by checking through |
| 204 | + /// [method@Gtk.Gesture.handles_sequence]. |
| 205 | + public var end: ((Gesture, OpaquePointer) -> Void)? |
| 206 | + |
| 207 | + /// Emitted whenever a sequence state changes. |
| 208 | + /// |
| 209 | + /// See [method@Gtk.Gesture.set_sequence_state] to know |
| 210 | + /// more about the expectable sequence lifetimes. |
| 211 | + public var sequenceStateChanged: ((Gesture, OpaquePointer, GtkEventSequenceState) -> Void)? |
| 212 | + |
| 213 | + /// Emitted whenever an event is handled while the gesture is recognized. |
| 214 | + /// |
| 215 | + /// @sequence is guaranteed to pertain to the set of active touches. |
| 216 | + public var update: ((Gesture, OpaquePointer) -> Void)? |
| 217 | + |
| 218 | + public var notifyNPoints: ((Gesture, OpaquePointer) -> Void)? |
| 219 | +} |
0 commit comments