Procházet zdrojové kódy

Merge pull request #4701 from adrientetar/textblock-height

TextBlock: provide expected height
David Catuhe před 7 roky
rodič
revize
7ce3fec2a4

+ 1 - 0
dist/preview release/what's new.md

@@ -30,6 +30,7 @@
 
 - All NPM packages have `latest`and `preview` streams [#3055](https://github.com/BabylonJS/Babylon.js/issues/3055) ([RaananW](https://github.com/RaananW))
 - Added New Tools Tab in the inspector (env texture and screenshot tools so far) ([sebavan](http://www.github.com/sebavan))
+- Added `TextBlock.computeExpectedHeight`, added `TextWrapping.Ellipsis` as `TextBlock.wordWrapping` possible value ([adrientetar](https://github.com/adrientetar))
 
 ### Core Engine
 

+ 79 - 13
gui/src/2D/controls/textBlock.ts

@@ -2,11 +2,31 @@
 
 module BABYLON.GUI {
     /**
+     * Enum that determines the text-wrapping mode to use.
+     */
+    export enum TextWrapping {
+        /**
+         * Clip the text when it's larger than Control.width; this is the default mode.
+         */
+        Clip = 0,
+
+        /**
+         * Wrap the text word-wise, i.e. try to add line-breaks at word boundary to fit within Control.width.
+         */
+        WordWrap = 1,
+
+        /**
+         * Ellipsize the text, i.e. shrink with trailing … when text is larger than Control.width.
+         */
+        Ellipsis,
+    }
+
+    /**
      * Class used to create text block control
      */
     export class TextBlock extends Control {
         private _text = "";
-        private _textWrapping = false;
+        private _textWrapping = TextWrapping.Clip;
         private _textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
         private _textVerticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
 
@@ -54,18 +74,18 @@ module BABYLON.GUI {
         /**
          * Gets or sets a boolean indicating if text must be wrapped
          */
-        public get textWrapping(): boolean {
+        public get textWrapping(): TextWrapping | boolean {
             return this._textWrapping;
         }
 
         /**
          * Gets or sets a boolean indicating if text must be wrapped
          */        
-        public set textWrapping(value: boolean) {
+        public set textWrapping(value: TextWrapping | boolean) {
             if (this._textWrapping === value) {
                 return;
             }
-            this._textWrapping = value;
+            this._textWrapping = +value;
             this._markAsDirty();
         }
 
@@ -249,29 +269,54 @@ module BABYLON.GUI {
         }
 
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
-            this._lines = [];
+            this._lines = this._breakLines(this._currentMeasure.width, context);
+            this.onLinesReadyObservable.notifyObservers(this);
+        }
+
+        protected _breakLines(refWidth: number, context: CanvasRenderingContext2D): object[] {
+            var lines = [];
             var _lines = this.text.split("\n");
 
-            if (this._textWrapping && !this._resizeToFit) {
+            if (this._textWrapping === TextWrapping.Ellipsis && !this._resizeToFit) {
+                for (var _line of _lines) {
+                    lines.push(this._parseLineEllipsis(_line, refWidth, context));
+                }
+            } else if (this._textWrapping === TextWrapping.WordWrap && !this._resizeToFit) {
                 for (var _line of _lines) {
-                    this._lines.push(this._parseLineWithTextWrapping(_line, context));
+                    lines.push(...this._parseLineWordWrap(_line, refWidth, context));
                 }
             } else {
                 for (var _line of _lines) {
-                    this._lines.push(this._parseLine(_line, context));
+                    lines.push(this._parseLine(_line, context));
                 }
             }
 
-            this.onLinesReadyObservable.notifyObservers(this);
+            return lines;
         }
 
         protected _parseLine(line: string = '', context: CanvasRenderingContext2D): object {
             return { text: line, width: context.measureText(line).width };
         }
 
-        protected _parseLineWithTextWrapping(line: string = '', context: CanvasRenderingContext2D): object {
+        protected _parseLineEllipsis(line: string = '', width: number,
+                                     context: CanvasRenderingContext2D): object {
+            var lineWidth = context.measureText(line).width;
+
+            if (lineWidth > width) {
+                line += '…';
+            }
+            while (line.length > 2 && lineWidth > width) {
+                line = line.slice(0, -2) + '…';
+                lineWidth = context.measureText(line).width;
+            }
+
+            return { text: line, width: lineWidth };
+        }
+
+        protected _parseLineWordWrap(line: string = '', width: number,
+                                     context: CanvasRenderingContext2D): object[] {
+            var lines = [];
             var words = line.split(' ');
-            var width = this._currentMeasure.width;
             var lineWidth = 0;
 
             for (var n = 0; n < words.length; n++) {
@@ -279,7 +324,7 @@ module BABYLON.GUI {
                 var metrics = context.measureText(testLine);
                 var testWidth = metrics.width;
                 if (testWidth > width && n > 0) {
-                    this._lines.push({ text: line, width: lineWidth });
+                    lines.push({ text: line, width: lineWidth });
                     line = words[n];
                     lineWidth = context.measureText(line).width;
                 }
@@ -288,8 +333,9 @@ module BABYLON.GUI {
                     line = testLine;
                 }
             }
+            lines.push({ text: line, width: lineWidth });
 
-            return { text: line, width: lineWidth };
+            return lines;
         }
 
         protected _renderLines(context: CanvasRenderingContext2D): void {
@@ -339,6 +385,26 @@ module BABYLON.GUI {
             }
         }
 
+        /**
+         * Given a width constraint applied on the text block, find the expected height
+         * @returns expected height
+         */
+        public computeExpectedHeight(): number {
+            if (this.text && this.widthInPixels) {
+                const context = document.createElement('canvas').getContext('2d');
+                if (context) {
+                    this._applyStates(context);
+                    if (!this._fontOffset) {
+                        this._fontOffset = Control._GetFontOffset(context.font);
+                    }
+                    const lines = this._lines ? this._lines : this._breakLines(
+                        this.widthInPixels - this.paddingLeftInPixels - this.paddingRightInPixels, context);
+                    return this.paddingTopInPixels + this.paddingBottomInPixels + this._fontOffset.height * lines.length;
+                }
+            }
+            return 0;
+        }
+
         dispose(): void {
             super.dispose();