// Somewhere to try a pointer change before deciding to keep it. // // Pointer speed, acceleration, scroll direction and scroll speed are all // settings you cannot read: the number means nothing, and the only honest test // is moving the pointer. Every one of them applies live, so this is simply a // place to move it that is not somebody's document. // // Entirely local. Nothing here writes a preference or touches the compositor, // and the scribble is not saved anywhere -- it exists for the length of a // question ("is that too fast?") and is thrown away. // // The canvas repaints only when the pointer has actually moved across it, // driven from the motion handler rather than a timer. A settings page that // repainted continuously would be a persistent GPU load on a high-refresh // display, in return for a picture that had not changed. import QtQuick import qs.config Column { id: root width: parent ? parent.width : 620 spacing: 10 Rectangle { id: pad width: parent.width height: 150 radius: Theme.cardRadius color: Theme.alpha(Theme.bgDark, 0.55) border.width: 1 border.color: Theme.alpha(Theme.fg, 0.08) clip: true // Segments drawn since the last paint. The canvas keeps what it has // already been given, so each paint adds the new piece of the stroke // instead of redrawing the whole scribble. property var pending: [] property bool wiping: false property bool drawn: false Canvas { id: scribble anchors.fill: parent renderStrategy: Canvas.Immediate onPaint: { const context = scribble.getContext("2d"); if (pad.wiping) { context.reset(); pad.wiping = false; pad.pending = []; return; } context.strokeStyle = Theme.accent; context.lineWidth = 2.4; context.lineCap = "round"; context.lineJoin = "round"; context.beginPath(); for (const segment of pad.pending) { context.moveTo(segment.fromX, segment.fromY); context.lineTo(segment.toX, segment.toY); } context.stroke(); pad.pending = []; } } Text { anchors.centerIn: parent visible: !pad.drawn text: "Draw here to feel pointer speed" color: Theme.fgMuted font.family: Theme.fontFamily font.pixelSize: Theme.fontSize } MouseArea { id: pointer property real lastX: 0 property real lastY: 0 anchors.fill: parent cursorShape: Qt.CrossCursor // The page is a Flickable, which would otherwise take the drag off // this and scroll instead of drawing. preventStealing: true onPressed: mouse => { pointer.lastX = mouse.x; pointer.lastY = mouse.y; pad.drawn = true; } onPositionChanged: mouse => { const segments = pad.pending; segments.push({ fromX: pointer.lastX, fromY: pointer.lastY, toX: mouse.x, toY: mouse.y }); pad.pending = segments; pointer.lastX = mouse.x; pointer.lastY = mouse.y; scribble.requestPaint(); } } SettingsButton { anchors.right: parent.right anchors.top: parent.top anchors.margins: 8 visible: pad.drawn text: "Clear" onClicked: { pad.wiping = true; pad.drawn = false; scribble.requestPaint(); } } } Rectangle { width: parent.width height: 110 radius: Theme.cardRadius color: Theme.alpha(Theme.bgDark, 0.55) border.width: 1 border.color: Theme.alpha(Theme.fg, 0.08) clip: true Flickable { id: strip anchors.fill: parent anchors.margins: 12 contentWidth: width contentHeight: lines.implicitHeight boundsBehavior: Flickable.StopAtBounds Column { id: lines width: parent.width spacing: 6 Repeater { model: [ "Scroll here to feel scroll speed and direction.", "Natural scrolling moves the content with your fingers.", "The quick brown fox jumps over the lazy dog.", "Line four.", "Line five.", "Line six.", "Line seven — still scrolling.", "Line eight.", "Line nine.", "Line ten, the bottom." ] Text { required property var modelData width: lines.width text: String(modelData) color: Theme.fgDim font.family: Theme.fontFamily font.pixelSize: Theme.fontSizeSmall elide: Text.ElideRight } } } } } }