Explorar el Código

Scroll Viewer with Image Bars

Guide hace 5 años
padre
commit
dd0038dd05

+ 1 - 0
gui/src/2D/controls/index.ts

@@ -22,5 +22,6 @@ export * from "./sliders/baseSlider";
 export * from "./sliders/slider";
 export * from "./sliders/imageBasedSlider";
 export * from "./sliders/scrollBar";
+export * from "./sliders/imageScrollBar";
 
 export * from "./statics";

+ 127 - 47
gui/src/2D/controls/scrollViewers/scrollViewer.ts

@@ -4,12 +4,14 @@ import { PointerInfo, PointerEventTypes } from "babylonjs/Events/pointerEvents";
 
 import { Rectangle } from "../rectangle";
 import { Grid } from "../grid";
+import { Image } from "../image";
 import { Control } from "../control";
 import { Container } from "../container";
 import { Measure } from "../../measure";
 import { AdvancedDynamicTexture } from "../../advancedDynamicTexture";
 import { _ScrollViewerWindow } from "./scrollViewerWindow";
 import { ScrollBar } from "../sliders/scrollBar";
+import { ImageScrollBar } from "../sliders/imageScrollBar";
 import { _TypeStore } from 'babylonjs/Misc/typeStore';
 
 /**
@@ -20,10 +22,12 @@ export class ScrollViewer extends Rectangle {
     private _horizontalBarSpace: Rectangle;
     private _verticalBarSpace: Rectangle;
     private _dragSpace: Rectangle;
-    private _horizontalBar: ScrollBar;
-    private _verticalBar: ScrollBar;
+    private _horizontalBar: ScrollBar | ImageScrollBar;
+    private _verticalBar: ScrollBar | ImageScrollBar;
     private _barColor: string;
     private _barBackground: string;
+    private _barImage: Image;
+    private _barBackgroundImage: Image;
     private _barSize: number = 20;
     private _endLeft: number;
     private _endTop: number;
@@ -33,18 +37,20 @@ export class ScrollViewer extends Rectangle {
     private _onPointerObserver: Nullable<Observer<PointerInfo>>;
     private _clientWidth: number;
     private _clientHeight: number;
+    private _useImageBar: Boolean;
+    private _thumbSize: number = 1;
 
     /**
      * Gets the horizontal scrollbar
      */
