AaronCameron.net
No ads. No Profit. No Master, But Truth.
Not a Member? - Login or Create an Account
Tuesday the 22nd of May 2012 @ 12:58am
Front Page Journal Projects Your Profile About
[]

LibN2L-4 Library Code Reference

Classes
Compounds
Files
Members
Method Index
Full Reference

cGuiTextDisplay.cpp

Go to the documentation of this file.
00001 /************************************************************************
00002 Nova-2 Library (libN2L, or simply n2l) Game development C++ Library
00003 Copyright (C) 2003  Aaron Cameron
00004 
00005 This library is free software; you can redistribute it and/or
00006 modify it under the terms of the GNU Lesser General Public
00007 License as published by the Free Software Foundation; either
00008 version 2.1 of the License, or (at your option) any later version.
00009 
00010 This library is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 Lesser General Public License for more details.
00014 
00015 You should have received a copy of the GNU Lesser General Public
00016 License along with this library; if not, write to the Free Software
00017 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00018 
00019 A copy of the GNU Lesser General Public License has been provided with
00020 this library in the file 'COPYING'.
00021 
00022 Contact information for the author of this library has been provided
00023 with this library in the file 'AUTHOR'.
00024 ************************************************************************/
00025 #include "gui/cGuiTextDisplay.h"
00026 
00027 #include "n2l/dynVars.h"
00028 #include "n2l/resourceManagement.h"
00029 #include "n2l/events.h"
00030 
00031 #include "gui/cGuiSlider.h"
00032 #include "gui/cGuiSEInt.h"
00033 #include "gui/cGuiACInt.h"
00034 
00035 #include "gui/cGuiFactory.h"
00036 
00037 namespace n2l
00038 {
00039 
00040 #   ifdef N2L_PASSIVE_GUI_REG
00041         tBool cGuiTextDisplay::smRegistered =
00042             cGuiFactory::current().registerLoader( "n2l::cGuiTextDisplay",
00043             cGuiElement::loadNew<cGuiTextDisplay> );
00044 #   endif
00045 
00046     /**************************************************************************/
00047     cGuiTextDisplay::cGuiTextDisplay()
00048     {
00049         reset();
00050     }
00051 
00052     /**************************************************************************/
00053     cGuiTextDisplay::~cGuiTextDisplay()
00054     {
00055         reset();
00056     }
00057 
00058     /**************************************************************************/
00059     cGuiTextDisplay::cGuiTextDisplay( const cVfsNodeInterface &iNode )
00060     {
00061         reset();
00062         load( iNode );
00063     }
00064 
00065     /**************************************************************************/
00066     cGuiTextDisplay::cGuiTextDisplay( const cDynVar &iDefinition )
00067     {
00068         reset();
00069         load( iDefinition );
00070     }
00071 
00072     /**************************************************************************/
00073     void cGuiTextDisplay::load( const cVfsNodeInterface &iNode )
00074     {
00075         cDynVar def;
00076         validateAndDecode( def, iNode, "n2l::cGuiTextDisplay" );
00077         load( def );
00078     }
00079 
00080     /**************************************************************************/
00081     void cGuiTextDisplay::load( const cDynVar &iDefinition )
00082     {
00083         // Load parent properties
00084         cGuiInteractive::load( iDefinition );
00085 
00086         // Now my properties
00087         if (iDefinition["textStyle"]) {
00088             if (iDefinition["textStyle"].isArray())
00089                 textStyle( cGuiTextStyle( iDefinition["textStyle"] ) );
00090             else textStyle( *cResourceManager::get<cGuiTextStyle>(
00091                 iDefinition["textStyle"]) );
00092         }
00093 
00094         if (iDefinition.keyExists("slider")) {
00095             if (iDefinition["slider"].isArray())
00096                 slider( cGuiSlider(iDefinition["slider"]) );
00097             else {
00098                 // Cleanly catch bad casts so we can show an error, instead
00099                 // of just exploding anonymously.
00100                 try {
00101                     const cAutoPtr<const cGuiSlider> Slider =
00102                         cResourceManager::getGuiElement(iDefinition["slider"]);
00103                     slider( *Slider );
00104                 }
00105                 catch (const cBadCastException & iException) {
00106                     throw cParsingException( "cGuiTextDisplay::load",
00107                         "Provided slider template file didn\'t "
00108                         "define a slider");
00109                 }
00110             }
00111         } // slider was an array
00112 
00113         // Specifically do the text last, so the 'lines' reflow happens as 
00114         // few times as possible.
00115         if (iDefinition.keyExists("text"))
00116             text( iDefinition["text"] );
00117     }
00118 
00119     /**************************************************************************/
00120     void cGuiTextDisplay::draw() const
00121     {
00122         tGuiPos textPos( innerPos() );
00123         const tFloat LineSeperation =
00124             mTextStyle.font()->glyphRowSeperation( mTextStyle.fontHeight() );
00125 
00126         const tFloat BottomEdge =
00127             (innerPos()+innerSize()).y()-mTextStyle.fontHeight();
00128 
00129         tGuiPos lineSize( innerSize().x(), mTextStyle.fontHeight() );
00130 
00131         tUint line=0;
00132         if (mSlider.isSet()) {
00133             line = tUint(mSlider->value()+0.5f);
00134             lineSize.x() -= mSlider->size().x();
00135         } else {
00136             line = mLineOffset;
00137         }
00138 
00139         while (line<mLines.size() && textPos.y()<BottomEdge)
00140         {
00141             // Catch the zero size, because draw() will see it as lease to
00142             // draw as much as it can.
00143             // not none.
00144             if (mLines[line].mSize)
00145                 mTextStyle.draw( textPos, lineSize, mText,
00146                     mLines[line].mSPos, mLines[line].mSize );
00147             ++line;
00148             textPos.y( textPos.y()+lineSize.y()+LineSeperation );
00149         }
00150 
00151         if (mSlider.isSet())
00152             mSlider->draw();
00153     }
00154 
00155     /**************************************************************************/
00156     void cGuiTextDisplay::textStyle( const cGuiTextStyle &iStyle )
00157     {
00158         mTextStyle = iStyle;
00159         propertyChanged();
00160     }
00161 
00162     /**************************************************************************/
00163     const cGuiTextStyle & cGuiTextDisplay::textStyle() const
00164     {
00165         return mTextStyle;
00166     }
00167 
00168     /**************************************************************************/
00169     void cGuiTextDisplay::slider( const cGuiSlider &iSliderTemplate )
00170     {
00171         mSlider = iSliderTemplate.clone();
00172         // Down on the wheel and kp should go deeper into the text
00173         mSlider->swapWheel( true );
00174         propertyChanged();
00175         dimensionChanged();
00176     }
00177 
00178     /**************************************************************************/
00179     void cGuiTextDisplay::text( const tString & iText )
00180     {
00181         mText = substringReplace("\t","    ",iText);
00182         propertyChanged();
00183     }
00184 
00185     /**************************************************************************/
00186     const tString & cGuiTextDisplay::text() const
00187     {
00188         return mText;
00189     }
00190 
00191     /**************************************************************************/
00192     void cGuiTextDisplay::lineInfo( const tUint &iLine,
00193         tUint &oSPos, tUint &oLen ) const
00194     {
00195         if (iLine >= mLines.size())
00196             throw cOutOfBoundsException( "cGuiTextDisplay::lineInfo",
00197                 "No such line to get info for.", asString(iLine) );
00198         oSPos = mLines[iLine].mSPos;
00199         oLen = mLines[iLine].mSize;
00200     }
00201 
00202     /**************************************************************************/
00203     const tUint cGuiTextDisplay::numLines() const
00204     {
00205         return mLines.size();
00206     }
00207 
00208     /**************************************************************************/
00209     const tUint &cGuiTextDisplay::lineOffset() const
00210     {
00211         return mLineOffset;
00212     }
00213 
00214     /**************************************************************************/
00215     void cGuiTextDisplay::lineOffset( const tUint &iOffset )
00216     {
00217         mLineOffset = n2lMin(iOffset, mLines.size());
00218     }
00219 
00220     /**************************************************************************/
00221     const cAutoPtr<cGuiElement> cGuiTextDisplay::clone() const
00222     {
00223         cAutoPtr<cGuiElement> newElement( new cGuiTextDisplay );
00224         cloneInto( newElement );
00225         return newElement;
00226     }
00227 
00228     /**************************************************************************/
00229     void cGuiTextDisplay::prop( const tString &iName, const cDynVar &iVal,
00230         const tString &iInnerKey )
00231     {
00232         if (iName == "textStyle") {
00233             if (iInnerKey.empty()) {
00234                 if (iVal.isArray())
00235                     textStyle( iVal );
00236                 else
00237                     textStyle( *cResourceManager::get<cGuiTextStyle>(iVal) );
00238             } else
00239                 mTextStyle.prop( iInnerKey, iVal );
00240 
00241         } else
00242             cGuiElement::prop( iName, iVal );
00243     }
00244 
00245     /**************************************************************************/
00246     const cDynVar cGuiTextDisplay::prop( const tString &iName,
00247         const tString &iInnerKey ) const
00248     {
00249         if (iName == "textStyle")
00250             return mTextStyle.prop( iInnerKey );
00251 
00252         return cGuiElement::prop( iName );
00253     }
00254 
00255     /**************************************************************************/
00256     void cGuiTextDisplay::systemEvent(
00257         const cAutoPtr<const cEventInterface> &i_iEvent )
00258     {
00259         cGuiInteractive::systemEvent( i_iEvent );
00260 
00261         if (i_iEvent->type()==EventType_MouseButton)
00262         {
00263             const cAutoPtr<const cMouseButtonEvent> Click( i_iEvent );
00264             // Intercept up and down clicks and send them to the 
00265             // slider instead of the canvas so that the wheel works
00266             // anywhere on the widget, rather than just on the
00267             // slide bar
00268             if ((Click->button()==MouseButton_Up ||
00269                 Click->button()==MouseButton_Down) &&
00270                 collides( Click->pos() ) )
00271             {
00272                 if (mSlider.isSet()) {
00273                     cAutoPtr<cMouseButtonEvent> fakeClick =
00274                         new cMouseButtonEvent(*Click);
00275                     fakeClick->pos( mSlider->pos() );
00276                     mSlider->systemEvent( fakeClick );
00277                 }
00278             } else {
00279                 // Slider is in here so we don't double send to it if
00280                 // the up or down wheel is used.
00281                 if (mSlider.isSet()) mSlider->systemEvent( i_iEvent );
00282             }
00283         } else {// if this is a mouse button.
00284             if (mSlider.isSet()) mSlider->systemEvent( i_iEvent );
00285         }
00286 
00287     }
00288 
00289     /**************************************************************************/
00290     void cGuiTextDisplay::systemEventOutside(
00291         const cAutoPtr<const cEventInterface> &i_iEvent )
00292     {
00293         cGuiInteractive::systemEventOutside( i_iEvent );
00294         if (mSlider.isSet()) mSlider->systemEventOutside( i_iEvent );
00295     }
00296 
00297     /**************************************************************************/
00298     void cGuiTextDisplay::cloneInto(
00299         const cAutoPtr<cGuiTextDisplay> &i_ioElement ) const
00300     {
00301         // Parent Properties first
00302         cGuiInteractive::cloneInto( i_ioElement );
00303         
00304         //  Now our properties.
00305         i_ioElement->textStyle(mTextStyle);
00306         if (mSlider.isSet())
00307             i_ioElement->slider( *mSlider );
00308         i_ioElement->text(mText);
00309 
00310         i_ioElement->mLineOffset = mLineOffset;
00311     }
00312 
00313     /**************************************************************************/
00314     void cGuiTextDisplay::dimensionChanged()
00315     {
00316         // Call our parent first
00317         cGuiInteractive::dimensionChanged();
00318 
00319         if (mSlider.isSet()) {
00320             mSlider->pos(
00321                 tGuiPos(innerPos().x()+innerSize().x()-mSlider->size().x(),
00322                 innerPos().y()) );
00323             mSlider->size( tGuiPos(mSlider->size().x(),innerSize().y()) );
00324         }
00325     }
00326 
00327     /**************************************************************************/
00328     void cGuiTextDisplay::propertyChanged()
00329     {
00330         // Call our parent first
00331         cGuiInteractive::propertyChanged();
00332 
00333         // Rebuild the line indicies.
00334         mLines.clear();
00335 
00336         const tFloat LineSeperation = mTextStyle.font()->glyphRowSeperation(
00337             mTextStyle.fontHeight() );
00338         tGuiPos lineSize( innerSize().x(), mTextStyle.fontHeight() );
00339         // If se have a slider, leave room for it.
00340         if (mSlider.isSet()) lineSize.x() -= mSlider->size().x();
00341 
00342         tString::size_type lastShownChar(0);
00343         tLineInfo lineInfo;
00344         const tLineInfo EmptyLine = {0,0};
00345 
00346         while (lastShownChar<mText.size())
00347         {
00348             // Find the next 'newline' character, this can be optimized
00349             // in the future.
00350             tString::size_type nextNewline( mText.find_first_of('\n',
00351                 lastShownChar) );
00352             // If there was a newline, seek until we hit it, rather than
00353             // showing the whole line.
00354             if (nextNewline!=tString::npos) {
00355                 lineInfo.mSPos = lastShownChar;
00356                 lineInfo.mSize = mTextStyle.wouldDraw( lineSize, mText,
00357                     lastShownChar, nextNewline-lastShownChar );
00358                 lastShownChar += (lineInfo.mSize);
00359                 // Strip the first newline, if there is one.  We don't
00360                 // want to render two.
00361                 if (mText[lastShownChar] == '\n') ++lastShownChar;
00362                 mLines.push_back(lineInfo);
00363 
00364                 while (mText[lastShownChar] == '\n') {
00365                     mLines.push_back(EmptyLine);
00366                     ++lastShownChar;
00367                 }
00368             } else {
00369                 lineInfo.mSPos = lastShownChar;
00370                 lineInfo.mSize = mTextStyle.wouldDraw( lineSize, mText,
00371                     lastShownChar );
00372                 //++lineInfo.mSize;
00373                 lastShownChar += lineInfo.mSize;
00374                 mLines.push_back(lineInfo);
00375                 if (mText[lastShownChar]==' ' ||
00376                     mText[lastShownChar]=='\n') ++lastShownChar;
00377             }
00378         } 
00379 
00380         // Set the slider min/max/range based on the line calculations
00381         if (mSlider.isSet()) {
00382             mSlider->min(0);
00383             mSlider->value(0);
00384             mSlider->max( mLines.size() );
00385             mSlider->range(
00386                 tUint(innerSize().y()/(lineSize.y()+LineSeperation)) );
00387         }
00388     }
00389     
00390     /**************************************************************************/
00391     void cGuiTextDisplay::reset()
00392     {
00393         pos( tGuiPos(0,0) );
00394         size( tGuiPos(0,0) );
00395         mText = "";
00396         mSlider = 0;
00397         mLineOffset = 0;
00398         mLineOffset = 0;
00399     }
00400 
00401 } // namespace n2l
©2012 Aaron Cameron