mirror of
https://github.com/captbaritone/webamp.git
synced 2026-01-23 18:25:30 +00:00
141 lines
3.1 KiB
TypeScript
141 lines
3.1 KiB
TypeScript
import { WindowInfo, WindowId } from "./types";
|
|
|
|
interface NewGraph {
|
|
[key: string]: {
|
|
above: string[];
|
|
left: string[];
|
|
};
|
|
}
|
|
|
|
interface PositionDiff {
|
|
[key: string]: {
|
|
x: number;
|
|
y: number;
|
|
};
|
|
}
|
|
|
|
export interface SizeDiff {
|
|
[key: string]: {
|
|
width: number;
|
|
height: number;
|
|
};
|
|
}
|
|
|
|
export function getPositionDiff(
|
|
graph: Graph,
|
|
sizeDiff: SizeDiff
|
|
): PositionDiff {
|
|
const newGraph: NewGraph = {};
|
|
const positionDiff: PositionDiff = {};
|
|
for (const key of Object.keys(graph)) {
|
|
newGraph[key] = { above: [], left: [] };
|
|
positionDiff[key] = { x: 0, y: 0 };
|
|
}
|
|
|
|
// Construct an inverted graph
|
|
for (const [key, neighbors] of Object.entries(graph)) {
|
|
const { below, right } = neighbors;
|
|
if (right != null) {
|
|
newGraph[right].left.push(key);
|
|
}
|
|
if (below != null) {
|
|
newGraph[below].above.push(key);
|
|
}
|
|
}
|
|
|
|
function walkRight(key: WindowId) {
|
|
const node = newGraph[key];
|
|
const nodeSizeDiff = sizeDiff[key];
|
|
node.left.forEach(left => {
|
|
positionDiff[left].x += nodeSizeDiff.width + positionDiff[key].x;
|
|
walkRight(left);
|
|
});
|
|
}
|
|
|
|
function walkDown(key: WindowId) {
|
|
const node = newGraph[key];
|
|
const nodeSizeDiff = sizeDiff[key];
|
|
node.above.forEach(above => {
|
|
positionDiff[above].y += nodeSizeDiff.height + positionDiff[key].y;
|
|
walkDown(above);
|
|
});
|
|
}
|
|
|
|
// Find disconnected nodes, and walk
|
|
for (const [key, neighbors] of Object.entries(graph)) {
|
|
if (neighbors.below == null) {
|
|
walkDown(key);
|
|
}
|
|
if (neighbors.right == null) {
|
|
walkRight(key);
|
|
}
|
|
}
|
|
|
|
return positionDiff;
|
|
}
|
|
|
|
interface Edges {
|
|
below?: WindowId;
|
|
right?: WindowId;
|
|
}
|
|
|
|
interface Graph {
|
|
// TODO: Ensure this is a WindowId
|
|
[id: string]: Edges;
|
|
}
|
|
|
|
export function generateGraph(windows: WindowInfo[]): Graph {
|
|
const bottoms: { [offset: number]: WindowInfo[] } = {};
|
|
const rights: { [offset: number]: WindowInfo[] } = {};
|
|
for (const w of windows) {
|
|
const bottom = w.y + w.height;
|
|
if (bottoms[bottom]) {
|
|
bottoms[bottom].push(w);
|
|
} else {
|
|
bottoms[bottom] = [w];
|
|
}
|
|
|
|
const right = w.x + w.width;
|
|
if (rights[right]) {
|
|
rights[right].push(w);
|
|
} else {
|
|
rights[right] = [w];
|
|
}
|
|
}
|
|
|
|
const graph: Graph = {};
|
|
for (const w of windows) {
|
|
const edges: Edges = {};
|
|
const top = w.y;
|
|
const left = w.x;
|
|
|
|
const tops = bottoms[top];
|
|
const lefts = rights[left];
|
|
if (tops) {
|
|
for (const below of tops) {
|
|
const isToTheLeft = below.x + below.width < w.x;
|
|
const isToTheRight = below.x > w.x + w.width;
|
|
|
|
const overlapsInX = !(isToTheLeft || isToTheRight);
|
|
if (overlapsInX) {
|
|
edges.below = below.key;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (lefts) {
|
|
for (const right of lefts) {
|
|
const isAbove = right.y + right.height < w.y;
|
|
const isBelow = right.y > w.y + w.height;
|
|
const overlapsInY = !(isAbove || isBelow);
|
|
if (overlapsInY) {
|
|
edges.right = right.key;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
graph[w.key] = edges;
|
|
}
|
|
return graph;
|
|
}
|