PageRenderTime 52ms CodeModel.GetById 30ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 0ms

/cui/widget.d

http://github.com/wilkie/djehuty
D | 344 lines | 227 code | 88 blank | 29 comment | 16 complexity | 4e5494dc0194e2fe813cbc22ba7f262f MD5 | raw file
  1module cui.widget;
  2
  3import djehuty;
  4
  5import cui.window;
  6import cui.application;
  7import cui.container;
  8
  9private import io.console;
 10
 11// 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.
 12class CuiWidget : Responder {
 13
 14	this() {
 15		Console.widget = this;
 16	}
 17
 18	this(int x, int y, int width, int height) {
 19		_x = x;
 20		_y = y;
 21		_base_x = x;
 22		_base_y = y;
 23		_width = width;
 24		_height = height;
 25		Console.widget = this;
 26	}
 27
 28	// Events
 29
 30	void onInit() {
 31	}
 32
 33	void onAdd() {
 34	}
 35
 36	void onRemove() {
 37	}
 38
 39	void onGotFocus() {
 40	}
 41
 42	void onDraw() {
 43	}
 44
 45	void onLostFocus() {
 46	}
 47
 48	void onResize() {
 49	}
 50
 51	void onKeyDown(Key key) {
 52	}
 53
 54	void onKeyChar(dchar keyChar) {
 55	}
 56
 57	void onPrimaryMouseDown() {
 58	}
 59
 60	void onPrimaryMouseUp() {
 61	}
 62
 63	void onSecondaryMouseDown() {
 64	}
 65
 66	void onSecondaryMouseUp() {
 67	}
 68
 69	void onTertiaryMouseDown() {
 70	}
 71
 72	void onTertiaryMouseUp() {
 73	}
 74
 75	void onMouseWheelY(int amount) {
 76	}
 77
 78	void onMouseWheelX(int amount) {
 79	}
 80
 81	void onMouseMove() {
 82	}
 83
 84	override void push(Dispatcher dsp) {
 85		if (cast(CuiWidget)dsp) {
 86			// Adding a child widget to this widget
 87			//_owner.push(dsp);
 88		}
 89		else {
 90			super.push(dsp);
 91		}
 92	}
 93
 94	void resize(uint width, uint height) {
 95		_width = width;
 96		_height = height;
 97		onDraw();
 98	}
 99
100	void move(uint left, uint top) {
101		_x = left;
102		_y = top;
103		onDraw();
104	}
105
106	bool isTabStop() {
107		return false;
108	}
109
110	bool isTabUseful() {
111		return false;
112	}
113
114	uint left() {
115		return _x;
116	}
117
118	uint top() {
119		return _y;
120	}
121
122	uint right() {
123		return _x + _width;
124	}
125
126	uint bottom() {
127		return _y + _height;
128	}
129
130	uint width() {
131		return _width;
132	}
133
134	uint height() {
135		return _height;
136	}
137
138	CuiWindow window() {
139		return _window;
140	}
141
142protected:
143
144	bool canDraw() {
145		return _window !is null && _window.isActive;
146	}
147
148	// This stores the widget currently clipped by the Console's clipping region
149	// That is, the one with focus, that can safely draw and not interfere with
150	// another widget.
151	static CuiWidget widgetClippingContext;
152
153	struct _Console {
154		// Description: This will move the terminal caret to the relative position indicated by the parameters.
155		// x: The x position within the widget bounds to move the caret.
156		// y: The y position within the widget bounds to move the caret.
157		final void position(uint x, uint y) {
158			if (x >= widget._width) {
159				x = widget._width - 1;
160			}
161
162			if (y >= widget._height) {
163				y = widget._height - 1;
164			}
165
166			io.console.Console.position = [widget._base_x + widget._x + x, widget._base_y + widget._y + y];
167		}
168
169		// Description: This function will hide the caret.
170		final void hideCaret() {
171			io.console.Console.hideCaret();
172		}
173
174		// Description: This function will show the caret.
175		final void showCaret() {
176			io.console.Console.showCaret();
177		}
178
179		final void forecolor(Color value) {
180			io.console.Console.forecolor = value;
181		}
182
183		final Color forecolor() {
184			return io.console.Console.forecolor;
185		}
186
187		final void backcolor(Color value) {
188			io.console.Console.backcolor(value);
189		}
190
191		final Color backcolor() {
192			return io.console.Console.backcolor;
193		}
194
195		// Description: This function will print to the widget.
196		final void put(...) {
197			Variadic vars = new Variadic(_arguments, _argptr);
198
199			putv(vars);
200		}
201
202		final void putv(Variadic vars) {
203			putString(toStrv(vars));
204		}
205
206		final void putlnv(Variadic vars) {
207			putv(vars);
208
209			io.console.Console.putChar('\n');
210		}
211
212		// Description: This function will print to the widget and then go to the next line.
213		final void putln(...) {
214			Variadic vars = new Variadic(_arguments, _argptr);
215
216			putlnv(vars);
217		}
218
219		final void putAt(uint x, uint y, ...) {
220			Variadic vars = new Variadic(_arguments, _argptr);
221
222			putStringAt(x, y, toStrv(vars));
223		}
224
225		final void putStringAt(int x, int y, string str) {
226			if (widget !is CuiWidget.widgetClippingContext) {
227				// We need to set up the current widget that wants to draw so that widgets
228				// above this one are clipped.
229			}
230
231			x += widget._base_x + widget._x;
232			y += widget._base_y + widget._y;
233
234			int r;
235			int b;
236
237			uint leftPos = 0;
238			uint rightPos = 0;
239
240			r = x + str.length;
241			b = y + 1;
242
243			uint global_x = widget._base_x + widget._x;
244			uint global_y = widget._base_y + widget._y;
245
246			uint _r = global_x + widget.width;
247			uint _b = global_y + widget.height;
248
249			if (_r > widget._base_x + widget._owner.width) {
250				_r = widget._base_x + widget._owner.width;
251			}
252
253			if (_b > widget._base_y + widget._owner.height) {
254				_b = widget._base_y + widget._owner.height;
255			}
256
257			// Test rectangular intersection
258			if ((r < global_x) || (b < global_y) || (x > _r) || (y > _b)) {
259				// Outside bounds of widget completely
260				return;
261			}
262
263			// Clip string (left edge)
264			if (x < global_x) {
265				leftPos = global_x - x;
266				x = 0;
267				io.console.Console.position = [x, y];
268			}
269
270			// Clip string (right edge)
271			if (r > _r) {
272				rightPos = r - _r;
273			}
274
275			str = str.substring(leftPos, str.length - rightPos - leftPos);
276
277			io.console.Console.putStringAt(x, y, str);
278		}
279
280		// Description: This function is for printing strings within widget bounds.
281		// str: The String to print.string idget bounds
282		final void putString(string str) {
283			// Clip to the bounds of the control and the owner container
284			Coord pos = io.console.Console.position;
285
286			// Get x and y relative to top left of widget
287			uint global_x = widget._base_x + widget._x;
288			uint global_y = widget._base_y + widget._y;
289
290			pos.x = pos.x - global_x;
291			pos.y = pos.y - global_y;
292
293			putStringAt(pos.x, pos.y, str);
294		}
295
296		final void putSpaces(uint numSpaces) {
297			static const char[128] spaces = ' ';
298
299			do {
300				uint pad = 128;
301				if (numSpaces < pad) {
302					pad = numSpaces;
303				}
304				put(spaces[0..pad]);
305				numSpaces -= pad;
306			} while (numSpaces > 0)
307		}
308
309	private:
310		CuiWidget widget;
311	}
312
313	_Console Console;
314
315	final void tabForward() {
316		_owner._tabForward();
317	}
318
319	final void tabBackward() {
320		_owner._tabBackward();
321	}
322
323private:
324
325	// For internal linked list of parent container
326	package CuiWidget _nextControl;
327	package CuiWidget _prevControl;
328
329	// Widget ultimate parent
330	package CuiWindow _window;
331	package CuiContainer _owner;
332
333	// Widget relative coordinates
334	uint _x = 0;
335	uint _y = 0;
336
337	 // Coordinates of global left-top
338	package uint _base_x = 0;
339	package uint _base_y = 0;
340
341	// Widget size
342	uint _width = 0;
343	uint _height = 0;
344}