Browse Source

Merge pull request #9408 from Flux159/focusable_button

Creating a new focusable button gui element.
David Catuhe 4 năm trước cách đây
mục cha
commit
b1d5ae9caf

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

@@ -4,6 +4,9 @@
 
 ## Updates
 
+- Added a `FocusableButton` gui control to simplify creating menus with keyboard navigation ([Flux159](https://github.com/Flux159))
+- Added `focus()` and `blur()` functions for controls that implement `IFocusableControl` ([Flux159](https://github.com/Flux159))
+
 ### General
 
 - Added static CenterToRef for vectors 2/3/4  ([aWeirdo](https://github.com/aWeirdo))

+ 2 - 23
gui/src/2D/advancedDynamicTexture.ts

@@ -16,34 +16,13 @@ import { Scene } from "babylonjs/scene";
 
 import { Container } from "./controls/container";
 import { Control } from "./controls/control";
+import { IFocusableControl } from './controls/focusableControl';
 import { Style } from "./style";
 import { Measure } from "./measure";
 import { Constants } from 'babylonjs/Engines/constants';
 import { Viewport } from 'babylonjs/Maths/math.viewport';
 import { Color3 } from 'babylonjs/Maths/math.color';
-/**
-* Interface used to define a control that can receive focus
-*/
-export interface IFocusableControl {
-    /**
-     * Function called when the control receives the focus
-     */
-    onFocus(): void;
-    /**
-     * Function called when the control loses the focus
-     */
-    onBlur(): void;
-    /**
-     * Function called to let the control handle keyboard events
-     * @param evt defines the current keyboard event
-     */
-    processKeyboard(evt: KeyboardEvent): void;
-    /**
-    * Function called to get the list of controls that should not steal the focus from this control
-    * @returns an array of controls
-    */
-    keepsFocusWith(): Nullable<Control[]>;
-}
+
 /**
 * Class used to create texture to support 2D GUI elements
 * @see https://doc.babylonjs.com/how_to/gui

+ 4 - 4
gui/src/2D/controls/button.ts

@@ -172,7 +172,7 @@ export class Button extends Rectangle {
      * @returns a new Button
      */
     public static CreateImageButton(name: string, text: string, imageUrl: string): Button {
-        var result = new Button(name);
+        var result = new this(name);
 
         // Adding text
         var textBlock = new TextBlock(name + "_button", text);
@@ -202,7 +202,7 @@ export class Button extends Rectangle {
      * @returns a new Button
      */
     public static CreateImageOnlyButton(name: string, imageUrl: string): Button {
-        var result = new Button(name);
+        var result = new this(name);
 
         // Adding image
         var iconImage = new Image(name + "_icon", imageUrl);
@@ -223,7 +223,7 @@ export class Button extends Rectangle {
      * @returns a new Button
      */
     public static CreateSimpleButton(name: string, text: string): Button {
-        var result = new Button(name);
+        var result = new this(name);
 
         // Adding text
         var textBlock = new TextBlock(name + "_button", text);
@@ -245,7 +245,7 @@ export class Button extends Rectangle {
      * @returns a new Button
      */
     public static CreateImageWithCenterTextButton(name: string, text: string, imageUrl: string): Button {
-        var result = new Button(name);
+        var result = new this(name);
 
         // Adding image
         var iconImage = new Image(name + "_icon", imageUrl);

+ 104 - 0
gui/src/2D/controls/focusableButton.ts

@@ -0,0 +1,104 @@
+import { Nullable } from "babylonjs/types";
+import { Vector2 } from "babylonjs/Maths/math.vector";
+
+import { Button } from "./button";
+import { Control } from "./control";
+import { _TypeStore } from 'babylonjs/Misc/typeStore';
+import { PointerInfoBase } from 'babylonjs/Events/pointerEvents';
+import { IFocusableControl } from "./focusableControl";
+import { Observable } from 'babylonjs/Misc/observable';
+
+/**
+ * Class used to create a focusable button that can easily handle keyboard events
+ */
+export class FocusableButton extends Button implements IFocusableControl {
+    /** Highlight color when button is focused */
+    public focusedColor: Nullable<string> = null;
+    private _isFocused = false;
+    private _unfocusedColor: Nullable<string> = null;
+
+    /** Observable raised when the control gets the focus */
+    public onFocusObservable = new Observable<Button>();
+    /** Observable raised when the control loses the focus */
+    public onBlurObservable = new Observable<Button>();
+    /** Observable raised when a key event was processed */
+    public onKeyboardEventProcessedObservable = new Observable<KeyboardEvent>();
+
+    constructor(public name?: string) {
+        super(name);
+
+        this._unfocusedColor = this.color;
+    }
+
+    /** @hidden */
+    public onBlur(): void {
+        if (this._isFocused) {
+            this._isFocused = false;
+            if (this.focusedColor && this._unfocusedColor != null) {
+                // Set color back to saved unfocused color
+                this.color = this._unfocusedColor;
+            }
+            this.onBlurObservable.notifyObservers(this);
+        }
+    }
+
+    /** @hidden */
+    public onFocus(): void {
+        this._isFocused = true;
+
+        if (this.focusedColor) {
+            // Save the unfocused color
+            this._unfocusedColor = this.color;
+            this.color = this.focusedColor;
+        }
+        this.onFocusObservable.notifyObservers(this);
+    }
+
+    /**
+     * Function called to get the list of controls that should not steal the focus from this control
+     * @returns an array of controls
+     */
+    public keepsFocusWith(): Nullable<Control[]> {
+        return null;
+    }
+
+    /**
+     * Function to focus a button programmatically
+     */
+    public focus() {
+        this._host.moveFocusToControl(this);
+    }
+
+    /**
+     * Function to unfocus a button programmatically
+     */
+    public blur() {
+        this._host.focusedControl = null;
+    }
+
+    /**
+     * Handles the keyboard event
+     * @param evt Defines the KeyboardEvent
+     */
+    public processKeyboard(evt: KeyboardEvent): void {
+        this.onKeyboardEventProcessedObservable.notifyObservers(evt, -1, this);
+    }
+
+    /** @hidden */
+    public _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number, pi: PointerInfoBase): boolean {
+        // Clicking on button should focus
+        this.focus();
+
+        return super._onPointerDown(target, coordinates, pointerId, buttonIndex, pi);
+    }
+
+    /** @hidden */
+    public displose() {
+        super.dispose();
+
+        this.onBlurObservable.clear();
+        this.onFocusObservable.clear();
+        this.onKeyboardEventProcessedObservable.clear();
+    }
+}
+_TypeStore.RegisteredTypes["BABYLON.GUI.FocusableButton"] = FocusableButton;

+ 34 - 0
gui/src/2D/controls/focusableControl.ts

@@ -0,0 +1,34 @@
+import { Nullable } from "babylonjs/types";
+import { Control } from "./control";
+
+/**
+* Interface used to define a control that can receive focus
+*/
+export interface IFocusableControl {
+    /**
+     * Function called when the control receives the focus
+     */
+    onFocus(): void;
+    /**
+     * Function called when the control loses the focus
+     */
+    onBlur(): void;
+    /**
+     * Function called to let the control handle keyboard events
+     * @param evt defines the current keyboard event
+     */
+    processKeyboard(evt: KeyboardEvent): void;
+    /**
+    * Function called to get the list of controls that should not steal the focus from this control
+    * @returns an array of controls
+    */
+    keepsFocusWith(): Nullable<Control[]>;
+    /**
+    * Function to focus the control programmatically
+    */
+    focus(): void;
+    /**
+    * Function to unfocus the control programmatically
+    */
+    blur(): void;
+}

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

@@ -4,6 +4,7 @@ export * from "./colorpicker";
 export * from "./container";
 export * from "./control";
 export * from "./ellipse";
+export * from './focusableButton';
 export * from "./grid";
 export * from "./image";
 export * from "./inputText";

+ 15 - 1
gui/src/2D/controls/inputText.ts

@@ -5,7 +5,7 @@ import { ClipboardEventTypes, ClipboardInfo } from "babylonjs/Events/clipboardEv
 import { PointerInfo, PointerEventTypes, PointerInfoBase } from 'babylonjs/Events/pointerEvents';
 
 import { Control } from "./control";
-import { IFocusableControl } from "../advancedDynamicTexture";
+import { IFocusableControl } from "./focusableControl";
 import { ValueAndUnit } from "../valueAndUnit";
 import { VirtualKeyboard } from "./virtualKeyboard";
 import { _TypeStore } from 'babylonjs/Misc/typeStore';
@@ -426,6 +426,20 @@ export class InputText extends Control implements IFocusableControl {
 
     }
 
+    /**
+     * Function to focus an inputText programmatically
+     */
+    public focus() {
+        this._host.moveFocusToControl(this);
+    }
+
+    /**
+     * Function to unfocus an inputText programmatically
+     */
+    public blur() {
+        this._host.focusedControl = null;
+    }
+
     protected _getTypeName(): string {
         return "InputText";
     }