summaryrefslogtreecommitdiffstats
path: root/krita/ui/kis_canvas.h
blob: b9e387386f79334c3bd895111b95c2f59ee76184 (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
/*
 *  Copyright (c) 1999 Matthias Elter  <[email protected]>
 *  Copyright (c) 2004-2006 Adrian Page <[email protected]>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#ifndef KIS_CANVAS_H_
#define KIS_CANVAS_H_

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <qwidget.h>
#ifdef HAVE_GL
#include <qgl.h>
#endif
#include <qpainter.h>

#include "kis_global.h"
#include "kis_point.h"
#include "kis_vec.h"
#include "kis_input_device.h"

#ifdef Q_WS_X11

// Irix has a different (and better) XInput tablet driver to
// the XFree/xorg driver. Qt needs a separate code path for that
// and so would we.
#if defined(HAVE_XINPUTEXT) && !defined(Q_OS_IRIX)
#define EXTENDED_X11_TABLET_SUPPORT
#endif

#include <map>
#include <X11/Xlib.h>

#if defined(EXTENDED_X11_TABLET_SUPPORT)
#include <X11/extensions/XInput.h>
#endif

#endif // Q_WS_X11

class KisEvent;
class KisMoveEvent;
class KisButtonPressEvent;
class KisButtonReleaseEvent;
class KisDoubleClickEvent;
class KisCanvasWidgetPainter;

class KisCanvasWidget : public QObject {
    Q_OBJECT

public:
    KisCanvasWidget();
    virtual ~KisCanvasWidget();
    
    // When enabled, the canvas may throw away move events if the application
    // is unable to keep up with them, i.e. intermediate move events in the event
    // queue are skipped.
    void enableMoveEventCompressionHint(bool enableMoveCompression) { m_enableMoveEventCompressionHint = enableMoveCompression; }

    virtual KisCanvasWidgetPainter *createPainter() = 0;

#ifdef EXTENDED_X11_TABLET_SUPPORT
    static KisInputDevice findActiveInputDevice();
    virtual void selectTabletDeviceEvents() = 0;

    static void selectTabletDeviceEvents(QWidget *widget);
#endif

#ifdef Q_WS_X11
    static void initX11Support();
#endif

signals:
    void sigGotPaintEvent(QPaintEvent*);
    void sigGotEnterEvent(QEvent*);
    void sigGotLeaveEvent(QEvent*);
    void sigGotMouseWheelEvent(QWheelEvent*);
    void sigGotKeyPressEvent(QKeyEvent*);
    void sigGotKeyReleaseEvent(QKeyEvent*);
    void sigGotDragEnterEvent(QDragEnterEvent*);
    void sigGotDropEvent(QDropEvent*);
    void sigGotMoveEvent(KisMoveEvent *);
    void sigGotButtonPressEvent(KisButtonPressEvent *);
    void sigGotButtonReleaseEvent(KisButtonReleaseEvent *);
    void sigGotDoubleClickEvent(KisDoubleClickEvent *);

protected:
    void widgetGotPaintEvent(QPaintEvent *event);
    void widgetGotMousePressEvent(QMouseEvent *event);
    void widgetGotMouseReleaseEvent(QMouseEvent *event);
    void widgetGotMouseDoubleClickEvent(QMouseEvent *event);
    void widgetGotMouseMoveEvent(QMouseEvent *event);
    void widgetGotTabletEvent(QTabletEvent *event);
    void widgetGotEnterEvent(QEvent *event );
    void widgetGotLeaveEvent(QEvent *event);
    void widgetGotWheelEvent(QWheelEvent *event);
    void widgetGotKeyPressEvent(QKeyEvent *event);
    void widgetGotKeyReleaseEvent(QKeyEvent *event);
    void widgetGotDragEnterEvent(QDragEnterEvent *event);
    void widgetGotDropEvent(QDropEvent *event);
    void moveEvent(KisMoveEvent *event);
    void buttonPressEvent(KisButtonPressEvent *event);
    void buttonReleaseEvent(KisButtonReleaseEvent *event);
    void doubleClickEvent(KisDoubleClickEvent *event);
    void translateTabletEvent(KisEvent *event);

protected:

    bool m_enableMoveEventCompressionHint;
    double m_lastPressure;

#ifdef Q_WS_X11
    // On X11 systems, Qt throws away mouse move events if the application
    // is unable to keep up with them. We override this behaviour so that
    // we receive all move events, so that painting follows the mouse's motion
    // accurately.
    bool x11Event(XEvent *event, Display *x11Display, WId winId, QPoint widgetOriginPos);
    static Qt::ButtonState translateX11ButtonState(int state);
    static Qt::ButtonState translateX11Button(unsigned int button);

    static bool X11SupportInitialised;

    // Modifier masks for alt/meta - detected at run-time
    static long X11AltMask;
    static long X11MetaMask;

    int m_lastRootX;
    int m_lastRootY;

#ifdef EXTENDED_X11_TABLET_SUPPORT

public:
    class X11TabletDevice
    {
    public:
        X11TabletDevice();
        X11TabletDevice(const XDeviceInfo *deviceInfo);

        bool mightBeTabletDevice() const { return m_mightBeTabletDevice; }

        XID id() const { return m_deviceId; }
        XDevice *xDevice() const { return m_XDevice; }
        QString name() const { return m_name; }

        KisInputDevice inputDevice() const { return m_inputDevice; }
        void setInputDevice(KisInputDevice inputDevice) { m_inputDevice = inputDevice; }

        void setEnabled(bool enabled);
        bool enabled() const;

        Q_INT32 numAxes() const;

        void setXAxis(Q_INT32 axis);
        void setYAxis(Q_INT32 axis);
        void setPressureAxis(Q_INT32 axis);
        void setXTiltAxis(Q_INT32 axis);
        void setYTiltAxis(Q_INT32 axis);
        void setWheelAxis(Q_INT32 axis);
        void setToolIDAxis(Q_INT32 axis);
        void setSerialNumberAxis(Q_INT32 axis);

        static const Q_INT32 NoAxis = -1;
        static const Q_INT32 DefaultAxis = -2;

        Q_INT32 xAxis() const;
        Q_INT32 yAxis() const;
        Q_INT32 pressureAxis() const;
        Q_INT32 xTiltAxis() const;
        Q_INT32 yTiltAxis() const;
        Q_INT32 wheelAxis() const;
        Q_INT32 toolIDAxis() const;
        Q_INT32 serialNumberAxis() const;

        void readSettingsFromConfig();
        void writeSettingsToConfig();

        // These return -1 if the device does not support the event
        int buttonPressEvent() const { return m_buttonPressEvent; }
        int buttonReleaseEvent() const { return m_buttonReleaseEvent; }
        int motionNotifyEvent() const { return m_motionNotifyEvent; }
        int proximityInEvent() const { return m_proximityInEvent; }
        int proximityOutEvent() const { return m_proximityOutEvent; }

        void enableEvents(QWidget *widget) const;

        class State
        {
        public:
            State() {}
            State(const KisPoint& pos, double pressure, const KisVector2D& tilt, double wheel,
                  Q_UINT32 toolID, Q_UINT32 serialNumber);

            // Position, pressure and wheel are normalised to 0 - 1
            KisPoint pos() const { return m_pos; }
            double pressure() const { return m_pressure; }
            // Tilt is normalised to -1->+1
            KisVector2D tilt() const { return m_tilt; }
            double wheel() const { return m_wheel; }
            // Wacom tool id and serial number of device.
            Q_UINT32 toolID() const { return m_toolID; }
            Q_UINT32 serialNumber() const { return m_serialNumber; }

        private:
            KisPoint m_pos;
            double m_pressure;
            KisVector2D m_tilt;
            double m_wheel;
            Q_UINT32 m_toolID;
            Q_UINT32 m_serialNumber;
        };

        State translateAxisData(const int *axisData) const;

    private:
        double translateAxisValue(int value, const XAxisInfo& axisInfo) const;

        XID m_deviceId;
        XDevice *m_XDevice;

        QString m_name;

        bool m_mightBeTabletDevice;
        KisInputDevice m_inputDevice;

        bool m_enabled;

        Q_INT32 m_xAxis;
        Q_INT32 m_yAxis;
        Q_INT32 m_pressureAxis;
        Q_INT32 m_xTiltAxis;
        Q_INT32 m_yTiltAxis;
        Q_INT32 m_wheelAxis;
        Q_INT32 m_toolIDAxis;
        Q_INT32 m_serialNumberAxis;

        QValueVector<XAxisInfo> m_axisInfo;

        int m_motionNotifyEvent;
        int m_buttonPressEvent;
        int m_buttonReleaseEvent;
        int m_proximityInEvent;
        int m_proximityOutEvent;

        QValueVector<XEventClass> m_eventClassList;
    };

    typedef std::map<XID, X11TabletDevice> X11XIDTabletDeviceMap;
    static X11XIDTabletDeviceMap& tabletDeviceMap();

protected:
    static int X11DeviceMotionNotifyEvent;
    static int X11DeviceButtonPressEvent;
    static int X11DeviceButtonReleaseEvent;
    static int X11ProximityInEvent;
    static int X11ProximityOutEvent;

    static X11XIDTabletDeviceMap X11TabletDeviceMap;

#endif // EXTENDED_X11_TABLET_SUPPORT

#endif // Q_WS_X11
};

class KisCanvas : public QObject {
    Q_OBJECT

public:
    KisCanvas(QWidget *parent, const char *name);
    virtual ~KisCanvas();
    
    // When enabled, the canvas may throw away move events if the application
    // is unable to keep up with them, i.e. intermediate move events in the event
    // queue are skipped.
    void enableMoveEventCompressionHint(bool enableMoveCompression);

    bool isOpenGLCanvas() const;

    /**
     * Returns true if the cursor is over the canvas.
     */
    bool cursorIsOverCanvas() const;

    /**
     * Handle the given event (which must be a key event) as if the canvas 
     * had received it directly.
     */
    void handleKeyEvent(QEvent *e);

    int width() const;
    int height() const;

    void update();
    void update(const QRect& r);
    void update(int x, int y, int width, int height);
    void repaint();
    void repaint(bool erase);
    void repaint(int x, int y, int width, int height, bool erase = true);
    void repaint(const QRect& r, bool erase = true);
    void repaint(const QRegion& r, bool erase = true);

    void updateGeometry();

#if defined(EXTENDED_X11_TABLET_SUPPORT)
    void selectTabletDeviceEvents();
#endif

signals:
    void sigGotPaintEvent(QPaintEvent*);
    void sigGotEnterEvent(QEvent*);
    void sigGotLeaveEvent(QEvent*);
    void sigGotMouseWheelEvent(QWheelEvent*);
    void sigGotKeyPressEvent(QKeyEvent*);
    void sigGotKeyReleaseEvent(QKeyEvent*);
    void sigGotDragEnterEvent(QDragEnterEvent*);
    void sigGotDropEvent(QDropEvent*);
    void sigGotMoveEvent(KisMoveEvent *);
    void sigGotButtonPressEvent(KisButtonPressEvent *);
    void sigGotButtonReleaseEvent(KisButtonReleaseEvent *);
    void sigGotDoubleClickEvent(KisDoubleClickEvent *);

protected:
    // Allow KisView to render on the widget directly, but everything else
    // has restricted access.
    friend class KisView;
    friend class KisCanvasPainter;

    // One of these will be valid, the other null. In Qt3, using a QPainter on
    // a QGLWidget is not reliable.
    QWidget *QPaintDeviceWidget() const;
#ifdef HAVE_GL
    QGLWidget *OpenGLWidget() const;
#endif
    void createQPaintDeviceCanvas();
#ifdef HAVE_GL
    void createOpenGLCanvas(QGLWidget *sharedContextWidget);
#endif
    void show();
    void hide();
    void setGeometry(int x, int y, int width, int height);

    void setUpdatesEnabled(bool updatesEnabled);
    bool isUpdatesEnabled() const;

    void setFocusPolicy(QWidget::FocusPolicy focusPolicy);

    const QCursor& cursor() const;
    void setCursor(const QCursor& cursor);

    KisCanvasWidgetPainter *createPainter();
    KisCanvasWidget *canvasWidget() const;

protected:
#ifdef HAVE_GL
    void createCanvasWidget(bool useOpenGL, QGLWidget *sharedContextWidget = 0);
#else
    void createCanvasWidget(bool useOpenGL);
#endif
    QWidget *m_parent;
    QString m_name;
    KisCanvasWidget *m_canvasWidget;
    bool m_enableMoveEventCompressionHint;
    bool m_useOpenGL;
};

#endif // KIS_CANVAS_H_