new image shape
Images files are picked from `~/DrawOnYourScreen/images/` (and `extensiondir/images/`) svg, png, jpeg, ...(pixbuf)
This commit is contained in:
parent
7a41c6157c
commit
1172e9da6f
|
|
@ -7,7 +7,7 @@ Then save your beautiful work by taking a screenshot.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* Basic shapes (rectangle, circle, ellipse, line, curve, text, free)
|
* Basic shapes (rectangle, circle, ellipse, line, curve, text, image, free)
|
||||||
* Basic transformations (move, rotate, resize, stretch, mirror, inverse)
|
* Basic transformations (move, rotate, resize, stretch, mirror, inverse)
|
||||||
* Smooth stroke
|
* Smooth stroke
|
||||||
* Draw over applications
|
* Draw over applications
|
||||||
|
|
@ -40,6 +40,10 @@ Then save your beautiful work by taking a screenshot.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
* Insertable images:
|
||||||
|
|
||||||
|
Add your images (jpeg, png, svg) to `~/.local/share/drawOnYourScreen/images/`.
|
||||||
|
|
||||||
* Screenshot Tool extension:
|
* Screenshot Tool extension:
|
||||||
|
|
||||||
[Screenshot Tool](https://extensions.gnome.org/extension/1112/screenshot-tool/) is a convenient extension to “create, copy, store and upload screenshots”. In order to select a screenshoot area with your pointer while keeping the drawing in place, you need first to tell DrawOnYourScreen to ungrab the pointer (`Ctrl + Super + Alt + D`).
|
[Screenshot Tool](https://extensions.gnome.org/extension/1112/screenshot-tool/) is a convenient extension to “create, copy, store and upload screenshots”. In order to select a screenshoot area with your pointer while keeping the drawing in place, you need first to tell DrawOnYourScreen to ungrab the pointer (`Ctrl + Super + Alt + D`).
|
||||||
|
|
|
||||||
56
area.js
56
area.js
|
|
@ -30,6 +30,7 @@ const Gtk = imports.gi.Gtk;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Pango = imports.gi.Pango;
|
const Pango = imports.gi.Pango;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
const System = imports.system;
|
||||||
|
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
const ExtensionUtils = imports.misc.extensionUtils;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
|
|
@ -39,6 +40,7 @@ const Me = ExtensionUtils.getCurrentExtension();
|
||||||
const Convenience = ExtensionUtils.getSettings ? ExtensionUtils : Me.imports.convenience;
|
const Convenience = ExtensionUtils.getSettings ? ExtensionUtils : Me.imports.convenience;
|
||||||
const Extension = Me.imports.extension;
|
const Extension = Me.imports.extension;
|
||||||
const Elements = Me.imports.elements;
|
const Elements = Me.imports.elements;
|
||||||
|
const Files = Me.imports.files;
|
||||||
const Menu = Me.imports.menu;
|
const Menu = Me.imports.menu;
|
||||||
const _ = imports.gettext.domain(Me.metadata['gettext-domain']).gettext;
|
const _ = imports.gettext.domain(Me.metadata['gettext-domain']).gettext;
|
||||||
|
|
||||||
|
|
@ -46,10 +48,13 @@ const CAIRO_DEBUG_EXTENDS = false;
|
||||||
const SVG_DEBUG_EXTENDS = false;
|
const SVG_DEBUG_EXTENDS = false;
|
||||||
const TEXT_CURSOR_TIME = 600; // ms
|
const TEXT_CURSOR_TIME = 600; // ms
|
||||||
|
|
||||||
const { Shapes, Manipulations, Transformations, LineCapNames, LineJoinNames, FillRuleNames,
|
const { Shapes, ShapeNames, Transformations, LineCapNames, LineJoinNames, FillRuleNames,
|
||||||
FontWeightNames, FontStyleNames, FontStretchNames, FontVariantNames } = Elements;
|
FontWeightNames, FontStyleNames, FontStretchNames, FontVariantNames } = Elements;
|
||||||
|
const Manipulations = { MOVE: 100, RESIZE: 101, MIRROR: 102 };
|
||||||
|
const ManipulationNames = { 100: "Move", 101: "Resize", 102: "Mirror" };
|
||||||
var Tools = Object.assign({}, Shapes, Manipulations);
|
var Tools = Object.assign({}, Shapes, Manipulations);
|
||||||
var ToolNames = { 0: "Free drawing", 1: "Line", 2: "Ellipse", 3: "Rectangle", 4: "Text", 5: "Polygon", 6: "Polyline", 100: "Move", 101: "Resize", 102: "Mirror" };
|
var ToolNames = Object.assign({}, ShapeNames, ManipulationNames);
|
||||||
|
|
||||||
var FontGenericNames = { 0: 'Theme', 1: 'Sans-Serif', 2: 'Serif', 3: 'Monospace', 4: 'Cursive', 5: 'Fantasy' };
|
var FontGenericNames = { 0: 'Theme', 1: 'Sans-Serif', 2: 'Serif', 3: 'Monospace', 4: 'Cursive', 5: 'Fantasy' };
|
||||||
|
|
||||||
var getDateString = function() {
|
var getDateString = function() {
|
||||||
|
|
@ -96,6 +101,7 @@ 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_STRING, GObject.TYPE_STRING, GObject.TYPE_DOUBLE, GObject.TYPE_BOOLEAN] },
|
Signals: { 'show-osd': { param_types: [GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_DOUBLE, GObject.TYPE_BOOLEAN] },
|
||||||
|
'show-osd-gicon': { param_types: [Gio.Icon.$gtype, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_DOUBLE, GObject.TYPE_BOOLEAN] },
|
||||||
'update-action-mode': {},
|
'update-action-mode': {},
|
||||||
'leave-drawing-mode': {} },
|
'leave-drawing-mode': {} },
|
||||||
|
|
||||||
|
|
@ -113,6 +119,7 @@ var DrawingArea = new Lang.Class({
|
||||||
this.undoneElements = [];
|
this.undoneElements = [];
|
||||||
this.currentElement = null;
|
this.currentElement = null;
|
||||||
this.currentTool = Shapes.NONE;
|
this.currentTool = Shapes.NONE;
|
||||||
|
this.currentImage = 0;
|
||||||
this.currentFontGeneric = 0;
|
this.currentFontGeneric = 0;
|
||||||
this.isSquareArea = false;
|
this.isSquareArea = false;
|
||||||
this.hasGrid = false;
|
this.hasGrid = false;
|
||||||
|
|
@ -169,6 +176,13 @@ var DrawingArea = new Lang.Class({
|
||||||
this.currentFillRule = evenodd ? Cairo.FillRule.EVEN_ODD : Cairo.FillRule.WINDING;
|
this.currentFillRule = evenodd ? Cairo.FillRule.EVEN_ODD : Cairo.FillRule.WINDING;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getImages() {
|
||||||
|
let images = Files.getImages();
|
||||||
|
if (!images[this.currentImage])
|
||||||
|
this.currentImage = Math.max(images.length - 1, 0);
|
||||||
|
return images;
|
||||||
|
},
|
||||||
|
|
||||||
vfunc_repaint: function() {
|
vfunc_repaint: function() {
|
||||||
let cr = this.get_context();
|
let cr = this.get_context();
|
||||||
|
|
||||||
|
|
@ -179,6 +193,8 @@ var DrawingArea = new Lang.Class({
|
||||||
}
|
}
|
||||||
|
|
||||||
cr.$dispose();
|
cr.$dispose();
|
||||||
|
if (this.elements.some(element => element.shape == Shapes.IMAGE) || this.currentElement && this.currentElement.shape == Shapes.IMAGE)
|
||||||
|
System.gc();
|
||||||
},
|
},
|
||||||
|
|
||||||
_redisplay: function() {
|
_redisplay: function() {
|
||||||
|
|
@ -266,7 +282,7 @@ var DrawingArea = new Lang.Class({
|
||||||
if (this.currentElement) {
|
if (this.currentElement) {
|
||||||
cr.save();
|
cr.save();
|
||||||
this.currentElement.buildCairo(cr, { showTextCursor: this.textHasCursor,
|
this.currentElement.buildCairo(cr, { showTextCursor: this.textHasCursor,
|
||||||
showTextRectangle: this.currentElement.shape == Shapes.TEXT && !this.isWriting,
|
showTextRectangle: this.currentElement.shape != Shapes.TEXT || !this.isWriting,
|
||||||
dummyStroke: this.currentElement.fill && this.currentElement.line.lineWidth == 0 });
|
dummyStroke: this.currentElement.fill && this.currentElement.line.lineWidth == 0 });
|
||||||
|
|
||||||
cr.stroke();
|
cr.stroke();
|
||||||
|
|
@ -477,6 +493,8 @@ var DrawingArea = new Lang.Class({
|
||||||
if (duplicate) {
|
if (duplicate) {
|
||||||
// deep cloning
|
// deep cloning
|
||||||
let copy = new this.grabbedElement.constructor(JSON.parse(JSON.stringify(this.grabbedElement)));
|
let copy = new this.grabbedElement.constructor(JSON.parse(JSON.stringify(this.grabbedElement)));
|
||||||
|
if (this.grabbedElement.image)
|
||||||
|
copy.image = this.grabbedElement.image;
|
||||||
this.elements.push(copy);
|
this.elements.push(copy);
|
||||||
this.grabbedElement = copy;
|
this.grabbedElement = copy;
|
||||||
}
|
}
|
||||||
|
|
@ -574,6 +592,18 @@ var DrawingArea = new Lang.Class({
|
||||||
textRightAligned: this.currentTextRightAligned,
|
textRightAligned: this.currentTextRightAligned,
|
||||||
points: []
|
points: []
|
||||||
});
|
});
|
||||||
|
} else if (this.currentTool == Shapes.IMAGE) {
|
||||||
|
let images = this.getImages();
|
||||||
|
if (!images.length)
|
||||||
|
return;
|
||||||
|
this.currentElement = new Elements.DrawingElement({
|
||||||
|
shape: this.currentTool,
|
||||||
|
color: this.currentColor.to_string(),
|
||||||
|
eraser: eraser,
|
||||||
|
image: images[this.currentImage],
|
||||||
|
operator: this.currentOperator,
|
||||||
|
points: []
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
this.currentElement = new Elements.DrawingElement({
|
this.currentElement = new Elements.DrawingElement({
|
||||||
shape: this.currentTool,
|
shape: this.currentTool,
|
||||||
|
|
@ -939,6 +969,15 @@ var DrawingArea = new Lang.Class({
|
||||||
this.emit('show-osd', null, this.currentTextRightAligned ? _("Right aligned") : _("Left aligned"), "", -1, false);
|
this.emit('show-osd', null, this.currentTextRightAligned ? _("Right aligned") : _("Left aligned"), "", -1, false);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
toggleImageFile: function() {
|
||||||
|
let images = this.getImages();
|
||||||
|
if (!images.length)
|
||||||
|
return;
|
||||||
|
if (images.length > 1)
|
||||||
|
this.currentImage = this.currentImage == images.length - 1 ? 0 : this.currentImage + 1;
|
||||||
|
this.emit('show-osd-gicon', images[this.currentImage].gicon, images[this.currentImage].toString(), "", -1, false);
|
||||||
|
},
|
||||||
|
|
||||||
toggleHelp: function() {
|
toggleHelp: function() {
|
||||||
if (this.helper.visible) {
|
if (this.helper.visible) {
|
||||||
this.helper.hideHelp();
|
this.helper.hideHelp();
|
||||||
|
|
@ -1034,7 +1073,10 @@ var DrawingArea = new Lang.Class({
|
||||||
this._stopDrawing();
|
this._stopDrawing();
|
||||||
}
|
}
|
||||||
|
|
||||||
let content = `<svg viewBox="0 0 ${this.width} ${this.height}" xmlns="http://www.w3.org/2000/svg">`;
|
let prefixes = 'xmlns="http://www.w3.org/2000/svg"';
|
||||||
|
if (this.elements.some(element => element.shape == Shapes.IMAGE))
|
||||||
|
prefixes += ' xmlns:xlink="http://www.w3.org/1999/xlink"';
|
||||||
|
let content = `<svg viewBox="0 0 ${this.width} ${this.height}" ${prefixes}>`;
|
||||||
if (SVG_DEBUG_EXTENDS)
|
if (SVG_DEBUG_EXTENDS)
|
||||||
content = `<svg viewBox="${-this.width} ${-this.height} ${2 * this.width} ${2 * this.height}" xmlns="http://www.w3.org/2000/svg">`;
|
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.activeBackgroundColor.to_string() : 'transparent';
|
||||||
|
|
@ -1156,7 +1198,11 @@ var DrawingArea = new Lang.Class({
|
||||||
return;
|
return;
|
||||||
if (contents instanceof Uint8Array)
|
if (contents instanceof Uint8Array)
|
||||||
contents = ByteArray.toString(contents);
|
contents = ByteArray.toString(contents);
|
||||||
this.elements.push(...JSON.parse(contents).map(object => new Elements.DrawingElement(object)));
|
this.elements.push(...JSON.parse(contents).map(object => {
|
||||||
|
if (object.image)
|
||||||
|
object.image = new Files.Image(object.image);
|
||||||
|
return new Elements.DrawingElement(object);
|
||||||
|
}));
|
||||||
|
|
||||||
if (notify)
|
if (notify)
|
||||||
this.emit('show-osd', 'document-open-symbolic', name, "", -1, false);
|
this.emit('show-osd', 'document-open-symbolic', name, "", -1, false);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
<!-- https://commons.wikimedia.org/wiki/File:Bananas.svg -->
|
||||||
|
<!-- public domain -->
|
||||||
|
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://web.resource.org/cc/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="559.62469" height="373.29596" id="svg2" sodipodi:version="0.32" inkscape:version="0.44" version="1.0" sodipodi:docbase="C:\Documents and Settings\Elembis\My Documents\Images\Shartak\Shartak.com" sodipodi:docname="bananas3.svg" inkscape:export-filename="C:\Documents and Settings\Elembis\My Documents\Images\Shartak\Shartak.com\banana.png" inkscape:export-xdpi="25.797226" inkscape:export-ydpi="25.797226">
|
||||||
|
<defs id="defs4"/>
|
||||||
|
<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" gridtolerance="10000" guidetolerance="10" objecttolerance="10" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="1" inkscape:cx="257.85399" inkscape:cy="231.60006" inkscape:document-units="px" inkscape:current-layer="layer1" inkscape:window-width="1024" inkscape:window-height="721" inkscape:window-x="-4" inkscape:window-y="-4"/>
|
||||||
|
<metadata id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" transform="translate(-66.38047,-391.3222)">
|
||||||
|
<g id="g9893" inkscape:transform-center-x="88.0002" inkscape:transform-center-y="113.00018">
|
||||||
|
<path transform="translate(-17.85713,318.6479)" sodipodi:nodetypes="csccccc" id="path17976" d="M 543,119 C 543,119 547,177 531,189 C 515,201 397,320 397,320 L 419,345 L 562,248 L 573,121 L 543,119 z " style="fill:#ffc701;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
|
||||||
|
<path sodipodi:nodetypes="csccccc" id="path18863" d="M 525.14247,437.64826 C 525.14247,437.64826 529.14247,495.64826 513.14247,507.64826 C 497.14247,519.64826 379.14247,638.64826 379.14247,638.64826 L 401.14247,663.64826 L 544.14247,566.64826 L 555.14247,439.64826 L 525.14247,437.64826 z " style="opacity:0.7;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
|
||||||
|
</g>
|
||||||
|
<g id="g2783">
|
||||||
|
<path id="path6424" d="M 519.9114,399.65406 L 483.38679,454.45323 C 483.38679,454.45323 454.12626,461.72103 439.29443,470.94146 C 424.46259,480.16189 377.85779,514.19114 274.74769,506.89067 C 171.63759,499.59021 156.32242,477.55739 133.97629,476.75109 C 111.63016,475.9448 77.83775,479.82705 69.64709,486.06507 C 61.45643,492.3031 71.25003,511.09366 71.25003,511.09366 C 71.25003,511.09366 101.21736,578.4951 210.30564,606.14897 C 319.39391,633.80284 448.5453,576.70729 448.5453,576.70729 L 538.74205,411.07361 L 519.9114,399.65406 z " style="fill:#ffc701;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"/>
|
||||||
|
<path id="path1895" d="M 517.00522,404.00971 L 483.38022,454.44721 C 483.38022,454.44721 454.1183,461.72678 439.28647,470.94721 C 424.45462,480.16764 377.86532,514.18518 274.75522,506.88471 C 171.64512,499.58425 156.3201,477.56601 133.97397,476.75971 C 111.62785,475.95343 77.85213,479.83419 69.66147,486.07221 C 69.2897,486.35536 68.96174,486.67778 68.66147,487.00971 C 87.94596,484.21174 116.37515,484.78053 136.38022,488.41596 C 174.77085,495.39252 209.97775,518.65573 299.50522,516.22846 C 426.73709,512.73998 441.6649,473.10304 459.38022,468.41596 C 484.00837,461.89991 530.48444,452.34626 517.00522,404.00971 z " style="fill:white;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;opacity:0.4"/>
|
||||||
|
<path id="path9086" d="M 106.96213,554.70796 C 128.49383,573.41467 161.44348,593.76255 210.30593,606.14918 C 222.07021,609.13143 234.0755,611.11073 246.11929,612.29962 L 284.83188,604.45269 C 220.5418,614.51673 142.31641,575.18761 106.96213,554.70796 z " style="opacity:0.4;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
|
||||||
|
</g>
|
||||||
|
<g id="g9941">
|
||||||
|
<path transform="translate(-17.85713,318.6479)" inkscape:transform-center-y="181" inkscape:transform-center-x="126" sodipodi:nodetypes="cssssssssc" id="path12644" d="M 546,120 C 546,120 567,175 561,189 C 555,203 520,283 455,313 C 390,343 223,339 219,331 C 215,323 219,407 320,438 C 421,469 550.08904,401.09271 573,379 C 602,351 657,279 641,225 C 625,171 613,187 604,172 C 595,157 585,128 585,116 C 585,104 547,120 546,120 z " style="opacity:1;fill:#ffc701;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"/>
|
||||||
|
<path id="path8981" d="M 533.7244,527.63751 C 518.52971,557.28537 486.49949,608.85189 437.13065,631.63751 C 372.13066,661.63751 205.13065,657.63751 201.13065,649.63751 C 200.13065,647.63751 199.64628,651.40313 201.0369,658.63751 L 201.06815,658.76251 L 203.13065,665.63751 C 203.13064,665.63751 202.9682,665.65254 202.75565,665.73126 C 202.85933,666.09273 202.98841,666.48596 203.0994,666.85626 C 203.2463,667.34553 203.37675,667.82087 203.5369,668.32501 C 203.82494,669.23173 204.17292,670.18568 204.50565,671.13751 C 204.61749,671.45746 204.70108,671.78151 204.81815,672.10626 C 205.04405,672.73471 205.32226,673.36688 205.56815,674.01251 C 205.8517,674.75499 206.10087,675.49879 206.4119,676.26251 C 206.6323,676.80515 206.89597,677.36609 207.13065,677.91876 C 207.44564,678.65842 207.75805,679.38112 208.0994,680.13751 C 208.26157,680.49795 208.4311,680.86725 208.5994,681.23126 C 209.69117,683.59259 210.89044,686.02408 212.25565,688.51251 C 212.29126,688.57728 212.34485,688.63516 212.38065,688.70001 C 212.39669,688.72911 212.39582,688.76464 212.4119,688.79376 C 212.77389,689.44818 213.15496,690.10127 213.5369,690.76251 C 213.57214,690.82361 213.59523,690.88885 213.63065,690.95001 C 214.03425,691.64604 214.45442,692.3411 214.88065,693.04376 C 215.33612,693.79463 215.80496,694.56759 216.2869,695.32501 C 216.29464,695.33717 216.3104,695.34409 216.31815,695.35626 C 216.77977,696.08134 217.23774,696.81355 217.7244,697.54376 C 217.72759,697.54854 217.75246,697.53898 217.75565,697.54376 C 258.55477,715.44577 403.2244,681.10626 468.13065,633.63751 C 513.82083,600.22229 528.80654,553.79612 533.7244,527.63751 z " style="opacity:0.6;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"/>
|
||||||
|
<path id="path17089" d="M 559.79937,430.17885 C 558.18509,430.20703 556.38497,430.42195 554.48687,430.74135 C 560.75792,449.99636 590.83405,543.70808 588.14312,561.6476 C 585.14312,581.6476 553.30943,654.34782 501.14312,685.6476 C 466.14312,706.6476 390.14312,739.6476 363.14312,744.6476 C 346.05557,747.81196 312.61613,752.46521 286.48687,751.11635 C 291.4351,753.10006 296.63167,754.95597 302.14312,756.6476 C 403.14312,787.6476 532.23216,719.74031 555.14312,697.6476 C 584.14312,669.6476 639.14312,597.6476 623.14312,543.6476 C 607.14312,489.6476 595.14312,505.6476 586.14312,490.6476 C 577.14312,475.6476 567.14312,446.6476 567.14312,434.6476 C 567.14312,431.2726 564.14254,430.10304 559.79937,430.17885 z " style="opacity:0.4;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
|
||||||
|
</g>
|
||||||
|
<g id="g9903">
|
||||||
|
<path sodipodi:nodetypes="cssccccc" id="path1933" d="M 533.14287,448.6479 C 533.14287,448.6479 514.14287,467.6479 519.14287,485.6479 C 524.14287,503.6479 541.14287,547.6479 478.14287,597.6479 C 415.14287,647.6479 232.14287,734.6479 109.14287,639.6479 C 74.14287,599.6479 94.14287,573.6479 94.14287,573.6479 C 94.14287,573.6479 114.12992,570.75757 122.14287,571.6479 C 132.14287,568.6479 179.14287,571.6479 223.14287,573.6479 C 282.05327,572.49008 443.14287,497.6479 474.14287,468.6479 C 474.14287,468.6479 512.14287,422.6479 513.14287,414.6479 C 514.14287,406.6479 540.14287,430.6479 541.14287,437.6479 C 542.14287,444.6479 533.14287,447.6479 533.14287,448.6479 z " style="fill:#ffc701;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"/>
|
||||||
|
<path sodipodi:nodetypes="cssccccsscc" id="path7201" d="M 514.60028,413.04467 C 513.79169,413.14037 513.25653,413.63842 513.13153,414.63842 C 512.13153,422.63842 474.13153,468.63841 474.13153,468.63842 C 443.13153,497.63842 282.04191,572.4806 223.13152,573.63842 C 179.13152,571.63842 132.13152,568.63842 122.13152,571.63842 C 114.11858,570.74809 94.13152,573.63842 94.13152,573.63842 C 94.13152,573.63842 93.7656,574.16602 93.22527,575.07592 C 104.18437,578.28284 124.12588,582.75014 156.38152,583.60717 C 230.77215,585.58373 262.00653,581.54467 326.50653,556.41967 C 394.13686,530.0753 484.82418,496.21955 520.38153,415.35717 C 517.97095,413.81698 515.90107,412.89071 514.60028,413.04467 z " style="opacity:0.4;fill:white;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"/>
|
||||||
|
<path id="path4646" d="M 518.58062,482.8981 C 510.39544,511.03311 477.26645,585.47414 350.14312,628.6481 C 194.69709,681.44109 156.81818,651.08254 106.61187,636.61685 C 107.43132,637.61484 108.2539,638.63184 109.14312,639.6481 C 232.14312,734.6481 415.14312,647.6481 478.14312,597.6481 C 541.14312,547.6481 524.14312,503.6481 519.14312,485.6481 C 518.88851,484.73149 518.71644,483.81726 518.58062,482.8981 z " style="opacity:0.4;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
|
||||||
|
</g>
|
||||||
|
<g id="g9946">
|
||||||
|
<path sodipodi:nodetypes="czsssz" id="path23294" d="M 534.47367,391.42537 C 528.72367,389.92537 508.71616,405.72925 509.06846,411.02017 C 509.42029,416.30405 528.53454,433.43637 540.64281,437.57407 C 544.64281,438.57407 566.64281,436.57407 567.64281,432.57407 C 568.64281,428.57407 568.64281,411.57407 564.64281,407.57407 C 560.64281,403.57407 541.16441,393.17078 534.47367,391.42537 z " style="fill:#884a13;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"/>
|
||||||
|
<path sodipodi:nodetypes="czsssz" id="path22407" d="M 534.47374,391.42502 C 528.72374,389.92502 508.71623,405.7289 509.06853,411.01982 C 509.42036,416.3037 528.53461,433.43602 540.64288,437.57372 C 544.64288,438.57372 566.64288,436.57372 567.64288,432.57372 C 568.64288,428.57372 568.64288,411.57372 564.64288,407.57372 C 560.64288,403.57372 541.16448,393.17043 534.47374,391.42502 z " style="fill:#884a13;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
|
||||||
|
<path id="path25958" d="M 533.23672,391.3354 C 526.30206,391.85508 508.75019,406.06266 509.08047,411.0229 C 509.222,413.14841 512.41917,417.17996 516.95547,421.5229 C 517.24178,413.18494 521.37892,401.08827 540.67422,393.7729 C 538.17765,392.66554 536.00097,391.82417 534.48672,391.42915 C 534.12734,391.3354 533.69903,391.30075 533.23672,391.3354 z " style="opacity:0.3;fill:white;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
|
||||||
|
<path id="path26854" d="M 564.58087,407.52257 C 564.73328,425.7813 549.04695,433.48138 538.20587,436.61632 C 539.04145,436.98636 539.85952,437.31721 540.64337,437.58507 C 544.64338,438.58507 566.64337,436.58507 567.64337,432.58507 C 568.64338,428.58507 568.64337,411.58507 564.64337,407.58507 C 564.62587,407.56758 564.59896,407.54031 564.58087,407.52257 z " style="opacity:0.4;fill:black;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 12 KiB |
96
elements.js
96
elements.js
|
|
@ -34,8 +34,8 @@ const reverseEnumeration = function(obj) {
|
||||||
return reversed;
|
return reversed;
|
||||||
};
|
};
|
||||||
|
|
||||||
var Shapes = { NONE: 0, LINE: 1, ELLIPSE: 2, RECTANGLE: 3, TEXT: 4, POLYGON: 5, POLYLINE: 6 };
|
var Shapes = { NONE: 0, LINE: 1, ELLIPSE: 2, RECTANGLE: 3, TEXT: 4, POLYGON: 5, POLYLINE: 6, IMAGE: 7 };
|
||||||
var Manipulations = { MOVE: 100, RESIZE: 101, MIRROR: 102 };
|
var ShapeNames = { 0: "Free drawing", 1: "Line", 2: "Ellipse", 3: "Rectangle", 4: "Text", 5: "Polygon", 6: "Polyline", 7: "Image" };
|
||||||
var Transformations = { TRANSLATION: 0, ROTATION: 1, SCALE_PRESERVE: 2, STRETCH: 3, REFLECTION: 4, INVERSION: 5 };
|
var Transformations = { TRANSLATION: 0, ROTATION: 1, SCALE_PRESERVE: 2, STRETCH: 3, REFLECTION: 4, INVERSION: 5 };
|
||||||
var LineCapNames = Object.assign(reverseEnumeration(Cairo.LineCap), { 2: 'Square' });
|
var LineCapNames = Object.assign(reverseEnumeration(Cairo.LineCap), { 2: 'Square' });
|
||||||
var LineJoinNames = reverseEnumeration(Cairo.LineJoin);
|
var LineJoinNames = reverseEnumeration(Cairo.LineJoin);
|
||||||
|
|
@ -46,7 +46,6 @@ var FontStyleNames = reverseEnumeration(Pango.Style);
|
||||||
var FontStretchNames = reverseEnumeration(Pango.Stretch);
|
var FontStretchNames = reverseEnumeration(Pango.Stretch);
|
||||||
var FontVariantNames = reverseEnumeration(Pango.Variant);
|
var FontVariantNames = reverseEnumeration(Pango.Variant);
|
||||||
|
|
||||||
|
|
||||||
const SVG_DEBUG_SUPERPOSES_CAIRO = false;
|
const SVG_DEBUG_SUPERPOSES_CAIRO = false;
|
||||||
const RADIAN = 180 / Math.PI; // degree
|
const RADIAN = 180 / Math.PI; // degree
|
||||||
const INVERSION_CIRCLE_RADIUS = 12; // px
|
const INVERSION_CIRCLE_RADIUS = 12; // px
|
||||||
|
|
@ -58,7 +57,9 @@ const MIN_ROTATION_ANGLE = Math.PI / 1000; // rad
|
||||||
const MIN_DRAWING_SIZE = 3; // px
|
const MIN_DRAWING_SIZE = 3; // px
|
||||||
|
|
||||||
var DrawingElement = function(params) {
|
var DrawingElement = function(params) {
|
||||||
return params.shape == Shapes.TEXT ? new TextElement(params) : new _DrawingElement(params);
|
return params.shape == Shapes.TEXT ? new TextElement(params) :
|
||||||
|
params.shape == Shapes.IMAGE ? new ImageElement(params) :
|
||||||
|
new _DrawingElement(params);
|
||||||
};
|
};
|
||||||
|
|
||||||
// DrawingElement represents a "brushstroke".
|
// DrawingElement represents a "brushstroke".
|
||||||
|
|
@ -109,9 +110,11 @@ const _DrawingElement = new Lang.Class({
|
||||||
},
|
},
|
||||||
|
|
||||||
buildCairo: function(cr, params) {
|
buildCairo: function(cr, params) {
|
||||||
let [success, color] = Clutter.Color.from_string(this.color);
|
if (this.color) {
|
||||||
if (success)
|
let [success, color] = Clutter.Color.from_string(this.color);
|
||||||
Clutter.cairo_set_source_color(cr, color);
|
if (success)
|
||||||
|
Clutter.cairo_set_source_color(cr, color);
|
||||||
|
}
|
||||||
|
|
||||||
if (this.showSymmetryElement) {
|
if (this.showSymmetryElement) {
|
||||||
let transformation = this.lastTransformation;
|
let transformation = this.lastTransformation;
|
||||||
|
|
@ -726,6 +729,85 @@ const TextElement = new Lang.Class({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const ImageElement = new Lang.Class({
|
||||||
|
Name: 'DrawOnYourScreenImageElement',
|
||||||
|
Extends: _DrawingElement,
|
||||||
|
|
||||||
|
_init: function(params) {
|
||||||
|
params.fill = false;
|
||||||
|
this.parent(params);
|
||||||
|
},
|
||||||
|
|
||||||
|
toJSON: function() {
|
||||||
|
return {
|
||||||
|
shape: this.shape,
|
||||||
|
color: this.color,
|
||||||
|
fill: this.fill,
|
||||||
|
eraser: this.eraser,
|
||||||
|
transformations: this.transformations,
|
||||||
|
image: this.image.toJson(),
|
||||||
|
preserveAspectRatio: this.preserveAspectRatio,
|
||||||
|
points: this.points.map((point) => [Math.round(point[0]*100)/100, Math.round(point[1]*100)/100])
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
_drawCairo: function(cr, params) {
|
||||||
|
if (this.points.length < 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let points = this.points;
|
||||||
|
let [x, y] = [Math.min(points[0][0], points[1][0]), Math.min(points[0][1], points[1][1])];
|
||||||
|
let [width, height] = [Math.abs(points[1][0] - points[0][0]), Math.abs(points[1][1] - points[0][1])];
|
||||||
|
|
||||||
|
if (width < 1 || height < 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cr.save();
|
||||||
|
this.image.setCairoSource(cr, x, y, width, height, this.preserveAspectRatio);
|
||||||
|
cr.rectangle(x, y, width, height);
|
||||||
|
cr.fill();
|
||||||
|
cr.restore();
|
||||||
|
|
||||||
|
if (params.showTextRectangle) {
|
||||||
|
cr.rectangle(x, y, width, height);
|
||||||
|
setDummyStroke(cr);
|
||||||
|
} else if (params.drawTextRectangle) {
|
||||||
|
cr.rectangle(x, y, width, height);
|
||||||
|
// Only draw the rectangle to find the element, not to show it.
|
||||||
|
cr.setLineWidth(0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getContainsPoint: function(cr, x, y) {
|
||||||
|
return cr.inFill(x, y);
|
||||||
|
},
|
||||||
|
|
||||||
|
_drawSvg: function(transAttribute) {
|
||||||
|
let points = this.points;
|
||||||
|
let row = "\n ";
|
||||||
|
let attributes = '';
|
||||||
|
|
||||||
|
if (points.length == 2) {
|
||||||
|
attributes = `fill="none"`;
|
||||||
|
row += `<image ${attributes} x="${Math.min(points[0][0], points[1][0])}" y="${Math.min(points[0][1], points[1][1])}" ` +
|
||||||
|
`width="${Math.abs(points[1][0] - points[0][0])}" height="${Math.abs(points[1][1] - points[0][1])}"${transAttribute} ` +
|
||||||
|
`preserveAspectRatio="${this.preserveAspectRatio ? 'xMinYMin' : 'none'}" ` +
|
||||||
|
`id="${this.image.displayName}" xlink:href="data:${this.image.contentType};base64,${this.image.base64}"/>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return row;
|
||||||
|
},
|
||||||
|
|
||||||
|
updateDrawing: function(x, y, transform) {
|
||||||
|
let points = this.points;
|
||||||
|
if (x == points[0][0] || y == points[0][1])
|
||||||
|
return;
|
||||||
|
|
||||||
|
points[1] = [x, y];
|
||||||
|
this.preserveAspectRatio = !transform;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const setDummyStroke = function(cr) {
|
const setDummyStroke = function(cr) {
|
||||||
cr.setLineWidth(2);
|
cr.setLineWidth(2);
|
||||||
cr.setLineCap(0);
|
cr.setLineCap(0);
|
||||||
|
|
|
||||||
|
|
@ -171,6 +171,7 @@ var AreaManager = new Lang.Class({
|
||||||
area.leaveDrawingHandler = area.connect('leave-drawing-mode', this.toggleDrawing.bind(this));
|
area.leaveDrawingHandler = area.connect('leave-drawing-mode', this.toggleDrawing.bind(this));
|
||||||
area.updateActionModeHandler = area.connect('update-action-mode', this.updateActionMode.bind(this));
|
area.updateActionModeHandler = area.connect('update-action-mode', this.updateActionMode.bind(this));
|
||||||
area.showOsdHandler = area.connect('show-osd', this.showOsd.bind(this));
|
area.showOsdHandler = area.connect('show-osd', this.showOsd.bind(this));
|
||||||
|
area.showOsdGiconHandler = area.connect('show-osd-gicon', this.showOsd.bind(this));
|
||||||
this.areas.push(area);
|
this.areas.push(area);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -191,11 +192,13 @@ var AreaManager = new Lang.Class({
|
||||||
'toggle-fill-rule': this.activeArea.toggleFillRule.bind(this.activeArea),
|
'toggle-fill-rule': this.activeArea.toggleFillRule.bind(this.activeArea),
|
||||||
'toggle-dash' : this.activeArea.toggleDash.bind(this.activeArea),
|
'toggle-dash' : this.activeArea.toggleDash.bind(this.activeArea),
|
||||||
'toggle-fill' : this.activeArea.toggleFill.bind(this.activeArea),
|
'toggle-fill' : this.activeArea.toggleFill.bind(this.activeArea),
|
||||||
|
'toggle-image-file' : this.activeArea.toggleImageFile.bind(this.activeArea),
|
||||||
'select-none-shape': () => this.activeArea.selectTool(Area.Tools.NONE),
|
'select-none-shape': () => this.activeArea.selectTool(Area.Tools.NONE),
|
||||||
'select-line-shape': () => this.activeArea.selectTool(Area.Tools.LINE),
|
'select-line-shape': () => this.activeArea.selectTool(Area.Tools.LINE),
|
||||||
'select-ellipse-shape': () => this.activeArea.selectTool(Area.Tools.ELLIPSE),
|
'select-ellipse-shape': () => this.activeArea.selectTool(Area.Tools.ELLIPSE),
|
||||||
'select-rectangle-shape': () => this.activeArea.selectTool(Area.Tools.RECTANGLE),
|
'select-rectangle-shape': () => this.activeArea.selectTool(Area.Tools.RECTANGLE),
|
||||||
'select-text-shape': () => this.activeArea.selectTool(Area.Tools.TEXT),
|
'select-text-shape': () => this.activeArea.selectTool(Area.Tools.TEXT),
|
||||||
|
'select-image-shape': () => this.activeArea.selectTool(Area.Tools.IMAGE),
|
||||||
'select-polygon-shape': () => this.activeArea.selectTool(Area.Tools.POLYGON),
|
'select-polygon-shape': () => this.activeArea.selectTool(Area.Tools.POLYGON),
|
||||||
'select-polyline-shape': () => this.activeArea.selectTool(Area.Tools.POLYLINE),
|
'select-polyline-shape': () => this.activeArea.selectTool(Area.Tools.POLYLINE),
|
||||||
'select-move-tool': () => this.activeArea.selectTool(Area.Tools.MOVE),
|
'select-move-tool': () => this.activeArea.selectTool(Area.Tools.MOVE),
|
||||||
|
|
@ -505,6 +508,7 @@ var AreaManager = new Lang.Class({
|
||||||
area.disconnect(area.leaveDrawingHandler);
|
area.disconnect(area.leaveDrawingHandler);
|
||||||
area.disconnect(area.updateActionModeHandler);
|
area.disconnect(area.updateActionModeHandler);
|
||||||
area.disconnect(area.showOsdHandler);
|
area.disconnect(area.showOsdHandler);
|
||||||
|
area.disconnect(area.showOsdGiconHandler);
|
||||||
let container = area.get_parent();
|
let container = area.get_parent();
|
||||||
container.get_parent().remove_actor(container);
|
container.get_parent().remove_actor(container);
|
||||||
container.destroy();
|
container.destroy();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,132 @@
|
||||||
|
/* jslint esversion: 6 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Abakkk
|
||||||
|
*
|
||||||
|
* This file is part of DrawOnYourScreen, a drawing extension for GNOME Shell.
|
||||||
|
* https://framagit.org/abakkk/DrawOnYourScreen
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const Gdk = imports.gi.Gdk;
|
||||||
|
const GdkPixbuf = imports.gi.GdkPixbuf;
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
|
const GLib = imports.gi.GLib;
|
||||||
|
const Lang = imports.lang;
|
||||||
|
|
||||||
|
const ExtensionUtils = imports.misc.extensionUtils;
|
||||||
|
const Me = ExtensionUtils.getCurrentExtension();
|
||||||
|
const EXAMPLE_IMAGES = Me.dir.get_child('data').get_child('images');
|
||||||
|
const USER_IMAGES = Gio.File.new_for_path(GLib.build_filenamev([GLib.get_user_data_dir(), Me.metadata['data-dir'], 'images']));
|
||||||
|
|
||||||
|
var Image = new Lang.Class({
|
||||||
|
Name: 'DrawOnYourScreenImage',
|
||||||
|
|
||||||
|
_init: function(params) {
|
||||||
|
for (let key in params)
|
||||||
|
this[key] = params[key];
|
||||||
|
},
|
||||||
|
|
||||||
|
toString: function() {
|
||||||
|
return this.displayName;
|
||||||
|
},
|
||||||
|
|
||||||
|
toJson: function() {
|
||||||
|
return {
|
||||||
|
displayName: this.displayName,
|
||||||
|
contentType: this.contentType,
|
||||||
|
_base64: this.base64,
|
||||||
|
_hash: this.hash
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
// only called from menu so file exists
|
||||||
|
get gicon() {
|
||||||
|
if (!this._gicon)
|
||||||
|
this._gicon = new Gio.FileIcon({ file: this.file });
|
||||||
|
return this._gicon;
|
||||||
|
},
|
||||||
|
|
||||||
|
get bytes() {
|
||||||
|
if (!this._bytes) {
|
||||||
|
if (this.file)
|
||||||
|
this._bytes = this.file.load_bytes(null)[0];
|
||||||
|
else
|
||||||
|
this._bytes = new GLib.Bytes(GLib.base64_decode(this._base64));
|
||||||
|
}
|
||||||
|
return this._bytes;
|
||||||
|
},
|
||||||
|
|
||||||
|
get base64() {
|
||||||
|
if (!this._base64)
|
||||||
|
this._base64 = GLib.base64_encode(this.bytes.get_data());
|
||||||
|
return this._base64;
|
||||||
|
},
|
||||||
|
|
||||||
|
get hash() {
|
||||||
|
if (!this._hash)
|
||||||
|
this._hash = this.bytes.hash();
|
||||||
|
return this._hash;
|
||||||
|
},
|
||||||
|
|
||||||
|
get pixbuf() {
|
||||||
|
if (!this._pixbuf) {
|
||||||
|
let stream = Gio.MemoryInputStream.new_from_bytes(this.bytes);
|
||||||
|
this._pixbuf = GdkPixbuf.Pixbuf.new_from_stream(stream, null);
|
||||||
|
stream.close(null);
|
||||||
|
}
|
||||||
|
return this._pixbuf;
|
||||||
|
},
|
||||||
|
|
||||||
|
getPixbufAtScale: function(width, height) {
|
||||||
|
let stream = Gio.MemoryInputStream.new_from_bytes(this.bytes);
|
||||||
|
let pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale(stream, width, height, true, null);
|
||||||
|
stream.close(null);
|
||||||
|
return pixbuf;
|
||||||
|
},
|
||||||
|
|
||||||
|
setCairoSource: function(cr, x, y, width, height, preserveAspectRatio) {
|
||||||
|
let pixbuf = preserveAspectRatio ? this.getPixbufAtScale(width, height)
|
||||||
|
: this.pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.BILINEAR);
|
||||||
|
Gdk.cairo_set_source_pixbuf(cr, pixbuf, x, y);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var getImages = function() {
|
||||||
|
let images = [];
|
||||||
|
|
||||||
|
[EXAMPLE_IMAGES, USER_IMAGES].forEach(directory => {
|
||||||
|
let enumerator;
|
||||||
|
try {
|
||||||
|
enumerator = directory.enumerate_children('standard::display-name,standard::content-type', Gio.FileQueryInfoFlags.NONE, null);
|
||||||
|
} catch(e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let fileInfo = enumerator.next_file(null);
|
||||||
|
while (fileInfo) {
|
||||||
|
if (fileInfo.get_content_type().indexOf('image') == 0)
|
||||||
|
images.push(new Image({ file: enumerator.get_child(fileInfo), contentType: fileInfo.get_content_type(), displayName: fileInfo.get_display_name() }));
|
||||||
|
fileInfo = enumerator.next_file(null);
|
||||||
|
}
|
||||||
|
enumerator.close(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
images.sort((a, b) => {
|
||||||
|
return b.displayName < a.displayName;
|
||||||
|
});
|
||||||
|
|
||||||
|
return images;
|
||||||
|
};
|
||||||
|
|
@ -179,6 +179,9 @@ msgstr ""
|
||||||
msgid "Select polyline"
|
msgid "Select polyline"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Select image"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Select text"
|
msgid "Select text"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
@ -227,6 +230,9 @@ msgstr ""
|
||||||
msgid "Toggle text alignment"
|
msgid "Toggle text alignment"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Change image file"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Hide panel and dock"
|
msgid "Hide panel and dock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
@ -316,6 +322,9 @@ msgstr ""
|
||||||
msgid "Polyline"
|
msgid "Polyline"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Image"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Move"
|
msgid "Move"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
||||||
42
menu.js
42
menu.js
|
|
@ -190,6 +190,18 @@ var DrawingMenu = new Lang.Class({
|
||||||
fontSection.itemActivated = () => {};
|
fontSection.itemActivated = () => {};
|
||||||
this.fontSection = fontSection;
|
this.fontSection = fontSection;
|
||||||
|
|
||||||
|
let imageSection = new PopupMenu.PopupMenuSection();
|
||||||
|
let images = this.area.getImages();
|
||||||
|
if (images.length) {
|
||||||
|
if (this.area.currentImage > images.length - 1)
|
||||||
|
this.area.currentImage = images.length - 1;
|
||||||
|
this._addSubMenuItem(imageSection, null, images, this.area, 'currentImage');
|
||||||
|
}
|
||||||
|
this._addSeparator(imageSection);
|
||||||
|
this.menu.addMenuItem(imageSection);
|
||||||
|
imageSection.itemActivated = () => {};
|
||||||
|
this.imageSection = imageSection;
|
||||||
|
|
||||||
let manager = Extension.manager;
|
let manager = Extension.manager;
|
||||||
this._addSimpleSwitchItem(this.menu, _("Hide panel and dock"), manager.hiddenList ? true : false, manager.togglePanelAndDockOpacity.bind(manager));
|
this._addSimpleSwitchItem(this.menu, _("Hide panel and dock"), manager.hiddenList ? true : false, manager.togglePanelAndDockOpacity.bind(manager));
|
||||||
this._addSimpleSwitchItem(this.menu, _("Add a drawing background"), this.area.hasBackground, this.area.toggleBackground.bind(this.area));
|
this._addSimpleSwitchItem(this.menu, _("Add a drawing background"), this.area.hasBackground, this.area.toggleBackground.bind(this.area));
|
||||||
|
|
@ -235,19 +247,13 @@ var DrawingMenu = new Lang.Class({
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateSectionVisibility: function() {
|
_updateSectionVisibility: function() {
|
||||||
if (this.area.currentTool == Area.Tools.TEXT) {
|
let [isText, isImage] = [this.area.currentTool == Area.Tools.TEXT, this.area.currentTool == Area.Tools.IMAGE];
|
||||||
this.lineSection.actor.hide();
|
this.lineSection.actor.visible = !isText && !isImage;
|
||||||
this.fontSection.actor.show();
|
this.fontSection.actor.visible = isText;
|
||||||
this.colorItem.setSensitive(true);
|
this.imageSection.actor.visible = isImage;
|
||||||
this.fillItem.setSensitive(false);
|
this.colorItem.setSensitive(!isImage);
|
||||||
this.fillSection.setSensitive(false);
|
this.fillItem.setSensitive(!isText && !isImage);
|
||||||
} else {
|
this.fillSection.setSensitive(!isText && !isImage);
|
||||||
this.lineSection.actor.show();
|
|
||||||
this.fontSection.actor.hide();
|
|
||||||
this.colorItem.setSensitive(true);
|
|
||||||
this.fillItem.setSensitive(true);
|
|
||||||
this.fillSection.setSensitive(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.area.fill)
|
if (this.area.fill)
|
||||||
this.fillSection.actor.show();
|
this.fillSection.actor.show();
|
||||||
|
|
@ -320,7 +326,9 @@ var DrawingMenu = new Lang.Class({
|
||||||
},
|
},
|
||||||
|
|
||||||
_addSubMenuItem: function(menu, icon, obj, target, targetProperty, callback) {
|
_addSubMenuItem: function(menu, icon, obj, target, targetProperty, callback) {
|
||||||
let item = new PopupMenu.PopupSubMenuMenuItem(_(obj[target[targetProperty]]), icon ? true : false);
|
if (targetProperty == 'currentImage')
|
||||||
|
icon = obj[target[targetProperty]].gicon;
|
||||||
|
let item = new PopupMenu.PopupSubMenuMenuItem(_(String(obj[target[targetProperty]])), icon ? true : false);
|
||||||
if (icon && icon instanceof GObject.Object && GObject.type_is_a(icon, Gio.Icon))
|
if (icon && icon instanceof GObject.Object && GObject.type_is_a(icon, Gio.Icon))
|
||||||
item.icon.set_gicon(icon);
|
item.icon.set_gicon(icon);
|
||||||
else if (icon)
|
else if (icon)
|
||||||
|
|
@ -340,12 +348,14 @@ var DrawingMenu = new Lang.Class({
|
||||||
else if (targetProperty == 'currentFontStyle')
|
else if (targetProperty == 'currentFontStyle')
|
||||||
text = `<span font_style="${obj[i].toLowerCase()}">${_(obj[i])}</span>`;
|
text = `<span font_style="${obj[i].toLowerCase()}">${_(obj[i])}</span>`;
|
||||||
else
|
else
|
||||||
text = _(obj[i]);
|
text = _(String(obj[i]));
|
||||||
|
|
||||||
let iCaptured = Number(i);
|
let iCaptured = Number(i);
|
||||||
let subItem = item.menu.addAction(text, () => {
|
let subItem = item.menu.addAction(text, () => {
|
||||||
item.label.set_text(_(obj[iCaptured]));
|
item.label.set_text(_(String(obj[iCaptured])));
|
||||||
target[targetProperty] = iCaptured;
|
target[targetProperty] = iCaptured;
|
||||||
|
if (targetProperty == 'currentImage')
|
||||||
|
item.icon.set_gicon(obj[iCaptured].gicon);
|
||||||
if (callback)
|
if (callback)
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
2
prefs.js
2
prefs.js
|
|
@ -54,6 +54,7 @@ var INTERNAL_KEYBINDINGS = {
|
||||||
'select-polygon-shape': "Select polygon",
|
'select-polygon-shape': "Select polygon",
|
||||||
'select-polyline-shape': "Select polyline",
|
'select-polyline-shape': "Select polyline",
|
||||||
'select-text-shape': "Select text",
|
'select-text-shape': "Select text",
|
||||||
|
'select-image-shape': "Select image",
|
||||||
'select-move-tool': "Select move",
|
'select-move-tool': "Select move",
|
||||||
'select-resize-tool': "Select resize",
|
'select-resize-tool': "Select resize",
|
||||||
'select-mirror-tool': "Select mirror",
|
'select-mirror-tool': "Select mirror",
|
||||||
|
|
@ -73,6 +74,7 @@ var INTERNAL_KEYBINDINGS = {
|
||||||
'toggle-font-weight': "Change font weight",
|
'toggle-font-weight': "Change font weight",
|
||||||
'toggle-font-style': "Change font style",
|
'toggle-font-style': "Change font style",
|
||||||
'toggle-text-alignment': "Toggle text alignment",
|
'toggle-text-alignment': "Toggle text alignment",
|
||||||
|
'toggle-image-file': "Change image file",
|
||||||
'-separator-5': '',
|
'-separator-5': '',
|
||||||
'toggle-panel-and-dock-visibility': "Hide panel and dock",
|
'toggle-panel-and-dock-visibility': "Hide panel and dock",
|
||||||
'toggle-background': "Add a drawing background",
|
'toggle-background': "Add a drawing background",
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -106,6 +106,11 @@
|
||||||
<summary>select text</summary>
|
<summary>select text</summary>
|
||||||
<description>select text</description>
|
<description>select text</description>
|
||||||
</key>
|
</key>
|
||||||
|
<key type="as" name="select-image-shape">
|
||||||
|
<default>["<Primary>i"]</default>
|
||||||
|
<summary>select image</summary>
|
||||||
|
<description>select image</description>
|
||||||
|
</key>
|
||||||
<key type="as" name="select-none-shape">
|
<key type="as" name="select-none-shape">
|
||||||
<default>["<Primary>p"]</default>
|
<default>["<Primary>p"]</default>
|
||||||
<summary>unselect shape (free drawing)</summary>
|
<summary>unselect shape (free drawing)</summary>
|
||||||
|
|
@ -227,7 +232,7 @@
|
||||||
<description>toggle font weight</description>
|
<description>toggle font weight</description>
|
||||||
</key>
|
</key>
|
||||||
<key type="as" name="toggle-font-style">
|
<key type="as" name="toggle-font-style">
|
||||||
<default>["<Primary>i"]</default>
|
<default>["<Primary><Shift>w"]</default>
|
||||||
<summary>toggle font style</summary>
|
<summary>toggle font style</summary>
|
||||||
<description>toggle font style</description>
|
<description>toggle font style</description>
|
||||||
</key>
|
</key>
|
||||||
|
|
@ -236,6 +241,11 @@
|
||||||
<summary>toggle text alignment</summary>
|
<summary>toggle text alignment</summary>
|
||||||
<description>toggle text alignment</description>
|
<description>toggle text alignment</description>
|
||||||
</key>
|
</key>
|
||||||
|
<key type="as" name="toggle-image-file">
|
||||||
|
<default>["<Primary><Shift>i"]</default>
|
||||||
|
<summary>toggle image file</summary>
|
||||||
|
<description>toggle image file</description>
|
||||||
|
</key>
|
||||||
<key type="as" name="open-user-stylesheet">
|
<key type="as" name="open-user-stylesheet">
|
||||||
<default>["<Primary>o"]</default>
|
<default>["<Primary>o"]</default>
|
||||||
<summary>open user stylesheet to edit style</summary>
|
<summary>open user stylesheet to edit style</summary>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue