• Main Page
  • Related Pages
  • Classes
  • Files
  • File List
  • File Members

label.cc

00001 /*
00002    $Id: label.cc,v 1.13 2008/05/28 22:04:13 ksterker Exp $
00003 
00004    (C) Copyright 2000/2001/2004 Joel Vennin
00005    Part of the Adonthell Project http://adonthell.linuxgames.com
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License.
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY.
00011 
00012    See the COPYING file for more details
00013 */
00014 
00015 #include "label.h"
00016 
00017 u_int16 label::cursor_blink_cycle = 75; 
00018 
00019 /**
00020    Constructor
00021 */
00022 label::label () : image ()
00023 {
00024     // no font at the beginning
00025     my_font_ = NULL;
00026     new_text_ = "";
00027     
00028     // init the cursor and the text vector
00029     init_vec_cursor (); 
00030     
00031     // set my default form
00032     set_form (NOTHING); 
00033     
00034     set_cursor_visible (false); 
00035 
00036     set_cursor_moveable (false); 
00037     
00038     cursor_cur_blink_ = 0;
00039 
00040     set_mask (true);
00041 }
00042 
00043 
00044 /**
00045    Destructor
00046 */
00047 label::~label ()
00048 {
00049 }
00050 
00051 
00052 /**
00053    Set the font
00054 */
00055 void label::set_font (win_font & font)
00056 {
00057     my_font_ = &font; 
00058     //  build (true); 
00059 }
00060 
00061 
00062 /**
00063    Set the text 
00064 */
00065 void label::set_text (const string & text)
00066 {
00067     // init the vector and the cursor
00068     init_vec_cursor ();
00069     
00070     my_old_cursor_ = my_cursor_;
00071     
00072     // set the text
00073     my_text_ = text;
00074     my_cursor_.idx = my_text_.length ();  
00075     
00076     // build the vector
00077     build (true);
00078 }
00079 
00080 
00081 
00082 /**
00083    Add text
00084 */
00085 void label::add_text (const string & text)
00086 {
00087     new_text_ += text;
00088     
00089     // collect more text if we have unfinished utf8
00090     int size = new_text_.length ();
00091     if (size == 2 && (u_int8) new_text_[0] >= 0xE0) return;
00092     if (size == 1 && (u_int8) new_text_[0] >= 0x80) return;
00093 
00094     my_old_cursor_ = my_cursor_; 
00095     
00096     if (my_old_cursor_.idx == my_text_.length ()) 
00097     {
00098         my_text_ += new_text_;
00099         my_cursor_.idx = my_text_.length (); 
00100     }
00101     else my_text_.insert (my_cursor_.idx, new_text_);
00102     new_text_ = "";
00103     
00104     build (false);
00105 }
00106 
00107 
00108 /**
00109    REsize the label
00110 */
00111 void label::resize (u_int16 l, u_int16 h)
00112 {
00113     image::resize (l, h); 
00114     set_text (my_text_); 
00115 }
00116 
00117 
00118 /**
00119    Set the form
00120 */
00121 void label::set_form (const u_int8 form)
00122 {
00123     my_form_ = form;
00124     build (true); 
00125 }
00126 
00127 
00128 /**
00129    Init vector and cursor
00130 */
00131 void label::init_vec_cursor ()
00132 {
00133     // init the cursor
00134     my_cursor_.pos_x = my_cursor_.pos_y = my_cursor_.line = my_cursor_.idx = 0;  
00135     
00136     // init the vector
00137     my_vect_.clear ();
00138     
00139     // create a line in the vector
00140     Sline_text tmp;
00141     tmp.pos_x = tmp.idx_beg = tmp.idx_end = 0; 
00142     
00143     // add the new line at the beginning of the vector
00144     my_vect_.push_back (tmp);
00145     
00146     // the beginning of the display line,  0 is the first line
00147     start_line_ = 0;
00148 }
00149 
00150 
00151 
00152 /**
00153    Update the vector 
00154    start :  it's the index where the function must start to update
00155 */
00156 
00157 void label::build (const bool erase_all)
00158 {
00159     if (my_font_ == NULL) return; 
00160     set_mask (false);  
00161     switch (my_form_)
00162     {
00163         case NOTHING :
00164             build_form_nothing (); 
00165             update_cursor ();
00166             draw_string (!erase_all); 
00167             break;  
00168             
00169         case AUTO_HEIGHT : 
00170             build_form_auto_height ();
00171             update_cursor ();
00172             draw_string (!erase_all); 
00173             break;
00174             
00175         case AUTO_SIZE :
00176             build_form_auto_size ();
00177             update_cursor ();
00178             draw_string (false);
00179             break; 
00180     }
00181     set_mask (true); 
00182 }
00183 
00184 
00185 
00186 /**
00187    Set if cursor is visible
00188 */
00189 void label::set_cursor_visible (const bool b)
00190 {
00191     visible_cursor_ = b; 
00192 }
00193 
00194 
00195 /**
00196    Set the cursor moveable with arrow
00197 */
00198 void label::set_cursor_moveable (const bool b)
00199 {
00200    moveable_cursor_ = b;   
00201 }
00202 
00203 
00204 /**
00205    Build the label when the form set top nothing
00206 */ 
00207 void label::build_form_nothing ()
00208 {
00209     // temporary variable
00210     u_int16 j, word_length, word_length_pix, start_idx;
00211     
00212     // temporary line
00213     Sline_text line_tmp;
00214     
00215     // we start at the beginning index of cursor line
00216     line_tmp.idx_beg = my_vect_[my_old_cursor_.line].idx_beg;  
00217     line_tmp.pos_x = 0;
00218 
00219     // we start always at the begin index of the line
00220     start_idx = line_tmp.idx_beg;   
00221     
00222     // erase the vector 
00223     vector <Sline_text>::iterator ii = my_vect_.begin ();
00224     u_int16 i = 0; 
00225     while (i != my_old_cursor_.line) { i++; ii++; } 
00226     my_vect_.erase (ii, my_vect_.end ());
00227 
00228     
00229     while (start_idx < my_text_.length () )
00230     { 
00231         // if cur letter is an \n
00232         if (my_text_[start_idx] == '\n')
00233         {
00234             // the last index of this line
00235             line_tmp.idx_end = start_idx;
00236             
00237             // add to the vector line 
00238             my_vect_.push_back (line_tmp); 
00239             
00240             // init a Sline_text
00241             line_tmp.pos_x = 0; 
00242             line_tmp.idx_beg = ++start_idx; 
00243         }
00244         else if (my_text_[start_idx] == ' ')
00245         {
00246             if ((*my_font_) [' '].length () + line_tmp.pos_x > length ())
00247             {
00248                 line_tmp.idx_end = start_idx;
00249                 
00250                 // add to the vector line 
00251                 my_vect_.push_back (line_tmp); 
00252                 
00253                 // init a Sline_text
00254                 line_tmp.pos_x = 0;
00255                 line_tmp.idx_beg = ++start_idx; 
00256                 
00257             } else 
00258             {
00259                 line_tmp.pos_x += (*my_font_) [' '].length ();
00260                 start_idx++;
00261             }
00262         }
00263         else
00264         { 
00265             // find a word
00266             
00267             switch (find_word (start_idx, word_length, word_length_pix, line_tmp.pos_x))
00268             {
00269                 case 0 : // enough place
00270                     line_tmp.pos_x += word_length_pix;
00271                     break;
00272                     
00273                 case 1 : // enough place,  but return at the next line 
00274                     // here we erase end of the last line
00275 
00276                     if (length () && height ())
00277                     {
00278                         
00279                         lock ();
00280                         fillrect (line_tmp.pos_x,
00281                                   (my_vect_.size () - start_line_) * my_font_->height (),
00282                                   length () - line_tmp.pos_x,
00283                                   my_font_->height (), screen::trans_col () );  
00284                         unlock (); 
00285                     }
00286                     line_tmp.idx_end = (start_idx - word_length) - 1;   
00287                     my_vect_.push_back (line_tmp); 
00288                     
00289                     line_tmp.pos_x = word_length_pix; 
00290                     line_tmp.idx_beg = start_idx - word_length;
00291                     
00292                     break;
00293                     
00294                 case 2 : // not enough place
00295                     
00296                     j = start_idx - word_length;
00297                     while (j < start_idx)
00298                     {
00299                         u_int16 c = ucd (j);
00300                         if (line_tmp.pos_x + (*my_font_) [c].length ()  > length ())
00301                         {
00302                             line_tmp.idx_end = j - 1;
00303                             my_vect_.push_back (line_tmp);
00304                             
00305                             line_tmp.pos_x = 0;
00306                             line_tmp.idx_beg = j; 
00307                         }
00308                         line_tmp.pos_x += (*my_font_) [c].length (); 
00309                         j++; 
00310                     }
00311                     break;  
00312             } 
00313         } 
00314     }
00315     
00316     // it is the last line
00317     line_tmp.idx_end = start_idx - 1;  
00318     my_vect_.push_back (line_tmp);    
00319 }
00320 
00321 
00322 void label::build_form_auto_height ()
00323 {
00324     // it's the same
00325     build_form_nothing (); 
00326     
00327     // now verify if it's always the same size
00328     
00329     u_int16 new_size = my_vect_.size () * my_font_->height ();
00330 
00331     if (new_size  != height ())
00332     {
00333         image tmp (length (), new_size);
00334         tmp.lock (); 
00335         tmp.fillrect (0, 0, length (), new_size, screen::trans_col ()); 
00336         tmp.unlock (); 
00337         draw (0, 0, 0, 0, length (), my_old_cursor_.pos_y + my_font_->height (), NULL, &tmp); 
00338         image::resize (length (), new_size); 
00339         tmp.draw (0, 0, NULL, this); 
00340     }
00341 }
00342 
00343 
00344 void label::build_form_auto_size ()
00345 {
00346     // find the max height and the max length
00347 
00348     // clear the vector_
00349     my_vect_.clear ();
00350     
00351     // temporary line
00352     Sline_text line_tmp;
00353     
00354     line_tmp.pos_x = 0;
00355     line_tmp.idx_beg = 0;
00356     u_int16 i = 0, max_length = 0; 
00357     
00358     while ( i < my_text_.size ())
00359     {
00360         if (my_text_[i] == '\n')
00361         {
00362             if (line_tmp.pos_x > max_length) max_length = line_tmp.pos_x; 
00363             line_tmp.idx_end = i; 
00364             my_vect_.push_back (line_tmp);
00365             
00366             line_tmp.idx_beg = i+1;
00367             line_tmp.pos_x = 0; 
00368         }
00369         else
00370         {
00371             line_tmp.pos_x += (*my_font_) [ucd (i)].length (); 
00372         }
00373         i++; 
00374     }
00375     
00376     if (line_tmp.pos_x > max_length) max_length = line_tmp.pos_x;
00377     // the last line
00378     line_tmp.idx_end = i-1;
00379     my_vect_.push_back (line_tmp);
00380     
00381     // now resize the label
00382     image::resize (max_length, my_vect_.size () * my_font_->height ());  
00383 }
00384 
00385 void label::clean_surface (const bool erase_all)
00386 {
00387     if (length () && height ())
00388     {     
00389         if ( my_cursor_.idx != my_text_.length ())
00390         {
00391             lock (); 
00392             fillrect ( my_old_cursor_.pos_x, my_old_cursor_.pos_y, length () - my_old_cursor_.pos_x,
00393                        my_font_->height (), screen::trans_col ()); 
00394             fillrect (0, my_old_cursor_.pos_y + my_font_->height (), length (),
00395                       height () -my_old_cursor_.pos_y + my_font_->height (), screen::trans_col ()); 
00396             unlock ();  
00397         } else if (erase_all) 
00398         {
00399             lock ();
00400             fillrect (0, 0, length (), height (), screen::trans_col ()); 
00401             unlock ();  
00402         }
00403     }
00404 }
00405 
00406 
00407 
00408 
00409 
00410 // find a word
00411 // index :  the word begin at the index
00412 // wlength : size of word
00413 // wlengthpix : size of word in pixel
00414 // length :
00415 
00416 // return 0 if enough size for this word,  1 if enough but must return on the next line, 2 if the word is bigger than the length 
00417 u_int8 label::find_word (u_int16 & index, u_int16 & wlength, u_int16 & wlengthpix, const u_int16 rlength)
00418 {
00419     wlength = index;
00420     wlengthpix = 0;
00421     while (index < my_text_.length ()  && my_text_[index] != ' ' && my_text_[index] != '\n')
00422     {
00423         wlengthpix += (*my_font_) [ucd (index)].length (); 
00424         index++;
00425     }
00426 
00427     // count of characters (which is != count of letters due to utf-8 encoding)
00428     wlength = index - wlength;
00429     
00430     // if size of word is bigger than the length of label 
00431     if (wlengthpix < length () - rlength)  return 0;
00432     else if (wlengthpix < length ())  return 1; 
00433     return 2;
00434 }
00435 
00436 
00437 
00438 void label::update_cursor ()
00439 {
00440     // find the cursor position
00441     bool b = false; 
00442     
00443     // init the blink cursor
00444     cursor_cur_blink_ = cursor_blink_cycle; 
00445     
00446     // find the iterator line where is the cursor
00447     while (!b && my_cursor_.line < my_vect_.size () )
00448     { 
00449         if (my_cursor_.idx >= my_vect_[my_cursor_.line].idx_beg &&
00450             my_cursor_.idx <= my_vect_[my_cursor_.line].idx_end ) b = true;
00451         else if (my_cursor_.idx >  my_vect_[my_cursor_.line].idx_end) 
00452         {
00453             if (my_cursor_.line ==  my_vect_.size () - 1) b = true; 
00454             else my_cursor_.line++;
00455         }
00456         else if (my_cursor_.idx <  my_vect_[my_cursor_.line].idx_beg)
00457         {
00458             my_cursor_.line--; 
00459         }
00460     }
00461  
00462     // now find the x position of the cursor
00463     my_cursor_.pos_x = 0;
00464     
00465     u_int16 j = my_vect_[my_cursor_.line].idx_beg;
00466     while (j < my_cursor_.idx) {
00467         my_cursor_.pos_x+= (*my_font_) [ucd (j)].length ();     
00468         j++;
00469     }
00470     // find y position
00471     my_cursor_.pos_y = (my_cursor_.line - start_line_) * my_font_->height (); 
00472 
00473     if (my_cursor_.pos_y > height ())
00474     {
00475         
00476 
00477     } 
00478 }
00479 
00480 
00481 
00482 // if bool is false redraw all,  if bool is true redraw just at beginning of the cursor 
00483 void label::draw_string (const bool at_cursor)
00484 { 
00485     u_int16 tmp_start_line;
00486     u_int16 tx = 0, ty = 0;
00487     u_int16 idx_cur_line, j; 
00488     u_int16 c;
00489     
00490     // if not at cursor, we erase all
00491     clean_surface (!at_cursor); 
00492     
00493     if (at_cursor)
00494     { 
00495         tmp_start_line =  my_old_cursor_.line; 
00496         tx = my_old_cursor_.pos_x;
00497         idx_cur_line = my_old_cursor_.idx;
00498         ty = (tmp_start_line - start_line_) * my_font_->height (); 
00499     }
00500     else
00501     { 
00502         tmp_start_line = start_line_; 
00503         idx_cur_line = my_vect_[tmp_start_line].idx_beg; 
00504     } 
00505     
00506     // draw the first line
00507     for (j = idx_cur_line;
00508          j < my_vect_[tmp_start_line].idx_end + 1 ;
00509          j++)
00510     {
00511         c = ucd (j);
00512         if (c != '\n' && my_font_->in_table (c))
00513         {
00514             (*my_font_) [c].draw (tx, ty, NULL, this);
00515             tx += (*my_font_) [c].length ();
00516         }
00517     }
00518     ty += my_font_->height ();
00519     tmp_start_line++; 
00520     
00521     
00522     // draw another line
00523     while (tmp_start_line < my_vect_.size ())
00524     {
00525         tx = 0; 
00526         for (j = my_vect_[tmp_start_line].idx_beg;
00527              j <  my_vect_[tmp_start_line].idx_end + 1 ;
00528              j++)
00529         {
00530             c = ucd (j);
00531             if (my_font_->in_table (c))
00532             {
00533                 (*my_font_) [c].draw (tx, ty, NULL, this);
00534                 tx += (*my_font_) [c].length (); 
00535             }
00536         }
00537         ty += my_font_->height ();
00538         tmp_start_line++;
00539     } 
00540 }
00541 
00542 
00543 bool label::update ()
00544 { 
00545     if (visible_cursor_)
00546     {
00547         if (! (height () && length ())) return true;  
00548         if (cursor_cur_blink_ == cursor_blink_cycle)
00549         {
00550             cursor_draw (); 
00551             cursor_cur_blink_ = 0; 
00552         }else if (cursor_cur_blink_ == (cursor_blink_cycle >> 1))
00553             cursor_undraw ();   
00554         cursor_cur_blink_++; 
00555     }  
00556     return true; 
00557 }
00558 
00559 
00560 
00561 void label::cursor_draw ()
00562 {
00563      // draw the cursor
00564     u_int16 idx = my_cursor_.idx;
00565     if (last_letter (idx)  || my_text_[idx] == '\n')  
00566         my_font_->cursor->draw (my_cursor_.pos_x, my_cursor_.pos_y,NULL, this);  
00567     else
00568         my_font_->cursor->draw (my_cursor_.pos_x, my_cursor_.pos_y,0, 0, 
00569                                 (*my_font_) [ucd (idx)].length (),
00570                                 my_font_->height (), NULL, this); 
00571 }
00572 
00573 void label::cursor_undraw ()
00574 { 
00575     // draw letter instead  
00576     u_int16 idx = my_cursor_.idx;
00577     if (last_letter (idx) || my_text_[idx] == '\n') 
00578     {
00579         lock (); 
00580         fillrect(my_cursor_.pos_x, my_cursor_.pos_y,
00581                  my_font_->cursor->length () ,
00582                  my_font_->cursor->height(),
00583                  screen::trans_col());
00584         unlock (); 
00585     }
00586     else (*my_font_) [ucd (idx)].draw (my_cursor_.pos_x, my_cursor_.pos_y, NULL, this);
00587 }
00588 
00589 bool label::last_letter (u_int16 idx) 
00590 {
00591     if ((u_int8) my_text_[idx] == 0xEF) return my_text_.length () - idx == 2;
00592     if ((u_int8) my_text_[idx] == 0xC3) return my_text_.length () - idx == 1;
00593     return my_cursor_.idx == my_text_.length ();
00594 }
00595 
00596 bool label::input_update ()
00597 {
00598 
00599     if(input::has_been_pushed(KEY_CURSOR_NEXT)) 
00600     {
00601         if (! (height () && length ())) return false;  
00602         // cursor_undraw (); 
00603         // cursor_next (); 
00604     }
00605     else if (input::has_been_pushed(KEY_CURSOR_PREVIOUS))
00606     {
00607         if (! (height () && length ())) return false;  
00608         // cursor_undraw ();  
00609         // cursor_previous (); 
00610     }
00611     
00612     return true; 
00613 }
00614 
00615 
00616 void label::cursor_next ()
00617 {
00618     if (!moveable_cursor_) return; 
00619     if (my_cursor_.idx < my_text_.length ()) 
00620     {
00621         u_int8 count;
00622         if (my_cursor_.idx < my_text_.length () - 2 && (u_int8) my_text_[my_cursor_.idx+1] == 0xEF) count = 3;
00623         else if (my_cursor_.idx < my_text_.length () - 1 && (u_int8) my_text_[my_cursor_.idx+1] == 0xC3) count = 2;
00624         else count = 1;
00625         
00626         my_cursor_.idx += count; 
00627         update_cursor ();
00628     }
00629 }
00630 
00631 
00632 void label::cursor_previous ()
00633 {
00634     if (!moveable_cursor_) return; 
00635     if (my_cursor_.idx > 0) 
00636     {
00637         u_int8 count;
00638         if (my_cursor_.idx > 2 && (u_int8) my_text_[my_cursor_.idx-3] == 0xEF) count = 3;
00639         else if (my_cursor_.idx > 1 && (u_int8) my_text_[my_cursor_.idx-2] == 0xC3) count = 2;
00640         else count = 1;
00641 
00642         my_cursor_.idx -= count;
00643         update_cursor ();
00644     }
00645 }
00646 
00647 
00648 const string label::text_string () const
00649 {
00650     return my_text_;  
00651 }
00652 
00653 const char * label::text_char () const
00654 {
00655     return my_text_.c_str (); 
00656 }
00657 
00658 // utf-8 --> utf-16
00659 u_int16 label::ucd (u_int16 & idx)
00660 {
00661     u_int8 c = my_text_[idx];
00662     if (c < 0x80) return c;
00663 
00664     if (c < 0xe0) 
00665     {
00666         u_int8 c1 = my_text_[++idx];
00667         return ((u_int16) (c & 0x1f) << 6)
00668             |   (u_int16) (c1 ^ 0x80);
00669     }
00670     
00671     u_int8 c1 = my_text_[++idx];
00672     u_int8 c2 = my_text_[++idx];
00673     return ((u_int16) (c & 0x0f) << 12)
00674         |  ((u_int16) (c1 ^ 0x80) << 6)
00675         |   (u_int16) (c2 ^ 0x80);
00676 }
00677 

Generated on Fri Mar 18 2011 for Adonthell by  doxygen 1.7.1