-    public get horizontalBar(): ScrollBar {
+    public get horizontalBar(): ScrollBar | ImageScrollBar {
         return this._horizontalBar;
     }
 
     /**
      * Gets the vertical scrollbar
      */
-    public get verticalBar(): ScrollBar {
+    public get verticalBar(): ScrollBar | ImageScrollBar {
         return this._verticalBar;
     }
 
@@ -88,9 +94,11 @@ export class ScrollViewer extends Rectangle {
     * Creates a new ScrollViewer
     * @param name of ScrollViewer
     */
-    constructor(name?: string) {
+    constructor(name?: string, isImageBased?: boolean) {
         super(name);
 
+        this._useImageBar = isImageBased ? isImageBased : false;
+
         this.onDirtyObservable.add(() => {
             this._horizontalBarSpace.color = this.color;
             this._verticalBarSpace.color = this.color;
@@ -106,8 +114,14 @@ export class ScrollViewer extends Rectangle {
         });
 
         this._grid = new Grid();
-        this._horizontalBar = new ScrollBar();
-        this._verticalBar = new ScrollBar();
+        if (this._useImageBar) {
+            this._horizontalBar = new ImageScrollBar();
+            this._verticalBar = new ImageScrollBar();
+        }
+        else {
+            this._horizontalBar = new ScrollBar();
+            this._verticalBar = new ScrollBar();
+        }
 
         this._window = new _ScrollViewerWindow();
         this._window.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
@@ -121,57 +135,29 @@ export class ScrollViewer extends Rectangle {
         super.addControl(this._grid);
         this._grid.addControl(this._window, 0, 0);
 
-        this._verticalBar.paddingLeft = 0;
-        this._verticalBar.width = "100%";
-        this._verticalBar.height = "100%";
-        this._verticalBar.barOffset = 0;
-        this._verticalBar.value = 0;
-        this._verticalBar.maximum = 1;
-        this._verticalBar.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
-        this._verticalBar.verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
-        this._verticalBar.isVertical = true;
-        this._verticalBar.rotation = Math.PI;
-        this._verticalBar.isVisible = false;
-
         this._verticalBarSpace = new Rectangle();
         this._verticalBarSpace.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
         this._verticalBarSpace.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
         this._verticalBarSpace.thickness = 1;
         this._grid.addControl(this._verticalBarSpace, 0, 1);
-        this._verticalBarSpace.addControl(this._verticalBar);
-
-        this._verticalBar.onValueChangedObservable.add((value) => {
-            this._window.top = value * this._endTop + "px";
-        });
-
-        this._horizontalBar.paddingLeft = 0;
-        this._horizontalBar.width = "100%";
-        this._horizontalBar.height = "100%";
-        this._horizontalBar.barOffset = 0;
-        this._horizontalBar.value = 0;
-        this._horizontalBar.maximum = 1;
-        this._horizontalBar.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
-        this._horizontalBar.verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
-        this._horizontalBar.isVisible = false;
+        this._addBar(this._verticalBar, this._verticalBarSpace, true, Math.PI);
 
         this._horizontalBarSpace = new Rectangle();
         this._horizontalBarSpace.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
         this._horizontalBarSpace.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
         this._horizontalBarSpace.thickness = 1;
         this._grid.addControl(this._horizontalBarSpace, 1, 0);
-        this._horizontalBarSpace.addControl(this._horizontalBar);
-
-        this._horizontalBar.onValueChangedObservable.add((value) => {
-            this._window.left = value * this._endLeft + "px";
-        });
+        this._addBar(this._horizontalBar, this._horizontalBarSpace, false, 0);
 
         this._dragSpace = new Rectangle();
         this._dragSpace.thickness = 1;
         this._grid.addControl(this._dragSpace, 1, 1);
 
         // Colors
-        this.barColor = "grey";
-        this.barBackground = "transparent";
+        if (!this._useImageBar) {
+            this.barColor = "grey";
+            this.barBackground = "transparent";
+        }
     }
 
     /** Reset the scroll viewer window to initial size */
@@ -228,6 +214,19 @@ export class ScrollViewer extends Rectangle {
         this._wheelPrecision = value;
     }
 
+    /** Gets or sets the scroll bar container background color */
+    public get scrollBackground(): string {
+        return this._dragSpace.background;
+    }
+
+    public set scrollBackground(color: string) {
+        if (this._dragSpace.background === color) {
+            return;
+        }
+
+        this._dragSpace.background = color;
+    }
+
     /** Gets or sets the bar color */
     public get barColor(): string {
         return this._barColor;
@@ -243,6 +242,23 @@ export class ScrollViewer extends Rectangle {
         this._verticalBar.color = color;
     }
 
+    /** Gets or sets the bar image */
+    public get barImage(): Image {
+        return this._barImage;
+    }
+
+    public set barImage(value: Image) {
+        if (this._barImage === value) {
+            return;
+        }
+
+        this._barImage = value;
+        let hb = <ImageScrollBar>this.horizontalBar;
+        let vb = <ImageScrollBar>this._verticalBar;
+        hb.thumbImage = value;
+        vb.thumbImage = value;
+    }
+
     /** Gets or sets the size of the bar */
     public get barSize(): number {
         return this._barSize;
@@ -264,6 +280,20 @@ export class ScrollViewer extends Rectangle {
         }
     }
 
+    /** Gets or sets the size of the thumb */
+    public get thumbSize(): number {
+        return this._thumbSize;
+    }
+
+    public set thumbSize(value: number) {
+        if (this._thumbSize === value) {
+            return;
+        }
+
+        this._thumbSize = value;
+        this._markAsDirty();
+    }
+
     /** Gets or sets the bar background */
     public get barBackground(): string {
         return this._barBackground;
@@ -275,11 +305,29 @@ export class ScrollViewer extends Rectangle {
         }
 
         this._barBackground = color;
-        this._horizontalBar.background = color;
-        this._verticalBar.background = color;
+        let hb = <ScrollBar>this._horizontalBar;
+        let vb = <ScrollBar>this._verticalBar;
+        hb.background = color;
+        vb.background = color;
         this._dragSpace.background = color;
     }
 
+    /** Gets or sets the bar background image */
+    public get barBackgroundImage(): Image {
+        return this._barBackgroundImage;
+    }
+
+    public set barBackgroundImage(value: Image) {
+        if (this._barBackgroundImage === value) {
+        }
+
+        this._barBackgroundImage = value;
+        let hb = <ImageScrollBar>this._horizontalBar;
+        let vb = <ImageScrollBar>this._verticalBar;
+        hb.backgroundImage = value;
+        vb.backgroundImage = value;
+    }
+
     /** @hidden */
     private _updateScroller(): void {
         let windowContentsWidth = this._window._currentMeasure.width;
@@ -326,11 +374,17 @@ export class ScrollViewer extends Rectangle {
             this._rebuildLayout = true;
         }
 
-        let horizontalMultiplicator = this._clientWidth / windowContentsWidth;
-        let verticalMultiplicator = this._clientHeight / windowContentsHeight;
+        if (this._useImageBar && this._barImage) {
+            this._horizontalBar.thumbWidth = Math.min(0.9 * this._clientWidth, this._thumbSize * this._barImage.domImage.width * this._horizontalBarSpace.heightInPixels / this._barImage.domImage.height) + "px";
+            this._verticalBar.thumbWidth = Math.min(0.9 * this._clientHeight, this._thumbSize * this._barImage.domImage.width * this._verticalBarSpace.widthInPixels / this._barImage.domImage.height) + "px";
+        }
+        else {
+            let horizontalMultiplicator = this._clientWidth / windowContentsWidth;
+            let verticalMultiplicator = this._clientHeight / windowContentsHeight;
 
-        this._horizontalBar.thumbWidth = (this._clientWidth * horizontalMultiplicator) + "px";
-        this._verticalBar.thumbWidth = (this._clientHeight * verticalMultiplicator) + "px";
+            this._horizontalBar.thumbWidth = Math.min(0.9 * this._clientWidth, this._thumbSize * (this._clientWidth * horizontalMultiplicator)) + "px";
+            this._verticalBar.thumbWidth = Math.min(0.9 * this._clientHeight, this._thumbSize * (this._clientHeight * verticalMultiplicator)) + "px";
+        }
     }
 
     public _link(host: AdvancedDynamicTexture): void {
@@ -340,6 +394,32 @@ export class ScrollViewer extends Rectangle {
     }
 
     /** @hidden */
+    private _addBar(barControl: ScrollBar | ImageScrollBar, barContainer: Rectangle, isVertical: boolean, rotation: number) {
+        barControl.paddingLeft = 0;
+        barControl.width = "100%";
+        barControl.height = "100%";
+        barControl.barOffset = 0;
+        barControl.value = 0;
+        barControl.maximum = 1;
+        barControl.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
+        barControl.verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
+        barControl.isVertical = isVertical;
+        barControl.rotation = rotation;
+        barControl.isVisible = false;
+
+        barContainer.addControl(barControl);
+
+        barControl.onValueChangedObservable.add((value) => {
+            if (rotation > 0) {
+                this._window.top = value * this._endTop + "px";
+            }
+            else {
+                this._window.left = value * this._endLeft + "px";
+            }
+        });
+    }
+
+    /** @hidden */
     private _attachWheel() {
         if (!this._host || this._onPointerObserver) {
             return;

+ 168 - 0
gui/src/2D/controls/sliders/imageScrollBar.ts

@@ -0,0 +1,168 @@
+import { Vector2 } from "babylonjs/Maths/math";
+import { BaseSlider } from "./baseSlider";
+import { Control } from "../control";
+import { Image } from "../image";
+import { Measure } from "../../measure";
+
+/**
+ * Class used to create slider controls
+ */
+export class ImageScrollBar extends BaseSlider {
+    private _backgroundImage: Image;
+    private _thumbImage: Image;
+    private _thumbMeasure = new Measure(0, 0, 0, 0);
+
+    /**
+     * Gets or sets the image used to render the background
+     */
+    public get backgroundImage(): Image {
+        return this._backgroundImage;
+    }
+
+    public set backgroundImage(value: Image) {
+        if (this._backgroundImage === value) {
+            return;
+        }
+
+        this._backgroundImage = value;
+
+        if (value && !value.isLoaded) {
+            value.onImageLoadedObservable.addOnce(() => this._markAsDirty());
+        }
+
+        this._markAsDirty();
+    }
+
+    /**
+     * Gets or sets the image used to render the thumb
+     */
+    public get thumbImage(): Image {
+        return this._thumbImage;
+    }
+
+    public set thumbImage(value: Image) {
+        if (this._thumbImage === value) {
+            return;
+        }
+
+        this._thumbImage = value;
+
+        if (value && !value.isLoaded) {
+            value.onImageLoadedObservable.addOnce(() => this._markAsDirty());
+        }
+
+        this._markAsDirty();
+    }
+
+    /**
+     * Creates a new ImageScrollBar
+     * @param name defines the control name
+     */
+    constructor(public name?: string) {
+        super(name);
+    }
+
+    protected _getTypeName(): string {
+        return "ImageScrollBar";
+    }
+
+    protected _getThumbThickness(): number {
+        var thumbThickness = 0;
+        if (this._thumbWidth.isPixel) {
+            thumbThickness = this._thumbWidth.getValue(this._host);
+        }
+        else {
+            thumbThickness = this._backgroundBoxThickness * this._thumbWidth.getValue(this._host);
+        }
+        return thumbThickness;
+    }
+
+    public _draw(context: CanvasRenderingContext2D): void {
+        context.save();
+
+        this._applyStates(context);
+
+        this._prepareRenderingData("rectangle");
+        const thumbPosition = this._getThumbPosition();
+        var left = this._renderLeft;
+        var top = this._renderTop;
+        var width = this._renderWidth;
+        var height = this._renderHeight;
+
+       // Background
+        if (this._backgroundImage) {
+            this._thumbMeasure.copyFromFloats(left, top, width, height);
+            if (this.isVertical) {
+                this._thumbMeasure.copyFromFloats(left, this._currentMeasure.top, width, height);
+                this._thumbMeasure.height += this._effectiveThumbThickness;
+                this._backgroundImage._currentMeasure.copyFrom(this._thumbMeasure);
+            } else {
+                this._thumbMeasure.copyFromFloats(this._currentMeasure.left, top, width, height);
+                this._thumbMeasure.width += this._effectiveThumbThickness;
+                this._backgroundImage._currentMeasure.copyFrom(this._thumbMeasure);
+            }
+            this._backgroundImage._draw(context);
+        }
+
+        // Thumb
+        if (this.isVertical) {
+            this._thumbMeasure.copyFromFloats(left - this._effectiveBarOffset, this._currentMeasure.top + thumbPosition, this._currentMeasure.width, this._effectiveThumbThickness);
+        } else {
+            this._thumbMeasure.copyFromFloats(this._currentMeasure.left + thumbPosition, this._currentMeasure.top, this._effectiveThumbThickness, this._currentMeasure.height);
+        }
+
+        this._thumbImage._currentMeasure.copyFrom(this._thumbMeasure);
+        this._thumbImage._draw(context);
+
+        context.restore();
+    }
+
+    private _first: boolean;
+    private _originX: number;
+    private _originY: number;
+
+    /** @hidden */
+    protected _updateValueFromPointer(x: number, y: number): void {
+        if (this.rotation != 0) {
+            this._invertTransformMatrix.transformCoordinates(x, y, this._transformedPosition);
+            x = this._transformedPosition.x;
+            y = this._transformedPosition.y;
+        }
+
+        if (this._first) {
+            this._first = false;
+            this._originX = x;
+            this._originY = y;
+
+            // Check if move is required
+            if (x < this._thumbMeasure.left || x > this._thumbMeasure.left + this._thumbMeasure.width || y < this._thumbMeasure.top || y > this._thumbMeasure.top + this._thumbMeasure.height) {
+                if (this.isVertical) {
+                    this.value = this.minimum + (1 - ((y - this._currentMeasure.top) / this._currentMeasure.height)) * (this.maximum - this.minimum);
+                }
+                else {
+                    this.value = this.minimum + ((x - this._currentMeasure.left) / this._currentMeasure.width) * (this.maximum - this.minimum);
+                }
+            }
+        }
+
+        // Delta mode
+        let delta = 0;
+        if (this.isVertical) {
+            delta = -((y - this._originY) / (this._currentMeasure.height - this._effectiveThumbThickness));
+        }
+        else {
+            delta = (x - this._originX) / (this._currentMeasure.width - this._effectiveThumbThickness);
+        }
+
+        this.value += delta * (this.maximum - this.minimum);
+
+        this._originX = x;
+        this._originY = y;
+    }
+
+    public _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean {
+        this._first = true;
+
+        return super._onPointerDown(target, coordinates, pointerId, buttonIndex);
+    }
+}