Selaa lähdekoodia

added C2D GridPanelLayout

Adam Bowman 8 vuotta sitten
vanhempi
commit
7a6701d57f

+ 408 - 0
canvas2D/src/Engine/babylon.canvas2dLayoutEngine.ts

@@ -191,4 +191,412 @@
             return false;
         }
     }
+
+
+    export class GridData implements ILayoutData{
+
+        row:number;
+        column:number;
+        rowSpan:number;
+        columnSpan:number;
+
+        constructor(row:number, column:number, rowSpan:number, columnSpan:number){
+
+            this.row = row;
+            this.column = column;
+
+            this.rowSpan = rowSpan === null ? 1 : rowSpan;
+            this.columnSpan = columnSpan === null ? 1 : columnSpan;
+
+        }
+
+    }
+
+    class GridDimensionDefinition {
+        public static Pixels = 1;
+        public static Stars = 2;
+        public static Auto = 3;
+        _parse(value: string, res: (v: number, vp: number, t: number) => void) {
+            let v = value.toLocaleLowerCase().trim();
+            if (v.indexOf("auto") === 0) {
+                res(null, null, GridDimensionDefinition.Auto);
+            } else if (v.indexOf("*") !== -1) {
+                let i = v.indexOf("*");
+                let w = parseFloat(v.substr(0, i));
+                res(w, null, GridDimensionDefinition.Stars);
+            } else {
+                let w = parseFloat(v);
+                res(w, w, GridDimensionDefinition.Pixels);
+            }
+        }
+    }
+    class RowDefinition extends GridDimensionDefinition {
+        heightPixels: number;
+        height: number;
+        heightType: number;
+    }
+    class ColumnDefinition extends GridDimensionDefinition {
+        widthPixels: number;
+        width: number;
+        widthType: number;
+    }
+
+    @className("GridPanelLayoutEngine")
+    export class GridPanelLayoutEngine extends LayoutEngineBase {
+        constructor(settings: { rows: [{ height: string }], columns: [{ width: string }] }) {
+            super();
+            this.layoutDirtyOnPropertyChangedMask = Prim2DBase.sizeProperty.flagId;
+            this._rows = new Array<RowDefinition>();
+            this._columns = new Array<ColumnDefinition>();
+            if (settings.rows) {
+                for (let row of settings.rows) {
+                    let r = new RowDefinition();
+                    r._parse(row.height, (v, vp, t) => {
+                        r.height = v;
+                        r.heightPixels = vp;
+                        r.heightType = t;
+                    });
+                    this._rows.push(r);
+                }
+            }
+            if (settings.columns) {
+                for (let col of settings.columns) {
+                    let r = new ColumnDefinition();
+                    r._parse(col.width, (v, vp, t) => {
+                        r.width = v;
+                        r.widthPixels = vp;
+                        r.widthType = t;
+                    });
+                    this._columns.push(r);
+                }
+            }
+
+        }
+
+        private _rows: Array<RowDefinition>;
+        private _columns: Array<ColumnDefinition>;
+        private _children: Prim2DBase[][] = [];
+        
+        private _rowBottoms: Array<number> = [];
+        private _columnLefts: Array<number> = [];
+
+        private _rowHeights: Array<number> = [];
+        private _columnWidths: Array<number> = [];
+
+        private static dstOffset = Vector4.Zero();
+        private static dstArea = Size.Zero();
+
+        public updateLayout(prim: Prim2DBase) {
+            if (prim._isFlagSet(SmartPropertyPrim.flagLayoutDirty)) {
+                
+                for (let child of prim.children) {
+                    if (child._isFlagSet(SmartPropertyPrim.flagNoPartOfLayout)) {
+                        continue;
+                    }
+                    let layoutArea: Size;
+                    if (child._hasMargin) {
+                        child.margin.computeWithAlignment(prim.layoutArea, child.actualSize, child.marginAlignment, GridPanelLayoutEngine.dstOffset, GridPanelLayoutEngine.dstArea, true);
+                        layoutArea = GridPanelLayoutEngine.dstArea.clone();
+                        child.layoutArea = layoutArea;
+                    } else {
+                        layoutArea = child.layoutArea;
+                        child.margin.computeArea(child.actualSize, layoutArea);
+                    }
+                }
+
+                let _children = this._children;
+
+                this._updateGrid(prim);
+
+                let rl = this._rows.length;
+                let cl = this._columns.length;
+
+                let offsetX = 0;
+                let offsetY = 0;
+
+                let columnWidth = 0;
+                let rowHeight = 0;
+                
+                for(let i = 0; i < _children.length; i++){
+                    let children = _children[i];
+
+                    if(children){
+
+                        let bottom = this._rowBottoms[i];
+                        let rowHeight = this._rowHeights[i];
+
+                        let oBottom = bottom;
+                        let oRowHeight = rowHeight;
+
+                        for(let j = 0; j < children.length; j++){
+                            
+                            let left = this._columnLefts[j];
+                            let columnWidth = this._columnWidths[j];
+
+                            let child = children[j];
+
+                            if(child){
+
+                                let gd = <GridData>child.layoutData;
+
+                                if(gd.columnSpan > 1){
+                                    for(let k = j+1; k < gd.columnSpan + j && k < cl; k++){
+                                        columnWidth += this._columnWidths[k];
+                                    }
+                                }
+
+                                if(gd.rowSpan > 1){
+                                    
+                                    for(let k = i+1; k < gd.rowSpan + i && k < rl; k++){
+                                        rowHeight += this._rowHeights[k];
+                                        bottom = this._rowBottoms[k];
+                                    }
+                                    
+                                }
+
+                                if(child.marginAlignment.horizontal === PrimitiveAlignment.AlignRight){
+                                    offsetX = columnWidth - child.actualWidth;
+                                }else if(child.marginAlignment.horizontal === PrimitiveAlignment.AlignCenter){
+                                    offsetX = columnWidth*.5 - child.actualWidth*.5;
+                                }else{
+                                    offsetX = 0;
+                                }
+
+                                if(child.marginAlignment.vertical === PrimitiveAlignment.AlignTop){
+                                    offsetY = rowHeight - child.actualHeight;
+                                }else if(child.marginAlignment.vertical === PrimitiveAlignment.AlignCenter){
+                                    offsetY = rowHeight*.5 - child.actualHeight*.5;
+                                }else{
+                                    offsetY = 0;
+                                }
+
+                                child.layoutAreaPos.x = left + offsetX;
+                                child.layoutAreaPos.y = bottom + offsetY;
+
+                                bottom = oBottom;
+                                rowHeight = oRowHeight;
+                                
+                            }
+
+                        }
+
+                    }
+                    
+                }
+
+                prim._clearFlags(SmartPropertyPrim.flagLayoutDirty);
+            }
+        }
+
+        get isChildPositionAllowed(): boolean {
+            return false;
+        }
+
+        private _getMaxChildHeightInRow(rowNum:number):number{
+
+            let rows = this._rows;
+            let cl = this._columns.length;
+            let rl = this._rows.length;
+            let children = this._children;
+            let row = rows[rowNum];
+            
+            let maxHeight = 0;
+
+            if(children){
+
+                for(let i = 0; i > cl; i++){
+                    let child = children[rowNum][i];
+                    if(child){
+                        if(maxHeight < child.actualHeight){
+                            maxHeight = child.actualHeight;
+                        }
+                    }
+                }
+
+            }
+
+            return maxHeight;
+
+        }
+
+        private _getMaxChildWidthInColumn(colNum:number):number{
+
+            let columns = this._columns;
+            let cl = this._columns.length;
+            let rl = this._rows.length;
+            let children = this._children;
+            let column = columns[colNum];
+            let maxWidth = 0;
+
+            maxWidth = 0;
+
+            if(children){
+
+                for(let i = 0; i > rl; i++){
+                    let child = children[i][colNum];
+                    if(child){
+                        if(maxWidth < child.actualWidth){
+                            maxWidth = child.actualWidth;
+                        }
+                    }
+                }
+
+            }
+
+            return maxWidth;
+
+        }
+
+        private _updateGrid(prim:Prim2DBase){
+
+            let _children = this._children;
+
+            //remove prim.children from _children
+            for(let i = 0; i < _children.length; i++){
+                let children = _children[i];
+                if(children){
+                    children.length = 0;
+                }
+            }
+
+            //add prim.children to _children
+            for(let child of prim.children){
+                
+                if(!child.layoutData || !child.parent){
+                    continue;
+                }
+
+                let gd = <GridData>child.layoutData;
+
+                if(!_children[gd.row]){
+                    _children[gd.row] = [];
+                }
+
+                _children[gd.row][gd.column] = child;
+
+            }
+
+
+            let rows = this._rows;
+            let columns = this._columns;
+
+            let rl = this._rows.length;
+            let cl = this._columns.length;
+
+            //get fixed and auto row heights first
+
+            var starIndexes = [];
+            var totalStars = 0;
+            var rowHeights = 0;
+            let columnWidths = 0;
+
+            for (let i = 0; i < rl; i++) {
+
+                let row = this._rows[i];
+
+                if(row.heightType == GridDimensionDefinition.Auto){
+
+                    this._rowHeights[i] = this._getMaxChildHeightInRow(i);
+                    rowHeights += this._rowHeights[i];
+
+                }else if(row.heightType == GridDimensionDefinition.Pixels){
+
+                    this._rowHeights[i] = row.heightPixels;
+                    rowHeights += this._rowHeights[i];
+
+                }else if(row.heightType == GridDimensionDefinition.Stars){
+
+                    starIndexes.push(i);
+
+                    totalStars += row.height;
+
+                }
+
+            }
+
+            //star row heights
+
+            if(starIndexes.length > 0){
+
+                let remainingHeight = prim.contentArea.width - rowHeights;
+
+                for(let i = 0; i < starIndexes.length; i++){
+
+                    let rowIndex = starIndexes[i];
+
+                    this._rowHeights[rowIndex] = (this._rows[rowIndex].height / totalStars) * remainingHeight;
+
+                }
+            }
+
+
+            //get fixed and auto column widths
+
+            starIndexes.length = 0;
+            totalStars = 0;
+
+            for (let i = 0; i < cl; i++) {
+
+                let column = this._columns[i];
+
+                if(column.widthType == GridDimensionDefinition.Auto){
+
+                    this._columnWidths[i] = this._getMaxChildWidthInColumn(i);
+                    columnWidths += this._columnWidths[i];
+
+                }else if(column.widthType == GridDimensionDefinition.Pixels){
+
+                    this._columnWidths[i] = column.widthPixels;
+                    columnWidths += this._columnWidths[i];
+
+                }else if(column.widthType == GridDimensionDefinition.Stars){
+
+                    starIndexes.push(i);
+
+                    totalStars += column.width;
+
+                }
+
+            }
+
+            //star column widths
+
+            if(starIndexes.length > 0){
+
+                let remainingWidth = prim.contentArea.width - columnWidths;
+
+                for(let i = 0; i < starIndexes.length; i++){
+
+                    let columnIndex = starIndexes[i];
+
+                    this._columnWidths[columnIndex] = (this._columns[columnIndex].width / totalStars) * remainingWidth;
+
+                }
+            }
+
+
+            let y = 0;
+            this._rowBottoms[rl - 1] = y;
+
+            for (let i = rl - 2; i >= 0; i--) {
+
+                y += this._rowHeights[i+1];
+                this._rowBottoms[i] = y;
+
+            }
+
+            let x = 0;
+            this._columnLefts[0] = x;
+            
+            for (let i = 1; i < cl; i++) {
+
+                x += this._columnWidths[i-1];
+                this._columnLefts[i] = x;
+
+            }
+
+        }
+
+    }
+
 }

+ 17 - 4
canvas2D/src/Engine/babylon.prim2dBase.ts

@@ -1620,10 +1620,7 @@
             }
 
             if (settings.layoutData) {
-                let p = this.parent;
-                if (p && p.layoutEngine) {
-                    p.layoutEngine.newChild(this, settings.layoutData);
-                }
+                this.layoutData = settings.layoutData;
             }
 
             // Dirty layout and positioning
@@ -3885,6 +3882,21 @@
             newPrimSize.copyFrom(primSize);
         }
 
+        /**
+         * Get/set the layout data to use for this primitive.
+         */
+        public get layoutData(): ILayoutData {
+            return this._layoutData;
+        }
+
+        public set layoutData(value: ILayoutData) {
+            if (this._layoutData === value) {
+                return;
+            }
+
+            this._layoutData = value;
+        }
+
         private _owner: Canvas2D;
         private _parent: Prim2DBase;
         private _actionManager: ActionManager;
@@ -3918,6 +3930,7 @@
         private _lastAutoSizeArea: Size;
         private _layoutAreaPos: Vector2;
         private _layoutArea: Size;
+        private _layoutData: ILayoutData;
         private _contentArea: Size;
         private _rotation: number;
         private _scale: Vector2;