Merge branch 'dev' into 'master'

v6.4

See merge request abakkk/DrawOnYourScreen!15
This commit is contained in:
abakkk 2020-09-19 00:34:29 +02:00
commit 34eb8e930b
7 changed files with 100 additions and 92 deletions

92
area.js
View File

@ -367,7 +367,8 @@ var DrawingArea = new Lang.Class({
} else if (button == 2) { } else if (button == 2) {
this.switchFill(); this.switchFill();
} else if (button == 3) { } else if (button == 3) {
this._stopDrawing(); this._stopAll();
this.menu.open(x, y); this.menu.open(x, y);
return Clutter.EVENT_STOP; return Clutter.EVENT_STOP;
} }
@ -376,7 +377,8 @@ var DrawingArea = new Lang.Class({
}, },
_onKeyboardPopupMenu: function() { _onKeyboardPopupMenu: function() {
this._stopDrawing(); this._stopAll();
if (this.helper.visible) if (this.helper.visible)
this.toggleHelp(); this.toggleHelp();
this.menu.popup(); this.menu.popup();
@ -701,6 +703,7 @@ var DrawingArea = new Lang.Class({
}, },
_startWriting: function() { _startWriting: function() {
let [stageX, stageY] = this.get_transformed_position();
let [x, y] = [this.currentElement.x, this.currentElement.y]; let [x, y] = [this.currentElement.x, this.currentElement.y];
this.currentElement.text = ''; this.currentElement.text = '';
this.currentElement.cursorPosition = 0; this.currentElement.cursorPosition = 0;
@ -711,16 +714,22 @@ var DrawingArea = new Lang.Class({
this.textHasCursor = true; this.textHasCursor = true;
this._redisplay(); this._redisplay();
this.textEntry = new St.Entry({ visible: false, x, y }); // Do not hide and do not set opacity to 0 because ibusCandidatePopup need a mapped text entry to init correctly its position.
this.get_parent().add_child(this.textEntry); this.textEntry = new St.Entry({ opacity: 1, x: stageX + x, y: stageY + y });
this.get_parent().insert_child_below(this.textEntry, this);
this.textEntry.grab_key_focus(); this.textEntry.grab_key_focus();
this.updateActionMode(); this.updateActionMode();
this.updatePointerCursor(); this.updatePointerCursor();
let ibusCandidatePopup = Main.layoutManager.uiGroup.get_children().filter(child => let ibusCandidatePopup = Main.layoutManager.uiGroup.get_children().find(child =>
child.has_style_class_name && child.has_style_class_name('candidate-popup-boxpointer'))[0] || null; child.has_style_class_name && child.has_style_class_name('candidate-popup-boxpointer'));
if (ibusCandidatePopup) { if (ibusCandidatePopup) {
this.ibusHandler = ibusCandidatePopup.connect('notify::visible', popup => popup.visible && (this.textEntry.visible = true)); this.ibusHandler = ibusCandidatePopup.connect('notify::visible', () => {
if (ibusCandidatePopup.visible) {
this.get_parent().set_child_above_sibling(this.textEntry, this);
this.textEntry.opacity = 255;
}
});
this.textEntry.connect('destroy', () => ibusCandidatePopup.disconnect(this.ibusHandler)); this.textEntry.connect('destroy', () => ibusCandidatePopup.disconnect(this.ibusHandler));
} }
@ -832,6 +841,21 @@ var DrawingArea = new Lang.Class({
}); });
}, },
// A priori there is nothing to stop, except transformations, if there is no current element.
// 'force' argument is passed when leaving drawing mode to ensure all is clean, as a workaround for possible bugs.
_stopAll: function(force) {
if (this.grabbedElement)
this._stopTransforming();
if (!this.currentElement && !force)
return;
if (this.isWriting)
this._stopWriting();
this._stopDrawing();
},
erase: function() { erase: function() {
this.deleteLastElement(); this.deleteLastElement();
this.elements = []; this.elements = [];
@ -840,21 +864,8 @@ var DrawingArea = new Lang.Class({
}, },
deleteLastElement: function() { deleteLastElement: function() {
if (this.currentElement) { this._stopAll();
if (this.motionHandler) { this.elements.pop();
this.disconnect(this.motionHandler);
this.motionHandler = null;
}
if (this.buttonReleasedHandler) {
this.disconnect(this.buttonReleasedHandler);
this.buttonReleasedHandler = null;
}
if (this.isWriting)
this._stopWriting();
this.currentElement = null;
} else {
this.elements.pop();
}
this._redisplay(); this._redisplay();
}, },
@ -1085,25 +1096,16 @@ var DrawingArea = new Lang.Class({
this.disconnect(this.keyboardPopupMenuHandler); this.disconnect(this.keyboardPopupMenuHandler);
this.keyboardPopupMenuHandler = null; this.keyboardPopupMenuHandler = null;
} }
if (this.motionHandler) {
this.disconnect(this.motionHandler);
this.motionHandler = null;
}
if (this.buttonReleasedHandler) {
this.disconnect(this.buttonReleasedHandler);
this.buttonReleasedHandler = null;
}
if (this.scrollHandler) { if (this.scrollHandler) {
this.disconnect(this.scrollHandler); this.disconnect(this.scrollHandler);
this.scrollHandler = null; this.scrollHandler = null;
} }
this.currentElement = null; this._stopAll(true);
this._stopTextCursorTimeout();
if (erase) if (erase)
this.erase(); this.erase();
else
this._redisplay();
this.closeMenu(); this.closeMenu();
this.get_parent().set_background_color(null); this.get_parent().set_background_color(null);
Files.Images.reset(); Files.Images.reset();
@ -1143,12 +1145,7 @@ var DrawingArea = new Lang.Class({
}, },
exportToSvg: function() { exportToSvg: function() {
// stop drawing or writing this._stopAll();
if (this.currentElement && this.currentElement.shape == Shapes.TEXT && this.isWriting) {
this._stopWriting();
} else if (this.currentElement && this.currentElement.shape != Shapes.TEXT) {
this._stopDrawing();
}
let prefixes = '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)) if (this.elements.some(element => element.shape == Shapes.IMAGE))
@ -1181,12 +1178,7 @@ var DrawingArea = new Lang.Class({
}, },
_saveAsJson: function(json, notify, callback) { _saveAsJson: function(json, notify, callback) {
// stop drawing or writing this._stopAll();
if (this.currentElement && this.currentElement.shape == Shapes.TEXT && this.isWriting) {
this._stopWriting();
} else if (this.currentElement && this.currentElement.shape != Shapes.TEXT) {
this._stopDrawing();
}
// do not use "content = JSON.stringify(this.elements, null, 2);", neither "content = JSON.stringify(this.elements);" // do not use "content = JSON.stringify(this.elements, null, 2);", neither "content = JSON.stringify(this.elements);"
// do compromise between disk usage and human readability // do compromise between disk usage and human readability
@ -1225,12 +1217,8 @@ var DrawingArea = new Lang.Class({
}, },
_loadJson: function(json, notify) { _loadJson: function(json, notify) {
// stop drawing or writing this._stopAll();
if (this.currentElement && this.currentElement.shape == Shapes.TEXT && this.isWriting) {
this._stopWriting();
} else if (this.currentElement && this.currentElement.shape != Shapes.TEXT) {
this._stopDrawing();
}
this.elements = []; this.elements = [];
this.currentElement = null; this.currentElement = null;

View File

@ -670,9 +670,9 @@ const TextElement = new Lang.Class({
layout.set_font_description(this.font); layout.set_font_description(this.font);
layout.set_text(this.text, -1); layout.set_text(this.text, -1);
this.textWidth = layout.get_pixel_size()[0]; this.textWidth = layout.get_pixel_size()[0];
cr.moveTo(this.x, this.y - layout.get_baseline() / Pango.SCALE); cr.moveTo(this.x, this.y);
layout.set_text(this.text, -1); layout.set_text(this.text, -1);
PangoCairo.show_layout(cr, layout); PangoCairo.show_layout_line(cr, layout.get_line(0));
if (params.showTextCursor) { if (params.showTextCursor) {
let cursorPosition = this.cursorPosition == -1 ? this.text.length : this.cursorPosition; let cursorPosition = this.cursorPosition == -1 ? this.text.length : this.cursorPosition;

View File

@ -318,11 +318,12 @@ var Images = {
}, },
addImagesFromClipboard: function(callback) { addImagesFromClipboard: function(callback) {
Clipboard.get_text(CLIPBOARD_TYPE, (clipBoard, text) => { Clipboard.get_text(CLIPBOARD_TYPE, (clipboard, text) => {
if (!text) if (!text)
return; return;
let lines = text.split('\n'); // Since 3.38 there is a line terminator character, that has to be removed with .trim().
let lines = text.split('\n').map(line => line.trim());
if (lines[0] == 'x-special/nautilus-clipboard') if (lines[0] == 'x-special/nautilus-clipboard')
lines = lines.slice(2); lines = lines.slice(2);
@ -443,7 +444,9 @@ var Jsons = {
return; return;
let directory = Gio.File.new_for_path(GLib.build_filenamev([GLib.get_user_data_dir(), Me.metadata['data-dir']])); let directory = Gio.File.new_for_path(GLib.build_filenamev([GLib.get_user_data_dir(), Me.metadata['data-dir']]));
this._monitor = directory.monitor(Gio.FileMonitorFlags.NONE, null); // It is important to specify that the file to monitor is a directory because maybe the directory does not exist yet
// and remove events would not be monitored.
this._monitor = directory.monitor_directory(Gio.FileMonitorFlags.NONE, null);
this._monitorHandler = this._monitor.connect('changed', (monitor, file) => { this._monitorHandler = this._monitor.connect('changed', (monitor, file) => {
if (file.get_basename() != `${Me.metadata['persistent-file-name']}.json` && file.get_basename().indexOf('.goutputstream')) if (file.get_basename() != `${Me.metadata['persistent-file-name']}.json` && file.get_basename().indexOf('.goutputstream'))
this.reset(); this.reset();

View File

@ -21,13 +21,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
const Clutter = imports.gi.Clutter;
const Gtk = imports.gi.Gtk; const Gtk = imports.gi.Gtk;
const Lang = imports.lang; const Lang = imports.lang;
const St = imports.gi.St; const St = imports.gi.St;
const Config = imports.misc.config; const Config = imports.misc.config;
const ExtensionUtils = imports.misc.extensionUtils; const ExtensionUtils = imports.misc.extensionUtils;
const Tweener = imports.ui.tweener;
const Me = ExtensionUtils.getCurrentExtension(); const Me = ExtensionUtils.getCurrentExtension();
const Convenience = ExtensionUtils.getSettings ? ExtensionUtils : Me.imports.convenience; const Convenience = ExtensionUtils.getSettings ? ExtensionUtils : Me.imports.convenience;
@ -35,6 +35,7 @@ const Shortcuts = Me.imports.shortcuts;
const _ = imports.gettext.domain(Me.metadata['gettext-domain']).gettext; const _ = imports.gettext.domain(Me.metadata['gettext-domain']).gettext;
const GS_VERSION = Config.PACKAGE_VERSION; const GS_VERSION = Config.PACKAGE_VERSION;
const Tweener = GS_VERSION < '3.33.0' ? imports.ui.tweener : null;
const HELPER_ANIMATION_TIME = 0.25; const HELPER_ANIMATION_TIME = 0.25;
const MEDIA_KEYS_SCHEMA = 'org.gnome.settings-daemon.plugins.media-keys'; const MEDIA_KEYS_SCHEMA = 'org.gnome.settings-daemon.plugins.media-keys';
@ -175,20 +176,33 @@ var DrawingHelper = new Lang.Class({
else else
this.vscrollbar_policy = Gtk.PolicyType.NEVER; this.vscrollbar_policy = Gtk.PolicyType.NEVER;
Tweener.removeTweens(this); if (Tweener) {
Tweener.addTween(this, { opacity: 255, Tweener.removeTweens(this);
time: HELPER_ANIMATION_TIME, Tweener.addTween(this, { opacity: 255,
transition: 'easeOutQuad', time: HELPER_ANIMATION_TIME,
onComplete: null }); transition: 'easeOutQuad' });
} else {
this.remove_all_transitions();
this.ease({ opacity: 255,
duration: HELPER_ANIMATION_TIME * 1000,
transition: Clutter.AnimationMode.EASE_OUT_QUAD });
}
}, },
hideHelp: function() { hideHelp: function() {
Tweener.removeTweens(this); if (Tweener) {
Tweener.addTween(this, { opacity: 0, Tweener.removeTweens(this);
time: HELPER_ANIMATION_TIME, Tweener.addTween(this, { opacity: 0,
transition: 'easeOutQuad', time: HELPER_ANIMATION_TIME,
onComplete: this.hide.bind(this) }); transition: 'easeOutQuad',
onComplete: this.hide.bind(this) });
} else {
this.remove_all_transitions();
this.ease({ opacity: 0,
duration: HELPER_ANIMATION_TIME * 1000,
transition: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: this.hide.bind(this) });
}
} }
}); });

View File

@ -10,7 +10,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Draw On Your Screen\n" "Project-Id-Version: Draw On Your Screen\n"
"Report-Msgid-Bugs-To: https://framagit.org/abakkk/DrawOnYourScreen/issues\n" "Report-Msgid-Bugs-To: https://framagit.org/abakkk/DrawOnYourScreen/issues\n"
"POT-Creation-Date: 2020-09-17 22:27+0200\n" "POT-Creation-Date: 2020-09-18 11:37+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -284,6 +284,12 @@ msgstr ""
msgid "Color" msgid "Color"
msgstr "" msgstr ""
msgid "Add to images"
msgstr ""
msgid "Delete"
msgstr ""
msgid "Type a name" msgid "Type a name"
msgstr "" msgstr ""
@ -417,7 +423,7 @@ msgstr ""
msgid "Smooth free drawing outline" msgid "Smooth free drawing outline"
msgstr "" msgstr ""
msgid "Unlock image ratio" msgid "Do not preserve image ratio"
msgstr "" msgstr ""
msgid "Rotate <span alpha=\"50%\">(while moving)</span>" msgid "Rotate <span alpha=\"50%\">(while moving)</span>"

35
menu.js
View File

@ -616,29 +616,24 @@ var DrawingMenu = new Lang.Class({
}); });
getActor(subItem).add_child(expander); getActor(subItem).add_child(expander);
let insertButton = new St.Button({ style_class: 'button draw-on-your-screen-menu-inline-button', let insertCallback = () => {
child: new St.Icon({ icon_name: 'insert-image-symbolic',
style_class: 'popup-menu-icon' }) });
getActor(subItem).add_child(insertButton);
insertButton.connect('clicked', () => {
this.area.currentImage = json.image; this.area.currentImage = json.image;
this.imageItem.update(); this.imageItem.update();
this.area.currentTool = this.drawingTools.IMAGE; this.area.currentTool = this.drawingTools.IMAGE;
this.toolItem.update(); this.toolItem.update();
this._updateSectionVisibility(); this._updateSectionVisibility();
}); };
let insertButton = new ActionButton(_("Add to images"), 'insert-image-symbolic', insertCallback, null, true);
getActor(subItem).add_child(insertButton);
let deleteButton = new St.Button({ style_class: 'button draw-on-your-screen-menu-inline-button draw-on-your-screen-menu-destructive-button', let deleteCallback = () => {
child: new St.Icon({ icon_name: 'edit-delete-symbolic',
style_class: 'popup-menu-icon' }) });
getActor(subItem).add_child(deleteButton);
deleteButton.connect('clicked', () => {
json.delete(); json.delete();
subItem.destroy(); subItem.destroy();
this.openDrawingSubMenuItem.setSensitive(!this.openDrawingSubMenu.isEmpty()); this.openDrawingSubMenuItem.setSensitive(!this.openDrawingSubMenu.isEmpty());
}); };
let deleteButton = new ActionButton(_("Delete"), 'edit-delete-symbolic', deleteCallback, null, true);
deleteButton.child.add_style_class_name('draw-on-your-screen-menu-destructive-button');
getActor(subItem).add_child(deleteButton);
}); });
this.openDrawingSubMenuItem.setSensitive(!this.openDrawingSubMenu.isEmpty()); this.openDrawingSubMenuItem.setSensitive(!this.openDrawingSubMenu.isEmpty());
@ -722,16 +717,18 @@ const ActionButton = new Lang.Class({
hideLabel: Dash.DashItemContainer.prototype.hideLabel, hideLabel: Dash.DashItemContainer.prototype.hideLabel,
_syncLabel: Dash.Dash.prototype._syncLabel, _syncLabel: Dash.Dash.prototype._syncLabel,
_init: function(name, icon, callback, callbackAfter) { _init: function(name, icon, callback, callbackAfter, inline) {
this._labelText = name; this._labelText = name;
let button = new St.Button({ track_hover: true, let button = new St.Button({ track_hover: true,
x_align: Clutter.ActorAlign.CENTER, x_align: Clutter.ActorAlign.CENTER,
accessible_name: name, accessible_name: name,
// use 'popup-menu' and 'popup-menu-item' style classes to provide theme colors style_class: `button draw-on-your-screen-menu-${inline ? 'inline' : 'action'}-button` });
//style_class: 'system-menu-action popup-menu-item popup-menu' });
style_class: 'button draw-on-your-screen-menu-action-button' });
button.child = new St.Icon(typeof icon == 'string' ? { icon_name: icon } : { gicon: icon }); button.child = new St.Icon(typeof icon == 'string' ? { icon_name: icon } : { gicon: icon });
if (inline)
button.child.add_style_class_name('popup-menu-icon');
button.connect('clicked', () => { button.connect('clicked', () => {
callback(); callback();
if (callbackAfter) if (callbackAfter)
@ -740,7 +737,7 @@ const ActionButton = new Lang.Class({
button.bind_property('reactive', button, 'can_focus', GObject.BindingFlags.DEFAULT); button.bind_property('reactive', button, 'can_focus', GObject.BindingFlags.DEFAULT);
button.connect('notify::hover', () => this._syncLabel(this)); button.connect('notify::hover', () => this._syncLabel(this));
this.parent({ child: button, x_expand: true }); this.parent({ child: button, x_expand: inline ? false : true });
}, },
get label() { get label() {

View File

@ -83,7 +83,7 @@ const getOthers = function() {
[_("Extend circle to ellipse"), getKeyLabel('<Primary>')], [_("Extend circle to ellipse"), getKeyLabel('<Primary>')],
[_("Curve line"), getKeyLabel('<Primary>')], [_("Curve line"), getKeyLabel('<Primary>')],
[_("Smooth free drawing outline"), getKeyLabel('<Primary>')], [_("Smooth free drawing outline"), getKeyLabel('<Primary>')],
[_("Unlock image ratio"), getKeyLabel('<Primary>')], [_("Do not preserve image ratio"), getKeyLabel('<Primary>')],
[_("Rotate <span alpha=\"50%\">(while moving)</span>"), getKeyLabel('<Primary>')], [_("Rotate <span alpha=\"50%\">(while moving)</span>"), getKeyLabel('<Primary>')],
[_("Stretch <span alpha=\"50%\">(while resizing)</span>"), getKeyLabel('<Primary>')], [_("Stretch <span alpha=\"50%\">(while resizing)</span>"), getKeyLabel('<Primary>')],
[_("Inverse <span alpha=\"50%\">(while mirroring)</span>"), getKeyLabel('<Primary>')], [_("Inverse <span alpha=\"50%\">(while mirroring)</span>"), getKeyLabel('<Primary>')],