replace user stylesheet with proper drawing settings

Since the most drawing params can be changed via menu or shortcuts, remove default.css and user.css.

* Missing params like palettes, dash, grid, etc, are added to prefs.
* Add palette choice to menu and shortcuts.
* Some defaults like fonts, line width, etc, are no longer modifiable by the user.
This commit is contained in:
abakkk 2020-08-31 09:43:00 +02:00
parent 01701538bb
commit b3a1a77160
10 changed files with 665 additions and 342 deletions

189
area.js
View File

@ -45,6 +45,7 @@ const _ = imports.gettext.domain(Me.metadata['gettext-domain']).gettext;
const CAIRO_DEBUG_EXTENDS = false;
const SVG_DEBUG_EXTENDS = false;
const TEXT_CURSOR_TIME = 600; // ms
const GRID_TILES_HORIZONTAL_NUMBER = 30;
const { Shapes, ShapeNames, Transformations, LineCapNames, LineJoinNames, FillRuleNames,
FontWeightNames, FontStyleNames, FontStretchNames, FontVariantNames } = Elements;
@ -55,6 +56,16 @@ var ToolNames = Object.assign({}, ShapeNames, ManipulationNames);
var FontGenericFamilies = ['Sans-Serif', 'Serif', 'Monospace', 'Cursive', 'Fantasy'];
const getClutterColorFromString = function(string, fallback) {
let [success, color] = Clutter.Color.from_string(string);
color.string = string;
if (success)
return color;
log(`${Me.metadata.uuid}: "${string}" color cannot be parsed.`);
return Clutter.Color.get_static(Clutter.StaticColor[fallback]);
};
// DrawingArea is the widget in which we draw, thanks to Cairo.
// It creates and manages a DrawingElement for each "brushstroke".
// It handles pointer/mouse/(touch?) events and some keyboard events.
@ -68,28 +79,39 @@ var DrawingArea = new Lang.Class({
_init: function(params, monitor, helper, loadPersistent) {
this.parent({ style_class: 'draw-on-your-screen', name: params.name});
this.connect('destroy', this._onDestroy.bind(this));
this.reactiveHandler = this.connect('notify::reactive', this._onReactiveChanged.bind(this));
this.monitor = monitor;
this.helper = helper;
this.elements = [];
this.undoneElements = [];
this.defaultFontFamily = 'Cantarell';
this.currentElement = null;
this.currentTool = Shapes.NONE;
this.currentImage = 0;
this.currentFontFamily = this.defaultFontFamily;
this.currentFontStyle = Pango.Style.NORMAL;
this.currentFontWeight = Pango.Weight.NORMAL;
this.currentFontStretch = Pango.Stretch.NORMAL;
this.currentFontVariant = Pango.Variant.NORMAL;
this.currentTextRightAligned = false;
this.currentLineWidth = 5;
this.currentLineJoin = Cairo.LineJoin.ROUND;
this.currentLineCap = Cairo.LineCap.ROUND;
this.currentFillRule = Cairo.FillRule.WINDING;
this.isSquareArea = false;
this.hasGrid = false;
this.hasBackground = false;
this.textHasCursor = false;
this.dashedLine = false;
this.fill = false;
this.colors = [Clutter.Color.new(0, 0, 0, 255)];
this.newThemeAttributes = {};
this.oldThemeAttributes = {};
this.connect('destroy', this._onDestroy.bind(this));
this.connect('notify::reactive', this._onReactiveChanged.bind(this));
this.drawingSettingsChangedHandler = Me.drawingSettings.connect('changed', this._onDrawingSettingsChanged.bind(this));
this._onDrawingSettingsChanged();
if (loadPersistent)
this._loadPersistent();
},
@ -121,6 +143,17 @@ var DrawingArea = new Lang.Class({
this._stopElementGrabber();
},
get currentPalette() {
return this._currentPalette;
},
set currentPalette(palette) {
this._currentPalette = palette;
this.colors = palette[1].map(colorString => getClutterColorFromString(colorString, 'WHITE'));
if (!this.colors[0])
this.colors.push(Clutter.Color.get_static(Clutter.StaticColor.WHITE));
},
get hasManipulationTool() {
// No Object.values method in GS 3.24.
return Object.keys(Manipulations).map(key => Manipulations[key]).indexOf(this.currentTool) != -1;
@ -142,20 +175,12 @@ var DrawingArea = new Lang.Class({
return images;
},
get currentFontFamily() {
return this._currentFontFamily || this.currentThemeFontFamily;
},
set currentFontFamily(fontFamily) {
this._currentFontFamily = fontFamily;
},
get fontFamilies() {
if (!this._fontFamilies) {
let pangoFontFamilies = Elements.getPangoFontFamilies().filter(family => {
return family != this.currentThemeFontFamily && FontGenericFamilies.indexOf(family) == -1;
return family != this.defaultFontFamily && FontGenericFamilies.indexOf(family) == -1;
});
this._fontFamilies = [this.currentThemeFontFamily].concat(FontGenericFamilies, pangoFontFamilies);
this._fontFamilies = [this.defaultFontFamily].concat(FontGenericFamilies, pangoFontFamilies);
}
return this._fontFamilies;
},
@ -179,57 +204,44 @@ var DrawingArea = new Lang.Class({
this.queue_repaint();
},
_updateStyle: function() {
try {
let themeNode = this.get_theme_node();
for (let i = 1; i < 10; i++) {
this.colors[i] = themeNode.get_color('-drawing-color' + i);
}
let font = themeNode.get_font();
this.newThemeAttributes.ThemeFontFamily = font.get_family();
try { this.newThemeAttributes.FontWeight = font.get_weight(); } catch(e) { this.newThemeAttributes.FontWeight = Pango.Weight.NORMAL; }
this.newThemeAttributes.FontStyle = font.get_style();
this.newThemeAttributes.FontStretch = font.get_stretch();
this.newThemeAttributes.FontVariant = font.get_variant();
this.newThemeAttributes.TextRightAligned = themeNode.get_text_align() == St.TextAlign.RIGHT;
this.newThemeAttributes.LineWidth = themeNode.get_length('-drawing-line-width');
this.newThemeAttributes.LineJoin = themeNode.get_double('-drawing-line-join');
this.newThemeAttributes.LineCap = themeNode.get_double('-drawing-line-cap');
this.newThemeAttributes.FillRule = themeNode.get_double('-drawing-fill-rule');
this.dashArray = [Math.abs(themeNode.get_length('-drawing-dash-array-on')), Math.abs(themeNode.get_length('-drawing-dash-array-off'))];
this.dashOffset = themeNode.get_length('-drawing-dash-offset');
this.gridGap = themeNode.get_length('-grid-overlay-gap');
this.gridLineWidth = themeNode.get_length('-grid-overlay-line-width');
this.gridInterlineWidth = themeNode.get_length('-grid-overlay-interline-width');
this.gridColor = themeNode.get_color('-grid-overlay-color');
this.squareAreaWidth = themeNode.get_length('-drawing-square-area-width');
this.squareAreaHeight = themeNode.get_length('-drawing-square-area-height');
this.activeBackgroundColor = themeNode.get_color('-drawing-background-color');
} catch(e) {
logError(e);
_onDrawingSettingsChanged: function() {
this.palettes = Me.drawingSettings.get_value('palettes').deep_unpack();
if (!this.colors) {
if (this.palettes[0])
this.currentPalette = this.palettes[0];
else
this.currentPalette = ['Palette', ['White']];
}
if (!this.currentColor)
this.currentColor = this.colors[0];
if (Me.drawingSettings.get_boolean('square-area-auto')) {
this.squareAreaSize = Math.pow(2, 6);
while (this.squareAreaSize * 2 < Math.min(this.monitor.width, this.monitor.height))
this.squareAreaSize *= 2;
} else {
this.squareAreaSize = Math.max(64, Me.drawingSettings.get_uint('square-area-size'));
}
for (let i = 1; i < 10; i++) {
this.colors[i] = this.colors[i].alpha ? this.colors[i] : this.colors[0];
this.areaBackgroundColor = getClutterColorFromString(Me.drawingSettings.get_string('area-background-color'), 'BLACK');
this.gridColor = getClutterColorFromString(Me.drawingSettings.get_string('grid-color'), 'GRAY');
if (Me.drawingSettings.get_boolean('grid-line-auto')) {
this.gridLineSpacing = Math.round(this.monitor.width / (5 * GRID_TILES_HORIZONTAL_NUMBER));
this.gridLineWidth = this.gridLineSpacing / 20;
} else {
this.gridLineSpacing = Math.max(1, Me.drawingSettings.get_uint('grid-line-spacing'));
this.gridLineWidth = Math.round(Math.max(0.1, Me.drawingSettings.get_double('grid-line-width')) * 100) / 100;
}
this.currentColor = this.currentColor || this.colors[1];
this._fontFamilies = null;
// SVG does not support 'Ultra-heavy' weight (1000)
this.newThemeAttributes.FontWeight = Math.min(this.newThemeAttributes.FontWeight, 900);
this.newThemeAttributes.LineWidth = (this.newThemeAttributes.LineWidth > 0) ? this.newThemeAttributes.LineWidth : 3;
this.newThemeAttributes.LineJoin = ([0, 1, 2].indexOf(this.newThemeAttributes.LineJoin) != -1) ? this.newThemeAttributes.LineJoin : Cairo.LineJoin.ROUND;
this.newThemeAttributes.LineCap = ([0, 1, 2].indexOf(this.newThemeAttributes.LineCap) != -1) ? this.newThemeAttributes.LineCap : Cairo.LineCap.ROUND;
this.newThemeAttributes.FillRule = ([0, 1].indexOf(this.newThemeAttributes.FillRule) != -1) ? this.newThemeAttributes.FillRule : Cairo.FillRule.WINDING;
for (let attributeName in this.newThemeAttributes) {
if (this.newThemeAttributes[attributeName] != this.oldThemeAttributes[attributeName]) {
this.oldThemeAttributes[attributeName] = this.newThemeAttributes[attributeName];
this[`current${attributeName}`] = this.newThemeAttributes[attributeName];
}
this.dashOffset = Math.round(Me.drawingSettings.get_double('dash-offset') * 100) / 100;
if (Me.drawingSettings.get_boolean('dash-array-auto')) {
this.dashArray = [0, 0];
} else {
let on = Math.round(Math.max(0, Me.drawingSettings.get_double('dash-array-on')) * 100) / 100;
let off = Math.round(Math.max(0, Me.drawingSettings.get_double('dash-array-off')) * 100) / 100;
this.dashArray = [on, off];
}
this.gridGap = this.gridGap && this.gridGap >= 1 ? this.gridGap : 10;
this.gridLineWidth = this.gridLineWidth || 0.4;
this.gridInterlineWidth = this.gridInterlineWidth || 0.2;
this.gridColor = this.gridColor && this.gridColor.alpha ? this.gridColor : Clutter.Color.new(127, 127, 127, 255);
},
_repaint: function(cr) {
@ -267,27 +279,27 @@ var DrawingArea = new Lang.Class({
cr.restore();
}
if (this.reactive && this.hasGrid && this.gridGap && this.gridGap >= 1) {
if (this.reactive && this.hasGrid) {
cr.save();
Clutter.cairo_set_source_color(cr, this.gridColor);
let [gridX, gridY] = [0, 0];
while (gridX < this.monitor.width / 2) {
cr.setLineWidth((gridX / this.gridGap) % 5 ? this.gridInterlineWidth : this.gridLineWidth);
cr.setLineWidth((gridX / this.gridLineSpacing) % 5 ? this.gridLineWidth / 2 : this.gridLineWidth);
cr.moveTo(this.monitor.width / 2 + gridX, 0);
cr.lineTo(this.monitor.width / 2 + gridX, this.monitor.height);
cr.moveTo(this.monitor.width / 2 - gridX, 0);
cr.lineTo(this.monitor.width / 2 - gridX, this.monitor.height);
gridX += this.gridGap;
gridX += this.gridLineSpacing;
cr.stroke();
}
while (gridY < this.monitor.height / 2) {
cr.setLineWidth((gridY / this.gridGap) % 5 ? this.gridInterlineWidth : this.gridLineWidth);
cr.setLineWidth((gridY / this.gridLineSpacing) % 5 ? this.gridLineWidth / 2 : this.gridLineWidth);
cr.moveTo(0, this.monitor.height / 2 + gridY);
cr.lineTo(this.monitor.width, this.monitor.height / 2 + gridY);
cr.moveTo(0, this.monitor.height / 2 - gridY);
cr.lineTo(this.monitor.width, this.monitor.height / 2 - gridY);
gridY += this.gridGap;
gridY += this.gridLineSpacing;
cr.stroke();
}
cr.restore();
@ -833,7 +845,7 @@ var DrawingArea = new Lang.Class({
toggleBackground: function() {
this.hasBackground = !this.hasBackground;
this.get_parent().set_background_color(this.hasBackground ? this.activeBackgroundColor : null);
this.get_parent().set_background_color(this.hasBackground ? this.areaBackgroundColor : null);
},
toggleGrid: function() {
@ -844,10 +856,8 @@ var DrawingArea = new Lang.Class({
toggleSquareArea: function() {
this.isSquareArea = !this.isSquareArea;
if (this.isSquareArea) {
let width = this.squareAreaWidth || this.squareAreaHeight || Math.min(this.monitor.width, this.monitor.height) * 3 / 4;
let height = this.squareAreaHeight || this.squareAreaWidth || Math.min(this.monitor.width, this.monitor.height) * 3 / 4;
this.set_position(Math.floor(this.monitor.width / 2 - width / 2), Math.floor(this.monitor.height / 2 - height / 2));
this.set_size(width, height);
this.set_position((this.monitor.width - this.squareAreaSize) / 2, (this.monitor.height - this.squareAreaSize) / 2);
this.set_size(this.squareAreaSize, this.squareAreaSize);
this.add_style_class_name('draw-on-your-screen-square-area');
} else {
this.set_position(0, 0);
@ -856,18 +866,17 @@ var DrawingArea = new Lang.Class({
}
},
switchColor: function() {
this.selectColor((this.currentColor == this.colors[1]) ? 2 : 1);
},
selectColor: function(index) {
if (!this.colors[index])
return;
this.currentColor = this.colors[index];
if (this.currentElement) {
this.currentElement.color = this.currentColor.to_string();
this._redisplay();
}
// Foreground color markup is not displayed since 3.36, use style instead but the transparency is lost.
this.emit('show-osd', null, this.currentColor.to_string(), this.currentColor.to_string().slice(0, 7), -1, false);
this.emit('show-osd', null, this.currentColor.string || this.currentColor.to_string(), this.currentColor.to_string().slice(0, 7), -1, false);
},
selectTool: function(tool) {
@ -881,6 +890,20 @@ var DrawingArea = new Lang.Class({
this.emit('show-osd', null, this.fill ? _("Fill") : _("Outline"), "", -1, false);
},
switchFillRule: function() {
this.currentFillRule = this.currentFillRule == 1 ? 0 : this.currentFillRule + 1;
this.emit('show-osd', null, _(FillRuleNames[this.currentFillRule]), "", -1, false);
},
switchColorPalette: function(reverse) {
let index = this.palettes.indexOf(this.currentPalette);
if (reverse)
this.currentPalette = index <= 0 ? this.palettes[this.palettes.length - 1] : this.palettes[index - 1];
else
this.currentPalette = index == this.palettes.length - 1 ? this.palettes[0] : this.palettes[index + 1];
this.emit('show-osd', null, this.currentPalette[0], "", -1, false);
},
switchDash: function() {
this.dashedLine = !this.dashedLine;
this.emit('show-osd', null, this.dashedLine ? _("Dashed line") : _("Full line"), "", -1, false);
@ -901,11 +924,6 @@ var DrawingArea = new Lang.Class({
this.emit('show-osd', null, _(LineCapNames[this.currentLineCap]), "", -1, false);
},
switchFillRule: function() {
this.currentFillRule = this.currentFillRule == 1 ? 0 : this.currentFillRule + 1;
this.emit('show-osd', null, _(FillRuleNames[this.currentFillRule]), "", -1, false);
},
switchFontWeight: function() {
let fontWeights = Object.keys(FontWeightNames).map(key => Number(key));
let index = fontWeights.indexOf(this.currentFontWeight);
@ -982,7 +1000,7 @@ var DrawingArea = new Lang.Class({
},
_onDestroy: function() {
this.disconnect(this.reactiveHandler);
Me.drawingSettings.disconnect(this.drawingSettingsChangedHandler);
this.erase();
if (this._menu)
this._menu.disable();
@ -999,8 +1017,7 @@ var DrawingArea = new Lang.Class({
this.buttonPressedHandler = this.connect('button-press-event', this._onButtonPressed.bind(this));
this.keyboardPopupMenuHandler = this.connect('popup-menu', this._onKeyboardPopupMenu.bind(this));
this.scrollHandler = this.connect('scroll-event', this._onScroll.bind(this));
this.get_parent().set_background_color(this.reactive && this.hasBackground ? this.activeBackgroundColor : null);
this._updateStyle();
this.get_parent().set_background_color(this.reactive && this.hasBackground ? this.areaBackgroundColor : null);
},
leaveDrawingMode: function(save) {
@ -1060,7 +1077,7 @@ var DrawingArea = new Lang.Class({
let content = `<svg viewBox="0 0 ${this.width} ${this.height}" ${prefixes}>`;
if (SVG_DEBUG_EXTENDS)
content = `<svg viewBox="${-this.width} ${-this.height} ${2 * this.width} ${2 * this.height}" xmlns="http://www.w3.org/2000/svg">`;
let backgroundColorString = this.hasBackground ? this.activeBackgroundColor.to_string() : 'transparent';
let backgroundColorString = this.hasBackground ? this.areaBackgroundColor.to_string() : 'transparent';
if (backgroundColorString != 'transparent') {
content += `\n <rect id="background" width="100%" height="100%" fill="${backgroundColorString}"/>`;
}

View File

@ -1,151 +0,0 @@
/*
* WARNING : user.css may be obsolete after an extension update.
*
* ~/.local/share/drawOnYourScreen/user.css file is automatically generated by activating "Edit style".
* Delete ~/.local/share/drawOnYourScreen/user.css file to retrieve the default drawing style.
*
* 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.
* Some attributes are modifiable in the user interface.
*
* line-join (no string):
* 0 : miter, 1 : round, 2 : bevel
* line-cap (no string):
* 0 : butt, 1 : round, 2 : square
* fill-rule (no string):
* 0 : nonzero (winding in Cairo), 1 : evenodd
*
* dash:
* By default, it is computed from the line width.
* dash-array-on is the length of dashes (put 0.1 to get dots or squares according to line-cap).
* dash-array-off is the length of gaps.
*
* 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.
*
* text-align: left or right.
*
*/
.draw-on-your-screen {
-drawing-line-width: 5px;
-drawing-line-join: 1;
-drawing-line-cap: 1;
-drawing-fill-rule: 0;
/*-drawing-dash-array-on: 5px;*/
/*-drawing-dash-array-off: 15px;*/
/*-drawing-dash-offset: 0px;*/
-drawing-background-color: #2e2e2e;
-grid-overlay-gap: 10px;
-grid-overlay-line-width: 0.4px;
-grid-overlay-interline-width: 0.2px;
-grid-overlay-color: Gray;
/*-drawing-square-area-width: 512px;*/
/*-drawing-square-area-height: 512px;*/
font-family: Cantarell;
font-weight: normal;
font-style: normal;
text-align: left;
}
/* Palette */
.draw-on-your-screen {
-drawing-color1: HotPink;
-drawing-color2: Cyan;
-drawing-color3: yellow;
-drawing-color4: Orangered;
-drawing-color5: Chartreuse;
-drawing-color6: DarkViolet;
-drawing-color7: White;
-drawing-color8: Gray;
-drawing-color9: Black;
}
/*
Example of alternative palettes from GNOME HIG Colors.
https://developer.gnome.org/hig/stable/icon-design.html
The last uncommented palette wins.
*/
/* lighter */
/*
.draw-on-your-screen {
-drawing-color1: rgb(153, 193, 241);
-drawing-color2: rgb(143, 240, 164);
-drawing-color3: rgb(249, 240, 107);
-drawing-color4: rgb(255, 190, 111);
-drawing-color5: rgb(246, 97, 81);
-drawing-color6: rgb(220, 138, 221);
-drawing-color7: rgb(205, 171, 143);
-drawing-color8: rgb(255, 255, 255);
-drawing-color9: rgb(119, 118, 123);
}
*/
/* light */
/*
.draw-on-your-screen {
-drawing-color1: rgb( 98, 160, 241);
-drawing-color2: rgb( 87, 227, 137);
-drawing-color3: rgb(248, 228, 92);
-drawing-color4: rgb(255, 163, 72);
-drawing-color5: rgb(237, 51, 59);
-drawing-color6: rgb(192, 97, 203);
-drawing-color7: rgb(181, 131, 90);
-drawing-color8: rgb(246, 245, 244);
-drawing-color9: rgb( 94, 92, 100);
}
*/
/* normal */
/*
.draw-on-your-screen {
-drawing-color1: rgb( 53, 132, 228);
-drawing-color2: rgb( 51, 209, 122);
-drawing-color3: rgb(246, 211, 45);
-drawing-color4: rgb(255, 120, 0);
-drawing-color5: rgb(224, 27, 36);
-drawing-color6: rgb(145, 65, 172);
-drawing-color7: rgb(152, 106, 68);
-drawing-color8: rgb(222, 221, 218);
-drawing-color9: rgb( 61, 56, 70);
}
*/
/* dark */
/*
.draw-on-your-screen {
-drawing-color1: rgb( 28, 113, 216);
-drawing-color2: rgb( 46, 194, 126);
-drawing-color3: rgb(245, 194, 17);
-drawing-color4: rgb(230, 97, 0);
-drawing-color5: rgb(192, 28, 40);
-drawing-color6: rgb(129, 61, 156);
-drawing-color7: rgb(134, 94, 60);
-drawing-color8: rgb(192, 191, 188);
-drawing-color9: rgb( 36, 31, 49);
}
*/
/* darker */
/*
.draw-on-your-screen {
-drawing-color1: rgb( 26, 095, 180);
-drawing-color2: rgb( 38, 162, 105);
-drawing-color3: rgb(229, 165, 10);
-drawing-color4: rgb(198, 70, 0);
-drawing-color5: rgb(165, 29, 45);
-drawing-color6: rgb( 97, 53, 131);
-drawing-color7: rgb( 99, 69, 44);
-drawing-color8: rgb(154, 153, 150);
-drawing-color9: rgb( 0, 0, 0);
}
*/

View File

@ -0,0 +1,32 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
<metadata>
Created by potrace 1.15, written by Peter Selinger 2001-2017
https://svgsilh.com/image/2026954.html
https://creativecommons.org/publicdomain/zero/1.0/
</metadata>
<g transform="translate(0,128) scale(1,-1)" fill="#555" stroke="none">
<path d="M61.4 111.9 c-11.9 -0.8 -22.5 -5.4 -30.9 -13.6 -7.6 -7.5 -12.5
-17 -14 -27.4 -0.4 -2.6 -0.5 -3.8 -0.5 -7 0 -4.4 0.4 -7.6 1.4 -11.7 0.9
-3.5 1.8 -6 3.5 -9.5 1.9 -3.8 3.6 -6.5 6.4 -9.8 1.2 -1.4 4.6 -4.8 6.2
-6.1 7.1 -5.8 15.4 -9.4 24.4 -10.6 3.1 -0.4 6.9 -0.5 8 -0.2 1.8 0.5 3.3 1.4
4.3 2.8 1.3 1.6 1.9 3.5 1.8 5.6 -0.1 2 -0.7 3.3 -2.2 5.1 -0.7 0.8 -1.4 2.2
-1.6 3.2 -0.3 1 -0.3 2.9 0 3.8 0.6 2.4 2.3 4.4 4.5 5.4 1.5 0.7 1.4 0.7 8.9 0.8
3.7 0 6.9 0.1 7 0.1 0.1 0 0.7 0.1 1.3 0.2 5.4 0.9 10.5 3.5 14.5 7.5 3.2 3.3 5.4
6.9 6.7 11.3 1.1 3.6 1.3 8.1 0.7 12.7 -1.9 13.4 -10.7 25.1 -23.8 31.8 -5.8
3 -12 4.7 -18.7 5.4 -1.5 0.2 -6.5 0.3 -7.9 0.2z m-8.4 -10.9 c2.7 -0.9 4.7
-3 5.5 -5.7 0.3 -1.1 0.3 -2.9 0 -4 -0.7 -2.8 -3 -5 -5.8 -5.8 -1.1 -0.3
-2.8 -0.3 -3.9 0 -2.8 0.7 -4.8 2.7 -5.7 5.5 -0.3 0.9 -0.4 2.7 -0.2 3.7 0.5 3.1 3
5.7 6.1 6.4 0.9 0.2 3.1 0.1 4 -0.2z m26 0.2 c3.2 -0.7 5.7 -3.3 6.2 -6.4 0.2
-1 0.1 -2.8 -0.2 -3.7 -0.9 -2.8 -2.9 -4.7 -5.7 -5.5 -1.1 -0.3 -2.8 -0.3 -3.9 0
-2.8 0.7 -5 2.3 -5.8 5.8 -0.3 1.1 -0.3 2.9 0 4 0.8 3 3.2 5.3 6.2 5.9 0.7
0.1 2.4 0.1 3.2 0z m-43.1 -21.3 c1.8 -0.3 3.1 -1 4.5 -2.3 1.3 -1.3 2 -2.7
2.3 -4.6 0.3 -2.5 -0.6 -5 -2.5 -6.7 -1 -0.9 -2 -1.5 -3.4 -1.9 -1 -0.3
-3 -0.3 -4 0 -3.6 1 -6 4.1 -6 7.8 0 1.7 0.4 3.1 1.3 4.4 1.8 2.6 4.9
4 7.9 3.5z m59.6 -0.2 c3.5 -1 5.8 -4.1 5.8 -7.7 0 -1.7 -0.4 -3 -1.3 -4.3
-2.5 -3.9 -7.7 -4.8 -11.5 -2.1 -1.2 0.9 -2.4 2.5 -2.9 4 -0.9 2.7 -0.2 5.8
1.8 7.9 1.2 1.3 2.7 2.1 4.4 2.5 1 0.2 2.7 0.1 3.6 -0.2z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -21,7 +21,6 @@
*/
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
@ -57,6 +56,7 @@ function init() {
function enable() {
Me.settings = Convenience.getSettings();
Me.internalShortcutSettings = Convenience.getSettings(Me.metadata['settings-schema'] + '.internal-shortcuts');
Me.drawingSettings = Convenience.getSettings(Me.metadata['settings-schema'] + '.drawing');
manager = new AreaManager();
}
@ -105,26 +105,6 @@ var AreaManager = new Lang.Class({
this.desktopSettingHandler = Me.settings.connect('changed::drawing-on-desktop', this.onDesktopSettingChanged.bind(this));
this.persistentSettingHandler = Me.settings.connect('changed::persistent-drawing', this.onPersistentSettingChanged.bind(this));
this.userStyleFile = Gio.File.new_for_path(GLib.build_filenamev([GLib.get_user_data_dir(), Me.metadata['data-dir'], 'user.css']));
if (this.userStyleFile.query_exists(null)) {
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
theme.load_stylesheet(this.userStyleFile);
}
this.userStyleMonitor = this.userStyleFile.monitor_file(Gio.FileMonitorFlags.WATCH_MOVES, null);
this.userStyleHandler = this.userStyleMonitor.connect('changed', (monitor, file, otherFile, eventType) => {
// 'CHANGED' events are followed by a 'CHANGES_DONE_HINT' event
if (eventType == Gio.FileMonitorEvent.CHANGED || eventType == Gio.FileMonitorEvent.ATTRIBUTE_CHANGED)
return;
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
if (theme.get_custom_stylesheets().indexOf(this.userStyleFile) != -1)
theme.unload_stylesheet(this.userStyleFile);
if (this.userStyleFile.query_exists(null))
theme.load_stylesheet(this.userStyleFile);
});
},
onDesktopSettingChanged: function() {
@ -218,14 +198,15 @@ var AreaManager = new Lang.Class({
'toggle-background': this.activeArea.toggleBackground.bind(this.activeArea),
'toggle-grid': this.activeArea.toggleGrid.bind(this.activeArea),
'toggle-square-area': this.activeArea.toggleSquareArea.bind(this.activeArea),
'reverse-switch-font-family': this.activeArea.switchFontFamily.bind(this.activeArea, true),
'switch-color-palette': this.activeArea.switchColorPalette.bind(this.activeArea, false),
'switch-color-palette-reverse': this.activeArea.switchColorPalette.bind(this.activeArea, true),
'switch-font-family': this.activeArea.switchFontFamily.bind(this.activeArea, false),
'switch-font-family-reverse': this.activeArea.switchFontFamily.bind(this.activeArea, true),
'switch-font-weight': this.activeArea.switchFontWeight.bind(this.activeArea),
'switch-font-style': this.activeArea.switchFontStyle.bind(this.activeArea),
'switch-text-alignment': this.activeArea.switchTextAlignment.bind(this.activeArea),
'toggle-panel-and-dock-visibility': this.togglePanelAndDockOpacity.bind(this),
'toggle-help': this.activeArea.toggleHelp.bind(this.activeArea),
'open-user-stylesheet': this.openUserStyleFile.bind(this),
'open-preferences': this.openPreferences.bind(this)
};
@ -251,7 +232,7 @@ var AreaManager = new Lang.Class({
Me.internalShortcutSettings,
Meta.KeyBindingFlags.NONE,
DRAWING_ACTION_MODE | WRITING_ACTION_MODE,
() => this.activeArea.selectColor(iCaptured));
this.activeArea.selectColor.bind(this.activeArea, iCaptured - 1));
}
},
@ -275,23 +256,6 @@ var AreaManager = new Lang.Class({
}
},
openUserStyleFile: function() {
if (!this.userStyleFile.query_exists(null)) {
if (!this.userStyleFile.get_parent().query_exists(null))
this.userStyleFile.get_parent().make_directory_with_parents(null);
let defaultStyleFile = Me.dir.get_child('data').get_child('default.css');
if (!defaultStyleFile.query_exists(null))
return;
let success = defaultStyleFile.copy(this.userStyleFile, Gio.FileCopyFlags.NONE, null, null);
if (!success)
return;
}
Gio.AppInfo.launch_default_for_uri(this.userStyleFile.get_uri(), global.create_app_launch_context(0, -1));
if (this.activeArea)
this.toggleDrawing();
},
eraseDrawing: function() {
for (let i = 0; i < this.areas.length; i++)
this.areas[i].erase();
@ -521,14 +485,6 @@ var AreaManager = new Lang.Class({
},
disable: function() {
if (this.userStyleHandler && this.userStyleMonitor) {
this.userStyleMonitor.disconnect(this.userStyleHandler);
this.userStyleHandler = null;
}
if (this.userStyleMonitor) {
this.userStyleMonitor.cancel();
this.userStyleMonitor = null;
}
if (this.monitorChangedHandler) {
Main.layoutManager.disconnect(this.monitorChangedHandler);
this.monitorChangedHandler = null;

View File

@ -47,6 +47,90 @@ msgstr ""
msgid "translator-credits"
msgstr ""
msgid "Drawing"
msgstr ""
msgid "Palettes"
msgstr ""
msgid "The palettes of drawing colors"
msgstr ""
msgid "Palette"
msgstr ""
msgid "Add a new palette"
msgstr ""
msgid "New palette"
msgstr ""
msgid "Rename the palette"
msgstr ""
msgid "Remove the palette"
msgstr ""
msgid "Auto"
msgstr ""
msgid "Area"
msgstr ""
msgid "Square area size"
msgstr ""
msgid "Compute the size of the square area from the screen size"
msgstr ""
msgid "The size of the square area in pixels"
msgstr ""
msgid "Background color"
msgstr ""
msgid "The color of the drawing area background"
msgstr ""
msgid "Grid overlay line"
msgstr ""
msgid "Compute the lengths from the screen size"
msgstr ""
msgid "The line width in pixels"
msgstr ""
msgid "The gap between lines in pixels"
msgstr ""
msgid "Grid overlay color"
msgstr ""
msgid "The color of the lines"
msgstr ""
msgid "Tools"
msgstr ""
msgid "Dash array"
msgstr ""
msgid "Compute the lengths from the line width"
msgstr ""
msgid "The dash length in pixels"
msgstr ""
msgid "The gap between the dashes in pixels"
msgstr ""
msgid "Dash offset"
msgstr ""
msgid "The dash offset in pixels"
msgstr ""
msgid "Preferences"
msgstr ""
@ -197,6 +281,15 @@ msgstr ""
msgid "Toggle fill/outline"
msgstr ""
msgid "Toggle fill rule"
msgstr ""
msgid "Change color palette"
msgstr ""
msgid "Change color palette (reverse)"
msgstr ""
msgid "Increment line width"
msgstr ""
@ -215,9 +308,6 @@ msgstr ""
msgid "Change linecap"
msgstr ""
msgid "Toggle fill rule"
msgstr ""
msgid "Change font family"
msgstr ""
@ -257,20 +347,12 @@ msgstr ""
msgid "Save drawing as a SVG file"
msgstr ""
msgid "Edit style"
msgstr ""
msgid "Open preferences"
msgstr ""
msgid "Show help"
msgstr ""
msgid ""
"<b>Default</b> drawing style attributes (color palette, font, line, dash) are defined in an editable <b>css</b> file.\n"
"See <i>“%s”</i>."
msgstr ""
msgid ""
"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"

67
menu.js
View File

@ -46,6 +46,7 @@ const GS_VERSION = Config.PACKAGE_VERSION;
const ICON_DIR = Me.dir.get_child('data').get_child('icons');
const SMOOTH_ICON_PATH = ICON_DIR.get_child('smooth-symbolic.svg').get_path();
const PALETTE_ICON_PATH = ICON_DIR.get_child('palette-symbolic.svg').get_path();
const COLOR_ICON_PATH = ICON_DIR.get_child('color-symbolic.svg').get_path();
const FILL_ICON_PATH = ICON_DIR.get_child('fill-symbolic.svg').get_path();
const STROKE_ICON_PATH = ICON_DIR.get_child('stroke-symbolic.svg').get_path();
@ -95,6 +96,7 @@ var DrawingMenu = new Lang.Class({
menuCloseFunc.bind(this.menu)(animate);
};
this.paletteIcon = new Gio.FileIcon({ file: Gio.File.new_for_path(PALETTE_ICON_PATH) });
this.colorIcon = new Gio.FileIcon({ file: Gio.File.new_for_path(COLOR_ICON_PATH) });
this.smoothIcon = new Gio.FileIcon({ file: Gio.File.new_for_path(SMOOTH_ICON_PATH) });
this.strokeIcon = new Gio.FileIcon({ file: Gio.File.new_for_path(STROKE_ICON_PATH) });
@ -164,6 +166,7 @@ var DrawingMenu = new Lang.Class({
this._addSeparator(this.menu, true);
this._addSubMenuItem(this.menu, 'document-edit-symbolic', Area.ToolNames, this.area, 'currentTool', this._updateSectionVisibility.bind(this));
this.paletteItem = this._addPaletteSubMenuItem(this.menu);
this.colorItem = this._addColorSubMenuItem(this.menu);
this.fillItem = this._addSwitchItem(this.menu, _("Fill"), this.strokeIcon, this.fillIcon, this.area, 'fill', this._updateSectionVisibility.bind(this));
this.fillSection = new PopupMenu.PopupMenuSection();
@ -216,7 +219,7 @@ var DrawingMenu = new Lang.Class({
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(_("Open preferences"), manager.openPreferences.bind(manager), 'document-page-setup-symbolic');
this.menu.addAction(_("Show help"), () => { this.close(); this.area.toggleHelp(); }, 'preferences-desktop-keyboard-shortcuts-symbolic');
this._updateActionSensitivity();
@ -254,6 +257,7 @@ var DrawingMenu = new Lang.Class({
this.fontSection.actor.visible = isText;
this.imageSection.actor.visible = isImage;
this.colorItem.setSensitive(!isImage);
this.paletteItem.setSensitive(!isImage);
this.fillItem.setSensitive(!isText && !isImage);
this.fillSection.setSensitive(!isText && !isImage);
@ -374,8 +378,37 @@ var DrawingMenu = new Lang.Class({
menu.addMenuItem(item);
},
_addPaletteSubMenuItem: function(menu) {
let text = _(this.area.currentPalette[0] || "Palette");
let item = new PopupMenu.PopupSubMenuMenuItem(text, true);
item.icon.set_gicon(this.paletteIcon);
item.menu.itemActivated = () => {
item.menu.close();
};
GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => {
this.area.palettes.forEach(palette => {
let [name, colors] = palette;
if (!colors[0])
return;
let subItem = item.menu.addAction(_(name || "Palette"), () => {
item.label.set_text(_(name || "Palette"));
this.area.currentPalette = palette;
this._populateColorSubMenu();
});
getActor(subItem).connect('key-focus-in', updateSubMenuAdjustment);
});
return GLib.SOURCE_REMOVE;
});
menu.addMenuItem(item);
return item;
},
_addColorSubMenuItem: function(menu) {
let item = new PopupMenu.PopupSubMenuMenuItem(_("Color"), true);
this.colorSubMenu = item.menu;
item.icon.set_gicon(this.colorIcon);
item.icon.set_style(`color:${this.area.currentColor.to_string().slice(0, 7)};`);
@ -383,24 +416,28 @@ var DrawingMenu = new Lang.Class({
item.menu.close();
};
GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => {
for (let i = 1; i < this.area.colors.length; i++) {
let text = this.area.colors[i].to_string();
let iCaptured = i;
let colorItem = item.menu.addAction(text, () => {
this.area.currentColor = this.area.colors[iCaptured];
item.icon.set_style(`color:${this.area.currentColor.to_string().slice(0, 7)};`);
});
// Foreground color markup is not displayed since 3.36, use style instead but the transparency is lost.
colorItem.label.set_style(`color:${this.area.colors[i].to_string().slice(0, 7)};`);
getActor(colorItem).connect('key-focus-in', updateSubMenuAdjustment);
}
return GLib.SOURCE_REMOVE;
});
this._populateColorSubMenu();
menu.addMenuItem(item);
return item;
},
_populateColorSubMenu: function() {
this.colorSubMenu.removeAll();
GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => {
this.area.colors.forEach(color => {
let text = color.string || color.to_string();
let subItem = this.colorSubMenu.addAction(text, () => {
this.area.currentColor = color;
this.colorItem.icon.set_style(`color:${color.to_string().slice(0, 7)};`);
});
// Foreground color markup is not displayed since 3.36, use style instead but the transparency is lost.
subItem.label.set_style(`color:${color.to_string().slice(0, 7)};`);
getActor(subItem).connect('key-focus-in', updateSubMenuAdjustment);
});
return GLib.SOURCE_REMOVE;
});
},
_addFontFamilySubMenuItem: function(menu, icon) {
let item = new PopupMenu.PopupSubMenuMenuItem(this.area.currentFontFamily, true);
item.icon.set_icon_name(icon);

317
prefs.js
View File

@ -20,16 +20,21 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
const Gdk = imports.gi.Gdk;
const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Config = imports.misc.config;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Convenience = ExtensionUtils.getSettings && ExtensionUtils.initTranslations ? ExtensionUtils : Me.imports.convenience;
const _ = imports.gettext.domain(Me.metadata['gettext-domain']).gettext;
const gettext = imports.gettext.domain(Me.metadata['gettext-domain']).gettext;
const _ = function(string) {
if (!string)
return "";
return gettext(string);
};
const _GTK = imports.gettext.domain('gtk30').gettext;
const GS_VERSION = Config.PACKAGE_VERSION;
@ -61,6 +66,8 @@ var INTERNAL_KEYBINDINGS = {
'-separator-2': '',
'switch-fill': "Toggle fill/outline",
'switch-fill-rule': "Toggle fill rule",
'switch-color-palette': "Change color palette",
'switch-color-palette-reverse': "Change color palette (reverse)",
'-separator-3': '',
'increment-line-width': "Increment line width",
'decrement-line-width': "Decrement line width",
@ -71,7 +78,7 @@ var INTERNAL_KEYBINDINGS = {
'switch-dash': "Dashed line",
'-separator-4': '',
'switch-font-family': "Change font family",
'reverse-switch-font-family': "Change font family (reverse)",
'switch-font-family-reverse': "Change font family (reverse)",
'switch-font-weight': "Change font weight",
'switch-font-style': "Change font style",
'switch-text-alignment': "Toggle text alignment",
@ -86,7 +93,6 @@ var INTERNAL_KEYBINDINGS = {
'open-next-json': "Open next drawing",
'save-as-json': "Save drawing",
'save-as-svg': "Save drawing as a SVG file",
'open-user-stylesheet': "Edit style",
'open-preferences': "Open preferences",
'toggle-help': "Show help"
};
@ -128,7 +134,6 @@ function buildPrefsWidget() {
let switcher = new Gtk.StackSwitcher({halign: Gtk.Align.CENTER, visible: true, stack: topStack});
GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => {
let window = topStack.get_toplevel();
window.resize(720,500);
let headerBar = window.get_titlebar();
headerBar.custom_title = switcher;
return false;
@ -147,6 +152,8 @@ const TopStack = new GObject.Class({
this.parent({ transition_type: 1, transition_duration: 500, expand: true });
this.prefsPage = new PrefsPage();
this.add_titled(this.prefsPage, 'prefs', _("Preferences"));
this.drawingPage = new DrawingPage();
this.add_titled(this.drawingPage, 'drawing', _("Drawing"));
this.aboutPage = new AboutPage();
this.add_titled(this.aboutPage, 'about', _("About"));
}
@ -158,7 +165,7 @@ const AboutPage = new GObject.Class({
Extends: Gtk.ScrolledWindow,
_init: function(params) {
this.parent();
this.parent({ hscrollbar_policy: Gtk.PolicyType.NEVER });
let vbox= new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, margin: MARGIN*3 });
this.add(vbox);
@ -199,13 +206,213 @@ const AboutPage = new GObject.Class({
});
const DrawingPage = new GObject.Class({
Name: 'DrawOnYourScreenDrawingPage',
GTypeName: 'DrawOnYourScreenDrawingPage',
Extends: Gtk.ScrolledWindow,
_init: function(params) {
this.parent({ hscrollbar_policy: Gtk.PolicyType.NEVER });
this.settings = Convenience.getSettings(Me.metadata['settings-schema'] + '.drawing');
this.schema = this.settings.settings_schema;
let box = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, margin: MARGIN*3 });
this.add(box);
let palettesFrame = new Gtk.Frame({ label_yalign: 1.0 });
palettesFrame.set_label_widget(new Gtk.Label({ margin_bottom: MARGIN/2, use_markup: true, label: "<b><big>" + _("Palettes") + "</big></b>" }));
box.add(palettesFrame);
let palettesScrolledWindow = new Gtk.ScrolledWindow({ vscrollbar_policy: Gtk.PolicyType.NEVER, margin_top: MARGIN/2, margin_bottom: MARGIN/2 });
palettesFrame.add(palettesScrolledWindow);
this.palettesListBox = new Gtk.ListBox({ selection_mode: 0, hexpand: true });
this.palettesListBox.get_style_context().add_class('background');
palettesScrolledWindow.add(this.palettesListBox);
this.settings.connect('changed::palettes', this._updatePalettes.bind(this));
this._updatePalettes();
this.addBox = new Gtk.Box({ margin_top: MARGIN/2, margin_bottom: MARGIN/2, margin_left: MARGIN, margin_right: MARGIN, tooltip_text: _("Add a new palette") });
let addButton = Gtk.Button.new_from_icon_name('list-add-symbolic', Gtk.IconSize.BUTTON);
this.addBox.pack_start(addButton, true, true, 4);
addButton.connect('clicked', this._addNewPalette.bind(this));
this.palettesListBox.add(this.addBox);
this.addBox.get_parent().set_activatable(false);
let areaFrame = new Gtk.Frame({ margin_top: 3*MARGIN, label_yalign: 1.0 });
areaFrame.set_label_widget(new Gtk.Label({ margin_bottom: MARGIN/2, use_markup: true, label: "<b><big>" + _("Area") + "</big></b>" }));
box.add(areaFrame);
let areaListBox = new Gtk.ListBox({ selection_mode: 0, hexpand: true, margin_top: MARGIN/2, margin_bottom: MARGIN/2 });
areaListBox.get_style_context().add_class('background');
areaFrame.add(areaListBox);
let squareAreaRow = new PrefRow({ label: _("Square area size") });
let squareAreaAutoButton = new Gtk.CheckButton({ label: _("Auto"), tooltip_text: _(this.schema.get_key('square-area-auto').get_description()) });
let squareAreaSizeButton = new PixelSpinButton({ width_chars: 5, digits: 0,
adjustment: Gtk.Adjustment.new(0, 64, 32768, 1, 10, 0),
tooltip_text: _(this.schema.get_key('square-area-size').get_description()) });
this.settings.bind('square-area-auto', squareAreaAutoButton, 'active', 0);
this.settings.bind('square-area-size', squareAreaSizeButton, 'value', 0);
squareAreaAutoButton.bind_property('active', squareAreaSizeButton, 'sensitive', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.INVERT_BOOLEAN);
squareAreaRow.addWidget(squareAreaAutoButton);
squareAreaRow.addWidget(squareAreaSizeButton);
areaListBox.add(squareAreaRow);
let backgroundColorRow = new PrefRow({ label: _("Background color") });
let backgroundColorButton = new ColorStringButton({ use_alpha: true, show_editor: true,
tooltip_text: _(this.schema.get_key('area-background-color').get_description()) });
this.settings.bind('area-background-color', backgroundColorButton, 'color-string', 0);
backgroundColorRow.addWidget(backgroundColorButton);
areaListBox.add(backgroundColorRow);
let gridLineRow = new PrefRow({ label: _("Grid overlay line") });
let gridLineAutoButton = new Gtk.CheckButton({ label: _("Auto"), tooltip_text: _(this.schema.get_key('grid-line-auto').get_description()) });
let gridLineWidthButton = new PixelSpinButton({ width_chars: 5, digits: 1,
adjustment: Gtk.Adjustment.new(0, 0.1, 10, 0.1, 1, 0),
tooltip_text: _(this.schema.get_key('grid-line-width').get_description()) });
let gridLineSpacingButton = new PixelSpinButton({ width_chars: 5, digits: 1,
adjustment: Gtk.Adjustment.new(0, 1, 16384, 1, 10, 0),
tooltip_text: _(this.schema.get_key('grid-line-spacing').get_description()) });
this.settings.bind('grid-line-auto', gridLineAutoButton, 'active', 0);
this.settings.bind('grid-line-width', gridLineWidthButton, 'value', 0);
this.settings.bind('grid-line-spacing', gridLineSpacingButton, 'value', 0);
gridLineAutoButton.bind_property('active', gridLineWidthButton, 'sensitive', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.INVERT_BOOLEAN);
gridLineAutoButton.bind_property('active', gridLineSpacingButton, 'sensitive', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.INVERT_BOOLEAN);
gridLineRow.addWidget(gridLineAutoButton);
gridLineRow.addWidget(gridLineWidthButton);
gridLineRow.addWidget(gridLineSpacingButton);
areaListBox.add(gridLineRow);
let gridColorRow = new PrefRow({ label: _("Grid overlay color") });
let gridColorButton = new ColorStringButton({ use_alpha: true, show_editor: true,
tooltip_text: _(this.schema.get_key('grid-color').get_description()) });
this.settings.bind('grid-color', gridColorButton, 'color-string', 0);
gridColorRow.addWidget(gridColorButton);
areaListBox.add(gridColorRow);
let toolsFrame = new Gtk.Frame({ margin_top: 3*MARGIN, label_yalign: 1.0 });
toolsFrame.set_label_widget(new Gtk.Label({ margin_bottom: MARGIN/2, use_markup: true, label: "<b><big>" + _("Tools") + "</big></b>" }));
box.add(toolsFrame);
let toolsListBox = new Gtk.ListBox({ selection_mode: 0, hexpand: true, margin_top: MARGIN/2, margin_bottom: MARGIN/2 });
toolsListBox.get_style_context().add_class('background');
toolsFrame.add(toolsListBox);
let dashArrayRow = new PrefRow({ label: _("Dash array") });
let dashArrayAutoButton = new Gtk.CheckButton({ label: _("Auto"), tooltip_text: _(this.schema.get_key('dash-array-auto').get_description()) });
let dashArrayOnButton = new PixelSpinButton({ width_chars: 5, digits: 1,
adjustment: Gtk.Adjustment.new(0, 0, 16384, 0.1, 1, 0),
tooltip_text: _(this.schema.get_key('dash-array-on').get_description()) });
let dashArrayOffButton = new PixelSpinButton({ width_chars: 5, digits: 1,
adjustment: Gtk.Adjustment.new(0, 0, 16384, 0.1, 1, 0),
tooltip_text: _(this.schema.get_key('dash-array-off').get_description()) });
this.settings.bind('dash-array-auto', dashArrayAutoButton, 'active', 0);
this.settings.bind('dash-array-on', dashArrayOnButton, 'value', 0);
this.settings.bind('dash-array-off', dashArrayOffButton, 'value', 0);
dashArrayAutoButton.bind_property('active', dashArrayOnButton, 'sensitive', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.INVERT_BOOLEAN);
dashArrayAutoButton.bind_property('active', dashArrayOffButton, 'sensitive', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.INVERT_BOOLEAN);
dashArrayRow.addWidget(dashArrayAutoButton);
dashArrayRow.addWidget(dashArrayOnButton);
dashArrayRow.addWidget(dashArrayOffButton);
toolsListBox.add(dashArrayRow);
let dashOffsetRow = new PrefRow({ label: _("Dash offset") });
let dashOffsetButton = new PixelSpinButton({ width_chars: 5, digits: 1,
adjustment: Gtk.Adjustment.new(0, -16384, 16384, 0.1, 1, 0),
tooltip_text: _(this.schema.get_key('dash-offset').get_description()) });
this.settings.bind('dash-offset', dashOffsetButton, 'value', 0);
dashOffsetRow.addWidget(dashOffsetButton);
toolsListBox.add(dashOffsetRow);
},
_updatePalettes: function() {
this.palettes = this.settings.get_value('palettes').deep_unpack();
this.palettesListBox.get_children().filter(row=> row.get_child() != this.addBox)
.slice(this.palettes.length)
.forEach(row => this.palettesListBox.remove(row));
let paletteBoxes = this.palettesListBox.get_children().map(row => row.get_child()).filter(child => child != this.addBox);
this.palettes.forEach((palette, paletteIndex) => {
let [name, colors] = palette;
let paletteBox;
if (paletteBoxes[paletteIndex]) {
paletteBox = paletteBoxes[paletteIndex];
let nameEntry = paletteBox.get_children()[0];
if (nameEntry.get_text() !== _(name)) {
GObject.signal_handler_block(nameEntry, nameEntry.paletteNameChangedHandler);
nameEntry.set_text(_(name));
GObject.signal_handler_unblock(nameEntry, nameEntry.paletteNameChangedHandler);
}
} else {
let nameEntry = new Gtk.Entry({ text: name, halign: Gtk.Align.START, tooltip_text: _("Rename the palette") });
nameEntry.paletteNameChangedHandler = nameEntry.connect('changed', this._onPaletteNameChanged.bind(this, paletteIndex));
let removeButton = Gtk.Button.new_from_icon_name('list-remove-symbolic', Gtk.IconSize.BUTTON);
removeButton.set_tooltip_text(_("Remove the palette"));
removeButton.connect('clicked', this._removePalette.bind(this, paletteIndex));
paletteBox = new Gtk.Box({ margin_top: MARGIN/2, margin_bottom: MARGIN/2, margin_left: MARGIN, margin_right: MARGIN });
paletteBox.pack_start(nameEntry, true, true, 4);
paletteBox.pack_start(new Gtk.Box({ spacing: 4 }), false, false, 4);
paletteBox.pack_start(removeButton, false, false, 4);
this.palettesListBox.insert(paletteBox, paletteIndex);
paletteBox.get_parent().set_activatable(false);
}
colors.splice(9);
while (colors.length < 9)
colors.push('transparent');
let colorsBox = paletteBox.get_children()[1];
let colorButtons = colorsBox.get_children();
colors.forEach((color, colorIndex) => {
if (colorButtons[colorIndex]) {
colorButtons[colorIndex].color_string = color;
} else {
let colorButton = new ColorStringButton({ color_string: color, use_alpha: true, show_editor: true, halign: Gtk.Align.START, hexpand: false });
colorButton.connect('notify::color-string', this._onPaletteColorChanged.bind(this, paletteIndex, colorIndex));
colorsBox.add(colorButton);
}
});
paletteBox.show_all();
});
},
_savePalettes: function() {
this.settings.set_value('palettes', new GLib.Variant('a(sas)', this.palettes));
},
_onPaletteNameChanged: function(index, entry) {
this.palettes[index][0] = entry.get_text();
this._savePalettes();
},
_onPaletteColorChanged: function(paletteIndex, colorIndex, colorButton) {
this.palettes[paletteIndex][1][colorIndex] = colorButton.get_rgba().to_string();
this._savePalettes();
},
_addNewPalette: function() {
let colors = Array(9).fill('Black');
this.palettes.push([_("New palette"), colors]);
this._savePalettes();
},
_removePalette: function(paletteIndex) {
this.palettes.splice(paletteIndex, 1);
this._savePalettes();
}
});
const PrefsPage = new GObject.Class({
Name: 'DrawOnYourScreenPrefsPage',
GTypeName: 'DrawOnYourScreenPrefsPage',
Extends: Gtk.ScrolledWindow,
_init: function(params) {
this.parent();
this.parent({ hscrollbar_policy: Gtk.PolicyType.NEVER });
let settings = Convenience.getSettings();
let internalShortcutSettings = Convenience.getSettings(Me.metadata['settings-schema'] + '.internal-shortcuts');
@ -311,19 +518,6 @@ const PrefsPage = new GObject.Class({
internalKeybindingsWidget.margin = MARGIN;
listBox.add(internalKeybindingsWidget);
let styleBox = new Gtk.Box({ margin: MARGIN });
let styleLabel = new Gtk.Label({
wrap: true,
xalign: 0,
use_markup: true,
label: _("<b>Default</b> drawing style attributes (color palette, font, line, dash) are defined in an editable <b>css</b> file.\n" +
"See <i>“%s”</i>.").format(_("Edit style"))
});
styleLabel.set_halign(1);
styleLabel.get_style_context().add_class('dim-label');
styleBox.pack_start(styleLabel, true, true, 4);
listBox.add(styleBox);
let noteBox = new Gtk.Box({ margin: MARGIN });
let noteLabel = new Gtk.Label({
wrap: true,
@ -346,6 +540,89 @@ const PrefsPage = new GObject.Class({
}
});
const PrefRow = new GObject.Class({
Name: 'DrawOnYourScreenPrefRow',
GTypeName: 'DrawOnYourScreenPrefRow',
Extends: Gtk.ListBoxRow,
_init: function(params) {
this.parent({ activatable: false });
let hbox = new Gtk.Box({ margin_top: MARGIN/2, margin_bottom: MARGIN/2, margin_left: MARGIN, margin_right: MARGIN });
this.add(hbox);
let labelBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
hbox.pack_start(labelBox, true, true, 4);
this.widgetBox = new Gtk.Box({ spacing: 4 });
hbox.pack_start(this.widgetBox, false, false, 4);
labelBox.pack_start(new Gtk.Label({ use_markup: true, label: params.label, halign: Gtk.Align.START }), true, true, 0);
if (params.desc) {
let desc = new Gtk.Label({ use_markup: true, label: `<small>${params.desc}</small>`, halign: Gtk.Align.START, wrap: true, xalign: 0 });
desc.get_style_context().add_class('dim-label');
labelBox.pack_start(desc, true, true, 0);
this.widgetBox.set_valign(Gtk.Align.START);
}
},
addWidget: function(widget) {
this.widgetBox.add(widget);
}
});
const PixelSpinButton = new GObject.Class({
Name: 'DrawOnYourScreenPixelSpinButton',
GTypeName: 'DrawOnYourScreenPixelSpinButton',
Extends: Gtk.SpinButton,
// Add 'px' unit.
vfunc_output: function() {
this.text = `${Math.round(this.value * 100) / 100} px`;
return true;
},
// Prevent accidental scrolling.
vfunc_scroll_event: function(event) {
return this.has_focus ? this.parent(event) : Gdk.EVENT_PROPAGATE;
}
});
// A color button that can be easily bound with a color string setting.
const ColorStringButton = new GObject.Class({
Name: 'DrawOnYourScreenColorStringButton',
GTypeName: 'DrawOnYourScreenColorStringButton',
Extends: Gtk.ColorButton,
Properties: {
'color-string': GObject.ParamSpec.string('color-string', 'colorString', 'A string that describes the color',
GObject.ParamFlags.READWRITE,
'black')
},
get color_string() {
return this._color_string || 'black';
},
set color_string(colorString) {
this._color_string = colorString;
let newRgba = new Gdk.RGBA();
newRgba.parse(colorString);
this.set_rgba(newRgba);
},
// Do nothing if the new color is equivalent to the old color (e.g. "black" and "rgb(0,0,0)").
vfunc_color_set(args) {
let oldRgba = new Gdk.RGBA();
oldRgba.parse(this.color_string);
if (!this.rgba.equal(oldRgba)) {
this._color_string = this.rgba.to_string();
this.notify('color-string');
}
}
});
// this code comes from Sticky Notes View by Sam Bull, https://extensions.gnome.org/extension/568/notes/
const KeybindingsWidget = new GObject.Class({
Name: 'DrawOnYourScreenKeybindings.Widget',

Binary file not shown.

View File

@ -37,6 +37,7 @@
<description>erase drawing</description>
</key>
<child name="internal-shortcuts" schema="org.gnome.shell.extensions.draw-on-your-screen.internal-shortcuts"/>
<child name="drawing" schema="org.gnome.shell.extensions.draw-on-your-screen.drawing"/>
</schema>
<schema path="/org/gnome/shell/extensions/draw-on-your-screen/internal-shortcuts/" id="org.gnome.shell.extensions.draw-on-your-screen.internal-shortcuts">
<key type="as" name="undo">
@ -229,7 +230,7 @@
<summary>switch font family</summary>
<description>switch font family</description>
</key>
<key type="as" name="reverse-switch-font-family">
<key type="as" name="switch-font-family-reverse">
<default>["&lt;Primary&gt;&lt;Shift&gt;f"]</default>
<summary>switch font family (reverse)</summary>
<description>switch font family (reverse)</description>
@ -244,6 +245,16 @@
<summary>switch font style</summary>
<description>switch font style</description>
</key>
<key type="as" name="switch-color-palette">
<default>["&lt;Primary&gt;KP_Divide","&lt;Primary&gt;slash"]</default>
<summary>switch color palette</summary>
<description>switch color palette</description>
</key>
<key type="as" name="switch-color-palette-reverse">
<default>["&lt;Primary&gt;&lt;Shift&gt;KP_Divide","&lt;Primary&gt;&lt;Shift&gt;slash"]</default>
<summary>switch color palette (reverse)</summary>
<description>switch color palette (reverse)</description>
</key>
<key type="as" name="switch-text-alignment">
<default>["&lt;Primary&gt;&lt;Shift&gt;a"]</default>
<summary>switch text alignment</summary>
@ -254,11 +265,6 @@
<summary>switch image file</summary>
<description>switch image file</description>
</key>
<key type="as" name="open-user-stylesheet">
<default>["&lt;Primary&gt;o"]</default>
<summary>open user stylesheet to edit style</summary>
<description>open user stylesheet to edit style</description>
</key>
<key type="as" name="save-as-svg">
<default>["&lt;Primary&gt;&lt;Shift&gt;s"]</default>
<summary>Save drawing as a svg file</summary>
@ -290,4 +296,75 @@
<description>toggle help</description>
</key>
</schema>
<schema path="/org/gnome/shell/extensions/draw-on-your-screen/drawing/" id="org.gnome.shell.extensions.draw-on-your-screen.drawing">
<key type="s" name="area-background-color">
<default>"#2e2e2e"</default>
<summary>Drawing area background color</summary>
<description>The color of the drawing area background</description>
</key>
<key type="b" name="dash-array-auto">
<default>true</default>
<summary>Automatic dash array</summary>
<description>Compute the lengths from the line width</description>
</key>
<key type="d" name="dash-array-on">
<default>5</default>
<summary>Dash array on</summary>
<description>The dash length in pixels</description>
</key>
<key type="d" name="dash-array-off">
<default>15</default>
<summary>Dash array off</summary>
<description>The gap between the dashes in pixels</description>
</key>
<key type="d" name="dash-offset">
<default>0</default>
<summary>Dash offset</summary>
<description>The dash offset in pixels</description>
</key>
<key type="s" name="grid-color">
<default>"Gray"</default>
<summary>Grid overlay color</summary>
<description>The color of the lines</description>
</key>
<key type="b" name="grid-line-auto">
<default>true</default>
<summary>Automatic grid overlay line</summary>
<description>Compute the lengths from the screen size</description>
</key>
<key type="u" name="grid-line-spacing">
<default>10</default>
<summary>Grid overlay line spacing</summary>
<description>The gap between lines in pixels</description>
</key>
<key type="d" name="grid-line-width">
<default>0.5</default>
<summary>Grid overlay line width</summary>
<description>The line width in pixels</description>
</key>
<key type="a(sas)" name="palettes">
<default>
[
("Palette", ["HotPink","Cyan","yellow","Orangered","Chartreuse","DarkViolet","White","Gray","Black"]),
("GNOME HIG lighter", ["rgb(153,193,241)","rgb(143,240,164)","rgb(249,240,107)","rgb(255,190,111)","rgb(246,97,81)","rgb(220,138,221)","rgb(205,171,143)","rgb(255,255,255)","rgb(119,118,123)"]),
("GNOME HIG light", ["rgb(98,160,241)","rgb(87,227,137)","rgb(248,228,92)","rgb(255,163,72)","rgb(237,51,59)","rgb(192,97,203)","rgb(181,131,90)","rgb(246,245,244)","rgb(94,92,100)"]),
("GNOME HIG normal", ["rgb(53,132,228)","rgb(51,209,122)","rgb(246,211,45)","rgb(255,120,0)","rgb(224,27,36)","rgb(145,65,172)","rgb(152,106,68)","rgb(222,221,218)","rgb(61,56,70)"]),
("GNOME HIG dark", ["rgb(28,113,216)","rgb(46,194,126)","rgb(245,194,17)","rgb(230,97,0)","rgb(192,28,40)","rgb(129,61,156)","rgb(134,94,60)","rgb(192,191,188)","rgb(36,31,49)"]),
("GNOME HIG darker", ["rgb(26,095,180)","rgb(38,162,105)","rgb(229,165,10)","rgb(198,70,0)","rgb(165,29,45)","rgb(97,53,131)","rgb(99,69,44)","rgb(154,153,150)","rgb(0,0,0)"])
]
</default>
<summary>Color palettes</summary>
<description>The palettes of drawing colors</description>
</key>
<key type="b" name="square-area-auto">
<default>true</default>
<summary>Automatic square area size</summary>
<description>Compute the size of the square area from the screen size</description>
</key>
<key type="u" name="square-area-size">
<default>512</default>
<summary>Square area size</summary>
<description>The size of the square area in pixels</description>
</key>
</schema>
</schemalist>

View File

@ -1,7 +1,3 @@
@import "./data/default.css";
/* The following styles don't affect the drawing */
/* square area */
.draw-on-your-screen-square-area {