/* ************************************************************************** description -------------------- copyright : (C) 2002 by Andreas Zehender email : zehender@kde.org ************************************************************************** ************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * **************************************************************************/ #include "pmtext.h" #include "pmxmlhelper.h" #include "pmtextedit.h" #include "pmmemento.h" #include "pmviewstructure.h" #include "pmresourcelocator.h" #include "pmtruetypecache.h" #include "pmdefaults.h" #include <tdelocale.h> const TQString c_defaultFont = TQString( "" ); const TQString c_defaultText = TQString( "" ); const double c_defaultThickness = 1.0; const PMVector c_defaultOffset = PMVector( 0.0, 0.0 ); int PMText::s_parameterKey = 0; int PMText::s_steps = c_defaultTextSteps; PMDefinePropertyClass( PMText, PMTextProperty ); PMMetaObject* PMText::s_pMetaObject = 0; PMObject* createNewText( PMPart* part ) { return new PMText( part ); } PMText::PMText( PMPart* part ) : Base( part ) { m_text = c_defaultText; m_font = c_defaultFont; m_thickness = c_defaultThickness; m_offset = c_defaultOffset; } PMText::PMText( const PMText& t ) : Base( t ) { m_text = t.m_text; m_font = t.m_font; m_thickness = t.m_thickness; m_offset = t.m_offset; } PMText::~PMText( ) { } TQString PMText::description( ) const { return i18n( "text" ); } void PMText::serialize( TQDomElement& e, TQDomDocument& doc ) const { e.setAttribute( "font", m_font ); e.setAttribute( "text", m_text ); e.setAttribute( "thickness", m_thickness ); e.setAttribute( "offset", m_offset.serializeXML( ) ); Base::serialize( e, doc ); } void PMText::readAttributes( const PMXMLHelper& h ) { m_font = h.stringAttribute( "font", c_defaultFont ); m_text = h.stringAttribute( "text", c_defaultText ); m_thickness = h.doubleAttribute( "thickness", c_defaultThickness ); m_offset = h.vectorAttribute( "offset", c_defaultOffset ); Base::readAttributes( h ); } PMMetaObject* PMText::metaObject( ) const { if( !s_pMetaObject ) { s_pMetaObject = new PMMetaObject( "Text", Base::metaObject( ), createNewText ); s_pMetaObject->addProperty( new PMTextProperty( "font", &PMText::setFont, &PMText::font ) ); s_pMetaObject->addProperty( new PMTextProperty( "text", &PMText::setText, &PMText::text ) ); s_pMetaObject->addProperty( new PMTextProperty( "thickness", &PMText::setThickness, &PMText::thickness ) ); s_pMetaObject->addProperty( new PMTextProperty( "offset", &PMText::setOffset, &PMText::offset ) ); } return s_pMetaObject; } void PMText::cleanUp( ) const { if( s_pMetaObject ) { delete s_pMetaObject; s_pMetaObject = 0; } Base::cleanUp( ); } void PMText::setFont( const TQString& f ) { if( f != m_font ) { if( m_pMemento ) m_pMemento->addData( s_pMetaObject, PMFontID, m_font ); m_font = f; setViewStructureChanged( ); } } void PMText::setText( const TQString& t ) { if( t != m_text ) { if( m_pMemento ) m_pMemento->addData( s_pMetaObject, PMTextID, m_text ); m_text = t; setViewStructureChanged( ); } } void PMText::setThickness( double t ) { if( t != m_thickness ) { if( m_pMemento ) m_pMemento->addData( s_pMetaObject, PMThicknessID, m_thickness ); m_thickness = t; setViewStructureChanged( ); } } void PMText::setOffset( const PMVector& o ) { if( o != m_offset ) { if( m_pMemento ) m_pMemento->addData( s_pMetaObject, PMOffsetID, m_offset ); m_offset = o; m_offset.resize( 2 ); setViewStructureChanged( ); } } PMDialogEditBase* PMText::editWidget( TQWidget* parent ) const { return new PMTextEdit( parent ); } void PMText::restoreMemento( PMMemento* s ) { PMMementoDataIterator it( s ); PMMementoData* data; for( ; it.current( ); ++it ) { data = it.current( ); if( data->objectType( ) == s_pMetaObject ) { switch( data->valueID( ) ) { case PMFontID: setFont( data->stringData( ) ); break; case PMTextID: setText( data->stringData( ) ); break; case PMThicknessID: setThickness( data->doubleData( ) ); break; case PMOffsetID: setOffset( data->vectorData( ) ); break; default: kdError( PMArea ) << "Wrong ID in PMText::restoreMemento\n"; break; } } } Base::restoreMemento( s ); } void PMText::createViewStructure( ) { // calculate needed points and lines int nlines = 0, npoints = 0; TQString file = PMResourceLocator::findFile( m_font ); PMTrueTypeFont* font = PMTrueTypeCache::font( file ); if( font && font->isValid( ) ) { TQTextStream str( &m_text, IO_ReadOnly ); TQChar c; PMTrueTypeOutline* ol; while( !str.atEnd( ) ) { str >> c; ol = font->outline( c ); if( ol ) { npoints += ol->segments( ) * 2 * s_steps; nlines += ol->segments( ) * ( 2 * s_steps + 1 ); } } } if( !m_pViewStructure ) m_pViewStructure = new PMViewStructure( npoints, nlines ); else { if( m_pViewStructure->points( ).size( ) != ( unsigned ) npoints ) m_pViewStructure->points( ).resize( npoints ); if( m_pViewStructure->lines( ).size( ) != ( unsigned ) nlines ) m_pViewStructure->lines( ).resize( nlines ); } if( ( nlines > 0 ) && ( npoints > 0 ) && font ) { // create the view structure TQTextStream str( &m_text, IO_ReadOnly ); TQChar c, oldc; PMTrueTypeOutline* ol; double dp = 1.0 / s_steps; int i; int hnpoints = npoints / 2; int pbase = 0; int lbase = 0; PMVector v2( 2 ); PMVector v3( 3 ); int firstPoint = 0; PMVector coffset( 0.0, 0.0, 0.0 ); double kerning = 0; PMPointArray& points = m_pViewStructure->points( ); PMLineArray& lines = m_pViewStructure->lines( ); while( !str.atEnd( ) ) { // iterate over all characters with valid outline str >> c; ol = font->outline( c ); if( ol ) { // kerning offset kerning = font->kerning( oldc, c ); coffset[0] += kerning; const PMSegmentListList& out = ol->outline( ); PMSegmentListList::ConstIterator oit; for( oit = out.begin( ); oit != out.end( ); ++oit ) { // iterate over all contours PMSegmentList::ConstIterator sit; PMSegmentList::ConstIterator eit = ( *oit ).end( ); eit--; firstPoint = pbase; for( sit = ( *oit ).begin( ); sit != ( *oit ).end( ); ++sit ) { // iterate over all segments for the current contour lines[lbase] = PMLine( pbase, pbase + hnpoints ); lbase++; for( i = 0; i < s_steps; i++ ) { v2 = ( *sit ).point( i * dp ); v3[0] = v2[0]; v3[1] = v2[1]; v3[2] = 0.0; v3 += coffset; points[pbase] = PMPoint( v3 ); v3[2] = m_thickness; points[pbase + hnpoints] = PMPoint( v3 ); if( ( i != ( s_steps - 1 ) ) || ( sit != eit ) ) { lines[lbase] = PMLine( pbase, pbase + 1 ); lbase++; lines[lbase] = PMLine( pbase + hnpoints, pbase + hnpoints + 1 ); lbase++; } else { lines[lbase] = PMLine( firstPoint, pbase ); lbase++; lines[lbase] = PMLine( firstPoint + hnpoints, pbase + hnpoints ); lbase++; } pbase++; } } } coffset[0] -= kerning; coffset[0] += ol->advance( ); coffset += m_offset; } oldc = c; } if( ( lbase != nlines ) || ( pbase != hnpoints ) ) kdError( PMArea ) << "PMText::createViewStructure is buggy!\n"; } } void PMText::setSteps( int s ) { if( s >= 1 ) s_steps = s; else kdDebug( PMArea ) << "PMText::setSteps: S must be greater than 0\n"; s_parameterKey++; }