/* This file is part of the KDE project Copyright (C) 2001 Andrea Rizzi Ulrich Kuettler 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 #include #include #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( 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