TabBar.ts 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. module INSPECTOR {
  2. /**
  3. * A tab bar will contains each view the inspector can have : Canvas2D, Meshes...
  4. * The default active tab is the first one of the list.
  5. */
  6. export class TabBar extends BasicElement {
  7. // The list of available tabs
  8. private _tabs: Array<Tab> = [];
  9. private _inspector: Inspector;
  10. /** The tab displaying all meshes */
  11. private _meshTab: MeshTab;
  12. /** The toolbar */
  13. private _toolBar: Toolbar;
  14. /** The icon displayed at the end of the toolbar displaying a combo box of tabs not displayed */
  15. private _moreTabsIcon: HTMLElement;
  16. /** The panel displayed when the 'more-tab' icon is selected */
  17. private _moreTabsPanel: HTMLElement;
  18. /** The list of tab displayed by clicking on the remainingIcon */
  19. private _invisibleTabs: Array<Tab> = [];
  20. /** The list of tabs visible, displayed in the tab bar */
  21. private _visibleTabs: Array<Tab> = [];
  22. constructor(inspector: Inspector, initialTab?: number) {
  23. super();
  24. this._inspector = inspector;
  25. this._tabs.push(new SceneTab(this, this._inspector));
  26. this._tabs.push(new ConsoleTab(this, this._inspector));
  27. this._tabs.push(new StatsTab(this, this._inspector));
  28. this._meshTab = new MeshTab(this, this._inspector);
  29. this._tabs.push(new TextureTab(this, this._inspector));
  30. this._tabs.push(this._meshTab);
  31. this._tabs.push(new ShaderTab(this, this._inspector));
  32. this._tabs.push(new LightTab(this, this._inspector));
  33. // Add only the tab canvas2D if Canvas2D is defined
  34. if (BABYLON.Canvas2D) {
  35. this._tabs.push(new Canvas2DTab(this, this._inspector));
  36. }
  37. this._tabs.push(new MaterialTab(this, this._inspector));
  38. this._tabs.push(new CameraTab(this, this._inspector));
  39. this._tabs.push(new SoundTab(this, this._inspector));
  40. this._toolBar = new Toolbar(this._inspector);
  41. this._build();
  42. //Check initialTab is defined and between tabs bounds
  43. if (!initialTab || initialTab < 0 || initialTab >= this._tabs.length) {
  44. initialTab = 0;
  45. console.warn('');
  46. }
  47. this._tabs[initialTab].active(true);
  48. // set all tab as visible
  49. for (let tab of this._tabs) {
  50. this._visibleTabs.push(tab);
  51. }
  52. }
  53. // No update
  54. public update() { }
  55. protected _build() {
  56. this._div.className = 'tabbar';
  57. this._div.appendChild(this._toolBar.toHtml());
  58. for (let tab of this._tabs) {
  59. this._div.appendChild(tab.toHtml());
  60. }
  61. this._moreTabsIcon = Helpers.CreateElement('i', 'fa fa-angle-double-right more-tabs');
  62. this._moreTabsPanel = Helpers.CreateDiv('more-tabs-panel');
  63. this._moreTabsIcon.addEventListener('click', () => {
  64. // Hide the 'more-tabs-panel' if already displayed
  65. if (this._moreTabsPanel.style.display == 'flex') {
  66. this._moreTabsPanel.style.display = 'none';
  67. } else {
  68. // Attach more-tabs-panel if not attached yet
  69. let topPanel = this._div.parentNode as HTMLElement;
  70. if (!topPanel.contains(this._moreTabsPanel)) {
  71. topPanel.appendChild(this._moreTabsPanel);
  72. }
  73. // Clean the 'more-tabs-panel'
  74. Helpers.CleanDiv(this._moreTabsPanel);
  75. // Add each invisible tabs to this panel
  76. for (let tab of this._invisibleTabs) {
  77. this._addInvisibleTabToPanel(tab);
  78. }
  79. // And display it
  80. this._moreTabsPanel.style.display = 'flex';
  81. }
  82. });
  83. }
  84. /**
  85. * Add a tab to the 'more-tabs' panel, displayed by clicking on the
  86. * 'more-tabs' icon
  87. */
  88. private _addInvisibleTabToPanel(tab: Tab) {
  89. let div = Helpers.CreateDiv('invisible-tab', this._moreTabsPanel);
  90. div.textContent = tab.name;
  91. div.addEventListener('click', () => {
  92. this._moreTabsPanel.style.display = 'none';
  93. this.switchTab(tab);
  94. });
  95. }
  96. /** Dispose the current tab, set the given tab as active, and refresh the treeview */
  97. public switchTab(tab: Tab) {
  98. // Dispose the active tab
  99. this.getActiveTab().dispose();
  100. // Deactivate all tabs
  101. for (let t of this._tabs) {
  102. t.active(false);
  103. }
  104. // activate the given tab
  105. tab.active(true);
  106. // Refresh the inspector
  107. this._inspector.refresh();
  108. }
  109. /** Display the mesh tab.
  110. * If a parameter is given, the given mesh details are displayed
  111. */
  112. public switchMeshTab(mesh?: BABYLON.AbstractMesh) {
  113. this.switchTab(this._meshTab);
  114. if (mesh) {
  115. let item = this._meshTab.getItemFor(mesh);
  116. this._meshTab.select(item);
  117. }
  118. }
  119. /** Returns the active tab */
  120. public getActiveTab(): Tab {
  121. for (let tab of this._tabs) {
  122. if (tab.isActive()) {
  123. return tab;
  124. }
  125. }
  126. }
  127. public get inspector(): Inspector {
  128. return this._inspector;
  129. }
  130. /**
  131. * Returns the total width in pixel of the tabbar,
  132. * that corresponds to the sum of the width of each visible tab + toolbar width
  133. */
  134. public getPixelWidth(): number {
  135. let sum = 0;
  136. for (let tab of this._visibleTabs) {
  137. sum += tab.getPixelWidth();
  138. }
  139. sum += this._toolBar.getPixelWidth();
  140. if (this._div.contains(this._moreTabsIcon)) {
  141. sum += 30; // $tabbarheight
  142. }
  143. return sum;
  144. }
  145. /** Display the remaining icon or not depending on the tabbar width.
  146. * This function should be called each time the inspector width is updated
  147. */
  148. public updateWidth() {
  149. let parentSize = this._div.parentElement.clientWidth;
  150. let lastTabWidth = 75;
  151. let currentSize = this.getPixelWidth();
  152. // Check if a tab should be removed : if the tab bar width is greater than
  153. // its parent width
  154. while (this._visibleTabs.length > 0 && currentSize > parentSize) {
  155. // Start by the last element
  156. let tab = this._visibleTabs.pop();
  157. // set it invisible
  158. this._invisibleTabs.push(tab);
  159. // and removes it from the DOM
  160. this._div.removeChild(tab.toHtml());
  161. currentSize = this.getPixelWidth() + lastTabWidth;
  162. }
  163. // Check if a tab can be added to the tab bar : if the tab bar width
  164. // + 100 (at least 100px is needed to add a tab) is less than its parent width
  165. if (this._invisibleTabs.length > 0) {
  166. if (currentSize + lastTabWidth < parentSize) {
  167. let lastTab = this._invisibleTabs.pop();
  168. this._div.appendChild(lastTab.toHtml());
  169. this._visibleTabs.push(lastTab);
  170. // Update more-tab icon in last position if needed
  171. if (this._div.contains(this._moreTabsIcon)) {
  172. this._div.removeChild(this._moreTabsIcon);
  173. }
  174. }
  175. }
  176. if (this._invisibleTabs.length > 0 && !this._div.contains(this._moreTabsIcon)) {
  177. this._div.appendChild(this._moreTabsIcon);
  178. }
  179. }
  180. }
  181. }