From 01701538bb7fb3f356230ec98d742ace5b269f66 Mon Sep 17 00:00:00 2001 From: abakkk Date: Sun, 23 Aug 2020 11:49:26 +0200 Subject: [PATCH 01/35] minor, rework settings --- area.js | 2 - extension.js | 49 ++++++++++-------- helper.js | 25 +++++---- prefs.js | 15 +++--- schemas/gschemas.compiled | Bin 4544 -> 4888 bytes ...extensions.draw-on-your-screen.gschema.xml | 3 ++ 6 files changed, 51 insertions(+), 43 deletions(-) diff --git a/area.js b/area.js index 2684308..f2d9c34 100644 --- a/area.js +++ b/area.js @@ -36,7 +36,6 @@ const Main = imports.ui.main; const Screenshot = imports.ui.screenshot; const Me = ExtensionUtils.getCurrentExtension(); -const Convenience = ExtensionUtils.getSettings ? ExtensionUtils : Me.imports.convenience; const Extension = Me.imports.extension; const Elements = Me.imports.elements; const Files = Me.imports.files; @@ -73,7 +72,6 @@ var DrawingArea = new Lang.Class({ this.connect('destroy', this._onDestroy.bind(this)); this.reactiveHandler = this.connect('notify::reactive', this._onReactiveChanged.bind(this)); - this.settings = Convenience.getSettings(); this.monitor = monitor; this.helper = helper; diff --git a/extension.js b/extension.js index a253683..632cb8e 100644 --- a/extension.js +++ b/extension.js @@ -28,11 +28,11 @@ const Shell = imports.gi.Shell; const St = imports.gi.St; const Config = imports.misc.config; +const ExtensionUtils = imports.misc.extensionUtils; const Main = imports.ui.main; const OsdWindow = imports.ui.osdWindow; const PanelMenu = imports.ui.panelMenu; -const ExtensionUtils = imports.misc.extensionUtils; const Me = ExtensionUtils.getCurrentExtension(); const Convenience = ExtensionUtils.getSettings && ExtensionUtils.initTranslations ? ExtensionUtils : Me.imports.convenience; const Area = Me.imports.area; @@ -55,12 +55,16 @@ function init() { } function enable() { + Me.settings = Convenience.getSettings(); + Me.internalShortcutSettings = Convenience.getSettings(Me.metadata['settings-schema'] + '.internal-shortcuts'); manager = new AreaManager(); } function disable() { manager.disable(); manager = null; + delete Me.settings; + delete Me.internalShortcutSettings; } // AreaManager assigns one DrawingArea per monitor (updateAreas()), @@ -70,26 +74,25 @@ var AreaManager = new Lang.Class({ Name: 'DrawOnYourScreenAreaManager', _init: function() { - this.settings = Convenience.getSettings(); this.areas = []; this.activeArea = null; this.enterGicon = new Gio.ThemedIcon({ name: 'applications-graphics-symbolic' }); this.leaveGicon = new Gio.ThemedIcon({ name: 'application-exit-symbolic' }); Main.wm.addKeybinding('toggle-drawing', - this.settings, + Me.settings, Meta.KeyBindingFlags.NONE, Shell.ActionMode.ALL, this.toggleDrawing.bind(this)); Main.wm.addKeybinding('toggle-modal', - this.settings, + Me.settings, Meta.KeyBindingFlags.NONE, Shell.ActionMode.ALL, this.toggleModal.bind(this)); Main.wm.addKeybinding('erase-drawing', - this.settings, + Me.settings, Meta.KeyBindingFlags.NONE, Shell.ActionMode.ALL, this.eraseDrawing.bind(this)); @@ -98,10 +101,10 @@ var AreaManager = new Lang.Class({ this.monitorChangedHandler = Main.layoutManager.connect('monitors-changed', this.updateAreas.bind(this)); this.updateIndicator(); - this.indicatorSettingHandler = this.settings.connect('changed::indicator-disabled', this.updateIndicator.bind(this)); + this.indicatorSettingHandler = Me.settings.connect('changed::indicator-disabled', this.updateIndicator.bind(this)); - this.desktopSettingHandler = this.settings.connect('changed::drawing-on-desktop', this.onDesktopSettingChanged.bind(this)); - this.persistentSettingHandler = this.settings.connect('changed::persistent-drawing', this.onPersistentSettingChanged.bind(this)); + this.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'])); @@ -125,14 +128,14 @@ var AreaManager = new Lang.Class({ }, onDesktopSettingChanged: function() { - if (this.settings.get_boolean("drawing-on-desktop")) + if (Me.settings.get_boolean("drawing-on-desktop")) this.areas.forEach(area => area.get_parent().show()); else this.areas.forEach(area => area.get_parent().hide()); }, onPersistentSettingChanged: function() { - if (this.settings.get_boolean('persistent-drawing')) + if (Me.settings.get_boolean('persistent-drawing')) this.areas[Main.layoutManager.primaryIndex].syncPersistent(); }, @@ -141,7 +144,7 @@ var AreaManager = new Lang.Class({ this.indicator.disable(); this.indicator = null; } - if (!this.settings.get_boolean('indicator-disabled')) + if (!Me.settings.get_boolean('indicator-disabled')) this.indicator = new DrawingIndicator(); }, @@ -156,13 +159,13 @@ var AreaManager = new Lang.Class({ let monitor = this.monitors[i]; let container = new St.Widget({ name: 'drawOnYourSreenContainer' + i }); let helper = new Helper.DrawingHelper({ name: 'drawOnYourSreenHelper' + i }, monitor); - let loadPersistent = i == Main.layoutManager.primaryIndex && this.settings.get_boolean('persistent-drawing'); + let loadPersistent = i == Main.layoutManager.primaryIndex && Me.settings.get_boolean('persistent-drawing'); let area = new Area.DrawingArea({ name: 'drawOnYourSreenArea' + i }, monitor, helper, loadPersistent); container.add_child(area); container.add_child(helper); Main.layoutManager._backgroundGroup.insert_child_above(container, Main.layoutManager._bgManagers[i].backgroundActor); - if (!this.settings.get_boolean("drawing-on-desktop")) + if (!Me.settings.get_boolean("drawing-on-desktop")) container.hide(); container.set_position(monitor.x, monitor.y); @@ -228,7 +231,7 @@ var AreaManager = new Lang.Class({ for (let key in this.internalKeybindings1) { Main.wm.addKeybinding(key, - this.settings, + Me.internalShortcutSettings, Meta.KeyBindingFlags.NONE, DRAWING_ACTION_MODE, this.internalKeybindings1[key]); @@ -236,7 +239,7 @@ var AreaManager = new Lang.Class({ for (let key in this.internalKeybindings2) { Main.wm.addKeybinding(key, - this.settings, + Me.internalShortcutSettings, Meta.KeyBindingFlags.NONE, DRAWING_ACTION_MODE | WRITING_ACTION_MODE, this.internalKeybindings2[key]); @@ -245,7 +248,7 @@ var AreaManager = new Lang.Class({ for (let i = 1; i < 10; i++) { let iCaptured = i; Main.wm.addKeybinding('select-color' + i, - this.settings, + Me.internalShortcutSettings, Meta.KeyBindingFlags.NONE, DRAWING_ACTION_MODE | WRITING_ACTION_MODE, () => this.activeArea.selectColor(iCaptured)); @@ -292,7 +295,7 @@ var AreaManager = new Lang.Class({ eraseDrawing: function() { for (let i = 0; i < this.areas.length; i++) this.areas[i].erase(); - if (this.settings.get_boolean('persistent-drawing')) + if (Me.settings.get_boolean('persistent-drawing')) this.areas[Main.layoutManager.primaryIndex].savePersistent(); }, @@ -345,7 +348,7 @@ var AreaManager = new Lang.Class({ Main.uiGroup.set_child_at_index(Main.layoutManager.keyboardBox, this.oldKeyboardIndex); Main.uiGroup.remove_actor(activeContainer); Main.layoutManager._backgroundGroup.insert_child_above(activeContainer, Main.layoutManager._bgManagers[activeIndex].backgroundActor); - if (!this.settings.get_boolean("drawing-on-desktop")) + if (!Me.settings.get_boolean("drawing-on-desktop")) activeContainer.hide(); } else { Main.layoutManager._backgroundGroup.remove_actor(activeContainer); @@ -387,7 +390,7 @@ var AreaManager = new Lang.Class({ toggleDrawing: function() { if (this.activeArea) { let activeIndex = this.areas.indexOf(this.activeArea); - let save = activeIndex == Main.layoutManager.primaryIndex && this.settings.get_boolean('persistent-drawing'); + let save = activeIndex == Main.layoutManager.primaryIndex && Me.settings.get_boolean('persistent-drawing'); this.showOsd(null, this.leaveGicon, _("Leaving drawing mode")); this.activeArea.leaveDrawingMode(save); @@ -410,7 +413,7 @@ var AreaManager = new Lang.Class({ } this.activeArea.enterDrawingMode(); - this.osdDisabled = this.settings.get_boolean('osd-disabled'); + this.osdDisabled = Me.settings.get_boolean('osd-disabled'); let label = _("Press %s for help").format(this.activeArea.helper.helpKeyLabel) + "\n\n" + _("Entering drawing mode"); this.showOsd(null, this.enterGicon, label, null, null, true); } @@ -531,15 +534,15 @@ var AreaManager = new Lang.Class({ this.monitorChangedHandler = null; } if (this.indicatorSettingHandler) { - this.settings.disconnect(this.indicatorSettingHandler); + Me.settings.disconnect(this.indicatorSettingHandler); this.indicatorSettingHandler = null; } if (this.desktopSettingHandler) { - this.settings.disconnect(this.desktopSettingHandler); + Me.settings.disconnect(this.desktopSettingHandler); this.desktopSettingHandler = null; } if (this.persistentSettingHandler) { - this.settings.disconnect(this.persistentSettingHandler); + Me.settings.disconnect(this.persistentSettingHandler); this.persistentSettingHandler = null; } diff --git a/helper.js b/helper.js index e3bfe2e..d6704e9 100644 --- a/helper.js +++ b/helper.js @@ -25,9 +25,9 @@ const Lang = imports.lang; const St = imports.gi.St; const Config = imports.misc.config; +const ExtensionUtils = imports.misc.extensionUtils; const Tweener = imports.ui.tweener; -const ExtensionUtils = imports.misc.extensionUtils; const Me = ExtensionUtils.getCurrentExtension(); const Convenience = ExtensionUtils.getSettings ? ExtensionUtils : Me.imports.convenience; const Prefs = Me.imports.prefs; @@ -55,24 +55,27 @@ var DrawingHelper = new Lang.Class({ this.parent(params); this.monitor = monitor; this.hide(); - this.settings = Convenience.getSettings(); - this.settingHandler = this.settings.connect('changed', this._onSettingChanged.bind(this)); - this.connect('destroy', () => this.settings.disconnect(this.settingHandler)); + this.settingsHandler = Me.settings.connect('changed', this._onSettingsChanged.bind(this)); + this.internalShortcutsettingsHandler = Me.internalShortcutSettings.connect('changed', this._onSettingsChanged.bind(this)); + this.connect('destroy', () => { + Me.settings.disconnect(this.settingsHandler); + Me.internalShortcutSettings.disconnect(this.internalShortcutsettingsHandler); + }); }, - _onSettingChanged: function(settings, key) { + _onSettingsChanged: function(settings, key) { if (key == 'toggle-help') this._updateHelpKeyLabel(); if (this.vbox) { this.vbox.destroy(); - this.vbox = null; + delete this.vbox; } }, _updateHelpKeyLabel: function() { - let [keyval, mods] = Gtk.accelerator_parse(this.settings.get_strv('toggle-help')[0]); + let [keyval, mods] = Gtk.accelerator_parse(Me.internalShortcutSettings.get_strv('toggle-help')[0]); this._helpKeyLabel = Gtk.accelerator_get_label(keyval, mods); }, @@ -94,9 +97,9 @@ var DrawingHelper = new Lang.Class({ this.vbox.add_child(hbox); continue; } - if (!this.settings.get_strv(settingKey)[0]) + if (!Me.settings.get_strv(settingKey)[0]) continue; - let [keyval, mods] = Gtk.accelerator_parse(this.settings.get_strv(settingKey)[0]); + let [keyval, mods] = Gtk.accelerator_parse(Me.settings.get_strv(settingKey)[0]); hbox.add_child(new St.Label({ text: _(Prefs.GLOBAL_KEYBINDINGS[settingKey]) })); hbox.add_child(new St.Label({ text: Gtk.accelerator_get_label(keyval, mods), x_expand: true })); this.vbox.add_child(hbox); @@ -124,9 +127,9 @@ var DrawingHelper = new Lang.Class({ continue; } let hbox = new St.BoxLayout({ vertical: false }); - if (!this.settings.get_strv(settingKey)[0]) + if (!Me.internalShortcutSettings.get_strv(settingKey)[0]) continue; - let [keyval, mods] = Gtk.accelerator_parse(this.settings.get_strv(settingKey)[0]); + let [keyval, mods] = Gtk.accelerator_parse(Me.internalShortcutSettings.get_strv(settingKey)[0]); hbox.add_child(new St.Label({ text: _(Prefs.INTERNAL_KEYBINDINGS[settingKey]) })); hbox.add_child(new St.Label({ text: Gtk.accelerator_get_label(keyval, mods), x_expand: true })); this.vbox.add_child(hbox); diff --git a/prefs.js b/prefs.js index 8ff013d..3706a50 100644 --- a/prefs.js +++ b/prefs.js @@ -207,7 +207,8 @@ const PrefsPage = new GObject.Class({ _init: function(params) { this.parent(); - this.settings = Convenience.getSettings(); + let settings = Convenience.getSettings(); + let internalShortcutSettings = Convenience.getSettings(Me.metadata['settings-schema'] + '.internal-shortcuts'); let box = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, margin: MARGIN*3 }); this.add(box); @@ -222,7 +223,7 @@ const PrefsPage = new GObject.Class({ let styleContext = listBox.get_style_context(); styleContext.add_class('background'); - let globalKeybindingsWidget = new KeybindingsWidget(GLOBAL_KEYBINDINGS, this.settings); + let globalKeybindingsWidget = new KeybindingsWidget(GLOBAL_KEYBINDINGS, settings); globalKeybindingsWidget.margin = MARGIN; listBox.add(globalKeybindingsWidget); @@ -235,7 +236,7 @@ const PrefsPage = new GObject.Class({ persistentLabelBox.pack_start(persistentLabel1, true, true, 0); persistentLabelBox.pack_start(persistentLabel2, true, true, 0); let persistentSwitch = new Gtk.Switch({valign: 3}); - this.settings.bind('persistent-drawing', persistentSwitch, 'active', 0); + settings.bind('persistent-drawing', persistentSwitch, 'active', 0); persistentBox.pack_start(persistentLabelBox, true, true, 4); persistentBox.pack_start(persistentSwitch, false, false, 4); listBox.add(persistentBox); @@ -249,7 +250,7 @@ const PrefsPage = new GObject.Class({ desktopLabelBox.pack_start(desktopLabel1, true, true, 0); desktopLabelBox.pack_start(desktopLabel2, true, true, 0); let desktopSwitch = new Gtk.Switch({valign: 3}); - this.settings.bind('drawing-on-desktop', desktopSwitch, 'active', 0); + settings.bind('drawing-on-desktop', desktopSwitch, 'active', 0); desktopBox.pack_start(desktopLabelBox, true, true, 4); desktopBox.pack_start(desktopSwitch, false, false, 4); listBox.add(desktopBox); @@ -260,7 +261,7 @@ const PrefsPage = new GObject.Class({ osdLabel1.set_halign(1); osdLabelBox.pack_start(osdLabel1, true, true, 0); let osdSwitch = new Gtk.Switch({valign: 3}); - this.settings.bind('osd-disabled', osdSwitch, 'active', 0); + settings.bind('osd-disabled', osdSwitch, 'active', 0); osdBox.pack_start(osdLabelBox, true, true, 4); osdBox.pack_start(osdSwitch, false, false, 4); listBox.add(osdBox); @@ -271,7 +272,7 @@ const PrefsPage = new GObject.Class({ indicatorLabel1.set_halign(1); indicatorLabelBox.pack_start(indicatorLabel1, true, true, 0); let indicatorSwitch = new Gtk.Switch({valign: 3}); - this.settings.bind('indicator-disabled', indicatorSwitch, 'active', 0); + settings.bind('indicator-disabled', indicatorSwitch, 'active', 0); indicatorBox.pack_start(indicatorLabelBox, true, true, 4); indicatorBox.pack_start(indicatorSwitch, false, false, 4); listBox.add(indicatorBox); @@ -306,7 +307,7 @@ const PrefsPage = new GObject.Class({ listBox.add(otherBox); } - let internalKeybindingsWidget = new KeybindingsWidget(INTERNAL_KEYBINDINGS, this.settings); + let internalKeybindingsWidget = new KeybindingsWidget(INTERNAL_KEYBINDINGS, internalShortcutSettings); internalKeybindingsWidget.margin = MARGIN; listBox.add(internalKeybindingsWidget); diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled index 92584ee8996575d7c52df4ad18a835ea688069e0..269a8e8bceeb2992fc975c8a1ebb5c936be614e0 100644 GIT binary patch literal 4888 zcmb7He`sCh89tfqmbIFu)@l-?M%QX;cW#oVX_Hc8tI?*_LQALw*=$el{c`WuoO{0O zIp-$1QHvXb8!CthMzE+TvpA&@ow%ylf`1f2h-|Wmf2p5wPscOdpxgGuE*6BKZ9V%liF^ zw?C)87Y%koe;hpgQ_EVu*0Rpw*SrP~tvfAp3!wabChw`D$OHx9x*0JY3NMh#3o<$1 znX;8 zFM&P_eg$~-!%ttOPJ0dXli+1Y{-qP&H&ds5DfAZbRlr!M=%G%VdN;TaST(av>$Is4 zgIRMGUltv|GPr%G z8xC$CDVKyln6s|1I-OvHapvGiFHd)?)~!jqWlBz1&`&L^3xnLH2f0fRa#u3QU3CVz z%d!IDJAtrGC+YYC)n^*g3x)4Ft{oJVA7;y8&~<@xDRX`ZbS%A`%sQd+Q&rS;G`Vm> z=0q?NsuJD~^+jz08DP?eQMy(A!X|dzWEg0(sUfC`9)>Lb320t|OYuL# zWw5dQtjmEb3|hf$K)b>iytRpr!k!TiGvduB8(ASHR*i_Z)TF&CqATXMo)%4sFI+9zfd zI&J1N3YNg>@R8T4)299)_-SBt_RSZl(`KAG@G0Qv@#_?I+RSGj{5PQO?y63k`Xaai zi{{8fbI;J9b}RG_@GZbEw%RAC(_RaG6fA+tsgWU z-U03bo_c5h9Cg~va~S+f;K03KT~D1h>oyI399Z?uee0;x<~SY${}K4}XCpJzX>=*%sQpbbvg@v3z+z>x1I56Gyi$;S>RUVPh0N;VBTv2;fic% zXO*k`UbKtP(>wMZ>`nglT1~C`EDNS&m@U|@^hDMvrTiz5HV?aWKpY6^c$<@do8x$? z{`;2n-5|WDR??-v33O(ZLkvnEN89mcGAv zu^G(5)U?1|Eg$E`CUHDjo1dq=`hF$jXYO`mPIe;itFnh1WKF!WD4rQ7g-g$rkof|? z0#f}>MSj(~l$2Y^Qe&{{5T(682g)fi0M629t(XZ8{!_BN|XbhN;Ym+u2ZKVtV9bv_A~LP%sl6P z^Ge`afOpXjpc}w7N8e{}0ON|G@2@`xuLpVn?!El|zq>Qf{LbZf(MEtrIF1{A zFUIvz-)VVw<~MBf;7P*nlr4@v(p* zOf8?(G)cz8y#Kg)f9d_;u$A(CT3M#yKbBAT`$lwzCvw1J@M5lu*Jn~R5Xu^N@0bh zYg^O5xVMZi>gs-O23>C-jw|yXM}pp|xF#2;w%)!7HY3N2@5Z^iRkMSmvNF0#*VPZ6A}y7YAlm=of&54_5~83 z5n@P;F_9055EDgX0>&2*2=GTtOfZ^=CPqj!Ax2I8Q4AukHFM^1OTEcr?OC&DpL6zk z?Xu}f%{4U3SLCk}+#TArw@9rFJn7PC6PfSoln!MNwc8bC@;pVkf!~P=2+HHiDezgq zc5`((%PxpIFE329P7M3P@(kPZ>U38dQf*5ev5T(iWnCdGeyh|z5Rjs<9kzWNFa?+j zOarE;Favgk*|6FCTnThZnGY`ACpY|N+ z&x2n9jy`d47j@c`puY}20&J9VXfw`n@I~PFPwHNzKW*w)!2bY~Gw)8LPJ2G|N+f?7 zut~q&!b=uU=gRcPPo2Oi3yRMy=fU3r1J@d>sne!D1}?*5J@3EvF?HJ1E5R9H z+m2uFr%rnw^bT+jQ1#Rzn>uaw#{s_p?A}uS6Ls3`&wlXtz&Ag4jZ&x0agBk?uqh56 z4dc*eoO19YpmFc4)AXm!{(xtIy?{l4j4OP-k?A2pr7EDnGmYJy-uC>EckbTp9VhsVqYb7 z+8nO~J^*y@|Lh&=v^np`z~_Lria-CLPMdKqfG-12uTf7@r_DTH1y6{?(mehsu1z~A|0 zuwQ6X?*wbWTc@@jqd#rN9|rFO`WrR{`-nE@nM6UzCGS4u^;-^lsq*>?Fm=&geqI5|3jwV zy1uLE2)9*WHc~NN3|_Nxrck}S=7_K(aeNm`GUXg32^U)Y9_=?LPt8&L>HP5SOZ%@$ zp4Lp{-!jg>CGl^W$e(vII3Wcb;<+Gkt7IwXu-URFHucSF%QLq}cn^2|j1 z9*Hw-9p_h&jL-=yBq!89!xV|1oHs+x+ntEP+Mym`O*0u_eX$Z)0&wkM+hHGYPldG! z>xEkZ=4~0U0$@%!PX5Y(NdT_tlKP12q6%Q`vJR*OYJmoTH4N*iIe-dqo#PnBc*6Q; zIXDC03c;RHl=}eIO01<=&(r|(0oGJYfjWTo7V9Y65tiz>qEEQO$_fusl8>xiC}x*E;>JG*hNq6_iU@wuM<EN7-hm&Re`LyV~KFnj*|3&ds8A^SL=H{bf|HHPtO*hlann-^l9| zMbkGNb0ld@^L%V`Zy-^k>5N{?TiO<6Mb2w{z^2bvU7oLob@SAw+kZ&cZ)(UfF|p-K z(wPs|MU?pXd$V+$bjoT@5^o@SAMO{&Hb>Hd;y6X=XIQ$C)qLA6&2n%*O|(YUg6$%y zaU7Yb^m46EXR2W98n$ZUpSqBA<<9hgEgKs_4mkFAqVZ^0&sw}wz}MZ+ixIFAmsvvj%+)>aIb&#pkK9%QX|nk>l=@<4)H#yf0%v qEc{IJl!@z(aQg*i6YtTq|ElC^)j0ox;kww0@%5H?X63kKzW)OPC^M@7 diff --git a/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml b/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml index 4fe2746..6211353 100644 --- a/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml +++ b/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml @@ -36,6 +36,9 @@ erase drawing erase drawing + + + ["<Primary>z"] undo From b3a1a771608fe1ecafbaccf344d7c8939901d44b Mon Sep 17 00:00:00 2001 From: abakkk Date: Mon, 31 Aug 2020 09:43:00 +0200 Subject: [PATCH 02/35] 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. --- area.js | 189 ++++++----- data/default.css | 151 --------- data/icons/palette-symbolic.svg | 32 ++ extension.js | 54 +-- locale/draw-on-your-screen.pot | 104 +++++- menu.js | 67 +++- prefs.js | 317 ++++++++++++++++-- schemas/gschemas.compiled | Bin 4888 -> 6985 bytes ...extensions.draw-on-your-screen.gschema.xml | 89 ++++- stylesheet.css | 4 - 10 files changed, 665 insertions(+), 342 deletions(-) delete mode 100644 data/default.css create mode 100644 data/icons/palette-symbolic.svg diff --git a/area.js b/area.js index f2d9c34..f7b5e4c 100644 --- a/area.js +++ b/area.js @@ -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 = ``; if (SVG_DEBUG_EXTENDS) content = ``; - let backgroundColorString = this.hasBackground ? this.activeBackgroundColor.to_string() : 'transparent'; + let backgroundColorString = this.hasBackground ? this.areaBackgroundColor.to_string() : 'transparent'; if (backgroundColorString != 'transparent') { content += `\n `; } diff --git a/data/default.css b/data/default.css deleted file mode 100644 index 4a03e08..0000000 --- a/data/default.css +++ /dev/null @@ -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); -} -*/ diff --git a/data/icons/palette-symbolic.svg b/data/icons/palette-symbolic.svg new file mode 100644 index 0000000..8a4174b --- /dev/null +++ b/data/icons/palette-symbolic.svg @@ -0,0 +1,32 @@ + + + + +Created by potrace 1.15, written by Peter Selinger 2001-2017 +https://svgsilh.com/image/2026954.html +https://creativecommons.org/publicdomain/zero/1.0/ + + + + + diff --git a/extension.js b/extension.js index 632cb8e..d12d1bd 100644 --- a/extension.js +++ b/extension.js @@ -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; diff --git a/locale/draw-on-your-screen.pot b/locale/draw-on-your-screen.pot index 15ef699..833681d 100644 --- a/locale/draw-on-your-screen.pot +++ b/locale/draw-on-your-screen.pot @@ -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 "" -"Default drawing style attributes (color palette, font, line, dash) are defined in an editable css file.\n" -"See “%s”." -msgstr "" - msgid "" "When you save elements made with eraser in a SVG file, " "they are colored with background color, transparent if it is disabled.\n" diff --git a/menu.js b/menu.js index 911f082..666279a 100644 --- a/menu.js +++ b/menu.js @@ -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); diff --git a/prefs.js b/prefs.js index 3706a50..cbf1d1e 100644 --- a/prefs.js +++ b/prefs.js @@ -20,16 +20,21 @@ * along with this program. If not, see . */ +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: "" + _("Palettes") + "" })); + 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: "" + _("Area") + "" })); + 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: "" + _("Tools") + "" })); + 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: _("Default drawing style attributes (color palette, font, line, dash) are defined in an editable css file.\n" + - "See “%s”.").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: `${params.desc}`, 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', diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled index 269a8e8bceeb2992fc975c8a1ebb5c936be614e0..67d7ed9556ee17ceed1f9bbda498276858967db1 100644 GIT binary patch literal 6985 zcmbVR3yc-j86FUHivo*)0#dr-ig)$S?w$L-gvTPQ3n;K=qi(GgXYZZ8ci6cz*O|Hd zz(;9At;CvI+C-X4#M)SFYb5azYpr6NG^QyHjV5AD8cf<0UyV&0A3;mMZ|2NnFKZKe z$;bcCfBy5I|NQ6mpR@fpskW|~t|Wd-Kp*t^#4I730Xh>n2bgtYSB~G*>6SK0M?gP= zVD@53I*s3-sU%%5y$*T;cxm2yw@{ya9{NjQ^w4Zc`o#;s{yXJ!&zGbPkPm=%E|4V4 zu69>VtFCoBHO(-(wFy@<9o;gW?uxCB%a$omT1{Ja%C@GNY)eX@s`sNkf-VsB|2%;< z&^dsoyX=k6*&q5nPa2cj@zDwV?1j(Cdi;fu7xA$c2>M2zed`6S0P}aPRwyD*{Rz;! zfqy*H{VmGL&xQO!(4PWN9)0Uc%E>Q;{CUvNfOhjPR`vJ`Aa8^7bAcmw-*Y}=N`5xv zOF*v!W{e#lq&|7-4}ms;;e_V-L!SQJ2l@aYz4Y6UsZYKQ^8KJ3C)cW04NYcTb+ZZu z{MKwR+;wXPn+?rgS3z_Vs?(*L6}_ywmMvFwM;$h_3N;hMUHJb?0OQJ7Gxiu->0E%# z^2fNtmZLiuM>pOU>T9;@{EzmvuzgpvP1TT{nq|A?rt9>a?iP+;!#2#-V_Cyo0XPSxF19Kvrb*rKp(wYHVudDXtx~T!Z*bAtLI45&O zb4FdOfkx53ki*#7_AeYm$9F$muV=TOyfqfgg~U8zD^B8TjAKr4%sCIZw&nt?*Z;<2 z=W@<*t#i&D2GyYS!P0;Im~!&-A)f%<0|aY~Jl7cMGr;4Ij$cK6@?5L0f*u7r4{c0Q zPQD%T6QC!7AB|jjm~!&e{{(avCg@x5efKYvljoXT0@?|T|H*oma`N=22)Y(1och7H zDJQ=e@*&U)V83(y2Fl4VfP4aUHxR5<@?5L;f&LD-_>*lbs84M(k8ke@)s#(=+ zEYFQK)pl*I>1a})YLDKeTc|DFT+>}m>bKQN>1snQk4kNG7p>^Zu3mplTmQE0Td(QZ zw7I{-(5p4970Ip+CzMa&YA`59)0Ysxp3FeAPB@K-QD>HqAmFB$3cdQTvLkhGovI+DN!AL zOK0I~R)nLJh3TY{LV0^fs(1SiYxnosBS%fku48XtXc^f|n$Gy9&}uq`ex?IYXj)N{ zSrG(AL_zF=mebiJI+n=`N8v=CaTK+c9KFaV^TK*M&8ESkt?CRD16N1lZbT|V}V$%+xm6m?)&FY^-)aIbUv9X!I7e{gz2T^8Gs;mXjox* z!j_8Ydgvuepb!Ka?t5b+re_I0qfm^ml0)ZNoD-&Cg?2m#Z{2z4y$f!Z=FE6{#@A+^ zo_X*b?DYu;=Vw>d)+@51o0>eXSAr7;i(fjiUP@HDct$c$3C_+7z;iF<8H(-8J6A!x zy_NfIWKM0m7E7pu^TWBLsoI(hsIsH)(pbPvCeiGws7?(9So^XyGQtA>x_jAvyv$Fj z{8C9;)LI@k=(XoHG>o03YFkaSB9|@0vi-W3r8WLT+fJp#2InPnB#t}B zm$BfvIUi^TkOm_^^sxvOskL-5z}$Qp@MYjDKt~HM!*_sA@R!H13VZ_S0fz%@djJoOu(4+7T; zIeE$tf*t|-g`7O)$3Q;>HVHX-$~h<7!19lm+mw^%z2Z3NJHXCVe~xnUUQPu% zACoe_{^zSHC(m4^12hMG=g}*VQ%=5v{($PhvRhVKl#}QDnE>4j^e*`5pOllQ{r#X% z0I$0DKTSD##^(s=o4{*t?VCwC`DKuQ0@{9&B;9z&`>QA?&zvm*+6!dgU-&5HXV-Z{UYc9@ZlljH09(O&)Y!{0YPp_p1I{=(2s!T+8dvu zK6&=5Z7Jp>aLLj~Jp1HnzXMbO+BdhIqCR={YZK^KfqkdnewK3bj6)4{H*nj_uNah* z_tr1y6F~b3`#+SE=RNia=uzO-g8TyIpejhMy*s-2+@?4LHL5~8nmB;5$PW~du zPlA35EJ>~1NI7}Nq5Tp`x)d1N|J-AglczsL(9M7|uDj)$Jfa)1d!34|@Nz5)z4J#F zSvqWl_rL1~cJ%3EdPR#wj)B8iTDa1$uNhj|l^d2ZS;c+Osi_T~+hP65pdDY&Ye$Kd z!@d$}E7H8BakHL!I&Kg8=}134oqnc8KNIO^TJ&v=d4}v-mVrv~dK1(5ot^4;HnN*- zvFrJri`#?Wxkx`ZoqoPWKOgDmr_(RA=ocdWLZDyK@X%D}(?yiO$#u*2a;td#HG?&M z#9aqB2b;sLt(INv1)Lz_Ss<2lpjy&7Il#_Eks zW49D5huu&QDDE3)qh`&L6UWfQMBUU6h+K&@&!Zfsz|vpb$v z!`4P{jW)}g6X}($dR@ga8tZgJH8n$4k@!}u@~AwfJNmG0=q`sM>|af^FQx&LRfZ@m zubvs7vf7BsN8|p(voYOj`dy@%NYCp>pEYh`%cPHIP7oQD@e=2cXxP4pb$b_9{at=p$}{Ta>b%ok1t6W1 zu!ZA{oyL0evz=Mv`E91qF+*==B2l|K1bNyrUr+j^ocUZX;f#q`DlJ+T=%W8TYpXeXE*LA-oV@PMZ`@D_gNeAmMH zjwd`#M(W_os3Vr8)CV4qdgsNL4s!|bv&{M7jYEFg8!~A?Au7F l@DhqYZA1YG>)Cp5wPscOdpxgGuE*6BKZ9V%liF^ zw?C)87Y%koe;hpgQ_EVu*0Rpw*SrP~tvfAp3!wabChw`D$OHx9x*0JY3NMh#3o<$1 znX;8 zFM&P_eg$~-!%ttOPJ0dXli+1Y{-qP&H&ds5DfAZbRlr!M=%G%VdN;TaST(av>$Is4 zgIRMGUltv|GPr%G z8xC$CDVKyln6s|1I-OvHapvGiFHd)?)~!jqWlBz1&`&L^3xnLH2f0fRa#u3QU3CVz z%d!IDJAtrGC+YYC)n^*g3x)4Ft{oJVA7;y8&~<@xDRX`ZbS%A`%sQd+Q&rS;G`Vm> z=0q?NsuJD~^+jz08DP?eQMy(A!X|dzWEg0(sUfC`9)>Lb320t|OYuL# zWw5dQtjmEb3|hf$K)b>iytRpr!k!TiGvduB8(ASHR*i_Z)TF&CqATXMo)%4sFI+9zfd zI&J1N3YNg>@R8T4)299)_-SBt_RSZl(`KAG@G0Qv@#_?I+RSGj{5PQO?y63k`Xaai zi{{8fbI;J9b}RG_@GZbEw%RAC(_RaG6fA+tsgWU z-U03bo_c5h9Cg~va~S+f;K03KT~D1h>oyI399Z?uee0;x<~SY${}K4}XCpJzX>=*%sQpbbvg@v3z+z>x1I56Gyi$;S>RUVPh0N;VBTv2;fic% zXO*k`UbKtP(>wMZ>`nglT1~C`EDNS&m@U|@^hDMvrTiz5HV?aWKpY6^c$<@do8x$? z{`;2n-5|WDR??-v33O(ZLkvnEN89mcGAv zu^G(5)U?1|Eg$E`CUHDjo1dq=`hF$jXYO`mPIe;itFnh1WKF!WD4rQ7g-g$rkof|? z0#f}>MSj(~l$2Y^Qe&{{5T(682g)fi0M629t(XZ8{!_BN|XbhN;Ym+u2ZKVtV9bv_A~LP%sl6P z^Ge`afOpXjpc}w7N8e{}0ON|G@2@`xuLpVn?!El|zq>Qf{LbZf(MEtrIF1{A zFUIvz-)VVw<~MBf;7P*nlr4@v(p* zOf8?(G)cz8y#Kg)f9d_;u$A(CT3M#yKbBAT`$lwzCvw1J@M5lu*Jn~R5Xu^N@0bh zYg^O5xVMZi>gs-O23>C-jw|yXM}pp|xF#2;w%)!7HY3N2@5Z^iRkMSmvNF0#*VPZ6A}y7Yerase drawing + @@ -229,7 +230,7 @@ switch font family switch font family - + ["<Primary><Shift>f"] switch font family (reverse) switch font family (reverse) @@ -244,6 +245,16 @@ switch font style switch font style + + ["<Primary>KP_Divide","<Primary>slash"] + switch color palette + switch color palette + + + ["<Primary><Shift>KP_Divide","<Primary><Shift>slash"] + switch color palette (reverse) + switch color palette (reverse) + ["<Primary><Shift>a"] switch text alignment @@ -254,11 +265,6 @@ switch image file switch image file - - ["<Primary>o"] - open user stylesheet to edit style - open user stylesheet to edit style - ["<Primary><Shift>s"] Save drawing as a svg file @@ -290,4 +296,75 @@ toggle help + + + "#2e2e2e" + Drawing area background color + The color of the drawing area background + + + true + Automatic dash array + Compute the lengths from the line width + + + 5 + Dash array on + The dash length in pixels + + + 15 + Dash array off + The gap between the dashes in pixels + + + 0 + Dash offset + The dash offset in pixels + + + "Gray" + Grid overlay color + The color of the lines + + + true + Automatic grid overlay line + Compute the lengths from the screen size + + + 10 + Grid overlay line spacing + The gap between lines in pixels + + + 0.5 + Grid overlay line width + The line width in pixels + + + + [ + ("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)"]) + ] + + Color palettes + The palettes of drawing colors + + + true + Automatic square area size + Compute the size of the square area from the screen size + + + 512 + Square area size + The size of the square area in pixels + + diff --git a/stylesheet.css b/stylesheet.css index 8da1267..66e12a6 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -1,7 +1,3 @@ -@import "./data/default.css"; - -/* The following styles don't affect the drawing */ - /* square area */ .draw-on-your-screen-square-area { From ecab1e2bed96f2cabf7d24e6c6c67784dfd1253e Mon Sep 17 00:00:00 2001 From: abakkk Date: Mon, 31 Aug 2020 10:04:43 +0200 Subject: [PATCH 03/35] 'open-previous/next-drawing' shortcuts Reuse `Ctrl + O` keybinding that have been freed by the previous commit (remove 'open-user-stylesheet') --- schemas/gschemas.compiled | Bin 6985 -> 6985 bytes ...extensions.draw-on-your-screen.gschema.xml | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled index 67d7ed9556ee17ceed1f9bbda498276858967db1..33fc25c62bfbdc43377393021af8b34bf7878148 100644 GIT binary patch delta 99 zcmX?UcG7Hv1s^Y`CSave drawing as a json file - ["<Primary>Page_Down"] + ["<Primary><Shift>o"] Open previous json file Open previous json file - ["<Primary>Page_Up"] + ["<Primary>o"] Open next json file Open next json file From a1286649211aa9026ff6072b7938d18e2ab21159 Mon Sep 17 00:00:00 2001 From: abakkk Date: Mon, 31 Aug 2020 11:05:33 +0200 Subject: [PATCH 04/35] minor, add 'exported' directive for linters --- area.js | 4 ++-- elements.js | 9 +++++---- extension.js | 5 +++-- files.js | 1 + helper.js | 1 + menu.js | 11 +++++++---- prefs.js | 5 +++-- 7 files changed, 22 insertions(+), 14 deletions(-) diff --git a/area.js b/area.js index f7b5e4c..ff12849 100644 --- a/area.js +++ b/area.js @@ -1,4 +1,5 @@ /* jslint esversion: 6 */ +/* exported Tools, ToolNames, FontGenericFamilies, DrawingArea */ /* * Copyright 2019 Abakkk @@ -47,8 +48,7 @@ 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; +const { Shapes, ShapeNames, Transformations, LineCapNames, LineJoinNames, FillRuleNames, FontWeightNames, FontStyleNames } = Elements; const Manipulations = { MOVE: 100, RESIZE: 101, MIRROR: 102 }; const ManipulationNames = { 100: "Move", 101: "Resize", 102: "Mirror" }; var Tools = Object.assign({}, Shapes, Manipulations); diff --git a/elements.js b/elements.js index c2214c7..e2b1acf 100644 --- a/elements.js +++ b/elements.js @@ -1,5 +1,3 @@ -/* jslint esversion: 6 */ - /* * Copyright 2019 Abakkk * @@ -20,6 +18,9 @@ * along with this program. If not, see . */ +/* jslint esversion: 6 */ +/* exported Shapes, ShapeNames, Transformations, LineCapNames, LineJoinNames, FillRuleNames, FontWeightNames, FontStyleNames, getPangoFontFamilies, DrawingElement */ + const Cairo = imports.cairo; const Clutter = imports.gi.Clutter; const Lang = imports.lang; @@ -43,8 +44,8 @@ var FillRuleNames = { 0: 'Nonzero', 1: 'Evenodd' }; var FontWeightNames = Object.assign(reverseEnumeration(Pango.Weight), { 200: "Ultra-light", 350: "Semi-light", 600: "Semi-bold", 800: "Ultra-bold" }); delete FontWeightNames[Pango.Weight.ULTRAHEAVY]; var FontStyleNames = reverseEnumeration(Pango.Style); -var FontStretchNames = reverseEnumeration(Pango.Stretch); -var FontVariantNames = reverseEnumeration(Pango.Variant); +const FontStretchNames = reverseEnumeration(Pango.Stretch); +const FontVariantNames = reverseEnumeration(Pango.Variant); var getPangoFontFamilies = function() { return PangoCairo.font_map_get_default().list_families().map(fontFamily => fontFamily.get_name()).sort((a,b) => a.localeCompare(b)); diff --git a/extension.js b/extension.js index d12d1bd..5f8607a 100644 --- a/extension.js +++ b/extension.js @@ -1,4 +1,5 @@ /* jslint esversion: 6 */ +/* exported manager, init, enable, disable, setCursor */ /* * Copyright 2019 Abakkk @@ -45,7 +46,7 @@ const HIDE_TIMEOUT_LONG = 2500; // ms, default is 1500 ms const DRAWING_ACTION_MODE = Math.pow(2,14); const WRITING_ACTION_MODE = Math.pow(2,15); // use 'login-dialog-message-warning' class in order to get GS theme warning color (default: #f57900) -var WARNING_COLOR_STYLE_CLASS_NAME = 'login-dialog-message-warning'; +const WARNING_COLOR_STYLE_CLASS_NAME = 'login-dialog-message-warning'; var manager; @@ -70,7 +71,7 @@ function disable() { // AreaManager assigns one DrawingArea per monitor (updateAreas()), // distributes keybinding callbacks to the active area // and handles stylesheet and monitor changes. -var AreaManager = new Lang.Class({ +const AreaManager = new Lang.Class({ Name: 'DrawOnYourScreenAreaManager', _init: function() { diff --git a/files.js b/files.js index 0001cc4..8315c20 100644 --- a/files.js +++ b/files.js @@ -1,4 +1,5 @@ /* jslint esversion: 6 */ +/* exported Image, getImages, getJsons, getDateString */ /* * Copyright 2019 Abakkk diff --git a/helper.js b/helper.js index d6704e9..7ed108d 100644 --- a/helper.js +++ b/helper.js @@ -1,4 +1,5 @@ /* jslint esversion: 6 */ +/* exported DrawingHelper */ /* * Copyright 2019 Abakkk diff --git a/menu.js b/menu.js index 666279a..b70ce5c 100644 --- a/menu.js +++ b/menu.js @@ -1,4 +1,5 @@ /* jslint esversion: 6 */ +/* exported DrawingMenu */ /* * Copyright 2019 Abakkk @@ -59,6 +60,8 @@ const FULL_LINE_ICON_PATH = ICON_DIR.get_child('full-line-symbolic.svg').get_pat // 150 labels with font-family style take ~15Mo const FONT_FAMILY_STYLE = true; +// use 'login-dialog-message-warning' class in order to get GS theme warning color (default: #f57900) +const WARNING_COLOR_STYLE_CLASS_NAME = 'login-dialog-message-warning'; const getActor = function(object) { return GS_VERSION < '3.33.0' ? object.actor : object; @@ -308,18 +311,18 @@ var DrawingMenu = new Lang.Class({ target[targetProperty] = Math.max(Math.round(value * 50), 0); label.set_text(target[targetProperty] + " px"); if (target[targetProperty] === 0) - label.add_style_class_name(Extension.WARNING_COLOR_STYLE_CLASS_NAME); + label.add_style_class_name(WARNING_COLOR_STYLE_CLASS_NAME); else - label.remove_style_class_name(Extension.WARNING_COLOR_STYLE_CLASS_NAME); + label.remove_style_class_name(WARNING_COLOR_STYLE_CLASS_NAME); }); } else { slider.connect('notify::value', () => { target[targetProperty] = Math.max(Math.round(slider.value * 50), 0); label.set_text(target[targetProperty] + " px"); if (target[targetProperty] === 0) - label.add_style_class_name(Extension.WARNING_COLOR_STYLE_CLASS_NAME); + label.add_style_class_name(WARNING_COLOR_STYLE_CLASS_NAME); else - label.remove_style_class_name(Extension.WARNING_COLOR_STYLE_CLASS_NAME); + label.remove_style_class_name(WARNING_COLOR_STYLE_CLASS_NAME); }); } diff --git a/prefs.js b/prefs.js index cbf1d1e..a92bb01 100644 --- a/prefs.js +++ b/prefs.js @@ -1,4 +1,5 @@ /* jslint esversion: 6 */ +/* exported GLOBAL_KEYBINDINGS, INTERNAL_KEYBINDINGS, OTHER_SHORTCUTS, init, buildPrefsWidget */ /* * Copyright 2019 Abakkk @@ -100,10 +101,10 @@ var INTERNAL_KEYBINDINGS = { if (GS_VERSION < "3.36") delete INTERNAL_KEYBINDINGS['open-preferences']; -function getKeyLabel(accel) { +const getKeyLabel = function(accel) { let [keyval, mods] = Gtk.accelerator_parse(accel); return Gtk.accelerator_get_label(keyval, mods); -} +}; var OTHER_SHORTCUTS = [ { desc: "Draw", get shortcut() { return _("Left click"); } }, From 1d95fac3bfc398f264640c6c430c5eae68c28984 Mon Sep 17 00:00:00 2001 From: abakkk Date: Mon, 31 Aug 2020 11:13:49 +0200 Subject: [PATCH 05/35] add warning log on activation for unsupported GNOME Shell versions As the extension may work in further GNOME Shell versions without targeted developpement, just add a small warning log without blocking anything. --- extension.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/extension.js b/extension.js index 5f8607a..9ce4894 100644 --- a/extension.js +++ b/extension.js @@ -55,6 +55,9 @@ function init() { } function enable() { + if (ExtensionUtils.isOutOfDate(Me)) + log(`${Me.metadata.uuid}: GNOME Shell ${Number.parseFloat(GS_VERSION)} is not supported.`); + Me.settings = Convenience.getSettings(); Me.internalShortcutSettings = Convenience.getSettings(Me.metadata['settings-schema'] + '.internal-shortcuts'); Me.drawingSettings = Convenience.getSettings(Me.metadata['settings-schema'] + '.drawing'); From 89067a8dd932e58671ff36df6a41b3942cde42a6 Mon Sep 17 00:00:00 2001 From: abakkk Date: Mon, 31 Aug 2020 13:05:41 +0200 Subject: [PATCH 06/35] use an Extension class --- area.js | 3 +-- extension.js | 61 ++++++++++++++++++++++++++++------------------------ menu.js | 7 +++--- 3 files changed, 37 insertions(+), 34 deletions(-) diff --git a/area.js b/area.js index ff12849..5bbeb5c 100644 --- a/area.js +++ b/area.js @@ -37,7 +37,6 @@ const Main = imports.ui.main; const Screenshot = imports.ui.screenshot; const Me = ExtensionUtils.getCurrentExtension(); -const Extension = Me.imports.extension; const Elements = Me.imports.elements; const Files = Me.imports.files; const Menu = Me.imports.menu; @@ -759,7 +758,7 @@ var DrawingArea = new Lang.Class({ setPointerCursor: function(pointerCursorName) { if (!this.currentPointerCursorName || this.currentPointerCursorName != pointerCursorName) { this.currentPointerCursorName = pointerCursorName; - Extension.setCursor(pointerCursorName); + Me.stateObj.areaManager.setCursor(pointerCursorName); } }, diff --git a/extension.js b/extension.js index 9ce4894..2f2e52b 100644 --- a/extension.js +++ b/extension.js @@ -1,5 +1,5 @@ /* jslint esversion: 6 */ -/* exported manager, init, enable, disable, setCursor */ +/* exported init */ /* * Copyright 2019 Abakkk @@ -48,28 +48,34 @@ const WRITING_ACTION_MODE = Math.pow(2,15); // use 'login-dialog-message-warning' class in order to get GS theme warning color (default: #f57900) const WARNING_COLOR_STYLE_CLASS_NAME = 'login-dialog-message-warning'; -var manager; - function init() { - Convenience.initTranslations(); + return new Extension(); } -function enable() { - if (ExtensionUtils.isOutOfDate(Me)) - log(`${Me.metadata.uuid}: GNOME Shell ${Number.parseFloat(GS_VERSION)} is not supported.`); +const Extension = new Lang.Class({ + Name: 'DrawOnYourScreenExtension', - 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(); -} + _init: function() { + Convenience.initTranslations(); + }, -function disable() { - manager.disable(); - manager = null; - delete Me.settings; - delete Me.internalShortcutSettings; -} + enable() { + if (ExtensionUtils.isOutOfDate(Me)) + log(`${Me.metadata.uuid}: GNOME Shell ${Number.parseFloat(GS_VERSION)} is not supported.`); + + Me.settings = Convenience.getSettings(); + Me.internalShortcutSettings = Convenience.getSettings(Me.metadata['settings-schema'] + '.internal-shortcuts'); + Me.drawingSettings = Convenience.getSettings(Me.metadata['settings-schema'] + '.drawing'); + this.areaManager = new AreaManager(); + }, + + disable() { + this.areaManager.disable(); + delete this.areaManager; + delete Me.settings; + delete Me.internalShortcutSettings; + } +}); // AreaManager assigns one DrawingArea per monitor (updateAreas()), // distributes keybinding callbacks to the active area @@ -337,7 +343,7 @@ const AreaManager = new Lang.Class({ Main.popModal(this.activeArea); if (source && source == global.display) this.showOsd(null, 'touchpad-disabled-symbolic', _("Keyboard and pointer released"), null, null, false); - setCursor('DEFAULT'); + this.setCursor('DEFAULT'); this.activeArea.reactive = false; this.removeInternalKeybindings(); } else { @@ -474,6 +480,14 @@ const AreaManager = new Lang.Class({ OsdWindow.HIDE_TIMEOUT = hideTimeoutSave; }, + setCursor: function(cursorName) { + // check display or screen (API changes) + if (global.display.set_cursor) + global.display.set_cursor(Meta.Cursor[cursorName]); + else if (global.screen && global.screen.set_cursor) + global.screen.set_cursor(Meta.Cursor[cursorName]); + }, + removeAreas: function() { for (let i = 0; i < this.areas.length; i++) { let area = this.areas[i]; @@ -564,12 +578,3 @@ const DrawingIndicator = new Lang.Class({ } }); -function setCursor(cursorName) { - // check display or screen (API changes) - if (global.display.set_cursor) - global.display.set_cursor(Meta.Cursor[cursorName]); - else if (global.screen && global.screen.set_cursor) - global.screen.set_cursor(Meta.Cursor[cursorName]); -} - - diff --git a/menu.js b/menu.js index b70ce5c..0fe7b6f 100644 --- a/menu.js +++ b/menu.js @@ -39,7 +39,6 @@ const ExtensionUtils = imports.misc.extensionUtils; const Me = ExtensionUtils.getCurrentExtension(); const Area = Me.imports.area; const Elements = Me.imports.elements; -const Extension = Me.imports.extension; const Files = Me.imports.files; const _ = imports.gettext.domain(Me.metadata['gettext-domain']).gettext; @@ -210,8 +209,8 @@ var DrawingMenu = new Lang.Class({ imageSection.itemActivated = () => {}; this.imageSection = imageSection; - let manager = Extension.manager; - this._addSimpleSwitchItem(this.menu, _("Hide panel and dock"), manager.hiddenList ? true : false, manager.togglePanelAndDockOpacity.bind(manager)); + let areaManager = Me.stateObj.areaManager; + this._addSimpleSwitchItem(this.menu, _("Hide panel and dock"), areaManager.hiddenList ? true : false, areaManager.togglePanelAndDockOpacity.bind(areaManager)); this._addSimpleSwitchItem(this.menu, _("Add a drawing background"), this.area.hasBackground, this.area.toggleBackground.bind(this.area)); this._addSimpleSwitchItem(this.menu, _("Add a grid overlay"), this.area.hasGrid, this.area.toggleGrid.bind(this.area)); this._addSimpleSwitchItem(this.menu, _("Square drawing area"), this.area.isSquareArea, this.area.toggleSquareArea.bind(this.area)); @@ -222,7 +221,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(_("Open preferences"), manager.openPreferences.bind(manager), 'document-page-setup-symbolic'); + this.menu.addAction(_("Open preferences"), areaManager.openPreferences.bind(areaManager), 'document-page-setup-symbolic'); this.menu.addAction(_("Show help"), () => { this.close(); this.area.toggleHelp(); }, 'preferences-desktop-keyboard-shortcuts-symbolic'); this._updateActionSensitivity(); From 6a8afcc20ae6333c14747dccea5c048e35be334f Mon Sep 17 00:00:00 2001 From: abakkk Date: Mon, 31 Aug 2020 14:03:24 +0200 Subject: [PATCH 07/35] use timestamps instead of Math.random in elementGrabber --- area.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/area.js b/area.js index 5bbeb5c..06198bd 100644 --- a/area.js +++ b/area.js @@ -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 ELEMENT_GRABBER_TIME = 80; // ms, default is about 16 ms const GRID_TILES_HORIZONTAL_NUMBER = 30; const { Shapes, ShapeNames, Transformations, LineCapNames, LineJoinNames, FillRuleNames, FontWeightNames, FontStyleNames } = Elements; @@ -434,8 +435,9 @@ var DrawingArea = new Lang.Class({ } // Reduce computing without notable effect. - if (Math.random() <= 0.75) + if (event.get_time() - (this.elementGrabberTimestamp || 0) < ELEMENT_GRABBER_TIME) return; + this.elementGrabberTimestamp = event.get_time(); let coords = event.get_coords(); let [s, x, y] = this.transform_stage_point(coords[0], coords[1]); From c1689cac756cab9e11db35a50f1889d4eced8040 Mon Sep 17 00:00:00 2001 From: abakkk Date: Tue, 1 Sep 2020 13:43:30 +0200 Subject: [PATCH 08/35] rework prefs, settings, locales Although there is a lot of changes, nothing is important. --- area.js | 2 +- extension.js | 4 +- helper.js | 80 ++- locale/draw-on-your-screen.pot | 73 ++- menu.js | 26 +- prefs.js | 375 +++++++------- schemas/gschemas.compiled | Bin 6985 -> 6977 bytes ...extensions.draw-on-your-screen.gschema.xml | 472 ++++++++---------- 8 files changed, 501 insertions(+), 531 deletions(-) diff --git a/area.js b/area.js index 06198bd..d58c65f 100644 --- a/area.js +++ b/area.js @@ -223,7 +223,7 @@ var DrawingArea = new Lang.Class({ this.squareAreaSize = Math.max(64, Me.drawingSettings.get_uint('square-area-size')); } - this.areaBackgroundColor = getClutterColorFromString(Me.drawingSettings.get_string('area-background-color'), 'BLACK'); + this.areaBackgroundColor = getClutterColorFromString(Me.drawingSettings.get_string('background-color'), 'BLACK'); this.gridColor = getClutterColorFromString(Me.drawingSettings.get_string('grid-color'), 'GRAY'); if (Me.drawingSettings.get_boolean('grid-line-auto')) { diff --git a/extension.js b/extension.js index 2f2e52b..64499ff 100644 --- a/extension.js +++ b/extension.js @@ -101,7 +101,7 @@ const AreaManager = new Lang.Class({ Shell.ActionMode.ALL, this.toggleModal.bind(this)); - Main.wm.addKeybinding('erase-drawing', + Main.wm.addKeybinding('erase-drawings', Me.settings, Meta.KeyBindingFlags.NONE, Shell.ActionMode.ALL, @@ -524,7 +524,7 @@ const AreaManager = new Lang.Class({ this.toggleDrawing(); Main.wm.removeKeybinding('toggle-drawing'); Main.wm.removeKeybinding('toggle-modal'); - Main.wm.removeKeybinding('erase-drawing'); + Main.wm.removeKeybinding('erase-drawings'); this.removeAreas(); if (this.indicator) this.indicator.disable(); diff --git a/helper.js b/helper.js index 7ed108d..176ddfe 100644 --- a/helper.js +++ b/helper.js @@ -38,12 +38,7 @@ const GS_VERSION = Config.PACKAGE_VERSION; const HELPER_ANIMATION_TIME = 0.25; const MEDIA_KEYS_SCHEMA = 'org.gnome.settings-daemon.plugins.media-keys'; -const MEDIA_KEYS_KEYS = { - 'screenshot': "Screenshot", - 'screenshot-clip': "Screenshot to clipboard", - 'area-screenshot': "Area screenshot", - 'area-screenshot-clip': "Area screenshot to clipboard" -}; +const MEDIA_KEYS_KEYS = ['screenshot', 'screenshot-clip', 'area-screenshot', 'area-screenshot-clip']; // DrawingHelper provides the "help osd" (Ctrl + F1) // It uses the same texts as in prefs @@ -92,55 +87,58 @@ var DrawingHelper = new Lang.Class({ this.add_actor(this.vbox); this.vbox.add_child(new St.Label({ text: _("Global") })); - for (let settingKey in Prefs.GLOBAL_KEYBINDINGS) { - let hbox = new St.BoxLayout({ vertical: false }); - if (settingKey.indexOf('-separator-') != -1) { - this.vbox.add_child(hbox); - continue; - } + for (let settingKey of Prefs.GLOBAL_KEYBINDINGS) { if (!Me.settings.get_strv(settingKey)[0]) continue; - let [keyval, mods] = Gtk.accelerator_parse(Me.settings.get_strv(settingKey)[0]); - hbox.add_child(new St.Label({ text: _(Prefs.GLOBAL_KEYBINDINGS[settingKey]) })); - hbox.add_child(new St.Label({ text: Gtk.accelerator_get_label(keyval, mods), x_expand: true })); - this.vbox.add_child(hbox); - } - - this.vbox.add_child(new St.Label({ text: _("Internal") })); - - for (let i = 0; i < Prefs.OTHER_SHORTCUTS.length; i++) { - if (Prefs.OTHER_SHORTCUTS[i].desc.indexOf('-separator-') != -1) { - this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-helper-separator' })); - continue; - } + let hbox = new St.BoxLayout({ vertical: false }); - hbox.add_child(new St.Label({ text: _(Prefs.OTHER_SHORTCUTS[i].desc) })); - hbox.add_child(new St.Label({ text: Prefs.OTHER_SHORTCUTS[i].shortcut, x_expand: true })); - hbox.get_children()[0].get_clutter_text().set_use_markup(true); + let [keyval, mods] = Gtk.accelerator_parse(Me.settings.get_strv(settingKey)[0]); + hbox.add_child(new St.Label({ text: Me.settings.settings_schema.get_key(settingKey).get_summary() })); + hbox.add_child(new St.Label({ text: Gtk.accelerator_get_label(keyval, mods), x_expand: true })); this.vbox.add_child(hbox); } this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-helper-separator' })); + this.vbox.add_child(new St.Label({ text: _("Internal") })); - for (let settingKey in Prefs.INTERNAL_KEYBINDINGS) { - if (settingKey.indexOf('-separator-') != -1) { + Prefs.OTHER_SHORTCUTS.forEach((object, index) => { + if (index) this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-helper-separator' })); - continue; + + for (let key in object) { + let hbox = new St.BoxLayout({ vertical: false }); + hbox.add_child(new St.Label({ text: _(key) })); + hbox.add_child(new St.Label({ text: object[key], x_expand: true })); + hbox.get_children()[0].get_clutter_text().set_use_markup(true); + this.vbox.add_child(hbox); } - let hbox = new St.BoxLayout({ vertical: false }); - if (!Me.internalShortcutSettings.get_strv(settingKey)[0]) - continue; - let [keyval, mods] = Gtk.accelerator_parse(Me.internalShortcutSettings.get_strv(settingKey)[0]); - hbox.add_child(new St.Label({ text: _(Prefs.INTERNAL_KEYBINDINGS[settingKey]) })); - hbox.add_child(new St.Label({ text: Gtk.accelerator_get_label(keyval, mods), x_expand: true })); - this.vbox.add_child(hbox); - } + }); + + this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-helper-separator' })); + + Prefs.INTERNAL_KEYBINDINGS.forEach((object, index) => { + if (index) + this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-helper-separator' })); + + for (let settingKey of object) { + if (!Me.internalShortcutSettings.get_strv(settingKey)[0]) + continue; + + let hbox = new St.BoxLayout({ vertical: false }); + let [keyval, mods] = Gtk.accelerator_parse(Me.internalShortcutSettings.get_strv(settingKey)[0]); + hbox.add_child(new St.Label({ text: Me.internalShortcutSettings.settings_schema.get_key(settingKey).get_summary() })); + hbox.add_child(new St.Label({ text: Gtk.accelerator_get_label(keyval, mods), x_expand: true })); + this.vbox.add_child(hbox); + } + }); let mediaKeysSettings; try { mediaKeysSettings = Convenience.getSettings(MEDIA_KEYS_SCHEMA); } catch(e) { return; } + + this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-helper-separator' })); this.vbox.add_child(new St.Label({ text: _("System") })); - for (let settingKey in MEDIA_KEYS_KEYS) { + for (let settingKey of MEDIA_KEYS_KEYS) { if (!mediaKeysSettings.settings_schema.has_key(settingKey)) continue; let shortcut = GS_VERSION < '3.33.0' ? mediaKeysSettings.get_string(settingKey) : mediaKeysSettings.get_strv(settingKey)[0]; @@ -148,7 +146,7 @@ var DrawingHelper = new Lang.Class({ continue; let [keyval, mods] = Gtk.accelerator_parse(shortcut); let hbox = new St.BoxLayout({ vertical: false }); - hbox.add_child(new St.Label({ text: _(MEDIA_KEYS_KEYS[settingKey]) })); + hbox.add_child(new St.Label({ text: mediaKeysSettings.settings_schema.get_key(settingKey).get_summary() })); hbox.add_child(new St.Label({ text: Gtk.accelerator_get_label(keyval, mods), x_expand: true })); this.vbox.add_child(hbox); } diff --git a/locale/draw-on-your-screen.pot b/locale/draw-on-your-screen.pot index 833681d..e279645 100644 --- a/locale/draw-on-your-screen.pot +++ b/locale/draw-on-your-screen.pot @@ -53,6 +53,9 @@ msgstr "" msgid "Palettes" msgstr "" +msgid "Color palettes" +msgstr "" + msgid "The palettes of drawing colors" msgstr "" @@ -80,6 +83,9 @@ msgstr "" msgid "Square area size" msgstr "" +msgid "Automatic square area size" +msgstr "" + msgid "Compute the size of the square area from the screen size" msgstr "" @@ -95,12 +101,21 @@ msgstr "" msgid "Grid overlay line" msgstr "" +msgid "Automatic grid overlay line" +msgstr "" + msgid "Compute the lengths from the screen size" msgstr "" +msgid "Grid overlay line spacing" +msgstr "" + msgid "The line width in pixels" msgstr "" +msgid "Grid overlay line width" +msgstr "" + msgid "The gap between lines in pixels" msgstr "" @@ -116,12 +131,21 @@ msgstr "" msgid "Dash array" msgstr "" +msgid "Automatic dash array" +msgstr "" + msgid "Compute the lengths from the line width" msgstr "" +msgid "Dash array on" +msgstr "" + msgid "The dash length in pixels" msgstr "" +msgid "Dash array off" +msgstr "" + msgid "The gap between the dashes in pixels" msgstr "" @@ -233,7 +257,7 @@ msgstr "" msgid "Internal" msgstr "" -msgid "(in drawing mode)" +msgid "In drawing mode" msgstr "" msgid "Undo last brushstroke" @@ -248,34 +272,61 @@ msgstr "" msgid "Smooth last brushstroke" msgstr "" -msgid "Select line" +msgid "Select color 1" msgstr "" -msgid "Select ellipse" +msgid "Select color 2" msgstr "" -msgid "Select rectangle" +msgid "Select color 3" msgstr "" -msgid "Select polygon" +msgid "Select color 4" msgstr "" -msgid "Select polyline" +msgid "Select color 5" msgstr "" -msgid "Select image" +msgid "Select color 6" msgstr "" -msgid "Select text" +msgid "Select color 7" msgstr "" -msgid "Select move" +msgid "Select color 8" msgstr "" -msgid "Select resize" +msgid "Select color 9" msgstr "" -msgid "Select mirror" +msgid "Select ellipse tool" +msgstr "" + +msgid "Select image tool" +msgstr "" + +msgid "Select line tool" +msgstr "" + +msgid "Select mirror tool" +msgstr "" + +msgid "Select move tool" +msgstr "" + +msgid "Select polygon tool" +msgstr "" + +msgid "Select polyline tool" +msgstr "" + +msgid "Select rectangle tool" +msgstr "" + +msgid "Select resize tool" +msgstr "" + +msgid "Select text tool" msgstr "" msgid "Toggle fill/outline" diff --git a/menu.js b/menu.js index 0fe7b6f..ba3f660 100644 --- a/menu.js +++ b/menu.js @@ -66,6 +66,10 @@ const getActor = function(object) { return GS_VERSION < '3.33.0' ? object.actor : object; }; +const getSummary = function(settingKey) { + return Me.internalShortcutSettings.settings_schema.get_key(settingKey).get_summary(); +}; + var DrawingMenu = new Lang.Class({ Name: 'DrawOnYourScreenDrawingMenu', @@ -159,7 +163,7 @@ var DrawingMenu = new Lang.Class({ this.menu.removeAll(); this.actionButtons = []; - let groupItem = new PopupMenu.PopupBaseMenuItem({ reactive: false, can_focus: false, style_class: "draw-on-your-screen-menu-group-item" }); + let groupItem = new PopupMenu.PopupBaseMenuItem({ reactive: false, can_focus: false, style_class: 'draw-on-your-screen-menu-group-item' }); getActor(groupItem).add_child(this._createActionButton(_("Undo"), this.area.undo.bind(this.area), 'edit-undo-symbolic')); getActor(groupItem).add_child(this._createActionButton(_("Redo"), this.area.redo.bind(this.area), 'edit-redo-symbolic')); getActor(groupItem).add_child(this._createActionButton(_("Erase"), this.area.deleteLastElement.bind(this.area), 'edit-clear-all-symbolic')); @@ -210,19 +214,19 @@ var DrawingMenu = new Lang.Class({ this.imageSection = imageSection; let areaManager = Me.stateObj.areaManager; - this._addSimpleSwitchItem(this.menu, _("Hide panel and dock"), areaManager.hiddenList ? true : false, areaManager.togglePanelAndDockOpacity.bind(areaManager)); - this._addSimpleSwitchItem(this.menu, _("Add a drawing background"), this.area.hasBackground, this.area.toggleBackground.bind(this.area)); - this._addSimpleSwitchItem(this.menu, _("Add a grid overlay"), this.area.hasGrid, this.area.toggleGrid.bind(this.area)); - this._addSimpleSwitchItem(this.menu, _("Square drawing area"), this.area.isSquareArea, this.area.toggleSquareArea.bind(this.area)); + this._addSimpleSwitchItem(this.menu, getSummary('toggle-panel-and-dock-visibility'), !!areaManager.hiddenList, areaManager.togglePanelAndDockOpacity.bind(areaManager)); + this._addSimpleSwitchItem(this.menu, getSummary('toggle-background'), this.area.hasBackground, this.area.toggleBackground.bind(this.area)); + this._addSimpleSwitchItem(this.menu, getSummary('toggle-grid'), this.area.hasGrid, this.area.toggleGrid.bind(this.area)); + this._addSimpleSwitchItem(this.menu, getSummary('toggle-square-area'), this.area.isSquareArea, this.area.toggleSquareArea.bind(this.area)); this._addSeparator(this.menu); this._addDrawingNameItem(this.menu); this._addOpenDrawingSubMenuItem(this.menu); this._addSaveDrawingSubMenuItem(this.menu); - this.menu.addAction(_("Save drawing as a SVG file"), this.area.saveAsSvg.bind(this.area), 'image-x-generic-symbolic'); - this.menu.addAction(_("Open preferences"), areaManager.openPreferences.bind(areaManager), 'document-page-setup-symbolic'); - this.menu.addAction(_("Show help"), () => { this.close(); this.area.toggleHelp(); }, 'preferences-desktop-keyboard-shortcuts-symbolic'); + this.menu.addAction(getSummary('save-as-svg'), this.area.saveAsSvg.bind(this.area), 'image-x-generic-symbolic'); + this.menu.addAction(getSummary('open-preferences'), areaManager.openPreferences.bind(areaManager), 'document-page-setup-symbolic'); + this.menu.addAction(getSummary('toggle-help'), () => { this.close(); this.area.toggleHelp(); }, 'preferences-desktop-keyboard-shortcuts-symbolic'); this._updateActionSensitivity(); this._updateSectionVisibility(); @@ -308,7 +312,7 @@ var DrawingMenu = new Lang.Class({ if (GS_VERSION < '3.33.0') { slider.connect('value-changed', (slider, value, property) => { target[targetProperty] = Math.max(Math.round(value * 50), 0); - label.set_text(target[targetProperty] + " px"); + label.set_text(_("%d px").format(target[targetProperty])); if (target[targetProperty] === 0) label.add_style_class_name(WARNING_COLOR_STYLE_CLASS_NAME); else @@ -317,7 +321,7 @@ var DrawingMenu = new Lang.Class({ } else { slider.connect('notify::value', () => { target[targetProperty] = Math.max(Math.round(slider.value * 50), 0); - label.set_text(target[targetProperty] + " px"); + label.set_text(_("%d px").format(target[targetProperty])); if (target[targetProperty] === 0) label.add_style_class_name(WARNING_COLOR_STYLE_CLASS_NAME); else @@ -539,7 +543,7 @@ var DrawingMenu = new Lang.Class({ }, _addSaveDrawingSubMenuItem: function(menu) { - let item = new PopupMenu.PopupSubMenuMenuItem(_("Save drawing"), true); + let item = new PopupMenu.PopupSubMenuMenuItem(getSummary('save-as-json'), true); this.saveDrawingSubMenuItem = item; this._updateSaveDrawingSubMenuItemSensitivity(); this.saveDrawingSubMenu = item.menu; diff --git a/prefs.js b/prefs.js index a92bb01..7e192cb 100644 --- a/prefs.js +++ b/prefs.js @@ -21,6 +21,7 @@ * along with this program. If not, see . */ +const Atk = imports.gi.Atk; const Gdk = imports.gi.Gdk; const GLib = imports.gi.GLib; const GObject = imports.gi.GObject; @@ -40,91 +41,48 @@ const _GTK = imports.gettext.domain('gtk30').gettext; const GS_VERSION = Config.PACKAGE_VERSION; const MARGIN = 10; +const ROWBOX_MARGIN_PARAMS = { margin_top: MARGIN / 2, margin_bottom: MARGIN / 2, margin_left: MARGIN, margin_right: MARGIN }; -var GLOBAL_KEYBINDINGS = { - 'toggle-drawing': "Enter/leave drawing mode", - 'toggle-modal': "Grab/ungrab keyboard and pointer", - 'erase-drawing': "Erase all drawings" -}; +var GLOBAL_KEYBINDINGS = ['toggle-drawing', 'toggle-modal', 'erase-drawings']; +var INTERNAL_KEYBINDINGS = [ + ['undo', 'undo', 'delete-last-element', 'smooth-last-element'], + ['select-none-shape', 'select-line-shape', 'select-ellipse-shape', 'select-rectangle-shape', 'select-polygon-shape', 'select-polyline-shape', + 'select-text-shape', 'select-image-shape', 'select-move-tool', 'select-resize-tool', 'select-mirror-tool'], + ['switch-fill', 'switch-fill-rule', 'switch-color-palette', 'switch-color-palette-reverse'], + ['increment-line-width', 'decrement-line-width', 'increment-line-width-more', 'decrement-line-width-more', + 'switch-linejoin', 'switch-linecap', 'switch-dash'], + ['switch-font-family', 'switch-font-family-reverse', 'switch-font-weight', 'switch-font-style', 'switch-text-alignment', 'switch-image-file'], + ['toggle-panel-and-dock-visibility', 'toggle-background', 'toggle-grid', 'toggle-square-area'], + ['open-previous-json', 'open-next-json', 'save-as-json', 'save-as-svg', 'open-preferences', 'toggle-help'] +]; -var INTERNAL_KEYBINDINGS = { - 'undo': "Undo last brushstroke", - 'redo': "Redo last brushstroke", - 'delete-last-element' : "Erase last brushstroke", - 'smooth-last-element': "Smooth last brushstroke", - '-separator-1': '', - 'select-none-shape': "Free drawing", - 'select-line-shape': "Select line", - 'select-ellipse-shape': "Select ellipse", - 'select-rectangle-shape': "Select rectangle", - 'select-polygon-shape': "Select polygon", - 'select-polyline-shape': "Select polyline", - 'select-text-shape': "Select text", - 'select-image-shape': "Select image", - 'select-move-tool': "Select move", - 'select-resize-tool': "Select resize", - 'select-mirror-tool': "Select mirror", - '-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", - 'increment-line-width-more': "Increment line width even more", - 'decrement-line-width-more': "Decrement line width even more", - 'switch-linejoin': "Change linejoin", - 'switch-linecap': "Change linecap", - 'switch-dash': "Dashed line", - '-separator-4': '', - 'switch-font-family': "Change font family", - '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", - 'switch-image-file': "Change image file", - '-separator-5': '', - 'toggle-panel-and-dock-visibility': "Hide panel and dock", - 'toggle-background': "Add a drawing background", - 'toggle-grid': "Add a grid overlay", - 'toggle-square-area': "Square drawing area", - '-separator-6': '', - 'open-previous-json': "Open previous drawing", - 'open-next-json': "Open next drawing", - 'save-as-json': "Save drawing", - 'save-as-svg': "Save drawing as a SVG file", - 'open-preferences': "Open preferences", - 'toggle-help': "Show help" -}; - -if (GS_VERSION < "3.36") - delete INTERNAL_KEYBINDINGS['open-preferences']; +if (GS_VERSION < '3.36') + delete INTERNAL_KEYBINDINGS[INTERNAL_KEYBINDINGS.length - 1]['open-preferences']; const getKeyLabel = function(accel) { let [keyval, mods] = Gtk.accelerator_parse(accel); return Gtk.accelerator_get_label(keyval, mods); }; -var OTHER_SHORTCUTS = [ - { desc: "Draw", get shortcut() { return _("Left click"); } }, - { desc: "Menu", get shortcut() { return _("Right click"); } }, - { desc: "Toggle fill/outline", get shortcut() { return _("Center click"); } }, - { desc: "Increment/decrement line width", get shortcut() { return _("Scroll"); } }, - { desc: "Select color", get shortcut() { return _("%s … %s").format(getKeyLabel('1'), getKeyLabel('9')); } }, - { desc: "Ignore pointer movement", get shortcut() { return _("%s held").format(getKeyLabel('space')); } }, - { desc: "Leave", shortcut: getKeyLabel('Escape') }, - { desc: "-separator-1", shortcut: "" }, - { desc: "Select eraser (while starting drawing)", shortcut: getKeyLabel('') }, - { desc: "Duplicate (while starting handling)", shortcut: getKeyLabel('') }, - { desc: "Rotate rectangle, polygon, polyline", shortcut: getKeyLabel('') }, - { desc: "Extend circle to ellipse", shortcut: getKeyLabel('') }, - { desc: "Curve line", shortcut: getKeyLabel('') }, - { desc: "Smooth free drawing outline", shortcut: getKeyLabel('') }, - { desc: "Rotate (while moving)", shortcut: getKeyLabel('') }, - { desc: "Stretch (while resizing)", shortcut: getKeyLabel('') }, - { desc: "Inverse (while mirroring)", shortcut: getKeyLabel('') } -]; +var OTHER_SHORTCUTS = [{ + get "Draw"() { return _("Left click"); }, + get "Menu"() { return _("Right click"); }, + get "Toggle fill/outline"() { return _("Center click"); }, + get "Increment/decrement line width"() { return _("Scroll"); }, + get "Select color"() { return _("%s … %s").format(getKeyLabel('1'), getKeyLabel('9')); }, + get "Ignore pointer movement"() { return _("%s held").format(getKeyLabel('space')); }, + "Leave": getKeyLabel('Escape'), + }, { + "Select eraser (while starting drawing)": getKeyLabel(''), + "Duplicate (while starting handling)": getKeyLabel(''), + "Rotate rectangle, polygon, polyline": getKeyLabel(''), + "Extend circle to ellipse": getKeyLabel(''), + "Curve line": getKeyLabel(''), + "Smooth free drawing outline": getKeyLabel(''), + "Rotate (while moving)": getKeyLabel(''), + "Stretch (while resizing)": getKeyLabel(''), + "Inverse (while mirroring)": getKeyLabel(''), +}]; function init() { Convenience.initTranslations(); @@ -168,7 +126,7 @@ const AboutPage = new GObject.Class({ _init: function(params) { this.parent({ hscrollbar_policy: Gtk.PolicyType.NEVER }); - let vbox= new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, margin: MARGIN*3 }); + let vbox= new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, margin: MARGIN * 3 }); this.add(vbox); let name = " " + _(Me.metadata.name) + ""; @@ -184,7 +142,7 @@ const AboutPage = new GObject.Class({ vbox.add(aboutLabel); - let creditBox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL, margin: 2*MARGIN }); + let creditBox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL, margin: 2 * MARGIN }); let leftBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL }); let rightBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL }); let leftLabel = new Gtk.Label({ wrap: true, valign: 1, halign: 2, justify: 1, use_markup: true, label: "" + _GTK("Created by") + "" }); @@ -218,42 +176,46 @@ const DrawingPage = new GObject.Class({ 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 }); + let box = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, margin: 3 * MARGIN, spacing: 3 * MARGIN }); 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: "" + _("Palettes") + "" })); + let palettesFrame = new Frame({ label: _("Palettes") }); box.add(palettesFrame); - let palettesScrolledWindow = new Gtk.ScrolledWindow({ vscrollbar_policy: Gtk.PolicyType.NEVER, margin_top: MARGIN/2, margin_bottom: MARGIN/2 }); + 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'); + this.palettesListBox.get_accessible().set_name(this.schema.get_key('palettes').get_summary()); + this.palettesListBox.get_accessible().set_description(this.schema.get_key('palettes').get_description()); 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") }); + this.addBox = new Gtk.Box(ROWBOX_MARGIN_PARAMS); let addButton = Gtk.Button.new_from_icon_name('list-add-symbolic', Gtk.IconSize.BUTTON); + addButton.set_tooltip_text(_("Add a new palette")); 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: "" + _("Area") + "" })); + let areaFrame = new Frame({ label: _("Area") }); box.add(areaFrame); - let areaListBox = new Gtk.ListBox({ selection_mode: 0, hexpand: true, margin_top: MARGIN/2, margin_bottom: MARGIN/2 }); + 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 squareAreaRow = new PrefRow({ label: this.schema.get_key('square-area-size').get_summary() }); + let squareAreaAutoButton = new Gtk.CheckButton({ label: _("Auto"), + name: this.schema.get_key('square-area-auto').get_summary(), + 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()) }); + name: this.schema.get_key('square-area-size').get_summary(), + 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); @@ -261,21 +223,26 @@ const DrawingPage = new GObject.Class({ squareAreaRow.addWidget(squareAreaSizeButton); areaListBox.add(squareAreaRow); - let backgroundColorRow = new PrefRow({ label: _("Background color") }); + let backgroundColorRow = new PrefRow({ label: this.schema.get_key('background-color').get_summary() }); 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); + name: this.schema.get_key('background-color').get_summary(), + tooltip_text: this.schema.get_key('background-color').get_description() }); + this.settings.bind('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 gridLineAutoButton = new Gtk.CheckButton({ label: _("Auto"), + name: this.schema.get_key('grid-line-auto').get_summary(), + 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()) }); + adjustment: Gtk.Adjustment.new(0, 0.1, 10, 0.1, 1, 0), + name: this.schema.get_key('grid-line-width').get_summary(), + 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()) }); + adjustment: Gtk.Adjustment.new(0, 1, 16384, 1, 10, 0), + name: this.schema.get_key('grid-line-spacing').get_summary(), + 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); @@ -286,29 +253,33 @@ const DrawingPage = new GObject.Class({ gridLineRow.addWidget(gridLineSpacingButton); areaListBox.add(gridLineRow); - let gridColorRow = new PrefRow({ label: _("Grid overlay color") }); + let gridColorRow = new PrefRow({ label: this.schema.get_key('grid-color').get_summary() }); let gridColorButton = new ColorStringButton({ use_alpha: true, show_editor: true, - tooltip_text: _(this.schema.get_key('grid-color').get_description()) }); + name: this.schema.get_key('grid-color').get_summary(), + 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: "" + _("Tools") + "" })); + let toolsFrame = new Frame({ label: _("Tools") }); box.add(toolsFrame); - let toolsListBox = new Gtk.ListBox({ selection_mode: 0, hexpand: true, margin_top: MARGIN/2, margin_bottom: MARGIN/2 }); + 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 dashArrayAutoButton = new Gtk.CheckButton({ label: _("Auto"), + name: this.schema.get_key('dash-array-auto').get_summary(), + 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()) }); + name: this.schema.get_key('dash-array-on').get_summary(), + 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()) }); + name: this.schema.get_key('dash-array-off').get_summary(), + 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); @@ -319,10 +290,11 @@ const DrawingPage = new GObject.Class({ dashArrayRow.addWidget(dashArrayOffButton); toolsListBox.add(dashArrayRow); - let dashOffsetRow = new PrefRow({ label: _("Dash offset") }); + let dashOffsetRow = new PrefRow({ label: this.schema.get_key('dash-offset').get_summary() }); 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()) }); + name: this.schema.get_key('dash-offset').get_summary(), + tooltip_text: this.schema.get_key('dash-offset').get_description() }); this.settings.bind('dash-offset', dashOffsetButton, 'value', 0); dashOffsetRow.addWidget(dashOffsetButton); toolsListBox.add(dashOffsetRow); @@ -353,7 +325,7 @@ const DrawingPage = new GObject.Class({ 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 = new Gtk.Box(ROWBOX_MARGIN_PARAMS); 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); @@ -416,108 +388,83 @@ const PrefsPage = new GObject.Class({ this.parent({ hscrollbar_policy: Gtk.PolicyType.NEVER }); let settings = Convenience.getSettings(); + let schema = settings.settings_schema; let internalShortcutSettings = Convenience.getSettings(Me.metadata['settings-schema'] + '.internal-shortcuts'); - let box = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, margin: MARGIN*3 }); + let box = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, margin: MARGIN * 3, spacing: 3 * MARGIN }); this.add(box); - let globalFrame = new Gtk.Frame({ label_yalign: 1.0 }); - globalFrame.set_label_widget(new Gtk.Label({ margin_bottom: MARGIN/2, use_markup: true, label: "" + _("Global") + "" })); + let globalFrame = new Frame({ label: _("Global") }); box.add(globalFrame); - let listBox = new Gtk.ListBox({ selection_mode: 0, hexpand: true, margin_top: MARGIN/2, margin_bottom: MARGIN/2 }); + let listBox = new Gtk.ListBox({ selection_mode: 0, hexpand: true, margin_top: MARGIN / 2, margin_bottom: MARGIN / 2 }); + listBox.get_style_context().add_class('background'); globalFrame.add(listBox); - let styleContext = listBox.get_style_context(); - styleContext.add_class('background'); - + let globalKeybindingsRow = new Gtk.ListBoxRow({ activatable: false }); let globalKeybindingsWidget = new KeybindingsWidget(GLOBAL_KEYBINDINGS, settings); - globalKeybindingsWidget.margin = MARGIN; - listBox.add(globalKeybindingsWidget); + globalKeybindingsRow.add(globalKeybindingsWidget); + listBox.add(globalKeybindingsRow); - let persistentBox = new Gtk.Box({ margin_top: MARGIN/2, margin_bottom: MARGIN/2, margin_left: MARGIN, margin_right: MARGIN }); - let persistentLabelBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL }); - let persistentLabel1 = new Gtk.Label({label: _("Persistent")}); - let persistentLabel2 = new Gtk.Label({ use_markup: true, halign: 1, wrap: true, xalign: 0, label: "" + _("Persistent drawing through session restart") + "" }); - persistentLabel1.set_halign(1); - persistentLabel2.get_style_context().add_class('dim-label'); - persistentLabelBox.pack_start(persistentLabel1, true, true, 0); - persistentLabelBox.pack_start(persistentLabel2, true, true, 0); - let persistentSwitch = new Gtk.Switch({valign: 3}); + let persistentKey = schema.get_key('persistent-drawing'); + let persistentRow = new PrefRow({ label: persistentKey.get_summary(), desc: persistentKey.get_description() }); + let persistentSwitch = new Gtk.Switch(); settings.bind('persistent-drawing', persistentSwitch, 'active', 0); - persistentBox.pack_start(persistentLabelBox, true, true, 4); - persistentBox.pack_start(persistentSwitch, false, false, 4); - listBox.add(persistentBox); + persistentRow.addWidget(persistentSwitch, true); + listBox.add(persistentRow); - let desktopBox = new Gtk.Box({ margin_top: MARGIN/2, margin_bottom: MARGIN/2, margin_left: MARGIN, margin_right: MARGIN }); - let desktopLabelBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL }); - let desktopLabel1 = new Gtk.Label({label: _("Drawing on the desktop")}); - let desktopLabel2 = new Gtk.Label({ use_markup: true, halign: 1, wrap: true, xalign: 0, label: "" + _("Draw On Your Screen becomes Draw On Your Desktop") + "" }); - desktopLabel1.set_halign(1); - desktopLabel2.get_style_context().add_class('dim-label'); - desktopLabelBox.pack_start(desktopLabel1, true, true, 0); - desktopLabelBox.pack_start(desktopLabel2, true, true, 0); - let desktopSwitch = new Gtk.Switch({valign: 3}); + let desktopKey = schema.get_key('drawing-on-desktop'); + let desktopRow = new PrefRow({ label: desktopKey.get_summary(), desc: desktopKey.get_description() }); + let desktopSwitch = new Gtk.Switch(); settings.bind('drawing-on-desktop', desktopSwitch, 'active', 0); - desktopBox.pack_start(desktopLabelBox, true, true, 4); - desktopBox.pack_start(desktopSwitch, false, false, 4); - listBox.add(desktopBox); + desktopRow.addWidget(desktopSwitch, true); + listBox.add(desktopRow); - let osdBox = new Gtk.Box({ margin_top: MARGIN/2, margin_bottom: MARGIN/2, margin_left: MARGIN, margin_right: MARGIN }); - let osdLabelBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL }); - let osdLabel1 = new Gtk.Label({label: _("Disable on-screen notifications")}); - osdLabel1.set_halign(1); - osdLabelBox.pack_start(osdLabel1, true, true, 0); - let osdSwitch = new Gtk.Switch({valign: 3}); + let osdKey = schema.get_key('osd-disabled'); + let osdRow = new PrefRow({ label: osdKey.get_summary(), desc: osdKey.get_description() }); + let osdSwitch = new Gtk.Switch(); settings.bind('osd-disabled', osdSwitch, 'active', 0); - osdBox.pack_start(osdLabelBox, true, true, 4); - osdBox.pack_start(osdSwitch, false, false, 4); - listBox.add(osdBox); + osdRow.addWidget(osdSwitch, true); + listBox.add(osdRow); - let indicatorBox = new Gtk.Box({ margin_top: MARGIN/2, margin_bottom: MARGIN/2, margin_left: MARGIN, margin_right: MARGIN }); - let indicatorLabelBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL }); - let indicatorLabel1 = new Gtk.Label({label: _("Disable panel indicator")}); - indicatorLabel1.set_halign(1); - indicatorLabelBox.pack_start(indicatorLabel1, true, true, 0); - let indicatorSwitch = new Gtk.Switch({valign: 3}); + let indicatorKey = schema.get_key('indicator-disabled'); + let indicatorRow = new PrefRow({ label: indicatorKey.get_summary(), desc: indicatorKey.get_description() }); + let indicatorSwitch = new Gtk.Switch(); settings.bind('indicator-disabled', indicatorSwitch, 'active', 0); - indicatorBox.pack_start(indicatorLabelBox, true, true, 4); - indicatorBox.pack_start(indicatorSwitch, false, false, 4); - listBox.add(indicatorBox); + indicatorRow.addWidget(indicatorSwitch, true); + listBox.add(indicatorRow); - let children = listBox.get_children(); - for (let i = 0; i < children.length; i++) { - if (children[i].activatable) - children[i].set_activatable(false); - } - - let internalFrame = new Gtk.Frame({ margin_top: 3*MARGIN, label_yalign: 1.0 }); - internalFrame.set_label_widget(new Gtk.Label({ margin_bottom: MARGIN/2, use_markup: true, label: "" + _("Internal") + " " + _("(in drawing mode)") })); + let internalFrame = new Frame({ label: _("Internal"), desc: _("In drawing mode") }); box.add(internalFrame); listBox = new Gtk.ListBox({ selection_mode: 0, hexpand: true, margin_top: MARGIN }); + listBox.get_style_context().add_class('background'); internalFrame.add(listBox); - styleContext = listBox.get_style_context(); - styleContext.add_class('background'); - - for (let i = 0; i < OTHER_SHORTCUTS.length; i++) { - if (OTHER_SHORTCUTS[i].desc.indexOf('-separator-') != -1) { - listBox.add(new Gtk.Box({ margin_top: MARGIN, margin_left: MARGIN, margin_right: MARGIN })); - continue; + OTHER_SHORTCUTS.forEach((object, index) => { + if (index) + listBox.add(new Gtk.Box(ROWBOX_MARGIN_PARAMS)); + + for (let key in object) { + let otherBox = new Gtk.Box({ margin_left: MARGIN, margin_right: MARGIN }); + let otherLabel = new Gtk.Label({ label: _(key), use_markup: true }); + otherLabel.set_halign(1); + let otherLabel2 = new Gtk.Label({ label: object[key] }); + otherBox.pack_start(otherLabel, true, true, 4); + otherBox.pack_start(otherLabel2, false, false, 4); + listBox.add(otherBox); } - let otherBox = new Gtk.Box({ margin_left: MARGIN, margin_right: MARGIN }); - let otherLabel = new Gtk.Label({ label: _(OTHER_SHORTCUTS[i].desc), use_markup: true }); - otherLabel.set_halign(1); - let otherLabel2 = new Gtk.Label({ label: OTHER_SHORTCUTS[i].shortcut }); - otherBox.pack_start(otherLabel, true, true, 4); - otherBox.pack_start(otherLabel2, false, false, 4); - listBox.add(otherBox); - } + }); - let internalKeybindingsWidget = new KeybindingsWidget(INTERNAL_KEYBINDINGS, internalShortcutSettings); - internalKeybindingsWidget.margin = MARGIN; - listBox.add(internalKeybindingsWidget); + listBox.add(new Gtk.Box(ROWBOX_MARGIN_PARAMS)); + + INTERNAL_KEYBINDINGS.forEach((array, index) => { + if (index) + listBox.add(new Gtk.Box(ROWBOX_MARGIN_PARAMS)); + + let internalKeybindingsWidget = new KeybindingsWidget(array, internalShortcutSettings); + listBox.add(internalKeybindingsWidget); + }); let noteBox = new Gtk.Box({ margin: MARGIN }); let noteLabel = new Gtk.Label({ @@ -533,10 +480,22 @@ const PrefsPage = new GObject.Class({ noteBox.pack_start(noteLabel, true, true, 4); listBox.add(noteBox); - children = listBox.get_children(); - for (let i = 0; i < children.length; i++) { - if (children[i].activatable) - children[i].set_activatable(false); + listBox.get_children().forEach(row => row.set_activatable(false)); + } +}); + +const Frame = new GObject.Class({ + Name: 'DrawOnYourScreenFrame', + GTypeName: 'DrawOnYourScreenFrame', + Extends: Gtk.Frame, + + _init: function(params) { + let labelWidget = new Gtk.Label({ margin_bottom: MARGIN / 2, use_markup: true, label: `${params.label}` }); + this.parent({ label_yalign: 1.0, label_widget: labelWidget }); + + if (params.desc) { + labelWidget.set_tooltip_text(params.desc); + this.get_accessible().set_description(params.desc); } } }); @@ -549,7 +508,7 @@ const PrefRow = new GObject.Class({ _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 }); + let hbox = new Gtk.Box(ROWBOX_MARGIN_PARAMS); this.add(hbox); let labelBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL }); @@ -558,17 +517,31 @@ const PrefRow = new GObject.Class({ 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); + this.label = new Gtk.Label({ use_markup: true, label: params.label, halign: Gtk.Align.START }); + labelBox.pack_start(this.label, true, true, 0); if (params.desc) { - let desc = new Gtk.Label({ use_markup: true, label: `${params.desc}`, halign: Gtk.Align.START, wrap: true, xalign: 0 }); - desc.get_style_context().add_class('dim-label'); - labelBox.pack_start(desc, true, true, 0); + this.desc = new Gtk.Label({ use_markup: true, label: `${params.desc}`, halign: Gtk.Align.START, wrap: true, xalign: 0 }); + this.desc.get_style_context().add_class('dim-label'); + labelBox.pack_start(this.desc, true, true, 0); this.widgetBox.set_valign(Gtk.Align.START); } }, - addWidget: function(widget) { + addWidget: function(widget, setRelationship) { this.widgetBox.add(widget); + + if (widget.name) + widget.get_accessible().set_name(widget.name); + + if (setRelationship) { + this.label.get_accessible().add_relationship(Atk.RelationType.LABEL_FOR, widget.get_accessible()); + widget.get_accessible().add_relationship(Atk.RelationType.LABELLED_BY, this.label.get_accessible()); + + if (this.desc) { + this.desc.get_accessible().add_relationship(Atk.RelationType.DESCRIPTION_FOR, widget.get_accessible()); + widget.get_accessible().add_relationship(Atk.RelationType.DESCRIBED_BY, this.desc.get_accessible()); + } + } } }); @@ -579,7 +552,7 @@ const PixelSpinButton = new GObject.Class({ // Add 'px' unit. vfunc_output: function() { - this.text = `${Math.round(this.value * 100) / 100} px`; + this.text = _("%d px").format(Math.round(this.value * 100) / 100); return true; }, @@ -631,7 +604,7 @@ const KeybindingsWidget = new GObject.Class({ Extends: Gtk.Box, _init: function(keybindings, settings) { - this.parent(); + this.parent(ROWBOX_MARGIN_PARAMS); this.set_orientation(Gtk.Orientation.VERTICAL); this._keybindings = keybindings; @@ -721,9 +694,7 @@ const KeybindingsWidget = new GObject.Class({ _refresh: function() { this._store.clear(); - for(let settings_key in this._keybindings) { - if (settings_key.indexOf('-separator-') != -1) - continue; + for(let settings_key of this._keybindings) { let [key, mods] = Gtk.accelerator_parse( this._settings.get_strv(settings_key)[0] ); @@ -738,7 +709,7 @@ const KeybindingsWidget = new GObject.Class({ ], [ settings_key, - _(this._keybindings[settings_key]), + this._settings.settings_schema.get_key(settings_key).get_summary(), mods, key ] diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled index 33fc25c62bfbdc43377393021af8b34bf7878148..85cce3ac7029a5c12ac2a8d6566f5660d0c427ac 100644 GIT binary patch delta 2233 zcmYL~4Qvx-0EWNoD2)BUy0We78Xd4;2VSV6FbuzL%2?2JHZ#+x?AG1ZLg|(3bsN8h zM5BNtgEKlKgiR9CsDzRVA;JU_A=Lzffy5aSQxX>^4ztBXOlF+#+ZDOx-TU18{oMC+ z_x0Q5SC{wgE4CI2v0gNaM!4(9VV`xT5Mt($5iNN7#+}m^-0Zr6QbfqU4?urWYpv75aXkA?) zRoU#Pk0)pHaS2q&$DopM6_u=ILU0mf3{3>!{m}i& zKR;o8@?6wUz`uk}4fZTyPUhs&@Eg$C)t~nuk7sX6P>?}52Gu0$J#0W`E($OJ=;O}C zN#N;^KqdG4t2i zui75<8;vM_yhf?+g0H2x%Qih_H+&^@qJNQl0a}sgVJW=u9Z;+L@(0Yx%=_Sj(DS|b zZ!#xy&yw()P<<{ZGta<9DfTdzlaa?o3BUu*eXy&B9g$1Xpb`EW^g^xynH>e-??Er- zax(LN_yuS~E+;cj!$+a5lgnJ}pUnR8oeP^iF2vrqlgC(KLr{qV5BwFVG1n299ks#t zK^t>9nRy>P3Ec}jZ?PXTACQLs1U2RAlUaWho<9#OdDS<%0MF0f*icZ7unsbI-DqG( zWaeJD0{zo;$-|t?&maQd4}J07VFzJ$Jj3*U;Ei}EFklBcfe)n-ND7f%*oZry>JC`zP>O~?xpTCC%cfl;hUj{M<$s^ zW*huThY)98I=-9r$um&j18;=J6QL>QWUgo{d;ofQKn=uk!xJh2{{xDxZaKpSWX=q4 zq_9C%l_#h3w_WUfRTycc@w^3@P?GAA7G0}MhX z8U0@tkogOE0e%g7V}<+`b27Ie1D}8znvP{(QZgTa4Hf0kK->9F)+ciUZum;*qf5<6 z=4AHog{w~N|LqaqP8Q%MyF|V415l`W^IGO)ewGRNHOTtZsRHKYa^xBK1my6nu4hi> zO5|6e9n{)?{v>lU2jqdThoU_}!yia3wq2LZc6&K~C|7y);5J3yu_i1E%_@71nRMD+ zzF51VD}Dp7fm^{TtAZg${bp=_33_!rQL!K){j zlRe1K!XHDf*!C{wC|*H2Hf0htXR!gKOOuHN4JJ99D@*$c0P zI)BzqGbeLE)$oPT{1NK|=Hz1JVR$p7-&|44oa~l3W&r4ho~}NbtG^rmJyi1Wt;uXa z&O<%~{|zd=bU4bKoR2&W{|EYfWC3SpGbiT6vhv+&k3<#IRE&mEmpaXCP*dk~6WQ?= zU2P6V)tD0ORGZCKG|pVt7D=GF%85I^Z1#@B3n1_XYMQG3fk3g?y8j#shJG>WqBa@Sv zAAt`*OEWo{`4IdbRF}!g%<*MQxhF2Nb64^pA6$;06a_W#b11-yR zL}o{Q@UzgZnC}YflUaWVejTdM)F-q4J-BP4$d-$Z=?XmGzHy@Bb5Dvn znJY9- z0d>Oze*A z3&{M<8-Nc&@5~Q=%bd(DNW&jNOX?5WFDaQ1aQZ|hLr2!0Sy5akw=*l&Vn3MTgCgFon?yO^Z%*m6Gr{RwvZ)o9S=47sf zt4w4H6z)57lsTCLs)jFvj84^TYE4zRFFCB;MFrXOah|U6OtIXa=d78YsdF+vx&J$Q z(TTj$psQ^Weaovc%$h&hh7whp%+XV~I`xsqlU1a(E3sg^u54Dd4kNh1&|=o@;z}z~ s?6to1xvimMXUaLrbU1w0j*=Iw?fC^(vZT&YW<4sI;V4Kw@AYT@2W$7tPyhe` diff --git a/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml b/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml index 7fca073..9b2e3c0 100644 --- a/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml +++ b/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml @@ -1,305 +1,251 @@ - + + + false - move drawing on desktop - move drawing on desktop + Drawing on the desktop + Draw On Your Screen becomes Draw On Your Desktop]]> - - false - persistent drawing - persistent drawing - - - false - disable OSD notifications - disable on-screen notifications + + ["<Alt><Super>e"] + Erase all drawings false - disable panel indicator - disable panel indicator + Disable panel indicator + + + false + Disable on-screen notifications + + + false + Persistent + Persistent drawing through session restart ["<Alt><Super>d"] - toggle drawing - enter or leave drawing mode + Enter/leave drawing mode ["<Primary><Alt><Super>d"] - toggle modeless/modal - toggle modeless/modal + Grab/ungrab keyboard and pointer + - - ["<Alt><Super>e"] - erase drawing - erase drawing - - - - - ["<Primary>z"] - undo - undo - - - ["<Primary><Shift>z"] - redo - redo - - - ["Delete"] - delete last element - delete last element - - - ["<Primary>equal"] - smooth last brushstroke - smooth last brushstroke - - - ["<Primary>b"] - toggle drawing background - toggle drawing background - - - ["<Primary>g"] - toggle grid overlay - toggle grid overlay - - - ["<Primary>h"] - hide or show panel and dock - hide or show panel and dock - - - ["<Primary>n"] - toggle square area - toggle square area - - - ["<Primary>e"] - select cercle - select a cercle - - - ["<Primary>r"] - select rectangle - select rectangle - - - ["<Primary>y"] - select polygon - select polygon - - - ["<Primary>u"] - select polyline - select polyline - - - ["<Primary>l"] - select line - select a line - - - ["<Primary>t"] - select text - select text - - - ["<Primary>i"] - select image - select image - - - ["<Primary>p"] - unselect shape (free drawing) - unselect shape (free drawing) - - - ["<Primary>m"] - select move tool - select move tool - - - ["<Primary>x"] - select resize tool - select resize tool - - - ["<Primary>c"] - select mirror tool - select mirror tool - - - KP_Add','plus']]]> - increment the line width - increment the line width - KP_Subtract','minus','minus']]]> - decrement the line width - decrement the line width - - - ["<Primary><Shift>KP_Add"] - increment the line width even more - increment the line width even more + Decrement line width ["<Primary><Shift>KP_Subtract"] - decrement the line width even more - decrement the line width even more + Decrement line width even more - - ["<Primary>j"] - switch linejoin - switch linejoin + + ["Delete"] + Erase last brushstroke - - ["<Primary>k"] - switch linecap - switch linecap + + KP_Add','plus']]]> + Increment line width - - KP_Multiply','asterisk','asterisk']]]> - switch fill rule - switch fill rule - - - ["<Primary>period"] - switch dash - switch dash - - - ["<Primary>a"] - switch fill - switch fill - - - KP_1','1']]]> - select color1 - select color1 - - - KP_2','2']]]> - select color2 - select color2 - - - KP_3','3']]]> - select color3 - select color3 - - - KP_4','4']]]> - select color4 - select color4 - - - KP_5','5']]]> - select color5 - select color5 - - - KP_6','6']]]> - select color6 - select color6 - - - KP_7','7']]]> - select color7 - select color7 - - - KP_8','8']]]> - select color8 - select color8 - - - KP_9','9']]]> - select color9 - select color9 - - - ["<Primary>f"] - switch font family - switch font family - - - ["<Primary><Shift>f"] - switch font family (reverse) - switch font family (reverse) - - - ["<Primary>w"] - switch font weight - switch font weight - - - ["<Primary><Shift>w"] - switch font style - switch font style - - - ["<Primary>KP_Divide","<Primary>slash"] - switch color palette - switch color palette - - - ["<Primary><Shift>KP_Divide","<Primary><Shift>slash"] - switch color palette (reverse) - switch color palette (reverse) - - - ["<Primary><Shift>a"] - switch text alignment - switch text alignment - - - ["<Primary><Shift>i"] - switch image file - switch image file - - - ["<Primary><Shift>s"] - Save drawing as a svg file - Save drawing as a svg file - - - ["<Primary>s"] - Save drawing as a json file - Save drawing as a json file - - - ["<Primary><Shift>o"] - Open previous json file - Open previous json file + + ["<Primary><Shift>KP_Add"] + Increment line width even more ["<Primary>o"] - Open next json file - Open next json file + Open next drawing ["<Primary>comma"] Open preferences - Open preferences + + + ["<Primary><Shift>o"] + Open previous drawing + + + ["<Primary><Shift>z"] + Redo last brushstroke + + + ["<Primary>s"] + Save drawing + + + ["<Primary><Shift>s"] + Save drawing as a SVG file + + + KP_1','1']]]> + Select color 1 + + + + KP_2','2']]]> + Select color 2 + + + KP_3','3']]]> + Select color 3 + + + KP_4','4']]]> + Select color 4 + + + KP_5','5']]]> + Select color 5 + + + KP_6','6']]]> + Select color 6 + + + KP_7','7']]]> + Select color 7 + + + KP_8','8']]]> + Select color 8 + + + KP_9','9']]]> + Select color 9 + + + ["<Primary>e"] + Select ellipse tool + + + ["<Primary>i"] + Select image tool + + + ["<Primary>l"] + Select line tool + + + ["<Primary>c"] + Select mirror tool + + + ["<Primary>m"] + Select move tool + + + ["<Primary>p"] + Free drawing + + + ["<Primary>y"] + Select polygon tool + + + ["<Primary>u"] + Select polyline tool + + + ["<Primary>r"] + Select rectangle tool + + + ["<Primary>x"] + Select resize tool + + + ["<Primary>t"] + Select text tool + + + ["<Primary>equal"] + Smooth last brushstroke + + + ["<Primary>KP_Divide","<Primary>slash"] + Change color palette + + + ["<Primary><Shift>KP_Divide","<Primary><Shift>slash"] + Change color palette (reverse) + + + ["<Primary>period"] + Dashed line + + + ["<Primary>a"] + Toggle fill/outline + + + KP_Multiply','asterisk','asterisk']]]> + Toggle fill rule + + + ["<Primary>f"] + Change font family + + + ["<Primary><Shift>f"] + Change font family (reverse) + + + ["<Primary><Shift>w"] + Change font style + + + ["<Primary>w"] + Change font weight + + + ["<Primary><Shift>i"] + Change image file + + + ["<Primary>k"] + Change linecap + + + ["<Primary>j"] + Change linejoin + + + ["<Primary><Shift>a"] + Toggle text alignment + + + ["<Primary>b"] + Add a drawing background + + + ["<Primary>g"] + Add a grid overlay ["<Primary>F1"] - toggle help - toggle help + Show help + + + ["<Primary>h"] + Hide panel and dock + + + ["<Primary>n"] + Square drawing area + + + ["<Primary>z"] + Undo last brushstroke - + "#2e2e2e" - Drawing area background color + Background color The color of the drawing area background From 2195aed3c0806157aa96612f340bbec93c34584c Mon Sep 17 00:00:00 2001 From: abakkk Date: Wed, 2 Sep 2020 16:37:58 +0200 Subject: [PATCH 09/35] move eraser/svg note Remove the note about eraser and svg export from the prefs and add it to readme "Tips and tricks". --- README.md | 6 +++++- locale/draw-on-your-screen.pot | 6 ------ prefs.js | 16 +--------------- 3 files changed, 6 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 83a00b0..7ca6ea9 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Then save your beautiful work by taking a screenshot. 6. `Super + Alt + D` to test 7. [https://framagit.org/abakkk/DrawOnYourScreen/issues](https://framagit.org/abakkk/DrawOnYourScreen/issues) to say it doesn't work -## Details +## Tips and tricks * Draw arrows: @@ -44,6 +44,10 @@ Then save your beautiful work by taking a screenshot. Add your images (jpeg, png, svg) to `~/.local/share/drawOnYourScreen/images/`. +* Eraser and SVG: + + There is no eraser in SVG so when you export elements made with the eraser to a SVG file, they are colored with the background color, transparent if it is disabled. See `“Add a drawing background”` or edit the SVG file afterwards. + * 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`). diff --git a/locale/draw-on-your-screen.pot b/locale/draw-on-your-screen.pot index e279645..a348150 100644 --- a/locale/draw-on-your-screen.pot +++ b/locale/draw-on-your-screen.pot @@ -404,12 +404,6 @@ msgstr "" msgid "Show help" msgstr "" -msgid "" -"When you save elements made with eraser in a SVG file, " -"they are colored with background color, transparent if it is disabled.\n" -"See “%s” or edit the SVG file afterwards." -msgstr "" - msgid "Screenshot" msgstr "" diff --git a/prefs.js b/prefs.js index 7e192cb..c5c1cfc 100644 --- a/prefs.js +++ b/prefs.js @@ -437,7 +437,7 @@ const PrefsPage = new GObject.Class({ let internalFrame = new Frame({ label: _("Internal"), desc: _("In drawing mode") }); box.add(internalFrame); - listBox = new Gtk.ListBox({ selection_mode: 0, hexpand: true, margin_top: MARGIN }); + listBox = new Gtk.ListBox({ selection_mode: 0, hexpand: true, margin_top: MARGIN, margin_bottom: MARGIN / 2 }); listBox.get_style_context().add_class('background'); internalFrame.add(listBox); @@ -466,20 +466,6 @@ const PrefsPage = new GObject.Class({ listBox.add(internalKeybindingsWidget); }); - let noteBox = new Gtk.Box({ margin: MARGIN }); - let noteLabel = new Gtk.Label({ - wrap: true, - xalign: 0, - use_markup: true, - label: _("When you save elements made with eraser in a SVG file, " + - "they are colored with background color, transparent if it is disabled.\n" + - "See “%s” or edit the SVG file afterwards.").format(_("Add a drawing background")) - }); - noteLabel.set_halign(1); - noteLabel.get_style_context().add_class('dim-label'); - noteBox.pack_start(noteLabel, true, true, 4); - listBox.add(noteBox); - listBox.get_children().forEach(row => row.set_activatable(false)); } }); From 5af13a1e129436643ff360e85fb9befa2cb8f023 Mon Sep 17 00:00:00 2001 From: abakkk Date: Wed, 2 Sep 2020 21:13:23 +0200 Subject: [PATCH 10/35] add reset button to prefs --- locale/draw-on-your-screen.pot | 3 +++ prefs.js | 36 +++++++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/locale/draw-on-your-screen.pot b/locale/draw-on-your-screen.pot index a348150..b05d3be 100644 --- a/locale/draw-on-your-screen.pot +++ b/locale/draw-on-your-screen.pot @@ -155,6 +155,9 @@ msgstr "" msgid "The dash offset in pixels" msgstr "" +msgid "Reset settings" +msgstr "" + msgid "Preferences" msgstr "" diff --git a/prefs.js b/prefs.js index c5c1cfc..bec7a2f 100644 --- a/prefs.js +++ b/prefs.js @@ -45,15 +45,15 @@ const ROWBOX_MARGIN_PARAMS = { margin_top: MARGIN / 2, margin_bottom: MARGIN / 2 var GLOBAL_KEYBINDINGS = ['toggle-drawing', 'toggle-modal', 'erase-drawings']; var INTERNAL_KEYBINDINGS = [ - ['undo', 'undo', 'delete-last-element', 'smooth-last-element'], + ['undo', 'redo', 'delete-last-element', 'smooth-last-element'], ['select-none-shape', 'select-line-shape', 'select-ellipse-shape', 'select-rectangle-shape', 'select-polygon-shape', 'select-polyline-shape', 'select-text-shape', 'select-image-shape', 'select-move-tool', 'select-resize-tool', 'select-mirror-tool'], ['switch-fill', 'switch-fill-rule', 'switch-color-palette', 'switch-color-palette-reverse'], - ['increment-line-width', 'decrement-line-width', 'increment-line-width-more', 'decrement-line-width-more', + ['increment-line-width', 'increment-line-width-more', 'decrement-line-width', 'decrement-line-width-more', 'switch-linejoin', 'switch-linecap', 'switch-dash'], ['switch-font-family', 'switch-font-family-reverse', 'switch-font-weight', 'switch-font-style', 'switch-text-alignment', 'switch-image-file'], ['toggle-panel-and-dock-visibility', 'toggle-background', 'toggle-grid', 'toggle-square-area'], - ['open-previous-json', 'open-next-json', 'save-as-json', 'save-as-svg', 'open-preferences', 'toggle-help'] + ['open-next-json', 'open-previous-json', 'save-as-json', 'save-as-svg', 'open-preferences', 'toggle-help'] ]; if (GS_VERSION < '3.36') @@ -194,6 +194,7 @@ const DrawingPage = new GObject.Class({ this._updatePalettes(); this.addBox = new Gtk.Box(ROWBOX_MARGIN_PARAMS); + this.addBox.margin_bottom = MARGIN; // add space for the scrollbar let addButton = Gtk.Button.new_from_icon_name('list-add-symbolic', Gtk.IconSize.BUTTON); addButton.set_tooltip_text(_("Add a new palette")); this.addBox.pack_start(addButton, true, true, 4); @@ -298,6 +299,11 @@ const DrawingPage = new GObject.Class({ this.settings.bind('dash-offset', dashOffsetButton, 'value', 0); dashOffsetRow.addWidget(dashOffsetButton); toolsListBox.add(dashOffsetRow); + + let resetButton = new Gtk.Button({ label: _("Reset settings"), halign: Gtk.Align.CENTER }); + resetButton.get_style_context().add_class('destructive-action'); + resetButton.connect('clicked', () => this.schema.list_keys().forEach(key => this.settings.reset(key))); + box.add(resetButton); }, _updatePalettes: function() { @@ -397,7 +403,7 @@ const PrefsPage = new GObject.Class({ let globalFrame = new Frame({ label: _("Global") }); box.add(globalFrame); - let listBox = new Gtk.ListBox({ selection_mode: 0, hexpand: true, margin_top: MARGIN / 2, margin_bottom: MARGIN / 2 }); + let listBox = new Gtk.ListBox({ selection_mode: 0, hexpand: true, margin_top: MARGIN, margin_bottom: MARGIN / 2 }); listBox.get_style_context().add_class('background'); globalFrame.add(listBox); @@ -437,7 +443,7 @@ const PrefsPage = new GObject.Class({ let internalFrame = new Frame({ label: _("Internal"), desc: _("In drawing mode") }); box.add(internalFrame); - listBox = new Gtk.ListBox({ selection_mode: 0, hexpand: true, margin_top: MARGIN, margin_bottom: MARGIN / 2 }); + listBox = new Gtk.ListBox({ selection_mode: 0, hexpand: true, margin_top: MARGIN, margin_bottom: MARGIN }); listBox.get_style_context().add_class('background'); internalFrame.add(listBox); @@ -467,6 +473,14 @@ const PrefsPage = new GObject.Class({ }); listBox.get_children().forEach(row => row.set_activatable(false)); + + let resetButton = new Gtk.Button({ label: _("Reset settings"), halign: Gtk.Align.CENTER }); + resetButton.get_style_context().add_class('destructive-action'); + resetButton.connect('clicked', () => { + internalShortcutSettings.settings_schema.list_keys().forEach(key => internalShortcutSettings.reset(key)); + settings.settings_schema.list_keys().forEach(key => settings.reset(key)); + }); + box.add(resetButton); } }); @@ -674,8 +688,20 @@ const KeybindingsWidget = new GObject.Class({ this.keybinding_column = keybinding_column; this.action_column = action_column; + this._settings.connect('changed', this._onSettingsChanged.bind(this)); this._refresh(); }, + + // Support the case where all the settings has been reset. + _onSettingsChanged: function() { + if (this._refreshTimeout) + GLib.source_remove(this._refreshTimeout); + + this._refreshTimeout = GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => { + this._refreshTimeout = 0; + this._refresh(); + }); + }, _refresh: function() { this._store.clear(); From f9769c11f263be83fdcbe7df39e24067ba51892e Mon Sep 17 00:00:00 2001 From: abakkk Date: Sat, 5 Sep 2020 00:03:05 +0200 Subject: [PATCH 11/35] default font and font description * Use interface font as default font * Work with a `Pango.FontDescription` instead of separate font properties. --- area.js | 52 ++++++++++++++++++++++++++++++---------------- elements.js | 60 ++++++++++++++++++++++++++++++++--------------------- 2 files changed, 70 insertions(+), 42 deletions(-) diff --git a/area.js b/area.js index d58c65f..f66705c 100644 --- a/area.js +++ b/area.js @@ -37,6 +37,7 @@ const Main = imports.ui.main; const Screenshot = imports.ui.screenshot; const Me = ExtensionUtils.getCurrentExtension(); +const Convenience = ExtensionUtils.getSettings ? ExtensionUtils : Me.imports.convenience; const Elements = Me.imports.elements; const Files = Me.imports.files; const Menu = Me.imports.menu; @@ -84,16 +85,14 @@ var DrawingArea = new Lang.Class({ 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.currentTextRightAligned = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL; + let fontName = St.Settings && St.Settings.get().font_name || Convenience.getSettings('org.gnome.desktop.interface').get_string('font-name'); + this.currentFont = Pango.FontDescription.from_string(fontName); + this.currentFont.unset_fields(Pango.FontMask.SIZE); + this.defaultFontFamily = this.currentFont.get_family(); this.currentLineWidth = 5; this.currentLineJoin = Cairo.LineJoin.ROUND; this.currentLineCap = Cairo.LineCap.ROUND; @@ -104,8 +103,6 @@ var DrawingArea = new Lang.Class({ this.textHasCursor = false; this.dashedLine = false; this.fill = false; - this.newThemeAttributes = {}; - this.oldThemeAttributes = {}; this.connect('destroy', this._onDestroy.bind(this)); this.connect('notify::reactive', this._onReactiveChanged.bind(this)); @@ -154,6 +151,30 @@ var DrawingArea = new Lang.Class({ this.colors.push(Clutter.Color.get_static(Clutter.StaticColor.WHITE)); }, + get currentFontFamily() { + return this.currentFont.get_family(); + }, + + set currentFontFamily(family) { + this.currentFont.set_family(family); + }, + + get currentFontStyle() { + return this.currentFont.get_style(); + }, + + set currentFontStyle(style) { + this.currentFont.set_style(style); + }, + + get currentFontWeight() { + return this.currentFont.get_weight(); + }, + + set currentFontWeight(weight) { + this.currentFont.set_weight(weight); + }, + get hasManipulationTool() { // No Object.values method in GS 3.24. return Object.keys(Manipulations).map(key => Manipulations[key]).indexOf(this.currentTool) != -1; @@ -573,12 +594,7 @@ var DrawingArea = new Lang.Class({ shape: this.currentTool, color: this.currentColor.to_string(), eraser: eraser, - font: { - family: this.currentFontFamily, - weight: this.currentFontWeight, - style: this.currentFontStyle, - stretch: this.currentFontStretch, - variant: this.currentFontVariant }, + font: this.currentFont.to_string(), text: _("Text"), textRightAligned: this.currentTextRightAligned, points: [] @@ -930,7 +946,7 @@ var DrawingArea = new Lang.Class({ let index = fontWeights.indexOf(this.currentFontWeight); this.currentFontWeight = index == fontWeights.length - 1 ? fontWeights[0] : fontWeights[index + 1]; if (this.currentElement && this.currentElement.font) { - this.currentElement.font.weight = this.currentFontWeight; + this.currentElement.font.set_weight(this.currentFontWeight); this._redisplay(); } this.emit('show-osd', null, `` + @@ -940,7 +956,7 @@ var DrawingArea = new Lang.Class({ switchFontStyle: function() { this.currentFontStyle = this.currentFontStyle == 2 ? 0 : this.currentFontStyle + 1; if (this.currentElement && this.currentElement.font) { - this.currentElement.font.style = this.currentFontStyle; + this.currentElement.font.set_style(this.currentFontStyle); this._redisplay(); } this.emit('show-osd', null, `` + @@ -954,7 +970,7 @@ var DrawingArea = new Lang.Class({ else this.currentFontFamily = (index == this.fontFamilies.length - 1) ? this.fontFamilies[0] : this.fontFamilies[index + 1]; if (this.currentElement && this.currentElement.font) { - this.currentElement.font.family = this.currentFontFamily; + this.currentElement.font.set_family(this.currentFontFamily); this._redisplay(); } this.emit('show-osd', null, `${_(this.currentFontFamily)}`, "", -1, false); diff --git a/elements.js b/elements.js index e2b1acf..e84fccc 100644 --- a/elements.js +++ b/elements.js @@ -44,8 +44,6 @@ var FillRuleNames = { 0: 'Nonzero', 1: 'Evenodd' }; var FontWeightNames = Object.assign(reverseEnumeration(Pango.Weight), { 200: "Ultra-light", 350: "Semi-light", 600: "Semi-bold", 800: "Ultra-bold" }); delete FontWeightNames[Pango.Weight.ULTRAHEAVY]; var FontStyleNames = reverseEnumeration(Pango.Style); -const FontStretchNames = reverseEnumeration(Pango.Stretch); -const FontVariantNames = reverseEnumeration(Pango.Variant); var getPangoFontFamilies = function() { return PangoCairo.font_map_get_default().list_families().map(fontFamily => fontFamily.get_name()).sort((a,b) => a.localeCompare(b)); @@ -85,6 +83,17 @@ const _DrawingElement = new Lang.Class({ this.font.weight = 400; if (params.font && params.font.weight === 1) this.font.weight = 700; + if (params.font && typeof params.font != 'string') { + // compatibility with v6.2- + let font = new Pango.FontDescription(); + ['family', 'weight', 'style', 'stretch', 'variant'].forEach(attribute => { + if (params.font[attribute] !== undefined) + try { + font[`set_${attribute}`](params.font[attribute]); + } catch(e) {} + }); + this.font = font.to_string(); + } if (params.transform && params.transform.center) { let angle = (params.transform.angle || 0) + (params.transform.startAngle || 0); @@ -594,7 +603,15 @@ const TextElement = new Lang.Class({ Name: 'DrawOnYourScreenTextElement', Extends: _DrawingElement, + _init: function(params) { + this.parent(params); + this.font = Pango.FontDescription.from_string(this.font); + }, + toJSON: function() { + // The font size is useless because it is always computed from the points during cairo/svg building. + this.font.unset_fields(Pango.FontMask.SIZE); + return { shape: this.shape, color: this.color, @@ -603,7 +620,7 @@ const TextElement = new Lang.Class({ text: this.text, lineIndex: this.lineIndex !== undefined ? this.lineIndex : undefined, textRightAligned: this.textRightAligned, - font: this.font, + font: this.font.to_string(), points: this.points.map((point) => [Math.round(point[0]*100)/100, Math.round(point[1]*100)/100]) }; }, @@ -630,15 +647,8 @@ const TextElement = new Lang.Class({ if (this.points.length == 2) { let layout = PangoCairo.create_layout(cr); let fontSize = this.height * Pango.SCALE; - let fontDescription = new Pango.FontDescription(); - fontDescription.set_absolute_size(fontSize); - ['family', 'weight', 'style', 'stretch', 'variant'].forEach(attribute => { - if (this.font[attribute] !== undefined) - try { - fontDescription[`set_${attribute}`](this.font[attribute]); - } catch(e) {} - }); - layout.set_font_description(fontDescription); + this.font.set_absolute_size(fontSize); + layout.set_font_description(this.font); layout.set_text(this.text, -1); this.textWidth = layout.get_pixel_size()[0]; cr.moveTo(this.x, this.y - layout.get_baseline() / Pango.SCALE); @@ -681,19 +691,21 @@ const TextElement = new Lang.Class({ attributes = `fill="${color}" ` + `stroke="transparent" ` + `stroke-opacity="0" ` + - `font-size="${height}"`; - - if (this.font.family) - attributes += ` font-family="${this.font.family}"`; - if (this.font.weight && this.font.weight != Pango.Weight.NORMAL) - attributes += ` font-weight="${this.font.weight}"`; - if (this.font.style && FontStyleNames[this.font.style]) - attributes += ` font-style="${FontStyleNames[this.font.style].toLowerCase()}"`; - if (FontStretchNames[this.font.stretch] && this.font.stretch != Pango.Stretch.NORMAL) - attributes += ` font-stretch="${FontStretchNames[this.font.stretch].toLowerCase()}"`; - if (this.font.variant && FontVariantNames[this.font.variant]) - attributes += ` font-variant="${FontVariantNames[this.font.variant].toLowerCase()}"`; + `font-size="${height}" ` + + `font-family="${this.font.get_family()}"`; + // this.font.to_string() is not valid to fill the svg 'font' shorthand property. + // Each property must be filled separately. + ['Stretch', 'Style', 'Variant'].forEach(attribute => { + let lower = attribute.toLowerCase(); + if (this.font[`get_${lower}`]() != Pango[attribute].NORMAL) { + let font = new Pango.FontDescription(); + font[`set_${lower}`](this.font[`get_${lower}`]()); + attributes += ` font-${lower}="${font.to_string()}"`; + } + }); + if (this.font.get_weight() != Pango.Weight.NORMAL) + attributes += ` font-weight="${this.font.get_weight()}"`; row += `${this.text}`; } From 2dd900bddf1aa0ca3a5562ef3b1f17bffefc07e3 Mon Sep 17 00:00:00 2001 From: abakkk Date: Mon, 7 Sep 2020 18:56:48 +0200 Subject: [PATCH 12/35] new DisplayStrings object Group the most strings to display in a new DisplayStrings object. It is used by both menu and osd notifications. --- area.js | 41 ++++++----- elements.js | 39 +++++----- files.js | 2 +- locale/draw-on-your-screen.pot | 3 - menu.js | 126 +++++++++++++++++++++++++-------- 5 files changed, 139 insertions(+), 72 deletions(-) diff --git a/area.js b/area.js index f66705c..845a1da 100644 --- a/area.js +++ b/area.js @@ -1,5 +1,5 @@ /* jslint esversion: 6 */ -/* exported Tools, ToolNames, FontGenericFamilies, DrawingArea */ +/* exported Tools, DrawingArea */ /* * Copyright 2019 Abakkk @@ -49,13 +49,12 @@ const TEXT_CURSOR_TIME = 600; // ms const ELEMENT_GRABBER_TIME = 80; // ms, default is about 16 ms const GRID_TILES_HORIZONTAL_NUMBER = 30; -const { Shapes, ShapeNames, Transformations, LineCapNames, LineJoinNames, FillRuleNames, FontWeightNames, FontStyleNames } = Elements; -const Manipulations = { MOVE: 100, RESIZE: 101, MIRROR: 102 }; -const ManipulationNames = { 100: "Move", 101: "Resize", 102: "Mirror" }; -var Tools = Object.assign({}, Shapes, Manipulations); -var ToolNames = Object.assign({}, ShapeNames, ManipulationNames); +const { Shapes, Transformations } = Elements; +const { DisplayStrings } = Menu; -var FontGenericFamilies = ['Sans-Serif', 'Serif', 'Monospace', 'Cursive', 'Fantasy']; +const FontGenericFamilies = ['Sans-Serif', 'Serif', 'Monospace', 'Cursive', 'Fantasy']; +const Manipulations = { MOVE: 100, RESIZE: 101, MIRROR: 102 }; +var Tools = Object.assign({}, Shapes, Manipulations); const getClutterColorFromString = function(string, fallback) { let [success, color] = Clutter.Color.from_string(string); @@ -115,7 +114,7 @@ var DrawingArea = new Lang.Class({ get menu() { if (!this._menu) - this._menu = new Menu.DrawingMenu(this, this.monitor); + this._menu = new Menu.DrawingMenu(this, this.monitor, Tools); return this._menu; }, @@ -898,18 +897,18 @@ var DrawingArea = new Lang.Class({ selectTool: function(tool) { this.currentTool = tool; - this.emit('show-osd', null, _(ToolNames[tool]), "", -1, false); + this.emit('show-osd', null, DisplayStrings.Tool[tool], "", -1, false); this.updatePointerCursor(); }, switchFill: function() { this.fill = !this.fill; - this.emit('show-osd', null, this.fill ? _("Fill") : _("Outline"), "", -1, false); + this.emit('show-osd', null, DisplayStrings.getFill(this.fill), "", -1, false); }, switchFillRule: function() { this.currentFillRule = this.currentFillRule == 1 ? 0 : this.currentFillRule + 1; - this.emit('show-osd', null, _(FillRuleNames[this.currentFillRule]), "", -1, false); + this.emit('show-osd', null, DisplayStrings.FillRule[this.currentFillRule], "", -1, false); }, switchColorPalette: function(reverse) { @@ -923,26 +922,26 @@ var DrawingArea = new Lang.Class({ switchDash: function() { this.dashedLine = !this.dashedLine; - this.emit('show-osd', null, this.dashedLine ? _("Dashed line") : _("Full line"), "", -1, false); + this.emit('show-osd', null, DisplayStrings.getDashedLine(this.dashedLine), "", -1, false); }, incrementLineWidth: function(increment) { this.currentLineWidth = Math.max(this.currentLineWidth + increment, 0); - this.emit('show-osd', null, _("%d px").format(this.currentLineWidth), "", 2 * this.currentLineWidth, false); + this.emit('show-osd', null, DisplayStrings.getPixels(this.currentLineWidth), "", 2 * this.currentLineWidth, false); }, switchLineJoin: function() { this.currentLineJoin = this.currentLineJoin == 2 ? 0 : this.currentLineJoin + 1; - this.emit('show-osd', null, _(LineJoinNames[this.currentLineJoin]), "", -1, false); + this.emit('show-osd', null, DisplayStrings.LineJoin[this.currentLineJoin], "", -1, false); }, switchLineCap: function() { this.currentLineCap = this.currentLineCap == 2 ? 0 : this.currentLineCap + 1; - this.emit('show-osd', null, _(LineCapNames[this.currentLineCap]), "", -1, false); + this.emit('show-osd', null, DisplayStrings.LineCap[this.currentLineCap], "", -1, false); }, switchFontWeight: function() { - let fontWeights = Object.keys(FontWeightNames).map(key => Number(key)); + let fontWeights = Object.keys(DisplayStrings.FontWeight).map(key => Number(key)); let index = fontWeights.indexOf(this.currentFontWeight); this.currentFontWeight = index == fontWeights.length - 1 ? fontWeights[0] : fontWeights[index + 1]; if (this.currentElement && this.currentElement.font) { @@ -950,7 +949,7 @@ var DrawingArea = new Lang.Class({ this._redisplay(); } this.emit('show-osd', null, `` + - `${_(FontWeightNames[this.currentFontWeight])}`, "", -1, false); + `${DisplayStrings.FontWeight[this.currentFontWeight]}`, "", -1, false); }, switchFontStyle: function() { @@ -959,8 +958,8 @@ var DrawingArea = new Lang.Class({ this.currentElement.font.set_style(this.currentFontStyle); this._redisplay(); } - this.emit('show-osd', null, `` + - `${_(FontStyleNames[this.currentFontStyle])}`, "", -1, false); + this.emit('show-osd', null, `` + + `${DisplayStrings.FontStyle[this.currentFontStyle]}`, "", -1, false); }, switchFontFamily: function(reverse) { @@ -973,7 +972,7 @@ var DrawingArea = new Lang.Class({ this.currentElement.font.set_family(this.currentFontFamily); this._redisplay(); } - this.emit('show-osd', null, `${_(this.currentFontFamily)}`, "", -1, false); + this.emit('show-osd', null, `${DisplayStrings.getFontFamily(this.currentFontFamily)}`, "", -1, false); }, switchTextAlignment: function() { @@ -982,7 +981,7 @@ var DrawingArea = new Lang.Class({ this.currentElement.textRightAligned = this.currentTextRightAligned; this._redisplay(); } - this.emit('show-osd', null, this.currentTextRightAligned ? _("Right aligned") : _("Left aligned"), "", -1, false); + this.emit('show-osd', null, DisplayStrings.getTextAlignment(this.currentTextRightAligned), "", -1, false); }, switchImageFile: function() { diff --git a/elements.js b/elements.js index e84fccc..e7b5905 100644 --- a/elements.js +++ b/elements.js @@ -19,7 +19,7 @@ */ /* jslint esversion: 6 */ -/* exported Shapes, ShapeNames, Transformations, LineCapNames, LineJoinNames, FillRuleNames, FontWeightNames, FontStyleNames, getPangoFontFamilies, DrawingElement */ +/* exported Shapes, Transformations, getPangoFontFamilies, DrawingElement */ const Cairo = imports.cairo; const Clutter = imports.gi.Clutter; @@ -27,28 +27,29 @@ const Lang = imports.lang; const Pango = imports.gi.Pango; const PangoCairo = imports.gi.PangoCairo; -const reverseEnumeration = function(obj) { - let reversed = {}; - Object.keys(obj).forEach(key => { - reversed[obj[key]] = key.slice(0,1) + key.slice(1).toLowerCase().replace('_', '-'); - }); - return reversed; -}; - var Shapes = { NONE: 0, LINE: 1, ELLIPSE: 2, RECTANGLE: 3, TEXT: 4, POLYGON: 5, POLYLINE: 6, IMAGE: 7 }; -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 LineCapNames = Object.assign(reverseEnumeration(Cairo.LineCap), { 2: 'Square' }); -var LineJoinNames = reverseEnumeration(Cairo.LineJoin); -var FillRuleNames = { 0: 'Nonzero', 1: 'Evenodd' }; -var FontWeightNames = Object.assign(reverseEnumeration(Pango.Weight), { 200: "Ultra-light", 350: "Semi-light", 600: "Semi-bold", 800: "Ultra-bold" }); -delete FontWeightNames[Pango.Weight.ULTRAHEAVY]; -var FontStyleNames = reverseEnumeration(Pango.Style); var getPangoFontFamilies = function() { return PangoCairo.font_map_get_default().list_families().map(fontFamily => fontFamily.get_name()).sort((a,b) => a.localeCompare(b)); }; +const getFillRuleSvgName = function(fillRule) { + return fillRule == Pango.FillRule.EVEN_ODD ? 'evenodd' : 'nonzero'; +}; + +const getLineCapSvgName = function(lineCap) { + return lineCap == Pango.LineCap.BUTT ? 'butt' : + lineCap == Pango.LineCap.SQUASH ? 'square' : + 'round'; +}; + +const getLineJoinSvgName = function(lineJoin) { + return lineJoin == Pango.LineJoin.MITER ? 'miter' : + lineJoin == Pango.LineJoin.BEVEL ? 'bevel' : + 'round'; +}; + const SVG_DEBUG_SUPERPOSES_CAIRO = false; const RADIAN = 180 / Math.PI; // degree const INVERSION_CIRCLE_RADIUS = 12; // px @@ -295,7 +296,7 @@ const _DrawingElement = new Lang.Class({ if (fill) { attributes = `fill="${color}"`; if (this.fillRule) - attributes += ` fill-rule="${FillRuleNames[this.fillRule].toLowerCase()}"`; + attributes += ` fill-rule="${getFillRuleSvgName(this.fillRule)}"`; } else { attributes = `fill="none"`; } @@ -304,9 +305,9 @@ const _DrawingElement = new Lang.Class({ attributes += ` stroke="${color}"` + ` stroke-width="${this.line.lineWidth}"`; if (this.line.lineCap) - attributes += ` stroke-linecap="${LineCapNames[this.line.lineCap].toLowerCase()}"`; + attributes += ` stroke-linecap="${getLineCapSvgName(this.line.lineCap)}"`; if (this.line.lineJoin && !this.isStraightLine) - attributes += ` stroke-linejoin="${LineJoinNames[this.line.lineJoin].toLowerCase()}"`; + attributes += ` stroke-linejoin="${getLineJoinSvgName(this.line.lineJoin)}"`; if (this.dash && this.dash.active && this.dash.array && this.dash.array[0] && this.dash.array[1]) attributes += ` stroke-dasharray="${this.dash.array[0]} ${this.dash.array[1]}" stroke-dashoffset="${this.dash.offset}"`; } else { diff --git a/files.js b/files.js index 8315c20..484a78c 100644 --- a/files.js +++ b/files.js @@ -1,5 +1,5 @@ /* jslint esversion: 6 */ -/* exported Image, getImages, getJsons, getDateString */ +/* exported Image, getImages, Json, getJsons, getDateString */ /* * Copyright 2019 Abakkk diff --git a/locale/draw-on-your-screen.pot b/locale/draw-on-your-screen.pot index b05d3be..3881e79 100644 --- a/locale/draw-on-your-screen.pot +++ b/locale/draw-on-your-screen.pot @@ -500,9 +500,6 @@ msgstr "" msgid "Square" msgstr "" -msgid "Dashed" -msgstr "" - # generic font-family SVG attribute msgid "Sans-Serif" msgstr "" diff --git a/menu.js b/menu.js index ba3f660..5483be8 100644 --- a/menu.js +++ b/menu.js @@ -1,5 +1,5 @@ /* jslint esversion: 6 */ -/* exported DrawingMenu */ +/* exported DisplayStrings, DrawingMenu */ /* * Copyright 2019 Abakkk @@ -37,8 +37,6 @@ const Slider = imports.ui.slider; const ExtensionUtils = imports.misc.extensionUtils; const Me = ExtensionUtils.getCurrentExtension(); -const Area = Me.imports.area; -const Elements = Me.imports.elements; const Files = Me.imports.files; const _ = imports.gettext.domain(Me.metadata['gettext-domain']).gettext; @@ -70,11 +68,81 @@ const getSummary = function(settingKey) { return Me.internalShortcutSettings.settings_schema.get_key(settingKey).get_summary(); }; +// Used by both menu and osd notifications. +var DisplayStrings = { + getDashedLine: function(dashed) { + return dashed ? _("Dashed line") : _("Full line"); + }, + + getFill: function(fill) { + return fill ? _("Fill") : _("Outline"); + }, + + get FillRule() { + if (!this._fillRules) + this._fillRules = { 0: _("Nonzero"), 1: _("Evenodd") }; + return this._fillRules; + }, + + getFontFamily: function(family) { + if (!this._fontGenericFamilies) + this._fontGenericFamilies = { 'Sans-Serif': _("Sans-Serif"), 'Serif': _("Serif"), 'Monospace': _("Monospace"), + 'Cursive': _("Cursive"), 'Fantasy': _("Fantasy") }; + return this._fontGenericFamilies[family] || family; + }, + + get FontStyle() { + if (!this._fontStyles) + this._fontStyles = { 0: _("Normal"), 1: _("Oblique"), 2: _("Italic") }; + return this._fontStyles; + }, + + FontStyleMarkup: { 0: 'normal', 1: 'oblique', 2: 'italic' }, + + get FontWeight() { + if (!this._fontWeights) + this._fontWeights = { 100: _("Thin"), 200: _("Ultra Light"), 300: _("Light"), 350: _("Semi Light"), + 380: _("Book"), 400: _("Normal"), 500: _("Medium"), 600: _("Semi Bold"), + 700: _("Bold"), 800: _("Ultra Bold"), 900: _("Heavy"), 1000:_("Ultra Heavy") }; + return this._fontWeights; + }, + + get LineCap() { + if (!this._lineCaps) + this._lineCaps = { 0: _("Butt"), 1: _("Round"), 2: _("Square") }; + return this._lineCaps; + }, + + get LineJoin() { + if (!this._lineJoins) + this._lineJoins = { 0: _("Miter"), 1: _("Round"), 2: _("Bevel") }; + return this._lineJoins; + }, + + getPixels(value) { + return _("%d px").format(value); + }, + + getTextAlignment: function(rightAligned) { + return rightAligned ? _("Right aligned") : _("Left aligned"); + }, + + get Tool() { + if (!this._tools) + this._tools = { 0: _("Free drawing"), 1: _("Line"), 2: _("Ellipse"), 3: _("Rectangle"), + 4: _("Text"), 5: _("Polygon"), 6: _("Polyline"), 7: _("Image"), + 100: _("Move"), 101: _("Resize"), 102: _("Mirror") }; + return this._tools; + } +}; + var DrawingMenu = new Lang.Class({ Name: 'DrawOnYourScreenDrawingMenu', - _init: function(area, monitor) { + _init: function(area, monitor, drawingTools) { this.area = area; + this.drawingTools = drawingTools; + let side = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL ? St.Side.RIGHT : St.Side.LEFT; this.menu = new PopupMenu.PopupMenu(Main.layoutManager.dummyCursor, 0.25, side); this.menuManager = new PopupMenu.PopupMenuManager(GS_VERSION < '3.33.0' ? { actor: this.area } : this.area); @@ -116,6 +184,8 @@ var DrawingMenu = new Lang.Class({ }, disable: function() { + delete this.area; + delete this.drawingTools; this.menuManager.removeMenu(this.menu); Main.layoutManager.uiGroup.remove_actor(this.menu.actor); this.menu.destroy(); @@ -171,21 +241,21 @@ var DrawingMenu = new Lang.Class({ this.menu.addMenuItem(groupItem); this._addSeparator(this.menu, true); - this._addSubMenuItem(this.menu, 'document-edit-symbolic', Area.ToolNames, this.area, 'currentTool', this._updateSectionVisibility.bind(this)); + this._addSubMenuItem(this.menu, 'document-edit-symbolic', DisplayStrings.Tool, 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.fillItem = this._addSwitchItem(this.menu, DisplayStrings.getFill(true), this.strokeIcon, this.fillIcon, this.area, 'fill', this._updateSectionVisibility.bind(this)); this.fillSection = new PopupMenu.PopupMenuSection(); this.fillSection.itemActivated = () => {}; - this.fillRuleItem = this._addSwitchItem(this.fillSection, _("Evenodd"), this.fillRuleNonzeroIcon, this.fillRuleEvenoddIcon, this.area, 'currentEvenodd'); + this.fillRuleItem = this._addSwitchItem(this.fillSection, DisplayStrings.FillRule[1], this.fillRuleNonzeroIcon, this.fillRuleEvenoddIcon, this.area, 'currentEvenodd'); this.menu.addMenuItem(this.fillSection); this._addSeparator(this.menu); let lineSection = new PopupMenu.PopupMenuSection(); this._addSliderItem(lineSection, this.area, 'currentLineWidth'); - this._addSubMenuItem(lineSection, this.linejoinIcon, Elements.LineJoinNames, this.area, 'currentLineJoin'); - this._addSubMenuItem(lineSection, this.linecapIcon, Elements.LineCapNames, this.area, 'currentLineCap'); - this._addSwitchItem(lineSection, _("Dashed"), this.fullLineIcon, this.dashedLineIcon, this.area, 'dashedLine'); + this._addSubMenuItem(lineSection, this.linejoinIcon, DisplayStrings.LineJoin, this.area, 'currentLineJoin'); + this._addSubMenuItem(lineSection, this.linecapIcon, DisplayStrings.LineCap, this.area, 'currentLineCap'); + this._addSwitchItem(lineSection, DisplayStrings.getDashedLine(true), this.fullLineIcon, this.dashedLineIcon, this.area, 'dashedLine'); this._addSeparator(lineSection); this.menu.addMenuItem(lineSection); lineSection.itemActivated = () => {}; @@ -193,9 +263,9 @@ var DrawingMenu = new Lang.Class({ let fontSection = new PopupMenu.PopupMenuSection(); this._addFontFamilySubMenuItem(fontSection, 'font-x-generic-symbolic'); - this._addSubMenuItem(fontSection, 'format-text-bold-symbolic', Elements.FontWeightNames, this.area, 'currentFontWeight'); - this._addSubMenuItem(fontSection, 'format-text-italic-symbolic', Elements.FontStyleNames, this.area, 'currentFontStyle'); - this._addSwitchItem(fontSection, _("Right aligned"), 'format-justify-left-symbolic', 'format-justify-right-symbolic', this.area, 'currentTextRightAligned'); + this._addSubMenuItem(fontSection, 'format-text-bold-symbolic', DisplayStrings.FontWeight, this.area, 'currentFontWeight'); + this._addSubMenuItem(fontSection, 'format-text-italic-symbolic', DisplayStrings.FontStyle, this.area, 'currentFontStyle'); + this._addSwitchItem(fontSection, DisplayStrings.getTextAlignment(true), 'format-justify-left-symbolic', 'format-justify-right-symbolic', this.area, 'currentTextRightAligned'); this._addSeparator(fontSection); this.menu.addMenuItem(fontSection); fontSection.itemActivated = () => {}; @@ -254,11 +324,11 @@ var DrawingMenu = new Lang.Class({ undoButton.reactive = this.area.elements.length > 0; redoButton.reactive = this.area.undoneElements.length > 0; eraseButton.reactive = this.area.elements.length > 0; - smoothButton.reactive = this.area.elements.length > 0 && this.area.elements[this.area.elements.length - 1].shape == Area.Tools.NONE; + smoothButton.reactive = this.area.elements.length > 0 && this.area.elements[this.area.elements.length - 1].shape == this.drawingTools.NONE; }, _updateSectionVisibility: function() { - let [isText, isImage] = [this.area.currentTool == Area.Tools.TEXT, this.area.currentTool == Area.Tools.IMAGE]; + let [isText, isImage] = [this.area.currentTool == this.drawingTools.TEXT, this.area.currentTool == this.drawingTools.IMAGE]; this.lineSection.actor.visible = !isText && !isImage; this.fontSection.actor.visible = isText; this.imageSection.actor.visible = isImage; @@ -306,13 +376,13 @@ var DrawingMenu = new Lang.Class({ _addSliderItem: function(menu, target, targetProperty) { let item = new PopupMenu.PopupBaseMenuItem({ activate: false }); - let label = new St.Label({ text: _("%d px").format(target[targetProperty]), style_class: 'draw-on-your-screen-menu-slider-label' }); + let label = new St.Label({ text: DisplayStrings.getPixels(target[targetProperty]), style_class: 'draw-on-your-screen-menu-slider-label' }); let slider = new Slider.Slider(target[targetProperty] / 50); if (GS_VERSION < '3.33.0') { slider.connect('value-changed', (slider, value, property) => { target[targetProperty] = Math.max(Math.round(value * 50), 0); - label.set_text(_("%d px").format(target[targetProperty])); + label.set_text(DisplayStrings.getPixels(target[targetProperty])); if (target[targetProperty] === 0) label.add_style_class_name(WARNING_COLOR_STYLE_CLASS_NAME); else @@ -321,7 +391,7 @@ var DrawingMenu = new Lang.Class({ } else { slider.connect('notify::value', () => { target[targetProperty] = Math.max(Math.round(slider.value * 50), 0); - label.set_text(_("%d px").format(target[targetProperty])); + label.set_text(DisplayStrings.getPixels(target[targetProperty])); if (target[targetProperty] === 0) label.add_style_class_name(WARNING_COLOR_STYLE_CLASS_NAME); else @@ -340,7 +410,7 @@ var DrawingMenu = new Lang.Class({ _addSubMenuItem: function(menu, icon, obj, target, targetProperty, callback) { if (targetProperty == 'currentImage') icon = obj[target[targetProperty]].gicon; - let item = new PopupMenu.PopupSubMenuMenuItem(_(String(obj[target[targetProperty]])), icon ? true : false); + 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)) item.icon.set_gicon(icon); else if (icon) @@ -354,15 +424,15 @@ var DrawingMenu = new Lang.Class({ for (let i in obj) { let text; if (targetProperty == 'currentFontWeight') - text = `${_(obj[i])}`; + text = `${obj[i]}`; else if (targetProperty == 'currentFontStyle') - text = `${_(obj[i])}`; + text = `${obj[i]}`; else - text = _(String(obj[i])); + text = String(obj[i]); let iCaptured = Number(i); let subItem = item.menu.addAction(text, () => { - item.label.set_text(_(String(obj[iCaptured]))); + item.label.set_text(String(obj[iCaptured])); target[targetProperty] = iCaptured; if (targetProperty == 'currentImage') item.icon.set_gicon(obj[iCaptured].gicon); @@ -374,9 +444,9 @@ var DrawingMenu = new Lang.Class({ getActor(subItem).connect('key-focus-in', updateSubMenuAdjustment); // change the display order of tools - if (obj == Area.ToolNames && i == Area.Tools.POLYGON) + if (obj == DisplayStrings.Tool && i == this.drawingTools.POLYGON) item.menu.moveMenuItem(subItem, 4); - else if (obj == Area.ToolNames && i == Area.Tools.POLYLINE) + else if (obj == DisplayStrings.Tool && i == this.drawingTools.POLYLINE) item.menu.moveMenuItem(subItem, 5); } return GLib.SOURCE_REMOVE; @@ -445,7 +515,7 @@ var DrawingMenu = new Lang.Class({ }, _addFontFamilySubMenuItem: function(menu, icon) { - let item = new PopupMenu.PopupSubMenuMenuItem(this.area.currentFontFamily, true); + let item = new PopupMenu.PopupSubMenuMenuItem(DisplayStrings.getFontFamily(this.area.currentFontFamily), true); item.icon.set_icon_name(icon); item.menu.itemActivated = () => { @@ -456,8 +526,8 @@ var DrawingMenu = new Lang.Class({ item.menu.open = (animate) => { if (!item.menu.isOpen && item.menu.isEmpty()) { this.area.fontFamilies.forEach(family => { - let subItem = item.menu.addAction(_(family), () => { - item.label.set_text(_(family)); + let subItem = item.menu.addAction(DisplayStrings.getFontFamily(family), () => { + item.label.set_text(DisplayStrings.getFontFamily(family)); this.area.currentFontFamily = family; }); if (FONT_FAMILY_STYLE) From 03b73862cc0425cde79fd85bd316b28a80f6e26a Mon Sep 17 00:00:00 2001 From: abakkk Date: Tue, 8 Sep 2020 20:11:57 +0200 Subject: [PATCH 13/35] .pot rework * .pot file can be generated automaticaly from new locale/POTFILES.in. * move shortcuts key and strings to new shortcut.js --- area.js | 7 +- extension.js | 4 +- helper.js | 43 +- locale/POTFILES.in | 8 + locale/draw-on-your-screen.pot | 824 +++++++++--------- menu.js | 44 +- prefs.js | 106 +-- ...extensions.draw-on-your-screen.gschema.xml | 145 +-- shortcuts.js | 102 +++ 9 files changed, 714 insertions(+), 569 deletions(-) create mode 100644 locale/POTFILES.in create mode 100644 shortcuts.js diff --git a/area.js b/area.js index 845a1da..1580a2d 100644 --- a/area.js +++ b/area.js @@ -42,6 +42,7 @@ const Elements = Me.imports.elements; const Files = Me.imports.files; const Menu = Me.imports.menu; const _ = imports.gettext.domain(Me.metadata['gettext-domain']).gettext; +const pgettext = imports.gettext.domain(Me.metadata['gettext-domain']).pgettext; const CAIRO_DEBUG_EXTENDS = false; const SVG_DEBUG_EXTENDS = false; @@ -392,6 +393,7 @@ var DrawingArea = new Lang.Class({ event.get_key_symbol() == Clutter.KEY_KP_Enter || event.get_key_symbol() == Clutter.KEY_Control_L) { if (this.currentElement.points.length == 2) + // Translators: %s is a key label this.emit('show-osd', null, _("Press %s to get\na fourth control point") .format(Gtk.accelerator_get_label(Clutter.KEY_Return, 0)), "", -1, true); this.currentElement.addPoint(); @@ -594,7 +596,8 @@ var DrawingArea = new Lang.Class({ color: this.currentColor.to_string(), eraser: eraser, font: this.currentFont.to_string(), - text: _("Text"), + // Translators: initial content of the text area + text: pgettext("text-area-content", "Text"), textRightAligned: this.currentTextRightAligned, points: [] }); @@ -626,6 +629,7 @@ var DrawingArea = new Lang.Class({ this.currentElement.startDrawing(startX, startY); if (this.currentTool == Shapes.POLYGON || this.currentTool == Shapes.POLYLINE) + // Translators: %s is a key label this.emit('show-osd', null, _("Press %s to mark vertices") .format(Gtk.accelerator_get_label(Clutter.KEY_Return, 0)), "", -1, true); @@ -687,6 +691,7 @@ var DrawingArea = new Lang.Class({ let [x, y] = [this.currentElement.x, this.currentElement.y]; this.currentElement.text = ''; this.currentElement.cursorPosition = 0; + // Translators: %s is a key label this.emit('show-osd', null, _("Type your text and press %s") .format(Gtk.accelerator_get_label(Clutter.KEY_Escape, 0)), "", -1, true); this._updateTextCursorTimeout(); diff --git a/extension.js b/extension.js index 64499ff..4395725 100644 --- a/extension.js +++ b/extension.js @@ -342,6 +342,7 @@ const AreaManager = new Lang.Class({ if (Main._findModal(this.activeArea) != -1) { Main.popModal(this.activeArea); if (source && source == global.display) + // Translators: "released" as the opposite of "grabbed" this.showOsd(null, 'touchpad-disabled-symbolic', _("Keyboard and pointer released"), null, null, false); this.setCursor('DEFAULT'); this.activeArea.reactive = false; @@ -388,7 +389,8 @@ const AreaManager = new Lang.Class({ this.activeArea.enterDrawingMode(); this.osdDisabled = Me.settings.get_boolean('osd-disabled'); - let label = _("Press %s for help").format(this.activeArea.helper.helpKeyLabel) + "\n\n" + _("Entering drawing mode"); + // Translators: %s is a key label + let label = "" + _("Press %s for help").format(this.activeArea.helper.helpKeyLabel) + "\n\n" + _("Entering drawing mode"); this.showOsd(null, this.enterGicon, label, null, null, true); } diff --git a/helper.js b/helper.js index 176ddfe..70d93d7 100644 --- a/helper.js +++ b/helper.js @@ -31,7 +31,7 @@ const Tweener = imports.ui.tweener; const Me = ExtensionUtils.getCurrentExtension(); const Convenience = ExtensionUtils.getSettings ? ExtensionUtils : Me.imports.convenience; -const Prefs = Me.imports.prefs; +const Shortcuts = Me.imports.shortcuts.Shortcuts; const _ = imports.gettext.domain(Me.metadata['gettext-domain']).gettext; const GS_VERSION = Config.PACKAGE_VERSION; @@ -87,49 +87,54 @@ var DrawingHelper = new Lang.Class({ this.add_actor(this.vbox); this.vbox.add_child(new St.Label({ text: _("Global") })); - for (let settingKey of Prefs.GLOBAL_KEYBINDINGS) { - if (!Me.settings.get_strv(settingKey)[0]) - continue; + Shortcuts.GLOBAL_KEYBINDINGS.forEach((settingKeys, index) => { + if (index) + this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-helper-separator' })); - let hbox = new St.BoxLayout({ vertical: false }); - let [keyval, mods] = Gtk.accelerator_parse(Me.settings.get_strv(settingKey)[0]); - hbox.add_child(new St.Label({ text: Me.settings.settings_schema.get_key(settingKey).get_summary() })); - hbox.add_child(new St.Label({ text: Gtk.accelerator_get_label(keyval, mods), x_expand: true })); - this.vbox.add_child(hbox); - } + settingKeys.forEach(settingKey => { + if (!Me.settings.get_strv(settingKey)[0]) + return; + + let hbox = new St.BoxLayout({ vertical: false }); + let [keyval, mods] = Gtk.accelerator_parse(Me.settings.get_strv(settingKey)[0]); + hbox.add_child(new St.Label({ text: Me.settings.settings_schema.get_key(settingKey).get_summary() })); + hbox.add_child(new St.Label({ text: Gtk.accelerator_get_label(keyval, mods), x_expand: true })); + this.vbox.add_child(hbox); + }); + }); this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-helper-separator' })); this.vbox.add_child(new St.Label({ text: _("Internal") })); - Prefs.OTHER_SHORTCUTS.forEach((object, index) => { + Shortcuts.OTHERS.forEach((pairs, index) => { if (index) this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-helper-separator' })); - for (let key in object) { + pairs.forEach(pair => { let hbox = new St.BoxLayout({ vertical: false }); - hbox.add_child(new St.Label({ text: _(key) })); - hbox.add_child(new St.Label({ text: object[key], x_expand: true })); + hbox.add_child(new St.Label({ text: pair[0] })); + hbox.add_child(new St.Label({ text: pair[1], x_expand: true })); hbox.get_children()[0].get_clutter_text().set_use_markup(true); this.vbox.add_child(hbox); - } + }); }); this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-helper-separator' })); - Prefs.INTERNAL_KEYBINDINGS.forEach((object, index) => { + Shortcuts.INTERNAL_KEYBINDINGS.forEach((settingKeys, index) => { if (index) this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-helper-separator' })); - for (let settingKey of object) { + settingKeys.forEach(settingKey => { if (!Me.internalShortcutSettings.get_strv(settingKey)[0]) - continue; + return; let hbox = new St.BoxLayout({ vertical: false }); let [keyval, mods] = Gtk.accelerator_parse(Me.internalShortcutSettings.get_strv(settingKey)[0]); hbox.add_child(new St.Label({ text: Me.internalShortcutSettings.settings_schema.get_key(settingKey).get_summary() })); hbox.add_child(new St.Label({ text: Gtk.accelerator_get_label(keyval, mods), x_expand: true })); this.vbox.add_child(hbox); - } + }); }); let mediaKeysSettings; diff --git a/locale/POTFILES.in b/locale/POTFILES.in new file mode 100644 index 0000000..3a9591f --- /dev/null +++ b/locale/POTFILES.in @@ -0,0 +1,8 @@ +# xgettext --from-code=UTF-8 --add-comments="Translators: " --no-location --package-name="Draw On Your Screen" --msgid-bugs-address="https://framagit.org/abakkk/DrawOnYourScreen/issues" -f locale/POTFILES.in +area.js +extension.js +helper.js +menu.js +prefs.js +shortcuts.js +schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml diff --git a/locale/draw-on-your-screen.pot b/locale/draw-on-your-screen.pot index 3881e79..588f5f6 100644 --- a/locale/draw-on-your-screen.pot +++ b/locale/draw-on-your-screen.pot @@ -8,9 +8,9 @@ # You are free to translate them or not. msgid "" msgstr "" -"Project-Id-Version: Draw On Your Screen VERSION\n" +"Project-Id-Version: Draw On Your Screen\n" "Report-Msgid-Bugs-To: https://framagit.org/abakkk/DrawOnYourScreen/issues\n" -"POT-Creation-Date: 2019-03-04 16:40+0100\n" +"POT-Creation-Date: 2020-09-09 08:40+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -19,177 +19,338 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -msgid "About" +#. Translators: %s is a key label +#, javascript-format +msgid "" +"Press %s to get\n" +"a fourth control point" msgstr "" -# You are free to translate the extension name, that is displayed in About page, or not. -msgid "Draw On You Screen" +msgid "Mark a point of symmetry" msgstr "" -msgid "Version %d" +msgid "Draw a line of symmetry" msgstr "" -msgid "Start drawing with Super+Alt+D and save your beautiful work by taking a screenshot" +#. Translators: initial content of the text area +msgctxt "text-area-content" +msgid "Text" msgstr "" -# Add your name here, for example: -# (add "\n" as separator if there is many translators) -# msgid "translator-credits" -# msgstr "Me" -# or, with mail: -# msgid "translator-credits" -# msgstr "Me" -# or, with page: -# msgid "translator-credits" -# msgstr "Me" -# else keep it empty. -# It will be displayed in about page -msgid "translator-credits" +#. Translators: %s is a key label +#, javascript-format +msgid "Press %s to mark vertices" msgstr "" -msgid "Drawing" +#. Translators: %s is a key label +#, javascript-format +msgid "Type your text and press %s" msgstr "" -msgid "Palettes" +#. Translators: "released" as the opposite of "grabbed" +msgid "Keyboard and pointer released" msgstr "" -msgid "Color palettes" +msgid "Keyboard and pointer grabbed" msgstr "" -msgid "The palettes of drawing colors" +msgid "Leaving drawing mode" +msgstr "" + +#. Translators: %s is a key label +#, javascript-format +msgid "Press %s for help" +msgstr "" + +msgid "Entering drawing mode" +msgstr "" + +msgid "Global" +msgstr "" + +msgid "Internal" +msgstr "" + +msgid "System" +msgstr "" + +msgid "Dashed line" +msgstr "" + +#. Translators: as the alternative to "Dashed line" +msgid "Full line" +msgstr "" + +msgid "Fill" +msgstr "" + +#. Translators: as the alternative to "Fill" +msgid "Outline" +msgstr "" + +#. Translators: fill-rule SVG attribute +msgid "Nonzero" +msgstr "" + +msgid "Evenodd" +msgstr "" + +#. Translators: generic font-family SVG attribute +msgctxt "font-family" +msgid "Sans-Serif" +msgstr "" + +msgctxt "font-family" +msgid "Serif" +msgstr "" + +msgctxt "font-family" +msgid "Monospace" +msgstr "" + +msgctxt "font-family" +msgid "Cursive" +msgstr "" + +msgctxt "font-family" +msgid "Fantasy" +msgstr "" + +#. Translators: font-style SVG attribute +msgctxt "font-style" +msgid "Normal" +msgstr "" + +msgctxt "font-style" +msgid "Oblique" +msgstr "" + +msgctxt "font-style" +msgid "Italic" +msgstr "" + +#. Translators: font-weight SVG attribute +msgctxt "font-weight" +msgid "Thin" +msgstr "" + +msgctxt "font-weight" +msgid "Ultra Light" +msgstr "" + +msgctxt "font-weight" +msgid "Light" +msgstr "" + +msgctxt "font-weight" +msgid "Semi Light" +msgstr "" + +msgctxt "font-weight" +msgid "Book" +msgstr "" + +msgctxt "font-weight" +msgid "Normal" +msgstr "" + +msgctxt "font-weight" +msgid "Medium" +msgstr "" + +msgctxt "font-weight" +msgid "Semi Bold" +msgstr "" + +msgctxt "font-weight" +msgid "Bold" +msgstr "" + +msgctxt "font-weight" +msgid "Ultra Bold" +msgstr "" + +msgctxt "font-weight" +msgid "Heavy" +msgstr "" + +msgctxt "font-weight" +msgid "Ultra Heavy" +msgstr "" + +#. Translators: stroke-linecap SVG attribute +msgctxt "stroke-linecap" +msgid "Butt" +msgstr "" + +msgctxt "stroke-linecap" +msgid "Round" +msgstr "" + +msgctxt "stroke-linecap" +msgid "Square" +msgstr "" + +#. Translators: stroke-linejoin SVG attribute +msgctxt "stroke-linejoin" +msgid "Miter" +msgstr "" + +msgctxt "stroke-linejoin" +msgid "Round" +msgstr "" + +msgctxt "stroke-linejoin" +msgid "Bevel" +msgstr "" + +#. Translators: value in pixel unit (e.g. "5 px") +#, javascript-format +msgid "%f px" +msgstr "" + +#. Translators: text alignment +msgid "Right aligned" +msgstr "" + +msgid "Left aligned" +msgstr "" + +msgctxt "drawing-tool" +msgid "Free drawing" +msgstr "" + +msgctxt "drawing-tool" +msgid "Line" +msgstr "" + +msgctxt "drawing-tool" +msgid "Ellipse" +msgstr "" + +msgctxt "drawing-tool" +msgid "Rectangle" +msgstr "" + +msgctxt "drawing-tool" +msgid "Text" +msgstr "" + +msgctxt "drawing-tool" +msgid "Polygon" +msgstr "" + +msgctxt "drawing-tool" +msgid "Polyline" +msgstr "" + +msgctxt "drawing-tool" +msgid "Image" +msgstr "" + +msgctxt "drawing-tool" +msgid "Move" +msgstr "" + +msgctxt "drawing-tool" +msgid "Resize" +msgstr "" + +msgctxt "drawing-tool" +msgid "Mirror" +msgstr "" + +msgid "Undo" +msgstr "" + +msgid "Redo" +msgstr "" + +msgid "Erase" +msgstr "" + +msgid "Smooth" msgstr "" msgid "Palette" msgstr "" +msgid "Color" +msgstr "" + +msgid "Open drawing" +msgstr "" + +#. Translators: "Preferences" page in preferences +msgid "Preferences" +msgstr "" + +#. Translators: "Drawing" page in preferences +msgid "Drawing" +msgstr "" + +#. Translators: "About" page in preferences +msgid "About" +msgstr "" + +#. Translators: you are free to translate the extension name, that is displayed in About page, or not +msgid "Draw On You Screen" +msgstr "" + +#. Translators: version number in "About" page +#, javascript-format +msgid "Version %d" +msgstr "" + +#. Translators: you are free to translate the extension description, that is displayed in About page, or not +msgid "" +"Start drawing with Super+Alt+D and save your beautiful work by taking a " +"screenshot" +msgstr "" + +#. Translators: add your name here or keep it empty, it will be displayed in about page, e.g. +#. msgstr "" +#. "translator1\n" +#. "translator2\n" +#. "translator3" +msgid "translator-credits" +msgstr "" + +msgid "Palettes" +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 "Automatic 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" +msgid "Auto" msgstr "" msgid "Grid overlay line" msgstr "" -msgid "Automatic grid overlay line" -msgstr "" - -msgid "Compute the lengths from the screen size" -msgstr "" - -msgid "Grid overlay line spacing" -msgstr "" - -msgid "The line width in pixels" -msgstr "" - -msgid "Grid overlay line width" -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 "Automatic dash array" -msgstr "" - -msgid "Compute the lengths from the line width" -msgstr "" - -msgid "Dash array on" -msgstr "" - -msgid "The dash length in pixels" -msgstr "" - -msgid "Dash array off" -msgstr "" - -msgid "The gap between the dashes in pixels" -msgstr "" - -msgid "Dash offset" -msgstr "" - -msgid "The dash offset in pixels" -msgstr "" - msgid "Reset settings" msgstr "" -msgid "Preferences" +msgid "Rename the palette" msgstr "" -msgid "Global" +msgid "Remove the palette" msgstr "" -msgid "Enter/leave drawing mode" +#. Translators: default name of a new palette +msgid "New palette" msgstr "" -# There is a similar text in GNOME Boxes (https://gitlab.gnome.org/GNOME/gnome-boxes/tree/master/po) -msgid "Grab/ungrab keyboard and pointer" -msgstr "" - -msgid "Erase all drawings" -msgstr "" - -msgid "Persistent" -msgstr "" - -msgid "Persistent drawing through session restart" -msgstr "" - -msgid "Drawing on the desktop" -msgstr "" - -msgid "Draw On Your Screen becomes Draw On Your Desktop" -msgstr "" - -msgid "Disable on-screen notifications" -msgstr "" - -msgid "Disable panel indicator" +msgid "In drawing mode" msgstr "" msgid "Draw" @@ -213,17 +374,19 @@ msgstr "" msgid "Scroll" msgstr "" +#. Translators: %s are key labels (Ctrl+F1 and Ctrl+F9) msgid "Select color" msgstr "" -# %s are key labels (Ctrl+F1 and Ctrl+F9) +#, javascript-format msgid "%s … %s" msgstr "" +#. Translators: %s is a key label msgid "Ignore pointer movement" msgstr "" -# %s is a key label +#, javascript-format msgid "%s held" msgstr "" @@ -257,22 +420,137 @@ msgstr "" msgid "Inverse (while mirroring)" msgstr "" -msgid "Internal" +msgid "Drawing on the desktop" msgstr "" -msgid "In drawing mode" +msgid "Draw On Your Screen becomes Draw On Your Desktop" msgstr "" -msgid "Undo last brushstroke" +msgid "Erase all drawings" msgstr "" -msgid "Redo last brushstroke" +msgid "Disable panel indicator" +msgstr "" + +msgid "Disable on-screen notifications" +msgstr "" + +msgid "Persistent" +msgstr "" + +msgid "Persistent drawing through session restart" +msgstr "" + +msgid "Enter/leave drawing mode" +msgstr "" + +#. Translators: there is a similar text in GNOME Boxes (https://gitlab.gnome.org/GNOME/gnome-boxes/tree/master/po) +msgid "Grab/ungrab keyboard and pointer" +msgstr "" + +msgid "Background color" +msgstr "" + +msgid "The color of the drawing area background" +msgstr "" + +msgid "Automatic dash array" +msgstr "" + +msgid "Compute the lengths from the line width" +msgstr "" + +msgid "Dash array on" +msgstr "" + +msgid "The dash length in pixels" +msgstr "" + +msgid "Dash array off" +msgstr "" + +msgid "The gap between the dashes in pixels" +msgstr "" + +msgid "Dash offset" +msgstr "" + +msgid "The dash offset in pixels" +msgstr "" + +msgid "Grid overlay color" +msgstr "" + +msgid "The color of the lines" +msgstr "" + +msgid "Automatic grid overlay line" +msgstr "" + +msgid "Compute the lengths from the screen size" +msgstr "" + +msgid "Grid overlay line spacing" +msgstr "" + +msgid "The gap between lines in pixels" +msgstr "" + +msgid "Grid overlay line width" +msgstr "" + +msgid "The line width in pixels" +msgstr "" + +msgid "Color palettes" +msgstr "" + +msgid "The palettes of drawing colors" +msgstr "" + +msgid "Automatic square area size" +msgstr "" + +msgid "Compute the size of the square area from the screen size" +msgstr "" + +msgid "Square area size" +msgstr "" + +msgid "The size of the square area in pixels" +msgstr "" + +msgid "Decrement line width" +msgstr "" + +msgid "Decrement line width even more" msgstr "" msgid "Erase last brushstroke" msgstr "" -msgid "Smooth last brushstroke" +msgid "Increment line width" +msgstr "" + +msgid "Increment line width even more" +msgstr "" + +msgid "Open next drawing" +msgstr "" + +msgid "Open preferences" +msgstr "" + +msgid "Open previous drawing" +msgstr "" + +msgid "Redo last brushstroke" +msgstr "" + +msgid "Save drawing" +msgstr "" + +msgid "Save drawing as a SVG file" msgstr "" msgid "Select color 1" @@ -317,6 +595,9 @@ msgstr "" msgid "Select move tool" msgstr "" +msgid "Select free drawing" +msgstr "" + msgid "Select polygon tool" msgstr "" @@ -332,10 +613,7 @@ msgstr "" msgid "Select text tool" msgstr "" -msgid "Toggle fill/outline" -msgstr "" - -msgid "Toggle fill rule" +msgid "Smooth last brushstroke" msgstr "" msgid "Change color palette" @@ -344,22 +622,10 @@ msgstr "" msgid "Change color palette (reverse)" msgstr "" -msgid "Increment line width" +msgid "Toggle fill/outline" msgstr "" -msgid "Decrement line width" -msgstr "" - -msgid "Increment line width even more" -msgstr "" - -msgid "Decrement line width even more" -msgstr "" - -msgid "Change linejoin" -msgstr "" - -msgid "Change linecap" +msgid "Toggle fill rule" msgstr "" msgid "Change font family" @@ -368,19 +634,22 @@ msgstr "" msgid "Change font family (reverse)" msgstr "" -msgid "Change font weight" -msgstr "" - msgid "Change font style" msgstr "" -msgid "Toggle text alignment" +msgid "Change font weight" msgstr "" msgid "Change image file" msgstr "" -msgid "Hide panel and dock" +msgid "Change linecap" +msgstr "" + +msgid "Change linejoin" +msgstr "" + +msgid "Toggle text alignment" msgstr "" msgid "Add a drawing background" @@ -389,251 +658,14 @@ msgstr "" msgid "Add a grid overlay" msgstr "" -msgid "Square drawing area" -msgstr "" - -msgid "Open previous drawing" -msgstr "" - -msgid "Open next drawing" -msgstr "" - -msgid "Save drawing as a SVG file" -msgstr "" - -msgid "Open preferences" -msgstr "" - msgid "Show help" msgstr "" -msgid "Screenshot" +msgid "Hide panel and dock" msgstr "" -msgid "Screenshot to clipboard" +msgid "Square drawing area" msgstr "" -msgid "Area screenshot" +msgid "Undo last brushstroke" msgstr "" - -msgid "Area screenshot to clipboard" -msgstr "" - -msgid "System" -msgstr "" - -msgid "Undo" -msgstr "" - -msgid "Redo" -msgstr "" - -msgid "Erase" -msgstr "" - -msgid "Smooth" -msgstr "" - -msgid "Free drawing" -msgstr "" - -msgid "Line" -msgstr "" - -msgid "Ellipse" -msgstr "" - -msgid "Rectangle" -msgstr "" - -msgid "Text" -msgstr "" - -msgid "Polygon" -msgstr "" - -msgid "Polyline" -msgstr "" - -msgid "Image" -msgstr "" - -msgid "Move" -msgstr "" - -msgid "Resize" -msgstr "" - -msgid "Mirror" -msgstr "" - -msgid "Color" -msgstr "" - -msgid "Fill" -msgstr "" - -# fill-rule SVG attribute -msgid "Evenodd" -msgstr "" - -msgid "%d px" -msgstr "" - -# stroke-linejoin SVG attribute -msgid "Miter" -msgstr "" - -# stroke-linejoin and stroke-linecap SVG attribute -msgid "Round" -msgstr "" - -# stroke-linejoin SVG attribute -msgid "Bevel" -msgstr "" - -# stroke-linecap SVG attribute -msgid "Butt" -msgstr "" - -# stroke-linecap SVG attribute -msgid "Square" -msgstr "" - -# generic font-family SVG attribute -msgid "Sans-Serif" -msgstr "" - -# generic font-family SVG attribute -msgid "Serif" -msgstr "" - -# generic font-family SVG attribute -msgid "Monospace" -msgstr "" - -# generic font-family SVG attribute -msgid "Cursive" -msgstr "" - -# generic font-family SVG attribute -msgid "Fantasy" -msgstr "" - -# font-weight SVG attribute -msgid "Thin" -msgstr "" - -# font-weight SVG attribute -msgid "Ultra-light" -msgstr "" - -# font-weight SVG attribute -msgid "Light" -msgstr "" - -# font-weight SVG attribute -msgid "Semi-light" -msgstr "" - -# font-weight SVG attribute -msgid "Book" -msgstr "" - -# font-weight and font-style SVG attribute -msgid "Normal" -msgstr "" - -# font-weight SVG attribute -msgid "Medium" -msgstr "" - -# font-weight SVG attribute -msgid "Semi-bold" -msgstr "" - -# font-weight SVG attribute -msgid "Bold" -msgstr "" - -# font-weight SVG attribute -msgid "Ultra-bold" -msgstr "" - -# font-weight SVG attribute -msgid "Heavy" -msgstr "" - -# font-style SVG attribute -msgid "Italic" -msgstr "" - -# font-style SVG attribute -msgid "Oblique" -msgstr "" - -msgid "Right aligned" -msgstr "" - -msgid "Open drawing" -msgstr "" - -msgid "Save drawing" -msgstr "" - -msgid "Leaving drawing mode" -msgstr "" - -# %s is a key label -msgid "Press %s for help" -msgstr "" - -msgid "Entering drawing mode" -msgstr "" - -# "released" as the opposite of "grabbed" -msgid "Keyboard and pointer released" -msgstr "" - -msgid "Keyboard and pointer grabbed" -msgstr "" - -# %s is a key label -msgid "" -"Press %s to get\n" -"a fourth control point" -msgstr "" - -msgid "Mark a point of symmetry" -msgstr "" - -msgid "Draw a line of symmetry" -msgstr "" - -# %s is a key label -msgid "" -"Press %s to mark vertices" -msgstr "" - -# %s is a key label -msgid "" -"Type your text and press %s" -msgstr "" - -# as the alternative to "Fill" -msgid "Outline" -msgstr "" - -msgid "Dashed line" -msgstr "" - -msgid "Full line" -msgstr "" - -msgid "Left aligned" -msgstr "" - -msgid "Nonzero" -msgstr "" - - diff --git a/menu.js b/menu.js index 5483be8..529667f 100644 --- a/menu.js +++ b/menu.js @@ -39,6 +39,7 @@ const ExtensionUtils = imports.misc.extensionUtils; const Me = ExtensionUtils.getCurrentExtension(); const Files = Me.imports.files; const _ = imports.gettext.domain(Me.metadata['gettext-domain']).gettext; +const pgettext = imports.gettext.domain(Me.metadata['gettext-domain']).pgettext; const GS_VERSION = Config.PACKAGE_VERSION; @@ -71,29 +72,37 @@ const getSummary = function(settingKey) { // Used by both menu and osd notifications. var DisplayStrings = { getDashedLine: function(dashed) { - return dashed ? _("Dashed line") : _("Full line"); + return dashed ? _("Dashed line") : + // Translators: as the alternative to "Dashed line" + _("Full line"); }, getFill: function(fill) { - return fill ? _("Fill") : _("Outline"); + return fill ? _("Fill") : + // Translators: as the alternative to "Fill" + _("Outline"); }, get FillRule() { if (!this._fillRules) + // Translators: fill-rule SVG attribute this._fillRules = { 0: _("Nonzero"), 1: _("Evenodd") }; return this._fillRules; }, getFontFamily: function(family) { if (!this._fontGenericFamilies) - this._fontGenericFamilies = { 'Sans-Serif': _("Sans-Serif"), 'Serif': _("Serif"), 'Monospace': _("Monospace"), - 'Cursive': _("Cursive"), 'Fantasy': _("Fantasy") }; + // Translators: generic font-family SVG attribute + this._fontGenericFamilies = { 'Sans-Serif': pgettext("font-family", "Sans-Serif"), 'Serif': pgettext("font-family", "Serif"), + 'Monospace': pgettext("font-family", "Monospace"), 'Cursive': pgettext("font-family", "Cursive"), + 'Fantasy': pgettext("font-family", "Fantasy") }; return this._fontGenericFamilies[family] || family; }, get FontStyle() { if (!this._fontStyles) - this._fontStyles = { 0: _("Normal"), 1: _("Oblique"), 2: _("Italic") }; + // Translators: font-style SVG attribute + this._fontStyles = { 0: pgettext("font-style", "Normal"), 1: pgettext("font-style", "Oblique"), 2: pgettext("font-style", "Italic") }; return this._fontStyles; }, @@ -101,37 +110,44 @@ var DisplayStrings = { get FontWeight() { if (!this._fontWeights) - this._fontWeights = { 100: _("Thin"), 200: _("Ultra Light"), 300: _("Light"), 350: _("Semi Light"), - 380: _("Book"), 400: _("Normal"), 500: _("Medium"), 600: _("Semi Bold"), - 700: _("Bold"), 800: _("Ultra Bold"), 900: _("Heavy"), 1000:_("Ultra Heavy") }; + // Translators: font-weight SVG attribute + this._fontWeights = { 100: pgettext("font-weight", "Thin"), 200: pgettext("font-weight", "Ultra Light"), 300: pgettext("font-weight", "Light"), + 350: pgettext("font-weight", "Semi Light"), 380: pgettext("font-weight", "Book"), 400: pgettext("font-weight", "Normal"), + 500: pgettext("font-weight", "Medium"), 600: pgettext("font-weight", "Semi Bold"), 700: pgettext("font-weight", "Bold"), + 800: pgettext("font-weight", "Ultra Bold"), 900: pgettext("font-weight", "Heavy"), 1000: pgettext("font-weight", "Ultra Heavy") }; return this._fontWeights; }, get LineCap() { if (!this._lineCaps) - this._lineCaps = { 0: _("Butt"), 1: _("Round"), 2: _("Square") }; + // Translators: stroke-linecap SVG attribute + this._lineCaps = { 0: pgettext("stroke-linecap", "Butt"), 1: pgettext("stroke-linecap", "Round"), 2: pgettext("stroke-linecap", "Square") }; return this._lineCaps; }, get LineJoin() { if (!this._lineJoins) - this._lineJoins = { 0: _("Miter"), 1: _("Round"), 2: _("Bevel") }; + // Translators: stroke-linejoin SVG attribute + this._lineJoins = { 0: pgettext("stroke-linejoin", "Miter"), 1: pgettext("stroke-linejoin", "Round"), 2: pgettext("stroke-linejoin", "Bevel") }; return this._lineJoins; }, getPixels(value) { - return _("%d px").format(value); + // Translators: value in pixel unit (e.g. "5 px") + return _("%f px").format(value); }, getTextAlignment: function(rightAligned) { + // Translators: text alignment return rightAligned ? _("Right aligned") : _("Left aligned"); }, get Tool() { if (!this._tools) - this._tools = { 0: _("Free drawing"), 1: _("Line"), 2: _("Ellipse"), 3: _("Rectangle"), - 4: _("Text"), 5: _("Polygon"), 6: _("Polyline"), 7: _("Image"), - 100: _("Move"), 101: _("Resize"), 102: _("Mirror") }; + this._tools = { 0: pgettext("drawing-tool", "Free drawing"), 1: pgettext("drawing-tool", "Line"), 2: pgettext("drawing-tool", "Ellipse"), + 3: pgettext("drawing-tool", "Rectangle"), 4: pgettext("drawing-tool", "Text"), 5: pgettext("drawing-tool", "Polygon"), + 6: pgettext("drawing-tool", "Polyline"), 7: pgettext("drawing-tool", "Image"), + 100: pgettext("drawing-tool", "Move"), 101: pgettext("drawing-tool", "Resize"), 102: pgettext("drawing-tool", "Mirror") }; return this._tools; } }; diff --git a/prefs.js b/prefs.js index bec7a2f..998cc56 100644 --- a/prefs.js +++ b/prefs.js @@ -1,5 +1,5 @@ /* jslint esversion: 6 */ -/* exported GLOBAL_KEYBINDINGS, INTERNAL_KEYBINDINGS, OTHER_SHORTCUTS, init, buildPrefsWidget */ +/* exported init, buildPrefsWidget */ /* * Copyright 2019 Abakkk @@ -27,10 +27,10 @@ const GLib = imports.gi.GLib; const GObject = imports.gi.GObject; const Gtk = imports.gi.Gtk; -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 Shortcuts = Me.imports.shortcuts.Shortcuts; const gettext = imports.gettext.domain(Me.metadata['gettext-domain']).gettext; const _ = function(string) { if (!string) @@ -39,51 +39,9 @@ const _ = function(string) { }; const _GTK = imports.gettext.domain('gtk30').gettext; -const GS_VERSION = Config.PACKAGE_VERSION; const MARGIN = 10; const ROWBOX_MARGIN_PARAMS = { margin_top: MARGIN / 2, margin_bottom: MARGIN / 2, margin_left: MARGIN, margin_right: MARGIN }; -var GLOBAL_KEYBINDINGS = ['toggle-drawing', 'toggle-modal', 'erase-drawings']; -var INTERNAL_KEYBINDINGS = [ - ['undo', 'redo', 'delete-last-element', 'smooth-last-element'], - ['select-none-shape', 'select-line-shape', 'select-ellipse-shape', 'select-rectangle-shape', 'select-polygon-shape', 'select-polyline-shape', - 'select-text-shape', 'select-image-shape', 'select-move-tool', 'select-resize-tool', 'select-mirror-tool'], - ['switch-fill', 'switch-fill-rule', 'switch-color-palette', 'switch-color-palette-reverse'], - ['increment-line-width', 'increment-line-width-more', 'decrement-line-width', 'decrement-line-width-more', - 'switch-linejoin', 'switch-linecap', 'switch-dash'], - ['switch-font-family', 'switch-font-family-reverse', 'switch-font-weight', 'switch-font-style', 'switch-text-alignment', 'switch-image-file'], - ['toggle-panel-and-dock-visibility', 'toggle-background', 'toggle-grid', 'toggle-square-area'], - ['open-next-json', 'open-previous-json', 'save-as-json', 'save-as-svg', 'open-preferences', 'toggle-help'] -]; - -if (GS_VERSION < '3.36') - delete INTERNAL_KEYBINDINGS[INTERNAL_KEYBINDINGS.length - 1]['open-preferences']; - -const getKeyLabel = function(accel) { - let [keyval, mods] = Gtk.accelerator_parse(accel); - return Gtk.accelerator_get_label(keyval, mods); -}; - -var OTHER_SHORTCUTS = [{ - get "Draw"() { return _("Left click"); }, - get "Menu"() { return _("Right click"); }, - get "Toggle fill/outline"() { return _("Center click"); }, - get "Increment/decrement line width"() { return _("Scroll"); }, - get "Select color"() { return _("%s … %s").format(getKeyLabel('1'), getKeyLabel('9')); }, - get "Ignore pointer movement"() { return _("%s held").format(getKeyLabel('space')); }, - "Leave": getKeyLabel('Escape'), - }, { - "Select eraser (while starting drawing)": getKeyLabel(''), - "Duplicate (while starting handling)": getKeyLabel(''), - "Rotate rectangle, polygon, polyline": getKeyLabel(''), - "Extend circle to ellipse": getKeyLabel(''), - "Curve line": getKeyLabel(''), - "Smooth free drawing outline": getKeyLabel(''), - "Rotate (while moving)": getKeyLabel(''), - "Stretch (while resizing)": getKeyLabel(''), - "Inverse (while mirroring)": getKeyLabel(''), -}]; - function init() { Convenience.initTranslations(); } @@ -110,10 +68,13 @@ const TopStack = new GObject.Class({ _init: function(params) { this.parent({ transition_type: 1, transition_duration: 500, expand: true }); this.prefsPage = new PrefsPage(); + // Translators: "Preferences" page in preferences this.add_titled(this.prefsPage, 'prefs', _("Preferences")); this.drawingPage = new DrawingPage(); + // Translators: "Drawing" page in preferences this.add_titled(this.drawingPage, 'drawing', _("Drawing")); this.aboutPage = new AboutPage(); + // Translators: "About" page in preferences this.add_titled(this.aboutPage, 'about', _("About")); } }); @@ -129,9 +90,12 @@ const AboutPage = new GObject.Class({ let vbox= new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, margin: MARGIN * 3 }); this.add(vbox); - let name = " " + _(Me.metadata.name) + ""; + // Translators: you are free to translate the extension name, that is displayed in About page, or not + let name = " " + _("Draw On You Screen") + ""; + // Translators: version number in "About" page let version = _("Version %d").format(Me.metadata.version); - let description = _(Me.metadata.description); + // Translators: you are free to translate the extension description, that is displayed in About page, or not + let description = _("Start drawing with Super+Alt+D and save your beautiful work by taking a screenshot"); let link = "" + Me.metadata.url + ""; let licenceName = _GTK("GNU General Public License, version 2 or later"); let licenceLink = "https://www.gnu.org/licenses/old-licenses/gpl-2.0.html"; @@ -153,6 +117,11 @@ const AboutPage = new GObject.Class({ creditBox.pack_start(rightBox, true, true, 5); vbox.add(creditBox); + // Translators: add your name here or keep it empty, it will be displayed in about page, e.g. + // msgstr "" + // "translator1\n" + // "translator2\n" + // "translator3" if (_("translator-credits") != "translator-credits" && _("translator-credits") != "") { leftBox.pack_start(new Gtk.Label(), false, false, 0); rightBox.pack_start(new Gtk.Label(), false, false, 0); @@ -162,7 +131,6 @@ const AboutPage = new GObject.Class({ rightBox.pack_start(rightLabel, false, false, 0); } } - }); const DrawingPage = new GObject.Class({ @@ -375,6 +343,7 @@ const DrawingPage = new GObject.Class({ _addNewPalette: function() { let colors = Array(9).fill('Black'); + // Translators: default name of a new palette this.palettes.push([_("New palette"), colors]); this._savePalettes(); }, @@ -407,10 +376,15 @@ const PrefsPage = new GObject.Class({ listBox.get_style_context().add_class('background'); globalFrame.add(listBox); - let globalKeybindingsRow = new Gtk.ListBoxRow({ activatable: false }); - let globalKeybindingsWidget = new KeybindingsWidget(GLOBAL_KEYBINDINGS, settings); - globalKeybindingsRow.add(globalKeybindingsWidget); - listBox.add(globalKeybindingsRow); + Shortcuts.GLOBAL_KEYBINDINGS.forEach((settingKeys, index) => { + if (index) + listBox.add(new Gtk.Box(ROWBOX_MARGIN_PARAMS)); + + let globalKeybindingsRow = new Gtk.ListBoxRow({ activatable: false }); + let globalKeybindingsWidget = new KeybindingsWidget(settingKeys, settings); + globalKeybindingsRow.add(globalKeybindingsWidget); + listBox.add(globalKeybindingsRow); + }); let persistentKey = schema.get_key('persistent-drawing'); let persistentRow = new PrefRow({ label: persistentKey.get_summary(), desc: persistentKey.get_description() }); @@ -447,28 +421,28 @@ const PrefsPage = new GObject.Class({ listBox.get_style_context().add_class('background'); internalFrame.add(listBox); - OTHER_SHORTCUTS.forEach((object, index) => { + Shortcuts.OTHERS.forEach((pairs, index) => { if (index) listBox.add(new Gtk.Box(ROWBOX_MARGIN_PARAMS)); - for (let key in object) { + pairs.forEach(pair => { let otherBox = new Gtk.Box({ margin_left: MARGIN, margin_right: MARGIN }); - let otherLabel = new Gtk.Label({ label: _(key), use_markup: true }); + let otherLabel = new Gtk.Label({ label: pair[0], use_markup: true }); otherLabel.set_halign(1); - let otherLabel2 = new Gtk.Label({ label: object[key] }); + let otherLabel2 = new Gtk.Label({ label: pair[1] }); otherBox.pack_start(otherLabel, true, true, 4); otherBox.pack_start(otherLabel2, false, false, 4); listBox.add(otherBox); - } + }); }); listBox.add(new Gtk.Box(ROWBOX_MARGIN_PARAMS)); - INTERNAL_KEYBINDINGS.forEach((array, index) => { + Shortcuts.INTERNAL_KEYBINDINGS.forEach((settingKeys, index) => { if (index) listBox.add(new Gtk.Box(ROWBOX_MARGIN_PARAMS)); - let internalKeybindingsWidget = new KeybindingsWidget(array, internalShortcutSettings); + let internalKeybindingsWidget = new KeybindingsWidget(settingKeys, internalShortcutSettings); listBox.add(internalKeybindingsWidget); }); @@ -552,7 +526,7 @@ const PixelSpinButton = new GObject.Class({ // Add 'px' unit. vfunc_output: function() { - this.text = _("%d px").format(Math.round(this.value * 100) / 100); + this.text = _("%f px").format(Number(this.value).toFixed(2)); return true; }, @@ -603,11 +577,11 @@ const KeybindingsWidget = new GObject.Class({ GTypeName: 'DrawOnYourScreenKeybindingsWidget', Extends: Gtk.Box, - _init: function(keybindings, settings) { + _init: function(settingKeys, settings) { this.parent(ROWBOX_MARGIN_PARAMS); this.set_orientation(Gtk.Orientation.VERTICAL); - this._keybindings = keybindings; + this._settingKeys = settingKeys; this._settings = settings; this._columns = { @@ -706,9 +680,9 @@ const KeybindingsWidget = new GObject.Class({ _refresh: function() { this._store.clear(); - for(let settings_key of this._keybindings) { + this._settingKeys.forEach(settingKey => { let [key, mods] = Gtk.accelerator_parse( - this._settings.get_strv(settings_key)[0] + this._settings.get_strv(settingKey)[0] ); let iter = this._store.append(); @@ -720,12 +694,12 @@ const KeybindingsWidget = new GObject.Class({ this._columns.KEY ], [ - settings_key, - this._settings.settings_schema.get_key(settings_key).get_summary(), + settingKey, + this._settings.settings_schema.get_key(settingKey).get_summary(), mods, key ] ); - } + }); } }); diff --git a/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml b/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml index 9b2e3c0..beea9e5 100644 --- a/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml +++ b/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml @@ -31,10 +31,82 @@ ["<Primary><Alt><Super>d"] + Grab/ungrab keyboard and pointer + + + "#2e2e2e" + Background color + The color of the drawing area background + + + true + Automatic dash array + Compute the lengths from the line width + + + 5 + Dash array on + The dash length in pixels + + + 15 + Dash array off + The gap between the dashes in pixels + + + 0 + Dash offset + The dash offset in pixels + + + "Gray" + Grid overlay color + The color of the lines + + + true + Automatic grid overlay line + Compute the lengths from the screen size + + + 10 + Grid overlay line spacing + The gap between lines in pixels + + + 0.5 + Grid overlay line width + The line width in pixels + + + + [ + ("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)"]) + ] + + Color palettes + The palettes of drawing colors + + + true + Automatic square area size + Compute the size of the square area from the screen size + + + 512 + Square area size + The size of the square area in pixels + + KP_Subtract','minus','minus']]]> @@ -139,7 +211,7 @@ ["<Primary>p"] - Free drawing + Select free drawing ["<Primary>y"] @@ -242,75 +314,4 @@ Undo last brushstroke - - - "#2e2e2e" - Background color - The color of the drawing area background - - - true - Automatic dash array - Compute the lengths from the line width - - - 5 - Dash array on - The dash length in pixels - - - 15 - Dash array off - The gap between the dashes in pixels - - - 0 - Dash offset - The dash offset in pixels - - - "Gray" - Grid overlay color - The color of the lines - - - true - Automatic grid overlay line - Compute the lengths from the screen size - - - 10 - Grid overlay line spacing - The gap between lines in pixels - - - 0.5 - Grid overlay line width - The line width in pixels - - - - [ - ("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)"]) - ] - - Color palettes - The palettes of drawing colors - - - true - Automatic square area size - Compute the size of the square area from the screen size - - - 512 - Square area size - The size of the square area in pixels - - diff --git a/shortcuts.js b/shortcuts.js new file mode 100644 index 0000000..6e9a07c --- /dev/null +++ b/shortcuts.js @@ -0,0 +1,102 @@ +/* jslint esversion: 6 */ +/* exported Shortcuts */ + +/* + * 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 . + */ + +const Gtk = imports.gi.Gtk; + +const GS_VERSION = imports.misc.config.PACKAGE_VERSION; +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 internalShortcutsSchema = Convenience.getSettings(Me.metadata['settings-schema'] + '.internal-shortcuts').settings_schema; + +const getKeyLabel = function(accel) { + let [keyval, mods] = Gtk.accelerator_parse(accel); + return Gtk.accelerator_get_label(keyval, mods); +}; + +// It is used by helper and prefs. +var Shortcuts = { + + // The setting keys of the "org.gnome.shell.extensions.draw-on-your-screen" schema. + GLOBAL_KEYBINDINGS: [ + ['toggle-drawing', 'toggle-modal', 'erase-drawings'] + ], + + // The setting keys of the "org.gnome.shell.extensions.draw-on-your-screen.internal-shortcuts" schema. + INTERNAL_KEYBINDINGS: [ + ['undo', 'redo', 'delete-last-element', 'smooth-last-element'], + ['select-none-shape', 'select-line-shape', 'select-ellipse-shape', 'select-rectangle-shape', 'select-polygon-shape', 'select-polyline-shape', + 'select-text-shape', 'select-image-shape', 'select-move-tool', 'select-resize-tool', 'select-mirror-tool'], + ['switch-fill', 'switch-fill-rule', 'switch-color-palette', 'switch-color-palette-reverse'], + ['increment-line-width', 'increment-line-width-more', 'decrement-line-width', 'decrement-line-width-more', + 'switch-linejoin', 'switch-linecap', 'switch-dash'], + ['switch-font-family', 'switch-font-family-reverse', 'switch-font-weight', 'switch-font-style', 'switch-text-alignment', 'switch-image-file'], + ['toggle-panel-and-dock-visibility', 'toggle-background', 'toggle-grid', 'toggle-square-area'], + ['open-next-json', 'open-previous-json', 'save-as-json', 'save-as-svg', 'open-preferences', 'toggle-help'] + ], + + // Use functions to get the translations "at runtime". + _otherFunctions: [[ + () => [_("Draw"), _("Left click")], + () => [_("Menu"), _("Right click")], + () => [internalShortcutsSchema.get_key('switch-fill').get_summary(), _("Center click")], + () => [_("Increment/decrement line width"), _("Scroll")], + // Translators: %s are key labels (Ctrl+F1 and Ctrl+F9) + () => [_("Select color"), _("%s … %s").format(getKeyLabel('1'), getKeyLabel('9'))], + // Translators: %s is a key label + () => [_("Ignore pointer movement"), _("%s held").format(getKeyLabel('space'))], + () => [_("Leave"), getKeyLabel('Escape')], + ], [ + () => [_("Select eraser (while starting drawing)"), getKeyLabel('')], + () => [_("Duplicate (while starting handling)"), getKeyLabel('')], + () => [_("Rotate rectangle, polygon, polyline"), getKeyLabel('')], + () => [_("Extend circle to ellipse"), getKeyLabel('')], + () => [_("Curve line"), getKeyLabel('')], + () => [_("Smooth free drawing outline"), getKeyLabel('')], + () => [_("Rotate (while moving)"), getKeyLabel('')], + () => [_("Stretch (while resizing)"), getKeyLabel('')], + () => [_("Inverse (while mirroring)"), getKeyLabel('')], + ]], + + get OTHERS() { + if (!this._others) { + this._others = []; + this._otherFunctions.forEach(getPairFunctions => { + let pairs = []; + getPairFunctions.forEach(getPairFunction => pairs.push(getPairFunction())); + this._others.push(pairs); + }); + } + return this._others; + } +}; + +if (GS_VERSION < '3.36') + // Remove 'open-preferences' keybinding. + Shortcuts.INTERNAL_KEYBINDINGS.forEach(settingKeys => { + let index = settingKeys.indexOf('open-preferences'); + if (index != -1) + settingKeys.splice(index, 1); + }); From 56008f30418e3676fa7f2d10a8e25392107a15ab Mon Sep 17 00:00:00 2001 From: abakkk Date: Wed, 9 Sep 2020 12:12:29 +0200 Subject: [PATCH 14/35] add ranges to drawing settings schema * It is no longer required to clamp the setting value in area.js. * Add a "range" property, completed with another 'step' property, to PixelSpinButton in order to directly initiate the lower and upper values of the adjustment from the relevant setting range. * Not related: fix an inversion between Pango and Cairo in element.js. --- area.js | 10 ++-- elements.js | 10 ++-- prefs.js | 46 +++++++++++++----- schemas/gschemas.compiled | Bin 6977 -> 7137 bytes ...extensions.draw-on-your-screen.gschema.xml | 6 +++ 5 files changed, 50 insertions(+), 22 deletions(-) diff --git a/area.js b/area.js index 1580a2d..321fb84 100644 --- a/area.js +++ b/area.js @@ -241,7 +241,7 @@ var DrawingArea = new Lang.Class({ 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')); + this.squareAreaSize = Me.drawingSettings.get_uint('square-area-size'); } this.areaBackgroundColor = getClutterColorFromString(Me.drawingSettings.get_string('background-color'), 'BLACK'); @@ -251,16 +251,16 @@ var DrawingArea = new Lang.Class({ 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.gridLineSpacing = Me.drawingSettings.get_uint('grid-line-spacing'); + this.gridLineWidth = Math.round(Me.drawingSettings.get_double('grid-line-width') * 100) / 100; } 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; + let on = Math.round(Me.drawingSettings.get_double('dash-array-on') * 100) / 100; + let off = Math.round(Me.drawingSettings.get_double('dash-array-off') * 100) / 100; this.dashArray = [on, off]; } }, diff --git a/elements.js b/elements.js index e7b5905..3191dfb 100644 --- a/elements.js +++ b/elements.js @@ -35,18 +35,18 @@ var getPangoFontFamilies = function() { }; const getFillRuleSvgName = function(fillRule) { - return fillRule == Pango.FillRule.EVEN_ODD ? 'evenodd' : 'nonzero'; + return fillRule == Cairo.FillRule.EVEN_ODD ? 'evenodd' : 'nonzero'; }; const getLineCapSvgName = function(lineCap) { - return lineCap == Pango.LineCap.BUTT ? 'butt' : - lineCap == Pango.LineCap.SQUASH ? 'square' : + return lineCap == Cairo.LineCap.BUTT ? 'butt' : + lineCap == Cairo.LineCap.SQUASH ? 'square' : 'round'; }; const getLineJoinSvgName = function(lineJoin) { - return lineJoin == Pango.LineJoin.MITER ? 'miter' : - lineJoin == Pango.LineJoin.BEVEL ? 'bevel' : + return lineJoin == Cairo.LineJoin.MITER ? 'miter' : + lineJoin == Cairo.LineJoin.BEVEL ? 'bevel' : 'round'; }; diff --git a/prefs.js b/prefs.js index 998cc56..dea0c8f 100644 --- a/prefs.js +++ b/prefs.js @@ -181,8 +181,8 @@ const DrawingPage = new GObject.Class({ let squareAreaAutoButton = new Gtk.CheckButton({ label: _("Auto"), name: this.schema.get_key('square-area-auto').get_summary(), 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), + let squareAreaSizeButton = new PixelSpinButton({ width_chars: 5, digits: 0, step: 1, + range: this.schema.get_key('square-area-size').get_range(), name: this.schema.get_key('square-area-size').get_summary(), tooltip_text: this.schema.get_key('square-area-size').get_description() }); this.settings.bind('square-area-auto', squareAreaAutoButton, 'active', 0); @@ -204,12 +204,12 @@ const DrawingPage = new GObject.Class({ let gridLineAutoButton = new Gtk.CheckButton({ label: _("Auto"), name: this.schema.get_key('grid-line-auto').get_summary(), 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), + let gridLineWidthButton = new PixelSpinButton({ width_chars: 5, digits: 1, step: 0.1, + range: this.schema.get_key('grid-line-width').get_range(), name: this.schema.get_key('grid-line-width').get_summary(), 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), + let gridLineSpacingButton = new PixelSpinButton({ width_chars: 5, digits: 1, step: 1, + range: this.schema.get_key('grid-line-spacing').get_range(), name: this.schema.get_key('grid-line-spacing').get_summary(), tooltip_text: this.schema.get_key('grid-line-spacing').get_description() }); this.settings.bind('grid-line-auto', gridLineAutoButton, 'active', 0); @@ -241,12 +241,12 @@ const DrawingPage = new GObject.Class({ let dashArrayAutoButton = new Gtk.CheckButton({ label: _("Auto"), name: this.schema.get_key('dash-array-auto').get_summary(), 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), + let dashArrayOnButton = new PixelSpinButton({ width_chars: 5, digits: 1, step: 0.1, + range: this.schema.get_key('dash-array-on').get_range(), name: this.schema.get_key('dash-array-on').get_summary(), 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), + let dashArrayOffButton = new PixelSpinButton({ width_chars: 5, digits: 1, step: 0.1, + range: this.schema.get_key('dash-array-off').get_range(), name: this.schema.get_key('dash-array-off').get_summary(), tooltip_text: this.schema.get_key('dash-array-off').get_description() }); this.settings.bind('dash-array-auto', dashArrayAutoButton, 'active', 0); @@ -260,8 +260,8 @@ const DrawingPage = new GObject.Class({ toolsListBox.add(dashArrayRow); let dashOffsetRow = new PrefRow({ label: this.schema.get_key('dash-offset').get_summary() }); - let dashOffsetButton = new PixelSpinButton({ width_chars: 5, digits: 1, - adjustment: Gtk.Adjustment.new(0, -16384, 16384, 0.1, 1, 0), + let dashOffsetButton = new PixelSpinButton({ width_chars: 5, digits: 1, step: 0.1, + range: this.schema.get_key('dash-offset').get_range(), name: this.schema.get_key('dash-offset').get_summary(), tooltip_text: this.schema.get_key('dash-offset').get_description() }); this.settings.bind('dash-offset', dashOffsetButton, 'value', 0); @@ -523,6 +523,28 @@ const PixelSpinButton = new GObject.Class({ Name: 'DrawOnYourScreenPixelSpinButton', GTypeName: 'DrawOnYourScreenPixelSpinButton', Extends: Gtk.SpinButton, + Properties: { + 'range': GObject.param_spec_variant('range', 'range', 'GSettings range', + GLib.VariantType.new('(sv)'), null, GObject.ParamFlags.WRITABLE), + + 'step': GObject.ParamSpec.double('step', 'step', 'step increment', + GObject.ParamFlags.WRITABLE, + 0, 1000, 1) + }, + + set range(range) { + let [type, variant] = range.deep_unpack(); + if (type == 'range') { + let [min, max] = variant.deep_unpack(); + this.adjustment.set_lower(min); + this.adjustment.set_upper(max); + } + }, + + set step(step) { + this.adjustment.set_step_increment(step); + this.adjustment.set_page_increment(step * 10); + }, // Add 'px' unit. vfunc_output: function() { diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled index 85cce3ac7029a5c12ac2a8d6566f5660d0c427ac..411939e81af313d67a206371573b8906ca47bd6a 100644 GIT binary patch delta 1897 zcmZ{kZ)j6z7{#AT12w5_YN{qRjJ6a>J5nCXz$wzue zfjV85JK_}lCNz3xi>(^Nnagp)S-54rNQdplm*mXk4!8^2cWgOL&dmQvE4&wK%5!G& z2s{Qg=Q%UDDw7ClsPz6|4GS@^$AAp{A@pi~05b~}ned#T*Ycd1d^fxU+Mnml5(6-M@zGHu8)_20& zprID)Z{*D7qT*R0T!Er@lFMvhwqigEz6$BEbAG^>MGlIXMSg}R4qf<&{h15VKMl`7 z*?4f3oS7&30PeIr{SY$qL+FN|Q1KIPI6T1tCy=?b7(4-Owv1{MFmr-y@E;-Lfua@m zXXefp;rF1^t4mkOnRya8Z!tq}-IxuMGi$Fe+yxmImB%U@cw@qV4tN*z<}UlUzwkjKQlLwg5QL`nr@pUXJ-8@T(?=|*WcSeBu7@YBQgWl zLczAT8`;3j*U=5{f^;uk){`@D1dqT^L1sro6FDHM9$0wrQu6ZUw>?k=zd)P+dh%ZN7kkJv`1h#vn~9imv6noHFQE@ttJfdE z!#X%mfV?;ZVl!|ta{c%ZT)dZarNjmM)$BfVW+ z)OCIj)@jIp+j{OaIUe|byHoQk&wY1ObF{X!derh(1ytk6;elwJIpdvCXX5m@*UGa) z{`H#=IZQ;xBDHkgr!INlr;?}%!u~t8Y&!dK1E>@n!O%a=s z%f;lj@c|YpynU=fg~UY+Xu_XCkL3o4Rj3<(3q798#mdL~hTcextHDoDN`r+zjhb?W#46N|52L-gT&#QqPobMVTdt{&SQBLMA5n9z zzgYbjad&`~oZG)x&iu}W&S4oLTV?u>U2Rk$vGNu?ivDiCWGNTxJon+p(I?-Y3@R6E zYsT=eQRsFku3UT%`8>XWUb6N)qFmgjH)$Ej+hokn+OvFMCompute the lengths from the line width + 5 Dash array on The dash length in pixels + 15 Dash array off The gap between the dashes in pixels + 0 Dash offset The dash offset in pixels @@ -73,11 +76,13 @@ Compute the lengths from the screen size + 10 Grid overlay line spacing The gap between lines in pixels + 0.5 Grid overlay line width The line width in pixels @@ -102,6 +107,7 @@ Compute the size of the square area from the screen size + 512 Square area size The size of the square area in pixels From 442d20b387b4315f3e45a8d8c23b43c686c1dd47 Mon Sep 17 00:00:00 2001 From: abakkk Date: Wed, 9 Sep 2020 22:25:56 +0200 Subject: [PATCH 15/35] paste image files from clipboard --- area.js | 11 ++- extension.js | 1 + files.js | 82 +++++++++++++----- schemas/gschemas.compiled | Bin 7137 -> 7216 bytes ...extensions.draw-on-your-screen.gschema.xml | 4 + 5 files changed, 74 insertions(+), 24 deletions(-) diff --git a/area.js b/area.js index 321fb84..fedd40f 100644 --- a/area.js +++ b/area.js @@ -190,7 +190,7 @@ var DrawingArea = new Lang.Class({ }, getImages() { - let images = Files.getImages(); + let images = Files.Images.getImages(); if (!images[this.currentImage]) this.currentImage = Math.max(images.length - 1, 0); return images; @@ -998,6 +998,15 @@ var DrawingArea = new Lang.Class({ this.emit('show-osd-gicon', images[this.currentImage].gicon, images[this.currentImage].toString(), "", -1, false); }, + pasteImageFiles: function() { + Files.Images.addImagesFromClipboard((images, index) => { + this.currentImage = index; + this.currentTool = Shapes.IMAGE; + this.updatePointerCursor(); + this.emit('show-osd-gicon', images[this.currentImage].gicon, images[this.currentImage].toString(), "", -1, false); + }); + }, + toggleHelp: function() { if (this.helper.visible) { this.helper.hideHelp(); diff --git a/extension.js b/extension.js index 4395725..d838cf9 100644 --- a/extension.js +++ b/extension.js @@ -180,6 +180,7 @@ const AreaManager = new Lang.Class({ 'decrement-line-width': () => this.activeArea.incrementLineWidth(-1), 'increment-line-width-more': () => this.activeArea.incrementLineWidth(5), 'decrement-line-width-more': () => this.activeArea.incrementLineWidth(-5), + 'paste-image-files': this.activeArea.pasteImageFiles.bind(this.activeArea), 'switch-linejoin': this.activeArea.switchLineJoin.bind(this.activeArea), 'switch-linecap': this.activeArea.switchLineCap.bind(this.activeArea), 'switch-fill-rule': this.activeArea.switchFillRule.bind(this.activeArea), diff --git a/files.js b/files.js index 484a78c..b345c16 100644 --- a/files.js +++ b/files.js @@ -1,5 +1,5 @@ /* jslint esversion: 6 */ -/* exported Image, getImages, Json, getJsons, getDateString */ +/* exported Image, Images, Json, getJsons, getDateString */ /* * Copyright 2019 Abakkk @@ -27,11 +27,14 @@ const GdkPixbuf = imports.gi.GdkPixbuf; const Gio = imports.gi.Gio; const GLib = imports.gi.GLib; const Lang = imports.lang; +const St = imports.gi.St; 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'])); +const Clipboard = St.Clipboard.get_default(); +const CLIPBOARD_TYPE = St.ClipboardType.CLIPBOARD; // wrapper around an image file var Image = new Lang.Class({ @@ -125,31 +128,64 @@ var Image = new Lang.Class({ } }); -var getImages = function() { - let images = []; +var Images = { + clipboardImages: [], - [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; - } + getImages: function() { + let images = []; - 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); - }); + [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 a.displayName.localeCompare(b.displayName); + }); + + return images.concat(this.clipboardImages); + }, - images.sort((a, b) => { - return a.displayName.localeCompare(b.displayName); - }); - - return images; + addImagesFromClipboard: function(callback) { + Clipboard.get_text(CLIPBOARD_TYPE, (clipBoard, text) => { + if (!text) + return; + + let lines = text.split('\n'); + if (lines[0] == 'x-special/nautilus-clipboard') + lines = lines.slice(2); + + let images = lines.filter(line => !!line) + .map(line => Gio.File.new_for_commandline_arg(line)) + .filter(file => file.query_exists(null)) + .map(file => [file, file.query_info('standard::display-name,standard::content-type', Gio.FileQueryInfoFlags.NONE, null)]) + .filter(pair => pair[1].get_content_type().indexOf('image') == 0) + .map(pair => new Image({ file: pair[0], contentType: pair[1].get_content_type(), displayName: pair[1].get_display_name() })); + + // Prevent duplicated + images.filter(image => !this.clipboardImages.map(clipboardImage => clipboardImage.file).some(clipboardFile => clipboardFile.equal(image.file))) + .forEach(image => this.clipboardImages.push(image)); + + if (images.length) { + let lastFile = images[images.length - 1].file; + let allImages = this.getImages(); + let index = allImages.findIndex(image => image.file.equal(lastFile)); + callback(allImages, index); + } + }); + } }; // wrapper around a json file diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled index 411939e81af313d67a206371573b8906ca47bd6a..0dcf5fba49ed9dbd8e6ce1ab30bc9e3d255b7906 100644 GIT binary patch delta 2600 zcmZveZA?>F0EQ1LtXdT42Q6*c3Nl39#qyybb`-91rFe4fJGncuHz3*+QU?h2X-@fOb zbI->;_nv!eMjHD+%o)3Ma<4VDTBQHxLl%H%X0Z_7`V)Rf$DH1dd>lFnKL7rtn>ju2Yf0JBTX6B!)9mT*nYTg1!1G3V zl-JX^J_MZr?+>pSV@~f!Zozt$fYgCUbv_pGhYbY*=w|Td8s%%| z^iJe$&@k{l^u?Le=Oa%-`#@dal55QA+0GF361X4n++j}7{3i5g(7k@oMdT^-2d8=p zVGf>}o5qRDtU%8SZfF2(D*EeB=JcHEP0&_Q@bG8_b9!DMf*uAx{kH1}b9&B1KXe$} z`DI`pb9#?R^@tlVW8m=Ut_c>V35IsB82yFuO z5A4It>6y1fli=g4ts~6o`Ox)4&w^YGgzeJ{@rpPHO=3^Jb$wJ%nHBJZPh&rH82sCO zHNc#{0Qm@X6y(-?wum`>G4e6!@4!~vJ|=WF;}Pg>aAvTwir3R~029z6ylJ*%uBYeqe&{B! zwfU5}jp^B;77zA+2MaP4=vg5N9R!6BR0ez96>wuAlQ~^h@K4{gARf1nVg>a2=q4Ck;&l$!b9Eq-I)CeiMnlKbhVwV;%gnZyB!448RU>V2- zc>qtpd6>Za0NW=0-R8l9gL@wEyS)Ou09JuoPzUNk1K?j7;2~ok;5Q#HG4s$+1LXmP z=K*{&#BO}k%>x7v0@(lNVSqES2=Ii0x2fQpPXW&Yd;vu{s0KVRECk#wJn7^E3y^Nl za+!mtQ1iNKvy&FjtZ@u;peflI(h{hFzwC8A@_tE!9P}1iA7?>%!M;1EM!se%ccf=H z$gQWuR9!O+O~}cjx;!(gmA$s5*7P;|)I>3z=sxmt&3<(qpU3X^^Y!ugfZX{`@t#&9uGs Ef5}x4Z~y=R delta 2566 zcmZveeQXnD0LHJ#WHPpO?fP9{D`SkoVaGNZhOYtgF_CN_$wE}9-EA$jy>h+509`R5 z5h57iHIWzy1EX1p$wr6-%?R+{P)TO+4~TyN5zRs%8U7&}4D)%ex2_{L`R#e`c|Y&H zd+%L;!~I3aj#vgR9Nkt>STBwLEJB{_OXnka1xy8npcq&|39y@#LLI;b+`tQ_gPEZ0 z1!m!Tj0*VKIaI<|fw`bMLwd|eGJ*v!P=jkyYf=ZDckuM;0CWH|ERc3fgU~zR%*o0s z=Jch=N1z^?B(+vu{fs$1^B}Yltn7L`6p+%Hi$WAMBTRx-MnT3iKY*+UtTuCc=Kati zQ2ca%1qYzFAs>eR1Ku#})3bg)ma_`1F?0IDGzuDETESYgfSwH^&_iJ7vsym~pyvQR z&T~U z@YaCJ+~UOZ=SyToSPoW{{Plzd^c)}vZ3MS|Ju!(ny%+g*XcrjNKe@=9o-20@+6%Vq zdQ{1r-huoY^fst_WIxNC-dLeDOg{G2>AuX2=s6)bv>MbNF1o@7^c-LXv;}lG`5!Q+ z=gLK(=fRBVlo;GL5IOeZ)}t~ zJ(u)v=n9V{UHh=Rfc?p0XG5V)x|CgaRfOUQTGt^HT z7re832%mrxqxZjMNAz3?er?>~y{p$_%;}AN3~dC~d)jm6^mf#5g(~2kMe_H|>G=o_ zK#zmfO{a{Pl)gYpW2P{dK+pC|?QB5LI~auC0iO@F^fRaD03*;mpCtYA`{sSj>A6B~ z=v)wM*|wZHJ-6jLr~>k8zMjgQ-iiDG^!S_j;|?xe#e(DTT!~)jccAs;r7xM&b3#MV z`yjO^s)r+Tdo&i4mNaY8cu3p3EF=|(A3c6C>B1$Z2%q2VGni_n|a@IK0Fck?U6;{mFi(>J7V!CaO_}OF6mo;U#qNNnE z(YZKnoVEq1JP+XOZXAx-*?6C@(*RFid~}Ty_9f_KkO!uKv6Frp{Mbp)Q<$fC9jFCC zz(aTvm=6|$mjO@iS9w@kV9EhcYyNn|7Xj=ELU+O=(lJcWo~2zKM&=cU;ywV~SBvd}UuXWkE8eM zCfZaClFj#xy>;g9Q4_knM~QYsbkxeJw?|C%)C-(T;)bn4G?u!`CKPv0?4~W0iii!^ zPO@vdEv~A1M2>}0x{PfUR}#87;__6QJ1DN=CDv6nmOEP9>@J!RVNWoxv8_#Vi2=92 jVZxx=*r1u+8INk3s*UxPGxsn)0`J;["<Primary><Shift>o"] Open previous drawing + + ["<Primary>v"] + Paste image files from the clipboard + ["<Primary><Shift>z"] Redo last brushstroke From 8277710510c9c6081a55e66a5ab8aae23ece4b66 Mon Sep 17 00:00:00 2001 From: abakkk Date: Thu, 10 Sep 2020 15:19:17 +0200 Subject: [PATCH 16/35] get all icons from Files.Icons --- area.js | 37 ++++++++++++++++++------------------- elements.js | 17 +++++++++-------- extension.js | 20 +++++++------------- files.js | 25 ++++++++++++++++++++++++- menu.js | 42 ++++++++---------------------------------- 5 files changed, 66 insertions(+), 75 deletions(-) diff --git a/area.js b/area.js index fedd40f..56abb52 100644 --- a/area.js +++ b/area.js @@ -73,8 +73,7 @@ const getClutterColorFromString = function(string, fallback) { var DrawingArea = new Lang.Class({ Name: 'DrawOnYourScreenDrawingArea', Extends: St.DrawingArea, - 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] }, + Signals: { 'show-osd': { param_types: [Gio.Icon.$gtype, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_DOUBLE, GObject.TYPE_BOOLEAN] }, 'update-action-mode': {}, 'leave-drawing-mode': {} }, @@ -198,10 +197,10 @@ var DrawingArea = new Lang.Class({ get fontFamilies() { if (!this._fontFamilies) { - let pangoFontFamilies = Elements.getPangoFontFamilies().filter(family => { + let otherFontFamilies = Elements.getAllFontFamilies().filter(family => { return family != this.defaultFontFamily && FontGenericFamilies.indexOf(family) == -1; }); - this._fontFamilies = [this.defaultFontFamily].concat(FontGenericFamilies, pangoFontFamilies); + this._fontFamilies = [this.defaultFontFamily].concat(FontGenericFamilies, otherFontFamilies); } return this._fontFamilies; }, @@ -995,7 +994,7 @@ var DrawingArea = new Lang.Class({ 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); + this.emit('show-osd', images[this.currentImage].gicon, images[this.currentImage].toString(), "", -1, false); }, pasteImageFiles: function() { @@ -1003,7 +1002,7 @@ var DrawingArea = new Lang.Class({ this.currentImage = index; this.currentTool = Shapes.IMAGE; this.updatePointerCursor(); - this.emit('show-osd-gicon', images[this.currentImage].gicon, images[this.currentImage].toString(), "", -1, false); + this.emit('show-osd', images[this.currentImage].gicon, images[this.currentImage].toString(), "", -1, false); }); }, @@ -1168,7 +1167,7 @@ var DrawingArea = new Lang.Class({ GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => { json.contents = contents; if (notify) - this.emit('show-osd', 'document-save-symbolic', name, "", -1, false); + this.emit('show-osd', Files.Icons.SAVE, name, "", -1, false); if (name != Me.metadata['persistent-file-name']) { this.jsonName = name; this.lastJsonContents = contents; @@ -1220,7 +1219,7 @@ var DrawingArea = new Lang.Class({ })); if (notify) - this.emit('show-osd', 'document-open-symbolic', name, "", -1, false); + this.emit('show-osd', Files.Icons.OPEN, name, "", -1, false); if (name != Me.metadata['persistent-file-name']) { this.jsonName = name; this.lastJsonContents = contents; @@ -1236,26 +1235,26 @@ var DrawingArea = new Lang.Class({ this._redisplay(); }, - loadNextJson: function() { - let names = Files.getJsons().map(json => json.name); - - if (!names.length) - return; - - let nextName = names[this.jsonName && names.indexOf(this.jsonName) != names.length - 1 ? names.indexOf(this.jsonName) + 1 : 0]; - this.loadJson(nextName, true); - }, - loadPreviousJson: function() { let names = Files.getJsons().map(json => json.name); if (!names.length) return; - let previousName = names[this.jsonName && names.indexOf(this.jsonName) > 0 ? names.indexOf(this.jsonName) - 1 : names.length - 1]; + let previousName = names[this.jsonName && names.indexOf(this.jsonName) != names.length - 1 ? names.indexOf(this.jsonName) + 1 : 0]; this.loadJson(previousName, true); }, + loadNextJson: function() { + let names = Files.getJsons().map(json => json.name); + + if (!names.length) + return; + + let nextName = names[this.jsonName && names.indexOf(this.jsonName) > 0 ? names.indexOf(this.jsonName) - 1 : names.length - 1]; + this.loadJson(nextName, true); + }, + get drawingContentsHasChanged() { let contents = `[\n ` + new Array(...this.elements.map(element => JSON.stringify(element))).join(`,\n\n `) + `\n]`; return contents != this.lastJsonContents; diff --git a/elements.js b/elements.js index 3191dfb..9be96ff 100644 --- a/elements.js +++ b/elements.js @@ -1,3 +1,6 @@ +/* jslint esversion: 6 */ +/* exported Shapes, Transformations, getAllFontFamilies, DrawingElement */ + /* * Copyright 2019 Abakkk * @@ -18,9 +21,6 @@ * along with this program. If not, see . */ -/* jslint esversion: 6 */ -/* exported Shapes, Transformations, getPangoFontFamilies, DrawingElement */ - const Cairo = imports.cairo; const Clutter = imports.gi.Clutter; const Lang = imports.lang; @@ -30,7 +30,7 @@ const PangoCairo = imports.gi.PangoCairo; var Shapes = { NONE: 0, LINE: 1, ELLIPSE: 2, RECTANGLE: 3, TEXT: 4, POLYGON: 5, POLYLINE: 6, IMAGE: 7 }; var Transformations = { TRANSLATION: 0, ROTATION: 1, SCALE_PRESERVE: 2, STRETCH: 3, REFLECTION: 4, INVERSION: 5 }; -var getPangoFontFamilies = function() { +var getAllFontFamilies = function() { return PangoCairo.font_map_get_default().list_families().map(fontFamily => fontFamily.get_name()).sort((a,b) => a.localeCompare(b)); }; @@ -80,12 +80,13 @@ const _DrawingElement = new Lang.Class({ if (params.transformations === undefined) this.transformations = []; - if (params.font && params.font.weight === 0) - this.font.weight = 400; - if (params.font && params.font.weight === 1) - this.font.weight = 700; + if (params.font && typeof params.font != 'string') { // compatibility with v6.2- + if (params.font.weight === 0) + this.font.weight = 400; + else if (params.font.weight === 1) + this.font.weight = 700; let font = new Pango.FontDescription(); ['family', 'weight', 'style', 'stretch', 'variant'].forEach(attribute => { if (params.font[attribute] !== undefined) diff --git a/extension.js b/extension.js index d838cf9..ec5a10e 100644 --- a/extension.js +++ b/extension.js @@ -21,7 +21,6 @@ * along with this program. If not, see . */ -const Gio = imports.gi.Gio; const Lang = imports.lang; const Meta = imports.gi.Meta; const Shell = imports.gi.Shell; @@ -36,6 +35,7 @@ const PanelMenu = imports.ui.panelMenu; const Me = ExtensionUtils.getCurrentExtension(); const Convenience = ExtensionUtils.getSettings && ExtensionUtils.initTranslations ? ExtensionUtils : Me.imports.convenience; const Area = Me.imports.area; +const Files = Me.imports.files; const Helper = Me.imports.helper; const _ = imports.gettext.domain(Me.metadata['gettext-domain']).gettext; @@ -86,8 +86,6 @@ const AreaManager = new Lang.Class({ _init: function() { this.areas = []; this.activeArea = null; - this.enterGicon = new Gio.ThemedIcon({ name: 'applications-graphics-symbolic' }); - this.leaveGicon = new Gio.ThemedIcon({ name: 'application-exit-symbolic' }); Main.wm.addKeybinding('toggle-drawing', Me.settings, @@ -164,7 +162,6 @@ const AreaManager = new Lang.Class({ area.leaveDrawingHandler = area.connect('leave-drawing-mode', this.toggleDrawing.bind(this)); area.updateActionModeHandler = area.connect('update-action-mode', this.updateActionMode.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); } }, @@ -344,7 +341,7 @@ const AreaManager = new Lang.Class({ Main.popModal(this.activeArea); if (source && source == global.display) // Translators: "released" as the opposite of "grabbed" - this.showOsd(null, 'touchpad-disabled-symbolic', _("Keyboard and pointer released"), null, null, false); + this.showOsd(null, Files.Icons.UNGRAB, _("Keyboard and pointer released"), null, null, false); this.setCursor('DEFAULT'); this.activeArea.reactive = false; this.removeInternalKeybindings(); @@ -357,7 +354,7 @@ const AreaManager = new Lang.Class({ this.activeArea.reactive = true; this.activeArea.initPointerCursor(); if (source && source == global.display) - this.showOsd(null, 'input-touchpad-symbolic', _("Keyboard and pointer grabbed"), null, null, false); + this.showOsd(null, Files.Icons.GRAB, _("Keyboard and pointer grabbed"), null, null, false); } return true; @@ -368,7 +365,7 @@ const AreaManager = new Lang.Class({ let activeIndex = this.areas.indexOf(this.activeArea); let save = activeIndex == Main.layoutManager.primaryIndex && Me.settings.get_boolean('persistent-drawing'); - this.showOsd(null, this.leaveGicon, _("Leaving drawing mode")); + this.showOsd(null, Files.Icons.LEAVE, _("Leaving drawing mode")); this.activeArea.leaveDrawingMode(save); if (this.hiddenList) this.togglePanelAndDockOpacity(); @@ -392,7 +389,7 @@ const AreaManager = new Lang.Class({ this.osdDisabled = Me.settings.get_boolean('osd-disabled'); // Translators: %s is a key label let label = "" + _("Press %s for help").format(this.activeArea.helper.helpKeyLabel) + "\n\n" + _("Entering drawing mode"); - this.showOsd(null, this.enterGicon, label, null, null, true); + this.showOsd(null, Files.Icons.ENTER, label, null, null, true); } if (this.indicator) @@ -426,10 +423,8 @@ const AreaManager = new Lang.Class({ if (level && GS_VERSION > '3.33.0') level = level / 100; - if (icon && typeof icon == 'string') - icon = new Gio.ThemedIcon({ name: icon }); - else if (!icon) - icon = this.enterGicon; + if (!icon) + icon = Files.Icons.ENTER; let osdWindow = Main.osdWindowManager._osdWindows[activeIndex]; @@ -497,7 +492,6 @@ const AreaManager = new Lang.Class({ area.disconnect(area.leaveDrawingHandler); area.disconnect(area.updateActionModeHandler); area.disconnect(area.showOsdHandler); - area.disconnect(area.showOsdGiconHandler); let container = area.get_parent(); container.get_parent().remove_actor(container); container.destroy(); diff --git a/files.js b/files.js index b345c16..867d1ff 100644 --- a/files.js +++ b/files.js @@ -1,5 +1,5 @@ /* jslint esversion: 6 */ -/* exported Image, Images, Json, getJsons, getDateString */ +/* exported Icons, Image, Images, Json, getJsons, getDateString */ /* * Copyright 2019 Abakkk @@ -35,6 +35,29 @@ 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'])); const Clipboard = St.Clipboard.get_default(); const CLIPBOARD_TYPE = St.ClipboardType.CLIPBOARD; +const ICON_DIR = Me.dir.get_child('data').get_child('icons'); +const ICON_NAMES = ['color', 'dashed-line', 'fillrule-evenodd', 'fillrule-nonzero', 'fill', 'full-line', 'linecap', 'linejoin', 'palette', 'smooth', 'stroke']; + +var Icons = { + get ENTER() { return this._enter || void (this._enter = new Gio.ThemedIcon({ name: 'applications-graphics-symbolic' })) || this._enter; }, + get GRAB() { return this._grab || void (this._grab = new Gio.ThemedIcon({ name: 'input-touchpad-symbolic' })) || this._grab; }, + get LEAVE() { return this._leave || void (this._leave = new Gio.ThemedIcon({ name: 'application-exit-symbolic' })) || this._leave; }, + get OPEN() { return this._open || void (this._open = new Gio.ThemedIcon({ name: 'document-open-symbolic' })) || this._open; }, + get SAVE() { return this._save || void (this._save = new Gio.ThemedIcon({ name: 'document-save-symbolic' })) || this._save; }, + get UNGRAB() { return this._ungrab || void (this._ungrab = new Gio.ThemedIcon({ name: 'touchpad-disabled-symbolic' })) || this._ungrab; } +}; + +ICON_NAMES.forEach(name => { + Object.defineProperty(Icons, name.toUpperCase().replace(/-/gi, '_'), { + get: function() { + if (!this[`_${name}`]) { + let file = Gio.File.new_for_path(ICON_DIR.get_child(`${name}-symbolic.svg`).get_path()); + this[`_${name}`] = file.query_exists(null) ? new Gio.FileIcon({ file }) : new Gio.ThemedIcon({ name: 'error-symbolic' }); + } + return this[`_${name}`]; + } + }); +}); // wrapper around an image file var Image = new Lang.Class({ diff --git a/menu.js b/menu.js index 529667f..5d28811 100644 --- a/menu.js +++ b/menu.js @@ -42,20 +42,6 @@ const _ = imports.gettext.domain(Me.metadata['gettext-domain']).gettext; const pgettext = imports.gettext.domain(Me.metadata['gettext-domain']).pgettext; 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(); -const LINEJOIN_ICON_PATH = ICON_DIR.get_child('linejoin-symbolic.svg').get_path(); -const LINECAP_ICON_PATH = ICON_DIR.get_child('linecap-symbolic.svg').get_path(); -const FILLRULE_NONZERO_ICON_PATH = ICON_DIR.get_child('fillrule-nonzero-symbolic.svg').get_path(); -const FILLRULE_EVENODD_ICON_PATH = ICON_DIR.get_child('fillrule-evenodd-symbolic.svg').get_path(); -const DASHED_LINE_ICON_PATH = ICON_DIR.get_child('dashed-line-symbolic.svg').get_path(); -const FULL_LINE_ICON_PATH = ICON_DIR.get_child('full-line-symbolic.svg').get_path(); - // 150 labels with font-family style take ~15Mo const FONT_FAMILY_STYLE = true; // use 'login-dialog-message-warning' class in order to get GS theme warning color (default: #f57900) @@ -185,18 +171,6 @@ var DrawingMenu = new Lang.Class({ this.saveDrawingSubMenu.close(); 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) }); - this.fillIcon = new Gio.FileIcon({ file: Gio.File.new_for_path(FILL_ICON_PATH) }); - this.fillRuleNonzeroIcon = new Gio.FileIcon({ file: Gio.File.new_for_path(FILLRULE_NONZERO_ICON_PATH) }); - this.fillRuleEvenoddIcon = new Gio.FileIcon({ file: Gio.File.new_for_path(FILLRULE_EVENODD_ICON_PATH) }); - this.linejoinIcon = new Gio.FileIcon({ file: Gio.File.new_for_path(LINEJOIN_ICON_PATH) }); - this.linecapIcon = new Gio.FileIcon({ file: Gio.File.new_for_path(LINECAP_ICON_PATH) }); - this.fullLineIcon = new Gio.FileIcon({ file: Gio.File.new_for_path(FULL_LINE_ICON_PATH) }); - this.dashedLineIcon = new Gio.FileIcon({ file: Gio.File.new_for_path(DASHED_LINE_ICON_PATH) }); }, disable: function() { @@ -253,25 +227,25 @@ var DrawingMenu = new Lang.Class({ getActor(groupItem).add_child(this._createActionButton(_("Undo"), this.area.undo.bind(this.area), 'edit-undo-symbolic')); getActor(groupItem).add_child(this._createActionButton(_("Redo"), this.area.redo.bind(this.area), 'edit-redo-symbolic')); getActor(groupItem).add_child(this._createActionButton(_("Erase"), this.area.deleteLastElement.bind(this.area), 'edit-clear-all-symbolic')); - getActor(groupItem).add_child(this._createActionButton(_("Smooth"), this.area.smoothLastElement.bind(this.area), this.smoothIcon)); + getActor(groupItem).add_child(this._createActionButton(_("Smooth"), this.area.smoothLastElement.bind(this.area), Files.Icons.SMOOTH)); this.menu.addMenuItem(groupItem); this._addSeparator(this.menu, true); this._addSubMenuItem(this.menu, 'document-edit-symbolic', DisplayStrings.Tool, 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, DisplayStrings.getFill(true), this.strokeIcon, this.fillIcon, this.area, 'fill', this._updateSectionVisibility.bind(this)); + this.fillItem = this._addSwitchItem(this.menu, DisplayStrings.getFill(true), Files.Icons.STROKE, Files.Icons.FILL, this.area, 'fill', this._updateSectionVisibility.bind(this)); this.fillSection = new PopupMenu.PopupMenuSection(); this.fillSection.itemActivated = () => {}; - this.fillRuleItem = this._addSwitchItem(this.fillSection, DisplayStrings.FillRule[1], this.fillRuleNonzeroIcon, this.fillRuleEvenoddIcon, this.area, 'currentEvenodd'); + this.fillRuleItem = this._addSwitchItem(this.fillSection, DisplayStrings.FillRule[1], Files.Icons.FILLRULE_NONZERO, Files.Icons.FILLRULE_EVENODD, this.area, 'currentEvenodd'); this.menu.addMenuItem(this.fillSection); this._addSeparator(this.menu); let lineSection = new PopupMenu.PopupMenuSection(); this._addSliderItem(lineSection, this.area, 'currentLineWidth'); - this._addSubMenuItem(lineSection, this.linejoinIcon, DisplayStrings.LineJoin, this.area, 'currentLineJoin'); - this._addSubMenuItem(lineSection, this.linecapIcon, DisplayStrings.LineCap, this.area, 'currentLineCap'); - this._addSwitchItem(lineSection, DisplayStrings.getDashedLine(true), this.fullLineIcon, this.dashedLineIcon, this.area, 'dashedLine'); + this._addSubMenuItem(lineSection, Files.Icons.LINEJOIN, DisplayStrings.LineJoin, this.area, 'currentLineJoin'); + this._addSubMenuItem(lineSection, Files.Icons.LINECAP, DisplayStrings.LineCap, this.area, 'currentLineCap'); + this._addSwitchItem(lineSection, DisplayStrings.getDashedLine(true), Files.Icons.FULL_LINE, Files.Icons.DASHED_LINE, this.area, 'dashedLine'); this._addSeparator(lineSection); this.menu.addMenuItem(lineSection); lineSection.itemActivated = () => {}; @@ -473,7 +447,7 @@ var DrawingMenu = new Lang.Class({ _addPaletteSubMenuItem: function(menu) { let text = _(this.area.currentPalette[0] || "Palette"); let item = new PopupMenu.PopupSubMenuMenuItem(text, true); - item.icon.set_gicon(this.paletteIcon); + item.icon.set_gicon(Files.Icons.PALETTE); item.menu.itemActivated = () => { item.menu.close(); @@ -501,7 +475,7 @@ var DrawingMenu = new Lang.Class({ _addColorSubMenuItem: function(menu) { let item = new PopupMenu.PopupSubMenuMenuItem(_("Color"), true); this.colorSubMenu = item.menu; - item.icon.set_gicon(this.colorIcon); + item.icon.set_gicon(Files.Icons.COLOR); item.icon.set_style(`color:${this.area.currentColor.to_string().slice(0, 7)};`); item.menu.itemActivated = () => { From a06d3186460f8df7fa260e19b1161bada7831199 Mon Sep 17 00:00:00 2001 From: abakkk Date: Thu, 10 Sep 2020 15:55:19 +0200 Subject: [PATCH 17/35] rework of shortcuts.js --- helper.js | 12 +++--- prefs.js | 12 +++--- shortcuts.js | 116 +++++++++++++++++++++++++-------------------------- 3 files changed, 70 insertions(+), 70 deletions(-) diff --git a/helper.js b/helper.js index 70d93d7..91d77fe 100644 --- a/helper.js +++ b/helper.js @@ -31,7 +31,7 @@ const Tweener = imports.ui.tweener; const Me = ExtensionUtils.getCurrentExtension(); const Convenience = ExtensionUtils.getSettings ? ExtensionUtils : Me.imports.convenience; -const Shortcuts = Me.imports.shortcuts.Shortcuts; +const Shortcuts = Me.imports.shortcuts; const _ = imports.gettext.domain(Me.metadata['gettext-domain']).gettext; const GS_VERSION = Config.PACKAGE_VERSION; @@ -106,17 +106,17 @@ var DrawingHelper = new Lang.Class({ this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-helper-separator' })); this.vbox.add_child(new St.Label({ text: _("Internal") })); - Shortcuts.OTHERS.forEach((pairs, index) => { + Shortcuts.OTHERS.forEach((object, index) => { if (index) this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-helper-separator' })); - pairs.forEach(pair => { + for (let key in object) { let hbox = new St.BoxLayout({ vertical: false }); - hbox.add_child(new St.Label({ text: pair[0] })); - hbox.add_child(new St.Label({ text: pair[1], x_expand: true })); + hbox.add_child(new St.Label({ text: key })); + hbox.add_child(new St.Label({ text: object[key], x_expand: true })); hbox.get_children()[0].get_clutter_text().set_use_markup(true); this.vbox.add_child(hbox); - }); + } }); this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-helper-separator' })); diff --git a/prefs.js b/prefs.js index dea0c8f..a8d4c30 100644 --- a/prefs.js +++ b/prefs.js @@ -30,7 +30,7 @@ const Gtk = imports.gi.Gtk; const ExtensionUtils = imports.misc.extensionUtils; const Me = ExtensionUtils.getCurrentExtension(); const Convenience = ExtensionUtils.getSettings && ExtensionUtils.initTranslations ? ExtensionUtils : Me.imports.convenience; -const Shortcuts = Me.imports.shortcuts.Shortcuts; +const Shortcuts = Me.imports.shortcuts; const gettext = imports.gettext.domain(Me.metadata['gettext-domain']).gettext; const _ = function(string) { if (!string) @@ -421,19 +421,19 @@ const PrefsPage = new GObject.Class({ listBox.get_style_context().add_class('background'); internalFrame.add(listBox); - Shortcuts.OTHERS.forEach((pairs, index) => { + Shortcuts.OTHERS.forEach((object, index) => { if (index) listBox.add(new Gtk.Box(ROWBOX_MARGIN_PARAMS)); - pairs.forEach(pair => { + for (let key in object) { let otherBox = new Gtk.Box({ margin_left: MARGIN, margin_right: MARGIN }); - let otherLabel = new Gtk.Label({ label: pair[0], use_markup: true }); + let otherLabel = new Gtk.Label({ label: key, use_markup: true }); otherLabel.set_halign(1); - let otherLabel2 = new Gtk.Label({ label: pair[1] }); + let otherLabel2 = new Gtk.Label({ label: object[key] }); otherBox.pack_start(otherLabel, true, true, 4); otherBox.pack_start(otherLabel2, false, false, 4); listBox.add(otherBox); - }); + } }); listBox.add(new Gtk.Box(ROWBOX_MARGIN_PARAMS)); diff --git a/shortcuts.js b/shortcuts.js index 6e9a07c..f99b448 100644 --- a/shortcuts.js +++ b/shortcuts.js @@ -1,5 +1,5 @@ /* jslint esversion: 6 */ -/* exported Shortcuts */ +/* exported GLOBAL_KEYBINDINGS, INTERNAL_KEYBINDINGS, OTHERS */ /* * Copyright 2019 Abakkk @@ -36,67 +36,67 @@ const getKeyLabel = function(accel) { return Gtk.accelerator_get_label(keyval, mods); }; -// It is used by helper and prefs. -var Shortcuts = { - - // The setting keys of the "org.gnome.shell.extensions.draw-on-your-screen" schema. - GLOBAL_KEYBINDINGS: [ - ['toggle-drawing', 'toggle-modal', 'erase-drawings'] - ], - - // The setting keys of the "org.gnome.shell.extensions.draw-on-your-screen.internal-shortcuts" schema. - INTERNAL_KEYBINDINGS: [ - ['undo', 'redo', 'delete-last-element', 'smooth-last-element'], - ['select-none-shape', 'select-line-shape', 'select-ellipse-shape', 'select-rectangle-shape', 'select-polygon-shape', 'select-polyline-shape', - 'select-text-shape', 'select-image-shape', 'select-move-tool', 'select-resize-tool', 'select-mirror-tool'], - ['switch-fill', 'switch-fill-rule', 'switch-color-palette', 'switch-color-palette-reverse'], - ['increment-line-width', 'increment-line-width-more', 'decrement-line-width', 'decrement-line-width-more', - 'switch-linejoin', 'switch-linecap', 'switch-dash'], - ['switch-font-family', 'switch-font-family-reverse', 'switch-font-weight', 'switch-font-style', 'switch-text-alignment', 'switch-image-file'], - ['toggle-panel-and-dock-visibility', 'toggle-background', 'toggle-grid', 'toggle-square-area'], - ['open-next-json', 'open-previous-json', 'save-as-json', 'save-as-svg', 'open-preferences', 'toggle-help'] - ], +// The setting keys of the "org.gnome.shell.extensions.draw-on-your-screen" schema. +var GLOBAL_KEYBINDINGS = [ + ['toggle-drawing', 'toggle-modal', 'erase-drawings'], +]; - // Use functions to get the translations "at runtime". - _otherFunctions: [[ - () => [_("Draw"), _("Left click")], - () => [_("Menu"), _("Right click")], - () => [internalShortcutsSchema.get_key('switch-fill').get_summary(), _("Center click")], - () => [_("Increment/decrement line width"), _("Scroll")], - // Translators: %s are key labels (Ctrl+F1 and Ctrl+F9) - () => [_("Select color"), _("%s … %s").format(getKeyLabel('1'), getKeyLabel('9'))], - // Translators: %s is a key label - () => [_("Ignore pointer movement"), _("%s held").format(getKeyLabel('space'))], - () => [_("Leave"), getKeyLabel('Escape')], - ], [ - () => [_("Select eraser (while starting drawing)"), getKeyLabel('')], - () => [_("Duplicate (while starting handling)"), getKeyLabel('')], - () => [_("Rotate rectangle, polygon, polyline"), getKeyLabel('')], - () => [_("Extend circle to ellipse"), getKeyLabel('')], - () => [_("Curve line"), getKeyLabel('')], - () => [_("Smooth free drawing outline"), getKeyLabel('')], - () => [_("Rotate (while moving)"), getKeyLabel('')], - () => [_("Stretch (while resizing)"), getKeyLabel('')], - () => [_("Inverse (while mirroring)"), getKeyLabel('')], - ]], - - get OTHERS() { - if (!this._others) { - this._others = []; - this._otherFunctions.forEach(getPairFunctions => { - let pairs = []; - getPairFunctions.forEach(getPairFunction => pairs.push(getPairFunction())); - this._others.push(pairs); - }); - } - return this._others; - } -}; +// The setting keys of the "org.gnome.shell.extensions.draw-on-your-screen.internal-shortcuts" schema. +var INTERNAL_KEYBINDINGS = [ + ['undo', 'redo', 'delete-last-element', 'smooth-last-element'], + ['select-none-shape', 'select-line-shape', 'select-ellipse-shape', 'select-rectangle-shape', 'select-polygon-shape', 'select-polyline-shape', + 'select-text-shape', 'select-image-shape', 'select-move-tool', 'select-resize-tool', 'select-mirror-tool'], + ['switch-fill', 'switch-fill-rule', 'switch-color-palette', 'switch-color-palette-reverse'], + ['increment-line-width', 'increment-line-width-more', 'decrement-line-width', 'decrement-line-width-more', + 'switch-linejoin', 'switch-linecap', 'switch-dash'], + ['switch-font-family', 'switch-font-family-reverse', 'switch-font-weight', 'switch-font-style', 'switch-text-alignment', 'switch-image-file'], + ['toggle-panel-and-dock-visibility', 'toggle-background', 'toggle-grid', 'toggle-square-area'], + ['open-next-json', 'open-previous-json', 'save-as-json', 'save-as-svg', 'open-preferences', 'toggle-help'], +]; -if (GS_VERSION < '3.36') +if (GS_VERSION < '3.36') { // Remove 'open-preferences' keybinding. - Shortcuts.INTERNAL_KEYBINDINGS.forEach(settingKeys => { + INTERNAL_KEYBINDINGS.forEach(settingKeys => { let index = settingKeys.indexOf('open-preferences'); if (index != -1) settingKeys.splice(index, 1); }); +} + +const getOthers = function() { + return [ + { + [_("Draw")]: _("Left click"), + [_("Menu")]: _("Right click"), + [internalShortcutsSchema.get_key('switch-fill').get_summary()]: _("Center click"), + [_("Increment/decrement line width")]: _("Scroll"), + // Translators: %s are key labels (Ctrl+F1 and Ctrl+F9) + [_("Select color")]: _("%s … %s").format(getKeyLabel('1'), getKeyLabel('9')), + // Translators: %s is a key label + [_("Ignore pointer movement")]: _("%s held").format(getKeyLabel('space')), + [_("Leave")]: getKeyLabel('Escape'), + }, { + [_("Select eraser (while starting drawing)")]: getKeyLabel(''), + [_("Duplicate (while starting handling)")]: getKeyLabel(''), + [_("Rotate rectangle, polygon, polyline")]: getKeyLabel(''), + [_("Extend circle to ellipse")]: getKeyLabel(''), + [_("Curve line")]: getKeyLabel(''), + [_("Smooth free drawing outline")]: getKeyLabel(''), + [_("Rotate (while moving)")]: getKeyLabel(''), + [_("Stretch (while resizing)")]: getKeyLabel(''), + [_("Inverse (while mirroring)")]: getKeyLabel(''), + }, + ]; +}; + +let _OTHERS; +// Equivalent to "var OTHERS = [[ ... ]]", but as a getter so the translations are got after the initTranslations call. +// 'this' is the module. +Object.defineProperty(this, 'OTHERS', { + get: function() { + if (!_OTHERS) + _OTHERS = getOthers(); + return _OTHERS; + } +}); + From 771bad2d59f9f3ad68f50306ad3ede219cc3ba96 Mon Sep 17 00:00:00 2001 From: abakkk Date: Fri, 11 Sep 2020 04:06:21 +0200 Subject: [PATCH 18/35] improve images * Let the user choose the directory. * Rework of Files.Images. * area.currentImage is now an ... image, not an index. * Add 'switch-image-file-reverse' keybinding. * Add image gicons (from thumbnails) in the submenu. * Images are reset on drawing mode left or on images added from the clipboard. --- README.md | 2 +- area.js | 43 ++++--- extension.js | 3 +- files.js | 117 ++++++++++++++---- locale/draw-on-your-screen.pot | 16 ++- menu.js | 80 ++++++------ prefs.js | 43 ++++++- schemas/gschemas.compiled | Bin 7216 -> 7392 bytes ...extensions.draw-on-your-screen.gschema.xml | 15 ++- shortcuts.js | 3 +- 10 files changed, 225 insertions(+), 97 deletions(-) diff --git a/README.md b/README.md index 7ca6ea9..3877926 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Then save your beautiful work by taking a screenshot. * Insertable images: - Add your images (jpeg, png, svg) to `~/.local/share/drawOnYourScreen/images/`. + You can insert images (jpeg, png, svg) in your drawings. By default images are sought in `~/.local/share/drawOnYourScreen/images/` but the location is configurable in the preferences. Another way is to copy-past the images from Nautilus or any clipboard source by using the usual `Ctrl + V` shortcut inside the drawing mode. * Eraser and SVG: diff --git a/area.js b/area.js index 56abb52..1978efb 100644 --- a/area.js +++ b/area.js @@ -86,7 +86,7 @@ var DrawingArea = new Lang.Class({ this.undoneElements = []; this.currentElement = null; this.currentTool = Shapes.NONE; - this.currentImage = 0; + this.currentImage = null; this.currentTextRightAligned = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL; let fontName = St.Settings && St.Settings.get().font_name || Convenience.getSettings('org.gnome.desktop.interface').get_string('font-name'); this.currentFont = Pango.FontDescription.from_string(fontName); @@ -150,6 +150,17 @@ var DrawingArea = new Lang.Class({ this.colors.push(Clutter.Color.get_static(Clutter.StaticColor.WHITE)); }, + get currentImage() { + if (!this._currentImage) + this._currentImage = Files.Images.getNext(this._currentImage); + + return this._currentImage; + }, + + set currentImage(image) { + this._currentImage = image; + }, + get currentFontFamily() { return this.currentFont.get_family(); }, @@ -188,13 +199,6 @@ var DrawingArea = new Lang.Class({ this.currentFillRule = evenodd ? Cairo.FillRule.EVEN_ODD : Cairo.FillRule.WINDING; }, - getImages() { - let images = Files.Images.getImages(); - if (!images[this.currentImage]) - this.currentImage = Math.max(images.length - 1, 0); - return images; - }, - get fontFamilies() { if (!this._fontFamilies) { let otherFontFamilies = Elements.getAllFontFamilies().filter(family => { @@ -601,14 +605,11 @@ var DrawingArea = new Lang.Class({ 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], + image: this.currentImage, operator: this.currentOperator, points: [] }); @@ -988,21 +989,18 @@ var DrawingArea = new Lang.Class({ this.emit('show-osd', null, DisplayStrings.getTextAlignment(this.currentTextRightAligned), "", -1, false); }, - switchImageFile: 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', images[this.currentImage].gicon, images[this.currentImage].toString(), "", -1, false); + switchImageFile: function(reverse) { + this.currentImage = Files.Images[reverse ? 'getPrevious' : 'getNext'](this.currentImage); + if (this.currentImage) + this.emit('show-osd', this.currentImage.gicon, this.currentImage.toString(), "", -1, false); }, pasteImageFiles: function() { - Files.Images.addImagesFromClipboard((images, index) => { - this.currentImage = index; + Files.Images.addImagesFromClipboard(lastImage => { + this.currentImage = lastImage; this.currentTool = Shapes.IMAGE; this.updatePointerCursor(); - this.emit('show-osd', images[this.currentImage].gicon, images[this.currentImage].toString(), "", -1, false); + this.emit('show-osd', this.currentImage.gicon, this.currentImage.toString(), "", -1, false); }); }, @@ -1088,6 +1086,7 @@ var DrawingArea = new Lang.Class({ this._redisplay(); this.closeMenu(); this.get_parent().set_background_color(null); + Files.Images.reset(); if (save) this.savePersistent(); }, diff --git a/extension.js b/extension.js index ec5a10e..7e60fb4 100644 --- a/extension.js +++ b/extension.js @@ -183,7 +183,8 @@ const AreaManager = new Lang.Class({ 'switch-fill-rule': this.activeArea.switchFillRule.bind(this.activeArea), 'switch-dash' : this.activeArea.switchDash.bind(this.activeArea), 'switch-fill' : this.activeArea.switchFill.bind(this.activeArea), - 'switch-image-file' : this.activeArea.switchImageFile.bind(this.activeArea), + 'switch-image-file' : this.activeArea.switchImageFile.bind(this.activeArea, false), + 'switch-image-file-reverse' : this.activeArea.switchImageFile.bind(this.activeArea, true), 'select-none-shape': () => this.activeArea.selectTool(Area.Tools.NONE), 'select-line-shape': () => this.activeArea.selectTool(Area.Tools.LINE), 'select-ellipse-shape': () => this.activeArea.selectTool(Area.Tools.ELLIPSE), diff --git a/files.js b/files.js index 867d1ff..492c506 100644 --- a/files.js +++ b/files.js @@ -31,8 +31,8 @@ const St = imports.gi.St; 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'])); +const EXAMPLE_IMAGE_DIRECTORY = Me.dir.get_child('data').get_child('images'); +const DEFAULT_USER_IMAGE_LOCATION = GLib.build_filenamev([GLib.get_user_data_dir(), Me.metadata['data-dir'], 'images']); const Clipboard = St.Clipboard.get_default(); const CLIPBOARD_TYPE = St.ClipboardType.CLIPBOARD; const ICON_DIR = Me.dir.get_child('data').get_child('icons'); @@ -66,6 +66,11 @@ var Image = new Lang.Class({ _init: function(params) { for (let key in params) this[key] = params[key]; + + if (this.info) { + this.displayName = this.info.get_display_name(); + this.contentType = this.info.get_content_type(); + } }, toString: function() { @@ -81,13 +86,31 @@ var Image = new Lang.Class({ }; }, - // only called from menu so file exists + get thumbnailFile() { + if (!this._thumbnailFile) { + if (this.info.has_attribute('thumbnail::path') && this.info.get_attribute_boolean('thumbnail::is-valid')) { + let thumbnailPath = this.info.get_attribute_as_string('thumbnail::path'); + this._thumbnailFile = Gio.File.new_for_path(thumbnailPath); + } + } + return this._thumbnailFile || null; + }, + + // only called from menu or area so this.file exists get gicon() { if (!this._gicon) - this._gicon = new Gio.FileIcon({ file: this.file }); + this._gicon = new Gio.FileIcon({ file: this.thumbnailFile || this.file }); return this._gicon; }, + // use only thumbnails in menu (memory) + get thumbnailGicon() { + if (this.contentType != 'image/svg+xml' && !this.thumbnailFile) + return null; + + return this.gicon; + }, + get bytes() { if (!this._bytes) { if (this.file) @@ -95,7 +118,7 @@ var Image = new Lang.Class({ // load_bytes available in GLib 2.56+ this._bytes = this.file.load_bytes(null)[0]; } catch(e) { - let [success_, contents] = this.file.load_contents(null); + let [, contents] = this.file.load_contents(null); if (contents instanceof Uint8Array) this._bytes = ByteArray.toGBytes(contents); else @@ -151,34 +174,73 @@ var Image = new Lang.Class({ } }); +// Get images with getPrevious, getNext, or by iterating over it. var Images = { - clipboardImages: [], + _images: [], + _clipboardImages: [], + _upToDate: false, - getImages: function() { - let images = []; + _clipboardImagesContains: function(file) { + return this._clipboardImages.some(image => image.file.equal(file)); + }, + + _getImages: function() { + if (this._upToDate) + return this._images; - [EXAMPLE_IMAGES, USER_IMAGES].forEach(directory => { + let images = []; + let userLocation = Me.drawingSettings.get_string('image-location') || DEFAULT_USER_IMAGE_LOCATION; + let userDirectory = Gio.File.new_for_commandline_arg(userLocation); + + [EXAMPLE_IMAGE_DIRECTORY, userDirectory].forEach(directory => { let enumerator; try { - enumerator = directory.enumerate_children('standard::display-name,standard::content-type', Gio.FileQueryInfoFlags.NONE, null); + enumerator = directory.enumerate_children('standard::,thumbnail::', 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); + let info = enumerator.next_file(null); + while (info) { + let file = enumerator.get_child(info); + + if (info.get_content_type().indexOf('image') == 0 && !this._clipboardImagesContains(file)) { + let index = this._images.findIndex(image => image.file.equal(file)); + if (index != -1) + images.push(this._images[index]); + else + images.push(new Image({ file, info })); + } + + info = enumerator.next_file(null); } enumerator.close(null); }); - images.sort((a, b) => { - return a.displayName.localeCompare(b.displayName); - }); - - return images.concat(this.clipboardImages); + this._images = images.concat(this._clipboardImages) + .sort((a, b) => a.toString().localeCompare(b.toString())); + this._upToDate = true; + return this._images; + }, + + [Symbol.iterator]: function() { + return this._getImages()[Symbol.iterator](); + }, + + getNext: function(currentImage) { + let images = this._getImages(); + let index = currentImage ? images.findIndex(image => image.file.equal(currentImage.file)) : 0; + return images[index == images.length - 1 ? 0 : index + 1] || null; + }, + + getPrevious: function(currentImage) { + let images = this._getImages(); + let index = currentImage ? images.findIndex(image => image.file.equal(currentImage.file)) : 0; + return images[index <= 0 ? images.length - 1 : index - 1] || null; + }, + + reset: function() { + this._upToDate = false; }, addImagesFromClipboard: function(callback) { @@ -193,20 +255,21 @@ var Images = { let images = lines.filter(line => !!line) .map(line => Gio.File.new_for_commandline_arg(line)) .filter(file => file.query_exists(null)) - .map(file => [file, file.query_info('standard::display-name,standard::content-type', Gio.FileQueryInfoFlags.NONE, null)]) + .map(file => [file, file.query_info('standard::,thumbnail::', Gio.FileQueryInfoFlags.NONE, null)]) .filter(pair => pair[1].get_content_type().indexOf('image') == 0) - .map(pair => new Image({ file: pair[0], contentType: pair[1].get_content_type(), displayName: pair[1].get_display_name() })); + .map(pair => new Image({ file: pair[0], info: pair[1] })); // Prevent duplicated - images.filter(image => !this.clipboardImages.map(clipboardImage => clipboardImage.file).some(clipboardFile => clipboardFile.equal(image.file))) - .forEach(image => this.clipboardImages.push(image)); + images.filter(image => !this._clipboardImagesContains(image.file)) + .forEach(image => this._clipboardImages.push(image)); if (images.length) { + this.reset(); + let allImages = this._getImages(); let lastFile = images[images.length - 1].file; - let allImages = this.getImages(); let index = allImages.findIndex(image => image.file.equal(lastFile)); - callback(allImages, index); - } + callback(allImages[index]); + } }); } }; diff --git a/locale/draw-on-your-screen.pot b/locale/draw-on-your-screen.pot index 588f5f6..e4f93a3 100644 --- a/locale/draw-on-your-screen.pot +++ b/locale/draw-on-your-screen.pot @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: Draw On Your Screen\n" "Report-Msgid-Bugs-To: https://framagit.org/abakkk/DrawOnYourScreen/issues\n" -"POT-Creation-Date: 2020-09-09 08:40+0200\n" +"POT-Creation-Date: 2020-09-11 03:43+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -502,6 +502,12 @@ msgstr "" msgid "The line width in pixels" msgstr "" +msgid "Image location" +msgstr "" + +msgid "The location of the directory in which the image tool picks" +msgstr "" + msgid "Color palettes" msgstr "" @@ -544,6 +550,9 @@ msgstr "" msgid "Open previous drawing" msgstr "" +msgid "Paste images from the clipboard" +msgstr "" + msgid "Redo last brushstroke" msgstr "" @@ -640,7 +649,10 @@ msgstr "" msgid "Change font weight" msgstr "" -msgid "Change image file" +msgid "Change image" +msgstr "" + +msgid "Change image (reverse)" msgstr "" msgid "Change linecap" diff --git a/menu.js b/menu.js index 5d28811..12e8e5c 100644 --- a/menu.js +++ b/menu.js @@ -262,12 +262,7 @@ var DrawingMenu = new Lang.Class({ 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._addImageSubMenuItem(imageSection); this._addSeparator(imageSection); this.menu.addMenuItem(imageSection); imageSection.itemActivated = () => {}; @@ -398,34 +393,27 @@ var DrawingMenu = new Lang.Class({ }, _addSubMenuItem: function(menu, icon, obj, target, targetProperty, callback) { - 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)) item.icon.set_gicon(icon); else if (icon) item.icon.set_icon_name(icon); - item.menu.itemActivated = () => { - item.menu.close(); - }; + item.menu.itemActivated = item.menu.close; GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => { - for (let i in obj) { + Object.keys(obj).forEach(key => { let text; if (targetProperty == 'currentFontWeight') - text = `${obj[i]}`; + text = `${obj[key]}`; else if (targetProperty == 'currentFontStyle') - text = `${obj[i]}`; + text = `${obj[key]}`; else - text = String(obj[i]); + text = String(obj[key]); - let iCaptured = Number(i); let subItem = item.menu.addAction(text, () => { - item.label.set_text(String(obj[iCaptured])); - target[targetProperty] = iCaptured; - if (targetProperty == 'currentImage') - item.icon.set_gicon(obj[iCaptured].gicon); + item.label.set_text(String(obj[key])); + target[targetProperty] = Number(key); if (callback) callback(); }); @@ -434,13 +422,14 @@ var DrawingMenu = new Lang.Class({ getActor(subItem).connect('key-focus-in', updateSubMenuAdjustment); // change the display order of tools - if (obj == DisplayStrings.Tool && i == this.drawingTools.POLYGON) + if (obj == DisplayStrings.Tool && Number(key) == this.drawingTools.POLYGON) item.menu.moveMenuItem(subItem, 4); - else if (obj == DisplayStrings.Tool && i == this.drawingTools.POLYLINE) + else if (obj == DisplayStrings.Tool && Number(key) == this.drawingTools.POLYLINE) item.menu.moveMenuItem(subItem, 5); - } + }); return GLib.SOURCE_REMOVE; }); + menu.addMenuItem(item); }, @@ -449,9 +438,7 @@ var DrawingMenu = new Lang.Class({ let item = new PopupMenu.PopupSubMenuMenuItem(text, true); item.icon.set_gicon(Files.Icons.PALETTE); - item.menu.itemActivated = () => { - item.menu.close(); - }; + item.menu.itemActivated = item.menu.close; GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => { this.area.palettes.forEach(palette => { @@ -468,6 +455,7 @@ var DrawingMenu = new Lang.Class({ }); return GLib.SOURCE_REMOVE; }); + menu.addMenuItem(item); return item; }, @@ -478,9 +466,7 @@ var DrawingMenu = new Lang.Class({ item.icon.set_gicon(Files.Icons.COLOR); item.icon.set_style(`color:${this.area.currentColor.to_string().slice(0, 7)};`); - item.menu.itemActivated = () => { - item.menu.close(); - }; + item.menu.itemActivated = item.menu.close; this._populateColorSubMenu(); menu.addMenuItem(item); @@ -508,9 +494,7 @@ var DrawingMenu = new Lang.Class({ let item = new PopupMenu.PopupSubMenuMenuItem(DisplayStrings.getFontFamily(this.area.currentFontFamily), true); item.icon.set_icon_name(icon); - item.menu.itemActivated = () => { - item.menu.close(); - }; + item.menu.itemActivated = item.menu.close; item.menu.openOld = item.menu.open; item.menu.open = (animate) => { @@ -531,6 +515,30 @@ var DrawingMenu = new Lang.Class({ menu.addMenuItem(item); }, + _addImageSubMenuItem: function(menu, images) { + let item = new PopupMenu.PopupSubMenuMenuItem(this.area.currentImage.toString(), true); + item.icon.set_gicon(this.area.currentImage.gicon); + + item.menu.itemActivated = item.menu.close; + + item.menu.openOld = item.menu.open; + item.menu.open = (animate) => { + if (!item.menu.isOpen && item.menu.isEmpty()) { + [...Files.Images].forEach(image => { + let subItem = item.menu.addAction(image.toString(), () => { + item.label.set_text(image.toString()); + this.area.currentImage = image; + item.icon.set_gicon(image.gicon); + }, image.thumbnailGicon || undefined); + getActor(subItem).connect('key-focus-in', updateSubMenuAdjustment); + }); + } + item.menu.openOld(); + }; + + menu.addMenuItem(item); + }, + _addDrawingNameItem: function(menu) { this.drawingNameMenuItem = new PopupMenu.PopupMenuItem('', { reactive: false, activate: false }); this.drawingNameMenuItem.setSensitive(false); @@ -554,9 +562,7 @@ var DrawingMenu = new Lang.Class({ item.setSensitive(Boolean(Files.getJsons().length)); item.icon.set_icon_name('document-open-symbolic'); - item.menu.itemActivated = () => { - item.menu.close(); - }; + item.menu.itemActivated = item.menu.close; item.menu.openOld = item.menu.open; item.menu.open = (animate) => { @@ -609,9 +615,7 @@ var DrawingMenu = new Lang.Class({ this.saveDrawingSubMenu = item.menu; item.icon.set_icon_name('document-save-symbolic'); - item.menu.itemActivated = () => { - item.menu.close(); - }; + item.menu.itemActivated = item.menu.close; item.menu.openOld = item.menu.open; item.menu.open = (animate) => { diff --git a/prefs.js b/prefs.js index a8d4c30..d334e29 100644 --- a/prefs.js +++ b/prefs.js @@ -23,6 +23,7 @@ const Atk = imports.gi.Atk; const Gdk = imports.gi.Gdk; +const Gio = imports.gi.Gio; const GLib = imports.gi.GLib; const GObject = imports.gi.GObject; const Gtk = imports.gi.Gtk; @@ -268,6 +269,14 @@ const DrawingPage = new GObject.Class({ dashOffsetRow.addWidget(dashOffsetButton); toolsListBox.add(dashOffsetRow); + let imageLocationRow = new PrefRow({ label: this.schema.get_key('image-location').get_summary() }); + let imageLocationButton = new FileChooserButton({ action: Gtk.FileChooserAction.SELECT_FOLDER, + name: this.schema.get_key('image-location').get_summary(), + tooltip_text: this.schema.get_key('image-location').get_description() }); + this.settings.bind('image-location', imageLocationButton, 'location', 0); + imageLocationRow.addWidget(imageLocationButton); + toolsListBox.add(imageLocationRow); + let resetButton = new Gtk.Button({ label: _("Reset settings"), halign: Gtk.Align.CENTER }); resetButton.get_style_context().add_class('destructive-action'); resetButton.connect('clicked', () => this.schema.list_keys().forEach(key => this.settings.reset(key))); @@ -565,8 +574,7 @@ const ColorStringButton = new GObject.Class({ Extends: Gtk.ColorButton, Properties: { 'color-string': GObject.ParamSpec.string('color-string', 'colorString', 'A string that describes the color', - GObject.ParamFlags.READWRITE, - 'black') + GObject.ParamFlags.READWRITE, 'black') }, get color_string() { @@ -593,6 +601,37 @@ const ColorStringButton = new GObject.Class({ } }); +const FileChooserButton = new GObject.Class({ + Name: 'DrawOnYourScreenFileChooserButton', + GTypeName: 'DrawOnYourScreenFileChooserButton', + Extends: Gtk.FileChooserButton, + Properties: { + 'location': GObject.ParamSpec.string('location', 'location', 'location', + GObject.ParamFlags.READWRITE, '') + }, + + get location() { + return this.get_file().get_path(); + }, + + set location(location) { + if (!location) { + this.unselect_all(); + if (this.get_file()) + this.set_file(Gio.File.new_for_path('aFileThatDoesNotExist')); + return; + } + + let file = Gio.File.new_for_commandline_arg(location); + if (file.query_exists(null)) + this.set_file(file); + }, + + vfunc_file_set: function(args) { + this.notify('location'); + } +}); + // 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', diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled index 0dcf5fba49ed9dbd8e6ce1ab30bc9e3d255b7906..5873a004f7d1fe0519ee087c1c5a4b82969803af 100644 GIT binary patch literal 7392 zcmb7J3yc-z6&_F&5n*{LPrD-OUA?p1xv#yK@K^+8p`vTHK5Bi<-aET@*x8xu%-mfr z3dO`&j3p(esZb?iO)af8qEut8RcxAuHnG8IBME7x>XR=*e=dyvev+a*_u6m%LHS1)D#~ie(^D0tG*eL= zcd&ENc7}~kuVz?Qr?J^LY|nITue0jvqpD-8O{d|iUd1&Gn{6p6m=HhOBj^G_|Id?{ z3_1l6y7S-viv6MA)07dV4G&9zpS|`KS;5bQyo84pK-f3(>{~Zz6_~zdnMM(L>Td?! z3OxVzvF9l#KMV3*pzi@~_5)NA{8Y%t@bDpUXzR8M89VZmAU_UzIXZAz-=xD}1y4Uq zklg@G7&+QUIeFT-9kc=Trwri_dHS;hbSI#^@w*e$CqEhT-Jl#N-x(aV43%*;?LjEu zw|uqbuUy{Os2lFeDx#Cpy$;i^nibu5T(xR?dcS2$$CqQxapl+(n7YbE zz%+p0g!tD_XAe-u`Of@33i?;zvw8o1f^zcHAwLef026ie&(6z~lczibS^!>L@!Tlo zB^0zCWl=rxp+r=889TY-6hc*>%j{DqM306hqV>kxUaL%#y$`iVpvG*rvM9K}M( zcl@QijzQO~s+MUR>Zn-_X8_-gt#V25`|%$Be!VJqTGFkgs;OqGTJ7lQsOnx#)m>L_ zs(QnB0*wjG(|)}&H0U}FyQ)?k%b~5yvj+dg&B_<+@VO9r_ce6afIUN3J#z~*gC7!$ z-*@wAJCJIi{YC@ri&=ZN^EIAAUR}2g-#3C8(HlG{J&xaN+C$2krfw@u>@d!#a+9mu zgNBP`ZB0#geb;DshO$<7hi)|;m{4x3nZBWjo?L68>&oPdW?$NoU$*MH$?I;sY2$V6 zJ?q!CTjpR5tC`{s_NTN$F0GYw>12n2aPWYStO9|*Gfav;cbNkO52PoSa6PqO)9 zy4;m6g^yXh%azjEY$(X!gDx$t<#VxxEUW;sQLPMfrL>lX#*D?ewSCpb!;jBA&1K~E?^SKWBG z{oS22Vn3_M8Q~>DrD+&)O|}E4H1tu+%4c?72*UX0G7Ok>QbR0YAs;?w%W1T$6+)+T zh*myb3|}*HWxOv*A9KYtVx7lWAeJjP-eqllbb70gGEK9^bfyePO41V2ODi$}VeHVb z#_&WfmC*IbOT2+X7-+aJ#zv-R89w8s9AB+~&hvFant~PD5f0wD>Hddj+@?&KaB#wR zCZ3wO?;PxrDG%q4E|%NZEpXVI_o|M@<-Vnqv}SpVX66^l$o z?7P?k#5%?^kXX#(bu8A7tnjSF{hliINt68&`#Sey?!DZHx%YBk z=041=LHGd5eVTq@dp+B8zSW!}4{EHvkpbtD_V7nAxdj$QWA76*?ygf@8X;_5kOC`PmdYQzPpdG+9KpN--GC&R}0Q>HJ zW#9@>)*{@idqH*Jy$}1gP)?qE`)1HbfX7aK@G|A(xmWK7Jpicv4H|Wj4&=Qcj+=!4A+pzzZAqK0rD7b0Oac`YLc|m--sz!1$;Yd1W(mU8lp&o0nsf#dtFQ* z?vZJ~rJOwdZ$olj2Hc){^M{m^XS*fP^+0%LB+oNrFX)ee1@oQ~@gy(e3Hl;%%YC0- zNju~j&%>Z&K->DsUr)=E7+~Fe&nlr0UgRMr{UTtEv`?P)GoZb|-WLKt$XWDbF3sP3&J{JcDnio?!`q56(v1!}S0aHyw4LHAT|WU$4~^1hlm;IH)1 zI?Ywlu8(3z_k0!XFfJ8@#kE4NoFB9~YWkI$I^f{OVL%@?t)}W4Be;by;&!Fo0cqC@ zK4Gy`(NT^^{TK@U3py;SsYHh(Jxl7zOMt}TLHHNx*`Ynz-%Xx4+C=X?`5xs6ORh*R z{oNA!8@N+eY5$wO_w+UTeOIseNF_0VX9Tll zdbv$HW zO_{YgXp=Cs=C?XQ|L*5gKWH*)Io@hMhT0cLdgX6d>yB>HwKNENz zq)*^gBAsJlQMt0p$Z`g7C+8GN_q-Wrs z!@?3Rk}I$|Y`QKkPsQpN=~Y5|VY|E(iC4%-Z?n{M>V~b_?6p`iqW6w`Z`x(b=W^gG;A(*NgbE;gl`N103IOX19&K48VcU#qGaNrfZH8ln!ditj z3AS*ocR}65dWbd9bYLpL`mPumwr-9-KC2APfI4OWN73(k@>6G!(BC-6( z@sqKZX(HF3AU8#**(v;@v4LVXe#(aNmU)5yyTK-!)W2RsKN6EdOyF=eN!az}c*t{u zXdA&ywwsHea$&nkb;c*DpO2sNp}v?-b=Mfcy`Nn%yhy*|3=iwA^H=!5!92}wA+}ox z?Mgpzv1r!uzXnkUBm2fU{X=p^?-AEx{8S9>%DBciuYo(UW`AfmSnzl#*yNaYWOq~e zJ~5_Ut?hQj*1E!WlW{Gb*8fthUyAgD=Hm%>x}Rd7GsAs7;Y?X*M*boW<=B2Xv>%S! Ti0L%EU@2_>5~TLjcuvzQIy zBZRYLENTRe2ImsXh-Psb<(~zYxRJSROtYmXTZT@e%aUorqWiu}sc6>Z*YCUEIrrRi z&pr2^6IvN8>-HN4VuUz%>8n4Ygb=4yLaY~?#W-{00r0%apH9WH9xo9mc8MU=fl4uHLOjKfUWhHi3GD?F8Gj#TeflKSADAlw;wBEx z^ta`+fIblg z^a;p2p+lhU+koc+3wXdDjX-Yz@7*oynbW5r4?!ovwfFa_cxUu6$T=LVfbQ{Y^OXz3 z$0OeitpOQdpKvp$S0S&39t0;RS1LDfP=^EFK_8S)r^W7e`27yw(0J^HSsQRB$3G5m z{O15QKt1KzU{pjj;E&IQ&#BSts<*gZ%??YOtKRRF4`P z_*}aka&PPcc{{!wsH2)?Fuqh~$0o@VRe?MjTfSIns?Ou~c+qa9*WMvSjxV>~?sHl^ z4GlhrAF+^~s(fk01-hdv@YqF8DO3EWC(j&NrOpbldr2S}qyP;_odHjsCLLZ63}K8= z6POof0rW){B72c6WQ#zyz%;|3$O)4R%?Aa*3W`86C;`>&6QgG67<$R6G7gPHZ}(N3 zeq&Cbirfr+7i{mnc#1haXG%M?3*;X-zL7b-N(6R^UYN6BhqbbV1@xSwUqY{g@=Mb9!DlPK(Zh^RFJ?%bb2T@-nCm7&A^NIX(03P*(tdhBq@kJi!Ie zx!4Zv0uKk=PnpvzQxQ52KI+dKV@_}8h4H*Hz^-wD)Px96vwx$msdVMxeLA^k;~kpP>*mTPH+c?ZpPRL(dMCL90M<;J&t>1w3FuEwmkc za=9kRoSu`e8+sZ{f5GYb1s{O6abg>56{Wi4eba2R$sOuAL6}i+qBlE-C(!c_#-S`pyzvUhL(ek)yI_gn4TT7K^vHd z>(jG-JG2)hSH(@TeR_5@2pu-y`ET2KKbr-^2>5!8K_7yb!wu21A%V}G8Tj|yP%ccb zJWFU5*q(FsW41%j8>ofu1e?O`(6gQW&^}Pf+=df)z=9xj6l@NkK+ik`<#)C!oYON; zhFXEo;da#dEy{whQXV#C$vfKAC?T8lTa3zr<8#_u9B4y`)i$rI$?ok~>lP}xI&HB$ zt24`>MwhS=ZTKBn$a3tyTp7wpxdm%~M@(@whu?_B2wdReH5cvcflro;Nxy z|8p}gTxV3H!-9Zcyc5~LfNTXDD9eD`J=|5 z^!S0soY>%L_FH`Z4!1IVa-QBO9~-h|RGL-}rftGFW%L;4WrpwH>2SA1n%=YwpHvP` zL5m%${p;zK^TW5%?7<#j>MkO+ThOytOeSq42=~k-G;*oV6nJ(I4r~?Nc$L{S?luZ6 z0Wp9(5zJL(XM(pEvwUiqpeSyw^doXIds^ADfA<&$-QQ6Sq&? zPDz_FPkwLAmdSV=A-(R|gxMuO&=h2b2eHZJ^?JM(zsKXoN%%!Zu1?<4R>>i~r6+BJ zdd8cvToxEI)xI{Dzs_mlUP;J9sm7!kH8>9Pi~+AtdanE;y-;2^6v_c~Co_FX!pxVf dL>3rx<#&dd=u#m+G-k>XgF1SJkWY+n{0D{OSY7}C diff --git a/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml b/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml index 7735448..47cad92 100644 --- a/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml +++ b/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml @@ -87,6 +87,11 @@ Grid overlay line width The line width in pixels + + "" + Image location + The location of the directory in which the image tool picks + [ @@ -148,7 +153,7 @@ ["<Primary>v"] - Paste image files from the clipboard + Paste images from the clipboard ["<Primary><Shift>z"] @@ -284,8 +289,12 @@ Change font weight - ["<Primary><Shift>i"] - Change image file + ["<Primary><Alt>i"] + Change image + + + ["<Primary><Alt><Shift>i"] + Change image (reverse) ["<Primary>k"] diff --git a/shortcuts.js b/shortcuts.js index f99b448..de77083 100644 --- a/shortcuts.js +++ b/shortcuts.js @@ -49,7 +49,8 @@ var INTERNAL_KEYBINDINGS = [ ['switch-fill', 'switch-fill-rule', 'switch-color-palette', 'switch-color-palette-reverse'], ['increment-line-width', 'increment-line-width-more', 'decrement-line-width', 'decrement-line-width-more', 'switch-linejoin', 'switch-linecap', 'switch-dash'], - ['switch-font-family', 'switch-font-family-reverse', 'switch-font-weight', 'switch-font-style', 'switch-text-alignment', 'switch-image-file'], + ['switch-font-family', 'switch-font-family-reverse', 'switch-font-weight', 'switch-font-style', 'switch-text-alignment'], + ['switch-image-file', 'switch-image-file-reverse', 'paste-image-files'], ['toggle-panel-and-dock-visibility', 'toggle-background', 'toggle-grid', 'toggle-square-area'], ['open-next-json', 'open-previous-json', 'save-as-json', 'save-as-svg', 'open-preferences', 'toggle-help'], ]; From 24682db69c4efb9e7131e8c3b253cc9d69c93183 Mon Sep 17 00:00:00 2001 From: abakkk Date: Sat, 12 Sep 2020 01:25:37 +0200 Subject: [PATCH 19/35] add a lot of icons * Complete Files.Icons. * Add a lot of icons in the menu and the osd notifications. --- area.js | 51 +++++++----- data/icons/arc-symbolic.svg | 7 ++ data/icons/tool-ellipse-symbolic.svg | 7 ++ data/icons/tool-line-symbolic.svg | 7 ++ data/icons/tool-move-symbolic.svg | 14 ++++ data/icons/tool-none-symbolic.svg | 14 ++++ data/icons/tool-polygon-symbolic.svg | 8 ++ data/icons/tool-polyline-symbolic.svg | 9 +++ data/icons/tool-rectangle-symbolic.svg | 7 ++ data/icons/tool-resize-symbolic.svg | 17 ++++ files.js | 32 +++++--- menu.js | 105 ++++++++++++++----------- 12 files changed, 204 insertions(+), 74 deletions(-) create mode 100644 data/icons/arc-symbolic.svg create mode 100644 data/icons/tool-ellipse-symbolic.svg create mode 100644 data/icons/tool-line-symbolic.svg create mode 100644 data/icons/tool-move-symbolic.svg create mode 100644 data/icons/tool-none-symbolic.svg create mode 100644 data/icons/tool-polygon-symbolic.svg create mode 100644 data/icons/tool-polyline-symbolic.svg create mode 100644 data/icons/tool-rectangle-symbolic.svg create mode 100644 data/icons/tool-resize-symbolic.svg diff --git a/area.js b/area.js index 1978efb..85fa316 100644 --- a/area.js +++ b/area.js @@ -55,7 +55,12 @@ const { DisplayStrings } = Menu; const FontGenericFamilies = ['Sans-Serif', 'Serif', 'Monospace', 'Cursive', 'Fantasy']; const Manipulations = { MOVE: 100, RESIZE: 101, MIRROR: 102 }; -var Tools = Object.assign({}, Shapes, Manipulations); +var Tools = Object.assign({ + getNameOf: function(value) { + return Object.keys(this).find(key => this[key] == value); + } +}, Shapes, Manipulations); +Object.defineProperty(Tools, 'getNameOf', { enumerable: false }); const getClutterColorFromString = function(string, fallback) { let [success, color] = Clutter.Color.from_string(string); @@ -397,8 +402,8 @@ var DrawingArea = new Lang.Class({ event.get_key_symbol() == Clutter.KEY_Control_L) { if (this.currentElement.points.length == 2) // Translators: %s is a key label - this.emit('show-osd', null, _("Press %s to get\na fourth control point") - .format(Gtk.accelerator_get_label(Clutter.KEY_Return, 0)), "", -1, true); + this.emit('show-osd', Files.Icons.ARC, _("Press %s to get\na fourth control point") + .format(Gtk.accelerator_get_label(Clutter.KEY_Return, 0)), "", -1, true); this.currentElement.addPoint(); this.updatePointerCursor(true); this._redisplay(); @@ -495,7 +500,7 @@ var DrawingArea = new Lang.Class({ if (this.grabbedElementLocked) { this.updatePointerCursor(); let label = controlPressed ? _("Mark a point of symmetry") : _("Draw a line of symmetry"); - this.emit('show-osd', null, label, "", -1, true); + this.emit('show-osd', Files.Icons.TOOL_MIRROR, label, "", -1, true); return; } } @@ -628,10 +633,12 @@ var DrawingArea = new Lang.Class({ this.currentElement.startDrawing(startX, startY); - if (this.currentTool == Shapes.POLYGON || this.currentTool == Shapes.POLYLINE) + if (this.currentTool == Shapes.POLYGON || this.currentTool == Shapes.POLYLINE) { + let icon = Files.Icons[this.currentTool == Shapes.POLYGON ? 'TOOL_POLYGON' : 'TOOL_POLYLINE']; // Translators: %s is a key label - this.emit('show-osd', null, _("Press %s to mark vertices") + this.emit('show-osd', icon, _("Press %s to mark vertices") .format(Gtk.accelerator_get_label(Clutter.KEY_Return, 0)), "", -1, true); + } this.motionHandler = this.connect('motion-event', (actor, event) => { if (this.spaceKeyPressed) @@ -692,8 +699,8 @@ var DrawingArea = new Lang.Class({ this.currentElement.text = ''; this.currentElement.cursorPosition = 0; // Translators: %s is a key label - this.emit('show-osd', null, _("Type your text and press %s") - .format(Gtk.accelerator_get_label(Clutter.KEY_Escape, 0)), "", -1, true); + this.emit('show-osd', Files.Icons.TOOL_TEXT, _("Type your text and press %s") + .format(Gtk.accelerator_get_label(Clutter.KEY_Escape, 0)), "", -1, true); this._updateTextCursorTimeout(); this.textHasCursor = true; this._redisplay(); @@ -897,23 +904,25 @@ var DrawingArea = new Lang.Class({ 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.string || this.currentColor.to_string(), this.currentColor.to_string().slice(0, 7), -1, false); + this.emit('show-osd', Files.Icons.COLOR, this.currentColor.string || this.currentColor.to_string(), this.currentColor.to_string().slice(0, 7), -1, false); }, selectTool: function(tool) { this.currentTool = tool; - this.emit('show-osd', null, DisplayStrings.Tool[tool], "", -1, false); + this.emit('show-osd', Files.Icons[`TOOL_${Tools.getNameOf(tool)}`] || null, DisplayStrings.Tool[tool], "", -1, false); this.updatePointerCursor(); }, switchFill: function() { this.fill = !this.fill; - this.emit('show-osd', null, DisplayStrings.getFill(this.fill), "", -1, false); + let icon = Files.Icons[this.fill ? 'FILL' : 'STROKE']; + this.emit('show-osd', icon, DisplayStrings.getFill(this.fill), "", -1, false); }, switchFillRule: function() { this.currentFillRule = this.currentFillRule == 1 ? 0 : this.currentFillRule + 1; - this.emit('show-osd', null, DisplayStrings.FillRule[this.currentFillRule], "", -1, false); + let icon = Files.Icons[this.currentEvenodd ? 'FILLRULE_EVENODD' : 'FILLRULE_NONZERO']; + this.emit('show-osd', icon, DisplayStrings.FillRule[this.currentFillRule], "", -1, false); }, switchColorPalette: function(reverse) { @@ -922,12 +931,13 @@ var DrawingArea = new Lang.Class({ 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); + this.emit('show-osd', Files.Icons.PALETTE, this.currentPalette[0], "", -1, false); }, switchDash: function() { this.dashedLine = !this.dashedLine; - this.emit('show-osd', null, DisplayStrings.getDashedLine(this.dashedLine), "", -1, false); + let icon = Files.Icons[this.dashedLine ? 'DASHED_LINE' : 'FULL_LINE']; + this.emit('show-osd', icon, DisplayStrings.getDashedLine(this.dashedLine), "", -1, false); }, incrementLineWidth: function(increment) { @@ -937,12 +947,12 @@ var DrawingArea = new Lang.Class({ switchLineJoin: function() { this.currentLineJoin = this.currentLineJoin == 2 ? 0 : this.currentLineJoin + 1; - this.emit('show-osd', null, DisplayStrings.LineJoin[this.currentLineJoin], "", -1, false); + this.emit('show-osd', Files.Icons.LINEJOIN, DisplayStrings.LineJoin[this.currentLineJoin], "", -1, false); }, switchLineCap: function() { this.currentLineCap = this.currentLineCap == 2 ? 0 : this.currentLineCap + 1; - this.emit('show-osd', null, DisplayStrings.LineCap[this.currentLineCap], "", -1, false); + this.emit('show-osd', Files.Icons.LINECAP, DisplayStrings.LineCap[this.currentLineCap], "", -1, false); }, switchFontWeight: function() { @@ -953,7 +963,7 @@ var DrawingArea = new Lang.Class({ this.currentElement.font.set_weight(this.currentFontWeight); this._redisplay(); } - this.emit('show-osd', null, `` + + this.emit('show-osd', Files.Icons.FONT_WEIGHT, `` + `${DisplayStrings.FontWeight[this.currentFontWeight]}`, "", -1, false); }, @@ -963,7 +973,7 @@ var DrawingArea = new Lang.Class({ this.currentElement.font.set_style(this.currentFontStyle); this._redisplay(); } - this.emit('show-osd', null, `` + + this.emit('show-osd', Files.Icons.FONT_STYLE, `` + `${DisplayStrings.FontStyle[this.currentFontStyle]}`, "", -1, false); }, @@ -977,7 +987,7 @@ var DrawingArea = new Lang.Class({ this.currentElement.font.set_family(this.currentFontFamily); this._redisplay(); } - this.emit('show-osd', null, `${DisplayStrings.getFontFamily(this.currentFontFamily)}`, "", -1, false); + this.emit('show-osd', Files.Icons.FONT_FAMILY, `${DisplayStrings.getFontFamily(this.currentFontFamily)}`, "", -1, false); }, switchTextAlignment: function() { @@ -986,7 +996,8 @@ var DrawingArea = new Lang.Class({ this.currentElement.textRightAligned = this.currentTextRightAligned; this._redisplay(); } - this.emit('show-osd', null, DisplayStrings.getTextAlignment(this.currentTextRightAligned), "", -1, false); + let icon = Files.Icons[this.currentTextRightAligned ? 'RIGHT_ALIGNED' : 'LEFT_ALIGNED']; + this.emit('show-osd', icon, DisplayStrings.getTextAlignment(this.currentTextRightAligned), "", -1, false); }, switchImageFile: function(reverse) { diff --git a/data/icons/arc-symbolic.svg b/data/icons/arc-symbolic.svg new file mode 100644 index 0000000..4bed5e4 --- /dev/null +++ b/data/icons/arc-symbolic.svg @@ -0,0 +1,7 @@ + + +https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/blob/master/Papirus/symbolic/actions/tool-arc-symbolic.svg +https://www.gnu.org/licenses/gpl-3.0.html + + + diff --git a/data/icons/tool-ellipse-symbolic.svg b/data/icons/tool-ellipse-symbolic.svg new file mode 100644 index 0000000..9eeb5fc --- /dev/null +++ b/data/icons/tool-ellipse-symbolic.svg @@ -0,0 +1,7 @@ + + +https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/blob/master/Papirus/symbolic/actions/tool-circle-move-symbolic.svg +https://www.gnu.org/licenses/gpl-3.0.html + + + diff --git a/data/icons/tool-line-symbolic.svg b/data/icons/tool-line-symbolic.svg new file mode 100644 index 0000000..fc731dd --- /dev/null +++ b/data/icons/tool-line-symbolic.svg @@ -0,0 +1,7 @@ + + +https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/blob/master/Papirus/symbolic/actions/tool-line-symbolic.svg +https://www.gnu.org/licenses/gpl-3.0.html + + + diff --git a/data/icons/tool-move-symbolic.svg b/data/icons/tool-move-symbolic.svg new file mode 100644 index 0000000..0a9f236 --- /dev/null +++ b/data/icons/tool-move-symbolic.svg @@ -0,0 +1,14 @@ + + + +Combination of https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/blob/master/Papirus/symbolic/actions/object-move-symbolic.svg +https://www.gnu.org/licenses/gpl-3.0.html +and https://gitlab.gnome.org/World/design/icon-library/-/blob/master/data/resources/icon-dev-kit/rotate-symbolic.svg +https://www.gnu.org/licenses/gpl-3.0.html +optimized with SVGO + + + + + + diff --git a/data/icons/tool-none-symbolic.svg b/data/icons/tool-none-symbolic.svg new file mode 100644 index 0000000..de6fd8a --- /dev/null +++ b/data/icons/tool-none-symbolic.svg @@ -0,0 +1,14 @@ + + + +Combination of https://www.svgrepo.com/svg/150374/pencil +https://creativecommons.org/publicdomain/zero/1.0/deed.en +and https://www.svgrepo.com/svg/29291/pencil +https://creativecommons.org/publicdomain/zero/1.0/deed.en +Optimized with svgo + + + + + + diff --git a/data/icons/tool-polygon-symbolic.svg b/data/icons/tool-polygon-symbolic.svg new file mode 100644 index 0000000..2ee0447 --- /dev/null +++ b/data/icons/tool-polygon-symbolic.svg @@ -0,0 +1,8 @@ + + +https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/blob/master/Papirus/symbolic/actions/tool-polygon-symbolic.svg +https://www.gnu.org/licenses/gpl-3.0.html + + + + diff --git a/data/icons/tool-polyline-symbolic.svg b/data/icons/tool-polyline-symbolic.svg new file mode 100644 index 0000000..fee381d --- /dev/null +++ b/data/icons/tool-polyline-symbolic.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/data/icons/tool-rectangle-symbolic.svg b/data/icons/tool-rectangle-symbolic.svg new file mode 100644 index 0000000..e513e9f --- /dev/null +++ b/data/icons/tool-rectangle-symbolic.svg @@ -0,0 +1,7 @@ + + +https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/blob/master/Papirus/symbolic/actions/tool-rectangle-symbolic.svg +https://www.gnu.org/licenses/gpl-3.0.html + + + diff --git a/data/icons/tool-resize-symbolic.svg b/data/icons/tool-resize-symbolic.svg new file mode 100644 index 0000000..96010ed --- /dev/null +++ b/data/icons/tool-resize-symbolic.svg @@ -0,0 +1,17 @@ + + +https://github.com/maoschanz/drawing/blob/master/src/tools/icons/tool-scale-symbolic.svg + + + + + + + + + + + diff --git a/files.js b/files.js index 492c506..d78398d 100644 --- a/files.js +++ b/files.js @@ -36,17 +36,21 @@ const DEFAULT_USER_IMAGE_LOCATION = GLib.build_filenamev([GLib.get_user_data_dir const Clipboard = St.Clipboard.get_default(); const CLIPBOARD_TYPE = St.ClipboardType.CLIPBOARD; const ICON_DIR = Me.dir.get_child('data').get_child('icons'); -const ICON_NAMES = ['color', 'dashed-line', 'fillrule-evenodd', 'fillrule-nonzero', 'fill', 'full-line', 'linecap', 'linejoin', 'palette', 'smooth', 'stroke']; - -var Icons = { - get ENTER() { return this._enter || void (this._enter = new Gio.ThemedIcon({ name: 'applications-graphics-symbolic' })) || this._enter; }, - get GRAB() { return this._grab || void (this._grab = new Gio.ThemedIcon({ name: 'input-touchpad-symbolic' })) || this._grab; }, - get LEAVE() { return this._leave || void (this._leave = new Gio.ThemedIcon({ name: 'application-exit-symbolic' })) || this._leave; }, - get OPEN() { return this._open || void (this._open = new Gio.ThemedIcon({ name: 'document-open-symbolic' })) || this._open; }, - get SAVE() { return this._save || void (this._save = new Gio.ThemedIcon({ name: 'document-save-symbolic' })) || this._save; }, - get UNGRAB() { return this._ungrab || void (this._ungrab = new Gio.ThemedIcon({ name: 'touchpad-disabled-symbolic' })) || this._ungrab; } +const ICON_NAMES = [ + 'arc', 'color', 'dashed-line', 'fillrule-evenodd', 'fillrule-nonzero', 'fill', 'full-line', 'linecap', 'linejoin', 'palette', 'smooth', 'stroke', + 'tool-ellipse', 'tool-line', 'tool-move', 'tool-none', 'tool-polygon', 'tool-polyline', 'tool-rectangle', 'tool-resize', +]; +const ThemedIconNames = { + ENTER: 'applications-graphics', LEAVE: 'application-exit', + GRAB: 'input-touchpad', UNGRAB: 'touchpad-disabled', + OPEN: 'document-open', SAVE: 'document-save', + FONT_FAMILY: 'font-x-generic', FONT_STYLE: 'format-text-italic', FONT_WEIGHT:'format-text-bold', + LEFT_ALIGNED: 'format-justify-left', RIGHT_ALIGNED: 'format-justify-right', + TOOL_IMAGE: 'insert-image', TOOL_MIRROR: 'view-mirror', TOOL_TEXT: 'insert-text', }; +var Icons = {}; + ICON_NAMES.forEach(name => { Object.defineProperty(Icons, name.toUpperCase().replace(/-/gi, '_'), { get: function() { @@ -59,6 +63,16 @@ ICON_NAMES.forEach(name => { }); }); +Object.keys(ThemedIconNames).forEach(key => { + Object.defineProperty(Icons, key, { + get: function() { + if (!this[`_${key}`]) + this[`_${key}`] = new Gio.ThemedIcon({ name: `${ThemedIconNames[key]}-symbolic` }); + return this[`_${key}`]; + } + }); +}); + // wrapper around an image file var Image = new Lang.Class({ Name: 'DrawOnYourScreenImage', diff --git a/menu.js b/menu.js index 12e8e5c..8316999 100644 --- a/menu.js +++ b/menu.js @@ -22,7 +22,6 @@ */ const Clutter = imports.gi.Clutter; -const Gio = imports.gi.Gio; const GLib = imports.gi.GLib; const GObject = imports.gi.GObject; const Gtk = imports.gi.Gtk; @@ -231,9 +230,9 @@ var DrawingMenu = new Lang.Class({ this.menu.addMenuItem(groupItem); this._addSeparator(this.menu, true); - this._addSubMenuItem(this.menu, 'document-edit-symbolic', DisplayStrings.Tool, this.area, 'currentTool', this._updateSectionVisibility.bind(this)); - this.paletteItem = this._addPaletteSubMenuItem(this.menu); - this.colorItem = this._addColorSubMenuItem(this.menu); + this._addToolSubMenuItem(this.menu, this._updateSectionVisibility.bind(this)); + this.paletteItem = this._addPaletteSubMenuItem(this.menu, Files.Icons.PALETTE); + this.colorItem = this._addColorSubMenuItem(this.menu, Files.Icons.COLOR); this.fillItem = this._addSwitchItem(this.menu, DisplayStrings.getFill(true), Files.Icons.STROKE, Files.Icons.FILL, this.area, 'fill', this._updateSectionVisibility.bind(this)); this.fillSection = new PopupMenu.PopupMenuSection(); this.fillSection.itemActivated = () => {}; @@ -252,10 +251,10 @@ var DrawingMenu = new Lang.Class({ this.lineSection = lineSection; let fontSection = new PopupMenu.PopupMenuSection(); - this._addFontFamilySubMenuItem(fontSection, 'font-x-generic-symbolic'); - this._addSubMenuItem(fontSection, 'format-text-bold-symbolic', DisplayStrings.FontWeight, this.area, 'currentFontWeight'); - this._addSubMenuItem(fontSection, 'format-text-italic-symbolic', DisplayStrings.FontStyle, this.area, 'currentFontStyle'); - this._addSwitchItem(fontSection, DisplayStrings.getTextAlignment(true), 'format-justify-left-symbolic', 'format-justify-right-symbolic', this.area, 'currentTextRightAligned'); + this._addFontFamilySubMenuItem(fontSection, Files.Icons.FONT_FAMILY); + this._addSubMenuItem(fontSection, Files.Icons.FONT_WEIGHT, DisplayStrings.FontWeight, this.area, 'currentFontWeight'); + this._addSubMenuItem(fontSection, Files.Icons.FONT_STYLE, DisplayStrings.FontStyle, this.area, 'currentFontStyle'); + this._addSwitchItem(fontSection, DisplayStrings.getTextAlignment(true), Files.Icons.LEFT_ALIGNED, Files.Icons.RIGHT_ALIGNED, this.area, 'currentTextRightAligned'); this._addSeparator(fontSection); this.menu.addMenuItem(fontSection); fontSection.itemActivated = () => {}; @@ -276,8 +275,8 @@ var DrawingMenu = new Lang.Class({ this._addSeparator(this.menu); this._addDrawingNameItem(this.menu); - this._addOpenDrawingSubMenuItem(this.menu); - this._addSaveDrawingSubMenuItem(this.menu); + this._addOpenDrawingSubMenuItem(this.menu, Files.Icons.OPEN); + this._addSaveDrawingSubMenuItem(this.menu, Files.Icons.SAVE); this.menu.addAction(getSummary('save-as-svg'), this.area.saveAsSvg.bind(this.area), 'image-x-generic-symbolic'); this.menu.addAction(getSummary('open-preferences'), areaManager.openPreferences.bind(areaManager), 'document-page-setup-symbolic'); @@ -334,18 +333,14 @@ var DrawingMenu = new Lang.Class({ item.icon = new St.Icon({ style_class: 'popup-menu-icon' }); getActor(item).insert_child_at_index(item.icon, 1); let icon = target[targetProperty] ? iconTrue : iconFalse; - if (icon && icon instanceof GObject.Object && GObject.type_is_a(icon, Gio.Icon)) + if (icon) item.icon.set_gicon(icon); - else if (icon) - item.icon.set_icon_name(icon); item.connect('toggled', (item, state) => { target[targetProperty] = state; let icon = target[targetProperty] ? iconTrue : iconFalse; - if (icon && icon instanceof GObject.Object && GObject.type_is_a(icon, Gio.Icon)) + if (icon) item.icon.set_gicon(icon); - else if (icon) - item.icon.set_icon_name(icon); if (onToggled) onToggled(); }); @@ -392,40 +387,25 @@ var DrawingMenu = new Lang.Class({ menu.addMenuItem(item); }, - _addSubMenuItem: function(menu, icon, obj, target, targetProperty, callback) { + _addSubMenuItem: function(menu, icon, obj, target, targetProperty) { 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)) - item.icon.set_gicon(icon); - else if (icon) - item.icon.set_icon_name(icon); + item.icon.set_gicon(icon); item.menu.itemActivated = item.menu.close; GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => { Object.keys(obj).forEach(key => { - let text; - if (targetProperty == 'currentFontWeight') - text = `${obj[key]}`; - else if (targetProperty == 'currentFontStyle') - text = `${obj[key]}`; - else - text = String(obj[key]); + let text = targetProperty == 'currentFontWeight' ? `${obj[key]}` : + targetProperty == 'currentFontStyle' ? `${obj[key]}` : + String(obj[key]); let subItem = item.menu.addAction(text, () => { item.label.set_text(String(obj[key])); target[targetProperty] = Number(key); - if (callback) - callback(); }); subItem.label.get_clutter_text().set_use_markup(true); getActor(subItem).connect('key-focus-in', updateSubMenuAdjustment); - - // change the display order of tools - if (obj == DisplayStrings.Tool && Number(key) == this.drawingTools.POLYGON) - item.menu.moveMenuItem(subItem, 4); - else if (obj == DisplayStrings.Tool && Number(key) == this.drawingTools.POLYLINE) - item.menu.moveMenuItem(subItem, 5); }); return GLib.SOURCE_REMOVE; }); @@ -433,10 +413,45 @@ var DrawingMenu = new Lang.Class({ menu.addMenuItem(item); }, - _addPaletteSubMenuItem: function(menu) { + _addToolSubMenuItem: function(menu, callback) { + let item = new PopupMenu.PopupSubMenuMenuItem(DisplayStrings.Tool[this.area.currentTool], true); + + let toolName = this.drawingTools.getNameOf(this.area.currentTool); + item.icon.set_gicon(Files.Icons[`TOOL_${toolName}`]); + + item.menu.itemActivated = item.menu.close; + + GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => { + Object.keys(DisplayStrings.Tool).forEach(key => { + let text = DisplayStrings.Tool[key]; + let toolName = this.drawingTools.getNameOf(key); + let subItemIcon = Files.Icons[`TOOL_${toolName}`]; + let subItem = item.menu.addAction(text, () => { + item.label.set_text(text); + item.icon.set_gicon(subItemIcon); + this.area.currentTool = Number(key); + callback(); + }, subItemIcon); + + subItem.label.get_clutter_text().set_use_markup(true); + getActor(subItem).connect('key-focus-in', updateSubMenuAdjustment); + + // change the display order of tools + if (key == this.drawingTools.POLYGON) + item.menu.moveMenuItem(subItem, Number(this.drawingTools.TEXT)); + else if (key == this.drawingTools.POLYLINE) + item.menu.moveMenuItem(subItem, Number(this.drawingTools.TEXT) + 1); + }); + return GLib.SOURCE_REMOVE; + }); + + menu.addMenuItem(item); + }, + + _addPaletteSubMenuItem: function(menu, icon) { let text = _(this.area.currentPalette[0] || "Palette"); let item = new PopupMenu.PopupSubMenuMenuItem(text, true); - item.icon.set_gicon(Files.Icons.PALETTE); + item.icon.set_gicon(icon); item.menu.itemActivated = item.menu.close; @@ -460,10 +475,10 @@ var DrawingMenu = new Lang.Class({ return item; }, - _addColorSubMenuItem: function(menu) { + _addColorSubMenuItem: function(menu, icon) { let item = new PopupMenu.PopupSubMenuMenuItem(_("Color"), true); this.colorSubMenu = item.menu; - item.icon.set_gicon(Files.Icons.COLOR); + item.icon.set_gicon(icon); item.icon.set_style(`color:${this.area.currentColor.to_string().slice(0, 7)};`); item.menu.itemActivated = item.menu.close; @@ -492,7 +507,7 @@ var DrawingMenu = new Lang.Class({ _addFontFamilySubMenuItem: function(menu, icon) { let item = new PopupMenu.PopupSubMenuMenuItem(DisplayStrings.getFontFamily(this.area.currentFontFamily), true); - item.icon.set_icon_name(icon); + item.icon.set_gicon(icon); item.menu.itemActivated = item.menu.close; @@ -555,12 +570,12 @@ var DrawingMenu = new Lang.Class({ } }, - _addOpenDrawingSubMenuItem: function(menu) { + _addOpenDrawingSubMenuItem: function(menu, icon) { let item = new PopupMenu.PopupSubMenuMenuItem(_("Open drawing"), true); this.openDrawingSubMenuItem = item; this.openDrawingSubMenu = item.menu; item.setSensitive(Boolean(Files.getJsons().length)); - item.icon.set_icon_name('document-open-symbolic'); + item.icon.set_gicon(icon); item.menu.itemActivated = item.menu.close; @@ -608,12 +623,12 @@ var DrawingMenu = new Lang.Class({ this.openDrawingSubMenuItem.setSensitive(!this.openDrawingSubMenu.isEmpty()); }, - _addSaveDrawingSubMenuItem: function(menu) { + _addSaveDrawingSubMenuItem: function(menu, icon) { let item = new PopupMenu.PopupSubMenuMenuItem(getSummary('save-as-json'), true); this.saveDrawingSubMenuItem = item; this._updateSaveDrawingSubMenuItemSensitivity(); this.saveDrawingSubMenu = item.menu; - item.icon.set_icon_name('document-save-symbolic'); + item.icon.set_gicon(icon); item.menu.itemActivated = item.menu.close; From 464aae77c62788434c5112ed50fb44d1a35aca1b Mon Sep 17 00:00:00 2001 From: abakkk Date: Sat, 12 Sep 2020 19:54:10 +0200 Subject: [PATCH 20/35] improve images again * Files.Images does the same thing, with just a new accessor (getSorted). * Files.Image is splited and the new subclass manage gicons. --- files.js | 206 ++++++++++++++++++++++++++++++++----------------------- menu.js | 2 +- 2 files changed, 122 insertions(+), 86 deletions(-) diff --git a/files.js b/files.js index d78398d..15c2b91 100644 --- a/files.js +++ b/files.js @@ -73,18 +73,13 @@ Object.keys(ThemedIconNames).forEach(key => { }); }); -// wrapper around an image file +// wrapper around an image file. If not subclassed, it is used with drawing files (.json) and it takes { displayName, contentType, base64, hash } as params. var Image = new Lang.Class({ Name: 'DrawOnYourScreenImage', _init: function(params) { for (let key in params) this[key] = params[key]; - - if (this.info) { - this.displayName = this.info.get_display_name(); - this.contentType = this.info.get_content_type(); - } }, toString: function() { @@ -100,47 +95,9 @@ var Image = new Lang.Class({ }; }, - get thumbnailFile() { - if (!this._thumbnailFile) { - if (this.info.has_attribute('thumbnail::path') && this.info.get_attribute_boolean('thumbnail::is-valid')) { - let thumbnailPath = this.info.get_attribute_as_string('thumbnail::path'); - this._thumbnailFile = Gio.File.new_for_path(thumbnailPath); - } - } - return this._thumbnailFile || null; - }, - - // only called from menu or area so this.file exists - get gicon() { - if (!this._gicon) - this._gicon = new Gio.FileIcon({ file: this.thumbnailFile || this.file }); - return this._gicon; - }, - - // use only thumbnails in menu (memory) - get thumbnailGicon() { - if (this.contentType != 'image/svg+xml' && !this.thumbnailFile) - return null; - - return this.gicon; - }, - get bytes() { - if (!this._bytes) { - if (this.file) - try { - // load_bytes available in GLib 2.56+ - this._bytes = this.file.load_bytes(null)[0]; - } catch(e) { - let [, contents] = this.file.load_contents(null); - if (contents instanceof Uint8Array) - this._bytes = ByteArray.toGBytes(contents); - else - this._bytes = contents.toGBytes(); - } - else - this._bytes = new GLib.Bytes(GLib.base64_decode(this.base64)); - } + if (!this._bytes) + this._bytes = new GLib.Bytes(GLib.base64_decode(this.base64)); return this._bytes; }, @@ -188,7 +145,61 @@ var Image = new Lang.Class({ } }); -// Get images with getPrevious, getNext, or by iterating over it. +// Add a gicon generator to Image. It is used with image files and it takes { file, info } as params. +const ImageWithGicon = new Lang.Class({ + Name: 'DrawOnYourScreenImageWithGicon', + Extends: Image, + + get displayName() { + return this.info.get_display_name(); + }, + + get contentType() { + return this.info.get_content_type(); + }, + + get thumbnailFile() { + if (!this._thumbnailFile) { + if (this.info.has_attribute('thumbnail::path') && this.info.get_attribute_boolean('thumbnail::is-valid')) { + let thumbnailPath = this.info.get_attribute_as_string('thumbnail::path'); + this._thumbnailFile = Gio.File.new_for_path(thumbnailPath); + } + } + return this._thumbnailFile || null; + }, + + get gicon() { + if (!this._gicon) + this._gicon = new Gio.FileIcon({ file: this.thumbnailFile || this.file }); + return this._gicon; + }, + + // use only thumbnails in menu (memory) + get thumbnailGicon() { + if (this.contentType != 'image/svg+xml' && !this.thumbnailFile) + return null; + + return this.gicon; + }, + + get bytes() { + if (!this._bytes) { + try { + // load_bytes available in GLib 2.56+ + this._bytes = this.file.load_bytes(null)[0]; + } catch(e) { + let [, contents] = this.file.load_contents(null); + if (contents instanceof Uint8Array) + this._bytes = ByteArray.toGBytes(contents); + else + this._bytes = contents.toGBytes(); + } + } + return this._bytes; + } +}); + +// Access images with getPrevious, getNext, getSorted or by iterating over it. var Images = { _images: [], _clipboardImages: [], @@ -198,57 +209,84 @@ var Images = { return this._clipboardImages.some(image => image.file.equal(file)); }, - _getImages: function() { + // Firstly iterate over the extension directory that contains Example.svg, + // secondly iterate over the directory that was configured by the user in prefs, + // finally iterate over the images pasted from the clipboard. + [Symbol.iterator]: function() { if (this._upToDate) - return this._images; + return this._images.concat(this._clipboardImages)[Symbol.iterator](); - let images = []; - let userLocation = Me.drawingSettings.get_string('image-location') || DEFAULT_USER_IMAGE_LOCATION; - let userDirectory = Gio.File.new_for_commandline_arg(userLocation); + this._upToDate = true; + let oldImages = this._images; + let newImages = this._images = []; + let clipboardImagesContains = this._clipboardImagesContains.bind(this); + let clipboardIterator = this._clipboardImages[Symbol.iterator](); - [EXAMPLE_IMAGE_DIRECTORY, userDirectory].forEach(directory => { - let enumerator; - try { - enumerator = directory.enumerate_children('standard::,thumbnail::', Gio.FileQueryInfoFlags.NONE, null); - } catch(e) { - return; - } + return { + getExampleEnumerator: function() { + try { + return EXAMPLE_IMAGE_DIRECTORY.enumerate_children('standard::,thumbnail::', Gio.FileQueryInfoFlags.NONE, null); + } catch(e) { + return this.getUserEnumerator(); + } + }, - let info = enumerator.next_file(null); - while (info) { - let file = enumerator.get_child(info); + getUserEnumerator: function() { + try { + let userLocation = Me.drawingSettings.get_string('image-location') || DEFAULT_USER_IMAGE_LOCATION; + let userDirectory = Gio.File.new_for_commandline_arg(userLocation); + return userDirectory.enumerate_children('standard::,thumbnail::', Gio.FileQueryInfoFlags.NONE, null); + } catch(e) { + return null; + } + }, + + get enumerator() { + if (this._enumerator === undefined) + this._enumerator = this.getExampleEnumerator(); + else if (this._enumerator && this._enumerator.get_container().equal(EXAMPLE_IMAGE_DIRECTORY) && this._enumerator.is_closed()) + this._enumerator = this.getUserEnumerator(); + else if (this._enumerator && this._enumerator.is_closed()) + this._enumerator = null; - if (info.get_content_type().indexOf('image') == 0 && !this._clipboardImagesContains(file)) { - let index = this._images.findIndex(image => image.file.equal(file)); - if (index != -1) - images.push(this._images[index]); - else - images.push(new Image({ file, info })); + return this._enumerator; + }, + + next: function() { + if (!this.enumerator) + return clipboardIterator.next(); + + let info = this.enumerator.next_file(null); + if (!info) { + this.enumerator.close(null); + return this.next(); } - info = enumerator.next_file(null); + let file = this.enumerator.get_child(info); + + if (info.get_content_type().indexOf('image') == 0 && !clipboardImagesContains(file)) { + let image = oldImages.find(image => image.file.equal(file)) || new ImageWithGicon({ file, info }); + newImages.push(image); + return { value: image, done: false }; + } else { + return this.next(); + } } - enumerator.close(null); - }); - - this._images = images.concat(this._clipboardImages) - .sort((a, b) => a.toString().localeCompare(b.toString())); - this._upToDate = true; - return this._images; + }; }, - [Symbol.iterator]: function() { - return this._getImages()[Symbol.iterator](); + getSorted: function() { + return [...this].sort((a, b) => a.toString().localeCompare(b.toString())); }, getNext: function(currentImage) { - let images = this._getImages(); - let index = currentImage ? images.findIndex(image => image.file.equal(currentImage.file)) : 0; + let images = this.getSorted(); + let index = currentImage ? images.findIndex(image => image.file.equal(currentImage.file)) : -1; return images[index == images.length - 1 ? 0 : index + 1] || null; }, getPrevious: function(currentImage) { - let images = this._getImages(); + let images = this.getSorted(); let index = currentImage ? images.findIndex(image => image.file.equal(currentImage.file)) : 0; return images[index <= 0 ? images.length - 1 : index - 1] || null; }, @@ -271,7 +309,7 @@ var Images = { .filter(file => file.query_exists(null)) .map(file => [file, file.query_info('standard::,thumbnail::', Gio.FileQueryInfoFlags.NONE, null)]) .filter(pair => pair[1].get_content_type().indexOf('image') == 0) - .map(pair => new Image({ file: pair[0], info: pair[1] })); + .map(pair => new ImageWithGicon({ file: pair[0], info: pair[1] })); // Prevent duplicated images.filter(image => !this._clipboardImagesContains(image.file)) @@ -279,10 +317,8 @@ var Images = { if (images.length) { this.reset(); - let allImages = this._getImages(); let lastFile = images[images.length - 1].file; - let index = allImages.findIndex(image => image.file.equal(lastFile)); - callback(allImages[index]); + callback(this._clipboardImages.find(image => image.file.equal(lastFile))); } }); } diff --git a/menu.js b/menu.js index 8316999..bc10dfa 100644 --- a/menu.js +++ b/menu.js @@ -539,7 +539,7 @@ var DrawingMenu = new Lang.Class({ item.menu.openOld = item.menu.open; item.menu.open = (animate) => { if (!item.menu.isOpen && item.menu.isEmpty()) { - [...Files.Images].forEach(image => { + Files.Images.getSorted().forEach(image => { let subItem = item.menu.addAction(image.toString(), () => { item.label.set_text(image.toString()); this.area.currentImage = image; From e53e69efcf322bec68775aec6c6c2e4ee2e7c2ad Mon Sep 17 00:00:00 2001 From: abakkk Date: Sun, 13 Sep 2020 15:46:22 +0200 Subject: [PATCH 21/35] minor, use array instead of object for "OTHER" shortcuts Array is more semantically appropriate. For example 2 actions may have the same translations (error of a translator). With an object (or a map), only the second would be displayed, which is problematic to alert to the problem. Additionally, handle the case where some GSettings keybinding values are empty. --- extension.js | 4 ++-- helper.js | 19 ++++++++++--------- prefs.js | 13 +++++++------ shortcuts.js | 38 +++++++++++++++++++------------------- 4 files changed, 38 insertions(+), 36 deletions(-) diff --git a/extension.js b/extension.js index 7e60fb4..95c1dd7 100644 --- a/extension.js +++ b/extension.js @@ -103,7 +103,7 @@ const AreaManager = new Lang.Class({ Me.settings, Meta.KeyBindingFlags.NONE, Shell.ActionMode.ALL, - this.eraseDrawing.bind(this)); + this.eraseDrawings.bind(this)); this.updateAreas(); this.monitorChangedHandler = Main.layoutManager.connect('monitors-changed', this.updateAreas.bind(this)); @@ -265,7 +265,7 @@ const AreaManager = new Lang.Class({ } }, - eraseDrawing: function() { + eraseDrawings: function() { for (let i = 0; i < this.areas.length; i++) this.areas[i].erase(); if (Me.settings.get_boolean('persistent-drawing')) diff --git a/helper.js b/helper.js index 91d77fe..444ff93 100644 --- a/helper.js +++ b/helper.js @@ -71,7 +71,7 @@ var DrawingHelper = new Lang.Class({ }, _updateHelpKeyLabel: function() { - let [keyval, mods] = Gtk.accelerator_parse(Me.internalShortcutSettings.get_strv('toggle-help')[0]); + let [keyval, mods] = Gtk.accelerator_parse(Me.internalShortcutSettings.get_strv('toggle-help')[0] || ''); this._helpKeyLabel = Gtk.accelerator_get_label(keyval, mods); }, @@ -96,7 +96,7 @@ var DrawingHelper = new Lang.Class({ return; let hbox = new St.BoxLayout({ vertical: false }); - let [keyval, mods] = Gtk.accelerator_parse(Me.settings.get_strv(settingKey)[0]); + let [keyval, mods] = Gtk.accelerator_parse(Me.settings.get_strv(settingKey)[0] || ''); hbox.add_child(new St.Label({ text: Me.settings.settings_schema.get_key(settingKey).get_summary() })); hbox.add_child(new St.Label({ text: Gtk.accelerator_get_label(keyval, mods), x_expand: true })); this.vbox.add_child(hbox); @@ -106,17 +106,18 @@ var DrawingHelper = new Lang.Class({ this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-helper-separator' })); this.vbox.add_child(new St.Label({ text: _("Internal") })); - Shortcuts.OTHERS.forEach((object, index) => { + Shortcuts.OTHERS.forEach((pairs, index) => { if (index) this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-helper-separator' })); - for (let key in object) { + pairs.forEach(pair => { + let [action, shortcut] = pair; let hbox = new St.BoxLayout({ vertical: false }); - hbox.add_child(new St.Label({ text: key })); - hbox.add_child(new St.Label({ text: object[key], x_expand: true })); + hbox.add_child(new St.Label({ text: action })); + hbox.add_child(new St.Label({ text: shortcut, x_expand: true })); hbox.get_children()[0].get_clutter_text().set_use_markup(true); this.vbox.add_child(hbox); - } + }); }); this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-your-screen-helper-separator' })); @@ -130,7 +131,7 @@ var DrawingHelper = new Lang.Class({ return; let hbox = new St.BoxLayout({ vertical: false }); - let [keyval, mods] = Gtk.accelerator_parse(Me.internalShortcutSettings.get_strv(settingKey)[0]); + let [keyval, mods] = Gtk.accelerator_parse(Me.internalShortcutSettings.get_strv(settingKey)[0] || ''); hbox.add_child(new St.Label({ text: Me.internalShortcutSettings.settings_schema.get_key(settingKey).get_summary() })); hbox.add_child(new St.Label({ text: Gtk.accelerator_get_label(keyval, mods), x_expand: true })); this.vbox.add_child(hbox); @@ -149,7 +150,7 @@ var DrawingHelper = new Lang.Class({ let shortcut = GS_VERSION < '3.33.0' ? mediaKeysSettings.get_string(settingKey) : mediaKeysSettings.get_strv(settingKey)[0]; if (!shortcut) continue; - let [keyval, mods] = Gtk.accelerator_parse(shortcut); + let [keyval, mods] = Gtk.accelerator_parse(shortcut || ''); let hbox = new St.BoxLayout({ vertical: false }); hbox.add_child(new St.Label({ text: mediaKeysSettings.settings_schema.get_key(settingKey).get_summary() })); hbox.add_child(new St.Label({ text: Gtk.accelerator_get_label(keyval, mods), x_expand: true })); diff --git a/prefs.js b/prefs.js index d334e29..c57f1b6 100644 --- a/prefs.js +++ b/prefs.js @@ -430,19 +430,20 @@ const PrefsPage = new GObject.Class({ listBox.get_style_context().add_class('background'); internalFrame.add(listBox); - Shortcuts.OTHERS.forEach((object, index) => { + Shortcuts.OTHERS.forEach((pairs, index) => { if (index) listBox.add(new Gtk.Box(ROWBOX_MARGIN_PARAMS)); - for (let key in object) { + pairs.forEach(pair => { + let [action, shortcut] = pair; let otherBox = new Gtk.Box({ margin_left: MARGIN, margin_right: MARGIN }); - let otherLabel = new Gtk.Label({ label: key, use_markup: true }); + let otherLabel = new Gtk.Label({ label: action, use_markup: true }); otherLabel.set_halign(1); - let otherLabel2 = new Gtk.Label({ label: object[key] }); + let otherLabel2 = new Gtk.Label({ label: shortcut }); otherBox.pack_start(otherLabel, true, true, 4); otherBox.pack_start(otherLabel2, false, false, 4); listBox.add(otherBox); - } + }); }); listBox.add(new Gtk.Box(ROWBOX_MARGIN_PARAMS)); @@ -743,7 +744,7 @@ const KeybindingsWidget = new GObject.Class({ this._settingKeys.forEach(settingKey => { let [key, mods] = Gtk.accelerator_parse( - this._settings.get_strv(settingKey)[0] + this._settings.get_strv(settingKey)[0] || '' ); let iter = this._store.append(); diff --git a/shortcuts.js b/shortcuts.js index de77083..5a04a67 100644 --- a/shortcuts.js +++ b/shortcuts.js @@ -66,27 +66,27 @@ if (GS_VERSION < '3.36') { const getOthers = function() { return [ - { - [_("Draw")]: _("Left click"), - [_("Menu")]: _("Right click"), - [internalShortcutsSchema.get_key('switch-fill').get_summary()]: _("Center click"), - [_("Increment/decrement line width")]: _("Scroll"), + [ + [_("Draw"), _("Left click")], + [_("Menu"), _("Right click")], + [internalShortcutsSchema.get_key('switch-fill').get_summary(), _("Center click")], + [_("Increment/decrement line width"), _("Scroll")], // Translators: %s are key labels (Ctrl+F1 and Ctrl+F9) - [_("Select color")]: _("%s … %s").format(getKeyLabel('1'), getKeyLabel('9')), + [_("Select color"), _("%s … %s").format(getKeyLabel('1'), getKeyLabel('9'))], // Translators: %s is a key label - [_("Ignore pointer movement")]: _("%s held").format(getKeyLabel('space')), - [_("Leave")]: getKeyLabel('Escape'), - }, { - [_("Select eraser (while starting drawing)")]: getKeyLabel(''), - [_("Duplicate (while starting handling)")]: getKeyLabel(''), - [_("Rotate rectangle, polygon, polyline")]: getKeyLabel(''), - [_("Extend circle to ellipse")]: getKeyLabel(''), - [_("Curve line")]: getKeyLabel(''), - [_("Smooth free drawing outline")]: getKeyLabel(''), - [_("Rotate (while moving)")]: getKeyLabel(''), - [_("Stretch (while resizing)")]: getKeyLabel(''), - [_("Inverse (while mirroring)")]: getKeyLabel(''), - }, + [_("Ignore pointer movement"), _("%s held").format(getKeyLabel('space'))], + [_("Leave"), getKeyLabel('Escape')], + ], [ + [_("Select eraser (while starting drawing)"), getKeyLabel('')], + [_("Duplicate (while starting handling)"), getKeyLabel('')], + [_("Rotate rectangle, polygon, polyline"), getKeyLabel('')], + [_("Extend circle to ellipse"), getKeyLabel('')], + [_("Curve line"), getKeyLabel('')], + [_("Smooth free drawing outline"), getKeyLabel('')], + [_("Rotate (while moving)"), getKeyLabel('')], + [_("Stretch (while resizing)"), getKeyLabel('')], + [_("Inverse (while mirroring)"), getKeyLabel('')], + ], ]; }; From 60091a94b6e87d2115a5c13a07b490a2e9e5e720 Mon Sep 17 00:00:00 2001 From: abakkk Date: Sun, 13 Sep 2020 23:50:09 +0200 Subject: [PATCH 22/35] rework of Files.Jsons In the same way as Files.Images. --- area.js | 83 +++++++-------------- extension.js | 2 + files.js | 199 ++++++++++++++++++++++++++++++++++++++++----------- menu.js | 12 ++-- 4 files changed, 190 insertions(+), 106 deletions(-) diff --git a/area.js b/area.js index 85fa316..4bdb9a5 100644 --- a/area.js +++ b/area.js @@ -1129,14 +1129,7 @@ var DrawingArea = new Lang.Class({ } content += "\n"; - let filename = `${Me.metadata['svg-file-name']} ${Files.getDateString()}.svg`; - let dir = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_PICTURES); - let path = GLib.build_filenamev([dir, filename]); - if (GLib.file_test(path, GLib.FileTest.EXISTS)) - return false; - let success = GLib.file_set_contents(path, content); - - if (success) { + if (Files.saveSvg(content)) { // pass the parent (bgContainer) to Flashspot because coords of this are relative let flashspot = new Screenshot.Flashspot(this.get_parent()); flashspot.fire(); @@ -1149,7 +1142,7 @@ var DrawingArea = new Lang.Class({ } }, - _saveAsJson: function(name, notify, callback) { + _saveAsJson: function(json, notify, callback) { // stop drawing or writing if (this.currentElement && this.currentElement.shape == Shapes.TEXT && this.isWriting) { this._stopWriting(); @@ -1157,46 +1150,31 @@ var DrawingArea = new Lang.Class({ this._stopDrawing(); } - let json = new Files.Json({ name }); - let oldContents; - - if (name == Me.metadata['persistent-file-name']) { - let oldContents = json.contents; - // do not create a file to write just an empty array - if (!oldContents && this.elements.length == 0) - return; - } - // do not use "content = JSON.stringify(this.elements, null, 2);", neither "content = JSON.stringify(this.elements);" // do compromise between disk usage and human readability - let contents = `[\n ` + new Array(...this.elements.map(element => JSON.stringify(element))).join(`,\n\n `) + `\n]`; - - if (name == Me.metadata['persistent-file-name'] && contents == oldContents) - return; + let contents = this.elements.length ? `[\n ` + new Array(...this.elements.map(element => JSON.stringify(element))).join(`,\n\n `) + `\n]` : '[]'; GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => { json.contents = contents; if (notify) - this.emit('show-osd', Files.Icons.SAVE, name, "", -1, false); - if (name != Me.metadata['persistent-file-name']) { - this.jsonName = name; - this.lastJsonContents = contents; - } + this.emit('show-osd', Files.Icons.SAVE, json.name, "", -1, false); + if (!json.isPersistent) + this.currentJson = json; if (callback) callback(); }); }, saveAsJsonWithName: function(name, callback) { - this._saveAsJson(name, false, callback); + this._saveAsJson(Files.Jsons.getNamed(name), false, callback); }, saveAsJson: function() { - this._saveAsJson(Files.getDateString(), true); + this._saveAsJson(Files.Jsons.getDated(), true); }, savePersistent: function() { - this._saveAsJson(Me.metadata['persistent-file-name']); + this._saveAsJson(Files.Jsons.getPersistent()); }, syncPersistent: function() { @@ -1208,7 +1186,7 @@ var DrawingArea = new Lang.Class({ }, - _loadJson: function(name, notify) { + _loadJson: function(json, notify) { // stop drawing or writing if (this.currentElement && this.currentElement.shape == Shapes.TEXT && this.isWriting) { this._stopWriting(); @@ -1218,56 +1196,45 @@ var DrawingArea = new Lang.Class({ this.elements = []; this.currentElement = null; - let contents = (new Files.Json({ name })).contents; - if (!contents) + if (!json.contents) return; - this.elements.push(...JSON.parse(contents).map(object => { + this.elements.push(...JSON.parse(json.contents).map(object => { if (object.image) object.image = new Files.Image(object.image); return new Elements.DrawingElement(object); })); if (notify) - this.emit('show-osd', Files.Icons.OPEN, name, "", -1, false); - if (name != Me.metadata['persistent-file-name']) { - this.jsonName = name; - this.lastJsonContents = contents; - } + this.emit('show-osd', Files.Icons.OPEN, json.name, "", -1, false); + if (!json.isPersistent) + this.currentJson = json; }, _loadPersistent: function() { - this._loadJson(Me.metadata['persistent-file-name']); + this._loadJson(Files.Jsons.getPersistent()); }, - loadJson: function(name, notify) { - this._loadJson(name, notify); + loadJson: function(json, notify) { + this._loadJson(json, notify); this._redisplay(); }, loadPreviousJson: function() { - let names = Files.getJsons().map(json => json.name); - - if (!names.length) - return; - - let previousName = names[this.jsonName && names.indexOf(this.jsonName) != names.length - 1 ? names.indexOf(this.jsonName) + 1 : 0]; - this.loadJson(previousName, true); + let json = Files.Jsons.getPrevious(this.currentJson || null); + if (json) + this.loadJson(json, true); }, loadNextJson: function() { - let names = Files.getJsons().map(json => json.name); - - if (!names.length) - return; - - let nextName = names[this.jsonName && names.indexOf(this.jsonName) > 0 ? names.indexOf(this.jsonName) - 1 : names.length - 1]; - this.loadJson(nextName, true); + let json = Files.Jsons.getNext(this.currentJson || null); + if (json) + this.loadJson(json, true); }, get drawingContentsHasChanged() { let contents = `[\n ` + new Array(...this.elements.map(element => JSON.stringify(element))).join(`,\n\n `) + `\n]`; - return contents != this.lastJsonContents; + return contents != (this.currentJson && this.currentJson.contents); } }); diff --git a/extension.js b/extension.js index 95c1dd7..ca34b88 100644 --- a/extension.js +++ b/extension.js @@ -524,6 +524,8 @@ const AreaManager = new Lang.Class({ Main.wm.removeKeybinding('toggle-modal'); Main.wm.removeKeybinding('erase-drawings'); this.removeAreas(); + Files.Images.disable(); + Files.Jsons.disable(); if (this.indicator) this.indicator.disable(); } diff --git a/files.js b/files.js index 15c2b91..a443c8b 100644 --- a/files.js +++ b/files.js @@ -1,5 +1,5 @@ /* jslint esversion: 6 */ -/* exported Icons, Image, Images, Json, getJsons, getDateString */ +/* exported Icons, Image, Images, Json, Jsons, getDateString, saveSvg */ /* * Copyright 2019 Abakkk @@ -205,6 +205,12 @@ var Images = { _clipboardImages: [], _upToDate: false, + disable: function() { + this._images = []; + this._clipboardImages = []; + this._upToDate = false; + }, + _clipboardImagesContains: function(file) { return this._clipboardImages.some(image => image.file.equal(file)); }, @@ -265,7 +271,7 @@ var Images = { let file = this.enumerator.get_child(info); if (info.get_content_type().indexOf('image') == 0 && !clipboardImagesContains(file)) { - let image = oldImages.find(image => image.file.equal(file)) || new ImageWithGicon({ file, info }); + let image = oldImages.find(oldImage => oldImage.file.equal(file)) || new ImageWithGicon({ file, info }); newImages.push(image); return { value: image, done: false }; } else { @@ -287,7 +293,7 @@ var Images = { getPrevious: function(currentImage) { let images = this.getSorted(); - let index = currentImage ? images.findIndex(image => image.file.equal(currentImage.file)) : 0; + let index = currentImage ? images.findIndex(image => image.file.equal(currentImage.file)) : -1; return images[index <= 0 ? images.length - 1 : index - 1] || null; }, @@ -333,6 +339,10 @@ var Json = new Lang.Class({ this[key] = params[key]; }, + get isPersistent() { + return this.name == Me.metadata['persistent-file-name']; + }, + toString: function() { return this.displayName || this.name; }, @@ -342,10 +352,10 @@ var Json = new Lang.Class({ }, get file() { - if (!this._file && this.name) + if (!this._file) this._file = Gio.File.new_for_path(GLib.build_filenamev([GLib.get_user_data_dir(), Me.metadata['data-dir'], `${this.name}.json`])); - return this._file || null; + return this._file; }, set file(file) { @@ -353,62 +363,167 @@ var Json = new Lang.Class({ }, get contents() { - let success_, contents; - try { - [success_, contents] = this.file.load_contents(null); - if (contents instanceof Uint8Array) - contents = ByteArray.toString(contents); - } catch(e) { - return null; + if (this._contents === undefined) { + try { + [, this._contents] = this.file.load_contents(null); + if (this._contents instanceof Uint8Array) + this._contents = ByteArray.toString(this._contents); + } catch(e) { + this._contents = null; + } } - return contents; + + return this._contents; }, set contents(contents) { + if (this.isPersistent && (this.contents == contents || !this.contents && contents == '[]')) + return; + try { this.file.replace_contents(contents, null, false, Gio.FileCreateFlags.NONE, null); } catch(e) { this.file.get_parent().make_directory_with_parents(null); this.file.replace_contents(contents, null, false, Gio.FileCreateFlags.NONE, null); } + + this._contents = contents; } }); -var getJsons = function() { - let directory = Gio.File.new_for_path(GLib.build_filenamev([GLib.get_user_data_dir(), Me.metadata['data-dir']])); +var Jsons = { + _jsons: [], + _upToDate: false, - let enumerator; - try { - enumerator = directory.enumerate_children('standard::name,standard::display-name,standard::content-type,time::modified', Gio.FileQueryInfoFlags.NONE, null); - } catch(e) { - return []; - } - - let jsons = []; - let fileInfo = enumerator.next_file(null); - while (fileInfo) { - if (fileInfo.get_content_type().indexOf('json') != -1 && fileInfo.get_name() != `${Me.metadata['persistent-file-name']}.json`) { - let file = enumerator.get_child(fileInfo); - jsons.push(new Json({ - file, - name: fileInfo.get_name().slice(0, -5), - displayName: fileInfo.get_display_name().slice(0, -5), - // fileInfo.get_modification_date_time: Gio 2.62+ - modificationUnixTime: fileInfo.get_attribute_uint64('time::modified') - })); + disable: function() { + if (this._monitor) { + this._monitor.disconnect(this._monitorHandler); + this._monitor.cancel(); } - fileInfo = enumerator.next_file(null); + + delete this._monitor; + delete this._persistent; + + this._jsons = []; + this._upToDate = false; + }, + + _updateMonitor: function() { + if (this._monitor) + return; + + 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); + this._monitorHandler = this._monitor.connect('changed', (monitor, file) => { + if (file.get_basename() != `${Me.metadata['persistent-file-name']}.json` && file.get_basename().indexOf('.goutputstream')) + this.reset(); + }); + }, + + [Symbol.iterator]: function() { + if (this._upToDate) + return this._jsons[Symbol.iterator](); + + this._updateMonitor(); + this._upToDate = true; + let newJsons = this._jsons = []; + + return { + get enumerator() { + if (this._enumerator === undefined) { + try { + let directory = Gio.File.new_for_path(GLib.build_filenamev([GLib.get_user_data_dir(), Me.metadata['data-dir']])); + this._enumerator = directory.enumerate_children('standard::name,standard::display-name,standard::content-type,time::modified', Gio.FileQueryInfoFlags.NONE, null); + } catch(e) { + this._enumerator = null; + } + } + + return this._enumerator; + }, + + next: function() { + if (!this.enumerator || this.enumerator.is_closed()) + return { done: true }; + + let info = this.enumerator.next_file(null); + if (!info) { + this.enumerator.close(null); + return this.next(); + } + + let file = this.enumerator.get_child(info); + + if (info.get_content_type().indexOf('json') != -1 && info.get_name() != `${Me.metadata['persistent-file-name']}.json`) { + let json = new Json({ + file, name: info.get_name().slice(0, -5), + displayName: info.get_display_name().slice(0, -5), + // info.get_modification_date_time: Gio 2.62+ + modificationUnixTime: info.get_attribute_uint64('time::modified') + }); + + newJsons.push(json); + return { value: json, done: false }; + } else { + return this.next(); + } + } + }; + }, + + getSorted: function() { + return [...this].sort((a, b) => b.modificationUnixTime - a.modificationUnixTime); + }, + + getNext: function(currentJson) { + let jsons = this.getSorted(); + let index = currentJson ? jsons.findIndex(json => json.name == currentJson.name) : -1; + return jsons[index == jsons.length - 1 ? 0 : index + 1] || null; + }, + + getPrevious: function(currentJson) { + let jsons = this.getSorted(); + let index = currentJson ? jsons.findIndex(json => json.name == currentJson.name) : -1; + return jsons[index <= 0 ? jsons.length - 1 : index - 1] || null; + }, + + getPersistent: function() { + if (!this._persistent) + this._persistent = new Json({ name: Me.metadata['persistent-file-name'] }); + + return this._persistent; + }, + + getDated: function() { + return new Json({ name: getDateString() }); + }, + + getNamed: function(name) { + return [...this].find(json => json.name == name) || new Json({ name }); + }, + + reset: function() { + this._upToDate = false; } - enumerator.close(null); - - jsons.sort((a, b) => { - return b.modificationUnixTime - a.modificationUnixTime; - }); - - return jsons; }; var getDateString = function() { let date = GLib.DateTime.new_now_local(); return `${date.format("%F")} ${date.format("%X")}`; }; + +var saveSvg = function(content) { + let filename = `${Me.metadata['svg-file-name']} ${getDateString()}.svg`; + let dir = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_PICTURES); + let path = GLib.build_filenamev([dir, filename]); + let file = Gio.File.new_for_path(path); + if (file.query_exists(null)) + return false; + + try { + return file.replace_contents(content, null, false, Gio.FileCreateFlags.NONE, null); + } catch(e) { + return false; + } +}; + diff --git a/menu.js b/menu.js index bc10dfa..c460073 100644 --- a/menu.js +++ b/menu.js @@ -562,10 +562,10 @@ var DrawingMenu = new Lang.Class({ }, _updateDrawingNameMenuItem: function() { - getActor(this.drawingNameMenuItem).visible = this.area.jsonName ? true : false; - if (this.area.jsonName) { + getActor(this.drawingNameMenuItem).visible = this.area.currentJson ? true : false; + if (this.area.currentJson) { let prefix = this.area.drawingContentsHasChanged ? "* " : ""; - this.drawingNameMenuItem.label.set_text(`${prefix}${this.area.jsonName}`); + this.drawingNameMenuItem.label.set_text(`${prefix}${this.area.currentJson.name}`); this.drawingNameMenuItem.label.get_clutter_text().set_use_markup(true); } }, @@ -574,7 +574,7 @@ var DrawingMenu = new Lang.Class({ let item = new PopupMenu.PopupSubMenuMenuItem(_("Open drawing"), true); this.openDrawingSubMenuItem = item; this.openDrawingSubMenu = item.menu; - item.setSensitive(Boolean(Files.getJsons().length)); + item.setSensitive(Boolean(Files.Jsons.getSorted().length)); item.icon.set_gicon(icon); item.menu.itemActivated = item.menu.close; @@ -591,10 +591,10 @@ var DrawingMenu = new Lang.Class({ _populateOpenDrawingSubMenu: function() { this.openDrawingSubMenu.removeAll(); - let jsons = Files.getJsons(); + let jsons = Files.Jsons.getSorted(); jsons.forEach(json => { let subItem = this.openDrawingSubMenu.addAction(`${String(json)}`, () => { - this.area.loadJson(json.name); + this.area.loadJson(json); this._updateDrawingNameMenuItem(); this._updateSaveDrawingSubMenuItemSensitivity(); }); From a8633f1fbc18993bc2af0709bcbe07661ec0ec4b Mon Sep 17 00:00:00 2001 From: abakkk Date: Mon, 14 Sep 2020 01:32:37 +0200 Subject: [PATCH 23/35] add gicons to menu openDrawingSubMenu items --- area.js | 25 ++++++++++++++++++++++--- files.js | 7 ++++++- menu.js | 11 ++++++++--- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/area.js b/area.js index 4bdb9a5..63c16e9 100644 --- a/area.js +++ b/area.js @@ -1102,6 +1102,27 @@ var DrawingArea = new Lang.Class({ this.savePersistent(); }, + // Used by the menu. + getSvgContentForJson(json) { + let elements = []; + + elements.push(...JSON.parse(json.contents).map(object => { + if (object.image) + object.image = new Files.Image(object.image); + return new Elements.DrawingElement(object); + })); + + let size = Math.min(this.monitor.width, this.monitor.height); + let [x, y] = [(this.monitor.width - size) / 2, (this.monitor.height - size) / 2]; + + let prefixes = 'xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"'; + let content = ``; + elements.forEach(element => content += element.buildSVG('transparent')); + content += "\n"; + + return content; + }, + saveAsSvg: function() { // stop drawing or writing if (this.currentElement && this.currentElement.shape == Shapes.TEXT && this.isWriting) { @@ -1124,9 +1145,7 @@ var DrawingArea = new Lang.Class({ content += `\n `; content += `\n `; } - for (let i = 0; i < this.elements.length; i++) { - content += this.elements[i].buildSVG(backgroundColorString); - } + this.elements.forEach(element => content += element.buildSVG(backgroundColorString)); content += "\n"; if (Files.saveSvg(content)) { diff --git a/files.js b/files.js index a443c8b..3339604 100644 --- a/files.js +++ b/files.js @@ -388,6 +388,11 @@ var Json = new Lang.Class({ } this._contents = contents; + }, + + createGicon: function(content) { + let bytes = new GLib.Bytes(content); + this.gicon = Gio.BytesIcon.new(bytes); } }); @@ -521,7 +526,7 @@ var saveSvg = function(content) { return false; try { - return file.replace_contents(content, null, false, Gio.FileCreateFlags.NONE, null); + return file.replace_contents(content, null, false, Gio.FileCreateFlags.NONE, null)[0]; } catch(e) { return false; } diff --git a/menu.js b/menu.js index c460073..ff66d71 100644 --- a/menu.js +++ b/menu.js @@ -591,13 +591,18 @@ var DrawingMenu = new Lang.Class({ _populateOpenDrawingSubMenu: function() { this.openDrawingSubMenu.removeAll(); - let jsons = Files.Jsons.getSorted(); - jsons.forEach(json => { + Files.Jsons.getSorted().forEach(json => { + if (!json.gicon) { + let svgContent = this.area.getSvgContentForJson(json); + json.createGicon(svgContent); + } + let subItem = this.openDrawingSubMenu.addAction(`${String(json)}`, () => { this.area.loadJson(json); this._updateDrawingNameMenuItem(); this._updateSaveDrawingSubMenuItemSensitivity(); - }); + }, json.gicon); + subItem.label.get_clutter_text().set_use_markup(true); getActor(subItem).connect('key-focus-in', updateSubMenuAdjustment); From b63c1e9ffacf0b1304e1ad678a86538c8ae08326 Mon Sep 17 00:00:00 2001 From: abakkk Date: Mon, 14 Sep 2020 22:44:20 +0200 Subject: [PATCH 24/35] add possibility to insert an image directly from drawing save (.json) The Image object is got from the Jsons objects of the openDrawing sub menu. --- files.js | 38 +++++++++++++++++++++++++++++++------- menu.js | 49 ++++++++++++++++++++++++++++++++++--------------- stylesheet.css | 18 +++++++++++++----- 3 files changed, 78 insertions(+), 27 deletions(-) diff --git a/files.js b/files.js index 3339604..b08958a 100644 --- a/files.js +++ b/files.js @@ -73,7 +73,8 @@ Object.keys(ThemedIconNames).forEach(key => { }); }); -// wrapper around an image file. If not subclassed, it is used with drawing files (.json) and it takes { displayName, contentType, base64, hash } as params. +// Wrapper around image data. If not subclassed, it is used when loading in the area an image element for a drawing file (.json) +// and it takes { displayName, contentType, base64, hash } as params. var Image = new Lang.Class({ Name: 'DrawOnYourScreenImage', @@ -199,6 +200,21 @@ const ImageWithGicon = new Lang.Class({ } }); +// It is directly generated from a Json object, without an image file. It takes { bytes, displayName, gicon } as params. +const ImageFromJson = new Lang.Class({ + Name: 'DrawOnYourScreenImageFromJson', + Extends: Image, + contentType: 'image/svg+xml', + + get bytes() { + return this._bytes; + }, + + set bytes(bytes) { + this._bytes = bytes; + } +}); + // Access images with getPrevious, getNext, getSorted or by iterating over it. var Images = { _images: [], @@ -287,13 +303,13 @@ var Images = { getNext: function(currentImage) { let images = this.getSorted(); - let index = currentImage ? images.findIndex(image => image.file.equal(currentImage.file)) : -1; + let index = currentImage && currentImage.file ? images.findIndex(image => image.file.equal(currentImage.file)) : -1; return images[index == images.length - 1 ? 0 : index + 1] || null; }, getPrevious: function(currentImage) { let images = this.getSorted(); - let index = currentImage ? images.findIndex(image => image.file.equal(currentImage.file)) : -1; + let index = currentImage && currentImage.file ? images.findIndex(image => image.file.equal(currentImage.file)) : -1; return images[index <= 0 ? images.length - 1 : index - 1] || null; }, @@ -330,7 +346,7 @@ var Images = { } }; -// wrapper around a json file +// Wrapper around a json file (drawing saves). var Json = new Lang.Class({ Name: 'DrawOnYourScreenJson', @@ -390,12 +406,20 @@ var Json = new Lang.Class({ this._contents = contents; }, - createGicon: function(content) { - let bytes = new GLib.Bytes(content); - this.gicon = Gio.BytesIcon.new(bytes); + createGicon: function(svgContent) { + this.svgBytes = new GLib.Bytes(svgContent); + this.gicon = Gio.BytesIcon.new(this.svgBytes); + }, + + get image() { + if (!this._image) + this._image = new ImageFromJson({ bytes: this.svgBytes, gicon: this.gicon, displayName: this.displayName }); + + return this._image; } }); +// Access jsons with getPersistent, getDated, getNamed, getPrevious, getNext, getSorted or by iterating over it. var Jsons = { _jsons: [], _upToDate: false, diff --git a/menu.js b/menu.js index ff66d71..7d3821d 100644 --- a/menu.js +++ b/menu.js @@ -230,7 +230,7 @@ var DrawingMenu = new Lang.Class({ this.menu.addMenuItem(groupItem); this._addSeparator(this.menu, true); - this._addToolSubMenuItem(this.menu, this._updateSectionVisibility.bind(this)); + this.toolItem = this._addToolSubMenuItem(this.menu, this._updateSectionVisibility.bind(this)); this.paletteItem = this._addPaletteSubMenuItem(this.menu, Files.Icons.PALETTE); this.colorItem = this._addColorSubMenuItem(this.menu, Files.Icons.COLOR); this.fillItem = this._addSwitchItem(this.menu, DisplayStrings.getFill(true), Files.Icons.STROKE, Files.Icons.FILL, this.area, 'fill', this._updateSectionVisibility.bind(this)); @@ -261,7 +261,7 @@ var DrawingMenu = new Lang.Class({ this.fontSection = fontSection; let imageSection = new PopupMenu.PopupMenuSection(); - this._addImageSubMenuItem(imageSection); + this.imageItem = this._addImageSubMenuItem(imageSection); this._addSeparator(imageSection); this.menu.addMenuItem(imageSection); imageSection.itemActivated = () => {}; @@ -414,10 +414,13 @@ var DrawingMenu = new Lang.Class({ }, _addToolSubMenuItem: function(menu, callback) { - let item = new PopupMenu.PopupSubMenuMenuItem(DisplayStrings.Tool[this.area.currentTool], true); - - let toolName = this.drawingTools.getNameOf(this.area.currentTool); - item.icon.set_gicon(Files.Icons[`TOOL_${toolName}`]); + let item = new PopupMenu.PopupSubMenuMenuItem('', true); + item.update = () => { + item.label.set_text(DisplayStrings.Tool[this.area.currentTool]); + let toolName = this.drawingTools.getNameOf(this.area.currentTool); + item.icon.set_gicon(Files.Icons[`TOOL_${toolName}`]); + }; + item.update(); item.menu.itemActivated = item.menu.close; @@ -427,9 +430,8 @@ var DrawingMenu = new Lang.Class({ let toolName = this.drawingTools.getNameOf(key); let subItemIcon = Files.Icons[`TOOL_${toolName}`]; let subItem = item.menu.addAction(text, () => { - item.label.set_text(text); - item.icon.set_gicon(subItemIcon); this.area.currentTool = Number(key); + item.update(); callback(); }, subItemIcon); @@ -446,6 +448,7 @@ var DrawingMenu = new Lang.Class({ }); menu.addMenuItem(item); + return item; }, _addPaletteSubMenuItem: function(menu, icon) { @@ -531,8 +534,12 @@ var DrawingMenu = new Lang.Class({ }, _addImageSubMenuItem: function(menu, images) { - let item = new PopupMenu.PopupSubMenuMenuItem(this.area.currentImage.toString(), true); - item.icon.set_gicon(this.area.currentImage.gicon); + let item = new PopupMenu.PopupSubMenuMenuItem('', true); + item.update = () => { + item.label.set_text(this.area.currentImage.toString()); + item.icon.set_gicon(this.area.currentImage.gicon); + }; + item.update(); item.menu.itemActivated = item.menu.close; @@ -541,9 +548,8 @@ var DrawingMenu = new Lang.Class({ if (!item.menu.isOpen && item.menu.isEmpty()) { Files.Images.getSorted().forEach(image => { let subItem = item.menu.addAction(image.toString(), () => { - item.label.set_text(image.toString()); this.area.currentImage = image; - item.icon.set_gicon(image.gicon); + item.update(); }, image.thumbnailGicon || undefined); getActor(subItem).connect('key-focus-in', updateSubMenuAdjustment); }); @@ -552,6 +558,7 @@ var DrawingMenu = new Lang.Class({ }; menu.addMenuItem(item); + return item; }, _addDrawingNameItem: function(menu) { @@ -612,10 +619,22 @@ var DrawingMenu = new Lang.Class({ }); getActor(subItem).add_child(expander); - let deleteButton = new St.Button({ style_class: 'draw-on-your-screen-menu-delete-button', + let insertButton = new St.Button({ style_class: 'button draw-on-your-screen-menu-insert-button', + 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.imageItem.update(); + this.area.currentTool = this.drawingTools.IMAGE; + this.toolItem.update(); + this._updateSectionVisibility(); + }); + + let deleteButton = new St.Button({ style_class: 'button draw-on-your-screen-menu-delete-button', child: new St.Icon({ icon_name: 'edit-delete-symbolic', - style_class: 'popup-menu-icon', - x_align: Clutter.ActorAlign.END }) }); + style_class: 'popup-menu-icon' }) }); getActor(subItem).add_child(deleteButton); deleteButton.connect('clicked', () => { diff --git a/stylesheet.css b/stylesheet.css index 66e12a6..0170137 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -44,7 +44,7 @@ padding-bottom: .3em; } -.draw-on-your-screen-menu .popup-menu-icon { +.draw-on-your-screen-menu .popup-menu-item > .popup-menu-icon { icon-size: 1em; /* default: 1.09 */ padding-top: 0.03em; } @@ -120,8 +120,16 @@ padding: 0.35em 0.57em; } -.draw-on-your-screen-menu-delete-button:hover { - color: #f57900; +.draw-on-your-screen-menu-delete-button, .draw-on-your-screen-menu-insert-button { + min-height: 1px; + padding: 2px 4px; /* default 3px 24px */ } - - + +.draw-on-your-screen-menu-delete-button:hover { + color: #e01b24; /* upstream destructive color, light: #e01b24, dark: #b2161d */ +} + +.draw-on-your-screen-menu-delete-button .popup-menu-icon, .draw-on-your-screen-menu-insert-button .popup-menu-icon { + icon-size: 0.85em; /* default 1.09 */ +} + From 42b4c9c00c1dae8ef0940a666f126988d43c9e9d Mon Sep 17 00:00:00 2001 From: abakkk Date: Tue, 15 Sep 2020 00:29:02 +0200 Subject: [PATCH 25/35] color and font * Pass Clutter color and Pango fontDescription objects to elements, not strings. * Do not use the color format '#rrggbbaa' in svg since it is not supported in GNOME 3.24. --- area.js | 34 ++++++++++++++++++++++------------ elements.js | 37 ++++++++++++++----------------------- menu.js | 2 +- 3 files changed, 37 insertions(+), 36 deletions(-) diff --git a/area.js b/area.js index 63c16e9..9d0e897 100644 --- a/area.js +++ b/area.js @@ -64,12 +64,14 @@ Object.defineProperty(Tools, 'getNameOf', { enumerable: false }); const getClutterColorFromString = function(string, fallback) { let [success, color] = Clutter.Color.from_string(string); - color.string = string; + color.toString = () => string; if (success) return color; log(`${Me.metadata.uuid}: "${string}" color cannot be parsed.`); - return Clutter.Color.get_static(Clutter.StaticColor[fallback]); + color = Clutter.Color.get_static(Clutter.StaticColor[fallback.toUpperCase()]); + color.toString = () => fallback.slice(0, 1).toUpperCase() + fallback.slice(1); + return color; }; // DrawingArea is the widget in which we draw, thanks to Cairo. @@ -150,7 +152,7 @@ var DrawingArea = new Lang.Class({ set currentPalette(palette) { this._currentPalette = palette; - this.colors = palette[1].map(colorString => getClutterColorFromString(colorString, 'WHITE')); + this.colors = palette[1].map(colorString => getClutterColorFromString(colorString, 'white')); if (!this.colors[0]) this.colors.push(Clutter.Color.get_static(Clutter.StaticColor.WHITE)); }, @@ -252,9 +254,9 @@ var DrawingArea = new Lang.Class({ this.squareAreaSize = Me.drawingSettings.get_uint('square-area-size'); } - this.areaBackgroundColor = getClutterColorFromString(Me.drawingSettings.get_string('background-color'), 'BLACK'); + this.areaBackgroundColor = getClutterColorFromString(Me.drawingSettings.get_string('background-color'), 'black'); - this.gridColor = getClutterColorFromString(Me.drawingSettings.get_string('grid-color'), 'GRAY'); + 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; @@ -601,9 +603,9 @@ var DrawingArea = new Lang.Class({ if (this.currentTool == Shapes.TEXT) { this.currentElement = new Elements.DrawingElement({ shape: this.currentTool, - color: this.currentColor.to_string(), + color: this.currentColor, eraser: eraser, - font: this.currentFont.to_string(), + font: this.currentFont.copy(), // Translators: initial content of the text area text: pgettext("text-area-content", "Text"), textRightAligned: this.currentTextRightAligned, @@ -612,7 +614,7 @@ var DrawingArea = new Lang.Class({ } else if (this.currentTool == Shapes.IMAGE) { this.currentElement = new Elements.DrawingElement({ shape: this.currentTool, - color: this.currentColor.to_string(), + color: this.currentColor, eraser: eraser, image: this.currentImage, operator: this.currentOperator, @@ -621,7 +623,7 @@ var DrawingArea = new Lang.Class({ } else { this.currentElement = new Elements.DrawingElement({ shape: this.currentTool, - color: this.currentColor.to_string(), + color: this.currentColor, eraser: eraser, fill: this.fill, fillRule: this.currentFillRule, @@ -900,11 +902,11 @@ var DrawingArea = new Lang.Class({ this.currentColor = this.colors[index]; if (this.currentElement) { - this.currentElement.color = this.currentColor.to_string(); + this.currentElement.color = this.currentColor; this._redisplay(); } // Foreground color markup is not displayed since 3.36, use style instead but the transparency is lost. - this.emit('show-osd', Files.Icons.COLOR, this.currentColor.string || this.currentColor.to_string(), this.currentColor.to_string().slice(0, 7), -1, false); + this.emit('show-osd', Files.Icons.COLOR, String(this.currentColor), this.currentColor.to_string().slice(0, 7), -1, false); }, selectTool: function(tool) { @@ -1107,6 +1109,10 @@ var DrawingArea = new Lang.Class({ let elements = []; elements.push(...JSON.parse(json.contents).map(object => { + if (object.color) + object.color = getClutterColorFromString(object.color, 'white'); + if (object.font && typeof object.font == 'string') + object.font = Pango.FontDescription.from_string(object.font); if (object.image) object.image = new Files.Image(object.image); return new Elements.DrawingElement(object); @@ -1137,7 +1143,7 @@ var DrawingArea = new Lang.Class({ let content = ``; if (SVG_DEBUG_EXTENDS) content = ``; - let backgroundColorString = this.hasBackground ? this.areaBackgroundColor.to_string() : 'transparent'; + let backgroundColorString = this.hasBackground ? String(this.areaBackgroundColor) : 'transparent'; if (backgroundColorString != 'transparent') { content += `\n `; } @@ -1219,6 +1225,10 @@ var DrawingArea = new Lang.Class({ return; this.elements.push(...JSON.parse(json.contents).map(object => { + if (object.color) + object.color = getClutterColorFromString(object.color, 'white'); + if (object.font && typeof object.font == 'string') + object.font = Pango.FontDescription.from_string(object.font); if (object.image) object.image = new Files.Image(object.image); return new Elements.DrawingElement(object); diff --git a/elements.js b/elements.js index 9be96ff..efef1c0 100644 --- a/elements.js +++ b/elements.js @@ -81,20 +81,19 @@ const _DrawingElement = new Lang.Class({ if (params.transformations === undefined) this.transformations = []; - if (params.font && typeof params.font != 'string') { + if (params.font && !(params.font instanceof Pango.FontDescription)) { // compatibility with v6.2- if (params.font.weight === 0) this.font.weight = 400; else if (params.font.weight === 1) this.font.weight = 700; - let font = new Pango.FontDescription(); + this.font = new Pango.FontDescription(); ['family', 'weight', 'style', 'stretch', 'variant'].forEach(attribute => { if (params.font[attribute] !== undefined) try { - font[`set_${attribute}`](params.font[attribute]); + this.font[`set_${attribute}`](params.font[attribute]); } catch(e) {} }); - this.font = font.to_string(); } if (params.transform && params.transform.center) { @@ -114,7 +113,7 @@ const _DrawingElement = new Lang.Class({ toJSON: function() { return { shape: this.shape, - color: this.color, + color: this.color.toString(), line: this.line, dash: this.dash, fill: this.fill, @@ -126,11 +125,8 @@ const _DrawingElement = new Lang.Class({ }, buildCairo: function(cr, params) { - if (this.color) { - let [success, color] = Clutter.Color.from_string(this.color); - if (success) - Clutter.cairo_set_source_color(cr, color); - } + if (this.color) + Clutter.cairo_set_source_color(cr, this.color); if (this.showSymmetryElement) { let transformation = this.lastTransformation; @@ -256,7 +252,7 @@ const _DrawingElement = new Lang.Class({ return inElement; }, - buildSVG: function(bgColor) { + buildSVG: function(bgcolorString) { let transAttribute = ''; this.transformations.slice(0).reverse().forEach(transformation => { transAttribute += transAttribute ? ' ' : ' transform="'; @@ -284,13 +280,13 @@ const _DrawingElement = new Lang.Class({ }); transAttribute += transAttribute ? '"' : ''; - return this._drawSvg(transAttribute); + return this._drawSvg(transAttribute, bgcolorString); }, - _drawSvg: function(transAttribute) { + _drawSvg: function(transAttribute, bgcolorString) { let row = "\n "; let points = this.points.map((point) => [Math.round(point[0]*100)/100, Math.round(point[1]*100)/100]); - let color = this.eraser ? bgColor : this.color; + let color = this.eraser ? bgcolorString : this.color.toString(); let fill = this.fill && !this.isStraightLine; let attributes = ''; @@ -605,18 +601,13 @@ const TextElement = new Lang.Class({ Name: 'DrawOnYourScreenTextElement', Extends: _DrawingElement, - _init: function(params) { - this.parent(params); - this.font = Pango.FontDescription.from_string(this.font); - }, - toJSON: function() { // The font size is useless because it is always computed from the points during cairo/svg building. this.font.unset_fields(Pango.FontMask.SIZE); return { shape: this.shape, - color: this.color, + color: this.color.toString(), eraser: this.eraser, transformations: this.transformations, text: this.text, @@ -683,10 +674,10 @@ const TextElement = new Lang.Class({ return cr.inFill(x, y); }, - _drawSvg: function(transAttribute) { + _drawSvg: function(transAttribute, bgcolorString) { let row = "\n "; let [x, y, height] = [Math.round(this.x*100)/100, Math.round(this.y*100)/100, Math.round(this.height*100)/100]; - let color = this.eraser ? bgColor : this.color; + let color = this.eraser ? bgcolorString : this.color.toString(); let attributes = ''; if (this.points.length == 2) { @@ -760,7 +751,7 @@ const ImageElement = new Lang.Class({ toJSON: function() { return { shape: this.shape, - color: this.color, + color: this.color.toString(), fill: this.fill, eraser: this.eraser, transformations: this.transformations, diff --git a/menu.js b/menu.js index 7d3821d..7609692 100644 --- a/menu.js +++ b/menu.js @@ -495,7 +495,7 @@ var DrawingMenu = new Lang.Class({ this.colorSubMenu.removeAll(); GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => { this.area.colors.forEach(color => { - let text = color.string || color.to_string(); + let text = String(color); let subItem = this.colorSubMenu.addAction(text, () => { this.area.currentColor = color; this.colorItem.icon.set_style(`color:${color.to_string().slice(0, 7)};`); From cde5bab27dc27637ea6f2b5c8ecfa33237859e95 Mon Sep 17 00:00:00 2001 From: abakkk Date: Tue, 15 Sep 2020 01:48:01 +0200 Subject: [PATCH 26/35] fix icons * Old Adwaita icon theme does not contain 'view-mirror-symbolic' icon. * Redraw `tool-no-symbolic.svg` because of bad rendering in old GNOMEs. --- data/icons/arc-symbolic.svg | 2 +- data/icons/color-symbolic.svg | 2 +- data/icons/dashed-line-symbolic.svg | 6 +++--- data/icons/fill-symbolic.svg | 2 +- data/icons/fillrule-evenodd-symbolic.svg | 2 +- data/icons/fillrule-nonzero-symbolic.svg | 2 +- data/icons/full-line-symbolic.svg | 2 +- data/icons/linecap-symbolic.svg | 4 ++-- data/icons/linejoin-symbolic.svg | 2 +- data/icons/palette-symbolic.svg | 2 +- data/icons/smooth-symbolic.svg | 8 ++++---- data/icons/stroke-symbolic.svg | 2 +- data/icons/tool-ellipse-symbolic.svg | 2 +- data/icons/tool-line-symbolic.svg | 2 +- data/icons/tool-mirror-symbolic.svg | 8 ++++++++ data/icons/tool-move-symbolic.svg | 4 ++-- data/icons/tool-none-symbolic.svg | 15 +++++++++------ data/icons/tool-polygon-symbolic.svg | 4 ++-- data/icons/tool-polyline-symbolic.svg | 14 +++++++------- data/icons/tool-rectangle-symbolic.svg | 2 +- data/icons/tool-resize-symbolic.svg | 14 ++++++-------- files.js | 4 ++-- 22 files changed, 57 insertions(+), 48 deletions(-) create mode 100644 data/icons/tool-mirror-symbolic.svg diff --git a/data/icons/arc-symbolic.svg b/data/icons/arc-symbolic.svg index 4bed5e4..fb2bea9 100644 --- a/data/icons/arc-symbolic.svg +++ b/data/icons/arc-symbolic.svg @@ -3,5 +3,5 @@ https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/blob/master/Papirus/symbolic/actions/tool-arc-symbolic.svg https://www.gnu.org/licenses/gpl-3.0.html - + diff --git a/data/icons/color-symbolic.svg b/data/icons/color-symbolic.svg index 39ae95d..0410239 100644 --- a/data/icons/color-symbolic.svg +++ b/data/icons/color-symbolic.svg @@ -7,7 +7,7 @@ Created by potrace 1.15, written by Peter Selinger 2001-2017 https://svgsilh.com/image/1745699.html https://creativecommons.org/publicdomain/zero/1.0 - + - - - + + + diff --git a/data/icons/fill-symbolic.svg b/data/icons/fill-symbolic.svg index 041bd49..7c652e2 100644 --- a/data/icons/fill-symbolic.svg +++ b/data/icons/fill-symbolic.svg @@ -1,3 +1,3 @@ - + diff --git a/data/icons/fillrule-evenodd-symbolic.svg b/data/icons/fillrule-evenodd-symbolic.svg index a74de4c..3f64343 100644 --- a/data/icons/fillrule-evenodd-symbolic.svg +++ b/data/icons/fillrule-evenodd-symbolic.svg @@ -1,3 +1,3 @@ - + diff --git a/data/icons/fillrule-nonzero-symbolic.svg b/data/icons/fillrule-nonzero-symbolic.svg index a3b9b2b..72e0cf2 100644 --- a/data/icons/fillrule-nonzero-symbolic.svg +++ b/data/icons/fillrule-nonzero-symbolic.svg @@ -1,3 +1,3 @@ - + diff --git a/data/icons/full-line-symbolic.svg b/data/icons/full-line-symbolic.svg index 1919ef3..9323bfe 100644 --- a/data/icons/full-line-symbolic.svg +++ b/data/icons/full-line-symbolic.svg @@ -1,3 +1,3 @@ - + diff --git a/data/icons/linecap-symbolic.svg b/data/icons/linecap-symbolic.svg index 0d3e9df..fdfe9f6 100644 --- a/data/icons/linecap-symbolic.svg +++ b/data/icons/linecap-symbolic.svg @@ -1,4 +1,4 @@ - - + + diff --git a/data/icons/linejoin-symbolic.svg b/data/icons/linejoin-symbolic.svg index 28a1f5e..084caa7 100644 --- a/data/icons/linejoin-symbolic.svg +++ b/data/icons/linejoin-symbolic.svg @@ -1,3 +1,3 @@ - + diff --git a/data/icons/palette-symbolic.svg b/data/icons/palette-symbolic.svg index 8a4174b..0f00fd4 100644 --- a/data/icons/palette-symbolic.svg +++ b/data/icons/palette-symbolic.svg @@ -7,7 +7,7 @@ Created by potrace 1.15, written by Peter Selinger 2001-2017 https://svgsilh.com/image/2026954.html https://creativecommons.org/publicdomain/zero/1.0/ - + - - - - + + + + diff --git a/data/icons/stroke-symbolic.svg b/data/icons/stroke-symbolic.svg index 78bc817..f693453 100644 --- a/data/icons/stroke-symbolic.svg +++ b/data/icons/stroke-symbolic.svg @@ -1,3 +1,3 @@ - + diff --git a/data/icons/tool-ellipse-symbolic.svg b/data/icons/tool-ellipse-symbolic.svg index 9eeb5fc..20d5ae8 100644 --- a/data/icons/tool-ellipse-symbolic.svg +++ b/data/icons/tool-ellipse-symbolic.svg @@ -3,5 +3,5 @@ https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/blob/master/Papirus/symbolic/actions/tool-circle-move-symbolic.svg https://www.gnu.org/licenses/gpl-3.0.html - + diff --git a/data/icons/tool-line-symbolic.svg b/data/icons/tool-line-symbolic.svg index fc731dd..dbc7688 100644 --- a/data/icons/tool-line-symbolic.svg +++ b/data/icons/tool-line-symbolic.svg @@ -3,5 +3,5 @@ https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/blob/master/Papirus/symbolic/actions/tool-line-symbolic.svg https://www.gnu.org/licenses/gpl-3.0.html - + diff --git a/data/icons/tool-mirror-symbolic.svg b/data/icons/tool-mirror-symbolic.svg new file mode 100644 index 0000000..fd269b0 --- /dev/null +++ b/data/icons/tool-mirror-symbolic.svg @@ -0,0 +1,8 @@ + + +https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/blob/master/Papirus/symbolic/actions/view-mirror-symbolic.svg +https://www.gnu.org/licenses/gpl-3.0.html + + + + diff --git a/data/icons/tool-move-symbolic.svg b/data/icons/tool-move-symbolic.svg index 0a9f236..41bedc4 100644 --- a/data/icons/tool-move-symbolic.svg +++ b/data/icons/tool-move-symbolic.svg @@ -7,8 +7,8 @@ and https://gitlab.gnome.org/World/design/icon-library/-/blob/master/data/resour https://www.gnu.org/licenses/gpl-3.0.html optimized with SVGO - + - + diff --git a/data/icons/tool-none-symbolic.svg b/data/icons/tool-none-symbolic.svg index de6fd8a..83dad1a 100644 --- a/data/icons/tool-none-symbolic.svg +++ b/data/icons/tool-none-symbolic.svg @@ -1,14 +1,17 @@ - + Combination of https://www.svgrepo.com/svg/150374/pencil https://creativecommons.org/publicdomain/zero/1.0/deed.en and https://www.svgrepo.com/svg/29291/pencil https://creativecommons.org/publicdomain/zero/1.0/deed.en -Optimized with svgo - - - - + + + + + + + + diff --git a/data/icons/tool-polygon-symbolic.svg b/data/icons/tool-polygon-symbolic.svg index 2ee0447..e54e5b7 100644 --- a/data/icons/tool-polygon-symbolic.svg +++ b/data/icons/tool-polygon-symbolic.svg @@ -3,6 +3,6 @@ https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/blob/master/Papirus/symbolic/actions/tool-polygon-symbolic.svg https://www.gnu.org/licenses/gpl-3.0.html - - + + diff --git a/data/icons/tool-polyline-symbolic.svg b/data/icons/tool-polyline-symbolic.svg index fee381d..2f7c894 100644 --- a/data/icons/tool-polyline-symbolic.svg +++ b/data/icons/tool-polyline-symbolic.svg @@ -1,9 +1,9 @@ - - - - - - - + + + + + + + diff --git a/data/icons/tool-rectangle-symbolic.svg b/data/icons/tool-rectangle-symbolic.svg index e513e9f..033e73a 100644 --- a/data/icons/tool-rectangle-symbolic.svg +++ b/data/icons/tool-rectangle-symbolic.svg @@ -3,5 +3,5 @@ https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/blob/master/Papirus/symbolic/actions/tool-rectangle-symbolic.svg https://www.gnu.org/licenses/gpl-3.0.html - + diff --git a/data/icons/tool-resize-symbolic.svg b/data/icons/tool-resize-symbolic.svg index 96010ed..2f4d37f 100644 --- a/data/icons/tool-resize-symbolic.svg +++ b/data/icons/tool-resize-symbolic.svg @@ -1,17 +1,15 @@ -https://github.com/maoschanz/drawing/blob/master/src/tools/icons/tool-scale-symbolic.svg +https://gitlab.gnome.org/GNOME/adwaita-icon-theme/-/blob/master/Adwaita/scalable/actions/view-fullscreen-symbolic.svg +https://creativecommons.org/licenses/by-sa/3.0/ - - - + + + - + diff --git a/files.js b/files.js index b08958a..d2eca2a 100644 --- a/files.js +++ b/files.js @@ -38,7 +38,7 @@ const CLIPBOARD_TYPE = St.ClipboardType.CLIPBOARD; const ICON_DIR = Me.dir.get_child('data').get_child('icons'); const ICON_NAMES = [ 'arc', 'color', 'dashed-line', 'fillrule-evenodd', 'fillrule-nonzero', 'fill', 'full-line', 'linecap', 'linejoin', 'palette', 'smooth', 'stroke', - 'tool-ellipse', 'tool-line', 'tool-move', 'tool-none', 'tool-polygon', 'tool-polyline', 'tool-rectangle', 'tool-resize', + 'tool-ellipse', 'tool-line', 'tool-mirror', 'tool-move', 'tool-none', 'tool-polygon', 'tool-polyline', 'tool-rectangle', 'tool-resize', ]; const ThemedIconNames = { ENTER: 'applications-graphics', LEAVE: 'application-exit', @@ -46,7 +46,7 @@ const ThemedIconNames = { OPEN: 'document-open', SAVE: 'document-save', FONT_FAMILY: 'font-x-generic', FONT_STYLE: 'format-text-italic', FONT_WEIGHT:'format-text-bold', LEFT_ALIGNED: 'format-justify-left', RIGHT_ALIGNED: 'format-justify-right', - TOOL_IMAGE: 'insert-image', TOOL_MIRROR: 'view-mirror', TOOL_TEXT: 'insert-text', + TOOL_IMAGE: 'insert-image', TOOL_TEXT: 'insert-text', }; var Icons = {}; From 99964991c0e2f1362380359fb166dbe629d2307d Mon Sep 17 00:00:00 2001 From: abakkk Date: Tue, 15 Sep 2020 02:06:39 +0200 Subject: [PATCH 27/35] change some shortcuts Replace some `Shift + Ctrl + ...` to `Ctrl + Alt + ...`. --- schemas/gschemas.compiled | Bin 7392 -> 7384 bytes ...extensions.draw-on-your-screen.gschema.xml | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled index 5873a004f7d1fe0519ee087c1c5a4b82969803af..9271c1aa9324aa634c237e58b1de25474f22fd4f 100644 GIT binary patch delta 841 zcmXw%O-LJ26oqeUq{TLxjv6QabWs#^5s9J&1*>he#?VcuigZy8ttOFZ(2PbAIxY*P zpt$Ht&`l|^Xka!j1kI*YL2x-M$)bx26|!qUX?xB%4jj(+&b#lv%VY9gW>uL|i3z^m7lQp?g=1$cijV0q&>~DQ){w#+>XyuEJZO&j;Zwb8;o}KKKZv z`g;P*$?Ow@FGCf7RvMX;nXkdOp=tl1-pLIv%CV7!=b&#VpH$}LD&!{IsiHyd)i37c zhsafUD^&aXagsUtKJq?z7d(H8s&8nAOR^D}q>deWQeW*@Q}xzu4G=*8_oU~3?F5Ypcq<`O)> z1)pdFJ_ilj2gp3I3g3dXmD7IKlR4-<{200p9r&4(E0CM;3n*y!A+t{ruGWhT-Q=Uz z!kP$S5bF3{xor&u<^>b*MJQx9BD4Mj{44ZB`)IJ9%%AHBZf z1c8fc;i64w1U`J57DBq4f}nOT@1jKugIYCEl;^y8Jvf}-J@>oc{kXi-Ue#+q@cV5| zq*i7Bwu*@DB>d$UEEPaBQu&(^S(8Ung!`_DTA6kkGTRq(1;xabg!9PH6KR(r&lN*pLc(pFFelqrr zIk^sb2!0c4n!1)@PQHXZ3ZH~FW6fWgli6n#eh3Xb{{ETyp>B!zv2l!0L0Vuyzi?`t~p&_pknT__~1?aAqlbN5wi_ne!H@Db_T#LN&Dh7h?{T~SI4g`-w*3A2p zG!JmWCobnG{kx`2R(*=f&RpfBFxD($QAr26!rR$*+-g1LeNMl zpKurML&g7N3UIa4qb>W!jMSoeCnws@ zzSiOtw5p1>Qj|bpdm`77%csnFBfOYdF~j+VRMIff2cPpJ&{Y;J)#klgGm}iF7sAPG L>Y;O6->oSave drawing - ["<Primary><Shift>s"] + ["<Primary><Alt>s"] Save drawing as a SVG file @@ -281,7 +281,7 @@ Change font family (reverse) - ["<Primary><Shift>w"] + ["<Primary><Alt>w"] Change font style @@ -305,7 +305,7 @@ Change linejoin - ["<Primary><Shift>a"] + ["<Primary><Alt>a"] Toggle text alignment From e3b32ace3bd4594dd4a08de188acb4b1c729fcba Mon Sep 17 00:00:00 2001 From: abakkk Date: Wed, 16 Sep 2020 08:52:36 +0200 Subject: [PATCH 28/35] fix ImageFromJson Do not use the same content for insertable image and gicon. The former depends on the area size whereas the later is square. --- area.js | 22 ++++++++++++++-------- files.js | 9 +++++---- menu.js | 6 ++---- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/area.js b/area.js index 9d0e897..569ee4b 100644 --- a/area.js +++ b/area.js @@ -1105,8 +1105,9 @@ var DrawingArea = new Lang.Class({ }, // Used by the menu. - getSvgContentForJson(json) { + getSvgContentsForJson(json) { let elements = []; + let elementsContent = ''; elements.push(...JSON.parse(json.contents).map(object => { if (object.color) @@ -1117,16 +1118,21 @@ var DrawingArea = new Lang.Class({ object.image = new Files.Image(object.image); return new Elements.DrawingElement(object); })); - - let size = Math.min(this.monitor.width, this.monitor.height); - let [x, y] = [(this.monitor.width - size) / 2, (this.monitor.height - size) / 2]; + elements.forEach(element => elementsContent += element.buildSVG('transparent')); let prefixes = 'xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"'; - let content = ``; - elements.forEach(element => content += element.buildSVG('transparent')); - content += "\n"; - return content; + let getGiconSvgContent = () => { + let size = Math.min(this.monitor.width, this.monitor.height); + let [x, y] = [(this.monitor.width - size) / 2, (this.monitor.height - size) / 2]; + return `${elementsContent}\n`; + }; + + let getImageSvgContent = () => { + return `${elementsContent}\n`; + }; + + return [getGiconSvgContent, getImageSvgContent]; }, saveAsSvg: function() { diff --git a/files.js b/files.js index d2eca2a..2442ac7 100644 --- a/files.js +++ b/files.js @@ -406,14 +406,15 @@ var Json = new Lang.Class({ this._contents = contents; }, - createGicon: function(svgContent) { - this.svgBytes = new GLib.Bytes(svgContent); - this.gicon = Gio.BytesIcon.new(this.svgBytes); + addSvgContents: function(getGiconSvgContent, getImageSvgContent) { + let giconSvgBytes = new GLib.Bytes(getGiconSvgContent()); + this.gicon = Gio.BytesIcon.new(giconSvgBytes); + this.getImageSvgBytes = () => new GLib.Bytes(getImageSvgContent()); }, get image() { if (!this._image) - this._image = new ImageFromJson({ bytes: this.svgBytes, gicon: this.gicon, displayName: this.displayName }); + this._image = new ImageFromJson({ bytes: this.getImageSvgBytes(), gicon: this.gicon, displayName: this.displayName }); return this._image; } diff --git a/menu.js b/menu.js index 7609692..4e51df1 100644 --- a/menu.js +++ b/menu.js @@ -599,10 +599,8 @@ var DrawingMenu = new Lang.Class({ _populateOpenDrawingSubMenu: function() { this.openDrawingSubMenu.removeAll(); Files.Jsons.getSorted().forEach(json => { - if (!json.gicon) { - let svgContent = this.area.getSvgContentForJson(json); - json.createGicon(svgContent); - } + if (!json.gicon) + json.addSvgContents(...this.area.getSvgContentsForJson(json)); let subItem = this.openDrawingSubMenu.addAction(`${String(json)}`, () => { this.area.loadJson(json); From 81bce359f9d732ed90c0f362625523ebade3f733 Mon Sep 17 00:00:00 2001 From: abakkk Date: Wed, 16 Sep 2020 13:42:22 +0200 Subject: [PATCH 29/35] improve icons, minor --- data/icons/arc-symbolic.svg | 2 +- data/icons/color-symbolic.svg | 2 +- data/icons/dashed-line-symbolic.svg | 6 +++--- data/icons/document-export-symbolic.svg | 8 ++++++++ data/icons/fill-symbolic.svg | 2 +- data/icons/fillrule-evenodd-symbolic.svg | 2 +- data/icons/fillrule-nonzero-symbolic.svg | 2 +- data/icons/full-line-symbolic.svg | 2 +- data/icons/linecap-symbolic.svg | 4 ++-- data/icons/linejoin-symbolic.svg | 2 +- data/icons/palette-symbolic.svg | 2 +- data/icons/smooth-symbolic.svg | 8 ++++---- data/icons/stroke-symbolic.svg | 2 +- data/icons/tool-ellipse-symbolic.svg | 2 +- data/icons/tool-line-symbolic.svg | 2 +- data/icons/tool-mirror-symbolic.svg | 4 ++-- data/icons/tool-move-symbolic.svg | 2 +- data/icons/tool-polygon-symbolic.svg | 4 ++-- data/icons/tool-rectangle-symbolic.svg | 2 +- files.js | 4 ++-- menu.js | 10 +++++----- 21 files changed, 41 insertions(+), 33 deletions(-) create mode 100644 data/icons/document-export-symbolic.svg diff --git a/data/icons/arc-symbolic.svg b/data/icons/arc-symbolic.svg index fb2bea9..5da0547 100644 --- a/data/icons/arc-symbolic.svg +++ b/data/icons/arc-symbolic.svg @@ -3,5 +3,5 @@ https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/blob/master/Papirus/symbolic/actions/tool-arc-symbolic.svg https://www.gnu.org/licenses/gpl-3.0.html - + diff --git a/data/icons/color-symbolic.svg b/data/icons/color-symbolic.svg index 0410239..163f40f 100644 --- a/data/icons/color-symbolic.svg +++ b/data/icons/color-symbolic.svg @@ -7,7 +7,7 @@ Created by potrace 1.15, written by Peter Selinger 2001-2017 https://svgsilh.com/image/1745699.html https://creativecommons.org/publicdomain/zero/1.0 - + - - - + + + diff --git a/data/icons/document-export-symbolic.svg b/data/icons/document-export-symbolic.svg new file mode 100644 index 0000000..eb158e9 --- /dev/null +++ b/data/icons/document-export-symbolic.svg @@ -0,0 +1,8 @@ + + +https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/blob/master/Papirus/symbolic/actions/document-export-symbolic.svg +https://www.gnu.org/licenses/gpl-3.0.html + + + + diff --git a/data/icons/fill-symbolic.svg b/data/icons/fill-symbolic.svg index 7c652e2..0a66829 100644 --- a/data/icons/fill-symbolic.svg +++ b/data/icons/fill-symbolic.svg @@ -1,3 +1,3 @@ - + diff --git a/data/icons/fillrule-evenodd-symbolic.svg b/data/icons/fillrule-evenodd-symbolic.svg index 3f64343..da0de94 100644 --- a/data/icons/fillrule-evenodd-symbolic.svg +++ b/data/icons/fillrule-evenodd-symbolic.svg @@ -1,3 +1,3 @@ - + diff --git a/data/icons/fillrule-nonzero-symbolic.svg b/data/icons/fillrule-nonzero-symbolic.svg index 72e0cf2..be3096c 100644 --- a/data/icons/fillrule-nonzero-symbolic.svg +++ b/data/icons/fillrule-nonzero-symbolic.svg @@ -1,3 +1,3 @@ - + diff --git a/data/icons/full-line-symbolic.svg b/data/icons/full-line-symbolic.svg index 9323bfe..b17a91b 100644 --- a/data/icons/full-line-symbolic.svg +++ b/data/icons/full-line-symbolic.svg @@ -1,3 +1,3 @@ - + diff --git a/data/icons/linecap-symbolic.svg b/data/icons/linecap-symbolic.svg index fdfe9f6..0df89de 100644 --- a/data/icons/linecap-symbolic.svg +++ b/data/icons/linecap-symbolic.svg @@ -1,4 +1,4 @@ - - + + diff --git a/data/icons/linejoin-symbolic.svg b/data/icons/linejoin-symbolic.svg index 084caa7..8d5951e 100644 --- a/data/icons/linejoin-symbolic.svg +++ b/data/icons/linejoin-symbolic.svg @@ -1,3 +1,3 @@ - + diff --git a/data/icons/palette-symbolic.svg b/data/icons/palette-symbolic.svg index 0f00fd4..7846c46 100644 --- a/data/icons/palette-symbolic.svg +++ b/data/icons/palette-symbolic.svg @@ -7,7 +7,7 @@ Created by potrace 1.15, written by Peter Selinger 2001-2017 https://svgsilh.com/image/2026954.html https://creativecommons.org/publicdomain/zero/1.0/ - + - - - - + + + + diff --git a/data/icons/stroke-symbolic.svg b/data/icons/stroke-symbolic.svg index f693453..29ed599 100644 --- a/data/icons/stroke-symbolic.svg +++ b/data/icons/stroke-symbolic.svg @@ -1,3 +1,3 @@ - + diff --git a/data/icons/tool-ellipse-symbolic.svg b/data/icons/tool-ellipse-symbolic.svg index 20d5ae8..9d93d08 100644 --- a/data/icons/tool-ellipse-symbolic.svg +++ b/data/icons/tool-ellipse-symbolic.svg @@ -3,5 +3,5 @@ https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/blob/master/Papirus/symbolic/actions/tool-circle-move-symbolic.svg https://www.gnu.org/licenses/gpl-3.0.html - + diff --git a/data/icons/tool-line-symbolic.svg b/data/icons/tool-line-symbolic.svg index dbc7688..953d9b5 100644 --- a/data/icons/tool-line-symbolic.svg +++ b/data/icons/tool-line-symbolic.svg @@ -3,5 +3,5 @@ https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/blob/master/Papirus/symbolic/actions/tool-line-symbolic.svg https://www.gnu.org/licenses/gpl-3.0.html - + diff --git a/data/icons/tool-mirror-symbolic.svg b/data/icons/tool-mirror-symbolic.svg index fd269b0..403970b 100644 --- a/data/icons/tool-mirror-symbolic.svg +++ b/data/icons/tool-mirror-symbolic.svg @@ -3,6 +3,6 @@ https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/blob/master/Papirus/symbolic/actions/view-mirror-symbolic.svg https://www.gnu.org/licenses/gpl-3.0.html - - + + diff --git a/data/icons/tool-move-symbolic.svg b/data/icons/tool-move-symbolic.svg index 41bedc4..d77f2e3 100644 --- a/data/icons/tool-move-symbolic.svg +++ b/data/icons/tool-move-symbolic.svg @@ -8,7 +8,7 @@ https://www.gnu.org/licenses/gpl-3.0.html optimized with SVGO - + diff --git a/data/icons/tool-polygon-symbolic.svg b/data/icons/tool-polygon-symbolic.svg index e54e5b7..9c1a0b6 100644 --- a/data/icons/tool-polygon-symbolic.svg +++ b/data/icons/tool-polygon-symbolic.svg @@ -3,6 +3,6 @@ https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/blob/master/Papirus/symbolic/actions/tool-polygon-symbolic.svg https://www.gnu.org/licenses/gpl-3.0.html - - + + diff --git a/data/icons/tool-rectangle-symbolic.svg b/data/icons/tool-rectangle-symbolic.svg index 033e73a..e7dbfe0 100644 --- a/data/icons/tool-rectangle-symbolic.svg +++ b/data/icons/tool-rectangle-symbolic.svg @@ -3,5 +3,5 @@ https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/blob/master/Papirus/symbolic/actions/tool-rectangle-symbolic.svg https://www.gnu.org/licenses/gpl-3.0.html - + diff --git a/files.js b/files.js index 2442ac7..22a31bc 100644 --- a/files.js +++ b/files.js @@ -37,7 +37,7 @@ const Clipboard = St.Clipboard.get_default(); const CLIPBOARD_TYPE = St.ClipboardType.CLIPBOARD; const ICON_DIR = Me.dir.get_child('data').get_child('icons'); const ICON_NAMES = [ - 'arc', 'color', 'dashed-line', 'fillrule-evenodd', 'fillrule-nonzero', 'fill', 'full-line', 'linecap', 'linejoin', 'palette', 'smooth', 'stroke', + 'arc', 'color', 'dashed-line', 'document-export', 'fillrule-evenodd', 'fillrule-nonzero', 'fill', 'full-line', 'linecap', 'linejoin', 'palette', 'smooth', 'stroke', 'tool-ellipse', 'tool-line', 'tool-mirror', 'tool-move', 'tool-none', 'tool-polygon', 'tool-polyline', 'tool-rectangle', 'tool-resize', ]; const ThemedIconNames = { @@ -56,7 +56,7 @@ ICON_NAMES.forEach(name => { get: function() { if (!this[`_${name}`]) { let file = Gio.File.new_for_path(ICON_DIR.get_child(`${name}-symbolic.svg`).get_path()); - this[`_${name}`] = file.query_exists(null) ? new Gio.FileIcon({ file }) : new Gio.ThemedIcon({ name: 'error-symbolic' }); + this[`_${name}`] = file.query_exists(null) ? new Gio.FileIcon({ file }) : new Gio.ThemedIcon({ name: 'action-unavailable-symbolic' }); } return this[`_${name}`]; } diff --git a/menu.js b/menu.js index 4e51df1..2e4f536 100644 --- a/menu.js +++ b/menu.js @@ -275,10 +275,10 @@ var DrawingMenu = new Lang.Class({ this._addSeparator(this.menu); this._addDrawingNameItem(this.menu); - this._addOpenDrawingSubMenuItem(this.menu, Files.Icons.OPEN); - this._addSaveDrawingSubMenuItem(this.menu, Files.Icons.SAVE); + this._addOpenDrawingSubMenuItem(this.menu, 'document-open-symbolic'); + this._addSaveDrawingSubMenuItem(this.menu, 'document-save-as-symbolic'); - this.menu.addAction(getSummary('save-as-svg'), this.area.saveAsSvg.bind(this.area), 'image-x-generic-symbolic'); + this.menu.addAction(getSummary('save-as-svg'), this.area.saveAsSvg.bind(this.area), Files.Icons.DOCUMENT_EXPORT); this.menu.addAction(getSummary('open-preferences'), areaManager.openPreferences.bind(areaManager), 'document-page-setup-symbolic'); this.menu.addAction(getSummary('toggle-help'), () => { this.close(); this.area.toggleHelp(); }, 'preferences-desktop-keyboard-shortcuts-symbolic'); @@ -582,7 +582,7 @@ var DrawingMenu = new Lang.Class({ this.openDrawingSubMenuItem = item; this.openDrawingSubMenu = item.menu; item.setSensitive(Boolean(Files.Jsons.getSorted().length)); - item.icon.set_gicon(icon); + item.icon.set_icon_name(icon); item.menu.itemActivated = item.menu.close; @@ -650,7 +650,7 @@ var DrawingMenu = new Lang.Class({ this.saveDrawingSubMenuItem = item; this._updateSaveDrawingSubMenuItemSensitivity(); this.saveDrawingSubMenu = item.menu; - item.icon.set_gicon(icon); + item.icon.set_icon_name(icon); item.menu.itemActivated = item.menu.close; From 1d73d9f0e3f35712c87d1d98d1a31dfb71b797cd Mon Sep 17 00:00:00 2001 From: abakkk Date: Wed, 16 Sep 2020 17:38:54 +0200 Subject: [PATCH 30/35] pass color and font when duplacting Fix commit 42b4c9c0 . --- area.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/area.js b/area.js index 569ee4b..0556a75 100644 --- a/area.js +++ b/area.js @@ -516,6 +516,10 @@ var DrawingArea = new Lang.Class({ if (duplicate) { // deep cloning let copy = new this.grabbedElement.constructor(JSON.parse(JSON.stringify(this.grabbedElement))); + if (this.grabbedElement.color) + copy.color = this.grabbedElement.color; + if (this.grabbedElement.font) + copy.font = this.grabbedElement.font; if (this.grabbedElement.image) copy.image = this.grabbedElement.image; this.elements.push(copy); From f9e25fa8f69e3e7c287a430de2f264f5cbc880e2 Mon Sep 17 00:00:00 2001 From: abakkk Date: Wed, 16 Sep 2020 17:58:06 +0200 Subject: [PATCH 31/35] clean svg exports * Group "transform" attributes. * Round "transform" attribute values. * Remove unused stroke attributes. * Add an "eraser" class attribute to let user retrieve the element role. --- elements.js | 84 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 30 deletions(-) diff --git a/elements.js b/elements.js index efef1c0..b89800d 100644 --- a/elements.js +++ b/elements.js @@ -253,32 +253,60 @@ const _DrawingElement = new Lang.Class({ }, buildSVG: function(bgcolorString) { - let transAttribute = ''; + let transforms = []; this.transformations.slice(0).reverse().forEach(transformation => { - transAttribute += transAttribute ? ' ' : ' transform="'; let center = this._getTransformedCenter(transformation); if (transformation.type == Transformations.TRANSLATION) { - transAttribute += `translate(${transformation.slideX},${transformation.slideY})`; + transforms.push(['translate', transformation.slideX, transformation.slideY]); } else if (transformation.type == Transformations.ROTATION) { - transAttribute += `translate(${center[0]},${center[1]}) `; - transAttribute += `rotate(${transformation.angle * RADIAN}) `; - transAttribute += `translate(${-center[0]},${-center[1]})`; + transforms.push(['translate', center[0], center[1]]); + transforms.push(['rotate', transformation.angle * RADIAN]); + transforms.push(['translate', -center[0], -center[1]]); } else if (transformation.type == Transformations.SCALE_PRESERVE || transformation.type == Transformations.STRETCH) { - transAttribute += `translate(${center[0]},${center[1]}) `; - transAttribute += `rotate(${transformation.angle * RADIAN}) `; - transAttribute += `scale(${transformation.scaleX},${transformation.scaleY}) `; - transAttribute += `rotate(${-transformation.angle * RADIAN}) `; - transAttribute += `translate(${-center[0]},${-center[1]})`; + transforms.push(['translate', center[0], center[1]]); + transforms.push(['rotate', transformation.angle * RADIAN]); + transforms.push(['scale', transformation.scaleX, transformation.scaleY]); + transforms.push(['rotate', -transformation.angle * RADIAN]); + transforms.push(['translate', -center[0], -center[1]]); } else if (transformation.type == Transformations.REFLECTION || transformation.type == Transformations.INVERSION) { - transAttribute += `translate(${transformation.slideX}, ${transformation.slideY}) `; - transAttribute += `rotate(${transformation.angle * RADIAN}) `; - transAttribute += `scale(${transformation.scaleX}, ${transformation.scaleY}) `; - transAttribute += `rotate(${-transformation.angle * RADIAN}) `; - transAttribute += `translate(${-transformation.slideX}, ${-transformation.slideY})`; + transforms.push(['translate', transformation.slideX, transformation.slideY]); + transforms.push(['rotate', transformation.angle * RADIAN]); + transforms.push(['scale', transformation.scaleX, transformation.scaleY]); + transforms.push(['rotate', -transformation.angle * RADIAN]); + transforms.push(['translate', -transformation.slideX, -transformation.slideY]); } }); - transAttribute += transAttribute ? '"' : ''; + + let grouped = []; + transforms.forEach((transform, index) => { + let [type, ...values] = transform; + + if (grouped.length && grouped[grouped.length - 1][0] == type) + values.forEach((value, valueIndex) => grouped[grouped.length - 1][valueIndex + 1] += value); + else + grouped.push(transform); + }); + + let filtered = grouped.filter(transform => { + let [type, ...values] = transform; + + if (type == 'scale') + return values.some(value => value != 1); + else + return values.some(value => value != 0); + }); + + let transAttribute = ''; + if (filtered.length) { + transAttribute = ' transform="'; + filtered.forEach((transform, index) => { + let [type, ...values] = transform; + transAttribute += `${index == 0 ? '' : ' '}${type}(${values.map(value => Number(value).toFixed(2))})`; + }); + + transAttribute += '"'; + } return this._drawSvg(transAttribute, bgcolorString); }, @@ -288,14 +316,14 @@ const _DrawingElement = new Lang.Class({ let points = this.points.map((point) => [Math.round(point[0]*100)/100, Math.round(point[1]*100)/100]); let color = this.eraser ? bgcolorString : this.color.toString(); let fill = this.fill && !this.isStraightLine; - let attributes = ''; + let attributes = this.eraser ? `class="eraser" ` : ''; if (fill) { - attributes = `fill="${color}"`; + attributes += `fill="${color}"`; if (this.fillRule) attributes += ` fill-rule="${getFillRuleSvgName(this.fillRule)}"`; } else { - attributes = `fill="none"`; + attributes += `fill="none"`; } if (this.line && this.line.lineWidth) { @@ -307,8 +335,6 @@ const _DrawingElement = new Lang.Class({ attributes += ` stroke-linejoin="${getLineJoinSvgName(this.line.lineJoin)}"`; if (this.dash && this.dash.active && this.dash.array && this.dash.array[0] && this.dash.array[1]) attributes += ` stroke-dasharray="${this.dash.array[0]} ${this.dash.array[1]}" stroke-dashoffset="${this.dash.offset}"`; - } else { - attributes += ` stroke="none"`; } if (this.shape == Shapes.LINE && points.length == 4) { @@ -678,14 +704,12 @@ const TextElement = new Lang.Class({ let row = "\n "; let [x, y, height] = [Math.round(this.x*100)/100, Math.round(this.y*100)/100, Math.round(this.height*100)/100]; let color = this.eraser ? bgcolorString : this.color.toString(); - let attributes = ''; + let attributes = this.eraser ? `class="eraser" ` : ''; if (this.points.length == 2) { - attributes = `fill="${color}" ` + - `stroke="transparent" ` + - `stroke-opacity="0" ` + - `font-size="${height}" ` + - `font-family="${this.font.get_family()}"`; + attributes += `fill="${color}" ` + + `font-size="${height}" ` + + `font-family="${this.font.get_family()}"`; // this.font.to_string() is not valid to fill the svg 'font' shorthand property. // Each property must be filled separately. @@ -795,10 +819,10 @@ const ImageElement = new Lang.Class({ _drawSvg: function(transAttribute) { let points = this.points; let row = "\n "; - let attributes = ''; + let attributes = this.eraser ? `class="eraser" ` : ''; if (points.length == 2) { - attributes = `fill="none"`; + attributes += `fill="none"`; row += ` Date: Wed, 16 Sep 2020 22:12:54 +0200 Subject: [PATCH 32/35] group menu items at the bottom In addition, 'Save as a SVG file' -> "Export to a SVG file'. --- area.js | 6 +- extension.js | 4 +- locale/draw-on-your-screen.pot | 16 +- menu.js | 139 ++++++++++++------ schemas/gschemas.compiled | Bin 7384 -> 7376 bytes ...extensions.draw-on-your-screen.gschema.xml | 8 +- shortcuts.js | 2 +- stylesheet.css | 30 ++-- 8 files changed, 124 insertions(+), 81 deletions(-) diff --git a/area.js b/area.js index 0556a75..61dc879 100644 --- a/area.js +++ b/area.js @@ -1139,7 +1139,7 @@ var DrawingArea = new Lang.Class({ return [getGiconSvgContent, getImageSvgContent]; }, - saveAsSvg: function() { + exportToSvg: function() { // stop drawing or writing if (this.currentElement && this.currentElement.shape == Shapes.TEXT && this.isWriting) { this._stopWriting(); @@ -1204,8 +1204,8 @@ var DrawingArea = new Lang.Class({ this._saveAsJson(Files.Jsons.getNamed(name), false, callback); }, - saveAsJson: function() { - this._saveAsJson(Files.Jsons.getDated(), true); + saveAsJson: function(notify, callback) { + this._saveAsJson(Files.Jsons.getDated(), notify, callback); }, savePersistent: function() { diff --git a/extension.js b/extension.js index ca34b88..c7d9b42 100644 --- a/extension.js +++ b/extension.js @@ -200,8 +200,8 @@ const AreaManager = new Lang.Class({ // available when writing this.internalKeybindings2 = { - 'save-as-svg': this.activeArea.saveAsSvg.bind(this.activeArea), - 'save-as-json': this.activeArea.saveAsJson.bind(this.activeArea), + 'export-to-svg': this.activeArea.exportToSvg.bind(this.activeArea), + 'save-as-json': this.activeArea.saveAsJson.bind(this.activeArea, true, null), 'open-previous-json': this.activeArea.loadPreviousJson.bind(this.activeArea), 'open-next-json': this.activeArea.loadNextJson.bind(this.activeArea), 'toggle-background': this.activeArea.toggleBackground.bind(this.activeArea), diff --git a/locale/draw-on-your-screen.pot b/locale/draw-on-your-screen.pot index e4f93a3..231ace4 100644 --- a/locale/draw-on-your-screen.pot +++ b/locale/draw-on-your-screen.pot @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: Draw On Your Screen\n" "Report-Msgid-Bugs-To: https://framagit.org/abakkk/DrawOnYourScreen/issues\n" -"POT-Creation-Date: 2020-09-11 03:43+0200\n" +"POT-Creation-Date: 2020-09-16 21:11+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -272,13 +272,19 @@ msgstr "" msgid "Smooth" msgstr "" +msgid "Open drawing" +msgstr "" + +msgid "Save drawing as…" +msgstr "" + msgid "Palette" msgstr "" msgid "Color" msgstr "" -msgid "Open drawing" +msgid "Type a name" msgstr "" #. Translators: "Preferences" page in preferences @@ -535,6 +541,9 @@ msgstr "" msgid "Erase last brushstroke" msgstr "" +msgid "Export drawing to a SVG file" +msgstr "" + msgid "Increment line width" msgstr "" @@ -559,9 +568,6 @@ msgstr "" msgid "Save drawing" msgstr "" -msgid "Save drawing as a SVG file" -msgstr "" - msgid "Select color 1" msgstr "" diff --git a/menu.js b/menu.js index 2e4f536..86a6032 100644 --- a/menu.js +++ b/menu.js @@ -30,6 +30,7 @@ const St = imports.gi.St; const BoxPointer = imports.ui.boxpointer; const Config = imports.misc.config; +const Dash = imports.ui.dash; const Main = imports.ui.main; const PopupMenu = imports.ui.popupMenu; const Slider = imports.ui.slider; @@ -221,12 +222,17 @@ var DrawingMenu = new Lang.Class({ _redisplay: function() { this.menu.removeAll(); - this.actionButtons = []; let groupItem = new PopupMenu.PopupBaseMenuItem({ reactive: false, can_focus: false, style_class: 'draw-on-your-screen-menu-group-item' }); - getActor(groupItem).add_child(this._createActionButton(_("Undo"), this.area.undo.bind(this.area), 'edit-undo-symbolic')); - getActor(groupItem).add_child(this._createActionButton(_("Redo"), this.area.redo.bind(this.area), 'edit-redo-symbolic')); - getActor(groupItem).add_child(this._createActionButton(_("Erase"), this.area.deleteLastElement.bind(this.area), 'edit-clear-all-symbolic')); - getActor(groupItem).add_child(this._createActionButton(_("Smooth"), this.area.smoothLastElement.bind(this.area), Files.Icons.SMOOTH)); + this.undoButton = new ActionButton(_("Undo"), 'edit-undo-symbolic', this.area.undo.bind(this.area), this._updateActionSensitivity.bind(this)); + this.redoButton = new ActionButton(_("Redo"), 'edit-redo-symbolic', this.area.redo.bind(this.area), this._updateActionSensitivity.bind(this)); + this.eraseButton = new ActionButton(_("Erase"), 'edit-clear-all-symbolic', this.area.deleteLastElement.bind(this.area), this._updateActionSensitivity.bind(this)); + this.smoothButton = new ActionButton(_("Smooth"), Files.Icons.SMOOTH, this.area.smoothLastElement.bind(this.area), this._updateActionSensitivity.bind(this)); + this.eraseButton.child.add_style_class_name('draw-on-your-screen-menu-destructive-button'); + this.smoothButton.child.add_style_class_name('draw-on-your-screen-menu-destructive-button'); + getActor(groupItem).add_child(this.undoButton); + getActor(groupItem).add_child(this.redoButton); + getActor(groupItem).add_child(this.eraseButton); + getActor(groupItem).add_child(this.smoothButton); this.menu.addMenuItem(groupItem); this._addSeparator(this.menu, true); @@ -275,40 +281,33 @@ var DrawingMenu = new Lang.Class({ this._addSeparator(this.menu); this._addDrawingNameItem(this.menu); - this._addOpenDrawingSubMenuItem(this.menu, 'document-open-symbolic'); - this._addSaveDrawingSubMenuItem(this.menu, 'document-save-as-symbolic'); + this._addOpenDrawingSubMenuItem(this.menu, _("Open drawing"), 'document-open-symbolic'); + this._addSaveDrawingSubMenuItem(this.menu, _("Save drawing as…"), 'document-save-as-symbolic'); + this._addSeparator(this.menu); - this.menu.addAction(getSummary('save-as-svg'), this.area.saveAsSvg.bind(this.area), Files.Icons.DOCUMENT_EXPORT); - this.menu.addAction(getSummary('open-preferences'), areaManager.openPreferences.bind(areaManager), 'document-page-setup-symbolic'); - this.menu.addAction(getSummary('toggle-help'), () => { this.close(); this.area.toggleHelp(); }, 'preferences-desktop-keyboard-shortcuts-symbolic'); + groupItem = new PopupMenu.PopupBaseMenuItem({ reactive: false, can_focus: false, style_class: 'draw-on-your-screen-menu-group-item' }); + this.saveButton = new ActionButton(getSummary('save-as-json'), 'document-save-symbolic', this.area.saveAsJson.bind(this.area, false, this._onDrawingSaved.bind(this)), null); + this.svgButton = new ActionButton(getSummary('export-to-svg'), Files.Icons.DOCUMENT_EXPORT, this.area.exportToSvg.bind(this.area), null); + this.prefsButton = new ActionButton(getSummary('open-preferences'), 'document-page-setup-symbolic', areaManager.openPreferences.bind(areaManager), null); + this.helpButton = new ActionButton(getSummary('toggle-help'), 'preferences-desktop-keyboard-shortcuts-symbolic', () => { this.close(); this.area.toggleHelp(); }, null); + getActor(groupItem).add_child(this.saveButton); + getActor(groupItem).add_child(this.svgButton); + getActor(groupItem).add_child(this.prefsButton); + getActor(groupItem).add_child(this.helpButton); + this.menu.addMenuItem(groupItem); this._updateActionSensitivity(); this._updateSectionVisibility(); }, - // from system.js (GS 3.34-) - _createActionButton: function(accessibleName, callback, icon) { - let button = new St.Button({ track_hover: true, - x_align: Clutter.ActorAlign.CENTER, - accessible_name: accessibleName, - // use 'popup-menu' and 'popup-menu-item' style classes to provide theme colors - style_class: 'system-menu-action popup-menu-item popup-menu' }); - button.child = new St.Icon(typeof icon == 'string' ? { icon_name: icon } : { gicon: icon }); - button.connect('clicked', () => { - callback(); - this._updateActionSensitivity(); - }); - button.bind_property('reactive', button, 'can_focus', GObject.BindingFlags.DEFAULT); - this.actionButtons.push(button); - return new St.Bin({ child: button, x_expand: true }); - }, - _updateActionSensitivity: function() { - let [undoButton, redoButton, eraseButton, smoothButton] = this.actionButtons; - undoButton.reactive = this.area.elements.length > 0; - redoButton.reactive = this.area.undoneElements.length > 0; - eraseButton.reactive = this.area.elements.length > 0; - smoothButton.reactive = this.area.elements.length > 0 && this.area.elements[this.area.elements.length - 1].shape == this.drawingTools.NONE; + this.undoButton.child.reactive = this.area.elements.length > 0; + this.redoButton.child.reactive = this.area.undoneElements.length > 0; + this.eraseButton.child.reactive = this.area.elements.length > 0; + this.smoothButton.child.reactive = this.area.elements.length > 0 && this.area.elements[this.area.elements.length - 1].shape == this.drawingTools.NONE; + this.saveButton.child.reactive = this.area.elements.length > 0; + this.svgButton.child.reactive = this.area.elements.length > 0; + this.saveDrawingSubMenuItem.setSensitive(this.area.elements.length > 0); }, _updateSectionVisibility: function() { @@ -577,8 +576,8 @@ var DrawingMenu = new Lang.Class({ } }, - _addOpenDrawingSubMenuItem: function(menu, icon) { - let item = new PopupMenu.PopupSubMenuMenuItem(_("Open drawing"), true); + _addOpenDrawingSubMenuItem: function(menu, label, icon) { + let item = new PopupMenu.PopupSubMenuMenuItem(label, true); this.openDrawingSubMenuItem = item; this.openDrawingSubMenu = item.menu; item.setSensitive(Boolean(Files.Jsons.getSorted().length)); @@ -605,7 +604,7 @@ var DrawingMenu = new Lang.Class({ let subItem = this.openDrawingSubMenu.addAction(`${String(json)}`, () => { this.area.loadJson(json); this._updateDrawingNameMenuItem(); - this._updateSaveDrawingSubMenuItemSensitivity(); + this._updateActionSensitivity(); }, json.gicon); subItem.label.get_clutter_text().set_use_markup(true); @@ -617,7 +616,7 @@ var DrawingMenu = new Lang.Class({ }); getActor(subItem).add_child(expander); - let insertButton = new St.Button({ style_class: 'button draw-on-your-screen-menu-insert-button', + let insertButton = new St.Button({ style_class: 'button draw-on-your-screen-menu-inline-button', child: new St.Icon({ icon_name: 'insert-image-symbolic', style_class: 'popup-menu-icon' }) }); getActor(subItem).add_child(insertButton); @@ -630,7 +629,7 @@ var DrawingMenu = new Lang.Class({ this._updateSectionVisibility(); }); - let deleteButton = new St.Button({ style_class: 'button draw-on-your-screen-menu-delete-button', + let deleteButton = new St.Button({ style_class: 'button draw-on-your-screen-menu-inline-button draw-on-your-screen-menu-destructive-button', child: new St.Icon({ icon_name: 'edit-delete-symbolic', style_class: 'popup-menu-icon' }) }); getActor(subItem).add_child(deleteButton); @@ -645,10 +644,9 @@ var DrawingMenu = new Lang.Class({ this.openDrawingSubMenuItem.setSensitive(!this.openDrawingSubMenu.isEmpty()); }, - _addSaveDrawingSubMenuItem: function(menu, icon) { - let item = new PopupMenu.PopupSubMenuMenuItem(getSummary('save-as-json'), true); + _addSaveDrawingSubMenuItem: function(menu, label, icon) { + let item = new PopupMenu.PopupSubMenuMenuItem(label, true); this.saveDrawingSubMenuItem = item; - this._updateSaveDrawingSubMenuItemSensitivity(); this.saveDrawingSubMenu = item.menu; item.icon.set_icon_name(icon); @@ -674,13 +672,14 @@ var DrawingMenu = new Lang.Class({ _populateSaveDrawingSubMenu: function() { this.saveDrawingSubMenu.removeAll(); - let saveEntry = new DrawingMenuEntry({ initialTextGetter: Files.getDateString, - entryActivateCallback: (text) => { - this.area.saveAsJsonWithName(text, this._onDrawingSaved.bind(this)); - this.saveDrawingSubMenu.toggle(); - }, - invalidStrings: [Me.metadata['persistent-file-name'], '/'], - primaryIconName: 'insert-text' }); + let saveEntry = new Entry({ initialTextGetter: () => this.area.currentJson ? this.area.currentJson.name : "", + hint_text: _("Type a name"), + entryActivateCallback: (text) => { + this.area.saveAsJsonWithName(text, this._onDrawingSaved.bind(this)); + this.saveDrawingSubMenu.toggle(); + }, + invalidStrings: [Me.metadata['persistent-file-name'], '/'], + primaryIconName: 'insert-text' }); this.saveDrawingSubMenu.addMenuItem(saveEntry.item); }, @@ -712,8 +711,51 @@ const updateSubMenuAdjustment = function(itemActor) { adjustment.set_value(newScrollValue); }; +// An action button that uses upstream dash item tooltips. +const ActionButton = new Lang.Class({ + Name: 'DrawOnYourScreenDrawingMenuActionButton', + Extends: St.Bin, + _labelShowing: false, + _resetHoverTimeoutId: 0, + _showLabelTimeoutId: 0, + showLabel: Dash.DashItemContainer.prototype.showLabel, + hideLabel: Dash.DashItemContainer.prototype.hideLabel, + _syncLabel: Dash.Dash.prototype._syncLabel, + + _init: function(name, icon, callback, callbackAfter) { + this._labelText = name; + + let button = new St.Button({ track_hover: true, + x_align: Clutter.ActorAlign.CENTER, + accessible_name: name, + // use 'popup-menu' and 'popup-menu-item' style classes to provide theme colors + //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.connect('clicked', () => { + callback(); + if (callbackAfter) + callbackAfter(); + }); + button.bind_property('reactive', button, 'can_focus', GObject.BindingFlags.DEFAULT); + button.connect('notify::hover', () => this._syncLabel(this)); + + this.parent({ child: button, x_expand: true }); + }, + + get label() { + if (!this._label) { + this._label = new St.Label({ style_class: 'dash-label' }); + Main.layoutManager.uiGroup.add_actor(this._label); + this.connect('destroy', () => this._label.destroy()); + } + + return this._label; + } +}); + // based on searchItem.js, https://github.com/leonardo-bartoli/gnome-shell-extension-Recents -const DrawingMenuEntry = new Lang.Class({ +const Entry = new Lang.Class({ Name: 'DrawOnYourScreenDrawingMenuEntry', _init: function(params) { @@ -726,6 +768,7 @@ const DrawingMenuEntry = new Lang.Class({ this.itemActor = GS_VERSION < '3.33.0' ? this.item.actor : this.item; this.entry = new St.Entry({ + hint_text: params.hint_text || "", style_class: 'search-entry draw-on-your-screen-menu-entry', track_hover: true, reactive: true, diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled index 9271c1aa9324aa634c237e58b1de25474f22fd4f..53d5dbc4d661ccc3f82e74be45e90f97d3df8a5e 100644 GIT binary patch delta 1528 zcmaKsZ)j6j7{=eU)_-Z5HmOZ+ykIN0*gE1YwVN4QQ?1&T39VMBGB&ds(_l0;xvg<( zqo8d51MvvTOW`Uj)msg6^fUifFPco;kM&1V90lEVRyP4BFkoQ4{Kx@b4 zR_63}Q}2e zgQT#+Dy$0h)ZM>mD2MYyo1xY^XZzno&fCsIpMdiA`L7MN&#KxyB2}CnS`RMW>&hA` zV^y~!VgEkpA>f=jY#8d1RUJjbH<^WwgYO@n^BU@n(^J?-bG)x6y@2G(vLV;_1hGzC2cTCG0x z>@)03i`>S=Myo*2LLT}j_-NgCpRf@w!kW zW@|h>$ETpfz)T;0RM>dD;7YU5aqxG?y_IZ4??gTU{SCBPjp*5E8d|Q4ta|1i<#>Ab zse?9yc56I6$9F>eL5G#s@`8n9&=HU~&*a#Mp8M%GbV4<`y44MrCzp5Ku{DNM{qcn9 zH{<@~U_@k1XCk^UlsMG9rX^-JC-I!>Ldp8%!Km5W=iePl_MuzuY~__=)#df5uy`UGt{9RnrFdM zIG&#KRD-spVijBySOM_)N{I?-ZrcJipe@_VGqe~~1MDkl1UT4m0EsjJZqk*Y7SsWr zw>+EixriB$L}FooBoW>H-~C3^UC(0mOtW98bm#28vLe;42Z~pVs9N1nnr^oR)Jc8Y EzfGtk;{X5v delta 1568 zcmaKsVQ5=b7=};UPOE8_Hr?7J2Dg@8Y?aK7t+Ul`Yqe@u94u^uBBBdzOzYBhCRtpa zTRRw7Q9*ZvO=zK2kTKL&f>LGD?OzoJl_>;7*+73dEY?4EFtt8!dZ+&kJiPCHzk9!P z?#a1lp|#LD(_Yb0YK*zVXOmf|~C(_Ed!(aky#;7*l0(W-l6tZ-3tRvU2%K z@?+?0aAxKDr^@BMQ#9It$M{ z6#YWE{Ce_*>O;m{=i=n)nQ;~5Lln$9W9s3?;qX=E@*21W-3_l!-Cs~Hzmfb1dI~zb z$2*nFYlYrIKY*q4sTIebSX&!Xm9ZIs*G4vZsZpo`-59u zCechPYmBLbp2oR%9P9Hx=yB{0|7!nF$n|>j=#NmjyZn}82i>Zt)|eWNjyA#Bi?JEU zPPo+rB*i60hrz#myuq;n?c9^<*zO7qq5-Y-xfqSLHOzVA-%7> zR-+w_!O8B(Ps-)B4*lo_c=Xuff^vBu`7Bz1K+Vx>%H_2!mQYW~m^G}$3P1b^<)=&; zVF6OH=XMnzz-uXQqU*!PJmwA{uK^m-E|{2Jov6Gf+Jn9TM|T{URv&o{Jc_;zoo*j_ z^_dJa{v|FRcMI|=ETBuUeb8FN6|^hjvT*I+<3asOlQ%r;Lq-ho7G6(PhLQOfiAa^yc*p^gAq2go68p`gm%HU zU#q8z6T++iK{N;5?){D~^uQQ;9_F*J=kH>483V#m)umnvXC< zBFYq!iRkkKsYGVA!+$MuYza+?ydHGCmfFQ&t*-&61GgMXtS_{|*@|n1O~6-QJf3-P z;{pBHujXzW3*FbIgSZSf0-Mup15QV?2DSh@+-!zAXapVFI^g-{jQu9GA^%&bzQleW V_Ig_Eo=AhOinNxtQaTaY_YV-vD6jwk diff --git a/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml b/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml index b90abe1..9568ed4 100644 --- a/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml +++ b/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml @@ -131,6 +131,10 @@ ["Delete"] Erase last brushstroke + + ["<Primary><Alt>s"] + Export drawing to a SVG file + KP_Add','plus']]]> Increment line width @@ -163,10 +167,6 @@ ["<Primary>s"] Save drawing - - ["<Primary><Alt>s"] - Save drawing as a SVG file - KP_1','1']]]> Select color 1 diff --git a/shortcuts.js b/shortcuts.js index 5a04a67..ac66815 100644 --- a/shortcuts.js +++ b/shortcuts.js @@ -52,7 +52,7 @@ var INTERNAL_KEYBINDINGS = [ ['switch-font-family', 'switch-font-family-reverse', 'switch-font-weight', 'switch-font-style', 'switch-text-alignment'], ['switch-image-file', 'switch-image-file-reverse', 'paste-image-files'], ['toggle-panel-and-dock-visibility', 'toggle-background', 'toggle-grid', 'toggle-square-area'], - ['open-next-json', 'open-previous-json', 'save-as-json', 'save-as-svg', 'open-preferences', 'toggle-help'], + ['open-next-json', 'open-previous-json', 'save-as-json', 'export-to-svg', 'open-preferences', 'toggle-help'], ]; if (GS_VERSION < '3.36') { diff --git a/stylesheet.css b/stylesheet.css index 0170137..768f8ca 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -76,23 +76,20 @@ margin-top: 0; } -/* system-menu-action: from GS 3.34- */ -.draw-on-your-screen-menu .system-menu-action { - min-width: 0; - border: none; - border-radius: 32px; - padding: 12px; - margin: 0; +.draw-on-your-screen-menu-destructive-button:hover { + color: #e01b24; /* upstream destructive color, light: #e01b24, dark: #b2161d */ } -.draw-on-your-screen-menu .system-menu-action:hover, -.draw-on-your-screen-menu .system-menu-action:focus { - border: none; +/* override .button upstream style class */ +.draw-on-your-screen-menu-action-button { + min-height: 0; + min-width: 0; + border-radius: 32px; padding: 12px; } -.draw-on-your-screen-menu .system-menu-action > StIcon { - icon-size: 16px; +.draw-on-your-screen-menu-action-button > StIcon { + icon-size: 1em; } .draw-on-your-screen-menu-slider-label { @@ -120,16 +117,13 @@ padding: 0.35em 0.57em; } -.draw-on-your-screen-menu-delete-button, .draw-on-your-screen-menu-insert-button { +/* override .button upstream style class */ +.draw-on-your-screen-menu-inline-button { min-height: 1px; padding: 2px 4px; /* default 3px 24px */ } -.draw-on-your-screen-menu-delete-button:hover { - color: #e01b24; /* upstream destructive color, light: #e01b24, dark: #b2161d */ -} - -.draw-on-your-screen-menu-delete-button .popup-menu-icon, .draw-on-your-screen-menu-insert-button .popup-menu-icon { +.draw-on-your-screen-menu-inline-button .popup-menu-icon { icon-size: 0.85em; /* default 1.09 */ } From 23eea44661285ac116f339464ad8bb627518d31b Mon Sep 17 00:00:00 2001 From: abakkk Date: Thu, 17 Sep 2020 17:30:30 +0200 Subject: [PATCH 33/35] add "Persistent over toggles' setting * Rename "Persistent" to "Persistent over restarts". * If disabled, "Persistent over toggles" has priority over "Persistent over restarts" and "Drawing on the desktop". Close issue #42. --- area.js | 7 ++- extension.js | 52 +++++++++++++----- locale/draw-on-your-screen.pot | 12 +++- prefs.js | 21 +++++-- schemas/gschemas.compiled | Bin 7376 -> 7464 bytes ...extensions.draw-on-your-screen.gschema.xml | 11 +++- 6 files changed, 76 insertions(+), 27 deletions(-) diff --git a/area.js b/area.js index 61dc879..d28a846 100644 --- a/area.js +++ b/area.js @@ -1064,7 +1064,7 @@ var DrawingArea = new Lang.Class({ this.get_parent().set_background_color(this.reactive && this.hasBackground ? this.areaBackgroundColor : null); }, - leaveDrawingMode: function(save) { + leaveDrawingMode: function(save, erase) { if (this.stageKeyPressedHandler) { global.stage.disconnect(this.stageKeyPressedHandler); this.stageKeyPressedHandler = null; @@ -1100,7 +1100,10 @@ var DrawingArea = new Lang.Class({ this.currentElement = null; this._stopTextCursorTimeout(); - this._redisplay(); + if (erase) + this.erase(); + else + this._redisplay(); this.closeMenu(); this.get_parent().set_background_color(null); Files.Images.reset(); diff --git a/extension.js b/extension.js index c7d9b42..1363f17 100644 --- a/extension.js +++ b/extension.js @@ -112,21 +112,42 @@ const AreaManager = new Lang.Class({ this.indicatorSettingHandler = Me.settings.connect('changed::indicator-disabled', this.updateIndicator.bind(this)); 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.persistentOverRestartsSettingHandler = Me.settings.connect('changed::persistent-over-restarts', this.onPersistentOverRestartsSettingChanged.bind(this)); + this.persistentOverTogglesSettingHandler = Me.settings.connect('changed::persistent-over-toggles', this.onPersistentOverTogglesSettingChanged.bind(this)); + }, + + get persistentOverToggles() { + return Me.settings.get_boolean('persistent-over-toggles'); + }, + + get persistentOverRestarts() { + return Me.settings.get_boolean('persistent-over-toggles') && Me.settings.get_boolean('persistent-over-restarts'); + }, + + get onDesktop() { + return Me.settings.get_boolean('persistent-over-toggles') && Me.settings.get_boolean('drawing-on-desktop'); }, onDesktopSettingChanged: function() { - if (Me.settings.get_boolean("drawing-on-desktop")) + if (this.onDesktop) this.areas.forEach(area => area.get_parent().show()); else this.areas.forEach(area => area.get_parent().hide()); }, - onPersistentSettingChanged: function() { - if (Me.settings.get_boolean('persistent-drawing')) + onPersistentOverRestartsSettingChanged: function() { + if (this.persistentOverRestarts) this.areas[Main.layoutManager.primaryIndex].syncPersistent(); }, + onPersistentOverTogglesSettingChanged: function() { + if (!this.persistentOverToggles && !this.activeArea) + this.eraseDrawings(); + + this.onPersistentOverRestartsSettingChanged(); + this.onDesktopSettingChanged(); + }, + updateIndicator: function() { if (this.indicator) { this.indicator.disable(); @@ -147,13 +168,13 @@ const AreaManager = new Lang.Class({ let monitor = this.monitors[i]; let container = new St.Widget({ name: 'drawOnYourSreenContainer' + i }); let helper = new Helper.DrawingHelper({ name: 'drawOnYourSreenHelper' + i }, monitor); - let loadPersistent = i == Main.layoutManager.primaryIndex && Me.settings.get_boolean('persistent-drawing'); + let loadPersistent = i == Main.layoutManager.primaryIndex && this.persistentOverRestarts; let area = new Area.DrawingArea({ name: 'drawOnYourSreenArea' + i }, monitor, helper, loadPersistent); container.add_child(area); container.add_child(helper); Main.layoutManager._backgroundGroup.insert_child_above(container, Main.layoutManager._bgManagers[i].backgroundActor); - if (!Me.settings.get_boolean("drawing-on-desktop")) + if (!this.onDesktop) container.hide(); container.set_position(monitor.x, monitor.y); @@ -268,7 +289,7 @@ const AreaManager = new Lang.Class({ eraseDrawings: function() { for (let i = 0; i < this.areas.length; i++) this.areas[i].erase(); - if (Me.settings.get_boolean('persistent-drawing')) + if (this.persistentOverRestarts) this.areas[Main.layoutManager.primaryIndex].savePersistent(); }, @@ -321,7 +342,7 @@ const AreaManager = new Lang.Class({ Main.uiGroup.set_child_at_index(Main.layoutManager.keyboardBox, this.oldKeyboardIndex); Main.uiGroup.remove_actor(activeContainer); Main.layoutManager._backgroundGroup.insert_child_above(activeContainer, Main.layoutManager._bgManagers[activeIndex].backgroundActor); - if (!Me.settings.get_boolean("drawing-on-desktop")) + if (!this.onDesktop) activeContainer.hide(); } else { Main.layoutManager._backgroundGroup.remove_actor(activeContainer); @@ -364,10 +385,11 @@ const AreaManager = new Lang.Class({ toggleDrawing: function() { if (this.activeArea) { let activeIndex = this.areas.indexOf(this.activeArea); - let save = activeIndex == Main.layoutManager.primaryIndex && Me.settings.get_boolean('persistent-drawing'); + let save = activeIndex == Main.layoutManager.primaryIndex && this.persistentOverRestarts; + let erase = !this.persistentOverToggles; this.showOsd(null, Files.Icons.LEAVE, _("Leaving drawing mode")); - this.activeArea.leaveDrawingMode(save); + this.activeArea.leaveDrawingMode(save, erase); if (this.hiddenList) this.togglePanelAndDockOpacity(); @@ -513,9 +535,13 @@ const AreaManager = new Lang.Class({ Me.settings.disconnect(this.desktopSettingHandler); this.desktopSettingHandler = null; } - if (this.persistentSettingHandler) { - Me.settings.disconnect(this.persistentSettingHandler); - this.persistentSettingHandler = null; + if (this.persistentOverTogglesSettingHandler) { + Me.settings.disconnect(this.persistentOverTogglesSettingHandler); + this.persistentOverTogglesSettingHandler = null; + } + if (this.persistentOverRestartsSettingHandler) { + Me.settings.disconnect(this.persistentOverRestartsSettingHandler); + this.persistentOverRestartsSettingHandler = null; } if (this.activeArea) diff --git a/locale/draw-on-your-screen.pot b/locale/draw-on-your-screen.pot index 231ace4..0703d4c 100644 --- a/locale/draw-on-your-screen.pot +++ b/locale/draw-on-your-screen.pot @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: Draw On Your Screen\n" "Report-Msgid-Bugs-To: https://framagit.org/abakkk/DrawOnYourScreen/issues\n" -"POT-Creation-Date: 2020-09-16 21:11+0200\n" +"POT-Creation-Date: 2020-09-17 13:38+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -441,10 +441,16 @@ msgstr "" msgid "Disable on-screen notifications" msgstr "" -msgid "Persistent" +msgid "Persistent over toggles" msgstr "" -msgid "Persistent drawing through session restart" +msgid "Drawing remains when toggling drawing mode" +msgstr "" + +msgid "Persistent over restarts" +msgstr "" + +msgid "Drawing is automatically saved to a file" msgstr "" msgid "Enter/leave drawing mode" diff --git a/prefs.js b/prefs.js index c57f1b6..26a6ac9 100644 --- a/prefs.js +++ b/prefs.js @@ -395,18 +395,27 @@ const PrefsPage = new GObject.Class({ listBox.add(globalKeybindingsRow); }); - let persistentKey = schema.get_key('persistent-drawing'); - let persistentRow = new PrefRow({ label: persistentKey.get_summary(), desc: persistentKey.get_description() }); - let persistentSwitch = new Gtk.Switch(); - settings.bind('persistent-drawing', persistentSwitch, 'active', 0); - persistentRow.addWidget(persistentSwitch, true); - listBox.add(persistentRow); + let persistentOverTogglesKey = schema.get_key('persistent-over-toggles'); + let persistentOverTogglesRow = new PrefRow({ label: persistentOverTogglesKey.get_summary(), desc: persistentOverTogglesKey.get_description() }); + let persistentOverTogglesSwitch = new Gtk.Switch(); + settings.bind('persistent-over-toggles', persistentOverTogglesSwitch, 'active', 0); + persistentOverTogglesRow.addWidget(persistentOverTogglesSwitch, true); + listBox.add(persistentOverTogglesRow); + + let persistentOverRestartsKey = schema.get_key('persistent-over-restarts'); + let persistentOverRestartsRow = new PrefRow({ label: persistentOverRestartsKey.get_summary(), desc: persistentOverRestartsKey.get_description() }); + let persistentOverRestartsSwitch = new Gtk.Switch(); + settings.bind('persistent-over-restarts', persistentOverRestartsSwitch, 'active', 0); + persistentOverRestartsRow.addWidget(persistentOverRestartsSwitch, true); + persistentOverTogglesSwitch.bind_property('active', persistentOverRestartsSwitch, 'sensitive', GObject.BindingFlags.SYNC_CREATE); + listBox.add(persistentOverRestartsRow); let desktopKey = schema.get_key('drawing-on-desktop'); let desktopRow = new PrefRow({ label: desktopKey.get_summary(), desc: desktopKey.get_description() }); let desktopSwitch = new Gtk.Switch(); settings.bind('drawing-on-desktop', desktopSwitch, 'active', 0); desktopRow.addWidget(desktopSwitch, true); + persistentOverTogglesSwitch.bind_property('active', desktopSwitch, 'sensitive', GObject.BindingFlags.SYNC_CREATE); listBox.add(desktopRow); let osdKey = schema.get_key('osd-disabled'); diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled index 53d5dbc4d661ccc3f82e74be45e90f97d3df8a5e..76b17efbbdb4dbb3ddec71fd0a4fff0ce6d9962b 100644 GIT binary patch delta 2402 zcmZ9N4NR0}0LLFe6oK%>4-SMzjk!a+b&f5DTOEzcImWxyx&6zY)`~6?;TI=2Z`~Tkm^SsaZbJtxQ zo!(eF-=1Jh(pY2e^E@)t@GLO$Y3M}y_2olI#6_me1n`_;#_aDn_N(%eG-KwFZ^Ikk zX_y+p|9w;;t|T}ajX)_V6{)T?q_(GGIIe-DnOft(pG2LTHm7P(;w18g_-n|VICWd~ z#mVH2_!;CWO^dv)0=?KN=*9bxt!87raWnE(s9?O0NLs{B~ zDw0ks7b~~p+KRA$^=hBj`Lf^R_EBt_Did>?t|rV%@dVv<)itXhCAyUOcu^?e4Th>i zVQ)>?>96$$ok4FX><)%Q`p9}5RR#W#$LXmKxvP9$kCipmCajG7|I5KH2R|HQ_>8LB zK$g(jJZ+>lmCJmTus@(w5A9Ufc&cA?hyB6-4#HupDu_)o z_Hk2cLYBiDbcejoSQ4AWj5)sWtQi&S81O7FtK@Kp3YyL*Hb!(VwP-GU3hK+c`B6H3 zibs-{;UQG_o&O8vV&&WM26TAl{yODi8+i+U0A&t5^PqBZ3i%Pd3*|@Wx|EBlA2B_^ zO%y-3Vx8LoypV03cVX`^eIVAk)fv0RWw?0#?Vps3A0SWWaulMSt0uNt^gcth$7#sq&`Fh?IW5R9Ur1wV%Nwbo5iE>=U`_zx)Sn>{||;#Bg>a&Bb& zoQrkN)9{kC_ESmE4UaTt47MG`kD~KeD_+f~mRN)7#;=Gk2k$8t>uwF;Nu!N9ck$f> z<>GAeJbW4|8TIEM%Ei`X@nxv8`OCe^#mp&U0>DH~_-FPorG1b|jTs)TCjG-g6d0X2q<>D-I7ruB*#F%R}+2>TSm_Qw` z!PlcVTPOA?7w3_;;D^zY;<_cu#oFFZ{6|z;zN=KZSgYTQ-$VUT-+kp`t*DLP=1R1u zd4eOK{;iiW6a)x&qDk9!TMdcTP!vCkauYvys3Eat(1YJX+po3vDHrFE+s7I6EGm2} z{VU~SYhw6%ROvYRo^o+S9XA54D1OkzI_OdScQih0kG0fdE%g9CBGZ_quiTiRhQwOx zJiG|m<|p4#E>_27_%f6QI{CEHmkbl}?tyK=E6?7~-|^<9yQUKQv?H!Og^fi{=t z{Gwc}4_fe_QO3A+mz9fEe*hnmWy}-xecj5%Iumw$8j9aMv2LC`Et{LN{9(W9r$uu2X{;Tw z+KKc7w(7?s5u604yyd<}Z+#^_en7i-2_ t@b}UDSbeeTNAc6B+{zt;FDmFE98h6+N4pvl>u}j}`Jc;eFUt5ZxYjr<-gnM_VrP$9AnPoIiWLzZ|XG-n?JW`+2^f@AEw0 z=b>xqz>?OAs(VSsq|GqqA-{_$hTm#)86QUHGH+u}v0(%4gt`7zCyV`skmL-|OC zG3Dg*CmU1pe#>G9ZR@8_N%f@ESm)&IsMVWu<$f}WUYlul7#odz^!b_lLW{G=OK6m$ z@u`V5wKCj;rtVz2K#^GEBlsS4{KC+2<>GAeR{S!uHSCURjMbP-$1sg+sCQ3uhSn}l zBah=xFz3f=)A~V+HPI5X)hKDlV6Aeo>eS(lsNUtZCM4E`_Tw$cocm!^<6BZ@8#9TH zHbQN5IIwxM-&^Pjx|@6rn@#LSisMCJgU7eY9S#HwJ-(2;-tYDBq;b_3@b?jvjwT}Q zE#HC(kL@o;ZDY21gCSoi>}?2-*Nr_$-e3!aJpU``s*hD9uPF8g-J$=%sn!g4fkU%OREtU@)o8_iDn%B4bLtza+Sj`m;g zxusm}B=5yX(ZU0n-zyhe3!BMeP@U`ihswoKy|@IZLgNQrtb<;Ie}r-!hpnv^YpXl( zlW5)cn{!l1tgY_HuOeI3q`S(+dT|_2nnle8N7I#yXOi1znW!nC@$uO;-RcnQaFyZf zkiDpMrE;+fZNc9}Q%85@D;Fzo#XHgKMXQRHi*@L_@jmqB&nI!v;^^N2BlpJGLCSD-c3-a(X)P7>Dkk~pacs*(?U3Wrt z#F}UXKY%I{b;PO@Z39lDXA>P_b@bySXwixu|iSc5MkKk>&eE;yS3)X3;Va>D~??d;h&lahWSpU`s@ZV5nqL5gH;<(Le z%+oisJ2hUc6}#}|s46jDtnoGYHdJlpuCazX_7ZlW{_s0JDkRq7I*kuFd)~|XH2q&- C4#Zpl diff --git a/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml b/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml index 9568ed4..8a656cb 100644 --- a/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml +++ b/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml @@ -20,10 +20,15 @@ false Disable on-screen notifications - + + true + Persistent over toggles + Drawing remains when toggling drawing mode + + false - Persistent - Persistent drawing through session restart + Persistent over restarts + Drawing is automatically saved to a file ["<Alt><Super>d"] From 509fa0be295a9a4e485eb842658ca87c3c7d399a Mon Sep 17 00:00:00 2001 From: abakkk Date: Thu, 17 Sep 2020 21:59:38 +0200 Subject: [PATCH 34/35] adjust some translated strings --- locale/draw-on-your-screen.pot | 14 +++++++++----- prefs.js | 2 +- ...hell.extensions.draw-on-your-screen.gschema.xml | 7 ++++--- shortcuts.js | 1 + 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/locale/draw-on-your-screen.pot b/locale/draw-on-your-screen.pot index 0703d4c..e94b500 100644 --- a/locale/draw-on-your-screen.pot +++ b/locale/draw-on-your-screen.pot @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: Draw On Your Screen\n" "Report-Msgid-Bugs-To: https://framagit.org/abakkk/DrawOnYourScreen/issues\n" -"POT-Creation-Date: 2020-09-17 13:38+0200\n" +"POT-Creation-Date: 2020-09-17 22:27+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -305,7 +305,7 @@ msgstr "" #. Translators: version number in "About" page #, javascript-format -msgid "Version %d" +msgid "Version %f" msgstr "" #. Translators: you are free to translate the extension description, that is displayed in About page, or not @@ -417,6 +417,9 @@ msgstr "" msgid "Smooth free drawing outline" msgstr "" +msgid "Unlock image ratio" +msgstr "" + msgid "Rotate (while moving)" msgstr "" @@ -529,13 +532,13 @@ msgstr "" msgid "Automatic square area size" msgstr "" -msgid "Compute the size of the square area from the screen size" +msgid "Compute the area size from the screen size" msgstr "" msgid "Square area size" msgstr "" -msgid "The size of the square area in pixels" +msgid "The size of the area in pixels" msgstr "" msgid "Decrement line width" @@ -565,7 +568,7 @@ msgstr "" msgid "Open previous drawing" msgstr "" -msgid "Paste images from the clipboard" +msgid "Add images from the clipboard" msgstr "" msgid "Redo last brushstroke" @@ -688,6 +691,7 @@ msgstr "" msgid "Hide panel and dock" msgstr "" +#. Translators: It is an action: "Make the drawing area a square" msgid "Square drawing area" msgstr "" diff --git a/prefs.js b/prefs.js index 26a6ac9..30369ea 100644 --- a/prefs.js +++ b/prefs.js @@ -94,7 +94,7 @@ const AboutPage = new GObject.Class({ // Translators: you are free to translate the extension name, that is displayed in About page, or not let name = " " + _("Draw On You Screen") + ""; // Translators: version number in "About" page - let version = _("Version %d").format(Me.metadata.version); + let version = _("Version %f").format(Me.metadata.version); // Translators: you are free to translate the extension description, that is displayed in About page, or not let description = _("Start drawing with Super+Alt+D and save your beautiful work by taking a screenshot"); let link = "" + Me.metadata.url + ""; diff --git a/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml b/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml index 8a656cb..d7a9158 100644 --- a/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml +++ b/schemas/org.gnome.shell.extensions.draw-on-your-screen.gschema.xml @@ -114,13 +114,13 @@ true Automatic square area size - Compute the size of the square area from the screen size + Compute the area size from the screen size 512 Square area size - The size of the square area in pixels + The size of the area in pixels @@ -162,7 +162,7 @@ ["<Primary>v"] - Paste images from the clipboard + Add images from the clipboard ["<Primary><Shift>z"] @@ -331,6 +331,7 @@ ["<Primary>n"] + Square drawing area diff --git a/shortcuts.js b/shortcuts.js index ac66815..488485a 100644 --- a/shortcuts.js +++ b/shortcuts.js @@ -83,6 +83,7 @@ const getOthers = function() { [_("Extend circle to ellipse"), getKeyLabel('')], [_("Curve line"), getKeyLabel('')], [_("Smooth free drawing outline"), getKeyLabel('')], + [_("Unlock image ratio"), getKeyLabel('')], [_("Rotate (while moving)"), getKeyLabel('')], [_("Stretch (while resizing)"), getKeyLabel('')], [_("Inverse (while mirroring)"), getKeyLabel('')], From b4d680b5ba7c035351c73e84b31ae1aaa33c06f2 Mon Sep 17 00:00:00 2001 From: abakkk Date: Thu, 17 Sep 2020 22:34:00 +0200 Subject: [PATCH 35/35] version -> 6.3 --- NEWS | 14 ++++++++++++++ README.md | 2 +- metadata.json | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 9b28481..31c38da 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,17 @@ +v6.3 - September 2020 +===================== + +* Replace user stylesheet with proper drawing settings +* Multi-palettes +* Possibility to add insertable images from the clipboard +* Image directory is configurable +* Thumbnails in "Open drawing" sub-menu +* Drawings can be directly inserted as an image. +* Add a lot of icons in the menu and the OSD notifications +* Group menu items at the bottom +* Add tooltips to menu buttons +* New "Persistent over toggles' setting #42 + v6.2 - August 2020 ================== diff --git a/README.md b/README.md index 3877926..88f8f48 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Then save your beautiful work by taking a screenshot. ## Features -* Basic shapes (rectangle, circle, ellipse, line, curve, text, image, free) +* Basic shapes (rectangle, circle, ellipse, line, curve, polygon, polyline, text, image, free) * Basic transformations (move, rotate, resize, stretch, mirror, inverse) * Smooth stroke * Draw over applications diff --git a/metadata.json b/metadata.json index 4690c5b..c581739 100644 --- a/metadata.json +++ b/metadata.json @@ -17,5 +17,5 @@ "3.34", "3.36" ], - "version": 6.2 + "version": 6.3 }