1
0
Fork 0

feat(core): Better support for macro removal an node id tracking

This commit is contained in:
Joost De Cock 2023-10-18 16:00:15 +02:00
parent 7939c1bc45
commit cb106578b3
24 changed files with 327 additions and 223 deletions

View file

@ -9,11 +9,12 @@ import { measurements } from './plugin-measurements.mjs'
import { mirror } from './plugin-mirror.mjs' import { mirror } from './plugin-mirror.mjs'
import { round } from './plugin-round.mjs' import { round } from './plugin-round.mjs'
import { sprinkle } from './plugin-sprinkle.mjs' import { sprinkle } from './plugin-sprinkle.mjs'
import { ringsector } from './plugin-ringsector.mjs'
// Setup our new design // Setup our new design
const Plugintest = new Design({ const Plugintest = new Design({
data, data,
parts: [annotations, flip, gore, i18nStack, measurements, mirror, round, sprinkle], parts: [annotations, flip, gore, i18nStack, measurements, mirror, round, sprinkle, ringsector],
}) })
// Named exports // Named exports
@ -26,6 +27,7 @@ export {
mirror, mirror,
round, round,
sprinkle, sprinkle,
ringsector,
Plugintest, Plugintest,
i18n, i18n,
} }

View file

@ -63,7 +63,7 @@ const pluginMirror = ({
macro('bannerbox', { macro('bannerbox', {
topLeft: new Point(options.mirrorLine === 'b' ? -35 : 5, -25), topLeft: new Point(options.mirrorLine === 'b' ? -35 : 5, -25),
bottomRight: new Point(65, 50), bottomRight: new Point(65, 50),
text: 'plugin = measurements', text: 'plugin = mirror',
...store.get('bannerbox.plugin'), ...store.get('bannerbox.plugin'),
}) })
} }

View file

@ -0,0 +1,33 @@
import { ringsectorPlugin } from '@freesewing/plugin-ringsector'
import { base } from './base.mjs'
const pluginRingsector = ({ points, Point, paths, options, macro, part, store }) => {
if (['ringsector', 'all'].indexOf(options.plugin) !== -1) {
const pathId = macro('ringsector', {
angle: options.ringsectorAngle,
insideRadius: options.ringsectorInsideRadius,
outsideRadius: options.ringsectorOutsideRadius,
}).paths.path
macro('bannerbox', {
topLeft: paths[pathId].edge('topLeft'),
bottomRight: paths[pathId].edge('bottomRight'),
text: 'macro = ringsector',
...store.get('bannerbox.macro'),
})
}
return part
}
export const ringsector = {
name: 'plugintest.ringsector',
plugins: ringsectorPlugin,
after: base,
options: {
ringsectorInsideRadius: { count: 30, min: 10, max: 50, menu: 'ringsector' },
ringsectorOutsideRadius: { count: 60, min: 60, max: 120, menu: 'ringsector' },
ringsectorAngle: { deg: 75, min: 30, max: 120, menu: 'ringsector' },
},
draft: pluginRingsector,
}

View file

