Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

CEGUIMultiLineEditbox.cpp

Go to the documentation of this file.
00001 /************************************************************************
00002         filename:       CEGUIMultiLineEditbox.cpp
00003         created:        30/6/2004
00004         author:         Paul D Turner
00005         
00006         purpose:        Implementation of the Multi-line edit box base class
00007 *************************************************************************/
00008 /*************************************************************************
00009     Crazy Eddie's GUI System (http://www.cegui.org.uk)
00010     Copyright (C)2004 - 2005 Paul D Turner (paul@cegui.org.uk)
00011 
00012     This library is free software; you can redistribute it and/or
00013     modify it under the terms of the GNU Lesser General Public
00014     License as published by the Free Software Foundation; either
00015     version 2.1 of the License, or (at your option) any later version.
00016 
00017     This library is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00020     Lesser General Public License for more details.
00021 
00022     You should have received a copy of the GNU Lesser General Public
00023     License along with this library; if not, write to the Free Software
00024     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025 *************************************************************************/
00026 #include "elements/CEGUIMultiLineEditbox.h"
00027 #include "elements/CEGUIScrollbar.h"
00028 #include "CEGUITextUtils.h"
00029 #include "CEGUIImage.h"
00030 #include "CEGUIExceptions.h"
00031 
00032 
00033 // Start of CEGUI namespace section
00034 namespace CEGUI
00035 {
00036 const String MultiLineEditbox::EventNamespace("MultiLineEditbox");
00037 
00038 /*************************************************************************
00039         TODO:
00040 
00041         Clipboard support
00042         Undo support
00043 *************************************************************************/
00044 /*************************************************************************
00045         Static Properties for this class
00046 *************************************************************************/
00047 MultiLineEditboxProperties::ReadOnly                            MultiLineEditbox::d_readOnlyProperty;
00048 MultiLineEditboxProperties::WordWrap                            MultiLineEditbox::d_wordWrapProperty;
00049 MultiLineEditboxProperties::CaratIndex                          MultiLineEditbox::d_caratIndexProperty;
00050 MultiLineEditboxProperties::SelectionStart                      MultiLineEditbox::d_selectionStartProperty;
00051 MultiLineEditboxProperties::SelectionLength                     MultiLineEditbox::d_selectionLengthProperty;
00052 MultiLineEditboxProperties::MaxTextLength                       MultiLineEditbox::d_maxTextLengthProperty;
00053 MultiLineEditboxProperties::NormalTextColour            MultiLineEditbox::d_normalTextColourProperty;
00054 MultiLineEditboxProperties::SelectedTextColour          MultiLineEditbox::d_selectedTextColourProperty;
00055 MultiLineEditboxProperties::ActiveSelectionColour       MultiLineEditbox::d_activeSelectionColourProperty;
00056 MultiLineEditboxProperties::InactiveSelectionColour     MultiLineEditbox::d_inactiveSelectionColourProperty;
00057 
00058 
00059 /*************************************************************************
00060         Constants
00061 *************************************************************************/
00062 // event names
00063 const String MultiLineEditbox::EventReadOnlyModeChanged( (utf8*)"ReadOnlyChanged" );
00064 const String MultiLineEditbox::EventWordWrapModeChanged( (utf8*)"WordWrapModeChanged" );
00065 const String MultiLineEditbox::EventMaximumTextLengthChanged( (utf8*)"MaximumTextLengthChanged" );
00066 const String MultiLineEditbox::EventCaratMoved( (utf8*)"CaratMoved" );
00067 const String MultiLineEditbox::EventTextSelectionChanged( (utf8*)"TextSelectionChanged" );
00068 const String MultiLineEditbox::EventEditboxFull( (utf8*)"EditboxFullEvent" );
00069 const String MultiLineEditbox::EventVertScrollbarModeChanged( (utf8*)"VertScrollbarModeChanged" );
00070 const String MultiLineEditbox::EventHorzScrollbarModeChanged( (utf8*)"HorzScrollbarModeChanged" );
00071 
00072 // default colours
00073 const argb_t MultiLineEditbox::DefaultNormalTextColour                  = 0xFFFFFFFF;
00074 const argb_t MultiLineEditbox::DefaultSelectedTextColour                = 0xFF000000;
00075 const argb_t MultiLineEditbox::DefaultNormalSelectionColour             = 0xFF6060FF;
00076 const argb_t MultiLineEditbox::DefaultInactiveSelectionColour   = 0xFF808080;
00077 
00078 // Static data initialisation
00079 String MultiLineEditbox::d_lineBreakChars((utf8*)"\n");
00080 
00081 
00082 /*************************************************************************
00083         Constructor for the MultiLineEditbox base class.
00084 *************************************************************************/
00085 MultiLineEditbox::MultiLineEditbox(const String& type, const String& name) :
00086         Window(type, name),
00087         d_readOnly(false),
00088         d_maxTextLen(String::max_size()),
00089         d_caratPos(0),
00090         d_selectionStart(0),
00091         d_selectionEnd(0),
00092         d_dragging(false),
00093         d_dragAnchorIdx(0),
00094         d_wordWrap(true),
00095         d_widestExtent(0.0f),
00096         d_forceVertScroll(false),
00097         d_forceHorzScroll(false),
00098         d_selectionBrush(NULL),
00099         d_normalTextColour(DefaultNormalTextColour),
00100         d_selectTextColour(DefaultSelectedTextColour),
00101         d_selectBrushColour(DefaultNormalSelectionColour),
00102         d_inactiveSelectBrushColour(DefaultInactiveSelectionColour)
00103 {
00104         // add events specific to this widget.
00105         addMultiLineEditboxEvents();
00106 
00107         addMultiLineEditboxProperties();
00108 
00109         // we always need a terminating \n
00110         d_text.append(1, '\n');
00111 }
00112 
00113 
00114 /*************************************************************************
00115         Destructor for the MultiLineEditbox base class.
00116 *************************************************************************/
00117 MultiLineEditbox::~MultiLineEditbox(void)
00118 {
00119 }
00120 
00121 
00122 /*************************************************************************
00123         Initialise the Window based object ready for use.       
00124 *************************************************************************/
00125 void MultiLineEditbox::initialise(void)
00126 {
00127         // create the component sub-widgets
00128         d_vertScrollbar = createVertScrollbar(getName() + "__auto_vscrollbar__");
00129         d_horzScrollbar = createHorzScrollbar(getName() + "__auto_hscrollbar__");
00130 
00131         addChildWindow(d_vertScrollbar);
00132         addChildWindow(d_horzScrollbar);
00133 
00134     d_vertScrollbar->subscribeEvent(Scrollbar::EventScrollPositionChanged, Event::Subscriber(&MultiLineEditbox::handle_scrollChange, this));
00135     d_horzScrollbar->subscribeEvent(Scrollbar::EventScrollPositionChanged, Event::Subscriber(&MultiLineEditbox::handle_scrollChange, this));
00136 
00137         formatText();
00138         performChildWindowLayout();
00139 }
00140 
00141 
00142 /*************************************************************************
00143         return true if the edit box has input focus.    
00144 *************************************************************************/
00145 bool MultiLineEditbox::hasInputFocus(void) const
00146 {
00147         return isActive();
00148 }
00149 
00150 
00151 /*************************************************************************
00152         return the current selection start point.       
00153 *************************************************************************/
00154 size_t MultiLineEditbox::getSelectionStartIndex(void) const
00155 {
00156         return (d_selectionStart != d_selectionEnd) ? d_selectionStart : d_caratPos;
00157 }
00158 
00159 
00160 /*************************************************************************
00161         return the current selection end point.
00162 *************************************************************************/
00163 size_t MultiLineEditbox::getSelectionEndIndex(void) const
00164 {
00165         return (d_selectionStart != d_selectionEnd) ? d_selectionEnd : d_caratPos;
00166 }
00167 
00168 
00169 /*************************************************************************
00170         return the length of the current selection (in code points / characters).       
00171 *************************************************************************/
00172 size_t MultiLineEditbox::getSelectionLength(void) const
00173 {
00174         return d_selectionEnd - d_selectionStart;
00175 }
00176 
00177 
00178 /*************************************************************************
00179         Add multi-line edit box specific events 
00180 *************************************************************************/
00181 void MultiLineEditbox::addMultiLineEditboxEvents(void)
00182 {
00183         addEvent(EventReadOnlyModeChanged);
00184         addEvent(EventWordWrapModeChanged);
00185         addEvent(EventMaximumTextLengthChanged);
00186         addEvent(EventCaratMoved);
00187         addEvent(EventTextSelectionChanged);
00188         addEvent(EventEditboxFull);
00189         addEvent(EventVertScrollbarModeChanged);
00190         addEvent(EventHorzScrollbarModeChanged);
00191 }
00192 
00193 
00194 /*************************************************************************
00195         Perform the actual rendering for this Window.   
00196 *************************************************************************/
00197 void MultiLineEditbox::populateRenderCache()
00198 {
00199         // get the derived class to render general stuff before we handle the text itself
00200         cacheEditboxBaseImagery();
00201 
00202         //
00203         // Render edit box text
00204         //
00205         Rect textarea(getTextRenderArea());
00206 
00207         cacheTextLines(textarea);
00208 
00209         if (hasInputFocus() && !isReadOnly())
00210         {
00211                 cacheCaratImagery(textarea);
00212         }
00213 
00214 }
00215 
00216 
00217 /*************************************************************************
00218         Specify whether the edit box is read-only.      
00219 *************************************************************************/
00220 void MultiLineEditbox::setReadOnly(bool setting)
00221 {
00222         // if setting is changed
00223         if (d_readOnly != setting)
00224         {
00225                 d_readOnly = setting;
00226                 WindowEventArgs args(this);
00227                 onReadOnlyChanged(args);
00228         }
00229 
00230 }
00231 
00232 
00233 /*************************************************************************
00234         Set the current position of the carat.  
00235 *************************************************************************/
00236 void MultiLineEditbox::setCaratIndex(size_t carat_pos)
00237 {
00238         // make sure new position is valid
00239         if (carat_pos > d_text.length() - 1)
00240         {
00241                 carat_pos = d_text.length() - 1;
00242         }
00243 
00244         // if new position is different
00245         if (d_caratPos != carat_pos)
00246         {
00247                 d_caratPos = carat_pos;
00248                 ensureCaratIsVisible();
00249 
00250                 // Trigger "carat moved" event
00251                 WindowEventArgs args(this);
00252                 onCaratMoved(args);
00253         }
00254 
00255 }
00256 
00257 
00258 /*************************************************************************
00259         Define the current selection for the edit box   
00260 *************************************************************************/
00261 void MultiLineEditbox::setSelection(size_t start_pos, size_t end_pos)
00262 {
00263         // ensure selection start point is within the valid range
00264         if (start_pos > d_text.length() - 1)
00265         {
00266                 start_pos = d_text.length() - 1;
00267         }
00268 
00269         // ensure selection end point is within the valid range
00270         if (end_pos > d_text.length() - 1)
00271         {
00272                 end_pos = d_text.length() - 1;
00273         }
00274 
00275         // ensure start is before end
00276         if (start_pos > end_pos)
00277         {
00278                 size_t tmp = end_pos;
00279                 end_pos = start_pos;
00280                 start_pos = tmp;
00281         }
00282 
00283         // only change state if values are different.
00284         if ((start_pos != d_selectionStart) || (end_pos != d_selectionEnd))
00285         {
00286                 // setup selection
00287                 d_selectionStart = start_pos;
00288                 d_selectionEnd   = end_pos;
00289 
00290                 // Trigger "selection changed" event
00291                 WindowEventArgs args(this);
00292                 onTextSelectionChanged(args);
00293         }
00294 
00295 }
00296 
00297 
00298 /*************************************************************************
00299         set the maximum text length for this edit box.  
00300 *************************************************************************/
00301 void MultiLineEditbox::setMaxTextLength(size_t max_len)
00302 {
00303         if (d_maxTextLen != max_len)
00304         {
00305                 d_maxTextLen = max_len;
00306 
00307                 // Trigger max length changed event
00308                 WindowEventArgs args(this);
00309                 onMaximumTextLengthChanged(args);
00310 
00311                 // trim string
00312                 if (d_text.length() > d_maxTextLen)
00313                 {
00314                         d_text.resize(d_maxTextLen);
00315                         onTextChanged(args);
00316                 }
00317 
00318         }
00319 
00320 }
00321 
00322 
00323 /*************************************************************************
00324         Set the colour to be used for rendering edit box text in the normal,
00325         unselected state.       
00326 *************************************************************************/
00327 void MultiLineEditbox::setNormalTextColour(const colour& col)
00328 {
00329         d_normalTextColour = col;
00330         requestRedraw();
00331 }
00332 
00333 
00334 /*************************************************************************
00335         Set the colour to be used for rendering the edit box text when
00336         within the selected region.     
00337 *************************************************************************/
00338 void MultiLineEditbox::setSelectedTextColour(const colour& col)
00339 {
00340         d_selectTextColour = col;
00341         requestRedraw();
00342 }
00343 
00344 
00345 /*************************************************************************
00346         Set the colour to be used for rendering the edit box selection
00347         highlight when the edit box is active.  
00348 *************************************************************************/
00349 void MultiLineEditbox::setNormalSelectBrushColour(const colour& col)
00350 {
00351         d_selectBrushColour = col;
00352         requestRedraw();
00353 }
00354 
00355 
00356 /*************************************************************************
00357         Set the colour to be used for rendering the edit box selection
00358         highlight when the edit box is inactive.        
00359 *************************************************************************/
00360 void MultiLineEditbox::setInactiveSelectBrushColour(const colour& col)
00361 {
00362         d_inactiveSelectBrushColour = col;
00363         requestRedraw();
00364 }
00365 
00366 
00367 /*************************************************************************
00368         Scroll the view so that the current carat position is visible.
00369 *************************************************************************/
00370 void MultiLineEditbox::ensureCaratIsVisible(void)
00371 {
00372         // calculate the location of the carat
00373         const Font* fnt = getFont();
00374         size_t caratLine = getLineNumberFromIndex(d_caratPos);
00375 
00376         if (caratLine < d_lines.size())
00377         {
00378                 Rect textArea(getTextRenderArea());
00379 
00380                 size_t caratLineIdx = d_caratPos - d_lines[caratLine].d_startIdx;
00381 
00382                 float ypos = caratLine * fnt->getLineSpacing();
00383                 float xpos = fnt->getTextExtent(d_text.substr(d_lines[caratLine].d_startIdx, caratLineIdx));
00384 
00385                 // adjust position for scroll bars
00386                 xpos -= d_horzScrollbar->getScrollPosition();
00387                 ypos -= d_vertScrollbar->getScrollPosition();
00388 
00389                 // if carat is above window, scroll up
00390                 if (ypos < 0)
00391                 {
00392                         d_vertScrollbar->setScrollPosition(d_vertScrollbar->getScrollPosition() + ypos);
00393                 }
00394                 // if carat is below the window, scroll down
00395                 else if ((ypos += fnt->getLineSpacing()) > textArea.getHeight())
00396                 {
00397                         d_vertScrollbar->setScrollPosition(d_vertScrollbar->getScrollPosition() + (ypos - textArea.getHeight()) + fnt->getLineSpacing());
00398                 }
00399 
00400                 // if carat is left of the window, scroll left
00401                 if (xpos < 0)
00402                 {
00403                         d_horzScrollbar->setScrollPosition(d_horzScrollbar->getScrollPosition() + xpos - 50);
00404                 }
00405                 // if carat is right of the window, scroll right
00406                 else if (xpos > textArea.getWidth())
00407                 {
00408                         d_horzScrollbar->setScrollPosition(d_horzScrollbar->getScrollPosition() + (xpos - textArea.getWidth()) + 50);
00409                 }
00410 
00411         }
00412 
00413 }
00414 
00415 
00416 /*************************************************************************
00417         Set whether the text will be word wrapped or not.
00418 *************************************************************************/
00419 void MultiLineEditbox::setWordWrapping(bool setting)
00420 {
00421         if (setting != d_wordWrap)
00422         {
00423                 d_wordWrap = setting;
00424                 formatText();
00425 
00426                 WindowEventArgs args(this);
00427                 onWordWrapModeChanged(args);
00428         }
00429 
00430 }
00431 
00432 
00433 /*************************************************************************
00434         display required integrated scroll bars according to current state
00435         of the edit box and update their values.
00436 *************************************************************************/
00437 void MultiLineEditbox::configureScrollbars(void)
00438 {
00439         float totalHeight       = (float)d_lines.size() * getFont()->getLineSpacing();
00440         float widestItem        = d_widestExtent;
00441 
00442         //
00443         // First show or hide the scroll bars as needed (or requested)
00444         //
00445         // show or hide vertical scroll bar as required (or as specified by option)
00446         if ((totalHeight > getTextRenderArea().getHeight()) || d_forceVertScroll)
00447         {
00448                 d_vertScrollbar->show();
00449 
00450                 // show or hide horizontal scroll bar as required (or as specified by option)
00451                 if ((widestItem > getTextRenderArea().getWidth()) || d_forceHorzScroll)
00452                 {
00453                         d_horzScrollbar->show();
00454                 }
00455                 else
00456                 {
00457                         d_horzScrollbar->hide();
00458                 }
00459 
00460         }
00461         else
00462         {
00463                 // show or hide horizontal scroll bar as required (or as specified by option)
00464                 if ((widestItem > getTextRenderArea().getWidth()) || d_forceHorzScroll)
00465                 {
00466                         d_horzScrollbar->show();
00467 
00468                         // show or hide vertical scroll bar as required (or as specified by option)
00469                         if ((totalHeight > getTextRenderArea().getHeight()) || d_forceVertScroll)
00470                         {
00471                                 d_vertScrollbar->show();
00472                         }
00473                         else
00474                         {
00475                                 d_vertScrollbar->hide();
00476                         }
00477 
00478                 }
00479                 else
00480                 {
00481                         d_vertScrollbar->hide();
00482                         d_horzScrollbar->hide();
00483                 }
00484 
00485         }
00486 
00487         //
00488         // Set up scroll bar values
00489         //
00490         Rect renderArea(getTextRenderArea());
00491 
00492         d_vertScrollbar->setDocumentSize(totalHeight);
00493         d_vertScrollbar->setPageSize(renderArea.getHeight());
00494         d_vertScrollbar->setStepSize(ceguimax(1.0f, renderArea.getHeight() / 10.0f));
00495         d_vertScrollbar->setScrollPosition(d_vertScrollbar->getScrollPosition());
00496 
00497         d_horzScrollbar->setDocumentSize(widestItem);
00498         d_horzScrollbar->setPageSize(renderArea.getWidth());
00499         d_horzScrollbar->setStepSize(ceguimax(1.0f, renderArea.getWidth() / 10.0f));
00500         d_horzScrollbar->setScrollPosition(d_horzScrollbar->getScrollPosition());
00501 }
00502 
00503 
00504 /*************************************************************************
00505         Render text lines.      
00506 *************************************************************************/
00507 void MultiLineEditbox::cacheTextLines(const Rect& dest_area)
00508 {
00509     // text is already formatted, we just grab the lines and render them with the required alignment.
00510     Rect drawArea(dest_area);
00511     drawArea.offset(Point(-d_horzScrollbar->getScrollPosition(), -d_vertScrollbar->getScrollPosition()));
00512 
00513     Renderer* renderer = System::getSingleton().getRenderer();
00514     const Font* fnt = getFont();
00515 
00516     if (fnt)
00517     {
00518         // get layers to use for rendering
00519         float textZ = renderer->getZLayer(4) - renderer->getCurrentZ();
00520         float selZ  = renderer->getZLayer(3) - renderer->getCurrentZ();
00521 
00522         // calculate final colours to use.
00523         ColourRect colours;
00524         float alpha = getEffectiveAlpha();
00525         colour normalTextCol = d_normalTextColour;
00526         normalTextCol.setAlpha(normalTextCol.getAlpha() * alpha);
00527         colour selectTextCol = d_selectTextColour;
00528         selectTextCol.setAlpha(selectTextCol.getAlpha() * alpha);
00529         colour selectBrushCol = hasInputFocus() ? d_selectBrushColour : d_inactiveSelectBrushColour;
00530         selectBrushCol.setAlpha(selectBrushCol.getAlpha() * alpha);
00531 
00532         // for each formatted line.
00533         for (size_t i = 0; i < d_lines.size(); ++i)
00534         {
00535             Rect lineRect(drawArea);
00536             const LineInfo& currLine = d_lines[i];
00537             String lineText(d_text.substr(currLine.d_startIdx, currLine.d_length));
00538 
00539             // if it is a simple 'no selection area' case
00540             if ((currLine.d_startIdx >= d_selectionEnd) ||
00541                 ((currLine.d_startIdx + currLine.d_length) <= d_selectionStart) ||
00542                 (d_selectionBrush == NULL))
00543             {
00544                 colours.setColours(normalTextCol);
00545                 // render the complete line.
00546                 d_renderCache.cacheText(lineText, fnt, LeftAligned, lineRect, textZ, colours, &dest_area);
00547             }
00548             // we have at least some selection highlighting to do
00549             else
00550             {
00551                 // Start of actual rendering section.
00552                 String sect;
00553                 size_t sectIdx = 0, sectLen;
00554                 float selStartOffset = 0.0f, selAreaWidth = 0.0f;
00555 
00556                 // render any text prior to selected region of line.
00557                 if (currLine.d_startIdx < d_selectionStart)
00558                 {
00559                     // calculate length of text section
00560                     sectLen = d_selectionStart - currLine.d_startIdx;
00561 
00562                     // get text for this section
00563                     sect = lineText.substr(sectIdx, sectLen);
00564                     sectIdx += sectLen;
00565 
00566                     // get the pixel offset to the beginning of the selection area highlight.
00567                     selStartOffset = fnt->getTextExtent(sect);
00568 
00569                     // draw this portion of the text
00570                     colours.setColours(normalTextCol);
00571                     d_renderCache.cacheText(sect, fnt, LeftAligned, lineRect, textZ, colours, &dest_area);
00572 
00573                     // set position ready for next portion of text
00574                     lineRect.d_left += selStartOffset;
00575                 }
00576 
00577                 // calculate the length of the selected section
00578                 sectLen = ceguimin(d_selectionEnd - currLine.d_startIdx, currLine.d_length) - sectIdx;
00579 
00580                 // get the text for this section
00581                 sect = lineText.substr(sectIdx, sectLen);
00582                 sectIdx += sectLen;
00583 
00584                 // get the extent to use as the width of the selection area highlight
00585                 selAreaWidth = fnt->getTextExtent(sect);
00586 
00587                 // draw the text for this section
00588                 colours.setColours(selectTextCol);
00589                 d_renderCache.cacheText(sect, fnt, LeftAligned, lineRect, textZ, colours, &dest_area);
00590 
00591                 // render any text beyond selected region of line
00592                 if (sectIdx < currLine.d_length)
00593                 {
00594                     // update render position to the end of the selected area.
00595                     lineRect.d_left += selAreaWidth;
00596 
00597                     // calculate length of this section
00598                     sectLen = currLine.d_length - sectIdx;
00599 
00600                     // get the text for this section
00601                     sect = lineText.substr(sectIdx, sectLen);
00602 
00603                     // render the text for this section.
00604                     colours.setColours(normalTextCol);
00605                     d_renderCache.cacheText(sect, fnt, LeftAligned, lineRect, textZ, colours, &dest_area);
00606                 }
00607 
00608                 // calculate area for the selection brush on this line
00609                 lineRect.d_left = drawArea.d_left + selStartOffset;
00610                 lineRect.d_right = lineRect.d_left + selAreaWidth;
00611                 lineRect.d_bottom = lineRect.d_top + fnt->getLineSpacing();
00612 
00613                 // render the selection area brush for this line
00614                 colours.setColours(selectBrushCol);
00615                 d_renderCache.cacheImage(*d_selectionBrush, lineRect, selZ, colours, &dest_area);
00616             }
00617 
00618             // update master position for next line in paragraph.
00619             drawArea.d_top += fnt->getLineSpacing();
00620         }
00621     }
00622 }
00623 
00624 
00625 /*************************************************************************
00626         Format the text into lines as needed by the current formatting options.
00627 *************************************************************************/
00628 void MultiLineEditbox::formatText(void)
00629 {
00630         // clear old formatting data
00631         d_lines.clear();
00632         d_widestExtent = 0.0f;
00633 
00634         String paraText;
00635 
00636         const Font* fnt = getFont();
00637 
00638         if (fnt != NULL)
00639         {
00640                 float areaWidth = getTextRenderArea().getWidth();
00641 
00642                 String::size_type       currPos = 0;
00643                 String::size_type       paraLen;
00644                 LineInfo        line;
00645 
00646                 while (currPos < d_text.length())
00647                 {
00648                         if ((paraLen = d_text.find_first_of(d_lineBreakChars, currPos)) == String::npos)
00649                         {
00650                                 paraLen = d_text.length() - currPos;
00651                         }
00652                         else
00653                         {
00654                                 ++paraLen -= currPos;
00655                         }
00656 
00657                         paraText = d_text.substr(currPos, paraLen);
00658 
00659                         if (!d_wordWrap || (areaWidth <= 0.0f))
00660                         {
00661                                 // no word wrapping, so we are just one long line.
00662                                 line.d_startIdx = currPos;
00663                                 line.d_length   = paraLen;
00664                                 line.d_extent   = fnt->getTextExtent(paraText); 
00665                                 d_lines.push_back(line);
00666 
00667                                 // update widest, if needed.
00668                                 if (line.d_extent > d_widestExtent)
00669                                 {
00670                                         d_widestExtent = line.d_extent;
00671                                 }
00672 
00673                         }
00674                         // must word-wrap the paragraph text
00675                         else
00676                         {
00677                                 String::size_type lineIndex = 0;
00678 
00679                                 // while there is text in the string
00680                                 while (lineIndex < paraLen)
00681                                 {
00682                                         String::size_type  lineLen = 0;
00683                                         float lineExtent = 0.0f;
00684 
00685                                         // loop while we have not reached the end of the paragraph string
00686                                         while (lineLen < (paraLen - lineIndex))
00687                                         {
00688                                                 // get cp / char count of next token
00689                                                 size_t nextTokenSize = getNextTokenLength(paraText, lineIndex + lineLen);
00690 
00691                                                 // get pixel width of the token
00692                                                 float tokenExtent  = fnt->getTextExtent(paraText.substr(lineIndex + lineLen, nextTokenSize));
00693 
00694                                                 // would adding this token would overflow the available width
00695                                                 if ((lineExtent + tokenExtent) > areaWidth)
00696                                                 {
00697                                                         // Was this the first token?
00698                                                         if (lineLen == 0)
00699                                                         {
00700                                                                 // get point at which to break the token
00701                                                                 lineLen = fnt->getCharAtPixel(paraText.substr(lineIndex, nextTokenSize), areaWidth);
00702                                                         }
00703 
00704                                                         // text wraps, exit loop early with line info up until wrap point
00705                                                         break;
00706                                                 }
00707 
00708                                                 // add this token to current line
00709                                                 lineLen    += nextTokenSize;
00710                                                 lineExtent += tokenExtent;
00711                                         }
00712 
00713                                         // set up line info and add to collection
00714                                         line.d_startIdx = currPos + lineIndex;
00715                                         line.d_length   = lineLen;
00716                                         line.d_extent   = lineExtent;
00717                                         d_lines.push_back(line);
00718 
00719                                         // update widest, if needed.
00720                                         if (lineExtent > d_widestExtent)
00721                                         {
00722                                                 d_widestExtent = lineExtent;
00723                                         }
00724 
00725                                         // update position in string
00726                                         lineIndex += lineLen;
00727                                 }
00728 
00729                         }
00730 
00731                         // skip to next 'paragraph' in text
00732                         currPos += paraLen;
00733                 }
00734 
00735         }
00736 
00737         configureScrollbars();
00738         requestRedraw();
00739 }
00740 
00741 
00742 /*************************************************************************
00743         Return the length of the next token in String 'text' starting at
00744         index 'start_idx'.
00745 *************************************************************************/
00746 size_t MultiLineEditbox::getNextTokenLength(const String& text, size_t start_idx) const
00747 {
00748         String::size_type pos = text.find_first_of(TextUtils::DefaultWrapDelimiters, start_idx);
00749 
00750         // handle case where no more whitespace exists (so this is last token)
00751         if (pos == String::npos)
00752         {
00753                 return (text.length() - start_idx);
00754         }
00755         // handle 'delimiter' token cases
00756         else if ((pos - start_idx) == 0)
00757         {
00758                 return 1;
00759         }
00760         else
00761         {
00762                 return (pos - start_idx);
00763         }
00764 
00765 }
00766 
00767 
00768 /*************************************************************************
00769         Return the text code point index that is rendered closest to screen
00770         position 'pt'.  
00771 *************************************************************************/
00772 size_t MultiLineEditbox::getTextIndexFromPosition(const Point& pt) const
00773 {
00774         //
00775         // calculate final window position to be checked
00776         //
00777         Point wndPt = screenToWindow(pt);
00778 
00779         if (getMetricsMode() == Relative)
00780         {
00781                 wndPt = relativeToAbsolute(wndPt);
00782         }
00783 
00784         Rect textArea(getTextRenderArea());
00785 
00786         wndPt.d_x -= textArea.d_left;
00787         wndPt.d_y -= textArea.d_top;
00788 
00789         // factor in scroll bar values
00790         wndPt.d_x += d_horzScrollbar->getScrollPosition();
00791         wndPt.d_y += d_vertScrollbar->getScrollPosition();
00792 
00793         size_t lineNumber = static_cast<size_t>(wndPt.d_y / getFont()->getLineSpacing());
00794 
00795         if (lineNumber >= d_lines.size())
00796         {
00797                 lineNumber = d_lines.size() - 1;
00798         }
00799 
00800         String lineText(d_text.substr(d_lines[lineNumber].d_startIdx, d_lines[lineNumber].d_length));
00801 
00802         size_t lineIdx = getFont()->getCharAtPixel(lineText, wndPt.d_x);
00803 
00804         if (lineIdx >= lineText.length() - 1)
00805         {
00806                 lineIdx = lineText.length() - 1;
00807         }
00808 
00809         return d_lines[lineNumber].d_startIdx + lineIdx;
00810 }
00811 
00812 
00813 /*************************************************************************
00814         Return the line number a given index falls on with the current
00815         formatting.  Will return last line if index is out of range.
00816 *************************************************************************/
00817 size_t MultiLineEditbox::getLineNumberFromIndex(size_t index) const
00818 {
00819         size_t lineCount = d_lines.size();
00820 
00821         if (lineCount == 0)
00822         {
00823                 return 0;
00824         }
00825         else if (index >= d_text.length() - 1)
00826         {
00827                 return lineCount - 1;
00828         }
00829         else
00830         {
00831                 size_t indexCount = 0;
00832                 size_t caratLine = 0;
00833 
00834                 for (; caratLine < lineCount; ++caratLine)
00835                 {
00836                         indexCount += d_lines[caratLine].d_length;
00837 
00838                         if (index < indexCount)
00839                         {
00840                                 return caratLine;
00841                         }
00842 
00843                 }
00844 
00845         }
00846 
00847         throw InvalidRequestException((utf8*)"MultiLineEditbox::getLineNumberFromIndex - Unable to identify a line from the given, invalid, index.");
00848 }
00849 
00850 
00851 
00852 /*************************************************************************
00853         Clear the current selection setting
00854 *************************************************************************/
00855 void MultiLineEditbox::clearSelection(void)
00856 {
00857         // perform action only if required.
00858         if (getSelectionLength() != 0)
00859         {
00860                 setSelection(0, 0);
00861         }
00862 
00863 }
00864 
00865 
00866 /*************************************************************************
00867         Erase the currently selected text.
00868 *************************************************************************/
00869 void MultiLineEditbox::eraseSelectedText(bool modify_text)
00870 {
00871         if (getSelectionLength() != 0)
00872         {
00873                 // setup new carat position and remove selection highlight.
00874                 setCaratIndex(getSelectionStartIndex());
00875 
00876                 // erase the selected characters (if required)
00877                 if (modify_text)
00878                 {
00879                         d_text.erase(getSelectionStartIndex(), getSelectionLength());
00880 
00881                         // trigger notification that text has changed.
00882                         WindowEventArgs args(this);
00883                         onTextChanged(args);
00884                 }
00885 
00886                 clearSelection();
00887         }
00888 
00889 }
00890 
00891 
00892 /*************************************************************************
00893         Processing for backspace key
00894 *************************************************************************/
00895 void MultiLineEditbox::handleBackspace(void)
00896 {
00897         if (!isReadOnly())
00898         {
00899                 if (getSelectionLength() != 0)
00900                 {
00901                         eraseSelectedText();
00902                 }
00903                 else if (d_caratPos > 0)
00904                 {
00905                         d_text.erase(d_caratPos - 1, 1);
00906                         setCaratIndex(d_caratPos - 1);
00907 
00908                         WindowEventArgs args(this);
00909                         onTextChanged(args);
00910                 }
00911 
00912         }
00913 }
00914 
00915 
00916 /*************************************************************************
00917         Processing for Delete key
00918 *************************************************************************/
00919 void MultiLineEditbox::handleDelete(void)
00920 {
00921         if (!isReadOnly())
00922         {
00923                 if (getSelectionLength() != 0)
00924                 {
00925                         eraseSelectedText();
00926                 }
00927                 else if (getCaratIndex() < d_text.length() - 1)
00928                 {
00929                         d_text.erase(d_caratPos, 1);
00930                         ensureCaratIsVisible();
00931 
00932                         WindowEventArgs args(this);
00933                         onTextChanged(args);
00934                 }
00935 
00936         }
00937 
00938 }
00939 
00940 
00941 /*************************************************************************
00942         Processing to move carat one character left
00943 *************************************************************************/
00944 void MultiLineEditbox::handleCharLeft(uint sysKeys)
00945 {
00946         if (d_caratPos > 0)
00947         {
00948                 setCaratIndex(d_caratPos - 1);
00949         }
00950 
00951         if (sysKeys & Shift)
00952         {
00953                 setSelection(d_caratPos, d_dragAnchorIdx);      
00954         }
00955         else
00956         {
00957                 clearSelection();
00958         }
00959 
00960 }
00961 
00962 
00963 /*************************************************************************
00964         Processing to move carat one word left
00965 *************************************************************************/
00966 void MultiLineEditbox::handleWordLeft(uint sysKeys)
00967 {
00968         if (d_caratPos > 0)
00969         {
00970                 setCaratIndex(TextUtils::getWordStartIdx(d_text, getCaratIndex()));
00971         }
00972 
00973         if (sysKeys & Shift)
00974         {
00975                 setSelection(d_caratPos, d_dragAnchorIdx);      
00976         }
00977         else
00978         {
00979                 clearSelection();
00980         }
00981 
00982 }
00983 
00984 
00985 /*************************************************************************
00986         Processing to move carat one character right
00987 *************************************************************************/
00988 void MultiLineEditbox::handleCharRight(uint sysKeys)
00989 {
00990         if (d_caratPos < d_text.length() - 1)
00991         {
00992                 setCaratIndex(d_caratPos + 1);
00993         }
00994 
00995         if (sysKeys & Shift)
00996         {
00997                 setSelection(d_caratPos, d_dragAnchorIdx);      
00998         }
00999         else
01000         {
01001                 clearSelection();
01002         }
01003 
01004 }
01005 
01006 
01007 /*************************************************************************
01008         Processing to move carat one word right
01009 *************************************************************************/
01010 void MultiLineEditbox::handleWordRight(uint sysKeys)
01011 {
01012         if (d_caratPos < d_text.length() - 1)
01013         {
01014                 setCaratIndex(TextUtils::getNextWordStartIdx(d_text, getCaratIndex()));
01015         }
01016 
01017         if (sysKeys & Shift)
01018         {
01019                 setSelection(d_caratPos, d_dragAnchorIdx);      
01020         }
01021         else
01022         {
01023                 clearSelection();
01024         }
01025 
01026 }
01027 
01028 
01029 /*************************************************************************
01030         Processing to move carat to the start of the text.
01031 *************************************************************************/
01032 void MultiLineEditbox::handleDocHome(uint sysKeys)
01033 {
01034         if (d_caratPos > 0)
01035         {
01036                 setCaratIndex(0);
01037         }
01038 
01039         if (sysKeys & Shift)
01040         {
01041                 setSelection(d_caratPos, d_dragAnchorIdx);      
01042         }
01043         else
01044         {
01045                 clearSelection();
01046         }
01047 
01048 }
01049 
01050 
01051 /*************************************************************************
01052         Processing to move carat to the end of the text
01053 *************************************************************************/
01054 void MultiLineEditbox::handleDocEnd(uint sysKeys)
01055 {
01056         if (d_caratPos < d_text.length() - 1)
01057         {
01058                 setCaratIndex(d_text.length() - 1);
01059         }
01060 
01061         if (sysKeys & Shift)
01062         {
01063                 setSelection(d_caratPos, d_dragAnchorIdx);      
01064         }
01065         else
01066         {
01067                 clearSelection();
01068         }
01069 
01070 }
01071 
01072 
01073 /*************************************************************************
01074         Processing to move carat to the start of the current line.      
01075 *************************************************************************/
01076 void MultiLineEditbox::handleLineHome(uint sysKeys)
01077 {
01078         size_t line = getLineNumberFromIndex(d_caratPos);
01079 
01080         if (line < d_lines.size())
01081         {
01082                 size_t lineStartIdx = d_lines[line].d_startIdx;
01083 
01084                 if (d_caratPos > lineStartIdx)
01085                 {
01086                         setCaratIndex(lineStartIdx);
01087                 }
01088 
01089                 if (sysKeys & Shift)
01090                 {
01091                         setSelection(d_caratPos, d_dragAnchorIdx);      
01092                 }
01093                 else
01094                 {
01095                         clearSelection();
01096                 }
01097 
01098         }
01099 
01100 }
01101 
01102 
01103 /*************************************************************************
01104         Processing to move carat to the end of the current line
01105 *************************************************************************/
01106 void MultiLineEditbox::handleLineEnd(uint sysKeys)
01107 {
01108         size_t line = getLineNumberFromIndex(d_caratPos);
01109 
01110         if (line < d_lines.size())
01111         {
01112                 size_t lineEndIdx = d_lines[line].d_startIdx + d_lines[line].d_length - 1;
01113 
01114                 if (d_caratPos < lineEndIdx)
01115                 {
01116                         setCaratIndex(lineEndIdx);
01117                 }
01118 
01119                 if (sysKeys & Shift)
01120                 {
01121                         setSelection(d_caratPos, d_dragAnchorIdx);      
01122                 }
01123                 else
01124                 {
01125                         clearSelection();
01126                 }
01127 
01128         }
01129 
01130 }
01131 
01132 
01133 /*************************************************************************
01134         Processing to move carat up a line.
01135 *************************************************************************/
01136 void MultiLineEditbox::handleLineUp(uint sysKeys)
01137 {
01138         size_t caratLine = getLineNumberFromIndex(d_caratPos);
01139 
01140         if (caratLine > 0)
01141         {
01142                 float caratPixelOffset = getFont()->getTextExtent(d_text.substr(d_lines[caratLine].d_startIdx, d_caratPos - d_lines[caratLine].d_startIdx));
01143 
01144                 --caratLine;
01145 
01146                 size_t newLineIndex = getFont()->getCharAtPixel(d_text.substr(d_lines[caratLine].d_startIdx, d_lines[caratLine].d_length), caratPixelOffset);
01147 
01148                 setCaratIndex(d_lines[caratLine].d_startIdx + newLineIndex);
01149         }
01150 
01151         if (sysKeys & Shift)
01152         {
01153                 setSelection(d_caratPos, d_dragAnchorIdx);      
01154         }
01155         else
01156         {
01157                 clearSelection();
01158         }
01159 
01160 }
01161 
01162 
01163 /*************************************************************************
01164         Processing to move carat down a line.
01165 *************************************************************************/
01166 void MultiLineEditbox::handleLineDown(uint sysKeys)
01167 {
01168         size_t caratLine = getLineNumberFromIndex(d_caratPos);
01169 
01170         if ((d_lines.size() > 1) && (caratLine < (d_lines.size() - 1)))
01171         {
01172                 float caratPixelOffset = getFont()->getTextExtent(d_text.substr(d_lines[caratLine].d_startIdx, d_caratPos - d_lines[caratLine].d_startIdx));
01173 
01174                 ++caratLine;
01175 
01176                 size_t newLineIndex = getFont()->getCharAtPixel(d_text.substr(d_lines[caratLine].d_startIdx, d_lines[caratLine].d_length), caratPixelOffset);
01177 
01178                 setCaratIndex(d_lines[caratLine].d_startIdx + newLineIndex);
01179         }
01180 
01181         if (sysKeys & Shift)
01182         {
01183                 setSelection(d_caratPos, d_dragAnchorIdx);      
01184         }
01185         else
01186         {
01187                 clearSelection();
01188         }
01189 
01190 }
01191 
01192 
01193 /*************************************************************************
01194         Processing to insert a new line / paragraph.
01195 *************************************************************************/
01196 void MultiLineEditbox::handleNewLine(uint sysKeys)
01197 {
01198         if (!isReadOnly())
01199         {
01200                 // erase selected text
01201                 eraseSelectedText();
01202 
01203                 // if there is room
01204                 if (d_text.length() - 1 < d_maxTextLen)
01205                 {
01206                         d_text.insert(getCaratIndex(), 1, 0x0a);
01207                         d_caratPos++;
01208 
01209                         WindowEventArgs args(this);
01210                         onTextChanged(args);
01211                 }
01212 
01213         }
01214 
01215 }
01216 
01217 
01218 /*************************************************************************
01219         Handler for when a mouse button is pushed
01220 *************************************************************************/
01221 void MultiLineEditbox::onMouseButtonDown(MouseEventArgs& e)
01222 {
01223         // base class handling
01224         Window::onMouseButtonDown(e);
01225 
01226         if (e.button == LeftButton)
01227         {
01228                 // grab inputs
01229                 if (captureInput())
01230                 {
01231                         // handle mouse down
01232                         clearSelection();
01233                         d_dragging = true;
01234                         d_dragAnchorIdx = getTextIndexFromPosition(e.position);
01235                         setCaratIndex(d_dragAnchorIdx);
01236                 }
01237 
01238                 e.handled = true;
01239         }
01240 
01241 }
01242 
01243 
01244 /*************************************************************************
01245         Handler for when mouse button is released
01246 *************************************************************************/
01247 void MultiLineEditbox::onMouseButtonUp(MouseEventArgs& e)
01248 {
01249         // base class processing
01250         Window::onMouseButtonUp(e);
01251 
01252         if (e.button == LeftButton)
01253         {
01254                 releaseInput();
01255                 e.handled = true;
01256         }
01257 
01258 }
01259 
01260 
01261 /*************************************************************************
01262         Handler for when mouse button is double-clicked
01263 *************************************************************************/
01264 void MultiLineEditbox::onMouseDoubleClicked(MouseEventArgs& e)
01265 {
01266         // base class processing
01267         Window::onMouseDoubleClicked(e);
01268 
01269         if (e.button == LeftButton)
01270         {
01271                 d_dragAnchorIdx = TextUtils::getWordStartIdx(d_text, (d_caratPos == d_text.length()) ? d_caratPos : d_caratPos + 1);
01272                 d_caratPos              = TextUtils::getNextWordStartIdx(d_text, d_caratPos);
01273 
01274                 // perform actual selection operation.
01275                 setSelection(d_dragAnchorIdx, d_caratPos);
01276 
01277                 e.handled = true;
01278         }
01279 
01280 }
01281 
01282 
01283 /*************************************************************************
01284         Handler for when mouse button is triple-clicked.
01285 *************************************************************************/
01286 void MultiLineEditbox::onMouseTripleClicked(MouseEventArgs& e)
01287 {
01288         // base class processing
01289         Window::onMouseTripleClicked(e);
01290 
01291         if (e.button == LeftButton)
01292         {
01293                 size_t caratLine = getLineNumberFromIndex(d_caratPos);
01294                 size_t lineStart = d_lines[caratLine].d_startIdx;
01295 
01296                 // find end of last paragraph
01297                 String::size_type paraStart = d_text.find_last_of(d_lineBreakChars, lineStart);
01298 
01299                 // if no previous paragraph, selection will start at the beginning.
01300                 if (paraStart == String::npos)
01301                 {
01302                         paraStart = 0;
01303                 }
01304 
01305                 // find end of this paragraph
01306                 String::size_type paraEnd = d_text.find_first_of(d_lineBreakChars, lineStart);
01307 
01308                 // if paragraph has no end, which actually should never happen, fix the
01309                 // erroneous situation and select up to end at end of text.
01310                 if (paraEnd == String::npos)
01311                 {
01312                         d_text.append(1, '\n');
01313                         paraEnd = d_text.length() - 1;
01314                 }
01315 
01316                 // set up selection using new values.
01317                 d_dragAnchorIdx = paraStart;
01318                 setCaratIndex(paraEnd);
01319                 setSelection(d_dragAnchorIdx, d_caratPos);
01320                 e.handled = true;
01321         }
01322 
01323 }
01324 
01325 
01326 /*************************************************************************
01327         Handler for when mouse moves in the window.
01328 *************************************************************************/
01329 void MultiLineEditbox::onMouseMove(MouseEventArgs& e)
01330 {
01331         // base class processing
01332         Window::onMouseMove(e);
01333 
01334         if (d_dragging)
01335         {
01336                 setCaratIndex(getTextIndexFromPosition(e.position));
01337                 setSelection(d_caratPos, d_dragAnchorIdx);
01338         }
01339 
01340         e.handled = true;
01341 }
01342 
01343 
01344 /*************************************************************************
01345         Handler for when capture is lost.
01346 *************************************************************************/
01347 void MultiLineEditbox::onCaptureLost(WindowEventArgs& e)
01348 {
01349         d_dragging = false;
01350 
01351         // base class processing
01352         Window::onCaptureLost(e);
01353 
01354         e.handled = true;
01355 }
01356 
01357 
01358 /*************************************************************************
01359         Handler for when character (printable keys) are typed
01360 *************************************************************************/
01361 void MultiLineEditbox::onCharacter(KeyEventArgs& e)
01362 {
01363         // base class processing
01364         Window::onCharacter(e);
01365 
01366         // only need to take notice if we have focus
01367         if (hasInputFocus() && !isReadOnly() && getFont()->isCodepointAvailable(e.codepoint))
01368         {
01369                 // erase selected text
01370                 eraseSelectedText();
01371 
01372                 // if there is room
01373                 if (d_text.length() - 1 < d_maxTextLen)
01374                 {
01375                         d_text.insert(getCaratIndex(), 1, e.codepoint);
01376                         d_caratPos++;
01377 
01378                         WindowEventArgs args(this);
01379                         onTextChanged(args);
01380                 }
01381                 else
01382                 {
01383                         // Trigger text box full event
01384                         WindowEventArgs args(this);
01385                         onEditboxFullEvent(args);
01386                 }
01387 
01388         }
01389 
01390         e.handled = true;
01391 }
01392 
01393 
01394 /*************************************************************************
01395         Handler for when non-printable keys are typed.
01396 *************************************************************************/
01397 void MultiLineEditbox::onKeyDown(KeyEventArgs& e)
01398 {
01399         // base class processing
01400         Window::onKeyDown(e);
01401 
01402         if (hasInputFocus() && !isReadOnly())
01403         {
01404                 WindowEventArgs args(this);
01405                 switch (e.scancode)
01406                 {
01407                 case Key::LeftShift:
01408                 case Key::RightShift:
01409                         if (getSelectionLength() == 0)
01410                         {
01411                                 d_dragAnchorIdx = getCaratIndex();
01412                         }
01413                         break;
01414 
01415                 case Key::Backspace:
01416                         handleBackspace();
01417                         break;
01418 
01419                 case Key::Delete:
01420                         handleDelete();
01421                         break;
01422 
01423                 case Key::Return:
01424                 case Key::NumpadEnter:
01425                         handleNewLine(e.sysKeys);
01426                         break;
01427 
01428                 case Key::ArrowLeft:
01429                         if (e.sysKeys & Control)
01430                         {
01431                                 handleWordLeft(e.sysKeys);
01432                         }
01433                         else
01434                         {
01435                                 handleCharLeft(e.sysKeys);
01436                         }
01437                         break;
01438 
01439                 case Key::ArrowRight:
01440                         if (e.sysKeys & Control)
01441                         {
01442                                 handleWordRight(e.sysKeys);
01443                         }
01444                         else
01445                         {
01446                                 handleCharRight(e.sysKeys);
01447                         }
01448                         break;
01449 
01450                 case Key::ArrowUp:
01451                         handleLineUp(e.sysKeys);
01452                         break;
01453 
01454                 case Key::ArrowDown:
01455                         handleLineDown(e.sysKeys);
01456                         break;
01457 
01458                 case Key::Home:
01459                         if (e.sysKeys & Control)
01460                         {
01461                                 handleDocHome(e.sysKeys);
01462                         }
01463                         else
01464                         {
01465                                 handleLineHome(e.sysKeys);
01466                         }
01467                         break;
01468 
01469                 case Key::End:
01470                         if (e.sysKeys & Control)
01471                         {
01472                                 handleDocEnd(e.sysKeys);
01473                         }
01474                         else
01475                         {
01476                                 handleLineEnd(e.sysKeys);
01477                         }
01478                         break;
01479 
01480         // default case is now to leave event as (possibly) unhandled.
01481         default:
01482             return;
01483                 }
01484 
01485                 e.handled = true;
01486         }
01487 
01488 }
01489 
01490 
01491 /*************************************************************************
01492         Handler for when text is programmatically changed.
01493 *************************************************************************/
01494 void MultiLineEditbox::onTextChanged(WindowEventArgs& e)
01495 {
01496     // ensure last character is a new line
01497     if ((d_text.length() == 0) || (d_text[d_text.length() - 1] != '\n'))
01498         d_text.append(1, '\n');
01499 
01500     // base class processing
01501     Window::onTextChanged(e);
01502 
01503     // clear selection
01504     clearSelection();
01505     // layout new text
01506     formatText();
01507     // layout child windows (scrollbars) since text layout may have changed
01508     performChildWindowLayout();
01509     // ensure carat is still within the text
01510     setCaratIndex(getCaratIndex());
01511     // ensure carat is visible
01512     // NB: this will already have been called at least once, but since we
01513     // may have changed the formatting of the text, it needs to be called again.
01514     ensureCaratIsVisible();
01515 
01516     e.handled = true;
01517 }
01518 
01519 
01520 /*************************************************************************
01521         Handler for when widget size is changed.
01522 *************************************************************************/
01523 void MultiLineEditbox::onSized(WindowEventArgs& e)
01524 {
01525         formatText();
01526 
01527         // base class handling
01528         Window::onSized(e);
01529 
01530         e.handled = true;
01531 }
01532 
01533 
01534 /*************************************************************************
01535         Handler for mouse wheel changes
01536 *************************************************************************/
01537 void MultiLineEditbox::onMouseWheel(MouseEventArgs& e)
01538 {
01539         // base class processing.
01540         Window::onMouseWheel(e);
01541 
01542         if (d_vertScrollbar->isVisible() && (d_vertScrollbar->getDocumentSize() > d_vertScrollbar->getPageSize()))
01543         {
01544                 d_vertScrollbar->setScrollPosition(d_vertScrollbar->getScrollPosition() + d_vertScrollbar->getStepSize() * -e.wheelChange);
01545         }
01546         else if (d_horzScrollbar->isVisible() && (d_horzScrollbar->getDocumentSize() > d_horzScrollbar->getPageSize()))
01547         {
01548                 d_horzScrollbar->setScrollPosition(d_horzScrollbar->getScrollPosition() + d_horzScrollbar->getStepSize() * -e.wheelChange);
01549         }
01550 
01551         e.handled = true;
01552 }
01553 
01554 
01555 /*************************************************************************
01556         Handler called when the read-only state of the edit box changes 
01557 *************************************************************************/
01558 void MultiLineEditbox::onReadOnlyChanged(WindowEventArgs& e)
01559 {
01560         fireEvent(EventReadOnlyModeChanged, e, EventNamespace);
01561 }
01562 
01563 
01564 /*************************************************************************
01565         Handler called when the word wrap mode for the the edit box changes
01566 *************************************************************************/
01567 void MultiLineEditbox::onWordWrapModeChanged(WindowEventArgs& e)
01568 {
01569         fireEvent(EventWordWrapModeChanged, e, EventNamespace);
01570 }
01571 
01572 
01573 /*************************************************************************
01574         Handler called when the maximum text length for the edit box changes    
01575 *************************************************************************/
01576 void MultiLineEditbox::onMaximumTextLengthChanged(WindowEventArgs& e)
01577 {
01578         fireEvent(EventMaximumTextLengthChanged, e, EventNamespace);
01579 }
01580 
01581 
01582 /*************************************************************************
01583         Handler called when the carat moves.    
01584 *************************************************************************/
01585 void MultiLineEditbox::onCaratMoved(WindowEventArgs& e)
01586 {
01587         requestRedraw();
01588         fireEvent(EventCaratMoved, e, EventNamespace);
01589 }
01590 
01591 
01592 /*************************************************************************
01593         Handler called when the text selection changes  
01594 *************************************************************************/
01595 void MultiLineEditbox::onTextSelectionChanged(WindowEventArgs& e)
01596 {
01597         requestRedraw();
01598         fireEvent(EventTextSelectionChanged, e, EventNamespace);
01599 }
01600 
01601 
01602 /*************************************************************************
01603         Handler called when the edit box is full        
01604 *************************************************************************/
01605 void MultiLineEditbox::onEditboxFullEvent(WindowEventArgs& e)
01606 {
01607         fireEvent(EventEditboxFull, e, EventNamespace);
01608 }
01609 
01610 
01611 /*************************************************************************
01612         Handler called when the 'always show' setting for the vertical
01613         scroll bar changes.     
01614 *************************************************************************/
01615 void MultiLineEditbox::onVertScrollbarModeChanged(WindowEventArgs& e)
01616 {
01617         requestRedraw();
01618         fireEvent(EventVertScrollbarModeChanged, e, EventNamespace);
01619 }
01620 
01621 
01622 /*************************************************************************
01623         Handler called when 'always show' setting for the horizontal scroll
01624         bar changes.    
01625 *************************************************************************/
01626 void MultiLineEditbox::onHorzScrollbarModeChanged(WindowEventArgs& e)
01627 {
01628         requestRedraw();
01629         fireEvent(EventHorzScrollbarModeChanged, e, EventNamespace);
01630 }
01631 
01632 
01633 /*************************************************************************
01634         Return whether the text in the edit box will be word-wrapped.
01635 *************************************************************************/
01636 bool MultiLineEditbox::isWordWrapped(void) const
01637 {
01638         return d_wordWrap;
01639 }
01640 
01641 
01642 /*************************************************************************
01643         Add new properties for this class
01644 *************************************************************************/
01645 void MultiLineEditbox::addMultiLineEditboxProperties(void)
01646 {
01647         addProperty(&d_readOnlyProperty);
01648         addProperty(&d_wordWrapProperty);
01649         addProperty(&d_caratIndexProperty);
01650         addProperty(&d_selectionStartProperty);
01651         addProperty(&d_selectionLengthProperty);
01652         addProperty(&d_maxTextLengthProperty);
01653         addProperty(&d_normalTextColourProperty);
01654         addProperty(&d_selectedTextColourProperty);
01655         addProperty(&d_activeSelectionColourProperty);
01656         addProperty(&d_inactiveSelectionColourProperty);
01657 }
01658 
01659 /*************************************************************************
01660     Handler for scroll position changes.
01661 *************************************************************************/
01662 bool MultiLineEditbox::handle_scrollChange(const EventArgs& args)
01663 {
01664     // simply trigger a redraw of the Listbox.
01665     requestRedraw();
01666     return true;
01667 }
01668 
01669 
01670 
01671 } // End of  CEGUI namespace section

Generated on Wed Sep 7 09:56:32 2005 for Crazy Eddies GUI System by  doxygen 1.4.3