/gui/window.d

http://github.com/wilkie/djehuty · D · 1068 lines · 643 code · 228 blank · 197 comment · 129 complexity · b3a55e775f35bc0cb0e3154e8e05db21 MD5 · raw file

  1. /*
  2. * window.d
  3. *
  4. * This module implements a GUI Window class. Widgets can be pushed to this window.
  5. *
  6. * Author: Dave Wilkinson
  7. * Originated: June 24th, 2009
  8. *
  9. */
  10. module gui.window;
  11. import gui.widget;
  12. import gui.application;
  13. import resource.menu;
  14. import platform.vars.view;
  15. import platform.vars.menu;
  16. import platform.vars.window;
  17. import scaffold.color;
  18. import scaffold.window;
  19. import scaffold.view;
  20. import scaffold.menu;
  21. import graphics.view;
  22. import graphics.graphics;
  23. import core.definitions;
  24. import core.color;
  25. import core.string;
  26. import core.event;
  27. import core.main;
  28. import core.system;
  29. import interfaces.container;
  30. import binding.c;
  31. // Description: This class implements and abstracts a common window. This window is a control container and a view canvas.
  32. class Window : Responder, AbstractContainer {
  33. public:
  34. // Constructors
  35. // Description: Will create the window with certain default parameters
  36. // windowTitle: The initial title for the window.
  37. // windowStyle: The initial style for the window.
  38. // color: The initial color for the window.
  39. // x: The initial x position of the window.
  40. // y: The initial y position of the window.
  41. // width: The initial width of the client area of the window.
  42. // height: The initial height of the client area of the window.
  43. this(string windowTitle, WindowStyle windowStyle, Color color, int x, int y, int width, int height) {
  44. _color = color;
  45. _window_title = windowTitle.dup;
  46. _width = width;
  47. _height = height;
  48. _x = x;
  49. _y = y;
  50. _style = windowStyle;
  51. _position = WindowPosition.User;
  52. }
  53. // Description: Will create the window with certain default parameters
  54. // windowTitle: The initial title for the window.
  55. // windowStyle: The initial style for the window.
  56. // sysColor: The initial color for the window which is taken from a platform color setting.
  57. // x: The initial x position of the window.
  58. // y: The initial y position of the window.
  59. // width: The initial width of the client area of the window.
  60. // height: The initial height of the client area of the window.
  61. this(string windowTitle, WindowStyle windowStyle, SystemColor sysColor, int x, int y, int width, int height) {
  62. ColorGetSystemColor(_color, sysColor);
  63. _window_title = windowTitle.dup;
  64. _width = width;
  65. _height = height;
  66. _x = x;
  67. _y = y;
  68. _style = windowStyle;
  69. _position = WindowPosition.User;
  70. }
  71. this(string windowTitle, WindowStyle windowStyle, Color color, WindowPosition pos, int width, int height) {
  72. _color = color;
  73. _window_title = windowTitle.dup;
  74. _width = width;
  75. _height = height;
  76. _position = pos;
  77. _style = windowStyle;
  78. }
  79. this(string windowTitle, WindowStyle windowStyle, SystemColor sysColor, WindowPosition pos, int width, int height) {
  80. ColorGetSystemColor(_color, sysColor);
  81. _window_title = windowTitle.dup;
  82. _width = width;
  83. _height = height;
  84. _position = pos;
  85. _style = windowStyle;
  86. }
  87. ~this() {
  88. uninitialize();
  89. remove();
  90. }
  91. // Properties
  92. // Widget Container Margins
  93. int baseLeft() {
  94. return 0;
  95. }
  96. int baseTop() {
  97. return 0;
  98. }
  99. // Methods //
  100. // Description: Will get the title of the window.
  101. // Returns: The string representing the title.
  102. string text() {
  103. return _window_title.dup;
  104. }
  105. // Description: Will set the title of the window.
  106. // str: The new title.
  107. void text(string str) {
  108. _window_title = str.dup;
  109. if (!_inited) { return; }
  110. WindowSetTitle(this, &_pfvars);
  111. }
  112. Window nextWindow() {
  113. return _nextWindow;
  114. }
  115. // Description: Sets the flag to make the window hidden or visible.
  116. // bShow: Pass true to show the window and false to hide it.
  117. void visible(bool bShow) {
  118. if (_visible == bShow) { return; }
  119. _visible = !_visible;
  120. if (_inited) {
  121. GuiApplication app = cast(GuiApplication)responder;
  122. if (!_visible) {
  123. app._windowVisibleCount--;
  124. }
  125. else {
  126. app._windowVisibleCount++;
  127. }
  128. WindowSetVisible(this, &_pfvars, bShow);
  129. // safe guard:
  130. // fights off infection from ZOMBIE PROCESSES!!!
  131. if (app.isZombie()) {
  132. app.destroyAllWindows();
  133. app.exit(0);
  134. }
  135. }
  136. onVisibilityChange();
  137. }
  138. // Description: Will return whether or not the window is flagged as hidden or visible. The window may not actually be visible due to it not being created or added.
  139. // Returns: It will return true when the window is flagged to be visible and false otherwise.
  140. bool visible() {
  141. return _visible;
  142. }
  143. // Description: Will set the window to take a different state: WindowState.Minimized, WindowState.Maximized, WindowState.Fullscreen, WindowState.Normal
  144. // state: A WindowState value representing the new state.
  145. void state(WindowState state) {
  146. if (_state == state) { return; }
  147. _state = state;
  148. if (_nextWindow !is null) {
  149. WindowSetState(this, &_pfvars);
  150. }
  151. onStateChange();
  152. }
  153. // Description: Will return the current state of the window.
  154. // Returns: The current WindowState value for the window.
  155. WindowState state() {
  156. return _state;
  157. }
  158. // Description: Will set the window to take a different style: WindowStyle.Fixed (non-sizable), WindowStyle.Sizable (resizable window), WindowStyle.Popup (borderless).
  159. // style: A WindowStyle value representing the new style.
  160. void style(WindowStyle style) {
  161. if (this.state == WindowState.Fullscreen)
  162. { return; }
  163. _style = style;
  164. if (_nextWindow !is null) {
  165. WindowSetStyle(this, &_pfvars);
  166. }
  167. }
  168. // Description: Will return the current style of the window.
  169. // Returns: The current WindowStyle value for the window.
  170. WindowStyle style() {
  171. return _style;
  172. }
  173. // Description: Will return the width of the client area of the window.
  174. // Returns: The width of the client area of the window.
  175. uint width() {
  176. if (_state == WindowState.Fullscreen) {
  177. return System.Display.width;
  178. }
  179. return _width;
  180. }
  181. // Description: Will return the height of the client area of the window.
  182. // Returns: The height of the client area of the window.
  183. uint height() {
  184. if (_state == WindowState.Fullscreen) {
  185. return System.Display.height;
  186. }
  187. return _height;
  188. }
  189. // Description: Will return the x coordinate of the window's position in screen coordinates. Note that this is not the client area, but rather the whole window.
  190. // Returns: The x position of the top-left corner of the window.
  191. uint x() {
  192. if (_state == WindowState.Fullscreen) {
  193. return 0;
  194. }
  195. return _x;
  196. }
  197. // Description: Will return the y coordinate of the window's position in screen coordinates. Note that this is not the client area, but rather the whole window.
  198. // Returns: The y position of the top-left corner of the window.
  199. uint y() {
  200. if (_state == WindowState.Fullscreen) {
  201. return 0;
  202. }
  203. return _y;
  204. }
  205. // Methods
  206. // Description: Will attempt to destroy the window and its children. It will be removed from the hierarchy.
  207. void remove() {
  208. if (!_inited) { return; }
  209. // the window was added
  210. // destroy
  211. // TODO: Fire the event, and allow confirmation
  212. // TODO: Add a FORCE DESTROY function method
  213. _inited = false;
  214. WindowDestroy(this, &_pfvars);
  215. }
  216. // Description: This function will Size the window to fit a client area with the dimensions given by width and height.
  217. // width: The new width of the client area.
  218. // height: The new height of the client area.
  219. void resize(uint width, uint height) {
  220. _width = width;
  221. _height = height;
  222. if (_inited) {
  223. WindowRebound(this, &_pfvars);
  224. }
  225. onResize();
  226. }
  227. // Description: This function will move the window so that the top-left corner of the window (not client area) is set to the point (x,y).
  228. // x: The new x coordinate of the top-left corner.
  229. // y: The new y coordinate of the top-left corner.
  230. void move(uint x, uint y) {
  231. _x = x;
  232. _y = y;
  233. if (_inited) {
  234. WindowReposition(this, &_pfvars);
  235. }
  236. onMove();
  237. }
  238. void ClientToScreen(ref int x, ref int y) {
  239. if (_inited == false) { return; }
  240. WindowClientToScreen(this, &_pfvars, x, y);
  241. }
  242. void ClientToScreen(ref Coord pt) {
  243. if (_inited == false) { return; }
  244. WindowClientToScreen(this, &_pfvars, pt);
  245. }
  246. void ClientToScreen(ref Rect rt) {
  247. if (_inited == false) { return; }
  248. WindowClientToScreen(this, &_pfvars, rt);
  249. }
  250. Window parent() {
  251. return _parent;
  252. }
  253. // add a child window to this window
  254. void addWindow(Window window) {
  255. /*
  256. if (_inited == false) { return; }
  257. // add the window to the root window list
  258. UpdateWindowList(window);
  259. // mark the parent
  260. window._parent = this;
  261. UpdateChildWindowList(window);
  262. // add one to the window count
  263. ApplicationPlusWindow(cast(GuiApplication)Djehuty.app);
  264. // add one to the child window count
  265. _numChildren++;
  266. // create the window via platform calls
  267. WindowCreate(this, &this._pfvars, window, window._pfvars);
  268. // create the window's view object
  269. window.onInitialize();
  270. // call the onAdd event of the new window
  271. window.onAdd();*/
  272. //PrintChildWindowList(this);
  273. }
  274. // Events //
  275. // Description: This event will be called when the window is added to the window hierarchy.
  276. void onAdd() {
  277. }
  278. // Description: This event will be called when the window is removed from the window hierarchy.
  279. void onRemove() {
  280. }
  281. // Description: This event is called when the mouse wheel is scrolled vertically (the common scroll method).
  282. // amount: the number of standard 'ticks' that the scroll wheel makes
  283. void onMouseWheelY(uint amount) {
  284. }
  285. // Description: This event is called when the mouse wheel is scrolled horizontally.
  286. // amount: the number of standard 'ticks' that the scroll wheel makes
  287. void onMouseWheelX(uint amount) {
  288. }
  289. // Description: This event is called when the mouse enters the client area of the window
  290. void onMouseEnter() {
  291. }
  292. // Description: This event is called when the window is moved, either from the OS or the move() function.
  293. void onMove() {
  294. }
  295. // Description: This event is called when the window is hidden or shown.
  296. void onVisibilityChange() {
  297. }
  298. // Description: This event is called when the window is maximized, minimized, put into fullscreen, or restored.
  299. void onStateChange() {
  300. }
  301. // Description: This event is called when a menu item belonging to the window is activated.
  302. // mnu: A reference to the menu that was activated.
  303. void onMenu(Menu mnu) {
  304. }
  305. void onInitialize() {
  306. _view = new WindowView;
  307. _viewVars = _view.createForWindow(this, &_pfvars);
  308. }
  309. void onUninitialize() {
  310. _view.destroy();
  311. _view = null;
  312. }
  313. void onDraw() {
  314. if (_view !is null) {
  315. Graphics g = _view.lock();
  316. WindowStartDraw(this, &_pfvars, _view, *_viewVars);
  317. Brush brush = new Brush(this.color);
  318. Pen pen = new Pen(Color.Black);
  319. g.brush = brush;
  320. g.pen = pen;
  321. g.fillRect(0,0,this.width,this.height);
  322. brush = new Brush(Color.White);
  323. g.brush = brush;
  324. Widget c = _firstControl;
  325. if (c !is null) {
  326. do {
  327. c = c._prevControl;
  328. c.onDraw(g);
  329. } while (c !is _firstControl)
  330. }
  331. WindowEndDraw(this, &_pfvars, _view, *_viewVars);
  332. _view.unlock();
  333. }
  334. }
  335. void onKeyChar(dchar keyChar) {
  336. // dispatch to focused control
  337. if (_focused_control !is null) {
  338. if (_focused_control.onKeyChar(keyChar)) {
  339. onDraw();
  340. }
  341. }
  342. }
  343. void onKeyDown(Key key) {
  344. // dispatch to focused control
  345. if (_focused_control !is null) {
  346. if (_focused_control.onKeyDown(key)) {
  347. onDraw();
  348. }
  349. }
  350. }
  351. void onKeyUp(Key key) {
  352. // dispatch to focused control
  353. if (_focused_control !is null) {
  354. if (_focused_control.onKeyUp(key)) {
  355. onDraw();
  356. }
  357. }
  358. }
  359. void onMouseLeave() {
  360. if (_last_control !is null) {
  361. _last_control._hovered = false;
  362. if(_last_control.onMouseLeave()) {
  363. onDraw();
  364. }
  365. _last_control = null;
  366. }
  367. }
  368. void onMouseMove() {
  369. //select the control to send the message to
  370. Widget control;
  371. if (_captured_control !is null) {
  372. control = _captured_control;
  373. if (controlAtPoint(mouseProps.x, mouseProps.y) is control && control.visible) {
  374. //within bounds of control
  375. if (!control._hovered) {
  376. //currently, hover state says control is outside
  377. control._hovered = true;
  378. if (control.onMouseEnter() | control.onMouseMove(mouseProps)) {
  379. onDraw();
  380. }
  381. }
  382. else if (control.onMouseMove(mouseProps)) {
  383. onDraw();
  384. }
  385. }
  386. else {
  387. //outside bounds of control
  388. if (control._hovered) {
  389. //currently, hover state says control is inside
  390. control._hovered = false;
  391. if (control.onMouseLeave() | control.onMouseMove(mouseProps)) {
  392. onDraw();
  393. }
  394. }
  395. else if (control.onMouseMove(mouseProps)) {
  396. onDraw();
  397. }
  398. }
  399. //change the cursor to reflect the new control
  400. //ChangeCursor(window->captured_control->ctrl_info.ctrl_cursor);
  401. } // no control that has captured the mouse input
  402. else if ((control = controlAtPoint(mouseProps.x, mouseProps.y)) !is null) {
  403. //when there is a control to pass a MouseLeave to...
  404. if (_last_control !is control && _last_control !is null) {
  405. control._hovered = true;
  406. _last_control._hovered = false;
  407. if(_last_control.onMouseLeave() |
  408. control.onMouseEnter() | control.onMouseMove(mouseProps)) {
  409. onDraw();
  410. }
  411. } //otherwise, there is just one control to worry about
  412. else {
  413. if(!control._hovered) {
  414. //wasn't hovered over before
  415. control._hovered = true;
  416. if(control.onMouseEnter() | control.onMouseMove(mouseProps)) {
  417. onDraw();
  418. }
  419. }
  420. else if(control.onMouseMove(mouseProps)) {
  421. onDraw();
  422. }
  423. }
  424. //change the cursor to reflect the new control
  425. //ChangeCursor(index->ctrl_cursor);
  426. _last_control = control;
  427. }
  428. else {
  429. //mouse is on window, not control
  430. if (_last_control !is null) {
  431. _last_control._hovered = false;
  432. if(_last_control.onMouseLeave()) {
  433. onDraw();
  434. }
  435. _last_control = null;
  436. }
  437. }
  438. }
  439. // Description: Called when the primary mouse button (usually the left button) is pressed.
  440. void onPrimaryMouseDown() {
  441. Widget target;
  442. bool ret = mouseEventCommon(target);
  443. _captured_control = target;
  444. if((target !is null) && (ret | target.onPrimaryMouseDown(mouseProps))) {
  445. onDraw();
  446. }
  447. }
  448. // Description: Called when the primary mouse button (usually the left button) is released.
  449. void onPrimaryMouseUp() {
  450. Widget target;
  451. bool ret = mouseEventCommon(target);
  452. _captured_control = null;
  453. if((target !is null) && (ret | target.onPrimaryMouseUp(mouseProps))) {
  454. onDraw();
  455. }
  456. }
  457. // Description: Called when the secondary mouse button (usually the right button) is pressed.
  458. void onSecondaryMouseDown() {
  459. Widget target;
  460. bool ret = mouseEventCommon(target);
  461. _captured_control = target;
  462. if((target !is null) && (ret | target.onSecondaryMouseDown(mouseProps))) {
  463. onDraw();
  464. }
  465. }
  466. // Description: Called when the secondary mouse button (usually the right button) is released.
  467. void onSecondaryMouseUp() {
  468. Widget target;
  469. bool ret = mouseEventCommon(target);
  470. _captured_control = null;
  471. if((target !is null) && (ret | target.onSecondaryMouseUp(mouseProps))) {
  472. onDraw();
  473. }
  474. }
  475. // Description: Called when the tertiary mouse button (usually the middle button) is pressed.
  476. void onTertiaryMouseDown() {
  477. Widget target;
  478. bool ret = mouseEventCommon(target);
  479. _captured_control = target;
  480. if((target !is null) && (ret | target.onTertiaryMouseDown(mouseProps))) {
  481. onDraw();
  482. }
  483. }
  484. // Description: Called when the tertiary mouse button (usually the middle button) is released.
  485. void onTertiaryMouseUp() {
  486. Widget target;
  487. bool ret = mouseEventCommon(target);
  488. _captured_control = null;
  489. if((target !is null) && (ret | target.onTertiaryMouseUp(mouseProps))) {
  490. onDraw();
  491. }
  492. }
  493. // Description: This event is called when another uncommon mouse button is pressed down over the window.
  494. // button: The identifier of this button.
  495. void onOtherMouseDown(uint button) {
  496. Widget target;
  497. bool ret = mouseEventCommon(target);
  498. _captured_control = target;
  499. if((target !is null) && (ret | target.onOtherMouseDown(mouseProps, button))) {
  500. onDraw();
  501. }
  502. }
  503. // Description: This event is called when another uncommon mouse button is released over the window.
  504. // button: The identifier of this button.
  505. void onOtherMouseUp(uint button) {
  506. Widget target;
  507. bool ret = mouseEventCommon(target);
  508. _captured_control = null;
  509. if((target !is null) && (ret | target.onOtherMouseUp(mouseProps, button))) {
  510. onDraw();
  511. }
  512. }
  513. void onResize() {
  514. ViewResizeForWindow(_view, _viewVars, this, &_pfvars);
  515. onDraw();
  516. }
  517. void onLostFocus() {
  518. //currently focused control will lose focus
  519. if (_focused_control !is null) {
  520. _focused_control._focused = false;
  521. if (_focused_control.onLostFocus(true)) {
  522. onDraw();
  523. }
  524. }
  525. }
  526. void onGotFocus() {
  527. //currently focused control will regain focus
  528. if (_focused_control !is null) {
  529. _focused_control._focused = true;
  530. if (_focused_control.onGotFocus(true)) {
  531. onDraw();
  532. }
  533. }
  534. }
  535. // Methods //
  536. // Description: This will give the preferred position for the window.
  537. // Returns: The position this window was created with.
  538. WindowPosition position() {
  539. return _position;
  540. }
  541. // Description: This will retreive the current window color.
  542. // Returns: The color currently associated with the window.
  543. Color color() {
  544. return _color;
  545. }
  546. // Description: This will set the current window color.
  547. // color: The color to associate with the window.
  548. void color(ref Color clr) {
  549. _color = clr;
  550. }
  551. // Description: This will set the current window color to a specific platform color.
  552. // sysColor: The system color index to associate with the window.
  553. void color(SystemColor clr) {
  554. ColorGetSystemColor(_color, clr);
  555. }
  556. // Description: This will force a redraw of the entire window.
  557. void redraw() {
  558. onDraw();
  559. }
  560. // Widget Maintenance //
  561. // Description: This function will return the visible control at the point given.
  562. // x: The x coordinate to start the search.
  563. // y: The y coordinate to start the search.
  564. // Returns: The top-most visible control at the point (x,y) or null.
  565. Widget controlAtPoint(int x, int y) {
  566. Widget ctrl = _firstControl;
  567. if (ctrl !is null) {
  568. do {
  569. if (ctrl.containsPoint(x,y) && ctrl.visible) {
  570. if (ctrl.isContainer()) {
  571. Widget innerCtrl = (cast(AbstractContainer)ctrl).controlAtPoint(x,y);
  572. if (innerCtrl !is null) { return innerCtrl; }
  573. }
  574. else {
  575. return ctrl;
  576. }
  577. }
  578. ctrl = ctrl._nextControl;
  579. } while (ctrl !is _firstControl)
  580. }
  581. return null;
  582. }
  583. override void push(Dispatcher dsp) {
  584. if (cast(Widget)dsp !is null) {
  585. Widget control = cast(Widget)dsp;
  586. // do not add a control that is already part of another window
  587. if (control.parent !is null) { return; }
  588. // Set the window it belongs to
  589. control._window = this;
  590. // add to the control linked list
  591. if (_firstControl is null && _lastControl is null) {
  592. // first control
  593. _firstControl = control;
  594. _lastControl = control;
  595. control._nextControl = control;
  596. control._prevControl = control;
  597. }
  598. else {
  599. // next control
  600. control._nextControl = _firstControl;
  601. control._prevControl = _lastControl;
  602. _firstControl._prevControl = control;
  603. _lastControl._nextControl = control;
  604. _firstControl = control;
  605. }
  606. // increase the number of controls
  607. _numControls++;
  608. // set the control's parent
  609. control._view = _view;
  610. control._container = this;
  611. super.push(control);
  612. // call the control's event
  613. control.onAdd();
  614. return;
  615. }
  616. super.push(dsp);
  617. }
  618. // Description: Removes the control as long as this control is a part of the current window.
  619. // control: A reference to the control that should be removed from the window.
  620. void removeControl(Widget control) {
  621. if (control.isOfWindow(this)) {
  622. if (_firstControl is null && _lastControl is null) {
  623. // it is the last control
  624. _firstControl = null;
  625. _lastControl = null;
  626. }
  627. else {
  628. // is it not the last control
  629. if (_firstControl is control) {
  630. _firstControl = _firstControl._nextControl;
  631. }
  632. if (_lastControl is control) {
  633. _lastControl = _lastControl._prevControl;
  634. }
  635. control.removeControl;
  636. }
  637. _numControls--;
  638. }
  639. }
  640. void removeAll() {
  641. // will go through and remove all of the controls
  642. Widget c = _firstControl;
  643. Widget tmp;
  644. if (c is null) { return; }
  645. do {
  646. tmp = c._nextControl;
  647. c.removeControl();
  648. c = tmp;
  649. } while (c !is _firstControl);
  650. _firstControl = null;
  651. _lastControl = null;
  652. }
  653. // Menus //
  654. // Description: Sets the menu for the window. This menu's subitems will be displayed typically as a menu bar.
  655. // mnuMain: A Menu object representing the main menu for the window. Pass null to have no menu.
  656. void menu(Menu mnuMain) {
  657. _mainMenu = mnuMain;
  658. if (mnuMain is null) {
  659. // remove the menu
  660. }
  661. else {
  662. // Switch out and apply the menu
  663. // platform specific
  664. MenuPlatformVars* mnuVars = MenuGetPlatformVars(mnuMain);
  665. WindowSetMenu(mnuVars, this, &_pfvars);
  666. }
  667. }
  668. // Description: Gets the current menu for the window. It will return null when no menu is available.
  669. // Returns: The Menu object representing the main menu for the window.
  670. Menu menu() {
  671. return _mainMenu;
  672. }
  673. // public properties
  674. Mouse mouseProps;
  675. protected:
  676. final bool mouseEventCommon(out Widget target) {
  677. if (_captured_control !is null) {
  678. target = _captured_control;
  679. }
  680. else if ((target = controlAtPoint(mouseProps.x, mouseProps.y)) !is null) {
  681. bool ret = false;
  682. //consider the focus of the control
  683. if(_focused_control !is target) {
  684. if (_focused_control !is null) {
  685. //the current focused control gets unfocused
  686. _focused_control._focused = false;
  687. ret = _focused_control.onLostFocus(false);
  688. }
  689. //focus this control
  690. _focused_control = target;
  691. _focused_control._focused = true;
  692. ret |= _focused_control.onGotFocus(false);
  693. }
  694. return ret;
  695. //change the cursor to reflect the new control
  696. //ChangeCursor(index->ctrl_cursor);
  697. }
  698. return false;
  699. }
  700. package final void uninitialize() {
  701. if (_nextWindow is null) { return; }
  702. onRemove();
  703. removeAll();
  704. _prevWindow._nextWindow = _nextWindow;
  705. _nextWindow._prevWindow = _prevWindow;
  706. // destroy the window's view object
  707. onUninitialize();
  708. GuiApplication app = cast(GuiApplication)responder;
  709. if (app._windowListHead is this && app._windowListTail is this) {
  710. app._windowListHead = null;
  711. app._windowListTail = null;
  712. }
  713. else {
  714. if (app._windowListHead is this) {
  715. app._windowListHead = app._windowListHead._nextWindow;
  716. }
  717. if (app._windowListTail is this) {
  718. app._windowListTail = app._windowListHead._prevWindow;
  719. }
  720. }
  721. _nextWindow = null;
  722. _prevWindow = null;
  723. // Decrement Window length
  724. app._windowCount--;
  725. // Check to see if this was invisible
  726. if (_visible) {
  727. // Decrement Window Visible length
  728. app._windowVisibleCount--;
  729. // If there are no visible windows, quit (for now)
  730. if (app.isZombie()) {
  731. // just kill the app
  732. app.destroyAllWindows();
  733. app.exit(0);
  734. }
  735. }
  736. // is it a parent window of some kind?
  737. // destroy and uninitialize all children
  738. if (_firstChild !is null) {
  739. Window child = _firstChild;
  740. do {
  741. child.remove();
  742. child = child._nextSibling;
  743. } while (child !is _firstChild)
  744. }
  745. // is it a child window of some kind?
  746. // unlink it within the sibling list
  747. if (_parent !is null) {
  748. Window p = _parent;
  749. p._numChildren--;
  750. _prevSibling._nextSibling = _nextSibling;
  751. _nextSibling._prevSibling = _prevSibling;
  752. if (p._firstChild is this && p._lastChild is this) {
  753. // unreference this, the last child
  754. // the parent now has no children
  755. p._firstChild = null;
  756. p._lastChild = null;
  757. }
  758. else {
  759. if (p._firstChild is this) {
  760. p._firstChild = p._firstChild._nextSibling;
  761. }
  762. if (p._lastChild is this) {
  763. p._lastChild = p._lastChild._prevSibling;
  764. }
  765. }
  766. }
  767. _parent = null;
  768. _nextSibling = null;
  769. _prevSibling = null;
  770. _firstChild = null;
  771. _lastChild = null;
  772. }
  773. package WindowView _view = null;
  774. package ViewPlatformVars* _viewVars;
  775. Color _color;
  776. WindowPosition _position;
  777. // imposes left and top margins on the window, when set
  778. long _constraint_x = 0;
  779. long _constraint_y = 0;
  780. string _window_title;
  781. package uint _width, _height;
  782. package uint _x, _y;
  783. package WindowStyle _style;
  784. package WindowState _state;
  785. private:
  786. // head and tail of the control linked list
  787. Widget _firstControl = null; //head
  788. Widget _lastControl = null; //tail
  789. int _numControls = 0;
  790. Widget _captured_control = null;
  791. Widget _last_control = null;
  792. Widget _focused_control = null;
  793. Menu _mainMenu = null;
  794. // linked list implementation
  795. // to keep track of all windows
  796. package Window _nextWindow = null;
  797. package Window _prevWindow = null;
  798. // children windows will follow suit:
  799. Window _firstChild = null; //head
  800. Window _lastChild = null; //tail
  801. uint _numChildren = 0; // child count
  802. // parent is null when it is a root window
  803. Window _parent = null;
  804. // these may be null when it is an only child
  805. Window _nextSibling = null;
  806. Window _prevSibling = null;
  807. package bool _visible = false;
  808. bool _fullscreen = false;
  809. package bool _inited = false;
  810. package WindowPlatformVars _pfvars;
  811. }
  812. // Definition: This is a View that defines the graphical client area of a Window.
  813. class WindowView : View {
  814. this() {
  815. super();
  816. }
  817. override void create(int width, int height) {
  818. }
  819. protected:
  820. override void _platformCreate() {
  821. ViewCreateForWindow(this, &_pfvars, _window, _windowVars);
  822. }
  823. private:
  824. ViewPlatformVars* createForWindow(Window window, WindowPlatformVars* windowVars) {
  825. _window = window;
  826. _windowVars = windowVars;
  827. View.create(window.width, window.height);
  828. return &_pfvars;
  829. }
  830. Window _window;
  831. WindowPlatformVars* _windowVars;
  832. }