Merge branch 'dev' into 'master'

v5.1

Closes #20 and #22

See merge request abakkk/DrawOnYourScreen!8
This commit is contained in:
abakkk 2020-03-06 16:30:22 +01:00
commit 9e92996cc0
19 changed files with 1186 additions and 337 deletions

51
NEWS Normal file
View File

@ -0,0 +1,51 @@
v5.1 - March 2020
=================
* Add "Open" and "Save drawing"
* Change some keyboard shortcuts
* Replace "smoothed stroke" preference with `Ctrl` key modifier
* Add `space` key modifier to ignore pointer movement #20
* User style is now stored in user data directory (`user.css`)
* Customizable square area size #22
v5 - December 2019
==================
* Improve pointer cursor
* Add 3.24 version as supported
* Use maxLevel in line-width OSD
* Small fix with text shape that displayed keybindings
v4.1 - October 2019
===================
* GS 3.34 compatibility
* Create drawing menu on demand
* Allow 0 px line width because stroke lines cannot have color with some transparency
v4 - April 2019
===============
* Add drawing menu
* Add panel indicator
* Prefs to disable indicator and notifications
* Change middle click action
v3 - March 2019
===============
* Fix area container integration #1
* Add persistence
v2 - March 2019
===============
* Add transformations
* Add square area
v1 - March 2019
===============
* Initial release

View File

