288 lines
10 KiB
JavaScript
288 lines
10 KiB
JavaScript
import {Tile, TileState} from './tile.js';
|
|
import {Direction} from './tileWindowManager.js';
|
|
import {Position} from './position.js';
|
|
export class Monitor {
|
|
_root;
|
|
_index;
|
|
_fullscreenState = false;
|
|
constructor(index) {
|
|
this._index = index;
|
|
this._root = null;
|
|
}
|
|
|
|
set root(root) {
|
|
this._root = root;
|
|
}
|
|
|
|
get root() {
|
|
return this._root;
|
|
}
|
|
|
|
get index() {
|
|
return this._index;
|
|
}
|
|
|
|
get fullscreen() {
|
|
return this._fullscreenState;
|
|
}
|
|
|
|
set fullscreen(b) {
|
|
this._fullscreenState = b;
|
|
}
|
|
|
|
size() {
|
|
return this._root ? this._root._nr_tiles : 0;
|
|
}
|
|
|
|
updateSize() {
|
|
if (this._root) {
|
|
const area = global.workspace_manager.get_active_workspace().get_work_area_for_monitor(this.index);
|
|
if (area) {
|
|
let pos = new Position(1.0, 0, 0, area.width, area.height);
|
|
pos.splitProportion = this._root.position.splitProportion;
|
|
this._root.resize(pos);
|
|
}
|
|
}
|
|
}
|
|
|
|
static bestFitMonitor(monitors) {
|
|
return monitors.reduce((acc, val) => val.size() < acc.size() ? val : acc, monitors[0]);
|
|
}
|
|
|
|
static tileDistance(t1, t2) {
|
|
let vector = [t1.position.x - t2.position.x, t1.position.y - t2.position.y];
|
|
return Math.sqrt(vector[0] * vector[0] + vector[1] * vector[1]);
|
|
}
|
|
|
|
closestTile(source, dir) {
|
|
// Class to store the result
|
|
class BestTile {
|
|
tile = null;
|
|
distance = null;
|
|
constructor(tile = null, distance = null) {
|
|
this.tile = tile;
|
|
this.distance = distance;
|
|
}
|
|
}
|
|
;
|
|
// We search for the closest tile in a Direction. We recursively iterate the tree
|
|
let findClosest = tile => {
|
|
switch (dir) {
|
|
case Direction.East:
|
|
if (tile.leaf && tile.position.x > source.position.x) {
|
|
return new BestTile(tile, Monitor.tileDistance(tile, source));
|
|
} else if (tile.leaf) {
|
|
return new BestTile();
|
|
} else if (tile.child1 && tile.child2) {
|
|
let res1 = findClosest(tile.child1);
|
|
let res2 = findClosest(tile.child2);
|
|
if ((res1.distance && res2.distance && res1.distance > res2.distance) ||
|
|
(res2.distance && !res1.distance))
|
|
return res2;
|
|
|
|
else if ((res1.distance && res2.distance && res1.distance < res2.distance) ||
|
|
(res1.distance && !res2.distance))
|
|
return res1;
|
|
|
|
else
|
|
return new BestTile();
|
|
}
|
|
return new BestTile();
|
|
case Direction.West:
|
|
if (tile.leaf && tile.position.x < source.position.x) {
|
|
return new BestTile(tile, Monitor.tileDistance(tile, source));
|
|
} else if (tile.leaf) {
|
|
return new BestTile();
|
|
} else if (tile.child1 && tile.child2) {
|
|
let res1 = findClosest(tile.child1);
|
|
let res2 = findClosest(tile.child2);
|
|
if ((res1.distance && res2.distance && res1.distance > res2.distance) ||
|
|
(res2.distance && !res1.distance))
|
|
return res2;
|
|
|
|
else if ((res1.distance && res2.distance && res1.distance < res2.distance) ||
|
|
(res1.distance && !res2.distance))
|
|
return res1;
|
|
|
|
else
|
|
return new BestTile();
|
|
}
|
|
return new BestTile();
|
|
case Direction.North:
|
|
if (tile.leaf && tile.position.y < source.position.y) {
|
|
return new BestTile(tile, Monitor.tileDistance(tile, source));
|
|
} else if (tile.leaf) {
|
|
return new BestTile();
|
|
} else if (tile.child1 && tile.child2) {
|
|
let res1 = findClosest(tile.child1);
|
|
let res2 = findClosest(tile.child2);
|
|
if ((res1.distance && res2.distance && res1.distance > res2.distance) ||
|
|
(res2.distance && !res1.distance))
|
|
return res2;
|
|
|
|
else if ((res1.distance && res2.distance && res1.distance < res2.distance) ||
|
|
(res1.distance && !res2.distance))
|
|
return res1;
|
|
|
|
else
|
|
return new BestTile();
|
|
}
|
|
return new BestTile();
|
|
case Direction.South:
|
|
if (tile.leaf && tile.position.y > source.position.y) {
|
|
return new BestTile(tile, Monitor.tileDistance(tile, source));
|
|
} else if (tile.leaf) {
|
|
return new BestTile();
|
|
} else if (tile.child1 && tile.child2) {
|
|
let res1 = findClosest(tile.child1);
|
|
let res2 = findClosest(tile.child2);
|
|
if ((res1.distance && res2.distance && res1.distance > res2.distance) ||
|
|
(res2.distance && !res1.distance))
|
|
return res2;
|
|
|
|
else if ((res1.distance && res2.distance && res1.distance < res2.distance) ||
|
|
(res1.distance && !res2.distance))
|
|
return res1;
|
|
|
|
else
|
|
return new BestTile();
|
|
}
|
|
return new BestTile();
|
|
default:
|
|
return new BestTile();
|
|
}
|
|
};
|
|
if (this.root) {
|
|
let res = findClosest(this.root);
|
|
return res.tile;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
destroy() {
|
|
this._index = -1;
|
|
this._root = null;
|
|
}
|
|
|
|
static fromObject(obj) {
|
|
let monitor = new Monitor(obj._index);
|
|
monitor.fullscreen = obj._fullscreenState;
|
|
if (!obj._root)
|
|
monitor.root = null;
|
|
else
|
|
monitor.root = Tile.fromObject(obj._root);
|
|
return monitor;
|
|
}
|
|
|
|
closestMonitor(dir) {
|
|
let nMonitors = global.display.get_n_monitors();
|
|
let _currGeo = global.display.get_monitor_geometry(this.index);
|
|
let min;
|
|
let best = null;
|
|
switch (dir) {
|
|
case Direction.North:
|
|
for (let i = 0; i < nMonitors; i++) {
|
|
if (this.index !== i) {
|
|
let _geometry = global.display.get_monitor_geometry(i);
|
|
if (_geometry.y < _currGeo.y && (min === undefined || _geometry.y > min)) {
|
|
min = _geometry.y;
|
|
best = i;
|
|
}
|
|
}
|
|
}
|
|
return best;
|
|
case Direction.South:
|
|
for (let i = 0; i < nMonitors; i++) {
|
|
if (this.index !== i) {
|
|
let _geometry = global.display.get_monitor_geometry(i);
|
|
if (_geometry.y > _currGeo.y && (min === undefined || _geometry.y < min)) {
|
|
min = _geometry.y;
|
|
best = i;
|
|
}
|
|
}
|
|
}
|
|
return best;
|
|
case Direction.East:
|
|
for (let i = 0; i < nMonitors; i++) {
|
|
if (this.index !== i) {
|
|
let _geometry = global.display.get_monitor_geometry(i);
|
|
if (_geometry.x > _currGeo.x && (min === undefined || _geometry.x < min)) {
|
|
min = _geometry.x;
|
|
best = i;
|
|
}
|
|
}
|
|
}
|
|
return best;
|
|
case Direction.West:
|
|
for (let i = 0; i < nMonitors; i++) {
|
|
if (this.index !== i) {
|
|
let _geometry = global.display.get_monitor_geometry(i);
|
|
if (_geometry.x < _currGeo.x && (!min || _geometry.x > min)) {
|
|
min = _geometry.x;
|
|
best = i;
|
|
}
|
|
}
|
|
}
|
|
return best;
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/** Returns tile closest to the edge on a monitor
|
|
* - If the monitor is in fullscreen it returns the maximized window
|
|
*
|
|
* @param {Direction} dir
|
|
* @returns {Tile | null}
|
|
*/
|
|
getTile(dir) {
|
|
if (this.root === null)
|
|
return null;
|
|
if (this.fullscreen)
|
|
return this.root.find(t => t.state === TileState.MAXIMIZED);
|
|
let getTileBis = t => {
|
|
switch (dir) {
|
|
case Direction.East:
|
|
if (t.child2 !== null && t.child1 !== null)
|
|
return t.child1.position.x > t.child2.position.x ? getTileBis(t.child1) : getTileBis(t.child2);
|
|
else if (t.child1 !== null)
|
|
return getTileBis(t.child1);
|
|
else if (t.child2 !== null)
|
|
return getTileBis(t.child2);
|
|
else
|
|
return t;
|
|
case Direction.West:
|
|
if (t.child2 !== null && t.child1 !== null)
|
|
return t.child1.position.x < t.child2.position.x ? getTileBis(t.child1) : getTileBis(t.child2);
|
|
else if (t.child1 !== null)
|
|
return getTileBis(t.child1);
|
|
else if (t.child2 !== null)
|
|
return getTileBis(t.child2);
|
|
else
|
|
return t;
|
|
case Direction.North:
|
|
if (t.child2 !== null && t.child1 !== null)
|
|
return t.child1.position.y < t.child2.position.y ? getTileBis(t.child1) : getTileBis(t.child2);
|
|
else if (t.child1 !== null)
|
|
return getTileBis(t.child1);
|
|
else if (t.child2 !== null)
|
|
return getTileBis(t.child2);
|
|
else
|
|
return t;
|
|
case Direction.South:
|
|
if (t.child2 !== null && t.child1 !== null)
|
|
return t.child1.position.y > t.child2.position.y ? getTileBis(t.child1) : getTileBis(t.child2);
|
|
else if (t.child1 !== null)
|
|
return getTileBis(t.child1);
|
|
else if (t.child2 !== null)
|
|
return getTileBis(t.child2);
|
|
else
|
|
return t;
|
|
default:
|
|
return t;
|
|
}
|
|
};
|
|
return getTileBis(this.root);
|
|
}
|
|
}
|