|  | Home · Examples

# Code for Tablet Example

    /****************************************************************************
    **
    ** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
    **
    ** This file is part of Qt Jambi.
    **
    ** ** This file may be used under the terms of the GNU General Public
    ** License version 2.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 GNU
    ** General Public Licensing requirements will be met:
    ** http://www.trolltech.com/products/qt/opensource.html
    **
    ** If you are unsure which license is appropriate for your use, please
    ** review the following information:
    ** http://www.trolltech.com/products/qt/licensing.html or contact the
    ** sales department at sales@trolltech.com.

    **
    ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
    ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
    **
    ****************************************************************************/

    package com.trolltech.examples;

    import com.trolltech.qt.core.*;
    import com.trolltech.qt.gui.*;

    public class Tablet extends QMainWindow
    {
        public static TabletCanvas myCanvas;

        private QAction brushColorAction;

        private QActionGroup alphaChannelGroup;
        private QAction alphaChannelPressureAction;
        private QAction alphaChannelTiltAction;
        private QAction noAlphaChannelAction;

        private QActionGroup colorSaturationGroup;
        private QAction colorSaturationVTiltAction;
        private QAction colorSaturationHTiltAction;
        private QAction colorSaturationPressureAction;
        private QAction noColorSaturationAction;

        private QActionGroup lineWidthGroup;
        private QAction lineWidthPressureAction;
        private QAction lineWidthTiltAction;
        private QAction lineWidthFixedAction;

        private QAction exitAction;
        private QAction saveAction;
        private QAction loadAction;

        private QAction aboutAction;
        private QAction aboutQtAction;

        private QMenu fileMenu;
        private QMenu brushMenu;
        private QMenu tabletMenu;
        private QMenu helpMenu;
        private QMenu colorSaturationMenu;
        private QMenu lineWidthMenu;
        private QMenu alphaChannelMenu;

        public enum AlphaChannelType { AlphaPressure, AlphaTilt, NoAlpha }
        public enum ColorSaturationType { SaturationVTilt, SaturationHTilt,
                                       SaturationPressure, NoSaturation }
        public enum LineWidthType { LineWidthPressure, LineWidthTilt, NoLineWidth }

        public Tablet()
        {
            myCanvas = new TabletCanvas();

            createActions();
            createMenus();

            myCanvas.setColor(new QColor(Qt.GlobalColor.red));
            myCanvas.setLineWidthType(LineWidthType.LineWidthPressure);
            myCanvas.setAlphaChannelType(AlphaChannelType.NoAlpha);
            myCanvas.setColorSaturationType(ColorSaturationType.NoSaturation);

            setWindowTitle(tr("Tablet Example"));
            setCentralWidget(myCanvas);
        }

        public void brushColorAct()
        {
            QColor color = QColorDialog.getColor(myCanvas.color());

            if (color.isValid())
                myCanvas.setColor(color);
        }

        public void alphaActionTriggered(QAction action)
        {
            if (action.equals(alphaChannelPressureAction)) {
                myCanvas.setAlphaChannelType(AlphaChannelType.AlphaPressure);
            } else if (action.equals(alphaChannelTiltAction)) {
                myCanvas.setAlphaChannelType(AlphaChannelType.AlphaTilt);
            } else {
                myCanvas.setAlphaChannelType(AlphaChannelType.NoAlpha);
            }
        }

        public void lineWidthActionTriggered(QAction action)
        {
            if (action.equals(lineWidthPressureAction)) {
                myCanvas.setLineWidthType(LineWidthType.LineWidthPressure);
            } else if (action.equals(lineWidthTiltAction)) {
                myCanvas.setLineWidthType(LineWidthType.LineWidthTilt);
            } else {
                myCanvas.setLineWidthType(LineWidthType.NoLineWidth);
            }
        }

        public void saturationActionTriggered(QAction action)
        {
            if (action.equals(colorSaturationVTiltAction)) {
                myCanvas.setColorSaturationType(ColorSaturationType.SaturationVTilt);
            } else if (action.equals(colorSaturationHTiltAction)) {
                myCanvas.setColorSaturationType(ColorSaturationType.SaturationHTilt);
            } else if (action.equals(colorSaturationPressureAction)) {
                myCanvas.setColorSaturationType(ColorSaturationType.SaturationPressure);
            } else {
                myCanvas.setColorSaturationType(ColorSaturationType.NoSaturation);
            }
        }

        public void saveAct()
        {
            String path = QDir.currentPath() + tr("/untitled.png");
            String fileName = QFileDialog.getSaveFileName(this, tr("Save Picture"),
                                     path);

            if (!myCanvas.saveImage(fileName))
                QMessageBox.information(this, tr("Error Saving Picture"),
                                              tr("Could not save the image"));
        }

        public void loadAct()
        {
            String fileName = QFileDialog.getOpenFileName(this, tr("Open Picture"),
                                                                QDir.currentPath());

            if (!myCanvas.loadImage(fileName))
                QMessageBox.information(this, tr("Error Opening Picture"),
                                              tr("Could not open picture"));
        }

        public void aboutAct()
        {
            QMessageBox.about(this, tr("About Tablet Example"),
                           tr("This example shows use of a Wacom tablet in Jambi Qt"));
        }

        private void createActions()
        {
            brushColorAction = new QAction(tr("&Brush Color..."), this);
            brushColorAction.setShortcut(tr("Ctrl+C"));
            brushColorAction.triggered.connect(this, "brushColorAct()");

            alphaChannelPressureAction = new QAction(tr("&Pressure"), this);
            alphaChannelPressureAction.setCheckable(true);

            alphaChannelTiltAction = new QAction(tr("&Tilt"), this);
            alphaChannelTiltAction.setCheckable(true);

            noAlphaChannelAction = new QAction(tr("No Alpha Channel"), this);
            noAlphaChannelAction.setCheckable(true);
            noAlphaChannelAction.setChecked(true);

            alphaChannelGroup = new QActionGroup(this);
            alphaChannelGroup.addAction(alphaChannelPressureAction);
            alphaChannelGroup.addAction(alphaChannelTiltAction);
            alphaChannelGroup.addAction(noAlphaChannelAction);
            alphaChannelGroup.triggered.connect(this, "alphaActionTriggered(QAction)");

            colorSaturationVTiltAction = new QAction(tr("&Vertical Tilt"), this);
            colorSaturationVTiltAction.setCheckable(true);

            colorSaturationHTiltAction = new QAction(tr("&Horizontal Tilt"), this);
            colorSaturationHTiltAction.setCheckable(true);

            colorSaturationPressureAction = new QAction(tr("&Pressure"), this);
            colorSaturationPressureAction.setCheckable(true);

            noColorSaturationAction = new QAction(tr("&No Color Saturation"), this);
            noColorSaturationAction.setCheckable(true);
            noColorSaturationAction.setChecked(true);

            colorSaturationGroup = new QActionGroup(this);
            colorSaturationGroup.addAction(colorSaturationVTiltAction);
            colorSaturationGroup.addAction(colorSaturationHTiltAction);
            colorSaturationGroup.addAction(colorSaturationPressureAction);
            colorSaturationGroup.addAction(noColorSaturationAction);
            colorSaturationGroup.triggered.connect(this, "saturationActionTriggered(QAction)");

            lineWidthPressureAction = new QAction(tr("&Pressure"), this);
            lineWidthPressureAction.setCheckable(true);
            lineWidthPressureAction.setChecked(true);
            lineWidthTiltAction = new QAction(tr("&Tilt"), this);
            lineWidthTiltAction.setCheckable(true);

            lineWidthFixedAction = new QAction(tr("&Fixed"), this);
            lineWidthFixedAction.setCheckable(true);

            lineWidthGroup = new QActionGroup(this);
            lineWidthGroup.addAction(lineWidthPressureAction);
            lineWidthGroup.addAction(lineWidthTiltAction);
            lineWidthGroup.addAction(lineWidthFixedAction);
            lineWidthGroup.triggered.connect(this, "lineWidthActionTriggered(QAction)");

            exitAction = new QAction(tr("E&xit"), this);
            exitAction.setShortcut(tr("Ctrl+X"));
            exitAction.triggered.connect(this, "close()");

            loadAction = new QAction(tr("&Open..."), this);
            loadAction.setShortcut(tr("Ctrl+O"));
            loadAction.triggered.connect(this, "loadAct()");

            saveAction = new QAction(tr("&Save As..."), this);
            saveAction.setShortcut(tr("Ctrl+S"));
            saveAction.triggered.connect(this, "saveAct()");

            aboutAction = new QAction(tr("A&bout"), this);
            aboutAction.setShortcut(tr("Ctrl+B"));
            aboutAction.triggered.connect(this, "aboutAct()");

            aboutQtAction = new QAction(tr("About &Qt Jambi"), this);
            aboutQtAction.setShortcut(tr("Ctrl+Q"));
            aboutQtAction.triggered.connect(QApplication.instance(), "aboutQt()");
        }

        private void createMenus()
        {
            fileMenu = menuBar().addMenu(tr("&File"));
            fileMenu.addAction(loadAction);
            fileMenu.addAction(saveAction);
            fileMenu.addSeparator();
            fileMenu.addAction(exitAction);

            brushMenu = menuBar().addMenu(tr("&Brush"));
            brushMenu.addAction(brushColorAction);

            tabletMenu = menuBar().addMenu(tr("&Tablet"));

            lineWidthMenu = tabletMenu.addMenu(tr("&Line Width"));
            lineWidthMenu.addAction(lineWidthPressureAction);
            lineWidthMenu.addAction(lineWidthTiltAction);
            lineWidthMenu.addAction(lineWidthFixedAction);

            alphaChannelMenu = tabletMenu.addMenu(tr("&Alpha Channel"));
            alphaChannelMenu.addAction(alphaChannelPressureAction);
            alphaChannelMenu.addAction(alphaChannelTiltAction);
            alphaChannelMenu.addAction(noAlphaChannelAction);

            colorSaturationMenu = tabletMenu.addMenu(tr("&Color Saturation"));
            colorSaturationMenu.addAction(colorSaturationVTiltAction);
            colorSaturationMenu.addAction(colorSaturationHTiltAction);
            colorSaturationMenu.addAction(noColorSaturationAction);

            helpMenu = menuBar().addMenu("&Help");
            helpMenu.addAction(aboutAction);
            helpMenu.addAction(aboutQtAction);
        }

        class TabletCanvas extends QWidget
        {
            private AlphaChannelType alphaChannelType;
            private ColorSaturationType colorSaturationType;
            private LineWidthType lineWidthType;
            private QTabletEvent.TabletDevice myTabletDevice;
            private QColor myColor;

            private QImage image;
            private QBrush myBrush;
            private QPen myPen;
            private boolean deviceDown;
            private QPoint polyLine[] = new QPoint[3];

            public TabletCanvas()
            {
                myBrush = new QBrush();
                myPen = new QPen();
                image = new QImage(500, 500, QImage.Format.Format_ARGB32);
                QPainter painter = new QPainter(image);
                painter.fillRect(0, 0, 499, 499, new QBrush(new QColor(Qt.GlobalColor.white)));
                setAutoFillBackground(true);
                deviceDown = false;
                myColor = new QColor(Qt.GlobalColor.red);
                myTabletDevice = QTabletEvent.TabletDevice.Stylus;
                alphaChannelType = AlphaChannelType.NoAlpha;
                colorSaturationType = ColorSaturationType.NoSaturation;
                lineWidthType = LineWidthType.LineWidthPressure;
            }

            public void setAlphaChannelType(AlphaChannelType type)
            {
                alphaChannelType = type;
            }

            public void setColorSaturationType(ColorSaturationType type)
            {
                colorSaturationType = type;
            }

            public void setLineWidthType(LineWidthType type)
            {
                lineWidthType = type;
            }

            public void setColor(QColor color)
            {
                myColor = color;
            }

            public QColor color()
            {
                return myColor;
            }

            public void setTabletDevice(QTabletEvent.TabletDevice device)
            {
                myTabletDevice = device;
            }

            boolean saveImage(String file)
            {
                return image.save(file);
            }

            boolean loadImage(String file)
            {
                boolean success = image.load(file);

                if (success) {
                    update();
                    return true;
                }
                return false;
            }

            @Override
            protected void tabletEvent(QTabletEvent event)
            {
                switch (event.type()) {
                    case TabletPress:
                        if (deviceDown)
                            deviceDown = true;
                        break;
                    case TabletRelease:
                        if (!deviceDown)
                            deviceDown = false;
                        break;
                    case TabletMove:
                        polyLine[2] = polyLine[1];
                        polyLine[1] = polyLine[0];
                        polyLine[0] = event.pos();

                        if (deviceDown) {
                            updateBrush(event);
                            QPainter painter = new QPainter(image);
                            paintImage(painter, event);
                        }
                        break;
                    default:
                        break;
                }
                update();
            }

            @Override
            protected void paintEvent(QPaintEvent event)
            {
                QPainter painter = new QPainter(this);
                painter.drawImage(new QPoint(0, 0), image);
            }

            private void paintImage(QPainter painter, QTabletEvent event)
            {
                QPoint brushAdjust = new QPoint(10, 10);

                switch (myTabletDevice) {
                    case Stylus:
                        painter.setBrush(myBrush);
                        painter.setPen(myPen);
                        painter.drawLine(polyLine[1], event.pos());
                        break;
                    case Airbrush:
                        myBrush.setColor(myColor);
                        myBrush.setStyle(brushPattern(event.pressure()));
                        painter.setPen(Qt.PenStyle.NoPen);
                        painter.setBrush(myBrush);

                        for (int i = 0; i < 3; ++i) {
                            painter.drawEllipse(new QRect(polyLine[i].subtract(brushAdjust),
                                                          polyLine[i].add(brushAdjust)));
                        }
                        break;
                    default:
                        System.err.println("Unsupported tablet device.");
                }
            }

            private Qt.BrushStyle brushPattern(double value)
            {
                int pattern = ((int) (value * 100.0)) % 7;

                switch (pattern) {
                    case 0:
                        return Qt.BrushStyle.SolidPattern;
                    case 1:
                        return Qt.BrushStyle.Dense1Pattern;
                    case 2:
                        return Qt.BrushStyle.Dense2Pattern;
                    case 3:
                        return Qt.BrushStyle.Dense3Pattern;
                   case 4:
                        return Qt.BrushStyle.Dense4Pattern;
                    case 5:
                        return Qt.BrushStyle.Dense5Pattern;
                    case 6:
                        return Qt.BrushStyle.Dense6Pattern;
                    default:
                        return Qt.BrushStyle.Dense7Pattern;
                }
            }

            private void updateBrush(QTabletEvent event)
            {
                int hue, value, alpha;
                hue = myColor.hue();
                value = myColor.value();
                alpha = myColor.alpha();

                int vValue = (int) (((event.yTilt() + 60.0) / 120.0) * 255);
                int hValue = (int) (((event.xTilt() + 60.0) / 120.0) * 255);

                switch (alphaChannelType) {
                    case AlphaPressure:
                        myColor.setAlpha((int) (event.pressure() * 255.0));
                        break;
                    case AlphaTilt:
                        myColor.setAlpha(Math.max(Math.abs(vValue - 127), Math.abs(hValue - 127)));
                        break;
                    default:
                        myColor.setAlpha(255);
                }

                switch (colorSaturationType) {
                    case SaturationVTilt:
                        myColor.setHsv(hue, vValue, value, alpha);
                        break;
                    case SaturationHTilt:
                        myColor.setHsv(hue, hValue, value, alpha);
                        break;
                    case SaturationPressure:
                        myColor.setHsv(hue, (int) (event.pressure() * 255.0), value, alpha);
                        break;
                    default:
                        ;
                }

                switch (lineWidthType) {
                    case LineWidthPressure:
                        myPen.setWidthF(event.pressure() * 10 + 1);
                        break;
                    case LineWidthTilt:
                        myPen.setWidthF(Math.max(Math.abs(vValue - 127), Math.abs(hValue - 127)) / 12);
                        break;
                    default:
                        myPen.setWidthF(1);
                }

                if (event.pointerType().equals(QTabletEvent.PointerType.Eraser)) {
                    myBrush.setColor(new QColor(Qt.GlobalColor.white));
                    myPen.setColor(new QColor(Qt.GlobalColor.white));
                    myPen.setWidthF(event.pressure() * 10 + 1);
                } else {
                    myBrush.setColor(myColor);
                    myPen.setColor(myColor);
                }
            }
        }

        public class TabletApplication extends QApplication
        {
            public TabletApplication(String args[])
            {
                super(args);
            }

            @Override
            public boolean event(QEvent event)
            {
                if (event.type().equals(QEvent.Type.TabletEnterProximity) ||
                    event.type().equals(QEvent.Type.TabletLeaveProximity)) {
                    Tablet.myCanvas.setTabletDevice(((QTabletEvent) event).device());
                    return true;
                }
                return super.event(event);
            }
        }

        public static void main(String args[])
        {
            Tablet.TabletApplication.initialize(args);

            Tablet mainWindow = new Tablet();
            mainWindow.resize(500, 500);
            mainWindow.show();

            Tablet.TabletApplication.exec();
        }
    }