From 9a87008f2b3fbd3382c8383cbef2d0cbd9e69a75 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Fri, 13 Sep 2024 10:01:01 +0200 Subject: [PATCH 1/8] Add popup menu and labeled popup menu funcs --- src/fontra/client/core/ui-utils.js | 38 ++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/fontra/client/core/ui-utils.js b/src/fontra/client/core/ui-utils.js index d811a542f..07dbbb6a0 100644 --- a/src/fontra/client/core/ui-utils.js +++ b/src/fontra/client/core/ui-utils.js @@ -169,6 +169,44 @@ export function labeledTextInput(label, controller, key, options) { return items; } +export function popUpMenu(controller, key, menuItems, options) { + const popUpID = options?.id || `pop-up-${uniqueID()}-${key}`; + + const selectElement = html.select( + { + id: popUpID, + onchange: (event) => { + controller.model[key] = event.target.value; + }, + }, + menuItems.map((menuItem) => + html.option( + { + value: menuItem.identifier, + }, + [menuItem.value] + ) + ) + ); + selectElement.value = controller.model[key]; + + controller.addKeyListener(key, (event) => { + selectElement.value = event.newValue; + }); + + if (options?.class) { + selectElement.className = options.class; + } + + return selectElement; +} + +export function labeledPopUpMenu(label, controller, key, menuItems, options) { + const popUpMenuElement = popUpMenu(controller, key, menuItems, options); + const items = [labelForElement(label, popUpMenuElement), popUpMenuElement]; + return items; +} + export const DefaultFormatter = { toString: (value) => (value !== undefined && value !== null ? value.toString() : ""), fromString: (value) => { From 81fc0b0c1a1e95fcc4d259712622578fdf861cf8 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Fri, 13 Sep 2024 10:02:35 +0200 Subject: [PATCH 2/8] Beginnings of locationBase UI --- .../editor/panel-designspace-navigation.js | 37 ++++++++++++++++--- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/src/fontra/views/editor/panel-designspace-navigation.js b/src/fontra/views/editor/panel-designspace-navigation.js index 7eeba70d1..07564a83d 100644 --- a/src/fontra/views/editor/panel-designspace-navigation.js +++ b/src/fontra/views/editor/panel-designspace-navigation.js @@ -4,7 +4,7 @@ import * as html from "/core/html-utils.js"; import { htmlToElement } from "/core/html-utils.js"; import { translate } from "/core/localization.js"; import { controllerKey, ObservableController } from "/core/observable-object.js"; -import { labeledTextInput } from "/core/ui-utils.js"; +import { labeledPopUpMenu, labeledTextInput } from "/core/ui-utils.js"; import { boolInt, enumerate, @@ -812,6 +812,8 @@ export default class DesignspaceNavigationPanel extends Panel { ...this.sceneSettings.glyphLocation, }); + const locationBase = undefined; // take from font source, if any + const { location: newLocation, sourceName, @@ -823,7 +825,8 @@ export default class DesignspaceNavigationPanel extends Panel { glyph, "", "", - location + location, + locationBase ); if (!newLocation) { return; @@ -875,7 +878,8 @@ export default class DesignspaceNavigationPanel extends Panel { glyph, source.name, source.layerName, - source.location + source.location, + source.locationBase ); if (!newLocation) { return; @@ -915,7 +919,8 @@ export default class DesignspaceNavigationPanel extends Panel { glyph, sourceName, layerName, - location + location, + locationBase ) { const validateInput = () => { const warnings = []; @@ -951,6 +956,7 @@ export default class DesignspaceNavigationPanel extends Panel { layerName: layerName === sourceName ? "" : layerName, suggestedSourceName: suggestedSourceName, suggestedLayerName: sourceName || suggestedSourceName, + locationBase: locationBase || "", }); nameController.addKeyListener("sourceName", (event) => { @@ -960,6 +966,7 @@ export default class DesignspaceNavigationPanel extends Panel { }); locationController.addListener((event) => { + nameController.model.locationBase = ""; const suggestedSourceName = suggestedSourceNameFromLocation( makeSparseLocation(locationController.model, locationAxes) ); @@ -986,12 +993,22 @@ export default class DesignspaceNavigationPanel extends Panel { ); } + const fontSourceMenuItems = [ + { identifier: "", value: "None" }, + ...Object.entries(this.fontController.sources).map( + ([sourceIdentifier, source]) => { + return { identifier: sourceIdentifier, value: source.name }; + } + ), + ]; + const { contentElement, warningElement } = this._sourcePropertiesContentElement( locationAxes, nameController, locationController, layerNames, - sourceLocations + sourceLocations, + fontSourceMenuItems ); const dialog = await dialogSetup(title, null, [ @@ -1040,7 +1057,8 @@ export default class DesignspaceNavigationPanel extends Panel { nameController, locationController, layerNames, - sourceLocations + sourceLocations, + fontSourceMenuItems ) { const locationElement = html.createDomElement("designspace-location", { style: `grid-column: 1 / -1; @@ -1055,6 +1073,7 @@ export default class DesignspaceNavigationPanel extends Panel { }); locationElement.axes = locationAxes; locationElement.controller = locationController; + const contentElement = html.div( { style: `overflow: hidden; @@ -1068,6 +1087,12 @@ export default class DesignspaceNavigationPanel extends Panel { `, }, [ + ...labeledPopUpMenu( + "Location Base:", + nameController, + "locationBase", + fontSourceMenuItems + ), ...labeledTextInput("Source name:", nameController, "sourceName", { placeholderKey: "suggestedSourceName", id: "source-name-text-input", From 5fd2c205b3a93c36314bc85de6b007013b3cecb1 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Fri, 20 Sep 2024 10:15:04 +0200 Subject: [PATCH 3/8] Return edited locationBase from dialog runner --- src/fontra/views/editor/panel-designspace-navigation.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/fontra/views/editor/panel-designspace-navigation.js b/src/fontra/views/editor/panel-designspace-navigation.js index 07564a83d..763fdf5e0 100644 --- a/src/fontra/views/editor/panel-designspace-navigation.js +++ b/src/fontra/views/editor/panel-designspace-navigation.js @@ -812,13 +812,14 @@ export default class DesignspaceNavigationPanel extends Panel { ...this.sceneSettings.glyphLocation, }); - const locationBase = undefined; // take from font source, if any + const suggestedLocationBase = undefined; // take from font source, if any const { location: newLocation, sourceName, layerName, layerNames, + locationBase, } = await this._sourcePropertiesRunDialog( "Add source", "Add", @@ -826,7 +827,7 @@ export default class DesignspaceNavigationPanel extends Panel { "", "", location, - locationBase + suggestedLocationBase ); if (!newLocation) { return; @@ -872,6 +873,7 @@ export default class DesignspaceNavigationPanel extends Panel { sourceName, layerName, layerNames, + locationBase, } = await this._sourcePropertiesRunDialog( "Source properties", "Done", @@ -1035,8 +1037,9 @@ export default class DesignspaceNavigationPanel extends Panel { nameController.model.sourceName || nameController.model.suggestedSourceName; layerName = nameController.model.layerName || nameController.model.suggestedLayerName; + locationBase = nameController.model.locationBase || null; - return { location: newLocation, sourceName, layerName, layerNames }; + return { location: newLocation, sourceName, layerName, layerNames, locationBase }; } _sourcePropertiesLocationAxes(glyph) { From d690f6be49125a2c05c0e290feb4492cc94b1071 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Fri, 20 Sep 2024 12:06:27 +0200 Subject: [PATCH 4/8] Add helper func --- src/fontra/client/core/utils.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/fontra/client/core/utils.js b/src/fontra/client/core/utils.js index 7d3fff886..34be76af5 100644 --- a/src/fontra/client/core/utils.js +++ b/src/fontra/client/core/utils.js @@ -580,6 +580,14 @@ export async function mapObjectValuesAsync(obj, func) { return result; } +export function filterObject(obj, func) { + // Return a copy of the object containing the items for which `func(key, value)` + // returns `true`. + return Object.fromEntries( + Object.entries(obj).filter(([key, value]) => func(key, value)) + ); +} + let _uniqueID = 1; export function uniqueID() { return _uniqueID++; From b50f114809189a3f2be404c52889b404e48b5eb6 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Fri, 20 Sep 2024 13:08:54 +0200 Subject: [PATCH 5/8] Make location base popup changes reflect location sliders --- .../editor/panel-designspace-navigation.js | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/fontra/views/editor/panel-designspace-navigation.js b/src/fontra/views/editor/panel-designspace-navigation.js index 763fdf5e0..2c2f4ea2f 100644 --- a/src/fontra/views/editor/panel-designspace-navigation.js +++ b/src/fontra/views/editor/panel-designspace-navigation.js @@ -9,6 +9,7 @@ import { boolInt, enumerate, escapeHTMLCharacters, + filterObject, objectsEqual, range, rgbaToCSS, @@ -967,8 +968,36 @@ export default class DesignspaceNavigationPanel extends Panel { validateInput(); }); + const glyphAxisNames = new Set(glyph.axes.map((axis) => axis.name)); + + nameController.addKeyListener("locationBase", (event) => { + if (!event.newValue) { + return; + } + const fontSource = this.fontController.sources[event.newValue]; + const sourceLocation = fontSource.location; + const fontLocation = filterObject( + sourceLocation, + (name, value) => !glyphAxisNames.has(name) + ); + const glyphLocation = filterObject(locationController.model, (name, value) => + glyphAxisNames.has(name) + ); + const newLocation = { + ...this.fontController.fontSourcesInstancer.defaultLocation, + ...sourceLocation, + ...glyphLocation, + }; + for (const [name, value] of Object.entries(newLocation)) { + locationController.setItem(name, value, { sentByLocationBase: true }); + } + nameController.model.sourceName = fontSource.name; + }); + locationController.addListener((event) => { - nameController.model.locationBase = ""; + if (!event.senderInfo?.sentByLocationBase) { + nameController.model.locationBase = ""; + } const suggestedSourceName = suggestedSourceNameFromLocation( makeSparseLocation(locationController.model, locationAxes) ); From 90bbcd459c216825c64085a481a2331b6a6502c9 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 24 Sep 2024 08:59:58 +0200 Subject: [PATCH 6/8] Make edit source properties set locationBase --- .../editor/panel-designspace-navigation.js | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/fontra/views/editor/panel-designspace-navigation.js b/src/fontra/views/editor/panel-designspace-navigation.js index 2c2f4ea2f..57de5608d 100644 --- a/src/fontra/views/editor/panel-designspace-navigation.js +++ b/src/fontra/views/editor/panel-designspace-navigation.js @@ -888,14 +888,19 @@ export default class DesignspaceNavigationPanel extends Panel { return; } + const filteredLocation = stripLocation(newLocation, locationBase, glyph); + await this.sceneController.editGlyphAndRecordChanges((glyph) => { const source = glyph.sources[sourceIndex]; - if (!objectsEqual(source.location, newLocation)) { - source.location = newLocation; + if (!objectsEqual(source.location, filteredLocation)) { + source.location = filteredLocation; } if (sourceName !== source.name) { source.name = sourceName; } + + source.locationBase = locationBase; + const oldLayerName = source.layerName; if (layerName !== oldLayerName) { source.layerName = layerName; @@ -968,7 +973,7 @@ export default class DesignspaceNavigationPanel extends Panel { validateInput(); }); - const glyphAxisNames = new Set(glyph.axes.map((axis) => axis.name)); + const glyphAxisNames = getGlyphAxisNamesSet(glyph); nameController.addKeyListener("locationBase", (event) => { if (!event.newValue) { @@ -1072,10 +1077,10 @@ export default class DesignspaceNavigationPanel extends Panel { } _sourcePropertiesLocationAxes(glyph) { - const glyphAxisNames = glyph.axes.map((axis) => axis.name); + const glyphAxisNames = getGlyphAxisNamesSet(glyph); const fontAxes = mapAxesFromUserSpaceToSourceSpace( // Don't include font axes that also exist as glyph axes - this.fontController.fontAxes.filter((axis) => !glyphAxisNames.includes(axis.name)) + this.fontController.fontAxes.filter((axis) => !glyphAxisNames.has(axis.name)) ); return [ ...fontAxes, @@ -1319,6 +1324,17 @@ function suggestedSourceNameFromLocation(location) { ); } +function getGlyphAxisNamesSet(glyph) { + return new Set(glyph.axes.map((axis) => axis.name)); +} + +function stripLocation(location, locationBase, glyph) { + const glyphAxisNames = getGlyphAxisNamesSet(glyph); + return locationBase + ? filterObject(location, (name, value) => !glyphAxisNames.has(name)) + : location; +} + function makeIconCellFactory( iconPaths, triggerOnDoubleClick = false, From 67d855f2306fbb51088a3c241a28637660db807c Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 24 Sep 2024 09:01:58 +0200 Subject: [PATCH 7/8] Make add source apply locationBase --- src/fontra/views/editor/panel-designspace-navigation.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/fontra/views/editor/panel-designspace-navigation.js b/src/fontra/views/editor/panel-designspace-navigation.js index 57de5608d..f9225497a 100644 --- a/src/fontra/views/editor/panel-designspace-navigation.js +++ b/src/fontra/views/editor/panel-designspace-navigation.js @@ -834,6 +834,8 @@ export default class DesignspaceNavigationPanel extends Panel { return; } + const filteredLocation = stripLocation(newLocation, locationBase, glyph); + const getGlyphFunc = this.sceneController.sceneModel.fontController.getGlyph.bind( this.sceneController.sceneModel.fontController ); @@ -849,7 +851,8 @@ export default class DesignspaceNavigationPanel extends Panel { GlyphSource.fromObject({ name: sourceName, layerName: layerName, - location: newLocation, + location: filteredLocation, + locationBase: locationBase, }) ); if (layerNames.indexOf(layerName) < 0) { From 4c670ddaf58af40c3f4a158fa7dec2fc0aca475a Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 24 Sep 2024 15:47:48 +0200 Subject: [PATCH 8/8] Formatting --- src/fontra/client/core/ui-utils.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/fontra/client/core/ui-utils.js b/src/fontra/client/core/ui-utils.js index 07dbbb6a0..a4084e58d 100644 --- a/src/fontra/client/core/ui-utils.js +++ b/src/fontra/client/core/ui-utils.js @@ -180,12 +180,7 @@ export function popUpMenu(controller, key, menuItems, options) { }, }, menuItems.map((menuItem) => - html.option( - { - value: menuItem.identifier, - }, - [menuItem.value] - ) + html.option({ value: menuItem.identifier }, [menuItem.value]) ) ); selectElement.value = controller.model[key];