lib

textelement.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2001 Andrea Rizzi <rizzi@kde.org>
3 Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19*/
20
21#include <tqfontmetrics.h>
22#include <tqpainter.h>
23
24#include <kdebug.h>
25
26#include "basicelement.h"
27#include "contextstyle.h"
28#include "elementtype.h"
29#include "elementvisitor.h"
30#include "fontstyle.h"
31#include "formulaelement.h"
32#include "kformulacommand.h"
33#include "sequenceelement.h"
34#include "symboltable.h"
35#include "textelement.h"
36
37
38KFORMULA_NAMESPACE_BEGIN
39
40TextElement::TextElement(TQChar ch, bool beSymbol, BasicElement* parent)
41 : BasicElement(parent), character(ch), symbol(beSymbol)
42{
43 charStyle( anyChar );
44 charFamily( anyFamily );
45}
46
47
48TextElement::TextElement( const TextElement& other )
49 : BasicElement( other ),
50 character( other.character ),
51 symbol( other.symbol ),
52 m_format( other.m_format )
53{
54}
55
56
58{
59 return visitor->visit( this );
60}
61
62
64{
65 if ( isSymbol() ) {
66 return getSymbolTable().charClass( character );
67 }
68
69 switch ( character.unicode() ) {
70 case '+':
71 case '-':
72 case '*':
73 //case '/': because it counts as text -- no extra spaces
74 return BINOP;
75 case '=':
76 case '<':
77 case '>':
78 return RELATION;
79 case ',':
80 case ';':
81 case ':':
82 return PUNCTUATION;
83 case '\\':
84 return SEPARATOR;
85 case '\0':
86 return ELEMENT;
87 default:
88 if ( character.isNumber() ) {
89 return NUMBER;
90 }
91 else {
92 return ORDINARY;
93 }
94 }
95}
96
97
99{
100 if (getElementType() != 0) {
101 return getElementType()->isInvisible(*this);
102 }
103 return false;
104}
105
106
113 ContextStyle::IndexStyle /*istyle*/,
114 StyleAttributes& style )
115{
116 double factor = style.sizeFactor();
117 luPt mySize = context.getAdjustedSize( tstyle, factor );
118
119 setCharStyle( style.charStyle() );
120 setCharFamily( style.charFamily() );
121
122 TQFont font = getFont( context, style );
123 double fontsize = context.layoutUnitPtToPt( mySize );
124 double scriptsize = pow( style.scriptSizeMultiplier(), style.scriptLevel() );
125 double size = fontsize * scriptsize;
126 font.setPointSizeFloat( size < style.scriptMinSize() ? style.scriptMinSize() : size );
127
128 TQFontMetrics fm( font );
129 if ( character == applyFunctionChar || character == invisibleTimes || character == invisibleComma ) {
130 setWidth( 0 );
131 setHeight( 0 );
132 setBaseline( getHeight() );
133 }
134 else {
135 TQChar ch = getRealCharacter(context);
136 if ( ch == TQChar::null ) {
137 setWidth( tqRound( context.getEmptyRectWidth( factor ) * 2./3. ) );
138 setHeight( tqRound( context.getEmptyRectHeight( factor ) * 2./3. ) );
139 setBaseline( getHeight() );
140 }
141 else {
142 TQRect bound = fm.boundingRect( ch );
143 setWidth( context.ptToLayoutUnitPt( fm.width( ch ) ) );
144 setHeight( context.ptToLayoutUnitPt( bound.height() ) );
145 setBaseline( context.ptToLayoutUnitPt( -bound.top() ) );
146
147 // There are some glyphs in TeX that have
148 // baseline==0. (\int, \sum, \prod)
149 if ( getBaseline() == 0 ) {
150 //setBaseline( getHeight()/2 + context.axisHeight( tstyle ) );
151 setBaseline( -1 );
152 }
153 }
154 }
155}
156
162void TextElement::draw( TQPainter& painter, const LuPixelRect& /*r*/,
163 const ContextStyle& context,
165 ContextStyle::IndexStyle /*istyle*/,
166 StyleAttributes& style,
167 const LuPixelPoint& parentOrigin )
168{
169 if ( character == applyFunctionChar || character == invisibleTimes || character == invisibleComma ) {
170 return;
171 }
172
173 LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
174 //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
175 // return;
176
177 // Let container set the color, instead of elementType
178 //setUpPainter( context, painter );
179 painter.setPen( style.color() );
180
181 setCharStyle( style.charStyle() );
182 setCharFamily( style.charFamily() );
183
184 double factor = style.sizeFactor();
185 luPt mySize = context.getAdjustedSize( tstyle, factor );
186 TQFont font = getFont( context, style );
187 double fontsize = context.layoutUnitPtToPt( mySize );
188 double scriptsize = pow( style.scriptSizeMultiplier(), style.scriptLevel() );
189 double size = fontsize * scriptsize;
190 font.setPointSizeFloat( size < style.scriptMinSize() ? style.scriptMinSize() : size );
191 painter.setFont( font );
192
193 //kdDebug( DEBUGID ) << "TextElement::draw font=" << font.rawName() << endl;
194 //kdDebug( DEBUGID ) << "TextElement::draw size=" << mySize << endl;
195 //kdDebug( DEBUGID ) << "TextElement::draw size=" << context.layoutUnitToFontSize( mySize, false ) << endl;
196 //kdDebug( DEBUGID ) << "TextElement::draw height: " << getHeight() << endl;
197 //kdDebug( DEBUGID ) << "TextElement::draw width: " << getWidth() << endl;
198 //kdDebug( DEBUGID ) << endl;
199
200 // Each starting element draws the whole token
201 /*
202 ElementType* token = getElementType();
203 if ( ( token != 0 ) && !symbol ) {
204 TQString text = token->text( static_cast<SequenceElement*>( getParent() ) );
205// kdDebug() << "draw text: " << text[0].unicode()
206// << " " << painter.font().family().latin1()
207// << endl;
208 painter.fillRect( context.layoutUnitToPixelX( parentOrigin.x() ),
209 context.layoutUnitToPixelY( parentOrigin.y() ),
210 context.layoutUnitToPixelX( getParent()->getWidth() ),
211 context.layoutUnitToPixelY( getParent()->getHeight() ),
212 style.background() );
213 painter.drawText( context.layoutUnitToPixelX( myPos.x() ),
214 context.layoutUnitToPixelY( myPos.y()+getBaseline() ),
215 text );
216 }
217 else {
218 */
219 TQChar ch = getRealCharacter(context);
220 if ( ch != TQChar::null ) {
221 luPixel bl = getBaseline();
222 if ( bl == -1 ) {
223 // That's quite hacky and actually not the way it's
224 // meant to be. You shouldn't calculate a lot in
225 // draw. But I don't see how else to deal with
226 // baseline==0 glyphs without yet another flag.
227 bl = -( getHeight()/2 + context.axisHeight( tstyle, factor ) );
228 }
229 painter.drawText( context.layoutUnitToPixelX( myPos.x() ),
230 context.layoutUnitToPixelY( myPos.y()+bl ),
231 TQString(ch) );
232 }
233 else {
234 painter.setPen( TQPen( context.getErrorColor(),
235 context.layoutUnitToPixelX( context.getLineWidth( factor ) ) ) );
236 painter.drawRect( context.layoutUnitToPixelX( myPos.x() ),
237 context.layoutUnitToPixelY( myPos.y() ),
238 context.layoutUnitToPixelX( getWidth() ),
239 context.layoutUnitToPixelY( getHeight() ) );
240 }
241// }
242
243 // Debug
244 //painter.setBrush(TQt::NoBrush);
245// if ( isSymbol() ) {
246// painter.setPen( TQt::red );
247// painter.drawRect( context.layoutUnitToPixelX( myPos.x() ),
248// context.layoutUnitToPixelX( myPos.y() ),
249// context.layoutUnitToPixelX( getWidth() ),
250// context.layoutUnitToPixelX( getHeight() ) );
251// painter.setPen(TQt::green);
252// painter.drawLine(myPos.x(), myPos.y()+axis( context, tstyle ),
253// myPos.x()+getWidth(), myPos.y()+axis( context, tstyle ));
254// }
255}
256
257
259{
260 cmd->addTextElement( this );
261}
262
263void TextElement::setCharStyle( CharStyle cs )
264{
265 charStyle( cs );
266 formula()->changed();
267}
268
269void TextElement::setCharFamily( CharFamily cf )
270{
271 charFamily( cf );
272 formula()->changed();
273}
274
276{
277 return character;
278/*
279 if ( !isSymbol() ) {
280 const FontStyle& fontStyle = context.fontStyle();
281 const AlphaTable* alphaTable = fontStyle.alphaTable();
282 if ( alphaTable != 0 ) {
283 AlphaTableEntry ate = alphaTable->entry( character,
284 charFamily(),
285 charStyle() );
286 if ( ate.valid() ) {
287 return ate.pos;
288 }
289 }
290 return character;
291 }
292 else {
293 return getSymbolTable().character(character, charStyle());
294 }
295*/
296}
297
298
299TQFont TextElement::getFont(const ContextStyle& context, const StyleAttributes& style)
300{
301 const FontStyle& fontStyle = context.fontStyle();
302 TQFont font;
303 if ( style.customFont() ) {
304 font = style.font();
305 }
306 else if (getElementType() != 0) {
307 font = getElementType()->getFont(context);
308 }
309 else {
310 font = context.getDefaultFont();
311 }
312 switch ( charStyle() ) {
313 case anyChar:
314 font.setItalic( false );
315 font.setBold( false );
316 break;
317 case normalChar:
318 font.setItalic( false );
319 font.setBold( false );
320 break;
321 case boldChar:
322 font.setItalic( false );
323 font.setBold( true );
324 break;
325 case italicChar:
326 font.setItalic( true );
327 font.setBold( false );
328 break;
329 case boldItalicChar:
330 font.setItalic( true );
331 font.setBold( true );
332 break;
333 }
334 return fontStyle.symbolTable()->font( character, font );
335}
336
337
338void TextElement::setUpPainter(const ContextStyle& context, TQPainter& painter)
339{
340 if (getElementType() != 0) {
341 getElementType()->setUpPainter(context, painter);
342 }
343 else {
344 painter.setPen(TQt::red);
345 }
346}
347
348const SymbolTable& TextElement::getSymbolTable() const
349{
350 return formula()->getSymbolTable();
351}
352
353
354void TextElement::writeMathML( TQDomDocument& doc, TQDomNode& parent, bool ) const
355{
356 parent.appendChild( doc.createTextNode( getCharacter() ) );
357}
358
362void TextElement::writeDom(TQDomElement element)
363{
364 BasicElement::writeDom(element);
365 element.setAttribute("CHAR", TQString(character));
366 //TQString s;
367 //element.setAttribute("CHAR", s.sprintf( "#x%05X", character ) );
368 if (symbol) element.setAttribute("SYMBOL", "3");
369
370 switch ( charStyle() ) {
371 case anyChar: break;
372 case normalChar: element.setAttribute("STYLE", "normal"); break;
373 case boldChar: element.setAttribute("STYLE", "bold"); break;
374 case italicChar: element.setAttribute("STYLE", "italic"); break;
375 case boldItalicChar: element.setAttribute("STYLE", "bolditalic"); break;
376 }
377
378 switch ( charFamily() ) {
379 case normalFamily: element.setAttribute("FAMILY", "normal"); break;
380 case scriptFamily: element.setAttribute("FAMILY", "script"); break;
381 case frakturFamily: element.setAttribute("FAMILY", "fraktur"); break;
382 case doubleStruckFamily: element.setAttribute("FAMILY", "doublestruck"); break;
383 case anyFamily: break;
384 }
385}
386
391bool TextElement::readAttributesFromDom(TQDomElement element)
392{
394 return false;
395 }
396 TQString charStr = element.attribute("CHAR");
397 if(!charStr.isNull()) {
398 character = charStr.at(0);
399 }
400 TQString symbolStr = element.attribute("SYMBOL");
401 if(!symbolStr.isNull()) {
402 int symbolInt = symbolStr.toInt();
403 if ( symbolInt == 1 ) {
404 character = getSymbolTable().unicodeFromSymbolFont(character);
405 }
406 if ( symbolInt == 2 ) {
407 switch ( character.unicode() ) {
408 case 0x03D5: character = 0x03C6; break;
409 case 0x03C6: character = 0x03D5; break;
410 case 0x03Ba: character = 0x03BA; break;
411 case 0x00B4: character = 0x2032; break;
412 case 0x2215: character = 0x2244; break;
413 case 0x00B7: character = 0x2022; break;
414 case 0x1D574: character = 0x2111; break;
415 case 0x1D579: character = 0x211C; break;
416 case 0x2219: character = 0x22C5; break;
417 case 0x2662: character = 0x26C4; break;
418 case 0x220B: character = 0x220D; break;
419 case 0x224C: character = 0x2245; break;
420 case 0x03DB: character = 0x03C2; break;
421 }
422 }
423 symbol = symbolInt != 0;
424 }
425
426 TQString styleStr = element.attribute("STYLE");
427 if ( styleStr == "normal" ) {
428 charStyle( normalChar );
429 }
430 else if ( styleStr == "bold" ) {
431 charStyle( boldChar );
432 }
433 else if ( styleStr == "italic" ) {
434 charStyle( italicChar );
435 }
436 else if ( styleStr == "bolditalic" ) {
437 charStyle( boldItalicChar );
438 }
439 else {
440 charStyle( anyChar );
441 }
442
443 TQString familyStr = element.attribute( "FAMILY" );
444 if ( familyStr == "normal" ) {
445 charFamily( normalFamily );
446 }
447 else if ( familyStr == "script" ) {
448 charFamily( scriptFamily );
449 }
450 else if ( familyStr == "fraktur" ) {
451 charFamily( frakturFamily );
452 }
453 else if ( familyStr == "doublestruck" ) {
454 charFamily( doubleStruckFamily );
455 }
456 else {
457 charFamily( anyFamily );
458 }
459
460// kdDebug() << "charStyle=" << charStyle()
461// << " charFamily=" << charFamily()
462// << " format=" << int( format() ) << endl;
463
464 return true;
465}
466
473{
475}
476
478{
479 if ( isSymbol() ) {
480 TQString texName = getSymbolTable().name( character );
481 if ( !texName.isNull() )
482 return " \\" + texName + " ";
483 return " ? ";
484 }
485 else {
486 return TQString(character);
487 }
488}
489
490TQString TextElement::formulaString()
491{
492 if ( isSymbol() ) {
493 TQString texName = getSymbolTable().name( character );
494 if ( !texName.isNull() )
495 return " " + texName + " ";
496 return " ? ";
497 }
498 else {
499 return character;
500 }
501}
502
503
504EmptyElement::EmptyElement( BasicElement* parent )
505 : BasicElement( parent )
506{
507}
508
509EmptyElement::EmptyElement( const EmptyElement& other )
510 : BasicElement( other )
511{
512}
513
514
516{
517 return visitor->visit( this );
518}
519
520
523 ContextStyle::IndexStyle /*istyle*/,
524 StyleAttributes& style )
525{
526 luPt mySize = context.getAdjustedSize( tstyle, style.sizeFactor() );
527 //kdDebug( DEBUGID ) << "TextElement::calcSizes size=" << mySize << endl;
528
529 TQFont font = context.getDefaultFont();
530 font.setPointSizeFloat( context.layoutUnitPtToPt( mySize ) );
531
532 TQFontMetrics fm( font );
533 TQChar ch = 'A';
534 TQRect bound = fm.boundingRect( ch );
535 setWidth( 0 );
536 setHeight( context.ptToLayoutUnitPt( bound.height() ) );
537 setBaseline( context.ptToLayoutUnitPt( -bound.top() ) );
538}
539
540void EmptyElement::draw( TQPainter& painter, const LuPixelRect& /*r*/,
541 const ContextStyle& context,
542 ContextStyle::TextStyle /*tstyle*/,
543 ContextStyle::IndexStyle /*istyle*/,
544 StyleAttributes& /*style*/ ,
545 const LuPixelPoint& parentOrigin )
546{
547 LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
548 /*
549 if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
550 return;
551 */
552
553 if ( context.edit() ) {
554 painter.setPen( context.getHelpColor() );
555 painter.drawLine( context.layoutUnitToPixelX( myPos.x() ),
556 context.layoutUnitToPixelY( myPos.y() ),
557 context.layoutUnitToPixelX( myPos.x() ),
558 context.layoutUnitToPixelY( myPos.y()+getHeight() ) );
559 }
560}
561
563{
564 return "{}";
565}
566
567KFORMULA_NAMESPACE_END
Basis of every formula element.
virtual FormulaElement * formula()
Provide fast access to the rootElement for each child.
virtual bool readContentFromDom(TQDomNode &node)
Reads our content from the node.
ElementType * getElementType() const
virtual bool readAttributesFromDom(TQDomElement element)
Reads our attributes from the element.
virtual void writeDom(TQDomElement element)
Appends our attributes to the dom element.
Contains all the style information for the formela.
luPt getAdjustedSize(TextStyle tstyle, double factor) const
Calculates the font size corresponding to the given TextStyle.
TextStyle
Textstyles like in TeX.
luPixel getLineWidth(double factor) const
All simple lines like the one that makes up a fraction.
virtual TQFont getFont(const ContextStyle &context)
virtual bool isInvisible(const TextElement &) const
Definition elementtype.h:60
virtual void setUpPainter(const ContextStyle &context, TQPainter &painter)
sets the painters pen to a appropriate value
An element that represents an empty box.
virtual void calcSizes(const ContextStyle &cstyle, ContextStyle::TextStyle tstyle, ContextStyle::IndexStyle istyle, StyleAttributes &style)
Calculates our width and height and our children's parentPosition.
virtual bool accept(ElementVisitor *visitor)
Visit this element.
virtual TQString toLatex()
Draws the whole element including its children.
Base for all font commands that act on the current selection.
void addTextElement(TextElement *element)
Collects all elements that are to be modified.
Base class for all supported font styles.
Definition fontstyle.h:41
const SymbolTable * symbolTable() const
the table for ordinary symbols (those that have a unicode value)
Definition fontstyle.h:52
virtual void changed()
Gets called whenever something changes and we need to recalc.
const SymbolTable & getSymbolTable() const
int layoutUnitToPixelX(int lupix) const
The "layout unit pixel" -> "[zoomed] view pixel" conversions.
The symbol table.
Definition symboltable.h:77
An element that represents one char.
Definition textelement.h:37
virtual void dispatchFontCommand(FontCommand *cmd)
Draws the whole element including its children.
void setUpPainter(const ContextStyle &context, TQPainter &painter)
Sets up the painter to be used for drawing.
virtual bool isInvisible() const
virtual void writeMathML(TQDomDocument &doc, TQDomNode &parent, bool oasisFormat=false) const
Same as above, just MathML.
virtual TQString toLatex()
virtual bool accept(ElementVisitor *visitor)
Visit this element.
virtual TQChar getCharacter() const
Definition textelement.h:65
TQChar getRealCharacter(const ContextStyle &context)
bool isSymbol() const
Moves the cursor away from the given child.
virtual void writeDom(TQDomElement element)
Appends our attributes to the dom element.
virtual TokenType getTokenType() const
virtual void calcSizes(const ContextStyle &cstyle, ContextStyle::TextStyle tstyle, ContextStyle::IndexStyle istyle, StyleAttributes &style)
Calculates our width and height and our children's parentPosition.
virtual bool readAttributesFromDom(TQDomElement element)
Reads our attributes from the element.
virtual bool readContentFromDom(TQDomNode &node)
Reads our content from the node.
TQFont getFont(const ContextStyle &context, const StyleAttributes &style)