garrynewman / GWEN

Abandoned: GWEN - GUI Without Extravagant Nonsense.
MIT License
427 stars 102 forks source link

SFML renderer MeasureText issues (width of space character) #60

Open Walley7 opened 11 years ago

Walley7 commented 11 years ago

SFML2 returns a width of 0 for the space glyph, which end up connecting to issues caused with multi line labels (all text ends up on the same line due to bounds not incrementing correctly). This may apply to SFML as well, though I haven't checked.

A semi hacky solution (tested to solve the multi line problem, but not much beyond that) is the following MeasureText function (the last 4 lines in the else statement being the brunt of the fix):


Gwen::Point Gwen::Renderer::SFML2::MeasureText( Gwen::Font* pFont, const Gwen::UnicodeString& text )
{
    // If the font doesn't exist, or the font size should be changed
    if ( !pFont->data || fabs( pFont->realsize - pFont->size * Scale() ) > 2 )
    {
        FreeFont( pFont );
        LoadFont( pFont );
    }

    const sf::Font* pSFFont = reinterpret_cast( pFont->data );

    sf::FloatRect sz;

    // MULTI LINE FIX: problem was SFML measuring spaces as having no dimensions
    if (text != L" ") {
        sf::Text sfStr;
        sfStr.setString( text );
        sfStr.setFont( *pSFFont );
        sfStr.setScale( Scale(), Scale() );
        sfStr.setCharacterSize( pFont->realsize );
        sz = sfStr.getLocalBounds();
    }
    else {
        sf::Text sfStr;
        sfStr.setString( text );
        sfStr.setFont( *pSFFont );
        sfStr.setScale( Scale(), Scale() );
        sfStr.setCharacterSize( pFont->realsize );
        sz = sfStr.getLocalBounds();

        // SFML gives 0 dimensions for a space, use advance and line spacing instead
        sz.left = 0.0f;
        sz.top = 0.0f;
        sz.width = pSFFont->getGlyph(L' ', pFont->realsize, false).advance;
        sz.height = pSFFont->getLineSpacing(pFont->realsize);
    }

    return Gwen::Point( sz.left + sz.width, sz.top + sz.height );
}
Wizzard033 commented 11 years ago

The fix seems to work for LabelMultiline but makes TextBox crash.

Wizzard033 commented 11 years ago

Here's the fix on the fix:

Gwen::Point Gwen::Renderer::SFML2::MeasureText( Gwen::Font* pFont, const Gwen::UnicodeString& text )
{
    // If the font doesn't exist, or the font size should be changed
    if ( !pFont->data || fabs( pFont->realsize - pFont->size * Scale() ) > 2 )
    {
        FreeFont( pFont );
        LoadFont( pFont );
    }

    const sf::Font* pSFFont = reinterpret_cast<sf::Font*>( pFont->data );

    sf::FloatRect sz;

    if (pSFFont) {
        if ( text != L" " ) {
            sf::Text sfStr;
            sfStr.setString( text );
            sfStr.setFont( *pSFFont );
            sfStr.setScale( Scale(), Scale() );
            sfStr.setCharacterSize( pFont->realsize );
            sz = sfStr.getLocalBounds();
        }

        // SFML gives 0 dimensions for a space, use line spacing instead
        sz.height = pSFFont->getLineSpacing( pFont->realsize );
    }

    return Gwen::Point( sz.left + sz.width, sz.top + sz.height );
}
Wizzard033 commented 11 years ago

The text in text entries was moving up/down depending on what character was typed and not handling trailing and preceding spaces properly. Final fix?

Gwen::Point Gwen::Renderer::SFML2::MeasureText( Gwen::Font* pFont, const Gwen::UnicodeString& text )
{
    // If the font doesn't exist, or the font size should be changed
    if ( !pFont->data || fabs( pFont->realsize - pFont->size * Scale() ) > 2 )
    {
        FreeFont( pFont );
        LoadFont( pFont );
    }

    const sf::Font* pSFFont = reinterpret_cast<sf::Font*>( pFont->data );

    Gwen::Point sz;

    if ( pSFFont ) {
        for ( Gwen::UnicodeString::const_iterator it = text.begin(); it != text.end(); ++it ) {
            sz.x += pSFFont->getGlyph( *it, pFont->realsize, false ).advance * Scale();
        }
        sz.y = pSFFont->getLineSpacing( pFont->realsize ) * Scale();
    }

    return sz;
}

(I ninja-edited a multiplication by Scale())