@ -1,12 +1,11 @@
__Draw On Your Screen__
=======================
# Draw On Your Screen
Start drawing with Super+Alt+D.
Then save your beautiful work by taking a screenshot.
![](https://framagit.org/abakkk/DrawOnYourScreen/raw/ressources/screenshot.jpg)
Features :
----------
## Features
* Basic shapes (rectangle, circle, ellipse, line, curve, text, free)
* Smooth stroke
@ -15,13 +14,26 @@ Features :
* Multi-monitor support
* Export to SVG
Install :
----------
## Install
1. Download and decompress or clone the repository
2. Place the resulting directory in ~/.local/share/gnome-shell/extensions
3. IMPORTANT: change the directory name to drawOnYourScreen@abakkk.framagit.org
4. A small shot of `alt + F2` `r` to restart Gnome-shell under Xorg, restart or relogin under Wayland
5. Enable the extension in Gnome-tweak-tool
2. Place the resulting directory in `~/.local/share/gnome-shell/extensions`
3. **Change the directory name** to `drawOnYourScreen@abakkk.framagit.org`
4. Xorg: type `alt + F2` and `r` to restart gnome-shell
Wayland: restart or re-login
5. Enable the extension in gnome-tweaks
6. `Super + Alt + D` to test
7. [https://framagit.org/abakkk/DrawOnYourScreen/issues](https://framagit.org/abakkk/DrawOnYourScreen/issues) to say it doesn't work
## Details
* Draw arrows:
Intersect two lines and curve the second thanks to the `Ctrl` key.
![How to draw an arrow](https://framagit.org/abakkk/DrawOnYourScreen/uploads/af8f96d33cfeff49bb922a1ef9f4a4ce/arrow-screencast.webm)
* Screenshot Tool extension:
[Screenshot Tool](https://extensions.gnome.org/extension/1112/screenshot-tool/) is a convenient extension to “create, copy, store and upload screenshots”. To use it while drawing mode is active, toggle the area selection mode thanks to the Screenshot Tool shortcut (`Super + F11` by default, see its preferences) and **hold** the `space` key when selecting the area with pointer to avoid drawing.

54
data/default.css Normal file
View File

@ -0,0 +1,54 @@
/*
* Except for the font, you don't need to restart the extension.
* Just save this file as ~/.local/share/drawOnYourScreen/user.css and the changes will be applied for your next brushstroke.
*
* ~/.local/share/drawOnYourScreen/user.css file is automatically generated by activating "Edit style".
* Delete ~/.local/share/drawOnYourScreen/user.css file to retrieve default drawing style.
*
* 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).
*
* square area:
* Drawing in a square area is convenient when using the extension as a vector graphics editor. By default,
* when toggling 'Square drawing area', the area is sized to 75% of monitor size. You can fix and customize this size
* by uncommenting square-area-width and square-area-height lines.
*
* 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 supports depend 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;
/*-drawing-square-area-width: 512px;*/
/*-drawing-square-area-height: 512px;*/
font-family: Cantarell;
font-weight: normal;
font-style: normal;
}

View File

Before

Width:  |  Height:  |  Size: 321 B

After

Width:  |  Height:  |  Size: 321 B

View File

Before

Width:  |  Height:  |  Size: 196 B

After

Width:  |  Height:  |  Size: 196 B

View File

Before

Width:  |  Height:  |  Size: 153 B

After

Width:  |  Height:  |  Size: 153 B

View File

Before

Width:  |  Height:  |  Size: 235 B

After

Width:  |  Height:  |  Size: 235 B

View File

Before

Width:  |  Height:  |  Size: 174 B

After

Width:  |  Height:  |  Size: 174 B

View File

Before

Width:  |  Height:  |  Size: 691 B

After

Width:  |  Height:  |  Size: 691 B

594
draw.js
View File

@ -3,7 +3,7 @@
/*
* Copyright 2019 Abakkk
*
* This file is part of DrowOnYourScreen, a drawing extension for GNOME Shell.
* This file is part of DrawOnYourScreen, a drawing extension for GNOME Shell.
* https://framagit.org/abakkk/DrawOnYourScreen
*
* This program is free software: you can redistribute it and/or modify
@ -20,6 +20,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
const ByteArray = imports.byteArray;
const Cairo = imports.cairo;
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
@ -40,29 +41,66 @@ 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 ExtensionJs = Extension.imports.extension;
const Prefs = Extension.imports.prefs;
const _ = imports.gettext.domain(Extension.metadata["gettext-domain"]).gettext;
const Me = ExtensionUtils.getCurrentExtension();
const Convenience = ExtensionUtils.getSettings ? ExtensionUtils : Me.imports.convenience;
const Extension = Me.imports.extension;
const Prefs = Me.imports.prefs;
const _ = imports.gettext.domain(Me.metadata['gettext-domain']).gettext;
const GS_VERSION = Config.PACKAGE_VERSION;
const FILL_ICON_PATH = Extension.dir.get_child('icons').get_child('fill-symbolic.svg').get_path();
const STROKE_ICON_PATH = Extension.dir.get_child('icons').get_child('stroke-symbolic.svg').get_path();
const LINEJOIN_ICON_PATH = Extension.dir.get_child('icons').get_child('linejoin-symbolic.svg').get_path();
const LINECAP_ICON_PATH = Extension.dir.get_child('icons').get_child('linecap-symbolic.svg').get_path();
const DASHED_LINE_ICON_PATH = Extension.dir.get_child('icons').get_child('dashed-line-symbolic.svg').get_path();
const FULL_LINE_ICON_PATH = Extension.dir.get_child('icons').get_child('full-line-symbolic.svg').get_path();
const FILL_ICON_PATH = Me.dir.get_child('data').get_child('icons').get_child('fill-symbolic.svg').get_path();
const STROKE_ICON_PATH = Me.dir.get_child('data').get_child('icons').get_child('stroke-symbolic.svg').get_path();
const LINEJOIN_ICON_PATH = Me.dir.get_child('data').get_child('icons').get_child('linejoin-symbolic.svg').get_path();
const LINECAP_ICON_PATH = Me.dir.get_child('data').get_child('icons').get_child('linecap-symbolic.svg').get_path();
const DASHED_LINE_ICON_PATH = Me.dir.get_child('data').get_child('icons').get_child('dashed-line-symbolic.svg').get_path();
const FULL_LINE_ICON_PATH = Me.dir.get_child('data').get_child('icons').get_child('full-line-symbolic.svg').get_path();
var Shapes = { NONE: 0, LINE: 1, ELLIPSE: 2, RECTANGLE: 3, TEXT: 4 };
var TextState = { DRAWING: 0, WRITING: 1 };
var ShapeNames = { 0: "Free drawing", 1: "Line", 2: "Ellipse", 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' };
const TextState = { DRAWING: 0, WRITING: 1 };
const ShapeNames = { 0: "Free drawing", 1: "Line", 2: "Ellipse", 3: "Rectangle", 4: "Text" };
const LineCapNames = { 0: 'Butt', 1: 'Round', 2: 'Square' };
const LineJoinNames = { 0: 'Miter', 1: 'Round', 2: 'Bevel' };
const FontWeightNames = { 0: 'Normal', 1: 'Bold' };
const FontStyleNames = { 0: 'Normal', 1: 'Italic', 2: 'Oblique' };
const FontFamilyNames = { 0: 'Default', 1: 'Sans-Serif', 2: 'Serif', 3: 'Monospace', 4: 'Cursive', 5: 'Fantasy' };
const getDateString = function() {
let date = GLib.DateTime.new_now_local();
return `${date.format("%F")} ${date.format("%X")}`;
};
const 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".
@ -70,13 +108,11 @@ var FontFamilyNames = { 0: 'Default', 1: 'Sans-Serif', 2: 'Serif', 3: 'Monospac
var DrawingArea = new Lang.Class({
Name: 'DrawOnYourScreenDrawingArea',
Extends: St.DrawingArea,
Signals: { 'show-osd': { param_types: [GObject.TYPE_STRING, GObject.TYPE_DOUBLE] },
Signals: { 'show-osd': { param_types: [GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_DOUBLE] },
'stop-drawing': {} },
_init: function(params, monitor, helper, loadJson) {
this.parent({ style_class: 'draw-on-your-screen', name: params && params.name ? params.name : ""});
this.connect('repaint', this._repaint.bind(this));
_init: function(params, monitor, helper, loadPersistent) {
this.parent({ style_class: 'draw-on-your-screen', name: params.name});
this.settings = Convenience.getSettings();
this.monitor = monitor;
@ -93,13 +129,13 @@ var DrawingArea = new Lang.Class({
this.fill = false;
this.colors = [Clutter.Color.new(0, 0, 0, 255)];
if (loadJson)
this._loadJson();
if (loadPersistent)
this._loadPersistent();
},
get menu() {
if (!this._menu)
this._menu = new DrawingMenu(this);
this._menu = new DrawingMenu(this, this.monitor);
return this._menu;
},
@ -124,6 +160,8 @@ var DrawingArea = new Lang.Class({
this.fontFamily = font.get_family();
this.currentFontWeight = font.get_weight();
this.currentFontStyle = font.get_style();
this.squareAreaWidth = themeNode.get_length('-drawing-square-area-width');
this.squareAreaHeight = themeNode.get_length('-drawing-square-area-height');
} catch(e) {
logError(e);
}
@ -142,8 +180,8 @@ var DrawingArea = new Lang.Class({
this.currentFontStyle = this.currentFontStyle == 2 ? 1 : ( this.currentFontStyle == 1 ? 2 : 0);
},
_repaint: function(area) {
let cr = area.get_context();
vfunc_repaint: function() {
let cr = this.get_context();
for (let i = 0; i < this.elements.length; i++) {
let isStraightLine = this.elements[i].shape == Shapes.LINE &&
@ -173,6 +211,9 @@ var DrawingArea = new Lang.Class({
},
_onButtonPressed: function(actor, event) {
if (this.spaceKeyPressed)
return Clutter.EVENT_PROPAGATE;
let button = event.get_button();
let [x, y] = event.get_coords();
let shiftPressed = event.has_shift_modifier();
@ -210,6 +251,20 @@ var DrawingArea = new Lang.Class({
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 (event.get_key_symbol() == Clutter.Escape) {
this.emit('stop-drawing');
@ -218,12 +273,12 @@ var DrawingArea = new Lang.Class({
} else if (this.currentElement && this.currentElement.shape == Shapes.TEXT && this.currentElement.state == TextState.WRITING) {
if (event.get_key_symbol() == Clutter.KEY_BackSpace) {
this.currentElement.text = this.currentElement.text.slice(0, -1);
this._updateCursorTimeout();
this._updateTextCursorTimeout();
} 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._updateTextCursorTimeout();
this._redisplay();
});
return Clutter.EVENT_STOP;
@ -237,7 +292,7 @@ var DrawingArea = new Lang.Class({
} else {
let unicode = event.get_key_unicode();
this.currentElement.text += unicode;
this._updateCursorTimeout();
this._updateTextCursorTimeout();
}
this._redisplay();
return Clutter.EVENT_STOP;
@ -270,8 +325,6 @@ var DrawingArea = new Lang.Class({
this._stopDrawing();
});
this.smoothedStroke = this.settings.get_boolean('smoothed-stroke');
this.currentElement = new DrawingElement ({
shape: this.currentShape,
color: this.currentColor.to_string(),
@ -294,6 +347,9 @@ var DrawingArea = new Lang.Class({
}
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)
@ -322,8 +378,8 @@ var DrawingArea = new Lang.Class({
if (this.currentElement.shape == Shapes.TEXT && this.currentElement.state == TextState.DRAWING) {
this.currentElement.state = TextState.WRITING;
this.currentElement.text = '';
this.emit('show-osd', _("Type your text\nand press Enter"), -1);
this._updateCursorTimeout();
this.emit('show-osd', null, _("Type your text\nand press Enter"), -1);
this._updateTextCursorTimeout();
this.textHasCursor = true;
this._redisplay();
this.updatePointerCursor();
@ -342,7 +398,7 @@ var DrawingArea = new Lang.Class({
if (!this.currentElement)
return;
if (this.currentElement.shape == Shapes.NONE)
this.currentElement.addPoint(x, y, this.smoothedStroke);
this.currentElement.addPoint(x, y, controlPressed);
else if ((this.currentElement.shape == Shapes.RECTANGLE || this.currentElement.shape == Shapes.TEXT) && (controlPressed || this.currentElement.transform.active))
this.currentElement.transformRectangle(x, y);
else if (this.currentElement.shape == Shapes.ELLIPSE && (controlPressed || this.currentElement.transform.active))
@ -360,14 +416,14 @@ var DrawingArea = new Lang.Class({
if (this.currentElement.text.length > 0)
this.elements.push(this.currentElement);
this.currentElement = null;
this._stopCursorTimeout();
this._stopTextCursorTimeout();
this._redisplay();
},
setPointerCursor: function(pointerCursorName) {
if (!this.currentPointerCursorName || this.currentPointerCursorName != pointerCursorName) {
this.currentPointerCursorName = pointerCursorName;
ExtensionJs.setCursor(pointerCursorName);
Extension.setCursor(pointerCursorName);
}
},
@ -378,20 +434,20 @@ var DrawingArea = new Lang.Class({
this.setPointerCursor('MOVE_OR_RESIZE_WINDOW');
},
_stopCursorTimeout: function() {
if (this.cursorTimeoutId) {
Mainloop.source_remove(this.cursorTimeoutId);
this.cursorTimeoutId = null;
_stopTextCursorTimeout: function() {
if (this.textCursorTimeoutId) {
Mainloop.source_remove(this.textCursorTimeoutId);
this.textCursorTimeoutId = null;
}
this.textHasCursor = false;
},
_updateCursorTimeout: function() {
this._stopCursorTimeout();
this.cursorTimeoutId = Mainloop.timeout_add(600, () => {
_updateTextCursorTimeout: function() {
this._stopTextCursorTimeout();
this.textCursorTimeoutId = Mainloop.timeout_add(600, () => {
this.textHasCursor = !this.textHasCursor;
this._redisplay();
return true;
return GLib.SOURCE_CONTINUE;
});
},
@ -413,7 +469,7 @@ var DrawingArea = new Lang.Class({
this.buttonReleasedHandler = null;
}
this.currentElement = null;
this._stopCursorTimeout();
this._stopTextCursorTimeout();
} else {
this.elements.pop();
}
@ -447,9 +503,10 @@ var DrawingArea = new Lang.Class({
toggleSquareArea: function() {
this.isSquareArea = !this.isSquareArea;
if (this.isSquareArea) {
let squareWidth = Math.min(this.monitor.width, this.monitor.height) * 3 / 4;
this.set_position(Math.floor(this.monitor.width / 2 - squareWidth / 2), Math.floor(this.monitor.height / 2 - squareWidth / 2));
this.set_size(squareWidth, squareWidth);
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);
@ -468,38 +525,38 @@ var DrawingArea = new Lang.Class({
this.currentElement.color = this.currentColor.to_string();
this._redisplay();
}
this.emit('show-osd', `<span foreground="${this.currentColor.to_string()}">${this.currentColor.to_string()}</span>`, -1);
this.emit('show-osd', null, `<span foreground="${this.currentColor.to_string()}">${this.currentColor.to_string()}</span>`, -1);
},
selectShape: function(shape) {
this.currentShape = shape;
this.emit('show-osd', _(ShapeNames[shape]), -1);
this.emit('show-osd', null, _(ShapeNames[shape]), -1);
this.updatePointerCursor();
},
toggleFill: function() {
this.fill = !this.fill;
this.emit('show-osd', this.fill ? _("Fill") : _("Stroke"), -1);
this.emit('show-osd', null, this.fill ? _("Fill") : _("Stroke"), -1);
},
toggleDash: function() {
this.dashedLine = !this.dashedLine;
this.emit('show-osd', this.dashedLine ? _("Dashed line") : _("Full line"), -1);
this.emit('show-osd', null, this.dashedLine ? _("Dashed line") : _("Full line"), -1);
},
incrementLineWidth: function(increment) {
this.currentLineWidth = Math.max(this.currentLineWidth + increment, 0);
this.emit('show-osd', this.currentLineWidth + " " + _("px"), 2 * this.currentLineWidth);
this.emit('show-osd', null, this.currentLineWidth + " " + _("px"), 2 * this.currentLineWidth);
},
toggleLineJoin: function() {
this.currentLineJoin = this.currentLineJoin == 2 ? 0 : this.currentLineJoin + 1;
this.emit('show-osd', _(LineJoinNames[this.currentLineJoin]), -1);
this.emit('show-osd', null, _(LineJoinNames[this.currentLineJoin]), -1);
},
toggleLineCap: function() {
this.currentLineCap = this.currentLineCap == 2 ? 0 : this.currentLineCap + 1;
this.emit('show-osd', _(LineCapNames[this.currentLineCap]), -1);
this.emit('show-osd', null, _(LineCapNames[this.currentLineCap]), -1);
},
toggleFontWeight: function() {
@ -508,7 +565,7 @@ var DrawingArea = new Lang.Class({
this.currentElement.font.weight = this.currentFontWeight;
this._redisplay();
}
this.emit('show-osd', `<span font_weight="${FontWeightNames[this.currentFontWeight].toLowerCase()}">${_(FontWeightNames[this.currentFontWeight])}</span>`, -1);
this.emit('show-osd', null, `<span font_weight="${FontWeightNames[this.currentFontWeight].toLowerCase()}">${_(FontWeightNames[this.currentFontWeight])}</span>`, -1);
},
toggleFontStyle: function() {
@ -517,7 +574,7 @@ var DrawingArea = new Lang.Class({
this.currentElement.font.style = this.currentFontStyle;
this._redisplay();
}
this.emit('show-osd', `<span font_style="${FontStyleNames[this.currentFontStyle].toLowerCase()}">${_(FontStyleNames[this.currentFontStyle])}</span>`, -1);
this.emit('show-osd', null, `<span font_style="${FontStyleNames[this.currentFontStyle].toLowerCase()}">${_(FontStyleNames[this.currentFontStyle])}</span>`, -1);
},
toggleFontFamily: function() {
@ -527,7 +584,7 @@ var DrawingArea = new Lang.Class({
this.currentElement.font.family = currentFontFamily;
this._redisplay();
}
this.emit('show-osd', `<span font_family="${currentFontFamily}">${_(currentFontFamily)}</span>`, -1);
this.emit('show-osd', null, `<span font_family="${currentFontFamily}">${_(currentFontFamily)}</span>`, -1);
},
toggleHelp: function() {
@ -538,7 +595,9 @@ var DrawingArea = new Lang.Class({
},
enterDrawingMode: function() {
this.keyPressedHandler = this.connect('key-press-event', this._onKeyPressed.bind(this));
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));
@ -547,6 +606,14 @@ var DrawingArea = new Lang.Class({
},
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;
@ -576,15 +643,16 @@ var DrawingArea = new Lang.Class({
this.helper.hideHelp();
this.currentElement = null;
this._stopCursorTimeout();
this._stopTextCursorTimeout();
this.currentShape = Shapes.NONE;
this.dashedLine = false;
this.fill = false;
this._redisplay();
this.menu.close();
if (this._menu)
this._menu.close();
this.get_parent().set_background_color(null);
if (save)
this.saveAsJson();
this.savePersistent();
},
saveAsSvg: function() {
@ -605,8 +673,7 @@ var DrawingArea = new Lang.Class({
}
content += "\n</svg>";
let date = GLib.DateTime.new_now_local();
let filename = `DrawOnYourScreen ${date.format("%F")} ${date.format("%X")}.svg`;
let filename = `${Me.metadata['svg-file-name']} ${getDateString()}.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))
@ -626,34 +693,73 @@ var DrawingArea = new Lang.Class({
}
},
saveAsJson: function() {
let filename = `DrawOnYourScreen.json`;
let dir = GLib.get_user_data_dir();
let path = GLib.build_filenamev([dir, filename]);
let oldContents;
if (GLib.file_test(path, GLib.FileTest.EXISTS)) {
oldContents = GLib.file_get_contents(path)[1];
if (oldContents instanceof Uint8Array)
oldContents = imports.byteArray.toString(oldContents);
_saveAsJson: function(name, notify) {
// stop drawing or writing
if (this.currentElement && this.currentElement.shape == Shapes.TEXT && this.currentElement.state == TextState.WRITING) {
this._stopWriting();
} else if (this.currentElement && this.currentElement.shape != Shapes.TEXT) {
this._stopDrawing();
}
// do not create a file to write just an empty array
if (!oldContents && this.elements.length == 0)
return;
let dir = GLib.build_filenamev([GLib.get_user_data_dir(), Me.metadata['data-dir']]);
if (!GLib.file_test(dir, GLib.FileTest.EXISTS))
GLib.mkdir_with_parents(dir, 0o700);
let path = GLib.build_filenamev([dir, `${name}.json`]);
let oldContents;
if (name == Me.metadata['persistent-file-name']) {
if (GLib.file_test(path, GLib.FileTest.EXISTS)) {
oldContents = GLib.file_get_contents(path)[1];
if (oldContents instanceof Uint8Array)
oldContents = ByteArray.toString(oldContents);
}
// do not create a file to write just an empty array
if (!oldContents && this.elements.length == 0)
return;
}
// do not use "content = JSON.stringify(this.elements, null, 2);", neither "content = JSON.stringify(this.elements);"
// because of compromise between disk usage and human readability
let contents = `[\n ` + new Array(...this.elements.map(element => JSON.stringify(element))).join(`,\n\n `) + `\n]`;
if (contents != oldContents)
GLib.file_set_contents(path, contents);
if (name == Me.metadata['persistent-file-name'] && contents == oldContents)
return;
GLib.file_set_contents(path, contents);
if (notify)
this.emit('show-osd', 'document-save-symbolic', name, -1);
if (name != Me.metadata['persistent-file-name']) {
this.jsonName = name;
this.lastJsonContents = contents;
}
},
_loadJson: function() {
let filename = `DrawOnYourScreen.json`;
saveAsJsonWithName: function(name) {
this._saveAsJson(name);
},
saveAsJson: function() {
this._saveAsJson(getDateString(), true);
},
savePersistent: function() {
this._saveAsJson(Me.metadata['persistent-file-name']);
},
syncPersistent: function() {
// do not override peristent.json with an empty drawing when changing persistency setting
if (!this.elements.length)
this._loadPersistent();
else
this.savePersistent();
},
_loadJson: function(name, notify) {
let dir = GLib.get_user_data_dir();
let path = GLib.build_filenamev([dir, filename]);
let path = GLib.build_filenamev([dir, Me.metadata['data-dir'], `${name}.json`]);
if (!GLib.file_test(path, GLib.FileTest.EXISTS))
return;
@ -661,8 +767,52 @@ var DrawingArea = new Lang.Class({
if (!success)
return;
if (contents instanceof Uint8Array)
contents = imports.byteArray.toString(contents);
contents = ByteArray.toString(contents);
this.elements.push(...JSON.parse(contents).map(object => new DrawingElement(object)));
if (notify)
this.emit('show-osd', 'document-open-symbolic', name, -1);
if (name != Me.metadata['persistent-file-name']) {
this.jsonName = name;
this.lastJsonContents = contents;
}
},
_loadPersistent: function() {
this._loadJson(Me.metadata['persistent-file-name']);
},
loadJson: function(name, notify) {
this.elements = [];
this.currentElement = null;
this._stopTextCursorTimeout();
this._loadJson(name, notify);
this._redisplay();
},
loadNextJson: function() {
let names = getJsonFiles().map(file => file.name);
if (!names.length)
return;
let nextName = names[this.jsonName && names.indexOf(this.jsonName) != names.length - 1 ? names.indexOf(this.jsonName) + 1 : 0];
this.loadJson(nextName, true);
},
loadPreviousJson: function() {
let names = getJsonFiles().map(file => file.name);
if (!names.length)
return;
let previousName = names[this.jsonName && names.indexOf(this.jsonName) > 0 ? names.indexOf(this.jsonName) - 1 : names.length - 1];
this.loadJson(previousName, true);
},
get drawingContentsHasChanged() {
let contents = `[\n ` + new Array(...this.elements.map(element => JSON.stringify(element))).join(`,\n\n `) + `\n]`;
return contents != this.lastJsonContents;
},
disable: function() {
@ -674,7 +824,7 @@ var DrawingArea = new Lang.Class({
// 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({
const DrawingElement = new Lang.Class({
Name: 'DrawOnYourScreenDrawingElement',
_init: function(params) {
@ -893,7 +1043,7 @@ var DrawingElement = new Lang.Class({
},
});
function getAngle(xO, yO, xA, yA, xB, yB) {
const getAngle = function(xO, yO, xA, yA, xB, yB) {
// calculate angle of rotation in absolute value
// cos(AOB) = (OA.OB)/(||OA||*||OB||) where OA.OB = (xA-xO)*(xB-xO) + (yA-yO)*(yB-yO)
let angle = Math.acos( ((xA - xO)*(xB - xO) + (yA - yO)*(yB - yO)) / (Math.hypot(xA - xO, yA - yO) * Math.hypot(xB - xO, yB - yO)) );
@ -907,11 +1057,11 @@ function getAngle(xO, yO, xA, yA, xB, yB) {
if (xA < xO)
angle = - angle;
return angle;
}
};
var HELPER_ANIMATION_TIME = 0.25;
var MEDIA_KEYS_SCHEMA = 'org.gnome.settings-daemon.plugins.media-keys';
var MEDIA_KEYS_KEYS = {
const HELPER_ANIMATION_TIME = 0.25;
const MEDIA_KEYS_SCHEMA = 'org.gnome.settings-daemon.plugins.media-keys';
const MEDIA_KEYS_KEYS = {
'screenshot': "Screenshot",
'screenshot-clip': "Screenshot to clipboard",
'area-screenshot': "Area screenshot",
@ -952,7 +1102,7 @@ var DrawingHelper = new Lang.Class({
for (let i = 0; i < Prefs.OTHER_SHORTCUTS.length; i++) {
if (Prefs.OTHER_SHORTCUTS[i].desc.indexOf('-separator-') != -1) {
this.vbox.add(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-separator' }));
this.vbox.add(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-helper-separator' }));
continue;
}
let hbox = new St.BoxLayout({ vertical: false });
@ -961,11 +1111,11 @@ var DrawingHelper = new Lang.Class({
this.vbox.add(hbox);
}
this.vbox.add(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-separator' }));
this.vbox.add(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-helper-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' }));
this.vbox.add(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-helper-separator' }));
continue;
}
let hbox = new St.BoxLayout({ vertical: false });
@ -997,7 +1147,7 @@ var DrawingHelper = new Lang.Class({
this.opacity = 0;
this.show();
let maxHeight = this.monitor.height*(3/4);
let maxHeight = this.monitor.height * 3 / 4;
this.set_height(Math.min(this.height, maxHeight));
this.set_position(Math.floor(this.monitor.width / 2 - this.width / 2),
Math.floor(this.monitor.height / 2 - this.height / 2));
@ -1024,10 +1174,14 @@ var DrawingHelper = new Lang.Class({
},
});
var DrawingMenu = new Lang.Class({
const getActor = function(object) {
return GS_VERSION < '3.33.0' ? object.actor : object;
};
const DrawingMenu = new Lang.Class({
Name: 'DrawOnYourScreenDrawingMenu',
_init: function(area) {
_init: function(area, monitor) {
this.area = area;
let side = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL ? St.Side.RIGHT : St.Side.LEFT;
this.menu = new PopupMenu.PopupMenu(Main.layoutManager.dummyCursor, 0.25, side);
@ -1036,12 +1190,25 @@ var DrawingMenu = new Lang.Class({
Main.layoutManager.uiGroup.add_actor(this.menu.actor);
this.menu.actor.add_style_class_name('background-menu draw-on-your-screen-menu');
this.menu.actor.set_style('max-height:' + monitor.height + 'px;');
this.menu.actor.hide();
// do not close the menu on item activated
this.menu.itemActivated = () => {};
this.menu.connect('open-state-changed', this._onMenuOpenStateChanged.bind(this));
// Case where the menu is closed (escape key) while the save entry clutter_text is active:
// St.Entry clutter_text set the DEFAULT cursor on leave event with a delay and
// overrides the cursor set by area.updatePointerCursor().
// In order to update drawing cursor on menu closed, we need to leave the saveEntry before closing menu.
// Since escape key press event can't be captured easily, the job is done in the menu close function.
let menuCloseFunc = this.menu.close;
this.menu.close = (animate) => {
if (this.saveDrawingSubMenu && this.saveDrawingSubMenu.isOpen)
this.saveDrawingSubMenu.close();
menuCloseFunc.bind(this.menu)(animate);
};
this.strokeIcon = new Gio.FileIcon({ file: Gio.File.new_for_path(STROKE_ICON_PATH) });
this.fillIcon = new Gio.FileIcon({ file: Gio.File.new_for_path(FILL_ICON_PATH) });
this.linejoinIcon = new Gio.FileIcon({ file: Gio.File.new_for_path(LINEJOIN_ICON_PATH) });
@ -1062,7 +1229,8 @@ var DrawingMenu = new Lang.Class({
} else {
this.area.updatePointerCursor();
// actionMode has changed, set previous actionMode in order to keep internal shortcuts working
Main.actionMode = ExtensionJs.DRAWING_ACTION_MODE | Shell.ActionMode.NORMAL;
Main.actionMode = Extension.DRAWING_ACTION_MODE | Shell.ActionMode.NORMAL;
this.area.grab_key_focus();
}
},
@ -1127,15 +1295,19 @@ var DrawingMenu = new Lang.Class({
this.menu.addMenuItem(fontSection);
this.fontSection = fontSection;
let manager = ExtensionJs.manager;
let manager = Extension.manager;
this._addSwitchItemWithCallback(this.menu, _("Hide panel and dock"), manager.hiddenList ? true : false, manager.togglePanelAndDockOpacity.bind(manager));
this._addSwitchItemWithCallback(this.menu, _("Add a drawing background"), this.area.hasBackground, this.area.toggleBackground.bind(this.area));
this._addSwitchItemWithCallback(this.menu, _("Square drawing area"), this.area.isSquareArea, this.area.toggleSquareArea.bind(this.area));
this._addSeparator(this.menu);
this.menu.addAction(_("Save drawing as a SVG file"), this.area.saveAsSvg.bind(this.area), 'document-save-symbolic');
this.menu.addAction(_("Open stylesheet.css"), manager.openStylesheetFile.bind(manager), 'document-open-symbolic');
this.menu.addAction(_("Show help"), this.area.toggleHelp.bind(this.area), 'preferences-desktop-keyboard-shortcuts-symbolic');
this._addDrawingNameItem(this.menu);
this._addOpenDrawingSubMenuItem(this.menu);
this._addSaveDrawingSubMenuItem(this.menu);
this.menu.addAction(_("Save drawing as a SVG file"), this.area.saveAsSvg.bind(this.area), 'image-x-generic-symbolic');
this.menu.addAction(_("Edit style"), manager.openUserStyleFile.bind(manager), 'document-page-setup-symbolic');
this.menu.addAction(_("Show help"), () => { this.close(); this.area.toggleHelp(); }, 'preferences-desktop-keyboard-shortcuts-symbolic');
this.updateSectionVisibility();
},
@ -1154,10 +1326,9 @@ var DrawingMenu = new Lang.Class({
_addSwitchItem: function(menu, label, iconFalse, iconTrue, target, targetProperty) {
let item = new PopupMenu.PopupSwitchMenuItem(label, target[targetProperty]);
let itemActor = GS_VERSION < '3.33.0' ? item.actor : item;
item.icon = new St.Icon({ style_class: 'popup-menu-icon' });
itemActor.insert_child_at_index(item.icon, 1);
getActor(item).insert_child_at_index(item.icon, 1);
item.icon.set_gicon(target[targetProperty] ? iconTrue : iconFalse);
item.connect('toggled', (item, state) => {
@ -1176,34 +1347,32 @@ var DrawingMenu = new Lang.Class({
_addSliderItem: function(menu, target, targetProperty) {
let item = new PopupMenu.PopupBaseMenuItem({ activate: false });
let itemActor = GS_VERSION < '3.33.0' ? item.actor : item;
let label = new St.Label({ text: target[targetProperty] + " " + _("px"), style_class: 'draw-on-your-screen-menu-slider-label' });
let slider = new Slider.Slider(target[targetProperty] / 50);
let sliderActor = GS_VERSION < '3.33.0' ? slider.actor : slider;
if (GS_VERSION < '3.33.0') {
slider.connect('value-changed', (slider, value, property) => {
target[targetProperty] = Math.max(Math.round(value * 50), 0);
label.set_text(target[targetProperty] + " px");
if (target[targetProperty] === 0)
label.add_style_class_name(ExtensionJs.WARNING_COLOR_STYLE_CLASS_NAME);
label.add_style_class_name(Extension.WARNING_COLOR_STYLE_CLASS_NAME);
else
label.remove_style_class_name(ExtensionJs.WARNING_COLOR_STYLE_CLASS_NAME);
label.remove_style_class_name(Extension.WARNING_COLOR_STYLE_CLASS_NAME);
});
} else {
slider.connect('notify::value', () => {
target[targetProperty] = Math.max(Math.round(slider.value * 50), 0);
label.set_text(target[targetProperty] + " px");
if (target[targetProperty] === 0)
label.add_style_class_name(ExtensionJs.WARNING_COLOR_STYLE_CLASS_NAME);
label.add_style_class_name(Extension.WARNING_COLOR_STYLE_CLASS_NAME);
else
label.remove_style_class_name(ExtensionJs.WARNING_COLOR_STYLE_CLASS_NAME);
label.remove_style_class_name(Extension.WARNING_COLOR_STYLE_CLASS_NAME);
});
}
itemActor.add(sliderActor, { expand: true });
itemActor.add(label);
itemActor.connect('key-press-event', slider.onKeyPressEvent.bind(slider));
getActor(item).add(getActor(slider), { expand: true });
getActor(item).add(label);
getActor(item).connect('key-press-event', slider.onKeyPressEvent.bind(slider));
menu.addMenuItem(item);
},
@ -1269,11 +1438,200 @@ var DrawingMenu = new Lang.Class({
menu.addMenuItem(item);
},
_addDrawingNameItem: function(menu) {
this.drawingNameMenuItem = new PopupMenu.PopupMenuItem('', { reactive: false, activate: false });
this.drawingNameMenuItem.setSensitive(false);
menu.addMenuItem(this.drawingNameMenuItem);
this._updateDrawingNameMenuItem();
},
_updateDrawingNameMenuItem: function() {
getActor(this.drawingNameMenuItem).visible = this.area.jsonName ? true : false;
if (this.area.jsonName) {
let prefix = this.area.drawingContentsHasChanged ? "* " : "";
this.drawingNameMenuItem.label.set_text(`<i>${prefix}${this.area.jsonName}</i>`);
this.drawingNameMenuItem.label.get_clutter_text().set_use_markup(true);
}
},
_addOpenDrawingSubMenuItem: function(menu) {
let item = new PopupMenu.PopupSubMenuMenuItem(_("Open drawing"), true);
this.openDrawingSubMenuItem = item;
this.openDrawingSubMenu = item.menu;
item.icon.set_icon_name('document-open-symbolic');
item.menu.itemActivated = () => {
item.menu.close();
};
Mainloop.timeout_add(0, () => {
this._populateOpenDrawingSubMenu();
// small trick to prevent the menu from "jumping" on first opening
item.menu.open();
item.menu.close();
return GLib.SOURCE_REMOVE;
});
menu.addMenuItem(item);
},
_populateOpenDrawingSubMenu: function() {
this.openDrawingSubMenu.removeAll();
let jsonFiles = getJsonFiles();
jsonFiles.forEach(file => {
let item = this.openDrawingSubMenu.addAction(`<i>${file.displayName}</i>`, () => {
this.area.loadJson(file.name);
this._updateDrawingNameMenuItem();
this._updateSaveDrawingSubMenuItemSensitivity();
});
item.label.get_clutter_text().set_use_markup(true);
let expander = new St.Bin({
style_class: 'popup-menu-item-expander',
x_expand: true,
});
getActor(item).add_child(expander);
let deleteButton = new St.Button({ style_class: 'draw-on-your-screen-menu-delete-button',
child: new St.Icon({ icon_name: 'edit-delete-symbolic',
style_class: 'popup-menu-icon',
x_align: Clutter.ActorAlign.END }) });
getActor(item).add_child(deleteButton);
deleteButton.connect('clicked', () => {
file.delete();
this._populateOpenDrawingSubMenu();
});
});
this.openDrawingSubMenuItem.setSensitive(!this.openDrawingSubMenu.isEmpty());
},
_addSaveDrawingSubMenuItem: function(menu) {
let item = new PopupMenu.PopupSubMenuMenuItem(_("Save drawing"), true);
this.saveDrawingSubMenuItem = item;
this._updateSaveDrawingSubMenuItemSensitivity();
this.saveDrawingSubMenu = item.menu;
item.icon.set_icon_name('document-save-symbolic');
item.menu.itemActivated = () => {
item.menu.close();
};
Mainloop.timeout_add(0, () => {
this._populateSaveDrawingSubMenu();
// small trick to prevent the menu from "jumping" on first opening
item.menu.open();
item.menu.close();
return GLib.SOURCE_REMOVE;
});
menu.addMenuItem(item);
},
_updateSaveDrawingSubMenuItemSensitivity: function() {
this.saveDrawingSubMenuItem.setSensitive(this.area.elements.length > 0);
},
_populateSaveDrawingSubMenu: function() {
this.saveEntry = new DrawingMenuEntry({ initialTextGetter: getDateString,
entryActivateCallback: (text) => {
this.area.saveAsJsonWithName(text);
this.saveDrawingSubMenu.toggle();
this._updateDrawingNameMenuItem();
this._populateOpenDrawingSubMenu();
},
invalidStrings: [Me.metadata['persistent-file-name'], '/'],
primaryIconName: 'insert-text' });
this.saveDrawingSubMenu.addMenuItem(this.saveEntry.item);
},
_addSeparator: function(menu) {
let separator = new PopupMenu.PopupSeparatorMenuItem(' ');
let separatorActor = GS_VERSION < '3.33.0' ? separator.actor : separator;
separatorActor.add_style_class_name('draw-on-your-screen-menu-separator');
menu.addMenuItem(separator);
let separatorItem = new PopupMenu.PopupSeparatorMenuItem(' ');
getActor(separatorItem).add_style_class_name('draw-on-your-screen-menu-separator-item');
menu.addMenuItem(separatorItem);
}
});
// based on searchItem.js, https://github.com/leonardo-bartoli/gnome-shell-extension-Recents
const DrawingMenuEntry = new Lang.Class({
Name: 'DrawOnYourScreenDrawingMenuEntry',
_init: function(params) {
this.params = params;
this.item = new PopupMenu.PopupBaseMenuItem({ style_class: 'draw-on-your-screen-menu-entry-item',
activate: false,
reactive: true,
can_focus: false });
this.itemActor = GS_VERSION < '3.33.0' ? this.item.actor : this.item;
this.entry = new St.Entry({
style_class: 'search-entry draw-on-your-screen-menu-entry',
track_hover: true,
reactive: true,
can_focus: true
});
this.entry.set_primary_icon(new St.Icon({ style_class: 'search-entry-icon',
icon_name: this.params.primaryIconName }));
this.entry.clutter_text.connect('text-changed', this._onTextChanged.bind(this));
this.entry.clutter_text.connect('activate', this._onTextActivated.bind(this));
this.clearIcon = new St.Icon({
style_class: 'search-entry-icon',
icon_name: 'edit-clear-symbolic'
});
this.entry.connect('secondary-icon-clicked', this._reset.bind(this));
getActor(this.item).add(this.entry, { expand: true });
getActor(this.item).connect('notify::mapped', (actor) => {
if (actor.mapped) {
this.entry.set_text(this.params.initialTextGetter());
this.entry.clutter_text.grab_key_focus();
}
});
},
_setError: function(hasError) {
if (hasError)
this.entry.add_style_class_name('draw-on-your-screen-menu-entry-error');
else
this.entry.remove_style_class_name('draw-on-your-screen-menu-entry-error');
},
_reset: function() {
this.entry.text = '';
this.entry.clutter_text.set_cursor_visible(true);
this.entry.clutter_text.set_selection(0, 0);
this._setError(false);
},
_onTextActivated: function(clutterText) {
let text = clutterText.get_text();
if (text.length == 0)
return;
if (this._getIsInvalid())
return;
this._reset();
this.params.entryActivateCallback(text);
},
_onTextChanged: function(clutterText) {
let text = clutterText.get_text();
this.entry.set_secondary_icon(text.length ? this.clearIcon : null);
if (text.length)
this._setError(this._getIsInvalid());
},
_getIsInvalid: function() {
for (let i = 0; i < this.params.invalidStrings.length; i++) {
if (this.entry.text.indexOf(this.params.invalidStrings[i]) != -1)
return true;
}
return false;
}
});

View File

@ -3,7 +3,7 @@
/*
* Copyright 2019 Abakkk
*
* This file is part of DrowOnYourScreen, a drawing extension for GNOME Shell.
* This file is part of DrawOnYourScreen, a drawing extension for GNOME Shell.
* https://framagit.org/abakkk/DrawOnYourScreen
*
* This program is free software: you can redistribute it and/or modify
@ -21,6 +21,7 @@
*/
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
@ -31,10 +32,11 @@ const Main = imports.ui.main;
const OsdWindow = imports.ui.osdWindow;
const PanelMenu = imports.ui.panelMenu;
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;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Convenience = ExtensionUtils.getSettings && ExtensionUtils.initTranslations ? ExtensionUtils : Me.imports.convenience;
const Draw = Me.imports.draw;
const _ = imports.gettext.domain(Me.metadata['gettext-domain']).gettext;
const GS_VERSION = Config.PACKAGE_VERSION;
@ -92,16 +94,25 @@ var AreaManager = new Lang.Class({
this.desktopSettingHandler = this.settings.connect('changed::drawing-on-desktop', this.onDesktopSettingChanged.bind(this));
this.persistentSettingHandler = this.settings.connect('changed::persistent-drawing', this.onPersistentSettingChanged.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);
});
this.userStyleFile = Gio.File.new_for_path(GLib.build_filenamev([GLib.get_user_data_dir(), Me.metadata['data-dir'], 'user.css']));
if (this.userStyleFile.query_exists(null)) {
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
theme.load_stylesheet(this.userStyleFile);
}
this.userStyleMonitor = this.userStyleFile.monitor_file(Gio.FileMonitorFlags.WATCH_MOVES, null);
this.userStyleHandler = this.userStyleMonitor.connect('changed', (monitor, file, otherFile, eventType) => {
// 'CHANGED' events are followed by a 'CHANGES_DONE_HINT' event
if (eventType == Gio.FileMonitorEvent.CHANGED || eventType == Gio.FileMonitorEvent.ATTRIBUTE_CHANGED)
return;
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
if (theme.get_custom_stylesheets().indexOf(this.userStyleFile) != -1)
theme.unload_stylesheet(this.userStyleFile);
if (this.userStyleFile.query_exists(null))
theme.load_stylesheet(this.userStyleFile);
});
},
onDesktopSettingChanged: function() {
@ -113,7 +124,7 @@ var AreaManager = new Lang.Class({
onPersistentSettingChanged: function() {
if (this.settings.get_boolean('persistent-drawing'))
this.areas[Main.layoutManager.primaryIndex].saveAsJson();
this.areas[Main.layoutManager.primaryIndex].syncPersistent();
},
updateIndicator: function() {
@ -136,8 +147,8 @@ var AreaManager = new Lang.Class({
let monitor = this.monitors[i];
let container = new St.Widget({ name: 'drawOnYourSreenContainer' + i });
let helper = new Draw.DrawingHelper({ name: 'drawOnYourSreenHelper' + i }, monitor);
let load = i == Main.layoutManager.primaryIndex && this.settings.get_boolean('persistent-drawing');
let area = new Draw.DrawingArea({ name: 'drawOnYourSreenArea' + i }, monitor, helper, load);
let loadPersistent = i == Main.layoutManager.primaryIndex && this.settings.get_boolean('persistent-drawing');
let area = new Draw.DrawingArea({ name: 'drawOnYourSreenArea' + i }, monitor, helper, loadPersistent);
container.add_child(area);
container.add_child(helper);
@ -161,6 +172,9 @@ var AreaManager = new Lang.Class({
'delete-last-element': this.activeArea.deleteLastElement.bind(this.activeArea),
'smooth-last-element': this.activeArea.smoothLastElement.bind(this.activeArea),
'save-as-svg': this.activeArea.saveAsSvg.bind(this.activeArea),
'save-as-json': this.activeArea.saveAsJson.bind(this.activeArea),
'open-previous-json': this.activeArea.loadPreviousJson.bind(this.activeArea),
'open-next-json': this.activeArea.loadNextJson.bind(this.activeArea),
'toggle-background': this.activeArea.toggleBackground.bind(this.activeArea),
'toggle-square-area': this.activeArea.toggleSquareArea.bind(this.activeArea),
'increment-line-width': () => this.activeArea.incrementLineWidth(1),
@ -181,7 +195,7 @@ var AreaManager = new Lang.Class({
'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)
'open-user-stylesheet': this.openUserStyleFile.bind(this)
};
for (let key in this.internalKeybindings) {
@ -212,9 +226,19 @@ var AreaManager = new Lang.Class({
}
},
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));
openUserStyleFile: function() {
if (!this.userStyleFile.query_exists(null)) {
if (!this.userStyleFile.get_parent().query_exists(null))
this.userStyleFile.get_parent().make_directory_with_parents(null);
let defaultStyleFile = Me.dir.get_child('data').get_child('default.css');
if (!defaultStyleFile.query_exists(null))
return;
let success = defaultStyleFile.copy(this.userStyleFile, Gio.FileCopyFlags.NONE, null, null);
if (!success)
return;
}
Gio.AppInfo.launch_default_for_uri(this.userStyleFile.get_uri(), global.create_app_launch_context(0, -1));
if (this.activeArea)
this.toggleDrawing();
},
@ -223,7 +247,7 @@ var AreaManager = new Lang.Class({
for (let i = 0; i < this.areas.length; i++)
this.areas[i].erase();
if (this.settings.get_boolean('persistent-drawing'))
this.areas[Main.layoutManager.primaryIndex].saveAsJson();
this.areas[Main.layoutManager.primaryIndex].savePersistent();
},
togglePanelAndDockOpacity: function() {
@ -315,11 +339,12 @@ var AreaManager = new Lang.Class({
},
// use level -1 to set no level (null)
showOsd: function(emitter, label, level, maxLevel) {
showOsd: function(emitter, iconName, label, level) {
if (this.osdDisabled)
return;
let activeIndex = this.areas.indexOf(this.activeArea);
if (activeIndex != -1) {
let maxLevel;
if (level == -1)
level = null;
else if (level > 100)
@ -329,7 +354,9 @@ var AreaManager = new Lang.Class({
// GS 3.34+ : bar from 0 to 1
if (level && GS_VERSION > '3.33.0')
level = level / 100;
Main.osdWindowManager.show(activeIndex, this.enterGicon, label, level, maxLevel);
let icon = iconName && new Gio.ThemedIcon({ name: iconName });
Main.osdWindowManager.show(activeIndex, icon || this.enterGicon, label, level, maxLevel);
Main.osdWindowManager._osdWindows[activeIndex]._label.get_clutter_text().set_use_markup(true);
if (level === 0) {
@ -357,9 +384,13 @@ var AreaManager = new Lang.Class({
},
disable: function() {
if (this.stylesheetChangedHandler) {
this.stylesheetMonitor.disconnect(this.stylesheetChangedHandler);
this.stylesheetChangedHandler = null;
if (this.userStyleHandler && this.userStyleMonitor) {
this.userStyleMonitor.disconnect(this.userStyleHandler);
this.userStyleHandler = null;
}
if (this.userStyleMonitor) {
this.userStyleMonitor.cancel();
this.userStyleMonitor = null;
}
if (this.monitorChangedHandler) {
Main.layoutManager.disconnect(this.monitorChangedHandler);

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Draw On Your Screen VERSION\n"
"Report-Msgid-Bugs-To: https://framagit.org/abakkk/DrawOnYourScreen/issues\n"
"POT-Creation-Date: 2019-03-04 16:40+0100\n"
"POT-Creation-Date: 2020-01-03 08:00+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"
@ -19,17 +19,17 @@ msgstr ""
# Add your name here, for example:
# (add "\n" as separator if there is many translators)
# msgid "Translators"
# msgid "translator-credits"
# msgstr "Me"
# or, with mail:
# msgid "Translators"
# msgid "translator-credits"
# msgstr "<a href=\"mailto:me@mail.org\">Me</a>"
# or, with page:
# msgid "Translators"
# msgid "translator-credits"
# msgstr "<a href=\"https://...\">Me</a>"
# else keep it empty.
# It will be displayed in about page
msgid "Translators"
msgid "translator-credits"
msgstr ""
#: extension.js
@ -108,6 +108,12 @@ msgstr ""
msgid "Color"
msgstr ""
msgid "Open drawing"
msgstr ""
msgid "Save drawing"
msgstr ""
#: prefs.js
msgid "Preferences"
@ -196,10 +202,20 @@ msgstr ""
msgid "Square drawing area"
msgstr ""
msgid "Open previous drawing"
msgstr ""
msgid "Open next drawing"
msgstr ""
# already in draw.js
#msgid "Save drawing"
#msgstr ""
msgid "Save drawing as a SVG file"
msgstr ""
msgid "Open stylesheet.css"
msgid "Edit style"
msgstr ""
msgid "Show help"
@ -246,6 +262,12 @@ msgstr ""
msgid "Shift key held"
msgstr ""
msgid "Ignore pointer movement"
msgstr ""
msgid "Space key held"
msgstr ""
msgid "Leave"
msgstr ""
@ -269,18 +291,18 @@ msgstr ""
msgid "Global"
msgstr ""
msgid "Drawing on the desktop"
msgstr ""
msgid "Draw On Your Screen becomes Draw On Your Desktop"
msgstr ""
msgid "Persistent"
msgstr ""
msgid "Persistent drawing through session restart"
msgstr ""
msgid "Drawing on the desktop"
msgstr ""
msgid "<i>Draw On Your Screen</i> becomes <i>Draw On Your Desktop</i>"
msgstr ""
msgid "Disable on-screen notifications"
msgstr ""
@ -297,32 +319,24 @@ msgid ""
"By pressing <b>Ctrl</b> key <b>during</b> the drawing process, you can:\n"
" . rotate a rectangle or a text area\n"
" . extend and rotate an ellipse\n"
" . curve a line (cubic Bezier curve)"
msgstr ""
msgid "Smooth stroke during the drawing process"
" . curve a line (cubic Bezier curve)\n"
" . smooth a free drawing stroke (you may prefer to smooth the stroke afterward, see <i>“%s”</i>)"
msgstr ""
msgid ""
"You can also smooth the stroke afterward\n"
"See “%s”"
msgstr ""
msgid "Change the style"
msgstr ""
msgid "See stylesheet.css"
"<b>Default</b> drawing style attributes (color palette, font, line, dash) are defined in an editable <b>css</b> file.\n"
"See <i>“%s”</i>."
msgstr ""
msgid ""
"<u>Note</u>: When you save elements made with <b>eraser</b> in a <b>SVG</b> file,\n"
"<u>Note</u>: When you save elements made with <b>eraser</b> in a <b>SVG</b> file, "
"they are colored with background color, transparent if it is disabled.\n"
"(See “%s” or edit the SVG file afterwards)"
"See <i>“%s”</i> or edit the SVG file afterwards."
msgstr ""
# The following words refer to SVG attributes.
# You have the choice to translate or not
# You are free to translate them or not.
#msgid "Butt"
#msgstr ""

Binary file not shown.

View File

@ -0,0 +1,325 @@
# Copyright (C) 2019 Listed translators
#
# This file is distributed under the same license as Draw On Your Screen.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: Draw On Your Screen VERSION\n"
"Report-Msgid-Bugs-To: https://framagit.org/abakkk/DrawOnYourScreen/issues\n"
"POT-Creation-Date: 2019-06-15 08:47+0200\n"
"PO-Revision-Date: 2019-06-15 09:52+0200\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.8.7.1\n"
"Last-Translator: albano battistella <albano_battistella@hotmail.com>\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Language: it_IT\n"
# add your name here, for example:
# "Albano Battistella\n"
# "<a href=\"mailto:ali@mail.org\">Ali</a>\n"
# "<a href=\"https://...\">丽</a>"
# It will be displayed in About page
msgid "Translators"
msgstr "Albano Battistella"
#: extension.js
msgid "Leaving drawing mode"
msgstr "Lascia la modalità di disegno"
msgid "Press Ctrl + F1 for help"
msgstr "Premi Ctrl + F1 per aiuto"
msgid "Entering drawing mode"
msgstr "Entra in modalità disegno"
#: draw.js
msgid "Free drawing"
msgstr "Disegno libero"
msgid "Line"
msgstr "Linea"
msgid "Ellipse"
msgstr "Ellisse"
msgid "Rectangle"
msgstr "Rettangolo"
msgid "Text"
msgstr "Testo"
msgid "Fill"
msgstr "Riempi"
msgid "Stroke"
msgstr "Tratto"
msgid "Dashed line"
msgstr "Linea tratteggiata"
msgid "Full line"
msgstr "Linea piena"
msgid ""
"Type your text\n"
"and press Enter"
msgstr ""
"Digita il tuo testo\n"
"e premere Invio"
msgid "Screenshot"
msgstr "Screenshot"
msgid "Screenshot to clipboard"
msgstr "Screenshot negli appunti"
msgid "Area screenshot"
msgstr "Area screenshot"
msgid "Area screenshot to clipboard"
msgstr "Area screenshot negli appunti"
msgid "System"
msgstr "Sistema"
msgid "Undo"
msgstr "Annulla"
msgid "Redo"
msgstr "Ripeti"
msgid "Erase"
msgstr "Cancella"
msgid "Smooth"
msgstr "Liscio"
msgid "Dashed"
msgstr "tratteggiato"
msgid "Color"
msgstr "Colore"
#: prefs.js
msgid "Preferences"
msgstr "Preferenze"
msgid "About"
msgstr "Informazioni su"
# GLOBAL_KEYBINDINGS
msgid "Enter/leave drawing mode"
msgstr "Entra/esci dalla modalità disegno"
msgid "Erase all drawings"
msgstr "Cancella tutti i disegni"
# INTERNAL_KEYBINDINGS
msgid "Undo last brushstroke"
msgstr "Annulla l'ultima pennellata"
msgid "Redo last brushstroke"
msgstr "Ripeti l'ultima pennellata"
msgid "Erase last brushstroke"
msgstr "Cancella l'ultima pennellata"
msgid "Smooth last brushstroke"
msgstr "Liscia l'ultima pennellata"
msgid "Select line"
msgstr "Seleziona la linea"
msgid "Select ellipse"
msgstr "Seleziona l'ellisse"
msgid "Select rectangle"
msgstr "Seleziona il rettangolo"
msgid "Select text"
msgstr "Seleziona il testo"
msgid "Unselect shape (free drawing)"
msgstr "Deseleziona forma (disegno libero)"
msgid "Toggle fill/stroke"
msgstr "Attiva / disattiva riempimento / tratto"
msgid "Increment line width"
msgstr "Incrementa la larghezza della linea"
msgid "Decrement line width"
msgstr "Decrementa la larghezza della linea"
msgid "Increment line width even more"
msgstr "Aumentare la larghezza della linea ancora di più"
msgid "Decrement line width even more"
msgstr "Decrementa la larghezza della linea ancora di più"
msgid "Change linejoin"
msgstr "Cambia linejoin"
msgid "Change linecap"
msgstr "Cambia il limite di riga"
# already in draw.js
# msgid "Dashed line"
# msgstr ""
msgid "Change font family (generic name)"
msgstr "Cambia la famiglia del font (nome generico)"
msgid "Change font weight"
msgstr "Cambiare spessore del font"
msgid "Change font style"
msgstr "Cambia stile del font"
msgid "Hide panel and dock"
msgstr "Nascondi pannello e dock"
msgid "Add a drawing background"
msgstr "Aggiungi uno sfondo di disegno"
msgid "Square drawing area"
msgstr "Area di disegno quadrata"
msgid "Save drawing as a SVG file"
msgstr "Salva disegno come file SVG"
msgid "Open stylesheet.css"
msgstr "Apri stylesheet.css"
msgid "Show help"
msgstr "Mostra aiuto"
# OTHER_SHORTCUTS
msgid "Draw"
msgstr "Disegna"
msgid "Left click"
msgstr "Clic sinistro"
msgid "Menu"
msgstr "Menu"
msgid "Right click"
msgstr "Clic destro"
msgid "Center click"
msgstr "clic centro"
msgid "Transform shape (when drawing)"
msgstr "Trasforma la forma (quando si disegna)"
msgid "Ctrl key"
msgstr "Tasto Ctrl"
msgid "Increment/decrement line width"
msgstr "Incrementa/decrementa larghezza della linea"
msgid "Scroll"
msgstr "Scorri"
msgid "Select color"
msgstr "Seleziona colore"
msgid "Ctrl+1...9"
msgstr "Ctrl+1...9"
msgid "Select eraser"
msgstr "Seleziona gomma"
msgid "Shift key held"
msgstr "Tasto MAIUSC premuto"
msgid "Leave"
msgstr "Lascia"
msgid "Escape key"
msgstr "tasto Esc"
# About page
# you are free to translate the extension name
# msgid "Draw On You Screen"
# msgstr ""
msgid "Version %d"
msgstr "Versione %d"
msgid ""
"Start drawing with Super+Alt+D and save your beautiful work by taking a "
"screenshot"
msgstr ""
"Inizia a disegnare con Super + Alt + D e salva il tuo bellissimo lavoro "
"scattando uno screenshot"
# Prefs page
msgid "Global"
msgstr "Globale"
msgid "Drawing on the desktop"
msgstr "Disegno sul desktop"
msgid "Draw On Your Screen becomes Draw On Your Desktop"
msgstr "Draw On Your Screen diventa Draw On Your Desktop"
msgid "Persistent"
msgstr "Persistente"
msgid "Persistent drawing through session restart"
msgstr "Disegno persistente attraverso il riavvio della sessione"
msgid "Disable on-screen notifications"
msgstr "Disabilita le notifiche sullo schermo"
msgid "Disable panel indicator"
msgstr "Disabilita indicatore del pannello"
msgid "Internal"
msgstr "Interno"
msgid "(in drawing mode)"
msgstr "(in modalità disegno)"
msgid ""
"By pressing <b>Ctrl</b> key <b>during</b> the drawing process, you can:\n"
" . rotate a rectangle or a text area\n"
" . extend and rotate an ellipse\n"
" . curve a line (cubic Bezier curve)"
msgstr ""
"Premendo il tasto <b> Ctrl </ b> <b> durante </ b> del processo di disegno, "
"puoi:\n"
" . ruotare un rettangolo o un'area di testo\n"
" . estendere e ruotare un'ellisse\n"
" . curvare una linea (curva Bezier cubica)"
msgid "Smooth stroke during the drawing process"
msgstr "Colpo liscio durante il processo di disegno"
msgid ""
"You can also smooth the stroke afterward\n"
"See “%s”"
msgstr ""
"Puoi anche lisciare il tratto in seguito\n"
"Vedi \"% s\""
msgid "Change the style"
msgstr "Cambia lo stile"
msgid "See stylesheet.css"
msgstr "Vedi stylesheet.css"
msgid ""
"<u>Note</u>: When you save elements made with <b>eraser</b> in a <b>SVG</b> "
"file,\n"
"they are colored with background color, transparent if it is disabled.\n"
"(See “%s” or edit the SVG file afterwards)"
msgstr ""
"<u> Nota </ u>: quando salvi gli elementi creati con <b> gomma da "
"cancellare </ b> in un file <b> SVG </ b>,\n"
"questi sono colorati con il colore di sfondo, trasparente se disabilitati.\n"
"(Vedi \"% s\" o modifica il file SVG in seguito)"

View File

@ -5,6 +5,9 @@
"url": "https://framagit.org/abakkk/DrawOnYourScreen",
"settings-schema": "org.gnome.shell.extensions.draw-on-your-screen",
"gettext-domain": "draw-on-your-screen",
"data-dir": "drawOnYourScreen",
"persistent-file-name": "persistent",
"svg-file-name": "DrawOnYourScreen",
"shell-version": [
"3.24",
"3.26",
@ -13,5 +16,5 @@
"3.32",
"3.34"
],
"version": 5
"version": 5.1
}

175
prefs.js
View File

@ -3,7 +3,7 @@
/*
* Copyright 2019 Abakkk
*
* This file is part of DrowOnYourScreen, a drawing extension for GNOME Shell.
* This file is part of DrawOnYourScreen, a drawing extension for GNOME Shell.
* https://framagit.org/abakkk/DrawOnYourScreen
*
* This program is free software: you can redistribute it and/or modify
@ -26,10 +26,9 @@ const Lang = imports.lang;
const Mainloop = imports.mainloop;
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 Me = ExtensionUtils.getCurrentExtension();
const Convenience = ExtensionUtils.getSettings && ExtensionUtils.initTranslations ? ExtensionUtils : Me.imports.convenience;
const _ = imports.gettext.domain(Me.metadata['gettext-domain']).gettext;
const _GTK = imports.gettext.domain('gtk30').gettext;
const MARGIN = 10;
@ -68,8 +67,11 @@ var INTERNAL_KEYBINDINGS = {
'toggle-background': "Add a drawing background",
'toggle-square-area': "Square drawing area",
'-separator-5': '',
'open-previous-json': "Open previous drawing",
'open-next-json': "Open next drawing",
'save-as-json': "Save drawing",
'save-as-svg': "Save drawing as a SVG file",
'open-stylesheet': "Open stylesheet.css",
'open-user-stylesheet': "Edit style",
'toggle-help': "Show help"
};
@ -81,6 +83,7 @@ var OTHER_SHORTCUTS = [
{ desc: "Increment/decrement line width", shortcut: "Scroll" },
{ desc: "Select color", shortcut: "Ctrl+1...9" },
{ desc: "Select eraser", shortcut: "Shift key held" },
{ desc: "Ignore pointer movement", shortcut: "Space key held" },
{ desc: "Leave", shortcut: "Escape key" }
];
@ -103,7 +106,7 @@ function buildPrefsWidget() {
return topStack;
}
var TopStack = new GObject.Class({
const TopStack = new GObject.Class({
Name: 'DrawOnYourScreenTopStack',
GTypeName: 'DrawOnYourScreenTopStack',
Extends: Gtk.Stack,
@ -117,7 +120,7 @@ var TopStack = new GObject.Class({
}
});
var AboutPage = new GObject.Class({
const AboutPage = new GObject.Class({
Name: 'DrawOnYourScreenAboutPage',
GTypeName: 'DrawOnYourScreenAboutPage',
Extends: Gtk.ScrolledWindow,
@ -128,10 +131,10 @@ var AboutPage = new GObject.Class({
let vbox= new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, margin: MARGIN*3 });
this.add(vbox);
let name = "<b> " + _(Metadata.name) + "</b>";
let version = _("Version %d").format(Metadata.version);
let description = _(Metadata.description);
let link = "<span><a href=\"" + Metadata.url + "\">" + Metadata.url + "</a></span>";
let name = "<b> " + _(Me.metadata.name) + "</b>";
let version = _("Version %d").format(Me.metadata.version);
let description = _(Me.metadata.description);
let link = "<span><a href=\"" + Me.metadata.url + "\">" + Me.metadata.url + "</a></span>";
let licenceName = _GTK("GNU General Public License, version 2 or later");
let licenceLink = "https://www.gnu.org/licenses/old-licenses/gpl-2.0.html";
let licence = "<small>" + _GTK("This program comes with absolutely no warranty.\nSee the <a href=\"%s\">%s</a> for details.").format(licenceLink, licenceName) + "</small>";
@ -152,11 +155,11 @@ var AboutPage = new GObject.Class({
creditBox.pack_start(rightBox, true, true, 5);
vbox.add(creditBox);
if (_("Translators") != "Translators" && _("Translators") != "") {
if (_("translator-credits") != "translator-credits" && _("translator-credits") != "") {
leftBox.pack_start(new Gtk.Label(), false, false, 0);
rightBox.pack_start(new Gtk.Label(), false, false, 0);
leftLabel = new Gtk.Label({ wrap: true, valign: 1, halign: 2, justify: 1, use_markup: true, label: "<small>" + _GTK("Translated by") + "</small>" });
rightLabel = new Gtk.Label({ wrap: true, valign: 1, halign: 1, justify: 0, use_markup: true, label: "<small>" + _("Translators") + "</small>" });
rightLabel = new Gtk.Label({ wrap: true, valign: 1, halign: 1, justify: 0, use_markup: true, label: "<small>" + _("translator-credits") + "</small>" });
leftBox.pack_start(leftLabel, false, false, 0);
rightBox.pack_start(rightLabel, false, false, 0);
}
@ -164,7 +167,7 @@ var AboutPage = new GObject.Class({
});
var PrefsPage = new GObject.Class({
const PrefsPage = new GObject.Class({
Name: 'DrawOnYourScreenPrefsPage',
GTypeName: 'DrawOnYourScreenPrefsPage',
Extends: Gtk.ScrolledWindow,
@ -174,83 +177,88 @@ var PrefsPage = new GObject.Class({
this.settings = Convenience.getSettings();
let box = new Gtk.Box({orientation: Gtk.Orientation.VERTICAL, margin: MARGIN*3 });
let box = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, margin: MARGIN*3 });
this.add(box);
let listBox = new Gtk.ListBox({ selection_mode: 0, hexpand: true });
box.add(listBox);
let globalFrame = new Gtk.Frame({ label_yalign: 1.0 });
globalFrame.set_label_widget(new Gtk.Label({ margin_bottom: MARGIN/2, use_markup: true, label: "<b><big>" + _("Global") + "</big></b>" }));
box.add(globalFrame);
let listBox = new Gtk.ListBox({ selection_mode: 0, hexpand: true, margin_top: MARGIN/2, margin_bottom: MARGIN/2 });
globalFrame.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);
let desktopBox = new Gtk.Box({ margin: MARGIN });
let desktopLabelBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
let desktopLabel1 = new Gtk.Label({label: _("Drawing on the desktop")});
let desktopLabel2 = new Gtk.Label({ use_markup: true, halign: 1, label: "<small>" + _("Draw On Your Screen becomes Draw On Your Desktop") + "</small>" });
desktopLabel1.set_halign(1);
desktopLabel2.get_style_context().add_class("dim-label");
desktopLabelBox.pack_start(desktopLabel1, true, true, 0);
desktopLabelBox.pack_start(desktopLabel2, true, true, 0);
let desktopSwitch = new Gtk.Switch({valign: 3});
this.settings.bind("drawing-on-desktop", desktopSwitch, "active", 0);
desktopBox.pack_start(desktopLabelBox, true, true, 4);
desktopBox.pack_start(desktopSwitch, false, false, 4);
listBox.add(desktopBox);
let persistentBox = new Gtk.Box({ margin: MARGIN });
let persistentBox = new Gtk.Box({ margin_top: MARGIN/2, margin_bottom: MARGIN/2, margin_left: MARGIN, margin_right: MARGIN });
let persistentLabelBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
let persistentLabel1 = new Gtk.Label({label: _("Persistent")});
let persistentLabel2 = new Gtk.Label({ use_markup: true, halign: 1, label: "<small>" + _("Persistent drawing through session restart") + "</small>" });
let persistentLabel2 = new Gtk.Label({ use_markup: true, halign: 1, wrap: true, xalign: 0, label: "<small>" + _("Persistent drawing through session restart") + "</small>" });
persistentLabel1.set_halign(1);
persistentLabel2.get_style_context().add_class("dim-label");
persistentLabel2.get_style_context().add_class('dim-label');
persistentLabelBox.pack_start(persistentLabel1, true, true, 0);
persistentLabelBox.pack_start(persistentLabel2, true, true, 0);
let persistentSwitch = new Gtk.Switch({valign: 3});
this.settings.bind("persistent-drawing", persistentSwitch, "active", 0);
this.settings.bind('persistent-drawing', persistentSwitch, 'active', 0);
persistentBox.pack_start(persistentLabelBox, true, true, 4);
persistentBox.pack_start(persistentSwitch, false, false, 4);
listBox.add(persistentBox);
let osdBox = new Gtk.Box({ margin: MARGIN });
let desktopBox = new Gtk.Box({ margin_top: MARGIN/2, margin_bottom: MARGIN/2, margin_left: MARGIN, margin_right: MARGIN });
let desktopLabelBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
let desktopLabel1 = new Gtk.Label({label: _("Drawing on the desktop")});
let desktopLabel2 = new Gtk.Label({ use_markup: true, halign: 1, wrap: true, xalign: 0, label: "<small>" + _("<i>Draw On Your Screen</i> becomes <i>Draw On Your Desktop</i>") + "</small>" });
desktopLabel1.set_halign(1);
desktopLabel2.get_style_context().add_class('dim-label');
desktopLabelBox.pack_start(desktopLabel1, true, true, 0);
desktopLabelBox.pack_start(desktopLabel2, true, true, 0);
let desktopSwitch = new Gtk.Switch({valign: 3});
this.settings.bind('drawing-on-desktop', desktopSwitch, 'active', 0);
desktopBox.pack_start(desktopLabelBox, true, true, 4);
desktopBox.pack_start(desktopSwitch, false, false, 4);
listBox.add(desktopBox);
let osdBox = new Gtk.Box({ margin_top: MARGIN/2, margin_bottom: MARGIN/2, margin_left: MARGIN, margin_right: MARGIN });
let osdLabelBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
let osdLabel1 = new Gtk.Label({label: _("Disable on-screen notifications")});
osdLabel1.set_halign(1);
osdLabelBox.pack_start(osdLabel1, true, true, 0);
let osdSwitch = new Gtk.Switch({valign: 3});
this.settings.bind("osd-disabled", osdSwitch, "active", 0);
this.settings.bind('osd-disabled', osdSwitch, 'active', 0);
osdBox.pack_start(osdLabelBox, true, true, 4);
osdBox.pack_start(osdSwitch, false, false, 4);
listBox.add(osdBox);
let indicatorBox = new Gtk.Box({ margin: MARGIN });
let indicatorBox = new Gtk.Box({ margin_top: MARGIN/2, margin_bottom: MARGIN/2, margin_left: MARGIN, margin_right: MARGIN });
let indicatorLabelBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
let indicatorLabel1 = new Gtk.Label({label: _("Disable panel indicator")});
indicatorLabel1.set_halign(1);
indicatorLabelBox.pack_start(indicatorLabel1, true, true, 0);
let indicatorSwitch = new Gtk.Switch({valign: 3});
this.settings.bind("indicator-disabled", indicatorSwitch, "active", 0);
this.settings.bind('indicator-disabled', indicatorSwitch, 'active', 0);
indicatorBox.pack_start(indicatorLabelBox, true, true, 4);
indicatorBox.pack_start(indicatorSwitch, false, false, 4);
listBox.add(indicatorBox);
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);
let children = listBox.get_children();
for (let i = 0; i < children.length; i++) {
if (children[i].activatable)
children[i].set_activatable(false);
}
listBox.add(new Gtk.Box({ margin_top: MARGIN/2, margin_left: MARGIN, margin_right: MARGIN }));
let internalFrame = new Gtk.Frame({ margin_top: 3*MARGIN, label_yalign: 1.0 });
internalFrame.set_label_widget(new Gtk.Label({ margin_bottom: MARGIN/2, use_markup: true, label: "<b><big>" + _("Internal") + " </big></b>" + _("(in drawing mode)") }));
box.add(internalFrame);
listBox = new Gtk.ListBox({ selection_mode: 0, hexpand: true, margin_top: MARGIN });
internalFrame.add(listBox);
styleContext = listBox.get_style_context();
styleContext.add_class('background');
for (let i = 0; i < OTHER_SHORTCUTS.length; i++) {
if (OTHER_SHORTCUTS[i].desc.indexOf('-separator-') != -1) {
@ -266,70 +274,63 @@ var PrefsPage = new GObject.Class({
listBox.add(otherBox);
}
listBox.add(new Gtk.Box({ margin_top: MARGIN, margin_left: MARGIN, margin_right: MARGIN }));
let controlBox = new Gtk.Box({ margin_top: MARGIN, margin_left: MARGIN, margin_right: MARGIN, margin_bottom:MARGIN });
let controlBox = new Gtk.Box({ margin: MARGIN, margin_top: 2*MARGIN });
let controlLabel = new Gtk.Label({
wrap: true,
xalign: 0,
use_markup: true,
label: _("By pressing <b>Ctrl</b> key <b>during</b> the drawing process, you can:\n . rotate a rectangle or a text area\n . extend and rotate an ellipse\n . curve a line (cubic Bezier curve)")
label: _("By pressing <b>Ctrl</b> key <b>during</b> the drawing process, you can:\n" +
" . rotate a rectangle or a text area\n" +
" . extend and rotate an ellipse\n" +
" . curve a line (cubic Bezier curve)\n" +
" . smooth a free drawing stroke (you may prefer to smooth the stroke afterward, see <i>“%s”</i>)").format(_("Smooth last brushstroke"))
});
controlLabel.set_halign(1);
controlLabel.get_style_context().add_class("dim-label");
controlLabel.get_style_context().add_class('dim-label');
controlBox.pack_start(controlLabel, true, true, 4);
listBox.add(controlBox);
let smoothBox = new Gtk.Box({ margin: MARGIN });
let smoothLabelBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
let smoothLabel1 = new Gtk.Label({label: _("Smooth stroke during the drawing process")});
let smoothLabel2 = new Gtk.Label({ use_markup: true, halign: 1, label: "<small>" + _("You can also smooth the stroke afterward\nSee “%s”").format(_("Smooth last brushstroke")) + "</small>" });
smoothLabel1.set_halign(1);
smoothLabel2.get_style_context().add_class("dim-label");
smoothLabelBox.pack_start(smoothLabel1, true, true, 0);
smoothLabelBox.pack_start(smoothLabel2, true, true, 0);
let smoothSwitch = new Gtk.Switch({valign: 3});
this.settings.bind("smoothed-stroke", smoothSwitch, "active", 0);
smoothBox.pack_start(smoothLabelBox, true, true, 4);
smoothBox.pack_start(smoothSwitch, false, false, 4);
listBox.add(smoothBox);
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") });
let styleBox = new Gtk.Box({ margin: MARGIN });
let styleLabel = new Gtk.Label({
wrap: true,
xalign: 0,
use_markup: true,
label: _("<b>Default</b> drawing style attributes (color palette, font, line, dash) are defined in an editable <b>css</b> file.\n" +
"See <i>“%s”</i>.").format(_("Edit style"))
});
styleLabel.set_halign(1);
let styleLabel2 = new Gtk.Label({ label: _("See stylesheet.css") });
styleLabel.get_style_context().add_class('dim-label');
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 noteBox = new Gtk.Box({ margin: MARGIN });
let noteLabel = new Gtk.Label({
wrap: true,
xalign: 0,
use_markup: true,
label: _("<u>Note</u>: When you save elements made with <b>eraser</b> in a <b>SVG</b> file,\nthey are colored with background color, transparent if it is disabled.\n(See “%s” or edit the SVG file afterwards)").format(_("Add a drawing background"))
label: _("<u>Note</u>: When you save elements made with <b>eraser</b> in a <b>SVG</b> file, " +
"they are colored with background color, transparent if it is disabled.\n" +
"See <i>“%s”</i> or edit the SVG file afterwards.").format(_("Add a drawing background"))
});
noteLabel.set_halign(1);
noteLabel.get_style_context().add_class("dim-label");
noteLabel.get_style_context().add_class('dim-label');
noteBox.pack_start(noteLabel, true, true, 4);
listBox.add(noteBox);
let children = listBox.get_children();
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/
var KeybindingsWidget = new GObject.Class({
const KeybindingsWidget = new GObject.Class({
Name: 'DrawOnYourScreenKeybindings.Widget',
GTypeName: 'DrawOnYourScreenKeybindingsWidget',
Extends: Gtk.Box,

Binary file not shown.

View File

@ -1,11 +1,6 @@
<?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="b" name="smoothed-stroke">
<default>false</default>
<summary>smoothed stroke</summary>
<description>smoothed stroke</description>
</key>
<key type="b" name="drawing-on-desktop">
<default>false</default>
<summary>move drawing on desktop</summary>
@ -107,12 +102,12 @@
<description>decrement the line width</description>
</key>
<key type="as" name="increment-line-width-more">
<default>["&lt;Primary&gt;Page_Up"]</default>
<default>["&lt;Primary&gt;&lt;Shift&gt;KP_Add"]</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>["&lt;Primary&gt;Page_Down"]</default>
<default>["&lt;Primary&gt;&lt;Shift&gt;KP_Subtract"]</default>
<summary>decrement the line width even more</summary>
<description>decrement the line width even more</description>
</key>
@ -196,16 +191,31 @@
<summary>toggle font style</summary>
<description>toggle font style</description>
</key>
<key type="as" name="open-stylesheet">
<key type="as" name="open-user-stylesheet">
<default>["&lt;Primary&gt;o"]</default>
<summary>open stylesheet</summary>
<description>open stylesheet</description>
<summary>open user stylesheet to edit style</summary>
<description>open user stylesheet to edit style</description>
</key>
<key type="as" name="save-as-svg">
<default>["&lt;Primary&gt;s"]</default>
<default>["&lt;Primary&gt;&lt;Shift&gt;s"]</default>
<summary>Save drawing as a svg file</summary>
<description>Save drawing as a svg file</description>
</key>
<key type="as" name="save-as-json">
<default>["&lt;Primary&gt;s"]</default>
<summary>Save drawing as a json file</summary>
<description>Save drawing as a json file</description>
</key>
<key type="as" name="open-previous-json">
<default>["&lt;Primary&gt;Page_Down"]</default>
<summary>Open previous json file</summary>
<description>Open previous json file</description>
</key>
<key type="as" name="open-next-json">
<default>["&lt;Primary&gt;Page_Up"]</default>
<summary>Open next json file</summary>
<description>Open next json file</description>
</key>
<key type="as" name="toggle-help">
<default>["&lt;Primary&gt;F1"]</default>
<summary>toggle help</summary>

View File

@ -1,50 +1,6 @@
/*
* 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
*
*/
@import "./data/default.css";
.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 */
/* square area */
@ -56,8 +12,7 @@
outline: none;
}
/* The following styles don't affect the drawing,
* but the "Ctrl + F1" on-screen-display */
/* "Ctrl + F1" on-screen-display */
.draw-on-your-screen-helper {
margin: 0;
@ -73,36 +28,71 @@
font-weight: normal;
}
.draw-on-your-screen-separator {
.draw-on-your-screen-helper-separator {
min-height: 0.6em;
}
/* context menu */
.draw-on-your-screen-menu {
font-size: 0.98em; /* default: 1em */
font-size: 0.97em; /* default: 1em */
}
.draw-on-your-screen-menu .popup-menu-item {
padding-top: .37em; /* default: .4em */
padding-bottom: .37em;
padding-top: .3em; /* default: .4em */
padding-bottom: .3em;
}
.draw-on-your-screen-menu .popup-menu-icon {
icon-size: 1.04em; /* default: 1.09 */
icon-size: 1em; /* default: 1.09 */
padding-top: 0.03em;
}
.draw-on-your-screen-menu .toggle-switch {
height: 20px; /* default: 22px */
}
height: 1.35em; /* default: 22px */
}
.draw-on-your-screen-menu-separator StLabel {
.draw-on-your-screen-menu-separator-item {
padding-top: 0.14em;
padding-bottom: 0.14em;
}
.draw-on-your-screen-menu-separator-item StLabel {
font-size: 0;
}
.draw-on-your-screen-menu-separator-item .popup-separator-menu-item {
margin-top: 0.2em; /* default 6px */
margin-bottom: 0.2em; /* default 6px */
}
.draw-on-your-screen-menu-slider-label {
min-width: 3em;
text-align: right;
}
.draw-on-your-screen-menu-entry-item {
padding-right: 1.15em; /* default 1.75em */
spacing: 0; /* default 12px */
}
.draw-on-your-screen-menu-entry {
border: none;
border-radius: 3px;
padding: 0.35em 0.57em;
width: 10em;
}
.draw-on-your-screen-menu-entry-error {
color: #f57900; /* upstream warning_color */
}
.draw-on-your-screen-menu-entry:focus {
padding: 0.35em 0.57em;
}
.draw-on-your-screen-menu-delete-button:hover {
color: #f57900;
}