aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/App.vue1
-rw-r--r--src/components/Settings.vue5
-rw-r--r--src/lib.ts29
3 files changed, 34 insertions, 1 deletions
diff --git a/src/App.vue b/src/App.vue
index 51e2f79..d93e327 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -45,6 +45,7 @@ const defaultLayoutOptions: LayoutOptions = {
maxTileSz: 200, //px
layoutType: 'sweep', //'sqr' | 'rect' | 'sweep'
rectMode: 'auto first-row', //'horz' | 'vert' | 'linear' | 'auto' | 'auto first-row'
+ rectSepLeaves: true,
sweepMode: 'left', //'left' | 'top' | 'shorter' | 'auto'
sweptNodesPrio: 'pow-2/3', //'linear' | 'sqrt' | 'pow-2/3'
sweepingToParent: true,
diff --git a/src/components/Settings.vue b/src/components/Settings.vue
index 4fa3e03..97b08d1 100644
--- a/src/components/Settings.vue
+++ b/src/components/Settings.vue
@@ -83,6 +83,11 @@ export default defineComponent({
</div>
<hr class="border-stone-400"/>
<div>
+ <label> <input type="checkbox" v-model="layoutOptions.rectSepLeaves"
+ @change="onLayoutOptChg"/> Rect leaves to start </label>
+ </div>
+ <hr class="border-stone-400"/>
+ <div>
<label> <input type="checkbox" v-model="layoutOptions.sweepingToParent"
@change="onLayoutOptChg"/> Sweep to parent</label>
</div>
diff --git a/src/lib.ts b/src/lib.ts
index e83429d..0a23686 100644
--- a/src/lib.ts
+++ b/src/lib.ts
@@ -143,7 +143,8 @@ export type LayoutOptions = {
maxTileSz: number;
layoutType: 'sqr' | 'rect' | 'sweep'; // The LayoutFn function to use
rectMode: 'horz' | 'vert' | 'linear' | 'auto' | 'auto first-row';
- // Layout in 1 row, 1 column, 1 row or column, or multiple rows (with/without first-row-heuristic)
+ // Rect layout in 1 row, 1 column, 1 row or column, or multiple rows (with/without first-row-heuristic)
+ rectSepLeaves: boolean; // Rect layout moves leaf nodes to start
sweepMode: 'left' | 'top' | 'shorter' | 'auto'; // Sweep to left, top, shorter-side, or to minimise empty space
sweptNodesPrio: 'linear' | 'sqrt' | 'pow-2/3'; // Specifies allocation of space to swept-vs-remaining nodes
sweepingToParent: boolean; // Allow swept nodes to occupy empty space in a parent's swept-leaves area
@@ -341,6 +342,24 @@ let rectLayout: LayoutFn = function (node, pos, dims, showHeader, allowCollapse,
if (newDims[0] * newDims[1] <= 0){
return false;
}
+ // Reorder children if applicable
+ let oldNode: LayoutNode, oldChildIdxs: number[];
+ if (opts.rectSepLeaves){ // Change 'node' to leaves-to-start version, and store old-child-order indices
+ oldNode = node;
+ let leaves: LayoutNode[] = [], nonLeaves: LayoutNode[] = [];
+ let leafIdxs = [] as number[], nonLeafIdxs = [] as number[];
+ node.children.forEach((child, idx) => {
+ if (child.children.length == 0){
+ leaves.push(child);
+ leafIdxs.push(idx);
+ } else {
+ nonLeaves.push(child);
+ nonLeafIdxs.push(idx);
+ }
+ });
+ node = new LayoutNode(node.tolNode, leaves.concat(...nonLeaves));
+ oldChildIdxs = leafIdxs.concat(...nonLeafIdxs);
+ }
// Try finding arrangement with low empty space
// Done by searching possible rows groupings, allocating within rows using dCounts, and trimming empty space
let numChildren = node.children.length;
@@ -519,6 +538,9 @@ let rectLayout: LayoutFn = function (node, pos, dims, showHeader, allowCollapse,
}
}
if (usedTree == null){ // If no found layout
+ if (opts.rectSepLeaves){
+ node = oldNode!;
+ }
if (allowCollapse){
node.children = [];
LayoutNode.updateDCounts(node, 1 - node.dCount);
@@ -527,6 +549,11 @@ let rectLayout: LayoutFn = function (node, pos, dims, showHeader, allowCollapse,
return false;
}
// Create layout
+ if (opts.rectSepLeaves){ // Restore old 'node', and reorder 'usedTree's children to match
+ node = oldNode!;
+ let usedChildren = [...usedTree.children];
+ range(numChildren).forEach(idx => usedTree!.children[oldChildIdxs[idx]] = usedChildren[idx]);
+ }
usedTree.copyTreeForRender(node);
let usedDims: [number, number] = [dims[0] - usedEmpRight, dims[1] - usedEmpBottom];
node.assignLayoutData(pos, usedDims, {showHeader, empSpc: lowestEmpSpc});