Implement a simple autobind

This commit is contained in:
Bán Dénes 2022-02-27 18:18:16 +01:00
parent d23bd71b7a
commit b928cbd35d
17 changed files with 221 additions and 28 deletions

View file

@ -44,7 +44,7 @@ const _in = exports.in = (raw, name, arr) => {
const arr = exports.arr = (raw, name, length, _type, _default) => units => {
assert(type(raw)(units) == 'array', `Field "${name}" should be an array!`)
assert(length == 0 || raw.length == length, `Field "${name}" should be an array of length ${length}!`)
raw = raw.map(val => val || _default)
raw = raw.map(val => val === undefined ? _default : val)
raw.map(val => assert(type(val)(units) == _type, `Field "${name}" should contain ${_type}s!`))
if (_type == 'number') {
raw = raw.map(val => mathnum(val)(units))
@ -62,8 +62,8 @@ const wh = exports.wh = (raw, name) => units => {
return xy(raw, name)(units)
}
exports.trbl = (raw, name) => units => {
exports.trbl = (raw, name, _default=0) => units => {
if (!Array.isArray(raw)) raw = [raw, raw, raw, raw]
if (raw.length == 2) raw = [raw[1], raw[0], raw[1], raw[0]]
return numarr(raw, name, 4, 'number', 0)(units)
return arr(raw, name, 4, 'number', _default)(units)
}

View file

@ -198,8 +198,7 @@ exports.parse = (config = {}, points = {}, units = {}) => {
// process keys that are common to all part declarations
const operation = u[a.in(part.operation || 'add', `${name}.operation`, ['add', 'subtract', 'intersect', 'stack'])]
const what = a.in(part.what || 'outline', `${name}.what`, ['rectangle', 'circle', 'polygon', 'outline'])
const bound_by_default = ['rectangle']
const bound = part.bound === undefined ? bound_by_default.includes(what) : !!part.bound
const bound = !!part.bound
const mirror = a.sane(part.mirror || false, `${name}.mirror`, 'boolean')()
// `where` is delayed until we have all, potentially what-dependent units
// default where is [0, 0], as per filter parsing

View file

@ -43,6 +43,7 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor, global_key,
// column layout
const col_minmax = {}
if (!Object.keys(cols).length) {
cols.default = {}
}
@ -52,6 +53,7 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor, global_key,
// column-level sanitization
col = col || {}
col_minmax[col_name] = {min: Infinity, max: -Infinity}
a.unexpected(
col,
@ -93,6 +95,7 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor, global_key,
width: units.$default_width,
height: units.$default_height,
padding: units.$default_padding,
autobind: units.$default_autobind,
skip: false,
asym: 'both',
colrow: '{{col.name}}_{{row}}',
@ -155,21 +158,83 @@ const render_zone = exports._render_zone = (zone_name, zone, anchor, global_key,
// actually laying out keys
for (const key of keys) {
// copy the current column anchor
let point = col_anchor.clone()
// apply transformations
for (const r of rotations) {
point.rotate(r.angle, r.origin)
}
point.r += key.orient
point.shift(key.shift)
point.r += key.rotate
// save new key
point.meta = key
points[key.name] = point
// collect minmax stats for autobind
col_minmax[col_name].min = Math.min(col_minmax[col_name].min, point.y)
col_minmax[col_name].max = Math.max(col_minmax[col_name].max, point.y)
// advance the column anchor to the next position
col_anchor.y += key.padding
}
first_col = false
}
// autobind
let col_names = Object.keys(col_minmax)
let col_index = 0
for (const [col_name, bounds] of Object.entries(col_minmax)) {
for (const point of Object.values(points)) {
if (point.meta.col.name != col_name) continue
if (!point.meta.autobind) continue
const autobind = a.sane(point.meta.autobind, `${point.meta.name}.autobind`, 'number')(units)
// specify default as -1, so we can recognize where it was left undefined even after number-ification
const bind = point.meta.bind = a.trbl(point.meta.bind, `${point.meta.name}.bind`, -1)(units)
// up
if (bind[0] == -1) {
if (point.y < bounds.max) bind[0] = autobind
else bind[0] = 0
}
// right
if (bind[1] == -1) {
bind[1] = 0
if (col_index < col_names.length - 1) {
const right = col_minmax[col_names[col_index + 1]]
if (point.y >= right.min && point.y <= right.max) {
bind[1] = autobind
}
}
}
// down
if (bind[2] == -1) {
if (point.y > bounds.min) bind[2] = autobind
else bind[2] = 0
}
// left
if (bind[3] == -1) {
bind[3] = 0
if (col_index > 0) {
const left = col_minmax[col_names[col_index - 1]]
if (point.y >= left.min && point.y <= left.max) {
bind[3] = autobind
}
}
}
}
col_index++
}
return points
}

View file

@ -11,7 +11,8 @@ const default_units = {
$default_splay: 0,
$default_height: 'u-1',
$default_width: 'u-1',
$default_padding: 'u'
$default_padding: 'u',
$default_autobind: 10
}
exports.parse = (config = {}) => {