diff options
Diffstat (limited to 'lib/kformula/textelement.cpp')
-rw-r--r-- | lib/kformula/textelement.cpp | 567 |
1 files changed, 567 insertions, 0 deletions
diff --git a/lib/kformula/textelement.cpp b/lib/kformula/textelement.cpp new file mode 100644 index 00000000..7f146b49 --- /dev/null +++ b/lib/kformula/textelement.cpp @@ -0,0 +1,567 @@ +/* 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 |