Something went wrong. Try again.
Starship Simulator Controls thoriumsim.com
Something went wrong. Try again.
15 kB · 529 lines
TypeScript
at develop
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530import { Attribute } from "../Attribute";import { AttributeDefinitions } from "../AttributeDefinitions";import { DockLocation } from "../DockLocation";import { DropInfo } from "../DropInfo";import { Orientation } from "../Orientation";import { Rect } from "../Rect";import { CLASSES } from "../Types";import type { IDraggable } from "./IDraggable";import type { IDropTarget } from "./IDropTarget";import type { IJsonBorderNode } from "./IJsonModel";import { Model } from "./Model";import { Node } from "./Node";import { TabNode } from "./TabNode";import type { TabSetNode } from "./TabSetNode";import { adjustSelectedIndex } from "./Utils";
export class BorderNode extends Node implements IDropTarget { static readonly TYPE = "border";
/** @internal */ static fromJson(json: any, model: Model) { const location = DockLocation.getByName(json.location); const border = new BorderNode(location, json, model); if (json.children) { border.children = json.children.map((jsonChild: any) => { const child = TabNode.fromJson(jsonChild, model); child.setParent(border); return child; }); }
return border; } /** @internal */ private static attributeDefinitions: AttributeDefinitions = BorderNode.createAttributeDefinitions();
/** @internal */ private outerRect: Rect = Rect.empty(); /** @internal */ private contentRect: Rect = Rect.empty(); /** @internal */ private tabHeaderRect: Rect = Rect.empty(); /** @internal */ private location: DockLocation;
/** @internal */ constructor(location: DockLocation, json: any, model: Model) { super(model);
this.location = location; this.attributes.id = `border_${location.getName()}`; BorderNode.attributeDefinitions.fromJson(json, this.attributes); model.addNode(this); }
getLocation() { return this.location; }
getClassName() { return this.getAttr("className") as string | undefined; }
isHorizontal() { return this.location.orientation === Orientation.HORZ; }
getSize() { const defaultSize = this.getAttr("size") as number; const selected = this.getSelected(); if (selected === -1) { return defaultSize; } const tabNode = this.children[selected] as TabNode; const tabBorderSize = this.isHorizontal() ? tabNode.getAttr("borderWidth") : tabNode.getAttr("borderHeight"); if (tabBorderSize === -1) { return defaultSize; } return tabBorderSize; }
getMinSize() { const selectedNode = this.getSelectedNode(); let min = this.getAttr("minSize") as number; if (selectedNode) { const nodeMin = this.isHorizontal() ? selectedNode.getMinWidth() : selectedNode.getMinHeight(); min = Math.max(min, nodeMin); } return min; }
getMaxSize() { const selectedNode = this.getSelectedNode(); let max = this.getAttr("maxSize") as number; if (selectedNode) { const nodeMax = this.isHorizontal() ? selectedNode.getMaxWidth() : selectedNode.getMaxHeight(); max = Math.min(max, nodeMax); } return max; }
getSelected(): number { return this.attributes.selected as number; }
isAutoHide() { return this.getAttr("enableAutoHide") as boolean; }
getSelectedNode(): TabNode | undefined { if (this.getSelected() !== -1) { return this.children[this.getSelected()] as TabNode; } return undefined; }
getOrientation() { return this.location.getOrientation(); }
/** * Returns the config attribute that can be used to store node specific data that * WILL be saved to the json. The config attribute should be changed via the action Actions.updateNodeAttributes rather * than directly, for example: * this.state.model.doAction( * FlexLayout.Actions.updateNodeAttributes(node.getId(), {config:myConfigObject})); */ getConfig() { return this.attributes.config; }
isMaximized() { return false; }
isShowing() { return this.attributes.show as boolean; }
toJson(): IJsonBorderNode { const json: any = {}; BorderNode.attributeDefinitions.toJson(json, this.attributes); json.location = this.location.getName(); json.children = this.children.map((child) => (child as TabNode).toJson()); return json; }
/** @internal */ isAutoSelectTab(whenOpen?: boolean) { if (whenOpen == null) { whenOpen = this.getSelected() !== -1; } if (whenOpen) { return this.getAttr("autoSelectTabWhenOpen") as boolean; } return this.getAttr("autoSelectTabWhenClosed") as boolean; }
isEnableTabScrollbar() { return this.getAttr("enableTabScrollbar") as boolean; }
/** @internal */ setSelected(index: number) { this.attributes.selected = index; }
/** @internal */ getTabHeaderRect() { return this.tabHeaderRect; }
/** @internal */ setTabHeaderRect(r: Rect) { this.tabHeaderRect = r; }
/** @internal */ getOuterRect() { return this.outerRect; }
/** @internal */ setOuterRect(r: Rect) { this.outerRect = r; }
/** @internal */ getRect() { return this.tabHeaderRect!; }
/** @internal */ getContentRect() { return this.contentRect; }
/** @internal */ setContentRect(r: Rect) { this.contentRect = r; }
/** @internal */ isEnableDrop() { return this.getAttr("enableDrop") as boolean; }
/** @internal */ setSize(pos: number) { const selected = this.getSelected(); if (selected === -1) { this.attributes.size = pos; } else { const tabNode = this.children[selected] as TabNode; const tabBorderSize = this.isHorizontal() ? tabNode.getAttr("borderWidth") : tabNode.getAttr("borderHeight"); if (tabBorderSize === -1) { this.attributes.size = pos; } else { if (this.isHorizontal()) { tabNode.setBorderWidth(pos); } else { tabNode.setBorderHeight(pos); } } } }
/** @internal */ updateAttrs(json: any) { BorderNode.attributeDefinitions.update(json, this.attributes); }
/** @internal */ remove(node: TabNode) { const removedIndex = this.removeChild(node); if (this.getSelected() !== -1) { adjustSelectedIndex(this, removedIndex); } }
/** @internal */ canDrop(dragNode: Node & IDraggable, x: number, y: number): DropInfo | undefined { if (!(dragNode instanceof TabNode)) { return undefined; }
let dropInfo: DropInfo | undefined; const dockLocation = DockLocation.CENTER;
if (this.tabHeaderRect!.contains(x, y)) { if (this.location.orientation === Orientation.VERT) { if (this.children.length > 0) { let child = this.children[0]; let childRect = (child as TabNode).getTabRect()!; const childY = childRect.y;
const childHeight = childRect.height;
let pos = this.tabHeaderRect!.x; let childCenter = 0; for (let i = 0; i < this.children.length; i++) { child = this.children[i]; childRect = (child as TabNode).getTabRect()!; childCenter = childRect.x + childRect.width / 2; if (x >= pos && x < childCenter) { const outlineRect = new Rect(childRect.x - 2, childY, 3, childHeight); dropInfo = new DropInfo( this, outlineRect, dockLocation, i, CLASSES.FLEXLAYOUT__OUTLINE_RECT, ); break; } pos = childCenter; } if (dropInfo == null) { const outlineRect = new Rect(childRect.getRight() - 2, childY, 3, childHeight); dropInfo = new DropInfo( this, outlineRect, dockLocation, this.children.length, CLASSES.FLEXLAYOUT__OUTLINE_RECT, ); } } else { const outlineRect = new Rect(this.tabHeaderRect!.x + 1, this.tabHeaderRect!.y + 2, 3, 18); dropInfo = new DropInfo( this, outlineRect, dockLocation, 0, CLASSES.FLEXLAYOUT__OUTLINE_RECT, ); } } else { if (this.children.length > 0) { let child = this.children[0]; let childRect = (child as TabNode).getTabRect()!; const childX = childRect.x; const childWidth = childRect.width;
let pos = this.tabHeaderRect!.y; let childCenter = 0; for (let i = 0; i < this.children.length; i++) { child = this.children[i]; childRect = (child as TabNode).getTabRect()!; childCenter = childRect.y + childRect.height / 2; if (y >= pos && y < childCenter) { const outlineRect = new Rect(childX, childRect.y - 2, childWidth, 3); dropInfo = new DropInfo( this, outlineRect, dockLocation, i, CLASSES.FLEXLAYOUT__OUTLINE_RECT, ); break; } pos = childCenter; } if (dropInfo == null) { const outlineRect = new Rect(childX, childRect.getBottom() - 2, childWidth, 3); dropInfo = new DropInfo( this, outlineRect, dockLocation, this.children.length, CLASSES.FLEXLAYOUT__OUTLINE_RECT, ); } } else { const outlineRect = new Rect(this.tabHeaderRect!.x + 2, this.tabHeaderRect!.y + 1, 18, 3); dropInfo = new DropInfo( this, outlineRect, dockLocation, 0, CLASSES.FLEXLAYOUT__OUTLINE_RECT, ); } } if (!dragNode.canDockInto(dragNode, dropInfo)) { return undefined; } } else if (this.getSelected() !== -1 && this.outerRect!.contains(x, y)) { const outlineRect = this.outerRect; dropInfo = new DropInfo( this, outlineRect!, dockLocation, -1, CLASSES.FLEXLAYOUT__OUTLINE_RECT, ); if (!dragNode.canDockInto(dragNode, dropInfo)) { return undefined; } }
return dropInfo; }
/** @internal */ drop(dragNode: Node & IDraggable, location: DockLocation, index: number, select?: boolean): void { let fromIndex = 0; const dragParent = dragNode.getParent() as BorderNode | TabSetNode; if (dragParent !== undefined) { fromIndex = dragParent.removeChild(dragNode); // if selected node in border is being docked into a different border then deselect border tabs if ( dragParent !== this && dragParent instanceof BorderNode && dragParent.getSelected() === fromIndex ) { dragParent.setSelected(-1); } else { adjustSelectedIndex(dragParent, fromIndex); } }
// if dropping a tab back to same tabset and moving to forward position then reduce insertion index if (dragNode instanceof TabNode && dragParent === this && fromIndex < index && index > 0) { index--; }
// simple_bundled dock to existing tabset let insertPos = index; if (insertPos === -1) { insertPos = this.children.length; }
if (dragNode instanceof TabNode) { this.addChild(dragNode, insertPos); }
if (select || (select !== false && this.isAutoSelectTab())) { this.setSelected(insertPos); }
this.model.tidy(); }
/** @internal */ getSplitterBounds(index: number, useMinSize = false) { const pBounds = [0, 0]; const minSize = useMinSize ? this.getMinSize() : 0; const maxSize = useMinSize ? this.getMaxSize() : 99999; const rootRow = this.model.getRoot(Model.MAIN_WINDOW_ID); const innerRect = rootRow.getRect(); const splitterSize = this.model.getSplitterSize(); if (this.location === DockLocation.TOP) { pBounds[0] = this.tabHeaderRect!.getBottom() + minSize; const maxPos = this.tabHeaderRect!.getBottom() + maxSize; pBounds[1] = Math.max( pBounds[0], innerRect.getBottom() - rootRow.getMinHeight() - splitterSize, ); pBounds[1] = Math.min(pBounds[1], maxPos); } else if (this.location === DockLocation.LEFT) { pBounds[0] = this.tabHeaderRect!.getRight() + minSize; const maxPos = this.tabHeaderRect!.getRight() + maxSize; pBounds[1] = Math.max( pBounds[0], innerRect.getRight() - rootRow.getMinWidth() - splitterSize, ); pBounds[1] = Math.min(pBounds[1], maxPos); } else if (this.location === DockLocation.BOTTOM) { pBounds[1] = this.tabHeaderRect!.y - minSize - splitterSize; const maxPos = this.tabHeaderRect!.y - maxSize - splitterSize; pBounds[0] = Math.min(pBounds[1], innerRect.y + rootRow.getMinHeight()); pBounds[0] = Math.max(pBounds[0], maxPos); } else if (this.location === DockLocation.RIGHT) { pBounds[1] = this.tabHeaderRect!.x - minSize - splitterSize; const maxPos = this.tabHeaderRect!.x - maxSize - splitterSize; pBounds[0] = Math.min(pBounds[1], innerRect.x + rootRow.getMinWidth()); pBounds[0] = Math.max(pBounds[0], maxPos); } return pBounds; }
/** @internal */ calculateSplit(splitter: BorderNode, splitterPos: number) { const pBounds = this.getSplitterBounds(splitterPos); if (this.location === DockLocation.BOTTOM || this.location === DockLocation.RIGHT) { return Math.max(0, pBounds[1] - splitterPos); } return Math.max(0, splitterPos - pBounds[0]); }
/** @internal */ getAttributeDefinitions() { return BorderNode.attributeDefinitions; }
/** @internal */ static getAttributeDefinitions() { return BorderNode.attributeDefinitions; }
/** @internal */ private static createAttributeDefinitions(): AttributeDefinitions { const attributeDefinitions = new AttributeDefinitions(); attributeDefinitions.add("type", BorderNode.TYPE, true).setType(Attribute.STRING).setFixed();
attributeDefinitions .add("selected", -1) .setType(Attribute.NUMBER) .setDescription(`index of selected/visible tab in border; -1 means no tab selected`); attributeDefinitions .add("show", true) .setType(Attribute.BOOLEAN) .setDescription(`show/hide this border`); attributeDefinitions .add("config", undefined) .setType("any") .setDescription(`a place to hold json config used in your own code`);
attributeDefinitions .addInherited("enableDrop", "borderEnableDrop") .setType(Attribute.BOOLEAN) .setDescription(`whether tabs can be dropped into this border`); attributeDefinitions .addInherited("className", "borderClassName") .setType(Attribute.STRING) .setDescription(`class applied to tab button`); attributeDefinitions .addInherited("autoSelectTabWhenOpen", "borderAutoSelectTabWhenOpen") .setType(Attribute.BOOLEAN) .setDescription(`whether to select new/moved tabs in border when the border is already open`); attributeDefinitions .addInherited("autoSelectTabWhenClosed", "borderAutoSelectTabWhenClosed") .setType(Attribute.BOOLEAN) .setDescription( `whether to select new/moved tabs in border when the border is currently closed`, ); attributeDefinitions .addInherited("size", "borderSize") .setType(Attribute.NUMBER) .setDescription(`size of the tab area when selected`); attributeDefinitions .addInherited("minSize", "borderMinSize") .setType(Attribute.NUMBER) .setDescription(`the minimum size of the tab area`); attributeDefinitions .addInherited("maxSize", "borderMaxSize") .setType(Attribute.NUMBER) .setDescription(`the maximum size of the tab area`); attributeDefinitions .addInherited("enableAutoHide", "borderEnableAutoHide") .setType(Attribute.BOOLEAN) .setDescription(`hide border if it has zero tabs`); attributeDefinitions .addInherited("enableTabScrollbar", "borderEnableTabScrollbar") .setType(Attribute.BOOLEAN) .setDescription(`whether to show a mini scrollbar for the tabs`); return attributeDefinitions; }}