selector.ts 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. import { Rectangle } from "./rectangle";
  2. import { StackPanel } from "./stackPanel";
  3. import { Control } from "./control";
  4. import { TextBlock } from "./textBlock";
  5. import { Checkbox } from "./checkbox";
  6. import { RadioButton } from "./radioButton";
  7. import { Slider } from "./sliders/slider";
  8. import { Container } from "./container";
  9. /** Class used to create a RadioGroup
  10. * which contains groups of radio buttons
  11. */
  12. export class SelectorGroup {
  13. private _groupPanel = new StackPanel();
  14. private _selectors: StackPanel[] = new Array();
  15. private _groupHeader: TextBlock;
  16. /**
  17. * Creates a new SelectorGroup
  18. * @param name of group, used as a group heading
  19. */
  20. constructor(
  21. /** name of SelectorGroup */
  22. public name: string) {
  23. this._groupPanel.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
  24. this._groupPanel.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
  25. this._groupHeader = this._addGroupHeader(name);
  26. }
  27. /** Gets the groupPanel of the SelectorGroup */
  28. public get groupPanel(): StackPanel {
  29. return this._groupPanel;
  30. }
  31. /** Gets the selectors array */
  32. public get selectors(): StackPanel[] {
  33. return this._selectors;
  34. }
  35. /** Gets and sets the group header */
  36. public get header() {
  37. return this._groupHeader.text;
  38. }
  39. public set header(label: string) {
  40. if (this._groupHeader.text === "label") {
  41. return;
  42. }
  43. this._groupHeader.text = label;
  44. }
  45. /** @hidden */
  46. private _addGroupHeader(text: string): TextBlock {
  47. var groupHeading = new TextBlock("groupHead", text);
  48. groupHeading.width = 0.9;
  49. groupHeading.height = "30px";
  50. groupHeading.textWrapping = true;
  51. groupHeading.color = "black";
  52. groupHeading.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
  53. groupHeading.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
  54. groupHeading.left = "2px";
  55. this._groupPanel.addControl(groupHeading);
  56. return groupHeading;
  57. }
  58. /** @hidden*/
  59. public _getSelector(selectorNb: number) {
  60. if (selectorNb < 0 || selectorNb >= this._selectors.length) {
  61. return;
  62. }
  63. return this._selectors[selectorNb];
  64. }
  65. /** Removes the selector at the given position
  66. * @param selectorNb the position of the selector within the group
  67. */
  68. public removeSelector(selectorNb: number) {
  69. if (selectorNb < 0 || selectorNb >= this._selectors.length) {
  70. return;
  71. }
  72. this._groupPanel.removeControl(this._selectors[selectorNb]);
  73. this._selectors.splice(selectorNb, 1);
  74. }
  75. }
  76. /** Class used to create a CheckboxGroup
  77. * which contains groups of checkbox buttons
  78. */
  79. export class CheckboxGroup extends SelectorGroup {
  80. /** Adds a checkbox as a control
  81. * @param text is the label for the selector
  82. * @param func is the function called when the Selector is checked
  83. * @param checked is true when Selector is checked
  84. */
  85. public addCheckbox(text: string, func = (s: boolean) => { }, checked: boolean = false): void {
  86. var checked = checked || false;
  87. var button = new Checkbox();
  88. button.width = "20px";
  89. button.height = "20px";
  90. button.color = "#364249";
  91. button.background = "#CCCCCC";
  92. button.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
  93. button.onIsCheckedChangedObservable.add(function(state) {
  94. func(state);
  95. });
  96. var _selector = Control.AddHeader(button, text, "200px", { isHorizontal: true, controlFirst: true });
  97. _selector.height = "30px";
  98. _selector.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
  99. _selector.left = "4px";
  100. this.groupPanel.addControl(_selector);
  101. this.selectors.push(_selector);
  102. button.isChecked = checked;
  103. if (this.groupPanel.parent && this.groupPanel.parent.parent) {
  104. button.color = (<SelectionPanel>this.groupPanel.parent.parent).buttonColor;
  105. button.background = (<SelectionPanel>this.groupPanel.parent.parent).buttonBackground;
  106. }
  107. }
  108. /** @hidden */
  109. public _setSelectorLabel(selectorNb: number, label: string) {
  110. (<TextBlock>this.selectors[selectorNb].children[1]).text = label;
  111. }
  112. /** @hidden */
  113. public _setSelectorLabelColor(selectorNb: number, color: string) {
  114. (<TextBlock>this.selectors[selectorNb].children[1]).color = color;
  115. }
  116. /** @hidden */
  117. public _setSelectorButtonColor(selectorNb: number, color: string) {
  118. this.selectors[selectorNb].children[0].color = color;
  119. }
  120. /** @hidden */
  121. public _setSelectorButtonBackground(selectorNb: number, color: string) {
  122. (<Checkbox>this.selectors[selectorNb].children[0]).background = color;
  123. }
  124. }
  125. /** Class used to create a RadioGroup
  126. * which contains groups of radio buttons
  127. */
  128. export class RadioGroup extends SelectorGroup {
  129. private _selectNb = 0;
  130. /** Adds a radio button as a control
  131. * @param label is the label for the selector
  132. * @param func is the function called when the Selector is checked
  133. * @param checked is true when Selector is checked
  134. */
  135. public addRadio(label: string, func = (n: number) => { }, checked = false): void {
  136. var nb = this._selectNb++;
  137. var button = new RadioButton();
  138. button.name = label;
  139. button.width = "20px";
  140. button.height = "20px";
  141. button.color = "#364249";
  142. button.background = "#CCCCCC";
  143. button.group = this.name;
  144. button.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
  145. button.onIsCheckedChangedObservable.add(function(state) {
  146. if (state) {
  147. func(nb);
  148. }
  149. });
  150. var _selector = Control.AddHeader(button, label, "200px", { isHorizontal: true, controlFirst: true });
  151. _selector.height = "30px";
  152. _selector.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
  153. _selector.left = "4px";
  154. this.groupPanel.addControl(_selector);
  155. this.selectors.push(_selector);
  156. button.isChecked = checked;
  157. if (this.groupPanel.parent && this.groupPanel.parent.parent) {
  158. button.color = (<SelectionPanel>this.groupPanel.parent.parent).buttonColor;
  159. button.background = (<SelectionPanel>this.groupPanel.parent.parent).buttonBackground;
  160. }
  161. }
  162. /** @hidden */
  163. public _setSelectorLabel(selectorNb: number, label: string) {
  164. (<TextBlock>this.selectors[selectorNb].children[1]).text = label;
  165. }
  166. /** @hidden */
  167. public _setSelectorLabelColor(selectorNb: number, color: string) {
  168. (<TextBlock>this.selectors[selectorNb].children[1]).color = color;
  169. }
  170. /** @hidden */
  171. public _setSelectorButtonColor(selectorNb: number, color: string) {
  172. this.selectors[selectorNb].children[0].color = color;
  173. }
  174. /** @hidden */
  175. public _setSelectorButtonBackground(selectorNb: number, color: string) {
  176. (<RadioButton>this.selectors[selectorNb].children[0]).background = color;
  177. }
  178. }
  179. /** Class used to create a SliderGroup
  180. * which contains groups of slider buttons
  181. */
  182. export class SliderGroup extends SelectorGroup {
  183. /**
  184. * Adds a slider to the SelectorGroup
  185. * @param label is the label for the SliderBar
  186. * @param func is the function called when the Slider moves
  187. * @param unit is a string describing the units used, eg degrees or metres
  188. * @param min is the minimum value for the Slider
  189. * @param max is the maximum value for the Slider
  190. * @param value is the start value for the Slider between min and max
  191. * @param onValueChange is the function used to format the value displayed, eg radians to degrees
  192. */
  193. public addSlider(label: string, func = (v: number) => { }, unit: string = "Units", min: number = 0, max: number = 0, value: number = 0, onValueChange = (v: number) => { return v | 0; }): void {
  194. var button = new Slider();
  195. button.name = unit;
  196. button.value = value;
  197. button.minimum = min;
  198. button.maximum = max;
  199. button.width = 0.9;
  200. button.height = "20px";
  201. button.color = "#364249";
  202. button.background = "#CCCCCC";
  203. button.borderColor = "black";
  204. button.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
  205. button.left = "4px";
  206. button.paddingBottom = "4px";
  207. button.onValueChangedObservable.add(function(value) {
  208. (<TextBlock>button.parent!.children[0]).text = button.parent!.children[0].name + ": " + onValueChange(value) + " " + button.name;
  209. func(value);
  210. });
  211. var _selector = Control.AddHeader(button, label + ": " + onValueChange(value) + " " + unit, "30px", { isHorizontal: false, controlFirst: false });
  212. _selector.height = "60px";
  213. _selector.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
  214. _selector.left = "4px";
  215. _selector.children[0].name = label;
  216. this.groupPanel.addControl(_selector);
  217. this.selectors.push(_selector);
  218. if (this.groupPanel.parent && this.groupPanel.parent.parent) {
  219. button.color = (<SelectionPanel>this.groupPanel.parent.parent).buttonColor;
  220. button.background = (<SelectionPanel>this.groupPanel.parent.parent).buttonBackground;
  221. }
  222. }
  223. /** @hidden */
  224. public _setSelectorLabel(selectorNb: number, label: string) {
  225. this.selectors[selectorNb].children[0].name = label;
  226. (<TextBlock>this.selectors[selectorNb].children[0]).text = label + ": " + (<Slider>this.selectors[selectorNb].children[1]).value + " " + this.selectors[selectorNb].children[1].name;
  227. }
  228. /** @hidden */
  229. public _setSelectorLabelColor(selectorNb: number, color: string) {
  230. (<TextBlock>this.selectors[selectorNb].children[0]).color = color;
  231. }
  232. /** @hidden */
  233. public _setSelectorButtonColor(selectorNb: number, color: string) {
  234. this.selectors[selectorNb].children[1].color = color;
  235. }
  236. /** @hidden */
  237. public _setSelectorButtonBackground(selectorNb: number, color: string) {
  238. (<Slider>this.selectors[selectorNb].children[1]).background = color;
  239. }
  240. }
  241. /** Class used to hold the controls for the checkboxes, radio buttons and sliders
  242. * @see https://doc.babylonjs.com/how_to/selector
  243. */
  244. export class SelectionPanel extends Rectangle {
  245. private _panel: StackPanel;
  246. private _buttonColor: string = "#364249";
  247. private _buttonBackground: string = "#CCCCCC";
  248. private _headerColor: string = "black";
  249. private _barColor: string = "white";
  250. private _barHeight: string = "2px";
  251. private _spacerHeight: string = "20px";
  252. private _labelColor: string;
  253. private _groups: SelectorGroup[];
  254. private _bars: any[] = new Array();
  255. /**
  256. * Creates a new SelectionPanel
  257. * @param name of SelectionPanel
  258. * @param groups is an array of SelectionGroups
  259. */
  260. constructor(
  261. /** name of SelectionPanel */
  262. public name: string,
  263. /** an array of SelectionGroups */
  264. public groups: SelectorGroup[] = []) {
  265. super(name);
  266. this._groups = groups;
  267. this.thickness = 2;
  268. this._panel = new StackPanel();
  269. this._panel.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
  270. this._panel.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
  271. this._panel.top = 5;
  272. this._panel.left = 5;
  273. this._panel.width = 0.95;
  274. if (groups.length > 0) {
  275. for (var i = 0; i < groups.length - 1; i++) {
  276. this._panel.addControl(groups[i].groupPanel);
  277. this._addSpacer();
  278. }
  279. this._panel.addControl(groups[groups.length - 1].groupPanel);
  280. }
  281. this.addControl(this._panel);
  282. }
  283. protected _getTypeName(): string {
  284. return "SelectionPanel";
  285. }
  286. /** Gets the (stack) panel of the SelectionPanel */
  287. public get panel(): StackPanel {
  288. return this._panel;
  289. }
  290. /** Gets or sets the headerColor */
  291. public get headerColor(): string {
  292. return this._headerColor;
  293. }
  294. public set headerColor(color: string) {
  295. if (this._headerColor === color) {
  296. return;
  297. }
  298. this._headerColor = color;
  299. this._setHeaderColor();
  300. }
  301. private _setHeaderColor() {
  302. for (var i = 0; i < this._groups.length; i++) {
  303. this._groups[i].groupPanel.children[0].color = this._headerColor;
  304. }
  305. }
  306. /** Gets or sets the button color */
  307. public get buttonColor(): string {
  308. return this._buttonColor;
  309. }
  310. public set buttonColor(color: string) {
  311. if (this._buttonColor === color) {
  312. return;
  313. }
  314. this._buttonColor = color;
  315. this._setbuttonColor();
  316. }
  317. private _setbuttonColor() {
  318. for (var i = 0; i < this._groups.length; i++) {
  319. for (var j = 0; j < this._groups[i].selectors.length; j++) {
  320. (<CheckboxGroup | RadioGroup | SliderGroup>this._groups[i])._setSelectorButtonColor(j, this._buttonColor);
  321. }
  322. }
  323. }
  324. /** Gets or sets the label color */
  325. public get labelColor(): string {
  326. return this._labelColor;
  327. }
  328. public set labelColor(color: string) {
  329. if (this._labelColor === color) {
  330. return;
  331. }
  332. this._labelColor = color;
  333. this._setLabelColor();
  334. }
  335. private _setLabelColor() {
  336. for (var i = 0; i < this._groups.length; i++) {
  337. for (var j = 0; j < this._groups[i].selectors.length; j++) {
  338. (<CheckboxGroup | RadioGroup | SliderGroup>this._groups[i])._setSelectorLabelColor(j, this._labelColor);
  339. }
  340. }
  341. }
  342. /** Gets or sets the button background */
  343. public get buttonBackground(): string {
  344. return this._buttonBackground;
  345. }
  346. public set buttonBackground(color: string) {
  347. if (this._buttonBackground === color) {
  348. return;
  349. }
  350. this._buttonBackground = color;
  351. this._setButtonBackground();
  352. }
  353. private _setButtonBackground() {
  354. for (var i = 0; i < this._groups.length; i++) {
  355. for (var j = 0; j < this._groups[i].selectors.length; j++) {
  356. (<CheckboxGroup | RadioGroup | SliderGroup>this._groups[i])._setSelectorButtonBackground(j, this._buttonBackground);
  357. }
  358. }
  359. }
  360. /** Gets or sets the color of separator bar */
  361. public get barColor(): string {
  362. return this._barColor;
  363. }
  364. public set barColor(color: string) {
  365. if (this._barColor === color) {
  366. return;
  367. }
  368. this._barColor = color;
  369. this._setBarColor();
  370. }
  371. private _setBarColor() {
  372. for (var i = 0; i < this._bars.length; i++) {
  373. this._bars[i].children[0].background = this._barColor;
  374. }
  375. }
  376. /** Gets or sets the height of separator bar */
  377. public get barHeight(): string {
  378. return this._barHeight;
  379. }
  380. public set barHeight(value: string) {
  381. if (this._barHeight === value) {
  382. return;
  383. }
  384. this._barHeight = value;
  385. this._setBarHeight();
  386. }
  387. private _setBarHeight() {
  388. for (var i = 0; i < this._bars.length; i++) {
  389. this._bars[i].children[0].height = this._barHeight;
  390. }
  391. }
  392. /** Gets or sets the height of spacers*/
  393. public get spacerHeight(): string {
  394. return this._spacerHeight;
  395. }
  396. public set spacerHeight(value: string) {
  397. if (this._spacerHeight === value) {
  398. return;
  399. }
  400. this._spacerHeight = value;
  401. this._setSpacerHeight();
  402. }
  403. private _setSpacerHeight() {
  404. for (var i = 0; i < this._bars.length; i++) {
  405. this._bars[i].height = this._spacerHeight;
  406. }
  407. }
  408. /** Adds a bar between groups */
  409. private _addSpacer(): void {
  410. var separator = new Container();
  411. separator.width = 1;
  412. separator.height = this._spacerHeight;
  413. separator.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
  414. var bar = new Rectangle();
  415. bar.width = 1;
  416. bar.height = this._barHeight;
  417. bar.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
  418. bar.verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
  419. bar.background = this._barColor;
  420. bar.color = "transparent";
  421. separator.addControl(bar);
  422. this._panel.addControl(separator);
  423. this._bars.push(separator);
  424. }
  425. /** Add a group to the selection panel
  426. * @param group is the selector group to add
  427. */
  428. public addGroup(group: SelectorGroup): void {
  429. if (this._groups.length > 0) {
  430. this._addSpacer();
  431. }
  432. this._panel.addControl(group.groupPanel);
  433. this._groups.push(group);
  434. group.groupPanel.children[0].color = this._headerColor;
  435. for (var j = 0; j < group.selectors.length; j++) {
  436. (<CheckboxGroup | RadioGroup | SliderGroup>group)._setSelectorButtonColor(j, this._buttonColor);
  437. (<CheckboxGroup | RadioGroup | SliderGroup>group)._setSelectorButtonBackground(j, this._buttonBackground);
  438. }
  439. }
  440. /** Remove the group from the given position
  441. * @param groupNb is the position of the group in the list
  442. */
  443. public removeGroup(groupNb: number): void {
  444. if (groupNb < 0 || groupNb >= this._groups.length) {
  445. return;
  446. }
  447. var group = this._groups[groupNb];
  448. this._panel.removeControl(group.groupPanel);
  449. this._groups.splice(groupNb, 1);
  450. if (groupNb < this._bars.length) {
  451. this._panel.removeControl(this._bars[groupNb]);
  452. this._bars.splice(groupNb, 1);
  453. }
  454. }
  455. /** Change a group header label
  456. * @param label is the new group header label
  457. * @param groupNb is the number of the group to relabel
  458. * */
  459. public setHeaderName(label: string, groupNb: number) {
  460. if (groupNb < 0 || groupNb >= this._groups.length) {
  461. return;
  462. }
  463. var group = this._groups[groupNb];
  464. (<TextBlock>group.groupPanel.children[0]).text = label;
  465. }
  466. /** Change selector label to the one given
  467. * @param label is the new selector label
  468. * @param groupNb is the number of the groupcontaining the selector
  469. * @param selectorNb is the number of the selector within a group to relabel
  470. * */
  471. public relabel(label: string, groupNb: number, selectorNb: number): void {
  472. if (groupNb < 0 || groupNb >= this._groups.length) {
  473. return;
  474. }
  475. var group = this._groups[groupNb];
  476. if (selectorNb < 0 || selectorNb >= group.selectors.length) {
  477. return;
  478. }
  479. (<CheckboxGroup | RadioGroup | SliderGroup>group)._setSelectorLabel(selectorNb, label);
  480. }
  481. /** For a given group position remove the selector at the given position
  482. * @param groupNb is the number of the group to remove the selector from
  483. * @param selectorNb is the number of the selector within the group
  484. */
  485. public removeFromGroupSelector(groupNb: number, selectorNb: number): void {
  486. if (groupNb < 0 || groupNb >= this._groups.length) {
  487. return;
  488. }
  489. var group = this._groups[groupNb];
  490. if (selectorNb < 0 || selectorNb >= group.selectors.length) {
  491. return;
  492. }
  493. group.removeSelector(selectorNb);
  494. }
  495. /** For a given group position of correct type add a checkbox button
  496. * @param groupNb is the number of the group to remove the selector from
  497. * @param label is the label for the selector
  498. * @param func is the function called when the Selector is checked
  499. * @param checked is true when Selector is checked
  500. */
  501. public addToGroupCheckbox(groupNb: number, label: string, func = () => { }, checked: boolean = false): void {
  502. if (groupNb < 0 || groupNb >= this._groups.length) {
  503. return;
  504. }
  505. var group = this._groups[groupNb];
  506. (<CheckboxGroup>group).addCheckbox(label, func, checked);
  507. }
  508. /** For a given group position of correct type add a radio button
  509. * @param groupNb is the number of the group to remove the selector from
  510. * @param label is the label for the selector
  511. * @param func is the function called when the Selector is checked
  512. * @param checked is true when Selector is checked
  513. */
  514. public addToGroupRadio(groupNb: number, label: string, func = () => { }, checked: boolean = false): void {
  515. if (groupNb < 0 || groupNb >= this._groups.length) {
  516. return;
  517. }
  518. var group = this._groups[groupNb];
  519. (<RadioGroup>group).addRadio(label, func, checked);
  520. }
  521. /**
  522. * For a given slider group add a slider
  523. * @param groupNb is the number of the group to add the slider to
  524. * @param label is the label for the Slider
  525. * @param func is the function called when the Slider moves
  526. * @param unit is a string describing the units used, eg degrees or metres
  527. * @param min is the minimum value for the Slider
  528. * @param max is the maximum value for the Slider
  529. * @param value is the start value for the Slider between min and max
  530. * @param onVal is the function used to format the value displayed, eg radians to degrees
  531. */
  532. public addToGroupSlider(groupNb: number, label: string, func = () => { }, unit: string = "Units", min: number = 0, max: number = 0, value: number = 0, onVal = (v: number) => { return v | 0; }): void {
  533. if (groupNb < 0 || groupNb >= this._groups.length) {
  534. return;
  535. }
  536. var group = this._groups[groupNb];
  537. (<SliderGroup>group).addSlider(label, func, unit, min, max, value, onVal);
  538. }
  539. }