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. Start drawing with Super+Alt+D.
Then save your beautiful work by taking a screenshot. Then save your beautiful work by taking a screenshot.
![](https://framagit.org/abakkk/DrawOnYourScreen/raw/ressources/screenshot.jpg) ![](https://framagit.org/abakkk/DrawOnYourScreen/raw/ressources/screenshot.jpg)
Features : ## Features
----------
* Basic shapes (rectangle, circle, ellipse, line, curve, text, free) * Basic shapes (rectangle, circle, ellipse, line, curve, text, free)
* Smooth stroke * Smooth stroke
@ -15,13 +14,26 @@ Features :
* Multi-monitor support * Multi-monitor support
* Export to SVG * Export to SVG
Install : ## Install
----------
1. Download and decompress or clone the repository 1. Download and decompress or clone the repository
2. Place the resulting directory in ~/.local/share/gnome-shell/extensions 2. Place the resulting directory in `~/.local/share/gnome-shell/extensions`
3. IMPORTANT: change the directory name to drawOnYourScreen@abakkk.framagit.org 3. **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 4. Xorg: type `alt + F2` and `r` to restart gnome-shell
5. Enable the extension in Gnome-tweak-tool Wayland: restart or re-login
5. Enable the extension in gnome-tweaks
6. `Super + Alt + D` to test 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 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

574
draw.js
View File

@ -3,7 +3,7 @@
/* /*
* Copyright 2019 Abakkk * 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 * https://framagit.org/abakkk/DrawOnYourScreen
* *
* This program is free software: you can redistribute it and/or modify * 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/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
const ByteArray = imports.byteArray;
const Cairo = imports.cairo; const Cairo = imports.cairo;
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
@ -40,29 +41,66 @@ const Screenshot = imports.ui.screenshot;
const Tweener = imports.ui.tweener; const Tweener = imports.ui.tweener;
const ExtensionUtils = imports.misc.extensionUtils; const ExtensionUtils = imports.misc.extensionUtils;
const Extension = ExtensionUtils.getCurrentExtension(); const Me = ExtensionUtils.getCurrentExtension();
const Convenience = Extension.imports.convenience; const Convenience = ExtensionUtils.getSettings ? ExtensionUtils : Me.imports.convenience;
const ExtensionJs = Extension.imports.extension; const Extension = Me.imports.extension;
const Prefs = Extension.imports.prefs; const Prefs = Me.imports.prefs;
const _ = imports.gettext.domain(Extension.metadata["gettext-domain"]).gettext; const _ = imports.gettext.domain(Me.metadata['gettext-domain']).gettext;
const GS_VERSION = Config.PACKAGE_VERSION; const GS_VERSION = Config.PACKAGE_VERSION;
const FILL_ICON_PATH = Extension.dir.get_child('icons').get_child('fill-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 = Extension.dir.get_child('icons').get_child('stroke-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 = Extension.dir.get_child('icons').get_child('linejoin-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 = Extension.dir.get_child('icons').get_child('linecap-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 = Extension.dir.get_child('icons').get_child('dashed-line-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 = Extension.dir.get_child('icons').get_child('full-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 Shapes = { NONE: 0, LINE: 1, ELLIPSE: 2, RECTANGLE: 3, TEXT: 4 };
var TextState = { DRAWING: 0, WRITING: 1 }; const TextState = { DRAWING: 0, WRITING: 1 };
var ShapeNames = { 0: "Free drawing", 1: "Line", 2: "Ellipse", 3: "Rectangle", 4: "Text" }; const ShapeNames = { 0: "Free drawing", 1: "Line", 2: "Ellipse", 3: "Rectangle", 4: "Text" };
var LineCapNames = { 0: 'Butt', 1: 'Round', 2: 'Square' }; const LineCapNames = { 0: 'Butt', 1: 'Round', 2: 'Square' };
var LineJoinNames = { 0: 'Miter', 1: 'Round', 2: 'Bevel' }; const LineJoinNames = { 0: 'Miter', 1: 'Round', 2: 'Bevel' };
var FontWeightNames = { 0: 'Normal', 1: 'Bold' }; const FontWeightNames = { 0: 'Normal', 1: 'Bold' };
var FontStyleNames = { 0: 'Normal', 1: 'Italic', 2: 'Oblique' }; const FontStyleNames = { 0: 'Normal', 1: 'Italic', 2: 'Oblique' };
var FontFamilyNames = { 0: 'Default', 1: 'Sans-Serif', 2: 'Serif', 3: 'Monospace', 4: 'Cursive', 5: 'Fantasy' }; 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. // DrawingArea is the widget in which we draw, thanks to Cairo.
// It creates and manages a DrawingElement for each "brushstroke". // 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({ var DrawingArea = new Lang.Class({
Name: 'DrawOnYourScreenDrawingArea', Name: 'DrawOnYourScreenDrawingArea',
Extends: St.DrawingArea, 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': {} }, 'stop-drawing': {} },
_init: function(params, monitor, helper, loadJson) { _init: function(params, monitor, helper, loadPersistent) {
this.parent({ style_class: 'draw-on-your-screen', name: params && params.name ? params.name : ""}); this.parent({ style_class: 'draw-on-your-screen', name: params.name});
this.connect('repaint', this._repaint.bind(this));
this.settings = Convenience.getSettings(); this.settings = Convenience.getSettings();
this.monitor = monitor; this.monitor = monitor;
@ -93,13 +129,13 @@ var DrawingArea = new Lang.Class({
this.fill = false; this.fill = false;
this.colors = [Clutter.Color.new(0, 0, 0, 255)]; this.colors = [Clutter.Color.new(0, 0, 0, 255)];
if (loadJson) if (loadPersistent)
this._loadJson(); this._loadPersistent();
}, },
get menu() { get menu() {
if (!this._menu) if (!this._menu)
this._menu = new DrawingMenu(this); this._menu = new DrawingMenu(this, this.monitor);
return this._menu; return this._menu;
}, },
@ -124,6 +160,8 @@ var DrawingArea = new Lang.Class({
this.fontFamily = font.get_family(); this.fontFamily = font.get_family();
this.currentFontWeight = font.get_weight(); this.currentFontWeight = font.get_weight();
this.currentFontStyle = font.get_style(); 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) { } catch(e) {
logError(e); logError(e);
} }
@ -142,8 +180,8 @@ var DrawingArea = new Lang.Class({
this.currentFontStyle = this.currentFontStyle == 2 ? 1 : ( this.currentFontStyle == 1 ? 2 : 0); this.currentFontStyle = this.currentFontStyle == 2 ? 1 : ( this.currentFontStyle == 1 ? 2 : 0);
}, },
_repaint: function(area) { vfunc_repaint: function() {
let cr = area.get_context(); let cr = this.get_context();
for (let i = 0; i < this.elements.length; i++) { for (let i = 0; i < this.elements.length; i++) {
let isStraightLine = this.elements[i].shape == Shapes.LINE && let isStraightLine = this.elements[i].shape == Shapes.LINE &&
@ -173,6 +211,9 @@ var DrawingArea = new Lang.Class({
}, },
_onButtonPressed: function(actor, event) { _onButtonPressed: function(actor, event) {
if (this.spaceKeyPressed)
return Clutter.EVENT_PROPAGATE;
let button = event.get_button(); let button = event.get_button();
let [x, y] = event.get_coords(); let [x, y] = event.get_coords();
let shiftPressed = event.has_shift_modifier(); let shiftPressed = event.has_shift_modifier();
@ -210,6 +251,20 @@ var DrawingArea = new Lang.Class({
return Clutter.EVENT_STOP; 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) { _onKeyPressed: function(actor, event) {
if (event.get_key_symbol() == Clutter.Escape) { if (event.get_key_symbol() == Clutter.Escape) {
this.emit('stop-drawing'); 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) { } else if (this.currentElement && this.currentElement.shape == Shapes.TEXT && this.currentElement.state == TextState.WRITING) {
if (event.get_key_symbol() == Clutter.KEY_BackSpace) { if (event.get_key_symbol() == Clutter.KEY_BackSpace) {
this.currentElement.text = this.currentElement.text.slice(0, -1); this.currentElement.text = this.currentElement.text.slice(0, -1);
this._updateCursorTimeout(); this._updateTextCursorTimeout();
} else if (event.has_control_modifier() && event.get_key_symbol() == 118) { } else if (event.has_control_modifier() && event.get_key_symbol() == 118) {
// Ctrl + V // Ctrl + V
St.Clipboard.get_default().get_text(St.ClipboardType.CLIPBOARD, (clipBoard, clipText) => { St.Clipboard.get_default().get_text(St.ClipboardType.CLIPBOARD, (clipBoard, clipText) => {
this.currentElement.text += clipText; this.currentElement.text += clipText;
this._updateCursorTimeout(); this._updateTextCursorTimeout();
this._redisplay(); this._redisplay();
}); });
return Clutter.EVENT_STOP; return Clutter.EVENT_STOP;
@ -237,7 +292,7 @@ var DrawingArea = new Lang.Class({
} else { } else {
let unicode = event.get_key_unicode(); let unicode = event.get_key_unicode();
this.currentElement.text += unicode; this.currentElement.text += unicode;
this._updateCursorTimeout(); this._updateTextCursorTimeout();
} }
this._redisplay(); this._redisplay();
return Clutter.EVENT_STOP; return Clutter.EVENT_STOP;
@ -270,8 +325,6 @@ var DrawingArea = new Lang.Class({
this._stopDrawing(); this._stopDrawing();
}); });
this.smoothedStroke = this.settings.get_boolean('smoothed-stroke');
this.currentElement = new DrawingElement ({ this.currentElement = new DrawingElement ({
shape: this.currentShape, shape: this.currentShape,
color: this.currentColor.to_string(), color: this.currentColor.to_string(),
@ -294,6 +347,9 @@ var DrawingArea = new Lang.Class({
} }
this.motionHandler = this.connect('motion-event', (actor, event) => { this.motionHandler = this.connect('motion-event', (actor, event) => {
if (this.spaceKeyPressed)
return;
let coords = event.get_coords(); let coords = event.get_coords();
let [s, x, y] = this.transform_stage_point(coords[0], coords[1]); let [s, x, y] = this.transform_stage_point(coords[0], coords[1]);
if (!s) if (!s)
@ -322,8 +378,8 @@ var DrawingArea = new Lang.Class({
if (this.currentElement.shape == Shapes.TEXT && this.currentElement.state == TextState.DRAWING) { if (this.currentElement.shape == Shapes.TEXT && this.currentElement.state == TextState.DRAWING) {
this.currentElement.state = TextState.WRITING; this.currentElement.state = TextState.WRITING;
this.currentElement.text = ''; this.currentElement.text = '';
this.emit('show-osd', _("Type your text\nand press Enter"), -1); this.emit('show-osd', null, _("Type your text\nand press Enter"), -1);
this._updateCursorTimeout(); this._updateTextCursorTimeout();
this.textHasCursor = true; this.textHasCursor = true;
this._redisplay(); this._redisplay();
this.updatePointerCursor(); this.updatePointerCursor();
@ -342,7 +398,7 @@ var DrawingArea = new Lang.Class({
if (!this.currentElement) if (!this.currentElement)
return; return;
if (this.currentElement.shape == Shapes.NONE) 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)) else if ((this.currentElement.shape == Shapes.RECTANGLE || this.currentElement.shape == Shapes.TEXT) && (controlPressed || this.currentElement.transform.active))
this.currentElement.transformRectangle(x, y); this.currentElement.transformRectangle(x, y);
else if (this.currentElement.shape == Shapes.ELLIPSE && (controlPressed || this.currentElement.transform.active)) 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) if (this.currentElement.text.length > 0)
this.elements.push(this.currentElement); this.elements.push(this.currentElement);
this.currentElement = null; this.currentElement = null;
this._stopCursorTimeout(); this._stopTextCursorTimeout();
this._redisplay(); this._redisplay();
}, },
setPointerCursor: function(pointerCursorName) { setPointerCursor: function(pointerCursorName) {
if (!this.currentPointerCursorName || this.currentPointerCursorName != pointerCursorName) { if (!this.currentPointerCursorName || this.currentPointerCursorName != pointerCursorName) {
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'); this.setPointerCursor('MOVE_OR_RESIZE_WINDOW');
}, },
_stopCursorTimeout: function() { _stopTextCursorTimeout: function() {
if (this.cursorTimeoutId) { if (this.textCursorTimeoutId) {
Mainloop.source_remove(this.cursorTimeoutId); Mainloop.source_remove(this.textCursorTimeoutId);
this.cursorTimeoutId = null; this.textCursorTimeoutId = null;
} }
this.textHasCursor = false; this.textHasCursor = false;
}, },
_updateCursorTimeout: function() { _updateTextCursorTimeout: function() {
this._stopCursorTimeout(); this._stopTextCursorTimeout();
this.cursorTimeoutId = Mainloop.timeout_add(600, () => { this.textCursorTimeoutId = Mainloop.timeout_add(600, () => {
this.textHasCursor = !this.textHasCursor; this.textHasCursor = !this.textHasCursor;
this._redisplay(); this._redisplay();
return true; return GLib.SOURCE_CONTINUE;
}); });
}, },
@ -413,7 +469,7 @@ var DrawingArea = new Lang.Class({
this.buttonReleasedHandler = null; this.buttonReleasedHandler = null;
} }
this.currentElement = null; this.currentElement = null;
this._stopCursorTimeout(); this._stopTextCursorTimeout();
} else { } else {
this.elements.pop(); this.elements.pop();
} }
@ -447,9 +503,10 @@ var DrawingArea = new Lang.Class({
toggleSquareArea: function() { toggleSquareArea: function() {
this.isSquareArea = !this.isSquareArea; this.isSquareArea = !this.isSquareArea;
if (this.isSquareArea) { if (this.isSquareArea) {
let squareWidth = Math.min(this.monitor.width, this.monitor.height) * 3 / 4; let width = this.squareAreaWidth || this.squareAreaHeight || 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)); let height = this.squareAreaHeight || this.squareAreaWidth || Math.min(this.monitor.width, this.monitor.height) * 3 / 4;
this.set_size(squareWidth, squareWidth); 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'); this.add_style_class_name('draw-on-your-screen-square-area');
} else { } else {
this.set_position(0, 0); this.set_position(0, 0);
@ -468,38 +525,38 @@ var DrawingArea = new Lang.Class({
this.currentElement.color = this.currentColor.to_string(); this.currentElement.color = this.currentColor.to_string();
this._redisplay(); 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) { selectShape: function(shape) {
this.currentShape = shape; this.currentShape = shape;
this.emit('show-osd', _(ShapeNames[shape]), -1); this.emit('show-osd', null, _(ShapeNames[shape]), -1);
this.updatePointerCursor(); this.updatePointerCursor();
}, },
toggleFill: function() { toggleFill: function() {
this.fill = !this.fill; 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() { toggleDash: function() {
this.dashedLine = !this.dashedLine; 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) { incrementLineWidth: function(increment) {
this.currentLineWidth = Math.max(this.currentLineWidth + increment, 0); 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() { toggleLineJoin: function() {
this.currentLineJoin = this.currentLineJoin == 2 ? 0 : this.currentLineJoin + 1; 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() { toggleLineCap: function() {
this.currentLineCap = this.currentLineCap == 2 ? 0 : this.currentLineCap + 1; 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() { toggleFontWeight: function() {
@ -508,7 +565,7 @@ var DrawingArea = new Lang.Class({
this.currentElement.font.weight = this.currentFontWeight; this.currentElement.font.weight = this.currentFontWeight;
this._redisplay(); 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() { toggleFontStyle: function() {
@ -517,7 +574,7 @@ var DrawingArea = new Lang.Class({
this.currentElement.font.style = this.currentFontStyle; this.currentElement.font.style = this.currentFontStyle;
this._redisplay(); 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() { toggleFontFamily: function() {
@ -527,7 +584,7 @@ var DrawingArea = new Lang.Class({
this.currentElement.font.family = currentFontFamily; this.currentElement.font.family = currentFontFamily;
this._redisplay(); 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() { toggleHelp: function() {
@ -538,6 +595,8 @@ var DrawingArea = new Lang.Class({
}, },
enterDrawingMode: function() { enterDrawingMode: function() {
this.stageKeyPressedHandler = global.stage.connect('key-press-event', this._onStageKeyPressed.bind(this));
this.stageKeyReleasedHandler = global.stage.connect('key-release-event', this._onStageKeyReleased.bind(this));
this.keyPressedHandler = this.connect('key-press-event', this._onKeyPressed.bind(this)); this.keyPressedHandler = this.connect('key-press-event', this._onKeyPressed.bind(this));
this.buttonPressedHandler = this.connect('button-press-event', this._onButtonPressed.bind(this)); this.buttonPressedHandler = this.connect('button-press-event', this._onButtonPressed.bind(this));
this._onKeyboardPopupMenuHandler = this.connect('popup-menu', this._onKeyboardPopupMenu.bind(this)); this._onKeyboardPopupMenuHandler = this.connect('popup-menu', this._onKeyboardPopupMenu.bind(this));
@ -547,6 +606,14 @@ var DrawingArea = new Lang.Class({
}, },
leaveDrawingMode: function(save) { 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) { if (this.keyPressedHandler) {
this.disconnect(this.keyPressedHandler); this.disconnect(this.keyPressedHandler);
this.keyPressedHandler = null; this.keyPressedHandler = null;
@ -576,15 +643,16 @@ var DrawingArea = new Lang.Class({
this.helper.hideHelp(); this.helper.hideHelp();
this.currentElement = null; this.currentElement = null;
this._stopCursorTimeout(); this._stopTextCursorTimeout();
this.currentShape = Shapes.NONE; this.currentShape = Shapes.NONE;
this.dashedLine = false; this.dashedLine = false;
this.fill = false; this.fill = false;
this._redisplay(); this._redisplay();
this.menu.close(); if (this._menu)
this._menu.close();
this.get_parent().set_background_color(null); this.get_parent().set_background_color(null);
if (save) if (save)
this.saveAsJson(); this.savePersistent();
}, },
saveAsSvg: function() { saveAsSvg: function() {
@ -605,8 +673,7 @@ var DrawingArea = new Lang.Class({
} }
content += "\n</svg>"; content += "\n</svg>";
let date = GLib.DateTime.new_now_local(); let filename = `${Me.metadata['svg-file-name']} ${getDateString()}.svg`;
let filename = `DrawOnYourScreen ${date.format("%F")} ${date.format("%X")}.svg`;
let dir = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_PICTURES); let dir = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_PICTURES);
let path = GLib.build_filenamev([dir, filename]); let path = GLib.build_filenamev([dir, filename]);
if (GLib.file_test(path, GLib.FileTest.EXISTS)) if (GLib.file_test(path, GLib.FileTest.EXISTS))
@ -626,34 +693,73 @@ var DrawingArea = new Lang.Class({
} }
}, },
saveAsJson: function() { _saveAsJson: function(name, notify) {
let filename = `DrawOnYourScreen.json`; // stop drawing or writing
let dir = GLib.get_user_data_dir(); if (this.currentElement && this.currentElement.shape == Shapes.TEXT && this.currentElement.state == TextState.WRITING) {
let path = GLib.build_filenamev([dir, filename]); this._stopWriting();
} else if (this.currentElement && this.currentElement.shape != Shapes.TEXT) {
this._stopDrawing();
}
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; let oldContents;
if (name == Me.metadata['persistent-file-name']) {
if (GLib.file_test(path, GLib.FileTest.EXISTS)) { if (GLib.file_test(path, GLib.FileTest.EXISTS)) {
oldContents = GLib.file_get_contents(path)[1]; oldContents = GLib.file_get_contents(path)[1];
if (oldContents instanceof Uint8Array) if (oldContents instanceof Uint8Array)
oldContents = imports.byteArray.toString(oldContents); oldContents = ByteArray.toString(oldContents);
} }
// do not create a file to write just an empty array // do not create a file to write just an empty array
if (!oldContents && this.elements.length == 0) if (!oldContents && this.elements.length == 0)
return; return;
}
// do not use "content = JSON.stringify(this.elements, null, 2);", neither "content = JSON.stringify(this.elements);" // 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 // 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]`; let contents = `[\n ` + new Array(...this.elements.map(element => JSON.stringify(element))).join(`,\n\n `) + `\n]`;
if (contents != oldContents) if (name == Me.metadata['persistent-file-name'] && contents == oldContents)
return;
GLib.file_set_contents(path, contents); 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() { saveAsJsonWithName: function(name) {
let filename = `DrawOnYourScreen.json`; 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 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)) if (!GLib.file_test(path, GLib.FileTest.EXISTS))
return; return;
@ -661,8 +767,52 @@ var DrawingArea = new Lang.Class({
if (!success) if (!success)
return; return;
if (contents instanceof Uint8Array) if (contents instanceof Uint8Array)
contents = imports.byteArray.toString(contents); contents = ByteArray.toString(contents);
this.elements.push(...JSON.parse(contents).map(object => new DrawingElement(object))); 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() { disable: function() {
@ -674,7 +824,7 @@ var DrawingArea = new Lang.Class({
// DrawingElement represents a "brushstroke". // DrawingElement represents a "brushstroke".
// It can be converted into a cairo path as well as a svg element. // It can be converted into a cairo path as well as a svg element.
// See DrawingArea._startDrawing() to know its params. // See DrawingArea._startDrawing() to know its params.
var DrawingElement = new Lang.Class({ const DrawingElement = new Lang.Class({
Name: 'DrawOnYourScreenDrawingElement', Name: 'DrawOnYourScreenDrawingElement',
_init: function(params) { _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 // calculate angle of rotation in absolute value
// cos(AOB) = (OA.OB)/(||OA||*||OB||) where OA.OB = (xA-xO)*(xB-xO) + (yA-yO)*(yB-yO) // 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)) ); 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) if (xA < xO)
angle = - angle; angle = - angle;
return angle; return angle;
} };
var HELPER_ANIMATION_TIME = 0.25; const HELPER_ANIMATION_TIME = 0.25;
var MEDIA_KEYS_SCHEMA = 'org.gnome.settings-daemon.plugins.media-keys'; const MEDIA_KEYS_SCHEMA = 'org.gnome.settings-daemon.plugins.media-keys';
var MEDIA_KEYS_KEYS = { const MEDIA_KEYS_KEYS = {
'screenshot': "Screenshot", 'screenshot': "Screenshot",
'screenshot-clip': "Screenshot to clipboard", 'screenshot-clip': "Screenshot to clipboard",
'area-screenshot': "Area screenshot", 'area-screenshot': "Area screenshot",
@ -952,7 +1102,7 @@ var DrawingHelper = new Lang.Class({
for (let i = 0; i < Prefs.OTHER_SHORTCUTS.length; i++) { for (let i = 0; i < Prefs.OTHER_SHORTCUTS.length; i++) {
if (Prefs.OTHER_SHORTCUTS[i].desc.indexOf('-separator-') != -1) { 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; continue;
} }
let hbox = new St.BoxLayout({ vertical: false }); let hbox = new St.BoxLayout({ vertical: false });
@ -961,11 +1111,11 @@ var DrawingHelper = new Lang.Class({
this.vbox.add(hbox); 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) { for (let settingKey in Prefs.INTERNAL_KEYBINDINGS) {
if (settingKey.indexOf('-separator-') != -1) { 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; continue;
} }
let hbox = new St.BoxLayout({ vertical: false }); let hbox = new St.BoxLayout({ vertical: false });
@ -997,7 +1147,7 @@ var DrawingHelper = new Lang.Class({
this.opacity = 0; this.opacity = 0;
this.show(); 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_height(Math.min(this.height, maxHeight));
this.set_position(Math.floor(this.monitor.width / 2 - this.width / 2), this.set_position(Math.floor(this.monitor.width / 2 - this.width / 2),
Math.floor(this.monitor.height / 2 - this.height / 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', Name: 'DrawOnYourScreenDrawingMenu',
_init: function(area) { _init: function(area, monitor) {
this.area = area; this.area = area;
let side = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL ? St.Side.RIGHT : St.Side.LEFT; 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); 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); 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.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(); this.menu.actor.hide();
// do not close the menu on item activated // do not close the menu on item activated
this.menu.itemActivated = () => {}; this.menu.itemActivated = () => {};
this.menu.connect('open-state-changed', this._onMenuOpenStateChanged.bind(this)); 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.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.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) }); this.linejoinIcon = new Gio.FileIcon({ file: Gio.File.new_for_path(LINEJOIN_ICON_PATH) });
@ -1062,7 +1229,8 @@ var DrawingMenu = new Lang.Class({
} else { } else {
this.area.updatePointerCursor(); this.area.updatePointerCursor();
// actionMode has changed, set previous actionMode in order to keep internal shortcuts working // 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.menu.addMenuItem(fontSection);
this.fontSection = 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, _("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, _("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._addSwitchItemWithCallback(this.menu, _("Square drawing area"), this.area.isSquareArea, this.area.toggleSquareArea.bind(this.area));
this._addSeparator(this.menu); this._addSeparator(this.menu);
this.menu.addAction(_("Save drawing as a SVG file"), this.area.saveAsSvg.bind(this.area), 'document-save-symbolic'); this._addDrawingNameItem(this.menu);
this.menu.addAction(_("Open stylesheet.css"), manager.openStylesheetFile.bind(manager), 'document-open-symbolic'); this._addOpenDrawingSubMenuItem(this.menu);
this.menu.addAction(_("Show help"), this.area.toggleHelp.bind(this.area), 'preferences-desktop-keyboard-shortcuts-symbolic'); 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(); this.updateSectionVisibility();
}, },
@ -1154,10 +1326,9 @@ var DrawingMenu = new Lang.Class({
_addSwitchItem: function(menu, label, iconFalse, iconTrue, target, targetProperty) { _addSwitchItem: function(menu, label, iconFalse, iconTrue, target, targetProperty) {
let item = new PopupMenu.PopupSwitchMenuItem(label, 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' }); 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.icon.set_gicon(target[targetProperty] ? iconTrue : iconFalse);
item.connect('toggled', (item, state) => { item.connect('toggled', (item, state) => {
@ -1176,34 +1347,32 @@ var DrawingMenu = new Lang.Class({
_addSliderItem: function(menu, target, targetProperty) { _addSliderItem: function(menu, target, targetProperty) {
let item = new PopupMenu.PopupBaseMenuItem({ activate: false }); 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 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 slider = new Slider.Slider(target[targetProperty] / 50);
let sliderActor = GS_VERSION < '3.33.0' ? slider.actor : slider;
if (GS_VERSION < '3.33.0') { if (GS_VERSION < '3.33.0') {
slider.connect('value-changed', (slider, value, property) => { slider.connect('value-changed', (slider, value, property) => {
target[targetProperty] = Math.max(Math.round(value * 50), 0); target[targetProperty] = Math.max(Math.round(value * 50), 0);
label.set_text(target[targetProperty] + " px"); label.set_text(target[targetProperty] + " px");
if (target[targetProperty] === 0) 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 else
label.remove_style_class_name(ExtensionJs.WARNING_COLOR_STYLE_CLASS_NAME); label.remove_style_class_name(Extension.WARNING_COLOR_STYLE_CLASS_NAME);
}); });
} else { } else {
slider.connect('notify::value', () => { slider.connect('notify::value', () => {
target[targetProperty] = Math.max(Math.round(slider.value * 50), 0); target[targetProperty] = Math.max(Math.round(slider.value * 50), 0);
label.set_text(target[targetProperty] + " px"); label.set_text(target[targetProperty] + " px");
if (target[targetProperty] === 0) 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 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 }); getActor(item).add(getActor(slider), { expand: true });
itemActor.add(label); getActor(item).add(label);
itemActor.connect('key-press-event', slider.onKeyPressEvent.bind(slider)); getActor(item).connect('key-press-event', slider.onKeyPressEvent.bind(slider));
menu.addMenuItem(item); menu.addMenuItem(item);
}, },
@ -1269,11 +1438,200 @@ var DrawingMenu = new Lang.Class({
menu.addMenuItem(item); 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) { _addSeparator: function(menu) {
let separator = new PopupMenu.PopupSeparatorMenuItem(' '); let separatorItem = new PopupMenu.PopupSeparatorMenuItem(' ');
let separatorActor = GS_VERSION < '3.33.0' ? separator.actor : separator; getActor(separatorItem).add_style_class_name('draw-on-your-screen-menu-separator-item');
separatorActor.add_style_class_name('draw-on-your-screen-menu-separator'); menu.addMenuItem(separatorItem);
menu.addMenuItem(separator);
} }
}); });
// 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 * 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 * https://framagit.org/abakkk/DrawOnYourScreen
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -21,6 +21,7 @@
*/ */
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang; const Lang = imports.lang;
const Meta = imports.gi.Meta; const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell; const Shell = imports.gi.Shell;
@ -31,10 +32,11 @@ const Main = imports.ui.main;
const OsdWindow = imports.ui.osdWindow; const OsdWindow = imports.ui.osdWindow;
const PanelMenu = imports.ui.panelMenu; const PanelMenu = imports.ui.panelMenu;
const Extension = imports.misc.extensionUtils.getCurrentExtension(); const ExtensionUtils = imports.misc.extensionUtils;
const Convenience = Extension.imports.convenience; const Me = ExtensionUtils.getCurrentExtension();
const Draw = Extension.imports.draw; const Convenience = ExtensionUtils.getSettings && ExtensionUtils.initTranslations ? ExtensionUtils : Me.imports.convenience;
const _ = imports.gettext.domain(Extension.metadata["gettext-domain"]).gettext; const Draw = Me.imports.draw;
const _ = imports.gettext.domain(Me.metadata['gettext-domain']).gettext;
const GS_VERSION = Config.PACKAGE_VERSION; 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.desktopSettingHandler = this.settings.connect('changed::drawing-on-desktop', this.onDesktopSettingChanged.bind(this));
this.persistentSettingHandler = this.settings.connect('changed::persistent-drawing', this.onPersistentSettingChanged.bind(this)); this.persistentSettingHandler = this.settings.connect('changed::persistent-drawing', this.onPersistentSettingChanged.bind(this));
if (Extension.stylesheet) { this.userStyleFile = Gio.File.new_for_path(GLib.build_filenamev([GLib.get_user_data_dir(), Me.metadata['data-dir'], 'user.css']));
this.stylesheetMonitor = Extension.stylesheet.monitor(Gio.FileMonitorFlags.NONE, null);
this.stylesheetChangedHandler = this.stylesheetMonitor.connect('changed', (monitor, file, otherFile, eventType) => { if (this.userStyleFile.query_exists(null)) {
if ((eventType != 0 && eventType != 3) || !Extension.stylesheet.query_exists(null))
return;
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
theme.unload_stylesheet(Extension.stylesheet); theme.load_stylesheet(this.userStyleFile);
theme.load_stylesheet(Extension.stylesheet);
});
} }
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() { onDesktopSettingChanged: function() {
@ -113,7 +124,7 @@ var AreaManager = new Lang.Class({
onPersistentSettingChanged: function() { onPersistentSettingChanged: function() {
if (this.settings.get_boolean('persistent-drawing')) if (this.settings.get_boolean('persistent-drawing'))
this.areas[Main.layoutManager.primaryIndex].saveAsJson(); this.areas[Main.layoutManager.primaryIndex].syncPersistent();
}, },
updateIndicator: function() { updateIndicator: function() {
@ -136,8 +147,8 @@ var AreaManager = new Lang.Class({
let monitor = this.monitors[i]; let monitor = this.monitors[i];
let container = new St.Widget({ name: 'drawOnYourSreenContainer' + i }); let container = new St.Widget({ name: 'drawOnYourSreenContainer' + i });
let helper = new Draw.DrawingHelper({ name: 'drawOnYourSreenHelper' + i }, monitor); let helper = new Draw.DrawingHelper({ name: 'drawOnYourSreenHelper' + i }, monitor);
let load = i == Main.layoutManager.primaryIndex && this.settings.get_boolean('persistent-drawing'); let loadPersistent = i == Main.layoutManager.primaryIndex && this.settings.get_boolean('persistent-drawing');
let area = new Draw.DrawingArea({ name: 'drawOnYourSreenArea' + i }, monitor, helper, load); let area = new Draw.DrawingArea({ name: 'drawOnYourSreenArea' + i }, monitor, helper, loadPersistent);
container.add_child(area); container.add_child(area);
container.add_child(helper); container.add_child(helper);
@ -161,6 +172,9 @@ var AreaManager = new Lang.Class({
'delete-last-element': this.activeArea.deleteLastElement.bind(this.activeArea), 'delete-last-element': this.activeArea.deleteLastElement.bind(this.activeArea),
'smooth-last-element': this.activeArea.smoothLastElement.bind(this.activeArea), 'smooth-last-element': this.activeArea.smoothLastElement.bind(this.activeArea),
'save-as-svg': this.activeArea.saveAsSvg.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-background': this.activeArea.toggleBackground.bind(this.activeArea),
'toggle-square-area': this.activeArea.toggleSquareArea.bind(this.activeArea), 'toggle-square-area': this.activeArea.toggleSquareArea.bind(this.activeArea),
'increment-line-width': () => this.activeArea.incrementLineWidth(1), '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-font-style': this.activeArea.toggleFontStyle.bind(this.activeArea),
'toggle-panel-and-dock-visibility': this.togglePanelAndDockOpacity.bind(this), 'toggle-panel-and-dock-visibility': this.togglePanelAndDockOpacity.bind(this),
'toggle-help': this.activeArea.toggleHelp.bind(this.activeArea), '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) { for (let key in this.internalKeybindings) {
@ -212,9 +226,19 @@ var AreaManager = new Lang.Class({
} }
}, },
openStylesheetFile: function() { openUserStyleFile: function() {
if (Extension.stylesheet && Extension.stylesheet.query_exists(null)) if (!this.userStyleFile.query_exists(null)) {
Gio.AppInfo.launch_default_for_uri(Extension.stylesheet.get_uri(), global.create_app_launch_context(0, -1)); 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) if (this.activeArea)
this.toggleDrawing(); this.toggleDrawing();
}, },
@ -223,7 +247,7 @@ var AreaManager = new Lang.Class({
for (let i = 0; i < this.areas.length; i++) for (let i = 0; i < this.areas.length; i++)
this.areas[i].erase(); this.areas[i].erase();
if (this.settings.get_boolean('persistent-drawing')) if (this.settings.get_boolean('persistent-drawing'))
this.areas[Main.layoutManager.primaryIndex].saveAsJson(); this.areas[Main.layoutManager.primaryIndex].savePersistent();
}, },
togglePanelAndDockOpacity: function() { togglePanelAndDockOpacity: function() {
@ -315,11 +339,12 @@ var AreaManager = new Lang.Class({
}, },
// use level -1 to set no level (null) // use level -1 to set no level (null)
showOsd: function(emitter, label, level, maxLevel) { showOsd: function(emitter, iconName, label, level) {
if (this.osdDisabled) if (this.osdDisabled)
return; return;
let activeIndex = this.areas.indexOf(this.activeArea); let activeIndex = this.areas.indexOf(this.activeArea);
if (activeIndex != -1) { if (activeIndex != -1) {
let maxLevel;
if (level == -1) if (level == -1)
level = null; level = null;
else if (level > 100) else if (level > 100)
@ -329,7 +354,9 @@ var AreaManager = new Lang.Class({
// GS 3.34+ : bar from 0 to 1 // GS 3.34+ : bar from 0 to 1
if (level && GS_VERSION > '3.33.0') if (level && GS_VERSION > '3.33.0')
level = level / 100; 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); Main.osdWindowManager._osdWindows[activeIndex]._label.get_clutter_text().set_use_markup(true);
if (level === 0) { if (level === 0) {
@ -357,9 +384,13 @@ var AreaManager = new Lang.Class({
}, },
disable: function() { disable: function() {
if (this.stylesheetChangedHandler) { if (this.userStyleHandler && this.userStyleMonitor) {
this.stylesheetMonitor.disconnect(this.stylesheetChangedHandler); this.userStyleMonitor.disconnect(this.userStyleHandler);
this.stylesheetChangedHandler = null; this.userStyleHandler = null;
}
if (this.userStyleMonitor) {
this.userStyleMonitor.cancel();
this.userStyleMonitor = null;
} }
if (this.monitorChangedHandler) { if (this.monitorChangedHandler) {
Main.layoutManager.disconnect(this.monitorChangedHandler); Main.layoutManager.disconnect(this.monitorChangedHandler);

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Draw On Your Screen VERSION\n" "Project-Id-Version: Draw On Your Screen VERSION\n"
"Report-Msgid-Bugs-To: https://framagit.org/abakkk/DrawOnYourScreen/issues\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" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -19,17 +19,17 @@ msgstr ""
# Add your name here, for example: # Add your name here, for example:
# (add "\n" as separator if there is many translators) # (add "\n" as separator if there is many translators)
# msgid "Translators" # msgid "translator-credits"
# msgstr "Me" # msgstr "Me"
# or, with mail: # or, with mail:
# msgid "Translators" # msgid "translator-credits"
# msgstr "<a href=\"mailto:me@mail.org\">Me</a>" # msgstr "<a href=\"mailto:me@mail.org\">Me</a>"
# or, with page: # or, with page:
# msgid "Translators" # msgid "translator-credits"
# msgstr "<a href=\"https://...\">Me</a>" # msgstr "<a href=\"https://...\">Me</a>"
# else keep it empty. # else keep it empty.
# It will be displayed in about page # It will be displayed in about page
msgid "Translators" msgid "translator-credits"
msgstr "" msgstr ""
#: extension.js #: extension.js
@ -108,6 +108,12 @@ msgstr ""
msgid "Color" msgid "Color"
msgstr "" msgstr ""
msgid "Open drawing"
msgstr ""
msgid "Save drawing"
msgstr ""
#: prefs.js #: prefs.js
msgid "Preferences" msgid "Preferences"
@ -196,10 +202,20 @@ msgstr ""
msgid "Square drawing area" msgid "Square drawing area"
msgstr "" 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" msgid "Save drawing as a SVG file"
msgstr "" msgstr ""
msgid "Open stylesheet.css" msgid "Edit style"
msgstr "" msgstr ""
msgid "Show help" msgid "Show help"
@ -246,6 +262,12 @@ msgstr ""
msgid "Shift key held" msgid "Shift key held"
msgstr "" msgstr ""
msgid "Ignore pointer movement"
msgstr ""
msgid "Space key held"
msgstr ""
msgid "Leave" msgid "Leave"
msgstr "" msgstr ""
@ -269,18 +291,18 @@ msgstr ""
msgid "Global" msgid "Global"
msgstr "" msgstr ""
msgid "Drawing on the desktop"
msgstr ""
msgid "Draw On Your Screen becomes Draw On Your Desktop"
msgstr ""
msgid "Persistent" msgid "Persistent"
msgstr "" msgstr ""
msgid "Persistent drawing through session restart" msgid "Persistent drawing through session restart"
msgstr "" 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" msgid "Disable on-screen notifications"
msgstr "" msgstr ""
@ -297,32 +319,24 @@ msgid ""
"By pressing <b>Ctrl</b> key <b>during</b> the drawing process, you can:\n" "By pressing <b>Ctrl</b> key <b>during</b> the drawing process, you can:\n"
" . rotate a rectangle or a text area\n" " . rotate a rectangle or a text area\n"
" . extend and rotate an ellipse\n" " . extend and rotate an ellipse\n"
" . curve a line (cubic Bezier curve)" " . curve a line (cubic Bezier curve)\n"
msgstr "" " . smooth a free drawing stroke (you may prefer to smooth the stroke afterward, see <i>“%s”</i>)"
msgid "Smooth stroke during the drawing process"
msgstr "" msgstr ""
msgid "" msgid ""
"You can also smooth the stroke afterward\n" "<b>Default</b> drawing style attributes (color palette, font, line, dash) are defined in an editable <b>css</b> file.\n"
"See “%s”" "See <i>“%s”</i>."
msgstr ""
msgid "Change the style"
msgstr ""
msgid "See stylesheet.css"
msgstr "" msgstr ""
msgid "" 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" "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 "" msgstr ""
# The following words refer to SVG attributes. # 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" #msgid "Butt"
#msgstr "" #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", "url": "https://framagit.org/abakkk/DrawOnYourScreen",
"settings-schema": "org.gnome.shell.extensions.draw-on-your-screen", "settings-schema": "org.gnome.shell.extensions.draw-on-your-screen",
"gettext-domain": "draw-on-your-screen", "gettext-domain": "draw-on-your-screen",
"data-dir": "drawOnYourScreen",
"persistent-file-name": "persistent",
"svg-file-name": "DrawOnYourScreen",
"shell-version": [ "shell-version": [
"3.24", "3.24",
"3.26", "3.26",
@ -13,5 +16,5 @@
"3.32", "3.32",
"3.34" "3.34"
], ],
"version": 5 "version": 5.1
} }

173
prefs.js
View File

@ -3,7 +3,7 @@
/* /*
* Copyright 2019 Abakkk * 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 * https://framagit.org/abakkk/DrawOnYourScreen
* *
* This program is free software: you can redistribute it and/or modify * 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 Mainloop = imports.mainloop;
const ExtensionUtils = imports.misc.extensionUtils; const ExtensionUtils = imports.misc.extensionUtils;
const Extension = ExtensionUtils.getCurrentExtension(); const Me = ExtensionUtils.getCurrentExtension();
const Convenience = Extension.imports.convenience; const Convenience = ExtensionUtils.getSettings && ExtensionUtils.initTranslations ? ExtensionUtils : Me.imports.convenience;
const Metadata = Extension.metadata; const _ = imports.gettext.domain(Me.metadata['gettext-domain']).gettext;
const _ = imports.gettext.domain(Extension.metadata["gettext-domain"]).gettext;
const _GTK = imports.gettext.domain('gtk30').gettext; const _GTK = imports.gettext.domain('gtk30').gettext;
const MARGIN = 10; const MARGIN = 10;
@ -68,8 +67,11 @@ var INTERNAL_KEYBINDINGS = {
'toggle-background': "Add a drawing background", 'toggle-background': "Add a drawing background",
'toggle-square-area': "Square drawing area", 'toggle-square-area': "Square drawing area",
'-separator-5': '', '-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", 'save-as-svg': "Save drawing as a SVG file",
'open-stylesheet': "Open stylesheet.css", 'open-user-stylesheet': "Edit style",
'toggle-help': "Show help" 'toggle-help': "Show help"
}; };
@ -81,6 +83,7 @@ var OTHER_SHORTCUTS = [
{ desc: "Increment/decrement line width", shortcut: "Scroll" }, { desc: "Increment/decrement line width", shortcut: "Scroll" },
{ desc: "Select color", shortcut: "Ctrl+1...9" }, { desc: "Select color", shortcut: "Ctrl+1...9" },
{ desc: "Select eraser", shortcut: "Shift key held" }, { desc: "Select eraser", shortcut: "Shift key held" },
{ desc: "Ignore pointer movement", shortcut: "Space key held" },
{ desc: "Leave", shortcut: "Escape key" } { desc: "Leave", shortcut: "Escape key" }
]; ];
@ -103,7 +106,7 @@ function buildPrefsWidget() {
return topStack; return topStack;
} }
var TopStack = new GObject.Class({ const TopStack = new GObject.Class({
Name: 'DrawOnYourScreenTopStack', Name: 'DrawOnYourScreenTopStack',
GTypeName: 'DrawOnYourScreenTopStack', GTypeName: 'DrawOnYourScreenTopStack',
Extends: Gtk.Stack, Extends: Gtk.Stack,
@ -117,7 +120,7 @@ var TopStack = new GObject.Class({
} }
}); });
var AboutPage = new GObject.Class({ const AboutPage = new GObject.Class({
Name: 'DrawOnYourScreenAboutPage', Name: 'DrawOnYourScreenAboutPage',
GTypeName: 'DrawOnYourScreenAboutPage', GTypeName: 'DrawOnYourScreenAboutPage',
Extends: Gtk.ScrolledWindow, Extends: Gtk.ScrolledWindow,
@ -128,10 +131,10 @@ var AboutPage = new GObject.Class({
let vbox= new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, margin: MARGIN*3 }); let vbox= new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, margin: MARGIN*3 });
this.add(vbox); this.add(vbox);
let name = "<b> " + _(Metadata.name) + "</b>"; let name = "<b> " + _(Me.metadata.name) + "</b>";
let version = _("Version %d").format(Metadata.version); let version = _("Version %d").format(Me.metadata.version);
let description = _(Metadata.description); let description = _(Me.metadata.description);
let link = "<span><a href=\"" + Metadata.url + "\">" + Metadata.url + "</a></span>"; 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 licenceName = _GTK("GNU General Public License, version 2 or later");
let licenceLink = "https://www.gnu.org/licenses/old-licenses/gpl-2.0.html"; 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>"; 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); creditBox.pack_start(rightBox, true, true, 5);
vbox.add(creditBox); vbox.add(creditBox);
if (_("Translators") != "Translators" && _("Translators") != "") { if (_("translator-credits") != "translator-credits" && _("translator-credits") != "") {
leftBox.pack_start(new Gtk.Label(), false, false, 0); leftBox.pack_start(new Gtk.Label(), false, false, 0);
rightBox.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>" }); 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); leftBox.pack_start(leftLabel, false, false, 0);
rightBox.pack_start(rightLabel, 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', Name: 'DrawOnYourScreenPrefsPage',
GTypeName: 'DrawOnYourScreenPrefsPage', GTypeName: 'DrawOnYourScreenPrefsPage',
Extends: Gtk.ScrolledWindow, Extends: Gtk.ScrolledWindow,
@ -177,80 +180,85 @@ var PrefsPage = new GObject.Class({
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); this.add(box);
let listBox = new Gtk.ListBox({ selection_mode: 0, hexpand: true }); let globalFrame = new Gtk.Frame({ label_yalign: 1.0 });
box.add(listBox); 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(); let styleContext = listBox.get_style_context();
styleContext.add_class('background'); 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); let globalKeybindingsWidget = new KeybindingsWidget(GLOBAL_KEYBINDINGS, this.settings);
globalKeybindingsWidget.margin = MARGIN; globalKeybindingsWidget.margin = MARGIN;
listBox.add(globalKeybindingsWidget); listBox.add(globalKeybindingsWidget);
let desktopBox = 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 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 persistentLabelBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL }); let persistentLabelBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
let persistentLabel1 = new Gtk.Label({label: _("Persistent")}); 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); 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(persistentLabel1, true, true, 0);
persistentLabelBox.pack_start(persistentLabel2, true, true, 0); persistentLabelBox.pack_start(persistentLabel2, true, true, 0);
let persistentSwitch = new Gtk.Switch({valign: 3}); 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(persistentLabelBox, true, true, 4);
persistentBox.pack_start(persistentSwitch, false, false, 4); persistentBox.pack_start(persistentSwitch, false, false, 4);
listBox.add(persistentBox); 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 osdLabelBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
let osdLabel1 = new Gtk.Label({label: _("Disable on-screen notifications")}); let osdLabel1 = new Gtk.Label({label: _("Disable on-screen notifications")});
osdLabel1.set_halign(1); osdLabel1.set_halign(1);
osdLabelBox.pack_start(osdLabel1, true, true, 0); osdLabelBox.pack_start(osdLabel1, true, true, 0);
let osdSwitch = new Gtk.Switch({valign: 3}); 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(osdLabelBox, true, true, 4);
osdBox.pack_start(osdSwitch, false, false, 4); osdBox.pack_start(osdSwitch, false, false, 4);
listBox.add(osdBox); 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 indicatorLabelBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
let indicatorLabel1 = new Gtk.Label({label: _("Disable panel indicator")}); let indicatorLabel1 = new Gtk.Label({label: _("Disable panel indicator")});
indicatorLabel1.set_halign(1); indicatorLabel1.set_halign(1);
indicatorLabelBox.pack_start(indicatorLabel1, true, true, 0); indicatorLabelBox.pack_start(indicatorLabel1, true, true, 0);
let indicatorSwitch = new Gtk.Switch({valign: 3}); 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(indicatorLabelBox, true, true, 4);
indicatorBox.pack_start(indicatorSwitch, false, false, 4); indicatorBox.pack_start(indicatorSwitch, false, false, 4);
listBox.add(indicatorBox); listBox.add(indicatorBox);
this.addSeparator(listBox);
let internalTitleBox = new Gtk.Box({ margin: MARGIN }); let children = listBox.get_children();
let internalTitleLabel = new Gtk.Label({ use_markup: true, label: "<b><big>" + _("Internal") + " </big></b>" + _("(in drawing mode)") + " <b><big>:</big></b>" }); for (let i = 0; i < children.length; i++) {
internalTitleLabel.set_halign(1); if (children[i].activatable)
internalTitleBox.pack_start(internalTitleLabel, true, true, 4); children[i].set_activatable(false);
listBox.add(internalTitleBox); }
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++) { for (let i = 0; i < OTHER_SHORTCUTS.length; i++) {
if (OTHER_SHORTCUTS[i].desc.indexOf('-separator-') != -1) { if (OTHER_SHORTCUTS[i].desc.indexOf('-separator-') != -1) {
@ -266,70 +274,63 @@ var PrefsPage = new GObject.Class({
listBox.add(otherBox); listBox.add(otherBox);
} }
listBox.add(new Gtk.Box({ margin_top: MARGIN, margin_left: MARGIN, margin_right: MARGIN })); let controlBox = new Gtk.Box({ margin: MARGIN, margin_top: 2*MARGIN });
let controlBox = new Gtk.Box({ margin_top: MARGIN, margin_left: MARGIN, margin_right: MARGIN, margin_bottom:MARGIN });
let controlLabel = new Gtk.Label({ let controlLabel = new Gtk.Label({
wrap: true,
xalign: 0,
use_markup: true, 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.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); controlBox.pack_start(controlLabel, true, true, 4);
listBox.add(controlBox); 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); let internalKeybindingsWidget = new KeybindingsWidget(INTERNAL_KEYBINDINGS, this.settings);
internalKeybindingsWidget.margin = MARGIN; internalKeybindingsWidget.margin = MARGIN;
listBox.add(internalKeybindingsWidget); listBox.add(internalKeybindingsWidget);
let styleBox = new Gtk.Box({ margin_top: MARGIN, margin_left: MARGIN, margin_right: MARGIN, margin_bottom:MARGIN }); let styleBox = new Gtk.Box({ margin: MARGIN });
let styleLabel = new Gtk.Label({ label: _("Change the style") }); 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); 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(styleLabel, true, true, 4);
styleBox.pack_start(styleLabel2, false, false, 4);
listBox.add(styleBox); 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({ let noteLabel = new Gtk.Label({
wrap: true,
xalign: 0,
use_markup: true, 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.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); noteBox.pack_start(noteLabel, true, true, 4);
listBox.add(noteBox); listBox.add(noteBox);
let children = listBox.get_children(); children = listBox.get_children();
for (let i = 0; i < children.length; i++) { for (let i = 0; i < children.length; i++) {
if (children[i].activatable) if (children[i].activatable)
children[i].set_activatable(false); 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/ // 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', Name: 'DrawOnYourScreenKeybindings.Widget',
GTypeName: 'DrawOnYourScreenKeybindingsWidget', GTypeName: 'DrawOnYourScreenKeybindingsWidget',
Extends: Gtk.Box, Extends: Gtk.Box,

Binary file not shown.

View File

@ -1,11 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<schemalist gettext-domain="gnome-shell-extensions"> <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"> <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"> <key type="b" name="drawing-on-desktop">
<default>false</default> <default>false</default>
<summary>move drawing on desktop</summary> <summary>move drawing on desktop</summary>
@ -107,12 +102,12 @@
<description>decrement the line width</description> <description>decrement the line width</description>
</key> </key>
<key type="as" name="increment-line-width-more"> <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> <summary>increment the line width even more</summary>
<description>increment the line width even more</description> <description>increment the line width even more</description>
</key> </key>
<key type="as" name="decrement-line-width-more"> <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> <summary>decrement the line width even more</summary>
<description>decrement the line width even more</description> <description>decrement the line width even more</description>
</key> </key>
@ -196,16 +191,31 @@
<summary>toggle font style</summary> <summary>toggle font style</summary>
<description>toggle font style</description> <description>toggle font style</description>
</key> </key>
<key type="as" name="open-stylesheet"> <key type="as" name="open-user-stylesheet">
<default>["&lt;Primary&gt;o"]</default> <default>["&lt;Primary&gt;o"]</default>
<summary>open stylesheet</summary> <summary>open user stylesheet to edit style</summary>
<description>open stylesheet</description> <description>open user stylesheet to edit style</description>
</key> </key>
<key type="as" name="save-as-svg"> <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> <summary>Save drawing as a svg file</summary>
<description>Save drawing as a svg file</description> <description>Save drawing as a svg file</description>
</key> </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"> <key type="as" name="toggle-help">
<default>["&lt;Primary&gt;F1"]</default> <default>["&lt;Primary&gt;F1"]</default>
<summary>toggle help</summary> <summary>toggle help</summary>

View File

@ -1,50 +1,6 @@
/* @import "./data/default.css";
* 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 { /* The following styles don't affect the drawing */
-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;
}
/*********************************************/
/* square area */ /* square area */
@ -56,8 +12,7 @@
outline: none; outline: none;
} }
/* The following styles don't affect the drawing, /* "Ctrl + F1" on-screen-display */
* but the "Ctrl + F1" on-screen-display */
.draw-on-your-screen-helper { .draw-on-your-screen-helper {
margin: 0; margin: 0;
@ -73,36 +28,71 @@
font-weight: normal; font-weight: normal;
} }
.draw-on-your-screen-separator { .draw-on-your-screen-helper-separator {
min-height: 0.6em; min-height: 0.6em;
} }
/* context menu */ /* context menu */
.draw-on-your-screen-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 { .draw-on-your-screen-menu .popup-menu-item {
padding-top: .37em; /* default: .4em */ padding-top: .3em; /* default: .4em */
padding-bottom: .37em; padding-bottom: .3em;
} }
.draw-on-your-screen-menu .popup-menu-icon { .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 { .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; 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 { .draw-on-your-screen-menu-slider-label {
min-width: 3em; min-width: 3em;
text-align: right; 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;
}