From c78f5e82da5d8fdc096f561bec46cd9dd21d9398 Mon Sep 17 00:00:00 2001 From: abakkk Date: Wed, 5 Aug 2020 23:30:25 +0200 Subject: [PATCH] Extend font family possibilities To fix in the future: memory usage of font-styled item labels --- area.js | 40 +++++++++++++++++++++++++++++----------- elements.js | 4 ++++ menu.js | 40 ++++++++++++++++++++++++++++++++-------- 3 files changed, 65 insertions(+), 19 deletions(-) diff --git a/area.js b/area.js index e8e220b..775bdeb 100644 --- a/area.js +++ b/area.js @@ -54,7 +54,7 @@ const ManipulationNames = { 100: "Move", 101: "Resize", 102: "Mirror" }; var Tools = Object.assign({}, Shapes, Manipulations); var ToolNames = Object.assign({}, ShapeNames, ManipulationNames); -var FontGenericNames = { 0: 'Theme', 1: 'Sans-Serif', 2: 'Serif', 3: 'Monospace', 4: 'Cursive', 5: 'Fantasy' }; +var FontGenericFamilies = ['Sans-Serif', 'Serif', 'Monospace', 'Cursive', 'Fantasy']; // DrawingArea is the widget in which we draw, thanks to Cairo. // It creates and manages a DrawingElement for each "brushstroke". @@ -82,7 +82,6 @@ var DrawingArea = new Lang.Class({ this.currentElement = null; this.currentTool = Shapes.NONE; this.currentImage = 0; - this.currentFontGeneric = 0; this.isSquareArea = false; this.hasGrid = false; this.hasBackground = false; @@ -145,6 +144,24 @@ 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; + }); + this._fontFamilies = [this.currentThemeFontFamily].concat(FontGenericFamilies, pangoFontFamilies); + } + return this._fontFamilies; + }, + vfunc_repaint: function() { let cr = this.get_context(); @@ -198,6 +215,7 @@ var DrawingArea = new Lang.Class({ this.colors[i] = this.colors[i].alpha ? this.colors[i] : this.colors[0]; } 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; @@ -545,7 +563,7 @@ var DrawingArea = new Lang.Class({ color: this.currentColor.to_string(), eraser: eraser, font: { - family: (this.currentFontGeneric == 0 ? this.currentThemeFontFamily : FontGenericNames[this.currentFontGeneric]), + family: this.currentFontFamily, weight: this.currentFontWeight, style: this.currentFontStyle, stretch: this.currentFontStretch, @@ -913,13 +931,13 @@ var DrawingArea = new Lang.Class({ }, toggleFontFamily: function() { - this.currentFontGeneric = this.currentFontGeneric == 5 ? 0 : this.currentFontGeneric + 1; - let currentFontFamily = this.currentFontGeneric == 0 ? this.currentThemeFontFamily : FontGenericNames[this.currentFontGeneric]; + let index = Math.max(0, this.fontFamilies.indexOf(this.currentFontFamily)); + this.currentFontFamily = (index == this.fontFamilies.length - 1) ? 0 : this.fontFamilies[index + 1]; if (this.currentElement && this.currentElement.font) { - this.currentElement.font.family = currentFontFamily; + this.currentElement.font.family = this.currentFontFamily; this._redisplay(); } - this.emit('show-osd', null, `${_(currentFontFamily)}`, "", -1, false); + this.emit('show-osd', null, `${_(this.currentFontFamily)}`, "", -1, false); }, toggleTextAlignment: function() { @@ -978,7 +996,7 @@ var DrawingArea = new Lang.Class({ this.stageKeyReleasedHandler = global.stage.connect('key-release-event', this._onStageKeyReleased.bind(this)); 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.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(); @@ -1001,9 +1019,9 @@ var DrawingArea = new Lang.Class({ this.disconnect(this.buttonPressedHandler); this.buttonPressedHandler = null; } - if (this._onKeyboardPopupMenuHandler) { - this.disconnect(this._onKeyboardPopupMenuHandler); - this._onKeyboardPopupMenuHandler = null; + if (this.keyboardPopupMenuHandler) { + this.disconnect(this.keyboardPopupMenuHandler); + this.keyboardPopupMenuHandler = null; } if (this.motionHandler) { this.disconnect(this.motionHandler); diff --git a/elements.js b/elements.js index 4615e93..c2214c7 100644 --- a/elements.js +++ b/elements.js @@ -46,6 +46,10 @@ var FontStyleNames = reverseEnumeration(Pango.Style); var FontStretchNames = reverseEnumeration(Pango.Stretch); var 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)); +}; + const SVG_DEBUG_SUPERPOSES_CAIRO = false; const RADIAN = 180 / Math.PI; // degree const INVERSION_CIRCLE_RADIUS = 12; // px diff --git a/menu.js b/menu.js index 1c64232..b70eca4 100644 --- a/menu.js +++ b/menu.js @@ -56,6 +56,9 @@ const FILLRULE_EVENODD_ICON_PATH = ICON_DIR.get_child('fillrule-evenodd-symbolic 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; + const getActor = function(object) { return GS_VERSION < '3.33.0' ? object.actor : object; }; @@ -180,9 +183,7 @@ var DrawingMenu = new Lang.Class({ this.lineSection = lineSection; let fontSection = new PopupMenu.PopupMenuSection(); - let FontGenericNamesCopy = Object.create(Area.FontGenericNames); - FontGenericNamesCopy[0] = this.area.currentThemeFontFamily; - this._addSubMenuItem(fontSection, 'font-x-generic-symbolic', FontGenericNamesCopy, this.area, 'currentFontGeneric'); + 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'); @@ -342,9 +343,7 @@ var DrawingMenu = new Lang.Class({ GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => { for (let i in obj) { let text; - if (targetProperty == 'currentFontGeneric') - text = `${_(obj[i])}`; - else if (targetProperty == 'currentFontWeight') + if (targetProperty == 'currentFontWeight') text = `${_(obj[i])}`; else if (targetProperty == 'currentFontStyle') text = `${_(obj[i])}`; @@ -391,7 +390,6 @@ var DrawingMenu = new Lang.Class({ this.area.currentColor = this.area.colors[iCaptured]; item.icon.set_style(`color:${this.area.currentColor.to_string().slice(0, 7)};`); }); - colorItem.label.get_clutter_text().set_use_markup(true); // 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)};`); } @@ -401,6 +399,32 @@ var DrawingMenu = new Lang.Class({ return item; }, + _addFontFamilySubMenuItem: function(menu, icon) { + let item = new PopupMenu.PopupSubMenuMenuItem(this.area.currentFontFamily, true); + item.icon.set_icon_name(icon); + + item.menu.itemActivated = () => { + item.menu.close(); + }; + + item.menu.openOld = item.menu.open; + 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)); + this.area.currentFontFamily = family; + }); + if (FONT_FAMILY_STYLE) + subItem.label.set_style(`font-family:${family}`); + }); + } + item.menu.openOld(); + }; + + menu.addMenuItem(item); + }, + _addDrawingNameItem: function(menu) { this.drawingNameMenuItem = new PopupMenu.PopupMenuItem('', { reactive: false, activate: false }); this.drawingNameMenuItem.setSensitive(false); @@ -420,8 +444,8 @@ var DrawingMenu = new Lang.Class({ _addOpenDrawingSubMenuItem: function(menu) { let item = new PopupMenu.PopupSubMenuMenuItem(_("Open drawing"), true); this.openDrawingSubMenuItem = item; - this.openDrawingSubMenuItem.setSensitive(Boolean(Files.getJsons().length)); this.openDrawingSubMenu = item.menu; + item.setSensitive(Boolean(Files.getJsons().length)); item.icon.set_icon_name('document-open-symbolic'); item.menu.itemActivated = () => {