@ -31,20 +31,12 @@ export function draftCurvedWaistband({
) )
// Call the RingSector macro to draft the waistband // Call the RingSector macro to draft the waistband
macro('ringsector', { const ids = macro('ringsector', {
angle: an + anExtra, angle: an + anExtra,
insideRadius: rad, insideRadius: rad,
outsideRadius: rad + absoluteOptions.waistbandWidth, outsideRadius: rad + absoluteOptions.waistbandWidth,
}) })
const storeRoot = [ const pathId = ids.paths.path
'parts',
part.name,
'macros',
'@freesewing/plugin-ringsector',
'ids',
'ringsector',
]
const pathId = store.get([...storeRoot, 'paths', 'path'])
paths.seam = paths[pathId].clone().addClass('fabric') paths.seam = paths[pathId].clone().addClass('fabric')
paths[pathId].hide() paths[pathId].hide()
@ -52,7 +44,7 @@ export function draftCurvedWaistband({
* Macros ensure they can be used more than once in a part, and will generate unique (and complex) * Macros ensure they can be used more than once in a part, and will generate unique (and complex)
* point names. Since we're only calling the macro once here, we will simplify these names * point names. Since we're only calling the macro once here, we will simplify these names
*/ */
for (const [shortId, uid] of Object.entries(store.get([...storeRoot, 'points']))) { for (const [shortId, uid] of Object.entries(ids.points)) {
points[shortId] = points[uid].copy() points[shortId] = points[uid].copy()
// Some points are rotated, we need those too // Some points are rotated, we need those too
if (points[uid + 'Rotated']) points[shortId + 'Rotated'] = points[uid + 'Rotated'].copy() if (points[uid + 'Rotated']) points[shortId + 'Rotated'] = points[uid + 'Rotated'].copy()

View file

@ -86,21 +86,13 @@ function sandySkirt({
radiusWaist + store.get('fullLength') * options.lengthBonus - absoluteOptions.waistbandWidth radiusWaist + store.get('fullLength') * options.lengthBonus - absoluteOptions.waistbandWidth
// Call the RingSector macro to draft the part // Call the RingSector macro to draft the part
macro('ringsector', { const ids = macro('ringsector', {
angle: an, angle: an,
insideRadius: radiusWaist, insideRadius: radiusWaist,
outsideRadius: radiusHem, outsideRadius: radiusHem,
rotate: true, rotate: true,
}) })
const storeRoot = [ const pathId = ids.paths.path
'parts',
part.name,
'macros',
'@freesewing/plugin-ringsector',
'ids',
'ringsector',
]
const pathId = store.get([...storeRoot, 'paths', 'path'])
paths.seam = paths[pathId].clone().addClass('fabric') paths.seam = paths[pathId].clone().addClass('fabric')
paths[pathId].hide() paths[pathId].hide()
@ -108,7 +100,7 @@ function sandySkirt({
* Macros ensure they can be used more than once in a part, and will generate unique (and complex) * Macros ensure they can be used more than once in a part, and will generate unique (and complex)
* point names. Since we're only calling the macro once here, we will simplify these names * point names. Since we're only calling the macro once here, we will simplify these names
*/ */
for (const [shortId, uid] of Object.entries(store.get([...storeRoot, 'points']))) { for (const [shortId, uid] of Object.entries(ids.points)) {
points[shortId] = points[uid].copy() points[shortId] = points[uid].copy()
// Some points are rotated, we need those too // Some points are rotated, we need those too
if (points[uid + 'Rotated']) points[shortId + 'Rotated'] = points[uid + 'Rotated'].copy() if (points[uid + 'Rotated']) points[shortId + 'Rotated'] = points[uid + 'Rotated'].copy()

View file

@ -359,8 +359,20 @@ Part.prototype.__macroClosure = function (props) {
const self = this const self = this
const method = function (key, args) { const method = function (key, args) {
const macro = utils.__macroName(key) const macro = utils.__macroName(key)
if (typeof self[macro] === 'function') return self[macro](args, props) let parentMacro
else if ('context' in self) if (typeof self[macro] === 'function') {
if ('context' in self) {
parentMacro = self.context.store.get('activeMacro', false)
self.context.store.set('activeMacro', key)
}
const result = self[macro](args, props)
if ('context' in self) {
if (parentMacro) self.context.store.set('activeMacro', parentMacro)
else self.context.store.unset('activeMacro')
}
return result
} else if ('context' in self)
self.context.store.log.warn('Unknown macro `' + key + '` used in ' + self.name) self.context.store.log.warn('Unknown macro `' + key + '` used in ' + self.name)
} }

View file

@ -2,8 +2,20 @@ import set from 'lodash.set'
import unset from 'lodash.unset' import unset from 'lodash.unset'
import get from 'lodash.get' import get from 'lodash.get'
// Don't allow setting of these top-level keys in the store /*
const avoid = ['set', 'setIfUnset', 'push', 'unset', 'get', 'extend'] * Don't allow setting of these top-level keys in the store
*/
const avoid = [
'set',
'setIfUnset',
'push',
'unset',
'get',
'extend',
'generateMacroIds',
'getMacroIds',
'removeMacroNodes',
]
////////////////////////////////////////////// //////////////////////////////////////////////
// CONSTRUCTOR // // CONSTRUCTOR //
@ -18,8 +30,7 @@ const avoid = ['set', 'setIfUnset', 'push', 'unset', 'get', 'extend']
*/ */
export function Store(methods = []) { export function Store(methods = []) {
/* /*
* Default logging methods * Default logging containers
* You can override these with a plugin
*/ */
const logs = { const logs = {
debug: [], debug: [],
@ -27,6 +38,11 @@ export function Store(methods = []) {
warn: [], warn: [],
error: [], error: [],
} }
/*
* Default logging methods
* You can override these with a plugin
*/
this.log = { this.log = {
debug: function (...data) { debug: function (...data) {
logs.debug.push(...data) logs.debug.push(...data)
@ -42,17 +58,73 @@ export function Store(methods = []) {
logs.error.push(...data) logs.error.push(...data)
}, },
} }
/*
* Attach logs object
*/
this.logs = logs this.logs = logs
/*
* Method to generate macro IDs
*/
this.generateMacroIds = function (keys, id, macro = false) {
if (!macro) macro = this.get('activeMacro')
const ids = {}
for (const key of keys) ids[key] = `__macro_${macro}_${id}_${key}`
return ids
}
/*
* Method to store macro IDs
*/
this.storeMacroIds = function (id, ids, macro = false, part = false) {
if (!macro) macro = this.get('activeMacro')
if (!part) part = this.get('activePart')
this.set(['parts', part, 'macros', macro, 'ids', id], ids)
}
/*
* Method to retrieve macro IDs
*/
this.getMacroIds = function (id, macro = false, part = false) {
if (!macro) macro = this.get('activeMacro')
if (!part) part = this.get('activePart')
return this.get(['parts', part, 'macros', macro, 'ids', id], false)
}
/*
* Method to remove nodes added by a macro
*/
this.removeMacroNodes = function (id, macro, part) {
const toRemove = this.getMacroIds(id, macro, part.name)
if (toRemove) {
if (toRemove.points) {
for (const nodeId of Object.values(toRemove.points)) delete part.points[nodeId]
}
if (toRemove.paths) {
for (const nodeId of Object.values(toRemove.paths)) delete part.paths[nodeId]
}
}
return this.getMacroIds(id, macro)
}
/*
* Add fallback packing algorithm
*/
this.pack = fallbackPacker
/*
* Attache passed-in methods
*/
for (const [path, method] of methods) { for (const [path, method] of methods) {
if (avoid.indexOf(path) !== -1) { if (avoid.indexOf(path) !== -1) {
this.log.warn(`You cannot overwrite \`store.${path}()\``) this.log.warn(`You cannot overwrite \`store.${path}()\``)
} else set(this, path, method) } else set(this, path, method)
} }
// Fallback packing algorithm
this.pack = fallbackPacker
return this return this
} }

View file

@ -363,4 +363,72 @@ describe('Part', () => {
expect(typeof pattern.parts[0].to.paths.line).to.equal('object') expect(typeof pattern.parts[0].to.paths.line).to.equal('object')
expect(pattern.parts[0].to.paths.curve.ops[1].cp2.x).to.equal(200) expect(pattern.parts[0].to.paths.curve.ops[1].cp2.x).to.equal(200)
}) })
it('Should set/unset the name of the active macro', () => {
const activeMacro = []
const plugin = {
name: 'testplugin',
version: '0.0.1',
macros: {
macro1: (config, { part, store }) => {
activeMacro.push(store.activeMacro)
return part
},
},
}
const part = {
name: 'test',
draft: ({ macro, part }) => {
activeMacro.push(part.activeMacro)
macro('macro1')
activeMacro.push(part.activeMacro)
return part
},
}
const design = new Design({ parts: [part], plugins: [plugin] })
const pattern = new design()
pattern.draft()
expect(activeMacro[0]).to.equal(undefined)
expect(activeMacro[1]).to.equal('macro1')
expect(activeMacro[2]).to.equal(undefined)
})
it('Should set/unset the name of the active macro in a nested macro', () => {
const activeMacro = []
const plugin = {
name: 'testplugin',
version: '0.0.1',
macros: {
macro1: (config, { macro, part, store }) => {
activeMacro.push(store.activeMacro)
macro('macro2')
activeMacro.push(store.activeMacro)
return part
},
macro2: (config, { part, store }) => {
activeMacro.push(store.activeMacro)
return part
},
},
}
const part = {
name: 'test',
draft: ({ macro, part }) => {
activeMacro.push(part.activeMacro)
macro('macro1')
activeMacro.push(part.activeMacro)
return part
},
}
const design = new Design({ parts: [part], plugins: [plugin] })
const pattern = new design()
pattern.draft()
expect(activeMacro[0]).to.equal(undefined)
expect(activeMacro[1]).to.equal('macro1')
expect(activeMacro[2]).to.equal('macro2')
expect(activeMacro[3]).to.equal('macro1')
expect(activeMacro[4]).to.equal(undefined)
})
}) })

View file

@ -1,5 +1,3 @@
import { getIds } from './utils.mjs'
/* /*
* Defaults for the bannner macro * Defaults for the bannner macro
*/ */
@ -15,12 +13,8 @@ const macroDefaults = {
/* /*
* The rmbanner macro * The rmbanner macro
*/ */
const rmbanner = function (id = macroDefaults.id, { paths, store, part }) { const rmbanner = (id = macroDefaults.id, { store, part }) =>
for (const pid of Object.values( store.removeMacroNodes(id, 'banner', part)
store.get(['parts', part.name, 'macros', 'banner', 'ids', id, 'paths'], {})
))
delete paths[pid]
}
const banner = function (config, { part, paths, store, complete }) { const banner = function (config, { part, paths, store, complete }) {
/* /*
@ -36,7 +30,7 @@ const banner = function (config, { part, paths, store, complete }) {
/* /*
* Get the list of IDs * Get the list of IDs
*/ */
const ids = getIds(['banner'], mc.id, 'banner') const ids = store.generateMacroIds(['banner'], mc.id)
/* /*
* Prepare the path to hold the banner text * Prepare the path to hold the banner text
@ -57,9 +51,12 @@ const banner = function (config, { part, paths, store, complete }) {
/* /*
* Store all IDs in the store so we can remove this macro with rmbanner * Store all IDs in the store so we can remove this macro with rmbanner
*/ */
store.set(['parts', part.name, 'macros', 'banner', 'ids', mc.id, 'paths'], ids) store.storeMacroIds(mc.id, { paths: ids })
return store.getMacroIds(config.id, 'banner') /*
* Returning ids is a best practice for FreeSewing macros
*/
return store.getMacroIds(mc.id)
} }
// Export macros // Export macros

View file

@ -1,5 +1,3 @@
import { getIds } from './utils.mjs'
/* /*
* Defaults for the bannerbox macro * Defaults for the bannerbox macro
*/ */
@ -20,12 +18,9 @@ const macroDefaults = {
* Removing all this is easy as all IDs are available in the store * Removing all this is easy as all IDs are available in the store
* and all we need to remove are paths. * and all we need to remove are paths.
*/ */
const rmbannerbox = function (id = macroDefaults.id, { paths, store, part, macro }) { const rmbannerbox = (id = macroDefaults.id, { macro, store, part }) => {
for (const pid of Object.values(
store.get(['parts', part.name, 'macros', 'bannerbox', 'ids', id, 'paths'], {})
))
delete paths[pid]
macro('rmbanner', id) macro('rmbanner', id)
return store.removeMacroNodes(id, 'bannerbox', part)
} }
/* /*
@ -64,7 +59,7 @@ const bannerbox = function (config, { Point, paths, Path, part, macro, log, stor
/* /*
* Get the list of IDs * Get the list of IDs
*/ */
const ids = getIds(['box'], mc.id, 'bannerbox') const ids = store.generateMacroIds(['box'], mc.id)
/* /*
* Calculate the offset from the bounding box * Calculate the offset from the bounding box
@ -99,9 +94,12 @@ const bannerbox = function (config, { Point, paths, Path, part, macro, log, stor
/* /*
* Store all IDs in the store so we can remove this macro with rmtitle * Store all IDs in the store so we can remove this macro with rmtitle
*/ */
store.set(['parts', part.name, 'macros', 'bannerbox', 'ids', mc.id, 'paths'], ids) store.storeMacroIds(mc.id, { paths: ids })
return store.getMacroIds(mc.id, 'bannerbox') /*
* Returning ids is a best practice for FreeSewing macros
*/
return store.getMacroIds(mc.id)
} }
export const bannerboxMacros = { bannerbox, rmbannerbox } export const bannerboxMacros = { bannerbox, rmbannerbox }

View file

@ -1,5 +1,3 @@
import { getIds } from './utils.mjs'
/* /*
* Defaults for the bartack macro * Defaults for the bartack macro
*/ */
@ -122,26 +120,25 @@ function createBartack(config, props) {
/* /*
* Get the list of IDs * Get the list of IDs
*/ */
const ids = getIds(['stitches'], mc.id, name) const ids = props.store.generateMacroIds(['stitches'], mc.id)
paths[ids.stitches] = bartackPath(guide, mc, props).attr('class', mc.classes) paths[ids.stitches] = bartackPath(guide, mc, props).attr('class', mc.classes)
/* /*
* Store all IDs in the store so we can remove this macro with rm[name] * Store all IDs in the store so we can remove this macro with rm[name]
*/ */
props.store.set(['parts', props.part.name, 'macros', name, 'ids', mc.id, 'paths'], ids) props.store.storeMacroIds(mc.id, { paths: ids })
return props.store.getMacroIds(mc.id, name) /*
* Returning ids is a best practice for FreeSewing macros
*/
return props.store.getMacroIds(mc.id)
} }
/* /*
* The method that will remove all macros * The method that will remove all macros
*/ */
const removeBartack = function (name = 'bartack', id = macroDefaults.id, { paths, store, part }) { const removeBartack = (name = 'bartack', id = macroDefaults.id, { store, part }) =>
for (const pid of Object.values( store.removeMacroNodes(id, name, part)
store.get(['parts', part.name, 'macros', name, 'ids', id, 'paths'], {})
))
delete paths[pid]
}
/* /*
* The rmbartackalong and rmbartackfractionalong macros just call rmbartack with the correct name * The rmbartackalong and rmbartackfractionalong macros just call rmbartack with the correct name

View file

@ -1,5 +1,3 @@
import { getIds } from './utils.mjs'
/* /*
* Defaults for the title macro * Defaults for the title macro
*/ */
@ -17,14 +15,8 @@ const macroDefaults = {
/* /*
* The rmcrossbox macro * The rmcrossbox macro
*/ */
const rmcrossbox = function (id = macroDefaults.id, { paths, points, store, part }) { const rmcrossbox = (id = macroDefaults.id, { store, part }) =>
const both = store.get(['parts', part.name, 'macros', 'title', 'ids', id], { store.removeMacroNodes(id, 'crossbox', part)
paths: {},
points: {},
})
for (const pid of Object.values(both.points)) delete points[pid]
for (const pid of Object.values(both.paths)) delete paths[pid]
}
/* /*
* The crossbox macro * The crossbox macro
@ -62,7 +54,7 @@ const crossbox = function (config, { points, Point, paths, Path, complete, store
/* /*
* Get the list of IDs * Get the list of IDs
*/ */
const flatIds = getIds(['box', 'cross', 'text'], mc.id, 'crossbox') const flatIds = store.generateMacroIds(['box', 'cross', 'text'], mc.id)
const ids = { const ids = {
paths: { paths: {
box: flatIds.box, box: flatIds.box,
@ -118,9 +110,12 @@ const crossbox = function (config, { points, Point, paths, Path, complete, store
* Store all IDs in the store so we can remove this macro with rmtitle * Store all IDs in the store so we can remove this macro with rmtitle
* Just make sure to keep points and paths apart * Just make sure to keep points and paths apart
*/ */
store.set(['parts', part.name, 'macros', 'title', 'ids', mc.id], ids) store.storeMacroIds(mc.id, ids)
return store.getMacroIds(mc.id, 'crossbox') /*
* Returning ids is a best practice for FreeSewing macros
*/
return store.getMacroIds(mc.id)
} }
// Export macros // Export macros

View file

@ -1,5 +1,3 @@
import { getIds } from './utils.mjs'
/* /*
* Defaults for the cutonfold macro * Defaults for the cutonfold macro
*/ */
@ -36,12 +34,8 @@ export const cutonfoldDefs = [
/* /*
* The rmcutonfold macro * The rmcutonfold macro
*/ */
const rmcutonfold = function (id = macroDefaults.id, { paths, store, part }) { const rmcutonfold = (id = macroDefaults.id, { store, part }) =>
for (const pid of Object.values( store.removeMacroNodes(id, 'cutonfold', part)
store.get(['parts', part.name, 'macros', 'cutonfold', 'ids', id, 'paths'], {})
))
delete paths[pid]
}
/* /*
* The cutonfold macro * The cutonfold macro
@ -86,7 +80,7 @@ const cutonfold = function (config, { paths, Path, complete, store, scale, log,
/* /*
* Get the list of IDs * Get the list of IDs
*/ */
const ids = getIds(['line'], mc.id, 'cutonfold') const ids = store.generateMacroIds(['line'], mc.id)
/* /*
* Draw the path * Draw the path
@ -106,9 +100,12 @@ const cutonfold = function (config, { paths, Path, complete, store, scale, log,
/* /*
* Store all IDs in the store so we can remove this macro with rmcutonfold * Store all IDs in the store so we can remove this macro with rmcutonfold
*/ */
store.set(['parts', part.name, 'macros', 'cutonfold', 'ids', mc.id, 'paths'], ids) store.storeMacroIds(mc.id, { paths: ids })
return store.getMacroIds(mc.id, 'cutonfold') /*
* Returning ids is a best practice for FreeSewing macros
*/
return store.getMacroIds(mc.id)
} }
// Export macros // Export macros

View file

@ -1,5 +1,3 @@
import { getIds } from './utils.mjs'
// Export defs // Export defs
export const dimensionsDefs = [ export const dimensionsDefs = [
{ {
@ -122,7 +120,7 @@ const addDimension = (config, props, type) => {
/* /*
* Get the list of IDs * Get the list of IDs
*/ */
const ids = getIds(['line', 'from', 'to'], mc.id, type) const ids = props.store.generateMacroIds(['line', 'from', 'to'], mc.id)
/* /*
* Draw the dimension * Draw the dimension
@ -150,28 +148,28 @@ const addDimension = (config, props, type) => {
/* /*
* Store all IDs in the store so we can remove this macro with rm variants * Store all IDs in the store so we can remove this macro with rm variants
*/ */
props.store.set(['parts', props.part.name, 'macros', type, 'ids', mc.id, 'paths'], ids) props.store.storeMacroIds(mc.id, { paths: ids })
return props.store.getMacroIds(mc.id, type) /*
* Returning ids is a best practice for FreeSewing macros
*/
return props.store.getMacroIds(mc.id)
} }
/* /*
* This method handles the 'remove' part for all macros * This method handles the 'remove' part for all macros
*/ */
const removeDimension = function (id = macroDefaults.id, { paths, store, part }, type) { const removeDimension = function (id = macroDefaults.id, { store, part }, type) {
for (const pid of Object.values( return store.removeMacroNodes(id, type, part)
store.get(['parts', part.name, 'macros', type, 'ids', id, 'paths'], {})
))
delete paths[pid]
} }
/* /*
* This method removes all dimensions of a given type * This method removes all dimensions of a given type
*/ */
const removeDimensionType = function ({ paths, store, part }, type) { const removeDimensionType = function ({ paths, store, part }, type) {
for (const ids of Object.values(store.get(['parts', part.name, 'macros', type, 'ids'], {}))) { // Get all macro IDs of the given type
for (const pid of Object.values(ids.paths)) delete paths[pid] const ids = store.get(['parts', part.name, 'macros', type, 'ids'], {})
} for (const id in ids) store.removeMacroNodes(id, type, part)
} }
/* /*

View file

@ -1,5 +1,3 @@
import { getIds } from './utils.mjs'
/* /*
* Defaults for the grainline macro * Defaults for the grainline macro
*/ */
@ -34,12 +32,8 @@ export const grainlineDefs = [
/* /*
* The rmgrainline macro * The rmgrainline macro
*/ */
const rmgrainline = function (id = macroDefaults.id, { paths, store, part }) { const rmgrainline = (id = macroDefaults.id, { store, part }) =>
for (const pid of Object.values( store.removeMacroNodes(id, 'grainline', part)
store.get(['parts', part.name, 'macros', 'grainline', 'ids', id, 'paths'], {})
))
delete paths[pid]
}
/* /*
* The grainline macro * The grainline macro
@ -80,7 +74,7 @@ const grainline = function (config = {}, { paths, Path, Point, complete, store,
/* /*
* Get the list of IDs * Get the list of IDs
*/ */
const ids = getIds(['line'], mc.id, 'grainline') const ids = store.generateMacroIds(['line'], mc.id)
/* /*
* Draw the path * Draw the path
@ -98,9 +92,12 @@ const grainline = function (config = {}, { paths, Path, Point, complete, store,
/* /*
* Store all IDs in the store so we can remove this macro with rmgrainline * Store all IDs in the store so we can remove this macro with rmgrainline
*/ */
store.set(['parts', part.name, 'macros', 'grainline', 'ids', mc.id, 'paths'], ids) store.storeMacroIds(mc.id, { paths: ids })
return store.getMacroIds(mc.id, 'grainline') /*
* Returning ids is a best practice for FreeSewing macros
*/
return store.getMacroIds(mc.id)
} }
// Export macros // Export macros

View file

@ -21,7 +21,6 @@ import { pleatMacros, pleatDefs } from './pleat.mjs'
import { sewtogetherMacros, sewtogetherDefs } from './sewtogether.mjs' import { sewtogetherMacros, sewtogetherDefs } from './sewtogether.mjs'
// Only stores // Only stores
import { flagStores } from './flag.mjs' import { flagStores } from './flag.mjs'
import { utilsStores } from './utils.mjs'
export const plugin = { export const plugin = {
name, name,
@ -62,7 +61,7 @@ export const plugin = {
...sewtogetherMacros, ...sewtogetherMacros,
...titleMacros, ...titleMacros,
}, },
store: [...cutlistStores, ...flagStores, ...utilsStores], store: [...cutlistStores, ...flagStores],
} }
export const annotationsPlugin = plugin export const annotationsPlugin = plugin

View file

@ -1,5 +1,3 @@
import { getIds } from './utils.mjs'
/* /*
* Defaults for the pleat macro * Defaults for the pleat macro
*/ */
@ -29,12 +27,8 @@ export const pleatDefs = [
/* /*
* The rmpleat macro * The rmpleat macro
*/ */
const rmpleat = function (id = macroDefaults.id, { paths, store, part }) { const rmpleat = (id = macroDefaults.id, { store, part }) =>
for (const pid of Object.values( store.removeMacroNodes(id, 'rmpleat', part)
store.get(['parts', part.name, 'macros', 'pleat', 'ids', id, 'paths'], {})
))
delete paths[pid]
}
/* /*
* The pleat macro * The pleat macro
@ -71,7 +65,7 @@ const pleat = function (config, { paths, Path, log, Point, complete, scale, stor
* Get the list of IDs * Get the list of IDs
* Initialize the verticle cadence * Initialize the verticle cadence
*/ */
const ids = getIds(['from', 'to', 'arrow'], mc.id, 'pleat') const ids = store.generateMacroIds(['from', 'to', 'arrow'], mc.id)
const toIn = mc.to.shift(mc.from.shiftTowards(mc.to, 0.1).angle(mc.to) + 90, mc.margin * scale) const toIn = mc.to.shift(mc.from.shiftTowards(mc.to, 0.1).angle(mc.to) + 90, mc.margin * scale)
const fromIn = mc.from.shift( const fromIn = mc.from.shift(
@ -109,9 +103,12 @@ const pleat = function (config, { paths, Path, log, Point, complete, scale, stor
/* /*
* Store all IDs in the store so we can remove this macro with rmpleat * Store all IDs in the store so we can remove this macro with rmpleat
*/ */
store.set(['parts', part.name, 'macros', 'pleat', 'ids', mc.id, 'paths'], ids) store.storeMacroIds(mc.id, { paths: ids })
return store.getMacroIds(mc.id, 'pleat') /*
* Returning ids is a best practice for FreeSewing macros
*/
return store.getMacroIds(mc.id)
} }
// Export macros // Export macros

View file

@ -1,5 +1,3 @@
import { getIds } from './utils.mjs'
/* /*
* Defaults for the title macro * Defaults for the title macro
*/ */
@ -65,9 +63,7 @@ const sizes = {
*/ */
const removeScaleAnnotation = function (id = false, { paths, points, store, part }, type) { const removeScaleAnnotation = function (id = false, { paths, points, store, part }, type) {
if (!id) id = type if (!id) id = type
const both = store.get(['parts', part.name, 'macros', type, 'ids', id], { paths: {}, points: {} }) return store.removeMacroNodes(id, type, part)
for (const pid of Object.values(both.points)) delete points[pid]
for (const pid of Object.values(both.paths)) delete paths[pid]
} }
/* /*
@ -114,7 +110,7 @@ const scalebox = function (
/* /*
* Get the list of IDs * Get the list of IDs
*/ */
const ids = getIds( const ids = store.generateMacroIds(
[ [
'metric', 'metric',
'imperial', 'imperial',
@ -125,8 +121,7 @@ const scalebox = function (
'textText', 'textText',
'textLink', 'textLink',
], ],
mc.id, mc.id
'scalebox'
) )
/* /*
@ -245,7 +240,7 @@ const scalebox = function (
/* /*
* Store all IDs in the store so we can remove this macro with rmscaleboc * Store all IDs in the store so we can remove this macro with rmscaleboc
*/ */
store.set(['parts', part.name, 'macros', 'scalebox', 'ids', mc.id], { store.storeMacroIds(mc.id, {
points: { points: {
textLead: ids.textLead, textLead: ids.textLead,
textMetric: ids.textMetric, textMetric: ids.textMetric,
@ -260,7 +255,10 @@ const scalebox = function (
}, },
}) })
return store.getMacroIds(mc.id, 'scalebox') /*
* Returning ids is a best practice for FreeSewing macros
*/
return store.getMacroIds(mc.id)
} }
/* /*
@ -306,7 +304,7 @@ const miniscale = function (
/* /*
* Get the list of IDs * Get the list of IDs
*/ */
const ids = getIds(['metric', 'imperial', 'textMetric', 'textImperial'], mc.id, 'miniscale') const ids = store.generateMacroIds(['metric', 'imperial', 'textMetric', 'textImperial'], mc.id)
/* /*
* Box points (no need to add these to the part) * Box points (no need to add these to the part)
@ -384,7 +382,7 @@ const miniscale = function (
/* /*
* Store all IDs in the store so we can remove this macro with rmscaleboc * Store all IDs in the store so we can remove this macro with rmscaleboc
*/ */
store.set(['parts', part.name, 'macros', 'miniscale', 'ids', mc.id], { store.storeMacroIds(mc.id, {
points: { points: {
textMetric: ids.textMetric, textMetric: ids.textMetric,
textImperial: ids.textImperial, textImperial: ids.textImperial,
@ -394,6 +392,11 @@ const miniscale = function (
imperial: ids.imperial, imperial: ids.imperial,
}, },
}) })
/*
* Returning ids is a best practice for FreeSewing macros
*/
return store.getMacroIds(mc.id)
} }
// Export macros // Export macros

View file

@ -1,5 +1,3 @@
import { getIds } from './utils.mjs'
/* /*
* Defaults for the sewtogether macro * Defaults for the sewtogether macro
*/ */
@ -42,12 +40,8 @@ export const sewtogetherDefs = [
/* /*
* The rmsewtogether macro * The rmsewtogether macro
*/ */
const rmsewtogether = function (id = macroDefaults.id, { paths, store, part }) { const rmsewtogether = (id = macroDefaults.id, { store, part }) =>
for (const pid of Object.values( store.removeMacroNodes(id, 'sewtogether', part)
store.get(['parts', part.name, 'macros', 'sewtogether', 'ids', id, 'paths'], {})
))
delete paths[pid]
}
/* /*
* The sewtogether macro * The sewtogether macro
@ -89,7 +83,7 @@ const sewtogether = function (config, { paths, Path, log, Point, complete, sa, s
* Get the list of IDs * Get the list of IDs
* Initialize the verticle cadence * Initialize the verticle cadence
*/ */
const ids = getIds(['curve', 'hinge'], mc.id, 'sewtogether') const ids = store.generateMacroIds(['curve', 'hinge'], mc.id)
/* /*
* Draw the curve * Draw the curve
@ -124,9 +118,12 @@ const sewtogether = function (config, { paths, Path, log, Point, complete, sa, s
/* /*
* Store all IDs in the store so we can remove this macro with rmsewtogether * Store all IDs in the store so we can remove this macro with rmsewtogether
*/ */
store.set(['parts', part.name, 'macros', 'sewtogether', 'ids', mc.id, 'paths'], ids) store.storeMacroIds(mc.id, { paths: ids })
return store.getMacroIds(mc.id, 'sewtogether') /*
* Returning ids is a best practice for FreeSewing macros
*/
return store.getMacroIds(mc.id)
} }
// Export macros // Export macros

View file

@ -1,5 +1,3 @@
import { getIds } from './utils.mjs'
/* /*
* Defaults for the title macro * Defaults for the title macro
*/ */
@ -24,24 +22,10 @@ const macroDefaults = {
}, },
} }
/*
* Removing all this is easy as all IDs are available in the store
* and all we need to remove are points.
*/
const removeTitleMacro = function (id = macroDefaults.id, { points, store, part }) {
for (const pid of Object.values(
store.get(['parts', part.name, 'macros', 'title', 'ids', id, 'points'], {})
))
delete points[pid]
}
/* /*
* The title macro * The title macro
*/ */
const addTitleMacro = function ( const title = function (config, { Point, points, scale, locale, store, part, log, complete }) {
config,
{ Point, points, scale, locale, store, part, log, complete }
) {
/* /*
* Don't add a title when complete is false, unless force is true * Don't add a title when complete is false, unless force is true
*/ */
@ -92,7 +76,7 @@ const addTitleMacro = function (
* Get the list of IDs * Get the list of IDs
* Initialize the verticle cadence * Initialize the verticle cadence
*/ */
const ids = getIds(['cutlist', 'date', 'for', 'name', 'nr', 'title'], mc.id, 'title') const ids = store.generateMacroIds(['cutlist', 'date', 'for', 'name', 'nr', 'title'], mc.id)
let shift = mc.dy let shift = mc.dy
@ -229,13 +213,16 @@ const addTitleMacro = function (
/* /*
* Store all IDs in the store so we can remove this macro with rmtitle * Store all IDs in the store so we can remove this macro with rmtitle
*/ */
store.set(['parts', part.name, 'macros', 'title', 'ids', mc.id, 'points'], ids) store.storeMacroIds(mc.id, { points: ids })
return store.getMacroIds(mc.id, 'title') /*
* Returning ids is a best practice for FreeSewing macros
*/
return store.getMacroIds(mc.id)
} }
// Export macros // Export macros
export const titleMacros = { export const titleMacros = {
title: addTitleMacro, title,
rmtitle: removeTitleMacro, rmtitle: (id = macroDefaults.id, { store, part }) => store.removeMacroNodes(id, 'title', part),
} }

View file

@ -1,27 +0,0 @@
/*
* Helper method to get the various IDs for a macro
*/
export const getIds = (keys, id, macroName) => {
const ids = {}
for (const key of keys) ids[key] = `__macro_${macroName}_${id}_${key}`
return ids
}
/*
* Helper method to get an existing macro id
*/
const getIdsFromStore = (store, id, macroName, partName = false) => {
if (!partName) partName = store.activePart
const data = store.get(['parts', partName, 'macros', macroName, 'ids', id])
return data ? data : false
}
/*
* Add these to the store
*/
export const utilsStores = [
['createMacroIds', (store, keys, id, macroName) => getIds(keys, id, macroName)],
['getMacroIds', getIdsFromStore],
]

View file

@ -66,7 +66,7 @@ export const plugin = {
* Get the list of IDs * Get the list of IDs
*/ */
const ids = getIds(keys, id) const ids = getIds(keys, id)
const pathId = getIds(['path'], id).path const pathIds = getIds(['path'], id)
/** /**
* Calculates the distance of the control point for the internal * Calculates the distance of the control point for the internal
@ -145,8 +145,8 @@ export const plugin = {
points[ids[id] + 'Rotated'].rotate(deg, points[ids.in2Flipped]) points[ids[id] + 'Rotated'].rotate(deg, points[ids.in2Flipped])
} }
} }
// Return the path of the full ring sector // Construct the path of the full ring sector
paths[pathId] = new Path() paths[pathIds.path] = new Path()
.move(points[ids.in2Flipped]) .move(points[ids.in2Flipped])
.curve(points[ids.in2cFlipped], points[ids.in1cFlipped], points[ids.in1]) .curve(points[ids.in2cFlipped], points[ids.in1cFlipped], points[ids.in1])
.curve(points[ids.in1c], points[ids.in2c], points[ids.in2]) .curve(points[ids.in1c], points[ids.in2c], points[ids.in2])
@ -158,8 +158,15 @@ export const plugin = {
/* /*
* Store all IDs in the store so we can remove this macro with rmringsector * Store all IDs in the store so we can remove this macro with rmringsector
*/ */
store.set(['parts', part.name, 'macros', name, 'ids', id, 'paths'], { path: pathId }) store.storeMacroIds(mc.id, {
store.set(['parts', part.name, 'macros', name, 'ids', id, 'points'], ids) paths: pathIds,
points: ids,
})
/*
* Returning ids is a best practice for FreeSewing macros
*/
return store.getMacroIds(mc.id)
}, },
}, },
} }

View file

@ -1,5 +1,4 @@
import { name, version } from '../data.mjs' import { name, version } from '../data.mjs'
import { getIds } from './utils.mjs'
/* /*
* These are the keys for macro IDs * These are the keys for macro IDs
@ -22,7 +21,9 @@ export const plugin = {
hide = true, hide = true,
} = mc } = mc
let { radius = 66.6 } = mc let { radius = 66.6 } = mc
const ids = getIds([...pointKeys, ...pathKeys], id, name) const pointIds = store.generateMacroIds(pointKeys, id)
const pathIds = store.generateMacroIds(pathKeys, id)
const ids = { ...pointIds, ...pathIds }
const fd = from.dist(via) const fd = from.dist(via)
const td = to.dist(via) const td = to.dist(via)
@ -41,16 +42,15 @@ export const plugin = {
/* /*
* Store all IDs in the store so we can remove this macro with rmtitle * Store all IDs in the store so we can remove this macro with rmtitle
*/ */
store.set( store.storeMacroIds(mc.id, {
['parts', part.name, 'macros', 'round', 'ids', mc.id, 'points'], paths: pathIds,
getIds(pointKeys, id, name) points: pointIds,
) })
store.set(
['parts', part.name, 'macros', 'round', 'ids', mc.id, 'paths'],
getIds(pathKeys, id, name)
)
return store.getMacroIds(id, 'round') /*
* Returning ids is a best practice for FreeSewing macros
*/
return store.getMacroIds(mc.id)
}, },
}, },
} }

View file

@ -1,9 +0,0 @@
/*
* Helper method to get the various IDs for a macro
*/
export const getIds = (keys, id, macroName) => {
const ids = {}
for (const key of keys) ids[key] = `__macro_${macroName}_${id}_${key}`
return ids
}