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.
568 lines
18 KiB
568 lines
18 KiB
/* This file is part of the KDE project
|
|
Copyright (C) 2001 Andrea Rizzi <rizzi@kde.org>
|
|
Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include <tqfontmetrics.h>
|
|
#include <tqpainter.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include "basicelement.h"
|
|
#include "contextstyle.h"
|
|
#include "elementtype.h"
|
|
#include "elementvisitor.h"
|
|
#include "fontstyle.h"
|
|
#include "formulaelement.h"
|
|
#include "kformulacommand.h"
|
|
#include "sequenceelement.h"
|
|
#include "symboltable.h"
|
|
#include "textelement.h"
|
|
|
|
|
|
KFORMULA_NAMESPACE_BEGIN
|
|
|
|
TextElement::TextElement(TQChar ch, bool beSymbol, BasicElement* parent)
|
|
: BasicElement(parent), character(ch), symbol(beSymbol)
|
|
{
|
|
charStyle( anyChar );
|
|
charFamily( anyFamily );
|
|
}
|
|
|
|
|
|
TextElement::TextElement( const TextElement& other )
|
|
: BasicElement( other ),
|
|
character( other.character ),
|
|
symbol( other.symbol ),
|
|
m_format( other.m_format )
|
|
{
|
|
}
|
|
|
|
|
|
bool TextElement::accept( ElementVisitor* visitor )
|
|
{
|
|
return visitor->visit( this );
|
|
}
|
|
|
|
|
|
TokenType TextElement::getTokenType() const
|
|
{
|
|
if ( isSymbol() ) {
|
|
return getSymbolTable().charClass( character );
|
|
}
|
|
|
|
switch ( character.unicode() ) {
|
|
case '+':
|
|
case '-':
|
|
case '*':
|
|
//case '/': because it counts as text -- no extra spaces
|
|
return BINOP;
|
|
case '=':
|
|
case '<':
|
|
case '>':
|
|
return RELATION;
|
|
case ',':
|
|
case ';':
|
|
case ':':
|
|
return PUNCTUATION;
|
|
case '\\':
|
|
return SEPARATOR;
|
|
case '\0':
|
|
return ELEMENT;
|
|
default:
|
|
if ( character.isNumber() ) {
|
|
return NUMBER;
|
|
}
|
|
else {
|
|
return ORDINARY;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool TextElement::isInvisible() const
|
|
{
|
|
if (getElementType() != 0) {
|
|
return getElementType()->isInvisible(*this);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Calculates our width and height and
|
|
* our children's parentPosition.
|
|
*/
|
|
void TextElement::calcSizes( const ContextStyle& context,
|
|
ContextStyle::TextStyle tstyle,
|
|
ContextStyle::IndexStyle /*istyle*/,
|
|
StyleAttributes& style )
|
|
{
|
|
double factor = style.sizeFactor();
|
|
luPt mySize = context.getAdjustedSize( tstyle, factor );
|
|
|
|
setCharStyle( style.charStyle() );
|
|
setCharFamily( style.charFamily() );
|
|
|
|
TQFont font = getFont( context, style );
|
|
double fontsize = context.layoutUnitPtToPt( mySize );
|
|
double scriptsize = pow( style.scriptSizeMultiplier(), style.scriptLevel() );
|
|
double size = fontsize * scriptsize;
|
|
font.setPointSizeFloat( size < style.scriptMinSize() ? style.scriptMinSize() : size );
|
|
|
|
TQFontMetrics fm( font );
|
|
if ( character == applyFunctionChar || character == invisibleTimes || character == invisibleComma ) {
|
|
setWidth( 0 );
|
|
setHeight( 0 );
|
|
setBaseline( getHeight() );
|
|
}
|
|
else {
|
|
TQChar ch = getRealCharacter(context);
|
|
if ( ch == TQChar::null ) {
|
|
setWidth( tqRound( context.getEmptyRectWidth( factor ) * 2./3. ) );
|
|
setHeight( tqRound( context.getEmptyRectHeight( factor ) * 2./3. ) );
|
|
setBaseline( getHeight() );
|
|
}
|
|
else {
|
|
TQRect bound = fm.boundingRect( ch );
|
|
setWidth( context.ptToLayoutUnitPt( fm.width( ch ) ) );
|
|
setHeight( context.ptToLayoutUnitPt( bound.height() ) );
|
|
setBaseline( context.ptToLayoutUnitPt( -bound.top() ) );
|
|
|
|
// There are some glyphs in TeX that have
|
|
// baseline==0. (\int, \sum, \prod)
|
|
if ( getBaseline() == 0 ) {
|
|
//setBaseline( getHeight()/2 + context.axisHeight( tstyle ) );
|
|
setBaseline( -1 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Draws the whole element including its children.
|
|
* The `parentOrigin' is the point this element's parent starts.
|
|
* We can use our parentPosition to get our own origin then.
|
|
*/
|
|
void TextElement::draw( TQPainter& painter, const LuPixelRect& /*r*/,
|
|
const ContextStyle& context,
|
|
ContextStyle::TextStyle tstyle,
|
|
ContextStyle::IndexStyle /*istyle*/,
|
|
StyleAttributes& style,
|
|
const LuPixelPoint& parentOrigin )
|
|
{
|
|
if ( character == applyFunctionChar || character == invisibleTimes || character == invisibleComma ) {
|
|
return;
|
|
}
|
|
|
|
LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
|
|
//if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
|
|
// return;
|
|
|
|
// Let container set the color, instead of elementType
|
|
//setUpPainter( context, painter );
|
|
painter.setPen( style.color() );
|
|
|
|
setCharStyle( style.charStyle() );
|
|
setCharFamily( style.charFamily() );
|
|
|
|
double factor = style.sizeFactor();
|
|
luPt mySize = context.getAdjustedSize( tstyle, factor );
|
|
TQFont font = getFont( context, style );
|
|
double fontsize = context.layoutUnitPtToPt( mySize );
|
|
double scriptsize = pow( style.scriptSizeMultiplier(), style.scriptLevel() );
|
|
double size = fontsize * scriptsize;
|
|
font.setPointSizeFloat( size < style.scriptMinSize() ? style.scriptMinSize() : size );
|
|
painter.setFont( font );
|
|
|
|
//kdDebug( DEBUGID ) << "TextElement::draw font=" << font.rawName() << endl;
|
|
//kdDebug( DEBUGID ) << "TextElement::draw size=" << mySize << endl;
|
|
//kdDebug( DEBUGID ) << "TextElement::draw size=" << context.layoutUnitToFontSize( mySize, false ) << endl;
|
|
//kdDebug( DEBUGID ) << "TextElement::draw height: " << getHeight() << endl;
|
|
//kdDebug( DEBUGID ) << "TextElement::draw width: " << getWidth() << endl;
|
|
//kdDebug( DEBUGID ) << endl;
|
|
|
|
// Each starting element draws the whole token
|
|
/*
|
|
ElementType* token = getElementType();
|
|
if ( ( token != 0 ) && !symbol ) {
|
|
TQString text = token->text( static_cast<SequenceElement*>( getParent() ) );
|
|
// kdDebug() << "draw text: " << text[0].unicode()
|
|
// << " " << painter.font().family().latin1()
|
|
// << endl;
|
|
painter.fillRect( context.layoutUnitToPixelX( parentOrigin.x() ),
|
|
context.layoutUnitToPixelY( parentOrigin.y() ),
|
|
context.layoutUnitToPixelX( getParent()->getWidth() ),
|
|
context.layoutUnitToPixelY( getParent()->getHeight() ),
|
|
style.background() );
|
|
painter.drawText( context.layoutUnitToPixelX( myPos.x() ),
|
|
context.layoutUnitToPixelY( myPos.y()+getBaseline() ),
|
|
text );
|
|
}
|
|
else {
|
|
*/
|
|
TQChar ch = getRealCharacter(context);
|
|
if ( ch != TQChar::null ) {
|
|
luPixel bl = getBaseline();
|
|
if ( bl == -1 ) {
|
|
// That's quite hacky and actually not the way it's
|
|
// meant to be. You shouldn't calculate a lot in
|
|
// draw. But I don't see how else to deal with
|
|
// baseline==0 glyphs without yet another flag.
|
|
bl = -( getHeight()/2 + context.axisHeight( tstyle, factor ) );
|
|
}
|
|
painter.drawText( context.layoutUnitToPixelX( myPos.x() ),
|
|
context.layoutUnitToPixelY( myPos.y()+bl ),
|
|
TQString(ch) );
|
|
}
|
|
else {
|
|
painter.setPen( TQPen( context.getErrorColor(),
|
|
context.layoutUnitToPixelX( context.getLineWidth( factor ) ) ) );
|
|
painter.drawRect( context.layoutUnitToPixelX( myPos.x() ),
|
|
context.layoutUnitToPixelY( myPos.y() ),
|
|
context.layoutUnitToPixelX( getWidth() ),
|
|
context.layoutUnitToPixelY( getHeight() ) );
|
|
}
|
|
// }
|
|
|
|
// Debug
|
|
//painter.setBrush(TQt::NoBrush);
|
|
// if ( isSymbol() ) {
|
|
// painter.setPen( TQt::red );
|
|
// painter.drawRect( context.layoutUnitToPixelX( myPos.x() ),
|
|
// context.layoutUnitToPixelX( myPos.y() ),
|
|
// context.layoutUnitToPixelX( getWidth() ),
|
|
// context.layoutUnitToPixelX( getHeight() ) );
|
|
// painter.setPen(TQt::green);
|
|
// painter.drawLine(myPos.x(), myPos.y()+axis( context, tstyle ),
|
|
// myPos.x()+getWidth(), myPos.y()+axis( context, tstyle ));
|
|
// }
|
|
}
|
|
|
|
|
|
void TextElement::dispatchFontCommand( FontCommand* cmd )
|
|
{
|
|
cmd->addTextElement( this );
|
|
}
|
|
|
|
void TextElement::setCharStyle( CharStyle cs )
|
|
{
|
|
charStyle( cs );
|
|
formula()->changed();
|
|
}
|
|
|
|
void TextElement::setCharFamily( CharFamily cf )
|
|
{
|
|
charFamily( cf );
|
|
formula()->changed();
|
|
}
|
|
|
|
TQChar TextElement::getRealCharacter(const ContextStyle& context)
|
|
{
|
|
return character;
|
|
/*
|
|
if ( !isSymbol() ) {
|
|
const FontStyle& fontStyle = context.fontStyle();
|
|
const AlphaTable* alphaTable = fontStyle.alphaTable();
|
|
if ( alphaTable != 0 ) {
|
|
AlphaTableEntry ate = alphaTable->entry( character,
|
|
charFamily(),
|
|
charStyle() );
|
|
if ( ate.valid() ) {
|
|
return ate.pos;
|
|
}
|
|
}
|
|
return character;
|
|
}
|
|
else {
|
|
return getSymbolTable().character(character, charStyle());
|
|
}
|
|
*/
|
|
}
|
|
|
|
|
|
TQFont TextElement::getFont(const ContextStyle& context, const StyleAttributes& style)
|
|
{
|
|
const FontStyle& fontStyle = context.fontStyle();
|
|
TQFont font;
|
|
if ( style.customFont() ) {
|
|
font = style.font();
|
|
}
|
|
else if (getElementType() != 0) {
|
|
font = getElementType()->getFont(context);
|
|
}
|
|
else {
|
|
font = context.getDefaultFont();
|
|
}
|
|
switch ( charStyle() ) {
|
|
case anyChar:
|
|
font.setItalic( false );
|
|
font.setBold( false );
|
|
break;
|
|
case normalChar:
|
|
font.setItalic( false );
|
|
font.setBold( false );
|
|
break;
|
|
case boldChar:
|
|
font.setItalic( false );
|
|
font.setBold( true );
|
|
break;
|
|
case italicChar:
|
|
font.setItalic( true );
|
|
font.setBold( false );
|
|
break;
|
|
case boldItalicChar:
|
|
font.setItalic( true );
|
|
font.setBold( true );
|
|
break;
|
|
}
|
|
return fontStyle.symbolTable()->font( character, font );
|
|
}
|
|
|
|
|
|
void TextElement::setUpPainter(const ContextStyle& context, TQPainter& painter)
|
|
{
|
|
if (getElementType() != 0) {
|
|
getElementType()->setUpPainter(context, painter);
|
|
}
|
|
else {
|
|
painter.setPen(TQt::red);
|
|
}
|
|
}
|
|
|
|
const SymbolTable& TextElement::getSymbolTable() const
|
|
{
|
|
return formula()->getSymbolTable();
|
|
}
|
|
|
|
|
|
void TextElement::writeMathML( TQDomDocument& doc, TQDomNode& parent, bool ) const
|
|
{
|
|
parent.appendChild( doc.createTextNode( getCharacter() ) );
|
|
}
|
|
|
|
/**
|
|
* Appends our attributes to the dom element.
|
|
*/
|
|
void TextElement::writeDom(TQDomElement element)
|
|
{
|
|
BasicElement::writeDom(element);
|
|
element.setAttribute("CHAR", TQString(character));
|
|
//TQString s;
|
|
//element.setAttribute("CHAR", s.sprintf( "#x%05X", character ) );
|
|
if (symbol) element.setAttribute("SYMBOL", "3");
|
|
|
|
switch ( charStyle() ) {
|
|
case anyChar: break;
|
|
case normalChar: element.setAttribute("STYLE", "normal"); break;
|
|
case boldChar: element.setAttribute("STYLE", "bold"); break;
|
|
case italicChar: element.setAttribute("STYLE", "italic"); break;
|
|
case boldItalicChar: element.setAttribute("STYLE", "bolditalic"); break;
|
|
}
|
|
|
|
switch ( charFamily() ) {
|
|
case normalFamily: element.setAttribute("FAMILY", "normal"); break;
|
|
case scriptFamily: element.setAttribute("FAMILY", "script"); break;
|
|
case frakturFamily: element.setAttribute("FAMILY", "fraktur"); break;
|
|
case doubleStruckFamily: element.setAttribute("FAMILY", "doublestruck"); break;
|
|
case anyFamily: break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reads our attributes from the element.
|
|
* Returns false if it failed.
|
|
*/
|
|
bool TextElement::readAttributesFromDom(TQDomElement element)
|
|
{
|
|
if (!BasicElement::readAttributesFromDom(element)) {
|
|
return false;
|
|
}
|
|
TQString charStr = element.attribute("CHAR");
|
|
if(!charStr.isNull()) {
|
|
character = charStr.at(0);
|
|
}
|
|
TQString symbolStr = element.attribute("SYMBOL");
|
|
if(!symbolStr.isNull()) {
|
|
int symbolInt = symbolStr.toInt();
|
|
if ( symbolInt == 1 ) {
|
|
character = getSymbolTable().unicodeFromSymbolFont(character);
|
|
}
|
|
if ( symbolInt == 2 ) {
|
|
switch ( character.unicode() ) {
|
|
case 0x03D5: character = 0x03C6; break;
|
|
case 0x03C6: character = 0x03D5; break;
|
|
case 0x03Ba: character = 0x03BA; break;
|
|
case 0x00B4: character = 0x2032; break;
|
|
case 0x2215: character = 0x2244; break;
|
|
case 0x00B7: character = 0x2022; break;
|
|
case 0x1D574: character = 0x2111; break;
|
|
case 0x1D579: character = 0x211C; break;
|
|
case 0x2219: character = 0x22C5; break;
|
|
case 0x2662: character = 0x26C4; break;
|
|
case 0x220B: character = 0x220D; break;
|
|
case 0x224C: character = 0x2245; break;
|
|
case 0x03DB: character = 0x03C2; break;
|
|
}
|
|
}
|
|
symbol = symbolInt != 0;
|
|
}
|
|
|
|
TQString styleStr = element.attribute("STYLE");
|
|
if ( styleStr == "normal" ) {
|
|
charStyle( normalChar );
|
|
}
|
|
else if ( styleStr == "bold" ) {
|
|
charStyle( boldChar );
|
|
}
|
|
else if ( styleStr == "italic" ) {
|
|
charStyle( italicChar );
|
|
}
|
|
else if ( styleStr == "bolditalic" ) {
|
|
charStyle( boldItalicChar );
|
|
}
|
|
else {
|
|
charStyle( anyChar );
|
|
}
|
|
|
|
TQString familyStr = element.attribute( "FAMILY" );
|
|
if ( familyStr == "normal" ) {
|
|
charFamily( normalFamily );
|
|
}
|
|
else if ( familyStr == "script" ) {
|
|
charFamily( scriptFamily );
|
|
}
|
|
else if ( familyStr == "fraktur" ) {
|
|
charFamily( frakturFamily );
|
|
}
|
|
else if ( familyStr == "doublestruck" ) {
|
|
charFamily( doubleStruckFamily );
|
|
}
|
|
else {
|
|
charFamily( anyFamily );
|
|
}
|
|
|
|
// kdDebug() << "charStyle=" << charStyle()
|
|
// << " charFamily=" << charFamily()
|
|
// << " format=" << int( format() ) << endl;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Reads our content from the node. Sets the node to the next node
|
|
* that needs to be read.
|
|
* Returns false if it failed.
|
|
*/
|
|
bool TextElement::readContentFromDom(TQDomNode& node)
|
|
{
|
|
return BasicElement::readContentFromDom(node);
|
|
}
|
|
|
|
TQString TextElement::toLatex()
|
|
{
|
|
if ( isSymbol() ) {
|
|
TQString texName = getSymbolTable().name( character );
|
|
if ( !texName.isNull() )
|
|
return " \\" + texName + " ";
|
|
return " ? ";
|
|
}
|
|
else {
|
|
return TQString(character);
|
|
}
|
|
}
|
|
|
|
TQString TextElement::formulaString()
|
|
{
|
|
if ( isSymbol() ) {
|
|
TQString texName = getSymbolTable().name( character );
|
|
if ( !texName.isNull() )
|
|
return " " + texName + " ";
|
|
return " ? ";
|
|
}
|
|
else {
|
|
return character;
|
|
}
|
|
}
|
|
|
|
|
|
EmptyElement::EmptyElement( BasicElement* parent )
|
|
: BasicElement( parent )
|
|
{
|
|
}
|
|
|
|
EmptyElement::EmptyElement( const EmptyElement& other )
|
|
: BasicElement( other )
|
|
{
|
|
}
|
|
|
|
|
|
bool EmptyElement::accept( ElementVisitor* visitor )
|
|
{
|
|
return visitor->visit( this );
|
|
}
|
|
|
|
|
|
void EmptyElement::calcSizes( const ContextStyle& context,
|
|
ContextStyle::TextStyle tstyle,
|
|
ContextStyle::IndexStyle /*istyle*/,
|
|
StyleAttributes& style )
|
|
{
|
|
luPt mySize = context.getAdjustedSize( tstyle, style.sizeFactor() );
|
|
//kdDebug( DEBUGID ) << "TextElement::calcSizes size=" << mySize << endl;
|
|
|
|
TQFont font = context.getDefaultFont();
|
|
font.setPointSizeFloat( context.layoutUnitPtToPt( mySize ) );
|
|
|
|
TQFontMetrics fm( font );
|
|
TQChar ch = 'A';
|
|
TQRect bound = fm.boundingRect( ch );
|
|
setWidth( 0 );
|
|
setHeight( context.ptToLayoutUnitPt( bound.height() ) );
|
|
setBaseline( context.ptToLayoutUnitPt( -bound.top() ) );
|
|
}
|
|
|
|
void EmptyElement::draw( TQPainter& painter, const LuPixelRect& /*r*/,
|
|
const ContextStyle& context,
|
|
ContextStyle::TextStyle /*tstyle*/,
|
|
ContextStyle::IndexStyle /*istyle*/,
|
|
StyleAttributes& /*style*/ ,
|
|
const LuPixelPoint& parentOrigin )
|
|
{
|
|
LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
|
|
/*
|
|
if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
|
|
return;
|
|
*/
|
|
|
|
if ( context.edit() ) {
|
|
painter.setPen( context.getHelpColor() );
|
|
painter.drawLine( context.layoutUnitToPixelX( myPos.x() ),
|
|
context.layoutUnitToPixelY( myPos.y() ),
|
|
context.layoutUnitToPixelX( myPos.x() ),
|
|
context.layoutUnitToPixelY( myPos.y()+getHeight() ) );
|
|
}
|
|
}
|
|
|
|
TQString EmptyElement::toLatex()
|
|
{
|
|
return "{}";
|
|
}
|
|
|
|
KFORMULA_NAMESPACE_END
|