diff --git a/elements.js b/elements.js
index eef5cd8..9e531d2 100644
--- a/elements.js
+++ b/elements.js
@@ -20,31 +20,17 @@
* along with this program. If not, see .
*/
-const ByteArray = imports.byteArray;
const Cairo = imports.cairo;
const Clutter = imports.gi.Clutter;
-const Gio = imports.gi.Gio;
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Pango = imports.gi.Pango;
const PangoCairo = imports.gi.PangoCairo;
-const St = imports.gi.St;
-
-const Screenshot = imports.ui.screenshot;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
-const Convenience = ExtensionUtils.getSettings ? ExtensionUtils : Me.imports.convenience;
-const Extension = Me.imports.extension;
-const Menu = Me.imports.menu;
const _ = imports.gettext.domain(Me.metadata['gettext-domain']).gettext;
-const CAIRO_DEBUG_EXTENDS = false;
-const SVG_DEBUG_EXTENDS = false;
const SVG_DEBUG_SUPERPOSES_CAIRO = false;
-const TEXT_CURSOR_TIME = 600; // ms
const reverseEnumeration = function(obj) {
let reversed = {};
@@ -69,1139 +55,6 @@ var FontStyleNames = reverseEnumeration(Pango.Style);
var FontStretchNames = reverseEnumeration(Pango.Stretch);
var FontVariantNames = reverseEnumeration(Pango.Variant);
-var getDateString = function() {
- let date = GLib.DateTime.new_now_local();
- return `${date.format("%F")} ${date.format("%X")}`;
-};
-
-var getJsonFiles = function() {
- let directory = Gio.File.new_for_path(GLib.build_filenamev([GLib.get_user_data_dir(), Me.metadata['data-dir']]));
-
- let enumerator;
- try {
- enumerator = directory.enumerate_children('standard::name,standard::display-name,standard::content-type,time::modified', Gio.FileQueryInfoFlags.NONE, null);
- } catch(e) {
- return [];
- }
-
- let jsonFiles = [];
- let fileInfo = enumerator.next_file(null);
- while (fileInfo) {
- if (fileInfo.get_content_type().indexOf('json') != -1 && fileInfo.get_name() != `${Me.metadata['persistent-file-name']}.json`) {
- let file = enumerator.get_child(fileInfo);
- jsonFiles.push({ name: fileInfo.get_name().slice(0, -5),
- displayName: fileInfo.get_display_name().slice(0, -5),
- // fileInfo.get_modification_date_time: Gio 2.62+
- modificationUnixTime: fileInfo.get_attribute_uint64('time::modified'),
- delete: () => file.delete(null) });
- }
- fileInfo = enumerator.next_file(null);
- }
- enumerator.close(null);
-
- jsonFiles.sort((a, b) => {
- return b.modificationUnixTime - a.modificationUnixTime;
- });
-
- return jsonFiles;
-};
-
-// DrawingArea is the widget in which we draw, thanks to Cairo.
-// It creates and manages a DrawingElement for each "brushstroke".
-// It handles pointer/mouse/(touch?) events and some keyboard events.
-var DrawingArea = new Lang.Class({
- Name: 'DrawOnYourScreenDrawingArea',
- Extends: St.DrawingArea,
- Signals: { 'show-osd': { param_types: [GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_DOUBLE, GObject.TYPE_BOOLEAN] },
- 'update-action-mode': {},
- 'leave-drawing-mode': {} },
-
- _init: function(params, monitor, helper, loadPersistent) {
- this.parent({ style_class: 'draw-on-your-screen', name: params.name});
-
- this.connect('destroy', this._onDestroy.bind(this));
- this.reactiveHandler = this.connect('notify::reactive', this._onReactiveChanged.bind(this));
-
- this.settings = Convenience.getSettings();
- this.monitor = monitor;
- this.helper = helper;
-
- this.elements = [];
- this.undoneElements = [];
- this.currentElement = null;
- this.currentTool = Shapes.NONE;
- this.currentFontGeneric = 0;
- this.isSquareArea = false;
- this.hasGrid = false;
- this.hasBackground = false;
- this.textHasCursor = false;
- this.dashedLine = false;
- this.fill = false;
- this.colors = [Clutter.Color.new(0, 0, 0, 255)];
- this.newThemeAttributes = {};
- this.oldThemeAttributes = {};
-
- if (loadPersistent)
- this._loadPersistent();
- },
-
- get menu() {
- if (!this._menu)
- this._menu = new Menu.DrawingMenu(this, this.monitor);
- return this._menu;
- },
-
- closeMenu: function() {
- if (this._menu)
- this._menu.close();
- },
-
- get isWriting() {
- return this.textEntry ? true : false;
- },
-
- get currentTool() {
- return this._currentTool;
- },
-
- set currentTool(tool) {
- this._currentTool = tool;
- if (this.hasManipulationTool)
- this._startElementGrabber();
- else
- this._stopElementGrabber();
- },
-
- get hasManipulationTool() {
- // No Object.values method in GS 3.24.
- return Object.keys(Manipulations).map(key => Manipulations[key]).indexOf(this.currentTool) != -1;
- },
-
- // Boolean wrapper for switch menu item.
- get currentEvenodd() {
- return this.currentFillRule == Cairo.FillRule.EVEN_ODD;
- },
-
- set currentEvenodd(evenodd) {
- this.currentFillRule = evenodd ? Cairo.FillRule.EVEN_ODD : Cairo.FillRule.WINDING;
- },
-
- vfunc_repaint: function() {
- let cr = this.get_context();
-
- try {
- this._repaint(cr);
- } catch(e) {
- logError(e, "An error occured while painting");
- }
-
- cr.$dispose();
- },
-
- _redisplay: function() {
- // force area to emit 'repaint'
- this.queue_repaint();
- },
-
- _updateStyle: function() {
- try {
- let themeNode = this.get_theme_node();
- for (let i = 1; i < 10; i++) {
- this.colors[i] = themeNode.get_color('-drawing-color' + i);
- }
- let font = themeNode.get_font();
- this.newThemeAttributes.ThemeFontFamily = font.get_family();
- try { this.newThemeAttributes.FontWeight = font.get_weight(); } catch(e) { this.newThemeAttributes.FontWeight = Pango.Weight.NORMAL; }
- this.newThemeAttributes.FontStyle = font.get_style();
- this.newThemeAttributes.FontStretch = font.get_stretch();
- this.newThemeAttributes.FontVariant = font.get_variant();
- this.newThemeAttributes.TextRightAligned = themeNode.get_text_align() == St.TextAlign.RIGHT;
- this.newThemeAttributes.LineWidth = themeNode.get_length('-drawing-line-width');
- this.newThemeAttributes.LineJoin = themeNode.get_double('-drawing-line-join');
- this.newThemeAttributes.LineCap = themeNode.get_double('-drawing-line-cap');
- this.newThemeAttributes.FillRule = themeNode.get_double('-drawing-fill-rule');
- this.dashArray = [Math.abs(themeNode.get_length('-drawing-dash-array-on')), Math.abs(themeNode.get_length('-drawing-dash-array-off'))];
- this.dashOffset = themeNode.get_length('-drawing-dash-offset');
- this.gridGap = themeNode.get_length('-grid-overlay-gap');
- this.gridLineWidth = themeNode.get_length('-grid-overlay-line-width');
- this.gridInterlineWidth = themeNode.get_length('-grid-overlay-interline-width');
- this.gridColor = themeNode.get_color('-grid-overlay-color');
- this.squareAreaWidth = themeNode.get_length('-drawing-square-area-width');
- this.squareAreaHeight = themeNode.get_length('-drawing-square-area-height');
- this.activeBackgroundColor = themeNode.get_color('-drawing-background-color');
- } catch(e) {
- logError(e);
- }
-
- for (let i = 1; i < 10; i++) {
- this.colors[i] = this.colors[i].alpha ? this.colors[i] : this.colors[0];
- }
- this.currentColor = this.currentColor || this.colors[1];
- // SVG does not support 'Ultra-heavy' weight (1000)
- this.newThemeAttributes.FontWeight = Math.min(this.newThemeAttributes.FontWeight, 900);
- this.newThemeAttributes.LineWidth = (this.newThemeAttributes.LineWidth > 0) ? this.newThemeAttributes.LineWidth : 3;
- this.newThemeAttributes.LineJoin = ([0, 1, 2].indexOf(this.newThemeAttributes.LineJoin) != -1) ? this.newThemeAttributes.LineJoin : Cairo.LineJoin.ROUND;
- this.newThemeAttributes.LineCap = ([0, 1, 2].indexOf(this.newThemeAttributes.LineCap) != -1) ? this.newThemeAttributes.LineCap : Cairo.LineCap.ROUND;
- this.newThemeAttributes.FillRule = ([0, 1].indexOf(this.newThemeAttributes.FillRule) != -1) ? this.newThemeAttributes.FillRule : Cairo.FillRule.WINDING;
- for (let attributeName in this.newThemeAttributes) {
- if (this.newThemeAttributes[attributeName] != this.oldThemeAttributes[attributeName]) {
- this.oldThemeAttributes[attributeName] = this.newThemeAttributes[attributeName];
- this[`current${attributeName}`] = this.newThemeAttributes[attributeName];
- }
- }
- this.gridGap = this.gridGap && this.gridGap >= 1 ? this.gridGap : 10;
- this.gridLineWidth = this.gridLineWidth || 0.4;
- this.gridInterlineWidth = this.gridInterlineWidth || 0.2;
- this.gridColor = this.gridColor && this.gridColor.alpha ? this.gridColor : Clutter.Color.new(127, 127, 127, 255);
- },
-
- _repaint: function(cr) {
- if (CAIRO_DEBUG_EXTENDS) {
- cr.scale(0.5, 0.5);
- cr.translate(this.monitor.width, this.monitor.height);
- }
-
- for (let i = 0; i < this.elements.length; i++) {
- cr.save();
-
- this.elements[i].buildCairo(cr, { showTextRectangle: this.grabbedElement && this.grabbedElement == this.elements[i],
- drawTextRectangle: this.grabPoint ? true : false });
-
- if (this.grabPoint)
- this._searchElementToGrab(cr, this.elements[i]);
-
- if (this.elements[i].fill && !this.elements[i].isStraightLine) {
- cr.fillPreserve();
- if (this.elements[i].shape == Shapes.NONE || this.elements[i].shape == Shapes.LINE)
- cr.closePath();
- }
-
- cr.stroke();
- cr.restore();
- }
-
- if (this.currentElement) {
- cr.save();
- this.currentElement.buildCairo(cr, { showTextCursor: this.textHasCursor,
- showTextRectangle: this.currentElement.shape == Shapes.TEXT && !this.isWriting,
- dummyStroke: this.currentElement.fill && this.currentElement.line.lineWidth == 0 });
-
- cr.stroke();
- cr.restore();
- }
-
- if (this.reactive && this.hasGrid && this.gridGap && this.gridGap >= 1) {
- cr.save();
- Clutter.cairo_set_source_color(cr, this.gridColor);
-
- let [gridX, gridY] = [this.gridGap, this.gridGap];
- while (gridX < this.monitor.width) {
- cr.setLineWidth((gridX / this.gridGap) % 5 ? this.gridInterlineWidth : this.gridLineWidth);
- cr.moveTo(gridX, 0);
- cr.lineTo(gridX, this.monitor.height);
- gridX += this.gridGap;
- cr.stroke();
- }
- while (gridY < this.monitor.height) {
- cr.setLineWidth((gridY / this.gridGap) % 5 ? this.gridInterlineWidth : this.gridLineWidth);
- cr.moveTo(0, gridY);
- cr.lineTo(this.monitor.width, gridY);
- gridY += this.gridGap;
- cr.stroke();
- }
- cr.restore();
- }
- },
-
- _onButtonPressed: function(actor, event) {
- if (this.spaceKeyPressed)
- return Clutter.EVENT_PROPAGATE;
-
- let button = event.get_button();
- let [x, y] = event.get_coords();
- let controlPressed = event.has_control_modifier();
- let shiftPressed = event.has_shift_modifier();
-
- if (this.currentElement && this.currentElement.shape == Shapes.TEXT && this.isWriting)
- // finish writing
- this._stopWriting();
-
- if (this.helper.visible) {
- // hide helper
- this.toggleHelp();
- return Clutter.EVENT_STOP;
- }
-
- if (button == 1) {
- if (this.hasManipulationTool) {
- if (this.grabbedElement)
- this._startTransforming(x, y, controlPressed, shiftPressed);
- } else {
- this._startDrawing(x, y, shiftPressed);
- }
- return Clutter.EVENT_STOP;
- } else if (button == 2) {
- this.toggleFill();
- } else if (button == 3) {
- this._stopDrawing();
- this.menu.open(x, y);
- return Clutter.EVENT_STOP;
- }
-
- return Clutter.EVENT_PROPAGATE;
- },
-
- _onKeyboardPopupMenu: function() {
- this._stopDrawing();
- if (this.helper.visible)
- this.toggleHelp();
- this.menu.popup();
- return Clutter.EVENT_STOP;
- },
-
- _onStageKeyPressed: function(actor, event) {
- if (event.get_key_symbol() == Clutter.KEY_space)
- this.spaceKeyPressed = true;
-
- return Clutter.EVENT_PROPAGATE;
- },
-
- _onStageKeyReleased: function(actor, event) {
- if (event.get_key_symbol() == Clutter.KEY_space)
- this.spaceKeyPressed = false;
-
- return Clutter.EVENT_PROPAGATE;
- },
-
- _onKeyPressed: function(actor, event) {
- if (this.currentElement && this.currentElement.shape == Shapes.LINE) {
- if (event.get_key_symbol() == Clutter.KEY_Return ||
- event.get_key_symbol() == Clutter.KEY_KP_Enter ||
- event.get_key_symbol() == Clutter.KEY_Control_L) {
- if (this.currentElement.points.length == 2)
- this.emit('show-osd', null, _("Press %s to get\na fourth control point")
- .format(Gtk.accelerator_get_label(Clutter.KEY_Return, 0)), "", -1, true);
- this.currentElement.addPoint();
- this.updatePointerCursor(true);
- this._redisplay();
- return Clutter.EVENT_STOP;
- } else {
- return Clutter.EVENT_PROPAGATE;
- }
-
- } else if (this.currentElement &&
- (this.currentElement.shape == Shapes.POLYGON || this.currentElement.shape == Shapes.POLYLINE) &&
- (event.get_key_symbol() == Clutter.KEY_Return || event.get_key_symbol() == Clutter.KEY_KP_Enter)) {
- this.currentElement.addPoint();
- return Clutter.EVENT_STOP;
-
- } else if (event.get_key_symbol() == Clutter.KEY_Escape) {
- if (this.helper.visible)
- this.toggleHelp();
- else
- this.emit('leave-drawing-mode');
- return Clutter.EVENT_STOP;
-
- } else {
- return Clutter.EVENT_PROPAGATE;
- }
- },
-
- _onScroll: function(actor, event) {
- if (this.helper.visible)
- return Clutter.EVENT_PROPAGATE;
- let direction = event.get_scroll_direction();
- if (direction == Clutter.ScrollDirection.UP)
- this.incrementLineWidth(1);
- else if (direction == Clutter.ScrollDirection.DOWN)
- this.incrementLineWidth(-1);
- else
- return Clutter.EVENT_PROPAGATE;
- return Clutter.EVENT_STOP;
- },
-
- _searchElementToGrab: function(cr, element) {
- if (element.getContainsPoint(cr, this.grabPoint[0], this.grabPoint[1]))
- this.grabbedElement = element;
- else if (this.grabbedElement == element)
- this.grabbedElement = null;
-
- if (element == this.elements[this.elements.length - 1])
- // All elements have been tested, the winner is the last.
- this.updatePointerCursor();
- },
-
- _startElementGrabber: function() {
- if (this.elementGrabberHandler)
- return;
-
- this.elementGrabberHandler = this.connect('motion-event', (actor, event) => {
- if (this.motionHandler || this.grabbedElementLocked) {
- this.grabPoint = null;
- return;
- }
-
- // Reduce computing without notable effect.
- if (Math.random() <= 0.75)
- return;
-
- let coords = event.get_coords();
- let [s, x, y] = this.transform_stage_point(coords[0], coords[1]);
- if (!s)
- return;
-
- this.grabPoint = [x, y];
- this.grabbedElement = null;
- // this._redisplay calls this._searchElementToGrab.
- this._redisplay();
- });
- },
-
- _stopElementGrabber: function() {
- if (this.elementGrabberHandler) {
- this.disconnect(this.elementGrabberHandler);
- this.grabPoint = null;
- this.elementGrabberHandler = null;
- }
- },
-
- _startTransforming: function(stageX, stageY, controlPressed, duplicate) {
- let [success, startX, startY] = this.transform_stage_point(stageX, stageY);
-
- if (!success)
- return;
-
- if (this.currentTool == Manipulations.MIRROR) {
- this.grabbedElementLocked = !this.grabbedElementLocked;
- if (this.grabbedElementLocked) {
- this.updatePointerCursor();
- let label = controlPressed ? _("Mark a point of symmetry") : _("Draw a line of symmetry");
- this.emit('show-osd', null, label, "", -1, true);
- return;
- }
- }
-
- this.grabPoint = null;
-
- this.buttonReleasedHandler = this.connect('button-release-event', (actor, event) => {
- this._stopTransforming();
- });
-
- if (duplicate) {
- // deep cloning
- let copy = new DrawingElement(JSON.parse(JSON.stringify(this.grabbedElement)));
- this.elements.push(copy);
- this.grabbedElement = copy;
- }
-
- if (this.currentTool == Manipulations.MOVE)
- this.grabbedElement.startTransformation(startX, startY, controlPressed ? Transformations.ROTATION : Transformations.TRANSLATION);
- else if (this.currentTool == Manipulations.RESIZE)
- this.grabbedElement.startTransformation(startX, startY, controlPressed ? Transformations.STRETCH : Transformations.SCALE_PRESERVE);
- else if (this.currentTool == Manipulations.MIRROR) {
- this.grabbedElement.startTransformation(startX, startY, controlPressed ? Transformations.INVERSION : Transformations.REFLECTION);
- this._redisplay();
- }
-
-
- this.motionHandler = this.connect('motion-event', (actor, event) => {
- if (this.spaceKeyPressed)
- return;
-
- let coords = event.get_coords();
- let [s, x, y] = this.transform_stage_point(coords[0], coords[1]);
- if (!s)
- return;
- let controlPressed = event.has_control_modifier();
- this._updateTransforming(x, y, controlPressed);
- });
- },
-
- _updateTransforming: function(x, y, controlPressed) {
- if (controlPressed && this.grabbedElement.lastTransformation.type == Transformations.TRANSLATION) {
- this.grabbedElement.stopTransformation();
- this.grabbedElement.startTransformation(x, y, Transformations.ROTATION);
- } else if (!controlPressed && this.grabbedElement.lastTransformation.type == Transformations.ROTATION) {
- this.grabbedElement.stopTransformation();
- this.grabbedElement.startTransformation(x, y, Transformations.TRANSLATION);
- }
-
- if (controlPressed && this.grabbedElement.lastTransformation.type == Transformations.SCALE_PRESERVE) {
- this.grabbedElement.stopTransformation();
- this.grabbedElement.startTransformation(x, y, Transformations.STRETCH);
- } else if (!controlPressed && this.grabbedElement.lastTransformation.type == Transformations.STRETCH) {
- this.grabbedElement.stopTransformation();
- this.grabbedElement.startTransformation(x, y, Transformations.SCALE_PRESERVE);
- }
-
- if (controlPressed && this.grabbedElement.lastTransformation.type == Transformations.REFLECTION) {
- this.grabbedElement.transformations.pop();
- this.grabbedElement.startTransformation(x, y, Transformations.INVERSION);
- } else if (!controlPressed && this.grabbedElement.lastTransformation.type == Transformations.INVERSION) {
- this.grabbedElement.transformations.pop();
- this.grabbedElement.startTransformation(x, y, Transformations.REFLECTION);
- }
-
- this.grabbedElement.updateTransformation(x, y);
- this._redisplay();
- },
-
- _stopTransforming: function() {
- if (this.motionHandler) {
- this.disconnect(this.motionHandler);
- this.motionHandler = null;
- }
- if (this.buttonReleasedHandler) {
- this.disconnect(this.buttonReleasedHandler);
- this.buttonReleasedHandler = null;
- }
-
- this.grabbedElement.stopTransformation();
- this.grabbedElement = null;
- this.grabbedElementLocked = false;
- this._redisplay();
- },
-
- _startDrawing: function(stageX, stageY, eraser) {
- let [success, startX, startY] = this.transform_stage_point(stageX, stageY);
-
- if (!success)
- return;
-
- this.buttonReleasedHandler = this.connect('button-release-event', (actor, event) => {
- this._stopDrawing();
- });
-
- this.currentElement = new DrawingElement ({
- shape: this.currentTool,
- color: this.currentColor.to_string(),
- line: { lineWidth: this.currentLineWidth, lineJoin: this.currentLineJoin, lineCap: this.currentLineCap },
- dash: { active: this.dashedLine, array: this.dashedLine ? [this.dashArray[0] || this.currentLineWidth, this.dashArray[1] || this.currentLineWidth * 3] : [0, 0] , offset: this.dashOffset },
- fill: this.fill,
- fillRule: this.currentFillRule,
- eraser: eraser,
- transform: { active: false, center: [0, 0], angle: 0, startAngle: 0, ratio: 1 },
- points: []
- });
-
- if (this.currentTool == Shapes.TEXT) {
- this.currentElement.fill = false;
- this.currentElement.font = {
- family: (this.currentFontGeneric == 0 ? this.currentThemeFontFamily : FontGenericNames[this.currentFontGeneric]),
- weight: this.currentFontWeight,
- style: this.currentFontStyle,
- stretch: this.currentFontStretch,
- variant: this.currentFontVariant };
- this.currentElement.text = _("Text");
- this.currentElement.textRightAligned = this.currentTextRightAligned;
- }
-
- this.currentElement.startDrawing(startX, startY);
-
- if (this.currentTool == Shapes.POLYGON || this.currentTool == Shapes.POLYLINE)
- this.emit('show-osd', null, _("Press %s to mark vertices")
- .format(Gtk.accelerator_get_label(Clutter.KEY_Return, 0)), "", -1, true);
-
- this.motionHandler = this.connect('motion-event', (actor, event) => {
- if (this.spaceKeyPressed)
- return;
-
- let coords = event.get_coords();
- let [s, x, y] = this.transform_stage_point(coords[0], coords[1]);
- if (!s)
- return;
- let controlPressed = event.has_control_modifier();
- this._updateDrawing(x, y, controlPressed);
- });
- },
-
- _updateDrawing: function(x, y, controlPressed) {
- if (!this.currentElement)
- return;
-
- this.currentElement.updateDrawing(x, y, controlPressed);
-
- this._redisplay();
- this.updatePointerCursor(controlPressed);
- },
-
- _stopDrawing: function() {
- if (this.motionHandler) {
- this.disconnect(this.motionHandler);
- this.motionHandler = null;
- }
- if (this.buttonReleasedHandler) {
- this.disconnect(this.buttonReleasedHandler);
- this.buttonReleasedHandler = null;
- }
-
- // skip when a polygon has not at least 3 points
- if (this.currentElement && this.currentElement.shape == Shapes.POLYGON && this.currentElement.points.length < 3)
- this.currentElement = null;
-
- if (this.currentElement)
- this.currentElement.stopDrawing();
-
- if (this.currentElement && this.currentElement.points.length >= 2) {
- if (this.currentElement.shape == Shapes.TEXT && !this.isWriting) {
- this._startWriting();
- return;
- }
-
- this.elements.push(this.currentElement);
- }
-
- this.currentElement = null;
- this._redisplay();
- this.updatePointerCursor();
- },
-
- _startWriting: function() {
- this.currentElement.text = '';
- this.currentElement.cursorPosition = 0;
- this.emit('show-osd', null, _("Type your text and press %s")
- .format(Gtk.accelerator_get_label(Clutter.KEY_Escape, 0)), "", -1, true);
- this._updateTextCursorTimeout();
- this.textHasCursor = true;
- this._redisplay();
-
- this.textEntry = new St.Entry({ visible: false });
- this.get_parent().add_child(this.textEntry);
- this.textEntry.grab_key_focus();
- this.updateActionMode();
- this.updatePointerCursor();
-
- this.textEntry.clutterText.connect('activate', (clutterText) => {
- let startNewLine = true;
- this._stopWriting(startNewLine);
- clutterText.text = "";
- });
-
- this.textEntry.clutterText.connect('text-changed', (clutterText) => {
- GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => {
- this.currentElement.text = clutterText.text;
- this.currentElement.cursorPosition = clutterText.cursorPosition;
- this._updateTextCursorTimeout();
- this._redisplay();
- });
- });
-
- this.textEntry.clutterText.connect('key-press-event', (clutterText, event) => {
- if (event.get_key_symbol() == Clutter.KEY_Escape) {
- this._stopWriting();
- return Clutter.EVENT_STOP;
- }
-
- // 'cursor-changed' signal is not emitted if the text entry is not visible.
- // So key events related to the cursor must be listened.
- if (event.get_key_symbol() == Clutter.KEY_Left || event.get_key_symbol() == Clutter.KEY_Right ||
- event.get_key_symbol() == Clutter.KEY_Home || event.get_key_symbol() == Clutter.KEY_End) {
- GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => {
- this.currentElement.cursorPosition = clutterText.cursorPosition;
- this._updateTextCursorTimeout();
- this.textHasCursor = true;
- this._redisplay();
- });
- }
-
- return Clutter.EVENT_PROPAGATE;
- });
- },
-
- _stopWriting: function(startNewLine) {
- if (this.currentElement.text.length > 0)
- this.elements.push(this.currentElement);
-
- if (startNewLine && this.currentElement.points.length == 2) {
- this.currentElement.lineIndex = this.currentElement.lineIndex || 0;
- // copy object, the original keep existing in this.elements
- this.currentElement = Object.create(this.currentElement);
- this.currentElement.lineIndex ++;
- let height = Math.abs(this.currentElement.points[1][1] - this.currentElement.points[0][1]);
- // define a new 'points' array, the original keep existing in this.elements
- this.currentElement.points = [
- [this.currentElement.points[0][0], this.currentElement.points[0][1] + height],
- [this.currentElement.points[1][0], this.currentElement.points[1][1] + height]
- ];
- this.currentElement.text = "";
- } else {
- this.currentElement = null;
- this._stopTextCursorTimeout();
- this.textEntry.destroy();
- delete this.textEntry;
- this.grab_key_focus();
- this.updateActionMode();
- this.updatePointerCursor();
- }
-
- this._redisplay();
- },
-
- setPointerCursor: function(pointerCursorName) {
- if (!this.currentPointerCursorName || this.currentPointerCursorName != pointerCursorName) {
- this.currentPointerCursorName = pointerCursorName;
- Extension.setCursor(pointerCursorName);
- }
- },
-
- updatePointerCursor: function(controlPressed) {
- if (this.currentTool == Manipulations.MIRROR && this.grabbedElementLocked)
- this.setPointerCursor('CROSSHAIR');
- else if (this.hasManipulationTool)
- this.setPointerCursor(this.grabbedElement ? 'MOVE_OR_RESIZE_WINDOW' : 'DEFAULT');
- else if (this.currentElement && this.currentElement.shape == Shapes.TEXT && this.isWriting)
- this.setPointerCursor('IBEAM');
- else if (!this.currentElement)
- this.setPointerCursor(this.currentTool == Shapes.NONE ? 'POINTING_HAND' : 'CROSSHAIR');
- else if (this.currentElement.shape != Shapes.NONE && controlPressed)
- this.setPointerCursor('MOVE_OR_RESIZE_WINDOW');
- },
-
- initPointerCursor: function() {
- this.currentPointerCursorName = null;
- this.updatePointerCursor();
- },
-
- _stopTextCursorTimeout: function() {
- if (this.textCursorTimeoutId) {
- GLib.source_remove(this.textCursorTimeoutId);
- this.textCursorTimeoutId = null;
- }
- this.textHasCursor = false;
- },
-
- _updateTextCursorTimeout: function() {
- this._stopTextCursorTimeout();
- this.textCursorTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, TEXT_CURSOR_TIME, () => {
- this.textHasCursor = !this.textHasCursor;
- this._redisplay();
- return GLib.SOURCE_CONTINUE;
- });
- },
-
- erase: function() {
- this.deleteLastElement();
- this.elements = [];
- this.undoneElements = [];
- this._redisplay();
- },
-
- deleteLastElement: function() {
- if (this.currentElement) {
- if (this.motionHandler) {
- this.disconnect(this.motionHandler);
- this.motionHandler = null;
- }
- if (this.buttonReleasedHandler) {
- this.disconnect(this.buttonReleasedHandler);
- this.buttonReleasedHandler = null;
- }
- if (this.isWriting)
- this._stopWriting();
- this.currentElement = null;
- } else {
- this.elements.pop();
- }
- this._redisplay();
- },
-
- undo: function() {
- if (this.elements.length > 0)
- this.undoneElements.push(this.elements.pop());
- this._redisplay();
- },
-
- redo: function() {
- if (this.undoneElements.length > 0)
- this.elements.push(this.undoneElements.pop());
- this._redisplay();
- },
-
- smoothLastElement: function() {
- if (this.elements.length > 0 && this.elements[this.elements.length - 1].shape == Shapes.NONE) {
- this.elements[this.elements.length - 1].smoothAll();
- this._redisplay();
- }
- },
-
- toggleBackground: function() {
- this.hasBackground = !this.hasBackground;
- this.get_parent().set_background_color(this.hasBackground ? this.activeBackgroundColor : null);
- },
-
- toggleGrid: function() {
- this.hasGrid = !this.hasGrid;
- this._redisplay();
- },
-
- toggleSquareArea: function() {
- this.isSquareArea = !this.isSquareArea;
- if (this.isSquareArea) {
- let width = this.squareAreaWidth || this.squareAreaHeight || Math.min(this.monitor.width, this.monitor.height) * 3 / 4;
- let height = this.squareAreaHeight || this.squareAreaWidth || Math.min(this.monitor.width, this.monitor.height) * 3 / 4;
- this.set_position(Math.floor(this.monitor.width / 2 - width / 2), Math.floor(this.monitor.height / 2 - height / 2));
- this.set_size(width, height);
- this.add_style_class_name('draw-on-your-screen-square-area');
- } else {
- this.set_position(0, 0);
- this.set_size(this.monitor.width, this.monitor.height);
- this.remove_style_class_name('draw-on-your-screen-square-area');
- }
- },
-
- toggleColor: function() {
- this.selectColor((this.currentColor == this.colors[1]) ? 2 : 1);
- },
-
- selectColor: function(index) {
- this.currentColor = this.colors[index];
- if (this.currentElement) {
- this.currentElement.color = this.currentColor.to_string();
- this._redisplay();
- }
- // Foreground color markup is not displayed since 3.36, use style instead but the transparency is lost.
- this.emit('show-osd', null, this.currentColor.to_string(), this.currentColor.to_string().slice(0, 7), -1, false);
- },
-
- selectTool: function(tool) {
- this.currentTool = tool;
- this.emit('show-osd', null, _(ToolNames[tool]), "", -1, false);
- this.updatePointerCursor();
- },
-
- toggleFill: function() {
- this.fill = !this.fill;
- this.emit('show-osd', null, this.fill ? _("Fill") : _("Outline"), "", -1, false);
- },
-
- toggleDash: function() {
- this.dashedLine = !this.dashedLine;
- this.emit('show-osd', null, this.dashedLine ? _("Dashed line") : _("Full line"), "", -1, false);
- },
-
- incrementLineWidth: function(increment) {
- this.currentLineWidth = Math.max(this.currentLineWidth + increment, 0);
- this.emit('show-osd', null, _("%d px").format(this.currentLineWidth), "", 2 * this.currentLineWidth, false);
- },
-
- toggleLineJoin: function() {
- this.currentLineJoin = this.currentLineJoin == 2 ? 0 : this.currentLineJoin + 1;
- this.emit('show-osd', null, _(LineJoinNames[this.currentLineJoin]), "", -1, false);
- },
-
- toggleLineCap: function() {
- this.currentLineCap = this.currentLineCap == 2 ? 0 : this.currentLineCap + 1;
- this.emit('show-osd', null, _(LineCapNames[this.currentLineCap]), "", -1, false);
- },
-
- toggleFillRule: function() {
- this.currentFillRule = this.currentFillRule == 1 ? 0 : this.currentFillRule + 1;
- this.emit('show-osd', null, _(FillRuleNames[this.currentFillRule]), "", -1, false);
- },
-
- toggleFontWeight: function() {
- let fontWeights = Object.keys(FontWeightNames).map(key => Number(key));
- let index = fontWeights.indexOf(this.currentFontWeight);
- this.currentFontWeight = index == fontWeights.length - 1 ? fontWeights[0] : fontWeights[index + 1];
- if (this.currentElement && this.currentElement.font) {
- this.currentElement.font.weight = this.currentFontWeight;
- this._redisplay();
- }
- this.emit('show-osd', null, `` +
- `${_(FontWeightNames[this.currentFontWeight])}`, "", -1, false);
- },
-
- toggleFontStyle: function() {
- this.currentFontStyle = this.currentFontStyle == 2 ? 0 : this.currentFontStyle + 1;
- if (this.currentElement && this.currentElement.font) {
- this.currentElement.font.style = this.currentFontStyle;
- this._redisplay();
- }
- this.emit('show-osd', null, `` +
- `${_(FontStyleNames[this.currentFontStyle])}`, "", -1, false);
- },
-
- toggleFontFamily: function() {
- this.currentFontGeneric = this.currentFontGeneric == 5 ? 0 : this.currentFontGeneric + 1;
- let currentFontFamily = this.currentFontGeneric == 0 ? this.currentThemeFontFamily : FontGenericNames[this.currentFontGeneric];
- if (this.currentElement && this.currentElement.font) {
- this.currentElement.font.family = currentFontFamily;
- this._redisplay();
- }
- this.emit('show-osd', null, `${_(currentFontFamily)}`, "", -1, false);
- },
-
- toggleTextAlignment: function() {
- this.currentTextRightAligned = !this.currentTextRightAligned;
- if (this.currentElement && this.currentElement.textRightAligned !== undefined) {
- this.currentElement.textRightAligned = this.currentTextRightAligned;
- this._redisplay();
- }
- this.emit('show-osd', null, this.currentTextRightAligned ? _("Right aligned") : _("Left aligned"), "", -1, false);
- },
-
- toggleHelp: function() {
- if (this.helper.visible) {
- this.helper.hideHelp();
- if (this.textEntry)
- this.textEntry.grab_key_focus();
- } else {
- this.helper.showHelp();
- this.grab_key_focus();
- }
-
- },
-
- // The area is reactive when it is modal.
- _onReactiveChanged: function() {
- if (this.hasGrid)
- this._redisplay();
- if (this.helper.visible)
- this.toggleHelp();
- if (this.textEntry && this.reactive)
- this.textEntry.grab_key_focus();
- },
-
- _onDestroy: function() {
- this.disconnect(this.reactiveHandler);
- this.erase();
- if (this._menu)
- this._menu.disable();
- },
-
- updateActionMode: function() {
- this.emit('update-action-mode');
- },
-
- enterDrawingMode: function() {
- this.stageKeyPressedHandler = global.stage.connect('key-press-event', this._onStageKeyPressed.bind(this));
- this.stageKeyReleasedHandler = global.stage.connect('key-release-event', this._onStageKeyReleased.bind(this));
- this.keyPressedHandler = this.connect('key-press-event', this._onKeyPressed.bind(this));
- this.buttonPressedHandler = this.connect('button-press-event', this._onButtonPressed.bind(this));
- this._onKeyboardPopupMenuHandler = this.connect('popup-menu', this._onKeyboardPopupMenu.bind(this));
- this.scrollHandler = this.connect('scroll-event', this._onScroll.bind(this));
- this.get_parent().set_background_color(this.reactive && this.hasBackground ? this.activeBackgroundColor : null);
- this._updateStyle();
- },
-
- leaveDrawingMode: function(save) {
- if (this.stageKeyPressedHandler) {
- global.stage.disconnect(this.stageKeyPressedHandler);
- this.stageKeyPressedHandler = null;
- }
- if (this.stageKeyReleasedHandler) {
- global.stage.disconnect(this.stageKeyReleasedHandler);
- this.stageKeyReleasedHandler = null;
- }
- if (this.keyPressedHandler) {
- this.disconnect(this.keyPressedHandler);
- this.keyPressedHandler = null;
- }
- if (this.buttonPressedHandler) {
- this.disconnect(this.buttonPressedHandler);
- this.buttonPressedHandler = null;
- }
- if (this._onKeyboardPopupMenuHandler) {
- this.disconnect(this._onKeyboardPopupMenuHandler);
- this._onKeyboardPopupMenuHandler = null;
- }
- if (this.motionHandler) {
- this.disconnect(this.motionHandler);
- this.motionHandler = null;
- }
- if (this.buttonReleasedHandler) {
- this.disconnect(this.buttonReleasedHandler);
- this.buttonReleasedHandler = null;
- }
- if (this.scrollHandler) {
- this.disconnect(this.scrollHandler);
- this.scrollHandler = null;
- }
-
- this.currentElement = null;
- this._stopTextCursorTimeout();
- this._redisplay();
- this.closeMenu();
- this.get_parent().set_background_color(null);
- if (save)
- this.savePersistent();
- },
-
- saveAsSvg: function() {
- // stop drawing or writing
- if (this.currentElement && this.currentElement.shape == Shapes.TEXT && this.isWriting) {
- this._stopWriting();
- } else if (this.currentElement && this.currentElement.shape != Shapes.TEXT) {
- this._stopDrawing();
- }
-
- let content = `