From 27ea6a8be943fbf5a00a86bba5a14fcd75cec801 Mon Sep 17 00:00:00 2001 From: abakkk Date: Tue, 26 Mar 2019 22:28:24 +0100 Subject: [PATCH 1/6] add context menu --- draw.js | 191 ++++++++++++++++++++++++++++++++- extension.js | 11 +- icons/dashed-line-symbolic.svg | 3 + icons/fill-symbolic.svg | 3 + icons/linecap-symbolic.svg | 4 + icons/linejoin-symbolic.svg | 4 + locale/draw-on-your-screen.pot | 18 ++++ stylesheet.css | 21 ++++ 8 files changed, 250 insertions(+), 5 deletions(-) create mode 100644 icons/dashed-line-symbolic.svg create mode 100644 icons/fill-symbolic.svg create mode 100644 icons/linecap-symbolic.svg create mode 100644 icons/linejoin-symbolic.svg diff --git a/draw.js b/draw.js index af90830..fa5ca6f 100644 --- a/draw.js +++ b/draw.js @@ -22,21 +22,35 @@ const Cairo = imports.cairo; const Clutter = imports.gi.Clutter; +const GdkPixbuf = imports.gi.GdkPixbuf; const GLib = imports.gi.GLib; +const GObject = imports.gi.GObject; const Gtk = imports.gi.Gtk; const Lang = imports.lang; const Mainloop = imports.mainloop; +const Shell = imports.gi.Shell; const Signals = imports.signals; const St = imports.gi.St; + +const BoxPointer = imports.ui.boxpointer; +const Main = imports.ui.main; +const PopupMenu = imports.ui.popupMenu; +const Slider = imports.ui.slider; const Screenshot = imports.ui.screenshot; const Tweener = imports.ui.tweener; const ExtensionUtils = imports.misc.extensionUtils; const Extension = ExtensionUtils.getCurrentExtension(); const Convenience = Extension.imports.convenience; +const ExtensionJs = Extension.imports.extension; const Prefs = Extension.imports.prefs; const _ = imports.gettext.domain(Extension.metadata["gettext-domain"]).gettext; +const FILL_ICON_PATH = Extension.dir.get_child('icons').get_child('fill-symbolic.svg').get_path(); +const LINEJOIN_ICON_PATH = Extension.dir.get_child('icons').get_child('linejoin-symbolic.svg').get_path(); +const LINECAP_ICON_PATH = Extension.dir.get_child('icons').get_child('linecap-symbolic.svg').get_path(); +const DASHED_LINE_ICON_PATH = Extension.dir.get_child('icons').get_child('dashed-line-symbolic.svg').get_path(); + var Shapes = { NONE: 0, LINE: 1, ELLIPSE: 2, RECTANGLE: 3, TEXT: 4 }; var ShapeNames = { 0: "Free drawing", 1: "Line", 2: "Ellipse", 3: "Rectangle", 4: "Text" }; var LineCapNames = { 0: 'Butt', 1: 'Round', 2: 'Square' }; @@ -60,6 +74,7 @@ var DrawingArea = new Lang.Class({ this.settings = Convenience.getSettings(); this.emitter = new DrawingAreaEmitter(); this.monitor = monitor; + this.menu = new DrawingMenu(this); this.helper = helper; this.elements = []; @@ -70,6 +85,7 @@ var DrawingArea = new Lang.Class({ this.hasBackground = false; this.textHasCursor = false; this.dashedLine = false; + this.fill = false; this.colors = [Clutter.Color.new(0, 0, 0, 255)]; if (loadJson) @@ -159,7 +175,9 @@ var DrawingArea = new Lang.Class({ } else if (button == 2) { this.toggleShape(); } else if (button == 3) { - this._startDrawing(x, y, true, shiftPressed); + /*this._startDrawing(x, y, true, shiftPressed); + return Clutter.EVENT_STOP;*/ + this.menu.open(x, y); return Clutter.EVENT_STOP; } @@ -941,3 +959,174 @@ var DrawingHelper = new Lang.Class({ }, }); + +var DrawingMenu = new Lang.Class({ + Name: 'DrawOnYourScreenDrawingMenu', + + _init: function(area) { + this.area = area; + 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({ actor: this.area }); + this.menuManager.addMenu(this.menu); + + Main.layoutManager.uiGroup.add_actor(this.menu.actor); + this.menu.actor.add_style_class_name('background-menu draw-on-your-screen-menu'); + this.menu.actor.hide(); + + // do not close the menu on item activated + this.menu.itemActivated = () => {}; + this.menu.connect('open-state-changed', this._onMenuOpenStateChanged.bind(this)); + }, + + _onMenuOpenStateChanged: function(menu, open) { + if (!open) + // actionMode has changed, set previous actionMode in order to keep internal shortcuts working + Main.actionMode = ExtensionJs.DRAWING_ACTION_MODE | Shell.ActionMode.NORMAL; + }, + + open: function(x, y) { + this._redisplay(); + Main.layoutManager.setDummyCursorGeometry(x, y, 0, 0); + let monitor = this.area.monitor; + this.menu._arrowAlignment = (y - monitor.y) / monitor.height; + this.menu.open(BoxPointer.PopupAnimation.NONE); + this.menuManager.ignoreRelease(); + }, + + _redisplay: function() { + this.menu.removeAll(); + + this.menu.addAction(_("Undo"), this.area.undo.bind(this.area), 'edit-undo-symbolic'); + this.menu.addAction(_("Redo"), this.area.redo.bind(this.area), 'edit-redo-symbolic'); + this.menu.addAction(_("Erase"), this.area.deleteLastElement.bind(this.area), 'edit-clear-all-symbolic'); + this.menu.addAction(_("Smooth"), this.area.smoothLastElement.bind(this.area), 'format-text-strikethrough-symbolic'); + this._addSeparator(); + + this._addSubMenuItem(null, null, ShapeNames, this.area, 'currentShape'); + this._addColorSubMenuItem(); + let fillIcon = GdkPixbuf.Pixbuf.new_from_file_at_size(FILL_ICON_PATH, 24, 24); + this._addSwitchItem(_("Fill"), fillIcon, this.area, 'fill'); + this._addSeparator(); + + this._addSliderItem(this.area, 'currentLineWidth'); + let linejoinIcon = GdkPixbuf.Pixbuf.new_from_file_at_size(LINEJOIN_ICON_PATH, 24, 24); + this._addSubMenuItem(null, linejoinIcon, LineJoinNames, this.area, 'currentLineJoin'); + let linecapIcon = GdkPixbuf.Pixbuf.new_from_file_at_size(LINECAP_ICON_PATH, 24, 24); + this._addSubMenuItem(null, linecapIcon, LineCapNames, this.area, 'currentLineCap'); + let dashedLineIcon = GdkPixbuf.Pixbuf.new_from_file_at_size(DASHED_LINE_ICON_PATH, 24, 24); + this._addSwitchItem(_("Dashed"), dashedLineIcon, this.area, 'dashedLine'); + this._addSeparator(); + + let FontFamilyNamesCopy = Object.create(FontFamilyNames); + FontFamilyNamesCopy[0] = this.area.fontFamily; + this._addSubMenuItem(null, 'font-x-generic-symbolic', FontFamilyNamesCopy, this.area, 'currentFontFamilyId'); + this._addSubMenuItem(null, 'format-text-bold-symbolic', FontWeightNames, this.area, 'currentFontWeight'); + this._addSubMenuItem(null, 'format-text-italic-symbolic', FontStyleNames, this.area, 'currentFontStyle'); + this._addSeparator(); + + let manager = ExtensionJs.manager; + this._addSwitchItemWithCallback(_("Hide panel and dock"), manager.hiddenList ? true : false, manager.togglePanelAndDockOpacity.bind(manager)); + this._addSwitchItemWithCallback(_("Add a drawing background"), this.area.hasBackground, this.area.toggleBackground.bind(this.area)); + this._addSwitchItemWithCallback(_("Square drawing area"), this.area.isSquareArea, this.area.toggleSquareArea.bind(this.area)); + this._addSeparator(); + + this.menu.addAction(_("Save drawing as a SVG file"), this.area.saveAsSvg.bind(this.area), 'document-save-symbolic'); + this.menu.addAction(_("Open stylesheet.css"), manager.openStylesheetFile.bind(manager), 'document-open-symbolic'); + this.menu.addAction(_("Show help"), this.area.toggleHelp.bind(this.area), 'preferences-desktop-keyboard-shortcuts-symbolic'); + }, + + _addSwitchItem: function(label, icon, target, targetProperty) { + let item = new PopupMenu.PopupSwitchMenuItem(label, target[targetProperty]); + + if (icon) { + item.icon = new St.Icon({ style_class: 'popup-menu-icon' }); + item.actor.insert_child_at_index(item.icon, 1); + if (icon instanceof GObject.Object && GObject.type_is_a(icon, GdkPixbuf.Pixbuf)) + item.icon.set_gicon(icon); + else + item.icon.set_icon_name(icon); + } + + item.connect('toggled', (item, state) => { + target[targetProperty] = state; + }); + this.menu.addMenuItem(item); + }, + + _addSwitchItemWithCallback: function(label, active, onToggled) { + let item = new PopupMenu.PopupSwitchMenuItem(label, active); + item.connect('toggled', onToggled); + this.menu.addMenuItem(item); + }, + + _addSliderItem: function(target, targetProperty) { + let item = new PopupMenu.PopupBaseMenuItem({ activate: false }); + let label = new St.Label({ text: target[targetProperty] + " px", style_class: 'draw-on-your-screen-menu-slider-label' }); + let slider = new Slider.Slider(target[targetProperty] / 50); + + slider.connect('value-changed', (slider, value, property) => { + target[targetProperty] = Math.max(Math.round(value * 50), 1); + label.set_text(target[targetProperty] + " px"); + }); + + item.actor.add(slider.actor, { expand: true }); + item.actor.add(label); + item.actor.connect('key-press-event', slider.onKeyPressEvent.bind(slider)); + this.menu.addMenuItem(item); + }, + + _addSubMenuItem: function(label, icon, obj, target, targetProperty) { + let text = label ? label + _(obj[target[targetProperty]]).toLowerCase() : _(obj[target[targetProperty]]); + let item = new PopupMenu.PopupSubMenuMenuItem(text, icon ? true : false); + if (icon && icon instanceof GObject.Object && GObject.type_is_a(icon, GdkPixbuf.Pixbuf)) + item.icon.set_gicon(icon); + else if (icon) + item.icon.set_icon_name(icon); + + item.menu.itemActivated = () => { + item.menu.close(); + }; + + Mainloop.timeout_add(0, () => { + for (let i in obj) { + item.menu.addAction(_(obj[i]), () => { + let text = label ? label + _(obj[i]).toLowerCase() : _(obj[i]); + item.label.set_text(text); + target[targetProperty] = i; + }); + } + return GLib.SOURCE_REMOVE; + }); + this.menu.addMenuItem(item); + }, + + _addColorSubMenuItem: function() { + let item = new PopupMenu.PopupSubMenuMenuItem(_("Color"), true); + item.icon.set_icon_name('document-edit-symbolic'); + item.icon.set_style(`color:${this.area.currentColor.to_string().slice(0, 7)};`); + + item.menu.itemActivated = () => { + item.menu.close(); + }; + + Mainloop.timeout_add(0, () => { + for (let i = 1; i < this.area.colors.length; i++) { + let text = `${this.area.colors[i].to_string()}`; + let colorItem = item.menu.addAction(text, () => { + this.area.currentColor = this.area.colors[i]; + item.icon.set_style(`color:${this.area.currentColor.to_string().slice(0, 7)};`); + }); + colorItem.label.get_clutter_text().set_use_markup(true); + } + return GLib.SOURCE_REMOVE; + }); + this.menu.addMenuItem(item); + }, + + _addSeparator: function() { + let separator = new PopupMenu.PopupSeparatorMenuItem(); + this.menu.addMenuItem(separator); + } +}); + diff --git a/extension.js b/extension.js index 40c8273..6ff4f77 100644 --- a/extension.js +++ b/extension.js @@ -32,6 +32,9 @@ const Convenience = Extension.imports.convenience; const Draw = Extension.imports.draw; const _ = imports.gettext.domain(Extension.metadata["gettext-domain"]).gettext; +// DRAWING_ACTION_MODE is a custom Shell.ActionMode +var DRAWING_ACTION_MODE = Math.pow(2,14); + let manager; function init() { @@ -164,7 +167,7 @@ var AreaManager = new Lang.Class({ Main.wm.addKeybinding(key, this.settings, Meta.KeyBindingFlags.NONE, - 256, + DRAWING_ACTION_MODE, this.internalKeybindings[key]); } @@ -172,7 +175,7 @@ var AreaManager = new Lang.Class({ Main.wm.addKeybinding('select-color' + i, this.settings, Meta.KeyBindingFlags.NONE, - 256, + DRAWING_ACTION_MODE, () => this.activeArea.selectColor(i)); } }, @@ -270,8 +273,8 @@ var AreaManager = new Lang.Class({ activeContainer.get_parent().remove_actor(activeContainer); Main.uiGroup.add_child(activeContainer); - // 256 is a custom Shell.ActionMode - if (!Main.pushModal(this.areas[currentIndex], { actionMode: 256 | 1 })) + // add Shell.ActionMode.NORMAL to keep system keybindings enabled (e.g. Alt + F2 ...) + if (!Main.pushModal(this.areas[currentIndex], { actionMode: DRAWING_ACTION_MODE | Shell.ActionMode.NORMAL })) return; this.activeArea = this.areas[currentIndex]; this.addInternalKeybindings(); diff --git a/icons/dashed-line-symbolic.svg b/icons/dashed-line-symbolic.svg new file mode 100644 index 0000000..9e019e9 --- /dev/null +++ b/icons/dashed-line-symbolic.svg @@ -0,0 +1,3 @@ + + + diff --git a/icons/fill-symbolic.svg b/icons/fill-symbolic.svg new file mode 100644 index 0000000..7f80c03 --- /dev/null +++ b/icons/fill-symbolic.svg @@ -0,0 +1,3 @@ + + + diff --git a/icons/linecap-symbolic.svg b/icons/linecap-symbolic.svg new file mode 100644 index 0000000..7ef7d69 --- /dev/null +++ b/icons/linecap-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/icons/linejoin-symbolic.svg b/icons/linejoin-symbolic.svg new file mode 100644 index 0000000..f4ab5f4 --- /dev/null +++ b/icons/linejoin-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/locale/draw-on-your-screen.pot b/locale/draw-on-your-screen.pot index a1ab2ec..47f3a3c 100644 --- a/locale/draw-on-your-screen.pot +++ b/locale/draw-on-your-screen.pot @@ -69,6 +69,24 @@ msgstr "" msgid "System" msgstr "" +msgid "Undo" +msgstr "" + +msgid "Redo" +msgstr "" + +msgid "Erase" +msgstr "" + +msgid "Smooth" +msgstr "" + +msgid "Fill" +msgstr "" + +msgid "Dashed" +msgstr "" + #: prefs.js # GLOBAL_KEYBINDINGS diff --git a/stylesheet.css b/stylesheet.css index 13db721..e753273 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -77,4 +77,25 @@ min-height: 0.6em; } + /* context menu */ + + .draw-on-your-screen-menu { + font-size: 95%; + } + + .draw-on-your-screen-menu .popup-menu-item { + padding-top: .35em; + padding-bottom: .35em; +} + + .draw-on-your-screen-menu .popup-separator-menu-item { + margin-top: 0; + margin-bottom: 0; + } + + .draw-on-your-screen-menu-slider-label { + min-width: 3em; + text-align: right; + } + From 05e6c7b33f8bbade08222267c52e2baf08377a30 Mon Sep 17 00:00:00 2001 From: abakkk Date: Wed, 27 Mar 2019 00:59:48 +0100 Subject: [PATCH 2/6] reinstate fill and change dashed shortcut --- draw.js | 13 ++++++++----- extension.js | 1 + locale/draw-on-your-screen.pot | 12 +++++++++--- prefs.js | 1 + schemas/gschemas.compiled | Bin 3080 -> 3140 bytes ...extensions.draw-on-your-screen.gschema.xml | 7 ++++++- 6 files changed, 25 insertions(+), 9 deletions(-) diff --git a/draw.js b/draw.js index fa5ca6f..f2e52b0 100644 --- a/draw.js +++ b/draw.js @@ -170,13 +170,11 @@ var DrawingArea = new Lang.Class({ } if (button == 1) { - this._startDrawing(x, y, false, shiftPressed); + this._startDrawing(x, y, shiftPressed); return Clutter.EVENT_STOP; } else if (button == 2) { this.toggleShape(); } else if (button == 3) { - /*this._startDrawing(x, y, true, shiftPressed); - return Clutter.EVENT_STOP;*/ this.menu.open(x, y); return Clutter.EVENT_STOP; } @@ -231,7 +229,7 @@ var DrawingArea = new Lang.Class({ return Clutter.EVENT_STOP; }, - _startDrawing: function(stageX, stageY, fill, eraser) { + _startDrawing: function(stageX, stageY, eraser) { let [success, startX, startY] = this.transform_stage_point(stageX, stageY); if (!success) @@ -248,7 +246,7 @@ var DrawingArea = new Lang.Class({ color: this.currentColor.to_string(), line: { lineWidth: this.currentLineWidth, lineJoin: this.currentLineJoin, lineCap: this.currentLineCap }, dash: { array: this.dashedLine ? this.dashArray : [0, 0] , offset: this.dashedLine ? this.dashOffset : 0 }, - fill: fill, + fill: this.fill, eraser: eraser, transform: { active: false, center: [0, 0], angle: 0, startAngle: 0, ratio: 1 }, text: '', @@ -424,6 +422,11 @@ var DrawingArea = new Lang.Class({ this.selectShape((this.currentShape == Object.keys(Shapes).length - 1) ? 0 : this.currentShape + 1); }, + toggleFill: function() { + this.fill = !this.fill; + this.emitter.emit('show-osd', this.fill ? _("Fill") : _("Stroke"), null); + }, + toggleDash: function() { this.dashedLine = !this.dashedLine; this.emitter.emit('show-osd', this.dashedLine ? _("Dashed line") : _("Full line"), null); diff --git a/extension.js b/extension.js index 6ff4f77..176c37d 100644 --- a/extension.js +++ b/extension.js @@ -150,6 +150,7 @@ var AreaManager = new Lang.Class({ 'toggle-linejoin': this.activeArea.toggleLineJoin.bind(this.activeArea), 'toggle-linecap': this.activeArea.toggleLineCap.bind(this.activeArea), 'toggle-dash' : this.activeArea.toggleDash.bind(this.activeArea), + 'toggle-fill' : this.activeArea.toggleFill.bind(this.activeArea), 'select-none-shape': () => this.activeArea.selectShape(Draw.Shapes.NONE), 'select-line-shape': () => this.activeArea.selectShape(Draw.Shapes.LINE), 'select-ellipse-shape': () => this.activeArea.selectShape(Draw.Shapes.ELLIPSE), diff --git a/locale/draw-on-your-screen.pot b/locale/draw-on-your-screen.pot index 47f3a3c..a9615d9 100644 --- a/locale/draw-on-your-screen.pot +++ b/locale/draw-on-your-screen.pot @@ -43,6 +43,12 @@ msgstr "" msgid "Text" msgstr "" +msgid "Fill" +msgstr "" + +msgid "Stroke" +msgstr "" + msgid "Dashed line" msgstr "" @@ -81,9 +87,6 @@ msgstr "" msgid "Smooth" msgstr "" -msgid "Fill" -msgstr "" - msgid "Dashed" msgstr "" @@ -148,6 +151,9 @@ msgstr "" msgid "Unselect shape (free drawing)" msgstr "" +msgid "Select fill/stroke" +msgstr "" + msgid "Change font family (generic name)" msgstr "" diff --git a/prefs.js b/prefs.js index adca46c..643bfe7 100644 --- a/prefs.js +++ b/prefs.js @@ -56,6 +56,7 @@ var INTERNAL_KEYBINDINGS = { 'select-rectangle-shape': "Select rectangle", 'select-text-shape': "Select text", 'select-none-shape': "Unselect shape (free drawing)", + 'toggle-fill': "Select fill/stroke", '-separator-3': '', 'toggle-font-family': "Change font family (generic name)", 'toggle-font-weight': "Change font weight", diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled index dfce124bc6d9c4dd8dc2e7db0ed13bc53f71b76d..6645b28b84262d3cc1ca01aba32b9b08235c0a7f 100644 GIT binary patch literal 3140 zcmZuzU1%It6rO5gV{4N%t<|(qliJ!%VRlW^w27p#)%3@zkPs@t2h-V|ySvlO&a5+& z-)bl-TJQ(yi$NN+2>w8!0k!nOpY%n7P|S;3@g)Ht6tuM9gHW`7-_4!fnRFMvd|%F- zJ@?#m&poq;pEEqmZ~{$z?gtMp>%<+(whCOeIN3qwv!r%JI}J`$Yg+Zansy7HefPki zJ)`Xh_X4h$OXeK6Ad-Gw*mhEk2g30!*YT64XN>8tqffXap6+KnAsl{JOYD?X`487- zK17wmUEno9El>wE02=_Lq-_GY7h*H81$Yo>iC`=A!wTEL+krj!#O9BRfn4n75>6QYg&)D5stgJ*!j>5CuHPR)E~!IyzEx0b%7 zoq8?o3*aT-po&k;_}9Vp*wH)s^H=CkT?czJxDA+kZT2kf)QzzBfi2*WibKsfbw zg>k59KMg($*!@F~(@xF&FM)pmuK)CAKkd}DurGpd05cc1y0lZXZfyJp;Dv85+q6@& z-xA<1;QhBwUZb6w=h6o@fWHgPG7dH46v3|p!#CTT=ua)r5&RkO-dFvzv{SP`=fFP# zTN*!*{X@SoyU;0fTv z;}^5EQ`7%l@HwDv@-f+O)Xeh|_-kM;Yw^lUP5T0DOTe$6w8;HZbHCTYt2nDR|NJlg zsafZG@HSxGpH1J;PR(=g1ar1={?r3^0tlhq2XK~fvvt6B0Ih;EUY<{A-_mSa5500W zaULP8#<_zd)i{eD0$KsixCej)umj-1;M&UB#97t|Yy>#FIMbQ|Q(%x5gcIntOyNb5k}rysd{Lyz zFN#!!7ez|be3f_B#b*6r!WOZ-EtPjPr(N-Uc9rwl73Sj!Q}#)zUflzED;xAo;^bHc z70$yx4Toj(^F|RXm;Aj7>$XRpqyFt>@AhzA?$L5`d>@*^9}e6icf(I29WE+Qbme+> zxSla8bi>#E(Hy^3%Eu3%N6uz<)$UH0A`=HnKHvs_gihX~3Zu8LQw(e#4r$y12L z?=x~@sMj5HFg79uls(cB@k1URx}2yS@!M><3;oBTCsjt*}p6F7oOn@U7bGt57e4yOIv*=yNb)O@ZDkC$Qps;v?Mr#!N15!j((^-Ym`9O=!jCqqh!j`$oruSg zw=ioIEPDd0Mb^v4{Y=A;&m(Nqa!t(CNZS63BZh}=_JmQ&%L&h;;JQKnwmDSt6Zo!; zQOt0dW%4pd^O;m}Dit;AhyFTXhIy$|4KS2cAxi57@%#AqLyst-r1J(l@0F)y(0rx4eKjmnEw;9-?a6k9~pb6LtY%jtNXkw=VYrOQ` zs@K>pPK#@cm^2$tF@8w z)a&8Tfv*8QDxRA0i{Ls8%2Udxrr!kK2fTOZ+84}2T?4-ltOIom?mzUYH^4suJ_GDm zd8mVWz%#%BVEVc9r|45x!k-5(0+Rd~V)W;QcTAFEgH+>#!Gm4EW&f zleg$ov(6m&G*FfNbQOK-P4K6{7lA*rO+h`>tY-%N1MrUa!d1pob3M$1ZvtByJ__cS zn)AB|=K1A2>9i#^%e3Wj$IKr}oqevE)!p%~<47ITy=G5ZGUaQwV@u7;=sAf7@Pu)> z(zujkIc~D(|7ZFJl2LS0tZgVx8-%wM=RfWWJh8#Tp7QaLP}oypJHBd1 zO~|008cw^;h;86iJYn3RigTsm6#JcrGUkxqHGxs&_BA9vIJgLdZLW=(hMy_PgK;@D zGU&T{%E!e1*DG4qaf6*7w%@0xe-xhk%(o^-Etz3S?JCns%eDy$;( WL;B(Sj`|-vret4CC_h*=Li`I!LCtvp 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 57c0d1c..770e394 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 @@ -117,10 +117,15 @@ toggle linecap - ["<Primary>a"] + ["<Primary>period"] toggle dash toggle dash + + ["<Primary>a"] + toggle fill + toggle fill + KP_1','1']]]> select color1 From c04dd01b4479cf9c218fdc86bb589d4c5a6fcc16 Mon Sep 17 00:00:00 2001 From: abakkk Date: Wed, 27 Mar 2019 01:07:20 +0100 Subject: [PATCH 3/6] change prefs and helper order, to be the same as in the menu --- locale/draw-on-your-screen.pot | 36 +++++++++++++++++----------------- prefs.js | 14 ++++++------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/locale/draw-on-your-screen.pot b/locale/draw-on-your-screen.pot index a9615d9..ef0631d 100644 --- a/locale/draw-on-your-screen.pot +++ b/locale/draw-on-your-screen.pot @@ -114,6 +114,24 @@ msgstr "" msgid "Smooth last brushstroke" msgstr "" +msgid "Select line" +msgstr "" + +msgid "Select ellipse" +msgstr "" + +msgid "Select rectangle" +msgstr "" + +msgid "Select text" +msgstr "" + +msgid "Unselect shape (free drawing)" +msgstr "" + +msgid "Select fill/stroke" +msgstr "" + msgid "Increment line width" msgstr "" @@ -136,24 +154,6 @@ msgstr "" #msgid "Dashed line" #msgstr "" -msgid "Select line" -msgstr "" - -msgid "Select ellipse" -msgstr "" - -msgid "Select rectangle" -msgstr "" - -msgid "Select text" -msgstr "" - -msgid "Unselect shape (free drawing)" -msgstr "" - -msgid "Select fill/stroke" -msgstr "" - msgid "Change font family (generic name)" msgstr "" diff --git a/prefs.js b/prefs.js index 643bfe7..922437d 100644 --- a/prefs.js +++ b/prefs.js @@ -43,6 +43,13 @@ var INTERNAL_KEYBINDINGS = { 'delete-last-element' : "Erase last brushstroke", 'smooth-last-element': "Smooth last brushstroke", '-separator-1': '', + 'select-line-shape': "Select line", + 'select-ellipse-shape': "Select ellipse", + 'select-rectangle-shape': "Select rectangle", + 'select-text-shape': "Select text", + 'select-none-shape': "Unselect shape (free drawing)", + 'toggle-fill': "Select fill/stroke", + '-separator-2': '', 'increment-line-width': "Increment line width", 'decrement-line-width': "Decrement line width", 'increment-line-width-more': "Increment line width even more", @@ -50,13 +57,6 @@ var INTERNAL_KEYBINDINGS = { 'toggle-linejoin': "Change linejoin", 'toggle-linecap': "Change linecap", 'toggle-dash': "Dashed line", - '-separator-2': '', - 'select-line-shape': "Select line", - 'select-ellipse-shape': "Select ellipse", - 'select-rectangle-shape': "Select rectangle", - 'select-text-shape': "Select text", - 'select-none-shape': "Unselect shape (free drawing)", - 'toggle-fill': "Select fill/stroke", '-separator-3': '', 'toggle-font-family': "Change font family (generic name)", 'toggle-font-weight': "Change font weight", From 2a0c6536f20c2bc76a94e32d20528d1658337c1a Mon Sep 17 00:00:00 2001 From: abakkk Date: Wed, 27 Mar 2019 14:23:34 +0100 Subject: [PATCH 4/6] complete context menu implementation (27ea6a8be943fbf5a00a86bba5a14fcd75cec801) 1. close menu when leaving drawing mode 2. open menu with 'popup-menu' key (doesn't work for closing) 3. update 'disable' methods --- draw.js | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/draw.js b/draw.js index f2e52b0..1038a68 100644 --- a/draw.js +++ b/draw.js @@ -175,6 +175,7 @@ var DrawingArea = new Lang.Class({ } else if (button == 2) { this.toggleShape(); } else if (button == 3) { + this._stopDrawing(); this.menu.open(x, y); return Clutter.EVENT_STOP; } @@ -182,6 +183,14 @@ var DrawingArea = new Lang.Class({ return Clutter.EVENT_PROPAGATE; }, + _onKeyboardPopupMenu: function() { + this._stopDrawing(); + if (this.helper.visible) + this.helper.hideHelp(); + this.menu.popup(); + return Clutter.EVENT_STOP; + }, + _onKeyPressed: function(actor, event) { if (event.get_key_symbol() == Clutter.Escape) { this.emitter.emit('stop-drawing'); @@ -485,6 +494,7 @@ var DrawingArea = new Lang.Class({ enterDrawingMode: function() { this.keyPressedHandler = this.connect('key-press-event', this._onKeyPressed.bind(this)); this.buttonPressedHandler = this.connect('button-press-event', this._onButtonPressed.bind(this)); + this._onKeyboardPopupMenuHandler = this.connect('popup-menu', this._onKeyboardPopupMenu.bind(this)); this.scrollHandler = this.connect('scroll-event', this._onScroll.bind(this)); this.selectShape(Shapes.NONE); this.get_parent().set_background_color(this.hasBackground ? this.activeBackgroundColor : null); @@ -500,6 +510,10 @@ var DrawingArea = new Lang.Class({ this.disconnect(this.buttonPressedHandler); this.buttonPressedHandler = null; } + if (this._onKeyboardPopupMenuHandler) { + this.disconnect(this._onKeyboardPopupMenuHandler); + this._onKeyboardPopupMenuHandler = null; + } if (this.motionHandler) { this.disconnect(this.motionHandler); this.motionHandler = null; @@ -520,6 +534,7 @@ var DrawingArea = new Lang.Class({ this._stopCursorTimeout(); this.dashedLine = false; this._redisplay(); + this.menu.close(); this.get_parent().set_background_color(null); if (save) this.saveAsJson(); @@ -605,6 +620,7 @@ var DrawingArea = new Lang.Class({ disable: function() { this.erase(); + this.menu.disable(); } }); @@ -982,13 +998,32 @@ var DrawingMenu = new Lang.Class({ this.menu.connect('open-state-changed', this._onMenuOpenStateChanged.bind(this)); }, + disable: function() { + this.menuManager.removeMenu(this.menu); + Main.layoutManager.uiGroup.remove_actor(this.menu.actor); + this.menu.actor.destroy(); + }, + _onMenuOpenStateChanged: function(menu, open) { if (!open) // actionMode has changed, set previous actionMode in order to keep internal shortcuts working Main.actionMode = ExtensionJs.DRAWING_ACTION_MODE | Shell.ActionMode.NORMAL; }, + popup: function() { + if (this.menu.isOpen) { + this.close(); + } else { + this.open(); + this.menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false); + } + }, + open: function(x, y) { + if (this.menu.isOpen) + return; + if (x === undefined || y === undefined) + [x, y] = [this.area.monitor.x + this.area.monitor.width / 2, this.area.monitor.y + this.area.monitor.height / 2]; this._redisplay(); Main.layoutManager.setDummyCursorGeometry(x, y, 0, 0); let monitor = this.area.monitor; @@ -997,6 +1032,11 @@ var DrawingMenu = new Lang.Class({ this.menuManager.ignoreRelease(); }, + close: function() { + if (this.menu.isOpen) + this.menu.close(); + }, + _redisplay: function() { this.menu.removeAll(); From f7997b9336d86ee43eb9ff8147f8924a5ee1d6fd Mon Sep 17 00:00:00 2001 From: abakkk Date: Wed, 27 Mar 2019 22:11:51 +0100 Subject: [PATCH 5/6] line section and font section visibility depends on shape and fill --- draw.js | 93 +++++++++++++++++++++++++++++++------------------- stylesheet.css | 11 +++--- 2 files changed, 63 insertions(+), 41 deletions(-) diff --git a/draw.js b/draw.js index 1038a68..3a29ec9 100644 --- a/draw.js +++ b/draw.js @@ -1044,42 +1044,62 @@ var DrawingMenu = new Lang.Class({ this.menu.addAction(_("Redo"), this.area.redo.bind(this.area), 'edit-redo-symbolic'); this.menu.addAction(_("Erase"), this.area.deleteLastElement.bind(this.area), 'edit-clear-all-symbolic'); this.menu.addAction(_("Smooth"), this.area.smoothLastElement.bind(this.area), 'format-text-strikethrough-symbolic'); - this._addSeparator(); + this._addSeparator(this.menu); - this._addSubMenuItem(null, null, ShapeNames, this.area, 'currentShape'); - this._addColorSubMenuItem(); + this._addSubMenuItem(this.menu, null, ShapeNames, this.area, 'currentShape', this.updateSectionVisibility.bind(this)); + this._addColorSubMenuItem(this.menu); let fillIcon = GdkPixbuf.Pixbuf.new_from_file_at_size(FILL_ICON_PATH, 24, 24); - this._addSwitchItem(_("Fill"), fillIcon, this.area, 'fill'); - this._addSeparator(); + this._addSwitchItem(this.menu, _("Fill"), fillIcon, this.area, 'fill', this.updateSectionVisibility.bind(this)); + this._addSeparator(this.menu); - this._addSliderItem(this.area, 'currentLineWidth'); + let lineSection = new PopupMenu.PopupMenuSection(); + this._addSliderItem(lineSection, this.area, 'currentLineWidth'); let linejoinIcon = GdkPixbuf.Pixbuf.new_from_file_at_size(LINEJOIN_ICON_PATH, 24, 24); - this._addSubMenuItem(null, linejoinIcon, LineJoinNames, this.area, 'currentLineJoin'); + this._addSubMenuItem(lineSection, linejoinIcon, LineJoinNames, this.area, 'currentLineJoin'); let linecapIcon = GdkPixbuf.Pixbuf.new_from_file_at_size(LINECAP_ICON_PATH, 24, 24); - this._addSubMenuItem(null, linecapIcon, LineCapNames, this.area, 'currentLineCap'); + this._addSubMenuItem(lineSection, linecapIcon, LineCapNames, this.area, 'currentLineCap'); let dashedLineIcon = GdkPixbuf.Pixbuf.new_from_file_at_size(DASHED_LINE_ICON_PATH, 24, 24); - this._addSwitchItem(_("Dashed"), dashedLineIcon, this.area, 'dashedLine'); - this._addSeparator(); + this._addSwitchItem(lineSection, _("Dashed"), dashedLineIcon, this.area, 'dashedLine'); + this._addSeparator(lineSection); + this.menu.addMenuItem(lineSection); + this.lineSection = lineSection; + let fontSection = new PopupMenu.PopupMenuSection(); let FontFamilyNamesCopy = Object.create(FontFamilyNames); FontFamilyNamesCopy[0] = this.area.fontFamily; - this._addSubMenuItem(null, 'font-x-generic-symbolic', FontFamilyNamesCopy, this.area, 'currentFontFamilyId'); - this._addSubMenuItem(null, 'format-text-bold-symbolic', FontWeightNames, this.area, 'currentFontWeight'); - this._addSubMenuItem(null, 'format-text-italic-symbolic', FontStyleNames, this.area, 'currentFontStyle'); - this._addSeparator(); + this._addSubMenuItem(fontSection, 'font-x-generic-symbolic', FontFamilyNamesCopy, this.area, 'currentFontFamilyId'); + this._addSubMenuItem(fontSection, 'format-text-bold-symbolic', FontWeightNames, this.area, 'currentFontWeight'); + this._addSubMenuItem(fontSection, 'format-text-italic-symbolic', FontStyleNames, this.area, 'currentFontStyle'); + this._addSeparator(fontSection); + this.menu.addMenuItem(fontSection); + this.fontSection = fontSection; let manager = ExtensionJs.manager; - this._addSwitchItemWithCallback(_("Hide panel and dock"), manager.hiddenList ? true : false, manager.togglePanelAndDockOpacity.bind(manager)); - this._addSwitchItemWithCallback(_("Add a drawing background"), this.area.hasBackground, this.area.toggleBackground.bind(this.area)); - this._addSwitchItemWithCallback(_("Square drawing area"), this.area.isSquareArea, this.area.toggleSquareArea.bind(this.area)); - this._addSeparator(); + this._addSwitchItemWithCallback(this.menu, _("Hide panel and dock"), manager.hiddenList ? true : false, manager.togglePanelAndDockOpacity.bind(manager)); + this._addSwitchItemWithCallback(this.menu, _("Add a drawing background"), this.area.hasBackground, this.area.toggleBackground.bind(this.area)); + this._addSwitchItemWithCallback(this.menu, _("Square drawing area"), this.area.isSquareArea, this.area.toggleSquareArea.bind(this.area)); + this._addSeparator(this.menu); this.menu.addAction(_("Save drawing as a SVG file"), this.area.saveAsSvg.bind(this.area), 'document-save-symbolic'); this.menu.addAction(_("Open stylesheet.css"), manager.openStylesheetFile.bind(manager), 'document-open-symbolic'); this.menu.addAction(_("Show help"), this.area.toggleHelp.bind(this.area), 'preferences-desktop-keyboard-shortcuts-symbolic'); + + this.updateSectionVisibility(); }, - _addSwitchItem: function(label, icon, target, targetProperty) { + updateSectionVisibility: function() { + if (this.area.fill || this.area.currentShape == Shapes.TEXT) + this.lineSection.actor.hide(); + else + this.lineSection.actor.show(); + + if (this.area.currentShape != Shapes.TEXT) + this.fontSection.actor.hide(); + else + this.fontSection.actor.show(); + }, + + _addSwitchItem: function(menu, label, icon, target, targetProperty, callback) { let item = new PopupMenu.PopupSwitchMenuItem(label, target[targetProperty]); if (icon) { @@ -1093,17 +1113,19 @@ var DrawingMenu = new Lang.Class({ item.connect('toggled', (item, state) => { target[targetProperty] = state; + if (callback) + callback(); }); - this.menu.addMenuItem(item); + menu.addMenuItem(item); }, - _addSwitchItemWithCallback: function(label, active, onToggled) { + _addSwitchItemWithCallback: function(menu, label, active, onToggled) { let item = new PopupMenu.PopupSwitchMenuItem(label, active); item.connect('toggled', onToggled); - this.menu.addMenuItem(item); + menu.addMenuItem(item); }, - _addSliderItem: function(target, targetProperty) { + _addSliderItem: function(menu, target, targetProperty) { let item = new PopupMenu.PopupBaseMenuItem({ activate: false }); let label = new St.Label({ text: target[targetProperty] + " px", style_class: 'draw-on-your-screen-menu-slider-label' }); let slider = new Slider.Slider(target[targetProperty] / 50); @@ -1116,12 +1138,11 @@ var DrawingMenu = new Lang.Class({ item.actor.add(slider.actor, { expand: true }); item.actor.add(label); item.actor.connect('key-press-event', slider.onKeyPressEvent.bind(slider)); - this.menu.addMenuItem(item); + menu.addMenuItem(item); }, - _addSubMenuItem: function(label, icon, obj, target, targetProperty) { - let text = label ? label + _(obj[target[targetProperty]]).toLowerCase() : _(obj[target[targetProperty]]); - let item = new PopupMenu.PopupSubMenuMenuItem(text, icon ? true : false); + _addSubMenuItem: function(menu, icon, obj, target, targetProperty, callback) { + let item = new PopupMenu.PopupSubMenuMenuItem(_(obj[target[targetProperty]]), icon ? true : false); if (icon && icon instanceof GObject.Object && GObject.type_is_a(icon, GdkPixbuf.Pixbuf)) item.icon.set_gicon(icon); else if (icon) @@ -1134,17 +1155,18 @@ var DrawingMenu = new Lang.Class({ Mainloop.timeout_add(0, () => { for (let i in obj) { item.menu.addAction(_(obj[i]), () => { - let text = label ? label + _(obj[i]).toLowerCase() : _(obj[i]); - item.label.set_text(text); + item.label.set_text(_(obj[i])); target[targetProperty] = i; + if (callback) + callback(); }); } return GLib.SOURCE_REMOVE; }); - this.menu.addMenuItem(item); + menu.addMenuItem(item); }, - _addColorSubMenuItem: function() { + _addColorSubMenuItem: function(menu) { let item = new PopupMenu.PopupSubMenuMenuItem(_("Color"), true); item.icon.set_icon_name('document-edit-symbolic'); item.icon.set_style(`color:${this.area.currentColor.to_string().slice(0, 7)};`); @@ -1164,12 +1186,13 @@ var DrawingMenu = new Lang.Class({ } return GLib.SOURCE_REMOVE; }); - this.menu.addMenuItem(item); + menu.addMenuItem(item); }, - _addSeparator: function() { - let separator = new PopupMenu.PopupSeparatorMenuItem(); - this.menu.addMenuItem(separator); + _addSeparator: function(menu) { + let separator = new PopupMenu.PopupSeparatorMenuItem(' '); + separator.actor.add_style_class_name('draw-on-your-screen-menu-separator'); + menu.addMenuItem(separator); } }); diff --git a/stylesheet.css b/stylesheet.css index e753273..54e1592 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -80,17 +80,16 @@ /* context menu */ .draw-on-your-screen-menu { - font-size: 95%; + font-size: 0.98em; /* default: 1em */ } .draw-on-your-screen-menu .popup-menu-item { - padding-top: .35em; - padding-bottom: .35em; + padding-top: .37em; /* default: .4em */ + padding-bottom: .37em; } - .draw-on-your-screen-menu .popup-separator-menu-item { - margin-top: 0; - margin-bottom: 0; + .draw-on-your-screen-menu-separator StLabel { + font-size: 0; } .draw-on-your-screen-menu-slider-label { From 1b799da43d2f01835c6d5fe70c02272843ca1718 Mon Sep 17 00:00:00 2001 From: abakkk Date: Thu, 28 Mar 2019 00:17:13 +0100 Subject: [PATCH 6/6] minor, initialize fill when leaving, as other properties --- draw.js | 1 + 1 file changed, 1 insertion(+) diff --git a/draw.js b/draw.js index 3a29ec9..4ebcaad 100644 --- a/draw.js +++ b/draw.js @@ -533,6 +533,7 @@ var DrawingArea = new Lang.Class({ this.currentElement = null; this._stopCursorTimeout(); this.dashedLine = false; + this.fill = false; this._redisplay(); this.menu.close(); this.get_parent().set_background_color(null);