scripts/screen/FrameManager_mesh.js
import nstructjs from '../path-controller/util/struct.js';
import * as ui_base from "../core/ui_base.js";
import * as FrameManager_ops from "./FrameManager_ops.js";
import cconst from "../config/const.js";
import {UIBase} from '../core/ui_base.js';
import {Vector2} from '../path-controller/util/vectormath.js';
import {createMenu, Menu} from '../widgets/ui_menu.js';
import {popModalLight, pushModalLight} from '../path-controller/util/simple_events.js';
import {AreaFlags} from './ScreenArea.js';
export let SnapLimit = 1;
export const BORDER_ZINDEX_BASE = 25
export function snap(c, snap_limit = SnapLimit) {
if (Array.isArray(c)) {
for (let i = 0; i < c.length; i++) {
c[i] = Math.floor(c[i]/snap_limit)*snap_limit;
}
} else {
c = Math.floor(c/snap_limit)*snap_limit;
}
return c;
}
export function snapi(c, snap_limit = SnapLimit) {
//return snap(c, snap_limit);
if (Array.isArray(c)) {
for (let i = 0; i < c.length; i++) {
c[i] = Math.ceil(c[i]/snap_limit)*snap_limit;
}
} else {
c = Math.ceil(c/snap_limit)*snap_limit;
}
return c;
}
export class ScreenVert extends Vector2 {
constructor(pos, id, added_id) {
super(pos);
this.added_id = added_id;
this.sareas = [];
this.borders = [];
this._id = id;
}
static hash(pos, added_id, limit) {
let x = snap(pos[0], limit);
let y = snap(pos[1], limit);
return "" + x + ":" + y + ": + added_id";
}
valueOf() {
return ScreenVert.hash(this, this.added_id);
}
[Symbol.keystr]() {
return ScreenVert.hash(this, this.added_id);
}
loadSTRUCT(reader) {
reader(this);
}
}
ScreenVert.STRUCT = `
pathux.ScreenVert {
0 : float;
1 : float;
}
`;
nstructjs.register(ScreenVert);
export class ScreenHalfEdge {
constructor(border, sarea) {
this.sarea = sarea;
this.border = border;
this.side = sarea._side(border);
}
get v1() {
return this.border.v1;
}
get v2() {
return this.border.v2;
}
[Symbol.keystr]() {
return this.sarea._id + ":" + this.border._id;
}
}
export class ScreenBorder extends ui_base.UIBase {
constructor() {
super();
this.visibleToPick = false;
this.screen = undefined;
this.v1 = undefined;
this.v2 = undefined;
this._id = undefined;
this._hash = undefined;
this.outer = undefined;
this.halfedges = []; //all bordering borders, including ones with nonshared verts
this.sareas = [];
this._innerstyle = document.createElement("style");
this._style = undefined;
this.shadow.appendChild(this._innerstyle);
this.inner = document.createElement("div");
//this.inner.innerText = "sdfsdfsdf";
this.shadow.appendChild(this.inner);
let call_menu = ScreenBorder.bindBorderMenu(this);
this.addEventListener("mousedown", (e) => {
let ok = this.movable;
if (e.button === 2) {
call_menu(e);
return;
}
if (!ok) {
console.log("border is not movable");
return;
}
console.log("area resize start!");
let tool = new FrameManager_ops.AreaResizeTool(this.screen, this, [e.x, e.y]);
tool.start();
e.preventDefault();
e.stopPropagation();
}, {capture: true});
}
static bindBorderMenu(elem, usePickElement=false) {
let on_dblclick = (e) => {
if (usePickElement && elem.pickElement(e.x, e.y) !== elem) {
return;
}
let menu = [
["Split Area", () => {
elem.ctx.screen.splitTool();
}],
Menu.SEP,
["Collapse Area", () => {
elem.ctx.screen.removeAreaTool(elem instanceof ScreenBorder ? elem : undefined);
}],
];
menu = createMenu(elem.ctx, "", menu);
//if (e.button === 2) {
menu.ignoreFirstClick = 2;
//}
elem.ctx.screen.popupMenu(menu, e.x-15, e.y-15);
e.preventDefault();
e.stopPropagation();
}
elem.addEventListener("contextmenu", (e) => e.preventDefault());
elem.addEventListener("dblclick", on_dblclick, {capture: true});
return on_dblclick;
}
getOtherSarea(sarea) {
console.log(this.halfedges, this.halfedges.length);
for (let he of this.halfedges) {
console.log(he);
let ok = he.sarea !== sarea;
ok = ok && he.sarea._verts.indexOf(this.v1) >= 0;
ok = ok && he.sarea._verts.indexOf(this.v2) >= 0;
if (ok) {
return he.sarea;
}
}
}
get locked() {
for (let sarea of this.sareas) {
let mask = 1<<sarea._borders.indexOf(this);
let lock = sarea.borderLock & mask;
if (lock || (sarea.flag & AreaFlags.NO_COLLAPSE)) {
return true;
}
}
return false;
}
get dead() {
return !this.parentNode;
}
get side() {
throw new Error("side accedd");
}
set side(val) {
throw new Error("side accedd");
}
get valence() {
let ret = 0; //this.sareas.length;
let horiz = this.horiz;
let visit = {};
for (let i = 0; i < 2; i++) {
let sv = i ? this.v2 : this.v1;
//console.log(sv);
for (let sa of sv.borders) {
if (sa.horiz != this.horiz)
continue;
if (sa._id in visit)
continue;
visit[sa._id] = 1;
let a0x = Math.min(this.v1[0], this.v2[0]);
let a0y = Math.min(this.v1[1], this.v2[1]);
let a1x = Math.max(this.v1[0], this.v2[0]);
let a1y = Math.max(this.v1[1], this.v2[1]);
let b0x = Math.min(sa.v1[0], sa.v2[0]);
let b0y = Math.min(sa.v1[1], sa.v2[1]);
let b1x = Math.min(sa.v1[0], sa.v2[0]);
let b1y = Math.min(sa.v1[1], sa.v2[1]);
let ok;
let eps = 0.001;
if (horiz) {
ok = (a0y <= b1y + eps && a1y >= a0y - eps);
} else {
ok = (a0x <= b1x + eps && a1x >= a0x - eps);
}
if (ok) {
//console.log("found");
ret += sa.sareas.length;
}
}
}
return ret;
}
get horiz() {
let dx = this.v2[0] - this.v1[0];
let dy = this.v2[1] - this.v1[1];
return Math.abs(dx) > Math.abs(dy);
}
static hash(v1, v2) {
return Math.min(v1._id, v2._id) + ":" + Math.max(v1._id, v2._id);
}
static define() {
return {
tagname: "screenborder-x",
style : "screenborder"
};
}
otherVertex(v) {
if (v === this.v1)
return this.v2;
else
return this.v1;
}
setCSS() {
this.style["pointer-events"] = this.movable ? "auto" : "none";
if (this._style === undefined) {
this._style = document.createElement("style");
this.appendChild(this._style);
}
let dpi = UIBase.getDPI();
let pad = this.getDefault("mouse-threshold") / dpi;
let wid = this.getDefault("border-width");
let v1 = this.v1, v2 = this.v2;
let vec = new Vector2(v2).sub(v1);
let x = Math.min(v1[0], v2[0]), y = Math.min(v1[1], v2[1]);
let w, h;
let cursor, bstyle;
this.style["display"] = "flex";
this.style["display"] = this.horiz ? "row" : "column";
this.style["justify-content"] = "center";
this.style["align-items"] = "center";
if (!this.horiz) {
this.style["padding-left"] = this.style["padding-right"] = pad + "px";
x -= wid*0.5 + pad;
w = wid*2;
h = Math.abs(vec[1]);
cursor = 'e-resize';
bstyle = "border-left-style : solid;\n border-right-style : solid;\n";
bstyle = "border-top-style : none;\n border-bottom-style : none;\n";
} else {
this.style["padding-top"] = this.style["padding-bottom"] = pad + "px";
y -= wid*0.5 + pad;
w = Math.abs(vec[0]);
h = wid;
cursor = 'n-resize';
bstyle = "border-top-style : solid;\n border-bottom-style : solid;\n";
}
let color = this.getDefault("border-outer");
let debug = cconst.DEBUG.screenborders;
if (debug) {
wid = 4;
let alpha = 1.0;
let c = this.sareas.length*75;
let r = 0, g = 0, b = 0;
if (this.movable) {
b = 255;
}
if (this.halfedges.length > 1) {
g = 255;
}
if (this.outer) {
r = 255;
}
color = `rgba(${r}, ${g}, ${b}, ${alpha})`;
}
let innerbuf = `
.screenborder_inner_${this._id} {
${bstyle}
${this.horiz ? 'height' : 'width'} : ${wid}px;
${!this.horiz ? 'height' : 'width'} : 100%;
margin : 0px;
padding : 0px;
background-color : ${this.getDefault("border-inner")};
border-color : ${color};
border-width : ${wid*0.5}px;
border-style : ${debug && this.outer ? "dashed" : "solid"};
pointer-events : none;
}`;
let sbuf = `
.screenborder_${this._id} {
}
`;
let ok = this.movable;
if (!this.outer) {
for (let sarea of this.sareas) {
ok = ok || sarea.floating;
}
}
if (ok) {
sbuf += `
.screenborder_${this._id}:hover {
cursor : ${cursor};
}
`;
}
this._style.textContent = sbuf;
this._innerstyle.textContent = innerbuf;
this.setAttribute("class", "screenborder_" + this._id);
this.inner.setAttribute("class", "screenborder_inner_" + this._id);
this.style["position"] = UIBase.PositionKey;
this.style["left"] = x + "px";
this.style["top"] = y + "px";
this.style["width"] = w + "px";
this.style["height"] = h + "px";
this.style["z-index"] = "" + BORDER_ZINDEX_BASE;
}
valueOf() {
return ScreenBorder.hash(this.v1, this.v2);
}
[Symbol.keystr]() {
return ScreenBorder.hash(this.v1, this.v2);
}
}
ui_base.UIBase.internalRegister(ScreenBorder);