1 /*
2      PLIB - A Suite of Portable Game Libraries
3      Copyright (C) 1998,2002  Steve Baker
4 
5      This library is free software; you can redistribute it and/or
6      modify it under the terms of the GNU Library General Public
7      License as published by the Free Software Foundation; either
8      version 2 of the License, or (at your option) any later version.
9 
10      This library is distributed in the hope that it will be useful,
11      but WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Library General Public License for more details.
14 
15      You should have received a copy of the GNU Library General Public
16      License along with this library; if not, write to the Free Software
17      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18 
19      For further information visit http://plib.sourceforge.net
20 
21      $Id: puAuxLargeInput.cxx 2068 2006-03-20 15:17:35Z fayjf $
22 */
23 
24 
25 #include "puAuxLocal.h"
26 
UL_RTTI_DEF2(puaLargeInput,puInputBase,puGroup)27 UL_RTTI_DEF2(puaLargeInput,puInputBase,puGroup)
28 
29 
30 // Callbacks from the internal widgets
31 
32 static void puaLargeInputHandleRightSlider ( puObject *slider )
33 {
34   float val = ((puaScrollBar *)slider)->getMaxValue () - slider->getFloatValue () ;
35 
36   puaLargeInput* text = (puaLargeInput*) slider->getUserData () ;
37   //int lines_in_window = text->getLinesInWindow () ;
38   int num_lines = text->getNumLines () ;
39 
40   if ( num_lines > 0 )
41     text->setTopLineInWindow ( int ( val + 0.5f ) ) ;
42 }
43 
44 // Private function from the widget itself
45 
normalizeCursors(void)46 void puaLargeInput::normalizeCursors ( void )
47 {
48   puInputBase::normalizeCursors () ;
49 
50   // Set the top line in the window so that the last line is at the bottom of the window
51 
52   if ( top_line_in_window > num_lines - lines_in_window + 2 )
53     top_line_in_window = num_lines - lines_in_window + 2 ;
54 
55   if ( top_line_in_window < 0 ) top_line_in_window = 0 ;
56 }
57 
removeSelectRegion(void)58 void puaLargeInput::removeSelectRegion ( void )
59 {
60   puInputBase::removeSelectRegion () ;
61 
62   wrapText () ;
63 }
64 
65 
66 // Public functions from the widget itself
67 
puaLargeInput(int x,int y,int w,int h,int arrows,int sl_width,int wrap_text)68 puaLargeInput::puaLargeInput ( int x, int y, int w, int h, int arrows, int sl_width, int wrap_text ) :
69     puInputBase (), puGroup ( x, y )
70 {
71   setColour ( PUCOL_MISC, 0.1f, 0.1f, 1.0f ) ; // Colour of the 'I' bar cursor
72 
73   // Set the variables
74 
75   type |= PUCLASS_LARGEINPUT ;
76   num_lines = 1 ;
77   slider_width = sl_width ;
78   lines_in_window = ( h - (bottom_slider?slider_width:0) ) /
79                     ( getLegendFont().getStringHeight() + getLegendFont().getStringDescender() + 1 ) ;
80   top_line_in_window = 0 ;
81   max_width = 0 ;
82 
83   widget = this ;
84 
85   // Set up the widgets
86 
87   frame = new puFrame ( 0, 0, w, h );
88 
89   if ( wrap_text )
90     bottom_slider = (puSlider *)NULL ;
91   else
92   {
93     bottom_slider = new puSlider ( 0, 0, w - slider_width, FALSE, slider_width ) ,
94     bottom_slider->setValue ( 0.0f ) ;   // All the way to the left
95 //    bottom_slider->setDelta(0.1f); // Commented out CBModes and Deltas for these sliders to increase response time and to ensure the sliders react properly even when first selected - JCJ 13 Jun 2002
96     bottom_slider->setSliderFraction (1.0f) ;
97 //    bottom_slider->setCBMode( PUSLIDER_DELTA );
98   }
99 
100   right_slider = new puaScrollBar ( w - slider_width, (bottom_slider?slider_width:0),
101                                     h - (bottom_slider?slider_width:0), arrows, TRUE, slider_width ) ,
102   right_slider->setValue ( 1.0f ) ;    // All the way to the top
103 //  right_slider->setDelta(0.1f);
104   right_slider->setSliderFraction (1.0f) ;
105   right_slider->setStepSize ( 1.0f ) ;
106 //  right_slider->setCBMode( PUSLIDER_DELTA );
107   right_slider->setUserData ( this ) ;
108   right_slider->setCallback ( puaLargeInputHandleRightSlider ) ;
109 
110   setValue ( "\n" ) ;
111 
112   close  () ;
113   reveal () ;
114 }
115 
setSize(int w,int h)116 void puaLargeInput::setSize ( int w, int h )
117 {
118   // Resize the frame:
119   frame->setSize ( w, h ) ;
120 
121   // Resize and reposition the sliders
122   if ( bottom_slider )
123     bottom_slider->setSize ( w - slider_width, slider_width ) ;
124   else  // No bottom slider, rewrap the text
125     wrapText () ;
126 
127   right_slider->setPosition ( w-slider_width, (bottom_slider?slider_width:0) ) ;
128   right_slider->setSize ( slider_width, h-(bottom_slider?slider_width:0) ) ;
129 
130   lines_in_window = ( h - (bottom_slider?slider_width:0) ) /
131                     ( getLegendFont().getStringHeight() + getLegendFont().getStringDescender() + 1 ) ;
132 
133   int line_size = legendFont.getStringHeight () +     // Height of a line
134                   legendFont.getStringDescender() ;  // of text, in pixels
135   int box_height = ( abox.max[1] - abox.min[1] - slider_width ) / line_size ;
136   int right_slider_max = num_lines - lines_in_window + 1 ;
137   if ( right_slider_max < 1 ) right_slider_max = 1 ;
138 
139   right_slider->setSliderFraction ( float(box_height) / float(right_slider_max) ) ;
140   right_slider->setMaxValue ( float(right_slider_max) ) ;
141 }
142 
setSelectRegion(int s,int e)143 void puaLargeInput::setSelectRegion ( int s, int e )
144 {
145   select_start_position = s ;
146   select_end_position   = e ;
147   char *lin_ptr = ( bottom_slider ? getStringValue () : getDisplayedText () ) ;
148   char *text_start = lin_ptr ;
149 
150   if ( num_lines > lines_in_window )
151   {
152     int select_start_line = 0 ;
153     while ( lin_ptr && ( lin_ptr <= text_start + select_start_position ) )  // Count the lines
154     {
155       select_start_line++ ;
156       lin_ptr = strchr ( lin_ptr+1, '\n' ) ;
157     }
158 
159     int select_end_line = select_start_line ;
160     while ( lin_ptr && ( lin_ptr <= text_start + select_end_position ) )  // Count the lines
161     {
162       select_end_line++ ;
163       lin_ptr = strchr ( lin_ptr+1, '\n' ) ;
164     }
165 
166     if ( select_end_line > top_line_in_window + lines_in_window )
167       top_line_in_window = select_end_line - lines_in_window - 1 ;
168 
169     if ( select_start_line < top_line_in_window )
170       top_line_in_window = select_start_line - 1 ;
171 
172     if ( top_line_in_window < 0 ) top_line_in_window = 0 ;
173 
174     right_slider->setValue ( num_lines - lines_in_window - top_line_in_window ) ;
175   }
176 }
177 
selectEntireLine(void)178 void  puaLargeInput::selectEntireLine ( void )
179 {
180   char *temp_text = ( bottom_slider ? getStringValue () : getDisplayedText () ) ;
181 
182   if ( select_start_position < 0 )
183       select_start_position = 0 ;
184 
185   if ( ( *(temp_text + select_start_position + 1) != '\n' ) &&
186        ( *(temp_text + select_start_position) != '\0' ) )
187     select_start_position ++ ;
188 
189   while ( ( select_start_position > 0 ) && ( *(temp_text + select_start_position) != '\n' ) )
190     select_start_position -- ;
191 
192   if ( select_start_position > 0 )
193     select_start_position++ ;
194 
195   select_end_position = int ( strchr ( temp_text + select_end_position, '\n' ) + 1 - temp_text) ;
196   if ( select_end_position <= 1 ) select_end_position = strlen ( temp_text ) ;
197   //else select_end_position = int ( select_end_position - temp_text ) ;/** Needs real fixing **/
198 
199   puPostRefresh () ;
200 }
201 
addNewLine(const char * l)202 void  puaLargeInput::addNewLine ( const char *l )
203 {
204   char *text = getStringValue () ;
205   if ( cursor_position > 0 )  // If not at start of line, go to start of next line
206     cursor_position = int (strchr ( text + cursor_position - 1, '\n' ) - text + 1) ;
207 
208   select_end_position = select_start_position = cursor_position ;
209   addText ( l ) ;
210 }
211 
addText(const char * l)212 void  puaLargeInput::addText ( const char *l )
213 {
214   char *text = getStringValue () ;
215 
216   if ( l == NULL ) return ;
217 
218   int l_len = strlen ( l ) ;
219   int text_len = strlen ( text ) ;
220   int length = l_len + text_len  /* Length of the final string */
221                + select_start_position - select_end_position + 2 ;
222   if ( *(l+l_len-1) == '\n' ) length -- ;           // Decrement "length" for each final
223   if ( text[select_end_position] == '\n' ) length -- ;  // carriage return already there
224 
225   char *temp_text = new char [ length ] ;
226 
227   memcpy ( temp_text, text, select_start_position ) ;
228   memcpy ( temp_text + select_start_position, l, l_len + 1 ) ;  /* Plus one to get the final '\0' */
229   int temp_text_len = select_start_position + l_len ;
230 
231   if ( ( *(l+l_len-1) == '\n' ) && ( text[select_end_position] == '\n' ) )
232   {
233     temp_text[temp_text_len-1] = '\0' ;  /* Erase the duplicate carriage return */
234     temp_text_len -- ;
235   }
236   else if ( ( *(l+l_len-1) != '\n' ) && ( text[select_end_position] != '\n' ) )
237   {
238     strcpy ( temp_text + temp_text_len, "\n" ) ;  /* Add a carriage return */
239     temp_text_len ++ ;
240   }
241 
242   memcpy ( temp_text + temp_text_len, text + select_end_position, text_len - select_end_position + 1 ) ;
243   int temp_select_start = select_start_position ;
244   setValue ( temp_text ) ;
245   delete [] temp_text ;
246   setSelectRegion ( temp_select_start,
247                     temp_select_start + strlen(l) ) ;
248   setCursor ( select_end_position ) ;
249 }
250 
appendText(const char * l)251 void  puaLargeInput::appendText ( const char *l )
252 {
253   if ( !l ) return ;
254 
255   int str_val_len = strlen ( getStringValue () ) ;
256   int l_len = strlen ( l ) ;
257   if ( str_val_len == 1 ) str_val_len = 0 ;  /* Don't want null line at the beginning */
258   int length = str_val_len + l_len + 2 ;
259   if ( *(l+l_len-1) == '\n' ) length -- ;  /* Already have a trailing carriage return, decrement the length */
260 
261   char *temp_text = new char [ length ] ;
262   int temp_text_len ;
263 
264   if ( str_val_len > 0 )  /* More than just the empty carriage return */
265   {
266     memcpy ( temp_text, getStringValue (), str_val_len ) ;
267     temp_text_len = str_val_len ;
268   }
269   else
270     temp_text_len = 0 ;
271 
272   memcpy ( temp_text + temp_text_len, l, l_len + 1 ) ;  /* Plus one to get the final '\0' */
273   temp_text_len += l_len ;
274   if ( *(l+l_len-1) != '\n' )
275   {
276     strcpy ( temp_text + temp_text_len, "\n" ) ;
277     temp_text_len ++ ;
278   }
279 
280   setValue ( temp_text ) ;
281   setSelectRegion ( str_val_len, temp_text_len ) ;
282   setCursor ( str_val_len ) ;
283   delete [] temp_text ;
284 }
285 
removeText(int start,int end)286 void  puaLargeInput::removeText ( int start, int end )
287 {
288   int str_val_len = strlen ( getStringValue () ) ;
289   char *temp_text = new char [ str_val_len + start - end + 1 ] ;
290   memcpy ( temp_text, getStringValue (), start ) ;
291   memcpy ( temp_text + start, getStringValue ()+end, str_val_len - end + 1 ) ;  /* Plus one to get the final '\0' */
292   setValue ( temp_text ) ;
293   setCursor ( start ) ;
294   setSelectRegion ( start, start ) ;
295   delete [] temp_text ;
296 }
297 
setValue(const char * s)298 void  puaLargeInput::setValue ( const char *s )
299 {
300   if ( bottom_slider ) bottom_slider->setSliderFraction ( 0.0f ) ;
301   right_slider->setSliderFraction ( 0.0f ) ;
302 
303   if ( s == NULL )
304   {
305     puValue::setValue ( "\n" ) ;
306     num_lines = 0 ;
307     cursor_position = select_start_position = select_end_position = 0 ;
308     return ;
309   }
310 
311   int s_len = strlen ( s ) ;
312   int length = s_len + 2 ;
313   if ( ( s_len > 0 ) && ( *(s+s_len-1) == '\n' ) )
314     length -- ;  /* Already have a trailing carriage return, don't need to add one */
315 
316   char *text = new char [ length ] ;
317   memcpy ( text, s, s_len + 1 ) ;  /* Plus one to get the final '\0' */
318   if ( ( s [ 0 ] == '\0' ) || ( *(s+s_len-1) != '\n' ) )
319     strcpy ( text + s_len, "\n" ) ;
320 
321   puValue::setValue ( text ) ;
322   delete [] text ;
323 
324   // Find the greatest width of a line
325   max_width = 0 ;
326 
327   float line_width = 0.0f ;       // Width of current line
328   if ( !bottom_slider ) wrapText () ;
329   char *this_char = ( bottom_slider ? getStringValue () : getDisplayedText () ) ;   // Pointer to character in text
330 
331   num_lines = 0 ;
332 
333   while ( *this_char != '\0' )
334   {
335     char *line_end = strchr ( this_char, '\n' ) ;
336     if ( line_end )  // Found an end-of-line
337     {
338       *line_end = '\0' ;  // Temporary break in line
339       line_width = legendFont.getFloatStringWidth ( this_char ) ;
340       *line_end = '\n' ;  // Reset the carriage return
341 
342       if ( max_width < line_width )
343         max_width = line_width ;
344 
345       num_lines++ ;                 // Increment line counter
346 
347       this_char = line_end + 1 ;
348     }
349     else  // No carriage return.  Since a carriage return should be the last character,
350       this_char++ ;        // we should not get here.
351   }
352 
353   if ( max_width < line_width )
354     max_width = line_width ;
355 
356   // Set slider fractions
357 
358   int line_size = legendFont.getStringHeight () +     // Height of a line
359                   legendFont.getStringDescender() ;  // of text, in pixels
360 
361   int box_width = abox.max[0] - abox.min[0] - slider_width ;   // Input box width, in pixels
362   int box_height = ( abox.max[1] - abox.min[1] - slider_width ) / line_size ;
363                                                 // Input box height, in lines
364 
365   if ( bottom_slider )
366     bottom_slider->setSliderFraction ( float(box_width) / float(max_width) ) ;
367 
368   int right_slider_max = num_lines - lines_in_window + 1 ;
369   if ( right_slider_max < 1 ) right_slider_max = 1 ;
370 
371   right_slider->setSliderFraction ( float(box_height) / float(right_slider_max) ) ;
372   right_slider->setMaxValue ( float(right_slider_max) ) ;
373 
374   // Normalize the cursors
375   normalizeCursors () ;
376 }
377 
378 
draw(int dx,int dy)379 void puaLargeInput::draw ( int dx, int dy )
380 {
381   if ( !visible || ( window != puGetWindow () ) ) return ;
382   normalizeCursors () ;
383 
384   // 3D Input boxes look nicest if they are always in inverse style.
385 
386   abox.draw ( dx, dy, ( (style==PUSTYLE_SMALL_BEVELLED ||
387                          style==PUSTYLE_SMALL_SHADED) ) ? -style :
388                         (accepting ? -style : style ), colour, FALSE, border_thickness ) ;
389 
390   if ( r_cb )
391     r_cb ( this, dx, dy, render_data ) ;
392   else
393   {
394     // Calculate window parameters:
395 
396     int xwidget = abox.min[0] + dx ;
397     int ywidget = abox.min[1] + dy ;
398 
399     int line_size = legendFont.getStringHeight () +         // Height of a line
400                     legendFont.getStringDescender() + 1 ;  // of text, in pixels
401 
402     int xx = int(legendFont.getFloatStringWidth ( " " )) ;
403     int yy = int( abox.max[1] - abox.min[1] - legendFont.getStringHeight () * 1.5f ) ;
404 
405     int box_width = abox.max[0] - abox.min[0] - slider_width - xx - xx ;   // Input box width, in pixels
406     int box_height = ( abox.max[1] - abox.min[1] - (bottom_slider?slider_width:0) ) / line_size ;
407                                                   // Input box height, in lines
408 
409     float bottom_value = bottom_slider ? bottom_slider->getFloatValue () : 0.0f ;
410 
411     int beg_pos      // Position in window of start of line, in pixels
412                 = int(( box_width - max_width ) * bottom_value ) ;
413 ////  int end_pos      // Position in window of end of line, in pixels
414 ////              = beg_pos + max_width - 1 ;
415     if ( top_line_in_window < 0 ) top_line_in_window = 0 ;
416     int end_lin      // Position on line count of bottom of window, in lines
417                 = top_line_in_window + box_height ;
418 
419    /* Removed IF statement to permit highlighting to remain even when widget not active - JCJ 13 Jun 2002 */
420 
421     char *val = bottom_slider ? getStringValue () : getDisplayedText () ;
422 
423     // Highlight the select area
424 
425     if ( select_end_position > 0 &&
426           select_end_position != select_start_position )
427     {
428        // First:  find the positions on the window of the selection start and end
429 
430        char temp_char = val[ select_start_position ] ;
431        val [ select_start_position ] = '\0' ;
432 
433        xx = dx + abox.min[0] + int(legendFont.getFloatStringWidth ( " " )) ;
434        yy = (int)( abox.max[1] - abox.min[1] - legendFont.getStringHeight () * 1.5f
435                + top_line_in_window * line_size ) ;   // Offset y-coord for unprinted lines
436 
437        char *end_of_line = strchr ( val, '\n' ) ;
438        char *start_of_line = val;
439 
440        // Step down the lines until you reach the line with the selection start
441 
442        int select_start_line = 0 ;
443 
444        while ( end_of_line )
445        {
446          select_start_line++ ;
447          start_of_line = end_of_line + 1 ;
448          yy -= line_size ;
449          end_of_line = strchr ( start_of_line, '\n' ) ;
450        }
451 
452        int start_pos = int(legendFont.getFloatStringWidth ( start_of_line )) + xx +
453                        beg_pos ;   // Start of selection
454 
455        val [ select_start_position ] = temp_char ;
456 
457        // Now repeat the process for the end of the selection.
458 
459        temp_char = val[ select_end_position ] ;
460        val [ select_end_position ] = '\0' ;
461 
462        end_of_line = strchr ( start_of_line, '\n' ) ;
463 
464        // Step down the lines until you reach the line with the selection end
465 
466        int select_end_line = select_start_line ;
467 
468        while ( end_of_line )
469        {
470          select_end_line++ ;
471          start_of_line = end_of_line + 1 ;
472          end_of_line = strchr ( start_of_line, '\n' ) ;
473        }
474 
475        int end_pos = int(legendFont.getFloatStringWidth ( start_of_line )) + xx +
476                      beg_pos ;   // End of selection
477 
478        val [ select_end_position ] = temp_char ;
479 
480        // Now draw the selection area.
481 
482        for ( int line_count = select_start_line ; ( ( line_count <= select_end_line ) && ( line_count <= end_lin ) ) ;
483                  line_count++ )
484        {
485          if ( line_count >= top_line_in_window )
486          {
487            int x_start, x_end ;
488 
489            if ( line_count == select_start_line )
490              x_start = ( start_pos > xx ) ? start_pos : xx ;
491            else
492              x_start = xx ;
493 
494            x_start = ( x_start < abox.max[0] + dx ) ? x_start : abox.max[0] + dx ;
495 
496            if ( line_count == select_end_line )
497              x_end = ( end_pos < abox.max[0] + dx ) ? end_pos : abox.max[0] + dx ;
498            else
499              x_end = abox.max[0] + dx ;
500 
501            x_end = ( x_end > xx ) ? x_end : xx ;
502 
503            int top = dy + abox.min[1] + yy + legendFont.getStringHeight () ;
504            int bot = dy + abox.min[1] + yy - legendFont.getStringDescender() ;
505 
506            glColor3f ( 1.0f, 1.0f, 0.7f ) ;
507            glRecti ( x_start, bot, x_end, top ) ;
508          }
509 
510          yy -= line_size ;
511          if ( line_count == end_lin ) break ;
512        }
513      }
514 
515 
516     // Draw the text
517 
518     {
519       // If greyed out then halve the opacity when drawing the text
520 
521       if ( active )
522         glColor4fv ( colour [ PUCOL_LEGEND ] ) ;
523       else
524         glColor4f ( colour [ PUCOL_LEGEND ][0],
525                     colour [ PUCOL_LEGEND ][1],
526                     colour [ PUCOL_LEGEND ][2],
527                     colour [ PUCOL_LEGEND ][3] / 2.0f ) ; // 50% more transparent
528 
529       char *val ;                   // Pointer to the actual text in the box
530       val = bottom_slider ? getStringValue () : getDisplayedText () ;
531 
532       if ( val )
533       {
534         char *end_of_line = strchr (val, '\n') ;
535         int line_count = 0;
536 
537         xx = int(legendFont.getFloatStringWidth ( " " )) ;
538         yy = int( abox.max[1] - abox.min[1] - legendFont.getStringHeight () * 1.5f ) ;
539 
540         while ( end_of_line )  // While there is a carriage return in the string
541         {
542           if ( line_count < top_line_in_window )
543           {                                        // Before the start of the window
544             val = end_of_line + 1 ;
545             end_of_line = strchr (val, '\n') ;     // Just go to the next line
546           }
547           else if ( line_count <= end_lin )        // Within the window, draw it
548           {
549             char temp_char = *end_of_line ;   // Temporary holder for last char on line
550 
551             *end_of_line = '\0' ;     // Make end-of-line be an end-of-string
552 
553             int start_pos = beg_pos ;
554             int end_pos      // Position in window of end of line, in pixels
555                     = start_pos + int(legendFont.getFloatStringWidth ( val )) ;
556 
557             if ( end_pos > start_pos )  // If we actually have text in the line
558             {
559                 char * lastonleft = val ;
560                 char * firstonright = end_of_line ;
561                 int leftpos = start_pos ;
562                 int rightpos = end_pos ;
563                 while ( lastonleft < firstonright - 1 )
564                 {
565                     int chpos = -leftpos * ( firstonright - lastonleft ) / ( rightpos - leftpos ) + 1;
566                     if ( chpos >= firstonright - lastonleft ) chpos = firstonright - lastonleft - 1 ;
567                     char placeholder = *(lastonleft + chpos) ;
568                     *(lastonleft + chpos) = '\0' ;
569                     int strwidth = legendFont.getStringWidth ( val ) ;
570                     *(lastonleft + chpos) = placeholder ;
571                     if ( strwidth + start_pos < 0 ) /* Still to the left of the window */
572                     {
573                         lastonleft = lastonleft + chpos ;
574                         placeholder = *lastonleft ;
575                         *lastonleft = '\0' ;
576                         leftpos = start_pos + legendFont.getStringWidth ( val ) ;
577                         *lastonleft = placeholder ;
578                     }
579                     else
580                     {
581                         firstonright = lastonleft + chpos ;
582                         placeholder = *firstonright ;
583                         *firstonright = '\0' ;
584                         rightpos = start_pos + legendFont.getStringWidth ( val ) ;
585                         *firstonright = placeholder ;
586                     }
587                 }
588                 if ( leftpos >= 0 )
589                 {
590                   val = lastonleft ;
591                   start_pos = leftpos ;
592                 }
593                 else
594                 {
595                   val = firstonright ;
596                   start_pos = rightpos ;
597                 }
598             }
599 
600             while ( end_pos > box_width )  // Step up the line until it is in the window
601             {
602               *end_of_line = temp_char ;
603               end_of_line-- ;
604               temp_char = *end_of_line ;
605               *end_of_line = '\0' ;
606               end_pos = start_pos + legendFont.getStringWidth ( val ) ;
607             }
608 
609             if ( val < end_of_line )                 // If any text shows in the window,
610               legendFont.drawString ( val,           // draw it.
611                                       dx + abox.min[0] + xx + start_pos,
612                                       dy + abox.min[1] + yy ) ;
613 
614             *end_of_line = temp_char ;     // Restore the end-of-line character
615 
616             if ( temp_char != '\n' )               // If we had to step up from the end of
617               end_of_line = strchr (val, '\n') ;   // the line, go back to the actual end
618 
619             yy -= line_size ;
620             val = end_of_line + 1 ;
621             end_of_line = strchr (val, '\n') ;     // On to the next line
622           }
623           else if ( line_count > end_lin )        // Have gone beyond window, end process
624             end_of_line = NULL ;
625 
626           line_count++ ;
627 
628         }     // while ( end_of_line )
629       }     // if ( val )
630     }
631 
632     if ( accepting )
633     {
634       char *val ;                   // Pointer to the actual text in the box
635       val = bottom_slider ? getStringValue () : getDisplayedText () ;
636 
637       // Draw the 'I' bar cursor.
638 
639       if ( val && ( cursor_position >= 0 ) )
640       {
641         char temp_char = val[ cursor_position ] ;
642         val [ cursor_position ] = '\0' ;
643 
644         xx = int(legendFont.getFloatStringWidth ( " " )) ;
645         yy = int( abox.max[1] - abox.min[1] - legendFont.getStringHeight () * 1.5f )
646                 + top_line_in_window * line_size ;   // Offset y-coord for unprinted lines
647 
648         char *end_of_line = strchr ( val, '\n' ) ;
649         char *start_of_line = val ;
650 
651         // Step down the lines until you reach the line with the cursor
652 
653         int line_count = 1 ;
654 
655         while ( end_of_line )
656         {
657           line_count++ ;
658           start_of_line = end_of_line + 1 ;
659           yy -= line_size ;
660           end_of_line = strchr ( start_of_line, '\n' ) ;
661         }
662 
663         if ( ( line_count > top_line_in_window ) && ( line_count <= end_lin ) )
664         {
665           int begpos      // Position in window of start of line, in pixels
666                     = int( ( box_width - max_width ) * bottom_value ) ;
667           int cpos = int( legendFont.getFloatStringWidth ( start_of_line ) + xx +
668                      abox.min[0] + begpos ) ;
669           int top = int( abox.min[1] + yy + legendFont.getStringHeight () ) ;
670           int bot = int( abox.min[1] + yy - legendFont.getStringDescender () ) ;
671           if ( ( cpos > abox.min[0] ) && ( cpos < abox.max[0] ) )
672           {
673             glColor4fv ( colour [ PUCOL_MISC ] ) ;
674             glBegin   ( GL_LINES ) ;
675             glVertex2i ( dx + cpos    , dy + bot ) ;
676             glVertex2i ( dx + cpos    , dy + top ) ;
677             glVertex2i ( dx + cpos - 1, dy + bot ) ;
678             glVertex2i ( dx + cpos - 1, dy + top ) ;
679             glVertex2i ( dx + cpos - 4, dy + bot ) ;
680             glVertex2i ( dx + cpos + 3, dy + bot ) ;
681             glVertex2i ( dx + cpos - 4, dy + top ) ;
682             glVertex2i ( dx + cpos + 3, dy + top ) ;
683             glEnd      () ;
684           }
685         }
686 
687         val[ cursor_position ] = temp_char ;
688       }
689     }
690 
691     // Draw the other widgets in the large input box
692 
693     if ( bottom_slider ) bottom_slider->draw ( xwidget, ywidget ) ;
694     right_slider->draw ( xwidget, ywidget ) ;
695   }
696 
697   draw_label ( dx, dy ) ;
698 }
699 
700 
checkHit(int button,int updown,int x,int y)701 int puaLargeInput::checkHit ( int button, int updown, int x, int y )
702 {
703   int xwidget = x - abox.min[0] ;
704   int ywidget = y - abox.min[1] ;
705 
706   if ( bottom_slider )
707   {
708     if ( bottom_slider->checkHit ( button, updown, xwidget, ywidget ) ) return TRUE ;
709   }
710 
711   if ( right_slider->checkHit ( button, updown, xwidget, ywidget ) ) return TRUE ;
712 
713   // If the user has clicked within the bottom slider or to its right, don't activate.
714 
715   if ( y < slider_width ) return FALSE ;
716 
717   if ( puObject::checkHit ( button, updown, x, y ) )
718     return TRUE ;
719 
720   return FALSE ;
721 }
722 
723 
doHit(int button,int updown,int x,int y)724 void puaLargeInput::doHit ( int button, int updown, int x, int y )
725 {
726   if ( puActiveWidget() && ( this != puActiveWidget() ) )
727   {
728     // Active widget exists and is not this one; call its down callback if it exists
729 
730     puActiveWidget()->invokeDownCallback () ;
731     puDeactivateWidget () ;
732   }
733 
734   if ( updown != PU_DRAG )
735     puMoveToLast ( this );
736 
737   if ( button == active_mouse_button )
738   {
739     // Most GUI's activate a button on button-UP not button-DOWN.
740 
741     // Text and window parameters:
742 
743     int line_size = legendFont.getStringHeight () +         // Height of a line
744                     legendFont.getStringDescender() + 1 ;  // of text, in pixels
745 
746     int box_width = abox.max[0] - abox.min[0] - slider_width ;   // Input box width, in pixels
747 //  int box_height = ( abox.max[1] - abox.min[1] ) / line_size ;
748                                                // Input box height, in lines
749 
750     float bottom_value = bottom_slider ? bottom_slider->getFloatValue () : 0.0f ;
751 
752     int beg_pos      // Position in window of start of line, in pixels
753                 = int( ( box_width - max_width ) * bottom_value ) ;
754 //  int end_pos      // Position in window of end of line, in pixels
755 //              = (int)( beg_pos + max_width - 1 ) ;
756     if ( top_line_in_window < 0 ) top_line_in_window = 0 ;
757 //  int end_lin      // Position on line count of bottom of window, in lines
758 //              = top_line_in_window + box_height - 1 ;
759 
760 //  int xx = legendFont.getStringWidth ( " " ) ;
761     int yy = int( abox.max[1] - legendFont.getStringHeight () * 1.5f
762             + top_line_in_window * line_size ) ;   // Offset y-coord for unprinted lines
763 
764     // Get the line number and position on the line of the mouse
765 
766     char *strval = bottom_slider ? getStringValue () : getDisplayedText () ;
767     char *tmpval = ulStrDup ( strval ) ;
768 
769     int i = strlen ( tmpval ) ;
770 
771     char *end_of_line = strchr ( tmpval, '\n' ) ;
772     char *start_of_line = tmpval;
773 
774     // Step down the lines until the y-coordinate is less than the mouse
775 
776     int line_count = 0 ;
777 
778     while ( ( yy > y ) && end_of_line )
779     {
780       line_count++ ;
781       start_of_line = end_of_line + 1 ;
782       yy -= line_size ;
783       end_of_line = strchr ( start_of_line, '\n' ) ;
784     }
785 
786     if ( end_of_line )
787     {
788       *end_of_line = '\0' ;
789 
790       i = strlen ( tmpval ) ;
791 
792       int length, prev_length = 0 ;
793       while ( x <= (length = legendFont.getStringWidth ( start_of_line )
794                     + abox.min[0] + beg_pos) &&
795               i > 0 )
796       {
797         prev_length = length ;
798         tmpval[--i] = '\0' ;
799       }
800 
801       if ( ( x - length ) < ( prev_length - x ) )
802         i-- ;   // Mouse is closer to previous character than next character
803     }
804 
805     // Now process the mouse click itself.
806 
807     if ( updown == active_mouse_edge || active_mouse_edge == PU_UP_AND_DOWN )
808     {
809       lowlight () ;
810 
811       accepting = TRUE ;
812       cursor_position = i ;
813       normalizeCursors () ;
814       puSetActiveWidget ( this, x, y ) ;
815       invokeCallback () ;
816     }
817     else if ( updown == PU_DOWN )
818     {
819       // We get here if the active edge is not down but the mouse button has
820       // been pressed.  Start a selection.
821 
822       select_start_position = i ;
823       select_end_position = i ;
824     }
825     else if ( updown == PU_DRAG )
826     {
827       // Drag -- extend the selection.
828 
829       if ( (select_end_position - i) > (i - select_start_position) )
830         select_start_position = i ;   // Cursor closer to start than to end
831       else
832         select_end_position = i ;     // Cursor closer to end than to start
833 
834       if (select_start_position > select_end_position)
835       {
836         i = select_end_position ;
837         select_end_position = select_start_position ;
838         select_start_position = i ;
839       }
840     }
841     else
842       highlight () ;
843 
844     delete [] tmpval ;
845   }
846   else
847     lowlight () ;
848 }
849 
checkKey(int key,int updown)850 int puaLargeInput::checkKey ( int key, int updown )
851 {
852   if ( updown == PU_UP || !isAcceptingInput () || !isActive () ||
853        !isVisible () || ( window != puGetWindow () ) )
854     return FALSE ;
855 
856   if ( puActiveWidget() && ( this != puActiveWidget() ) )
857   {
858     // Active widget exists and is not this one; call its down callback if it exists
859 
860     puActiveWidget()->invokeDownCallback () ;
861     puDeactivateWidget () ;
862   }
863 
864   normalizeCursors () ;
865 
866   //char *old_text = getStringValue () ;
867   char *old_text = bottom_slider ? getStringValue () : getDisplayedText () ;
868   int lines_in_window = getLinesInWindow () ;  /* Added lines_in_window and num_lines to allow for "END" */
869   int num_lines = getNumLines () ;             /* and PGUP/DOWN to work properly        - JCJ 20 Jun 2002 */
870   int line_width = 0 ;                         /* Width of current line (for bottomslider) */
871   int line_width_to_cursor = 0 ;               /* Width of current line up to the cursor position */
872   int prev_line_width = 0 ;                    /* Width of previous line (for left mouse arrow) */
873   int i = 1;                                   /* Happy useful variable */
874   int line_counter = 0 ;                       /* Happy useful variable #2 */
875   int box_width = abox.max[0] - abox.min[0] - slider_width ;   /* Text box width */
876   int tmp_cursor_position = cursor_position ;  /* Temporary cursor position for counting without moving the cursor */
877   int bottom_line_in_window = 0;                  /* # of bottom line in window */
878   int current_line_in_window = 0;                 /* Current line # in window */
879   char *line_end = 0 ;
880   char* p = new char[ strlen(old_text)+1 ] ;
881   float bottom_value = bottom_slider ? bottom_slider->getFloatValue () : 0.0f ; /* Value of the bottom slider */
882   if ( old_text[1] != '\0' ) /* Ensure that we don't delete something that doesn't exist! - JCJ 22 July 2002 */
883   {
884     /*Count how many characters from the beginning of the line the cursor is*/
885     while ( ( old_text [ cursor_position - i ] != '\n' ) &&
886              ( i < cursor_position ) )
887      i++ ;            /* Step back to the beginning of the line */
888     if ( i < cursor_position ) i-- ;
889 
890     /*Find the length of the current line*/
891     while ( ( old_text [ tmp_cursor_position ] != '\n' ) &&
892              ( tmp_cursor_position > 0) )
893       tmp_cursor_position-- ;
894 
895     strcpy ( p, ( old_text + tmp_cursor_position + 1 ) ) ;
896     if ( bottom_slider )
897     {
898       line_end = strchr ( p, '\n' ) ;
899       if ( line_end )  // Found an end-of-line
900       {
901         *line_end = '\0' ;  // Temporary break in line
902         line_width = int(legendFont.getFloatStringWidth ( p )) ;
903         *line_end = '\n' ;  // Reset the carriage return
904       }
905       /*Now delete all characters in the string beyond i, and re-find its width*/
906       p [i+1] = '\0' ;
907       line_width_to_cursor = int(legendFont.getFloatStringWidth ( p )) ;
908     }
909 
910     /* Now find the length of the previous line */
911     tmp_cursor_position-- ;
912     while ( ( old_text [ tmp_cursor_position ] != '\n' ) &&
913             ( tmp_cursor_position > 0) )
914       tmp_cursor_position-- ;
915 
916     strcpy ( p, ( old_text + tmp_cursor_position + 1 ) ) ;
917     if ( bottom_slider )
918     {
919       line_end = strchr ( p, '\n' ) ;
920       if ( line_end )  /*Actually, we KNOW there's a line after this one, but hey, let's be safe, eh? - JCJ 21 Jun 2002 */
921       {
922         *line_end = '\0' ;  // Temporary break in line
923         prev_line_width = legendFont.getStringWidth ( p ) ;
924         *line_end = '\n' ;  // Reset the carriage return
925       }
926     }
927 
928     delete [] p  ;
929     p = NULL ;
930   }
931 
932   bool done = true ;
933 
934   switch ( key )
935   {
936   case PU_KEY_PAGE_UP   :
937     while ( old_text [ cursor_position ] != '\0' ) /* Move the cursor to the top of the data */
938       cursor_position-- ;
939     select_start_position = select_end_position = cursor_position ;
940     setTopLineInWindow ( top_line_in_window - lines_in_window + 2 ) ;
941     right_slider->setValue (1.0f - float(top_line_in_window) / num_lines ) ;
942     break;
943   case PU_KEY_PAGE_DOWN :
944     while ( old_text [ cursor_position ] != '\0' ) /* Move the cursor to the end of the data */
945       cursor_position++ ;
946     select_start_position = select_end_position = cursor_position ;
947     setTopLineInWindow ( top_line_in_window + lines_in_window - 2 ) ; /* Plus two for consistency - JCJ 20 Jun 2002 */
948     right_slider->setValue (1.0f - float(top_line_in_window) / num_lines ) ;
949     break;
950   case PU_KEY_INSERT    : return FALSE ;
951 
952   case PU_KEY_UP   :
953   case PU_KEY_DOWN :
954     /* Determine the current line, the line at the top of the window, and the line at the bottom.*/
955     bottom_line_in_window = top_line_in_window + getLinesInWindow() ;
956     while ( line_counter < cursor_position) {
957       if ( old_text [ line_counter ] == '\n' ) current_line_in_window++ ;
958       line_counter++ ;
959     }
960     if ( key == PU_KEY_UP )
961     {
962       // Step backwards to the beginning of the previous line
963       cursor_position -= (i + 2) ;
964       while ( ( old_text [ cursor_position ] != '\n' ) &&
965               ( cursor_position > 0 ) )
966         cursor_position-- ;
967       if ( cursor_position > 0 ) cursor_position++ ;
968 
969       // Step down the line "i" spaces or to the end of the line
970       while ( ( old_text [ cursor_position ] != '\n' ) &&
971               ( i > 0 ) )
972       {
973         cursor_position++ ;
974         i-- ;
975       }
976       if (current_line_in_window <= top_line_in_window) {
977           setTopLineInWindow ( top_line_in_window - 1 ); /* Go up - JCJ 21 Jun 2002 */
978           right_slider->setValue (1.0f - float(top_line_in_window) / num_lines ) ;
979       }
980     }
981     else   // Down-arrow key
982     {
983       // Skip to beginning of next line
984       while ( old_text [ cursor_position ] != '\n' && old_text [ cursor_position ] != '\0' )
985         cursor_position++ ;
986       cursor_position++ ;
987 
988       // Step down the line "i" spaces or to the end of the line
989       // or to the end of the text
990 
991       while ( ( old_text [ cursor_position ] != '\n' ) &&
992               ( cursor_position < (int)strlen ( old_text ) ) &&
993               ( i > 0 ) )
994       {
995         cursor_position++ ;
996         i-- ;
997       }
998       if ((current_line_in_window+1) >= bottom_line_in_window) {
999           setTopLineInWindow ( top_line_in_window + 1 ); /* Go down - JCJ 21 Jun 2002 */
1000           right_slider->setValue (1.0f - float(top_line_in_window) / num_lines ) ;
1001       }
1002 
1003     }
1004 
1005     select_start_position = select_end_position = cursor_position ;
1006     break ;
1007 
1008   case 0x1B :  // ESC
1009   case '\t' :  // TAB  -- End of input
1010     rejectInput () ;
1011     normalizeCursors () ;
1012     invokeCallback () ;
1013     puDeactivateWidget () ;
1014     break ;
1015 
1016   case PU_KEY_HOME   :
1017     while ( ( old_text [ cursor_position-1 ] != '\n' )  &&
1018               ( cursor_position > 0 ) )               /* Move the cursor to the start of the line, but minus one so */
1019       cursor_position-- ;                             /* it does not find a \n immediately if located at the end.   */
1020     select_start_position = select_end_position = cursor_position ; /* Also corrects overshoots.  - JCJ 20 Jun 2002 */
1021     if ( bottom_slider ) bottom_slider->setValue ( 0.0f ) ;
1022     break ;
1023   case PU_KEY_END    :
1024     if (bottom_slider)
1025     {
1026       bottom_slider->setValue ( ( (line_width - box_width)<0 ) ? 0.0f : float(line_width+10) / max_width);
1027     }
1028     while ( old_text [ cursor_position ] != '\n' ) /* Move the cursor to the end of the line - JCJ 20 Jun 2002 */
1029       cursor_position++ ;
1030     select_start_position = select_end_position = cursor_position ;
1031     break ;
1032 
1033   case PU_KEY_LEFT   :
1034   case PU_KEY_RIGHT  :
1035     if ( key == PU_KEY_LEFT )
1036       {
1037 	/* This stops it crashing out sometimes when wrappable text is used.
1038 	 * Since there is no bottom scrollbar when wrapped text is turned on, the bottom
1039 	 * slider code could make the application die when the user pressed the left
1040 	 * cursor key before they began the first line.
1041 	 * Fix by Simon <sickz6sickz AT hotmail DOT com> */
1042 	cursor_position-- ; /* Left key pressed */
1043 	if ( bottom_slider )
1044 	  {
1045 	    if (old_text [ cursor_position ] == '\n')
1046 	      bottom_slider->setValue( ( (prev_line_width - box_width)<0 ) ? 0.0f : float(prev_line_width+10) /max_width);
1047 	    /* If the cursor is going off the left edge of the box, scroll left. */
1048 	    else if ((bottom_value*max_width) > line_width_to_cursor+5) {
1049 	      bottom_slider->setValue( ((bottom_value*max_width)-(box_width/2)-5)<0 ? 0.0f :
1050 				       ((bottom_value*max_width)-(box_width/2)-5)/max_width ) ;
1051 	    }
1052 	  }
1053       } else {
1054 	cursor_position++ ; /* Right key pressed */
1055 	if ( bottom_slider ) {
1056 	  if (old_text [ cursor_position-1 ] == '\n')
1057 	    bottom_slider->setValue(0.0f) ;
1058 	  else if ((bottom_value*max_width)+(box_width) < line_width_to_cursor+5) {
1059 	    bottom_slider->setValue( ((bottom_value*max_width)+(box_width/2)+5)/max_width ) ;
1060 	  }
1061 	}
1062       }
1063     select_start_position = select_end_position = cursor_position ;
1064     break ;
1065 
1066   default :
1067     done = false ;
1068     break ;
1069   }
1070 
1071   if ( ! done && ! input_disabled )
1072   {
1073     char *p = NULL ;
1074     int temp_cursor = cursor_position ;
1075 
1076     switch ( key )
1077     {
1078     case '\b' :  // Backspace
1079       if ( select_start_position != select_end_position )
1080         removeSelectRegion () ;
1081       else if ( cursor_position > 0 )
1082       {
1083         p = new char [ strlen(old_text) ] ;
1084         memcpy ( p, old_text, cursor_position ) ;
1085         --cursor_position ;
1086         strcpy ( p + cursor_position, old_text + cursor_position + 1 ) ;
1087         setValue ( p ) ;
1088         setCursor ( temp_cursor - 1 ) ;
1089         delete [] p ;
1090       }
1091 
1092       break ;
1093 
1094     case 0x7F :  // DEL
1095       if ( select_start_position != select_end_position )
1096         removeSelectRegion () ;
1097       else if (cursor_position != (int)strlen ( old_text ) )
1098       {
1099         p = new char [ strlen(old_text) ] ;
1100         memcpy ( p, old_text, cursor_position ) ;
1101         strcpy ( p + cursor_position, old_text + cursor_position + 1 ) ;
1102         setValue ( p ) ;
1103         setCursor ( temp_cursor ) ;
1104         delete [] p ;
1105       }
1106 
1107       break ;
1108 
1109     case 0x15 /* ^U */ : getStringValue () [ 0 ] = '\0' ; break ;
1110     case 0x03 /* ^C */ :
1111     case 0x18 /* ^X */ :  /* Cut or copy selected text */
1112       if ( select_start_position != select_end_position )
1113       {
1114         extern void puSetPasteBuffer ( const char *ch ) ;
1115         p = getStringValue () ;
1116         char ch = p[select_end_position] ;
1117         p[select_end_position] = '\0' ;
1118         puSetPasteBuffer ( p + select_start_position ) ;
1119         p[select_end_position] = ch ;
1120 
1121         if ( key == 0x18 )  /* Cut, remove text from string */
1122           removeSelectRegion () ;
1123       }
1124 
1125       break ;
1126 
1127     case 0x16 /* ^V */ : /* Paste buffer into text */
1128       {
1129         extern char *puGetPasteBuffer () ;
1130         if ( select_start_position != select_end_position )
1131           removeSelectRegion () ;
1132 
1133         if ( puGetPasteBuffer () )  // Make sure something has been cut previously!
1134         {
1135           int str_val_len = strlen ( getStringValue () ) ;
1136           int paste_len = strlen ( puGetPasteBuffer () ) ;
1137           p = new char [ str_val_len + paste_len + 1 ] ;
1138           memcpy ( p, getStringValue (), cursor_position ) ;
1139           memcpy ( p + cursor_position, puGetPasteBuffer (), paste_len ) ;
1140           memcpy ( p + cursor_position + paste_len, getStringValue() + cursor_position, str_val_len - cursor_position + 1 ) ;
1141           temp_cursor += paste_len ;
1142           setValue ( p ) ;
1143           setCursor ( temp_cursor ) ;
1144           delete [] p ;
1145         }
1146       }
1147 
1148       break ;
1149 
1150     default:
1151       if ( ( key < ' ' || key > 127 ) && ( key != '\n' )
1152                                       && ( key != '\r' ) ) return FALSE ;
1153 
1154       if ( key == '\r' ) key = '\n' ;
1155 
1156       if ( valid_data )
1157       {
1158         if ( !strchr ( valid_data, key ) ) return TRUE ;
1159       }
1160 
1161       if ( select_start_position != select_end_position ) // remove selected text
1162       {
1163         temp_cursor -= ( select_end_position - select_start_position ) ;
1164         removeSelectRegion () ;
1165       }
1166 
1167       p = new char [ strlen(old_text) + 2 ] ;
1168 
1169       memcpy ( p, old_text, cursor_position ) ;
1170 
1171       p [ cursor_position ] = key ;
1172 
1173       strcpy ( p + cursor_position + 1, ( old_text + cursor_position ) ) ;
1174       bottom_line_in_window = top_line_in_window + getLinesInWindow() ;
1175 
1176       /* If running off the screen, scroll right. - JCJ 28 Jun 2002 */
1177       if ((bottom_value*max_width)+(box_width) < line_width_to_cursor+5) {
1178           bottom_slider->setValue( ((bottom_value*max_width)+(box_width/2)+5)/max_width ) ;
1179       }
1180 
1181       if (key == '\n') {
1182       /* If pressing enter, figure out which line this is. */
1183           while ( line_counter < cursor_position) {
1184               if ( old_text [ line_counter ] == '\n' ) current_line_in_window++ ;
1185               line_counter++ ;
1186           }
1187       /* If hitting enter at the bottom of the screen, scroll down. - JCJ 28 Jun 2002 */
1188           if ( (current_line_in_window+1) >= bottom_line_in_window ) {
1189               setTopLineInWindow ( top_line_in_window + 1 );
1190               right_slider->setValue (1.0f - float(top_line_in_window) / num_lines ) ;
1191           }
1192       }
1193 
1194       setValue ( p ) ;
1195       setCursor ( temp_cursor + 1 ) ;
1196       delete [] p ;
1197 
1198       break ;
1199     }
1200   }
1201 
1202   normalizeCursors () ;
1203   return TRUE ;
1204 }
1205 
wrapText(void)1206 void puaLargeInput::wrapText ( void )
1207 {
1208   // Wrap the text in "text" and put it in "displayed_text"
1209 
1210   delete [] displayed_text ;
1211   displayed_text = ulStrDup ( getStringValue () ) ;
1212 
1213   char *displayed_text_wp = displayed_text,
1214        *space_ptr,
1215        *old_space_ptr ;
1216 
1217   /* Somewhat inspired by tuxracer */
1218   while ( *displayed_text_wp != '\0' )
1219   {
1220     old_space_ptr = NULL ;
1221     space_ptr = strchr ( displayed_text_wp, ' ' ) ;
1222 
1223     while (1)
1224     {
1225       if ( space_ptr != NULL )
1226         *space_ptr = '\0' ;
1227 
1228       if ( legendFont.getStringWidth ( displayed_text_wp ) >
1229            (   ( abox.max[0] - abox.min[0] )
1230              - slider_width
1231              - PUSTR_LGAP
1232              - ( getStyle () == PUSTYLE_BOXED ? getBorderThickness () : 0 )
1233              - PUSTR_RGAP
1234            )
1235          )
1236         break ;
1237 
1238       old_space_ptr = space_ptr ;
1239 
1240       if ( space_ptr == NULL )
1241         /* Entire string fits in widget */
1242         break ;
1243 
1244       // Check for carriage return in the original string
1245       if ( strrchr ( displayed_text_wp, '\n' ) > displayed_text_wp )
1246         displayed_text_wp = strrchr ( displayed_text_wp, '\n' ) + 1 ;
1247 
1248       *space_ptr = ' ' ;
1249 
1250       space_ptr = strchr ( space_ptr+1, ' ' ) ;
1251     }
1252 
1253     if ( old_space_ptr == NULL )
1254     /* Either string is too wide for area, or the entire remaining portion
1255        of string fits in area (space_ptr == NULL). */
1256     {
1257       displayed_text_wp += strlen (displayed_text_wp) ;
1258 
1259       if ( space_ptr != NULL )
1260       /* Advance past the NULL since there's more string left */
1261         displayed_text_wp += 1 ;
1262     }
1263     else
1264     {
1265       if ( space_ptr != NULL )
1266         *space_ptr = ' ' ;
1267       *old_space_ptr = '\n' ;
1268 
1269       displayed_text_wp = old_space_ptr + 1 ;
1270     }
1271   }
1272 }
1273 
1274 
1275