/cui/widget.d

http://github.com/wilkie/djehuty · D · 344 lines · 227 code · 88 blank · 29 comment · 16 complexity · 4e5494dc0194e2fe813cbc22ba7f262f MD5 · raw file

  1. module cui.widget;
  2. import djehuty;
  3. import cui.window;
  4. import cui.application;
  5. import cui.container;
  6. private import io.console;
  7. // Description: This class abstracts part of the console's screen. When attached to a window, this class will receive input through the events. Keyboard events will be passed only when the control is activated. A control can decide not to be activatable by setting it's _isTabStop to false.
  8. class CuiWidget : Responder {
  9. this() {
  10. Console.widget = this;
  11. }
  12. this(int x, int y, int width, int height) {
  13. _x = x;
  14. _y = y;
  15. _base_x = x;
  16. _base_y = y;
  17. _width = width;
  18. _height = height;
  19. Console.widget = this;
  20. }
  21. // Events
  22. void onInit() {
  23. }
  24. void onAdd() {
  25. }
  26. void onRemove() {
  27. }
  28. void onGotFocus() {
  29. }
  30. void onDraw() {
  31. }
  32. void onLostFocus() {
  33. }
  34. void onResize() {
  35. }
  36. void onKeyDown(Key key) {
  37. }
  38. void onKeyChar(dchar keyChar) {
  39. }
  40. void onPrimaryMouseDown() {
  41. }
  42. void onPrimaryMouseUp() {
  43. }
  44. void onSecondaryMouseDown() {
  45. }
  46. void onSecondaryMouseUp() {
  47. }
  48. void onTertiaryMouseDown() {
  49. }
  50. void onTertiaryMouseUp() {
  51. }
  52. void onMouseWheelY(int amount) {
  53. }
  54. void onMouseWheelX(int amount) {
  55. }
  56. void onMouseMove() {
  57. }
  58. override void push(Dispatcher dsp) {
  59. if (cast(CuiWidget)dsp) {
  60. // Adding a child widget to this widget
  61. //_owner.push(dsp);
  62. }
  63. else {
  64. super.push(dsp);
  65. }
  66. }
  67. void resize(uint width, uint height) {
  68. _width = width;
  69. _height = height;
  70. onDraw();
  71. }
  72. void move(uint left, uint top) {
  73. _x = left;
  74. _y = top;
  75. onDraw();
  76. }
  77. bool isTabStop() {
  78. return false;
  79. }
  80. bool isTabUseful() {
  81. return false;
  82. }
  83. uint left() {
  84. return _x;
  85. }
  86. uint top() {
  87. return _y;
  88. }
  89. uint right() {
  90. return _x + _width;
  91. }
  92. uint bottom() {
  93. return _y + _height;
  94. }
  95. uint width() {
  96. return _width;
  97. }
  98. uint height() {
  99. return _height;
  100. }
  101. CuiWindow window() {
  102. return _window;
  103. }
  104. protected:
  105. bool canDraw() {
  106. return _window !is null && _window.isActive;
  107. }
  108. // This stores the widget currently clipped by the Console's clipping region
  109. // That is, the one with focus, that can safely draw and not interfere with
  110. // another widget.
  111. static CuiWidget widgetClippingContext;
  112. struct _Console {
  113. // Description: This will move the terminal caret to the relative position indicated by the parameters.
  114. // x: The x position within the widget bounds to move the caret.
  115. // y: The y position within the widget bounds to move the caret.
  116. final void position(uint x, uint y) {
  117. if (x >= widget._width) {
  118. x = widget._width - 1;
  119. }
  120. if (y >= widget._height) {
  121. y = widget._height - 1;
  122. }
  123. io.console.Console.position = [widget._base_x + widget._x + x, widget._base_y + widget._y + y];
  124. }
  125. // Description: This function will hide the caret.
  126. final void hideCaret() {
  127. io.console.Console.hideCaret();
  128. }
  129. // Description: This function will show the caret.
  130. final void showCaret() {
  131. io.console.Console.showCaret();
  132. }
  133. final void forecolor(Color value) {
  134. io.console.Console.forecolor = value;
  135. }
  136. final Color forecolor() {
  137. return io.console.Console.forecolor;
  138. }
  139. final void backcolor(Color value) {
  140. io.console.Console.backcolor(value);
  141. }
  142. final Color backcolor() {
  143. return io.console.Console.backcolor;
  144. }
  145. // Description: This function will print to the widget.
  146. final void put(...) {
  147. Variadic vars = new Variadic(_arguments, _argptr);
  148. putv(vars);
  149. }
  150. final void putv(Variadic vars) {
  151. putString(toStrv(vars));
  152. }
  153. final void putlnv(Variadic vars) {
  154. putv(vars);
  155. io.console.Console.putChar('\n');
  156. }
  157. // Description: This function will print to the widget and then go to the next line.
  158. final void putln(...) {
  159. Variadic vars = new Variadic(_arguments, _argptr);
  160. putlnv(vars);
  161. }
  162. final void putAt(uint x, uint y, ...) {
  163. Variadic vars = new Variadic(_arguments, _argptr);
  164. putStringAt(x, y, toStrv(vars));
  165. }
  166. final void putStringAt(int x, int y, string str) {
  167. if (widget !is CuiWidget.widgetClippingContext) {
  168. // We need to set up the current widget that wants to draw so that widgets
  169. // above this one are clipped.
  170. }
  171. x += widget._base_x + widget._x;
  172. y += widget._base_y + widget._y;
  173. int r;
  174. int b;
  175. uint leftPos = 0;
  176. uint rightPos = 0;
  177. r = x + str.length;
  178. b = y + 1;
  179. uint global_x = widget._base_x + widget._x;
  180. uint global_y = widget._base_y + widget._y;
  181. uint _r = global_x + widget.width;
  182. uint _b = global_y + widget.height;
  183. if (_r > widget._base_x + widget._owner.width) {
  184. _r = widget._base_x + widget._owner.width;
  185. }
  186. if (_b > widget._base_y + widget._owner.height) {
  187. _b = widget._base_y + widget._owner.height;
  188. }
  189. // Test rectangular intersection
  190. if ((r < global_x) || (b < global_y) || (x > _r) || (y > _b)) {
  191. // Outside bounds of widget completely
  192. return;
  193. }
  194. // Clip string (left edge)
  195. if (x < global_x) {
  196. leftPos = global_x - x;
  197. x = 0;
  198. io.console.Console.position = [x, y];
  199. }
  200. // Clip string (right edge)
  201. if (r > _r) {
  202. rightPos = r - _r;
  203. }
  204. str = str.substring(leftPos, str.length - rightPos - leftPos);
  205. io.console.Console.putStringAt(x, y, str);
  206. }
  207. // Description: This function is for printing strings within widget bounds.
  208. // str: The String to print.string idget bounds
  209. final void putString(string str) {
  210. // Clip to the bounds of the control and the owner container
  211. Coord pos = io.console.Console.position;
  212. // Get x and y relative to top left of widget
  213. uint global_x = widget._base_x + widget._x;
  214. uint global_y = widget._base_y + widget._y;
  215. pos.x = pos.x - global_x;
  216. pos.y = pos.y - global_y;
  217. putStringAt(pos.x, pos.y, str);
  218. }
  219. final void putSpaces(uint numSpaces) {
  220. static const char[128] spaces = ' ';
  221. do {
  222. uint pad = 128;
  223. if (numSpaces < pad) {
  224. pad = numSpaces;
  225. }
  226. put(spaces[0..pad]);
  227. numSpaces -= pad;
  228. } while (numSpaces > 0)
  229. }
  230. private:
  231. CuiWidget widget;
  232. }
  233. _Console Console;
  234. final void tabForward() {
  235. _owner._tabForward();
  236. }
  237. final void tabBackward() {
  238. _owner._tabBackward();
  239. }
  240. private:
  241. // For internal linked list of parent container
  242. package CuiWidget _nextControl;
  243. package CuiWidget _prevControl;
  244. // Widget ultimate parent
  245. package CuiWindow _window;
  246. package CuiContainer _owner;
  247. // Widget relative coordinates
  248. uint _x = 0;
  249. uint _y = 0;
  250. // Coordinates of global left-top
  251. package uint _base_x = 0;
  252. package uint _base_y = 0;
  253. // Widget size
  254. uint _width = 0;
  255. uint _height = 0;
  256. }