Warning, /graphics/washipad/src/Sketch.qml is written in an unsupported language. File is not indexed.

0001 // This file is part of Washi Pad
0002 // SPDX-FileCopyrightText: 2018 Kevin Ottens <ervin@kde.org>
0003 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 
0005 import QtQuick 2.0
0006 import QtQuick.Window 2.0
0007 import QtQuick.Controls 2.15
0008 
0009 
0010 import WashiPad 1.0
0011 
0012 Item {
0013     id: root
0014     readonly property size size: Qt.size(sketchContent.width, sketchContent.height)
0015     readonly property point cursorPos: Qt.point(handler.point.x, handler.point.y)
0016 
0017     property SketchModel model
0018     property color penColor: "black"
0019     readonly property var penType: (penColor === Qt.rgba(0, 0, 0, 1)) ? Stroke.Outline : Stroke.Fill
0020     property alias isMouseSupportEnabled: mouseArea.enabled
0021 
0022     Flickable {
0023         id: flickable
0024 
0025         anchors.fill: parent
0026 
0027         clip: true
0028         topMargin: contentHeight * 0.1
0029         bottomMargin: topMargin
0030         rightMargin: contentWidth * 0.1
0031         leftMargin: rightMargin
0032 
0033         interactive: !mouseArea.isPress
0034 
0035         contentWidth: sketchContent.width
0036         contentHeight: sketchContent.height
0037 
0038         PaintingCanvas {
0039             id: sketchContent
0040 
0041             StrokeListItem {
0042                 id: fillStrokes
0043                 anchors.fill: parent
0044                 z: 0
0045                 type: Stroke.Fill
0046                 model: root.model
0047             }
0048 
0049             StrokeListItem {
0050                 id: outlineStrokes
0051                 anchors.fill: parent
0052                 z: 1
0053                 type: Stroke.Outline
0054                 model: root.model
0055             }
0056 
0057             StrokeItem {
0058                 id: currentStroke
0059                 anchors.fill: parent
0060                 z: stroke.type === Stroke.Outline ? 1 : 0
0061             }
0062         }
0063 
0064         ScrollBar.vertical: ScrollBar {anchors.right: flickable.right}
0065         ScrollBar.horizontal: ScrollBar {anchors.bottom: flickable.bottom}
0066 
0067         MouseArea {
0068             id: mouseArea
0069 
0070             property bool isPress: false
0071             property var lastButton
0072 
0073             anchors.fill: parent
0074             acceptedButtons: Qt.LeftButton | Qt.RightButton
0075 
0076             onPressed: {
0077                 if (!isPress) {
0078                     isPress = true
0079                     lastButton = mouse.button
0080 
0081                     handler.pressed = isPress
0082                 }
0083             }
0084 
0085             onReleased: {
0086                 if (mouse.button === lastButton) {
0087                     isPress = false
0088 
0089                     handler.pressed = isPress
0090                 }
0091             }
0092 
0093             onPositionChanged: {
0094                 handler.mouseMoved(mouse.x - flickable.contentX, mouse.y - flickable.contentY, lastButton)
0095             }
0096         }
0097     }
0098 
0099     SketchViewHandler {
0100         id: handler
0101 
0102         function isEraser() {
0103             return point.pointer === TabletEvent.Eraser
0104         }
0105 
0106         function isEmpty(rect) {
0107             return rect.left === rect.right
0108                 && rect.top === rect.bottom
0109         }
0110 
0111         function createPoint() {
0112             return Qt.vector2d(point.x + flickable.contentX,
0113                                point.y + flickable.contentY)
0114         }
0115 
0116         function addSample() {
0117             var sample = createSample(createPoint(), pressureEquation.width)
0118             currentStroke.addSample(sample)
0119         }
0120 
0121         function eraseSamples() {
0122             var point = createPoint()
0123             var radius = cursor.height / 2
0124 
0125             outlineStrokes.eraseArea(point, radius)
0126             fillStrokes.eraseArea(point, radius)
0127         }
0128 
0129         onPressedChanged: {
0130             if (isEraser())
0131                 return
0132 
0133             if (!pressed && !isEmpty(currentStroke.stroke.boundingRect())) {
0134                 addSample()
0135                 if (currentStroke.stroke.type === Stroke.Outline)
0136                     outlineStrokes.addStroke(currentStroke.stroke)
0137                 else
0138                     fillStrokes.addStroke(currentStroke.stroke)
0139                 currentStroke.stroke = createStroke(penType, root.penColor)
0140                 return
0141             }
0142 
0143             currentStroke.stroke = createStroke(penType, root.penColor)
0144         }
0145 
0146         onPointChanged: {
0147             if (!pressed)
0148                 return
0149 
0150             if (!isEraser())
0151                 addSample()
0152             else
0153                 eraseSamples()
0154         }
0155     }
0156 
0157     PressureEquation {
0158         id: pressureEquation
0159         readonly property real minOutlineWidth: 2
0160         readonly property real maxOutlineWidth: 10
0161 
0162         readonly property real minFillWidth: minOutlineWidth * 2
0163         readonly property real maxFillWidth: maxOutlineWidth * 2
0164 
0165         readonly property real minEraserWidth: minOutlineWidth * 4
0166         readonly property real maxEraserWidth: maxOutlineWidth * 8
0167 
0168         pressure: handler.point.pressure
0169         minWidth: handler.isEraser() ? minEraserWidth
0170                 : root.penType === Stroke.Fill ? minFillWidth
0171                 : minOutlineWidth
0172         maxWidth: handler.isEraser() ? maxEraserWidth
0173                 : root.penType === Stroke.Fill ? maxFillWidth
0174                 : maxOutlineWidth
0175     }
0176 
0177     Rectangle {
0178         id: cursor
0179 
0180         color: "transparent"
0181         border.color: handler.isEraser() ? Qt.rgba(1, 0, 0, 0.75) : Qt.rgba(0, 0, 1, 0.75)
0182         border.width: 2
0183         x: handler.point.x - width / 2
0184         y: handler.point.y - height / 2
0185         width: height
0186         height: pressureEquation.width * 1.5
0187         radius: height / 2
0188     }
0189 }