grid.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. /// <reference path="../../../../dist/preview release/babylon.d.ts"/>
  2. module BABYLON.GUI {
  3. /**
  4. * Class used to create a 2D grid container
  5. */
  6. export class Grid extends Container {
  7. private _rowDefinitions = new Array<ValueAndUnit>();
  8. private _columnDefinitions = new Array<ValueAndUnit>();
  9. private _cells: {[key: string]:Container} = {};
  10. private _childControls = new Array<Control>();
  11. /** Gets the list of children */
  12. public get children(): Control[] {
  13. return this._childControls;
  14. }
  15. /**
  16. * Adds a new row to the grid
  17. * @param height defines the height of the row (either in pixel or a value between 0 and 1)
  18. * @param isPixel defines if the height is expressed in pixel (or in percentage)
  19. * @returns the current grid
  20. */
  21. public addRowDefinition(height: number, isPixel = false): Grid {
  22. this._rowDefinitions.push(new ValueAndUnit(height, isPixel ? ValueAndUnit.UNITMODE_PIXEL : ValueAndUnit.UNITMODE_PERCENTAGE));
  23. this._markAsDirty();
  24. return this;
  25. }
  26. /**
  27. * Adds a new column to the grid
  28. * @param width defines the width of the column (either in pixel or a value between 0 and 1)
  29. * @param isPixel defines if the width is expressed in pixel (or in percentage)
  30. * @returns the current grid
  31. */
  32. public addColumnDefinition(width: number, isPixel = false): Grid {
  33. this._columnDefinitions.push(new ValueAndUnit(width, isPixel ? ValueAndUnit.UNITMODE_PIXEL : ValueAndUnit.UNITMODE_PERCENTAGE));
  34. this._markAsDirty();
  35. return this;
  36. }
  37. /**
  38. * Update a row definition
  39. * @param index defines the index of the row to update
  40. * @param height defines the height of the row (either in pixel or a value between 0 and 1)
  41. * @param isPixel defines if the weight is expressed in pixel (or in percentage)
  42. * @returns the current grid
  43. */
  44. public setRowDefinition(index: number, height: number, isPixel = false): Grid {
  45. if (index < 0 || index >= this._rowDefinitions.length) {
  46. return this;
  47. }
  48. this._rowDefinitions[index] = new ValueAndUnit(height,isPixel ? ValueAndUnit.UNITMODE_PIXEL : ValueAndUnit.UNITMODE_PERCENTAGE);
  49. this._markAsDirty();
  50. return this;
  51. }
  52. /**
  53. * Update a column definition
  54. * @param index defines the index of the column to update
  55. * @param width defines the width of the column (either in pixel or a value between 0 and 1)
  56. * @param isPixel defines if the width is expressed in pixel (or in percentage)
  57. * @returns the current grid
  58. */
  59. public setColumnDefinition(index: number, width: number, isPixel = false): Grid {
  60. if (index < 0 || index >= this._columnDefinitions.length) {
  61. return this;
  62. }
  63. this._columnDefinitions[index] = new ValueAndUnit(width, isPixel ? ValueAndUnit.UNITMODE_PIXEL : ValueAndUnit.UNITMODE_PERCENTAGE);
  64. this._markAsDirty();
  65. return this;
  66. }
  67. private _removeCell(cell: Container, key: string) {
  68. if (!cell) {
  69. return;
  70. }
  71. super.removeControl(cell);
  72. for (var control of cell.children) {
  73. let childIndex = this._childControls.indexOf(control);
  74. if (childIndex !== -1) {
  75. this._childControls.splice(childIndex, 1);
  76. }
  77. }
  78. delete this._cells[key];
  79. }
  80. private _offsetCell(previousKey: string, key: string) {
  81. if (!this._cells[key]) {
  82. return;
  83. }
  84. this._cells[previousKey] = this._cells[key];
  85. for (var control of this._cells[previousKey].children) {
  86. control._tag = previousKey;
  87. }
  88. delete this._cells[key];
  89. }
  90. /**
  91. * Remove a column definition at specified index
  92. * @param index defines the index of the column to remove
  93. * @returns the current grid
  94. */
  95. public removeColumnDefinition(index: number): Grid {
  96. if (index < 0 || index >= this._columnDefinitions.length) {
  97. return this;
  98. }
  99. for (var x = 0; x < this._rowDefinitions.length; x++) {
  100. let key = `${x}:${index}`;
  101. let cell = this._cells[key];
  102. this._removeCell(cell, key);
  103. }
  104. for (var x = 0; x < this._rowDefinitions.length; x++) {
  105. for (var y = index + 1; y < this._columnDefinitions.length; y++) {
  106. let previousKey = `${x}:${y - 1}`;
  107. let key = `${x}:${y}`;
  108. this._offsetCell(previousKey, key);
  109. }
  110. }
  111. this._columnDefinitions.splice(index, 1);
  112. this._markAsDirty();
  113. return this;
  114. }
  115. /**
  116. * Remove a row definition at specified index
  117. * @param index defines the index of the row to remove
  118. * @returns the current grid
  119. */
  120. public removeRowDefinition(index: number): Grid {
  121. if (index < 0 || index >= this._rowDefinitions.length) {
  122. return this;
  123. }
  124. for (var y = 0; y < this._columnDefinitions.length; y++) {
  125. let key = `${index}:${y}`;
  126. let cell = this._cells[key];
  127. this._removeCell(cell, key);
  128. }
  129. for (var y = 0; y < this._columnDefinitions.length; y++) {
  130. for (var x = index + 1; x < this._rowDefinitions.length; x++) {
  131. let previousKey = `${x - 1}:${y}`;
  132. let key = `${x}:${y}`;
  133. this._offsetCell(previousKey, key);
  134. }
  135. }
  136. this._rowDefinitions.splice(index, 1);
  137. this._markAsDirty();
  138. return this;
  139. }
  140. /**
  141. * Adds a new control to the current grid
  142. * @param control defines the control to add
  143. * @param row defines the row where to add the control (0 by default)
  144. * @param column defines the column where to add the control (0 by default)
  145. * @returns the current grid
  146. */
  147. public addControl(control: Control, row: number = 0, column: number = 0): Grid {
  148. if (this._rowDefinitions.length === 0) {
  149. // Add default row definition
  150. this.addRowDefinition(1, false);
  151. }
  152. if (this._columnDefinitions.length === 0) {
  153. // Add default column definition
  154. this.addColumnDefinition(1, false);
  155. }
  156. let x = Math.min(row, this._rowDefinitions.length - 1);
  157. let y = Math.min(column, this._columnDefinitions.length - 1);
  158. let key = `${x}:${y}`;
  159. let goodContainer = this._cells[key];
  160. if (!goodContainer) {
  161. goodContainer = new Container(key);
  162. this._cells[key] = goodContainer;
  163. goodContainer.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
  164. goodContainer.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
  165. super.addControl(goodContainer);
  166. }
  167. goodContainer.addControl(control);
  168. this._childControls.push(control);
  169. control._tag = key;
  170. this._markAsDirty();
  171. return this;
  172. }
  173. /**
  174. * Removes a control from the current container
  175. * @param control defines the control to remove
  176. * @returns the current container
  177. */
  178. public removeControl(control: Control): Container {
  179. var index = this._childControls.indexOf(control);
  180. if (index !== -1) {
  181. this._childControls.splice(index, 1);
  182. }
  183. let cell = this._cells[control._tag];
  184. if (cell) {
  185. cell.removeControl(control);
  186. }
  187. this._markAsDirty();
  188. return this;
  189. }
  190. /**
  191. * Creates a new Grid
  192. * @param name defines control name
  193. */
  194. constructor(public name?: string) {
  195. super(name);
  196. }
  197. protected _getTypeName(): string {
  198. return "Grid";
  199. }
  200. protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
  201. let widths = [];
  202. let heights = [];
  203. let lefts = [];
  204. let tops = [];
  205. let availableWidth = this._currentMeasure.width;
  206. let globalWidthPercentage = 0;
  207. let availableHeight = this._currentMeasure.height;
  208. let globalHeightPercentage = 0;
  209. // Heights
  210. let index = 0;
  211. for (var value of this._rowDefinitions) {
  212. if (value.isPixel) {
  213. let height = value.getValue(this._host);
  214. availableHeight -= height;
  215. heights[index] = height;
  216. } else {
  217. globalHeightPercentage += value.internalValue;
  218. }
  219. index++;
  220. }
  221. let top = 0;
  222. index = 0;
  223. for (var value of this._rowDefinitions) {
  224. tops.push(top);
  225. if (!value.isPixel) {
  226. let height = (value.internalValue / globalHeightPercentage) * availableHeight;
  227. top += height;
  228. heights[index] = height;
  229. } else {
  230. top += value.getValue(this._host);
  231. }
  232. index++;
  233. }
  234. // Widths
  235. index = 0;
  236. for (var value of this._columnDefinitions) {
  237. if (value.isPixel) {
  238. let width = value.getValue(this._host);
  239. availableWidth -= width;
  240. widths[index] = width;
  241. } else {
  242. globalWidthPercentage += value.internalValue;
  243. }
  244. index++;
  245. }
  246. let left = 0;
  247. index = 0;
  248. for (var value of this._columnDefinitions) {
  249. lefts.push(left);
  250. if (!value.isPixel) {
  251. let width = (value.internalValue / globalWidthPercentage) * availableWidth;
  252. left += width;
  253. widths[index] = width;
  254. } else {
  255. left += value.getValue(this._host);
  256. }
  257. index++;
  258. }
  259. // Setting child sizes
  260. for (var key in this._cells) {
  261. if (!this._cells.hasOwnProperty(key)) {
  262. continue;
  263. }
  264. let split = key.split(":");
  265. let x = parseInt(split[0]);
  266. let y = parseInt(split[1]);
  267. let cell = this._cells[key];
  268. cell.left = lefts[y] + "px";
  269. cell.top = tops[x] + "px";
  270. cell.width = widths[y] + "px";
  271. cell.height = heights[x] + "px";
  272. }
  273. super._additionalProcessing(parentMeasure, context);
  274. }
  275. /** Releases associated resources */
  276. public dispose() {
  277. super.dispose();
  278. for (var control of this._childControls) {
  279. control.dispose();
  280. }
  281. }
  282. }
  283. }