189 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			189 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
"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);
 | 
						|
    }
 | 
						|
 | 
						|
};
 |