Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

ctrl_text.cpp

00001 /*****************************************************************************
00002  * ctrl_text.cpp
00003  *****************************************************************************
00004  * Copyright (C) 2003 the VideoLAN team
00005  * $Id: ctrl_text.cpp 12207 2005-08-15 15:54:32Z asmax $
00006  *
00007  * Authors: Cyril Deguet     <[email protected]>
00008  *          Olivier Teulière <[email protected]>
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00023  *****************************************************************************/
00024 
00025 #include "ctrl_text.hpp"
00026 #include "../events/evt_generic.hpp"
00027 #include "../events/evt_mouse.hpp"
00028 #include "../src/generic_bitmap.hpp"
00029 #include "../src/generic_font.hpp"
00030 #include "../src/os_factory.hpp"
00031 #include "../src/os_graphics.hpp"
00032 #include "../src/os_timer.hpp"
00033 #include "../utils/position.hpp"
00034 #include "../utils/ustring.hpp"
00035 #include "../utils/var_text.hpp"
00036 
00037 
00038 #define MOVING_TEXT_STEP 1
00039 #define MOVING_TEXT_DELAY 30
00040 #define SEPARATOR_STRING "   "
00041 
00042 
00043 CtrlText::CtrlText( intf_thread_t *pIntf, VarText &rVariable,
00044                     const GenericFont &rFont, const UString &rHelp,
00045                     uint32_t color, VarBool *pVisible ):
00046     CtrlGeneric( pIntf, rHelp, pVisible ), m_fsm( pIntf ),
00047     m_rVariable( rVariable ), m_cmdToManual( this ),
00048     m_cmdManualMoving( this ), m_cmdManualStill( this ),
00049     m_cmdMove( this ), m_pEvt( NULL ), m_rFont( rFont ),
00050     m_color( color ), m_pImg( NULL ), m_pImgDouble( NULL ),
00051     m_pCurrImg( NULL ), m_xPos( 0 ), m_xOffset( 0 ),
00052     m_cmdUpdateText( this )
00053 {
00054     m_pTimer = OSFactory::instance( pIntf )->createOSTimer( m_cmdUpdateText );
00055 
00056     // States
00057     m_fsm.addState( "still" );
00058     m_fsm.addState( "moving" );
00059     m_fsm.addState( "manual1" );
00060     m_fsm.addState( "manual2" );
00061     m_fsm.addState( "outStill" );
00062     m_fsm.addState( "outMoving" );
00063 
00064     // Transitions
00065     m_fsm.addTransition( "still", "mouse:left:down", "manual1",
00066                          &m_cmdToManual );
00067     m_fsm.addTransition( "manual1", "mouse:left:up", "moving",
00068                          &m_cmdManualMoving );
00069     m_fsm.addTransition( "moving", "mouse:left:down", "manual2",
00070                          &m_cmdToManual );
00071     m_fsm.addTransition( "manual2", "mouse:left:up", "still",
00072                          &m_cmdManualStill );
00073     m_fsm.addTransition( "manual1", "motion", "manual1", &m_cmdMove );
00074     m_fsm.addTransition( "manual2", "motion", "manual2", &m_cmdMove );
00075     m_fsm.addTransition( "still", "leave", "outStill" );
00076     m_fsm.addTransition( "outStill", "enter", "still" );
00077     m_fsm.addTransition( "moving", "leave", "outMoving" );
00078     m_fsm.addTransition( "outMoving", "enter", "moving" );
00079 
00080     // Initial state
00081     m_fsm.setState( "moving" );
00082 
00083     // Observe the variable
00084     m_rVariable.addObserver( this );
00085 
00086     // Set the text
00087     displayText( m_rVariable.get() );
00088 }
00089 
00090 
00091 CtrlText::~CtrlText()
00092 {
00093     m_rVariable.delObserver( this );
00094     if( m_pTimer )
00095     {
00096         delete m_pTimer;
00097     }
00098     if( m_pImg )
00099     {
00100         delete m_pImg;
00101     }
00102     if( m_pImgDouble )
00103     {
00104         delete m_pImgDouble;
00105     }
00106 }
00107 
00108 
00109 void CtrlText::handleEvent( EvtGeneric &rEvent )
00110 {
00111     // Save the event to use it in callbacks
00112     m_pEvt = &rEvent;
00113 
00114     m_fsm.handleTransition( rEvent.getAsString() );
00115 }
00116 
00117 
00118 bool CtrlText::mouseOver( int x, int y ) const
00119 {
00120     if( m_pCurrImg )
00121     {
00122         // We have 3 different ways of deciding when to return true here:
00123         //  1) the mouse is exactly over the text (so if you click between two
00124         //     letters, the text control doesn't catch the event)
00125         //  2) the mouse is over the rectangle of the control
00126         //  3) the mouse is over the rectangle of the visible text
00127         // I don't know which one is the best...
00128 #if 0
00129         return( x >= 0 && x < getPosition()->getWidth()
00130              && m_pCurrImg->hit( x - m_xPos, y ) );
00131 #endif
00132 #if 1
00133         return( x >= 0 && x < getPosition()->getWidth()
00134              && y >= 0 && y < getPosition()->getHeight() );
00135 #endif
00136 #if 0
00137         return( x >= 0 && x < getPosition()->getWidth()
00138              && y >= 0 && y < getPosition()->getHeight()
00139              && x < m_pCurrImg->getWidth() && x < m_pCurrImg->getHeight() );
00140 #endif
00141     }
00142     else
00143     {
00144         return false;
00145     }
00146 }
00147 
00148 
00149 void CtrlText::draw( OSGraphics &rImage, int xDest, int yDest )
00150 {
00151     if( m_pCurrImg )
00152     {
00153         // Compute the dimensions to draw
00154         int width = min( m_pCurrImg->getWidth() + m_xPos,
00155                          getPosition()->getWidth() );
00156         int height = min( m_pCurrImg->getHeight(), getPosition()->getHeight() );
00157         // Draw the current image
00158         if( width > 0 && height > 0 )
00159         {
00160             rImage.drawBitmap( *m_pCurrImg, -m_xPos, 0, xDest, yDest,
00161                             width, height, true );
00162         }
00163     }
00164 }
00165 
00166 
00167 void CtrlText::setText( const UString &rText, uint32_t color )
00168 {
00169     // Change the color
00170     if( color != 0xFFFFFFFF )
00171     {
00172         m_color = color;
00173     }
00174 
00175     // Change the text
00176     m_rVariable.set( rText );
00177 }
00178 
00179 
00180 void CtrlText::onUpdate( Subject<VarText> &rVariable )
00181 {
00182     displayText( m_rVariable.get() );
00183 }
00184 
00185 
00186 void CtrlText::displayText( const UString &rText )
00187 {
00188     // Create the images ('normal' and 'double') from the text
00189     // 'Normal' image
00190     if( m_pImg )
00191     {
00192         delete m_pImg;
00193     }
00194     m_pImg = m_rFont.drawString( rText, m_color );
00195     if( !m_pImg )
00196     {
00197         return;
00198     }
00199     // 'Double' image
00200     const UString doubleStringWithSep = rText + SEPARATOR_STRING + rText;
00201     if( m_pImgDouble )
00202     {
00203         delete m_pImgDouble;
00204     }
00205     m_pImgDouble = m_rFont.drawString( doubleStringWithSep, m_color );
00206 
00207     // Update the current image used, as if the control size had changed
00208     onChangePosition();
00209     m_xPos = 0;
00210 
00211     if( getPosition() )
00212     {
00213         // If the control was in the moving state, check if the scrolling is
00214         // still necessary
00215         const string &rState = m_fsm.getState();
00216         if( rState == "moving" || rState == "outMoving" )
00217         {
00218             if( m_pImg && m_pImg->getWidth() >= getPosition()->getWidth() )
00219             {
00220                 m_pCurrImg = m_pImgDouble;
00221                 m_pTimer->start( MOVING_TEXT_DELAY, false );
00222             }
00223             else
00224             {
00225                 m_pTimer->stop();
00226             }
00227         }
00228         notifyLayout( getPosition()->getWidth(), getPosition()->getHeight() );
00229     }
00230 }
00231 
00232 
00233 void CtrlText::onChangePosition()
00234 {
00235     if( m_pImg && getPosition() )
00236     {
00237         if( m_pImg->getWidth() < getPosition()->getWidth() )
00238         {
00239             m_pCurrImg = m_pImg;
00240         }
00241         else
00242         {
00243             m_pCurrImg = m_pImgDouble;
00244         }
00245     }
00246     else
00247     {
00248         // m_pImg is a better default value than m_pImgDouble, but anyway we
00249         // don't care because the control is never drawn without position :)
00250         m_pCurrImg = m_pImg;
00251     }
00252 }
00253 
00254 
00255 void CtrlText::CmdToManual::execute()
00256 {
00257     EvtMouse *pEvtMouse = (EvtMouse*)m_pParent->m_pEvt;
00258 
00259     // Compute the offset
00260     m_pParent->m_xOffset = pEvtMouse->getXPos() - m_pParent->m_xPos;
00261 
00262     m_pParent->m_pTimer->stop();
00263     m_pParent->captureMouse();
00264 }
00265 
00266 
00267 void CtrlText::CmdManualMoving::execute()
00268 {
00269     m_pParent->releaseMouse();
00270 
00271     // Start the automatic movement, but only if the text is wider than the
00272     // control
00273     if( m_pParent->m_pImg &&
00274         m_pParent->m_pImg->getWidth() >= m_pParent->getPosition()->getWidth() )
00275     {
00276         // The current image may have been set incorrectly in displayText(), so
00277         // set the correct value
00278         m_pParent->m_pCurrImg = m_pParent->m_pImgDouble;
00279 
00280         m_pParent->m_pTimer->start( MOVING_TEXT_DELAY, false );
00281     }
00282 }
00283 
00284 
00285 void CtrlText::CmdManualStill::execute()
00286 {
00287     m_pParent->releaseMouse();
00288 }
00289 
00290 
00291 void CtrlText::CmdMove::execute()
00292 {
00293     EvtMouse *pEvtMouse = (EvtMouse*)m_pParent->m_pEvt;
00294 
00295     // Do nothing if the text fits in the control
00296     if( m_pParent->m_pImg &&
00297         m_pParent->m_pImg->getWidth() >= m_pParent->getPosition()->getWidth() )
00298     {
00299         // The current image may have been set incorrectly in displayText(), so
00300         // we set the correct value
00301         m_pParent->m_pCurrImg = m_pParent->m_pImgDouble;
00302 
00303         // Compute the new position of the left side, and make sure it is
00304         // in the correct range
00305         m_pParent->m_xPos = (pEvtMouse->getXPos() - m_pParent->m_xOffset);
00306         m_pParent->adjust( m_pParent->m_xPos );
00307 
00308         m_pParent->notifyLayout( m_pParent->getPosition()->getWidth(),
00309                              m_pParent->getPosition()->getHeight() );
00310     }
00311 }
00312 
00313 
00314 void CtrlText::CmdUpdateText::execute()
00315 {
00316     m_pParent->m_xPos -= MOVING_TEXT_STEP;
00317     m_pParent->adjust( m_pParent->m_xPos );
00318 
00319     m_pParent->notifyLayout( m_pParent->getPosition()->getWidth(),
00320                          m_pParent->getPosition()->getHeight() );
00321 }
00322 
00323 
00324 void CtrlText::adjust( int &position )
00325 {
00326     // {m_pImgDouble->getWidth()  - m_pImg->getWidth()} is the period of the
00327     // bitmap; remember that the string used to generate m_pImgDouble is of the
00328     // form: "foo  foo", the number of spaces being a parameter
00329     if( !m_pImg )
00330     {
00331         return;
00332     }
00333     position %= m_pImgDouble->getWidth() - m_pImg->getWidth();
00334     if( position > 0 )
00335     {
00336         position -= m_pImgDouble->getWidth() - m_pImg->getWidth();
00337     }
00338 }
00339 

Generated on Tue Dec 20 10:14:41 2005 for vlc-0.8.4a by  doxygen 1.4.2