summaryrefslogtreecommitdiffstats
path: root/Lib/webbrowser.py
blob: 6cf8942527418fd177eec246e59a81f79d9fffb0 (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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
#! /usr/bin/env python
"""Interfaces for launching and remotely controlling Web browsers."""
# Maintained by Georg Brandl.

import os
import shlex
import sys
import stat
import subprocess
import time

__all__ = ["Error", "open", "open_new", "open_new_tab", "get", "register"]

class Error(Exception):
    pass

_browsers = {}          # Dictionary of available browser controllers
_tryorder = []          # Preference order of available browsers

def register(name, klass, instance=None, update_tryorder=1):
    """Register a browser connector and, optionally, connection."""
    _browsers[name.lower()] = [klass, instance]
    if update_tryorder > 0:
        _tryorder.append(name)
    elif update_tryorder < 0:
        _tryorder.insert(0, name)

def get(using=None):
    """Return a browser launcher instance appropriate for the environment."""
    if using is not None:
        alternatives = [using]
    else:
        alternatives = _tryorder
    for browser in alternatives:
        if '%s' in browser:
            # User gave us a command line, split it into name and args
            browser = shlex.split(browser)
            if browser[-1] == '&':
                return BackgroundBrowser(browser[:-1])
            else:
                return GenericBrowser(browser)
        else:
            # User gave us a browser name or path.
            try:
                command = _browsers[browser.lower()]
            except KeyError:
                command = _synthesize(browser)
            if command[1] is not None:
                return command[1]
            elif command[0] is not None:
                return command[0]()
    raise Error("could not locate runnable browser")

# Please note: the following definition hides a builtin function.
# It is recommended one does "import webbrowser" and uses webbrowser.open(url)
# instead of "from webbrowser import *".

def open(url, new=0, autoraise=1):
    for name in _tryorder:
        browser = get(name)
        if browser.open(url, new, autoraise):
            return True
    return False

def open_new(url):
    return open(url, 1)

def open_new_tab(url):
    return open(url, 2)


def _synthesize(browser, update_tryorder=1):
    """Attempt to synthesize a controller base on existing controllers.

    This is useful to create a controller when a user specifies a path to
    an entry in the BROWSER environment variable -- we can copy a general
    controller to operate using a specific installation of the desired
    browser in this way.

    If we can't create a controller in this way, or if there is no
    executable for the requested browser, return [None, None].

    """
    cmd = browser.split()[0]
    if not _iscommand(cmd):
        return [None, None]
    name = os.path.basename(cmd)
    try:
        command = _browsers[name.lower()]
    except KeyError:
        return [None, None]
    # now attempt to clone to fit the new name:
    controller = command[1]
    if controller and name.lower() == controller.basename:
        import copy
        controller = copy.copy(controller)
        controller.name = browser
        controller.basename = os.path.basename(browser)
        register(browser, None, controller, update_tryorder)
        return [None, controller]
    return [None, None]


if sys.platform[:3] == "win":
    def _isexecutable(cmd):
        cmd = cmd.lower()
        if os.path.isfile(cmd) and cmd.endswith((".exe", ".bat")):
            return True
        for ext in ".exe", ".bat":
            if os.path.isfile(cmd + ext):
                return True
        return False
else:
    def _isexecutable(cmd):
        if os.path.isfile(cmd):
            mode = os.stat(cmd)[stat.ST_MODE]
            if mode & stat.S_IXUSR or mode & stat.S_IXGRP or mode & stat.S_IXOTH:
                return True
        return False

def _iscommand(cmd):
    """Return True if cmd is executable or can be found on the executable
    search path."""
    if _isexecutable(cmd):
        return True
    path = os.environ.get("PATH")
    if not path:
        return False
    for d in path.split(os.pathsep):
        exe = os.path.join(d, cmd)
        if _isexecutable(exe):
            return True
    return False


# General parent classes

class BaseBrowser(object):
    """Parent class for all browsers. Do not use directly."""

    args = ['%s']

    def __init__(self, name=""):
        self.name = name
        self.basename = name

    def open(self, url, new=0, autoraise=1):
        raise NotImplementedError

    def open_new(self, url):
        return self.open(url, 1)

    def open_new_tab(self, url):
        return self.open(url, 2)


class GenericBrowser(BaseBrowser):
    """Class for all browsers started with a command
       and without remote functionality."""

    def __init__(self, name):
        if isinstance(name, basestring):
            self.name = name
            self.args = ["%s"]
        else:
            # name should be a list with arguments
            self.name = name[0]
            self.args = name[1:]
        self.basename = os.path.basename(self.name)

    def open(self, url, new=0, autoraise=1):
        cmdline = [self.name] + [arg.replace("%s", url)
                                 for arg in self.args]
        try:
            if sys.platform[:3] == 'win':
                p = subprocess.Popen(cmdline)
            else:
                p = subprocess.Popen(cmdline, close_fds=True)
            return not p.wait()
        except OSError:
            return False


class BackgroundBrowser(GenericBrowser):
    """Class for all browsers which are to be started in the
       background."""

    def open(self, url, new=0, autoraise=1):
        cmdline = [self.name] + [arg.replace("%s", url)
                                 for arg in self.args]
        try:
            if sys.platform[:3] == 'win':
                p = subprocess.Popen(cmdline)
            else:
                setsid = getattr(os, 'setsid', None)
                if not setsid:
                    setsid = getattr(os, 'setpgrp', None)
                p = subprocess.Popen(cmdline, close_fds=True, preexec_fn=setsid)
            return (p.poll() is None)
        except OSError:
            return False


class UnixBrowser(BaseBrowser):
    """Parent class for all Unix browsers with remote functionality."""

    raise_opts = None
    remote_args = ['%action', '%s']
    remote_action = None
    remote_action_newwin = None
    remote_action_newtab = None
    background = False
    redirect_stdout = True

    def _invoke(self, args, remote, autoraise):
        raise_opt = []
        if remote and self.raise_opts:
            # use autoraise argument only for remote invocation
            autoraise = int(bool(autoraise))
            opt = self.raise_opts[autoraise]
            if opt: raise_opt = [opt]

        cmdline = [self.name] + raise_opt + args

        if remote or self.background:
            inout = file(os.devnull, "r+")
        else:
            # for TTY browsers, we need stdin/out
            inout = None
        # if possible, put browser in separate process group, so
        # keyboard interrupts don't affect browser as well as Python
        setsid = getattr(os, 'setsid', None)
        if not setsid:
            setsid = getattr(os, 'setpgrp', None)

        p = subprocess.Popen(cmdline, close_fds=True, stdin=inout,
                             stdout=(self.redirect_stdout and inout or None),
                             stderr=inout, preexec_fn=setsid)
        if remote:
            # wait five secons. If the subprocess is not finished, the
            # remote invocation has (hopefully) started a new instance.
            time.sleep(1)
            rc = p.poll()
            if rc is None:
                time.sleep(4)
                rc = p.poll()
                if rc is None:
                    return True
            # if remote call failed, open() will try direct invocation
            return not rc
        elif self.background:
            if p.poll() is None:
                return True
            else:
                return False
        else:
            return not p.wait()

    def open(self, url, new=0, autoraise=1):
        if new == 0:
            action = self.remote_action
        elif new == 1:
            action = self.remote_action_newwin
        elif new == 2:
            if self.remote_action_newtab is None:
                action = self.remote_action_newwin
            else:
                action = self.remote_action_newtab
        else:
            raise Error("Bad 'new' parameter to open(); " +
                        "expected 0, 1, or 2, got %s" % new)

        args = [arg.replace("%s", url).replace("%action", action)
                for arg in self.remote_args]
        success = self._invoke(args, True, autoraise)
        if not success:
            # remote invocation failed, try straight way
            args = [arg.replace("%s", url) for arg in self.args]
            return self._invoke(args, False, False)
        else:
            return True


class Mozilla(UnixBrowser):
    """Launcher class for Mozilla/Netscape browsers."""

    raise_opts = ["-noraise", "-raise"]

    remote_args = ['-remote', 'openURL(%s%action)']
    remote_action = ""
    remote_action_newwin = ",new-window"
    remote_action_newtab = ",new-tab"

    background = True

Netscape = Mozilla


class Galeon(UnixBrowser):
    """Launcher class for Galeon/Epiphany browsers."""

    raise_opts = ["-noraise", ""]
    remote_args = ['%action', '%s']
    remote_action = "-n"
    remote_action_newwin = "-w"

    background = True


class Opera(UnixBrowser):
    "Launcher class for Opera browser."

    raise_opts = ["", "-raise"]

    remote_args = ['-remote', 'openURL(%s%action)']
    remote_action = ""
    remote_action_newwin = ",new-window"
    remote_action_newtab = ",new-page"
    background = True


class Elinks(UnixBrowser):
    "Launcher class for Elinks browsers."

    remote_args = ['-remote', 'openURL(%s%action)']
    remote_action = ""
    remote_action_newwin = ",new-window"
    remote_action_newtab = ",new-tab"
    background = False

    # elinks doesn't like its stdout to be redirected -
    # it uses redirected stdout as a signal to do -dump
    redirect_stdout = False


class Konqueror(BaseBrowser):
    """Controller for the KDE File Manager (kfm, or Konqueror).

    See the output of ``kfmclient --commands``
    for more information on the Konqueror remote-control interface.
    """

    def open(self, url, new=0, autoraise=1):
        # XXX Currently I know no way to prevent KFM from opening a new win.
        if new == 2:
            action = "newTab"
        else:
            action = "openURL"

        devnull = file(os.devnull, "r+")
        # if possible, put browser in separate process group, so
        # keyboard interrupts don't affect browser as well as Python
        setsid = getattr(os, 'setsid', None)
        if not setsid:
            setsid = getattr(os, 'setpgrp', None)

        try:
            p = subprocess.Popen(["kfmclient", action, url],
                                 close_fds=True, stdin=devnull,
                                 stdout=devnull, stderr=devnull)
        except OSError:
            # fall through to next variant
            pass
        else:
            p.wait()
            # kfmclient's return code unfortunately has no meaning as it seems
            return True

        try:
            p = subprocess.Popen(["konqueror", "--silent", url],
                                 close_fds=True, stdin=devnull,
                                 stdout=devnull, stderr=devnull,
                                 preexec_fn=setsid)
        except OSError:
            # fall through to next variant
            pass
        else:
            if p.poll() is None:
                # Should be running now.
                return True

        try:
            p = subprocess.Popen(["kfm", "-d", url],
                                 close_fds=True, stdin=devnull,
                                 stdout=devnull, stderr=devnull,
                                 preexec_fn=setsid)
        except OSError:
            return False
        else:
            return (p.poll() is None)


class Grail(BaseBrowser):
    # There should be a way to maintain a connection to Grail, but the
    # Grail remote control protocol doesn't really allow that at this
    # point.  It probably never will!
    def _find_grail_rc(self):
        import glob
        import pwd
        import socket
        import tempfile
        tempdir = os.path.join(tempfile.gettempdir(),
                               ".grail-unix")
        user = pwd.getpwuid(os.getuid())[0]
        filename = os.path.join(tempdir, user + "-*")
        maybes = glob.glob(filename)
        if not maybes:
            return None
        s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        for fn in maybes:
            # need to PING each one until we find one that's live
            try:
                s.connect(fn)
            except socket.error:
                # no good; attempt to clean it out, but don't fail:
                try:
                    os.unlink(fn)
                except IOError:
                    pass
            else:
                return s

    def _remote(self, action):
        s = self._find_grail_rc()
        if not s:
            return 0
        s.send(action)
        s.close()
        return 1

    def open(self, url, new=0, autoraise=1):
        if new:
            ok = self._remote("LOADNEW " + url)
        else:
            ok = self._remote("LOAD " + url)
        return ok


#
# Platform support for Unix
#

# These are the right tests because all these Unix browsers require either
# a console terminal or an X display to run.

def register_X_browsers():

    # The default GNOME browser
    if "GNOME_DESKTOP_SESSION_ID" in os.environ and _iscommand("gnome-open"):
        register("gnome-open", None, BackgroundBrowser("gnome-open"))

    # The default KDE browser
    if "KDE_FULL_SESSION" in os.environ and _iscommand("kfmclient"):
        register("kfmclient", Konqueror, Konqueror("kfmclient"))

    # The Mozilla/Netscape browsers
    for browser in ("mozilla-firefox", "firefox",
                    "mozilla-firebird", "firebird",
                    "seamonkey", "mozilla", "netscape"):
        if _iscommand(browser):
            register(browser, None, Mozilla(browser))

    # Konqueror/kfm, the KDE browser.
    if _iscommand("kfm"):
        register("kfm", Konqueror, Konqueror("kfm"))
    elif _iscommand("konqueror"):
        register("konqueror", Konqueror, Konqueror("konqueror"))

    # Gnome's Galeon and Epiphany
    for browser in ("galeon", "epiphany"):
        if _iscommand(browser):
            register(browser, None, Galeon(browser))

    # Skipstone, another Gtk/Mozilla based browser
    if _iscommand("skipstone"):
        register("skipstone", None, BackgroundBrowser("skipstone"))

    # Opera, quite popular
    if _iscommand("opera"):
        register("opera", None, Opera("opera"))

    # Next, Mosaic -- old but still in use.
    if _iscommand("mosaic"):
        register("mosaic", None, BackgroundBrowser("mosaic"))

    # Grail, the Python browser. Does anybody still use it?
    if _iscommand("grail"):
        register("grail", Grail, None)

# Prefer X browsers if present
if os.environ.get("DISPLAY"):
    register_X_browsers()

# Also try console browsers
if os.environ.get("TERM"):
    # The Links/elinks browsers <http://artax.karlin.mff.cuni.cz/~mikulas/links/>
    if _iscommand("links"):
        register("links", None, GenericBrowser("links"))
    if _iscommand("elinks"):
        register("elinks", None, Elinks("elinks"))
    # The Lynx browser <http://lynx.isc.org/>, <http://lynx.browser.org/>
    if _iscommand("lynx"):
        register("lynx", None, GenericBrowser("lynx"))
    # The w3m browser <http://w3m.sourceforge.net/>
    if _iscommand("w3m"):
        register("w3m", None, GenericBrowser("w3m"))

#
# Platform support for Windows
#

if sys.platform[:3] == "win":
    class WindowsDefault(BaseBrowser):
        def open(self, url, new=0, autoraise=1):
            try:
                os.startfile(url)
            except WindowsError:
                # [Error 22] No application is associated with the specified
                # file for this operation: '<URL>'
                return False
            else:
                return True

    _tryorder = []
    _browsers = {}

    # First try to use the default Windows browser
    register("windows-default", WindowsDefault)

    # Detect some common Windows browsers, fallback to IE
    iexplore = os.path.join(os.environ.get("PROGRAMFILES", "C:\\Program Files"),
                            "Internet Explorer\\IEXPLORE.EXE")
    for browser in ("firefox", "firebird", "seamonkey", "mozilla",
                    "netscape", "opera", iexplore):
        if _iscommand(browser):
            register(browser, None, BackgroundBrowser(browser))

#
# Platform support for MacOS
#

try:
    import ic
except ImportError:
    pass
else:
    class InternetConfig(BaseBrowser):
        def open(self, url, new=0, autoraise=1):
            ic.launchurl(url)
            return True # Any way to get status?

    register("internet-config", InternetConfig, update_tryorder=-1)

if sys.platform == 'darwin':
    # Adapted from patch submitted to SourceForge by Steven J. Burr
    class MacOSX(BaseBrowser):
        """Launcher class for Aqua browsers on Mac OS X

        Optionally specify a browser name on instantiation.  Note that this
        will not work for Aqua browsers if the user has moved the application
        package after installation.

        If no browser is specified, the default browser, as specified in the
        Internet System Preferences panel, will be used.
        """
        def __init__(self, name):
            self.name = name

        def open(self, url, new=0, autoraise=1):
            assert "'" not in url
            # hack for local urls
            if not ':' in url:
                url = 'file:'+url

            # new must be 0 or 1
            new = int(bool(new))
            if self.name == "default":
                # User called open, open_new or get without a browser parameter
                script = 'open location "%s"' % url.replace('"', '%22') # opens in default browser
            else:
                # User called get and chose a browser
                if self.name == "OmniWeb":
                    toWindow = ""
                else:
                    # Include toWindow parameter of OpenURL command for browsers
                    # that support it.  0 == new window; -1 == existing
                    toWindow = "toWindow %d" % (new - 1)
                cmd = 'OpenURL "%s"' % url.replace('"', '%22')
                script = '''tell application "%s"
                                activate
                                %s %s
                            end tell''' % (self.name, cmd, toWindow)
            # Open pipe to AppleScript through osascript command
            osapipe = os.popen("osascript", "w")
            if osapipe is None:
                return False
            # Write script to osascript's stdin
            osapipe.write(script)
            rc = osapipe.close()
            return not rc

    # Don't clear _tryorder or _browsers since OS X can use above Unix support
    # (but we prefer using the OS X specific stuff)
    register("MacOSX", None, MacOSX('default'), -1)


#
# Platform support for OS/2
#

if sys.platform[:3] == "os2" and _iscommand("netscape"):
    _tryorder = []
    _browsers = {}
    register("os2netscape", None,
             GenericBrowser(["start", "netscape", "%s"]), -1)


# OK, now that we know what the default preference orders for each
# platform are, allow user to override them with the BROWSER variable.
if "BROWSER" in os.environ:
    _userchoices = os.environ["BROWSER"].split(os.pathsep)
    _userchoices.reverse()

    # Treat choices in same way as if passed into get() but do register
    # and prepend to _tryorder
    for cmdline in _userchoices:
        if cmdline != '':
            _synthesize(cmdline, -1)
    cmdline = None # to make del work if _userchoices was empty
    del cmdline
    del _userchoices

# what to do if _tryorder is now empty?


def main():
    import getopt
    usage = """Usage: %s [-n | -t] url
    -n: open new window
    -t: open new tab""" % sys.argv[0]
    try:
        opts, args = getopt.getopt(sys.argv[1:], 'ntd')
    except getopt.error, msg:
        print >>sys.stderr, msg
        print >>sys.stderr, usage
        sys.exit(1)
    new_win = 0
    for o, a in opts:
        if o == '-n': new_win = 1
        elif o == '-t': new_win = 2
    if len(args) <> 1:
        print >>sys.stderr, usage
        sys.exit(1)

    url = args[0]
    open(url, new_win)

    print "\a"

if __name__ == "__main__":
    main()
s contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef KNOB_H +#define KNOB_H + +#include + +class Knob : public QGraphicsEllipseItem +{ +public: + Knob(); + + bool sceneEvent(QEvent *event); +}; + +#endif // KNOB_H diff --git a/examples/multitouch/knobs/knobs.pro b/examples/multitouch/knobs/knobs.pro new file mode 100644 index 0000000..90f0ba5 --- /dev/null +++ b/examples/multitouch/knobs/knobs.pro @@ -0,0 +1,2 @@ +HEADERS = knob.h +SOURCES = main.cpp knob.cpp diff --git a/examples/multitouch/knobs/main.cpp b/examples/multitouch/knobs/main.cpp new file mode 100644 index 0000000..c5a7ea7 --- /dev/null +++ b/examples/multitouch/knobs/main.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "knob.h" + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + + QGraphicsScene scene; + QGraphicsView view(&scene); + view.viewport()->setAttribute(Qt::WA_AcceptTouchEvents); + + Knob *knob1 = new Knob; + knob1->setPos(-110, 0); + Knob *knob2 = new Knob; + + scene.addItem(knob1); + scene.addItem(knob2); + + view.showFullScreen(); + view.fitInView(scene.sceneRect().adjusted(-20, -20, 20, 20), Qt::KeepAspectRatio); + + return app.exec(); +} diff --git a/examples/multitouch/multitouch.pro b/examples/multitouch/multitouch.pro index b2b2b76..b3d1d55 100644 --- a/examples/multitouch/multitouch.pro +++ b/examples/multitouch/multitouch.pro @@ -1,2 +1,2 @@ TEMPLATE = subdirs -SUBDIRS = pinchzoom fingerpaint +SUBDIRS = pinchzoom fingerpaint knobs -- cgit v0.12 From 0103e7871000f224a1048649b4eca18a7840fe3b Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Wed, 25 Mar 2009 13:30:38 +0100 Subject: initial implementation of multitouch support on Windows 7 WM_TOUCH* messages are translated to QTouchEvents and sent to the appropriate widget. we set the qt_tabletChokeMouse variable according to the result of the event processing to make sure that mouse events are sent when touch events are not handled. --- src/gui/kernel/qapplication_p.h | 27 ++++- src/gui/kernel/qapplication_win.cpp | 192 ++++++++++++++++++++++++++++++++++++ src/gui/kernel/qwidget_win.cpp | 4 + 3 files changed, 220 insertions(+), 3 deletions(-) diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index 252d0cb..ccd9f41 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -55,6 +55,7 @@ // #include "QtGui/qapplication.h" +#include "QtGui/qevent.h" #include "QtGui/qfont.h" #include "QtGui/qcursor.h" #include "QtGui/qregion.h" @@ -77,10 +78,7 @@ class QClipboard; class QGraphicsScene; class QGraphicsSystem; class QInputContext; -class QKeyEvent; -class QMouseEvent; class QObject; -class QWheelEvent; class QWidget; extern bool qt_is_gui_used; @@ -189,6 +187,12 @@ extern "C" { } #endif +#if defined(Q_WS_WIN) +typedef BOOL (WINAPI *qt_RegisterTouchWindowPtr)(HWND, ULONG); +typedef BOOL (WINAPI *qt_GetTouchInputInfoPtr)(HANDLE, UINT, PVOID, int); +typedef BOOL (WINAPI *qt_CloseTouchInputHandlePtr)(HANDLE); +#endif + class QScopedLoopLevelCounter { QThreadData *threadData; @@ -427,6 +431,23 @@ public: QPointer currentMultitouchWidget; static void updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent); +#if defined(Q_WS_WIN) + static qt_RegisterTouchWindowPtr RegisterTouchWindow; + static qt_GetTouchInputInfoPtr GetTouchInputInfo; + static qt_CloseTouchInputHandlePtr CloseTouchInputHandle; + + QMap touchInputIDToTouchPointID; + QVector allTouchPoints; + QList currentTouchPoints, activeTouchPoints; + + static bool sendTouchEvent(QWidget *widget, QTouchEvent *touchEvent); + + void initializeMultitouch(); + void insertActiveTouch(QTouchEvent::TouchPoint *touchPoint); + void removeActiveTouch(QTouchEvent::TouchPoint *touchPoint); + bool translateTouchEvent(const MSG &msg); +#endif + private: #ifdef Q_WS_QWS QMap maxWindowRects; diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index fae0335..7c7f7f6 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -88,6 +88,7 @@ extern void qt_wince_hide_taskbar(HWND hwnd); //defined in qguifunctions_wince.c #include "qdebug.h" #include #include +#include "qevent_p.h" //#define ALIEN_DEBUG @@ -112,6 +113,39 @@ extern void qt_wince_hide_taskbar(HWND hwnd); //defined in qguifunctions_wince.c # include #endif +#ifndef WM_TOUCHMOVE + +# define WM_TOUCHMOVE 0x0240 +# define WM_TOUCHDOWN 0x0241 +# define WM_TOUCHUP 0x0242 + +# define TOUCHEVENTF_MOVE 0x0001 +# define TOUCHEVENTF_DOWN 0x0002 +# define TOUCHEVENTF_UP 0x0004 +# define TOUCHEVENTF_INRANGE 0x0008 +# define TOUCHEVENTF_PRIMARY 0x0010 +# define TOUCHEVENTF_NOCOALESCE 0x0020 +# define TOUCHEVENTF_PEN 0x0040 + +# define TOUCHINPUTMASKF_TIMEFROMSYSTEM 0x0001 +# define TOUCHINPUTMASKF_EXTRAINFO 0x0002 +# define TOUCHINPUTMASKF_CONTACTAREA 0x0004 + +typedef struct tagTOUCHINPUT +{ + LONG x; + LONG y; + HANDLE hSource; + DWORD dwID; + DWORD dwFlags; + DWORD dwMask; + DWORD dwTime; + ULONG_PTR dwExtraInfo; + DWORD cxContact; + DWORD cyContact; +} TOUCHINPUT, *PTOUCHINPUT; + +#endif #ifndef FLASHW_STOP typedef struct { @@ -856,6 +890,8 @@ void qt_init(QApplicationPrivate *priv, int) if (ptrUpdateLayeredWindow && !ptrUpdateLayeredWindowIndirect) ptrUpdateLayeredWindowIndirect = qt_updateLayeredWindowIndirect; #endif + + priv->initializeMultitouch(); } /***************************************************************************** @@ -1726,6 +1762,11 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam result = widget->translateWheelEvent(msg); } else { switch (message) { + case WM_TOUCHMOVE: + case WM_TOUCHDOWN: + case WM_TOUCHUP: + result = getQApplicationPrivateInternal()->translateTouchEvent(msg); + break; case WM_KEYDOWN: // keyboard event case WM_SYSKEYDOWN: qt_keymapper_private()->updateKeyMap(msg); @@ -3953,4 +3994,155 @@ void QSessionManager::cancel() #endif //QT_NO_SESSIONMANAGER +qt_RegisterTouchWindowPtr QApplicationPrivate::RegisterTouchWindow = 0; +qt_GetTouchInputInfoPtr QApplicationPrivate::GetTouchInputInfo = 0; +qt_CloseTouchInputHandlePtr QApplicationPrivate::CloseTouchInputHandle = 0; + +void QApplicationPrivate::initializeMultitouch() +{ + QLibrary library(QLatin1String("user32")); + RegisterTouchWindow = static_cast(library.resolve("RegisterTouchWindow")); + GetTouchInputInfo = static_cast(library.resolve("GetTouchInputInfo")); + CloseTouchInputHandle = static_cast(library.resolve("CloseTouchInputHandle")); + + currentMultitouchWidget = 0; + touchInputIDToTouchPointID.clear(); + allTouchPoints.clear(); + currentTouchPoints.clear(); + activeTouchPoints.clear(); +} + +void QApplicationPrivate::insertActiveTouch(QTouchEvent::TouchPoint *touchPoint) +{ + // insort deviceNumber + int at = 0; + for (; at < currentTouchPoints.count(); ++at) { + if (currentTouchPoints.at(at)->id() > touchPoint->id()) + break; + } + currentTouchPoints.insert(at, touchPoint); + activeTouchPoints = currentTouchPoints; + + if (currentTouchPoints.count() > allTouchPoints.count()) { + qFatal("Qt: INTERNAL ERROR: currentTouchPoints.count() (%d) > allTouchPoints.count() (%d)", + currentTouchPoints.count(), + allTouchPoints.count()); + } +} + +void QApplicationPrivate::removeActiveTouch(QTouchEvent::TouchPoint *touchPoint) +{ + for (int i = qMin(currentTouchPoints.count() - 1, touchPoint->id()); i >= 0; --i) { + if (currentTouchPoints.at(i) == touchPoint) { + currentTouchPoints.removeAt(i); + break; + } + } + + // leave activeTouchPoints unchanged, since we need to make sure + // that the Release for deviceNumber is sent +} + +bool QApplicationPrivate::translateTouchEvent(const MSG &msg) +{ + Q_Q(QApplication); + + bool sendTouchBegin = currentTouchPoints.isEmpty(); + activeTouchPoints = currentTouchPoints; + + QVector winTouchInputs(msg.wParam); + memset(winTouchInputs.data(), 0, sizeof(TOUCHINPUT) * winTouchInputs.count()); + QApplicationPrivate::GetTouchInputInfo((HANDLE) msg.lParam, msg.wParam, winTouchInputs.data(), sizeof(TOUCHINPUT)); + for (int i = 0; i < winTouchInputs.count(); ++i) { + const TOUCHINPUT &touchInput = winTouchInputs.at(i); + + int touchPointID = touchInputIDToTouchPointID.value(touchInput.dwID, -1); + if (touchPointID == -1) { + touchPointID = touchInputIDToTouchPointID.count(); + touchInputIDToTouchPointID.insert(touchInput.dwID, touchPointID); + } + + if (allTouchPoints.count() <= touchPointID) + allTouchPoints.resize(touchPointID + 1); + + QTouchEvent::TouchPoint *touchPoint = allTouchPoints.at(touchPointID); + if (!touchPoint) + touchPoint = allTouchPoints[touchPointID] = new QTouchEvent::TouchPoint(touchPointID); + + // update state + bool down = touchPoint->d->state != Qt::TouchPointReleased; + QPointF globalPos(qreal(touchInput.x) / qreal(100.), qreal(touchInput.y) / qreal(100.)); + if (!down && (touchInput.dwFlags & TOUCHEVENTF_DOWN)) { + insertActiveTouch(touchPoint); + touchPoint->d->state = Qt::TouchPointPressed; + touchPoint->d->globalPos = touchPoint->d->startGlobalPos = touchPoint->d->lastGlobalPos = globalPos; + touchPoint->d->pressure = qreal(1.); + } else if (down && (touchInput.dwFlags & TOUCHEVENTF_UP)) { + removeActiveTouch(touchPoint); + touchPoint->d->state = Qt::TouchPointReleased; + touchPoint->d->lastGlobalPos = touchPoint->d->globalPos; + touchPoint->d->globalPos = globalPos; + touchPoint->d->pressure = qreal(0.); + } else if (down) { + touchPoint->d->state = globalPos == touchPoint->d->globalPos + ? Qt::TouchPointStationary + : Qt::TouchPointMoved; + touchPoint->d->lastGlobalPos = touchPoint->d->globalPos; + touchPoint->d->globalPos = globalPos; + // pressure should still be 1. + } + } + QApplicationPrivate::CloseTouchInputHandle((HANDLE) msg.lParam); + + bool sendTouchEnd = currentTouchPoints.isEmpty(); + + if (activeTouchPoints.isEmpty()) + return false; + + if (sendTouchBegin) { + // the window under the first touch point gets the touch event + int firstTouchId = activeTouchPoints.first()->id(); + const QPoint &globalPos = allTouchPoints.at(firstTouchId)->d->globalPos.toPoint(); + QWidget *window = q->topLevelAt(globalPos); + if (window) { + QWidget *child = window->childAt(window->mapFromGlobal(globalPos)); + if (!child) + child = window; + currentMultitouchWidget = child; + } + } + + QWidget *widget = q->activePopupWidget(); + if (!widget) + widget = currentMultitouchWidget; + + if (sendTouchEnd) { + // reset currentMultitouchWindow when the last touch is released + currentMultitouchWidget = 0; + if (!currentTouchPoints.isEmpty()) { + qFatal("Qt: INTERNAL ERROR, currentTouchPoints should be empty!"); + } + } + + // deliver the event + if (widget && QApplicationPrivate::tryModalHelper(widget, 0)) { + QTouchEvent touchEvent((sendTouchBegin + ? QEvent::TouchBegin + : sendTouchEnd + ? QEvent::TouchEnd + : QEvent::TouchUpdate), + q->keyboardModifiers(), activeTouchPoints); + updateTouchPointsForWidget(widget, &touchEvent); + return (qt_tabletChokeMouse = sendTouchEvent(widget, &touchEvent)); + } + + return false; +} + +bool QApplicationPrivate::sendTouchEvent(QWidget *widget, QTouchEvent *touchEvent) +{ + bool res = QApplication::sendSpontaneousEvent(widget, touchEvent); + return res && touchEvent->isAccepted(); +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp index ffbb341..b55f1c8 100644 --- a/src/gui/kernel/qwidget_win.cpp +++ b/src/gui/kernel/qwidget_win.cpp @@ -503,6 +503,10 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO } } + // ### don't always register for touch events + if (QApplicationPrivate::RegisterTouchWindow && !desktop) + QApplicationPrivate::RegisterTouchWindow(id, 0); + q->setAttribute(Qt::WA_WState_Created); // accept move/resize events hd = 0; // no display context -- cgit v0.12 From 761cac16eb0a6d32f9e7d558867c5c1bbfb244f9 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Wed, 25 Mar 2009 13:49:34 +0100 Subject: show the example maximized, not fullscreen --- examples/multitouch/knobs/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/multitouch/knobs/main.cpp b/examples/multitouch/knobs/main.cpp index c5a7ea7..8f78cf9 100644 --- a/examples/multitouch/knobs/main.cpp +++ b/examples/multitouch/knobs/main.cpp @@ -59,7 +59,7 @@ int main(int argc, char **argv) scene.addItem(knob1); scene.addItem(knob2); - view.showFullScreen(); + view.showMaximized(); view.fitInView(scene.sceneRect().adjusted(-20, -20, 20, 20), Qt::KeepAspectRatio); return app.exec(); -- cgit v0.12 From e14f2ddd25a72f07a3215c1bc7f4755c48dd6e3a Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Thu, 12 Mar 2009 13:45:18 +0100 Subject: add a test for touch event propagation --- tests/auto/qapplication/tst_qapplication.cpp | 143 +++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/tests/auto/qapplication/tst_qapplication.cpp b/tests/auto/qapplication/tst_qapplication.cpp index cee3125..356768e 100644 --- a/tests/auto/qapplication/tst_qapplication.cpp +++ b/tests/auto/qapplication/tst_qapplication.cpp @@ -48,6 +48,7 @@ #include "qabstracteventdispatcher.h" #include +#include "private/qapplication_p.h" #include "private/qstylesheetstyle_p.h" #ifdef Q_OS_WINCE #include @@ -117,6 +118,8 @@ private slots: void windowsCommandLine_data(); void windowsCommandLine(); + + void touchEventPropagation(); }; class MyInputContext : public QInputContext @@ -1773,6 +1776,146 @@ void tst_QApplication::windowsCommandLine() #endif } +class TouchEventPropagationTestWidget : public QWidget +{ + Q_OBJECT + +public: + bool seenTouchEvent, acceptTouchEvent, seenMouseEvent, acceptMouseEvent; + + TouchEventPropagationTestWidget(QWidget *parent = 0) + : QWidget(parent), seenTouchEvent(false), acceptTouchEvent(false), seenMouseEvent(false), acceptMouseEvent(false) + { } + + void reset() + { + seenTouchEvent = acceptTouchEvent = seenMouseEvent = acceptMouseEvent = false; + } + + bool event(QEvent *event) + { + switch (event->type()) { + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: + // qDebug() << objectName() << "seenMouseEvent = true"; + seenMouseEvent = true; + event->setAccepted(acceptMouseEvent); + break; + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + // qDebug() << objectName() << "seenTouchEvent = true"; + seenTouchEvent = true; + event->setAccepted(acceptTouchEvent); + break; + default: + return QWidget::event(event); + } + return true; + } +}; + +void tst_QApplication::touchEventPropagation() +{ + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + QTouchEvent::TouchPoint touchPoint(0); + QTouchEvent touchEvent(QEvent::TouchBegin, Qt::NoModifier, QList() << (&touchPoint)); + + { + // touch event behavior on a window + TouchEventPropagationTestWidget window; + window.setObjectName("1. window"); + + QApplicationPrivate::sendTouchEvent(&window, &touchEvent); + QVERIFY(!window.seenTouchEvent); + QVERIFY(window.seenMouseEvent); + + window.reset(); + window.setAttribute(Qt::WA_AcceptsTouchEvents); + QApplicationPrivate::sendTouchEvent(&window, &touchEvent); + QVERIFY(window.seenTouchEvent); + QVERIFY(window.seenMouseEvent); + + window.reset(); + window.acceptTouchEvent = true; + QApplicationPrivate::sendTouchEvent(&window, &touchEvent); + QVERIFY(window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + } + + { + // touch event behavior on a window with a child widget + TouchEventPropagationTestWidget window; + window.setObjectName("2. window"); + TouchEventPropagationTestWidget widget(&window); + widget.setObjectName("2. widget"); + + QApplicationPrivate::sendTouchEvent(&widget, &touchEvent); + QVERIFY(!widget.seenTouchEvent); + QVERIFY(widget.seenMouseEvent); + QVERIFY(!window.seenTouchEvent); + QVERIFY(window.seenMouseEvent); + + window.reset(); + widget.reset(); + widget.setAttribute(Qt::WA_AcceptsTouchEvents); + QApplicationPrivate::sendTouchEvent(&widget, &touchEvent); + QVERIFY(widget.seenTouchEvent); + QVERIFY(widget.seenMouseEvent); + QVERIFY(!window.seenTouchEvent); + QVERIFY(window.seenMouseEvent); + + window.reset(); + widget.reset(); + widget.acceptMouseEvent = true; + QApplicationPrivate::sendTouchEvent(&widget, &touchEvent); + QVERIFY(widget.seenTouchEvent); + QVERIFY(widget.seenMouseEvent); + QVERIFY(!window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + + window.reset(); + widget.reset(); + widget.acceptTouchEvent = true; + QApplicationPrivate::sendTouchEvent(&widget, &touchEvent); + QVERIFY(widget.seenTouchEvent); + QVERIFY(!widget.seenMouseEvent); + QVERIFY(!window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + + window.reset(); + widget.reset(); + widget.setAttribute(Qt::WA_AcceptsTouchEvents, false); + window.setAttribute(Qt::WA_AcceptsTouchEvents); + QApplicationPrivate::sendTouchEvent(&widget, &touchEvent); + QVERIFY(!widget.seenTouchEvent); + QVERIFY(widget.seenMouseEvent); + QVERIFY(window.seenTouchEvent); + QVERIFY(window.seenMouseEvent); + + window.reset(); + widget.reset(); + window.acceptTouchEvent = true; + QApplicationPrivate::sendTouchEvent(&widget, &touchEvent); + QVERIFY(!widget.seenTouchEvent); + QVERIFY(!widget.seenMouseEvent); + QVERIFY(window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + + window.reset(); + widget.reset(); + widget.acceptMouseEvent = true; // doesn't matter, touch events are propagated first + window.acceptTouchEvent = true; + QApplicationPrivate::sendTouchEvent(&widget, &touchEvent); + QVERIFY(!widget.seenTouchEvent); + QVERIFY(!widget.seenMouseEvent); + QVERIFY(window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + } +} + //QTEST_APPLESS_MAIN(tst_QApplication) int main(int argc, char *argv[]) { -- cgit v0.12 From b2824b384485ddba95091e49f81733485f1a73be Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Thu, 26 Mar 2009 08:24:39 +0100 Subject: remove QApplicationPrivate::sendTouchEvent --- src/gui/kernel/qapplication_p.h | 2 -- src/gui/kernel/qapplication_win.cpp | 10 +++------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index ccd9f41..ce7110d 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -440,8 +440,6 @@ public: QVector allTouchPoints; QList currentTouchPoints, activeTouchPoints; - static bool sendTouchEvent(QWidget *widget, QTouchEvent *touchEvent); - void initializeMultitouch(); void insertActiveTouch(QTouchEvent::TouchPoint *touchPoint); void removeActiveTouch(QTouchEvent::TouchPoint *touchPoint); diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 7c7f7f6..cef8cf2 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -4133,16 +4133,12 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) : QEvent::TouchUpdate), q->keyboardModifiers(), activeTouchPoints); updateTouchPointsForWidget(widget, &touchEvent); - return (qt_tabletChokeMouse = sendTouchEvent(widget, &touchEvent)); + + bool res = QApplication::sendSpontaneousEvent(widget, &touchEvent); + return (qt_tabletChokeMouse = res && touchEvent.isAccepted()); } return false; } -bool QApplicationPrivate::sendTouchEvent(QWidget *widget, QTouchEvent *touchEvent) -{ - bool res = QApplication::sendSpontaneousEvent(widget, touchEvent); - return res && touchEvent->isAccepted(); -} - QT_END_NAMESPACE -- cgit v0.12 From b3a2c210973a77d1517d017637a3d6ef849f4089 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Thu, 26 Mar 2009 08:54:36 +0100 Subject: implement panning using touch events since we don't get mouse events to send to QGraphicsView's ScrollHandDrag handlers, we need to do it ourselves --- examples/multitouch/pinchzoom/graphicsview.cpp | 13 ++++++++----- examples/multitouch/pinchzoom/main.cpp | 1 - 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/examples/multitouch/pinchzoom/graphicsview.cpp b/examples/multitouch/pinchzoom/graphicsview.cpp index b77c926..f763e6f 100644 --- a/examples/multitouch/pinchzoom/graphicsview.cpp +++ b/examples/multitouch/pinchzoom/graphicsview.cpp @@ -41,9 +41,9 @@ #include "graphicsview.h" +#include #include - GraphicsView::GraphicsView(QGraphicsScene *scene, QWidget *parent) : QGraphicsView(scene, parent) { @@ -57,10 +57,13 @@ bool GraphicsView::event(QEvent *event) case QEvent::TouchUpdate: case QEvent::TouchEnd: { - qDebug("touch events"); - - QList touchPoints = static_cast(event)->touchPoints(); - if (touchPoints.count() == 2) { + QList touchPoints = static_cast(event)->touchPoints(); + if (touchPoints.count() == 1) { + const QTouchEvent::TouchPoint *touchPoint = touchPoints.first(); + QPointF delta = touchPoint->pos() - touchPoint->lastPos(); + horizontalScrollBar()->setValue(horizontalScrollBar()->value() - delta.x()); + verticalScrollBar()->setValue(verticalScrollBar()->value() - delta.y()); + } else if (touchPoints.count() == 2) { // determine scale factor const QTouchEvent::TouchPoint *touchPoint0 = touchPoints.first(); const QTouchEvent::TouchPoint *touchPoint1 = touchPoints.last(); diff --git a/examples/multitouch/pinchzoom/main.cpp b/examples/multitouch/pinchzoom/main.cpp index 6b25060..bb86870 100644 --- a/examples/multitouch/pinchzoom/main.cpp +++ b/examples/multitouch/pinchzoom/main.cpp @@ -78,7 +78,6 @@ int main(int argc, char **argv) //! [4] //! [5] view.setCacheMode(QGraphicsView::CacheBackground); view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); - view.setDragMode(QGraphicsView::ScrollHandDrag); //! [5] //! [6] view.setWindowTitle(QT_TRANSLATE_NOOP(QGraphicsView, "Colliding Mice")); view.showMaximized(); -- cgit v0.12 From 46caddc9fa82df4fba88ea4ef87dba692b18c1c9 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Mon, 30 Mar 2009 11:08:12 +0200 Subject: compile --- src/network/kernel/qauthenticator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp index 4f477bd..19243aa 100644 --- a/src/network/kernel/qauthenticator.cpp +++ b/src/network/kernel/qauthenticator.cpp @@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE -#include <../3rdparty/des/des.cpp> +#include <../../3rdparty/des/des.cpp> static QByteArray qNtlmPhase1(); static QByteArray qNtlmPhase3(QAuthenticatorPrivate *ctx, const QByteArray& phase2data); -- cgit v0.12 From be8b6047ccd43df1127beb4c602c58408ff9b612 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Tue, 31 Mar 2009 13:19:23 +0200 Subject: Add QSysInfo::WV_WINDOWS7 --- src/corelib/global/qglobal.cpp | 9 ++++++++- src/corelib/global/qglobal.h | 2 ++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index 459167e..bcb17a2 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -1054,6 +1054,7 @@ bool qSharedBuild() \value WV_XP Windows XP (operating system version 5.1) \value WV_2003 Windows Server 2003, Windows Server 2003 R2, Windows Home Server, Windows XP Professional x64 Edition (operating system version 5.2) \value WV_VISTA Windows Vista, Windows Server 2008 (operating system version 6.0) + \value WV_WINDOWS7 Windows 7 (operating system version 6.1) Alternatively, you may use the following macros which correspond directly to the Windows operating system version number: @@ -1062,6 +1063,7 @@ bool qSharedBuild() \value WV_5_1 Operating system version 5.1, corresponds to Windows XP \value WV_5_2 Operating system version 5.2, corresponds to Windows Server 2003, Windows Server 2003 R2, Windows Home Server, and Windows XP Professional x64 Edition \value WV_6_0 Operating system version 6.0, corresponds to Windows Vista and Windows Server 2008 + \value WV_6_1 Operation system version 6.1, corresponds to Windows 7 CE-based versions: @@ -1632,7 +1634,10 @@ QSysInfo::WinVersion QSysInfo::windowsVersion() if (osver.dwMajorVersion < 5) { winver = QSysInfo::WV_NT; } else if (osver.dwMajorVersion == 6) { - winver = QSysInfo::WV_VISTA; + if (osver.dwMinorVersion == 0) + winver = QSysInfo::WV_VISTA; + else + winver = QSysInfo::WV_WINDOWS7; } else if (osver.dwMinorVersion == 0) { winver = QSysInfo::WV_2000; } else if (osver.dwMinorVersion == 1) { @@ -1667,6 +1672,8 @@ QSysInfo::WinVersion QSysInfo::windowsVersion() winver = QSysInfo::WV_XP; else if (override == "VISTA") winver = QSysInfo::WV_VISTA; + else if (override == "WINDOWS7") + winver = QSysInfo::WV_WINDOWS7; } #endif diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 9522e39..872dcf5 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -1309,6 +1309,7 @@ public: WV_XP = 0x0030, WV_2003 = 0x0040, WV_VISTA = 0x0080, + WV_WINDOWS7 = 0x0090, WV_NT_based = 0x00f0, /* version numbers */ @@ -1317,6 +1318,7 @@ public: WV_5_1 = WV_XP, WV_5_2 = WV_2003, WV_6_0 = WV_VISTA, + WV_6_1 = WV_WINDOWS7, WV_CE = 0x0100, WV_CENET = 0x0200, -- cgit v0.12 From 726694c873104ac484a3d09c1a9f64f06a88f864 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Thu, 23 Apr 2009 14:57:12 +0200 Subject: the start of a manual test for touch events --- tests/manual/qtouchevent/form.ui | 1843 ++++++++++++++++++++++++++++++ tests/manual/qtouchevent/main.cpp | 58 + tests/manual/qtouchevent/multitouch.pro | 5 + tests/manual/qtouchevent/touchwidget.cpp | 56 + tests/manual/qtouchevent/touchwidget.h | 42 + 5 files changed, 2004 insertions(+) create mode 100644 tests/manual/qtouchevent/form.ui create mode 100644 tests/manual/qtouchevent/main.cpp create mode 100644 tests/manual/qtouchevent/multitouch.pro create mode 100644 tests/manual/qtouchevent/touchwidget.cpp create mode 100644 tests/manual/qtouchevent/touchwidget.h diff --git a/tests/manual/qtouchevent/form.ui b/tests/manual/qtouchevent/form.ui new file mode 100644 index 0000000..00e15ae --- /dev/null +++ b/tests/manual/qtouchevent/form.ui @@ -0,0 +1,1843 @@ + + + Form + + + + 0 + 0 + 791 + 499 + + + + Form + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 255 + 0 + + + + + + + 0 + 212 + 0 + + + + + + + 0 + 85 + 0 + + + + + + + 0 + 113 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 127 + 212 + 127 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 255 + 0 + + + + + + + 0 + 212 + 0 + + + + + + + 0 + 85 + 0 + + + + + + + 0 + 113 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 127 + 212 + 127 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 85 + 0 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 255 + 0 + + + + + + + 0 + 212 + 0 + + + + + + + 0 + 85 + 0 + + + + + + + 0 + 113 + 0 + + + + + + + 0 + 85 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 85 + 0 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 170 + 0 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + true + + + + + + Qt::Vertical + + + + 20 + 290 + + + + + + + + Qt::Horizontal + + + + 84 + 20 + + + + + + + + + 180 + 120 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 170 + + + + + + + 0 + 0 + 255 + + + + + + + 0 + 0 + 212 + + + + + + + 0 + 0 + 85 + + + + + + + 0 + 0 + 113 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 170 + + + + + + + 0 + 0 + 0 + + + + + + + 127 + 127 + 212 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 170 + + + + + + + 0 + 0 + 255 + + + + + + + 0 + 0 + 212 + + + + + + + 0 + 0 + 85 + + + + + + + 0 + 0 + 113 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 170 + + + + + + + 0 + 0 + 0 + + + + + + + 127 + 127 + 212 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 85 + + + + + + + 0 + 0 + 170 + + + + + + + 0 + 0 + 255 + + + + + + + 0 + 0 + 212 + + + + + + + 0 + 0 + 85 + + + + + + + 0 + 0 + 113 + + + + + + + 0 + 0 + 85 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 85 + + + + + + + 0 + 0 + 170 + + + + + + + 0 + 0 + 170 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 170 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + true + + + + + + + Qt::Horizontal + + + + 84 + 20 + + + + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 212 + 0 + 0 + + + + + + + 85 + 0 + 0 + + + + + + + 113 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 170 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 212 + 127 + 127 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 212 + 0 + 0 + + + + + + + 85 + 0 + 0 + + + + + + + 113 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 170 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 212 + 127 + 127 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 85 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 212 + 0 + 0 + + + + + + + 85 + 0 + 0 + + + + + + + 113 + 0 + 0 + + + + + + + 85 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 85 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + true + + + + + + Qt::Vertical + + + + 20 + 290 + + + + + + + + Qt::Horizontal + + + + 84 + 20 + + + + + + + + + 180 + 120 + + + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + true + + + + + + + Qt::Horizontal + + + + 83 + 20 + + + + + + + + + + + + 75 + true + + + + Test Name + + + + + + + Test description + + + + + + + + TouchWidget + QWidget +
touchwidget.h
+ 1 +
+
+ + +
diff --git a/tests/manual/qtouchevent/main.cpp b/tests/manual/qtouchevent/main.cpp new file mode 100644 index 0000000..c406543 --- /dev/null +++ b/tests/manual/qtouchevent/main.cpp @@ -0,0 +1,58 @@ +#include +#include + +#include "ui_form.h" +#include "touchwidget.h" + +class MultitouchTestWidget : public QWidget, public Ui::Form +{ + Q_OBJECT + +public: + MultitouchTestWidget(QWidget *parent = 0) + : QWidget(parent) + { + setupUi(this); + } +}; + +class tst_ManualMultitouch : public QObject +{ + Q_OBJECT + +public: + tst_ManualMultitouch(); + ~tst_ManualMultitouch(); + +private slots: + void touchBeginPropagation(); +}; + +tst_ManualMultitouch::tst_ManualMultitouch() +{ } + +tst_ManualMultitouch::~tst_ManualMultitouch() +{ } + +void tst_ManualMultitouch::touchBeginPropagation() +{ + MultitouchTestWidget testWidget; + testWidget.testNameLabel->setText("Touch event propagation"); + testWidget.testDescriptionLabel->setText("Touch, move, and release your finger over the green widget, the close this window."); + testWidget.greenWidget->setAttribute(Qt::WA_AcceptTouchEvents); + testWidget.greenWidget->acceptTouchBegin = true; + testWidget.show(); + + (void) qApp->exec(); + + QVERIFY(testWidget.greenWidget->seenTouchBegin); + QVERIFY(testWidget.greenWidget->seenTouchUpdate); + QVERIFY(testWidget.greenWidget->seenTouchEnd); + QVERIFY(!testWidget.greenWidget->seenMousePress); + QVERIFY(!testWidget.greenWidget->seenMouseMove); + QVERIFY(!testWidget.greenWidget->seenMouseRelease); +} + +QTEST_MAIN(tst_ManualMultitouch) + +#include "main.moc" diff --git a/tests/manual/qtouchevent/multitouch.pro b/tests/manual/qtouchevent/multitouch.pro new file mode 100644 index 0000000..de1ee06 --- /dev/null +++ b/tests/manual/qtouchevent/multitouch.pro @@ -0,0 +1,5 @@ +QT += testlib +SOURCES = main.cpp \ + touchwidget.cpp +FORMS += form.ui +HEADERS += touchwidget.h diff --git a/tests/manual/qtouchevent/touchwidget.cpp b/tests/manual/qtouchevent/touchwidget.cpp new file mode 100644 index 0000000..5205504 --- /dev/null +++ b/tests/manual/qtouchevent/touchwidget.cpp @@ -0,0 +1,56 @@ +#include "touchwidget.h" + +#include +#include + +bool TouchWidget::event(QEvent *event) +{ + switch (event->type()) { + case QEvent::TouchBegin: + seenTouchBegin = true; + if (acceptTouchBegin) { + event->accept(); + return true; + } + break; + case QEvent::TouchUpdate: + seenTouchUpdate = true; + if (acceptTouchUpdate) { + event->accept(); + return true; + } + break; + case QEvent::TouchEnd: + seenTouchEnd = true; + if (acceptTouchEnd) { + event->accept(); + return true; + } + break; + case QEvent::MouseButtonPress: + case QEvent::MouseButtonDblClick: + seenMousePress = true; + if (acceptMousePress) { + event->accept(); + return true; + } + break; + case QEvent::MouseMove: + seenMouseMove = true; + if (acceptMouseMove) { + event->accept(); + return true; + } + break; + case QEvent::MouseButtonRelease: + seenMouseRelease = true; + if (acceptMouseRelease) { + event->accept(); + return true; + } + break; + default: + break; + } + return QWidget::event(event); +} diff --git a/tests/manual/qtouchevent/touchwidget.h b/tests/manual/qtouchevent/touchwidget.h new file mode 100644 index 0000000..f438a87 --- /dev/null +++ b/tests/manual/qtouchevent/touchwidget.h @@ -0,0 +1,42 @@ +#ifndef TOUCHWIDGET_H +#define TOUCHWIDGET_H + +#include + +class TouchWidget : public QWidget +{ + Q_OBJECT + +public: + bool acceptTouchBegin, acceptTouchUpdate, acceptTouchEnd; + bool seenTouchBegin, seenTouchUpdate, seenTouchEnd; + bool acceptMousePress, acceptMouseMove, acceptMouseRelease; + bool seenMousePress, seenMouseMove, seenMouseRelease; + + inline TouchWidget(QWidget *parent = 0) + : QWidget(parent) + { + reset(); + } + + void reset() + { + acceptTouchBegin + = acceptTouchUpdate + = acceptTouchEnd + = seenTouchBegin + = seenTouchUpdate + = seenTouchEnd + = acceptMousePress + = acceptMouseMove + = acceptMouseRelease + = seenMousePress + = seenMouseMove + = seenMouseRelease + = false; + } + + bool event(QEvent *event); +}; + +#endif // TOUCHWIDGET_H -- cgit v0.12 From 704261859297dae22f90be32ed0e4b675fd02ed3 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Thu, 23 Apr 2009 15:54:06 +0200 Subject: Initial test for TouchBegin propagation and TouchUpdate/TouchEnd handling --- tests/manual/qtouchevent/main.cpp | 54 ++++++++++++++++++++++++++++++-- tests/manual/qtouchevent/touchwidget.cpp | 26 +++++++++++++++ tests/manual/qtouchevent/touchwidget.h | 20 +++--------- 3 files changed, 82 insertions(+), 18 deletions(-) diff --git a/tests/manual/qtouchevent/main.cpp b/tests/manual/qtouchevent/main.cpp index c406543..2aab4ca 100644 --- a/tests/manual/qtouchevent/main.cpp +++ b/tests/manual/qtouchevent/main.cpp @@ -38,13 +38,63 @@ void tst_ManualMultitouch::touchBeginPropagation() { MultitouchTestWidget testWidget; testWidget.testNameLabel->setText("Touch event propagation"); - testWidget.testDescriptionLabel->setText("Touch, move, and release your finger over the green widget, the close this window."); + testWidget.testDescriptionLabel->setText("Touch, move, and release your finger over the green widget."); testWidget.greenWidget->setAttribute(Qt::WA_AcceptTouchEvents); testWidget.greenWidget->acceptTouchBegin = true; - testWidget.show(); + testWidget.greenWidget->acceptTouchUpdate = true; + testWidget.greenWidget->acceptTouchEnd = true; + testWidget.greenWidget->closeWindowOnTouchEnd = true; + testWidget.showMaximized(); (void) qApp->exec(); + QVERIFY(testWidget.greenWidget->seenTouchBegin); + QVERIFY(testWidget.greenWidget->seenTouchUpdate); + QVERIFY(testWidget.greenWidget->seenTouchEnd); + QVERIFY(!testWidget.greenWidget->seenMousePress); + QVERIFY(!testWidget.greenWidget->seenMouseMove); + QVERIFY(!testWidget.greenWidget->seenMouseRelease); + + // again, ignoring the TouchEnd + testWidget.greenWidget->reset(); + testWidget.greenWidget->acceptTouchBegin = true; + testWidget.greenWidget->acceptTouchUpdate = true; + // testWidget.greenWidget->acceptTouchEnd = true; + testWidget.greenWidget->closeWindowOnTouchEnd = true; + testWidget.showMaximized(); + (void) qApp->exec(); + QVERIFY(testWidget.greenWidget->seenTouchBegin); + QVERIFY(testWidget.greenWidget->seenTouchUpdate); + QVERIFY(testWidget.greenWidget->seenTouchEnd); + QVERIFY(!testWidget.greenWidget->seenMousePress); + QVERIFY(!testWidget.greenWidget->seenMouseMove); + QVERIFY(!testWidget.greenWidget->seenMouseRelease); + + // again, ignoring TouchUpdates + testWidget.greenWidget->reset(); + testWidget.greenWidget->acceptTouchBegin = true; + // testWidget.greenWidget->acceptTouchUpdate = true; + testWidget.greenWidget->acceptTouchEnd = true; + testWidget.greenWidget->closeWindowOnTouchEnd = true; + testWidget.showMaximized(); + + (void) qApp->exec(); + QVERIFY(testWidget.greenWidget->seenTouchBegin); + QVERIFY(testWidget.greenWidget->seenTouchUpdate); + QVERIFY(testWidget.greenWidget->seenTouchEnd); + QVERIFY(!testWidget.greenWidget->seenMousePress); + QVERIFY(!testWidget.greenWidget->seenMouseMove); + QVERIFY(!testWidget.greenWidget->seenMouseRelease); + + // last time, ignoring TouchUpdates and TouchEnd + testWidget.greenWidget->reset(); + testWidget.greenWidget->acceptTouchBegin = true; + // testWidget.greenWidget->acceptTouchUpdate = true; + // testWidget.greenWidget->acceptTouchEnd = true; + testWidget.greenWidget->closeWindowOnTouchEnd = true; + testWidget.showMaximized(); + + (void) qApp->exec(); QVERIFY(testWidget.greenWidget->seenTouchBegin); QVERIFY(testWidget.greenWidget->seenTouchUpdate); QVERIFY(testWidget.greenWidget->seenTouchEnd); diff --git a/tests/manual/qtouchevent/touchwidget.cpp b/tests/manual/qtouchevent/touchwidget.cpp index 5205504..54ca685 100644 --- a/tests/manual/qtouchevent/touchwidget.cpp +++ b/tests/manual/qtouchevent/touchwidget.cpp @@ -3,6 +3,28 @@ #include #include + +void TouchWidget::reset() +{ + acceptTouchBegin + = acceptTouchUpdate + = acceptTouchEnd + = seenTouchBegin + = seenTouchUpdate + = seenTouchEnd + = closeWindowOnTouchEnd + + = acceptMousePress + = acceptMouseMove + = acceptMouseRelease + = seenMousePress + = seenMouseMove + = seenMouseRelease + = closeWindowOnMouseRelease + + = false; +} + bool TouchWidget::event(QEvent *event) { switch (event->type()) { @@ -22,6 +44,8 @@ bool TouchWidget::event(QEvent *event) break; case QEvent::TouchEnd: seenTouchEnd = true; + if (closeWindowOnTouchEnd) + window()->close(); if (acceptTouchEnd) { event->accept(); return true; @@ -44,6 +68,8 @@ bool TouchWidget::event(QEvent *event) break; case QEvent::MouseButtonRelease: seenMouseRelease = true; + if (closeWindowOnMouseRelease) + window()->close(); if (acceptMouseRelease) { event->accept(); return true; diff --git a/tests/manual/qtouchevent/touchwidget.h b/tests/manual/qtouchevent/touchwidget.h index f438a87..3e95610 100644 --- a/tests/manual/qtouchevent/touchwidget.h +++ b/tests/manual/qtouchevent/touchwidget.h @@ -10,8 +10,11 @@ class TouchWidget : public QWidget public: bool acceptTouchBegin, acceptTouchUpdate, acceptTouchEnd; bool seenTouchBegin, seenTouchUpdate, seenTouchEnd; + bool closeWindowOnTouchEnd; + bool acceptMousePress, acceptMouseMove, acceptMouseRelease; bool seenMousePress, seenMouseMove, seenMouseRelease; + bool closeWindowOnMouseRelease; inline TouchWidget(QWidget *parent = 0) : QWidget(parent) @@ -19,22 +22,7 @@ public: reset(); } - void reset() - { - acceptTouchBegin - = acceptTouchUpdate - = acceptTouchEnd - = seenTouchBegin - = seenTouchUpdate - = seenTouchEnd - = acceptMousePress - = acceptMouseMove - = acceptMouseRelease - = seenMousePress - = seenMouseMove - = seenMouseRelease - = false; - } + void reset(); bool event(QEvent *event); }; -- cgit v0.12 From 66ed5fc90fe44554e852a6f8dca4548154da781c Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Thu, 23 Apr 2009 17:54:17 +0200 Subject: update test to test basic event handling and touch begin propagation --- tests/manual/qtouchevent/form.ui | 572 +++++++++++++++++-------------- tests/manual/qtouchevent/main.cpp | 152 +++++++- tests/manual/qtouchevent/touchwidget.cpp | 7 +- 3 files changed, 460 insertions(+), 271 deletions(-) diff --git a/tests/manual/qtouchevent/form.ui b/tests/manual/qtouchevent/form.ui index 00e15ae..6cf4cba 100644 --- a/tests/manual/qtouchevent/form.ui +++ b/tests/manual/qtouchevent/form.ui @@ -6,16 +6,16 @@ 0 0 - 791 - 499 + 770 + 424 Form - - + + 0 @@ -37,8 +37,8 @@ - 0 - 170 + 170 + 0 0 @@ -46,8 +46,8 @@ - 0 - 255 + 255 + 0 0 @@ -55,8 +55,8 @@ - 0 - 212 + 212 + 0 0 @@ -64,8 +64,8 @@ - 0 - 85 + 85 + 0 0 @@ -73,8 +73,8 @@ - 0 - 113 + 113 + 0 0 @@ -118,8 +118,8 @@ - 0 - 170 + 170 + 0 0 @@ -136,8 +136,8 @@ - 127 - 212 + 212 + 127 127 @@ -174,8 +174,8 @@ - 0 - 170 + 170 + 0 0 @@ -183,8 +183,8 @@ - 0 - 255 + 255 + 0 0 @@ -192,8 +192,8 @@ - 0 - 212 + 212 + 0 0 @@ -201,8 +201,8 @@ - 0 - 85 + 85 + 0 0 @@ -210,8 +210,8 @@ - 0 - 113 + 113 + 0 0 @@ -255,8 +255,8 @@ - 0 - 170 + 170 + 0 0 @@ -273,8 +273,8 @@ - 127 - 212 + 212 + 127 127 @@ -302,8 +302,8 @@ - 0 - 85 + 85 + 0 0 @@ -311,8 +311,8 @@ - 0 - 170 + 170 + 0 0 @@ -320,8 +320,8 @@ - 0 - 255 + 255 + 0 0 @@ -329,8 +329,8 @@ - 0 - 212 + 212 + 0 0 @@ -338,8 +338,8 @@ - 0 - 85 + 85 + 0 0 @@ -347,8 +347,8 @@ - 0 - 113 + 113 + 0 0 @@ -356,8 +356,8 @@ - 0 - 85 + 85 + 0 0 @@ -374,8 +374,8 @@ - 0 - 85 + 85 + 0 0 @@ -383,8 +383,8 @@ - 0 - 170 + 170 + 0 0 @@ -392,8 +392,8 @@ - 0 - 170 + 170 + 0 0 @@ -410,8 +410,8 @@ - 0 - 170 + 170 + 0 0 @@ -440,35 +440,41 @@ true - + - + Qt::Vertical - 20 - 290 + 0 + 0 - + Qt::Horizontal - 84 - 20 + 0 + 0 - + + + + 0 + 0 + + 180 @@ -481,9 +487,9 @@ - 0 - 0 - 0 + 255 + 255 + 255 @@ -492,7 +498,7 @@ 0 0 - 170 + 0 @@ -501,7 +507,7 @@ 0 0 - 255 + 0 @@ -510,7 +516,7 @@ 0 0 - 212 + 0 @@ -519,7 +525,7 @@ 0 0 - 85 + 0 @@ -528,16 +534,16 @@ 0 0 - 113 + 0 - 0 - 0 - 0 + 255 + 255 + 255 @@ -553,18 +559,18 @@ - 0 - 0 - 0 + 255 + 255 + 255 - 255 - 255 - 255 + 0 + 0 + 0 @@ -573,7 +579,7 @@ 0 0 - 170 + 0 @@ -589,9 +595,9 @@ - 127 - 127 - 212 + 0 + 0 + 0 @@ -618,9 +624,9 @@ - 0 - 0 - 0 + 255 + 255 + 255 @@ -629,7 +635,7 @@ 0 0 - 170 + 0 @@ -638,7 +644,7 @@ 0 0 - 255 + 0 @@ -647,7 +653,7 @@ 0 0 - 212 + 0 @@ -656,7 +662,7 @@ 0 0 - 85 + 0 @@ -665,16 +671,16 @@ 0 0 - 113 + 0 - 0 - 0 - 0 + 255 + 255 + 255 @@ -690,18 +696,18 @@ - 0 - 0 - 0 + 255 + 255 + 255 - 255 - 255 - 255 + 0 + 0 + 0 @@ -710,7 +716,7 @@ 0 0 - 170 + 0 @@ -726,9 +732,9 @@ - 127 - 127 - 212 + 0 + 0 + 0 @@ -757,7 +763,7 @@ 0 0 - 85 + 0 @@ -766,7 +772,7 @@ 0 0 - 170 + 0 @@ -775,7 +781,7 @@ 0 0 - 255 + 0 @@ -784,7 +790,7 @@ 0 0 - 212 + 0 @@ -793,7 +799,7 @@ 0 0 - 85 + 0 @@ -802,7 +808,7 @@ 0 0 - 113 + 0 @@ -811,7 +817,7 @@ 0 0 - 85 + 0 @@ -829,7 +835,7 @@ 0 0 - 85 + 0 @@ -838,7 +844,7 @@ 0 0 - 170 + 0 @@ -847,7 +853,7 @@ 0 0 - 170 + 0 @@ -865,7 +871,7 @@ 0 0 - 170 + 0 @@ -896,14 +902,27 @@ - + Qt::Horizontal - 84 - 20 + 0 + 0 + + + + + + + + Qt::Vertical + + + + 0 + 0 @@ -911,8 +930,34 @@ - - + + + + + 16 + 75 + true + + + + Test Name + + + + + + + + 16 + + + + Test description + + + + + 0 @@ -934,8 +979,8 @@ - 170 - 0 + 0 + 170 0 @@ -943,8 +988,8 @@ - 255 - 0 + 0 + 255 0 @@ -952,8 +997,8 @@ - 212 - 0 + 0 + 212 0 @@ -961,8 +1006,8 @@ - 85 - 0 + 0 + 85 0 @@ -970,8 +1015,8 @@ - 113 - 0 + 0 + 113 0 @@ -1015,8 +1060,8 @@ - 170 - 0 + 0 + 170 0 @@ -1033,8 +1078,8 @@ - 212 - 127 + 127 + 212 127 @@ -1071,8 +1116,8 @@ - 170 - 0 + 0 + 170 0 @@ -1080,8 +1125,8 @@ - 255 - 0 + 0 + 255 0 @@ -1089,8 +1134,8 @@ - 212 - 0 + 0 + 212 0 @@ -1098,8 +1143,8 @@ - 85 - 0 + 0 + 85 0 @@ -1107,8 +1152,8 @@ - 113 - 0 + 0 + 113 0 @@ -1152,8 +1197,8 @@ - 170 - 0 + 0 + 170 0 @@ -1170,8 +1215,8 @@ - 212 - 127 + 127 + 212 127 @@ -1199,8 +1244,8 @@ - 85 - 0 + 0 + 85 0 @@ -1208,8 +1253,8 @@ - 170 - 0 + 0 + 170 0 @@ -1217,8 +1262,8 @@ - 255 - 0 + 0 + 255 0 @@ -1226,8 +1271,8 @@ - 212 - 0 + 0 + 212 0 @@ -1235,8 +1280,8 @@ - 85 - 0 + 0 + 85 0 @@ -1244,8 +1289,8 @@ - 113 - 0 + 0 + 113 0 @@ -1253,8 +1298,8 @@ - 85 - 0 + 0 + 85 0 @@ -1271,8 +1316,8 @@ - 85 - 0 + 0 + 85 0 @@ -1280,8 +1325,8 @@ - 170 - 0 + 0 + 170 0 @@ -1289,8 +1334,8 @@ - 170 - 0 + 0 + 170 0 @@ -1307,8 +1352,8 @@ - 170 - 0 + 0 + 170 0 @@ -1337,35 +1382,28 @@ true - - - - - Qt::Vertical - - - - 20 - 290 - - - - + - + Qt::Horizontal - 84 - 20 + 0 + 0 - + + + + 0 + 0 + + 180 @@ -1378,9 +1416,9 @@ - 255 - 255 - 255 + 0 + 0 + 0 @@ -1389,7 +1427,7 @@ 0 0 - 0 + 170 @@ -1398,7 +1436,7 @@ 0 0 - 0 + 255 @@ -1407,7 +1445,7 @@ 0 0 - 0 + 212 @@ -1416,7 +1454,7 @@ 0 0 - 0 + 85 @@ -1425,16 +1463,16 @@ 0 0 - 0 + 113 - 255 - 255 - 255 + 0 + 0 + 0 @@ -1450,18 +1488,18 @@ - 255 - 255 - 255 + 0 + 0 + 0 - 0 - 0 - 0 + 255 + 255 + 255 @@ -1470,7 +1508,7 @@ 0 0 - 0 + 170 @@ -1486,9 +1524,9 @@ - 0 - 0 - 0 + 127 + 127 + 212 @@ -1515,9 +1553,9 @@ - 255 - 255 - 255 + 0 + 0 + 0 @@ -1526,7 +1564,7 @@ 0 0 - 0 + 170 @@ -1535,7 +1573,7 @@ 0 0 - 0 + 255 @@ -1544,7 +1582,7 @@ 0 0 - 0 + 212 @@ -1553,7 +1591,7 @@ 0 0 - 0 + 85 @@ -1562,16 +1600,16 @@ 0 0 - 0 + 113 - 255 - 255 - 255 + 0 + 0 + 0 @@ -1587,18 +1625,18 @@ - 255 - 255 - 255 + 0 + 0 + 0 - 0 - 0 - 0 + 255 + 255 + 255 @@ -1607,7 +1645,7 @@ 0 0 - 0 + 170 @@ -1623,9 +1661,9 @@ - 0 - 0 - 0 + 127 + 127 + 212 @@ -1654,7 +1692,7 @@ 0 0 - 0 + 85 @@ -1663,7 +1701,7 @@ 0 0 - 0 + 170 @@ -1672,7 +1710,7 @@ 0 0 - 0 + 255 @@ -1681,7 +1719,7 @@ 0 0 - 0 + 212 @@ -1690,7 +1728,7 @@ 0 0 - 0 + 85 @@ -1699,7 +1737,7 @@ 0 0 - 0 + 113 @@ -1708,7 +1746,7 @@ 0 0 - 0 + 85 @@ -1726,7 +1764,7 @@ 0 0 - 0 + 85 @@ -1735,7 +1773,7 @@ 0 0 - 0 + 170 @@ -1744,7 +1782,7 @@ 0 0 - 0 + 170 @@ -1762,7 +1800,7 @@ 0 0 - 0 + 170 @@ -1793,14 +1831,40 @@ - + Qt::Horizontal - 83 - 20 + 0 + 0 + + + + + + + + Qt::Vertical + + + + 0 + 0 + + + + + + + + Qt::Vertical + + + + 0 + 0 @@ -1808,26 +1872,6 @@ - - - - - 75 - true - - - - Test Name - - - - - - - Test description - - - diff --git a/tests/manual/qtouchevent/main.cpp b/tests/manual/qtouchevent/main.cpp index 2aab4ca..7ed9b15 100644 --- a/tests/manual/qtouchevent/main.cpp +++ b/tests/manual/qtouchevent/main.cpp @@ -12,8 +12,15 @@ public: MultitouchTestWidget(QWidget *parent = 0) : QWidget(parent) { + setAttribute(Qt::WA_QuitOnClose, false);\ setupUi(this); } + + void closeEvent(QCloseEvent *event) + { + event->accept(); + QTimer::singleShot(1000, qApp, SLOT(quit())); + } }; class tst_ManualMultitouch : public QObject @@ -25,7 +32,8 @@ public: ~tst_ManualMultitouch(); private slots: - void touchBeginPropagation(); + void basicEventHandling(); + void touchEventPropagation(); }; tst_ManualMultitouch::tst_ManualMultitouch() @@ -34,11 +42,99 @@ tst_ManualMultitouch::tst_ManualMultitouch() tst_ManualMultitouch::~tst_ManualMultitouch() { } -void tst_ManualMultitouch::touchBeginPropagation() +void tst_ManualMultitouch::basicEventHandling() +{ + // first, make sure that we get mouse events when not enabling touch events + MultitouchTestWidget testWidget; + testWidget.testNameLabel->setText("Basic QTouchEvent handling test"); + testWidget.testDescriptionLabel->setText("Touch, hold, and release your finger on the green widget."); + testWidget.redWidget->hide(); + testWidget.blueWidget->hide(); + testWidget.greenWidget->closeWindowOnMouseRelease = true; + testWidget.showMaximized(); + + (void) qApp->exec(); + QVERIFY(!testWidget.greenWidget->seenTouchBegin); + QVERIFY(!testWidget.greenWidget->seenTouchUpdate); + QVERIFY(!testWidget.greenWidget->seenTouchEnd); + QVERIFY(testWidget.greenWidget->seenMousePress); + // QVERIFY(testWidget.greenWidget->seenMouseMove); + QVERIFY(testWidget.greenWidget->seenMouseRelease); + + // now enable touch and make sure we get the touch events + testWidget.greenWidget->reset(); + testWidget.greenWidget->setAttribute(Qt::WA_AcceptTouchEvents); + testWidget.greenWidget->acceptTouchBegin = true; + testWidget.greenWidget->acceptTouchUpdate = true; + testWidget.greenWidget->acceptTouchEnd = true; + testWidget.greenWidget->closeWindowOnTouchEnd = true; + testWidget.showMaximized(); + + (void) qApp->exec(); + QVERIFY(testWidget.greenWidget->seenTouchBegin + && testWidget.greenWidget->seenTouchUpdate + && testWidget.greenWidget->seenTouchEnd); + QVERIFY(!testWidget.greenWidget->seenMousePress + && !testWidget.greenWidget->seenMouseMove + && !testWidget.greenWidget->seenMouseRelease); + + // again, ignoring the TouchEnd + testWidget.greenWidget->reset(); + testWidget.greenWidget->acceptTouchBegin = true; + testWidget.greenWidget->acceptTouchUpdate = true; + // testWidget.greenWidget->acceptTouchEnd = true; + testWidget.greenWidget->closeWindowOnTouchEnd = true; + testWidget.showMaximized(); + + (void) qApp->exec(); + QVERIFY(testWidget.greenWidget->seenTouchBegin); + QVERIFY(testWidget.greenWidget->seenTouchUpdate); + QVERIFY(testWidget.greenWidget->seenTouchEnd); + QVERIFY(!testWidget.greenWidget->seenMousePress); + QVERIFY(!testWidget.greenWidget->seenMouseMove); + QVERIFY(!testWidget.greenWidget->seenMouseRelease); + + // again, ignoring TouchUpdates + testWidget.greenWidget->reset(); + testWidget.greenWidget->acceptTouchBegin = true; + // testWidget.greenWidget->acceptTouchUpdate = true; + testWidget.greenWidget->acceptTouchEnd = true; + testWidget.greenWidget->closeWindowOnTouchEnd = true; + testWidget.showMaximized(); + + (void) qApp->exec(); + QVERIFY(testWidget.greenWidget->seenTouchBegin); + QVERIFY(testWidget.greenWidget->seenTouchUpdate); + QVERIFY(testWidget.greenWidget->seenTouchEnd); + QVERIFY(!testWidget.greenWidget->seenMousePress); + QVERIFY(!testWidget.greenWidget->seenMouseMove); + QVERIFY(!testWidget.greenWidget->seenMouseRelease); + + // last time, ignoring TouchUpdates and TouchEnd + testWidget.greenWidget->reset(); + testWidget.greenWidget->acceptTouchBegin = true; + // testWidget.greenWidget->acceptTouchUpdate = true; + // testWidget.greenWidget->acceptTouchEnd = true; + testWidget.greenWidget->closeWindowOnTouchEnd = true; + testWidget.showMaximized(); + + (void) qApp->exec(); + QVERIFY(testWidget.greenWidget->seenTouchBegin); + QVERIFY(testWidget.greenWidget->seenTouchUpdate); + QVERIFY(testWidget.greenWidget->seenTouchEnd); + QVERIFY(!testWidget.greenWidget->seenMousePress); + QVERIFY(!testWidget.greenWidget->seenMouseMove); + QVERIFY(!testWidget.greenWidget->seenMouseRelease); +} + +void tst_ManualMultitouch::touchEventPropagation() { + // first, make sure the greenWidget gets TouchBegin even though blueWidget is not touch aware MultitouchTestWidget testWidget; - testWidget.testNameLabel->setText("Touch event propagation"); - testWidget.testDescriptionLabel->setText("Touch, move, and release your finger over the green widget."); + testWidget.testNameLabel->setText("QTouchEvent propagation test"); + testWidget.testDescriptionLabel->setText("Touch, hold, and release your finger on the blue widget."); + testWidget.redWidget->hide(); + // testWidget.blueWidget->setAttribute(Qt::WA_AcceptTouchEvents); testWidget.greenWidget->setAttribute(Qt::WA_AcceptTouchEvents); testWidget.greenWidget->acceptTouchBegin = true; testWidget.greenWidget->acceptTouchUpdate = true; @@ -47,6 +143,36 @@ void tst_ManualMultitouch::touchBeginPropagation() testWidget.showMaximized(); (void) qApp->exec(); + QVERIFY(!testWidget.blueWidget->seenTouchBegin); + QVERIFY(!testWidget.blueWidget->seenTouchUpdate); + QVERIFY(!testWidget.blueWidget->seenTouchEnd); + QVERIFY(!testWidget.blueWidget->seenMousePress); + QVERIFY(!testWidget.blueWidget->seenMouseMove); + QVERIFY(!testWidget.blueWidget->seenMouseRelease); + QVERIFY(testWidget.greenWidget->seenTouchBegin); + QVERIFY(testWidget.greenWidget->seenTouchUpdate); + QVERIFY(testWidget.greenWidget->seenTouchEnd); + QVERIFY(!testWidget.greenWidget->seenMousePress); + QVERIFY(!testWidget.greenWidget->seenMouseMove); + QVERIFY(!testWidget.greenWidget->seenMouseRelease); + + // again, but this time blueWidget should see the TouchBegin + testWidget.blueWidget->reset(); + testWidget.greenWidget->reset(); + testWidget.blueWidget->setAttribute(Qt::WA_AcceptTouchEvents); + testWidget.greenWidget->acceptTouchBegin = true; + testWidget.greenWidget->acceptTouchUpdate = true; + testWidget.greenWidget->acceptTouchEnd = true; + testWidget.greenWidget->closeWindowOnTouchEnd = true; + testWidget.showMaximized(); + + (void) qApp->exec(); + QVERIFY(testWidget.blueWidget->seenTouchBegin); + QVERIFY(!testWidget.blueWidget->seenTouchUpdate); + QVERIFY(!testWidget.blueWidget->seenTouchEnd); + QVERIFY(!testWidget.blueWidget->seenMousePress); + QVERIFY(!testWidget.blueWidget->seenMouseMove); + QVERIFY(!testWidget.blueWidget->seenMouseRelease); QVERIFY(testWidget.greenWidget->seenTouchBegin); QVERIFY(testWidget.greenWidget->seenTouchUpdate); QVERIFY(testWidget.greenWidget->seenTouchEnd); @@ -63,6 +189,12 @@ void tst_ManualMultitouch::touchBeginPropagation() testWidget.showMaximized(); (void) qApp->exec(); + QVERIFY(testWidget.blueWidget->seenTouchBegin); + QVERIFY(!testWidget.blueWidget->seenTouchUpdate); + QVERIFY(!testWidget.blueWidget->seenTouchEnd); + QVERIFY(!testWidget.blueWidget->seenMousePress); + QVERIFY(!testWidget.blueWidget->seenMouseMove); + QVERIFY(!testWidget.blueWidget->seenMouseRelease); QVERIFY(testWidget.greenWidget->seenTouchBegin); QVERIFY(testWidget.greenWidget->seenTouchUpdate); QVERIFY(testWidget.greenWidget->seenTouchEnd); @@ -79,6 +211,12 @@ void tst_ManualMultitouch::touchBeginPropagation() testWidget.showMaximized(); (void) qApp->exec(); + QVERIFY(testWidget.blueWidget->seenTouchBegin); + QVERIFY(!testWidget.blueWidget->seenTouchUpdate); + QVERIFY(!testWidget.blueWidget->seenTouchEnd); + QVERIFY(!testWidget.blueWidget->seenMousePress); + QVERIFY(!testWidget.blueWidget->seenMouseMove); + QVERIFY(!testWidget.blueWidget->seenMouseRelease); QVERIFY(testWidget.greenWidget->seenTouchBegin); QVERIFY(testWidget.greenWidget->seenTouchUpdate); QVERIFY(testWidget.greenWidget->seenTouchEnd); @@ -95,6 +233,12 @@ void tst_ManualMultitouch::touchBeginPropagation() testWidget.showMaximized(); (void) qApp->exec(); + QVERIFY(testWidget.blueWidget->seenTouchBegin); + QVERIFY(!testWidget.blueWidget->seenTouchUpdate); + QVERIFY(!testWidget.blueWidget->seenTouchEnd); + QVERIFY(!testWidget.blueWidget->seenMousePress); + QVERIFY(!testWidget.blueWidget->seenMouseMove); + QVERIFY(!testWidget.blueWidget->seenMouseRelease); QVERIFY(testWidget.greenWidget->seenTouchBegin); QVERIFY(testWidget.greenWidget->seenTouchUpdate); QVERIFY(testWidget.greenWidget->seenTouchEnd); diff --git a/tests/manual/qtouchevent/touchwidget.cpp b/tests/manual/qtouchevent/touchwidget.cpp index 54ca685..1e57c36 100644 --- a/tests/manual/qtouchevent/touchwidget.cpp +++ b/tests/manual/qtouchevent/touchwidget.cpp @@ -1,9 +1,10 @@ #include "touchwidget.h" -#include +#include +#include +#include #include - void TouchWidget::reset() { acceptTouchBegin @@ -69,7 +70,7 @@ bool TouchWidget::event(QEvent *event) case QEvent::MouseButtonRelease: seenMouseRelease = true; if (closeWindowOnMouseRelease) - window()->close(); + window()->close(); if (acceptMouseRelease) { event->accept(); return true; -- cgit v0.12 From ec2d71f0e4af0e0c286f0027d0242f456fdb2bb6 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Thu, 23 Apr 2009 17:57:46 +0200 Subject: Fix tests/manual/qtouchevent by choking mouse events even for ignored TouchUpdate and TouchEnd events. The behavior we want is that no mouse events are sent if the widget accepts the TouchBegin. --- src/gui/kernel/qapplication_p.h | 1 + src/gui/kernel/qapplication_win.cpp | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index ce7110d..91857ec 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -429,6 +429,7 @@ public: #endif QPointer currentMultitouchWidget; + bool currentMultitouchWidgetAcceptedTouchBegin; static void updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent); #if defined(Q_WS_WIN) diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 4878ea7..5a4efd6 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -4003,6 +4003,7 @@ void QApplicationPrivate::initializeMultitouch() CloseTouchInputHandle = static_cast(library.resolve("CloseTouchInputHandle")); currentMultitouchWidget = 0; + currentMultitouchWidgetAcceptedTouchBegin = false; touchInputIDToTouchPointID.clear(); allTouchPoints.clear(); currentTouchPoints.clear(); @@ -4106,6 +4107,9 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) if (!child) child = window; currentMultitouchWidget = child; + // if the TouchBegin handler recurses, we assume that means the event + // has been implicitly accepted and continue to send touch events + currentMultitouchWidgetAcceptedTouchBegin = true; } } @@ -4131,8 +4135,19 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) q->keyboardModifiers(), activeTouchPoints); updateTouchPointsForWidget(widget, &touchEvent); - bool res = QApplication::sendSpontaneousEvent(widget, &touchEvent); - return (qt_tabletChokeMouse = res && touchEvent.isAccepted()); + if (sendTouchBegin) { + bool res = QApplication::sendSpontaneousEvent(widget, &touchEvent); + qt_tabletChokeMouse + = currentMultitouchWidgetAcceptedTouchBegin + = (res && touchEvent.isAccepted()); + } else if (currentMultitouchWidgetAcceptedTouchBegin) { + (void) QApplication::sendSpontaneousEvent(widget, &touchEvent); + qt_tabletChokeMouse = true; + } else { + qt_tabletChokeMouse = false; + } + + return qt_tabletChokeMouse; } return false; -- cgit v0.12 From 34788b2cb7af9e515fe9de5c4dc81744dda68d1e Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Fri, 24 Apr 2009 12:41:44 +0200 Subject: Test that accepting the TouchBegin stops propagation --- tests/manual/qtouchevent/main.cpp | 106 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 103 insertions(+), 3 deletions(-) diff --git a/tests/manual/qtouchevent/main.cpp b/tests/manual/qtouchevent/main.cpp index 7ed9b15..a66a546 100644 --- a/tests/manual/qtouchevent/main.cpp +++ b/tests/manual/qtouchevent/main.cpp @@ -129,13 +129,110 @@ void tst_ManualMultitouch::basicEventHandling() void tst_ManualMultitouch::touchEventPropagation() { - // first, make sure the greenWidget gets TouchBegin even though blueWidget is not touch aware MultitouchTestWidget testWidget; testWidget.testNameLabel->setText("QTouchEvent propagation test"); testWidget.testDescriptionLabel->setText("Touch, hold, and release your finger on the blue widget."); - testWidget.redWidget->hide(); - // testWidget.blueWidget->setAttribute(Qt::WA_AcceptTouchEvents); + testWidget.redWidget->hide(); + + // test that accepting the TouchBegin event on the + // blueWidget stops propagation to the greenWidget + testWidget.blueWidget->setAttribute(Qt::WA_AcceptTouchEvents); testWidget.greenWidget->setAttribute(Qt::WA_AcceptTouchEvents); + testWidget.blueWidget->acceptTouchBegin = true; + testWidget.blueWidget->acceptTouchUpdate = true; + testWidget.blueWidget->acceptTouchEnd = true; + testWidget.blueWidget->closeWindowOnTouchEnd = true; + testWidget.showMaximized(); + + (void) qApp->exec(); + QVERIFY(testWidget.blueWidget->seenTouchBegin); + QVERIFY(testWidget.blueWidget->seenTouchUpdate); + QVERIFY(testWidget.blueWidget->seenTouchEnd); + QVERIFY(!testWidget.blueWidget->seenMousePress); + QVERIFY(!testWidget.blueWidget->seenMouseMove); + QVERIFY(!testWidget.blueWidget->seenMouseRelease); + QVERIFY(!testWidget.greenWidget->seenTouchBegin); + QVERIFY(!testWidget.greenWidget->seenTouchUpdate); + QVERIFY(!testWidget.greenWidget->seenTouchEnd); + QVERIFY(!testWidget.greenWidget->seenMousePress); + QVERIFY(!testWidget.greenWidget->seenMouseMove); + QVERIFY(!testWidget.greenWidget->seenMouseRelease); + + // ignoring TouchEnd + testWidget.blueWidget->reset(); + testWidget.greenWidget->reset(); + testWidget.blueWidget->acceptTouchBegin = true; + testWidget.blueWidget->acceptTouchUpdate = true; + // testWidget.blueWidget->acceptTouchEnd = true; + testWidget.blueWidget->closeWindowOnTouchEnd = true; + testWidget.showMaximized(); + + (void) qApp->exec(); + QVERIFY(testWidget.blueWidget->seenTouchBegin); + QVERIFY(testWidget.blueWidget->seenTouchUpdate); + QVERIFY(testWidget.blueWidget->seenTouchEnd); + QVERIFY(!testWidget.blueWidget->seenMousePress); + QVERIFY(!testWidget.blueWidget->seenMouseMove); + QVERIFY(!testWidget.blueWidget->seenMouseRelease); + QVERIFY(!testWidget.greenWidget->seenTouchBegin); + QVERIFY(!testWidget.greenWidget->seenTouchUpdate); + QVERIFY(!testWidget.greenWidget->seenTouchEnd); + QVERIFY(!testWidget.greenWidget->seenMousePress); + QVERIFY(!testWidget.greenWidget->seenMouseMove); + QVERIFY(!testWidget.greenWidget->seenMouseRelease); + + // ignoring TouchUpdate + testWidget.blueWidget->reset(); + testWidget.greenWidget->reset(); + testWidget.blueWidget->acceptTouchBegin = true; + // testWidget.blueWidget->acceptTouchUpdate = true; + testWidget.blueWidget->acceptTouchEnd = true; + testWidget.blueWidget->closeWindowOnTouchEnd = true; + testWidget.showMaximized(); + + (void) qApp->exec(); + QVERIFY(testWidget.blueWidget->seenTouchBegin); + QVERIFY(testWidget.blueWidget->seenTouchUpdate); + QVERIFY(testWidget.blueWidget->seenTouchEnd); + QVERIFY(!testWidget.blueWidget->seenMousePress); + QVERIFY(!testWidget.blueWidget->seenMouseMove); + QVERIFY(!testWidget.blueWidget->seenMouseRelease); + QVERIFY(!testWidget.greenWidget->seenTouchBegin); + QVERIFY(!testWidget.greenWidget->seenTouchUpdate); + QVERIFY(!testWidget.greenWidget->seenTouchEnd); + QVERIFY(!testWidget.greenWidget->seenMousePress); + QVERIFY(!testWidget.greenWidget->seenMouseMove); + QVERIFY(!testWidget.greenWidget->seenMouseRelease); + + // ignoring TouchUpdate and TouchEnd + testWidget.blueWidget->reset(); + testWidget.greenWidget->reset(); + testWidget.blueWidget->acceptTouchBegin = true; + // testWidget.blueWidget->acceptTouchUpdate = true; + // testWidget.blueWidget->acceptTouchEnd = true; + testWidget.blueWidget->closeWindowOnTouchEnd = true; + testWidget.showMaximized(); + + (void) qApp->exec(); + QVERIFY(testWidget.blueWidget->seenTouchBegin); + QVERIFY(testWidget.blueWidget->seenTouchUpdate); + QVERIFY(testWidget.blueWidget->seenTouchEnd); + QVERIFY(!testWidget.blueWidget->seenMousePress); + QVERIFY(!testWidget.blueWidget->seenMouseMove); + QVERIFY(!testWidget.blueWidget->seenMouseRelease); + QVERIFY(!testWidget.greenWidget->seenTouchBegin); + QVERIFY(!testWidget.greenWidget->seenTouchUpdate); + QVERIFY(!testWidget.greenWidget->seenTouchEnd); + QVERIFY(!testWidget.greenWidget->seenMousePress); + QVERIFY(!testWidget.greenWidget->seenMouseMove); + QVERIFY(!testWidget.greenWidget->seenMouseRelease); + + // repeat the test above, now ignoring touch events in the + // blueWidget, they should be propagated to the greenWidget + testWidget.blueWidget->setAttribute(Qt::WA_AcceptTouchEvents, false); + testWidget.greenWidget->setAttribute(Qt::WA_AcceptTouchEvents); + testWidget.blueWidget->reset(); + testWidget.greenWidget->reset(); testWidget.greenWidget->acceptTouchBegin = true; testWidget.greenWidget->acceptTouchUpdate = true; testWidget.greenWidget->acceptTouchEnd = true; @@ -181,6 +278,7 @@ void tst_ManualMultitouch::touchEventPropagation() QVERIFY(!testWidget.greenWidget->seenMouseRelease); // again, ignoring the TouchEnd + testWidget.blueWidget->reset(); testWidget.greenWidget->reset(); testWidget.greenWidget->acceptTouchBegin = true; testWidget.greenWidget->acceptTouchUpdate = true; @@ -203,6 +301,7 @@ void tst_ManualMultitouch::touchEventPropagation() QVERIFY(!testWidget.greenWidget->seenMouseRelease); // again, ignoring TouchUpdates + testWidget.blueWidget->reset(); testWidget.greenWidget->reset(); testWidget.greenWidget->acceptTouchBegin = true; // testWidget.greenWidget->acceptTouchUpdate = true; @@ -225,6 +324,7 @@ void tst_ManualMultitouch::touchEventPropagation() QVERIFY(!testWidget.greenWidget->seenMouseRelease); // last time, ignoring TouchUpdates and TouchEnd + testWidget.blueWidget->reset(); testWidget.greenWidget->reset(); testWidget.greenWidget->acceptTouchBegin = true; // testWidget.greenWidget->acceptTouchUpdate = true; -- cgit v0.12 From 76b3d0526b524b79603e4e1b337c32f3bfcc6340 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Fri, 24 Apr 2009 12:55:48 +0200 Subject: change the layout a bit in the test's form --- tests/manual/qtouchevent/form.ui | 3672 +++++++++++++++++++------------------- 1 file changed, 1838 insertions(+), 1834 deletions(-) diff --git a/tests/manual/qtouchevent/form.ui b/tests/manual/qtouchevent/form.ui index 6cf4cba..4c2da3a 100644 --- a/tests/manual/qtouchevent/form.ui +++ b/tests/manual/qtouchevent/form.ui @@ -13,924 +13,8 @@ Form - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - 0 - - - - - - - 170 - 0 - 0 - - - - - - - 255 - 0 - 0 - - - - - - - 212 - 0 - 0 - - - - - - - 85 - 0 - 0 - - - - - - - 113 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 170 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 212 - 127 - 127 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 0 - 0 - 0 - - - - - - - 170 - 0 - 0 - - - - - - - 255 - 0 - 0 - - - - - - - 212 - 0 - 0 - - - - - - - 85 - 0 - 0 - - - - - - - 113 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 170 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 212 - 127 - 127 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 85 - 0 - 0 - - - - - - - 170 - 0 - 0 - - - - - - - 255 - 0 - 0 - - - - - - - 212 - 0 - 0 - - - - - - - 85 - 0 - 0 - - - - - - - 113 - 0 - 0 - - - - - - - 85 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 85 - 0 - 0 - - - - - - - 170 - 0 - 0 - - - - - - - 170 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 170 - 0 - 0 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - true - - - - - - Qt::Vertical - - - - 0 - 0 - - - - - - - - Qt::Horizontal - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - 180 - 120 - - - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - true - - - - - - - Qt::Horizontal - - - - 0 - 0 - - - - - - - - Qt::Vertical - - - - 0 - 0 - - - - - - - - + + @@ -944,7 +28,7 @@ - + @@ -956,921 +40,1841 @@ - - - - - 0 - 0 - - - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 255 - 0 - - - - - - - 0 - 212 - 0 - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 113 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 127 - 212 - 127 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 255 - 0 - - - - - - - 0 - 212 - 0 - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 113 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 127 - 212 - 127 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 255 - 0 - - - - - - - 0 - 212 - 0 - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 113 - 0 - - - - - - - 0 - 85 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 85 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 170 - 0 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - true - - - - - - Qt::Horizontal - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - 180 - 120 - - - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 170 - - - - - - - 0 - 0 - 255 - - - - - - - 0 - 0 - 212 - - - - - - - 0 - 0 - 85 - - - - - - - 0 - 0 - 113 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 170 - - - - - - - 0 - 0 - 0 - - - - - - - 127 - 127 - 212 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 170 - - - - - - - 0 - 0 - 255 - - - - - - - 0 - 0 - 212 - - - - - - - 0 - 0 - 85 - - - - - - - 0 - 0 - 113 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 170 - - - - - - - 0 - 0 - 0 - - - - - - - 127 - 127 - 212 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 0 - 0 - 85 - - - - - - - 0 - 0 - 170 - - - - - - - 0 - 0 - 255 - - - - - - - 0 - 0 - 212 - - - - - - - 0 - 0 - 85 - - - - - - - 0 - 0 - 113 - - - - - - - 0 - 0 - 85 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 85 - - - - - - - 0 - 0 - 170 - - - - - - - 0 - 0 - 170 - - - - - - - 0 - 0 - 0 - - - - - - - 0 - 0 - 170 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - true - - - - - - - Qt::Horizontal - - - - 0 - 0 - - - - - - - - Qt::Vertical - - - - 0 - 0 - - - - - - - - Qt::Vertical - - - - 0 - 0 - - - - - - + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 255 + 0 + + + + + + + 0 + 212 + 0 + + + + + + + 0 + 85 + 0 + + + + + + + 0 + 113 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 127 + 212 + 127 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 255 + 0 + + + + + + + 0 + 212 + 0 + + + + + + + 0 + 85 + 0 + + + + + + + 0 + 113 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 127 + 212 + 127 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 85 + 0 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 255 + 0 + + + + + + + 0 + 212 + 0 + + + + + + + 0 + 85 + 0 + + + + + + + 0 + 113 + 0 + + + + + + + 0 + 85 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 85 + 0 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 170 + 0 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + true + + + + + + Qt::Horizontal + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + 180 + 120 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 170 + + + + + + + 0 + 0 + 255 + + + + + + + 0 + 0 + 212 + + + + + + + 0 + 0 + 85 + + + + + + + 0 + 0 + 113 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 170 + + + + + + + 0 + 0 + 0 + + + + + + + 127 + 127 + 212 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 170 + + + + + + + 0 + 0 + 255 + + + + + + + 0 + 0 + 212 + + + + + + + 0 + 0 + 85 + + + + + + + 0 + 0 + 113 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 170 + + + + + + + 0 + 0 + 0 + + + + + + + 127 + 127 + 212 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 85 + + + + + + + 0 + 0 + 170 + + + + + + + 0 + 0 + 255 + + + + + + + 0 + 0 + 212 + + + + + + + 0 + 0 + 85 + + + + + + + 0 + 0 + 113 + + + + + + + 0 + 0 + 85 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 85 + + + + + + + 0 + 0 + 170 + + + + + + + 0 + 0 + 170 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 170 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + true + + + + + + + Qt::Horizontal + + + + 0 + 0 + + + + + + + + Qt::Vertical + + + + 0 + 0 + + + + + + + + Qt::Vertical + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 212 + 0 + 0 + + + + + + + 85 + 0 + 0 + + + + + + + 113 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 170 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 212 + 127 + 127 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 212 + 0 + 0 + + + + + + + 85 + 0 + 0 + + + + + + + 113 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 170 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 212 + 127 + 127 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 85 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 212 + 0 + 0 + + + + + + + 85 + 0 + 0 + + + + + + + 113 + 0 + 0 + + + + + + + 85 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 85 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + true + + + + + + Qt::Vertical + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + 180 + 120 + + + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + true + + + + + + + Qt::Horizontal + + + + 0 + 0 + + + + + + + + Qt::Vertical + + + + 0 + 0 + + + + + + + + -- cgit v0.12 From ed2e1e64d922e3e531984d099a800515037c89f6 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Fri, 24 Apr 2009 13:00:31 +0200 Subject: Use a different widget color to indicate that we are testing different things --- tests/manual/qtouchevent/main.cpp | 196 +++++++++++++++++++------------------- 1 file changed, 100 insertions(+), 96 deletions(-) diff --git a/tests/manual/qtouchevent/main.cpp b/tests/manual/qtouchevent/main.cpp index a66a546..05fdc44 100644 --- a/tests/manual/qtouchevent/main.cpp +++ b/tests/manual/qtouchevent/main.cpp @@ -130,7 +130,7 @@ void tst_ManualMultitouch::basicEventHandling() void tst_ManualMultitouch::touchEventPropagation() { MultitouchTestWidget testWidget; - testWidget.testNameLabel->setText("QTouchEvent propagation test"); + testWidget.testNameLabel->setText("QTouchEvent propagation test, Blue blocks Green"); testWidget.testDescriptionLabel->setText("Touch, hold, and release your finger on the blue widget."); testWidget.redWidget->hide(); @@ -228,123 +228,127 @@ void tst_ManualMultitouch::touchEventPropagation() QVERIFY(!testWidget.greenWidget->seenMouseRelease); // repeat the test above, now ignoring touch events in the - // blueWidget, they should be propagated to the greenWidget - testWidget.blueWidget->setAttribute(Qt::WA_AcceptTouchEvents, false); - testWidget.greenWidget->setAttribute(Qt::WA_AcceptTouchEvents); - testWidget.blueWidget->reset(); - testWidget.greenWidget->reset(); - testWidget.greenWidget->acceptTouchBegin = true; - testWidget.greenWidget->acceptTouchUpdate = true; - testWidget.greenWidget->acceptTouchEnd = true; - testWidget.greenWidget->closeWindowOnTouchEnd = true; + // greyWidget, they should be propagated to the redWidget + testWidget.testNameLabel->setText("QTouchEvent propagation test, Red handles Grey's ignored events"); + testWidget.testDescriptionLabel->setText("Touch, hold, and release your finger on the grey widget."); + testWidget.greenWidget->hide(); + testWidget.redWidget->show(); + testWidget.greyWidget->setAttribute(Qt::WA_AcceptTouchEvents, false); + testWidget.redWidget->setAttribute(Qt::WA_AcceptTouchEvents); + testWidget.greyWidget->reset(); + testWidget.redWidget->reset(); + testWidget.redWidget->acceptTouchBegin = true; + testWidget.redWidget->acceptTouchUpdate = true; + testWidget.redWidget->acceptTouchEnd = true; + testWidget.redWidget->closeWindowOnTouchEnd = true; testWidget.showMaximized(); (void) qApp->exec(); - QVERIFY(!testWidget.blueWidget->seenTouchBegin); - QVERIFY(!testWidget.blueWidget->seenTouchUpdate); - QVERIFY(!testWidget.blueWidget->seenTouchEnd); - QVERIFY(!testWidget.blueWidget->seenMousePress); - QVERIFY(!testWidget.blueWidget->seenMouseMove); - QVERIFY(!testWidget.blueWidget->seenMouseRelease); - QVERIFY(testWidget.greenWidget->seenTouchBegin); - QVERIFY(testWidget.greenWidget->seenTouchUpdate); - QVERIFY(testWidget.greenWidget->seenTouchEnd); - QVERIFY(!testWidget.greenWidget->seenMousePress); - QVERIFY(!testWidget.greenWidget->seenMouseMove); - QVERIFY(!testWidget.greenWidget->seenMouseRelease); - - // again, but this time blueWidget should see the TouchBegin - testWidget.blueWidget->reset(); - testWidget.greenWidget->reset(); - testWidget.blueWidget->setAttribute(Qt::WA_AcceptTouchEvents); - testWidget.greenWidget->acceptTouchBegin = true; - testWidget.greenWidget->acceptTouchUpdate = true; - testWidget.greenWidget->acceptTouchEnd = true; - testWidget.greenWidget->closeWindowOnTouchEnd = true; + QVERIFY(!testWidget.greyWidget->seenTouchBegin); + QVERIFY(!testWidget.greyWidget->seenTouchUpdate); + QVERIFY(!testWidget.greyWidget->seenTouchEnd); + QVERIFY(!testWidget.greyWidget->seenMousePress); + QVERIFY(!testWidget.greyWidget->seenMouseMove); + QVERIFY(!testWidget.greyWidget->seenMouseRelease); + QVERIFY(testWidget.redWidget->seenTouchBegin); + QVERIFY(testWidget.redWidget->seenTouchUpdate); + QVERIFY(testWidget.redWidget->seenTouchEnd); + QVERIFY(!testWidget.redWidget->seenMousePress); + QVERIFY(!testWidget.redWidget->seenMouseMove); + QVERIFY(!testWidget.redWidget->seenMouseRelease); + + // again, but this time greyWidget should see the TouchBegin + testWidget.greyWidget->reset(); + testWidget.redWidget->reset(); + testWidget.greyWidget->setAttribute(Qt::WA_AcceptTouchEvents); + testWidget.redWidget->acceptTouchBegin = true; + testWidget.redWidget->acceptTouchUpdate = true; + testWidget.redWidget->acceptTouchEnd = true; + testWidget.redWidget->closeWindowOnTouchEnd = true; testWidget.showMaximized(); (void) qApp->exec(); - QVERIFY(testWidget.blueWidget->seenTouchBegin); - QVERIFY(!testWidget.blueWidget->seenTouchUpdate); - QVERIFY(!testWidget.blueWidget->seenTouchEnd); - QVERIFY(!testWidget.blueWidget->seenMousePress); - QVERIFY(!testWidget.blueWidget->seenMouseMove); - QVERIFY(!testWidget.blueWidget->seenMouseRelease); - QVERIFY(testWidget.greenWidget->seenTouchBegin); - QVERIFY(testWidget.greenWidget->seenTouchUpdate); - QVERIFY(testWidget.greenWidget->seenTouchEnd); - QVERIFY(!testWidget.greenWidget->seenMousePress); - QVERIFY(!testWidget.greenWidget->seenMouseMove); - QVERIFY(!testWidget.greenWidget->seenMouseRelease); + QVERIFY(testWidget.greyWidget->seenTouchBegin); + QVERIFY(!testWidget.greyWidget->seenTouchUpdate); + QVERIFY(!testWidget.greyWidget->seenTouchEnd); + QVERIFY(!testWidget.greyWidget->seenMousePress); + QVERIFY(!testWidget.greyWidget->seenMouseMove); + QVERIFY(!testWidget.greyWidget->seenMouseRelease); + QVERIFY(testWidget.redWidget->seenTouchBegin); + QVERIFY(testWidget.redWidget->seenTouchUpdate); + QVERIFY(testWidget.redWidget->seenTouchEnd); + QVERIFY(!testWidget.redWidget->seenMousePress); + QVERIFY(!testWidget.redWidget->seenMouseMove); + QVERIFY(!testWidget.redWidget->seenMouseRelease); // again, ignoring the TouchEnd - testWidget.blueWidget->reset(); - testWidget.greenWidget->reset(); - testWidget.greenWidget->acceptTouchBegin = true; - testWidget.greenWidget->acceptTouchUpdate = true; - // testWidget.greenWidget->acceptTouchEnd = true; - testWidget.greenWidget->closeWindowOnTouchEnd = true; + testWidget.greyWidget->reset(); + testWidget.redWidget->reset(); + testWidget.redWidget->acceptTouchBegin = true; + testWidget.redWidget->acceptTouchUpdate = true; + // testWidget.redWidget->acceptTouchEnd = true; + testWidget.redWidget->closeWindowOnTouchEnd = true; testWidget.showMaximized(); (void) qApp->exec(); - QVERIFY(testWidget.blueWidget->seenTouchBegin); - QVERIFY(!testWidget.blueWidget->seenTouchUpdate); - QVERIFY(!testWidget.blueWidget->seenTouchEnd); - QVERIFY(!testWidget.blueWidget->seenMousePress); - QVERIFY(!testWidget.blueWidget->seenMouseMove); - QVERIFY(!testWidget.blueWidget->seenMouseRelease); - QVERIFY(testWidget.greenWidget->seenTouchBegin); - QVERIFY(testWidget.greenWidget->seenTouchUpdate); - QVERIFY(testWidget.greenWidget->seenTouchEnd); - QVERIFY(!testWidget.greenWidget->seenMousePress); - QVERIFY(!testWidget.greenWidget->seenMouseMove); - QVERIFY(!testWidget.greenWidget->seenMouseRelease); + QVERIFY(testWidget.greyWidget->seenTouchBegin); + QVERIFY(!testWidget.greyWidget->seenTouchUpdate); + QVERIFY(!testWidget.greyWidget->seenTouchEnd); + QVERIFY(!testWidget.greyWidget->seenMousePress); + QVERIFY(!testWidget.greyWidget->seenMouseMove); + QVERIFY(!testWidget.greyWidget->seenMouseRelease); + QVERIFY(testWidget.redWidget->seenTouchBegin); + QVERIFY(testWidget.redWidget->seenTouchUpdate); + QVERIFY(testWidget.redWidget->seenTouchEnd); + QVERIFY(!testWidget.redWidget->seenMousePress); + QVERIFY(!testWidget.redWidget->seenMouseMove); + QVERIFY(!testWidget.redWidget->seenMouseRelease); // again, ignoring TouchUpdates - testWidget.blueWidget->reset(); - testWidget.greenWidget->reset(); - testWidget.greenWidget->acceptTouchBegin = true; - // testWidget.greenWidget->acceptTouchUpdate = true; - testWidget.greenWidget->acceptTouchEnd = true; - testWidget.greenWidget->closeWindowOnTouchEnd = true; + testWidget.greyWidget->reset(); + testWidget.redWidget->reset(); + testWidget.redWidget->acceptTouchBegin = true; + // testWidget.redWidget->acceptTouchUpdate = true; + testWidget.redWidget->acceptTouchEnd = true; + testWidget.redWidget->closeWindowOnTouchEnd = true; testWidget.showMaximized(); (void) qApp->exec(); - QVERIFY(testWidget.blueWidget->seenTouchBegin); - QVERIFY(!testWidget.blueWidget->seenTouchUpdate); - QVERIFY(!testWidget.blueWidget->seenTouchEnd); - QVERIFY(!testWidget.blueWidget->seenMousePress); - QVERIFY(!testWidget.blueWidget->seenMouseMove); - QVERIFY(!testWidget.blueWidget->seenMouseRelease); - QVERIFY(testWidget.greenWidget->seenTouchBegin); - QVERIFY(testWidget.greenWidget->seenTouchUpdate); - QVERIFY(testWidget.greenWidget->seenTouchEnd); - QVERIFY(!testWidget.greenWidget->seenMousePress); - QVERIFY(!testWidget.greenWidget->seenMouseMove); - QVERIFY(!testWidget.greenWidget->seenMouseRelease); + QVERIFY(testWidget.greyWidget->seenTouchBegin); + QVERIFY(!testWidget.greyWidget->seenTouchUpdate); + QVERIFY(!testWidget.greyWidget->seenTouchEnd); + QVERIFY(!testWidget.greyWidget->seenMousePress); + QVERIFY(!testWidget.greyWidget->seenMouseMove); + QVERIFY(!testWidget.greyWidget->seenMouseRelease); + QVERIFY(testWidget.redWidget->seenTouchBegin); + QVERIFY(testWidget.redWidget->seenTouchUpdate); + QVERIFY(testWidget.redWidget->seenTouchEnd); + QVERIFY(!testWidget.redWidget->seenMousePress); + QVERIFY(!testWidget.redWidget->seenMouseMove); + QVERIFY(!testWidget.redWidget->seenMouseRelease); // last time, ignoring TouchUpdates and TouchEnd - testWidget.blueWidget->reset(); - testWidget.greenWidget->reset(); - testWidget.greenWidget->acceptTouchBegin = true; - // testWidget.greenWidget->acceptTouchUpdate = true; - // testWidget.greenWidget->acceptTouchEnd = true; - testWidget.greenWidget->closeWindowOnTouchEnd = true; + testWidget.greyWidget->reset(); + testWidget.redWidget->reset(); + testWidget.redWidget->acceptTouchBegin = true; + // testWidget.redWidget->acceptTouchUpdate = true; + // testWidget.redWidget->acceptTouchEnd = true; + testWidget.redWidget->closeWindowOnTouchEnd = true; testWidget.showMaximized(); (void) qApp->exec(); - QVERIFY(testWidget.blueWidget->seenTouchBegin); - QVERIFY(!testWidget.blueWidget->seenTouchUpdate); - QVERIFY(!testWidget.blueWidget->seenTouchEnd); - QVERIFY(!testWidget.blueWidget->seenMousePress); - QVERIFY(!testWidget.blueWidget->seenMouseMove); + QVERIFY(testWidget.greyWidget->seenTouchBegin); + QVERIFY(!testWidget.greyWidget->seenTouchUpdate); + QVERIFY(!testWidget.greyWidget->seenTouchEnd); + QVERIFY(!testWidget.greyWidget->seenMousePress); + QVERIFY(!testWidget.greyWidget->seenMouseMove); QVERIFY(!testWidget.blueWidget->seenMouseRelease); - QVERIFY(testWidget.greenWidget->seenTouchBegin); - QVERIFY(testWidget.greenWidget->seenTouchUpdate); - QVERIFY(testWidget.greenWidget->seenTouchEnd); - QVERIFY(!testWidget.greenWidget->seenMousePress); - QVERIFY(!testWidget.greenWidget->seenMouseMove); - QVERIFY(!testWidget.greenWidget->seenMouseRelease); + QVERIFY(testWidget.redWidget->seenTouchBegin); + QVERIFY(testWidget.redWidget->seenTouchUpdate); + QVERIFY(testWidget.redWidget->seenTouchEnd); + QVERIFY(!testWidget.redWidget->seenMousePress); + QVERIFY(!testWidget.redWidget->seenMouseMove); + QVERIFY(!testWidget.redWidget->seenMouseRelease); } QTEST_MAIN(tst_ManualMultitouch) -- cgit v0.12 From 96d2094b48db6cccd7a0fb34a778bd3e71ba43b4 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Mon, 27 Apr 2009 13:21:12 +0200 Subject: add basic multi-touch event handling test, split existing tests into more logical pieces --- tests/manual/qtouchevent/main.cpp | 130 +++++++++++++++++++++++++------ tests/manual/qtouchevent/touchwidget.cpp | 4 + tests/manual/qtouchevent/touchwidget.h | 1 + 3 files changed, 110 insertions(+), 25 deletions(-) diff --git a/tests/manual/qtouchevent/main.cpp b/tests/manual/qtouchevent/main.cpp index 05fdc44..8b28967 100644 --- a/tests/manual/qtouchevent/main.cpp +++ b/tests/manual/qtouchevent/main.cpp @@ -32,8 +32,11 @@ public: ~tst_ManualMultitouch(); private slots: - void basicEventHandling(); - void touchEventPropagation(); + void ignoringTouchEventsEmulatesMouseEvents(); + void basicSingleTouchEventHandling(); + void basicMultiTouchEventHandling(); + void acceptingTouchBeginStopsPropagation(); + void ignoringTouchBeginPropagatesToParent(); }; tst_ManualMultitouch::tst_ManualMultitouch() @@ -42,17 +45,16 @@ tst_ManualMultitouch::tst_ManualMultitouch() tst_ManualMultitouch::~tst_ManualMultitouch() { } -void tst_ManualMultitouch::basicEventHandling() +void tst_ManualMultitouch::ignoringTouchEventsEmulatesMouseEvents() { // first, make sure that we get mouse events when not enabling touch events MultitouchTestWidget testWidget; - testWidget.testNameLabel->setText("Basic QTouchEvent handling test"); + testWidget.testNameLabel->setText("Mouse Event Emulation Test"); testWidget.testDescriptionLabel->setText("Touch, hold, and release your finger on the green widget."); testWidget.redWidget->hide(); testWidget.blueWidget->hide(); testWidget.greenWidget->closeWindowOnMouseRelease = true; testWidget.showMaximized(); - (void) qApp->exec(); QVERIFY(!testWidget.greenWidget->seenTouchBegin); QVERIFY(!testWidget.greenWidget->seenTouchUpdate); @@ -61,15 +63,34 @@ void tst_ManualMultitouch::basicEventHandling() // QVERIFY(testWidget.greenWidget->seenMouseMove); QVERIFY(testWidget.greenWidget->seenMouseRelease); - // now enable touch and make sure we get the touch events + // enable touch, but don't accept the events testWidget.greenWidget->reset(); testWidget.greenWidget->setAttribute(Qt::WA_AcceptTouchEvents); + testWidget.greenWidget->closeWindowOnMouseRelease = true; + testWidget.showMaximized(); + (void) qApp->exec(); + QVERIFY(testWidget.greenWidget->seenTouchBegin); + QVERIFY(!testWidget.greenWidget->seenTouchUpdate); + QVERIFY(!testWidget.greenWidget->seenTouchEnd); + QVERIFY(testWidget.greenWidget->seenMousePress); + // QVERIFY(testWidget.greenWidget->seenMouseMove); + QVERIFY(testWidget.greenWidget->seenMouseRelease); +} + +void tst_ManualMultitouch::basicSingleTouchEventHandling() +{ + // now enable touch and make sure we get the touch events + MultitouchTestWidget testWidget; + testWidget.testNameLabel->setText("Basic Single-Touch Event Handling Test"); + testWidget.testDescriptionLabel->setText("Touch, hold, and release your finger on the green widget."); + testWidget.redWidget->hide(); + testWidget.blueWidget->hide(); + testWidget.greenWidget->setAttribute(Qt::WA_AcceptTouchEvents); testWidget.greenWidget->acceptTouchBegin = true; testWidget.greenWidget->acceptTouchUpdate = true; testWidget.greenWidget->acceptTouchEnd = true; testWidget.greenWidget->closeWindowOnTouchEnd = true; testWidget.showMaximized(); - (void) qApp->exec(); QVERIFY(testWidget.greenWidget->seenTouchBegin && testWidget.greenWidget->seenTouchUpdate @@ -85,7 +106,6 @@ void tst_ManualMultitouch::basicEventHandling() // testWidget.greenWidget->acceptTouchEnd = true; testWidget.greenWidget->closeWindowOnTouchEnd = true; testWidget.showMaximized(); - (void) qApp->exec(); QVERIFY(testWidget.greenWidget->seenTouchBegin); QVERIFY(testWidget.greenWidget->seenTouchUpdate); @@ -101,7 +121,6 @@ void tst_ManualMultitouch::basicEventHandling() testWidget.greenWidget->acceptTouchEnd = true; testWidget.greenWidget->closeWindowOnTouchEnd = true; testWidget.showMaximized(); - (void) qApp->exec(); QVERIFY(testWidget.greenWidget->seenTouchBegin); QVERIFY(testWidget.greenWidget->seenTouchUpdate); @@ -117,7 +136,6 @@ void tst_ManualMultitouch::basicEventHandling() // testWidget.greenWidget->acceptTouchEnd = true; testWidget.greenWidget->closeWindowOnTouchEnd = true; testWidget.showMaximized(); - (void) qApp->exec(); QVERIFY(testWidget.greenWidget->seenTouchBegin); QVERIFY(testWidget.greenWidget->seenTouchUpdate); @@ -127,15 +145,83 @@ void tst_ManualMultitouch::basicEventHandling() QVERIFY(!testWidget.greenWidget->seenMouseRelease); } -void tst_ManualMultitouch::touchEventPropagation() +void tst_ManualMultitouch::basicMultiTouchEventHandling() { + // repeat, this time looking for multiple fingers MultitouchTestWidget testWidget; - testWidget.testNameLabel->setText("QTouchEvent propagation test, Blue blocks Green"); - testWidget.testDescriptionLabel->setText("Touch, hold, and release your finger on the blue widget."); - testWidget.redWidget->hide(); + testWidget.testNameLabel->setText("Basic Multi-Touch Event Handling Test"); + testWidget.testDescriptionLabel->setText("Touch, hold, and release several fingers on the red widget."); + testWidget.greenWidget->hide(); + testWidget.greyWidget->hide(); + testWidget.redWidget->setAttribute(Qt::WA_AcceptTouchEvents); + testWidget.redWidget->acceptTouchBegin = true; + testWidget.redWidget->acceptTouchUpdate = true; + testWidget.redWidget->acceptTouchEnd = true; + testWidget.redWidget->closeWindowOnTouchEnd = true; + testWidget.showMaximized(); + (void) qApp->exec(); + QVERIFY(testWidget.redWidget->seenTouchBegin); + QVERIFY(testWidget.redWidget->seenTouchUpdate); + QVERIFY(testWidget.redWidget->seenTouchEnd); + QVERIFY(testWidget.redWidget->touchPointCount > 1); + QVERIFY(!testWidget.greenWidget->seenMousePress); + QVERIFY(!testWidget.greenWidget->seenMouseMove); + QVERIFY(!testWidget.greenWidget->seenMouseRelease); + testWidget.redWidget->reset(); + testWidget.redWidget->acceptTouchBegin = true; + // testWidget.redWidget->acceptTouchUpdate = true; + testWidget.redWidget->acceptTouchEnd = true; + testWidget.redWidget->closeWindowOnTouchEnd = true; + testWidget.showMaximized(); + (void) qApp->exec(); + QVERIFY(testWidget.redWidget->seenTouchBegin); + QVERIFY(testWidget.redWidget->seenTouchUpdate); + QVERIFY(testWidget.redWidget->seenTouchEnd); + QVERIFY(testWidget.redWidget->touchPointCount > 1); + QVERIFY(!testWidget.greenWidget->seenMousePress); + QVERIFY(!testWidget.greenWidget->seenMouseMove); + QVERIFY(!testWidget.greenWidget->seenMouseRelease); + + testWidget.redWidget->reset(); + testWidget.redWidget->acceptTouchBegin = true; + testWidget.redWidget->acceptTouchUpdate = true; + // testWidget.redWidget->acceptTouchEnd = true; + testWidget.redWidget->closeWindowOnTouchEnd = true; + testWidget.showMaximized(); + (void) qApp->exec(); + QVERIFY(testWidget.redWidget->seenTouchBegin); + QVERIFY(testWidget.redWidget->seenTouchUpdate); + QVERIFY(testWidget.redWidget->seenTouchEnd); + QVERIFY(testWidget.redWidget->touchPointCount > 1); + QVERIFY(!testWidget.greenWidget->seenMousePress); + QVERIFY(!testWidget.greenWidget->seenMouseMove); + QVERIFY(!testWidget.greenWidget->seenMouseRelease); + + testWidget.redWidget->reset(); + testWidget.redWidget->acceptTouchBegin = true; + // testWidget.redWidget->acceptTouchUpdate = true; + // testWidget.redWidget->acceptTouchEnd = true; + testWidget.redWidget->closeWindowOnTouchEnd = true; + testWidget.showMaximized(); + (void) qApp->exec(); + QVERIFY(testWidget.redWidget->seenTouchBegin); + QVERIFY(testWidget.redWidget->seenTouchUpdate); + QVERIFY(testWidget.redWidget->seenTouchEnd); + QVERIFY(testWidget.redWidget->touchPointCount > 1); + QVERIFY(!testWidget.greenWidget->seenMousePress); + QVERIFY(!testWidget.greenWidget->seenMouseMove); + QVERIFY(!testWidget.greenWidget->seenMouseRelease); +} + +void tst_ManualMultitouch::acceptingTouchBeginStopsPropagation() +{ // test that accepting the TouchBegin event on the // blueWidget stops propagation to the greenWidget + MultitouchTestWidget testWidget; + testWidget.testNameLabel->setText("Touch Event Propagation Test: Accepting in Blue Blocks Green"); + testWidget.testDescriptionLabel->setText("Touch, hold, and release your finger on the blue widget."); + testWidget.redWidget->hide(); testWidget.blueWidget->setAttribute(Qt::WA_AcceptTouchEvents); testWidget.greenWidget->setAttribute(Qt::WA_AcceptTouchEvents); testWidget.blueWidget->acceptTouchBegin = true; @@ -143,7 +229,6 @@ void tst_ManualMultitouch::touchEventPropagation() testWidget.blueWidget->acceptTouchEnd = true; testWidget.blueWidget->closeWindowOnTouchEnd = true; testWidget.showMaximized(); - (void) qApp->exec(); QVERIFY(testWidget.blueWidget->seenTouchBegin); QVERIFY(testWidget.blueWidget->seenTouchUpdate); @@ -166,7 +251,6 @@ void tst_ManualMultitouch::touchEventPropagation() // testWidget.blueWidget->acceptTouchEnd = true; testWidget.blueWidget->closeWindowOnTouchEnd = true; testWidget.showMaximized(); - (void) qApp->exec(); QVERIFY(testWidget.blueWidget->seenTouchBegin); QVERIFY(testWidget.blueWidget->seenTouchUpdate); @@ -189,7 +273,6 @@ void tst_ManualMultitouch::touchEventPropagation() testWidget.blueWidget->acceptTouchEnd = true; testWidget.blueWidget->closeWindowOnTouchEnd = true; testWidget.showMaximized(); - (void) qApp->exec(); QVERIFY(testWidget.blueWidget->seenTouchBegin); QVERIFY(testWidget.blueWidget->seenTouchUpdate); @@ -212,7 +295,6 @@ void tst_ManualMultitouch::touchEventPropagation() // testWidget.blueWidget->acceptTouchEnd = true; testWidget.blueWidget->closeWindowOnTouchEnd = true; testWidget.showMaximized(); - (void) qApp->exec(); QVERIFY(testWidget.blueWidget->seenTouchBegin); QVERIFY(testWidget.blueWidget->seenTouchUpdate); @@ -226,13 +308,16 @@ void tst_ManualMultitouch::touchEventPropagation() QVERIFY(!testWidget.greenWidget->seenMousePress); QVERIFY(!testWidget.greenWidget->seenMouseMove); QVERIFY(!testWidget.greenWidget->seenMouseRelease); +} +void tst_ManualMultitouch::ignoringTouchBeginPropagatesToParent() +{ // repeat the test above, now ignoring touch events in the // greyWidget, they should be propagated to the redWidget - testWidget.testNameLabel->setText("QTouchEvent propagation test, Red handles Grey's ignored events"); + MultitouchTestWidget testWidget; + testWidget.testNameLabel->setText("Touch Event Propagation Test: Ignoring in Grey Propagates to Red"); testWidget.testDescriptionLabel->setText("Touch, hold, and release your finger on the grey widget."); testWidget.greenWidget->hide(); - testWidget.redWidget->show(); testWidget.greyWidget->setAttribute(Qt::WA_AcceptTouchEvents, false); testWidget.redWidget->setAttribute(Qt::WA_AcceptTouchEvents); testWidget.greyWidget->reset(); @@ -242,7 +327,6 @@ void tst_ManualMultitouch::touchEventPropagation() testWidget.redWidget->acceptTouchEnd = true; testWidget.redWidget->closeWindowOnTouchEnd = true; testWidget.showMaximized(); - (void) qApp->exec(); QVERIFY(!testWidget.greyWidget->seenTouchBegin); QVERIFY(!testWidget.greyWidget->seenTouchUpdate); @@ -266,7 +350,6 @@ void tst_ManualMultitouch::touchEventPropagation() testWidget.redWidget->acceptTouchEnd = true; testWidget.redWidget->closeWindowOnTouchEnd = true; testWidget.showMaximized(); - (void) qApp->exec(); QVERIFY(testWidget.greyWidget->seenTouchBegin); QVERIFY(!testWidget.greyWidget->seenTouchUpdate); @@ -289,7 +372,6 @@ void tst_ManualMultitouch::touchEventPropagation() // testWidget.redWidget->acceptTouchEnd = true; testWidget.redWidget->closeWindowOnTouchEnd = true; testWidget.showMaximized(); - (void) qApp->exec(); QVERIFY(testWidget.greyWidget->seenTouchBegin); QVERIFY(!testWidget.greyWidget->seenTouchUpdate); @@ -312,7 +394,6 @@ void tst_ManualMultitouch::touchEventPropagation() testWidget.redWidget->acceptTouchEnd = true; testWidget.redWidget->closeWindowOnTouchEnd = true; testWidget.showMaximized(); - (void) qApp->exec(); QVERIFY(testWidget.greyWidget->seenTouchBegin); QVERIFY(!testWidget.greyWidget->seenTouchUpdate); @@ -335,7 +416,6 @@ void tst_ManualMultitouch::touchEventPropagation() // testWidget.redWidget->acceptTouchEnd = true; testWidget.redWidget->closeWindowOnTouchEnd = true; testWidget.showMaximized(); - (void) qApp->exec(); QVERIFY(testWidget.greyWidget->seenTouchBegin); QVERIFY(!testWidget.greyWidget->seenTouchUpdate); diff --git a/tests/manual/qtouchevent/touchwidget.cpp b/tests/manual/qtouchevent/touchwidget.cpp index 1e57c36..0516c5b 100644 --- a/tests/manual/qtouchevent/touchwidget.cpp +++ b/tests/manual/qtouchevent/touchwidget.cpp @@ -24,6 +24,7 @@ void TouchWidget::reset() = closeWindowOnMouseRelease = false; + touchPointCount = 0; } bool TouchWidget::event(QEvent *event) @@ -31,6 +32,7 @@ bool TouchWidget::event(QEvent *event) switch (event->type()) { case QEvent::TouchBegin: seenTouchBegin = true; + touchPointCount = qMax(touchPointCount, static_cast(event)->touchPoints().count()); if (acceptTouchBegin) { event->accept(); return true; @@ -38,6 +40,7 @@ bool TouchWidget::event(QEvent *event) break; case QEvent::TouchUpdate: seenTouchUpdate = true; + touchPointCount = qMax(touchPointCount, static_cast(event)->touchPoints().count()); if (acceptTouchUpdate) { event->accept(); return true; @@ -45,6 +48,7 @@ bool TouchWidget::event(QEvent *event) break; case QEvent::TouchEnd: seenTouchEnd = true; + touchPointCount = qMax(touchPointCount, static_cast(event)->touchPoints().count()); if (closeWindowOnTouchEnd) window()->close(); if (acceptTouchEnd) { diff --git a/tests/manual/qtouchevent/touchwidget.h b/tests/manual/qtouchevent/touchwidget.h index 3e95610..2726deb 100644 --- a/tests/manual/qtouchevent/touchwidget.h +++ b/tests/manual/qtouchevent/touchwidget.h @@ -11,6 +11,7 @@ public: bool acceptTouchBegin, acceptTouchUpdate, acceptTouchEnd; bool seenTouchBegin, seenTouchUpdate, seenTouchEnd; bool closeWindowOnTouchEnd; + int touchPointCount; bool acceptMousePress, acceptMouseMove, acceptMouseRelease; bool seenMousePress, seenMouseMove, seenMouseRelease; -- cgit v0.12 From fecf5bf95329dd6e4aae6bac07e92fb637925101 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Mon, 27 Apr 2009 17:13:53 +0200 Subject: center the labels in the test's form --- tests/manual/qtouchevent/form.ui | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/manual/qtouchevent/form.ui b/tests/manual/qtouchevent/form.ui index 4c2da3a..c7fbb78 100644 --- a/tests/manual/qtouchevent/form.ui +++ b/tests/manual/qtouchevent/form.ui @@ -26,6 +26,9 @@ Test Name + + Qt::AlignCenter + @@ -38,6 +41,9 @@ Test description + + Qt::AlignCenter + -- cgit v0.12 From 2a0f0fdc016259dcc956599f41aa024ed06116b5 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Mon, 27 Apr 2009 17:32:22 +0200 Subject: 2 new tests for touch points 1. outside the widgets area and 2. over a child --- tests/manual/qtouchevent/main.cpp | 58 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/tests/manual/qtouchevent/main.cpp b/tests/manual/qtouchevent/main.cpp index 8b28967..bc33f16 100644 --- a/tests/manual/qtouchevent/main.cpp +++ b/tests/manual/qtouchevent/main.cpp @@ -37,6 +37,8 @@ private slots: void basicMultiTouchEventHandling(); void acceptingTouchBeginStopsPropagation(); void ignoringTouchBeginPropagatesToParent(); + void secondTouchPointOnParentGoesToChild(); + void secondTouchPointOnChildGoesToParent(); }; tst_ManualMultitouch::tst_ManualMultitouch() @@ -431,6 +433,62 @@ void tst_ManualMultitouch::ignoringTouchBeginPropagatesToParent() QVERIFY(!testWidget.redWidget->seenMouseRelease); } +void tst_ManualMultitouch::secondTouchPointOnParentGoesToChild() +{ + MultitouchTestWidget testWidget; + testWidget.testNameLabel->setText("Additional Touch-Points Outside Child's Rect Go to Child"); + testWidget.testDescriptionLabel->setText("Press and hold a finger on the blue widget, then on the green one, and release."); + testWidget.redWidget->hide(); + testWidget.greenWidget->setAttribute(Qt::WA_AcceptTouchEvents); + testWidget.blueWidget->setAttribute(Qt::WA_AcceptTouchEvents); + testWidget.blueWidget->acceptTouchBegin = true; + testWidget.greenWidget->acceptTouchBegin = true; + testWidget.blueWidget->closeWindowOnTouchEnd = true; + testWidget.showMaximized(); + (void) qApp->exec(); + QVERIFY(testWidget.blueWidget->seenTouchBegin); + QVERIFY(testWidget.blueWidget->seenTouchUpdate); + QVERIFY(testWidget.blueWidget->seenTouchEnd); + QVERIFY(!testWidget.blueWidget->seenMousePress); + QVERIFY(!testWidget.blueWidget->seenMouseMove); + QVERIFY(!testWidget.blueWidget->seenMouseRelease); + QVERIFY(testWidget.blueWidget->touchPointCount > 1); + QVERIFY(!testWidget.greenWidget->seenTouchBegin); + QVERIFY(!testWidget.greenWidget->seenTouchUpdate); + QVERIFY(!testWidget.greenWidget->seenTouchEnd); + QVERIFY(!testWidget.greenWidget->seenMousePress); + QVERIFY(!testWidget.greenWidget->seenMouseMove); + QVERIFY(!testWidget.greenWidget->seenMouseRelease); +} + +void tst_ManualMultitouch::secondTouchPointOnChildGoesToParent() +{ + MultitouchTestWidget testWidget; + testWidget.testNameLabel->setText("Additional Touch-Points Over Child's Rect Go to Parent"); + testWidget.testDescriptionLabel->setText("Press and hold a finger on the red widget, then on the red one, and release."); + testWidget.greenWidget->hide(); + testWidget.redWidget->setAttribute(Qt::WA_AcceptTouchEvents); + testWidget.greyWidget->setAttribute(Qt::WA_AcceptTouchEvents); + testWidget.greyWidget->acceptTouchBegin = true; + testWidget.redWidget->acceptTouchBegin = true; + testWidget.redWidget->closeWindowOnTouchEnd = true; + testWidget.showMaximized(); + (void) qApp->exec(); + QVERIFY(testWidget.redWidget->seenTouchBegin); + QVERIFY(testWidget.redWidget->seenTouchUpdate); + QVERIFY(testWidget.redWidget->seenTouchEnd); + QVERIFY(!testWidget.redWidget->seenMousePress); + QVERIFY(!testWidget.redWidget->seenMouseMove); + QVERIFY(!testWidget.redWidget->seenMouseRelease); + QVERIFY(testWidget.redWidget->touchPointCount > 1); + QVERIFY(!testWidget.greyWidget->seenTouchBegin); + QVERIFY(!testWidget.greyWidget->seenTouchUpdate); + QVERIFY(!testWidget.greyWidget->seenTouchEnd); + QVERIFY(!testWidget.greyWidget->seenMousePress); + QVERIFY(!testWidget.greyWidget->seenMouseMove); + QVERIFY(!testWidget.greyWidget->seenMouseRelease); +} + QTEST_MAIN(tst_ManualMultitouch) #include "main.moc" -- cgit v0.12 From 4cbbcf62949421ae5cad422b904b3ed1a004a724 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Tue, 28 Apr 2009 08:53:24 +0200 Subject: correct a typo in the test description --- tests/manual/qtouchevent/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/manual/qtouchevent/main.cpp b/tests/manual/qtouchevent/main.cpp index bc33f16..d48f487 100644 --- a/tests/manual/qtouchevent/main.cpp +++ b/tests/manual/qtouchevent/main.cpp @@ -465,7 +465,7 @@ void tst_ManualMultitouch::secondTouchPointOnChildGoesToParent() { MultitouchTestWidget testWidget; testWidget.testNameLabel->setText("Additional Touch-Points Over Child's Rect Go to Parent"); - testWidget.testDescriptionLabel->setText("Press and hold a finger on the red widget, then on the red one, and release."); + testWidget.testDescriptionLabel->setText("Press and hold a finger on the red widget, then on the grey one, and release."); testWidget.greenWidget->hide(); testWidget.redWidget->setAttribute(Qt::WA_AcceptTouchEvents); testWidget.greyWidget->setAttribute(Qt::WA_AcceptTouchEvents); -- cgit v0.12 From c4b9bccbecddbeeefc8ac9db91421ddaa2193858 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Tue, 28 Apr 2009 09:23:34 +0200 Subject: added 2 new tests for testing multi-touch on widget siblings and cousins --- tests/manual/qtouchevent/main.cpp | 62 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/tests/manual/qtouchevent/main.cpp b/tests/manual/qtouchevent/main.cpp index d48f487..9f2d413 100644 --- a/tests/manual/qtouchevent/main.cpp +++ b/tests/manual/qtouchevent/main.cpp @@ -12,7 +12,7 @@ public: MultitouchTestWidget(QWidget *parent = 0) : QWidget(parent) { - setAttribute(Qt::WA_QuitOnClose, false);\ + setAttribute(Qt::WA_QuitOnClose, false); setupUi(this); } @@ -39,6 +39,8 @@ private slots: void ignoringTouchBeginPropagatesToParent(); void secondTouchPointOnParentGoesToChild(); void secondTouchPointOnChildGoesToParent(); + void secondTouchPointOnSiblingGoesToSibling(); + void secondTouchPointOnCousinGoesToCousin(); }; tst_ManualMultitouch::tst_ManualMultitouch() @@ -489,6 +491,64 @@ void tst_ManualMultitouch::secondTouchPointOnChildGoesToParent() QVERIFY(!testWidget.greyWidget->seenMouseRelease); } +void tst_ManualMultitouch::secondTouchPointOnSiblingGoesToSibling() +{ + MultitouchTestWidget testWidget; + testWidget.testNameLabel->setText("Multi-Touch Interaction Test, Unrelated Widgets Get Separate Events"); + testWidget.testDescriptionLabel->setText("Press and hold a finger on the green widget, then the red one, and release."); + testWidget.blueWidget->hide(); + testWidget.greenWidget->setAttribute(Qt::WA_AcceptTouchEvents); + testWidget.greenWidget->acceptTouchBegin = true; + testWidget.greenWidget->closeWindowOnTouchEnd = true; + testWidget.greyWidget->hide(); + testWidget.redWidget->setAttribute(Qt::WA_AcceptTouchEvents); + testWidget.redWidget->acceptTouchBegin = true; + testWidget.showMaximized(); + (void) qApp->exec(); + QVERIFY(testWidget.greenWidget->seenTouchBegin); + QVERIFY(testWidget.greenWidget->seenTouchUpdate); + QVERIFY(testWidget.greenWidget->seenTouchEnd); + QVERIFY(!testWidget.greenWidget->seenMousePress); + QVERIFY(!testWidget.greenWidget->seenMouseMove); + QVERIFY(!testWidget.greenWidget->seenMouseRelease); + QVERIFY(testWidget.redWidget->seenTouchBegin); + QVERIFY(testWidget.redWidget->seenTouchUpdate); + QVERIFY(testWidget.redWidget->seenTouchEnd); + QVERIFY(!testWidget.redWidget->seenMousePress); + QVERIFY(!testWidget.redWidget->seenMouseMove); + QVERIFY(!testWidget.redWidget->seenMouseRelease); + QVERIFY(testWidget.greenWidget->touchPointCount == 1); + QVERIFY(testWidget.redWidget->touchPointCount == 1); +} + +void tst_ManualMultitouch::secondTouchPointOnCousinGoesToCousin() +{ + MultitouchTestWidget testWidget; + testWidget.testNameLabel->setText("Multi-Touch Interaction Test, Unrelated Widgets Get Separate Events"); + testWidget.testDescriptionLabel->setText("Press and hold a finger on the blue widget, then the grey one, and release."); + testWidget.blueWidget->setAttribute(Qt::WA_AcceptTouchEvents); + testWidget.blueWidget->acceptTouchBegin = true; + testWidget.blueWidget->closeWindowOnTouchEnd = true; + testWidget.greyWidget->setAttribute(Qt::WA_AcceptTouchEvents); + testWidget.greyWidget->acceptTouchBegin = true; + testWidget.showMaximized(); + (void) qApp->exec(); + QVERIFY(testWidget.blueWidget->seenTouchBegin); + QVERIFY(testWidget.blueWidget->seenTouchUpdate); + QVERIFY(testWidget.blueWidget->seenTouchEnd); + QVERIFY(!testWidget.blueWidget->seenMousePress); + QVERIFY(!testWidget.blueWidget->seenMouseMove); + QVERIFY(!testWidget.blueWidget->seenMouseRelease); + QVERIFY(testWidget.greyWidget->seenTouchBegin); + QVERIFY(testWidget.greyWidget->seenTouchUpdate); + QVERIFY(testWidget.greyWidget->seenTouchEnd); + QVERIFY(!testWidget.greyWidget->seenMousePress); + QVERIFY(!testWidget.greyWidget->seenMouseMove); + QVERIFY(!testWidget.greyWidget->seenMouseRelease); + QVERIFY(testWidget.blueWidget->touchPointCount == 1); + QVERIFY(testWidget.greyWidget->touchPointCount == 1); +} + QTEST_MAIN(tst_ManualMultitouch) #include "main.moc" -- cgit v0.12 From 520a67e50ed7717518d3072f8568de00b791f20a Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Wed, 29 Apr 2009 15:44:08 +0200 Subject: Use a widget attribute to keep track of whether or not TouchBegin has been accepted --- src/corelib/global/qnamespace.h | 1 + src/gui/kernel/qapplication.cpp | 1 + src/gui/kernel/qapplication_p.h | 1 - src/gui/kernel/qapplication_win.cpp | 12 +++++------- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index b73a873..15da2d6 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -486,6 +486,7 @@ public: WA_TranslucentBackground = 120, WA_AcceptTouchEvents = 121, + WA_AcceptedTouchBeginEvent = 122, // Add new attributes before this line WA_AttributeCount diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 4e61f66..bc9b827 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -4013,6 +4013,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e) res = widget->testAttribute(Qt::WA_AcceptTouchEvents) && d->notify_helper(widget, touchEvent); eventAccepted = touchEvent->isAccepted(); + widget->setAttribute(Qt::WA_AcceptedTouchBeginEvent, res && eventAccepted); touchEvent->spont = false; if (res && eventAccepted) { // the first widget to accept the TouchBegin gets an implicit grab. diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index 91857ec..ce7110d 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -429,7 +429,6 @@ public: #endif QPointer currentMultitouchWidget; - bool currentMultitouchWidgetAcceptedTouchBegin; static void updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent); #if defined(Q_WS_WIN) diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 7e07104..f1fb0a4 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -4000,7 +4000,6 @@ void QApplicationPrivate::initializeMultitouch() CloseTouchInputHandle = static_cast(library.resolve("CloseTouchInputHandle")); currentMultitouchWidget = 0; - currentMultitouchWidgetAcceptedTouchBegin = false; touchInputIDToTouchPointID.clear(); allTouchPoints.clear(); currentTouchPoints.clear(); @@ -4106,7 +4105,7 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) currentMultitouchWidget = child; // if the TouchBegin handler recurses, we assume that means the event // has been implicitly accepted and continue to send touch events - currentMultitouchWidgetAcceptedTouchBegin = true; + currentMultitouchWidget->setAttribute(Qt::WA_AcceptedTouchBeginEvent); } } @@ -4133,11 +4132,10 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) updateTouchPointsForWidget(widget, &touchEvent); if (sendTouchBegin) { - bool res = QApplication::sendSpontaneousEvent(widget, &touchEvent); - qt_tabletChokeMouse - = currentMultitouchWidgetAcceptedTouchBegin - = (res && touchEvent.isAccepted()); - } else if (currentMultitouchWidgetAcceptedTouchBegin) { + bool res = QApplication::sendSpontaneousEvent(widget, &touchEvent) + && touchEvent.isAccepted(); + qt_tabletChokeMouse = res; + } else if (widget->testAttribute(Qt::WA_AcceptedTouchBeginEvent)) { (void) QApplication::sendSpontaneousEvent(widget, &touchEvent); qt_tabletChokeMouse = true; } else { -- cgit v0.12 From a3504361a19428c12ac7e044762f252d8ba2b26f Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Wed, 29 Apr 2009 18:08:44 +0200 Subject: Don't store activeTouchPoints in QApplicationPrivate it's only needed and updated during delivery, so the extra copy isn't necessary --- src/gui/kernel/qapplication_p.h | 2 +- src/gui/kernel/qapplication_win.cpp | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index ce7110d..da66aab 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -438,7 +438,7 @@ public: QMap touchInputIDToTouchPointID; QVector allTouchPoints; - QList currentTouchPoints, activeTouchPoints; + QList currentTouchPoints; void initializeMultitouch(); void insertActiveTouch(QTouchEvent::TouchPoint *touchPoint); diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index f1fb0a4..c7ecdae 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -4003,7 +4003,6 @@ void QApplicationPrivate::initializeMultitouch() touchInputIDToTouchPointID.clear(); allTouchPoints.clear(); currentTouchPoints.clear(); - activeTouchPoints.clear(); } void QApplicationPrivate::insertActiveTouch(QTouchEvent::TouchPoint *touchPoint) @@ -4015,7 +4014,6 @@ void QApplicationPrivate::insertActiveTouch(QTouchEvent::TouchPoint *touchPoint) break; } currentTouchPoints.insert(at, touchPoint); - activeTouchPoints = currentTouchPoints; if (currentTouchPoints.count() > allTouchPoints.count()) { qFatal("Qt: INTERNAL ERROR: currentTouchPoints.count() (%d) > allTouchPoints.count() (%d)", @@ -4042,7 +4040,7 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) Q_Q(QApplication); bool sendTouchBegin = currentTouchPoints.isEmpty(); - activeTouchPoints = currentTouchPoints; + QList activeTouchPoints = currentTouchPoints; QVector winTouchInputs(msg.wParam); memset(winTouchInputs.data(), 0, sizeof(TOUCHINPUT) * winTouchInputs.count()); @@ -4068,6 +4066,7 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) QPointF globalPos(qreal(touchInput.x) / qreal(100.), qreal(touchInput.y) / qreal(100.)); if (!down && (touchInput.dwFlags & TOUCHEVENTF_DOWN)) { insertActiveTouch(touchPoint); + activeTouchPoints = currentTouchPoints; touchPoint->d->state = Qt::TouchPointPressed; touchPoint->d->globalPos = touchPoint->d->startGlobalPos = touchPoint->d->lastGlobalPos = globalPos; touchPoint->d->pressure = qreal(1.); -- cgit v0.12 From f9b4c7bea991d1786c60406abc9da95354b0d6e3 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Thu, 30 Apr 2009 10:24:20 +0200 Subject: Don't call RegisterTouchWindow() if we don't have a window id --- src/gui/kernel/qwidget_win.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp index 26e66b1..f53a3ef 100644 --- a/src/gui/kernel/qwidget_win.cpp +++ b/src/gui/kernel/qwidget_win.cpp @@ -498,7 +498,7 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO } // ### don't always register for touch events - if (QApplicationPrivate::RegisterTouchWindow && !desktop) + if (id && QApplicationPrivate::RegisterTouchWindow && !desktop) QApplicationPrivate::RegisterTouchWindow(id, 0); q->setAttribute(Qt::WA_WState_Created); // accept move/resize events -- cgit v0.12 From cd260501918ea767e8a3ca33a51b1cb4e1bbd45c Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Thu, 30 Apr 2009 11:27:43 +0200 Subject: Made the Touch* event detection very strict TouchBegin is only "seen" once before all other touch events, TouchUpdate must be after TouchBegin but before TouchEnd, and TouchEnd is only seen once after all other touch events. --- tests/manual/qtouchevent/touchwidget.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/manual/qtouchevent/touchwidget.cpp b/tests/manual/qtouchevent/touchwidget.cpp index 0516c5b..f029f8b 100644 --- a/tests/manual/qtouchevent/touchwidget.cpp +++ b/tests/manual/qtouchevent/touchwidget.cpp @@ -31,7 +31,7 @@ bool TouchWidget::event(QEvent *event) { switch (event->type()) { case QEvent::TouchBegin: - seenTouchBegin = true; + seenTouchBegin = !seenTouchBegin && !seenTouchUpdate && !seenTouchEnd; touchPointCount = qMax(touchPointCount, static_cast(event)->touchPoints().count()); if (acceptTouchBegin) { event->accept(); @@ -39,7 +39,7 @@ bool TouchWidget::event(QEvent *event) } break; case QEvent::TouchUpdate: - seenTouchUpdate = true; + seenTouchUpdate = seenTouchBegin && !seenTouchEnd; touchPointCount = qMax(touchPointCount, static_cast(event)->touchPoints().count()); if (acceptTouchUpdate) { event->accept(); @@ -47,7 +47,7 @@ bool TouchWidget::event(QEvent *event) } break; case QEvent::TouchEnd: - seenTouchEnd = true; + seenTouchEnd = seenTouchBegin && !seenTouchEnd; touchPointCount = qMax(touchPointCount, static_cast(event)->touchPoints().count()); if (closeWindowOnTouchEnd) window()->close(); -- cgit v0.12 From 33a9b5b4c7945c800b6590b993c841fb833276e8 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Thu, 30 Apr 2009 11:33:03 +0200 Subject: Determine whether TouchBegin or TouchEnd should be sent at the time of touchpoint addition/removal This will make it easier to change later when supporting touching multiple widgets --- src/gui/kernel/qapplication_win.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 9b756a6..60bad92 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -4039,7 +4039,8 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) { Q_Q(QApplication); - bool sendTouchBegin = currentTouchPoints.isEmpty(); + bool sendTouchBegin = false; + bool sendTouchEnd = false; QList activeTouchPoints = currentTouchPoints; QVector winTouchInputs(msg.wParam); @@ -4065,13 +4066,17 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) bool down = touchPoint->d->state != Qt::TouchPointReleased; QPointF globalPos(qreal(touchInput.x) / qreal(100.), qreal(touchInput.y) / qreal(100.)); if (!down && (touchInput.dwFlags & TOUCHEVENTF_DOWN)) { + sendTouchBegin = currentTouchPoints.isEmpty(); insertActiveTouch(touchPoint); activeTouchPoints = currentTouchPoints; + touchPoint->d->state = Qt::TouchPointPressed; touchPoint->d->globalPos = touchPoint->d->startGlobalPos = touchPoint->d->lastGlobalPos = globalPos; touchPoint->d->pressure = qreal(1.); } else if (down && (touchInput.dwFlags & TOUCHEVENTF_UP)) { removeActiveTouch(touchPoint); + sendTouchEnd = currentTouchPoints.isEmpty(); + touchPoint->d->state = Qt::TouchPointReleased; touchPoint->d->lastGlobalPos = touchPoint->d->globalPos; touchPoint->d->globalPos = globalPos; @@ -4087,8 +4092,6 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) } QApplicationPrivate::CloseTouchInputHandle((HANDLE) msg.lParam); - bool sendTouchEnd = currentTouchPoints.isEmpty(); - if (activeTouchPoints.isEmpty()) return false; -- cgit v0.12 From bdeefa6bd4b8721c737aeb63794034c3495be9a1 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Thu, 30 Apr 2009 13:33:44 +0200 Subject: Use the HWND from the Windows MSG to find which widget to send events to the logic for determining the event type has refactored as well --- src/gui/kernel/qapplication_p.h | 4 +-- src/gui/kernel/qapplication_win.cpp | 63 +++++++++++++++++++------------------ 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index e9db8f3..ef375d3 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -441,8 +441,8 @@ public: QList currentTouchPoints; void initializeMultitouch(); - void insertActiveTouch(QTouchEvent::TouchPoint *touchPoint); - void removeActiveTouch(QTouchEvent::TouchPoint *touchPoint); + QEvent::Type insertActiveTouch(QTouchEvent::TouchPoint *touchPoint); + QEvent::Type removeActiveTouch(QTouchEvent::TouchPoint *touchPoint); bool translateTouchEvent(const MSG &msg); #endif diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 60bad92..b9262af 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -4005,9 +4005,13 @@ void QApplicationPrivate::initializeMultitouch() currentTouchPoints.clear(); } -void QApplicationPrivate::insertActiveTouch(QTouchEvent::TouchPoint *touchPoint) +QEvent::Type QApplicationPrivate::insertActiveTouch(QTouchEvent::TouchPoint *touchPoint) { - // insort deviceNumber + QEvent::Type eventType = currentTouchPoints.isEmpty() + ? QEvent::TouchBegin + : QEvent::TouchUpdate; + + // insort touch point int at = 0; for (; at < currentTouchPoints.count(); ++at) { if (currentTouchPoints.at(at)->id() > touchPoint->id()) @@ -4020,9 +4024,11 @@ void QApplicationPrivate::insertActiveTouch(QTouchEvent::TouchPoint *touchPoint) currentTouchPoints.count(), allTouchPoints.count()); } + + return eventType; } -void QApplicationPrivate::removeActiveTouch(QTouchEvent::TouchPoint *touchPoint) +QEvent::Type QApplicationPrivate::removeActiveTouch(QTouchEvent::TouchPoint *touchPoint) { for (int i = qMin(currentTouchPoints.count() - 1, touchPoint->id()); i >= 0; --i) { if (currentTouchPoints.at(i) == touchPoint) { @@ -4031,16 +4037,18 @@ void QApplicationPrivate::removeActiveTouch(QTouchEvent::TouchPoint *touchPoint) } } - // leave activeTouchPoints unchanged, since we need to make sure - // that the Release for deviceNumber is sent + return currentTouchPoints.isEmpty() ? QEvent::TouchEnd : QEvent::TouchUpdate; } bool QApplicationPrivate::translateTouchEvent(const MSG &msg) { Q_Q(QApplication); - bool sendTouchBegin = false; - bool sendTouchEnd = false; + QWidget *widgetForHwnd = QWidget::find(msg.hwnd); + if (!widgetForHwnd) + return false; + + QEvent::Type eventType = QEvent::None; QList activeTouchPoints = currentTouchPoints; QVector winTouchInputs(msg.wParam); @@ -4066,22 +4074,22 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) bool down = touchPoint->d->state != Qt::TouchPointReleased; QPointF globalPos(qreal(touchInput.x) / qreal(100.), qreal(touchInput.y) / qreal(100.)); if (!down && (touchInput.dwFlags & TOUCHEVENTF_DOWN)) { - sendTouchBegin = currentTouchPoints.isEmpty(); - insertActiveTouch(touchPoint); + eventType = insertActiveTouch(touchPoint); + // make sure new points are added to activeTouchPoints as well activeTouchPoints = currentTouchPoints; touchPoint->d->state = Qt::TouchPointPressed; touchPoint->d->globalPos = touchPoint->d->startGlobalPos = touchPoint->d->lastGlobalPos = globalPos; touchPoint->d->pressure = qreal(1.); } else if (down && (touchInput.dwFlags & TOUCHEVENTF_UP)) { - removeActiveTouch(touchPoint); - sendTouchEnd = currentTouchPoints.isEmpty(); + eventType = removeActiveTouch(touchPoint); touchPoint->d->state = Qt::TouchPointReleased; touchPoint->d->lastGlobalPos = touchPoint->d->globalPos; touchPoint->d->globalPos = globalPos; touchPoint->d->pressure = qreal(0.); } else if (down) { + eventType = QEvent::TouchUpdate; touchPoint->d->state = globalPos == touchPoint->d->globalPos ? Qt::TouchPointStationary : Qt::TouchPointMoved; @@ -4092,30 +4100,28 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) } QApplicationPrivate::CloseTouchInputHandle((HANDLE) msg.lParam); - if (activeTouchPoints.isEmpty()) + Q_ASSERT(eventType != QEvent::None); + if (eventType == QEvent::None || activeTouchPoints.isEmpty()) return false; - if (sendTouchBegin) { + if (eventType == QEvent::TouchBegin) { // the window under the first touch point gets the touch event int firstTouchId = activeTouchPoints.first()->id(); const QPoint &globalPos = allTouchPoints.at(firstTouchId)->d->globalPos.toPoint(); - QWidget *window = q->topLevelAt(globalPos); - if (window) { - QWidget *child = window->childAt(window->mapFromGlobal(globalPos)); - if (!child) - child = window; - currentMultitouchWidget = child; - // if the TouchBegin handler recurses, we assume that means the event - // has been implicitly accepted and continue to send touch events - currentMultitouchWidget->setAttribute(Qt::WA_AcceptedTouchBeginEvent); - } + QWidget *child = widgetForHwnd->childAt(widgetForHwnd->mapFromGlobal(globalPos)); + if (!child) + child = widgetForHwnd; + currentMultitouchWidget = child; + // if the TouchBegin handler recurses, we assume that means the event + // has been implicitly accepted and continue to send touch events + currentMultitouchWidget->setAttribute(Qt::WA_AcceptedTouchBeginEvent); } QWidget *widget = q->activePopupWidget(); if (!widget) widget = currentMultitouchWidget; - if (sendTouchEnd) { + if (eventType == QEvent::TouchEnd) { // reset currentMultitouchWindow when the last touch is released currentMultitouchWidget = 0; if (!currentTouchPoints.isEmpty()) { @@ -4125,15 +4131,10 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) // deliver the event if (widget && QApplicationPrivate::tryModalHelper(widget, 0)) { - QTouchEvent touchEvent((sendTouchBegin - ? QEvent::TouchBegin - : sendTouchEnd - ? QEvent::TouchEnd - : QEvent::TouchUpdate), - q->keyboardModifiers(), activeTouchPoints); + QTouchEvent touchEvent(eventType, q->keyboardModifiers(), activeTouchPoints); updateTouchPointsForWidget(widget, &touchEvent); - if (sendTouchBegin) { + if (eventType == QEvent::TouchBegin) { bool res = QApplication::sendSpontaneousEvent(widget, &touchEvent) && touchEvent.isAccepted(); qt_tabletChokeMouse = res; -- cgit v0.12 From 36c97c3e530969d172179d715805804ffb96e792 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Mon, 4 May 2009 12:22:44 +0200 Subject: Initialize activeTouchPoints in the loop itself instead of before This will make it easier to make the change to sending touch events to multiple widgets. --- src/gui/kernel/qapplication_win.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index b9262af..fbedd19 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -4049,8 +4049,7 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) return false; QEvent::Type eventType = QEvent::None; - QList activeTouchPoints = currentTouchPoints; - + QList activeTouchPoints; QVector winTouchInputs(msg.wParam); memset(winTouchInputs.data(), 0, sizeof(TOUCHINPUT) * winTouchInputs.count()); QApplicationPrivate::GetTouchInputInfo((HANDLE) msg.lParam, msg.wParam, winTouchInputs.data(), sizeof(TOUCHINPUT)); @@ -4082,6 +4081,7 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) touchPoint->d->globalPos = touchPoint->d->startGlobalPos = touchPoint->d->lastGlobalPos = globalPos; touchPoint->d->pressure = qreal(1.); } else if (down && (touchInput.dwFlags & TOUCHEVENTF_UP)) { + activeTouchPoints = currentTouchPoints; eventType = removeActiveTouch(touchPoint); touchPoint->d->state = Qt::TouchPointReleased; @@ -4089,6 +4089,8 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) touchPoint->d->globalPos = globalPos; touchPoint->d->pressure = qreal(0.); } else if (down) { + if (activeTouchPoints.isEmpty()) + activeTouchPoints = currentTouchPoints; eventType = QEvent::TouchUpdate; touchPoint->d->state = globalPos == touchPoint->d->globalPos ? Qt::TouchPointStationary -- cgit v0.12 From 2d0f49df3a3c44601bf2e41ea722c2384b71aab0 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Mon, 4 May 2009 17:17:34 +0200 Subject: Support sending touch events (with multiple touch points) to multiple widgets simultaneously This is a first attempt, and it works, but it will need to be cleaned up to remove as much state from QWidgetPrivate as possible. --- src/gui/kernel/qapplication.cpp | 9 +- src/gui/kernel/qapplication_p.h | 11 ++- src/gui/kernel/qapplication_win.cpp | 191 +++++++++++++++++++++++------------- src/gui/kernel/qevent.h | 2 + src/gui/kernel/qevent_p.h | 1 + src/gui/kernel/qwidget_p.h | 3 + 6 files changed, 141 insertions(+), 76 deletions(-) diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 81c02e3..3a25abb 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -3997,6 +3997,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e) // Note: TouchUpdate and TouchEnd events are sent to d->currentMultitouchWidget and never propagated { QWidget *widget = static_cast(receiver); + QWidget *origin = widget; QTouchEvent *touchEvent = static_cast(e); bool eventAccepted = touchEvent->isAccepted(); @@ -4017,7 +4018,13 @@ bool QApplication::notify(QObject *receiver, QEvent *e) touchEvent->spont = false; if (res && eventAccepted) { // the first widget to accept the TouchBegin gets an implicit grab. - d->currentMultitouchWidget = widget; + for (int i = 0; i < touchEvent->_touchPoints.count(); ++i) { + QTouchEvent::TouchPoint *touchPoint = touchEvent->_touchPoints.at(i); + touchPoint->d->widget = widget; + } + if (origin != widget) + origin->d_func()->currentTouchPoints.clear(); + widget->d_func()->currentTouchPoints = touchEvent->_touchPoints; break; } else if (widget->isWindow() || widget->testAttribute(Qt::WA_NoMousePropagation)) { break; diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index ef375d3..1a2bad2 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -428,7 +428,6 @@ public: void sendSyntheticEnterLeave(QWidget *widget); #endif - QPointer currentMultitouchWidget; static void updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent); #if defined(Q_WS_WIN) @@ -437,12 +436,14 @@ public: static qt_CloseTouchInputHandlePtr CloseTouchInputHandle; QMap touchInputIDToTouchPointID; - QVector allTouchPoints; - QList currentTouchPoints; + QVector appAllTouchPoints; + QList appCurrentTouchPoints; void initializeMultitouch(); - QEvent::Type insertActiveTouch(QTouchEvent::TouchPoint *touchPoint); - QEvent::Type removeActiveTouch(QTouchEvent::TouchPoint *touchPoint); + static QTouchEvent::TouchPoint *findClosestTouchPoint(const QList &activeTouchPoints, + const QPointF &pos); + QEvent::Type appendTouchPoint(QTouchEvent::TouchPoint *touchPoint); + QEvent::Type removeTouchPoint(QTouchEvent::TouchPoint *touchPoint); bool translateTouchEvent(const MSG &msg); #endif diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index fbedd19..f13ab5d 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -75,6 +75,7 @@ extern void qt_wince_hide_taskbar(HWND hwnd); //defined in qguifunctions_wince.c #include "qcolormap.h" #include "qlayout.h" #include "qtooltip.h" +#include "qset.h" #include "qt_windows.h" #if defined(QT_NON_COMMERCIAL) #include "qnc_win.h" @@ -3999,45 +4000,76 @@ void QApplicationPrivate::initializeMultitouch() GetTouchInputInfo = static_cast(library.resolve("GetTouchInputInfo")); CloseTouchInputHandle = static_cast(library.resolve("CloseTouchInputHandle")); - currentMultitouchWidget = 0; touchInputIDToTouchPointID.clear(); - allTouchPoints.clear(); - currentTouchPoints.clear(); + appAllTouchPoints.clear(); } -QEvent::Type QApplicationPrivate::insertActiveTouch(QTouchEvent::TouchPoint *touchPoint) +QTouchEvent::TouchPoint *QApplicationPrivate::findClosestTouchPoint(const QList &appActiveTouchPoints, + const QPointF &pos) { - QEvent::Type eventType = currentTouchPoints.isEmpty() + QTouchEvent::TouchPoint *closestTouchPoint = 0; + qreal closestDistance; + for (int i = 0; i < appActiveTouchPoints.count(); ++i) { + QTouchEvent::TouchPoint *touchPoint = appActiveTouchPoints.at(i); + qreal distance = QLineF(pos, touchPoint->d->globalPos).length(); + if (!closestTouchPoint || distance < closestDistance) { + closestTouchPoint = touchPoint; + closestDistance = distance; + } + } + return closestTouchPoint; +} + +QEvent::Type QApplicationPrivate::appendTouchPoint(QTouchEvent::TouchPoint *touchPoint) +{ + QWidget *widget = touchPoint->d->widget; + QEvent::Type eventType = widget->d_func()->currentTouchPoints.isEmpty() ? QEvent::TouchBegin : QEvent::TouchUpdate; - // insort touch point + // insort touch point (for the app) int at = 0; - for (; at < currentTouchPoints.count(); ++at) { - if (currentTouchPoints.at(at)->id() > touchPoint->id()) + for (; at < appCurrentTouchPoints.count(); ++at) { + if (appCurrentTouchPoints.at(at)->id() > touchPoint->id()) break; } - currentTouchPoints.insert(at, touchPoint); + appCurrentTouchPoints.insert(at, touchPoint); + // again, for the widget's currentTouchPoints + for (at = 0; at < widget->d_func()->currentTouchPoints.count(); ++at) { + if (widget->d_func()->currentTouchPoints.at(at)->id() > touchPoint->id()) + break; + } + widget->d_func()->currentTouchPoints.insert(at, touchPoint); - if (currentTouchPoints.count() > allTouchPoints.count()) { - qFatal("Qt: INTERNAL ERROR: currentTouchPoints.count() (%d) > allTouchPoints.count() (%d)", - currentTouchPoints.count(), - allTouchPoints.count()); + if (appCurrentTouchPoints.count() > appAllTouchPoints.count()) { + qFatal("Qt: INTERNAL ERROR: appCurrentTouchPoints.count() (%d) > appAllTouchPoints.count() (%d)", + appCurrentTouchPoints.count(), + appAllTouchPoints.count()); } return eventType; } -QEvent::Type QApplicationPrivate::removeActiveTouch(QTouchEvent::TouchPoint *touchPoint) +QEvent::Type QApplicationPrivate::removeTouchPoint(QTouchEvent::TouchPoint *touchPoint) { - for (int i = qMin(currentTouchPoints.count() - 1, touchPoint->id()); i >= 0; --i) { - if (currentTouchPoints.at(i) == touchPoint) { - currentTouchPoints.removeAt(i); + QWidget *widget = touchPoint->d->widget; + + // remove touch point from all known touch points + for (int i = qMin(appCurrentTouchPoints.count() - 1, touchPoint->id()); i >= 0; --i) { + if (appCurrentTouchPoints.at(i) == touchPoint) { + appCurrentTouchPoints.removeAt(i); + break; + } + } + // again, for the widget's currentTouchPoints + for (int i = qMin(widget->d_func()->currentTouchPoints.count() - 1, touchPoint->id()); i >= 0; --i) { + if (widget->d_func()->currentTouchPoints.at(i) == touchPoint) { + widget->d_func()->currentTouchPoints.removeAt(i); break; } } - return currentTouchPoints.isEmpty() ? QEvent::TouchEnd : QEvent::TouchUpdate; + return widget->d_func()->currentTouchPoints.isEmpty() ? QEvent::TouchEnd : QEvent::TouchUpdate; } bool QApplicationPrivate::translateTouchEvent(const MSG &msg) @@ -4048,8 +4080,9 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) if (!widgetForHwnd) return false; - QEvent::Type eventType = QEvent::None; - QList activeTouchPoints; + QList appActiveTouchPoints = appCurrentTouchPoints; + + QSet widgetsNeedingEvents; QVector winTouchInputs(msg.wParam); memset(winTouchInputs.data(), 0, sizeof(TOUCHINPUT) * winTouchInputs.count()); QApplicationPrivate::GetTouchInputInfo((HANDLE) msg.lParam, msg.wParam, winTouchInputs.data(), sizeof(TOUCHINPUT)); @@ -4062,36 +4095,56 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) touchInputIDToTouchPointID.insert(touchInput.dwID, touchPointID); } - if (allTouchPoints.count() <= touchPointID) - allTouchPoints.resize(touchPointID + 1); + if (appAllTouchPoints.count() <= touchPointID) + appAllTouchPoints.resize(touchPointID + 1); - QTouchEvent::TouchPoint *touchPoint = allTouchPoints.at(touchPointID); + QTouchEvent::TouchPoint *touchPoint = appAllTouchPoints.at(touchPointID); if (!touchPoint) - touchPoint = allTouchPoints[touchPointID] = new QTouchEvent::TouchPoint(touchPointID); + touchPoint = appAllTouchPoints[touchPointID] = new QTouchEvent::TouchPoint(touchPointID); // update state bool down = touchPoint->d->state != Qt::TouchPointReleased; QPointF globalPos(qreal(touchInput.x) / qreal(100.), qreal(touchInput.y) / qreal(100.)); if (!down && (touchInput.dwFlags & TOUCHEVENTF_DOWN)) { - eventType = insertActiveTouch(touchPoint); + // determine which widget this event will go to + QWidget *w = widgetForHwnd->childAt(widgetForHwnd->mapFromGlobal(globalPos.toPoint())); + if (!w) + w = widgetForHwnd; + + QTouchEvent::TouchPoint *closestTouchPoint = findClosestTouchPoint(appActiveTouchPoints, globalPos); + if (closestTouchPoint + && (w->isAncestorOf(closestTouchPoint->d->widget) + || closestTouchPoint->d->widget->isAncestorOf(w))) { + w = closestTouchPoint->d->widget; + } + touchPoint->d->widget = w; + + w->d_func()->touchEventType = appendTouchPoint(touchPoint); // make sure new points are added to activeTouchPoints as well - activeTouchPoints = currentTouchPoints; + appActiveTouchPoints = appCurrentTouchPoints; + w->d_func()->activeTouchPoints = w->d_func()->currentTouchPoints; touchPoint->d->state = Qt::TouchPointPressed; - touchPoint->d->globalPos = touchPoint->d->startGlobalPos = touchPoint->d->lastGlobalPos = globalPos; + touchPoint->d->globalPos + = touchPoint->d->startGlobalPos + = touchPoint->d->lastGlobalPos + = globalPos; touchPoint->d->pressure = qreal(1.); } else if (down && (touchInput.dwFlags & TOUCHEVENTF_UP)) { - activeTouchPoints = currentTouchPoints; - eventType = removeActiveTouch(touchPoint); + QWidget *w = touchPoint->d->widget; + appActiveTouchPoints = appCurrentTouchPoints; + w->d_func()->activeTouchPoints = w->d_func()->currentTouchPoints; + w->d_func()->touchEventType = removeTouchPoint(touchPoint); touchPoint->d->state = Qt::TouchPointReleased; touchPoint->d->lastGlobalPos = touchPoint->d->globalPos; touchPoint->d->globalPos = globalPos; touchPoint->d->pressure = qreal(0.); } else if (down) { - if (activeTouchPoints.isEmpty()) - activeTouchPoints = currentTouchPoints; - eventType = QEvent::TouchUpdate; + QWidget *w = touchPoint->d->widget; + appActiveTouchPoints = appCurrentTouchPoints; + w->d_func()->activeTouchPoints = w->d_func()->currentTouchPoints; + w->d_func()->touchEventType = QEvent::TouchUpdate; touchPoint->d->state = globalPos == touchPoint->d->globalPos ? Qt::TouchPointStationary : Qt::TouchPointMoved; @@ -4099,58 +4152,56 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) touchPoint->d->globalPos = globalPos; // pressure should still be 1. } + + if (touchPoint->d->state != Qt::TouchPointStationary) + widgetsNeedingEvents.insert(touchPoint->d->widget); } QApplicationPrivate::CloseTouchInputHandle((HANDLE) msg.lParam); - Q_ASSERT(eventType != QEvent::None); - if (eventType == QEvent::None || activeTouchPoints.isEmpty()) + if (widgetsNeedingEvents.isEmpty()) return false; - if (eventType == QEvent::TouchBegin) { - // the window under the first touch point gets the touch event - int firstTouchId = activeTouchPoints.first()->id(); - const QPoint &globalPos = allTouchPoints.at(firstTouchId)->d->globalPos.toPoint(); - QWidget *child = widgetForHwnd->childAt(widgetForHwnd->mapFromGlobal(globalPos)); - if (!child) - child = widgetForHwnd; - currentMultitouchWidget = child; - // if the TouchBegin handler recurses, we assume that means the event - // has been implicitly accepted and continue to send touch events - currentMultitouchWidget->setAttribute(Qt::WA_AcceptedTouchBeginEvent); - } + bool returnValue = false; - QWidget *widget = q->activePopupWidget(); - if (!widget) - widget = currentMultitouchWidget; - - if (eventType == QEvent::TouchEnd) { - // reset currentMultitouchWindow when the last touch is released - currentMultitouchWidget = 0; - if (!currentTouchPoints.isEmpty()) { - qFatal("Qt: INTERNAL ERROR, currentTouchPoints should be empty!"); - } - } + QSet::ConstIterator it = widgetsNeedingEvents.constBegin(); + const QSet::ConstIterator end = widgetsNeedingEvents.constEnd(); + for (; it != end; ++it) { + QWidget *widget = *it; + if (!QApplicationPrivate::tryModalHelper(widget, 0)) + continue; - // deliver the event - if (widget && QApplicationPrivate::tryModalHelper(widget, 0)) { - QTouchEvent touchEvent(eventType, q->keyboardModifiers(), activeTouchPoints); + QTouchEvent touchEvent(widget->d_func()->touchEventType, q->keyboardModifiers(), widget->d_func()->activeTouchPoints); updateTouchPointsForWidget(widget, &touchEvent); - if (eventType == QEvent::TouchBegin) { + switch (widget->d_func()->touchEventType) { + case QEvent::TouchBegin: + { + // if the TouchBegin handler recurses, we assume that means the event + // has been implicitly accepted and continue to send touch events + widget->setAttribute(Qt::WA_AcceptedTouchBeginEvent); bool res = QApplication::sendSpontaneousEvent(widget, &touchEvent) && touchEvent.isAccepted(); - qt_tabletChokeMouse = res; - } else if (widget->testAttribute(Qt::WA_AcceptedTouchBeginEvent)) { - (void) QApplication::sendSpontaneousEvent(widget, &touchEvent); - qt_tabletChokeMouse = true; - } else { - qt_tabletChokeMouse = false; + returnValue = returnValue || (qt_tabletChokeMouse = res); + break; + } + case QEvent::TouchEnd: + if (!widget->d_func()->currentTouchPoints.isEmpty()) { + qFatal("Qt: INTERNAL ERROR, the widget's currentTouchPoints should be empty!"); + } + // fall-through intended + default: + if (widget->testAttribute(Qt::WA_AcceptedTouchBeginEvent)) { + (void) QApplication::sendSpontaneousEvent(widget, &touchEvent); + qt_tabletChokeMouse = true; + } else { + qt_tabletChokeMouse = false; + } + returnValue = returnValue || qt_tabletChokeMouse; + break; } - - return qt_tabletChokeMouse; } - return false; + return returnValue; } QT_END_NAMESPACE diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 506e0c1..e9a1386 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -746,6 +746,7 @@ public: private: QTouchEventTouchPointPrivate *d; + friend class QApplication; friend class QApplicationPrivate; }; @@ -759,6 +760,7 @@ public: protected: QList _touchPoints; + friend class QApplication; friend class QApplicationPrivate; }; diff --git a/src/gui/kernel/qevent_p.h b/src/gui/kernel/qevent_p.h index 5e24eeb..df7143e 100644 --- a/src/gui/kernel/qevent_p.h +++ b/src/gui/kernel/qevent_p.h @@ -98,6 +98,7 @@ public: pressure(qreal(-1.)) { } + QPointer widget; int id; Qt::TouchPointState state; QPointF pos, startPos, lastPos; diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index 8731551..df17566 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -663,6 +663,9 @@ public: } QSize adjustedSize() const; + + QEvent::Type touchEventType; + QList currentTouchPoints, activeTouchPoints; }; inline QWExtra *QWidgetPrivate::extraData() const -- cgit v0.12 From 7a5da4486708b096084fdaf83aba88f5d1b83e00 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Wed, 6 May 2009 14:08:34 +0200 Subject: fix QtOpenGL compilation, add missing include --- src/gui/kernel/qwidget_p.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index 2dd3061..2ab9ffe 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -60,6 +60,7 @@ #include "QtGui/qregion.h" #include "QtGui/qsizepolicy.h" #include "QtGui/qstyle.h" +#include "QtGui/qevent.h" #ifdef Q_WS_WIN #include "QtCore/qt_windows.h" -- cgit v0.12 From 58f25669087bf52357bc69f398b4713d33b03d1e Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Fri, 8 May 2009 13:04:19 +0200 Subject: don't store event state in QWidgetPrivate the only thing we store in the QWidgetPrivate is the current touch point list, nothing more (the rest is local state in the event translation code) --- src/gui/kernel/qapplication_win.cpp | 34 +++++++++++++++++++--------------- src/gui/kernel/qwidget_p.h | 3 +-- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 91c24da..60c6fd7 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -75,7 +75,6 @@ extern void qt_wince_hide_taskbar(HWND hwnd); //defined in qguifunctions_wince.c #include "qcolormap.h" #include "qlayout.h" #include "qtooltip.h" -#include "qset.h" #include "qt_windows.h" #if defined(QT_NON_COMMERCIAL) #include "qnc_win.h" @@ -4091,7 +4090,7 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) QList appActiveTouchPoints = appCurrentTouchPoints; - QSet widgetsNeedingEvents; + QHash widgetsNeedingEvents; QVector winTouchInputs(msg.wParam); memset(winTouchInputs.data(), 0, sizeof(TOUCHINPUT) * winTouchInputs.count()); QApplicationPrivate::GetTouchInputInfo((HANDLE) msg.lParam, msg.wParam, winTouchInputs.data(), sizeof(TOUCHINPUT)); @@ -4114,6 +4113,8 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) // update state bool down = touchPoint->d->state != Qt::TouchPointReleased; QPointF globalPos(qreal(touchInput.x) / qreal(100.), qreal(touchInput.y) / qreal(100.)); + QEvent::Type eventType = QEvent::None; + QList activeTouchPoints; if (!down && (touchInput.dwFlags & TOUCHEVENTF_DOWN)) { // determine which widget this event will go to QWidget *w = widgetForHwnd->childAt(widgetForHwnd->mapFromGlobal(globalPos.toPoint())); @@ -4128,10 +4129,10 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) } touchPoint->d->widget = w; - w->d_func()->touchEventType = appendTouchPoint(touchPoint); + eventType = appendTouchPoint(touchPoint); // make sure new points are added to activeTouchPoints as well appActiveTouchPoints = appCurrentTouchPoints; - w->d_func()->activeTouchPoints = w->d_func()->currentTouchPoints; + activeTouchPoints = w->d_func()->currentTouchPoints; touchPoint->d->state = Qt::TouchPointPressed; touchPoint->d->globalPos @@ -4142,8 +4143,8 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) } else if (down && (touchInput.dwFlags & TOUCHEVENTF_UP)) { QWidget *w = touchPoint->d->widget; appActiveTouchPoints = appCurrentTouchPoints; - w->d_func()->activeTouchPoints = w->d_func()->currentTouchPoints; - w->d_func()->touchEventType = removeTouchPoint(touchPoint); + activeTouchPoints = w->d_func()->currentTouchPoints; + eventType = removeTouchPoint(touchPoint); touchPoint->d->state = Qt::TouchPointReleased; touchPoint->d->lastGlobalPos = touchPoint->d->globalPos; @@ -4152,8 +4153,8 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) } else if (down) { QWidget *w = touchPoint->d->widget; appActiveTouchPoints = appCurrentTouchPoints; - w->d_func()->activeTouchPoints = w->d_func()->currentTouchPoints; - w->d_func()->touchEventType = QEvent::TouchUpdate; + activeTouchPoints = w->d_func()->currentTouchPoints; + eventType = QEvent::TouchUpdate; touchPoint->d->state = globalPos == touchPoint->d->globalPos ? Qt::TouchPointStationary : Qt::TouchPointMoved; @@ -4161,9 +4162,12 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) touchPoint->d->globalPos = globalPos; // pressure should still be 1. } + Q_ASSERT(eventType != QEvent::None); - if (touchPoint->d->state != Qt::TouchPointStationary) - widgetsNeedingEvents.insert(touchPoint->d->widget); + if (touchPoint->d->state != Qt::TouchPointStationary) { + widgetsNeedingEvents.insert(touchPoint->d->widget, + QTouchEvent(eventType, q->keyboardModifiers(), activeTouchPoints)); + } } QApplicationPrivate::CloseTouchInputHandle((HANDLE) msg.lParam); @@ -4172,17 +4176,17 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) bool returnValue = false; - QSet::ConstIterator it = widgetsNeedingEvents.constBegin(); - const QSet::ConstIterator end = widgetsNeedingEvents.constEnd(); + QHash::ConstIterator it = widgetsNeedingEvents.constBegin(); + const QHash::ConstIterator end = widgetsNeedingEvents.constEnd(); for (; it != end; ++it) { - QWidget *widget = *it; + QWidget *widget = it.key(); if (!QApplicationPrivate::tryModalHelper(widget, 0)) continue; - QTouchEvent touchEvent(widget->d_func()->touchEventType, q->keyboardModifiers(), widget->d_func()->activeTouchPoints); + QTouchEvent touchEvent = it.value(); updateTouchPointsForWidget(widget, &touchEvent); - switch (widget->d_func()->touchEventType) { + switch (touchEvent.type()) { case QEvent::TouchBegin: { // if the TouchBegin handler recurses, we assume that means the event diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index 2ab9ffe..5f5e1b1 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -666,8 +666,7 @@ public: QSize adjustedSize() const; - QEvent::Type touchEventType; - QList currentTouchPoints, activeTouchPoints; + QList currentTouchPoints; }; inline QWExtra *QWidgetPrivate::extraData() const -- cgit v0.12 From c45ba5929d2e6326449df124d42fc60032c1c93c Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Fri, 8 May 2009 13:06:47 +0200 Subject: warn about events that happen out of sequence --- tests/manual/qtouchevent/touchwidget.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/manual/qtouchevent/touchwidget.cpp b/tests/manual/qtouchevent/touchwidget.cpp index f029f8b..a8141cc 100644 --- a/tests/manual/qtouchevent/touchwidget.cpp +++ b/tests/manual/qtouchevent/touchwidget.cpp @@ -31,6 +31,9 @@ bool TouchWidget::event(QEvent *event) { switch (event->type()) { case QEvent::TouchBegin: + if (seenTouchBegin) qWarning("TouchBegin: already seen a TouchBegin"); + if (seenTouchUpdate) qWarning("TouchBegin: TouchUpdate cannot happen before TouchBegin"); + if (seenTouchEnd) qWarning("TouchBegin: TouchEnd cannot happen before TouchBegin"); seenTouchBegin = !seenTouchBegin && !seenTouchUpdate && !seenTouchEnd; touchPointCount = qMax(touchPointCount, static_cast(event)->touchPoints().count()); if (acceptTouchBegin) { @@ -39,6 +42,8 @@ bool TouchWidget::event(QEvent *event) } break; case QEvent::TouchUpdate: + if (!seenTouchBegin) qWarning("TouchUpdate: have not seen TouchBegin"); + if (seenTouchEnd) qWarning("TouchUpdate: TouchEnd cannot happen before TouchUpdate"); seenTouchUpdate = seenTouchBegin && !seenTouchEnd; touchPointCount = qMax(touchPointCount, static_cast(event)->touchPoints().count()); if (acceptTouchUpdate) { @@ -47,6 +52,8 @@ bool TouchWidget::event(QEvent *event) } break; case QEvent::TouchEnd: + if (!seenTouchBegin) qWarning("TouchEnd: have not seen TouchBegin"); + if (seenTouchEnd) qWarning("TouchEnd: already seen a TouchEnd"); seenTouchEnd = seenTouchBegin && !seenTouchEnd; touchPointCount = qMax(touchPointCount, static_cast(event)->touchPoints().count()); if (closeWindowOnTouchEnd) -- cgit v0.12 From 711701da5cc958bb44cd5ff2d6562cfca1f7eb85 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Fri, 8 May 2009 15:45:43 +0200 Subject: don't require TouchUpdate events for the single touch cases the finger may not move, meaning no update with move event is generated, even if we say "press, hold, release" when testing (the finger may not wobble enough) --- tests/manual/qtouchevent/main.cpp | 52 +++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/tests/manual/qtouchevent/main.cpp b/tests/manual/qtouchevent/main.cpp index 9f2d413..8097ab0 100644 --- a/tests/manual/qtouchevent/main.cpp +++ b/tests/manual/qtouchevent/main.cpp @@ -61,7 +61,7 @@ void tst_ManualMultitouch::ignoringTouchEventsEmulatesMouseEvents() testWidget.showMaximized(); (void) qApp->exec(); QVERIFY(!testWidget.greenWidget->seenTouchBegin); - QVERIFY(!testWidget.greenWidget->seenTouchUpdate); + // QVERIFY(!testWidget.greenWidget->seenTouchUpdate); QVERIFY(!testWidget.greenWidget->seenTouchEnd); QVERIFY(testWidget.greenWidget->seenMousePress); // QVERIFY(testWidget.greenWidget->seenMouseMove); @@ -74,7 +74,7 @@ void tst_ManualMultitouch::ignoringTouchEventsEmulatesMouseEvents() testWidget.showMaximized(); (void) qApp->exec(); QVERIFY(testWidget.greenWidget->seenTouchBegin); - QVERIFY(!testWidget.greenWidget->seenTouchUpdate); + // QVERIFY(!testWidget.greenWidget->seenTouchUpdate); QVERIFY(!testWidget.greenWidget->seenTouchEnd); QVERIFY(testWidget.greenWidget->seenMousePress); // QVERIFY(testWidget.greenWidget->seenMouseMove); @@ -96,12 +96,12 @@ void tst_ManualMultitouch::basicSingleTouchEventHandling() testWidget.greenWidget->closeWindowOnTouchEnd = true; testWidget.showMaximized(); (void) qApp->exec(); - QVERIFY(testWidget.greenWidget->seenTouchBegin - && testWidget.greenWidget->seenTouchUpdate - && testWidget.greenWidget->seenTouchEnd); - QVERIFY(!testWidget.greenWidget->seenMousePress - && !testWidget.greenWidget->seenMouseMove - && !testWidget.greenWidget->seenMouseRelease); + QVERIFY(testWidget.greenWidget->seenTouchBegin); + // QVERIFY(testWidget.greenWidget->seenTouchUpdate); + QVERIFY(testWidget.greenWidget->seenTouchEnd); + QVERIFY(!testWidget.greenWidget->seenMousePress); + QVERIFY(!testWidget.greenWidget->seenMouseMove); + QVERIFY(!testWidget.greenWidget->seenMouseRelease); // again, ignoring the TouchEnd testWidget.greenWidget->reset(); @@ -112,7 +112,7 @@ void tst_ManualMultitouch::basicSingleTouchEventHandling() testWidget.showMaximized(); (void) qApp->exec(); QVERIFY(testWidget.greenWidget->seenTouchBegin); - QVERIFY(testWidget.greenWidget->seenTouchUpdate); + // QVERIFY(testWidget.greenWidget->seenTouchUpdate); QVERIFY(testWidget.greenWidget->seenTouchEnd); QVERIFY(!testWidget.greenWidget->seenMousePress); QVERIFY(!testWidget.greenWidget->seenMouseMove); @@ -127,7 +127,7 @@ void tst_ManualMultitouch::basicSingleTouchEventHandling() testWidget.showMaximized(); (void) qApp->exec(); QVERIFY(testWidget.greenWidget->seenTouchBegin); - QVERIFY(testWidget.greenWidget->seenTouchUpdate); + // QVERIFY(testWidget.greenWidget->seenTouchUpdate); QVERIFY(testWidget.greenWidget->seenTouchEnd); QVERIFY(!testWidget.greenWidget->seenMousePress); QVERIFY(!testWidget.greenWidget->seenMouseMove); @@ -142,7 +142,7 @@ void tst_ManualMultitouch::basicSingleTouchEventHandling() testWidget.showMaximized(); (void) qApp->exec(); QVERIFY(testWidget.greenWidget->seenTouchBegin); - QVERIFY(testWidget.greenWidget->seenTouchUpdate); + // QVERIFY(testWidget.greenWidget->seenTouchUpdate); QVERIFY(testWidget.greenWidget->seenTouchEnd); QVERIFY(!testWidget.greenWidget->seenMousePress); QVERIFY(!testWidget.greenWidget->seenMouseMove); @@ -235,7 +235,7 @@ void tst_ManualMultitouch::acceptingTouchBeginStopsPropagation() testWidget.showMaximized(); (void) qApp->exec(); QVERIFY(testWidget.blueWidget->seenTouchBegin); - QVERIFY(testWidget.blueWidget->seenTouchUpdate); + // QVERIFY(testWidget.blueWidget->seenTouchUpdate); QVERIFY(testWidget.blueWidget->seenTouchEnd); QVERIFY(!testWidget.blueWidget->seenMousePress); QVERIFY(!testWidget.blueWidget->seenMouseMove); @@ -257,7 +257,7 @@ void tst_ManualMultitouch::acceptingTouchBeginStopsPropagation() testWidget.showMaximized(); (void) qApp->exec(); QVERIFY(testWidget.blueWidget->seenTouchBegin); - QVERIFY(testWidget.blueWidget->seenTouchUpdate); + // QVERIFY(testWidget.blueWidget->seenTouchUpdate); QVERIFY(testWidget.blueWidget->seenTouchEnd); QVERIFY(!testWidget.blueWidget->seenMousePress); QVERIFY(!testWidget.blueWidget->seenMouseMove); @@ -279,7 +279,7 @@ void tst_ManualMultitouch::acceptingTouchBeginStopsPropagation() testWidget.showMaximized(); (void) qApp->exec(); QVERIFY(testWidget.blueWidget->seenTouchBegin); - QVERIFY(testWidget.blueWidget->seenTouchUpdate); + // QVERIFY(testWidget.blueWidget->seenTouchUpdate); QVERIFY(testWidget.blueWidget->seenTouchEnd); QVERIFY(!testWidget.blueWidget->seenMousePress); QVERIFY(!testWidget.blueWidget->seenMouseMove); @@ -301,7 +301,7 @@ void tst_ManualMultitouch::acceptingTouchBeginStopsPropagation() testWidget.showMaximized(); (void) qApp->exec(); QVERIFY(testWidget.blueWidget->seenTouchBegin); - QVERIFY(testWidget.blueWidget->seenTouchUpdate); + // QVERIFY(testWidget.blueWidget->seenTouchUpdate); QVERIFY(testWidget.blueWidget->seenTouchEnd); QVERIFY(!testWidget.blueWidget->seenMousePress); QVERIFY(!testWidget.blueWidget->seenMouseMove); @@ -339,7 +339,7 @@ void tst_ManualMultitouch::ignoringTouchBeginPropagatesToParent() QVERIFY(!testWidget.greyWidget->seenMouseMove); QVERIFY(!testWidget.greyWidget->seenMouseRelease); QVERIFY(testWidget.redWidget->seenTouchBegin); - QVERIFY(testWidget.redWidget->seenTouchUpdate); + // QVERIFY(testWidget.redWidget->seenTouchUpdate); QVERIFY(testWidget.redWidget->seenTouchEnd); QVERIFY(!testWidget.redWidget->seenMousePress); QVERIFY(!testWidget.redWidget->seenMouseMove); @@ -362,7 +362,7 @@ void tst_ManualMultitouch::ignoringTouchBeginPropagatesToParent() QVERIFY(!testWidget.greyWidget->seenMouseMove); QVERIFY(!testWidget.greyWidget->seenMouseRelease); QVERIFY(testWidget.redWidget->seenTouchBegin); - QVERIFY(testWidget.redWidget->seenTouchUpdate); + // QVERIFY(testWidget.redWidget->seenTouchUpdate); QVERIFY(testWidget.redWidget->seenTouchEnd); QVERIFY(!testWidget.redWidget->seenMousePress); QVERIFY(!testWidget.redWidget->seenMouseMove); @@ -384,7 +384,7 @@ void tst_ManualMultitouch::ignoringTouchBeginPropagatesToParent() QVERIFY(!testWidget.greyWidget->seenMouseMove); QVERIFY(!testWidget.greyWidget->seenMouseRelease); QVERIFY(testWidget.redWidget->seenTouchBegin); - QVERIFY(testWidget.redWidget->seenTouchUpdate); + // QVERIFY(testWidget.redWidget->seenTouchUpdate); QVERIFY(testWidget.redWidget->seenTouchEnd); QVERIFY(!testWidget.redWidget->seenMousePress); QVERIFY(!testWidget.redWidget->seenMouseMove); @@ -406,7 +406,7 @@ void tst_ManualMultitouch::ignoringTouchBeginPropagatesToParent() QVERIFY(!testWidget.greyWidget->seenMouseMove); QVERIFY(!testWidget.greyWidget->seenMouseRelease); QVERIFY(testWidget.redWidget->seenTouchBegin); - QVERIFY(testWidget.redWidget->seenTouchUpdate); + // QVERIFY(testWidget.redWidget->seenTouchUpdate); QVERIFY(testWidget.redWidget->seenTouchEnd); QVERIFY(!testWidget.redWidget->seenMousePress); QVERIFY(!testWidget.redWidget->seenMouseMove); @@ -428,7 +428,7 @@ void tst_ManualMultitouch::ignoringTouchBeginPropagatesToParent() QVERIFY(!testWidget.greyWidget->seenMouseMove); QVERIFY(!testWidget.blueWidget->seenMouseRelease); QVERIFY(testWidget.redWidget->seenTouchBegin); - QVERIFY(testWidget.redWidget->seenTouchUpdate); + // QVERIFY(testWidget.redWidget->seenTouchUpdate); QVERIFY(testWidget.redWidget->seenTouchEnd); QVERIFY(!testWidget.redWidget->seenMousePress); QVERIFY(!testWidget.redWidget->seenMouseMove); @@ -449,7 +449,7 @@ void tst_ManualMultitouch::secondTouchPointOnParentGoesToChild() testWidget.showMaximized(); (void) qApp->exec(); QVERIFY(testWidget.blueWidget->seenTouchBegin); - QVERIFY(testWidget.blueWidget->seenTouchUpdate); + // QVERIFY(testWidget.blueWidget->seenTouchUpdate); QVERIFY(testWidget.blueWidget->seenTouchEnd); QVERIFY(!testWidget.blueWidget->seenMousePress); QVERIFY(!testWidget.blueWidget->seenMouseMove); @@ -477,7 +477,7 @@ void tst_ManualMultitouch::secondTouchPointOnChildGoesToParent() testWidget.showMaximized(); (void) qApp->exec(); QVERIFY(testWidget.redWidget->seenTouchBegin); - QVERIFY(testWidget.redWidget->seenTouchUpdate); + // QVERIFY(testWidget.redWidget->seenTouchUpdate); QVERIFY(testWidget.redWidget->seenTouchEnd); QVERIFY(!testWidget.redWidget->seenMousePress); QVERIFY(!testWidget.redWidget->seenMouseMove); @@ -506,13 +506,13 @@ void tst_ManualMultitouch::secondTouchPointOnSiblingGoesToSibling() testWidget.showMaximized(); (void) qApp->exec(); QVERIFY(testWidget.greenWidget->seenTouchBegin); - QVERIFY(testWidget.greenWidget->seenTouchUpdate); + // QVERIFY(testWidget.greenWidget->seenTouchUpdate); QVERIFY(testWidget.greenWidget->seenTouchEnd); QVERIFY(!testWidget.greenWidget->seenMousePress); QVERIFY(!testWidget.greenWidget->seenMouseMove); QVERIFY(!testWidget.greenWidget->seenMouseRelease); QVERIFY(testWidget.redWidget->seenTouchBegin); - QVERIFY(testWidget.redWidget->seenTouchUpdate); + // QVERIFY(testWidget.redWidget->seenTouchUpdate); QVERIFY(testWidget.redWidget->seenTouchEnd); QVERIFY(!testWidget.redWidget->seenMousePress); QVERIFY(!testWidget.redWidget->seenMouseMove); @@ -534,13 +534,13 @@ void tst_ManualMultitouch::secondTouchPointOnCousinGoesToCousin() testWidget.showMaximized(); (void) qApp->exec(); QVERIFY(testWidget.blueWidget->seenTouchBegin); - QVERIFY(testWidget.blueWidget->seenTouchUpdate); + // QVERIFY(testWidget.blueWidget->seenTouchUpdate); QVERIFY(testWidget.blueWidget->seenTouchEnd); QVERIFY(!testWidget.blueWidget->seenMousePress); QVERIFY(!testWidget.blueWidget->seenMouseMove); QVERIFY(!testWidget.blueWidget->seenMouseRelease); QVERIFY(testWidget.greyWidget->seenTouchBegin); - QVERIFY(testWidget.greyWidget->seenTouchUpdate); + // QVERIFY(testWidget.greyWidget->seenTouchUpdate); QVERIFY(testWidget.greyWidget->seenTouchEnd); QVERIFY(!testWidget.greyWidget->seenMousePress); QVERIFY(!testWidget.greyWidget->seenMouseMove); -- cgit v0.12 From 5d7e624593172a9901d0bb44d57fe6e7697fd113 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Fri, 8 May 2009 15:55:06 +0200 Subject: set qt_tabletChokeMouse to true whenever ANY touch event was accepted this makes sure we always get touch events, and the don't drop out seemingly randomly. --- src/gui/kernel/qapplication_win.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 60c6fd7..723a3b4 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -4175,6 +4175,7 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) return false; bool returnValue = false; + qt_tabletChokeMouse = false; QHash::ConstIterator it = widgetsNeedingEvents.constBegin(); const QHash::ConstIterator end = widgetsNeedingEvents.constEnd(); @@ -4194,7 +4195,7 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) widget->setAttribute(Qt::WA_AcceptedTouchBeginEvent); bool res = QApplication::sendSpontaneousEvent(widget, &touchEvent) && touchEvent.isAccepted(); - returnValue = returnValue || (qt_tabletChokeMouse = res); + returnValue = returnValue || (qt_tabletChokeMouse = qt_tabletChokeMouse || res); break; } case QEvent::TouchEnd: @@ -4206,8 +4207,6 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) if (widget->testAttribute(Qt::WA_AcceptedTouchBeginEvent)) { (void) QApplication::sendSpontaneousEvent(widget, &touchEvent); qt_tabletChokeMouse = true; - } else { - qt_tabletChokeMouse = false; } returnValue = returnValue || qt_tabletChokeMouse; break; -- cgit v0.12 From 1283c8734b137d1d7cc7c88e5e120e14c45852d1 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Fri, 8 May 2009 16:58:45 +0200 Subject: build the multitouch examples from the top-level build just needed to add multitouch to SUBDIRS in examples/examples.pro --- examples/examples.pro | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/examples.pro b/examples/examples.pro index 41501a0..2d49103 100644 --- a/examples/examples.pro +++ b/examples/examples.pro @@ -20,7 +20,8 @@ SUBDIRS = \ widgets \ uitools \ xml \ - script + script \ + multitouch contains(QT_CONFIG, phonon):!static: SUBDIRS += phonon contains(QT_CONFIG, webkit): SUBDIRS += webkit -- cgit v0.12 From 771e18e96d86f09bb047e5cf45cc33568e259a5d Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Fri, 8 May 2009 17:13:09 +0200 Subject: by default, ignore touch events if the widget is disabled --- src/gui/kernel/qwidget.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index cbf9585..968a423 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -7525,6 +7525,9 @@ bool QWidget::event(QEvent *event) case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: case QEvent::MouseMove: + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: case QEvent::ContextMenu: #ifndef QT_NO_WHEELEVENT case QEvent::Wheel: -- cgit v0.12 From a3d8cfb1ee89e0600add864db53d67552820b95a Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Thu, 26 Feb 2009 15:39:00 +0100 Subject: Merge of the maemo-gestures branch onto qt/4.5.0 This is a squashed merge of all of the changes in the maemo-gestures branch on-top of the qt/4.5.0 branch. --- examples/gestures/gestures.pro | 11 + examples/gestures/graphicsview/graphicsview.pro | 2 + examples/gestures/graphicsview/main.cpp | 151 +++++++ examples/gestures/imageviewer/imageviewer.pro | 12 + examples/gestures/imageviewer/imagewidget.cpp | 338 +++++++++++++++ examples/gestures/imageviewer/imagewidget.h | 122 ++++++ examples/gestures/imageviewer/main.cpp | 88 ++++ src/corelib/global/qnamespace.h | 15 + src/corelib/kernel/qcoreevent.h | 2 + src/gui/graphicsview/qgraphicsitem.cpp | 28 ++ src/gui/graphicsview/qgraphicsitem.h | 3 + src/gui/graphicsview/qgraphicsitem_p.h | 2 + src/gui/graphicsview/qgraphicsscene.cpp | 62 +++ src/gui/graphicsview/qgraphicsscene.h | 2 + src/gui/graphicsview/qgraphicsscene_p.h | 9 + src/gui/graphicsview/qgraphicsview.cpp | 9 +- src/gui/kernel/kernel.pri | 14 +- src/gui/kernel/qapplication.cpp | 57 ++- src/gui/kernel/qapplication.h | 1 + src/gui/kernel/qapplication_p.h | 1 + src/gui/kernel/qapplication_x11.cpp | 2 +- src/gui/kernel/qdirectionrecognizer.cpp | 176 ++++++++ src/gui/kernel/qdirectionrecognizer_p.h | 121 ++++++ src/gui/kernel/qdirectionsimplificator_p.h | 172 ++++++++ src/gui/kernel/qevent.cpp | 24 ++ src/gui/kernel/qevent.h | 34 ++ src/gui/kernel/qgesture.cpp | 133 ++++++ src/gui/kernel/qgesture.h | 128 ++++++ src/gui/kernel/qgesture_p.h | 100 +++++ src/gui/kernel/qgesturemanager.cpp | 405 ++++++++++++++++++ src/gui/kernel/qgesturemanager_p.h | 102 +++++ src/gui/kernel/qgesturerecognizer.h | 83 ++++ src/gui/kernel/qgesturestandardrecognizers.cpp | 543 ++++++++++++++++++++++++ src/gui/kernel/qgesturestandardrecognizers_p.h | 169 ++++++++ src/gui/kernel/qwidget.cpp | 45 ++ src/gui/kernel/qwidget.h | 10 + src/gui/kernel/qwidget_p.h | 3 + src/gui/widgets/qabstractscrollarea.cpp | 1 + 38 files changed, 3174 insertions(+), 6 deletions(-) create mode 100644 examples/gestures/gestures.pro create mode 100644 examples/gestures/graphicsview/graphicsview.pro create mode 100644 examples/gestures/graphicsview/main.cpp create mode 100644 examples/gestures/imageviewer/imageviewer.pro create mode 100644 examples/gestures/imageviewer/imagewidget.cpp create mode 100644 examples/gestures/imageviewer/imagewidget.h create mode 100644 examples/gestures/imageviewer/main.cpp create mode 100644 src/gui/kernel/qdirectionrecognizer.cpp create mode 100644 src/gui/kernel/qdirectionrecognizer_p.h create mode 100644 src/gui/kernel/qdirectionsimplificator_p.h create mode 100644 src/gui/kernel/qgesture.cpp create mode 100644 src/gui/kernel/qgesture.h create mode 100644 src/gui/kernel/qgesture_p.h create mode 100644 src/gui/kernel/qgesturemanager.cpp create mode 100644 src/gui/kernel/qgesturemanager_p.h create mode 100644 src/gui/kernel/qgesturerecognizer.h create mode 100644 src/gui/kernel/qgesturestandardrecognizers.cpp create mode 100644 src/gui/kernel/qgesturestandardrecognizers_p.h diff --git a/examples/gestures/gestures.pro b/examples/gestures/gestures.pro new file mode 100644 index 0000000..1e0f1a7 --- /dev/null +++ b/examples/gestures/gestures.pro @@ -0,0 +1,11 @@ +TEMPLATE = \ + subdirs +SUBDIRS = \ + imageviewer \ + graphicsview + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/gestures +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS gestures.pro README +sources.path = $$[QT_INSTALL_EXAMPLES]/gestures +INSTALLS += target sources diff --git a/examples/gestures/graphicsview/graphicsview.pro b/examples/gestures/graphicsview/graphicsview.pro new file mode 100644 index 0000000..9cef564 --- /dev/null +++ b/examples/gestures/graphicsview/graphicsview.pro @@ -0,0 +1,2 @@ +SOURCES = main.cpp + diff --git a/examples/gestures/graphicsview/main.cpp b/examples/gestures/graphicsview/main.cpp new file mode 100644 index 0000000..a0236ef --- /dev/null +++ b/examples/gestures/graphicsview/main.cpp @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +class PannableGraphicsView : public QGraphicsView +{ +public: + PannableGraphicsView() + { + grabGesture(Qt::Pan); + } +protected: + bool event(QEvent *event) + { + if (event->type() == QEvent::Gesture) { + QGestureEvent *ge = static_cast(event); + if (const QGesture *g = ge->gesture(Qt::Pan)) { + QPoint pt = g->pos() - g->lastPos(); + horizontalScrollBar()->setValue(horizontalScrollBar()->value() - pt.x()); + verticalScrollBar()->setValue(verticalScrollBar()->value() - pt.y()); + event->accept(); + return true; + } + } + return QGraphicsView::event(event); + } +}; + +class ImageItem : public QGraphicsItem +{ +public: + ImageItem() + : colored(false) + { + grabGesture(Qt::DoubleTap); + } + + QRectF boundingRect() const + { + return pixmap.isNull() ? QRectF(0, 0, 100, 100) + : QRectF(QPointF(0,0), QSizeF(pixmap.size())); + } + + void paint(QPainter *painter, const QStyleOptionGraphicsItem*, QWidget*) + { + if (pixmap.isNull()) { + painter->setBrush(QBrush( colored ? Qt::green : Qt::white)); + painter->drawRect(0, 0, 100, 100); + painter->drawLine(0, 0, 100, 100); + painter->drawLine(0, 100, 100, 0); + return; + } + painter->drawPixmap(0, 0, pixmap); + } + + bool sceneEvent(QEvent *event) + { + if (event->type() == QEvent::Gesture) { + QGestureEvent *gestureEvent = static_cast(event); + if (gestureEvent->gesture(Qt::DoubleTap)) { + event->accept(); + colored = !colored; + update(); + return true; + } else { + qWarning("Item received unknown gesture"); + } + } + return QGraphicsItem::sceneEvent(event); + } + +private: + QPixmap pixmap; + bool colored; +}; + +class MainWidget : public QWidget +{ + Q_OBJECT + +public: + MainWidget(QWidget *parent = 0) + : QWidget(parent) + { + QVBoxLayout *l = new QVBoxLayout(this); + view = new PannableGraphicsView; + l->addWidget(view); + scene = new QGraphicsScene(0, 0, 1024, 768, view); + view->setScene(scene); + + ImageItem *item = new ImageItem; + scene->addItem(item); + item->setPos(scene->width()/3, scene->height()/3); + } + +signals: +public slots: +private: + QGraphicsView *view; + QGraphicsScene *scene; +}; + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + QApplication::setAttribute(Qt::AA_EnableGestures); + MainWidget w; + w.show(); + return app.exec(); +} + +#include "main.moc" diff --git a/examples/gestures/imageviewer/imageviewer.pro b/examples/gestures/imageviewer/imageviewer.pro new file mode 100644 index 0000000..4c35dce --- /dev/null +++ b/examples/gestures/imageviewer/imageviewer.pro @@ -0,0 +1,12 @@ +###################################################################### +# Automatically generated by qmake (2.01a) Thu Sep 11 17:18:17 2008 +###################################################################### + +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . + +# Input +HEADERS += imagewidget.h +SOURCES += imagewidget.cpp main.cpp diff --git a/examples/gestures/imageviewer/imagewidget.cpp b/examples/gestures/imageviewer/imagewidget.cpp new file mode 100644 index 0000000..8932e29 --- /dev/null +++ b/examples/gestures/imageviewer/imagewidget.cpp @@ -0,0 +1,338 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "imagewidget.h" + +#include + +ImageWidget::ImageWidget(QWidget *parent) + : QWidget(parent) +{ + setAttribute(Qt::WA_PaintOnScreen); + setAttribute(Qt::WA_OpaquePaintEvent); + setAttribute(Qt::WA_NoSystemBackground); + + setObjectName("ImageWidget"); + + setMinimumSize(QSize(100,100)); + + position = 0; + zoomed = rotated = false; + + zoomedIn = false; + horizontalOffset = 0; + verticalOffset = 0; + + grabGesture(Qt::DoubleTap); + grabGesture(Qt::Pan); + grabGesture(Qt::LongTap); +} + +void ImageWidget::paintEvent(QPaintEvent*) +{ + QPainter p(this); + if (currentImage.isNull()) { + p.fillRect(geometry(), Qt::white); + return; + } + int hoffset = 0; + int voffset = 0; + const int w = pixmap.width(); + const int h = pixmap.height(); + p.save(); + if (zoomedIn) { + hoffset = horizontalOffset; + voffset = verticalOffset; + if (horizontalOffset > 0) + p.fillRect(0, 0, horizontalOffset, height(), Qt::white); + if (verticalOffset > 0) + p.fillRect(0, 0, width(), verticalOffset, Qt::white); + } + p.drawPixmap(hoffset, voffset, pixmap); + if (hoffset + w < width()) + p.fillRect(hoffset + w, 0, width() - w - hoffset, height(), Qt::white); + if (voffset + h < height()) + p.fillRect(0, voffset + h, width(), height() - h - voffset, Qt::white); + + // paint touch feedback + if (touchFeedback.tapped || touchFeedback.doubleTapped) { + p.setPen(QPen(Qt::gray, 2)); + p.drawEllipse(touchFeedback.position, 5, 5); + if (touchFeedback.doubleTapped) { + p.setPen(QPen(Qt::gray, 2, Qt::DotLine)); + p.drawEllipse(touchFeedback.position, 15, 15); + } else if (touchFeedback.tapAndHoldState != 0) { + QPoint pts[8] = { + touchFeedback.position + QPoint( 0, -15), + touchFeedback.position + QPoint( 10, -10), + touchFeedback.position + QPoint( 15, 0), + touchFeedback.position + QPoint( 10, 10), + touchFeedback.position + QPoint( 0, 15), + touchFeedback.position + QPoint(-10, 10), + touchFeedback.position + QPoint(-15, 0) + }; + for (int i = 0; i < (touchFeedback.tapAndHoldState-20)/10; ++i) + p.drawEllipse(pts[i], 3, 3); + } + } else if (touchFeedback.sliding) { + p.setPen(QPen(Qt::red, 3)); + QPoint endPos = QPoint(touchFeedback.position.x(), touchFeedback.slidingStartPosition.y()); + p.drawLine(touchFeedback.slidingStartPosition, endPos); + int dx = 10; + if (touchFeedback.slidingStartPosition.x() < endPos.x()) + dx = -1*dx; + p.drawLine(endPos, endPos + QPoint(dx, 5)); + p.drawLine(endPos, endPos + QPoint(dx, -5)); + } + + for (int i = 0; i < TouchFeedback::MaximumNumberOfTouches; ++i) { + if (touchFeedback.touches[i].isNull()) + break; + p.drawEllipse(touchFeedback.touches[i], 10, 10); + } + p.restore(); +} + +void ImageWidget::gestureEvent(QGestureEvent *event) +{ + touchFeedback.doubleTapped = false; + + Q_ASSERT(event); + if (event->contains(Qt::Tap)) { + // + } else if (const QGesture *g = event->gesture(Qt::DoubleTap)) { + touchFeedback.doubleTapped = true; + horizontalOffset = g->hotSpot().x() - currentImage.width()*1.0*g->hotSpot().x()/width(); + verticalOffset = g->hotSpot().y() - currentImage.height()*1.0*g->hotSpot().y()/height(); + setZoomedIn(!zoomedIn); + zoomed = rotated = false; + updateImage(); + } else if (const QGesture *g = event->gesture(Qt::Pan)) { + if (zoomedIn) { + // usual panning + if (g->state() == Qt::GestureStarted) + setCursor(Qt::SizeAllCursor); + else + setCursor(Qt::ArrowCursor); + const int dx = g->pos().x() - g->lastPos().x(); + const int dy = g->pos().y() - g->lastPos().y(); + horizontalOffset += dx; + verticalOffset += dy; + update(); + } else { + // only slide gesture should be accepted + const QPannableGesture *pg = dynamic_cast(g); + if (pg && pg->direction() != pg->lastDirection()) { + // ###: event->cancel(); + } + if (g->state() == Qt::GestureFinished) { + touchFeedback.sliding = false; + zoomed = rotated = false; + if (pg->direction() == QPannableGesture::Right) { + qDebug() << "slide right"; + goNextImage(); + } else if (pg->direction() == QPannableGesture::Left) { + qDebug() << "slide left"; + goPrevImage(); + } + updateImage(); + } + } + } else if (const QGesture *g = event->gesture(Qt::LongTap)) { + if (g->state() == Qt::GestureFinished) { + qDebug() << "tap and hold detected"; + touchFeedback.reset(); + update(); + + QMenu menu; + menu.addAction("Action 1"); + menu.addAction("Action 2"); + menu.addAction("Action 3"); + menu.exec(mapToGlobal(g->hotSpot())); + } + } else if (const QGesture *g = event->gesture(Qt::LongTap)) { + qDebug() << "long tap: " << (g->state() == Qt::GestureStarted ? "started" : "finished"); + } else { + qDebug() << "unknown gesture"; + } + feedbackFadeOutTimer.start(500, this); + event->accept(); +} + +void ImageWidget::resizeEvent(QResizeEvent*) +{ + updateImage(); +} + +void ImageWidget::updateImage() +{ + // should use qtconcurrent here? + transformation = QTransform(); + if (zoomedIn) { + } else { + if (currentImage.isNull()) + return; + if (zoomed) { + transformation = transformation.scale(zoom, zoom); + } else { + double xscale = (double)width()/currentImage.width(); + double yscale = (double)height()/currentImage.height(); + if (xscale < yscale) + yscale = xscale; + else + xscale = yscale; + transformation = transformation.scale(xscale, yscale); + } + if (rotated) + transformation = transformation.rotate(angle); + } + pixmap = QPixmap::fromImage(currentImage).transformed(transformation); + update(); +} + +void ImageWidget::openDirectory(const QString &path) +{ + this->path = path; + QDir dir(path); + QStringList nameFilters; + nameFilters << "*.jpg" << "*.png"; + files = dir.entryList(nameFilters, QDir::Files|QDir::Readable, QDir::Name); + + position = 0; + goToImage(0); + updateImage(); +} + +QImage ImageWidget::loadImage(const QString &fileName) +{ + QImageReader reader(fileName); + if (!reader.canRead()) { + qDebug() << fileName << ": can't load image"; + return QImage(); + } + QImage image; + if (!reader.read(&image)) { + qDebug() << fileName << ": corrupted image"; + return QImage(); + } + return image; +} + +void ImageWidget::setZoomedIn(bool zoomed) +{ + zoomedIn = zoomed; +} + +void ImageWidget::goNextImage() +{ + if (files.isEmpty()) + return; + if (position < files.size()-1) { + ++position; + prevImage = currentImage; + currentImage = nextImage; + if (position+1 < files.size()) + nextImage = loadImage(path+QLatin1String("/")+files.at(position+1)); + else + nextImage = QImage(); + } + setZoomedIn(false); + updateImage(); +} + +void ImageWidget::goPrevImage() +{ + if (files.isEmpty()) + return; + if (position > 0) { + --position; + nextImage = currentImage; + currentImage = prevImage; + if (position > 0) + prevImage = loadImage(path+QLatin1String("/")+files.at(position-1)); + else + prevImage = QImage(); + } + setZoomedIn(false); + updateImage(); +} + +void ImageWidget::goToImage(int index) +{ + if (files.isEmpty()) + return; + if (index < 0 || index >= files.size()) { + qDebug() << "goToImage: invalid index: " << index; + return; + } + if (index == position+1) { + goNextImage(); + return; + } + if (position > 0 && index == position-1) { + goPrevImage(); + return; + } + position = index; + pixmap = QPixmap(); + if (index > 0) + prevImage = loadImage(path+QLatin1String("/")+files.at(position-1)); + else + prevImage = QImage(); + currentImage = loadImage(path+QLatin1String("/")+files.at(position)); + if (position+1 < files.size()) + nextImage = loadImage(path+QLatin1String("/")+files.at(position+1)); + else + nextImage = QImage(); + setZoomedIn(false); + updateImage(); +} + +void ImageWidget::timerEvent(QTimerEvent *event) +{ + if (event->timerId() == touchFeedback.tapTimer.timerId()) { + touchFeedback.tapTimer.stop(); + } else if (event->timerId() == feedbackFadeOutTimer.timerId()) { + feedbackFadeOutTimer.stop(); + touchFeedback.reset(); + } + update(); +} diff --git a/examples/gestures/imageviewer/imagewidget.h b/examples/gestures/imageviewer/imagewidget.h new file mode 100644 index 0000000..56fcb40 --- /dev/null +++ b/examples/gestures/imageviewer/imagewidget.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef IMAGEWIDGET_H +#define IMAGEWIDGET_H + +#include +#include +#include + +#include + +class ImageWidget : public QWidget +{ +public: + ImageWidget(QWidget *parent = 0); + + void openDirectory(const QString &path); + +protected: + void paintEvent(QPaintEvent*); + void gestureEvent(QGestureEvent *event); + void resizeEvent(QResizeEvent*); + void timerEvent(QTimerEvent*); + +private: + void updateImage(); + QImage loadImage(const QString &fileName); + void loadImage(); + void setZoomedIn(bool zoomed); + void goNextImage(); + void goPrevImage(); + void goToImage(int index); + + QString path; + QStringList files; + int position; + + QImage prevImage, nextImage; + QImage currentImage; + QPixmap pixmap; + QTransform transformation; + + bool zoomedIn; + int horizontalOffset; + int verticalOffset; + + bool zoomed; + qreal zoom; + bool rotated; + qreal angle; + + struct TouchFeedback + { + bool tapped; + QPoint position; + bool sliding; + QPoint slidingStartPosition; + QBasicTimer tapTimer; + int tapState; + bool doubleTapped; + int tapAndHoldState; + + enum { MaximumNumberOfTouches = 5 }; + QPoint touches[MaximumNumberOfTouches]; + + inline TouchFeedback() { reset(); } + inline void reset() + { + tapped = false; + sliding = false; + tapTimer.stop(); + tapState = 0; + doubleTapped = false; + tapAndHoldState = 0; + for (int i = 0; i < MaximumNumberOfTouches; ++i) { + touches[i] = QPoint(); + } + } + } touchFeedback; + QBasicTimer feedbackFadeOutTimer; +}; + +#endif diff --git a/examples/gestures/imageviewer/main.cpp b/examples/gestures/imageviewer/main.cpp new file mode 100644 index 0000000..5494b12 --- /dev/null +++ b/examples/gestures/imageviewer/main.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "imagewidget.h" + +class MainWidget : public QMainWindow +{ + Q_OBJECT + +public: + MainWidget(QWidget *parent = 0); + +public slots: + void openDirectory(const QString &path); + +private: + bool loadImage(const QString &fileName); + + ImageWidget *imageWidget; +}; + +MainWidget::MainWidget(QWidget *parent) + : QMainWindow(parent) +{ + resize(400, 300); + imageWidget = new ImageWidget(this); + setCentralWidget(imageWidget); +} + +void MainWidget::openDirectory(const QString &path) +{ + imageWidget->openDirectory(path); +} + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + QApplication::setAttribute(Qt::AA_EnableGestures); + + MainWidget w; + w.show(); + + if (QApplication::arguments().size() > 1) + w.openDirectory(QApplication::arguments().at(1)); + return app.exec(); +} + +#include "main.moc" diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index 1635f8a..5747c3c 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -1550,6 +1550,21 @@ public: TouchPointStationary, TouchPointReleased }; + + typedef QString GestureType; + static const char UnknownGesture[] = "???"; + static const char Tap[] = "Tap"; + static const char DoubleTap[] = "DoubleTap"; + static const char LongTap[] = "LongTap"; + static const char Pan[] = "Pan"; + static const char Pinch[] = "Pinch"; + + enum GestureState + { + GestureStarted = 0, + GestureFinished = 1 + }; + } #ifdef Q_MOC_RUN ; diff --git a/src/corelib/kernel/qcoreevent.h b/src/corelib/kernel/qcoreevent.h index 42a75f8..c9f9f24 100644 --- a/src/corelib/kernel/qcoreevent.h +++ b/src/corelib/kernel/qcoreevent.h @@ -273,6 +273,8 @@ public: GraphicsSceneTouchUpdate = 197, GraphicsSceneTouchEnd = 198, + Gesture = 191, + // 512 reserved for Qt Jambi's MetaCall event // 513 reserved for Qt Jambi's DeleteOnMainThread event diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 3eef396..58f04f0 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -5788,6 +5788,20 @@ QVariant QGraphicsItem::inputMethodQuery(Qt::InputMethodQuery query) const return QVariant(); } +void QGraphicsItem::grabGesture(const Qt::GestureType &type) +{ + d_ptr->gestures.insert(type); + if (d_ptr->scene) + d_ptr->scene->d_func()->grabGesture(this, type); +} + +void QGraphicsItem::releaseGesture(const Qt::GestureType &type) +{ + d_ptr->gestures.remove(type); + if (d_ptr->scene) + d_ptr->scene->d_func()->releaseGesture(this, type); +} + /*! This virtual function is called by QGraphicsItem to notify custom items that some part of the item's state changes. By reimplementing this @@ -5812,6 +5826,20 @@ QVariant QGraphicsItem::inputMethodQuery(Qt::InputMethodQuery query) const QVariant QGraphicsItem::itemChange(GraphicsItemChange change, const QVariant &value) { Q_UNUSED(change); + if (change == QGraphicsItem::ItemSceneChange) { + if (!qVariantValue(value)) { + // the item has been removed from a scene, unsubscribe gestures. + Q_ASSERT(d_ptr->scene); + foreach(const Qt::GestureType &gesture, d_ptr->gestures) + d_ptr->scene->d_func()->releaseGesture(this, gesture); + } + } else if (change == QGraphicsItem::ItemSceneHasChanged) { + if (QGraphicsScene *scene = qVariantValue(value)) { + // item has been added to the scene + foreach(const Qt::GestureType &gesture, d_ptr->gestures) + scene->d_func()->grabGesture(this, gesture); + } + } return value; } diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h index ec3373a..42a5110 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -338,6 +338,9 @@ public: QVariant data(int key) const; void setData(int key, const QVariant &value); + void grabGesture(const Qt::GestureType &type); + void releaseGesture(const Qt::GestureType &type); + enum { Type = 1, UserType = 65536 diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 5e77dfd..a67a49a 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -54,6 +54,7 @@ // #include "qgraphicsitem.h" +#include "qset.h" #if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW @@ -297,6 +298,7 @@ public: int siblingIndex; int index; int depth; + QSet gestures; // Packed 32 bytes quint32 acceptedMouseButtons : 5; diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index f322305..fe6dde1 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -3950,6 +3950,9 @@ bool QGraphicsScene::event(QEvent *event) // geometries that do not have an explicit style set. update(); break; + case QEvent::Gesture: + gestureEvent(static_cast(event)); + break; case QEvent::GraphicsSceneTouchBegin: d->touchBeginEvent(static_cast(event)); break; @@ -5586,6 +5589,65 @@ void QGraphicsScene::setActiveWindow(QGraphicsWidget *widget) } } +void QGraphicsScenePrivate::addView(QGraphicsView *view) +{ + views << view; + foreach(const Qt::GestureType &gesture, grabbedGestures) + view->grabGesture(gesture); +} + +void QGraphicsScenePrivate::removeView(QGraphicsView *view) +{ + views.removeAll(view); + foreach(const Qt::GestureType &gesture, grabbedGestures) + view->releaseGesture(gesture); +} + +void QGraphicsScenePrivate::sendGestureEvent(QGraphicsItem *item, QGestureEvent *event) +{ + //### TODO: position translation + sendEvent(item, event); +} + +void QGraphicsScene::gestureEvent(QGestureEvent *event) +{ + Q_D(QGraphicsScene); + QList gestureTypes = event->gestureTypes(); + QList pts; + QGraphicsView *view = qobject_cast(event->targetWidget()); + if (!view) { + // something is wrong. + Q_ASSERT(view); + return; + } + foreach(const Qt::GestureType &type, gestureTypes) + pts << view->mapToScene(event->gesture(type)->hotSpot()); + foreach(QGraphicsItem *item, d->itemsWithGestures) { + for (int i = 0; i < pts.size(); ++i) { + if (item->contains(item->mapFromScene(pts.at(i)))) { + d->sendGestureEvent(item, event); + if (event->isAccepted()) + break; + } + } + } +} + +void QGraphicsScenePrivate::grabGesture(QGraphicsItem *item, const Qt::GestureType &type) +{ + if (!grabbedGestures.contains(type)) { + foreach(QGraphicsView *view, views) + view->grabGesture(type); + } + itemsWithGestures << item; + grabbedGestures << type; +} + +void QGraphicsScenePrivate::releaseGesture(QGraphicsItem *item, const Qt::GestureType &type) +{ + //### +} + // ### FIXME: the code for touch event support is mosly copied from // ### QGraphicsScenePrivate::mousePressEventHandler() and friends, need to // ### refactor to reduce code duplication diff --git a/src/gui/graphicsview/qgraphicsscene.h b/src/gui/graphicsview/qgraphicsscene.h index 9802f87..4680455 100644 --- a/src/gui/graphicsview/qgraphicsscene.h +++ b/src/gui/graphicsview/qgraphicsscene.h @@ -50,6 +50,7 @@ #include #include #include +#include QT_BEGIN_HEADER @@ -254,6 +255,7 @@ protected: virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); virtual void wheelEvent(QGraphicsSceneWheelEvent *event); virtual void inputMethodEvent(QInputMethodEvent *event); + virtual void gestureEvent(QGestureEvent *event); virtual void drawBackground(QPainter *painter, const QRectF &rect); virtual void drawForeground(QPainter *painter, const QRectF &rect); diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index de39205..cea0553 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -182,6 +182,9 @@ public: void storeMouseButtonsForMouseGrabber(QGraphicsSceneMouseEvent *event); QList views; + void addView(QGraphicsView *view); + void removeView(QGraphicsView *view); + bool painterStateProtection; QMultiMap sceneEventFilters; @@ -264,6 +267,12 @@ public: void resolvePalette(); void updatePalette(const QPalette &palette); + QSet itemsWithGestures; + QSet grabbedGestures; + void grabGesture(QGraphicsItem *item, const Qt::GestureType &type); + void releaseGesture(QGraphicsItem *item, const Qt::GestureType &type); + void sendGestureEvent(QGraphicsItem *item, QGestureEvent *event); + mutable QVector sceneTransformCache; mutable QBitArray validTransforms; mutable QVector freeSceneTransformSlots; diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 1aaaab9..acce717 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -1690,7 +1690,7 @@ void QGraphicsView::setScene(QGraphicsScene *scene) this, SLOT(updateScene(QList))); disconnect(d->scene, SIGNAL(sceneRectChanged(QRectF)), this, SLOT(updateSceneRect(QRectF))); - d->scene->d_func()->views.removeAll(this); + d->scene->d_func()->removeView(this); } // Assign the new scene and update the contents (scrollbars, etc.)). @@ -1698,7 +1698,7 @@ void QGraphicsView::setScene(QGraphicsScene *scene) connect(d->scene, SIGNAL(sceneRectChanged(QRectF)), this, SLOT(updateSceneRect(QRectF))); d->updateSceneSlotReimplementedChecked = false; - d->scene->d_func()->views << this; + d->scene->d_func()->addView(this); d->recalculateContentSize(); d->lastCenterPoint = sceneRect().center(); d->keepLastCenterPoint = true; @@ -2860,6 +2860,11 @@ bool QGraphicsView::event(QEvent *event) } } break; + case QEvent::Gesture: + QApplication::sendEvent(d->scene, event); + if (event->isAccepted()) + return true; + break; default: break; } diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index a1b982a..b6ef6b2 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -41,7 +41,13 @@ HEADERS += \ kernel/qwidgetaction.h \ kernel/qwidgetaction_p.h \ kernel/qwindowdefs.h \ - kernel/qkeymapper_p.h + kernel/qkeymapper_p.h \ + kernel/qgesture.h \ + kernel/qgesturemanager_p.h \ + kernel/qgesturerecognizer.h \ + kernel/qgesturestandardrecognizers_p.h \ + kernel/qdirectionrecognizer_p.h \ + kernel/qdirectionsimplificator_p.h SOURCES += \ kernel/qaction.cpp \ @@ -70,7 +76,11 @@ SOURCES += \ kernel/qwhatsthis.cpp \ kernel/qwidget.cpp \ kernel/qwidgetaction.cpp \ - kernel/qkeymapper.cpp + kernel/qkeymapper.cpp \ + kernel/qgesture.cpp \ + kernel/qgesturemanager.cpp \ + kernel/qgesturestandardrecognizers.cpp \ + kernel/qdirectionrecognizer.cpp win32 { DEFINES += QT_NO_DIRECTDRAW diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 1f4e1fe..b39cbc3 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -90,6 +90,8 @@ #include "qapplication.h" +#include + #ifdef Q_WS_WINCE #include "qdatetime.h" #include "qguifunctions_wince.h" @@ -98,6 +100,8 @@ extern bool qt_wince_is_mobile(); //qguifunctions_wince.cpp extern bool qt_wince_is_pocket_pc(); //qguifunctions_wince.cpp #endif +#include "qdatetime.h" + //#define ALIEN_DEBUG static void initResources() @@ -133,6 +137,8 @@ int QApplicationPrivate::autoMaximizeThreshold = -1; bool QApplicationPrivate::autoSipEnabled = false; #endif +QGestureManager *gestureManager = 0; + QApplicationPrivate::QApplicationPrivate(int &argc, char **argv, QApplication::Type type) : QCoreApplicationPrivate(argc, argv) { @@ -3700,6 +3706,27 @@ bool QApplication::notify(QObject *receiver, QEvent *e) QMouseEvent* mouse = static_cast(e); QPoint relpos = mouse->pos(); + if (QApplication::testAttribute(Qt::AA_EnableGestures)) { + if (!gestureManager) + gestureManager = new QGestureManager; + // if we are in gesture mode, we send all mouse events + // directly to gesture recognizer. + if (gestureManager->inGestureMode()) { + // ### should I send events through all application event filters? + if (gestureManager->filterEvent(e)) + return true; + } + if (w && (mouse->type() != QEvent::MouseMove || mouse->buttons() != 0)) { + // find the gesture target widget + QWidget *target = w; + while (target && target->gestures().isEmpty()) + target = target->parentWidget(); + if (target) { + gestureManager->setGestureTargetWidget(target); + res = gestureManager->filterEvent(e); + } + } + } if (e->spontaneous()) { if (e->type() == QEvent::MouseButtonPress) { QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, @@ -3993,6 +4020,35 @@ bool QApplication::notify(QObject *receiver, QEvent *e) } break; #endif + + case QEvent::Gesture: { + QWidget *w = static_cast(receiver); + QGestureEvent *g = static_cast(e); + bool eventAccepted = g->isAccepted(); + // Q_ASSERT(g->gesture() != 0); + // const QGesture &gesture = *g->gesture(); + QPoint relPos(0,0); + while (w) { + // QGesture qge(gesture.gestureType(), gesture.startPos()+relPos, gesture.lastPos()+relPos, + // gesture.currentPos()+relPos, gesture.direction(), gesture.rect().translated(relPos), + // gesture.hotSpot()+relPos, gesture.state(), gesture.startTime()); + // QGestureEvent ge(&qge, false); + // ### TODO: fix widget-relative positions in gesture event. + QGestureEvent ge = *g; + ge.m_targetWidget = w; + ge.spont = g->spontaneous(); + res = d->notify_helper(w, w == receiver ? g : &ge); + g->spont = false; + eventAccepted = (w == receiver ? g : &ge)->isAccepted(); + if (res && eventAccepted) + break; + if (w->isWindow()) + break; + relPos += w->pos(); + w = w->parentWidget(); + } + break; + } case QEvent::TouchBegin: // Note: TouchUpdate and TouchEnd events are sent to d->currentMultitouchWidget and never propagated { @@ -4000,7 +4056,6 @@ bool QApplication::notify(QObject *receiver, QEvent *e) QWidget *origin = widget; QTouchEvent *touchEvent = static_cast(e); bool eventAccepted = touchEvent->isAccepted(); - if (widget->testAttribute(Qt::WA_AcceptTouchEvents) && e->spontaneous()) { // give the widget focus if the focus policy allows it QApplicationPrivate::giveFocusAccordingToFocusPolicy(widget, diff --git a/src/gui/kernel/qapplication.h b/src/gui/kernel/qapplication.h index 2baf6dc..634226f 100644 --- a/src/gui/kernel/qapplication.h +++ b/src/gui/kernel/qapplication.h @@ -374,6 +374,7 @@ private: friend class QDirectPainter; friend class QDirectPainterPrivate; #endif + friend class QGestureManager; #if defined(Q_WS_WIN) friend QApplicationPrivate* getQApplicationPrivateInternal(); diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index 1a2bad2..40e928d 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -428,6 +428,7 @@ public: void sendSyntheticEnterLeave(QWidget *widget); #endif + QMap grabbedGestures; static void updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent); #if defined(Q_WS_WIN) diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index 90376b3..060e948 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -4414,7 +4414,6 @@ bool QETWidget::translateMouseEvent(const XEvent *event) QMouseEvent e(type, pos, globalPos, button, buttons, modifiers); QApplicationPrivate::sendMouseEvent(widget, &e, alienWidget, this, &qt_button_down, qt_last_mouse_receiver); - if (type == QEvent::MouseButtonPress && button == Qt::RightButton && (openPopupCount == oldOpenPopupCount)) { @@ -5022,6 +5021,7 @@ bool QETWidget::translatePropertyEvent(const XEvent *event) return true; } + // // Paint event translation // diff --git a/src/gui/kernel/qdirectionrecognizer.cpp b/src/gui/kernel/qdirectionrecognizer.cpp new file mode 100644 index 0000000..37b64e7 --- /dev/null +++ b/src/gui/kernel/qdirectionrecognizer.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdirectionrecognizer_p.h" + +#include + +QT_BEGIN_NAMESPACE + +static const int SIZE = 20; + +QDirectionSimpleRecognizer::QDirectionSimpleRecognizer() +{ +} + +Direction QDirectionSimpleRecognizer::addPosition(const QPoint &pos) +{ + if (!directions.isEmpty()) { + const QPoint tmp = pos - directions.back().point; + if (tmp.manhattanLength() < 5) + return Direction(); + } + if (lastPoint.isNull()) { + lastPoint = pos; + return Direction(); + } + int dx = pos.x() - lastPoint.x(); + int dy = pos.y() - lastPoint.y(); + Direction::DirectionType direction = Direction::None; + if (dx < 0) { + if (-1*dx >= SIZE/2) + direction = Direction::Left; + } else { + if (dx >= SIZE/2) + direction = Direction::Right; + } + if (dy < 0) { + if (-1*dy >= SIZE/2) + direction = Direction::Up; + } else { + if (dy >= SIZE/2) + direction = Direction::Down; + } + if (direction == Direction::None) + return Direction(); + + lastPoint = pos; + directions.push_back(Direction(direction, pos)); + return Direction(direction, pos); +} + + +DirectionList QDirectionSimpleRecognizer::getDirections() const +{ + return directions; +} + +void QDirectionSimpleRecognizer::reset() +{ + directions.clear(); + lastPoint = QPoint(); +} + + +/// QDirectionDiagonalRecognizer + +QDirectionDiagonalRecognizer::QDirectionDiagonalRecognizer() +{ +} + +Direction QDirectionDiagonalRecognizer::addPosition(const QPoint &pos) +{ + if (!directions.isEmpty()) { + const QPoint tmp = pos - directions.back().point; + if (tmp.manhattanLength() < 5) + return Direction(); + } + if (lastPoint.isNull()) { + lastPoint = pos; + return Direction(); + } + int dx = pos.x() - lastPoint.x(); + int dy = pos.y() - lastPoint.y(); + int distance = sqrt(static_cast(dx*dx + dy*dy)); + if (distance < SIZE/2) + return Direction(); + + Direction::DirectionType direction = Direction::None; + double angle = atan(1.0*qAbs(lastPoint.y() - pos.y())/qAbs(pos.x() - lastPoint.x())) * 180. / M_PI; + if (dx < 0 && dy <= 0) { + angle = 180 - angle; + } else if (dx <= 0 && dy > 0) { + angle += 180; + } else if (dx > 0 && dy > 0) { + angle = 360-angle; + } + if (angle < 0) + angle += 360; + if (angle <= 20) + direction = Direction::Right; + else if (angle <= 65) + direction = Direction::RightUp; + else if (angle <= 110) + direction = Direction::Up; + else if (angle <= 155) + direction = Direction::LeftUp; + else if (angle <= 200) + direction = Direction::Left; + else if (angle <= 245) + direction = Direction::LeftDown; + else if (angle <= 290) + direction = Direction::Down; + else if (angle <= 335) + direction = Direction::RightDown; + else + direction = Direction::Right; + + if (direction == Direction::None) + return Direction(); + + lastPoint = pos; + directions.push_back(Direction(direction, pos)); + return Direction(direction, pos); +} + + +DirectionList QDirectionDiagonalRecognizer::getDirections() const +{ + return directions; +} + +void QDirectionDiagonalRecognizer::reset() +{ + directions.clear(); + lastPoint = QPoint(); +} + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qdirectionrecognizer_p.h b/src/gui/kernel/qdirectionrecognizer_p.h new file mode 100644 index 0000000..6390990 --- /dev/null +++ b/src/gui/kernel/qdirectionrecognizer_p.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDIRECTIONRECOGNIZER_P_H +#define QDIRECTIONRECOGNIZER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qpoint.h" +#include "qlist.h" + +QT_BEGIN_NAMESPACE + +struct Direction +{ + enum DirectionType + { + None = 0, + LeftDown = 1, + DownLeft = LeftDown, + Down = 2, + RightDown = 3, + DownRight = RightDown, + Left = 4, + Right = 6, + LeftUp = 7, + UpLeft = LeftUp, + Up = 8, + RightUp = 9, + UpRight = RightUp + }; + DirectionType direction; + QPoint point; + + Direction(DirectionType dir, const QPoint &pt) + : direction(dir), point(pt) { } + Direction() + : direction(None) { } + + inline bool isEmpty() const { return direction == None; } + inline bool isNull() const { return direction == None; } +}; + +typedef QList DirectionList; + +class QDirectionSimpleRecognizer +{ +public: + QDirectionSimpleRecognizer(); + Direction addPosition(const QPoint &pos); + DirectionList getDirections() const; + void reset(); + +private: + QPoint lastPoint; + DirectionList directions; +}; + +class QDirectionDiagonalRecognizer +{ +public: + QDirectionDiagonalRecognizer(); + Direction addPosition(const QPoint &pos); + DirectionList getDirections() const; + void reset(); + +private: + QPoint lastPoint; + DirectionList directions; +}; + +QT_END_NAMESPACE + +#endif // QDIRECTIONRECOGNIZER_P_H diff --git a/src/gui/kernel/qdirectionsimplificator_p.h b/src/gui/kernel/qdirectionsimplificator_p.h new file mode 100644 index 0000000..7b71ca0 --- /dev/null +++ b/src/gui/kernel/qdirectionsimplificator_p.h @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDIRECTIONSIMPLIFICATOR_P_H +#define QDIRECTIONSIMPLIFICATOR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qdirectionrecognizer_p.h" + +QT_BEGIN_NAMESPACE + +class QDirectionSimplificator +{ +public: + QDirectionSimplificator(const DirectionList &dir); + + bool simplify(DirectionList *result); + +private: + DirectionList directions; + DirectionList lastResult; + enum State { + None, + Trim, // remove first and last element + AccidentalMoves, // 66866 => 6666 + ComplexAccidentalMoves, // 778788 => 777888 (swapping elements without changing direction) + ShortMoves, // (moves of length 1) + } state; + + struct SimplifyTrim + { + SimplifyTrim() : state(0) { } + bool operator()(DirectionList &directions) + { + if (state == 0) { + directions.removeFirst(); + state = 1; + } else if (state == 1) { + directions.removeLast(); + state = 2; + } else if (state == 2 && directions.size() >= 2) { + directions.removeFirst(); + directions.removeLast(); + state = 3; + } else { + return false; + } + return true; + } + int state; + }; + struct SimplifyAccidentalMoves + { + SimplifyAccidentalMoves() : state(0) { } + bool operator()(DirectionList &directions) + { + return false; + } + int state; + }; + struct SimplifyComplexAccidentalMoves + { + SimplifyComplexAccidentalMoves() : state(0) { } + bool operator()(DirectionList &directions) + { + return false; + } + int state; + }; + + SimplifyTrim trim; + SimplifyAccidentalMoves accidentalMoves; + SimplifyComplexAccidentalMoves complexAccidentalMoves; + //SimplifyShortMoves shortMoves; +}; + +QDirectionSimplificator::QDirectionSimplificator(const DirectionList &dir) + : directions(dir), state(None) +{ +} + +bool QDirectionSimplificator::simplify(DirectionList *result) +{ + if (directions.isEmpty() || !result) + return false; + *result = directions; + switch(state) { + case None: + state = Trim; + trim = SimplifyTrim(); + case Trim: + if (trim(*result)) + break; + *result = lastResult; + state = AccidentalMoves; + accidentalMoves = SimplifyAccidentalMoves(); + case AccidentalMoves: + if (accidentalMoves(*result)) + break; + *result = lastResult; + state = ComplexAccidentalMoves; + complexAccidentalMoves = SimplifyComplexAccidentalMoves(); + case ComplexAccidentalMoves: + if (complexAccidentalMoves(*result)) + break; + *result = lastResult; + // state = ShortMoves; + // shortMoves = SimplifyShortMoves(); + // case ShortMoves: + // if (shortMoves(*result)) + // break; + // state = None; + default: + return false; + } + lastResult = *result; + if (lastResult.isEmpty()) + return false; + return true; +} + +QT_END_NAMESPACE + +#endif // QDIRECTIONSIMPLIFICATOR_P_H diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index d571212..a7e1101 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -3310,6 +3310,9 @@ QDebug operator<<(QDebug dbg, const QEvent *e) { case QEvent::ChildRemoved: n = n ? n : "ChildRemoved"; dbg.nospace() << "QChildEvent(" << n << ", " << (static_cast(e))->child(); return dbg.space(); + case QEvent::Gesture: + n = "Gesture"; + break; default: dbg.nospace() << "QEvent(" << (const void *)e << ", type = " << e->type() << ')'; return dbg.space(); @@ -3506,6 +3509,27 @@ QMenubarUpdatedEvent::QMenubarUpdatedEvent(QMenuBar * const menuBar) #endif +QGestureEvent::QGestureEvent(QWidget *targetWidget, const QList &gestures, + const QSet &cancelledGestures) + : QEvent(QEvent::Gesture), m_targetWidget(targetWidget), + m_cancelledGestures(cancelledGestures) +{ + foreach(QGesture *r, gestures) + m_gestures.insert(r->gestureType(), QSharedPointer(r)); +} + +QGestureEvent::QGestureEvent(const QGestureEvent &event, const QPoint &offset) + : QEvent(QEvent::Gesture), m_targetWidget(event.m_targetWidget), + m_gestures(event.m_gestures), + m_cancelledGestures(event.m_cancelledGestures) +{ + //### use offset! +} + +QGestureEvent::~QGestureEvent() +{ +} + /*! \class QTouchEvent \brief The QTouchEvent class contains parameters that describe a touch event . diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index e9a1386..858e2ea 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -52,6 +52,10 @@ #include #include #include +#include +#include +#include +#include QT_BEGIN_HEADER @@ -710,6 +714,36 @@ private: }; #endif +class Q_GUI_EXPORT QGestureEvent : public QEvent +{ +public: + QGestureEvent(QWidget *targetWidget, const QList &gestures, + const QSet &cancelledGestures = QSet()); + // internal ctor + QGestureEvent(const QGestureEvent &gestures, const QPoint &offset); + ~QGestureEvent(); + + QWidget *targetWidget() const + { return m_targetWidget; } + + inline bool contains(const Qt::GestureType &gestureType) const + { return gesture(gestureType) != 0; } + inline QList gestureTypes() const + { return m_gestures.keys(); } + inline const QGesture* gesture(const Qt::GestureType &gestureType) const + { return m_gestures.value(gestureType, QSharedPointer()).data(); } + + inline QSet cancelledGestures() const + { return m_cancelledGestures; } + +protected: + QWidget *m_targetWidget; + QHash > m_gestures; + QSet m_cancelledGestures; + + friend class QApplication; +}; + #ifndef QT_NO_DEBUG_STREAM Q_GUI_EXPORT QDebug operator<<(QDebug, const QEvent *); #endif diff --git a/src/gui/kernel/qgesture.cpp b/src/gui/kernel/qgesture.cpp new file mode 100644 index 0000000..fbabb8f --- /dev/null +++ b/src/gui/kernel/qgesture.cpp @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgesture.h" +#include + +QGesture::QGesture(const Qt::GestureType &type, Qt::GestureState state) + : d(new QGesturePrivate), gestureType_(type), gestureState_(state) +{ +} + +QGesture::QGesture(const Qt::GestureType &type, const QPoint &startPos, + const QPoint &lastPos, const QPoint &pos, const QRect &rect, + const QPoint &hotSpot, const QDateTime &startTime, + uint duration, Qt::GestureState state) + : d(new QGesturePrivate), gestureType_(type), gestureState_(state) +{ + d->init(startPos, lastPos, pos, rect, hotSpot, startTime, duration); +} + +QGesture::QGesture(QGesturePrivate &dd, const Qt::GestureType &type, + Qt::GestureState state) + : d(&dd), gestureType_(type), gestureState_(state) +{ +} + +QGesture::~QGesture() +{ + delete d; d = 0; +} + +QRect QGesture::rect() const +{ + return d->rect; +} + +QPoint QGesture::hotSpot() const +{ + return d->hotSpot; +} + +QDateTime QGesture::startTime() const +{ + return d->startTime; +} + +uint QGesture::duration() const +{ + return d->duration; +} + +QPoint QGesture::startPos() const +{ + return d->startPos; +} + +QPoint QGesture::lastPos() const +{ + return d->lastPos; +} + +QPoint QGesture::pos() const +{ + return d->pos; +} + +QPannableGesture::QPannableGesture(const Qt::GestureType &type, Qt::GestureState state) + : QGesture(*new QPannableGesturePrivate, type, state) +{ +} + +QPannableGesture::QPannableGesture(const Qt::GestureType &type, const QPoint &startPos, + const QPoint &lastPos, const QPoint &pos, const QRect &rect, + const QPoint &hotSpot, const QDateTime &startTime, + uint duration, Qt::GestureState state) + : QGesture(*new QPannableGesturePrivate, type, state) +{ + d->init(startPos, lastPos, pos, rect, hotSpot, startTime, duration); + ((QPannableGesturePrivate*)d)->lastDirection = QPannableGesture::None; + ((QPannableGesturePrivate*)d)->direction = QPannableGesture::None; +} + +QPannableGesture::~QPannableGesture() +{ +} + +QPannableGesture::DirectionType QPannableGesture::lastDirection() const +{ + return ((QPannableGesturePrivate*)d)->lastDirection; +} + +QPannableGesture::DirectionType QPannableGesture::direction() const +{ + return ((QPannableGesturePrivate*)d)->direction; +} diff --git a/src/gui/kernel/qgesture.h b/src/gui/kernel/qgesture.h new file mode 100644 index 0000000..16a5704 --- /dev/null +++ b/src/gui/kernel/qgesture.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGESTURE_H +#define QGESTURE_H + +#include "qobject.h" +#include "qlist.h" +#include "qdatetime.h" +#include "qpoint.h" +#include "qrect.h" +#include "qsharedpointer.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QGesturePrivate; +class Q_GUI_EXPORT QGesture +{ +public: + explicit QGesture(const Qt::GestureType &type, Qt::GestureState state = Qt::GestureStarted); + QGesture(const Qt::GestureType &type, const QPoint &startPos, + const QPoint &lastPos, const QPoint &pos, const QRect &rect, + const QPoint &hotSpot, const QDateTime &startTime, + uint duration, Qt::GestureState state); + virtual ~QGesture(); + + inline Qt::GestureType gestureType() const { return gestureType_; } + inline Qt::GestureState state() const { return gestureState_; } + + QRect rect() const; + QPoint hotSpot() const; + QDateTime startTime() const; + uint duration() const; + + QPoint startPos() const; + QPoint lastPos() const; + QPoint pos() const; + +protected: + QGesture(QGesturePrivate &dd, const Qt::GestureType &type, Qt::GestureState state = Qt::GestureStarted); + QGesturePrivate *d; + +private: + Qt::GestureType gestureType_; + Qt::GestureState gestureState_; +}; + +class Q_GUI_EXPORT QPannableGesture : public QGesture +{ +public: + enum DirectionType + { + None = 0, + LeftDown = 1, + DownLeft = LeftDown, + Down = 2, + RightDown = 3, + DownRight = RightDown, + Left = 4, + Right = 6, + LeftUp = 7, + UpLeft = LeftUp, + Up = 8, + RightUp = 9, + UpRight = RightUp + }; + +public: + explicit QPannableGesture(const Qt::GestureType &type, Qt::GestureState state = Qt::GestureStarted); + QPannableGesture(const Qt::GestureType &type, const QPoint &startPos, + const QPoint &lastPos, const QPoint &pos, const QRect &rect, + const QPoint &hotSpot, const QDateTime &startTime, + uint duration, Qt::GestureState state); + ~QPannableGesture(); + + DirectionType lastDirection() const; + DirectionType direction() const; + + friend class QGestureRecognizerPan; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QGESTURE_H diff --git a/src/gui/kernel/qgesture_p.h b/src/gui/kernel/qgesture_p.h new file mode 100644 index 0000000..745590b --- /dev/null +++ b/src/gui/kernel/qgesture_p.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGESTURE_P_H +#define QGESTURE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qrect.h" +#include "qpoint.h" +#include "qdatetime.h" + +QT_BEGIN_NAMESPACE + +class QGesturePrivate +{ +public: + QGesturePrivate() + : duration(0) { } + + void init(const QPoint &startPos, const QPoint &lastPos, + const QPoint &pos, const QRect &rect, + const QPoint &hotSpot, const QDateTime &startTime, + uint duration) + { + this->rect = rect; + this->hotSpot = hotSpot; + this->startTime = startTime; + this->duration = duration; + this->startPos = startPos; + this->lastPos = lastPos; + this->pos = pos; + } + + QRect rect; + QPoint hotSpot; + QDateTime startTime; + uint duration; + QPoint startPos; + QPoint lastPos; + QPoint pos; +}; + +class QPannableGesturePrivate : public QGesturePrivate +{ +public: + QPannableGesture::DirectionType lastDirection; + QPannableGesture::DirectionType direction; +}; + +QT_END_NAMESPACE + +#endif // QGESTURE_P_H diff --git a/src/gui/kernel/qgesturemanager.cpp b/src/gui/kernel/qgesturemanager.cpp new file mode 100644 index 0000000..c244a0b --- /dev/null +++ b/src/gui/kernel/qgesturemanager.cpp @@ -0,0 +1,405 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgesturemanager_p.h" +#include "qgesture.h" +#include "qevent.h" + +#include "qapplication.h" +#include "private/qapplication_p.h" + +#include "private/qgesturestandardrecognizers_p.h" + +#include "qdebug.h" + +// #define GESTURE_DEBUG +#ifndef GESTURE_DEBUG +# define DEBUG if (0) qDebug +#else +# define DEBUG qDebug +#endif + +QT_BEGIN_NAMESPACE + +bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event); +static bool qt_sendGestureEvent(QWidget *receiver, QGestureEvent *event) +{ + QSet eventGestures = event->gestureTypes().toSet(); + while (receiver && (receiver->gestures() & eventGestures).isEmpty()) + receiver = receiver->parentWidget(); + return receiver ? qt_sendSpontaneousEvent(receiver, event) : false; +} + +static const unsigned int maximumGestureRecognitionTimeout = 2000; + +QGestureManager::QGestureManager() + : targetWidget(0), state(NotGesture) +{ + recognizers << new QDoubleTapGestureRecognizer(); + recognizers << new QLongTapGestureRecognizer(); + recognizers << new QGestureRecognizerPan(); + // recognizers << new QMultiTouchGestureRecognizer(); + + foreach(QGestureRecognizer *r, recognizers) + connect(r, SIGNAL(triggered(QGestureRecognizer::Result)), + this, SLOT(recognizerTriggered(QGestureRecognizer::Result))); +} + +bool QGestureManager::filterEvent(QEvent *event) +{ + if (!QApplication::testAttribute(Qt::AA_EnableGestures)) + return false; + + QList events; + events << event; + + QPoint currentPos; + switch (event->type()) { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + currentPos = static_cast(event)->pos(); break; + default: break; + } + + const QMap &grabbedGestures = qApp->d_func()->grabbedGestures; + + bool ret = false; + QSet startedGestures; + QSet finishedGestures; + QSet newMaybeGestures; + QSet cancelledGestures; + QSet notGestures; + if (state == NotGesture || state == MaybeGesture) { + DEBUG() << "QGestureManager: current event processing state: " + << (state == NotGesture ? "NotGesture" : "MaybeGesture"); + + Q_ASSERT(targetWidget != 0); + QSet stillMaybeGestures; + // try other recognizers. + foreach(QGestureRecognizer *r, recognizers) { + if (grabbedGestures.value(r->gestureType(), 0) <= 0) + continue; + QGestureRecognizer::Result result = r->recognize(events); + if (result == QGestureRecognizer::GestureStarted) { + DEBUG() << "QGestureManager: gesture started: " << r; + startedGestures << r; + } else if (result == QGestureRecognizer::GestureFinished) { + DEBUG() << "QGestureManager: gesture finished: " << r; + finishedGestures << r; + } else if (result == QGestureRecognizer::MaybeGesture) { + DEBUG() << "QGestureManager: maybe gesture: " << r; + newMaybeGestures << r; + } else { + // if it was maybe gesture, but isn't a gesture anymore. + DEBUG() << "QGestureManager: not gesture: " << r; + notGestures << r; + } + } + activeGestures -= newMaybeGestures; + activeGestures += startedGestures; + foreach(QGestureRecognizer *r, startedGestures+notGestures) { + QMap::iterator it = maybeGestures.find(r); + if (it != maybeGestures.end()) { + killTimer(it.value()); + maybeGestures.erase(it); + } + } + foreach(QGestureRecognizer *r, newMaybeGestures) { + if (!maybeGestures.contains(r)) { + int timerId = startTimer(maximumGestureRecognitionTimeout); + if (!timerId) + qWarning("QGestureManager: couldn't start timer!"); + maybeGestures.insert(r, timerId); + } + } + if (!finishedGestures.isEmpty() || !activeGestures.isEmpty()) { + // gesture found! + ret = true; + DEBUG() << "QGestureManager: sending gesture event for: " + << activeGestures << " and " << finishedGestures; + + QList gestures; + foreach(QGestureRecognizer *r, finishedGestures) { + if (QGesture *gesture = r->makeEvent()) + gestures << gesture; + } + foreach(QGestureRecognizer *r, activeGestures) { + if (QGesture *gesture = r->makeEvent()) + gestures << gesture; + } + Q_ASSERT(!gestures.isEmpty()); + QGestureEvent event(targetWidget, gestures); + qt_sendGestureEvent(targetWidget, &event); + + if (!activeGestures.isEmpty()) { + DEBUG() << "QGestureManager: new state = Gesture"; + state = Gesture; + } else if (!maybeGestures.isEmpty()) { + DEBUG() << "QGestureManager: new state = Maybe"; + state = MaybeGesture; + } else { + DEBUG() << "QGestureManager: new state = NotGesture"; + state = NotGesture; + } + } else if (!maybeGestures.isEmpty()) { + if (state != MaybeGesture) { + // We got a new set of events that look like a start + // of some gesture, so we switch to state MaybeGesture + // and wait for more events. + DEBUG() << "QGestureManager: new state = Maybe. Waiting for events"; + state = MaybeGesture; + // start gesture timer + } else { + // we still not sure if it is a gesture or not. + } + } else if (state == MaybeGesture) { + // last time we thought it looks like gesture, but now we + // know for sure that it isn't. + DEBUG() << "QGestureManager: new state = NotGesture"; + state = NotGesture; + } + foreach(QGestureRecognizer *r, finishedGestures) + r->reset(); + foreach(QGestureRecognizer *r, cancelledGestures) + r->reset(); + foreach(QGestureRecognizer *r, notGestures) + r->reset(); + } else if (state == Gesture) { + DEBUG() << "QGestureManager: current event processing state: Gesture"; + Q_ASSERT(!activeGestures.isEmpty()); + + foreach(QGestureRecognizer *r, recognizers) { + if (grabbedGestures.value(r->gestureType(), 0) <= 0) + continue; + QGestureRecognizer::Result result = r->recognize(events); + if (result == QGestureRecognizer::GestureStarted) { + DEBUG() << "QGestureManager: gesture started: " << r; + startedGestures << r; + } else if (result == QGestureRecognizer::GestureFinished) { + DEBUG() << "QGestureManager: gesture finished: " << r; + finishedGestures << r; + } else if (result == QGestureRecognizer::MaybeGesture) { + DEBUG() << "QGestureManager: maybe gesture: " << r; + newMaybeGestures << r; + } else { + // if it was an active gesture, but isn't a gesture anymore. + if (activeGestures.contains(r)) { + DEBUG() << "QGestureManager: cancelled gesture: " << r; + cancelledGestures << r; + } else { + DEBUG() << "QGestureManager: not gesture: " << r; + notGestures << r; + } + } + } + + activeGestures -= newMaybeGestures; + activeGestures -= cancelledGestures; + activeGestures -= finishedGestures; + activeGestures += startedGestures; + foreach(QGestureRecognizer *r, startedGestures+finishedGestures+notGestures) { + QMap::iterator it = maybeGestures.find(r); + if (it != maybeGestures.end()) { + killTimer(it.value()); + maybeGestures.erase(it); + } + } + foreach(QGestureRecognizer *r, newMaybeGestures) { + if (!maybeGestures.contains(r)) { + int timerId = startTimer(maximumGestureRecognitionTimeout); + if (!timerId) + qWarning("QGestureManager: couldn't start timer!"); + maybeGestures.insert(r, timerId); + } + } + QList gestures; + if (!finishedGestures.isEmpty() || !activeGestures.isEmpty()) { + // another gesture found! + ret = true; + DEBUG() << "QGestureManager: sending gesture event for: " + << activeGestures << " and " << finishedGestures; + + foreach(QGestureRecognizer *r, finishedGestures) { + if (QGesture *gesture = r->makeEvent()) + gestures << gesture; + } + foreach(QGestureRecognizer *r, activeGestures) { + if (QGesture *gesture = r->makeEvent()) + gestures << gesture; + } + } + QSet cancelledGestureNames; + foreach(QGestureRecognizer *r, cancelledGestures) + cancelledGestureNames << r->gestureType(); + if(!gestures.isEmpty()) { + QGestureEvent event(targetWidget, gestures, cancelledGestureNames); + qt_sendGestureEvent(targetWidget, &event); + } + + foreach(QGestureRecognizer *r, finishedGestures) + r->reset(); + foreach(QGestureRecognizer *r, cancelledGestures) + r->reset(); + foreach(QGestureRecognizer *r, notGestures) + r->reset(); + if (!activeGestures.isEmpty()) { + // nothing changed, we are still handling a gesture + } else if (!maybeGestures.isEmpty()) { + DEBUG() << "QGestureManager: new state = Maybe. Waiting for events: " << maybeGestures; + state = MaybeGesture; + } else { + DEBUG() << "QGestureManager: new state = NotGesture"; + state = NotGesture; + } + ret = true; + } + + lastPos = currentPos; + return ret; +} + +void QGestureManager::timerEvent(QTimerEvent *event) +{ + // sanity checks, remove later + Q_ASSERT((state == Gesture && !activeGestures.isEmpty()) || (state != Gesture && activeGestures.isEmpty())); + + typedef QMap MaybeGestureMap; + for (MaybeGestureMap::iterator it = maybeGestures.begin(), e = maybeGestures.end(); + it != e; ++it) { + if (it.value() == event->timerId()) { + DEBUG() << "QGestureManager: gesture timeout."; + QGestureRecognizer *r = it.key(); + r->reset(); + maybeGestures.erase(it); + killTimer(event->timerId()); + break; + } + } + + if (state == MaybeGesture && maybeGestures.isEmpty()) { + DEBUG() << "QGestureManager: new state = NotGesture because of timeout"; + state = NotGesture; + } +} + +bool QGestureManager::inGestureMode() +{ + return state == Gesture; +} + +void QGestureManager::setGestureTargetWidget(QWidget *widget) +{ + targetWidget = widget; +} + +void QGestureManager::recognizerTriggered(QGestureRecognizer::Result result) +{ + if (!QApplication::testAttribute(Qt::AA_EnableGestures)) + return; + + QGestureRecognizer *recognizer = qobject_cast(sender()); + if (!recognizer) + return; + if (qApp->d_func()->grabbedGestures.value(recognizer->gestureType(), 0) <= 0) { + recognizer->reset(); + return; + } + + switch (result) { + case QGestureRecognizer::GestureStarted: + case QGestureRecognizer::GestureFinished: { + if (result == QGestureRecognizer::GestureStarted) { + DEBUG() << "QGestureManager: gesture started: " << recognizer; + activeGestures << recognizer; + DEBUG() << "QGestureManager: new state = Gesture"; + state = Gesture; + } else { + DEBUG() << "QGestureManager: gesture finished: " << recognizer; + } + if (maybeGestures.contains(recognizer)) { + killTimer(maybeGestures.value(recognizer)); + maybeGestures.remove(recognizer); + } + QList gestures; + if (QGesture *gesture = recognizer->makeEvent()) + gestures << gesture; + if(!gestures.isEmpty()) { + QGestureEvent event(targetWidget, gestures); + qt_sendGestureEvent(targetWidget, &event); + } + if (result == QGestureRecognizer::GestureFinished) + recognizer->reset(); + } + break; + case QGestureRecognizer::MaybeGesture: { + DEBUG() << "QGestureManager: maybe gesture: " << recognizer; + if (activeGestures.contains(recognizer)) { + QGestureEvent event(targetWidget, QList(), + QSet() << recognizer->gestureType()); + qt_sendGestureEvent(targetWidget, &event); + } + if (!maybeGestures.contains(recognizer)) { + int timerId = startTimer(maximumGestureRecognitionTimeout); + if (!timerId) + qWarning("QGestureManager: couldn't start timer!"); + maybeGestures.insert(recognizer, timerId); + } + } + break; + case QGestureRecognizer::NotGesture: + DEBUG() << "QGestureManager: not gesture: " << recognizer; + if (maybeGestures.contains(recognizer)) { + killTimer(maybeGestures.value(recognizer)); + maybeGestures.remove(recognizer); + } + recognizer->reset(); + break; + default: + Q_ASSERT(false); + } +} + +QT_END_NAMESPACE + +#include "moc_qgesturemanager_p.cpp" + diff --git a/src/gui/kernel/qgesturemanager_p.h b/src/gui/kernel/qgesturemanager_p.h new file mode 100644 index 0000000..9853f1a --- /dev/null +++ b/src/gui/kernel/qgesturemanager_p.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGESTUREMANAGER_P_H +#define QGESTUREMANAGER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qlist.h" +#include "qset.h" +#include "qevent.h" +#include "qbasictimer.h" + +#include "qgesturerecognizer.h" + +QT_BEGIN_NAMESPACE + +class Q_GUI_EXPORT QGestureManager : public QObject +{ + Q_OBJECT +public: + QGestureManager(); + + // should be internal + void setGestureTargetWidget(QWidget *widget); + + bool filterEvent(QEvent *event); + bool inGestureMode(); + +protected: + void timerEvent(QTimerEvent *event); + +private slots: + void recognizerTriggered(QGestureRecognizer::Result); + +private: + QSet activeGestures; + QMap maybeGestures; + QSet recognizers; + + QWidget *targetWidget; + QPoint lastPos; + + enum State { + Gesture, + NotGesture, + MaybeGesture // that mean timers are up and waiting for some + // more events, and input events are handled by + // gesture recognizer explicitely + } state; +}; + +QT_END_NAMESPACE + +#endif // QGESTUREMANAGER_P_H diff --git a/src/gui/kernel/qgesturerecognizer.h b/src/gui/kernel/qgesturerecognizer.h new file mode 100644 index 0000000..3ed96c0 --- /dev/null +++ b/src/gui/kernel/qgesturerecognizer.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGESTURERECOGNIZER_H +#define QGESTURERECOGNIZER_H + +#include "qgesture.h" +#include "qevent.h" +#include "qlist.h" +#include "qset.h" + +QT_BEGIN_NAMESPACE + +class QGestureRecognizer : public QObject +{ + Q_OBJECT +public: + enum Result + { + NotGesture, + GestureStarted, + GestureFinished, + MaybeGesture + }; + + inline QGestureRecognizer() { } + //### remove this ctor + inline QGestureRecognizer(const char *type) : type_(QLatin1String(type)) { } + inline QGestureRecognizer(const Qt::GestureType &type) : type_(type) { } + inline Qt::GestureType gestureType() const { return type_; } + + virtual Result recognize(const QList &inputEvents) = 0; + virtual QGesture* makeEvent() const = 0; + virtual void reset() = 0; + +signals: + void triggered(QGestureRecognizer::Result result); + +protected: + Qt::GestureType type_; +}; + +QT_END_NAMESPACE + +#endif // QGESTURERECOGNIZER_P_H diff --git a/src/gui/kernel/qgesturestandardrecognizers.cpp b/src/gui/kernel/qgesturestandardrecognizers.cpp new file mode 100644 index 0000000..3a2fa1d --- /dev/null +++ b/src/gui/kernel/qgesturestandardrecognizers.cpp @@ -0,0 +1,543 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgesturestandardrecognizers_p.h" +#include "qgesture_p.h" + +// #define GESTURE_RECOGNIZER_DEBUG +#ifndef GESTURE_RECOGNIZER_DEBUG +# define DEBUG if (0) qDebug +#else +# define DEBUG qDebug +#endif + +QT_BEGIN_NAMESPACE +/* +QGestureRecognizerMouseTwoButtons::QGestureRecognizerMouseTwoButtons() + : QGestureRecognizer(Qt::MouseTwoButtonClick) +{ + clear(); +} + +QGestureRecognizer::Result QGestureRecognizerMouseTwoButtons::recognize(const QList &inputEvents) +{ + // get all mouse events + QList events; + for(int i = 0; i < inputEvents.count(); ++i) { + QEvent *event = inputEvents.at(i); + switch (event->type()) { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + events.push_back(static_cast(event)); + default: + break; + } + } + + QGestureRecognizer::Result result = QGestureRecognizer::NotGesture; + for(int i = 0; i < events.count(); ++i) { + QMouseEvent *event = events.at(i); + if (event->type() == QEvent::MouseButtonPress) { + if (userEvents[3]) { + // something wrong, we already has a gesture. + clear(); + } else if (userEvents[2]) { + // 1d, 2d, 1u, and user press another button. not gesture. + DEBUG() << "1"; + result = QGestureRecognizer::NotGesture; + clear(); + break; + } else if (userEvents[1]) { + // 1d, 2d, and user pressed third button. not gesture. + DEBUG() << "2"; + result = QGestureRecognizer::NotGesture; + clear(); + break; + } else if (userEvents[0]) { + // second button press. + DEBUG() << "3"; + userEvents[1] = event; + result = QGestureRecognizer::MaybeGesture; + } else { + // first button press. + DEBUG() << "4"; + userEvents[0] = event; + result = QGestureRecognizer::MaybeGesture; + } + } else if (event->type() == QEvent::MouseButtonRelease) { + if (userEvents[3]) { + // something wrong, we already has a gesture. + clear(); + } else if (userEvents[2]) { + // 1d, 2d, 1u, and button release + DEBUG() << "5"; + if (userEvents[1]->button() != event->button()) { + // got weird buttonreleased event. doesn't look like gesture. + result = QGestureRecognizer::NotGesture; + clear(); + break; + } + // gesture! + userEvents[3] = event; + result = QGestureRecognizer::GestureFinished; + break; + } else if (userEvents[1]) { + // 1d, 2d, and button release + DEBUG() << "6"; + if (userEvents[0]->button() != event->button()) { + // user released the wrong button. not gesture. + result = QGestureRecognizer::NotGesture; + clear(); + break; + } + // user released the right button! looks like gesture + userEvents[2] = event; + result = QGestureRecognizer::MaybeGesture; + } else if (userEvents[0]) { + // 1d, and some button was released. not a gesture. + DEBUG() << "7"; + result = QGestureRecognizer::NotGesture; + clear(); + break; + } + } + } + return result; +} + +QGesture* QGestureRecognizerMouseTwoButtons::makeEvent() const +{ + if (!userEvents[0] || !userEvents[1] || !userEvents[2] || !userEvents[3]) + return 0; + QGesture::Direction direction = + (userEvents[0]->button() < userEvents[1]->button() ? + QGesture::Left : QGesture::Right); + QList points; + points.push_back(userEvents[0]->globalPos()); + points.push_back(userEvents[1]->globalPos()); + QGesture *gesture = + new QGesture(Qt::MouseTwoButtonClick, points.at(0), points.at(1), points.at(1), + direction, + QRect(points.at(0), points.at(1)), + points.at(0)); + return gesture; +} + +void QGestureRecognizerMouseTwoButtons::reset() +{ + clear(); +} + +void QGestureRecognizerMouseTwoButtons::clear() +{ + userEvents[0] = userEvents[1] = userEvents[2] = userEvents[3] = 0; +} +*/ + +// +// QGestureRecognizerPan +// + +QGestureRecognizerPan::QGestureRecognizerPan() + : QGestureRecognizer(Qt::Pan), mousePressed(false), gestureFinished(false), + lastDirection(Direction::None) +{ +} + +QGestureRecognizer::Result QGestureRecognizerPan::recognize(const QList &inputEvents) +{ + // get all mouse events + QList events; + for(int i = 0; i < inputEvents.count(); ++i) { + QEvent *event = inputEvents.at(i); + switch (event->type()) { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: + events.push_back(static_cast(event)); + default: + break; + } + } + + QGestureRecognizer::Result result = QGestureRecognizer::NotGesture; + for(int i = 0; i < events.count(); ++i) { + QMouseEvent *event = events.at(i); + if (event->type() == QEvent::MouseButtonPress) { + if (lastDirection != Direction::None) { + DEBUG() << "Pan: MouseButtonPress: fail. another press during pan"; + result = QGestureRecognizer::NotGesture; + reset(); + break; + } + DEBUG() << "Pan: MouseButtonPress: maybe gesture started"; + result = QGestureRecognizer::MaybeGesture; + mousePressed = true; + pressedPos = lastPos = currentPos = event->pos(); + } else if (event->type() == QEvent::MouseButtonRelease) { + if (mousePressed && lastDirection != Direction::None) { + DEBUG() << "Pan: MouseButtonRelease: pan detected"; + result = QGestureRecognizer::GestureFinished; + gestureFinished = true; + currentPos = event->pos(); + internalReset(); + break; + } + DEBUG() << "Pan: MouseButtonRelease: some weird release detected, ignoring"; + result = QGestureRecognizer::NotGesture; + reset(); + break; + } else if (event->type() == QEvent::MouseMove) { + if (!mousePressed) + continue; + lastPos = currentPos; + currentPos = event->pos(); + Direction::DirectionType direction = + simpleRecognizer.addPosition(event->pos()).direction; + DEBUG() << "Pan: MouseMove: simplerecognizer result = " << direction; + if (lastDirection == Direction::None) { + if (direction == Direction::None) + result = QGestureRecognizer::MaybeGesture; + else + result = QGestureRecognizer::GestureStarted; + } else { + result = QGestureRecognizer::GestureStarted; + } + if (direction != Direction::None) + lastDirection = direction; + } + } + return result; +} + +QGesture* QGestureRecognizerPan::makeEvent() const +{ + QPannableGesture::DirectionType dir = QPannableGesture::None; + if (lastDirection == Direction::Left) + dir = QPannableGesture::Left; + else if (lastDirection == Direction::Right) + dir = QPannableGesture::Right; + else if (lastDirection == Direction::Up) + dir = QPannableGesture::Up; + else if (lastDirection == Direction::Down) + dir = QPannableGesture::Down; + else + return 0; + QPannableGesture *g = + new QPannableGesture(Qt::Pan, pressedPos, lastPos, currentPos, + QRect(), pressedPos, QDateTime(), 0, + gestureFinished ? Qt::GestureFinished : Qt::GestureStarted); + QPannableGesturePrivate *d = (QPannableGesturePrivate*)g->d; + d->lastDirection = dir; ///### + d->direction = dir; + + return g; +} + +void QGestureRecognizerPan::reset() +{ + mousePressed = false; + lastDirection = Direction::None; + gestureFinished = false; + diagonalRecognizer.reset(); + simpleRecognizer.reset(); +} + +void QGestureRecognizerPan::internalReset() +{ + mousePressed = false; + diagonalRecognizer.reset(); + simpleRecognizer.reset(); +} + + +// +// QDoubleTapGestureRecognizer +// +QDoubleTapGestureRecognizer::QDoubleTapGestureRecognizer() + : QGestureRecognizer(Qt::DoubleTap) +{ +} + +QGestureRecognizer::Result QDoubleTapGestureRecognizer::recognize(const QList &inputEvents) +{ + // get all mouse events + QList events; + for(int i = 0; i < inputEvents.count(); ++i) { + QEvent *event = inputEvents.at(i); + switch (event->type()) { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + events.push_back(static_cast(event)); + default: + break; + } + } + + QGestureRecognizer::Result result = QGestureRecognizer::NotGesture; + for(int i = 0; i < events.count(); ++i) { + QMouseEvent *event = events.at(i); + if (event->type() == QEvent::MouseButtonPress) { + if (pressedPosition.isNull()) { + result = QGestureRecognizer::MaybeGesture; + pressedPosition = event->pos(); + } else if ((pressedPosition - event->pos()).manhattanLength() < 10) { + result = QGestureRecognizer::GestureFinished; + } + } else if (event->type() == QEvent::MouseButtonRelease) { + if (!pressedPosition.isNull() && (pressedPosition - event->pos()).manhattanLength() < 10) + result = QGestureRecognizer::MaybeGesture; + } else if (event->type() == QEvent::MouseButtonDblClick) { + result = QGestureRecognizer::GestureFinished; + pressedPosition = event->pos(); + break; + } + } + return result; +} + +QGesture* QDoubleTapGestureRecognizer::makeEvent() const +{ + return new QGesture(Qt::DoubleTap, + pressedPosition, pressedPosition, pressedPosition, + QRect(), pressedPosition, QDateTime(), 0, Qt::GestureFinished); +} + +void QDoubleTapGestureRecognizer::reset() +{ + pressedPosition = QPoint(); +} + +// +// QLongTapGestureRecognizer +// +const int QLongTapGestureRecognizer::iterationCount = 40; +const int QLongTapGestureRecognizer::iterationTimeout = 50; + +QLongTapGestureRecognizer::QLongTapGestureRecognizer() + : QGestureRecognizer(Qt::LongTap), iteration(0) +{ +} + +QGestureRecognizer::Result QLongTapGestureRecognizer::recognize(const QList &inputEvents) +{ + // get all mouse events + QList events; + for(int i = 0; i < inputEvents.count(); ++i) { + QEvent *event = inputEvents.at(i); + switch (event->type()) { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: + events.push_back(static_cast(event)); + default: + break; + } + } + + QGestureRecognizer::Result result = QGestureRecognizer::NotGesture; + for(int i = 0; i < events.count(); ++i) { + QMouseEvent *event = events.at(i); + if (event->type() == QEvent::MouseButtonPress) { + if (timer.isActive()) + timer.stop(); + timer.start(QLongTapGestureRecognizer::iterationTimeout, this); + pressedPosition = event->pos(); + result = QGestureRecognizer::MaybeGesture; + } else if (event->type() == QEvent::MouseMove) { + if ((pressedPosition - event->pos()).manhattanLength() < 15) + result = QGestureRecognizer::GestureStarted; + else + result = QGestureRecognizer::NotGesture; + } else if (event->type() == QEvent::MouseButtonRelease) { + result = QGestureRecognizer::NotGesture; + timer.stop(); + break; + } + } + return result; +} + +void QLongTapGestureRecognizer::timerEvent(QTimerEvent *event) +{ + if (event->timerId() != timer.timerId()) + return; + if (++iteration == QLongTapGestureRecognizer::iterationCount) { + emit triggered(QGestureRecognizer::GestureFinished); + timer.stop(); + } else { + emit triggered(QGestureRecognizer::GestureStarted); + } +} + +QGesture* QLongTapGestureRecognizer::makeEvent() const +{ + return new QGesture(Qt::LongTap, + pressedPosition, pressedPosition, pressedPosition, + QRect(), pressedPosition, QDateTime(), 0, + iteration >= QLongTapGestureRecognizer::iterationCount ? + Qt::GestureFinished : Qt::GestureStarted); +} + +void QLongTapGestureRecognizer::reset() +{ + pressedPosition = QPoint(); + timer.stop(); + iteration = 0; +} + +// +// QMultiTouchGestureRecognizer +// + +/* +QMultiTouchGestureRecognizer::QMultiTouchGestureRecognizer() + : QGestureRecognizer(Qt::Pinch) +{ +} + +QGestureRecognizer::Result QMultiTouchGestureRecognizer::recognize(const QList &inputEvents) +{ + QGestureRecognizer::Result result = QGestureRecognizer::NotGesture; + for(int i = 0; i < inputEvents.count(); ++i) { + QEvent *inputEvent = inputEvents.at(i); + if (inputEvent->type() != QEvent::Pointer) { + if (touches.size() == 2) + result = QGestureRecognizer::GestureStarted; + else if (touches.size() == 1) + result = QGestureRecognizer::MaybeGesture; + continue; + } + QPointerEvent *event = static_cast(inputEvent); + Q_ASSERT(event->pointerCount() > 0); + for (int idx = 0; idx < event->pointerCount(); ++idx) { + switch (event->state(idx)) { + case QPointerEvent::Begin: + qDebug() << "Begin" << idx; + if (touches.size() == 2) { + // too many touches + qDebug() << "too many touches"; + result = QGestureRecognizer::MaybeGesture; + continue; + } + touches[event->pointerId(idx)].startPosition = event->pos(idx); + if (touches.size() == 1) { + result = QGestureRecognizer::MaybeGesture; + } else if (touches.size() == 2) { + result = QGestureRecognizer::GestureStarted; + } else { + result = QGestureRecognizer::NotGesture; + } + break; + + case QPointerEvent::Move: + qDebug() << "Move" << idx; + touches[event->pointerId(idx)].lastPosition = touches[event->pointerId(idx)].currentPosition; + touches[event->pointerId(idx)].currentPosition = event->pos(idx); + if (touches.size() == 1) + result = QGestureRecognizer::MaybeGesture; + else if (touches.size() == 2) + result = QGestureRecognizer::GestureStarted; + else + result = QGestureRecognizer::NotGesture; + break; + + case QPointerEvent::End: + qDebug() << "End" << idx; + touches.remove(event->pointerId(idx)); + if (touches.size() == 1) { + result = QGestureRecognizer::MaybeGesture; + } else if (touches.size() == 0) { + result = QGestureRecognizer::NotGesture; + } else { + qDebug() << "unexpected touch end event"; + return QGestureRecognizer::NotGesture; + } + break; + + case QPointerEvent::Stationary: + qDebug() << "Stationary" << idx; + if (touches.size() == 2) + result = QGestureRecognizer::GestureStarted; + else if (touches.size() == 1) + result = QGestureRecognizer::MaybeGesture; + break; + + default: + break; + } + } + } + return result; +} + +QGesture* QMultiTouchGestureRecognizer::makeEvent() const +{ + if (touches.size() != 2) + return 0; + + QGesture *g = new QGesture(Qt::Pinch); + QGesture::Data data; + + TapMap::const_iterator it = touches.begin(); + data.startPos = it->startPosition.toPoint(); + data.lastPos = it->lastPosition.toPoint(); + data.currentPos = it->currentPosition.toPoint(); + g->datas.push_back(data); + + ++it; + data.startPos = it->startPosition.toPoint(); + data.lastPos = it->lastPosition.toPoint(); + data.currentPos = it->currentPosition.toPoint(); + g->datas.push_back(data); + + return g; +} + +void QMultiTouchGestureRecognizer::reset() +{ + touches.clear(); +} +*/ + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qgesturestandardrecognizers_p.h b/src/gui/kernel/qgesturestandardrecognizers_p.h new file mode 100644 index 0000000..3b314e7 --- /dev/null +++ b/src/gui/kernel/qgesturestandardrecognizers_p.h @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGESTURESTANDARDRECOGNIZERS_P_H +#define QGESTURESTANDARDRECOGNIZERS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qevent.h" +#include "qbasictimer.h" +#include "qdebug.h" + +#include "qgesturerecognizer.h" +#include "private/qdirectionrecognizer_p.h" + +QT_BEGIN_NAMESPACE + +/* +class QGestureRecognizerMouseTwoButtons : public QGestureRecognizer +{ + Q_OBJECT +public: + QGestureRecognizerMouseTwoButtons(); + QGestureRecognizer::Result recognize(const QList &inputEvents); + + QGesture* makeEvent() const; + void reset(); + +private: + void clear(); + + // find the last two button click events + QMouseEvent* userEvents[4]; +}; +*/ + +class QGestureRecognizerPan : public QGestureRecognizer +{ + Q_OBJECT +public: + QGestureRecognizerPan(); + + QGestureRecognizer::Result recognize(const QList &inputEvents); + QGesture* makeEvent() const; + + void reset(); + +private: + void internalReset(); + + QPoint pressedPos; + QPoint lastPos; + QPoint currentPos; + bool mousePressed; + bool gestureFinished; + Direction::DirectionType lastDirection; + QDirectionDiagonalRecognizer diagonalRecognizer; + QDirectionSimpleRecognizer simpleRecognizer; +}; + +class QDoubleTapGestureRecognizer : public QGestureRecognizer +{ + Q_OBJECT +public: + QDoubleTapGestureRecognizer(); + + QGestureRecognizer::Result recognize(const QList &inputEvents); + QGesture* makeEvent() const; + void reset(); + +private: + QPoint pressedPosition; +}; + +class QLongTapGestureRecognizer : public QGestureRecognizer +{ + Q_OBJECT +public: + QLongTapGestureRecognizer(); + + QGestureRecognizer::Result recognize(const QList &inputEvents); + QGesture* makeEvent() const; + void reset(); + +protected: + void timerEvent(QTimerEvent *event); + +private: + QPoint pressedPosition; + QBasicTimer timer; + int iteration; + static const int iterationCount; + static const int iterationTimeout; +}; + +/* +class QMultiTouchGestureRecognizer : public QGestureRecognizer +{ + Q_OBJECT +public: + QMultiTouchGestureRecognizer(); + + QMap maybeGestureCompletion(); + QGestureRecognizer::Result recognize(const QList &inputEvents); + QGesture* makeEvent() const; + void reset(); + +private: + struct Tap { + //### should I use QPointF everywhere internally ?? + QPointF startPosition; + QPointF lastPosition; + QPointF currentPosition; + }; + typedef QMap TapMap; + TapMap touches; +}; +*/ + +QT_END_NAMESPACE + +#endif // QGESTURESTANDARDRECOGNIZERS_P_H diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index 968a423..f6be730 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -7532,6 +7532,7 @@ bool QWidget::event(QEvent *event) #ifndef QT_NO_WHEELEVENT case QEvent::Wheel: #endif + case QEvent::Gesture: return false; default: break; @@ -7927,6 +7928,9 @@ bool QWidget::event(QEvent *event) d->needWindowChange = false; break; #endif + case QEvent::Gesture: + gestureEvent((QGestureEvent*)event); + break; #ifndef QT_NO_PROPERTIES case QEvent::DynamicPropertyChange: { const QByteArray &propName = static_cast(event)->propertyName(); @@ -8732,6 +8736,11 @@ bool QWidget::qwsEvent(QWSEvent *) #endif +void QWidget::gestureEvent(QGestureEvent *event) +{ + event->ignore(); +} + /*! Ensures that the widget has been polished by QStyle (i.e., has a @@ -11016,6 +11025,42 @@ QWindowSurface *QWidget::windowSurface() const return bs ? bs->windowSurface : 0; } +void QWidget::grabGesture(Qt::GestureType gesture) +{ + Q_D(QWidget); + if (d->gestures.contains(gesture)) + return; + d->gestures << gesture; + ++qApp->d_func()->grabbedGestures[gesture]; +} + +void QWidget::grabGestures(const QSet &gestures) +{ + Q_D(QWidget); + foreach(const Qt::GestureType &gesture, gestures) { + if (!d->gestures.contains(gesture)) + ++qApp->d_func()->grabbedGestures[gesture]; + } + d->gestures.unite(gestures); +} + +void QWidget::releaseGesture(Qt::GestureType gesture) +{ + Q_D(QWidget); + QMap::iterator it = + qApp->d_func()->grabbedGestures.find(gesture); + if (it != qApp->d_func()->grabbedGestures.end() && + d->gestures.contains(gesture)) + ++it.value(); + d->gestures.remove(gesture); +} + +QSet QWidget::gestures() +{ + Q_D(const QWidget); + return d->gestures; +} + void QWidgetPrivate::getLayoutItemMargins(int *left, int *top, int *right, int *bottom) const { if (left) diff --git a/src/gui/kernel/qwidget.h b/src/gui/kernel/qwidget.h index 6703d26..afe637d 100644 --- a/src/gui/kernel/qwidget.h +++ b/src/gui/kernel/qwidget.h @@ -59,6 +59,8 @@ #include #endif +#include + QT_BEGIN_HEADER QT_BEGIN_NAMESPACE @@ -90,6 +92,7 @@ class QDragLeaveEvent; class QDropEvent; class QShowEvent; class QHideEvent; +class QGestureEvent; class QInputContext; class QIcon; class QWindowSurface; @@ -610,6 +613,11 @@ public: void setWindowSurface(QWindowSurface *surface); QWindowSurface *windowSurface() const; + void grabGesture(Qt::GestureType gesture); + void grabGestures(const QSet &gestures); + void releaseGesture(Qt::GestureType gesture); + QSet gestures(); + Q_SIGNALS: void customContextMenuRequested(const QPoint &pos); @@ -669,6 +677,8 @@ protected: // Misc. protected functions virtual void changeEvent(QEvent *); + virtual void gestureEvent(QGestureEvent *); + int metric(PaintDeviceMetric) const; virtual void inputMethodEvent(QInputMethodEvent *); diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index 5f5e1b1..178f7ba 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -57,6 +57,7 @@ #include "private/qobject_p.h" #include "QtCore/qrect.h" #include "QtCore/qlocale.h" +#include "QtCore/qset.h" #include "QtGui/qregion.h" #include "QtGui/qsizepolicy.h" #include "QtGui/qstyle.h" @@ -592,6 +593,8 @@ public: uint isGLWidget : 1; #endif + QSet gestures; + #if defined(Q_WS_X11) || defined (Q_WS_WIN) || defined(Q_WS_MAC) #ifdef Q_WS_MAC void setWSGeometry(bool dontShow=false, const QRect &oldRect = QRect()); diff --git a/src/gui/widgets/qabstractscrollarea.cpp b/src/gui/widgets/qabstractscrollarea.cpp index 9886969..190dbb5 100644 --- a/src/gui/widgets/qabstractscrollarea.cpp +++ b/src/gui/widgets/qabstractscrollarea.cpp @@ -908,6 +908,7 @@ bool QAbstractScrollArea::event(QEvent *e) case QEvent::DragMove: case QEvent::DragLeave: #endif + case QEvent::Gesture: return false; case QEvent::StyleChange: case QEvent::LayoutDirectionChange: -- cgit v0.12 From aa4334b77702d99d4aa3da853dd66104eb4a8123 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Thu, 26 Feb 2009 17:18:33 +0100 Subject: Fixed lastDirection in the Pan gesture. --- examples/gestures/graphicsview/main.cpp | 2 +- src/gui/kernel/qgesturestandardrecognizers.cpp | 48 +++++++++++++++++--------- src/gui/kernel/qgesturestandardrecognizers_p.h | 1 + 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/examples/gestures/graphicsview/main.cpp b/examples/gestures/graphicsview/main.cpp index a0236ef..250da06 100644 --- a/examples/gestures/graphicsview/main.cpp +++ b/examples/gestures/graphicsview/main.cpp @@ -53,7 +53,7 @@ protected: { if (event->type() == QEvent::Gesture) { QGestureEvent *ge = static_cast(event); - if (const QGesture *g = ge->gesture(Qt::Pan)) { + if (const QPannableGesture *g = dynamic_cast(ge->gesture(Qt::Pan))) { QPoint pt = g->pos() - g->lastPos(); horizontalScrollBar()->setValue(horizontalScrollBar()->value() - pt.x()); verticalScrollBar()->setValue(verticalScrollBar()->value() - pt.y()); diff --git a/src/gui/kernel/qgesturestandardrecognizers.cpp b/src/gui/kernel/qgesturestandardrecognizers.cpp index 3a2fa1d..504786a 100644 --- a/src/gui/kernel/qgesturestandardrecognizers.cpp +++ b/src/gui/kernel/qgesturestandardrecognizers.cpp @@ -178,7 +178,7 @@ void QGestureRecognizerMouseTwoButtons::clear() QGestureRecognizerPan::QGestureRecognizerPan() : QGestureRecognizer(Qt::Pan), mousePressed(false), gestureFinished(false), - lastDirection(Direction::None) + lastDirection(Direction::None), currentDirection(Direction::None) { } @@ -202,7 +202,7 @@ QGestureRecognizer::Result QGestureRecognizerPan::recognize(const QList for(int i = 0; i < events.count(); ++i) { QMouseEvent *event = events.at(i); if (event->type() == QEvent::MouseButtonPress) { - if (lastDirection != Direction::None) { + if (currentDirection != Direction::None) { DEBUG() << "Pan: MouseButtonPress: fail. another press during pan"; result = QGestureRecognizer::NotGesture; reset(); @@ -213,7 +213,7 @@ QGestureRecognizer::Result QGestureRecognizerPan::recognize(const QList mousePressed = true; pressedPos = lastPos = currentPos = event->pos(); } else if (event->type() == QEvent::MouseButtonRelease) { - if (mousePressed && lastDirection != Direction::None) { + if (mousePressed && currentDirection != Direction::None) { DEBUG() << "Pan: MouseButtonRelease: pan detected"; result = QGestureRecognizer::GestureFinished; gestureFinished = true; @@ -233,7 +233,7 @@ QGestureRecognizer::Result QGestureRecognizerPan::recognize(const QList Direction::DirectionType direction = simpleRecognizer.addPosition(event->pos()).direction; DEBUG() << "Pan: MouseMove: simplerecognizer result = " << direction; - if (lastDirection == Direction::None) { + if (currentDirection == Direction::None) { if (direction == Direction::None) result = QGestureRecognizer::MaybeGesture; else @@ -241,32 +241,45 @@ QGestureRecognizer::Result QGestureRecognizerPan::recognize(const QList } else { result = QGestureRecognizer::GestureStarted; } - if (direction != Direction::None) - lastDirection = direction; + if (direction != Direction::None) { + if (currentDirection != direction) + lastDirection = currentDirection; + currentDirection = direction; + } } } return result; } +static inline QPannableGesture::DirectionType convertPanningDirection(const Direction::DirectionType direction) +{ + switch (direction) { + case Direction::Left: + return QPannableGesture::Left; + case Direction::Right: + return QPannableGesture::Right; + case Direction::Up: + return QPannableGesture::Up; + case Direction::Down: + return QPannableGesture::Down; + default: + break; + } + return QPannableGesture::None; +} + QGesture* QGestureRecognizerPan::makeEvent() const { - QPannableGesture::DirectionType dir = QPannableGesture::None; - if (lastDirection == Direction::Left) - dir = QPannableGesture::Left; - else if (lastDirection == Direction::Right) - dir = QPannableGesture::Right; - else if (lastDirection == Direction::Up) - dir = QPannableGesture::Up; - else if (lastDirection == Direction::Down) - dir = QPannableGesture::Down; - else + QPannableGesture::DirectionType dir = convertPanningDirection(currentDirection); + QPannableGesture::DirectionType lastDir = convertPanningDirection(lastDirection); + if (dir == QPannableGesture::None) return 0; QPannableGesture *g = new QPannableGesture(Qt::Pan, pressedPos, lastPos, currentPos, QRect(), pressedPos, QDateTime(), 0, gestureFinished ? Qt::GestureFinished : Qt::GestureStarted); QPannableGesturePrivate *d = (QPannableGesturePrivate*)g->d; - d->lastDirection = dir; ///### + d->lastDirection = lastDir; d->direction = dir; return g; @@ -276,6 +289,7 @@ void QGestureRecognizerPan::reset() { mousePressed = false; lastDirection = Direction::None; + currentDirection = Direction::None; gestureFinished = false; diagonalRecognizer.reset(); simpleRecognizer.reset(); diff --git a/src/gui/kernel/qgesturestandardrecognizers_p.h b/src/gui/kernel/qgesturestandardrecognizers_p.h index 3b314e7..567cf65 100644 --- a/src/gui/kernel/qgesturestandardrecognizers_p.h +++ b/src/gui/kernel/qgesturestandardrecognizers_p.h @@ -101,6 +101,7 @@ private: bool mousePressed; bool gestureFinished; Direction::DirectionType lastDirection; + Direction::DirectionType currentDirection; QDirectionDiagonalRecognizer diagonalRecognizer; QDirectionSimpleRecognizer simpleRecognizer; }; -- cgit v0.12 From ce50bdd854497b2a2aedbdb4417b532799086241 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Fri, 27 Feb 2009 14:33:49 +0100 Subject: Added some documentation. Fixed missing const specifiers. --- doc/src/qnamespace.qdoc | 16 +++++++++++ src/gui/kernel/qevent.cpp | 44 ++++++++++++++++++++++++++++++ src/gui/kernel/qevent.h | 8 +++--- src/gui/kernel/qgesturerecognizer.h | 54 ++++++++++++++++++++++++++++++++++++- src/gui/kernel/qwidget.cpp | 27 ++++++++++++++++--- src/gui/kernel/qwidget.h | 6 ++--- 6 files changed, 144 insertions(+), 11 deletions(-) diff --git a/doc/src/qnamespace.qdoc b/doc/src/qnamespace.qdoc index 98f7e7c..c44b41e 100644 --- a/doc/src/qnamespace.qdoc +++ b/doc/src/qnamespace.qdoc @@ -2675,3 +2675,19 @@ \sa QPixmapBorders, qDrawBorderPixmap() */ + +/*! \typedef Qt::GestureType + + A string representing a type of a gesture. +*/ + +/*! + \enum Qt::GestureState + + This enum type describes the state of a gesture. + + \value GestureStarted The continuous gesture has started. + \value GestureFinished The gesture has finished. + + \sa QGesture +*/ diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index a7e1101..d7d193c 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -3509,6 +3509,50 @@ QMenubarUpdatedEvent::QMenubarUpdatedEvent(QMenuBar * const menuBar) #endif +/*! + \class QGestureEvent + \ingroup events + + \brief The QGestureEvent class provides the parameters used for + gesture recognition. + + The QGestureEvent class contains a list of gestures that are being + executed right now (QGestureEvent::gestureTypes()) and a list of + gestures that are cancelled (the gesture might be cancelled + because the window lost focus, or because of timeout, etc). + + \sa QGesture +*/ + +/*! \fn QWidget *QGestureEvent::targetWidget() const + + Returns the widget the gesture event is send to. +*/ + +/*! \fn bool contains(const Qt::GestureType &type) const + + Checks if the gesture event contains gesture of specific \a type. +*/ + +/*! \fn QList gestureTypes() const + + Returns a list of gesture names that the event contains. +*/ + +/*! \fn const QGesture* gesture(const Qt::GestureType &type) const + + Returns extended information about a gesture of specific \a type. +*/ + +/*! \fn QSet cancelledGestures() const + + Returns a set of gesture names that used to be executed, but got + cancelled (i.e. they were not finished properly). +*/ + + + + QGestureEvent::QGestureEvent(QWidget *targetWidget, const QList &gestures, const QSet &cancelledGestures) : QEvent(QEvent::Gesture), m_targetWidget(targetWidget), diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 858e2ea..cde7cb2 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -726,12 +726,12 @@ public: QWidget *targetWidget() const { return m_targetWidget; } - inline bool contains(const Qt::GestureType &gestureType) const - { return gesture(gestureType) != 0; } + inline bool contains(const Qt::GestureType &type) const + { return gesture(type) != 0; } inline QList gestureTypes() const { return m_gestures.keys(); } - inline const QGesture* gesture(const Qt::GestureType &gestureType) const - { return m_gestures.value(gestureType, QSharedPointer()).data(); } + inline const QGesture* gesture(const Qt::GestureType &type) const + { return m_gestures.value(type, QSharedPointer()).data(); } inline QSet cancelledGestures() const { return m_cancelledGestures; } diff --git a/src/gui/kernel/qgesturerecognizer.h b/src/gui/kernel/qgesturerecognizer.h index 3ed96c0..a831d8a 100644 --- a/src/gui/kernel/qgesturerecognizer.h +++ b/src/gui/kernel/qgesturerecognizer.h @@ -49,6 +49,58 @@ QT_BEGIN_NAMESPACE +/*! + \class QGestureRecognizer + + \brief The base class for implementing custom gestures. + + This is a base class, to create a custom gesture type, you should + subclass it and implement pure virtual functions. + + Usually gesture recognizer implements state machine, storing its + state internally in the recognizer object. The recognizer receives + input events through the QGestureRecognizer::recognize() virtual + function and decides whether the parsed event should change the + state of the recognizer - i.e. if the event starts or ends a + gesture or if it isn't related to gesture at all. +*/ + +/*! \fn Qt::GestureType gestureType() const + + Returns the name of the gesture that is handled by the recognizer. +*/ + +/*! \fn Result recognize(const QList &events) + + This is a pure virtual function that need to be implemented in + subclasses. + + Parses input \a events and returns the result, saying if the event + sequence is a gesture or not. +*/ + +/*! \fn QGesture* makeEvent() const + + Creates a new gesture object that will be send to the widget. This + function is called when the gesture recognizer returned a + QGestureRecognizer::GestureStarted or + QGestureRecognizer::GestureFinished state. + + Created gesture object is owned by the caller. + */ + +/*! \fn void reset() + + Resets the internal state of the gesture recognizer. +*/ + +/*! \fn void triggered(QGestureRecognizer::Result result) + + The gesture recognizer might emit the signal when the gesture + state changes asynchronously, i.e. without any event being + received. +*/ + class QGestureRecognizer : public QObject { Q_OBJECT @@ -67,7 +119,7 @@ public: inline QGestureRecognizer(const Qt::GestureType &type) : type_(type) { } inline Qt::GestureType gestureType() const { return type_; } - virtual Result recognize(const QList &inputEvents) = 0; + virtual Result recognize(const QList &events) = 0; virtual QGesture* makeEvent() const = 0; virtual void reset() = 0; diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index f6be730..aea0003 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -11025,7 +11025,13 @@ QWindowSurface *QWidget::windowSurface() const return bs ? bs->windowSurface : 0; } -void QWidget::grabGesture(Qt::GestureType gesture) +/*! + \fn void QWidget::grabGesture(const Qt::GestureType &gesture) + + Subscribes the widget to the specified \a gesture type. +*/ + +void QWidget::grabGesture(const Qt::GestureType &gesture) { Q_D(QWidget); if (d->gestures.contains(gesture)) @@ -11034,6 +11040,11 @@ void QWidget::grabGesture(Qt::GestureType gesture) ++qApp->d_func()->grabbedGestures[gesture]; } +/*! + \fn void QWidget::grabGestures(const QSet &gestures) + + Subscribes the widget to the specified list of \a gestures. +*/ void QWidget::grabGestures(const QSet &gestures) { Q_D(QWidget); @@ -11044,7 +11055,12 @@ void QWidget::grabGestures(const QSet &gestures) d->gestures.unite(gestures); } -void QWidget::releaseGesture(Qt::GestureType gesture) +/*! + \fn void QWidget::releaseGesture(const Qt::GestureType &gesture) + + Unsubscribes the widget from the specified \a gesture type. +*/ +void QWidget::releaseGesture(const Qt::GestureType &gesture) { Q_D(QWidget); QMap::iterator it = @@ -11055,7 +11071,12 @@ void QWidget::releaseGesture(Qt::GestureType gesture) d->gestures.remove(gesture); } -QSet QWidget::gestures() +/*! + \fn QSet QWidget::gestures() const + + Returns a list of gestures that the widget is subscribed to. +*/ +QSet QWidget::gestures() const { Q_D(const QWidget); return d->gestures; diff --git a/src/gui/kernel/qwidget.h b/src/gui/kernel/qwidget.h index afe637d..e36b966 100644 --- a/src/gui/kernel/qwidget.h +++ b/src/gui/kernel/qwidget.h @@ -613,10 +613,10 @@ public: void setWindowSurface(QWindowSurface *surface); QWindowSurface *windowSurface() const; - void grabGesture(Qt::GestureType gesture); + void grabGesture(const Qt::GestureType &gesture); void grabGestures(const QSet &gestures); - void releaseGesture(Qt::GestureType gesture); - QSet gestures(); + void releaseGesture(const Qt::GestureType &gesture); + QSet gestures() const; Q_SIGNALS: void customContextMenuRequested(const QPoint &pos); -- cgit v0.12 From 4e31add7d62f26036a43dfe77db1c6b7e333e21e Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Mon, 2 Mar 2009 16:32:39 +0100 Subject: Fixes: reset the internal gesture state when gesture in state 'maybe' is finished. --- src/gui/kernel/qgesturemanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/kernel/qgesturemanager.cpp b/src/gui/kernel/qgesturemanager.cpp index c244a0b..2d0137e 100644 --- a/src/gui/kernel/qgesturemanager.cpp +++ b/src/gui/kernel/qgesturemanager.cpp @@ -137,7 +137,7 @@ bool QGestureManager::filterEvent(QEvent *event) } activeGestures -= newMaybeGestures; activeGestures += startedGestures; - foreach(QGestureRecognizer *r, startedGestures+notGestures) { + foreach(QGestureRecognizer *r, startedGestures+finishedGestures+notGestures) { QMap::iterator it = maybeGestures.find(r); if (it != maybeGestures.end()) { killTimer(it.value()); -- cgit v0.12 From b349831a5ae7bca80f22240b1ed204dd3d87c71f Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Wed, 4 Mar 2009 11:39:49 +0100 Subject: Fixes: QGraphicsView respects the spontaneous event flag for graphicsscene events. Details: Copying the QEvent::spontaneous() flag from the received event to QGraphicsSceneEvent. --- src/corelib/kernel/qcoreevent.h | 3 +++ src/gui/graphicsview/qgraphicsscene.cpp | 1 + src/gui/graphicsview/qgraphicsview.cpp | 10 ++++++---- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/corelib/kernel/qcoreevent.h b/src/corelib/kernel/qcoreevent.h index c9f9f24..4ea3c70 100644 --- a/src/corelib/kernel/qcoreevent.h +++ b/src/corelib/kernel/qcoreevent.h @@ -313,6 +313,9 @@ private: friend class Q3AccelManager; friend class QShortcutMap; friend class QETWidget; + friend class QGraphicsView; + friend class QGraphicsViewPrivate; + friend class QGraphicsScenePrivate; }; class Q_CORE_EXPORT QTimerEvent : public QEvent diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index fe6dde1..873e28c 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -1335,6 +1335,7 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou // event is converted to a press. Known limitation: // Triple-clicking will not generate a doubleclick, though. QGraphicsSceneMouseEvent mousePress(QEvent::GraphicsSceneMousePress); + mousePress.spont = mouseEvent->spont; mousePress.accept(); mousePress.setButton(mouseEvent->button()); mousePress.setButtons(mouseEvent->buttons()); diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index acce717..97903d3 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -295,6 +295,8 @@ static const int QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS = 503; // largest prime < QT_BEGIN_NAMESPACE +bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event); + inline int q_round_bound(qreal d) //### (int)(qreal) INT_MAX != INT_MAX for single precision { if (d <= (qreal) INT_MIN) @@ -602,7 +604,7 @@ void QGraphicsViewPrivate::mouseMoveEventHandler(QMouseEvent *event) lastMouseMoveScenePoint = mouseEvent.scenePos(); lastMouseMoveScreenPoint = mouseEvent.screenPos(); mouseEvent.setAccepted(false); - QApplication::sendEvent(scene, &mouseEvent); + qt_sendSpontaneousEvent(scene, &mouseEvent); // Remember whether the last event was accepted or not. lastMouseEvent.setAccepted(mouseEvent.isAccepted()); @@ -3225,7 +3227,7 @@ void QGraphicsView::mouseDoubleClickEvent(QMouseEvent *event) mouseEvent.setAccepted(false); mouseEvent.setButton(event->button()); mouseEvent.setModifiers(event->modifiers()); - QApplication::sendEvent(d->scene, &mouseEvent); + qt_sendSpontaneousEvent(d->scene, &mouseEvent); } /*! @@ -3264,7 +3266,7 @@ void QGraphicsView::mousePressEvent(QMouseEvent *event) mouseEvent.setButton(event->button()); mouseEvent.setModifiers(event->modifiers()); mouseEvent.setAccepted(false); - QApplication::sendEvent(d->scene, &mouseEvent); + qt_sendSpontaneousEvent(d->scene, &mouseEvent); // Update the original mouse event accepted state. bool isAccepted = mouseEvent.isAccepted(); @@ -3434,7 +3436,7 @@ void QGraphicsView::mouseReleaseEvent(QMouseEvent *event) mouseEvent.setButton(event->button()); mouseEvent.setModifiers(event->modifiers()); mouseEvent.setAccepted(false); - QApplication::sendEvent(d->scene, &mouseEvent); + qt_sendSpontaneousEvent(d->scene, &mouseEvent); // Update the last mouse event selected state. d->lastMouseEvent.setAccepted(mouseEvent.isAccepted()); -- cgit v0.12 From fc84e3a05d01cce25949c605fc56dba4b4d3d183 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Thu, 5 Mar 2009 18:41:10 +0100 Subject: Fixes: improved gesture manager event filtering. Details: Several fixes - parsing only spontaneous mouse events and send gesture events to QGraphicsSceneItems according to their z-order --- src/gui/graphicsview/qgraphicsitem.cpp | 5 ++++ src/gui/graphicsview/qgraphicsitem.h | 1 + src/gui/graphicsview/qgraphicsscene.cpp | 19 ++++++++++----- src/gui/kernel/qapplication.cpp | 43 ++++++++++++++++++--------------- 4 files changed, 42 insertions(+), 26 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 58f04f0..a9ad1e1 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -5802,6 +5802,11 @@ void QGraphicsItem::releaseGesture(const Qt::GestureType &type) d_ptr->scene->d_func()->releaseGesture(this, type); } +QSet QGraphicsItem::gestures() const +{ + return d_ptr->gestures; +} + /*! This virtual function is called by QGraphicsItem to notify custom items that some part of the item's state changes. By reimplementing this diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h index 42a5110..2b4cdf5 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -340,6 +340,7 @@ public: void grabGesture(const Qt::GestureType &type); void releaseGesture(const Qt::GestureType &type); + QSet gestures() const; enum { Type = 1, diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 873e28c..21c7c81 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5614,18 +5614,25 @@ void QGraphicsScene::gestureEvent(QGestureEvent *event) { Q_D(QGraphicsScene); QList gestureTypes = event->gestureTypes(); - QList pts; QGraphicsView *view = qobject_cast(event->targetWidget()); if (!view) { // something is wrong. Q_ASSERT(view); return; } - foreach(const Qt::GestureType &type, gestureTypes) - pts << view->mapToScene(event->gesture(type)->hotSpot()); - foreach(QGraphicsItem *item, d->itemsWithGestures) { - for (int i = 0; i < pts.size(); ++i) { - if (item->contains(item->mapFromScene(pts.at(i)))) { + QPolygonF poly; + QMap hotSpots; + foreach(const Qt::GestureType &type, gestureTypes) { + QPointF pt = view->mapToScene(event->gesture(type)->hotSpot()); + hotSpots.insert(type, pt); + poly << pt; + } + + foreach(QGraphicsItem *item, items(poly, Qt::IntersectsItemBoundingRect)) { + QMap::const_iterator it = hotSpots.begin(), + e = hotSpots.end(); + for(; it != e; ++it) { + if (item->contains(item->mapFromScene(it.value())) && item->gestures().contains(it.key())) { d->sendGestureEvent(item, event); if (event->isAccepted()) break; diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index b39cbc3..88871a4 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -3706,28 +3706,31 @@ bool QApplication::notify(QObject *receiver, QEvent *e) QMouseEvent* mouse = static_cast(e); QPoint relpos = mouse->pos(); - if (QApplication::testAttribute(Qt::AA_EnableGestures)) { - if (!gestureManager) - gestureManager = new QGestureManager; - // if we are in gesture mode, we send all mouse events - // directly to gesture recognizer. - if (gestureManager->inGestureMode()) { - // ### should I send events through all application event filters? - if (gestureManager->filterEvent(e)) - return true; - } - if (w && (mouse->type() != QEvent::MouseMove || mouse->buttons() != 0)) { - // find the gesture target widget - QWidget *target = w; - while (target && target->gestures().isEmpty()) - target = target->parentWidget(); - if (target) { - gestureManager->setGestureTargetWidget(target); - res = gestureManager->filterEvent(e); + if (e->spontaneous()) { + if (QApplication::testAttribute(Qt::AA_EnableGestures)) { + QWidget *w = static_cast(receiver); + if (!gestureManager) + gestureManager = new QGestureManager; + // if we are in gesture mode, we send all mouse events + // directly to gesture recognizer. + if (gestureManager->inGestureMode()) { + if (gestureManager->filterEvent(e)) + return true; + } else { + QMouseEvent* mouse = static_cast(e); + if (w && (mouse->type() != QEvent::MouseMove || mouse->buttons() != 0)) { + // find the gesture target widget + QWidget *target = w; + while (target && target->gestures().isEmpty()) + target = target->parentWidget(); + if (target) { + gestureManager->setGestureTargetWidget(target); + if (gestureManager->filterEvent(e)) + return true; + } + } } } - } - if (e->spontaneous()) { if (e->type() == QEvent::MouseButtonPress) { QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, Qt::ClickFocus, -- cgit v0.12 From f1d955249ff00db79252967078005db9a9fe936c Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Fri, 6 Mar 2009 12:08:48 +0100 Subject: If the event wasn't consumed by the gesture target widget, then gesture manager should consume it as well. --- src/gui/kernel/qgesturemanager.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/gui/kernel/qgesturemanager.cpp b/src/gui/kernel/qgesturemanager.cpp index 2d0137e..c9bf0df 100644 --- a/src/gui/kernel/qgesturemanager.cpp +++ b/src/gui/kernel/qgesturemanager.cpp @@ -169,7 +169,8 @@ bool QGestureManager::filterEvent(QEvent *event) } Q_ASSERT(!gestures.isEmpty()); QGestureEvent event(targetWidget, gestures); - qt_sendGestureEvent(targetWidget, &event); + ret = qt_sendGestureEvent(targetWidget, &event); + ret = ret && event.isAccepted(); if (!activeGestures.isEmpty()) { DEBUG() << "QGestureManager: new state = Gesture"; @@ -273,7 +274,8 @@ bool QGestureManager::filterEvent(QEvent *event) cancelledGestureNames << r->gestureType(); if(!gestures.isEmpty()) { QGestureEvent event(targetWidget, gestures, cancelledGestureNames); - qt_sendGestureEvent(targetWidget, &event); + ret = qt_sendGestureEvent(targetWidget, &event); + ret = ret && event.isAccepted(); } foreach(QGestureRecognizer *r, finishedGestures) @@ -291,7 +293,6 @@ bool QGestureManager::filterEvent(QEvent *event) DEBUG() << "QGestureManager: new state = NotGesture"; state = NotGesture; } - ret = true; } lastPos = currentPos; -- cgit v0.12 From b231b0bcd36d531d3558cee12be263a98391b9db Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Fri, 6 Mar 2009 13:11:29 +0100 Subject: Fixes: Compilation fixes --- examples/gestures/imageviewer/imagewidget.cpp | 2 ++ src/gui/kernel/qgesturemanager_p.h | 1 + 2 files changed, 3 insertions(+) diff --git a/examples/gestures/imageviewer/imagewidget.cpp b/examples/gestures/imageviewer/imagewidget.cpp index 8932e29..0db62bb 100644 --- a/examples/gestures/imageviewer/imagewidget.cpp +++ b/examples/gestures/imageviewer/imagewidget.cpp @@ -148,10 +148,12 @@ void ImageWidget::gestureEvent(QGestureEvent *event) } else if (const QGesture *g = event->gesture(Qt::Pan)) { if (zoomedIn) { // usual panning +#ifndef QT_NO_CURSOR if (g->state() == Qt::GestureStarted) setCursor(Qt::SizeAllCursor); else setCursor(Qt::ArrowCursor); +#endif const int dx = g->pos().x() - g->lastPos().x(); const int dy = g->pos().y() - g->lastPos().y(); horizontalOffset += dx; diff --git a/src/gui/kernel/qgesturemanager_p.h b/src/gui/kernel/qgesturemanager_p.h index 9853f1a..1079cc4 100644 --- a/src/gui/kernel/qgesturemanager_p.h +++ b/src/gui/kernel/qgesturemanager_p.h @@ -53,6 +53,7 @@ // We mean it. // +#include "qwidget.h" #include "qlist.h" #include "qset.h" #include "qevent.h" -- cgit v0.12 From 3cad576b7ce221ca92c07a513c4c0fbe9886f8e5 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Fri, 6 Mar 2009 14:42:51 +0100 Subject: Fixes: Add missing functions for a adding custom gesture recognizers. --- src/gui/kernel/qapplication.cpp | 23 ++++++++++++++++------- src/gui/kernel/qapplication.h | 4 ++++ src/gui/kernel/qgesturemanager.cpp | 10 ++++++++++ src/gui/kernel/qgesturemanager_p.h | 3 +++ 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 88871a4..104271d 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -137,7 +137,7 @@ int QApplicationPrivate::autoMaximizeThreshold = -1; bool QApplicationPrivate::autoSipEnabled = false; #endif -QGestureManager *gestureManager = 0; +Q_GLOBAL_STATIC(QGestureManager, gestureManager); QApplicationPrivate::QApplicationPrivate(int &argc, char **argv, QApplication::Type type) : QCoreApplicationPrivate(argc, argv) @@ -3709,12 +3709,11 @@ bool QApplication::notify(QObject *receiver, QEvent *e) if (e->spontaneous()) { if (QApplication::testAttribute(Qt::AA_EnableGestures)) { QWidget *w = static_cast(receiver); - if (!gestureManager) - gestureManager = new QGestureManager; + QGestureManager *gm = gestureManager(); // if we are in gesture mode, we send all mouse events // directly to gesture recognizer. - if (gestureManager->inGestureMode()) { - if (gestureManager->filterEvent(e)) + if (gm->inGestureMode()) { + if (gm->filterEvent(e)) return true; } else { QMouseEvent* mouse = static_cast(e); @@ -3724,8 +3723,8 @@ bool QApplication::notify(QObject *receiver, QEvent *e) while (target && target->gestures().isEmpty()) target = target->parentWidget(); if (target) { - gestureManager->setGestureTargetWidget(target); - if (gestureManager->filterEvent(e)) + gm->setGestureTargetWidget(target); + if (gm->filterEvent(e)) return true; } } @@ -5090,6 +5089,16 @@ bool QApplicationPrivate::shouldSetFocus(QWidget *w, Qt::FocusPolicy policy) return true; } +void QApplication::addGestureRecognizer(QGestureRecognizer *recognizer) +{ + gestureManager()->addRecognizer(recognizer); +} + +void QApplication::removeGestureRecognizer(QGestureRecognizer *recognizer) +{ + gestureManager()->removeRecognizer(recognizer); +} + /*! \fn QDecoration &QApplication::qwsDecoration() Return the QWSDecoration used for decorating windows. diff --git a/src/gui/kernel/qapplication.h b/src/gui/kernel/qapplication.h index 634226f..70458ef 100644 --- a/src/gui/kernel/qapplication.h +++ b/src/gui/kernel/qapplication.h @@ -71,6 +71,7 @@ class QStyle; class QEventLoop; class QIcon; class QInputContext; +class QGestureRecognizer; template class QList; class QLocale; #if defined(Q_WS_QWS) @@ -266,6 +267,9 @@ public: static bool keypadNavigationEnabled(); #endif + void addGestureRecognizer(QGestureRecognizer *recognizer); + void removeGestureRecognizer(QGestureRecognizer *recognizer); + Q_SIGNALS: void lastWindowClosed(); void focusChanged(QWidget *old, QWidget *now); diff --git a/src/gui/kernel/qgesturemanager.cpp b/src/gui/kernel/qgesturemanager.cpp index c9bf0df..7954ae9 100644 --- a/src/gui/kernel/qgesturemanager.cpp +++ b/src/gui/kernel/qgesturemanager.cpp @@ -83,6 +83,16 @@ QGestureManager::QGestureManager() this, SLOT(recognizerTriggered(QGestureRecognizer::Result))); } +void QGestureManager::addRecognizer(QGestureRecognizer *recognizer) +{ + recognizers << recognizer; +} + +void QGestureManager::removeRecognizer(QGestureRecognizer *recognizer) +{ + recognizers.remove(recognizer); +} + bool QGestureManager::filterEvent(QEvent *event) { if (!QApplication::testAttribute(Qt::AA_EnableGestures)) diff --git a/src/gui/kernel/qgesturemanager_p.h b/src/gui/kernel/qgesturemanager_p.h index 1079cc4..762b70d 100644 --- a/src/gui/kernel/qgesturemanager_p.h +++ b/src/gui/kernel/qgesturemanager_p.h @@ -72,6 +72,9 @@ public: // should be internal void setGestureTargetWidget(QWidget *widget); + void addRecognizer(QGestureRecognizer *recognizer); + void removeRecognizer(QGestureRecognizer *recognizer); + bool filterEvent(QEvent *event); bool inGestureMode(); -- cgit v0.12 From b542556f2d75017af34e0bc8ee1336fa0c08c69d Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Fri, 6 Mar 2009 16:54:23 +0100 Subject: Forgot to export QGestureRecognizer class. --- src/gui/kernel/qgesturerecognizer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/kernel/qgesturerecognizer.h b/src/gui/kernel/qgesturerecognizer.h index a831d8a..ca8972b 100644 --- a/src/gui/kernel/qgesturerecognizer.h +++ b/src/gui/kernel/qgesturerecognizer.h @@ -101,7 +101,7 @@ QT_BEGIN_NAMESPACE received. */ -class QGestureRecognizer : public QObject +class Q_GUI_EXPORT QGestureRecognizer : public QObject { Q_OBJECT public: -- cgit v0.12 From 15588496830fee6fbe38fda76411e483a51ddd08 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Fri, 6 Mar 2009 14:45:43 +0100 Subject: Added colliding mice example with gesture support. --- examples/gestures/collidingmice/collidingmice.pro | 14 ++ examples/gestures/collidingmice/main.cpp | 114 ++++++++++++ examples/gestures/collidingmice/mice.qrc | 5 + examples/gestures/collidingmice/mouse.cpp | 200 ++++++++++++++++++++++ examples/gestures/collidingmice/mouse.h | 72 ++++++++ 5 files changed, 405 insertions(+) create mode 100644 examples/gestures/collidingmice/collidingmice.pro create mode 100644 examples/gestures/collidingmice/main.cpp create mode 100644 examples/gestures/collidingmice/mice.qrc create mode 100644 examples/gestures/collidingmice/mouse.cpp create mode 100644 examples/gestures/collidingmice/mouse.h diff --git a/examples/gestures/collidingmice/collidingmice.pro b/examples/gestures/collidingmice/collidingmice.pro new file mode 100644 index 0000000..5c7b42b --- /dev/null +++ b/examples/gestures/collidingmice/collidingmice.pro @@ -0,0 +1,14 @@ +HEADERS += \ + mouse.h +SOURCES += \ + main.cpp \ + mouse.cpp + +RESOURCES += \ + mice.qrc + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/gestures/collidingmice +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS collidingmice.pro images +sources.path = $$[QT_INSTALL_EXAMPLES]/gestures/collidingmice +INSTALLS += target sources diff --git a/examples/gestures/collidingmice/main.cpp b/examples/gestures/collidingmice/main.cpp new file mode 100644 index 0000000..56e9f7f --- /dev/null +++ b/examples/gestures/collidingmice/main.cpp @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mouse.h" + +#include + +#include + +static const int MouseCount = 7; + +class PannableGraphicsView : public QGraphicsView +{ +public: + PannableGraphicsView(QGraphicsScene *scene, QWidget *parent = 0) + : QGraphicsView(scene, parent) + { + grabGesture(Qt::Pan); + } +protected: + bool event(QEvent *event) + { + if (event->type() == QEvent::Gesture) { + QGestureEvent *ge = static_cast(event); + if (const QPannableGesture *g = dynamic_cast(ge->gesture(Qt::Pan))) { + QPoint pt = g->pos() - g->lastPos(); + horizontalScrollBar()->setValue(horizontalScrollBar()->value() - pt.x()); + verticalScrollBar()->setValue(verticalScrollBar()->value() - pt.y()); + event->accept(); + return true; + } + } + return QGraphicsView::event(event); + } +}; + +//! [0] +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + QApplication::setAttribute(Qt::AA_EnableGestures); + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); +//! [0] + +//! [1] + QGraphicsScene scene; + scene.setSceneRect(-600, -600, 1200, 1200); +//! [1] //! [2] + scene.setItemIndexMethod(QGraphicsScene::NoIndex); +//! [2] + +//! [3] + for (int i = 0; i < MouseCount; ++i) { + Mouse *mouse = new Mouse; + mouse->setPos(::sin((i * 6.28) / MouseCount) * 200, + ::cos((i * 6.28) / MouseCount) * 200); + scene.addItem(mouse); + } +//! [3] + +//! [4] + PannableGraphicsView view(&scene); + view.setRenderHint(QPainter::Antialiasing); + view.setBackgroundBrush(QPixmap(":/images/cheese.jpg")); +//! [4] //! [5] + view.setCacheMode(QGraphicsView::CacheBackground); + view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); + //view.setDragMode(QGraphicsView::ScrollHandDrag); +//! [5] //! [6] + view.setWindowTitle(QT_TRANSLATE_NOOP(QGraphicsView, "Colliding Mice")); + view.resize(400, 300); + view.show(); + + return app.exec(); +} +//! [6] diff --git a/examples/gestures/collidingmice/mice.qrc b/examples/gestures/collidingmice/mice.qrc new file mode 100644 index 0000000..accdb4d --- /dev/null +++ b/examples/gestures/collidingmice/mice.qrc @@ -0,0 +1,5 @@ + + + images/cheese.jpg + + diff --git a/examples/gestures/collidingmice/mouse.cpp b/examples/gestures/collidingmice/mouse.cpp new file mode 100644 index 0000000..1d9fa89 --- /dev/null +++ b/examples/gestures/collidingmice/mouse.cpp @@ -0,0 +1,200 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mouse.h" + +#include +#include +#include + +#include + +static const double Pi = 3.14159265358979323846264338327950288419717; +static double TwoPi = 2.0 * Pi; + +static qreal normalizeAngle(qreal angle) +{ + while (angle < 0) + angle += TwoPi; + while (angle > TwoPi) + angle -= TwoPi; + return angle; +} + +//! [0] +Mouse::Mouse() + : angle(0), speed(0), mouseEyeDirection(0), + color(qrand() % 256, qrand() % 256, qrand() % 256) +{ + rotate(qrand() % (360 * 16)); + startTimer(1000 / 33); +} +//! [0] + +//! [1] +QRectF Mouse::boundingRect() const +{ + qreal adjust = 0.5; + return QRectF(-18 - adjust, -22 - adjust, + 36 + adjust, 60 + adjust); +} +//! [1] + +//! [2] +QPainterPath Mouse::shape() const +{ + QPainterPath path; + path.addRect(-10, -20, 20, 40); + return path; +} +//! [2] + +//! [3] +void Mouse::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) +{ + // Body + painter->setBrush(color); + painter->drawEllipse(-10, -20, 20, 40); + + // Eyes + painter->setBrush(Qt::white); + painter->drawEllipse(-10, -17, 8, 8); + painter->drawEllipse(2, -17, 8, 8); + + // Nose + painter->setBrush(Qt::black); + painter->drawEllipse(QRectF(-2, -22, 4, 4)); + + // Pupils + painter->drawEllipse(QRectF(-8.0 + mouseEyeDirection, -17, 4, 4)); + painter->drawEllipse(QRectF(4.0 + mouseEyeDirection, -17, 4, 4)); + + // Ears + painter->setBrush(scene()->collidingItems(this).isEmpty() ? Qt::darkYellow : Qt::red); + painter->drawEllipse(-17, -12, 16, 16); + painter->drawEllipse(1, -12, 16, 16); + + // Tail + QPainterPath path(QPointF(0, 20)); + path.cubicTo(-5, 22, -5, 22, 0, 25); + path.cubicTo(5, 27, 5, 32, 0, 30); + path.cubicTo(-5, 32, -5, 42, 0, 35); + painter->setBrush(Qt::NoBrush); + painter->drawPath(path); +} +//! [3] + +//! [4] +void Mouse::timerEvent(QTimerEvent *) +{ +//! [4] + // Don't move too far away +//! [5] + QLineF lineToCenter(QPointF(0, 0), mapFromScene(0, 0)); + if (lineToCenter.length() > 150) { + qreal angleToCenter = ::acos(lineToCenter.dx() / lineToCenter.length()); + if (lineToCenter.dy() < 0) + angleToCenter = TwoPi - angleToCenter; + angleToCenter = normalizeAngle((Pi - angleToCenter) + Pi / 2); + + if (angleToCenter < Pi && angleToCenter > Pi / 4) { + // Rotate left + angle += (angle < -Pi / 2) ? 0.25 : -0.25; + } else if (angleToCenter >= Pi && angleToCenter < (Pi + Pi / 2 + Pi / 4)) { + // Rotate right + angle += (angle < Pi / 2) ? 0.25 : -0.25; + } + } else if (::sin(angle) < 0) { + angle += 0.25; + } else if (::sin(angle) > 0) { + angle -= 0.25; +//! [5] //! [6] + } +//! [6] + + // Try not to crash with any other mice +//! [7] + QList dangerMice = scene()->items(QPolygonF() + << mapToScene(0, 0) + << mapToScene(-30, -50) + << mapToScene(30, -50)); + foreach (QGraphicsItem *item, dangerMice) { + if (item == this) + continue; + + QLineF lineToMouse(QPointF(0, 0), mapFromItem(item, 0, 0)); + qreal angleToMouse = ::acos(lineToMouse.dx() / lineToMouse.length()); + if (lineToMouse.dy() < 0) + angleToMouse = TwoPi - angleToMouse; + angleToMouse = normalizeAngle((Pi - angleToMouse) + Pi / 2); + + if (angleToMouse >= 0 && angleToMouse < Pi / 2) { + // Rotate right + angle += 0.5; + } else if (angleToMouse <= TwoPi && angleToMouse > (TwoPi - Pi / 2)) { + // Rotate left + angle -= 0.5; +//! [7] //! [8] + } +//! [8] //! [9] + } +//! [9] + + // Add some random movement +//! [10] + if (dangerMice.size() > 1 && (qrand() % 10) == 0) { + if (qrand() % 1) + angle += (qrand() % 100) / 500.0; + else + angle -= (qrand() % 100) / 500.0; + } +//! [10] + +//! [11] + speed += (-50 + qrand() % 100) / 100.0; + + qreal dx = ::sin(angle) * 10; + mouseEyeDirection = (qAbs(dx / 5) < 1) ? 0 : dx / 5; + + rotate(dx); + setPos(mapToParent(0, -(3 + sin(speed) * 3))); +} +//! [11] diff --git a/examples/gestures/collidingmice/mouse.h b/examples/gestures/collidingmice/mouse.h new file mode 100644 index 0000000..7545fe6 --- /dev/null +++ b/examples/gestures/collidingmice/mouse.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MOUSE_H +#define MOUSE_H + +#include +#include + +//! [0] +class Mouse : public QObject, public QGraphicsItem +{ + Q_OBJECT + +public: + Mouse(); + + QRectF boundingRect() const; + QPainterPath shape() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, + QWidget *widget); + +protected: + void timerEvent(QTimerEvent *event); + +private: + qreal angle; + qreal speed; + qreal mouseEyeDirection; + QColor color; +}; +//! [0] + +#endif -- cgit v0.12 From 90ead023ec593bd3dba0ef8eb4e38f2299cfb783 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Fri, 6 Mar 2009 16:55:02 +0100 Subject: Implemented LinjaZax-like gesture in collidingmice example. --- examples/gestures/collidingmice/collidingmice.pro | 8 +- .../collidingmice/gesturerecognizerlinjazax.cpp | 189 +++++++++++++++++++++ .../collidingmice/gesturerecognizerlinjazax.h | 65 +++++++ examples/gestures/collidingmice/images/cheese.jpg | Bin 0 -> 3029 bytes examples/gestures/collidingmice/linjazaxgesture.h | 58 +++++++ examples/gestures/collidingmice/main.cpp | 19 ++- 6 files changed, 335 insertions(+), 4 deletions(-) create mode 100644 examples/gestures/collidingmice/gesturerecognizerlinjazax.cpp create mode 100644 examples/gestures/collidingmice/gesturerecognizerlinjazax.h create mode 100644 examples/gestures/collidingmice/images/cheese.jpg create mode 100644 examples/gestures/collidingmice/linjazaxgesture.h diff --git a/examples/gestures/collidingmice/collidingmice.pro b/examples/gestures/collidingmice/collidingmice.pro index 5c7b42b..15164ce 100644 --- a/examples/gestures/collidingmice/collidingmice.pro +++ b/examples/gestures/collidingmice/collidingmice.pro @@ -1,8 +1,12 @@ HEADERS += \ - mouse.h + mouse.h \ + gesturerecognizerlinjazax.h \ + linjazaxgesture.h + SOURCES += \ main.cpp \ - mouse.cpp + mouse.cpp \ + gesturerecognizerlinjazax.cpp RESOURCES += \ mice.qrc diff --git a/examples/gestures/collidingmice/gesturerecognizerlinjazax.cpp b/examples/gestures/collidingmice/gesturerecognizerlinjazax.cpp new file mode 100644 index 0000000..4c57209 --- /dev/null +++ b/examples/gestures/collidingmice/gesturerecognizerlinjazax.cpp @@ -0,0 +1,189 @@ +#include "gesturerecognizerlinjazax.h" + +#include +#include + +static const int SIZE = 20; + +DirectionSimpleRecognizer::DirectionSimpleRecognizer() +{ +} + +Direction DirectionSimpleRecognizer::addPosition(const QPoint &pos) +{ + if (!directions.isEmpty()) { + const QPoint tmp = pos - directions.back().point; + if (tmp.manhattanLength() < 5) + return Direction(); + } + if (lastPoint.isNull()) { + lastPoint = pos; + return Direction(); + } + int dx = pos.x() - lastPoint.x(); + int dy = pos.y() - lastPoint.y(); + QString direction; + if (dx < 0) { + if (-1*dx >= SIZE/2) + direction = "4"; + } else { + if (dx >= SIZE/2) + direction = "6"; + } + if (dy < 0) { + if (-1*dy >= SIZE/2) + direction = "8"; + } else { + if (dy >= SIZE/2) + direction = "2"; + } + if (direction.isEmpty()) + return Direction(); + + lastPoint = pos; + directions.push_back(Direction(direction, pos)); + return Direction(direction, pos); +} + + +DirectionList DirectionSimpleRecognizer::getDirections() const +{ + return directions; +} + +void DirectionSimpleRecognizer::reset() +{ + directions.clear(); + lastPoint = QPoint(); +} + +/////////////////////////////////////////////////////////////////////////// + +GestureRecognizerLinjaZax::GestureRecognizerLinjaZax() + : QGestureRecognizer("LinjaZax"), mousePressed(false), gestureFinished(false), + zoomState(LinjaZaxGesture::NoZoom) +{ +} + +QGestureRecognizer::Result GestureRecognizerLinjaZax::recognize(const QList &inputEvents) +{ + // get all mouse events + QList events; + for(int i = 0; i < inputEvents.count(); ++i) { + QEvent *event = inputEvents.at(i); + switch (event->type()) { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: + events.push_back(static_cast(event)); + default: + break; + } + } + + if (zoomState != LinjaZaxGesture::NoZoom && !lastDirections.isEmpty()) { + lastDirections = lastDirections.right(1); + zoomState = LinjaZaxGesture::NoZoom; + } + + QGestureRecognizer::Result result = QGestureRecognizer::NotGesture; + for(int i = 0; i < events.count(); ++i) { + QMouseEvent *event = events.at(i); + if (event->type() == QEvent::MouseButtonPress) { + if (!currentDirection.isEmpty()) { + result = QGestureRecognizer::NotGesture; + reset(); + break; + } + result = QGestureRecognizer::MaybeGesture; + mousePressed = true; + pressedPos = lastPos = currentPos = event->pos(); + } else if (event->type() == QEvent::MouseButtonRelease) { + if (mousePressed && !currentDirection.isEmpty()) { + result = QGestureRecognizer::GestureFinished; + gestureFinished = true; + currentPos = event->pos(); + internalReset(); + break; + } + result = QGestureRecognizer::NotGesture; + reset(); + break; + } else if (event->type() == QEvent::MouseMove) { + if (!mousePressed) + continue; + lastPos = currentPos; + currentPos = event->pos(); + QString direction = + simpleRecognizer.addPosition(event->pos()).direction; + if (currentDirection.isEmpty()) { + if (direction.isEmpty()) + result = QGestureRecognizer::MaybeGesture; + else + result = QGestureRecognizer::GestureStarted; + } else { + result = QGestureRecognizer::GestureStarted; + } + if (!direction.isEmpty()) { + if (currentDirection != direction) + lastDirections.append(direction); + currentDirection = direction; + if (lastDirections.length() > 5) + lastDirections.remove(0, 1); + if (lastDirections.contains("248")) + zoomState = LinjaZaxGesture::ZoomingIn; + else if (lastDirections.contains("268")) + zoomState = LinjaZaxGesture::ZoomingOut; + } + } + } + return result; +} + +static inline LinjaZaxGesture::DirectionType convertPanningDirection(const QString &direction) +{ + if (direction.length() == 1) { + if (direction == "4") + return LinjaZaxGesture::Left; + else if (direction == "6") + return LinjaZaxGesture::Right; + else if (direction == "8") + return LinjaZaxGesture::Up; + else if (direction == "2") + return LinjaZaxGesture::Down; + } + return LinjaZaxGesture::None; +} + +QGesture* GestureRecognizerLinjaZax::makeEvent() const +{ + LinjaZaxGesture::DirectionType dir = convertPanningDirection(currentDirection); + LinjaZaxGesture::DirectionType lastDir = convertPanningDirection(lastDirections.right(1)); + if (dir == LinjaZaxGesture::None) + return 0; + LinjaZaxGesture *g = + new LinjaZaxGesture("LinjaZax", pressedPos, lastPos, currentPos, + QRect(), pressedPos, QDateTime(), 0, + gestureFinished ? Qt::GestureFinished : Qt::GestureStarted); + g->lastDirection_ = lastDir; + g->direction_ = dir; + g->zoomState_ = zoomState; + + return g; +} + +void GestureRecognizerLinjaZax::reset() +{ + mousePressed = false; + lastDirections.clear(); + currentDirection.clear(); + gestureFinished = false; + simpleRecognizer.reset(); + zoomState = LinjaZaxGesture::NoZoom; +} + +void GestureRecognizerLinjaZax::internalReset() +{ + mousePressed = false; + simpleRecognizer.reset(); +} diff --git a/examples/gestures/collidingmice/gesturerecognizerlinjazax.h b/examples/gestures/collidingmice/gesturerecognizerlinjazax.h new file mode 100644 index 0000000..6579059 --- /dev/null +++ b/examples/gestures/collidingmice/gesturerecognizerlinjazax.h @@ -0,0 +1,65 @@ +#ifndef GESTURERECOGNIZERLINJAZAX_H +#define GESTURERECOGNIZERLINJAZAX_H + +#include +#include +#include +#include +#include + +#include "linjazaxgesture.h" + +struct Direction +{ + QString direction; + QPoint point; + + Direction(QString dir, const QPoint &pt) + : direction(dir), point(pt) { } + Direction() + : direction() { } + + inline bool isEmpty() const { return direction.isEmpty(); } + inline bool isNull() const { return direction.isEmpty(); } +}; +typedef QList DirectionList; + +class DirectionSimpleRecognizer +{ +public: + DirectionSimpleRecognizer(); + Direction addPosition(const QPoint &pos); + DirectionList getDirections() const; + void reset(); + +private: + QPoint lastPoint; + DirectionList directions; +}; + +class GestureRecognizerLinjaZax : public QGestureRecognizer +{ + Q_OBJECT +public: + GestureRecognizerLinjaZax(); + + QGestureRecognizer::Result recognize(const QList &inputEvents); + QGesture* makeEvent() const; + + void reset(); + +private: + void internalReset(); + + QPoint pressedPos; + QPoint lastPos; + QPoint currentPos; + bool mousePressed; + bool gestureFinished; + QString lastDirections; + QString currentDirection; + DirectionSimpleRecognizer simpleRecognizer; + LinjaZaxGesture::ZoomState zoomState; +}; + +#endif diff --git a/examples/gestures/collidingmice/images/cheese.jpg b/examples/gestures/collidingmice/images/cheese.jpg new file mode 100644 index 0000000..dea5795 Binary files /dev/null and b/examples/gestures/collidingmice/images/cheese.jpg differ diff --git a/examples/gestures/collidingmice/linjazaxgesture.h b/examples/gestures/collidingmice/linjazaxgesture.h new file mode 100644 index 0000000..9601675 --- /dev/null +++ b/examples/gestures/collidingmice/linjazaxgesture.h @@ -0,0 +1,58 @@ +#ifndef LINJAZAXGESTURE_H +#define LINJAZAXGESTURE_H + +#include + +class Q_GUI_EXPORT LinjaZaxGesture : public QGesture +{ +public: + enum DirectionType + { + None = 0, + LeftDown = 1, + DownLeft = LeftDown, + Down = 2, + RightDown = 3, + DownRight = RightDown, + Left = 4, + Right = 6, + LeftUp = 7, + UpLeft = LeftUp, + Up = 8, + RightUp = 9, + UpRight = RightUp + }; + + enum ZoomState + { + NoZoom, + ZoomingIn, + ZoomingOut + }; + +public: + explicit LinjaZaxGesture(const Qt::GestureType &type, Qt::GestureState state = Qt::GestureStarted) + : QGesture(type, state), lastDirection_(None), direction_(None), zoomState_(NoZoom) { } + LinjaZaxGesture(const Qt::GestureType &type, const QPoint &startPos, + const QPoint &lastPos, const QPoint &pos, const QRect &rect, + const QPoint &hotSpot, const QDateTime &startTime, + uint duration, Qt::GestureState state) + : QGesture(type, startPos, lastPos, pos, rect, hotSpot, startTime, duration, state) { } + ~LinjaZaxGesture() { } + + DirectionType lastDirection() const + { return lastDirection_; } + DirectionType direction() const + { return direction_; } + + ZoomState zoomState() const + { return zoomState_; } + +private: + DirectionType lastDirection_; + DirectionType direction_; + ZoomState zoomState_; + friend class GestureRecognizerLinjaZax; +}; + +#endif diff --git a/examples/gestures/collidingmice/main.cpp b/examples/gestures/collidingmice/main.cpp index 56e9f7f..9f50379 100644 --- a/examples/gestures/collidingmice/main.cpp +++ b/examples/gestures/collidingmice/main.cpp @@ -41,6 +41,9 @@ #include "mouse.h" +#include "gesturerecognizerlinjazax.h" +#include "linjazaxgesture.h" + #include #include @@ -53,14 +56,25 @@ public: PannableGraphicsView(QGraphicsScene *scene, QWidget *parent = 0) : QGraphicsView(scene, parent) { - grabGesture(Qt::Pan); + grabGesture("LinjaZax"); } protected: bool event(QEvent *event) { if (event->type() == QEvent::Gesture) { QGestureEvent *ge = static_cast(event); - if (const QPannableGesture *g = dynamic_cast(ge->gesture(Qt::Pan))) { + const LinjaZaxGesture *g = dynamic_cast(ge->gesture("LinjaZax")); + if (g) { + switch (g->zoomState()) { + case LinjaZaxGesture::ZoomingIn: + scale(1.5, 1.5); + break; + case LinjaZaxGesture::ZoomingOut: + scale(0.6, 0.6); + break; + default: + break; + }; QPoint pt = g->pos() - g->lastPos(); horizontalScrollBar()->setValue(horizontalScrollBar()->value() - pt.x()); verticalScrollBar()->setValue(verticalScrollBar()->value() - pt.y()); @@ -77,6 +91,7 @@ int main(int argc, char **argv) { QApplication app(argc, argv); QApplication::setAttribute(Qt::AA_EnableGestures); + app.addGestureRecognizer(new GestureRecognizerLinjaZax); qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); //! [0] -- cgit v0.12 From ed24f677a411c449a2a3f862906aff2a313b4425 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Fri, 6 Mar 2009 18:49:56 +0100 Subject: Added animation to zooming gesture in collidingmice example. --- .../collidingmice/gesturerecognizerlinjazax.cpp | 7 ++--- examples/gestures/collidingmice/main.cpp | 35 ++++++++++++++++++++++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/examples/gestures/collidingmice/gesturerecognizerlinjazax.cpp b/examples/gestures/collidingmice/gesturerecognizerlinjazax.cpp index 4c57209..3f90588 100644 --- a/examples/gestures/collidingmice/gesturerecognizerlinjazax.cpp +++ b/examples/gestures/collidingmice/gesturerecognizerlinjazax.cpp @@ -125,14 +125,13 @@ QGestureRecognizer::Result GestureRecognizerLinjaZax::recognize(const QList 5) lastDirections.remove(0, 1); - if (lastDirections.contains("248")) + if (lastDirections.contains("248") || lastDirections.contains("2448")) zoomState = LinjaZaxGesture::ZoomingIn; - else if (lastDirections.contains("268")) + else if (lastDirections.contains("268") || lastDirections.contains("2668")) zoomState = LinjaZaxGesture::ZoomingOut; } } diff --git a/examples/gestures/collidingmice/main.cpp b/examples/gestures/collidingmice/main.cpp index 9f50379..d6dbdb0 100644 --- a/examples/gestures/collidingmice/main.cpp +++ b/examples/gestures/collidingmice/main.cpp @@ -48,15 +48,26 @@ #include +#define ZOOMING_ANIMATION +#ifdef ZOOMING_ANIMATION +static const int AnimationSteps = 10; +#endif + static const int MouseCount = 7; class PannableGraphicsView : public QGraphicsView { + Q_OBJECT public: PannableGraphicsView(QGraphicsScene *scene, QWidget *parent = 0) : QGraphicsView(scene, parent) { grabGesture("LinjaZax"); +#ifdef ZOOMING_ANIMATION + timeline = new QTimeLine(700, this); + timeline->setFrameRange(0, AnimationSteps); + connect(timeline, SIGNAL(frameChanged(int)), this, SLOT(animationStep(int))); +#endif } protected: bool event(QEvent *event) @@ -67,10 +78,22 @@ protected: if (g) { switch (g->zoomState()) { case LinjaZaxGesture::ZoomingIn: +#ifdef ZOOMING_ANIMATION + scaleStep = 1. + 0.5/AnimationSteps; + timeline->stop(); + timeline->start(); +#else scale(1.5, 1.5); +#endif break; case LinjaZaxGesture::ZoomingOut: +#ifdef ZOOMING_ANIMATION + scaleStep = 1. - 0.5/AnimationSteps; + timeline->stop(); + timeline->start(); +#else scale(0.6, 0.6); +#endif break; default: break; @@ -84,6 +107,16 @@ protected: } return QGraphicsView::event(event); } +private slots: +#ifdef ZOOMING_ANIMATION + void animationStep(int step) + { + scale(scaleStep, scaleStep); + } +private: + qreal scaleStep; + QTimeLine *timeline; +#endif }; //! [0] @@ -127,3 +160,5 @@ int main(int argc, char **argv) return app.exec(); } //! [6] + +#include "main.moc" -- cgit v0.12 From 3e2cef8f6a58949b887add8ff1bb5e457e7be542 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Thu, 12 Mar 2009 16:07:36 +0100 Subject: Added QGraphicsSceneGestureEvent that extends plain QGestureEvent by providing some additional info (like a widget that received a gesture - for coordinates conversions). --- examples/gestures/graphicsview/main.cpp | 4 +- src/corelib/kernel/qcoreevent.h | 1 + src/gui/graphicsview/qgraphicsscene.cpp | 34 +++--- src/gui/graphicsview/qgraphicsscene.h | 3 +- src/gui/graphicsview/qgraphicsscene_p.h | 1 - src/gui/graphicsview/qgraphicssceneevent.cpp | 148 +++++++++++++++++++++++++++ src/gui/graphicsview/qgraphicssceneevent.h | 40 ++++++++ src/gui/graphicsview/qgraphicsview.cpp | 12 ++- src/gui/kernel/qapplication.cpp | 1 - src/gui/kernel/qevent.cpp | 26 +++-- src/gui/kernel/qevent.h | 8 +- src/gui/kernel/qgesturemanager.cpp | 8 +- 12 files changed, 236 insertions(+), 50 deletions(-) diff --git a/examples/gestures/graphicsview/main.cpp b/examples/gestures/graphicsview/main.cpp index 250da06..1b325ee 100644 --- a/examples/gestures/graphicsview/main.cpp +++ b/examples/gestures/graphicsview/main.cpp @@ -94,8 +94,8 @@ public: bool sceneEvent(QEvent *event) { - if (event->type() == QEvent::Gesture) { - QGestureEvent *gestureEvent = static_cast(event); + if (event->type() == QEvent::GraphicsSceneGesture) { + QGraphicsSceneGestureEvent *gestureEvent = static_cast(event); if (gestureEvent->gesture(Qt::DoubleTap)) { event->accept(); colored = !colored; diff --git a/src/corelib/kernel/qcoreevent.h b/src/corelib/kernel/qcoreevent.h index 4ea3c70..cb24723 100644 --- a/src/corelib/kernel/qcoreevent.h +++ b/src/corelib/kernel/qcoreevent.h @@ -274,6 +274,7 @@ public: GraphicsSceneTouchEnd = 198, Gesture = 191, + GraphicsSceneGesture = 192, // 512 reserved for Qt Jambi's MetaCall event // 513 reserved for Qt Jambi's DeleteOnMainThread event diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 21c7c81..7e23620 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -3951,8 +3951,8 @@ bool QGraphicsScene::event(QEvent *event) // geometries that do not have an explicit style set. update(); break; - case QEvent::Gesture: - gestureEvent(static_cast(event)); + case QEvent::GraphicsSceneGesture: + gestureEvent(static_cast(event)); break; case QEvent::GraphicsSceneTouchBegin: d->touchBeginEvent(static_cast(event)); @@ -5604,36 +5604,32 @@ void QGraphicsScenePrivate::removeView(QGraphicsView *view) view->releaseGesture(gesture); } -void QGraphicsScenePrivate::sendGestureEvent(QGraphicsItem *item, QGestureEvent *event) -{ - //### TODO: position translation - sendEvent(item, event); -} - -void QGraphicsScene::gestureEvent(QGestureEvent *event) +void QGraphicsScene::gestureEvent(QGraphicsSceneGestureEvent *event) { Q_D(QGraphicsScene); QList gestureTypes = event->gestureTypes(); - QGraphicsView *view = qobject_cast(event->targetWidget()); + QGraphicsView *view = qobject_cast(event->widget()); if (!view) { - // something is wrong. - Q_ASSERT(view); + qWarning("QGraphicsScene::gestureEvent: gesture event was received without a view"); return; } + + // find graphics items that intersects with gestures hot spots. QPolygonF poly; - QMap hotSpots; + QMap sceneHotSpots; foreach(const Qt::GestureType &type, gestureTypes) { - QPointF pt = view->mapToScene(event->gesture(type)->hotSpot()); - hotSpots.insert(type, pt); + QPointF pt = event->mapToScene(event->gesture(type)->hotSpot()); + sceneHotSpots.insert(type, pt); poly << pt; } + QList itemsInGestureArea = items(poly, Qt::IntersectsItemBoundingRect); - foreach(QGraphicsItem *item, items(poly, Qt::IntersectsItemBoundingRect)) { - QMap::const_iterator it = hotSpots.begin(), - e = hotSpots.end(); + foreach(QGraphicsItem *item, itemsInGestureArea) { + QMap::const_iterator it = sceneHotSpots.begin(), + e = sceneHotSpots.end(); for(; it != e; ++it) { if (item->contains(item->mapFromScene(it.value())) && item->gestures().contains(it.key())) { - d->sendGestureEvent(item, event); + d->sendEvent(item, event); if (event->isAccepted()) break; } diff --git a/src/gui/graphicsview/qgraphicsscene.h b/src/gui/graphicsview/qgraphicsscene.h index 4680455..45def44 100644 --- a/src/gui/graphicsview/qgraphicsscene.h +++ b/src/gui/graphicsview/qgraphicsscene.h @@ -80,6 +80,7 @@ class QGraphicsSceneHelpEvent; class QGraphicsSceneHoverEvent; class QGraphicsSceneMouseEvent; class QGraphicsSceneWheelEvent; +class QGraphicsSceneGestureEvent; class QGraphicsSimpleTextItem; class QGraphicsTextItem; class QGraphicsView; @@ -255,7 +256,7 @@ protected: virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); virtual void wheelEvent(QGraphicsSceneWheelEvent *event); virtual void inputMethodEvent(QInputMethodEvent *event); - virtual void gestureEvent(QGestureEvent *event); + virtual void gestureEvent(QGraphicsSceneGestureEvent *event); virtual void drawBackground(QPainter *painter, const QRectF &rect); virtual void drawForeground(QPainter *painter, const QRectF &rect); diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index cea0553..1cd1788 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -271,7 +271,6 @@ public: QSet grabbedGestures; void grabGesture(QGraphicsItem *item, const Qt::GestureType &type); void releaseGesture(QGraphicsItem *item, const Qt::GestureType &type); - void sendGestureEvent(QGraphicsItem *item, QGestureEvent *event); mutable QVector sceneTransformCache; mutable QBitArray validTransforms; diff --git a/src/gui/graphicsview/qgraphicssceneevent.cpp b/src/gui/graphicsview/qgraphicssceneevent.cpp index 3c9799b..4d9e7bb 100644 --- a/src/gui/graphicsview/qgraphicssceneevent.cpp +++ b/src/gui/graphicsview/qgraphicssceneevent.cpp @@ -299,6 +299,8 @@ #include #include #include +#include "qgraphicsview.h" +#include "qgraphicsitem.h" QT_BEGIN_NAMESPACE @@ -1704,6 +1706,152 @@ void QGraphicsSceneMoveEvent::setNewPos(const QPointF &pos) d->newPos = pos; } +/*! + \class QGraphicsSceneGestureEvent + \brief The QGraphicsSceneGestureEvent class provides gesture events for + the graphics view framework. + \since 4.6 + \ingroup graphicsview-api + + QGraphicsSceneGestureEvent extends information provided by + QGestureEvent by adding some convenience functions like + \l{QGraphicsSceneEvent::}{widget()} to get a widget that received + original gesture event, and convenience functions mapToScene(), + mapToItem() for converting positions of the gesture into + QGraphicsScene and QGraphicsItem coordinate system respectively. + + The scene sends the event to the first QGraphicsItem under the + mouse cursor that accepts gestures; a graphics item is set to accept + gestures with \l{QGraphicsItem::}{grabGesture()}. +*/ + +/*! \fn bool QGraphicsSceneGestureEvent::contains(const Qt::GestureType &type) const + + Checks if the gesture event contains gesture of specific \a type. +*/ + +/*! \fn QList QGraphicsSceneGestureEvent::gestureTypes() const + + Returns a list of gesture names that the event contains. +*/ + +/*! \fn const QGesture* QGraphicsSceneGestureEvent::gesture(const Qt::GestureType &type) const + + Returns extended information about a gesture of specific \a type. +*/ + +/*! \fn QList > QGraphicsSceneGestureEvent::gestures() const + + Returns extended information about all triggered gestures. +*/ + +/*! \fn QSet QGraphicsSceneGestureEvent::cancelledGestures() const + + Returns a set of gesture names that used to be executed, but got + cancelled (i.e. they were not finished properly). +*/ + +/*! \fn void QGraphicsSceneGestureEvent::setCancelledGestures(const QSet &) + + Returns a set of gesture names that used to be executed, but got + cancelled (i.e. they were not finished properly). +*/ + +QGraphicsSceneGestureEvent::QGraphicsSceneGestureEvent() + : QGraphicsSceneEvent(QEvent::GraphicsSceneGesture) +{ +} + +QGraphicsSceneGestureEvent::~QGraphicsSceneGestureEvent() +{ +} + +/*! + Maps the point \a point, which is in a view coordinate system, to + scene coordinate system, and returns the mapped coordinate. + + \a Point is in coordinate system of the widget that received + gesture event. + + \sa mapToScene(const QRect &rect), + mapToItem(const QPoint &point, QGraphicsItem *item), + mapToItem(const QRect &rect, QGraphicsItem *item), + {The Graphics View Coordinate System} +*/ +QPointF QGraphicsSceneGestureEvent::mapToScene(const QPoint &point) const +{ + if (QGraphicsView *view = qobject_cast(widget())) + return view->mapToScene(point); + return QPointF(); +} + +/*! + Maps the rectangular \a rect, which is in a view coordinate system, to + scene coordinate system, and returns the mapped coordinate. + + \a Point is in coordinate system of the widget that received + gesture event. + + \sa mapToScene(const QPoint &rect), + mapToItem(const QPoint &point, QGraphicsItem *item), + mapToItem(const QRect &rect, QGraphicsItem *item), + {The Graphics View Coordinate System} +*/ +QPolygonF QGraphicsSceneGestureEvent::mapToScene(const QRect &rect) const +{ + if (QGraphicsView *view = qobject_cast(widget())) + return view->mapToScene(rect); + return QPolygonF(); +} + +/*! + Maps the point \a point, which is in a view coordinate system, to + item's \a item coordinate system, and returns the mapped coordinate. + + If \a item is 0, this function returns the same as mapToScene(). + + \sa mapToScene(const QPoint &rect), mapToScene(const QRect &rect), + mapToItem(const QRect &, QGraphicsItem *item), + {The Graphics View Coordinate System} +*/ +QPointF QGraphicsSceneGestureEvent::mapToItem(const QPoint &point, QGraphicsItem *item) const +{ + if (item) { + if (QGraphicsView *view = qobject_cast(widget())) + return item->mapFromScene(view->mapToScene(point)); + } else { + return mapToScene(point); + } + return QPointF(); +} + +/*! + Maps the point \a point, which is in a view coordinate system, to + item's \a item coordinate system, and returns the mapped coordinate. + + If \a item is 0, this function returns the same as mapToScene(). + + \sa mapToScene(const QPoint &rect), mapToScene(const QRect &rect), + mapToItem(const QPoint &point, QGraphicsItem *item), + {The Graphics View Coordinate System} +*/ +QPolygonF QGraphicsSceneGestureEvent::mapToItem(const QRect &rect, QGraphicsItem *item) const +{ + if (item) { + if (QGraphicsView *view = qobject_cast(widget())) + return item->mapFromScene(view->mapToScene(rect)); + } else { + return mapToScene(rect); + } + return QPolygonF(); +} + +void QGraphicsSceneGestureEvent::setGestures(const QList > &gestures) +{ + foreach(const QSharedPointer &g, gestures) + m_gestures.insert(g->gestureType(), g); +} + class QGraphicsSceneTouchEventPrivate : public QGraphicsSceneEventPrivate { Q_DECLARE_PUBLIC(QGraphicsSceneTouchEvent) diff --git a/src/gui/graphicsview/qgraphicssceneevent.h b/src/gui/graphicsview/qgraphicssceneevent.h index 8ae3a99..d3899cd 100644 --- a/src/gui/graphicsview/qgraphicssceneevent.h +++ b/src/gui/graphicsview/qgraphicssceneevent.h @@ -44,6 +44,11 @@ #include #include +#include +#include +#include +#include +#include QT_BEGIN_HEADER @@ -302,6 +307,41 @@ public: void setNewPos(const QPointF &pos); }; +class QGesture; +class QGraphicsItem; +class QGraphicsSceneGestureEventPrivate; +class Q_GUI_EXPORT QGraphicsSceneGestureEvent : public QGraphicsSceneEvent +{ + Q_DECLARE_PRIVATE(QGraphicsSceneGestureEvent) +public: + QGraphicsSceneGestureEvent(); + ~QGraphicsSceneGestureEvent(); + + inline bool contains(const Qt::GestureType &type) const + { return gesture(type) != 0; } + inline QList gestureTypes() const + { return m_gestures.keys(); } + inline const QGesture* gesture(const Qt::GestureType &type) const + { return m_gestures.value(type, QSharedPointer()).data(); } + inline QList > gestures() const + { return m_gestures.values(); } + void setGestures(const QList > &gestures); + + inline QSet cancelledGestures() const + { return m_cancelledGestures; } + void setCancelledGestures(const QSet &cancelledGestures) + { m_cancelledGestures = cancelledGestures; } + + QPointF mapToScene(const QPoint &point) const; + QPolygonF mapToScene(const QRect &rect) const; + QPointF mapToItem(const QPoint &point, QGraphicsItem *item) const; + QPolygonF mapToItem(const QRect &rect, QGraphicsItem *item) const; + +protected: + QHash > m_gestures; + QSet m_cancelledGestures; +}; + class QGraphicsSceneTouchEventPrivate; class QGraphicsSceneTouchEventTouchPointPrivate; class Q_GUI_EXPORT QGraphicsSceneTouchEvent : public QGraphicsSceneEvent diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 97903d3..925763c 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -2862,10 +2862,16 @@ bool QGraphicsView::event(QEvent *event) } } break; - case QEvent::Gesture: - QApplication::sendEvent(d->scene, event); - if (event->isAccepted()) + case QEvent::Gesture: { + QGraphicsSceneGestureEvent gestureEvent; + gestureEvent.setWidget(this); + QGestureEvent *ev = static_cast(event); + gestureEvent.setGestures(ev->gestures()); + gestureEvent.setCancelledGestures(ev->cancelledGestures()); + QApplication::sendEvent(d->scene, &gestureEvent); + if (gestureEvent.isAccepted()) return true; + } break; default: break; diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 104271d..5774ae0 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -4037,7 +4037,6 @@ bool QApplication::notify(QObject *receiver, QEvent *e) // QGestureEvent ge(&qge, false); // ### TODO: fix widget-relative positions in gesture event. QGestureEvent ge = *g; - ge.m_targetWidget = w; ge.spont = g->spontaneous(); res = d->notify_helper(w, w == receiver ? g : &ge); g->spont = false; diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index d7d193c..6cdf781 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -3524,27 +3524,27 @@ QMenubarUpdatedEvent::QMenubarUpdatedEvent(QMenuBar * const menuBar) \sa QGesture */ -/*! \fn QWidget *QGestureEvent::targetWidget() const - - Returns the widget the gesture event is send to. -*/ - -/*! \fn bool contains(const Qt::GestureType &type) const +/*! \fn bool QGestureEvent::contains(const Qt::GestureType &type) const Checks if the gesture event contains gesture of specific \a type. */ -/*! \fn QList gestureTypes() const +/*! \fn QList QGestureEvent::gestureTypes() const Returns a list of gesture names that the event contains. */ -/*! \fn const QGesture* gesture(const Qt::GestureType &type) const +/*! \fn const QGesture* QGestureEvent::gesture(const Qt::GestureType &type) const Returns extended information about a gesture of specific \a type. */ -/*! \fn QSet cancelledGestures() const +/*! \fn QList > QGestureEvent::gestures() const + + Returns extended information about all triggered gestures. +*/ + +/*! \fn QSet QGestureEvent::cancelledGestures() const Returns a set of gesture names that used to be executed, but got cancelled (i.e. they were not finished properly). @@ -3553,18 +3553,16 @@ QMenubarUpdatedEvent::QMenubarUpdatedEvent(QMenuBar * const menuBar) -QGestureEvent::QGestureEvent(QWidget *targetWidget, const QList &gestures, +QGestureEvent::QGestureEvent(const QList &gestures, const QSet &cancelledGestures) - : QEvent(QEvent::Gesture), m_targetWidget(targetWidget), - m_cancelledGestures(cancelledGestures) + : QEvent(QEvent::Gesture), m_cancelledGestures(cancelledGestures) { foreach(QGesture *r, gestures) m_gestures.insert(r->gestureType(), QSharedPointer(r)); } QGestureEvent::QGestureEvent(const QGestureEvent &event, const QPoint &offset) - : QEvent(QEvent::Gesture), m_targetWidget(event.m_targetWidget), - m_gestures(event.m_gestures), + : QEvent(QEvent::Gesture), m_gestures(event.m_gestures), m_cancelledGestures(event.m_cancelledGestures) { //### use offset! diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index cde7cb2..603f358 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -717,27 +717,25 @@ private: class Q_GUI_EXPORT QGestureEvent : public QEvent { public: - QGestureEvent(QWidget *targetWidget, const QList &gestures, + QGestureEvent(const QList &gestures, const QSet &cancelledGestures = QSet()); // internal ctor QGestureEvent(const QGestureEvent &gestures, const QPoint &offset); ~QGestureEvent(); - QWidget *targetWidget() const - { return m_targetWidget; } - inline bool contains(const Qt::GestureType &type) const { return gesture(type) != 0; } inline QList gestureTypes() const { return m_gestures.keys(); } inline const QGesture* gesture(const Qt::GestureType &type) const { return m_gestures.value(type, QSharedPointer()).data(); } + inline QList > gestures() const + { return m_gestures.values(); } inline QSet cancelledGestures() const { return m_cancelledGestures; } protected: - QWidget *m_targetWidget; QHash > m_gestures; QSet m_cancelledGestures; diff --git a/src/gui/kernel/qgesturemanager.cpp b/src/gui/kernel/qgesturemanager.cpp index 7954ae9..9a287a0 100644 --- a/src/gui/kernel/qgesturemanager.cpp +++ b/src/gui/kernel/qgesturemanager.cpp @@ -178,7 +178,7 @@ bool QGestureManager::filterEvent(QEvent *event) gestures << gesture; } Q_ASSERT(!gestures.isEmpty()); - QGestureEvent event(targetWidget, gestures); + QGestureEvent event(gestures); ret = qt_sendGestureEvent(targetWidget, &event); ret = ret && event.isAccepted(); @@ -283,7 +283,7 @@ bool QGestureManager::filterEvent(QEvent *event) foreach(QGestureRecognizer *r, cancelledGestures) cancelledGestureNames << r->gestureType(); if(!gestures.isEmpty()) { - QGestureEvent event(targetWidget, gestures, cancelledGestureNames); + QGestureEvent event(gestures, cancelledGestureNames); ret = qt_sendGestureEvent(targetWidget, &event); ret = ret && event.isAccepted(); } @@ -375,7 +375,7 @@ void QGestureManager::recognizerTriggered(QGestureRecognizer::Result result) if (QGesture *gesture = recognizer->makeEvent()) gestures << gesture; if(!gestures.isEmpty()) { - QGestureEvent event(targetWidget, gestures); + QGestureEvent event(gestures); qt_sendGestureEvent(targetWidget, &event); } if (result == QGestureRecognizer::GestureFinished) @@ -385,7 +385,7 @@ void QGestureManager::recognizerTriggered(QGestureRecognizer::Result result) case QGestureRecognizer::MaybeGesture: { DEBUG() << "QGestureManager: maybe gesture: " << recognizer; if (activeGestures.contains(recognizer)) { - QGestureEvent event(targetWidget, QList(), + QGestureEvent event(QList(), QSet() << recognizer->gestureType()); qt_sendGestureEvent(targetWidget, &event); } -- cgit v0.12 From f8c5c2720b4a48dad0f68b83d9c494185e012cd1 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Thu, 12 Mar 2009 17:06:17 +0100 Subject: Moved the code that translated QGestureEvent to QGraphicsSceneGestureEvent to a viewport, so that the user could subscribe to gestures in a viewport as well. --- src/gui/graphicsview/qgraphicsview.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 925763c..6f142e3 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -2862,16 +2862,8 @@ bool QGraphicsView::event(QEvent *event) } } break; - case QEvent::Gesture: { - QGraphicsSceneGestureEvent gestureEvent; - gestureEvent.setWidget(this); - QGestureEvent *ev = static_cast(event); - gestureEvent.setGestures(ev->gestures()); - gestureEvent.setCancelledGestures(ev->cancelledGestures()); - QApplication::sendEvent(d->scene, &gestureEvent); - if (gestureEvent.isAccepted()) - return true; - } + case QEvent::Gesture: + viewportEvent(event); break; default: break; @@ -2953,6 +2945,17 @@ bool QGraphicsView::viewportEvent(QEvent *event) d->scene->d_func()->updateAll = false; } break; + case QEvent::Gesture: { + QGraphicsSceneGestureEvent gestureEvent; + gestureEvent.setWidget(this); + QGestureEvent *ev = static_cast(event); + gestureEvent.setGestures(ev->gestures()); + gestureEvent.setCancelledGestures(ev->cancelledGestures()); + QApplication::sendEvent(d->scene, &gestureEvent); + if (gestureEvent.isAccepted()) + return true; + } + break; case QEvent::TouchBegin: case QEvent::TouchUpdate: case QEvent::TouchEnd: -- cgit v0.12 From 86a160b083f9d43c07d42bbd7d2ef8b676552e38 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Fri, 13 Mar 2009 18:08:18 +0100 Subject: Modifications after the api review by Brad. Gesture types are now separated to internal ones, which are listed as enums (though they might be converted to strings internally), and third party gestures which are referenced by strings. From now on QGesture objects derive from QObject, which means third party gesture recognizer developers can use QObjects property s