PageRenderTime 6ms CodeModel.GetById 31ms app.highlight 27ms RepoModel.GetById 1ms app.codeStats 1ms

/gui/textfield.d

http://github.com/wilkie/djehuty
D | 672 lines | 390 code | 196 blank | 86 comment | 65 complexity | 1100387ee0904f40bc443c92a4804c78 MD5 | raw file
  1module gui.textfield;
  2
  3import gui.widget;
  4
  5import djehuty;
  6
  7import graphics.graphics;
  8
  9template ControlPrintCSTRList() {
 10	const char[] ControlPrintCSTRList = `
 11	this(int x, int y, int width, int height, string value) {
 12		super(x,y,width,height,value);
 13	}
 14	this(int x, int y, int width, int height, string value) {
 15		super(x,y,width,height,value);
 16	}
 17	`;
 18}
 19
 20// Description: This control provides a standard one line text field.
 21class TextField : Widget {
 22public:
 23
 24	enum Signal : uint {
 25		Selected,
 26		Unselected,
 27		Changed,
 28	}
 29
 30	this(int x, int y, int width, int height, string value) {
 31		super(x,y,width,height);
 32
 33		_value = value.dup;
 34	}
 35
 36	override void onAdd() {
 37		_clr_highlight = Color.fromRGB(0xf8,0xf8,0xf8);
 38		_clr_outline = Color.DarkGray;
 39		_clr_background = Color.White;
 40
 41		Graphics grp = _view.lock();
 42
 43		_font = new Font(FontSans, 8, 400, false, false, false);
 44		grp.font = (_font);
 45
 46		if (_value.length > 0)
 47		{
 48			grp.measureText(_value, _value_size);
 49		}
 50		else
 51		{
 52			grp.measureText(" ", _value_size);
 53			_value_size.x = 0;
 54		}
 55
 56		_view.unlock();
 57	}
 58
 59	void SelectionClear() {
 60		//deletes the selection
 61
 62		if (_caret_pos != _sel_start)
 63		{
 64			InternalSelectionClear();
 65
 66			RefreshViewport(_caret_pos);
 67		}
 68	}
 69
 70	override bool onMouseMove(ref Mouse mouseProps) {
 71		//find the section when the left mouse button is pressed
 72
 73		if (mouseProps.clicks != 1) {
 74			return false;
 75		}
 76
 77		if (mouseProps.leftDown) {
 78			Graphics grp = _view.lock();
 79			//grp.font = (_font);
 80
 81			uint sel_start = 0;
 82
 83			int x1 = mouseProps.x - (this.left + 3);
 84
 85			if (x1 < 0) {
 86				sel_start = 0;
 87			}
 88			else {
 89				int x_test;
 90
 91				Size s;
 92
 93				sel_start = _first_char;
 94
 95				grp.measureText(_value[_first_char.._first_char+1],s);
 96
 97				x_test = (s.x / 2);
 98
 99				while (x_test < x1 && sel_start < _value.length) {
100					//proceed further down the string
101					sel_start++;
102
103					//get length of total string so far
104					grp.measureText(_value[_first_char..sel_start],s);
105
106					x_test = s.x;
107
108					//get length of current character
109					grp.measureText(_value[sel_start..sel_start+1],s);
110
111					//add half of the current character
112					x_test += (s.x / 2);
113				}
114			}
115
116			if (_sel_start != sel_start) {
117				_sel_start = sel_start;
118				_view.unlock();
119
120				RefreshViewport(sel_start);
121				return true;
122			}
123
124			_view.unlock();
125
126			RefreshViewport(sel_start);
127
128		}
129		return false;
130	}
131
132	override bool onPrimaryMouseDown(ref Mouse mouseProps) {
133		//move caret
134
135		// -- this section takes 'x' in terms of the control's position
136		//    and gets the position under x.  Should be good for determining
137		//    selections
138
139		int x1 = mouseProps.x - (this.left + 3);
140
141		if (x1 < 0) { _caret_pos = 0; return true; }
142
143		Graphics grp = _view.lock();
144		//grp.font = (_font);
145
146		int x_test;
147
148		Size s;
149
150		_caret_pos = _first_char;
151		grp.measureText(_value[_first_char.._first_char+1], s);
152
153		x_test = (s.x / 2);
154
155		while (x_test < x1 && _caret_pos < _value.length) {
156			//proceed further down the string
157			_caret_pos++;
158
159			//get length of total string so far
160			grp.measureText(_value[_first_char.._caret_pos-_first_char], s);
161
162			x_test = s.x;
163
164			//get length of current character
165			grp.measureText(_value[_caret_pos.._caret_pos+1], s);
166
167			//add half of the current character
168			x_test += (s.x / 2);
169		}
170
171		//void out any previous selection
172		_sel_start = _caret_pos;
173
174		//capture mouse
175
176		requestCapture();
177
178		if ((mouseProps.clicks % 3) == 0) {
179			//select line
180			_caret_pos = 0;
181			_sel_start = _value.length;
182		}
183		if ((mouseProps.clicks % 2) == 0) {
184			//select text from the current caret position
185			//grab a word
186			_caret_pos = 0;
187			_sel_start = _value.length;
188		}
189		else {
190		}
191
192		_view.unlock();
193		return true;
194	}
195
196	override bool onPrimaryMouseUp(ref Mouse mouseProps) {
197		requestRelease();
198
199		return false;
200	}
201
202	override bool onGotFocus(bool withWindow) {
203		return true;
204	}
205
206	override bool onLostFocus(bool withWindow) {
207		return true;
208	}
209
210	// Key Presses
211
212	override bool onKeyDown(Key key) {
213		switch(key.code) {
214			case Key.Left:
215				if (_caret_pos != 0) {
216					_sel_start = --_caret_pos;
217				}
218
219				RefreshViewport(_caret_pos);
220
221				break;
222			case Key.Right:
223				if (_caret_pos != _value.length) {
224					_sel_start = ++_caret_pos;
225				}
226
227				RefreshViewport(_caret_pos);
228
229				break;
230			case Key.Up:
231				break;
232			case Key.Down:
233				break;
234			case Key.Delete:
235
236				if (_caret_pos == _sel_start) {
237					if ( _caret_pos != _value.length ) {
238						//delete the character to the right of the caret
239						string str_partA, str_partB;
240
241						str_partA = _value.substring(0, _caret_pos);
242						str_partB = _value.substring(_caret_pos+1);
243
244						_value = str_partA;
245						_value ~= str_partB;
246
247						//load the font, and get the size of the text when drawn
248
249						Graphics grp = _view.lock();
250						//grp.font = (_font);
251
252						if (_value.length > 0) {
253							grp.measureText(_value, _value_size);
254						}
255						else {
256							grp.measureText(" ", _value_size);
257							_value_size.x = 0;
258						}
259
260						_view.unlock();
261
262						RefreshViewport(_caret_pos);
263
264						//FIRE_EVENT(id, EventValueChanged, 0, 0);
265					}
266				}
267				else {
268					//clear selection
269					SelectionClear();
270				}
271
272				break;
273
274			case Key.Backspace:
275
276				//erase
277
278				if (_caret_pos == _sel_start) {
279					if (_caret_pos != 0) {
280						string str_partA, str_partB;
281
282						_caret_pos--;
283
284						str_partA = _value.substring(0, _caret_pos);
285						str_partB = _value.substring(_caret_pos+1);
286
287						_value = str_partA;
288						_value ~= str_partB;
289
290						_sel_start = _caret_pos;
291
292						//load the font, and get the size of the text when drawn
293
294						Graphics grp = _view.lock();
295						//grp.font = (_font);
296
297						if (_value.length > 0)
298						{
299							grp.measureText(_value, _value_size);
300						}
301						else
302						{
303							grp.measureText(" ", _value_size);
304							_value_size.x = 0;
305						}
306
307						_view.unlock();
308
309						RefreshViewport(_caret_pos);
310
311						//FIRE_EVENT(id, EventValueChanged, 0, 0);
312					}
313				}
314				else {
315					//erase the selection
316
317					SelectionClear();
318				}
319
320				break;
321
322			default:
323
324				//check for keyboard shortcut
325
326				break;
327		}
328
329		return true;
330	}
331
332	override bool onKeyChar(dchar character) {
333		//if this character is a character we can write out, then
334		//alter the text of the field
335
336		//add the letter into the text field
337
338		//if there is a selection, clear it first
339		SelectionClear();
340
341		string str_partA;
342		string str_partB;
343
344		str_partA = _value.substring(0, _caret_pos);
345
346		str_partB = _value.substring(_caret_pos);
347
348		_sel_start = ++_caret_pos;
349
350		_value = str_partA;
351		_value ~= Unicode.toUtf8([character]);
352		_value ~= str_partB;
353
354		//load the font, and get the size of the text when drawn
355
356		Graphics grp = _view.lock();
357		//grp.font = (_font);
358
359		if (_value.length > 0) {
360			grp.measureText(_value, _value_size);
361		}
362		else {
363			grp.measureText(" ", _value_size);
364			_value_size.x = 0;
365		}
366
367		_view.unlock();
368
369		RefreshViewport(_caret_pos);
370
371		//FIRE_EVENT(id, EventValueChanged, 0, 0);
372
373		return true;
374	}
375
376	override void onDraw(ref Graphics g) {
377		//Draw Background of Button
378		Brush brush = new Brush(_clr_background);
379
380		Pen pen = new Pen(_clr_outline);
381
382		g.brush = (brush);
383		g.pen = (pen);
384
385		g.drawRect(this.left, this.top, this.right, this.bottom);
386
387		//Draw 3D Effect
388		pen.setColor(_clr_highlight);
389		g.pen = (pen);
390
391		g.drawLine(this.left + 1, this.top + 1, this.right - 1, this.top + 1);
392		g.drawLine(this.left + 1, this.top + 1, this.left + 1, this.bottom - 1);
393
394		//Drawing Transparent Text
395		g.setTextModeTransparent();
396
397		//create Atmosphere for Selections
398		brush.setColor(Color.Black);
399		pen.setColor(Color.Black);
400
401		//Draw Text
402
403		Rect bounds;
404
405		bounds.left = this.left + 1;
406		bounds.right = this.right - 1;
407		bounds.top = this.top + 1;
408		bounds.bottom = this.bottom - 1;
409
410		//g.font = (_font);
411
412		g.forecolor = Color.Black;
413
414		if (_caret_pos == _sel_start || (_caret_pos < _first_char && _sel_start < _first_char)) {
415			//no selection visible
416			g.drawText(this.left+3, this.top+2, _value[_first_char.._value.length]);
417
418			//Draw Caret
419
420			if (_caret_pos >= _first_char && _focused) {
421				int x, y;
422
423				y = this.top + 2;
424				x = this.left + 3;
425
426				Size s;
427
428				if (_caret_pos > _first_char) {
429					g.measureText(_value[_first_char.._caret_pos],s);
430
431					x += s.x;
432				}
433
434				if (x < bounds.right) {
435					g.drawLine(x,y,x,y+_value_size.y);
436				}
437			}
438		}
439		else {
440			int x, y, x2, y2;
441			Size s;
442
443			uint from_pos;
444			uint to_pos;
445
446			if (_sel_start < _caret_pos) {
447				from_pos = _sel_start;
448				to_pos = _caret_pos;
449			}
450			else {
451				from_pos = _caret_pos;
452				to_pos = _sel_start;
453			}
454
455			x = this.left + 3;
456			y = this.top + 2;
457
458			//left side of the selection
459			if (from_pos < _first_char) {
460				from_pos = _first_char;
461			}
462
463			g.drawText(x,y,_value[_first_char..from_pos]);
464			g.measureText(_value[_first_char..from_pos],s);
465
466			x += s.x;
467
468			g.forecolor = (Color.White);
469
470			//draw background rect within the control's bounds
471			g.measureText(_value[from_pos..to_pos],s);
472
473			//get the width of the line above, use that to determine x2, the
474			//width of the selection rectangle.
475
476			//y2 is the height of the line with some room
477
478			//x2 is reused, since it determines the position of the next part
479			//of the string below when printing
480			x2 = x + s.x;
481			y2 = y + _value_size.y + 1;
482
483			if (x2 >= this.right) {
484				x2 = this.right - 1;
485			}
486
487			g.drawRect(x,y,x2,y2);
488
489			//the selection
490			g.drawText(x,y,_value[from_pos..to_pos]);
491
492			g.forecolor = (Color.Black);
493
494			//the right side of the selection
495			g.drawText(x2, y, _value[to_pos.._value.length]);
496		}
497	}
498
499	void text(string newTitle) {
500		_value = newTitle.dup;
501	}
502
503	string text() {
504		return _value.dup;
505	}
506
507protected:
508
509	string _value;
510
511private:
512
513	void RefreshViewport(uint onPos) {
514		//check to see if onPos is already within viewing area
515		//check to see what direction we are travelling
516		//if left... from onPos go backwards a certain distance
517		//if right... from onPos go forwards a certain distance
518		//set _first_char accordingly
519
520		if (_caret_pos > _value.length) {
521			_caret_pos = _value.length;
522		}
523
524		Size s;
525
526		//the width to move
527		int movement_width = 45;
528		int current_movement = 0;
529		uint i;
530
531		Graphics grp = _view.lock();
532
533		if (onPos > _first_char) {
534			//check to see if it is within the viewable area
535			grp.measureText(_value[_first_char..onPos], s);
536
537			if ((s.x + 3) < this.width) {
538				//we are good
539				_view.unlock();
540				return;
541			}
542			else {
543				//we are moving right
544
545				//go forward
546
547				i = onPos;
548
549				while(current_movement < movement_width) {
550					if (i > _value.length) {
551						i = _value.length;
552						break;
553					}
554
555					grp.measureText(_value[i..i+1], s);
556					current_movement += s.x;
557
558					i++;
559				}
560
561				//i is the rightmost character
562				//go backwards from onPos to find
563				//the first character
564
565				i = onPos;
566
567				while(current_movement < this.width) {
568					if (i<=0) {
569						i = 0;
570						break;
571					}
572
573					i--;
574
575					grp.measureText(_value[i..i+1],s);
576					current_movement += s.x;
577				}
578
579				//i is the new first character
580				_first_char = i + 1;
581			}
582		}
583		else {
584			//we are moving left
585
586			//go backward
587
588			i = onPos;
589
590			while(current_movement < movement_width) {
591				if (i<=0) {
592					i = 0;
593					break;
594				}
595
596				i--;
597
598				grp.measureText(_value[i..i+1],s);
599				current_movement += s.x;
600			}
601
602			//i is the new first character
603
604			_first_char = i;
605		}
606
607		_view.unlock();
608
609	}
610
611	void InternalSelectionClear() {
612		//deletes the selection
613
614		if (_caret_pos != _sel_start) {
615			if (_caret_pos < _sel_start) {
616				//swap the two positions, so that
617				//m_sel_start is at the beginning of the selection
618				//and m_caret_pos marks the end
619				_sel_start ^= _caret_pos;
620				_caret_pos ^= _sel_start;
621				_sel_start ^= _caret_pos;
622			}
623
624			string str_partA, str_partB;
625
626			// new_string = substring(0 ---> _sel_start)
627
628			str_partA = _value.substring(0, _sel_start);
629
630			// new_string += substring(_caret_pos ---> <EOS>);
631
632			str_partB = _value.substring(_caret_pos);
633
634			_value = str_partA;
635			_value ~= str_partB;
636
637			//turn off the selection
638			//make the selection start the new caret position
639			_caret_pos = _sel_start;
640
641			//load the font, and get the size of the text when drawn
642			Graphics grp = _view.lock();
643			//grp.font = (_font);
644
645			if (_value.length) {
646				grp.measureText(_value, _value_size);
647			}
648			else {
649				grp.measureText(" ", _value_size);
650				_value_size.x = 0;
651			}
652
653			_view.unlock();
654		}
655	}
656
657
658	Size _value_size;
659
660	Font _font;
661
662	uint _first_char;		//the first character drawn
663	uint _caret_pos;		//the caret position within the string
664	uint _caret_on;		//if caret is currently drawn
665
666	uint _sel_start;		//the start of the selection
667							//_caret_pos is the end
668
669	Color _clr_background;
670	Color _clr_highlight;
671	Color _clr_outline;
672}