You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
340 lines
9.3 KiB
340 lines
9.3 KiB
/*
|
|
**************************************************************************
|
|
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 <klocale.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++;
|
|
}
|