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 */ +} +