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 9271c1a..53d5dbc 100644 Binary files a/schemas/gschemas.compiled and b/schemas/gschemas.compiled differ 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 */ }