motion timeout

Add intermediate points to make quick free drawings smoother.
Do not redisplay the area at this step (crashes).
Use device.get_coords rather than global.get_pointer because the later return rounded (floor) values.

Fix #45.
This commit is contained in:
abakkk 2020-09-30 19:16:55 +02:00
parent 82aee30657
commit 6374cc8c47
2 changed files with 46 additions and 0 deletions

34
area.js
View File

@ -47,6 +47,7 @@ const pgettext = imports.gettext.domain(Me.metadata['gettext-domain']).pgettext;
const CAIRO_DEBUG_EXTENDS = false;
const SVG_DEBUG_EXTENDS = false;
const MOTION_TIME = 1; // ms, time accuracy for free drawing, max is about 33 ms. The lower it is, the smoother the drawing is.
const TEXT_CURSOR_TIME = 600; // ms
const ELEMENT_GRABBER_TIME = 80; // ms, default is about 16 ms
const GRID_TILES_HORIZONTAL_NUMBER = 30;
@ -656,6 +657,11 @@ var DrawingArea = new Lang.Class({
}
this.motionHandler = this.connect('motion-event', (actor, event) => {
if (this.motionTimeout) {
GLib.source_remove(this.motionTimeout);
this.motionTimeout = null;
}
if (this.spaceKeyPressed)
return;
@ -665,6 +671,30 @@ var DrawingArea = new Lang.Class({
return;
let controlPressed = event.has_control_modifier();
this._updateDrawing(x, y, controlPressed);
if (this.currentTool == Shapes.NONE) {
let device = event.get_device();
let sequence = event.get_event_sequence();
// Minimum time between two motion events is about 33 ms.
// Add intermediate points to make quick free drawings smoother.
this.motionTimeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, MOTION_TIME, () => {
let [success, coords] = device.get_coords(sequence);
if (!success)
return GLib.SOURCE_CONTINUE;
let [s, x, y] = this.transform_stage_point(coords.x, coords.y);
if (!s)
return GLib.SOURCE_CONTINUE;
// Important: do not call this._updateDrawing because the area MUST NOT BE REDISPLAYED at this step.
// It would lead to critical issues (bad performances and shell crashes).
// The area will be redisplayed, including the intermediate points, at the next motion event.
this.currentElement.addIntermediatePoint(x, y, controlPressed);
return GLib.SOURCE_CONTINUE;
});
}
});
},
@ -679,6 +709,10 @@ var DrawingArea = new Lang.Class({
},
_stopDrawing: function() {
if (this.motionTimeout) {
GLib.source_remove(this.motionTimeout);
this.motionTimeout = null;
}
if (this.motionHandler) {
this.disconnect(this.motionHandler);
this.motionHandler = null;

View File

@ -62,6 +62,7 @@ const MIN_REFLECTION_LINE_LENGTH = 10; // px
const MIN_TRANSLATION_DISTANCE = 1; // px
const MIN_ROTATION_ANGLE = Math.PI / 1000; // rad
const MIN_DRAWING_SIZE = 3; // px
const MIN_INTERMEDIATE_POINT_DISTANCE = 1; // px, the higher it is, the fewer points there will be
var DrawingElement = function(params) {
return params.shape == Shapes.TEXT ? new TextElement(params) :
@ -422,6 +423,17 @@ const _DrawingElement = new Lang.Class({
}
},
// For free drawing only.
addIntermediatePoint: function(x, y, transform) {
let points = this.points;
if (getNearness(points[points.length - 1], [x, y], MIN_INTERMEDIATE_POINT_DISTANCE))
return;
points.push([x, y]);
if (transform)
this._smooth(points.length - 1);
},
startDrawing: function(startX, startY) {
this.points.push([startX, startY]);