pvbemu/app/toolkit/Panel.js

189 lines
5.6 KiB
JavaScript
Raw Normal View History

2021-08-23 23:56:36 +00:00
"use strict";
// Box that can contain other components
Toolkit.Panel = class Panel extends Toolkit.Component {
// Object constructor
constructor(application) {
super(application, "div");
// Configure instance fields
this.application = application;
this.children = [];
this.crossAlign = "start";
this.direction = "row";
this.edge = "left";
this.hGap = "0";
this.layout = "split";
this.mainAlign = "start";
this.sizeable = false;
this.vGap = "0";
this.wrap = false;
// Configure element
this.element.style.minHeight = "0";
this.element.style.minWidth = "0";
// Configure layout
this.setSplitLayout("left", false);
}
///////////////////////////// Public Methods //////////////////////////////
// Add a component as a child of this container
add(component, index) {
// Determine the ordinal position of the element within the container
index = !(typeof index == "number") ? this.children.length :
Math.floor(Math.min(Math.max(0, index), this.children.length));
// Add the component to the container
component.parent = this;
this.children.splice(index, 0, component);
this.arrange();
}
// Create a Button and associate it with the application
newButton(options) {
return new Toolkit.Button(this.application, options);
}
// Create a MenuBar and associate it with the application
newMenuBar(options) {
return new Toolkit.MenuBar(this.application, options);
}
// Create a Panel and associate it with the application
newPanel(options) {
return new Toolkit.Panel(this.application, options);
}
// Remove a component from the container
remove(component) {
// Locate the component in the children
let index = this.children.indexOf(component);
if (index == -1)
return;
// Remove the component
component.parent = null;
component.element.remove();
this.children.splice(index, 1);
this.arrange();
}
// Configure the element with a flex layout
setFlexLayout(direction, mainAlign, crossAlign, gap, wrap) {
// Configure instance fields
this.layout = "flex";
this.crossAlign = crossAlign;
this.direction = direction;
this.mainAlign = mainAlign;
this.wrap = wrap;
// Working variables
switch (crossAlign) {
case "end" : crossAlign = "flex-end" ;
case "start": crossAlign = "flex-start";
}
switch (mainAlign) {
case "end" : mainAlign = "flex-end" ;
case "start": mainAlign = "flex-start";
}
// Configure element
this.element.style.alignItems = crossAlign;
this.element.style.display = "flex";
this.element.style.flexDirection = direction;
this.element.style.justifyContent = mainAlign;
if (direction == "column") {
this.hGap = gap;
this.element.style.rowGap = gap;
}
if (direction == "row") {
this.vGap = gap;
this.element.style.columnGap = gap;
}
if (wrap)
this.element.style.flexWrap = "wrap";
else this.element.style.removeProperty("flex-wrap");
// Manage components
this.arrange();
}
// Configure the element with a split layout
setSplitLayout(edge, sizeable) {
// Configure instance fields
this.layout = "split";
this.edge = edge;
this.sizeable = sizeable;
// Working variables
let rows = null, cols = null;
let tracks = [ "max-content", "auto" ];
if (sizeable)
tracks.splice(1, 0, "max-content");
// Processing by edge
switch (edge) {
case "bottom": tracks.reverse(); // Fallthrough
case "top" : rows = tracks.join(" "); break;
case "right" : tracks.reverse(); // Fallthrough
case "left" : cols = tracks.join(" ");
}
// Configure element
this.element.style.display = "grid";
if (cols != null)
this.element.style.gridTemplateColumns = cols;
else this.element.style.removeProperty("grid-template-columns");
if (rows != null)
this.element.style.gridTemplateRows = rows;
else this.element.style.removeProperty("grid-template-rows");
// Manage components
this.arrange();
}
///////////////////////////// Private Methods /////////////////////////////
// Configure the panel's DOM elements
arrange() {
let components = [];
// Remove all children from the DOM
for (let comp of this.children)
comp.element.remove();
// Split layout
if (this.layout == "split") {
components.push(this.children[0]);
components.push(this.children[1]);
if (this.sizeable)
components.splice(1, 0, this.splitter);
if (this.edge == "bottom" || this.edge == "right")
components.reverse();
}
// Flex and grid layouts
else {
for (let comp of this.children)
components.push(comp);
}
// Add the resulting elements to the DOM
for (let comp of components)
if (comp)
this.element.appendChild(comp.element);
}
};