1 /* 2 * This file is part of gtkD. 3 * 4 * gtkD is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License 6 * as published by the Free Software Foundation; either version 3 7 * of the License, or (at your option) any later version, with 8 * some exceptions, please read the COPYING file. 9 * 10 * gtkD 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 Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public License 16 * along with gtkD; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA 18 */ 19 20 // generated automatically - do not change 21 // find conversion definition on APILookup.txt 22 // implement new conversion functionalities on the wrap.utils pakage 23 24 25 module gtk.Gesture; 26 27 private import gdk.Device; 28 private import gdk.Event; 29 private import glib.ListG; 30 private import gobject.ObjectG; 31 private import gobject.Signals; 32 private import gtk.EventController; 33 private import gtk.c.functions; 34 public import gtk.c.types; 35 private import std.algorithm; 36 37 38 /** 39 * `GtkGesture` is the base class for gesture recognition. 40 * 41 * Although `GtkGesture` is quite generalized to serve as a base for 42 * multi-touch gestures, it is suitable to implement single-touch and 43 * pointer-based gestures (using the special %NULL `GdkEventSequence` 44 * value for these). 45 * 46 * The number of touches that a `GtkGesture` need to be recognized is 47 * controlled by the [property@Gtk.Gesture:n-points] property, if a 48 * gesture is keeping track of less or more than that number of sequences, 49 * it won't check whether the gesture is recognized. 50 * 51 * As soon as the gesture has the expected number of touches, it will check 52 * regularly if it is recognized, the criteria to consider a gesture as 53 * "recognized" is left to `GtkGesture` subclasses. 54 * 55 * A recognized gesture will then emit the following signals: 56 * 57 * - [signal@Gtk.Gesture::begin] when the gesture is recognized. 58 * - [signal@Gtk.Gesture::update], whenever an input event is processed. 59 * - [signal@Gtk.Gesture::end] when the gesture is no longer recognized. 60 * 61 * ## Event propagation 62 * 63 * In order to receive events, a gesture needs to set a propagation phase 64 * through [method@Gtk.EventController.set_propagation_phase]. 65 * 66 * In the capture phase, events are propagated from the toplevel down 67 * to the target widget, and gestures that are attached to containers 68 * above the widget get a chance to interact with the event before it 69 * reaches the target. 70 * 71 * In the bubble phase, events are propagated up from the target widget 72 * to the toplevel, and gestures that are attached to containers above 73 * the widget get a chance to interact with events that have not been 74 * handled yet. 75 * 76 * ## States of a sequence 77 * 78 * Whenever input interaction happens, a single event may trigger a cascade 79 * of `GtkGesture`s, both across the parents of the widget receiving the 80 * event and in parallel within an individual widget. It is a responsibility 81 * of the widgets using those gestures to set the state of touch sequences 82 * accordingly in order to enable cooperation of gestures around the 83 * `GdkEventSequence`s triggering those. 84 * 85 * Within a widget, gestures can be grouped through [method@Gtk.Gesture.group]. 86 * Grouped gestures synchronize the state of sequences, so calling 87 * [method@Gtk.Gesture.set_sequence_state] on one will effectively propagate 88 * the state throughout the group. 89 * 90 * By default, all sequences start out in the %GTK_EVENT_SEQUENCE_NONE state, 91 * sequences in this state trigger the gesture event handler, but event 92 * propagation will continue unstopped by gestures. 93 * 94 * If a sequence enters into the %GTK_EVENT_SEQUENCE_DENIED state, the gesture 95 * group will effectively ignore the sequence, letting events go unstopped 96 * through the gesture, but the "slot" will still remain occupied while 97 * the touch is active. 98 * 99 * If a sequence enters in the %GTK_EVENT_SEQUENCE_CLAIMED state, the gesture 100 * group will grab all interaction on the sequence, by: 101 * 102 * - Setting the same sequence to %GTK_EVENT_SEQUENCE_DENIED on every other 103 * gesture group within the widget, and every gesture on parent widgets 104 * in the propagation chain. 105 * - Emitting [signal@Gtk.Gesture::cancel] on every gesture in widgets 106 * underneath in the propagation chain. 107 * - Stopping event propagation after the gesture group handles the event. 108 * 109 * Note: if a sequence is set early to %GTK_EVENT_SEQUENCE_CLAIMED on 110 * %GDK_TOUCH_BEGIN/%GDK_BUTTON_PRESS (so those events are captured before 111 * reaching the event widget, this implies %GTK_PHASE_CAPTURE), one similar 112 * event will emulated if the sequence changes to %GTK_EVENT_SEQUENCE_DENIED. 113 * This way event coherence is preserved before event propagation is unstopped 114 * again. 115 * 116 * Sequence states can't be changed freely. 117 * See [method@Gtk.Gesture.set_sequence_state] to know about the possible 118 * lifetimes of a `GdkEventSequence`. 119 * 120 * ## Touchpad gestures 121 * 122 * On the platforms that support it, `GtkGesture` will handle transparently 123 * touchpad gesture events. The only precautions users of `GtkGesture` should 124 * do to enable this support are: 125 * 126 * - If the gesture has %GTK_PHASE_NONE, ensuring events of type 127 * %GDK_TOUCHPAD_SWIPE and %GDK_TOUCHPAD_PINCH are handled by the `GtkGesture` 128 */ 129 public class Gesture : EventController 130 { 131 /** the main Gtk struct */ 132 protected GtkGesture* gtkGesture; 133 134 /** Get the main Gtk struct */ 135 public GtkGesture* getGestureStruct(bool transferOwnership = false) 136 { 137 if (transferOwnership) 138 ownedRef = false; 139 return gtkGesture; 140 } 141 142 /** the main Gtk struct as a void* */ 143 protected override void* getStruct() 144 { 145 return cast(void*)gtkGesture; 146 } 147 148 /** 149 * Sets our main struct and passes it to the parent class. 150 */ 151 public this (GtkGesture* gtkGesture, bool ownedRef = false) 152 { 153 this.gtkGesture = gtkGesture; 154 super(cast(GtkEventController*)gtkGesture, ownedRef); 155 } 156 157 158 /** */ 159 public static GType getType() 160 { 161 return gtk_gesture_get_type(); 162 } 163 164 /** 165 * If there are touch sequences being currently handled by @gesture, 166 * returns %TRUE and fills in @rect with the bounding box containing 167 * all active touches. 168 * 169 * Otherwise, %FALSE will be returned. 170 * 171 * Note: This function will yield unexpected results on touchpad 172 * gestures. Since there is no correlation between physical and 173 * pixel distances, these will look as if constrained in an 174 * infinitely small area, @rect width and height will thus be 0 175 * regardless of the number of touchpoints. 176 * 177 * Params: 178 * rect = bounding box containing all active touches. 179 * 180 * Returns: %TRUE if there are active touches, %FALSE otherwise 181 */ 182 public bool getBoundingBox(out GdkRectangle rect) 183 { 184 return gtk_gesture_get_bounding_box(gtkGesture, &rect) != 0; 185 } 186 187 /** 188 * If there are touch sequences being currently handled by @gesture, 189 * returns %TRUE and fills in @x and @y with the center of the bounding 190 * box containing all active touches. 191 * 192 * Otherwise, %FALSE will be returned. 193 * 194 * Params: 195 * x = X coordinate for the bounding box center 196 * y = Y coordinate for the bounding box center 197 * 198 * Returns: %FALSE if no active touches are present, %TRUE otherwise 199 */ 200 public bool getBoundingBoxCenter(out double x, out double y) 201 { 202 return gtk_gesture_get_bounding_box_center(gtkGesture, &x, &y) != 0; 203 } 204 205 /** 206 * Returns the logical `GdkDevice` that is currently operating 207 * on @gesture. 208 * 209 * This returns %NULL if the gesture is not being interacted. 210 * 211 * Returns: a `GdkDevice`, or %NULL 212 */ 213 public Device getDevice() 214 { 215 auto __p = gtk_gesture_get_device(gtkGesture); 216 217 if(__p is null) 218 { 219 return null; 220 } 221 222 return ObjectG.getDObject!(Device)(cast(GdkDevice*) __p); 223 } 224 225 /** 226 * Returns all gestures in the group of @gesture 227 * 228 * Returns: The list 229 * of `GtkGesture`s, free with g_list_free() 230 */ 231 public ListG getGroup() 232 { 233 auto __p = gtk_gesture_get_group(gtkGesture); 234 235 if(__p is null) 236 { 237 return null; 238 } 239 240 return new ListG(cast(GList*) __p); 241 } 242 243 /** 244 * Returns the last event that was processed for @sequence. 245 * 246 * Note that the returned pointer is only valid as long as the 247 * @sequence is still interpreted by the @gesture. If in doubt, 248 * you should make a copy of the event. 249 * 250 * Params: 251 * sequence = a `GdkEventSequence` 252 * 253 * Returns: The last event from @sequence 254 */ 255 public Event getLastEvent(GdkEventSequence* sequence) 256 { 257 auto __p = gtk_gesture_get_last_event(gtkGesture, sequence); 258 259 if(__p is null) 260 { 261 return null; 262 } 263 264 return ObjectG.getDObject!(Event)(cast(GdkEvent*) __p); 265 } 266 267 /** 268 * Returns the `GdkEventSequence` that was last updated on @gesture. 269 * 270 * Returns: The last updated sequence 271 */ 272 public GdkEventSequence* getLastUpdatedSequence() 273 { 274 return gtk_gesture_get_last_updated_sequence(gtkGesture); 275 } 276 277 /** 278 * If @sequence is currently being interpreted by @gesture, 279 * returns %TRUE and fills in @x and @y with the last coordinates 280 * stored for that event sequence. 281 * 282 * The coordinates are always relative to the widget allocation. 283 * 284 * Params: 285 * sequence = a `GdkEventSequence`, or %NULL for pointer events 286 * x = return location for X axis of the sequence coordinates 287 * y = return location for Y axis of the sequence coordinates 288 * 289 * Returns: %TRUE if @sequence is currently interpreted 290 */ 291 public bool getPoint(GdkEventSequence* sequence, out double x, out double y) 292 { 293 return gtk_gesture_get_point(gtkGesture, sequence, &x, &y) != 0; 294 } 295 296 /** 297 * Returns the @sequence state, as seen by @gesture. 298 * 299 * Params: 300 * sequence = a #GdkEventSequence 301 * 302 * Returns: The sequence state in @gesture 303 */ 304 public GtkEventSequenceState getSequenceState(GdkEventSequence* sequence) 305 { 306 return gtk_gesture_get_sequence_state(gtkGesture, sequence); 307 } 308 309 /** 310 * Returns the list of `GdkEventSequences` currently being interpreted 311 * by @gesture. 312 * 313 * Returns: A list 314 * of `GdkEventSequence`, the list elements are owned by GTK and must 315 * not be freed or modified, the list itself must be deleted 316 * through g_list_free() 317 */ 318 public ListG getSequences() 319 { 320 auto __p = gtk_gesture_get_sequences(gtkGesture); 321 322 if(__p is null) 323 { 324 return null; 325 } 326 327 return new ListG(cast(GList*) __p); 328 } 329 330 /** 331 * Adds @gesture to the same group than @group_gesture. 332 * 333 * Gestures are by default isolated in their own groups. 334 * 335 * Both gestures must have been added to the same widget before 336 * they can be grouped. 337 * 338 * When gestures are grouped, the state of `GdkEventSequences` 339 * is kept in sync for all of those, so calling 340 * [method@Gtk.Gesture.set_sequence_state], on one will transfer 341 * the same value to the others. 342 * 343 * Groups also perform an "implicit grabbing" of sequences, if a 344 * `GdkEventSequence` state is set to %GTK_EVENT_SEQUENCE_CLAIMED 345 * on one group, every other gesture group attached to the same 346 * `GtkWidget` will switch the state for that sequence to 347 * %GTK_EVENT_SEQUENCE_DENIED. 348 * 349 * Params: 350 * gesture = a `GtkGesture` 351 */ 352 public void group(Gesture gesture) 353 { 354 gtk_gesture_group(gtkGesture, (gesture is null) ? null : gesture.getGestureStruct()); 355 } 356 357 /** 358 * Returns %TRUE if @gesture is currently handling events 359 * corresponding to @sequence. 360 * 361 * Params: 362 * sequence = a `GdkEventSequence` or %NULL 363 * 364 * Returns: %TRUE if @gesture is handling @sequence, %FALSE otherwise 365 */ 366 public bool handlesSequence(GdkEventSequence* sequence) 367 { 368 return gtk_gesture_handles_sequence(gtkGesture, sequence) != 0; 369 } 370 371 /** 372 * Returns %TRUE if the gesture is currently active. 373 * 374 * A gesture is active while there are touch sequences 375 * interacting with it. 376 * 377 * Returns: %TRUE if gesture is active 378 */ 379 public bool isActive() 380 { 381 return gtk_gesture_is_active(gtkGesture) != 0; 382 } 383 384 /** 385 * Returns %TRUE if both gestures pertain to the same group. 386 * 387 * Params: 388 * other = another `GtkGesture` 389 * 390 * Returns: whether the gestures are grouped 391 */ 392 public bool isGroupedWith(Gesture other) 393 { 394 return gtk_gesture_is_grouped_with(gtkGesture, (other is null) ? null : other.getGestureStruct()) != 0; 395 } 396 397 /** 398 * Returns %TRUE if the gesture is currently recognized. 399 * 400 * A gesture is recognized if there are as many interacting 401 * touch sequences as required by @gesture. 402 * 403 * Returns: %TRUE if gesture is recognized 404 */ 405 public bool isRecognized() 406 { 407 return gtk_gesture_is_recognized(gtkGesture) != 0; 408 } 409 410 /** 411 * Sets the state of @sequence in @gesture. 412 * 413 * Sequences start in state %GTK_EVENT_SEQUENCE_NONE, and whenever 414 * they change state, they can never go back to that state. Likewise, 415 * sequences in state %GTK_EVENT_SEQUENCE_DENIED cannot turn back to 416 * a not denied state. With these rules, the lifetime of an event 417 * sequence is constrained to the next four: 418 * 419 * * None 420 * * None → Denied 421 * * None → Claimed 422 * * None → Claimed → Denied 423 * 424 * Note: Due to event handling ordering, it may be unsafe to set the 425 * state on another gesture within a [signal@Gtk.Gesture::begin] signal 426 * handler, as the callback might be executed before the other gesture 427 * knows about the sequence. A safe way to perform this could be: 428 * 429 * ```c 430 * static void 431 * first_gesture_begin_cb (GtkGesture *first_gesture, 432 * GdkEventSequence *sequence, 433 * gpointer user_data) 434 * { 435 * gtk_gesture_set_sequence_state (first_gesture, sequence, GTK_EVENT_SEQUENCE_CLAIMED); 436 * gtk_gesture_set_sequence_state (second_gesture, sequence, GTK_EVENT_SEQUENCE_DENIED); 437 * } 438 * 439 * static void 440 * second_gesture_begin_cb (GtkGesture *second_gesture, 441 * GdkEventSequence *sequence, 442 * gpointer user_data) 443 * { 444 * if (gtk_gesture_get_sequence_state (first_gesture, sequence) == GTK_EVENT_SEQUENCE_CLAIMED) 445 * gtk_gesture_set_sequence_state (second_gesture, sequence, GTK_EVENT_SEQUENCE_DENIED); 446 * } 447 * ``` 448 * 449 * If both gestures are in the same group, just set the state on 450 * the gesture emitting the event, the sequence will be already 451 * be initialized to the group's global state when the second 452 * gesture processes the event. 453 * 454 * Params: 455 * sequence = a `GdkEventSequence` 456 * state = the sequence state 457 * 458 * Returns: %TRUE if @sequence is handled by @gesture, 459 * and the state is changed successfully 460 */ 461 public bool setSequenceState(GdkEventSequence* sequence, GtkEventSequenceState state) 462 { 463 return gtk_gesture_set_sequence_state(gtkGesture, sequence, state) != 0; 464 } 465 466 /** 467 * Sets the state of all sequences that @gesture is currently 468 * interacting with. 469 * 470 * See [method@Gtk.Gesture.set_sequence_state] for more details 471 * on sequence states. 472 * 473 * Params: 474 * state = the sequence state 475 * 476 * Returns: %TRUE if the state of at least one sequence 477 * was changed successfully 478 */ 479 public bool setState(GtkEventSequenceState state) 480 { 481 return gtk_gesture_set_state(gtkGesture, state) != 0; 482 } 483 484 /** 485 * Separates @gesture into an isolated group. 486 */ 487 public void ungroup() 488 { 489 gtk_gesture_ungroup(gtkGesture); 490 } 491 492 /** 493 * Emitted when the gesture is recognized. 494 * 495 * This means the number of touch sequences matches 496 * [property@Gtk.Gesture:n-points]. 497 * 498 * Note: These conditions may also happen when an extra touch 499 * (eg. a third touch on a 2-touches gesture) is lifted, in that 500 * situation @sequence won't pertain to the current set of active 501 * touches, so don't rely on this being true. 502 * 503 * Params: 504 * sequence = the `GdkEventSequence` that made the gesture 505 * to be recognized 506 */ 507 gulong addOnBegin(void delegate(GdkEventSequence*, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 508 { 509 return Signals.connect(this, "begin", dlg, connectFlags ^ ConnectFlags.SWAPPED); 510 } 511 512 /** 513 * Emitted when the gesture is recognized. 514 * 515 * This means the number of touch sequences matches 516 * [property@Gtk.Gesture:n-points]. 517 * 518 * Note: These conditions may also happen when an extra touch 519 * (eg. a third touch on a 2-touches gesture) is lifted, in that 520 * situation @sequence won't pertain to the current set of active 521 * touches, so don't rely on this being true. 522 * 523 * Params: 524 * sequence = the `GdkEventSequence` that made the gesture 525 * to be recognized 526 */ 527 gulong addOnBegin(void delegate(Event, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 528 { 529 return Signals.connect(this, "begin", dlg, connectFlags ^ ConnectFlags.SWAPPED); 530 } 531 532 /** 533 * Emitted whenever a sequence is cancelled. 534 * 535 * This usually happens on active touches when 536 * [method@Gtk.EventController.reset] is called on @gesture 537 * (manually, due to grabs...), or the individual @sequence 538 * was claimed by parent widgets' controllers (see 539 * [method@Gtk.Gesture.set_sequence_state]). 540 * 541 * @gesture must forget everything about @sequence as in 542 * response to this signal. 543 * 544 * Params: 545 * sequence = the `GdkEventSequence` that was cancelled 546 */ 547 gulong addOnCancel(void delegate(GdkEventSequence*, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 548 { 549 return Signals.connect(this, "cancel", dlg, connectFlags ^ ConnectFlags.SWAPPED); 550 } 551 552 /** 553 * Emitted whenever a sequence is cancelled. 554 * 555 * This usually happens on active touches when 556 * [method@Gtk.EventController.reset] is called on @gesture 557 * (manually, due to grabs...), or the individual @sequence 558 * was claimed by parent widgets' controllers (see 559 * [method@Gtk.Gesture.set_sequence_state]). 560 * 561 * @gesture must forget everything about @sequence as in 562 * response to this signal. 563 * 564 * Params: 565 * sequence = the `GdkEventSequence` that was cancelled 566 */ 567 gulong addOnCancel(void delegate(Event, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 568 { 569 return Signals.connect(this, "cancel", dlg, connectFlags ^ ConnectFlags.SWAPPED); 570 } 571 572 /** 573 * Emitted when @gesture either stopped recognizing the event 574 * sequences as something to be handled, or the number of touch 575 * sequences became higher or lower than [property@Gtk.Gesture:n-points]. 576 * 577 * Note: @sequence might not pertain to the group of sequences that 578 * were previously triggering recognition on @gesture (ie. a just 579 * pressed touch sequence that exceeds [property@Gtk.Gesture:n-points]). 580 * This situation may be detected by checking through 581 * [method@Gtk.Gesture.handles_sequence]. 582 * 583 * Params: 584 * sequence = the `GdkEventSequence` that made gesture 585 * recognition to finish 586 */ 587 gulong addOnEnd(void delegate(GdkEventSequence*, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 588 { 589 return Signals.connect(this, "end", dlg, connectFlags ^ ConnectFlags.SWAPPED); 590 } 591 592 /** 593 * Emitted when @gesture either stopped recognizing the event 594 * sequences as something to be handled, or the number of touch 595 * sequences became higher or lower than [property@Gtk.Gesture:n-points]. 596 * 597 * Note: @sequence might not pertain to the group of sequences that 598 * were previously triggering recognition on @gesture (ie. a just 599 * pressed touch sequence that exceeds [property@Gtk.Gesture:n-points]). 600 * This situation may be detected by checking through 601 * [method@Gtk.Gesture.handles_sequence]. 602 * 603 * Params: 604 * sequence = the `GdkEventSequence` that made gesture 605 * recognition to finish 606 */ 607 gulong addOnEnd(void delegate(Event, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 608 { 609 return Signals.connect(this, "end", dlg, connectFlags ^ ConnectFlags.SWAPPED); 610 } 611 612 /** 613 * Emitted whenever a sequence state changes. 614 * 615 * See [method@Gtk.Gesture.set_sequence_state] to know 616 * more about the expectable sequence lifetimes. 617 * 618 * Params: 619 * sequence = the `GdkEventSequence` that was cancelled 620 * state = the new sequence state 621 */ 622 gulong addOnSequenceStateChanged(void delegate(GdkEventSequence*, GtkEventSequenceState, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 623 { 624 return Signals.connect(this, "sequence-state-changed", dlg, connectFlags ^ ConnectFlags.SWAPPED); 625 } 626 627 /** 628 * Emitted whenever a sequence state changes. 629 * 630 * See [method@Gtk.Gesture.set_sequence_state] to know 631 * more about the expectable sequence lifetimes. 632 * 633 * Params: 634 * sequence = the `GdkEventSequence` that was cancelled 635 * state = the new sequence state 636 */ 637 gulong addOnSequenceStateChanged(void delegate(Event, GtkEventSequenceState, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 638 { 639 return Signals.connect(this, "sequence-state-changed", dlg, connectFlags ^ ConnectFlags.SWAPPED); 640 } 641 642 /** 643 * Emitted whenever an event is handled while the gesture is recognized. 644 * 645 * @sequence is guaranteed to pertain to the set of active touches. 646 * 647 * Params: 648 * sequence = the `GdkEventSequence` that was updated 649 */ 650 gulong addOnUpdate(void delegate(GdkEventSequence*, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 651 { 652 return Signals.connect(this, "update", dlg, connectFlags ^ ConnectFlags.SWAPPED); 653 } 654 655 /** 656 * Emitted whenever an event is handled while the gesture is recognized. 657 * 658 * @sequence is guaranteed to pertain to the set of active touches. 659 * 660 * Params: 661 * sequence = the `GdkEventSequence` that was updated 662 */ 663 gulong addOnUpdate(void delegate(Event, Gesture) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 664 { 665 return Signals.connect(this, "update", dlg, connectFlags ^ ConnectFlags.SWAPPED); 666 } 667 }