Browse Source

gui: word wrap + texAlignment

David Catuhe 8 years ago
parent
commit
602e70c86c

+ 1 - 1
gui/src/controls/container.js

@@ -51,8 +51,8 @@ var BABYLON;
                 this._markAsDirty();
             };
             Container.prototype._draw = function (parentMeasure, context) {
-                this._currentMeasure = parentMeasure.copy();
                 context.save();
+                _super.prototype._processMeasures.call(this, parentMeasure, context);
                 this.applyStates(context);
                 for (var _i = 0, _a = this._children; _i < _a.length; _i++) {
                     var child = _a[_i];

+ 2 - 3
gui/src/controls/container.ts

@@ -49,10 +49,9 @@ module BABYLON.GUI {
         }
 
         public _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
-            this._currentMeasure = parentMeasure.copy();
-
             context.save();
-            
+            super._processMeasures(parentMeasure, context);
+           
             this.applyStates(context);
 
             for (var child of this._children) {

+ 1 - 1
gui/src/controls/contentControl.js

@@ -39,8 +39,8 @@ var BABYLON;
                 // Implemented by child to be injected inside main draw
             };
             ContentControl.prototype._draw = function (parentMeasure, context) {
-                this._currentMeasure = parentMeasure.copy();
                 context.save();
+                _super.prototype._processMeasures.call(this, parentMeasure, context);
                 this.applyStates(context);
                 this._localDraw(context);
                 if (this._child) {

+ 3 - 3
gui/src/controls/contentControl.ts

@@ -28,10 +28,10 @@ module BABYLON.GUI {
         }
 
         public _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
-            this._currentMeasure = parentMeasure.copy();
-
             context.save();
-            
+
+            super._processMeasures(parentMeasure, context);
+           
             this.applyStates(context);
 
             this._localDraw(context);

+ 148 - 2
gui/src/controls/control.js

@@ -8,6 +8,8 @@ var BABYLON;
                 this.name = name;
                 this._zIndex = 0;
                 this._fontSize = 18;
+                this._width = 1;
+                this._height = 1;
                 this._horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
                 this._verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
                 this.fontFamily = "Arial";
@@ -40,6 +42,74 @@ var BABYLON;
                 enumerable: true,
                 configurable: true
             });
+            Object.defineProperty(Control.prototype, "width", {
+                get: function () {
+                    return this._width;
+                },
+                set: function (value) {
+                    if (value < 0) {
+                        value = 0;
+                    }
+                    if (value > 1) {
+                        value = 1;
+                    }
+                    if (this._width === value) {
+                        return;
+                    }
+                    this._width = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Control.prototype, "height", {
+                get: function () {
+                    return this._height;
+                },
+                set: function (value) {
+                    if (value < 0) {
+                        value = 0;
+                    }
+                    if (value > 1) {
+                        value = 1;
+                    }
+                    if (this._height === value) {
+                        return;
+                    }
+                    this._height = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Control.prototype, "widthConstantPixel", {
+                get: function () {
+                    return this._widthConstantPixel;
+                },
+                set: function (value) {
+                    if (this._widthConstantPixel === value) {
+                        return;
+                    }
+                    this._widthConstantPixel = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Control.prototype, "heightConstantPixel", {
+                get: function () {
+                    return this._heightConstantPixel;
+                },
+                set: function (value) {
+                    if (this._heightConstantPixel === value) {
+                        return;
+                    }
+                    this._heightConstantPixel = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
             Object.defineProperty(Control.prototype, "fontFamily", {
                 get: function () {
                     return this._fontFamily;
@@ -63,6 +133,22 @@ var BABYLON;
                         return;
                     }
                     this._fontSize = value;
+                    this._fontSizeConstantPixel = null;
+                    this._prepareFont();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Control.prototype, "fontSizeConstantPixel", {
+                get: function () {
+                    return this._fontSizeConstantPixel;
+                },
+                set: function (value) {
+                    if (this._fontSizeConstantPixel === value) {
+                        return;
+                    }
+                    this._fontSize = null;
+                    this._fontSizeConstantPixel = value;
                     this._prepareFont();
                 },
                 enumerable: true,
@@ -113,8 +199,63 @@ var BABYLON;
                     context.fillStyle = this._color;
                 }
             };
-            Control.prototype._draw = function (parentMeasure, context) {
+            Control.prototype._processMeasures = function (parentMeasure, context) {
+                this._measure(parentMeasure, context);
+                this._computeAlignment(parentMeasure, context);
+                // Clip
+                context.beginPath();
+                context.rect(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
+                context.clip();
+            };
+            Control.prototype._measure = function (parentMeasure, context) {
                 this._currentMeasure = parentMeasure.copy();
+                // Width / Height
+                if (this._widthConstantPixel) {
+                    this._currentMeasure.width = this._widthConstantPixel * this._scaleX;
+                }
+                else {
+                    this._currentMeasure.width *= this._width;
+                }
+                if (this._heightConstantPixel) {
+                    this._currentMeasure.height = this._heightConstantPixel * this._scaleY;
+                }
+                else {
+                    this._currentMeasure.height *= this._height;
+                }
+            };
+            Control.prototype._computeAlignment = function (parentMeasure, context) {
+                var width = this._currentMeasure.width;
+                var height = this._currentMeasure.height;
+                var parentWidth = parentMeasure.width;
+                var parentHeight = parentMeasure.height;
+                var x = 0;
+                var y = 0;
+                switch (this.horizontalAlignment) {
+                    case Control.HORIZONTAL_ALIGNMENT_LEFT:
+                        x = 0;
+                        break;
+                    case Control.HORIZONTAL_ALIGNMENT_RIGHT:
+                        x = parentWidth - width;
+                        break;
+                    case Control.HORIZONTAL_ALIGNMENT_CENTER:
+                        x = (parentWidth - width) / 2;
+                        break;
+                }
+                switch (this.verticalAlignment) {
+                    case Control.VERTICAL_ALIGNMENT_TOP:
+                        y = 0;
+                        break;
+                    case Control.VERTICAL_ALIGNMENT_BOTTOM:
+                        y = parentHeight - height;
+                        break;
+                    case Control.VERTICAL_ALIGNMENT_CENTER:
+                        y = (parentHeight - height) / 2;
+                        break;
+                }
+                this._currentMeasure.left = this._currentMeasure.left + x;
+                this._currentMeasure.top = this._currentMeasure.top + y;
+            };
+            Control.prototype._draw = function (parentMeasure, context) {
                 // Do nothing
             };
             Control.prototype._rescale = function (scaleX, scaleY) {
@@ -126,7 +267,12 @@ var BABYLON;
                 if (!this._fontFamily) {
                     return;
                 }
-                this._font = (this._fontSize * this._scaleX) + "px " + this._fontFamily;
+                if (this._fontSizeConstantPixel) {
+                    this._font = (this._fontSizeConstantPixel * this._scaleX) + "px " + this._fontFamily;
+                }
+                else {
+                    this._font = this._fontSize + "px " + this._fontFamily;
+                }
                 this._fontOffset = Control._GetFontOffset(this._font);
                 this._markAsDirty();
             };

+ 158 - 2
gui/src/controls/control.ts

@@ -9,7 +9,12 @@ module BABYLON.GUI {
         private _scaleY: number;
         private _fontFamily: string;
         private _fontSize = 18;
+        private _fontSizeConstantPixel: number;
         private _font: string;
+        private _width = 1;
+        private _widthConstantPixel: number;
+        private _height = 1;
+        private _heightConstantPixel: number;
         private _lastMeasuredFont: string;
         protected _fontOffset: {ascent: number, height: number, descent: number};
         private _color: string;
@@ -42,6 +47,72 @@ module BABYLON.GUI {
             this._markAsDirty();
         } 
 
+        public get width(): number {
+            return this._width;
+        }
+
+        public set width(value: number) {
+            if (value < 0) {
+                value = 0;
+            }
+
+            if (value > 1) {
+                value = 1;
+            }
+            if (this._width === value) {
+                return;
+            }
+
+            this._width = value;
+            this._markAsDirty();
+        }
+
+        public get height(): number {
+            return this._height;
+        }
+
+        public set height(value: number) {
+            if (value < 0) {
+                value = 0;
+            }
+
+            if (value > 1) {
+                value = 1;
+            }            
+            if (this._height === value) {
+                return;
+            }
+
+            this._height = value;
+            this._markAsDirty();
+        }   
+
+        public get widthConstantPixel(): number {
+            return this._widthConstantPixel;
+        }
+
+        public set widthConstantPixel(value: number) {
+            if (this._widthConstantPixel === value) {
+                return;
+            }
+
+            this._widthConstantPixel = value;
+            this._markAsDirty();
+        }
+
+        public get heightConstantPixel(): number {
+            return this._heightConstantPixel;
+        }
+
+        public set heightConstantPixel(value: number) {
+            if (this._heightConstantPixel === value) {
+                return;
+            }
+
+            this._heightConstantPixel = value;
+            this._markAsDirty();
+        }      
+
         public get fontFamily(): string {
             return this._fontFamily;
         }
@@ -65,6 +136,21 @@ module BABYLON.GUI {
             }
 
             this._fontSize = value;
+            this._fontSizeConstantPixel = null;
+            this._prepareFont();
+        }
+
+        public get fontSizeConstantPixel(): number {
+            return this._fontSizeConstantPixel;
+        }
+
+        public set fontSizeConstantPixel(value: number) {
+            if (this._fontSizeConstantPixel === value) {
+                return;
+            }
+            
+            this._fontSize = null;
+            this._fontSizeConstantPixel = value;
             this._prepareFont();
         }
 
@@ -119,8 +205,72 @@ module BABYLON.GUI {
             }
         }
 
-        public _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
+        protected _processMeasures(parentMeasure: Measure, context: CanvasRenderingContext2D) {
+            this._measure(parentMeasure, context);
+            this._computeAlignment(parentMeasure, context);
+                        
+            // Clip
+            context.beginPath();
+            context.rect(this._currentMeasure.left ,this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
+            context.clip();
+        }
+
+        protected _measure(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
             this._currentMeasure = parentMeasure.copy();
+            
+            // Width / Height
+            if (this._widthConstantPixel) {
+                this._currentMeasure.width = this._widthConstantPixel * this._scaleX;
+            } else {
+                this._currentMeasure.width *= this._width; 
+            }
+
+            if (this._heightConstantPixel) {
+                this._currentMeasure.height = this._heightConstantPixel * this._scaleY;
+            } else {
+                this._currentMeasure.height *= this._height; 
+            }
+        }
+
+        protected _computeAlignment(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
+            var width = this._currentMeasure.width;
+            var height = this._currentMeasure.height;
+
+            var parentWidth = parentMeasure.width;
+            var parentHeight = parentMeasure.height;
+
+            var x = 0;
+            var y = 0;
+
+            switch (this.horizontalAlignment) {
+                case Control.HORIZONTAL_ALIGNMENT_LEFT:
+                    x = 0
+                    break;
+                case Control.HORIZONTAL_ALIGNMENT_RIGHT:
+                    x = parentWidth - width;
+                    break;
+                case Control.HORIZONTAL_ALIGNMENT_CENTER:
+                    x = (parentWidth - width) / 2;
+                    break;
+            }
+
+            switch (this.verticalAlignment) {
+                case Control.VERTICAL_ALIGNMENT_TOP:
+                    y = 0;
+                    break;
+                case Control.VERTICAL_ALIGNMENT_BOTTOM:
+                    y = parentHeight - height;
+                    break;
+                case Control.VERTICAL_ALIGNMENT_CENTER:
+                    y = (parentHeight - height) / 2;
+                    break;
+            }
+            
+            this._currentMeasure.left = this._currentMeasure.left + x;
+            this._currentMeasure.top =  this._currentMeasure.top + y;            
+        }
+
+        public _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
             // Do nothing
         }
 
@@ -135,7 +285,13 @@ module BABYLON.GUI {
             if (!this._fontFamily) {
                 return;
             }
-            this._font = (this._fontSize * this._scaleX) + "px " + this._fontFamily;
+
+            if (this._fontSizeConstantPixel) {
+                this._font = (this._fontSizeConstantPixel * this._scaleX) + "px " + this._fontFamily;
+            } else {
+                this._font = this._fontSize + "px " + this._fontFamily;
+            }
+        
             this._fontOffset = Control._GetFontOffset(this._font);
             this._markAsDirty();
         }

+ 72 - 17
gui/src/controls/textBlock.js

@@ -18,6 +18,8 @@ var BABYLON;
             function TextBlock(name, text) {
                 var _this = _super.call(this, name) || this;
                 _this.name = name;
+                _this._textHorizontalAlignment = GUI.Control.HORIZONTAL_ALIGNMENT_CENTER;
+                _this._textVerticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_CENTER;
                 _this.text = text;
                 return _this;
             }
@@ -35,34 +37,86 @@ var BABYLON;
                 enumerable: true,
                 configurable: true
             });
-            TextBlock.prototype._draw = function (parentMeasure, context) {
-                context.save();
-                this.applyStates(context);
-                this._prepare(parentMeasure, context);
-                context.fillText(this.text, this._currentMeasure.left, this._currentMeasure.top);
-                context.restore();
-            };
-            TextBlock.prototype._prepare = function (parentMeasure, context) {
-                var width = parentMeasure.width;
-                var height = parentMeasure.height;
+            Object.defineProperty(TextBlock.prototype, "textHorizontalAlignment", {
+                get: function () {
+                    return this._textHorizontalAlignment;
+                },
+                set: function (value) {
+                    if (this._textHorizontalAlignment === value) {
+                        return;
+                    }
+                    this._textHorizontalAlignment = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(TextBlock.prototype, "textVerticalAlignment", {
+                get: function () {
+                    return this._textVerticalAlignment;
+                },
+                set: function (value) {
+                    if (this._textVerticalAlignment === value) {
+                        return;
+                    }
+                    this._textVerticalAlignment = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            TextBlock.prototype._drawText = function (text, textWidth, y, context) {
+                var width = this._currentMeasure.width;
                 var x = 0;
-                var y = 0;
-                var textSize = context.measureText(this.text);
-                switch (this.horizontalAlignment) {
+                switch (this._textHorizontalAlignment) {
                     case GUI.Control.HORIZONTAL_ALIGNMENT_LEFT:
                         x = 0;
                         break;
                     case GUI.Control.HORIZONTAL_ALIGNMENT_RIGHT:
-                        x = width - textSize.width;
+                        x = width - textWidth;
                         break;
                     case GUI.Control.HORIZONTAL_ALIGNMENT_CENTER:
-                        x = (width - textSize.width) / 2;
+                        x = (width - textWidth) / 2;
                         break;
                 }
+                context.fillText(text, this._currentMeasure.left + x, y);
+            };
+            TextBlock.prototype._draw = function (parentMeasure, context) {
+                context.save();
+                _super.prototype._processMeasures.call(this, parentMeasure, context);
+                this.applyStates(context);
+                this._computeTextAlignment(context);
+                var words = this.text.split(' ');
+                var line = '';
+                var width = this._currentMeasure.width;
+                var y = this._textY;
+                var lineWidth = 0;
+                for (var n = 0; n < words.length; n++) {
+                    var testLine = line + words[n] + ' ';
+                    var metrics = context.measureText(testLine);
+                    var testWidth = metrics.width;
+                    if (testWidth > width && n > 0) {
+                        this._drawText(line, lineWidth, y, context);
+                        line = words[n] + ' ';
+                        lineWidth = context.measureText(line).width;
+                        y += this._lineHeight;
+                    }
+                    else {
+                        lineWidth = testWidth;
+                        line = testLine;
+                    }
+                }
+                this._drawText(line, lineWidth, y, context);
+                context.restore();
+            };
+            TextBlock.prototype._computeTextAlignment = function (context) {
+                var width = this._currentMeasure.width;
+                var height = this._currentMeasure.height;
+                var y = 0;
                 if (!this._fontOffset) {
                     this._fontOffset = GUI.Control._GetFontOffset(context.font);
                 }
-                switch (this.verticalAlignment) {
+                switch (this._textVerticalAlignment) {
                     case GUI.Control.VERTICAL_ALIGNMENT_TOP:
                         y = this._fontOffset.ascent;
                         break;
@@ -73,7 +127,8 @@ var BABYLON;
                         y = (height / 2) + (this._fontOffset.ascent - this._fontOffset.height / 2);
                         break;
                 }
-                this._currentMeasure = new GUI.Measure(parentMeasure.left + x, parentMeasure.top + y, width, height);
+                this._lineHeight = this._fontOffset.height;
+                this._textY = this._currentMeasure.top + y;
             };
             return TextBlock;
         }(GUI.Control));

+ 81 - 22
gui/src/controls/textBlock.ts

@@ -3,6 +3,10 @@
 module BABYLON.GUI {
     export class TextBlock extends Control {
         private _text: string;
+        private _textY: number;
+        private _lineHeight: number;
+        private _textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
+        private _textVerticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
 
         public get text(): string {
             return this._text;
@@ -16,49 +20,103 @@ module BABYLON.GUI {
             this._markAsDirty();
         }
 
-        constructor(public name: string, text: string) {
-            super(name);
+        public get textHorizontalAlignment(): number {
+            return this._textHorizontalAlignment;
+        }
 
-            this.text = text;
+        public set textHorizontalAlignment(value: number) {
+            if (this._textHorizontalAlignment === value) {
+                return;
+            }
+
+            this._textHorizontalAlignment = value;
+            this._markAsDirty();
+        } 
+
+        public get textVerticalAlignment(): number {
+            return this._textVerticalAlignment;
         }
 
-        public _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
-            context.save();
-            
-            this.applyStates(context);
+        public set textVerticalAlignment(value: number) {
+            if (this._textVerticalAlignment === value) {
+                return;
+            }
 
-            this._prepare(parentMeasure, context)
+            this._textVerticalAlignment = value;
+            this._markAsDirty();
+        } 
 
-            context.fillText(this.text, this._currentMeasure.left, this._currentMeasure.top);
+        constructor(public name: string, text: string) {
+            super(name);
 
-            context.restore();
+            this.text = text;
         }
 
-        private _prepare(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
-            var width = parentMeasure.width;
-            var height = parentMeasure.height;
+        private _drawText(text: string, textWidth: number, y: number, context: CanvasRenderingContext2D): void {
 
+            var width = this._currentMeasure.width;
             var x = 0;
-            var y = 0;
-
-            var textSize = context.measureText(this.text);
-            switch (this.horizontalAlignment) {
+            switch (this._textHorizontalAlignment) {
                 case Control.HORIZONTAL_ALIGNMENT_LEFT:
                     x = 0
                     break;
                 case Control.HORIZONTAL_ALIGNMENT_RIGHT:
-                    x = width - textSize.width;
+                    x = width - textWidth;
                     break;
                 case Control.HORIZONTAL_ALIGNMENT_CENTER:
-                    x = (width - textSize.width) / 2;
+                    x = (width - textWidth) / 2;
                     break;
             }
 
+            context.fillText(text, this._currentMeasure.left + x, y);
+        }
+
+        public _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
+            context.save();
+
+            super._processMeasures(parentMeasure, context);
+            
+            this.applyStates(context);
+
+            this._computeTextAlignment(context);
+
+            var words = this.text.split(' ');
+            var line = '';
+
+            var width = this._currentMeasure.width;
+            var y = this._textY;
+            var lineWidth = 0;
+            for(var n = 0; n < words.length; n++) {
+                var testLine = line + words[n] + ' ';
+                var metrics = context.measureText(testLine);
+                var testWidth = metrics.width;
+                if (testWidth > width && n > 0) {
+                    this._drawText(line, lineWidth, y, context);
+                    line = words[n] + ' ';
+                    lineWidth = context.measureText(line).width;
+                    y += this._lineHeight;
+                }
+                else {
+                    lineWidth = testWidth;
+                    line = testLine;
+                }
+            }
+            this._drawText(line, lineWidth, y, context);
+
+            context.restore();
+        }
+
+        protected _computeTextAlignment(context: CanvasRenderingContext2D): void {
+            var width = this._currentMeasure.width;
+            var height = this._currentMeasure.height;
+
+            
+            var y = 0;
             if (!this._fontOffset) {
                 this._fontOffset = Control._GetFontOffset(context.font);
             }
 
-            switch (this.verticalAlignment) {
+            switch (this._textVerticalAlignment) {
                 case Control.VERTICAL_ALIGNMENT_TOP:
                     y = this._fontOffset.ascent;
                     break;
@@ -69,8 +127,9 @@ module BABYLON.GUI {
                     y = (height /2) + (this._fontOffset.ascent - this._fontOffset.height / 2);
                     break;
             }
-            
-            this._currentMeasure = new Measure(parentMeasure.left + x, parentMeasure.top + y, width, height);
+
+            this._lineHeight = this._fontOffset.height;            
+            this._textY = this._currentMeasure.top + y;
         }
     }    
 }