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

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 ulong     MultiLineEditbox::DefaultNormalTextColour                       = 0xFFFFFFFF;
00074 const ulong     MultiLineEditbox::DefaultSelectedTextColour                     = 0xFF000000;
00075 const ulong     MultiLineEditbox::DefaultNormalSelectionColour          = 0xFF6060FF;
00076 const ulong     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();
00129         d_horzScrollbar = createHorzScrollbar();
00130 
00131         addChildWindow(d_vertScrollbar);
00132         addChildWindow(d_horzScrollbar);
00133 
00134         formatText();
00135         layoutComponentWidgets();
00136 }
00137 
00138 
00139 /*************************************************************************
00140         return true if the edit box has input focus.    
00141 *************************************************************************/
00142 bool MultiLineEditbox::hasInputFocus(void) const
00143 {
00144         return isActive();
00145 }
00146 
00147 
00148 /*************************************************************************
00149         return the current selection start point.       
00150 *************************************************************************/
00151 ulong MultiLineEditbox::getSelectionStartIndex(void) const
00152 {
00153         return (d_selectionStart != d_selectionEnd) ? d_selectionStart : d_caratPos;
00154 }
00155 
00156 
00157 /*************************************************************************
00158         return the current selection end point.
00159 *************************************************************************/
00160 ulong MultiLineEditbox::getSelectionEndIndex(void) const
00161 {
00162         return (d_selectionStart != d_selectionEnd) ? d_selectionEnd : d_caratPos;
00163 }
00164 
00165 
00166 /*************************************************************************
00167         return the length of the current selection (in code points / characters).       
00168 *************************************************************************/
00169 ulong MultiLineEditbox::getSelectionLength(void) const
00170 {
00171         return d_selectionEnd - d_selectionStart;
00172 }
00173 
00174 
00175 /*************************************************************************
00176         Add multi-line edit box specific events 
00177 *************************************************************************/
00178 void MultiLineEditbox::addMultiLineEditboxEvents(void)
00179 {
00180         addEvent(EventReadOnlyModeChanged);
00181         addEvent(EventWordWrapModeChanged);
00182         addEvent(EventMaximumTextLengthChanged);
00183         addEvent(EventCaratMoved);
00184         addEvent(EventTextSelectionChanged);
00185         addEvent(EventEditboxFull);
00186         addEvent(EventVertScrollbarModeChanged);
00187         addEvent(EventHorzScrollbarModeChanged);
00188 }
00189 
00190 
00191 /*************************************************************************
00192         Perform the actual rendering for this Window.   
00193 *************************************************************************/
00194 void MultiLineEditbox::drawSelf(float z)
00195 {
00196         // get the derived class to render general stuff before we handle the text itself
00197         renderEditboxBaseImagery(z);
00198 
00199         //
00200         // Render edit box text
00201         //
00202         // calculate on-screen position of area we have to render into
00203         Rect absarea(getTextRenderArea());
00204         absarea.offset(getUnclippedPixelRect().getPosition());
00205 
00206         // calculate clipper for text rendering area
00207         Rect clipper(absarea.getIntersection(getPixelRect()));
00208 
00209         absarea.offset(Point(-d_horzScrollbar->getScrollPosition(), -d_vertScrollbar->getScrollPosition()));
00210         renderTextLines(absarea, clipper);
00211 
00212         if (hasInputFocus() && !isReadOnly())
00213         {
00214                 renderCarat(absarea.d_left, absarea.d_top, clipper);
00215         }
00216 
00217 }
00218 
00219 
00220 /*************************************************************************
00221         Specify whether the edit box is read-only.      
00222 *************************************************************************/
00223 void MultiLineEditbox::setReadOnly(bool setting)
00224 {
00225         // if setting is changed
00226         if (d_readOnly != setting)
00227         {
00228                 d_readOnly = setting;
00229                 WindowEventArgs args(this);
00230                 onReadOnlyChanged(args);
00231         }
00232 
00233 }
00234 
00235 
00236 /*************************************************************************
00237         Set the current position of the carat.  
00238 *************************************************************************/
00239 void MultiLineEditbox::setCaratIndex(ulong carat_pos)
00240 {
00241         // make sure new position is valid
00242         if (carat_pos > d_text.length() - 1)
00243         {
00244                 carat_pos = d_text.length() - 1;
00245         }
00246 
00247         // if new position is different
00248         if (d_caratPos != carat_pos)
00249         {
00250                 d_caratPos = carat_pos;
00251                 ensureCaratIsVisible();
00252 
00253                 // Trigger "carat moved" event
00254                 WindowEventArgs args(this);
00255                 onCaratMoved(args);
00256         }
00257 
00258 }
00259 
00260 
00261 /*************************************************************************
00262         Define the current selection for the edit box   
00263 *************************************************************************/
00264 void MultiLineEditbox::setSelection(ulong start_pos, ulong end_pos)
00265 {
00266         // ensure selection start point is within the valid range
00267         if (start_pos > d_text.length() - 1)
00268         {
00269                 start_pos = d_text.length() - 1;
00270         }
00271 
00272         // ensure selection end point is within the valid range
00273         if (end_pos > d_text.length() - 1)
00274         {
00275                 end_pos = d_text.length() - 1;
00276         }
00277 
00278         // ensure start is before end
00279         if (start_pos > end_pos)
00280         {
00281                 ulong tmp = end_pos;
00282                 end_pos = start_pos;
00283                 start_pos = tmp;
00284         }
00285 
00286         // only change state if values are different.
00287         if ((start_pos != d_selectionStart) || (end_pos != d_selectionEnd))
00288         {
00289                 // setup selection
00290                 d_selectionStart = start_pos;
00291                 d_selectionEnd   = end_pos;
00292 
00293                 // Trigger "selection changed" event
00294                 WindowEventArgs args(this);
00295                 onTextSelectionChanged(args);
00296         }
00297 
00298 }
00299 
00300 
00301 /*************************************************************************
00302         set the maximum text length for this edit box.  
00303 *************************************************************************/
00304 void MultiLineEditbox::setMaxTextLength(ulong max_len)
00305 {
00306         if (d_maxTextLen != max_len)
00307         {
00308                 d_maxTextLen = max_len;
00309 
00310                 // Trigger max length changed event
00311                 WindowEventArgs args(this);
00312                 onMaximumTextLengthChanged(args);
00313 
00314                 // trim string
00315                 if (d_text.length() > d_maxTextLen)
00316                 {
00317                         d_text.resize(d_maxTextLen);
00318                         onTextChanged(args);
00319                 }
00320 
00321         }
00322 
00323 }
00324 
00325 
00326 /*************************************************************************
00327         Set the colour to be used for rendering edit box text in the normal,
00328         unselected state.       
00329 *************************************************************************/
00330 void MultiLineEditbox::setNormalTextColour(const colour& col)
00331 {
00332         d_normalTextColour = col;
00333         requestRedraw();
00334 }
00335 
00336 
00337 /*************************************************************************
00338         Set the colour to be used for rendering the edit box text when
00339         within the selected region.     
00340 *************************************************************************/
00341 void MultiLineEditbox::setSelectedTextColour(const colour& col)
00342 {
00343         d_selectTextColour = col;
00344         requestRedraw();
00345 }
00346 
00347 
00348 /*************************************************************************
00349         Set the colour to be used for rendering the edit box selection
00350         highlight when the edit box is active.  
00351 *************************************************************************/
00352 void MultiLineEditbox::setNormalSelectBrushColour(const colour& col)
00353 {
00354         d_selectBrushColour = col;
00355         requestRedraw();
00356 }
00357 
00358 
00359 /*************************************************************************
00360         Set the colour to be used for rendering the edit box selection
00361         highlight when the edit box is inactive.        
00362 *************************************************************************/
00363 void MultiLineEditbox::setInactiveSelectBrushColour(const colour& col)
00364 {
00365         d_inactiveSelectBrushColour = col;
00366         requestRedraw();
00367 }
00368 
00369 
00370 /*************************************************************************
00371         Scroll the view so that the current carat position is visible.
00372 *************************************************************************/
00373 void MultiLineEditbox::ensureCaratIsVisible(void)
00374 {
00375         // calculate the location of the carat
00376         const Font* fnt = getFont();
00377 
00378         uint indexCount = 0;
00379         uint caratLine = getLineNumberFromIndex(d_caratPos);
00380 
00381         if (caratLine < (uint)d_lines.size())
00382         {
00383                 Rect textArea(getTextRenderArea());
00384 
00385                 uint caratLineIdx = d_caratPos - d_lines[caratLine].d_startIdx;
00386 
00387                 float ypos = caratLine * fnt->getLineSpacing();
00388                 float xpos = fnt->getTextExtent(d_text.substr(d_lines[caratLine].d_startIdx, caratLineIdx));
00389 
00390                 // adjust position for scroll bars
00391                 xpos -= d_horzScrollbar->getScrollPosition();
00392                 ypos -= d_vertScrollbar->getScrollPosition();
00393 
00394                 // if carat is above window, scroll up
00395                 if (ypos < 0)
00396                 {
00397                         d_vertScrollbar->setScrollPosition(d_vertScrollbar->getScrollPosition() + ypos);
00398                 }
00399                 // if carat is below the window, scroll down
00400                 else if ((ypos += fnt->getLineSpacing()) > textArea.getHeight())
00401                 {
00402                         d_vertScrollbar->setScrollPosition(d_vertScrollbar->getScrollPosition() + (ypos - textArea.getHeight()) + fnt->getLineSpacing());
00403                 }
00404 
00405                 // if carat is left of the window, scroll left
00406                 if (xpos < 0)
00407                 {
00408                         d_horzScrollbar->setScrollPosition(d_horzScrollbar->getScrollPosition() + xpos - 50);
00409                 }
00410                 // if carat is right of the window, scroll right
00411                 else if (xpos > textArea.getWidth())
00412                 {
00413                         d_horzScrollbar->setScrollPosition(d_horzScrollbar->getScrollPosition() + (xpos - textArea.getWidth()) + 50);
00414                 }
00415 
00416         }
00417 
00418 }
00419 
00420 
00421 /*************************************************************************
00422         Set whether the text will be word wrapped or not.
00423 *************************************************************************/
00424 void MultiLineEditbox::setWordWrapping(bool setting)
00425 {
00426         if (setting != d_wordWrap)
00427         {
00428                 d_wordWrap = setting;
00429                 formatText();
00430 
00431                 WindowEventArgs args(this);
00432                 onWordWrapModeChanged(args);
00433         }
00434 
00435 }
00436 
00437 
00438 /*************************************************************************
00439         display required integrated scroll bars according to current state
00440         of the edit box and update their values.
00441 *************************************************************************/
00442 void MultiLineEditbox::configureScrollbars(void)
00443 {
00444         float totalHeight       = (float)d_lines.size() * getFont()->getLineSpacing();
00445         float widestItem        = d_widestExtent;
00446 
00447         //
00448         // First show or hide the scroll bars as needed (or requested)
00449         //
00450         // show or hide vertical scroll bar as required (or as specified by option)
00451         if ((totalHeight > getTextRenderArea().getHeight()) || d_forceVertScroll)
00452         {
00453                 d_vertScrollbar->show();
00454 
00455                 // show or hide horizontal scroll bar as required (or as specified by option)
00456                 if ((widestItem > getTextRenderArea().getWidth()) || d_forceHorzScroll)
00457                 {
00458                         d_horzScrollbar->show();
00459                 }
00460                 else
00461                 {
00462                         d_horzScrollbar->hide();
00463                 }
00464 
00465         }
00466         else
00467         {
00468                 // show or hide horizontal scroll bar as required (or as specified by option)
00469                 if ((widestItem > getTextRenderArea().getWidth()) || d_forceHorzScroll)
00470                 {
00471                         d_horzScrollbar->show();
00472 
00473                         // show or hide vertical scroll bar as required (or as specified by option)
00474                         if ((totalHeight > getTextRenderArea().getHeight()) || d_forceVertScroll)
00475                         {
00476                                 d_vertScrollbar->show();
00477                         }
00478                         else
00479                         {
00480                                 d_vertScrollbar->hide();
00481                         }
00482 
00483                 }
00484                 else
00485                 {
00486                         d_vertScrollbar->hide();
00487                         d_horzScrollbar->hide();
00488                 }
00489 
00490         }
00491 
00492         //
00493         // Set up scroll bar values
00494         //
00495         Rect renderArea(getTextRenderArea());
00496 
00497         d_vertScrollbar->setDocumentSize(totalHeight);
00498         d_vertScrollbar->setPageSize(renderArea.getHeight());
00499         d_vertScrollbar->setStepSize(ceguimax(1.0f, renderArea.getHeight() / 10.0f));
00500         d_vertScrollbar->setScrollPosition(d_vertScrollbar->getScrollPosition());
00501 
00502         d_horzScrollbar->setDocumentSize(widestItem);
00503         d_horzScrollbar->setPageSize(renderArea.getWidth());
00504         d_horzScrollbar->setStepSize(ceguimax(1.0f, renderArea.getWidth() / 10.0f));
00505         d_horzScrollbar->setScrollPosition(d_horzScrollbar->getScrollPosition());
00506 }
00507 
00508 
00509 /*************************************************************************
00510         Render text lines.      
00511 *************************************************************************/
00512 void MultiLineEditbox::renderTextLines(const Rect& dest_area, const Rect& clipper) const
00513 {
00514         // text is already formatted, we just grab the lines and render them with the required alignment.
00515         Rect drawArea(dest_area);
00516         Renderer* renderer = System::getSingleton().getRenderer();
00517         const Font* fnt = getFont();
00518 
00519         if (fnt != NULL)
00520         {
00521                 // get layers to use for rendering
00522                 float textZ = renderer->getZLayer(4);
00523                 float selZ  = renderer->getZLayer(3);
00524 
00525                 // calculate final colours to use.
00526                 float alpha = getEffectiveAlpha();
00527                 colour normalTextCol  = ((d_normalTextColour & 0x00FFFFFF) | (((ulong)(((float)(d_normalTextColour >> 24)) * alpha)) << 24));
00528                 colour selectTextCol  = ((d_selectTextColour & 0x00FFFFFF) | (((ulong)(((float)(d_selectTextColour >> 24)) * alpha)) << 24));
00529 
00530                 colour selectBrushCol = hasInputFocus() ?
00531                         ((d_selectBrushColour & 0x00FFFFFF) | (((ulong)(((float)(d_selectBrushColour >> 24)) * alpha)) << 24)) :
00532                         ((d_inactiveSelectBrushColour & 0x00FFFFFF) | (((ulong)(((float)(d_selectBrushColour >> 24)) * alpha)) << 24));
00533 
00534                 // for each formatted line.
00535                 for (uint i = 0; i < (uint)d_lines.size(); ++i)
00536                 {
00537                         Rect lineRect(drawArea);
00538                         const LineInfo& currLine = d_lines[i];
00539                         String lineText(d_text.substr(currLine.d_startIdx, currLine.d_length));
00540 
00541                         // if it is a simple 'no selection area' case
00542                         if ((currLine.d_startIdx >= d_selectionEnd) ||
00543                                 ((currLine.d_startIdx + currLine.d_length) <= d_selectionStart) ||
00544                                 (d_selectionBrush == NULL))
00545                         {
00546                                 // render the complete line.
00547                                 fnt->drawText(lineText, lineRect, textZ, clipper, LeftAligned, ColourRect(normalTextCol));
00548                         }
00549                         //
00550                         // we have at least some selection highlight to do
00551                         //
00552                         else
00553                         {
00554                                 // Start of actual rendering section.
00555                                 String sect;
00556                                 uint sectIdx = 0, sectLen;
00557                                 float selStartOffset = 0.0f, selAreaWidth = 0.0f;
00558 
00559                                 // render any text prior to selected region of line.
00560                                 if (currLine.d_startIdx < d_selectionStart)
00561                                 {
00562                                         // calculate length of text section
00563                                         sectLen = d_selectionStart - currLine.d_startIdx;
00564 
00565                                         // get text for this section
00566                                         sect = lineText.substr(sectIdx, sectLen);
00567                                         sectIdx += sectLen;
00568 
00569                                         // get the pixel offset to the beginning of the selection area highlight.
00570                                         selStartOffset = fnt->getTextExtent(sect);
00571 
00572                                         // draw this portion of the text
00573                                         fnt->drawText(sect, lineRect, textZ, clipper, LeftAligned, ColourRect(normalTextCol));
00574 
00575                                         // set position ready for next portion of text
00576                                         lineRect.d_left += selStartOffset;
00577                                 }
00578 
00579                                 // calculate the length of the selected section
00580                                 sectLen = ceguimin(d_selectionEnd - currLine.d_startIdx, currLine.d_length) - sectIdx;
00581 
00582                                 // get the text for this section
00583                                 sect = lineText.substr(sectIdx, sectLen);
00584                                 sectIdx += sectLen;
00585 
00586                                 // get the extent to use as the width of the selection area highlight
00587                                 selAreaWidth = fnt->getTextExtent(sect);
00588 
00589                                 // draw the text for this section
00590                                 fnt->drawText(sect, lineRect, textZ, clipper, LeftAligned, ColourRect(selectTextCol));
00591 
00592                                 // render any text beyond selected region of line
00593                                 if (sectIdx < currLine.d_length)
00594                                 {
00595                                         // update render position to the end of the selected area.
00596                                         lineRect.d_left += selAreaWidth;
00597 
00598                                         // calculate length of this section
00599                                         sectLen = currLine.d_length - sectIdx;
00600 
00601                                         // get the text for this section
00602                                         sect = lineText.substr(sectIdx, sectLen);
00603 
00604                                         // render the text for this section.
00605                                         fnt->drawText(sect, lineRect, textZ, clipper, LeftAligned, ColourRect(normalTextCol));
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                                 d_selectionBrush->draw(lineRect, selZ, clipper, ColourRect(selectBrushCol));
00615                         }
00616 
00617                         // update master position for next line in paragraph.
00618                         drawArea.d_top += fnt->getLineSpacing();
00619                 }
00620 
00621         }
00622 
00623 }
00624 
00625 
00626 /*************************************************************************
00627         Format the text into lines as needed by the current formatting options.
00628 *************************************************************************/
00629 void MultiLineEditbox::formatText(void)
00630 {
00631         // clear old formatting data
00632         d_lines.clear();
00633         d_widestExtent = 0.0f;
00634 
00635         String paraText;
00636 
00637         const Font* fnt = getFont();
00638 
00639         if (fnt != NULL)
00640         {
00641                 float areaWidth = getTextRenderArea().getWidth();
00642 
00643                 String::size_type       currPos = 0;
00644                 String::size_type       paraLen;
00645                 LineInfo        line;
00646 
00647                 while (currPos < d_text.length())
00648                 {
00649                         if ((paraLen = d_text.find_first_of(d_lineBreakChars, currPos)) == String::npos)
00650                         {
00651                                 paraLen = d_text.length() - currPos;
00652                         }
00653                         else
00654                         {
00655                                 ++paraLen -= currPos;
00656                         }
00657 
00658                         paraText = d_text.substr(currPos, paraLen);
00659 
00660                         if (!d_wordWrap || (areaWidth <= 0.0f))
00661                         {
00662                                 // no word wrapping, so we are just one long line.
00663                                 line.d_startIdx = currPos;
00664                                 line.d_length   = (uint)paraLen;
00665                                 line.d_extent   = fnt->getTextExtent(paraText); 
00666                                 d_lines.push_back(line);
00667 
00668                                 // update widest, if needed.
00669                                 if (line.d_extent > d_widestExtent)
00670                                 {
00671                                         d_widestExtent = line.d_extent;
00672                                 }
00673 
00674                         }
00675                         // must word-wrap the paragraph text
00676                         else
00677                         {
00678                                 String::size_type lineIndex = 0;
00679 
00680                                 // while there is text in the string
00681                                 while (lineIndex < paraLen)
00682                                 {
00683                                         String::size_type  lineLen = 0;
00684                                         float lineExtent = 0.0f;
00685 
00686                                         // loop while we have not reached the end of the paragraph string
00687                                         while (lineLen < (paraLen - lineIndex))
00688                                         {
00689                                                 // get cp / char count of next token
00690                                                 uint nextTokenSize = getNextTokenLength(paraText, lineIndex + lineLen);
00691 
00692                                                 // get pixel width of the token
00693                                                 float tokenExtent  = fnt->getTextExtent(paraText.substr(lineIndex + lineLen, nextTokenSize));
00694 
00695                                                 // would adding this token would overflow the available width
00696                                                 if ((lineExtent + tokenExtent) > areaWidth)
00697                                                 {
00698                                                         // Was this the first token?
00699                                                         if (lineLen == 0)
00700                                                         {
00701                                                                 // get point at which to break the token
00702                                                                 lineLen = fnt->getCharAtPixel(paraText.substr(lineIndex, nextTokenSize), areaWidth);
00703                                                         }
00704 
00705                                                         // text wraps, exit loop early with line info up until wrap point
00706                                                         break;
00707                                                 }
00708 
00709                                                 // add this token to current line
00710                                                 lineLen    += nextTokenSize;
00711                                                 lineExtent += tokenExtent;
00712                                         }
00713 
00714                                         // set up line info and add to collection
00715                                         line.d_startIdx = currPos + lineIndex;
00716                                         line.d_length   = lineLen;
00717                                         line.d_extent   = lineExtent;
00718                                         d_lines.push_back(line);
00719 
00720                                         // update widest, if needed.
00721                                         if (lineExtent > d_widestExtent)
00722                                         {
00723                                                 d_widestExtent = lineExtent;
00724                                         }
00725 
00726                                         // update position in string
00727                                         lineIndex += lineLen;
00728                                 }
00729 
00730                         }
00731 
00732                         // skip to next 'paragraph' in text
00733                         currPos += paraLen;
00734                 }
00735 
00736         }
00737 
00738         configureScrollbars();
00739         requestRedraw();
00740 }
00741 
00742 
00743 /*************************************************************************
00744         Return the length of the next token in String 'text' starting at
00745         index 'start_idx'.
00746 *************************************************************************/
00747 uint MultiLineEditbox::getNextTokenLength(const String& text, uint start_idx) const
00748 {
00749         String::size_type pos = text.find_first_of(TextUtils::DefaultWrapDelimiters, start_idx);
00750 
00751         // handle case where no more whitespace exists (so this is last token)
00752         if (pos == String::npos)
00753         {
00754                 return ((uint)text.length()) - start_idx;
00755         }
00756         // handle 'delimiter' token cases
00757         else if (((uint)pos) - start_idx == 0)
00758         {
00759                 return 1;
00760         }
00761         else
00762         {
00763                 return ((uint)pos) - start_idx;
00764         }
00765 
00766 }
00767 
00768 
00769 /*************************************************************************
00770         Return the text code point index that is rendered closest to screen
00771         position 'pt'.  
00772 *************************************************************************/
00773 uint MultiLineEditbox::getTextIndexFromPosition(const Point& pt) const
00774 {
00775         //
00776         // calculate final window position to be checked
00777         //
00778         Point wndPt = screenToWindow(pt);
00779 
00780         if (getMetricsMode() == Relative)
00781         {
00782                 wndPt = relativeToAbsolute(wndPt);
00783         }
00784 
00785         Rect textArea(getTextRenderArea());
00786 
00787         wndPt.d_x -= textArea.d_left;
00788         wndPt.d_y -= textArea.d_top;
00789 
00790         // factor in scroll bar values
00791         wndPt.d_x += d_horzScrollbar->getScrollPosition();
00792         wndPt.d_y += d_vertScrollbar->getScrollPosition();
00793 
00794         uint lineNumber = (uint)(wndPt.d_y / getFont()->getLineSpacing());
00795 
00796         if (lineNumber >= (uint)d_lines.size())
00797         {
00798                 lineNumber = (uint)d_lines.size() - 1;
00799         }
00800 
00801         String lineText(d_text.substr(d_lines[lineNumber].d_startIdx, d_lines[lineNumber].d_length));
00802 
00803         uint lineIdx = getFont()->getCharAtPixel(lineText, wndPt.d_x);
00804 
00805         if (lineIdx >= (uint)lineText.length() - 1)
00806         {
00807                 lineIdx = (uint)lineText.length() - 1;
00808         }
00809 
00810         return d_lines[lineNumber].d_startIdx + lineIdx;
00811 }
00812 
00813 
00814 /*************************************************************************
00815         Return the line number a given index falls on with the current
00816         formatting.  Will return last line if index is out of range.
00817 *************************************************************************/
00818 uint MultiLineEditbox::getLineNumberFromIndex(uint index) const
00819 {
00820         uint lineCount = (uint)d_lines.size();
00821 
00822         if (lineCount == 0)
00823         {
00824                 return 0;
00825         }
00826         else if (index >= (uint)d_text.length() - 1)
00827         {
00828                 return lineCount - 1;
00829         }
00830         else
00831         {
00832                 uint indexCount = 0;
00833                 uint caratLine = 0;
00834 
00835                 for (; caratLine < lineCount; ++caratLine)
00836                 {
00837                         indexCount += d_lines[caratLine].d_length;
00838 
00839                         if (index < indexCount)
00840                         {
00841                                 return caratLine;
00842                         }
00843 
00844                 }
00845 
00846         }
00847 
00848         throw InvalidRequestException((utf8*)"MultiLineEditbox::getLineNumberFromIndex - Unable to identify a line from the given, invalid, index.");
00849 }
00850 
00851 
00852 
00853 /*************************************************************************
00854         Clear the current selection setting
00855 *************************************************************************/
00856 void MultiLineEditbox::clearSelection(void)
00857 {
00858         // perform action only if required.
00859         if (getSelectionLength() != 0)
00860         {
00861                 setSelection(0, 0);
00862         }
00863 
00864 }
00865 
00866 
00867 /*************************************************************************
00868         Erase the currently selected text.
00869 *************************************************************************/
00870 void MultiLineEditbox::eraseSelectedText(bool modify_text)
00871 {
00872         if (getSelectionLength() != 0)
00873         {
00874                 // setup new carat position and remove selection highlight.
00875                 setCaratIndex(getSelectionStartIndex());
00876 
00877                 // erase the selected characters (if required)
00878                 if (modify_text)
00879                 {
00880                         d_text.erase(getSelectionStartIndex(), getSelectionLength());
00881 
00882                         // trigger notification that text has changed.
00883                         WindowEventArgs args(this);
00884                         onTextChanged(args);
00885                 }
00886 
00887                 clearSelection();
00888         }
00889 
00890 }
00891 
00892 
00893 /*************************************************************************
00894         Processing for backspace key
00895 *************************************************************************/
00896 void MultiLineEditbox::handleBackspace(void)
00897 {
00898         if (!isReadOnly())
00899         {
00900                 if (getSelectionLength() != 0)
00901                 {
00902                         eraseSelectedText();
00903                 }
00904                 else if (d_caratPos > 0)
00905                 {
00906                         d_text.erase(d_caratPos - 1, 1);
00907                         setCaratIndex(d_caratPos - 1);
00908 
00909                         WindowEventArgs args(this);
00910                         onTextChanged(args);
00911                 }
00912 
00913         }
00914 }
00915 
00916 
00917 /*************************************************************************
00918         Processing for Delete key
00919 *************************************************************************/
00920 void MultiLineEditbox::handleDelete(void)
00921 {
00922         if (!isReadOnly())
00923         {
00924                 if (getSelectionLength() != 0)
00925                 {
00926                         eraseSelectedText();
00927                 }
00928                 else if (getCaratIndex() < d_text.length() - 1)
00929                 {
00930                         d_text.erase(d_caratPos, 1);
00931                         ensureCaratIsVisible();
00932 
00933                         WindowEventArgs args(this);
00934                         onTextChanged(args);
00935                 }
00936 
00937         }
00938 
00939 }
00940 
00941 
00942 /*************************************************************************
00943         Processing to move carat one character left
00944 *************************************************************************/
00945 void MultiLineEditbox::handleCharLeft(uint sysKeys)
00946 {
00947         if (d_caratPos > 0)
00948         {
00949                 setCaratIndex(d_caratPos - 1);
00950         }
00951 
00952         if (sysKeys & Shift)
00953         {
00954                 setSelection(d_caratPos, d_dragAnchorIdx);      
00955         }
00956         else
00957         {
00958                 clearSelection();
00959         }
00960 
00961 }
00962 
00963 
00964 /*************************************************************************
00965         Processing to move carat one word left
00966 *************************************************************************/
00967 void MultiLineEditbox::handleWordLeft(uint sysKeys)
00968 {
00969         if (d_caratPos > 0)
00970         {
00971                 setCaratIndex(TextUtils::getWordStartIdx(d_text, getCaratIndex()));
00972         }
00973 
00974         if (sysKeys & Shift)
00975         {
00976                 setSelection(d_caratPos, d_dragAnchorIdx);      
00977         }
00978         else
00979         {
00980                 clearSelection();
00981         }
00982 
00983 }
00984 
00985 
00986 /*************************************************************************
00987         Processing to move carat one character right
00988 *************************************************************************/
00989 void MultiLineEditbox::handleCharRight(uint sysKeys)
00990 {
00991         if (d_caratPos < d_text.length() - 1)
00992         {
00993                 setCaratIndex(d_caratPos + 1);
00994         }
00995 
00996         if (sysKeys & Shift)
00997         {
00998                 setSelection(d_caratPos, d_dragAnchorIdx);      
00999         }
01000         else
01001         {
01002                 clearSelection();
01003         }
01004 
01005 }
01006 
01007 
01008 /*************************************************************************
01009         Processing to move carat one word right
01010 *************************************************************************/
01011 void MultiLineEditbox::handleWordRight(uint sysKeys)
01012 {
01013         if (d_caratPos < d_text.length() - 1)
01014         {
01015                 setCaratIndex(TextUtils::getNextWordStartIdx(d_text, getCaratIndex()));
01016         }
01017 
01018         if (sysKeys & Shift)
01019         {
01020                 setSelection(d_caratPos, d_dragAnchorIdx);      
01021         }
01022         else
01023         {
01024                 clearSelection();
01025         }
01026 
01027 }
01028 
01029 
01030 /*************************************************************************
01031         Processing to move carat to the start of the text.
01032 *************************************************************************/
01033 void MultiLineEditbox::handleDocHome(uint sysKeys)
01034 {
01035         if (d_caratPos > 0)
01036         {
01037                 setCaratIndex(0);
01038         }
01039 
01040         if (sysKeys & Shift)
01041         {
01042                 setSelection(d_caratPos, d_dragAnchorIdx);      
01043         }
01044         else
01045         {
01046                 clearSelection();
01047         }
01048 
01049 }
01050 
01051 
01052 /*************************************************************************
01053         Processing to move carat to the end of the text
01054 *************************************************************************/
01055 void MultiLineEditbox::handleDocEnd(uint sysKeys)
01056 {
01057         if (d_caratPos < d_text.length() - 1)
01058         {
01059                 setCaratIndex(d_text.length() - 1);
01060         }
01061 
01062         if (sysKeys & Shift)
01063         {
01064                 setSelection(d_caratPos, d_dragAnchorIdx);      
01065         }
01066         else
01067         {
01068                 clearSelection();
01069         }
01070 
01071 }
01072 
01073 
01074 /*************************************************************************
01075         Processing to move carat to the start of the current line.      
01076 *************************************************************************/
01077 void MultiLineEditbox::handleLineHome(uint sysKeys)
01078 {
01079         uint line = getLineNumberFromIndex(d_caratPos);
01080 
01081         if (line < (uint)d_lines.size())
01082         {
01083                 uint lineStartIdx = d_lines[line].d_startIdx;
01084 
01085                 if (d_caratPos > lineStartIdx)
01086                 {
01087                         setCaratIndex(lineStartIdx);
01088                 }
01089 
01090                 if (sysKeys & Shift)
01091                 {
01092                         setSelection(d_caratPos, d_dragAnchorIdx);      
01093                 }
01094                 else
01095                 {
01096                         clearSelection();
01097                 }
01098 
01099         }
01100 
01101 }
01102 
01103 
01104 /*************************************************************************
01105         Processing to move carat to the end of the current line
01106 *************************************************************************/
01107 void MultiLineEditbox::handleLineEnd(uint sysKeys)
01108 {
01109         uint line = getLineNumberFromIndex(d_caratPos);
01110 
01111         if (line < (uint)d_lines.size())
01112         {
01113                 uint lineEndIdx = d_lines[line].d_startIdx + d_lines[line].d_length - 1;
01114 
01115                 if (d_caratPos < lineEndIdx)
01116                 {
01117                         setCaratIndex(lineEndIdx);
01118                 }
01119 
01120                 if (sysKeys & Shift)
01121                 {
01122                         setSelection(d_caratPos, d_dragAnchorIdx);      
01123                 }
01124                 else
01125                 {
01126                         clearSelection();
01127                 }
01128 
01129         }
01130 
01131 }
01132 
01133 
01134 /*************************************************************************
01135         Processing to move carat up a line.
01136 *************************************************************************/
01137 void MultiLineEditbox::handleLineUp(uint sysKeys)
01138 {
01139         uint caratLine = getLineNumberFromIndex(d_caratPos);
01140 
01141         if (caratLine > 0)
01142         {
01143                 float caratPixelOffset = getFont()->getTextExtent(d_text.substr(d_lines[caratLine].d_startIdx, d_caratPos - d_lines[caratLine].d_startIdx));
01144 
01145                 --caratLine;
01146 
01147                 uint newLineIndex = getFont()->getCharAtPixel(d_text.substr(d_lines[caratLine].d_startIdx, d_lines[caratLine].d_length), caratPixelOffset);
01148 
01149                 setCaratIndex(d_lines[caratLine].d_startIdx + newLineIndex);
01150         }
01151 
01152         if (sysKeys & Shift)
01153         {
01154                 setSelection(d_caratPos, d_dragAnchorIdx);      
01155         }
01156         else
01157         {
01158                 clearSelection();
01159         }
01160 
01161 }
01162 
01163 
01164 /*************************************************************************
01165         Processing to move carat down a line.
01166 *************************************************************************/
01167 void MultiLineEditbox::handleLineDown(uint sysKeys)
01168 {
01169         uint caratLine = getLineNumberFromIndex(d_caratPos);
01170 
01171         if ((d_lines.size() > 1) && (caratLine < (uint)(d_lines.size() - 1)))
01172         {
01173                 float caratPixelOffset = getFont()->getTextExtent(d_text.substr(d_lines[caratLine].d_startIdx, d_caratPos - d_lines[caratLine].d_startIdx));
01174 
01175                 ++caratLine;
01176 
01177                 uint newLineIndex = getFont()->getCharAtPixel(d_text.substr(d_lines[caratLine].d_startIdx, d_lines[caratLine].d_length), caratPixelOffset);
01178 
01179                 setCaratIndex(d_lines[caratLine].d_startIdx + newLineIndex);
01180         }
01181 
01182         if (sysKeys & Shift)
01183         {
01184                 setSelection(d_caratPos, d_dragAnchorIdx);      
01185         }
01186         else
01187         {
01188                 clearSelection();
01189         }
01190 
01191 }
01192 
01193 
01194 /*************************************************************************
01195         Processing to insert a new line / paragraph.
01196 *************************************************************************/
01197 void MultiLineEditbox::handleNewLine(uint sysKeys)
01198 {
01199         if (!isReadOnly())
01200         {
01201                 // erase selected text
01202                 eraseSelectedText();
01203 
01204                 // if there is room
01205                 if ((ulong)d_text.length() - 1 < d_maxTextLen)
01206                 {
01207                         d_text.insert(getCaratIndex(), 1, 0x0a);
01208                         d_caratPos++;
01209 
01210                         WindowEventArgs args(this);
01211                         onTextChanged(args);
01212                 }
01213 
01214         }
01215 
01216 }
01217 
01218 
01219 /*************************************************************************
01220         Handler for when a mouse button is pushed
01221 *************************************************************************/
01222 void MultiLineEditbox::onMouseButtonDown(MouseEventArgs& e)
01223 {
01224         // base class handling
01225         Window::onMouseButtonDown(e);
01226 
01227         if (e.button == LeftButton)
01228         {
01229                 // grab inputs
01230                 if (captureInput())
01231                 {
01232                         // handle mouse down
01233                         clearSelection();
01234                         d_dragging = true;
01235                         d_dragAnchorIdx = getTextIndexFromPosition(e.position);
01236                         setCaratIndex(d_dragAnchorIdx);
01237                 }
01238 
01239                 e.handled = true;
01240         }
01241 
01242 }
01243 
01244 
01245 /*************************************************************************
01246         Handler for when mouse button is released
01247 *************************************************************************/
01248 void MultiLineEditbox::onMouseButtonUp(MouseEventArgs& e)
01249 {
01250         // base class processing
01251         Window::onMouseButtonUp(e);
01252 
01253         if (e.button == LeftButton)
01254         {
01255                 releaseInput();
01256                 e.handled = true;
01257         }
01258 
01259 }
01260 
01261 
01262 /*************************************************************************
01263         Handler for when mouse button is double-clicked
01264 *************************************************************************/
01265 void MultiLineEditbox::onMouseDoubleClicked(MouseEventArgs& e)
01266 {
01267         // base class processing
01268         Window::onMouseDoubleClicked(e);
01269 
01270         if (e.button == LeftButton)
01271         {
01272                 d_dragAnchorIdx = TextUtils::getWordStartIdx(d_text, (d_caratPos == d_text.length()) ? d_caratPos : d_caratPos + 1);
01273                 d_caratPos              = TextUtils::getNextWordStartIdx(d_text, d_caratPos);
01274 
01275                 // perform actual selection operation.
01276                 setSelection(d_dragAnchorIdx, d_caratPos);
01277 
01278                 e.handled = true;
01279         }
01280 
01281 }
01282 
01283 
01284 /*************************************************************************
01285         Handler for when mouse button is triple-clicked.
01286 *************************************************************************/
01287 void MultiLineEditbox::onMouseTripleClicked(MouseEventArgs& e)
01288 {
01289         // base class processing
01290         Window::onMouseTripleClicked(e);
01291 
01292         if (e.button == LeftButton)
01293         {
01294                 uint caratLine = getLineNumberFromIndex(d_caratPos);
01295                 uint lineStart = d_lines[caratLine].d_startIdx;
01296 
01297                 // find end of last paragraph
01298                 String::size_type paraStart = d_text.find_last_of(d_lineBreakChars, lineStart);
01299 
01300                 // if no previous paragraph, selection will start at the beginning.
01301                 if (paraStart == String::npos)
01302                 {
01303                         paraStart = 0;
01304                 }
01305 
01306                 // find end of this paragraph
01307                 String::size_type paraEnd = d_text.find_first_of(d_lineBreakChars, lineStart);
01308 
01309                 // if paragraph has no end, which actually should never happen, fix the
01310                 // erroneous situation and select up to end at end of text.
01311                 if (paraEnd == String::npos)
01312                 {
01313                         d_text.append(1, '\n');
01314                         paraEnd = d_text.length() - 1;
01315                 }
01316 
01317                 // set up selection using new values.
01318                 d_dragAnchorIdx = paraStart;
01319                 setCaratIndex(paraEnd);
01320                 setSelection(d_dragAnchorIdx, d_caratPos);
01321                 e.handled = true;
01322         }
01323 
01324 }
01325 
01326 
01327 /*************************************************************************
01328         Handler for when mouse moves in the window.
01329 *************************************************************************/
01330 void MultiLineEditbox::onMouseMove(MouseEventArgs& e)
01331 {
01332         // base class processing
01333         Window::onMouseMove(e);
01334 
01335         if (d_dragging)
01336         {
01337                 setCaratIndex(getTextIndexFromPosition(e.position));
01338                 setSelection(d_caratPos, d_dragAnchorIdx);
01339         }
01340 
01341         e.handled = true;
01342 }
01343 
01344 
01345 /*************************************************************************
01346         Handler for when capture is lost.
01347 *************************************************************************/
01348 void MultiLineEditbox::onCaptureLost(WindowEventArgs& e)
01349 {
01350         d_dragging = false;
01351 
01352         // base class processing
01353         Window::onCaptureLost(e);
01354 
01355         e.handled = true;
01356 }
01357 
01358 
01359 /*************************************************************************
01360         Handler for when character (printable keys) are typed
01361 *************************************************************************/
01362 void MultiLineEditbox::onCharacter(KeyEventArgs& e)
01363 {
01364         // base class processing
01365         Window::onCharacter(e);
01366 
01367         // only need to take notice if we have focus
01368         if (hasInputFocus() && !isReadOnly() && getFont()->isCodepointAvailable(e.codepoint))
01369         {
01370                 // erase selected text
01371                 eraseSelectedText();
01372 
01373                 // if there is room
01374                 if ((ulong)d_text.length() - 1 < d_maxTextLen)
01375                 {
01376                         d_text.insert(getCaratIndex(), 1, e.codepoint);
01377                         d_caratPos++;
01378 
01379                         WindowEventArgs args(this);
01380                         onTextChanged(args);
01381                 }
01382                 else
01383                 {
01384                         // Trigger text box full event
01385                         WindowEventArgs args(this);
01386                         onEditboxFullEvent(args);
01387                 }
01388 
01389         }
01390 
01391         e.handled = true;
01392 }
01393 
01394 
01395 /*************************************************************************
01396         Handler for when non-printable keys are typed.
01397 *************************************************************************/
01398 void MultiLineEditbox::onKeyDown(KeyEventArgs& e)
01399 {
01400         // base class processing
01401         Window::onKeyDown(e);
01402 
01403         if (hasInputFocus() && !isReadOnly())
01404         {
01405                 WindowEventArgs args(this);
01406                 switch (e.scancode)
01407                 {
01408                 case Key::LeftShift:
01409                 case Key::RightShift:
01410                         if (getSelectionLength() == 0)
01411                         {
01412                                 d_dragAnchorIdx = getCaratIndex();
01413                         }
01414                         break;
01415 
01416                 case Key::Backspace:
01417                         handleBackspace();
01418                         break;
01419 
01420                 case Key::Delete:
01421                         handleDelete();
01422                         break;
01423 
01424                 case Key::Return:
01425                 case Key::NumpadEnter:
01426                         handleNewLine(e.sysKeys);
01427                         break;
01428 
01429                 case Key::ArrowLeft:
01430                         if (e.sysKeys & Control)
01431                         {
01432                                 handleWordLeft(e.sysKeys);
01433                         }
01434                         else
01435                         {
01436                                 handleCharLeft(e.sysKeys);
01437                         }
01438                         break;
01439 
01440                 case Key::ArrowRight:
01441                         if (e.sysKeys & Control)
01442                         {
01443                                 handleWordRight(e.sysKeys);
01444                         }
01445                         else
01446                         {
01447                                 handleCharRight(e.sysKeys);
01448                         }
01449                         break;
01450 
01451                 case Key::ArrowUp:
01452                         handleLineUp(e.sysKeys);
01453                         break;
01454 
01455                 case Key::ArrowDown:
01456                         handleLineDown(e.sysKeys);
01457                         break;
01458 
01459                 case Key::Home:
01460                         if (e.sysKeys & Control)
01461                         {
01462                                 handleDocHome(e.sysKeys);
01463                         }
01464                         else
01465                         {
01466                                 handleLineHome(e.sysKeys);
01467                         }
01468                         break;
01469 
01470                 case Key::End:
01471                         if (e.sysKeys & Control)
01472                         {
01473                                 handleDocEnd(e.sysKeys);
01474                         }
01475                         else
01476                         {
01477                                 handleLineEnd(e.sysKeys);
01478                         }
01479                         break;
01480                 }
01481 
01482                 e.handled = true;
01483         }
01484 
01485 }
01486 
01487 
01488 /*************************************************************************
01489         Handler for when text is programmatically changed.
01490 *************************************************************************/
01491 void MultiLineEditbox::onTextChanged(WindowEventArgs& e)
01492 {
01493         // ensure last character is a new line
01494         if ((d_text.length() == 0) || (d_text[d_text.length() - 1] != '\n'))
01495         {
01496                 d_text.append(1, '\n');
01497         }
01498 
01499         // base class processing
01500         Window::onTextChanged(e);
01501 
01502         // clear selection
01503         clearSelection();
01504 
01505         // make sure carat is within the text
01506         if (getCaratIndex() > d_text.length() - 1)
01507         {
01508                 setCaratIndex(d_text.length() - 1);
01509         }
01510 
01511         formatText();
01512         layoutComponentWidgets();
01513         ensureCaratIsVisible();
01514 
01515         e.handled = true;
01516 }
01517 
01518 
01519 /*************************************************************************
01520         Handler for when widget size is changed.
01521 *************************************************************************/
01522 void MultiLineEditbox::onSized(WindowEventArgs& e)
01523 {
01524         // base class handling
01525         Window::onSized(e);
01526 
01527         formatText();
01528         layoutComponentWidgets();
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 } // End of  CEGUI namespace section

Generated on Wed Feb 16 12:41:07 2005 for Crazy Eddies GUI System by  doxygen 1.3.9.1