babylon.gui.window.ts 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. module BABYLON {
  2. @className("Window", "BABYLON")
  3. export class Window extends ContentControl {
  4. static WINDOW_PROPCOUNT = ContentControl.CONTENTCONTROL_PROPCOUNT + 2;
  5. static leftProperty: Prim2DPropInfo;
  6. static bottomProperty: Prim2DPropInfo;
  7. static positionProperty: Prim2DPropInfo;
  8. constructor(scene: Scene, settings?: {
  9. id ?: string,
  10. templateName ?: string,
  11. styleName ?: string,
  12. content ?: any,
  13. contentAlignment?: string,
  14. left ?: number,
  15. bottom ?: number,
  16. minWidth ?: number,
  17. minHeight ?: number,
  18. maxWidth ?: number,
  19. maxHeight ?: number,
  20. width ?: number,
  21. height ?: number,
  22. worldPosition ?: Vector3,
  23. worldRotation ?: Quaternion,
  24. }) {
  25. if (!settings) {
  26. settings = {};
  27. }
  28. super(settings);
  29. if (!this._UIElementVisualToBuildList) {
  30. this._UIElementVisualToBuildList = new Array<UIElement>();
  31. }
  32. // Patch the owner and also the parent property through the whole tree
  33. this._patchUIElement(this, null);
  34. // Screen Space UI
  35. if (!settings.worldPosition && !settings.worldRotation) {
  36. this._canvas = Window.getScreenCanvas(scene);
  37. this._isWorldSpaceCanvas = false;
  38. this._left = (settings.left != null) ? settings.left : 0;
  39. this._bottom = (settings.bottom != null) ? settings.bottom : 0;
  40. }
  41. // WorldSpace UI
  42. else {
  43. let w = (settings.width == null) ? 100 : settings.width;
  44. let h = (settings.height == null) ? 100 : settings.height;
  45. let wpos = (settings.worldPosition == null) ? Vector3.Zero() : settings.worldPosition;
  46. let wrot = (settings.worldRotation == null) ? Quaternion.Identity() : settings.worldRotation;
  47. this._canvas = new WorldSpaceCanvas2D(scene, new Size(w, h), { id: "GUI Canvas", cachingStrategy: Canvas2D.CACHESTRATEGY_DONTCACHE, worldPosition: wpos, worldRotation: wrot });
  48. this._isWorldSpaceCanvas = true;
  49. }
  50. this._renderObserver = this._canvas.renderObservable.add((e, s) => this._canvasPreRender(), Canvas2D.RENDEROBSERVABLE_PRE);
  51. this._disposeObserver = this._canvas.disposeObservable.add((e, s) => this._canvasDisposed());
  52. this._canvas.propertyChanged.add((e, s) => {
  53. if (e.propertyName === "overPrim") {
  54. this._overPrimChanged(e.oldValue, e.newValue);
  55. }
  56. });
  57. this._mouseOverUIElement = null;
  58. }
  59. public get canvas(): Canvas2D {
  60. return this._canvas;
  61. }
  62. @dependencyProperty(ContentControl.CONTENTCONTROL_PROPCOUNT + 0, pi => Window.leftProperty = pi)
  63. public get left(): number {
  64. return this._left;
  65. }
  66. public set left(value: number) {
  67. let old = new Vector2(this._left, this._bottom);
  68. this._left = value;
  69. this.onPropertyChanged("_position", old, this._position);
  70. }
  71. @dependencyProperty(ContentControl.CONTENTCONTROL_PROPCOUNT + 1, pi => Window.bottomProperty = pi)
  72. public get bottom(): number {
  73. return this._bottom;
  74. }
  75. public set bottom(value: number) {
  76. let old = new Vector2(this._left, this._bottom);
  77. this._bottom = value;
  78. this.onPropertyChanged("_position", old, this._position);
  79. }
  80. @dependencyProperty(ContentControl.CONTENTCONTROL_PROPCOUNT + 2, pi => Window.positionProperty = pi)
  81. public get position(): Vector2 {
  82. return this._position;
  83. }
  84. public set position(value: Vector2) {
  85. this._left = value.x;
  86. this._bottom = value.y;
  87. }
  88. protected get _position(): Vector2 {
  89. return new Vector2(this.left, this.bottom);
  90. }
  91. protected createVisualTree() {
  92. super.createVisualTree();
  93. let p = this._visualPlaceholder;
  94. p.createSimpleDataBinding(Group2D.positionProperty, "position");
  95. }
  96. public _registerVisualToBuild(uiel: UIElement) {
  97. if (uiel._isFlagSet(UIElement.flagVisualToBuild)) {
  98. return;
  99. }
  100. if (!this._UIElementVisualToBuildList) {
  101. this._UIElementVisualToBuildList = new Array<UIElement>();
  102. }
  103. this._UIElementVisualToBuildList.push(uiel);
  104. uiel._setFlags(UIElement.flagVisualToBuild);
  105. }
  106. private _overPrimChanged(oldPrim: Prim2DBase, newPrim: Prim2DBase) {
  107. let curOverEl = this._mouseOverUIElement;
  108. let newOverEl: UIElement = null;
  109. let curGroup = newPrim ? newPrim.traverseUp(p => p instanceof Group2D) : null;
  110. while (curGroup) {
  111. let uiel = curGroup.getExternalData<UIElement>("_GUIOwnerElement_");
  112. if (uiel) {
  113. newOverEl = uiel;
  114. break;
  115. }
  116. curGroup = curGroup.parent ? curGroup.parent.traverseUp(p => p instanceof Group2D) : null;
  117. }
  118. if (curOverEl === newOverEl) {
  119. return;
  120. }
  121. if (curOverEl) {
  122. curOverEl.isMouseOver = false;
  123. }
  124. if (newOverEl) {
  125. newOverEl.isMouseOver = true;
  126. }
  127. this._mouseOverUIElement = newOverEl;
  128. }
  129. private _canvasPreRender() {
  130. // Check if we have visual to create
  131. if (this._UIElementVisualToBuildList.length > 0) {
  132. // Sort the UI Element to get the highest (so lowest hierarchy depth) in the hierarchy tree first
  133. let sortedElementList = this._UIElementVisualToBuildList.sort((a, b) => a.hierarchyDepth - b.hierarchyDepth);
  134. for (let el of sortedElementList) {
  135. el._createVisualTree();
  136. }
  137. this._UIElementVisualToBuildList.splice(0);
  138. }
  139. }
  140. private _canvasDisposed() {
  141. this._canvas.disposeObservable.remove(this._disposeObserver);
  142. this._canvas.renderObservable.remove(this._renderObserver);
  143. }
  144. private _canvas: Canvas2D;
  145. private _left: number;
  146. private _bottom: number;
  147. private _isWorldSpaceCanvas: boolean;
  148. private _renderObserver: Observer<Canvas2D>;
  149. private _disposeObserver: Observer<SmartPropertyBase>;
  150. private _UIElementVisualToBuildList: Array<UIElement>;
  151. private _mouseOverUIElement: UIElement;
  152. private static getScreenCanvas(scene: Scene): ScreenSpaceCanvas2D {
  153. let canvas = Tools.first(Window._screenCanvasList, c => c.scene === scene);
  154. if (canvas) {
  155. return canvas;
  156. }
  157. canvas = new ScreenSpaceCanvas2D(scene, { id: "GUI Canvas", cachingStrategy: Canvas2D.CACHESTRATEGY_DONTCACHE });
  158. Window._screenCanvasList.push(canvas);
  159. return canvas;
  160. }
  161. private static _screenCanvasList: Array<ScreenSpaceCanvas2D> = new Array<ScreenSpaceCanvas2D>();
  162. }
  163. @registerWindowRenderingTemplate("BABYLON.Window", "Default", () => new DefaultWindowRenderingTemplate ())
  164. export class DefaultWindowRenderingTemplate extends UIElementRenderingTemplateBase {
  165. createVisualTree(owner: UIElement, visualPlaceholder: Group2D): { root: Prim2DBase; contentPlaceholder: Prim2DBase } {
  166. let r = new Rectangle2D({ parent: visualPlaceholder, fill: "#808080FF" });
  167. return { root: r, contentPlaceholder: r };
  168. }
  169. }
  170. }