init
This commit is contained in:
parent
1f67bc15af
commit
7f9a3195b4
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
Copyright (c) 2011-2012, Giovanni Campagna <scampa.giovanni@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the GNOME nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
const Gettext = imports.gettext;
|
||||
const Gio = imports.gi.Gio;
|
||||
|
||||
const Config = imports.misc.config;
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
|
||||
/**
|
||||
* initTranslations:
|
||||
* @domain: (optional): the gettext domain to use
|
||||
*
|
||||
* Initialize Gettext to load translations from extensionsdir/locale.
|
||||
* If @domain is not provided, it will be taken from metadata['gettext-domain']
|
||||
*/
|
||||
function initTranslations(domain) {
|
||||
let extension = ExtensionUtils.getCurrentExtension();
|
||||
|
||||
domain = domain || extension.metadata['gettext-domain'];
|
||||
|
||||
// check if this extension was built with "make zip-file", and thus
|
||||
// has the locale files in a subfolder
|
||||
// otherwise assume that extension has been installed in the
|
||||
// same prefix as gnome-shell
|
||||
let localeDir = extension.dir.get_child('locale');
|
||||
if (localeDir.query_exists(null))
|
||||
Gettext.bindtextdomain(domain, localeDir.get_path());
|
||||
else
|
||||
Gettext.bindtextdomain(domain, Config.LOCALEDIR);
|
||||
}
|
||||
|
||||
/**
|
||||
* getSettings:
|
||||
* @schema: (optional): the GSettings schema id
|
||||
*
|
||||
* Builds and return a GSettings schema for @schema, using schema files
|
||||
* in extensionsdir/schemas. If @schema is not provided, it is taken from
|
||||
* metadata['settings-schema'].
|
||||
*/
|
||||
function getSettings(schema) {
|
||||
let extension = ExtensionUtils.getCurrentExtension();
|
||||
|
||||
schema = schema || extension.metadata['settings-schema'];
|
||||
|
||||
const GioSSS = Gio.SettingsSchemaSource;
|
||||
|
||||
// check if this extension was built with "make zip-file", and thus
|
||||
// has the schema files in a subfolder
|
||||
// otherwise assume that extension has been installed in the
|
||||
// same prefix as gnome-shell (and therefore schemas are available
|
||||
// in the standard folders)
|
||||
let schemaDir = extension.dir.get_child('schemas');
|
||||
let schemaSource;
|
||||
if (schemaDir.query_exists(null))
|
||||
schemaSource = GioSSS.new_from_directory(schemaDir.get_path(),
|
||||
GioSSS.get_default(),
|
||||
false);
|
||||
else
|
||||
schemaSource = GioSSS.get_default();
|
||||
|
||||
let schemaObj = schemaSource.lookup(schema, true);
|
||||
if (!schemaObj)
|
||||
throw new Error('Schema ' + schema + ' could not be found for extension '
|
||||
+ extension.metadata.uuid + '. Please check your installation.');
|
||||
|
||||
return new Gio.Settings({ settings_schema: schemaObj });
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,690 @@
|
|||
/* jslint esversion: 6 */
|
||||
|
||||
/*
|
||||
* Copyright 2019 Abakkk
|
||||
*
|
||||
* This file is part of DrowOnYourScreen, a drawing extension for GNOME Shell.
|
||||
* https://framagit.org/abakkk/DrawOnYourScreen
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const Cairo = imports.cairo;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
const Screenshot = imports.ui.screenshot;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const Extension = ExtensionUtils.getCurrentExtension();
|
||||
const Convenience = Extension.imports.convenience;
|
||||
const Prefs = Extension.imports.prefs;
|
||||
const _ = imports.gettext.domain(Extension.metadata["gettext-domain"]).gettext;
|
||||
|
||||
var Shapes = { NONE: 0, LINE: 1, ELLIPSE: 2, RECTANGLE: 3, TEXT: 4 };
|
||||
var ShapeNames = { 0: "Free drawing", 1: "Line", 2: "Circle", 3: "Rectangle", 4: "Text" };
|
||||
var LineCapNames = { 0: 'Butt', 1: 'Round', 2: 'Square' };
|
||||
var LineJoinNames = { 0: 'Miter', 1: 'Round', 2: 'Bevel' };
|
||||
var FontWeightNames = { 0: 'Normal', 1: 'Bold' };
|
||||
var FontStyleNames = { 0: 'Normal', 1: 'Italic', 2: 'Oblique' };
|
||||
var FontFamilyNames = { 0: 'Default', 1: 'Sans-Serif', 2: 'Serif', 3: 'Monospace', 4: 'Cursive', 5: 'Fantasy' };
|
||||
|
||||
// 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: 'DrawingArea',
|
||||
Extends: St.DrawingArea,
|
||||
|
||||
_init: function(params, helper) {
|
||||
this.parent({ style_class: 'draw-on-your-screen', name: params && params.name ? params.name : ""});
|
||||
|
||||
// 'style-changed' is emitted when 'this' is added to an actor
|
||||
// ('this' needs to be in the stage to query theme_node)
|
||||
this.connect('style-changed', this._onStyleChanged.bind(this));
|
||||
this.connect('repaint', this._repaint.bind(this));
|
||||
|
||||
this.emitter = new DrawingAreaEmitter();
|
||||
this.helper = helper;
|
||||
|
||||
this.elements = [];
|
||||
this.undoneElements = [];
|
||||
this.currentElement = null;
|
||||
this.currentShape = Shapes.NONE;
|
||||
this.hasBackground = false;
|
||||
this.textHasCursor = false;
|
||||
this.dashedLine = false;
|
||||
this.colors = [Clutter.Color.new(0, 0, 0, 255)];
|
||||
},
|
||||
|
||||
_redisplay: function() {
|
||||
// force area to emit 'repaint'
|
||||
this.queue_repaint();
|
||||
},
|
||||
|
||||
_onStyleChanged: function() {
|
||||
try {
|
||||
let themeNode = this.get_theme_node();
|
||||
for (let i = 1; i < 10; i++) {
|
||||
this.colors[i] = themeNode.get_color('-drawing-color' + i);
|
||||
}
|
||||
this.activeBackgroundColor = themeNode.get_color('-drawing-background-color');
|
||||
this.currentLineWidth = themeNode.get_length('-drawing-line-width');
|
||||
this.currentLineJoin = themeNode.get_double('-drawing-line-join');
|
||||
this.currentLineCap = themeNode.get_double('-drawing-line-cap');
|
||||
this.dashArray = [themeNode.get_length('-drawing-dash-array-on'), themeNode.get_length('-drawing-dash-array-off')];
|
||||
this.dashOffset = themeNode.get_length('-drawing-dash-offset');
|
||||
let font = themeNode.get_font();
|
||||
this.fontFamily = font.get_family();
|
||||
this.currentFontWeight = font.get_weight();
|
||||
this.currentFontStyle = font.get_style();
|
||||
} 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.colors[1];
|
||||
|
||||
this.currentLineWidth = (this.currentLineWidth > 0) ? this.currentLineWidth : 3;
|
||||
this.currentLineJoin = ([0, 1, 2].indexOf(this.currentLineJoin) != -1) ? this.currentLineJoin : Cairo.LineJoin.ROUND;
|
||||
this.currentLineCap = ([0, 1, 2].indexOf(this.currentLineCap) != -1) ? this.currentLineCap : Cairo.LineCap.ROUND;
|
||||
this.currentFontFamilyId = 0;
|
||||
this.currentFontWeight = this.currentFontWeight > 500 ? 1 : 0 ;
|
||||
// font style enum order of Cairo and Pango are different
|
||||
this.currentFontStyle = this.currentFontStyle == 2 ? 1 : ( this.currentFontStyle == 1 ? 2 : 0);
|
||||
},
|
||||
|
||||
_repaint: function(area) {
|
||||
let cr = area.get_context();
|
||||
|
||||
for (let i = 0; i < this.elements.length; i++) {
|
||||
this.elements[i].buildCairo(cr, false);
|
||||
|
||||
if (this.elements[i].fill && this.elements[i].shape != Shapes.LINE)
|
||||
cr.fill();
|
||||
else
|
||||
cr.stroke();
|
||||
}
|
||||
|
||||
if (this.currentElement) {
|
||||
this.currentElement.buildCairo(cr, this.textHasCursor);
|
||||
cr.stroke();
|
||||
}
|
||||
|
||||
cr.$dispose();
|
||||
},
|
||||
|
||||
_onButtonPressed: function(actor, event) {
|
||||
let button = event.get_button();
|
||||
let [x, y] = event.get_coords();
|
||||
let shiftPressed = event.has_shift_modifier();
|
||||
|
||||
// stop writing
|
||||
if (this.currentElement && this.currentElement.shape == Shapes.TEXT) {
|
||||
this._stopWriting();
|
||||
}
|
||||
|
||||
// hide helper
|
||||
if (this.helper.visible && button != 2) {
|
||||
this.helper.hideHelp();
|
||||
return Clutter.EVENT_STOP;
|
||||
}
|
||||
|
||||
if (button == 1) {
|
||||
this._startDrawing(x, y, false, shiftPressed);
|
||||
return Clutter.EVENT_STOP;
|
||||
} else if (button == 2) {
|
||||
this.toggleShape();
|
||||
} else if (button == 3) {
|
||||
this._startDrawing(x, y, true, shiftPressed);
|
||||
return Clutter.EVENT_STOP;
|
||||
}
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
_onKeyPressed: function(actor, event) {
|
||||
if (event.get_key_symbol() == Clutter.Escape) {
|
||||
this.emitter.emit('stop-drawing');
|
||||
this.erase();
|
||||
return Clutter.EVENT_STOP;
|
||||
} else if (this.currentElement && this.currentElement.shape == Shapes.TEXT) {
|
||||
if (event.get_key_symbol() == Clutter.KEY_BackSpace) {
|
||||
this.currentElement.text = this.currentElement.text.slice(0, -1);
|
||||
this._updateCursorTimeout();
|
||||
} else if (event.has_control_modifier() && event.get_key_symbol() == 118) {
|
||||
// Ctrl + V
|
||||
St.Clipboard.get_default().get_text(St.ClipboardType.CLIPBOARD, (clipBoard, clipText) => {
|
||||
this.currentElement.text += clipText;
|
||||
this._updateCursorTimeout();
|
||||
this._redisplay();
|
||||
});
|
||||
return Clutter.EVENT_STOP;
|
||||
} else if (event.get_key_symbol() == Clutter.KEY_Return || event.get_key_symbol() == 65421) {
|
||||
// stop writing
|
||||
// Clutter.KEY_Return is "Enter" and 65421 is KP_Enter
|
||||
this._stopWriting();
|
||||
} else {
|
||||
let unicode = event.get_key_unicode();
|
||||
this.currentElement.text += unicode;
|
||||
this._updateCursorTimeout();
|
||||
}
|
||||
this._redisplay();
|
||||
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;
|
||||
},
|
||||
|
||||
_startDrawing: function(stageX, stageY, fill, 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 ({
|
||||
color: this.currentColor,
|
||||
line: { lineWidth: this.currentLineWidth, lineJoin: this.currentLineJoin, lineCap: this.currentLineCap },
|
||||
dash: { array: this.dashedLine ? this.dashArray : [0, 0] , offset: this.dashedLine ? this.dashOffset : 0 },
|
||||
fill: fill,
|
||||
eraser: eraser,
|
||||
shape: this.currentShape == Shapes.TEXT ? Shapes.RECTANGLE : this.currentShape,
|
||||
text: '',
|
||||
font: { family: (this.currentFontFamilyId == 0 ? this.fontFamily : FontFamilyNames[this.currentFontFamilyId]), weight: this.currentFontWeight, style: this.currentFontStyle },
|
||||
points: [[startX, startY]]
|
||||
});
|
||||
|
||||
this.motionHandler = this.connect('motion-event', (actor, event) => {
|
||||
let coords = event.get_coords();
|
||||
let [s, x, y] = this.transform_stage_point(coords[0], coords[1]);
|
||||
if (!s)
|
||||
return;
|
||||
this._updateDrawing(x, y);
|
||||
});
|
||||
},
|
||||
|
||||
_stopDrawing: function() {
|
||||
if (this.motionHandler) {
|
||||
this.disconnect(this.motionHandler);
|
||||
this.motionHandler = null;
|
||||
}
|
||||
if (this.buttonReleasedHandler) {
|
||||
this.disconnect(this.buttonReleasedHandler);
|
||||
this.buttonReleasedHandler = null;
|
||||
}
|
||||
|
||||
// start writing
|
||||
if (this.currentShape == Shapes.TEXT && this.currentElement) {
|
||||
this.currentElement.shape = Shapes.TEXT;
|
||||
this.currentElement.text = '';
|
||||
this.emitter.emit('show-osd', _("Type your text\nand press Enter"), null);
|
||||
this._updateCursorTimeout();
|
||||
this._redisplay();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.currentElement) {
|
||||
this.elements.push(this.currentElement);
|
||||
}
|
||||
this.currentElement = null;
|
||||
this._redisplay();
|
||||
},
|
||||
|
||||
_updateDrawing: function(x, y) {
|
||||
if (!this.currentElement)
|
||||
return;
|
||||
if (this.currentElement.shape == Shapes.NONE)
|
||||
this.currentElement.points.push([x, y]);
|
||||
else
|
||||
this.currentElement.points[1] = [x, y];
|
||||
this._redisplay();
|
||||
},
|
||||
|
||||
_stopWriting: function() {
|
||||
this.elements.push(this.currentElement);
|
||||
this.currentElement = null;
|
||||
this._stopCursorTimeout();
|
||||
this._redisplay();
|
||||
},
|
||||
|
||||
_stopCursorTimeout: function() {
|
||||
if (this.cursorTimeoutId) {
|
||||
Mainloop.source_remove(this.cursorTimeoutId);
|
||||
this.cursorTimeoutId = null;
|
||||
}
|
||||
this.textHasCursor = false;
|
||||
},
|
||||
|
||||
_updateCursorTimeout: function() {
|
||||
this._stopCursorTimeout();
|
||||
this.cursorTimeoutId = Mainloop.timeout_add(600, () => {
|
||||
this.textHasCursor = !this.textHasCursor;
|
||||
this._redisplay();
|
||||
return true;
|
||||
});
|
||||
},
|
||||
|
||||
erase: function() {
|
||||
this.elements = [];
|
||||
this.undoneElements = [];
|
||||
this.currentElement = null;
|
||||
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;
|
||||
}
|
||||
this.currentElement = null;
|
||||
this._stopCursorTimeout();
|
||||
} 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();
|
||||
},
|
||||
|
||||
toggleBackground: function() {
|
||||
this.hasBackground = !this.hasBackground;
|
||||
this.get_parent().set_background_color(this.hasBackground ? this.activeBackgroundColor : null);
|
||||
},
|
||||
|
||||
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;
|
||||
this._redisplay();
|
||||
}
|
||||
this.emitter.emit('show-osd', this.currentColor.to_string(), null);
|
||||
},
|
||||
|
||||
selectShape: function(shape) {
|
||||
this.currentShape = shape;
|
||||
this.emitter.emit('show-osd', _(ShapeNames[shape]), null);
|
||||
},
|
||||
|
||||
toggleShape: function() {
|
||||
this.selectShape((this.currentShape == Object.keys(Shapes).length - 1) ? 0 : this.currentShape + 1);
|
||||
},
|
||||
|
||||
toggleDash: function() {
|
||||
this.dashedLine = !this.dashedLine;
|
||||
this.emitter.emit('show-osd', this.dashedLine ? _("Dashed line") : _("Full line"), null);
|
||||
},
|
||||
|
||||
incrementLineWidth: function(increment) {
|
||||
this.currentLineWidth = Math.max(this.currentLineWidth + increment, 1);
|
||||
this.emitter.emit('show-osd', this.currentLineWidth + "px", this.currentLineWidth);
|
||||
},
|
||||
|
||||
toggleLineJoin: function() {
|
||||
this.currentLineJoin = this.currentLineJoin == 2 ? 0 : this.currentLineJoin + 1;
|
||||
this.emitter.emit('show-osd', LineJoinNames[this.currentLineJoin], null);
|
||||
},
|
||||
|
||||
toggleLineCap: function() {
|
||||
this.currentLineCap = this.currentLineCap == 2 ? 0 : this.currentLineCap + 1;
|
||||
this.emitter.emit('show-osd', LineCapNames[this.currentLineCap], null);
|
||||
},
|
||||
|
||||
toggleFontWeight: function() {
|
||||
this.currentFontWeight = this.currentFontWeight == 1 ? 0 : this.currentFontWeight + 1;
|
||||
if (this.currentElement) {
|
||||
this.currentElement.font.weight = this.currentFontWeight;
|
||||
this._redisplay();
|
||||
}
|
||||
this.emitter.emit('show-osd', FontWeightNames[this.currentFontWeight], null);
|
||||
},
|
||||
|
||||
toggleFontStyle: function() {
|
||||
this.currentFontStyle = this.currentFontStyle == 2 ? 0 : this.currentFontStyle + 1;
|
||||
if (this.currentElement) {
|
||||
this.currentElement.font.style = this.currentFontStyle;
|
||||
this._redisplay();
|
||||
}
|
||||
this.emitter.emit('show-osd', FontStyleNames[this.currentFontStyle], null);
|
||||
},
|
||||
|
||||
toggleFontFamily: function() {
|
||||
this.currentFontFamilyId = this.currentFontFamilyId == 5 ? 0 : this.currentFontFamilyId + 1;
|
||||
let currentFontFamily = this.currentFontFamilyId == 0 ? this.fontFamily : FontFamilyNames[this.currentFontFamilyId];
|
||||
if (this.currentElement) {
|
||||
this.currentElement.font.family = currentFontFamily;
|
||||
this._redisplay();
|
||||
}
|
||||
this.emitter.emit('show-osd',currentFontFamily , null);
|
||||
},
|
||||
|
||||
toggleHelp: function() {
|
||||
if (this.helper.visible)
|
||||
this.helper.hideHelp();
|
||||
else
|
||||
this.helper.showHelp();
|
||||
},
|
||||
|
||||
enterDrawingMode: function() {
|
||||
this.keyPressedHandler = this.connect('key-press-event', this._onKeyPressed.bind(this));
|
||||
this.buttonPressedHandler = this.connect('button-press-event', this._onButtonPressed.bind(this));
|
||||
this.scrollHandler = this.connect('scroll-event', this._onScroll.bind(this));
|
||||
this.selectShape(Shapes.NONE);
|
||||
this.get_parent().set_background_color(this.hasBackground ? this.activeBackgroundColor : null);
|
||||
},
|
||||
|
||||
leaveDrawingMode: function() {
|
||||
if (this.keyPressedHandler) {
|
||||
this.disconnect(this.keyPressedHandler);
|
||||
this.keyPressedHandler = null;
|
||||
}
|
||||
if (this.buttonPressedHandler) {
|
||||
this.disconnect(this.buttonPressedHandler);
|
||||
this.buttonPressedHandler = 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;
|
||||
}
|
||||
|
||||
if (this.helper.visible)
|
||||
this.helper.hideHelp();
|
||||
|
||||
this.currentElement = null;
|
||||
this._stopCursorTimeout();
|
||||
this.dashedLine = false;
|
||||
this._redisplay();
|
||||
this.get_parent().set_background_color(null);
|
||||
},
|
||||
|
||||
save: function() {
|
||||
// stop drawing or writing
|
||||
if (this.currentElement && this.currentElement.shape == Shapes.TEXT) {
|
||||
this._stopWriting();
|
||||
} else if (this.currentElement && this.currentShape != Shapes.TEXT) {
|
||||
this._stopDrawing();
|
||||
}
|
||||
|
||||
let content = `<svg viewBox="0 0 ${this.width} ${this.height}" xmlns="http://www.w3.org/2000/svg">`;
|
||||
let backgroundColorString = this.hasBackground ? this.activeBackgroundColor.to_string() : 'transparent';
|
||||
if (backgroundColorString != 'transparent') {
|
||||
content += `\n <rect id="background" width="100%" height="100%" fill="${backgroundColorString}"/>`;
|
||||
}
|
||||
for (let i = 0; i < this.elements.length; i++) {
|
||||
content += this.elements[i].buildSVG(backgroundColorString);
|
||||
}
|
||||
content += "\n</svg>";
|
||||
|
||||
let date = GLib.DateTime.new_now_local();
|
||||
let filename = `DrawOnYourScreen ${date.format("%F")} ${date.format("%X")}.svg`;
|
||||
let dir = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_PICTURES);
|
||||
let path = GLib.build_filenamev([dir, filename]);
|
||||
if (GLib.file_test(path, GLib.FileTest.EXISTS))
|
||||
return false;
|
||||
let success = GLib.file_set_contents(path, content);
|
||||
|
||||
if (success) {
|
||||
// pass the parent (bgContainer) to Flashspot because coords of this are relative
|
||||
let flashspot = new Screenshot.Flashspot(this.get_parent());
|
||||
flashspot.fire();
|
||||
global.play_theme_sound(0, 'screen-capture', "Save as SVG", null);
|
||||
}
|
||||
},
|
||||
|
||||
disable: function() {
|
||||
if (this.theme && this.customStylesheetsChangedHandler) {
|
||||
this.theme.disconnect(this.customStylesheetsChangedHandler);
|
||||
this.customStylesheetsChangedHandler = null;
|
||||
}
|
||||
this.erase();
|
||||
}
|
||||
});
|
||||
|
||||
var DrawingAreaEmitter = new Lang.Class({
|
||||
Name: 'DrawingAreaEmitter',
|
||||
|
||||
_init: function() {
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(DrawingAreaEmitter.prototype);
|
||||
|
||||
|
||||
// DrawingElement represents a "brushstroke".
|
||||
// It can be converted into a cairo path as well as a svg element.
|
||||
// See DrawingArea._startDrawing() to know its params.
|
||||
var DrawingElement = new Lang.Class({
|
||||
Name: 'DrawingElement',
|
||||
|
||||
_init: function(params) {
|
||||
for (let key in params)
|
||||
this[key] = params[key];
|
||||
},
|
||||
|
||||
buildCairo: function(cr, showTextCursor) {
|
||||
cr.setLineCap(this.line.lineCap);
|
||||
cr.setLineJoin(this.line.lineJoin);
|
||||
cr.setLineWidth(this.line.lineWidth);
|
||||
|
||||
if (this.dash.array[0] > 0 && this.dash.array[1] > 0)
|
||||
cr.setDash(this.dash.array, this.dash.offset);
|
||||
else
|
||||
cr.setDash([1000000], 0);
|
||||
|
||||
if (this.eraser)
|
||||
cr.setOperator(Cairo.Operator.CLEAR);
|
||||
else
|
||||
cr.setOperator(Cairo.Operator.OVER);
|
||||
|
||||
Clutter.cairo_set_source_color(cr, this.color);
|
||||
|
||||
let [points, shape] = [this.points, this.shape];
|
||||
|
||||
if (shape == Shapes.NONE || shape == Shapes.LINE) {
|
||||
cr.moveTo(points[0][0], points[0][1]);
|
||||
for (let j = 1; j < points.length; j++) {
|
||||
cr.lineTo(points[j][0], points[j][1]);
|
||||
}
|
||||
} else if (shape == Shapes.ELLIPSE && points.length == 2) {
|
||||
let r = Math.hypot(points[1][0] - points[0][0], points[1][1] - points[0][1]);
|
||||
cr.arc(points[0][0], points[0][1], r, 0, 2 * Math.PI);
|
||||
|
||||
} else if (shape == Shapes.RECTANGLE && points.length == 2) {
|
||||
cr.rectangle(points[0][0], points[0][1], points[1][0] - points[0][0], points[1][1] - points[0][1]);
|
||||
} else if (shape == Shapes.TEXT && points.length == 2) {
|
||||
cr.selectFontFace(this.font.family, this.font.style, this.font.weight);
|
||||
cr.setFontSize(Math.abs(points[1][1] - points[0][1]));
|
||||
cr.moveTo(Math.min(points[0][0], points[1][0]), Math.max(points[0][1], points[1][1]));
|
||||
cr.showText((showTextCursor) ? (this.text + "_") : this.text);
|
||||
}
|
||||
},
|
||||
|
||||
buildSVG: function(bgColor) {
|
||||
let row = "\n ";
|
||||
let points = this.points.map((point) => [Math.round(point[0]*100)/100, Math.round(point[1]*100)/100]);
|
||||
let color = this.eraser ? bgColor : this.color.to_string();
|
||||
let attributes = `fill="${this.fill ? color : 'transparent'}" ` +
|
||||
`stroke="${this.fill ? 'transparent' : color}" ` +
|
||||
`stroke-width="${this.line.lineWidth}" ` +
|
||||
`stroke-linecap="${LineCapNames[this.line.lineCap].toLowerCase()}" ` +
|
||||
`stroke-linejoin="${LineJoinNames[this.line.lineJoin].toLowerCase()}"`;
|
||||
|
||||
if (this.dash.array[0] > 0 && this.dash.array[1] > 0)
|
||||
attributes += ` stroke-dasharray="${this.dash.array[0]} ${this.dash.array[1]}" stroke-dashoffset="${this.dash.offset}"`;
|
||||
|
||||
if (this.shape == Shapes.NONE || this.shape == Shapes.LINE) {
|
||||
row += `<path ${attributes} d="M${points[0][0]} ${points[0][1]}`;
|
||||
|
||||
for (let i = 1; i < points.length; i++) {
|
||||
row += ` L ${points[i][0]} ${points[i][1]}`;
|
||||
}
|
||||
|
||||
row += `${this.fill ? 'z' : ''}"/>`;
|
||||
} else if (this.shape == Shapes.ELLIPSE && points.length == 2) {
|
||||
let r = Math.hypot(points[1][0] - points[0][0], points[1][1] - points[0][1]);
|
||||
row += `<circle ${attributes} cx="${points[0][0]}" cy="${points[0][1]}" r="${r}"/>`;
|
||||
} else if (this.shape == Shapes.RECTANGLE && points.length == 2) {
|
||||
row += `<rect ${attributes} x="${Math.min(points[0][0], points[1][0])}" y="${Math.min(points[0][1], points[1][1])}" ` +
|
||||
`width="${Math.abs(points[1][0] - points[0][0])}" height="${Math.abs(points[1][1] - points[0][1])}"/>`;
|
||||
} else if (this.shape == Shapes.TEXT && points.length == 2) {
|
||||
attributes = `fill="${color}" ` +
|
||||
`stroke="transparent" ` +
|
||||
`font-family="${this.font.family}" ` +
|
||||
`font-size="${Math.abs(points[1][1] - points[0][1])}" ` +
|
||||
`font-weight="${FontWeightNames[this.font.weight].toLowerCase()}" ` +
|
||||
`font-style="${FontStyleNames[this.font.style].toLowerCase()}"`;
|
||||
|
||||
row += `<text ${attributes} x="${Math.min(points[0][0], points[1][0])}" y="${Math.max(points[0][1], points[1][1])}">${this.text}</text>`;
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
});
|
||||
|
||||
var HELPER_ANIMATION_TIME = 0.25;
|
||||
|
||||
// DrawingHelper provides the "help osd" (Ctrl + F1)
|
||||
// It uses the same texts as in prefs
|
||||
var DrawingHelper = new Lang.Class({
|
||||
Name: 'DrawingHelper',
|
||||
Extends: St.ScrollView,
|
||||
|
||||
_init: function(params, monitor) {
|
||||
this.parent(params);
|
||||
this.monitor = monitor;
|
||||
this.hide();
|
||||
this.vbox = new St.BoxLayout({ style_class: 'osd-window draw-on-your-screen-helper', vertical: true });
|
||||
this.add_actor(this.vbox);
|
||||
this.vbox.add(new St.Label({ text: _("Global") }));
|
||||
|
||||
let settings = Convenience.getSettings();
|
||||
|
||||
for (let settingKey in Prefs.GLOBAL_KEYBINDINGS) {
|
||||
let hbox = new St.BoxLayout({ vertical: false });
|
||||
if (settingKey.indexOf('-separator-') != -1) {
|
||||
this.vbox.add(hbox);
|
||||
continue;
|
||||
}
|
||||
let [keyval, mods] = Gtk.accelerator_parse(settings.get_strv(settingKey)[0]);
|
||||
hbox.add(new St.Label({ text: _(Prefs.GLOBAL_KEYBINDINGS[settingKey]) }));
|
||||
hbox.add(new St.Label({ text: Gtk.accelerator_get_label(keyval, mods) }), { expand: true });
|
||||
this.vbox.add(hbox);
|
||||
}
|
||||
|
||||
this.vbox.add(new St.Label({ text: _("Internal") }));
|
||||
|
||||
for (let desc in Prefs.OTHER_SHORTCUTS) {
|
||||
if (desc.indexOf('-separator-') != -1) {
|
||||
this.vbox.add(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-separator' }));
|
||||
continue;
|
||||
}
|
||||
let hbox = new St.BoxLayout({ vertical: false });
|
||||
hbox.add(new St.Label({ text: _(desc) }));
|
||||
hbox.add(new St.Label({ text: _(Prefs.OTHER_SHORTCUTS[desc]) }), { expand: true });
|
||||
this.vbox.add(hbox);
|
||||
}
|
||||
|
||||
this.vbox.add(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-separator' }));
|
||||
|
||||
for (let settingKey in Prefs.INTERNAL_KEYBINDINGS) {
|
||||
if (settingKey.indexOf('-separator-') != -1) {
|
||||
this.vbox.add(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-separator' }));
|
||||
continue;
|
||||
}
|
||||
let hbox = new St.BoxLayout({ vertical: false });
|
||||
let [keyval, mods] = Gtk.accelerator_parse(settings.get_strv(settingKey)[0]);
|
||||
hbox.add(new St.Label({ text: _(Prefs.INTERNAL_KEYBINDINGS[settingKey]) }));
|
||||
hbox.add(new St.Label({ text: Gtk.accelerator_get_label(keyval, mods) }), { expand: true });
|
||||
this.vbox.add(hbox);
|
||||
}
|
||||
},
|
||||
|
||||
showHelp: function() {
|
||||
this.opacity = 0;
|
||||
this.show();
|
||||
|
||||
let maxHeight = this.monitor.height*(3/4);
|
||||
if (this.height > maxHeight)
|
||||
this.vscrollbar_policy = Gtk.PolicyType.ALWAYS;
|
||||
else
|
||||
this.vscrollbar_policy = Gtk.PolicyType.NEVER;
|
||||
this.set_height(Math.min(this.height, maxHeight));
|
||||
this.set_position(this.monitor.x + Math.floor(this.monitor.width / 2 - this.width / 2),
|
||||
this.monitor.y + Math.floor(this.monitor.height / 2 - this.height / 2));
|
||||
|
||||
Tweener.removeTweens(this);
|
||||
Tweener.addTween(this, { opacity: 255,
|
||||
time: HELPER_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: null });
|
||||
},
|
||||
|
||||
hideHelp: function() {
|
||||
Tweener.removeTweens(this);
|
||||
Tweener.addTween(this, { opacity: 0,
|
||||
time: HELPER_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: this.hide.bind(this) });
|
||||
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,278 @@
|
|||
/* jslint esversion: 6 */
|
||||
|
||||
/*
|
||||
* Copyright 2019 Abakkk
|
||||
*
|
||||
* This file is part of DrowOnYourScreen, a drawing extension for GNOME Shell.
|
||||
* https://framagit.org/abakkk/DrawOnYourScreen
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const Main = imports.ui.main;
|
||||
const OsdWindow = imports.ui.osdWindow;
|
||||
const Extension = imports.misc.extensionUtils.getCurrentExtension();
|
||||
const Convenience = Extension.imports.convenience;
|
||||
const Draw = Extension.imports.draw;
|
||||
const _ = imports.gettext.domain(Extension.metadata["gettext-domain"]).gettext;
|
||||
|
||||
let manager;
|
||||
|
||||
function init() {
|
||||
Convenience.initTranslations();
|
||||
}
|
||||
|
||||
function enable() {
|
||||
manager = new AreaManager();
|
||||
}
|
||||
|
||||
function disable() {
|
||||
manager.disable();
|
||||
manager = null;
|
||||
}
|
||||
|
||||
// AreaManager assigns one DrawingArea per monitor (updateAreas()),
|
||||
// distributes keybinding callbacks to the active area
|
||||
// and handles stylesheet and monitor changes.
|
||||
var AreaManager = new Lang.Class({
|
||||
Name: 'AreaManager',
|
||||
|
||||
_init: function() {
|
||||
this.areas = [];
|
||||
this.drawingHandlers = [];
|
||||
this.activeArea = null;
|
||||
this.enterGicon = new Gio.ThemedIcon({ name: 'applications-graphics-symbolic' });
|
||||
this.leaveGicon = new Gio.ThemedIcon({ name: 'application-exit-symbolic' });
|
||||
|
||||
Main.wm.addKeybinding('toggle-drawing',
|
||||
Convenience.getSettings(),
|
||||
Meta.KeyBindingFlags.NONE,
|
||||
Shell.ActionMode.ALL,
|
||||
this.toggleDrawing.bind(this));
|
||||
|
||||
Main.wm.addKeybinding('erase-drawing',
|
||||
Convenience.getSettings(),
|
||||
Meta.KeyBindingFlags.NONE,
|
||||
Shell.ActionMode.ALL,
|
||||
this.eraseDrawing.bind(this));
|
||||
|
||||
this.updateAreas();
|
||||
this.monitorChangedHandler = Main.layoutManager.connect('monitors-changed', this.updateAreas.bind(this));
|
||||
|
||||
if (Extension.stylesheet) {
|
||||
this.stylesheetMonitor = Extension.stylesheet.monitor(Gio.FileMonitorFlags.NONE, null);
|
||||
this.stylesheetChangedHandler = this.stylesheetMonitor.connect('changed', (monitor, file, otherFile, eventType) => {
|
||||
if ((eventType != 0 && eventType != 3) || !Extension.stylesheet.query_exists(null))
|
||||
return;
|
||||
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
|
||||
theme.unload_stylesheet(Extension.stylesheet);
|
||||
theme.load_stylesheet(Extension.stylesheet);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
updateAreas: function() {
|
||||
if (this.activeArea)
|
||||
this.toggleDrawing();
|
||||
this.removeAreas();
|
||||
|
||||
this.monitors = Main.layoutManager.monitors;
|
||||
|
||||
for (let i = 0; i < this.monitors.length; i++) {
|
||||
let monitor = this.monitors[i];
|
||||
let helper = new Draw.DrawingHelper({ name: 'drawOnYourSreenHelper' + i }, monitor);
|
||||
let bgContainer = new St.Bin({ name: 'drawOnYourSreenContainer' + i });
|
||||
let area = new Draw.DrawingArea({ name: 'drawOnYourSreenArea' + i }, helper);
|
||||
bgContainer.set_child(area);
|
||||
Main.uiGroup.add_actor(bgContainer);
|
||||
Main.uiGroup.add_actor(helper);
|
||||
bgContainer.set_position(monitor.x, monitor.y);
|
||||
bgContainer.set_size(monitor.width, monitor.height);
|
||||
area.set_position(monitor.x, monitor.y);
|
||||
area.set_size(monitor.width, monitor.height);
|
||||
this.drawingHandlers.push(area.emitter.connect('stop-drawing', this.toggleDrawing.bind(this)));
|
||||
this.drawingHandlers.push(area.emitter.connect('show-osd', this.showOsd.bind(this)));
|
||||
this.areas.push(area);
|
||||
}
|
||||
},
|
||||
|
||||
addInternalKeybindings: function() {
|
||||
this.internalKeybindings = {
|
||||
'undo': this.activeArea.undo.bind(this.activeArea),
|
||||
'redo': this.activeArea.redo.bind(this.activeArea),
|
||||
'delete-last-element': this.activeArea.deleteLastElement.bind(this.activeArea),
|
||||
'save-as-svg': this.activeArea.save.bind(this.activeArea),
|
||||
'toggle-background': this.activeArea.toggleBackground.bind(this.activeArea),
|
||||
'increment-line-width': () => this.activeArea.incrementLineWidth(1),
|
||||
'decrement-line-width': () => this.activeArea.incrementLineWidth(-1),
|
||||
'increment-line-width-more': () => this.activeArea.incrementLineWidth(5),
|
||||
'decrement-line-width-more': () => this.activeArea.incrementLineWidth(-5),
|
||||
'toggle-linejoin': this.activeArea.toggleLineJoin.bind(this.activeArea),
|
||||
'toggle-linecap': this.activeArea.toggleLineCap.bind(this.activeArea),
|
||||
'toggle-dash' : this.activeArea.toggleDash.bind(this.activeArea),
|
||||
'select-none-shape': () => this.activeArea.selectShape(Draw.Shapes.NONE),
|
||||
'select-line-shape': () => this.activeArea.selectShape(Draw.Shapes.LINE),
|
||||
'select-ellipse-shape': () => this.activeArea.selectShape(Draw.Shapes.ELLIPSE),
|
||||
'select-rectangle-shape': () => this.activeArea.selectShape(Draw.Shapes.RECTANGLE),
|
||||
'select-text-shape': () => this.activeArea.selectShape(Draw.Shapes.TEXT),
|
||||
'toggle-font-family': this.activeArea.toggleFontFamily.bind(this.activeArea),
|
||||
'toggle-font-weight': this.activeArea.toggleFontWeight.bind(this.activeArea),
|
||||
'toggle-font-style': this.activeArea.toggleFontStyle.bind(this.activeArea),
|
||||
'toggle-panel-and-dock-visibility': this.togglePanelAndDockOpacity.bind(this),
|
||||
'toggle-help': this.activeArea.toggleHelp.bind(this.activeArea),
|
||||
'open-stylesheet': this.openStylesheetFile.bind(this)
|
||||
};
|
||||
|
||||
for (let key in this.internalKeybindings) {
|
||||
Main.wm.addKeybinding(key,
|
||||
Convenience.getSettings(),
|
||||
Meta.KeyBindingFlags.NONE,
|
||||
256,
|
||||
this.internalKeybindings[key]);
|
||||
}
|
||||
|
||||
for (let i = 1; i < 10; i++) {
|
||||
Main.wm.addKeybinding('select-color' + i,
|
||||
Convenience.getSettings(),
|
||||
Meta.KeyBindingFlags.NONE,
|
||||
256,
|
||||
() => this.activeArea.selectColor(i));
|
||||
}
|
||||
},
|
||||
|
||||
removeInternalKeybindings: function() {
|
||||
for (let key in this.internalKeybindings) {
|
||||
Main.wm.removeKeybinding(key);
|
||||
}
|
||||
|
||||
for (let i = 1; i < 10; i++) {
|
||||
Main.wm.removeKeybinding('select-color' + i);
|
||||
}
|
||||
},
|
||||
|
||||
openStylesheetFile: function() {
|
||||
if (Extension.stylesheet && Extension.stylesheet.query_exists(null))
|
||||
Gio.AppInfo.launch_default_for_uri(Extension.stylesheet.get_uri(), global.create_app_launch_context(0, -1));
|
||||
if (this.activeArea)
|
||||
this.toggleDrawing();
|
||||
},
|
||||
|
||||
eraseDrawing: function() {
|
||||
for (let i = 0; i < this.areas.length; i++) {
|
||||
this.areas[i].erase();
|
||||
}
|
||||
},
|
||||
|
||||
togglePanelAndDockOpacity: function() {
|
||||
if (this.hiddenList) {
|
||||
for (let i = 0; i < this.hiddenList.length; i++) {
|
||||
this.hiddenList[i].actor.set_opacity(this.hiddenList[i].oldOpacity);
|
||||
}
|
||||
this.hiddenList = null;
|
||||
} else {
|
||||
let activeIndex = this.areas.indexOf(this.activeArea);
|
||||
|
||||
// dash-to-dock
|
||||
let dtdContainers = Main.uiGroup.get_children().filter((actor) => {
|
||||
return actor.name && actor.name == 'dashtodockContainer' &&
|
||||
actor._delegate &&
|
||||
actor._delegate._monitorIndex !== undefined &&
|
||||
actor._delegate._monitorIndex == activeIndex;
|
||||
});
|
||||
|
||||
// for simplicity, we assume that main dash-to-panel panel is displayed on primary monitor
|
||||
// and we hide all secondary panels together if the active area is not on the primary
|
||||
let name = activeIndex == Main.layoutManager.primaryIndex ? 'panelBox' : 'dashtopanelSecondaryPanelBox';
|
||||
let panelBoxes = Main.uiGroup.get_children().filter((actor) => {
|
||||
return actor.name && actor.name == name;
|
||||
});
|
||||
|
||||
|
||||
let actorToHide = dtdContainers.concat(panelBoxes);
|
||||
this.hiddenList = [];
|
||||
for (let i = 0; i < actorToHide.length; i++) {
|
||||
this.hiddenList.push({ actor: actorToHide[i], oldOpacity: actorToHide[i].get_opacity() });
|
||||
actorToHide[i].set_opacity(0);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toggleDrawing: function() {
|
||||
if (this.activeArea) {
|
||||
if (this.hiddenList)
|
||||
this.togglePanelAndDockOpacity();
|
||||
Main.popModal(this.activeArea);
|
||||
let activeIndex = this.areas.indexOf(this.activeArea);
|
||||
this.removeInternalKeybindings();
|
||||
this.activeArea.reactive = false;
|
||||
this.activeArea.leaveDrawingMode();
|
||||
this.activeArea = null;
|
||||
global.display.set_cursor(Meta.Cursor.DEFAULT);
|
||||
Main.osdWindowManager.show(activeIndex, this.leaveGicon, _("Leaving drawing mode"), null);
|
||||
} else {
|
||||
// avoid to deal with Meta changes (global.display/global.screen)
|
||||
let currentIndex = Main.layoutManager.monitors.indexOf(Main.layoutManager.currentMonitor);
|
||||
// 256 is a custom Shell.ActionMode
|
||||
if (!Main.pushModal(this.areas[currentIndex], { actionMode: 256 | 1 }))
|
||||
return;
|
||||
this.activeArea = this.areas[currentIndex];
|
||||
this.addInternalKeybindings();
|
||||
this.activeArea.reactive = true;
|
||||
this.activeArea.enterDrawingMode();
|
||||
global.display.set_cursor(Meta.Cursor.POINTING_HAND);
|
||||
// increase OSD display time
|
||||
let hideTimeoutSave = OsdWindow.HIDE_TIMEOUT;
|
||||
OsdWindow.HIDE_TIMEOUT = 2000;
|
||||
Main.osdWindowManager.show(currentIndex, this.enterGicon, _("Press Ctrl + F1 for help") + "\n\n" + _("Entering drawing mode"), null);
|
||||
OsdWindow.HIDE_TIMEOUT = hideTimeoutSave;
|
||||
}
|
||||
},
|
||||
|
||||
showOsd: function(emitter, label, level, maxLevel) {
|
||||
let activeIndex = this.areas.indexOf(this.activeArea);
|
||||
if (activeIndex != -1)
|
||||
Main.osdWindowManager.show(activeIndex, this.enterGicon, label, level, maxLevel);
|
||||
},
|
||||
|
||||
removeAreas: function() {
|
||||
for (let i = 0; i < this.areas.length; i++) {
|
||||
let area = this.areas[i];
|
||||
Main.uiGroup.remove_actor(area.get_parent());
|
||||
area.emitter.disconnect(this.drawingHandlers[i]);
|
||||
area.disable();
|
||||
area.get_parent().destroy();
|
||||
}
|
||||
this.areas = [];
|
||||
this.drawingHandlers = [];
|
||||
},
|
||||
|
||||
disable: function() {
|
||||
if (this.stylesheetChangedHandler) {
|
||||
this.stylesheetMonitor.disconnect(this.stylesheetChangedHandler);
|
||||
this.stylesheetChangedHandler = null;
|
||||
}
|
||||
if (this.activeArea)
|
||||
this.toggleDrawing();
|
||||
Main.wm.removeKeybinding('toggle-drawing');
|
||||
Main.wm.removeKeybinding('erase-drawing');
|
||||
this.removeAreas();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,208 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-03-04 16:40+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: extension.js
|
||||
msgid "Leaving drawing mode"
|
||||
msgstr ""
|
||||
|
||||
msgid "Press Ctrl + F1 for help"
|
||||
msgstr ""
|
||||
|
||||
msgid "Entering drawing mode"
|
||||
msgstr ""
|
||||
|
||||
#: draw.js
|
||||
msgid "Free drawing"
|
||||
msgstr ""
|
||||
|
||||
msgid "Line"
|
||||
msgstr ""
|
||||
|
||||
msgid "Circle"
|
||||
msgstr ""
|
||||
|
||||
msgid "Rectangle"
|
||||
msgstr ""
|
||||
|
||||
msgid "Text"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dashed line"
|
||||
msgstr ""
|
||||
|
||||
msgid "Full line"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"Type your text\n"
|
||||
"and press Enter"
|
||||
msgstr ""
|
||||
|
||||
#: prefs.js
|
||||
msgid "Enter/leave drawing mode"
|
||||
msgstr ""
|
||||
|
||||
msgid "Erase all drawings"
|
||||
msgstr ""
|
||||
|
||||
msgid "Undo last brushstroke"
|
||||
msgstr ""
|
||||
|
||||
msgid "Redo last brushstroke"
|
||||
msgstr ""
|
||||
|
||||
msgid "Erase last brushstroke"
|
||||
msgstr ""
|
||||
|
||||
msgid "Increment line width"
|
||||
msgstr ""
|
||||
|
||||
msgid "Decrement line width"
|
||||
msgstr ""
|
||||
|
||||
msgid "Increment line width even more"
|
||||
msgstr ""
|
||||
|
||||
msgid "Decrement line width even more"
|
||||
msgstr ""
|
||||
|
||||
msgid "Change linejoin"
|
||||
msgstr ""
|
||||
|
||||
msgid "Change linecap"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dashed line"
|
||||
msgstr ""
|
||||
|
||||
msgid "Select line"
|
||||
msgstr ""
|
||||
|
||||
msgid "Select circle"
|
||||
msgstr ""
|
||||
|
||||
msgid "Select rectangle"
|
||||
msgstr ""
|
||||
|
||||
msgid "Select text"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unselect shape (free drawing)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Change font family (generic name)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Change font weight"
|
||||
msgstr ""
|
||||
|
||||
msgid "Change font style"
|
||||
msgstr ""
|
||||
|
||||
msgid "Hide panel and dock"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add a drawing background"
|
||||
msgstr ""
|
||||
|
||||
msgid "Save drawing as a SVG file"
|
||||
msgstr ""
|
||||
|
||||
msgid "Open stylesheet.css"
|
||||
msgstr ""
|
||||
|
||||
msgid "Show help"
|
||||
msgstr ""
|
||||
|
||||
msgid "Draw"
|
||||
msgstr ""
|
||||
|
||||
msgid "Left click"
|
||||
msgstr ""
|
||||
|
||||
msgid "Draw by filling in"
|
||||
msgstr ""
|
||||
|
||||
msgid "Right click"
|
||||
msgstr ""
|
||||
|
||||
msgid "Toggle shape"
|
||||
msgstr ""
|
||||
|
||||
msgid "Center click"
|
||||
msgstr ""
|
||||
|
||||
msgid "Increment/decrement line width"
|
||||
msgstr ""
|
||||
|
||||
msgid "Scroll"
|
||||
msgstr ""
|
||||
|
||||
msgid "Select color"
|
||||
msgstr ""
|
||||
|
||||
msgid "Ctrl+1...9"
|
||||
msgstr ""
|
||||
|
||||
msgid "Select eraser"
|
||||
msgstr ""
|
||||
|
||||
msgid "Shift key held"
|
||||
msgstr ""
|
||||
|
||||
msgid "Leave and erase all drawings"
|
||||
msgstr ""
|
||||
|
||||
msgid "Escape key"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"Start drawing with Super+Alt+D\n"
|
||||
"Then save your beautiful work by taking a screenshot"
|
||||
msgstr ""
|
||||
|
||||
msgid "Global"
|
||||
msgstr ""
|
||||
|
||||
msgid "Internal"
|
||||
msgstr ""
|
||||
|
||||
msgid "(in drawing mode)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Change the style"
|
||||
msgstr ""
|
||||
|
||||
msgid "See stylesheet.css"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"<u>Note</u>: When you save elements made with eraser in a SVG file,\n"
|
||||
"they are colored with background color, transparent if it is disabled.\n"
|
||||
"(See \"Add a drawing background\" or edit the SVG file afterwards)"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"<span size=\"small\">This program comes with ABSOLUTELY NO WARRANTY.\n"
|
||||
"See the <a href=\"https://www.gnu.org/licenses/old-licenses/gpl-2.0.html"
|
||||
"\">GNU General Public License, version 2 or later</a> for details.</span>"
|
||||
msgstr ""
|
||||
|
||||
msgid "Credits"
|
||||
msgstr ""
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"name": "Draw On You Screen",
|
||||
"description": "Start drawing with Super+Alt+D and save your beautiful work by taking a screenshot",
|
||||
"version": 1,
|
||||
"uuid": "drawOnYourScreen@abakkk.framagit.org",
|
||||
"url": "https://framagit.org/abakkk/DrawOnYourScreen",
|
||||
"settings-schema": "org.gnome.shell.extensions.draw-on-your-screen",
|
||||
"gettext-domain": "draw-on-your-screen",
|
||||
"shell-version": [
|
||||
"3.26",
|
||||
"3.28",
|
||||
"3.30"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,333 @@
|
|||
/* jslint esversion: 6 */
|
||||
|
||||
/*
|
||||
* Copyright 2019 Abakkk
|
||||
*
|
||||
* This file is part of DrowOnYourScreen, a drawing extension for GNOME Shell.
|
||||
* https://framagit.org/abakkk/DrawOnYourScreen
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const GObject = imports.gi.GObject;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Lang = imports.lang;
|
||||
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const Extension = ExtensionUtils.getCurrentExtension();
|
||||
const Convenience = Extension.imports.convenience;
|
||||
const Metadata = Extension.metadata;
|
||||
const _ = imports.gettext.domain(Extension.metadata["gettext-domain"]).gettext;
|
||||
|
||||
const MARGIN = 10;
|
||||
|
||||
var GLOBAL_KEYBINDINGS = {
|
||||
'toggle-drawing': "Enter/leave drawing mode",
|
||||
'erase-drawing': "Erase all drawings"
|
||||
};
|
||||
|
||||
var INTERNAL_KEYBINDINGS = {
|
||||
'undo': "Undo last brushstroke",
|
||||
'redo': "Redo last brushstroke",
|
||||
'delete-last-element' : "Erase last brushstroke",
|
||||
'-separator-1': '',
|
||||
'increment-line-width': "Increment line width",
|
||||
'decrement-line-width': "Decrement line width",
|
||||
'increment-line-width-more': "Increment line width even more",
|
||||
'decrement-line-width-more': "Decrement line width even more",
|
||||
'toggle-linejoin': "Change linejoin",
|
||||
'toggle-linecap': "Change linecap",
|
||||
'toggle-dash': "Dashed line",
|
||||
'-separator-2': '',
|
||||
'select-line-shape': "Select line",
|
||||
'select-ellipse-shape': "Select circle",
|
||||
'select-rectangle-shape': "Select rectangle",
|
||||
'select-text-shape': "Select text",
|
||||
'select-none-shape': "Unselect shape (free drawing)",
|
||||
'-separator-3': '',
|
||||
'toggle-font-family': "Change font family (generic name)",
|
||||
'toggle-font-weight': "Change font weight",
|
||||
'toggle-font-style': "Change font style",
|
||||
'-separator-4': '',
|
||||
'toggle-panel-and-dock-visibility': "Hide panel and dock",
|
||||
'toggle-background': "Add a drawing background",
|
||||
'-separator-5': '',
|
||||
'save-as-svg': "Save drawing as a SVG file",
|
||||
'open-stylesheet': "Open stylesheet.css",
|
||||
'toggle-help': "Show help"
|
||||
};
|
||||
|
||||
var OTHER_SHORTCUTS = {
|
||||
"Draw": "Left click",
|
||||
"Draw by filling in": "Right click",
|
||||
"Toggle shape": "Center click",
|
||||
"Increment/decrement line width": "Scroll",
|
||||
"Select color": "Ctrl+1...9",
|
||||
"Select eraser": "Shift key held",
|
||||
"Leave and erase all drawings": "Escape key"
|
||||
};
|
||||
|
||||
function init() {
|
||||
Convenience.initTranslations();
|
||||
}
|
||||
|
||||
function buildPrefsWidget() {
|
||||
let prefsPage = new PrefsPage();
|
||||
prefsPage.show_all();
|
||||
return prefsPage;
|
||||
}
|
||||
|
||||
const PrefsPage = new GObject.Class({
|
||||
Name: 'PrefsPage',
|
||||
GTypeName: 'PrefsPage',
|
||||
Extends: Gtk.ScrolledWindow,
|
||||
|
||||
_init: function(params) {
|
||||
this.parent();
|
||||
|
||||
this.settings = Convenience.getSettings();
|
||||
|
||||
let box = new Gtk.Box({orientation: Gtk.Orientation.VERTICAL, margin: MARGIN*3 });
|
||||
this.add(box);
|
||||
|
||||
let textBox1 = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, margin: MARGIN });
|
||||
let text1 = new Gtk.Label({ wrap: true, justify: 2, use_markup: true,
|
||||
label: _("Start drawing with Super+Alt+D\nThen save your beautiful work by taking a screenshot") });
|
||||
textBox1.pack_start(text1, false, false, 0);
|
||||
box.add(textBox1);
|
||||
|
||||
let listBox = new Gtk.ListBox({ selection_mode: 0, hexpand: true, margin_top: 2*MARGIN, margin_bottom: 2*MARGIN });
|
||||
box.add(listBox);
|
||||
|
||||
let styleContext = listBox.get_style_context();
|
||||
styleContext.add_class('background');
|
||||
|
||||
let globalTitleBox = new Gtk.Box({ margin: MARGIN });
|
||||
let globalTitleLabel = new Gtk.Label({ use_markup: true, label: "<b><big>" + _("Global") + " :</big></b>" });
|
||||
globalTitleLabel.set_halign(1);
|
||||
globalTitleBox.pack_start(globalTitleLabel, true, true, 4);
|
||||
listBox.add(globalTitleBox);
|
||||
|
||||
let globalKeybindingsWidget = new KeybindingsWidget(GLOBAL_KEYBINDINGS, this.settings);
|
||||
globalKeybindingsWidget.margin = MARGIN;
|
||||
listBox.add(globalKeybindingsWidget);
|
||||
this.addSeparator(listBox);
|
||||
|
||||
let internalTitleBox = new Gtk.Box({ margin: MARGIN });
|
||||
let internalTitleLabel = new Gtk.Label({ use_markup: true, label: "<b><big>" + _("Internal") + " </big></b>" + _("(in drawing mode)") + " <b><big>:</big></b>" });
|
||||
internalTitleLabel.set_halign(1);
|
||||
internalTitleBox.pack_start(internalTitleLabel, true, true, 4);
|
||||
listBox.add(internalTitleBox);
|
||||
|
||||
listBox.add(new Gtk.Box({ margin_top: MARGIN/2, margin_left: MARGIN, margin_right: MARGIN }));
|
||||
|
||||
for (let desc in OTHER_SHORTCUTS) {
|
||||
if (desc.indexOf('-separator-') != -1) {
|
||||
listBox.add(new Gtk.Box({ margin_top: MARGIN, margin_left: MARGIN, margin_right: MARGIN }));
|
||||
continue;
|
||||
}
|
||||
let otherBox = new Gtk.Box({ margin_left: MARGIN, margin_right: MARGIN });
|
||||
let otherLabel = new Gtk.Label({ label: _(desc) });
|
||||
otherLabel.set_halign(1);
|
||||
let otherLabel2 = new Gtk.Label({ label: _(OTHER_SHORTCUTS[desc]) });
|
||||
otherBox.pack_start(otherLabel, true, true, 4);
|
||||
otherBox.pack_start(otherLabel2, false, false, 4);
|
||||
listBox.add(otherBox);
|
||||
}
|
||||
|
||||
listBox.add(new Gtk.Box({ margin_top: MARGIN, margin_left: MARGIN, margin_right: MARGIN }));
|
||||
|
||||
let internalKeybindingsWidget = new KeybindingsWidget(INTERNAL_KEYBINDINGS, this.settings);
|
||||
internalKeybindingsWidget.margin = MARGIN;
|
||||
listBox.add(internalKeybindingsWidget);
|
||||
|
||||
let styleBox = new Gtk.Box({ margin_top: MARGIN, margin_left: MARGIN, margin_right: MARGIN, margin_bottom:MARGIN });
|
||||
let styleLabel = new Gtk.Label({ label: _("Change the style") });
|
||||
styleLabel.set_halign(1);
|
||||
let styleLabel2 = new Gtk.Label({ label: _("See stylesheet.css") });
|
||||
styleBox.pack_start(styleLabel, true, true, 4);
|
||||
styleBox.pack_start(styleLabel2, false, false, 4);
|
||||
listBox.add(styleBox);
|
||||
|
||||
let noteBox = new Gtk.Box({ margin_top: MARGIN, margin_left: MARGIN, margin_right: MARGIN, margin_bottom:MARGIN });
|
||||
let noteLabel = new Gtk.Label({
|
||||
use_markup: true,
|
||||
label: _("<u>Note</u>: When you save elements made with eraser in a SVG file,\nthey are colored with background color, transparent if it is disabled.\n(See \"Add a drawing background\" or edit the SVG file afterwards)")
|
||||
});
|
||||
noteLabel.set_halign(1);
|
||||
//let noteLabel2 = new Gtk.Label({ label: _("See notesheet.css") });
|
||||
noteBox.pack_start(noteLabel, true, true, 4);
|
||||
//noteBox.pack_start(noteLabel2, false, false, 4);
|
||||
listBox.add(noteBox);
|
||||
|
||||
this.addSeparator(listBox);
|
||||
|
||||
let licence = _("<span size=\"small\">This program comes with ABSOLUTELY NO WARRANTY.\nSee the <a href=\"https://www.gnu.org/licenses/old-licenses/gpl-2.0.html\">GNU General Public License, version 2 or later</a> for details.</span>");
|
||||
|
||||
let textBox2 = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
|
||||
let text2 = new Gtk.Label({ wrap: true, justify: 2, use_markup: true,
|
||||
label: "<small>Version" + " " + Metadata.version +"</small>\n\n" + "<span><a href=\"" + Metadata.url + "\">" + Metadata.url + "</a></span>" + "\n\n" + licence + "\n" });
|
||||
textBox2.pack_start(text2, false, false, 0);
|
||||
|
||||
let creditBox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL });
|
||||
let leftBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
|
||||
let rightBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
|
||||
let leftLabel = new Gtk.Label({ wrap: true, valign: 1, halign: 2, justify: 1, use_markup: true, label: "<small><u>" + _("Credits") + ":</u></small>" });
|
||||
let rightLabel = new Gtk.Label({ wrap: true, valign: 1, halign: 1, justify: 0, use_markup: true, label: "<small>Abakkk</small>" });
|
||||
leftBox.pack_start(leftLabel, true, true, 0);
|
||||
rightBox.pack_start(rightLabel, true, true, 0);
|
||||
creditBox.pack_start(leftBox, true, true, 5);
|
||||
creditBox.pack_start(rightBox, true, true, 5);
|
||||
textBox2.pack_start(creditBox, false, false, 0);
|
||||
|
||||
box.add(textBox2);
|
||||
|
||||
let children = listBox.get_children();
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
if (children[i].activatable)
|
||||
children[i].set_activatable(false);
|
||||
}
|
||||
},
|
||||
|
||||
addSeparator: function(container) {
|
||||
let separatorRow = new Gtk.ListBoxRow({sensitive: false});
|
||||
separatorRow.add(new Gtk.Separator({ margin: MARGIN }));
|
||||
container.add(separatorRow);
|
||||
}
|
||||
});
|
||||
|
||||
// this code comes from Sticky Notes View by Sam Bull, https://extensions.gnome.org/extension/568/notes/
|
||||
const KeybindingsWidget = new GObject.Class({
|
||||
Name: 'Keybindings.Widget',
|
||||
GTypeName: 'KeybindingsWidget',
|
||||
Extends: Gtk.Box,
|
||||
|
||||
_init: function(keybindings, settings) {
|
||||
this.parent();
|
||||
this.set_orientation(Gtk.Orientation.VERTICAL);
|
||||
|
||||
this._keybindings = keybindings;
|
||||
this._settings = settings;
|
||||
|
||||
this._columns = {
|
||||
NAME: 0,
|
||||
ACCEL_NAME: 1,
|
||||
MODS: 2,
|
||||
KEY: 3
|
||||
};
|
||||
|
||||
this._store = new Gtk.ListStore();
|
||||
this._store.set_column_types([
|
||||
GObject.TYPE_STRING,
|
||||
GObject.TYPE_STRING,
|
||||
GObject.TYPE_INT,
|
||||
GObject.TYPE_INT
|
||||
]);
|
||||
|
||||
this._tree_view = new Gtk.TreeView({
|
||||
model: this._store,
|
||||
hexpand: false,
|
||||
vexpand: false
|
||||
});
|
||||
this._tree_view.set_activate_on_single_click(false);
|
||||
this._tree_view.get_selection().set_mode(Gtk.SelectionMode.SINGLE);
|
||||
|
||||
let action_renderer = new Gtk.CellRendererText();
|
||||
let action_column = new Gtk.TreeViewColumn({
|
||||
title: "",
|
||||
expand: true,
|
||||
});
|
||||
action_column.pack_start(action_renderer, true);
|
||||
action_column.add_attribute(action_renderer, 'text', 1);
|
||||
this._tree_view.append_column(action_column);
|
||||
|
||||
let keybinding_renderer = new Gtk.CellRendererAccel({
|
||||
editable: true,
|
||||
accel_mode: Gtk.CellRendererAccelMode.GTK,
|
||||
xalign: 1
|
||||
});
|
||||
keybinding_renderer.connect('accel-edited',
|
||||
Lang.bind(this, function(renderer, iter, key, mods) {
|
||||
let value = Gtk.accelerator_name(key, mods);
|
||||
let [success, iterator ] =
|
||||
this._store.get_iter_from_string(iter);
|
||||
|
||||
if(!success) {
|
||||
printerr("Can't change keybinding");
|
||||
}
|
||||
|
||||
let name = this._store.get_value(iterator, 0);
|
||||
|
||||
this._store.set(
|
||||
iterator,
|
||||
[this._columns.MODS, this._columns.KEY],
|
||||
[mods, key]
|
||||
);
|
||||
this._settings.set_strv(name, [value]);
|
||||
})
|
||||
);
|
||||
|
||||
let keybinding_column = new Gtk.TreeViewColumn({
|
||||
title: "",
|
||||
});
|
||||
keybinding_column.pack_end(keybinding_renderer, false);
|
||||
keybinding_column.add_attribute(
|
||||
keybinding_renderer,
|
||||
'accel-mods',
|
||||
this._columns.MODS
|
||||
);
|
||||
keybinding_column.add_attribute(
|
||||
keybinding_renderer,
|
||||
'accel-key',
|
||||
this._columns.KEY
|
||||
);
|
||||
this._tree_view.append_column(keybinding_column);
|
||||
this._tree_view.columns_autosize();
|
||||
this._tree_view.set_headers_visible(false);
|
||||
|
||||
this.add(this._tree_view);
|
||||
this.keybinding_column = keybinding_column;
|
||||
this.action_column = action_column;
|
||||
|
||||
this._refresh();
|
||||
},
|
||||
|
||||
_refresh: function() {
|
||||
this._store.clear();
|
||||
|
||||
for(let settings_key in this._keybindings) {
|
||||
if (settings_key.indexOf('-separator-') != -1)
|
||||
continue;
|
||||
let [key, mods] = Gtk.accelerator_parse(
|
||||
this._settings.get_strv(settings_key)[0]
|
||||
);
|
||||
|
||||
let iter = this._store.append();
|
||||
this._store.set(iter,
|
||||
[
|
||||
this._columns.NAME,
|
||||
this._columns.ACCEL_NAME,
|
||||
this._columns.MODS,
|
||||
this._columns.KEY
|
||||
],
|
||||
[
|
||||
settings_key,
|
||||
_(this._keybindings[settings_key]),
|
||||
mods,
|
||||
key
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
Binary file not shown.
|
|
@ -0,0 +1,175 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<schemalist gettext-domain="gnome-shell-extensions">
|
||||
<schema path="/org/gnome/shell/extensions/draw-on-your-screen/" id="org.gnome.shell.extensions.draw-on-your-screen">
|
||||
<key type="as" name="toggle-drawing">
|
||||
<default>["<Alt><Super>d"]</default>
|
||||
<summary>toggle drawing</summary>
|
||||
<description>enter or leave drawing mode</description>
|
||||
</key>
|
||||
<key type="as" name="erase-drawing">
|
||||
<default>["<Alt><Super>e"]</default>
|
||||
<summary>erase drawing</summary>
|
||||
<description>erase drawing</description>
|
||||
</key>
|
||||
<key type="as" name="undo">
|
||||
<default>["<Primary>z"]</default>
|
||||
<summary>undo</summary>
|
||||
<description>undo</description>
|
||||
</key>
|
||||
<key type="as" name="redo">
|
||||
<default>["<Primary><Shift>z"]</default>
|
||||
<summary>redo</summary>
|
||||
<description>redo</description>
|
||||
</key>
|
||||
<key type="as" name="delete-last-element">
|
||||
<default>["Delete"]</default>
|
||||
<summary>delete last element</summary>
|
||||
<description>delete last element</description>
|
||||
</key>
|
||||
<key type="as" name="toggle-background">
|
||||
<default>["<Primary>b"]</default>
|
||||
<summary>toggle background</summary>
|
||||
<description>toggle background</description>
|
||||
</key>
|
||||
<key type="as" name="toggle-panel-and-dock-visibility">
|
||||
<default>["<Primary>h"]</default>
|
||||
<summary>hide or show panel and dock</summary>
|
||||
<description>hide or show panel and dock</description>
|
||||
</key>
|
||||
<key type="as" name="select-ellipse-shape">
|
||||
<default>["<Primary>e"]</default>
|
||||
<summary>select cercle</summary>
|
||||
<description>select a cercle</description>
|
||||
</key>
|
||||
<key type="as" name="select-rectangle-shape">
|
||||
<default>["<Primary>r"]</default>
|
||||
<summary>select rectangle</summary>
|
||||
<description>select rectangle</description>
|
||||
</key>
|
||||
<key type="as" name="select-line-shape">
|
||||
<default>["<Primary>l"]</default>
|
||||
<summary>select line</summary>
|
||||
<description>select a line</description>
|
||||
</key>
|
||||
<key type="as" name="select-text-shape">
|
||||
<default>["<Primary>t"]</default>
|
||||
<summary>select text</summary>
|
||||
<description>select text</description>
|
||||
</key>
|
||||
<key type="as" name="select-none-shape">
|
||||
<default>["<Primary>u"]</default>
|
||||
<summary>unselect shape (free drawing)</summary>
|
||||
<description>unselect shape (free drawing)</description>
|
||||
</key>
|
||||
<key type="as" name="increment-line-width">
|
||||
<default>["<Primary>KP_Add"]</default>
|
||||
<summary>increment the line width</summary>
|
||||
<description>increment the line width</description>
|
||||
</key>
|
||||
<key type="as" name="decrement-line-width">
|
||||
<default>["<Primary>KP_Subtract"]</default>
|
||||
<summary>decrement the line width</summary>
|
||||
<description>decrement the line width</description>
|
||||
</key>
|
||||
<key type="as" name="increment-line-width-more">
|
||||
<default>["<Primary>Page_Up"]</default>
|
||||
<summary>increment the line width even more</summary>
|
||||
<description>increment the line width even more</description>
|
||||
</key>
|
||||
<key type="as" name="decrement-line-width-more">
|
||||
<default>["<Primary>Page_Down"]</default>
|
||||
<summary>decrement the line width even more</summary>
|
||||
<description>decrement the line width even more</description>
|
||||
</key>
|
||||
<key type="as" name="toggle-linejoin">
|
||||
<default>["<Primary>j"]</default>
|
||||
<summary>toggle linejoin</summary>
|
||||
<description>toggle linejoin</description>
|
||||
</key>
|
||||
<key type="as" name="toggle-linecap">
|
||||
<default>["<Primary>k"]</default>
|
||||
<summary>toggle linecap</summary>
|
||||
<description>toggle linecap</description>
|
||||
</key>
|
||||
<key type="as" name="toggle-dash">
|
||||
<default>["<Primary>a"]</default>
|
||||
<summary>toggle dash</summary>
|
||||
<description>toggle dash</description>
|
||||
</key>
|
||||
<key type="as" name="select-color1">
|
||||
<default><![CDATA[['<Primary>KP_1','<Primary>1']]]></default>
|
||||
<summary>select color1</summary>
|
||||
<description>select color1</description>
|
||||
</key>
|
||||
<key type="as" name="select-color2">
|
||||
<default><![CDATA[['<Primary>KP_2','<Primary>2']]]></default>
|
||||
<summary>select color2</summary>
|
||||
<description>select color2</description>
|
||||
</key>
|
||||
<key type="as" name="select-color3">
|
||||
<default><![CDATA[['<Primary>KP_3','<Primary>3']]]></default>
|
||||
<summary>select color3</summary>
|
||||
<description>select color3</description>
|
||||
</key>
|
||||
<key type="as" name="select-color4">
|
||||
<default><![CDATA[['<Primary>KP_4','<Primary>4']]]></default>
|
||||
<summary>select color4</summary>
|
||||
<description>select color4</description>
|
||||
</key>
|
||||
<key type="as" name="select-color5">
|
||||
<default><![CDATA[['<Primary>KP_5','<Primary>5']]]></default>
|
||||
<summary>select color5</summary>
|
||||
<description>select color5</description>
|
||||
</key>
|
||||
<key type="as" name="select-color6">
|
||||
<default><![CDATA[['<Primary>KP_6','<Primary>6']]]></default>
|
||||
<summary>select color6</summary>
|
||||
<description>select color6</description>
|
||||
</key>
|
||||
<key type="as" name="select-color7">
|
||||
<default><![CDATA[['<Primary>KP_7','<Primary>7']]]></default>
|
||||
<summary>select color7</summary>
|
||||
<description>select color7</description>
|
||||
</key>
|
||||
<key type="as" name="select-color8">
|
||||
<default><![CDATA[['<Primary>KP_8','<Primary>8']]]></default>
|
||||
<summary>select color8</summary>
|
||||
<description>select color8</description>
|
||||
</key>
|
||||
<key type="as" name="select-color9">
|
||||
<default><![CDATA[['<Primary>KP_9','<Primary>9']]]></default>
|
||||
<summary>select color9</summary>
|
||||
<description>select color9</description>
|
||||
</key>
|
||||
<key type="as" name="toggle-font-family">
|
||||
<default>["<Primary>f"]</default>
|
||||
<summary>toggle font family</summary>
|
||||
<description>toggle font family</description>
|
||||
</key>
|
||||
<key type="as" name="toggle-font-weight">
|
||||
<default>["<Primary>w"]</default>
|
||||
<summary>toggle font weight</summary>
|
||||
<description>toggle font weight</description>
|
||||
</key>
|
||||
<key type="as" name="toggle-font-style">
|
||||
<default>["<Primary>i"]</default>
|
||||
<summary>toggle font style</summary>
|
||||
<description>toggle font style</description>
|
||||
</key>
|
||||
<key type="as" name="open-stylesheet">
|
||||
<default>["<Primary>o"]</default>
|
||||
<summary>open stylesheet</summary>
|
||||
<description>open stylesheet</description>
|
||||
</key>
|
||||
<key type="as" name="save-as-svg">
|
||||
<default>["<Primary>s"]</default>
|
||||
<summary>Save drawing as a svg file</summary>
|
||||
<description>Save drawing as a svg file</description>
|
||||
</key>
|
||||
<key type="as" name="toggle-help">
|
||||
<default>["<Primary>F1"]</default>
|
||||
<summary>toggle help</summary>
|
||||
<description>toggle help</description>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Except for the font,
|
||||
* you don't need to restart the extension.
|
||||
* Just save this file and the changes will be applied for your next brushstroke.
|
||||
*
|
||||
* line-join (no string):
|
||||
* 0 : miter, 1 : round, 2 : bevel
|
||||
* line-cap (no string):
|
||||
* 0 : butt, 1 : round, 2 : square
|
||||
*
|
||||
* dash:
|
||||
* dash-array-on is the length of dashes (no dashes if 0, you can put 0.1 to get dots or square according to line-cap)
|
||||
* dash-array-off is the length of gaps (no dashes if 0)
|
||||
*
|
||||
* font:
|
||||
* only one family : no comma separated list of families like "font1, font2, ..., Sans-Serif"
|
||||
* font family can be any font installed, or a generic family name (Serif, Sans-Serif, Monospace, Cursive, Fantasy)
|
||||
* font weight and font style : no upper case when string
|
||||
* weight <= 500 (or lighter, normal, medium) is rendered as normal
|
||||
* weight > 500 (or bolder, bold) is rendered as bold
|
||||
* oblique and italic style support depends on the font family and seem to be rendered identically
|
||||
*
|
||||
*/
|
||||
|
||||
.draw-on-your-screen {
|
||||
-drawing-line-width: 5px;
|
||||
-drawing-line-join: 1;
|
||||
-drawing-line-cap: 1;
|
||||
-drawing-dash-array-on: 5px;
|
||||
-drawing-dash-array-off: 15px;
|
||||
-drawing-dash-offset: 0px;
|
||||
-drawing-color1: HotPink;
|
||||
-drawing-color2: Cyan;
|
||||
-drawing-color3: yellow;
|
||||
-drawing-color4: Orangered;
|
||||
-drawing-color5: Chartreuse;
|
||||
-drawing-color6: DarkViolet;
|
||||
-drawing-color7: #ffffff;
|
||||
-drawing-color8: rgba(130, 130, 130, 0.3);
|
||||
-drawing-color9: rgb(0, 0, 0);
|
||||
-drawing-background-color: #2e3436; /* GS osd_bg_color: #2e3436, GTK Adwaita-dark theme_base_color: #2d2c2e */
|
||||
font-family: Cantarell;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
|
||||
/*
|
||||
* The following styles don't affect the drawing,
|
||||
* but the "Ctrl + F1" on-screen-display
|
||||
*
|
||||
*/
|
||||
|
||||
.draw-on-your-screen-helper {
|
||||
margin: 0;
|
||||
spacing: 0.5em;
|
||||
}
|
||||
|
||||
.draw-on-your-screen-helper StBoxLayout {
|
||||
spacing: 5em;
|
||||
}
|
||||
|
||||
.draw-on-your-screen-helper StBoxLayout StLabel {
|
||||
text-align: right;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.draw-on-your-screen-separator {
|
||||
min-height: 0.6em;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue