1 // Crimson Fields -- a game of tactical warfare
2 // Copyright (C) 2000-2007 Jens Granseuer
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 //
18
19 ////////////////////////////////////////////////////////////////////////
20 // textbox.cpp
21 ////////////////////////////////////////////////////////////////////////
22
23 #include <cctype>
24 #include <string.h>
25 #include <stdlib.h>
26
27 #include "textbox.h"
28 #include "misc.h"
29
30 ////////////////////////////////////////////////////////////////////////
31 // NAME : TextWidget::TextWidget
32 // DESCRIPTION: Create a new TextWidget
33 // PARAMETERS : id - widget identifier
34 // x - left edge of widget
35 // y - top edge of widget
36 // w - widget width
37 // h - widget height
38 // str - text to display (may be NULL)
39 // flags - widget flags (see widget.h for details)
40 // title - widget title (currently unused)
41 // window - widget parent window
42 // RETURNS : -
43 ////////////////////////////////////////////////////////////////////////
44
TextWidget(short id,short x,short y,unsigned short w,unsigned short h,const char * str,unsigned short flags,const char * title,Window * window)45 TextWidget::TextWidget( short id, short x, short y,
46 unsigned short w, unsigned short h, const char *str,
47 unsigned short flags, const char *title, Window *window ) :
48 Widget( id, x, y, w, h, flags, title, window ) {
49 textsurface = NULL;
50 spacing = 2;
51 SetText( str );
52 }
53
54 ////////////////////////////////////////////////////////////////////////
55 // NAME : TextWidget::~TextWidget
56 // DESCRIPTION: Destroy a TextWidget
57 // PARAMETERS : -
58 // RETURNS : -
59 ////////////////////////////////////////////////////////////////////////
60
~TextWidget(void)61 TextWidget::~TextWidget( void ) {
62 delete textsurface;
63 }
64
65 ////////////////////////////////////////////////////////////////////////
66 // NAME : TextWidget::SetText
67 // DESCRIPTION: Prepare the text for use and format it appropriately.
68 // PARAMETERS : str - string to display (may be NULL)
69 // RETURNS : -
70 ////////////////////////////////////////////////////////////////////////
71
SetText(const char * str)72 void TextWidget::SetText( const char *str ) {
73 delete textsurface;
74 textsurface = NULL;
75 rows = visrows = toprow = 0;
76
77 if ( !str ) return;
78
79 rows = font->TextHeight( str, w - 10, spacing );
80 if ( rows > 0 ) {
81 textsurface = new Surface();
82 if ( textsurface->Create( w - 10, rows, surface->GetView()->ScreenBPP(), 0 ) ) {
83 delete textsurface;
84 textsurface = NULL;
85 return;
86 }
87
88 textsurface->SetColorKey( Color(CF_COLOR_BLACK) );
89 textsurface->Flood( Color(CF_COLOR_BLACK) );
90
91 string full( str );
92 int pos = 0, endpos = full.size(), rowcnt = 0;
93 unsigned short xoff = 0;
94
95 while ( pos < endpos ) {
96 size_t linelen = font->FitText( &str[pos], w - 10, true );
97 string sub( full.substr( pos, linelen ) );
98
99 // remove newlines
100 size_t rep = 0;
101 while ( (rep = sub.find( '\n', rep )) != string::npos )
102 sub.erase( rep, 1 );
103
104 if ( flags & WIDGET_ALIGN_CENTER )
105 xoff = (w - 10 - font->TextWidth( sub.c_str() )) / 2;
106 font->Write( sub.c_str(), textsurface, xoff, rowcnt );
107
108 rowcnt += font->Height() + spacing;
109 pos += linelen;
110 }
111
112 visrows = h - 6;
113 if ( visrows > rows ) visrows = rows;
114 }
115 }
116
117 ////////////////////////////////////////////////////////////////////////
118 // NAME : TextWidget::Draw
119 // DESCRIPTION: Draw the widget and render the text.
120 // PARAMETERS : -
121 // RETURNS : -
122 ////////////////////////////////////////////////////////////////////////
123
Draw(void)124 void TextWidget::Draw( void ) {
125 surface->DrawBack( *this );
126 surface->DrawBox( *this, BOX_RECESSED );
127
128 if ( textsurface )
129 textsurface->Blit( surface, Rect(0,toprow,textsurface->Width(),visrows),
130 x + 5, y + 3 );
131 }
132
133 ////////////////////////////////////////////////////////////////////////
134 // NAME : TextWidget::SetRow
135 // DESCRIPTION: Set the first row visible in the widget textbox.
136 // PARAMETERS : top - first row to be visible; the widget automatically
137 // adjusts this value to fit as much text as possible
138 // into the box
139 // RETURNS : new top row set (after optimization)
140 ////////////////////////////////////////////////////////////////////////
141
SetRow(unsigned short top)142 unsigned short TextWidget::SetRow( unsigned short top ) {
143 unsigned short maxrow = rows - visrows;
144 if ( top <= maxrow ) toprow = top;
145 else toprow = maxrow;
146 Draw();
147 Show();
148 return toprow;
149 }
150
151
152 ////////////////////////////////////////////////////////////////////////
153 // NAME : TextScrollWidget::TextScrollWidget
154 // DESCRIPTION: Create a new TextScrollWidget.
155 // PARAMETERS : id - widget identifier
156 // x - left edge of widget
157 // y - top edge of widget
158 // w - widget width
159 // h - widget height
160 // str - text to display (may be NULL)
161 // flags - widget flags (see widget.h for details)
162 // title - widget title (currently unused)
163 // window - widget parent window
164 // RETURNS : -
165 ////////////////////////////////////////////////////////////////////////
166
TextScrollWidget(short id,short x,short y,unsigned short w,unsigned short h,const char * str,unsigned short flags,const char * title,Window * window)167 TextScrollWidget::TextScrollWidget( short id, short x, short y,
168 unsigned short w, unsigned short h, const char *str,
169 unsigned short flags, const char *title, Window *window ) :
170 CompositeWidget( id, x, y, w, h, 0, 0, window ) {
171
172 TextWidget *text = new TextWidget( 0, x, y, w, h, 0,
173 flags|WIDGET_COMPOSITE, title, window );
174 AddWidget( text );
175
176 SetText( str );
177 }
178
179 ////////////////////////////////////////////////////////////////////////
180 // NAME : TextWidget::WidgetActivated
181 // DESCRIPTION: Scroller has been used. Scroll the widget to the current
182 // row.
183 // PARAMETERS : widget - calling widget (slider)
184 // win - window the widget belongs to
185 // RETURNS : GUI_OK
186 ////////////////////////////////////////////////////////////////////////
187
WidgetActivated(Widget * widget,Window * win)188 GUI_Status TextScrollWidget::WidgetActivated( Widget *widget, Window *win ) {
189 TextWidget *t = static_cast<TextWidget *>( GetWidget( 0 ) );
190 t->SetRow( static_cast<SliderWidget *>(widget)->Level() );
191 return GUI_OK;
192 }
193
194 ////////////////////////////////////////////////////////////////////////
195 // NAME : TextScrollWidget::MouseDown
196 // DESCRIPTION: Distribute mouse down events to all components. Redirect
197 // all scrollwheel events to the slider so that scrolling
198 // works even if the pointer doesn't hover over the slider.
199 // PARAMETERS : button - button event
200 // RETURNS : GUI status
201 ////////////////////////////////////////////////////////////////////////
202
MouseDown(const SDL_MouseButtonEvent & button)203 GUI_Status TextScrollWidget::MouseDown( const SDL_MouseButtonEvent &button ) {
204 SDL_MouseButtonEvent mybutton = button;
205 if ( ((button.button == SDL_BUTTON_WHEELUP) ||
206 (button.button == SDL_BUTTON_WHEELDOWN)) &&
207 Contains( button.x - surface->LeftEdge(), button.y - surface->TopEdge() ) ) {
208 SliderWidget *s = static_cast<SliderWidget *>( GetWidget(1) );
209 if ( s ) {
210 // to address the slider widget we must adjust the click
211 // coordinates to be inside the slider box
212 mybutton.x = s->LeftEdge() + surface->LeftEdge();
213 mybutton.y = s->TopEdge() + surface->TopEdge();
214 }
215 }
216
217 return CompositeWidget::MouseDown( mybutton );
218 }
219
220 ////////////////////////////////////////////////////////////////////////
221 // NAME : TextScrollWidget::SetText
222 // DESCRIPTION: Set a new text to be displayed in the widget.
223 // PARAMETERS : str - string to display (may be NULL)
224 // RETURNS : -
225 ////////////////////////////////////////////////////////////////////////
226
SetText(const char * str)227 void TextScrollWidget::SetText( const char *str ) {
228 TextWidget *t = static_cast<TextWidget *>( GetWidget(0) );
229 SliderWidget *s = static_cast<SliderWidget *>( GetWidget(1) );
230
231 bool needslider = str && (font->TextHeight( str, w - 10, 2 ) > h - 6);
232
233 if ( needslider ) {
234 if ( !s ) {
235 s = new SliderWidget( 1, x + w - DEFAULT_SLIDER_SIZE, y,
236 DEFAULT_SLIDER_SIZE, h, 0, 0, 0, 0,
237 WIDGET_VSCROLL|WIDGET_HSCROLLKEY|WIDGET_VSCROLLKEY|WIDGET_COMPOSITE,
238 NULL, surface );
239 s->SetKeyStep( font->Height() + 2 );
240 s->SetHook( this );
241 AddWidget( s );
242
243 t->SetSize( x, y, w - s->Width(), h );
244 }
245 } else if ( s ) {
246 RemoveWidget( s );
247 t->SetSize( x, y, w + s->Width(), h );
248 delete s;
249 }
250
251 t->SetText( str );
252
253 if ( needslider ) {
254 s->Adjust( 0, t->Rows() - t->RowsVisible(), MAX(t->RowsVisible(),1) );
255 s->ScrollTo( 0 );
256 }
257 }
258
259
260 ////////////////////////////////////////////////////////////////////////
261 // NAME : TextListWidget::DrawNodes
262 // DESCRIPTION: Draw the list nodes.
263 // PARAMETERS : -
264 // RETURNS : -
265 ////////////////////////////////////////////////////////////////////////
266
DrawNodes(void)267 void TextListWidget::DrawNodes( void ) {
268 Rect box( x + 4, y + 1 + spacing, listboxw - 8, h - 2 - 2 * spacing );
269 Rect area( x + 1, y + 1, listboxw - 2, h - 2 );
270 short num = toprow / ItemHeight(); // number of top node
271 TLWNode *n = static_cast<TLWNode *>(list->GetNode( num )); // top node
272 short xoff = box.x, yoff = box.y + (num * ItemHeight()) - toprow;
273 Color fcol = font->GetColor();
274
275 if ( Disabled() )
276 font->SetColor( Color(CF_COLOR_GHOSTED) );
277
278 surface->DrawBack( area );
279
280 while ( n ) {
281 if ( flags & WIDGET_ALIGN_CENTER )
282 xoff = box.x + (box.w - font->TextWidth(n->Name())) / 2;
283
284 if ( num == current ) {
285 Rect hilite( x + 2, yoff, listboxw - 4, ItemHeight() );
286 hilite.Clip( area );
287 surface->FillRectAlpha( hilite, surface->GetFGPen() );
288 }
289
290 // print node name and clip to box
291 PrintItem( n, surface, xoff, yoff + 1, box );
292
293 yoff += ItemHeight();
294 if ( yoff >= box.y + box.h ) break;
295
296 ++num;
297 n = static_cast<TLWNode *>( n->Next() );
298 }
299
300 font->SetColor( fcol );
301 }
302
303 ////////////////////////////////////////////////////////////////////////
304 // NAME : TextListWidget::PrintItem
305 // DESCRIPTION: Print one item of the list widget. This can be used to
306 // customize the look of the list, e.g. colour and font.
307 // The item height must keep the same, though.
308 // PARAMETERS : item - node to print
309 // dest - destination surface
310 // x - left edge of printing area
311 // y - top edge of printing area
312 // clip - clipping rectangle
313 // RETURNS : -
314 ////////////////////////////////////////////////////////////////////////
315
PrintItem(const TLWNode * item,Surface * dest,short x,short y,const Rect & clip) const316 void TextListWidget::PrintItem( const TLWNode *item, Surface *dest,
317 short x, short y, const Rect &clip ) const {
318 font->Write( item->Name(), dest, x, y, clip );
319 }
320
321
322 ////////////////////////////////////////////////////////////////////////
323 // NAME : StringWidget::StringWidget
324 // DESCRIPTION: Create a new StringWidget.
325 // PARAMETERS : id - widget identifier
326 // x - left edge of widget
327 // y - top edge of widget
328 // w - widget width
329 // h - widget height
330 // str - string to display
331 // maxlen - maximum length of string in characters (not
332 // including the trailing NUL-byte)
333 // flags - widget flags (see widget.h for details)
334 // title - widget title
335 // window - widget parent window
336 // RETURNS : -
337 ////////////////////////////////////////////////////////////////////////
338
StringWidget(short id,short x,short y,unsigned short w,unsigned short h,const char * str,unsigned short maxlen,unsigned short flags,const char * title,Window * window)339 StringWidget::StringWidget( short id, short x, short y, unsigned short w,
340 unsigned short h, const char *str,
341 unsigned short maxlen, unsigned short flags,
342 const char *title, Window *window ) :
343 Widget( id, x, y, w, h, flags, title, window ),
344 cursor(0), maxlen(maxlen), offset(0),
345 strbox(x+4,y+(h-font->Height())/2,w-8,font->Height()),
346 validator(0) {
347 SetString( str, false );
348 }
349
350 ////////////////////////////////////////////////////////////////////////
351 // NAME : StringWidget::SetString
352 // DESCRIPTION: Set a new string to display in the widget.
353 // PARAMETERS : newstr - string to display (may be NULL)
354 // upd - whether to update the display (default value
355 // is "true")
356 // RETURNS : -
357 ////////////////////////////////////////////////////////////////////////
358
SetString(const char * newstr,bool upd)359 void StringWidget::SetString( const char *newstr, bool upd /* = true */ ) {
360 if ( newstr ) buffer.assign( newstr );
361 else buffer.erase();
362
363 if ( upd ) {
364 Draw();
365 Show();
366 }
367 }
368
369 ////////////////////////////////////////////////////////////////////////
370 // NAME : StringWidget::String
371 // DESCRIPTION: Get the current string.
372 // PARAMETERS : -
373 // RETURNS : pointer to the string, or NULL if string is empty
374 ////////////////////////////////////////////////////////////////////////
375
String(void) const376 const char *StringWidget::String( void ) const {
377 if ( !buffer.empty() ) return buffer.c_str();
378 return NULL;
379 }
380
381 ////////////////////////////////////////////////////////////////////////
382 // NAME : StringWidget::Draw
383 // DESCRIPTION: Draw the widget.
384 // PARAMETERS : -
385 // RETURNS : -
386 ////////////////////////////////////////////////////////////////////////
387
Draw(void)388 void StringWidget::Draw( void ) {
389 Rect clip;
390 surface->DrawBack( *this );
391 if ( !(flags & WIDGET_STYLE_NOBORDER ) )
392 surface->DrawBox( *this, BOX_RECESSED );
393 surface->GetClipRect( clip );
394 surface->SetClipRect( strbox );
395
396 if ( Clicked() )
397 surface->FillRect( strbox.x + CursorPos(), strbox.y,
398 CursorWidth(), font->Height(), surface->GetFGPen() );
399
400 short xoff = strbox.x - offset;
401 if ( flags & WIDGET_STR_PASSWORD ) {
402 unsigned short starw = font->CharWidth('*');
403 unsigned short len = buffer.size();
404
405 for ( int i = 0; i < len; ++i ) {
406 if ( Clicked() && (cursor == i) )
407 font->Write( '*', surface, xoff, strbox.y, surface->GetBGPen() );
408 else font->Write( '*', surface, xoff, strbox.y );
409 xoff += starw;
410 }
411
412 } else {
413 font->Write( buffer.c_str(), surface, strbox.x - offset, strbox.y, strbox );
414 if ( Clicked() && (cursor < buffer.size()) ) {
415 font->Write( buffer[cursor], surface, strbox.x + CursorPos(), strbox.y, surface->GetBGPen() );
416 }
417 }
418
419 surface->SetClipRect( clip );
420 PrintTitle( surface->GetFGPen() );
421 }
422
423 ////////////////////////////////////////////////////////////////////////
424 // NAME : StringWidget::MouseDown
425 // DESCRIPTION: React to mouse button presses.
426 // PARAMETERS : button - SDL_MouseButtonEvent received from the event
427 // handler
428 // RETURNS : GUI status
429 ////////////////////////////////////////////////////////////////////////
430
MouseDown(const SDL_MouseButtonEvent & button)431 GUI_Status StringWidget::MouseDown( const SDL_MouseButtonEvent &button ) {
432 if ( (button.button == SDL_BUTTON_LEFT) && !(flags & WIDGET_STR_CONST) &&
433 Contains( button.x - surface->LeftEdge(),
434 button.y - surface->TopEdge() ) ) {
435 short xoff = button.x - surface->LeftEdge() - x;
436 unsigned short len = buffer.size();
437
438 cursor = 0;
439 while ( (cursor < len) && (CursorPos() + CursorWidth() < xoff) )
440 ++cursor;
441
442 short curpix = CursorPos();
443 if ( curpix < 0 ) offset -= curpix;
444 else if ( curpix + CursorWidth() >= strbox.w ) {
445 offset += curpix + CursorWidth() - strbox.w;
446 }
447
448 return InputLoop();
449 }
450 return GUI_OK;
451 }
452
453 ////////////////////////////////////////////////////////////////////////
454 // NAME : StringWidget::KeyDown
455 // DESCRIPTION: React to key presses.
456 // PARAMETERS : key - SDL_keysym received from the event handler
457 // RETURNS : GUI status
458 ////////////////////////////////////////////////////////////////////////
459
KeyDown(const SDL_keysym & key)460 GUI_Status StringWidget::KeyDown( const SDL_keysym &key ) {
461 if ( (key.sym == this->key) && !(flags & WIDGET_STR_CONST) ) {
462 unsigned short buflen = font->TextWidth( buffer.c_str() );
463
464 cursor = buffer.size();
465 offset = MAX( 0, buflen + CursorWidth() - strbox.w );
466 return InputLoop();
467 }
468 return GUI_OK;
469 }
470
471 ////////////////////////////////////////////////////////////////////////
472 // NAME : StringWidget::InputLoop
473 // DESCRIPTION: After activation of the StringWidget, all events are
474 // exclusively handled by this function, until the
475 // widget is deselected at which point the control is given
476 // back to the main event handler.
477 // PARAMETERS : -
478 // RETURNS : GUI status
479 ////////////////////////////////////////////////////////////////////////
480
InputLoop(void)481 GUI_Status StringWidget::InputLoop( void ) {
482 SDL_Event event;
483 GUI_Status rc = GUI_OK;
484 int unicode;
485 bool quit = false;
486
487 Push();
488 unicode = SDL_EnableUNICODE( 1 );
489
490 do {
491 rc = surface->GetView()->FetchEvent( event );
492 if ( (rc == GUI_QUIT) || (rc == GUI_ERROR) ) quit = true;
493 else {
494 if ( ((event.type == SDL_MOUSEBUTTONDOWN) &&
495 !Contains( event.button.x - x, event.button.y - y )) ||
496 ((event.type == SDL_KEYUP) && ((event.key.keysym.sym == SDLK_RETURN) ||
497 (event.key.keysym.sym == SDLK_TAB))) ) {
498 quit = true;
499 } else if ( event.type == SDL_KEYDOWN ) {
500 CharInput( event.key.keysym.sym, event.key.keysym.unicode );
501 }
502 }
503 } while ( !quit );
504
505 cursor = offset = 0;
506
507 SDL_EnableUNICODE( unicode );
508 Release();
509 if ( hook ) hook->WidgetActivated( this, surface );
510 return rc;
511 }
512
513 ////////////////////////////////////////////////////////////////////////
514 // NAME : StringWidget::CharInput
515 // DESCRIPTION: Insert a new character in the input buffer.
516 // PARAMETERS : sym - ASCII symbol for printable characters
517 // unicode - UNICODE representation for non-printable chars
518 // RETURNS : -
519 ////////////////////////////////////////////////////////////////////////
520
CharInput(short sym,unsigned short unicode)521 void StringWidget::CharInput( short sym, unsigned short unicode ) {
522 bool changed = false;
523
524 if ( unicode ) {
525 switch ( unicode ) {
526 case '\b': // BACKSPACE - delete char at cursor-1
527 if ( cursor > 0 ) {
528 buffer.erase( --cursor, 1 );
529 changed = true;
530 }
531 break;
532 case 127: // DELETE - delete char at cursor
533 if ( cursor < buffer.size() ) {
534 buffer.erase( cursor, 1 );
535 changed = true;
536 }
537 break;
538 default:
539 if ( buffer.size() < maxlen ) { // insert char at cursor pos
540 bool accept = (validator ?
541 validator->ValidateKey( buffer.c_str(), unicode, cursor ) :
542 isprint(unicode) != 0 );
543 if ( accept ) {
544 buffer.insert( cursor++, 1, unicode );
545 changed = true;
546 }
547 }
548 }
549 } else switch ( sym ) {
550 case SDLK_LEFT: // move cursor left
551 if ( cursor > 0 ) {
552 --cursor;
553 changed = true;
554 }
555 break;
556 case SDLK_RIGHT:
557 if ( cursor < buffer.size() ) {
558 ++cursor;
559 changed = true;
560 }
561 break;
562 default:
563 break;
564 }
565
566 if ( changed ) {
567 short curpix = CursorPos();
568 if ( curpix < 0 ) offset += curpix;
569 else if ( curpix + CursorWidth() >= strbox.w )
570 offset += curpix + CursorWidth() - strbox.w;
571
572 Draw();
573 Show();
574 }
575 }
576
577 ////////////////////////////////////////////////////////////////////////
578 // NAME : StringWidget::CursorWidth
579 // DESCRIPTION: Get width of cursor in pixels.
580 // PARAMETERS : -
581 // RETURNS : cursor width
582 ////////////////////////////////////////////////////////////////////////
583
CursorWidth(void) const584 unsigned short StringWidget::CursorWidth( void ) const {
585 unsigned short curw;
586
587 if ( flags & WIDGET_STR_PASSWORD ) curw = font->CharWidth('*');
588 else if ( cursor < buffer.size() ) curw = font->CharWidth( buffer[cursor] );
589 else curw = font->Width();
590
591 return curw;
592 }
593
594 ////////////////////////////////////////////////////////////////////////
595 // NAME : StringWidget::CursorPos
596 // DESCRIPTION: Get position of cursor on display in pixels.
597 // PARAMETERS : -
598 // RETURNS : cursor position (- current offset)
599 ////////////////////////////////////////////////////////////////////////
600
CursorPos(void) const601 short StringWidget::CursorPos( void ) const {
602 unsigned short cp;
603 if ( flags & WIDGET_STR_PASSWORD )
604 cp = cursor * font->CharWidth('*');
605 else {
606 cp = font->TextWidth(buffer.substr(0, cursor + 1).c_str());
607 if ( buffer.size() > cursor ) cp -= CursorWidth();
608 }
609 return cp - offset;
610 }
611
612 ////////////////////////////////////////////////////////////////////////
613 // NAME : StringWidget::DispWidth
614 // DESCRIPTION: Get width of a character in pixels.
615 // PARAMETERS : ch - glyph to measure
616 // RETURNS : character width
617 ////////////////////////////////////////////////////////////////////////
618
DispWidth(short ch) const619 unsigned short StringWidget::DispWidth( short ch ) const {
620 unsigned short cw;
621
622 if ( flags & WIDGET_STR_PASSWORD ) cw = font->CharWidth('*');
623 else cw = font->CharWidth( ch );
624
625 return cw;
626 }
627
628 ////////////////////////////////////////////////////////////////////////
629 // NAME : StringWidget::SetFocus
630 // DESCRIPTION: Activate the widget, i.e. show the cursor and wait for
631 // user input.
632 // PARAMETERS : -
633 // RETURNS : GUI status
634 ////////////////////////////////////////////////////////////////////////
635
SetFocus(void)636 GUI_Status StringWidget::SetFocus( void ) {
637 cursor = 0;
638 return InputLoop();
639 }
640
641
642 ////////////////////////////////////////////////////////////////////////
643 // NAME : NumberWidget::NumberWidget
644 // DESCRIPTION: Create a new NumberWidget.
645 // PARAMETERS : id - widget identifier
646 // x - left edge of widget
647 // y - top edge of widget
648 // w - widget width
649 // h - widget height
650 // number - initial value to display
651 // min - minimum allowed value
652 // max - maximum allowed value
653 // flags - widget flags (see widget.h for details)
654 // title - widget title
655 // window - widget parent window
656 // RETURNS : -
657 ////////////////////////////////////////////////////////////////////////
658
NumberWidget(short id,short x,short y,unsigned short w,unsigned short h,long number,long min,long max,unsigned short flags,const char * title,Window * window)659 NumberWidget::NumberWidget( short id, short x, short y, unsigned short w, unsigned short h,
660 long number, long min, long max, unsigned short flags,
661 const char *title, Window *window ) :
662 StringWidget( id, x, y, w, h, itoa(number, numbuf), strlen(itoa(max,numbuf2)),
663 flags, title, window ) {
664 num = number;
665 minval = min;
666 maxval = max;
667 SetValidator( this );
668 }
669
670 ////////////////////////////////////////////////////////////////////////
671 // NAME : NumberWidget::SetNumber
672 // DESCRIPTION: Fill the widget with a value.
673 // PARAMETERS : number - new widget value
674 // upd - whether to update the display (default is true)
675 // RETURNS : -
676 ////////////////////////////////////////////////////////////////////////
677
SetNumber(long number,bool upd)678 void NumberWidget::SetNumber( long number, bool upd /* = true */ ) {
679 num = MIN( MAX( minval, number ), maxval );
680
681 SetString( itoa( num, numbuf ), upd );
682 }
683
684 ////////////////////////////////////////////////////////////////////////
685 // NAME : NumberWidget::ValidateKey
686 // DESCRIPTION: Only accept numbers for input.
687 // PARAMETERS : str - string currently entered in widget (not used)
688 // key - char to be entered
689 // pos - position at which to enter the char
690 // RETURNS : TRUE if key is accepted, FALSE if refused
691 ////////////////////////////////////////////////////////////////////////
692
ValidateKey(const char * str,unsigned short key,unsigned short pos) const693 bool NumberWidget::ValidateKey( const char *str, unsigned short key,
694 unsigned short pos ) const {
695 return ((key >= '0') && (key <= '9')) || ((key == '-') && (pos == 0));
696 }
697
698 ////////////////////////////////////////////////////////////////////////
699 // NAME : NumberWidget::SetMin
700 // DESCRIPTION: Set a new minimum value.
701 // PARAMETERS : min - new minimum
702 // RETURNS : -
703 ////////////////////////////////////////////////////////////////////////
704
SetMin(long min)705 void NumberWidget::SetMin( long min ) {
706 minval = min;
707
708 if ( Number() < min ) SetNumber( min );
709 }
710
711 ////////////////////////////////////////////////////////////////////////
712 // NAME : NumberWidget::SetMax
713 // DESCRIPTION: Set a new maximum value.
714 // PARAMETERS : max - new maximum
715 // RETURNS : -
716 ////////////////////////////////////////////////////////////////////////
717
SetMax(long max)718 void NumberWidget::SetMax( long max ) {
719 maxval = max;
720
721 if ( Number() > max ) SetNumber( max );
722 }
723
724 ////////////////////////////////////////////////////////////////////////
725 // NAME : NumberWidget::Release
726 // DESCRIPTION: When the widget is released make sure the number which
727 // was entered is inside the requested boundaries and
728 // adjust it if necessary.
729 // PARAMETERS : -
730 // RETURNS : -
731 ////////////////////////////////////////////////////////////////////////
732
Release(void)733 void NumberWidget::Release( void ) {
734 const char *str = String();
735 short n = (str ? atoi(str) : 0);
736 SetNumber( n );
737 StringWidget::Release();
738 }
739
740
741 ////////////////////////////////////////////////////////////////////////
742 // NAME : TLWNode::TLWNode
743 // DESCRIPTION: Create a new TextListWidget node.
744 // PARAMETERS : name - name to be displayed in TextListWidget
745 // data - arbitrary data for private use by caller
746 // id - node identifier; this is not used internally
747 // either and may be used by the caller
748 // RETURNS : -
749 ////////////////////////////////////////////////////////////////////////
750
TLWNode(const char * name,void * data,unsigned short id)751 TLWNode::TLWNode( const char *name, void *data, unsigned short id ) :
752 name(name), id(id), user_data(data) {
753 }
754
TLWNode(const char * name,void * data)755 TLWNode::TLWNode( const char *name, void *data ) :
756 name(name), id(0), user_data(data) {
757 }
758
TLWNode(const char * name)759 TLWNode::TLWNode( const char *name ) :
760 name(name), id(0), user_data(0) {
761 }
762
763 ////////////////////////////////////////////////////////////////////////
764 // NAME : TLWList::Sort
765 // DESCRIPTION: Sort the list in ascending alphabetical order.
766 // PARAMETERS : -
767 // RETURNS : -
768 ////////////////////////////////////////////////////////////////////////
769
Sort(void)770 void TLWList::Sort( void ) {
771 TLWList s;
772
773 while ( !IsEmpty() )
774 s.AddHead( RemHead() );
775
776 while ( !s.IsEmpty() )
777 InsertNodeSorted( static_cast<TLWNode *>(s.RemTail()) );
778 }
779
780 ////////////////////////////////////////////////////////////////////////
781 // NAME : TLWList::InsertNodeSorted
782 // DESCRIPTION: Insert a node into the list according to its name.
783 // Nodes will be sorted in ascending alphabetical order.
784 // PARAMETERS : n - TextListWidget node to be inserted
785 // RETURNS : -
786 ////////////////////////////////////////////////////////////////////////
787
InsertNodeSorted(TLWNode * n)788 void TLWList::InsertNodeSorted( TLWNode *n ) {
789 TLWNode *walk = static_cast<TLWNode *>( Tail() );
790
791 while ( walk && (strcmp( n->Name(), walk->Name()) < 0) )
792 walk = static_cast<TLWNode *>( walk->Prev() );
793
794 InsertNode( n, walk );
795 }
796
797 ////////////////////////////////////////////////////////////////////////
798 // NAME : TLWList::GetNodeByID
799 // DESCRIPTION: Retrieve the node with the given ID from the list.
800 // PARAMETERS : id - requested node identifier
801 // RETURNS : pointer to the node, or NULL if not found
802 ////////////////////////////////////////////////////////////////////////
803
GetNodeByID(unsigned short id) const804 TLWNode *TLWList::GetNodeByID( unsigned short id ) const {
805 TLWNode *walk = static_cast<TLWNode *>( Head() );
806
807 while ( walk && (walk->ID() != id) )
808 walk = static_cast<TLWNode *>( walk->Next() );
809
810 return walk;
811 }
812
813