spaceelement.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 Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20*/
21
22#include <tqfontmetrics.h>
23#include <tqpainter.h>
24
25#include <kdebug.h>
26#include <kprinter.h>
27
28#include "contextstyle.h"
29#include "elementvisitor.h"
30#include "spaceelement.h"
31
32
33KFORMULA_NAMESPACE_BEGIN
34
35
36SpaceElement::SpaceElement( SpaceWidth space, bool tab, BasicElement* parent )
37 : BasicElement( parent ),
38 m_tab( tab ),
39 m_widthType( NoSize ),
40 m_heightType( NoSize ),
41 m_depthType( NoSize ),
42 m_lineBreak( NoBreakType )
43{
44 // Backwards compatibility with KFO format
45 switch ( space ) {
46 case NEGTHIN:
47 m_widthType = NegativeThinMathSpace;
48 break;
49 case THIN:
50 m_widthType = ThinMathSpace;
51 break;
52 case MEDIUM:
53 m_widthType = MediumMathSpace;
54 break;
55 case THICK:
56 m_widthType = ThickMathSpace;
57 break;
58 case QUAD:
59 m_widthType = VeryVeryThickMathSpace;
60 break;
61 }
62}
63
64
65SpaceElement::SpaceElement( const SpaceElement& other )
66 : BasicElement( other ),
67 m_widthType( other.m_widthType ),
68 m_width( other.m_width ),
69 m_heightType( other.m_heightType ),
70 m_height( other.m_height ),
71 m_depthType( other.m_depthType ),
72 m_depth( other.m_depth ),
73 m_lineBreak( other.m_lineBreak )
74{
75}
76
77
79{
80 return visitor->visit( this );
81}
82
83
86 ContextStyle::IndexStyle /*istyle*/,
87 StyleAttributes& style )
88{
89 double factor = style.sizeFactor();
90 luPt mySize = context.getAdjustedSize( tstyle, factor );
91 TQFont font = context.getDefaultFont();
92 font.setPointSize( mySize );
93
94 TQFontMetrics fm( font );
95 TQChar w = 'M';
96 LuPixelRect hbound = fm.boundingRect( w );
97 TQChar h = 'x';
98 LuPixelRect vbound = fm.boundingRect( h );
99
100 double width = style.getSpace( m_widthType, m_width );
101 if ( m_widthType == AbsoluteSize ) {
102 width = m_width / context.layoutUnitPtToPt( context.getBaseSize() );
103 }
104 else if ( m_widthType == PixelSize ) {
105 width = context.pixelYToPt( m_width ) / context.layoutUnitPtToPt( context.getBaseSize() );
106 }
107 double height = style.getSpace( m_heightType, m_height );
108 if ( m_heightType == AbsoluteSize ) {
109 height = m_height / context.layoutUnitPtToPt( context.getBaseSize() );
110 }
111 else if ( m_heightType == PixelSize ) {
112 height = context.pixelYToPt( m_height ) / context.layoutUnitPtToPt( context.getBaseSize() );
113 }
114 double depth = style.getSpace( m_depthType, m_depth );
115 if ( m_depthType == AbsoluteSize ) {
116 depth = m_depth / context.layoutUnitPtToPt( context.getBaseSize() );
117 }
118 else if ( m_depthType == PixelSize ) {
119 depth = context.pixelYToPt( m_depth ) / context.layoutUnitPtToPt( context.getBaseSize() );
120 }
121
122 setWidth( hbound.width() * width );
123 setHeight( vbound.height() * height + vbound.height() * depth );
124 setBaseline( vbound.height() * height );
125
126 if ( m_tab ) {
127 getParent()->registerTab( this );
128 }
129}
130
131void SpaceElement::draw( TQPainter& painter, const LuPixelRect& /*r*/,
132 const ContextStyle& context,
133 ContextStyle::TextStyle /*tstyle*/,
134 ContextStyle::IndexStyle /*istyle*/,
135 StyleAttributes& /*style*/,
136 const LuPixelPoint& parentOrigin )
137{
138 LuPixelPoint myPos(parentOrigin.x()+getX(), parentOrigin.y()+getY());
139 // there is such a thing as negative space!
140 //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
141 // return;
142
143 if ( context.edit() ) {
144 painter.setPen( context.getEmptyColor() );
145 painter.drawLine( context.layoutUnitToPixelX( myPos.x() ),
146 context.layoutUnitToPixelY( myPos.y()+getHeight() ),
147 context.layoutUnitToPixelX( myPos.x()+getWidth()-1 ),
148 context.layoutUnitToPixelY( myPos.y()+getHeight() ) );
149 painter.drawLine( context.layoutUnitToPixelX( myPos.x() ),
150 context.layoutUnitToPixelY( myPos.y()+getHeight() ),
151 context.layoutUnitToPixelX( myPos.x() ),
152 context.layoutUnitToPixelY( myPos.y()+getHeight()-getHeight()/5 ) );
153 painter.drawLine( context.layoutUnitToPixelX( myPos.x()+getWidth()-1 ),
154 context.layoutUnitToPixelY( myPos.y()+getHeight() ),
155 context.layoutUnitToPixelX( myPos.x()+getWidth()-1 ),
156 context.layoutUnitToPixelY( myPos.y()+getHeight()-getHeight()/5 ) );
157 }
158}
159
160
161void SpaceElement::writeDom(TQDomElement element)
162{
163 BasicElement::writeDom(element);
164 switch ( m_widthType ) {
165 case NegativeVeryVeryThinMathSpace:
166 case NegativeVeryThinMathSpace:
167 case NegativeThinMathSpace:
168 case NegativeMediumMathSpace:
169 case NegativeThickMathSpace:
170 case NegativeVeryThickMathSpace:
171 case NegativeVeryVeryThickMathSpace:
172 element.setAttribute( "WIDTH", "negthin" );
173 break;
174 case VeryVeryThinMathSpace:
175 case VeryThinMathSpace:
176 case ThinMathSpace:
177 element.setAttribute( "WIDTH", "thin" );
178 break;
179 case MediumMathSpace:
180 element.setAttribute( "WIDTH", "medium" );
181 break;
182 case ThickMathSpace:
183 element.setAttribute( "WIDTH", "thick" );
184 break;
185 case VeryThickMathSpace:
186 case VeryVeryThickMathSpace:
187 element.setAttribute( "WIDTH", "quad" );
188 break;
189 case AbsoluteSize:
190 case RelativeSize:
191 case PixelSize:
192 if ( m_width < 0 ) {
193 element.setAttribute( "WIDTH", "negthin" );
194 }
195 else {
196 element.setAttribute( "WIDTH", "thin" );
197 }
198 default:
199 break;
200 }
201 if ( m_tab ) {
202 element.setAttribute( "TAB", "true" );
203 }
204}
205
206bool SpaceElement::readAttributesFromDom( TQDomElement element )
207{
208 if ( !BasicElement::readAttributesFromDom( element ) ) {
209 return false;
210 }
211 TQString widthStr = element.attribute( "WIDTH" );
212 if( !widthStr.isNull() ) {
213 if ( widthStr.lower() == "quad" ) {
214 m_widthType = VeryVeryThickMathSpace;
215 }
216 else if ( widthStr.lower() == "thick" ) {
217 m_widthType = ThickMathSpace;
218 }
219 else if ( widthStr.lower() == "medium" ) {
220 m_widthType = MediumMathSpace;
221 }
222 else if ( widthStr.lower() == "negthin" ) {
223 m_widthType = NegativeThinMathSpace;
224 }
225 else {
226 m_widthType = ThinMathSpace;
227 }
228 }
229 else {
230 return false;
231 }
232 TQString tabStr = element.attribute( "TAB" );
233 m_tab = !tabStr.isNull();
234 return true;
235}
236
238{
240}
241
242bool SpaceElement::readAttributesFromMathMLDom(const TQDomElement& element)
243{
245 return false;
246 }
247
248 TQString widthStr = element.attribute( "width" ).stripWhiteSpace().lower();
249 if ( ! widthStr.isNull() ) {
250 m_width = getSize( widthStr, &m_widthType );
251 if ( m_widthType == NoSize ) {
252 m_widthType = getSpace( widthStr );
253 }
254 }
255 TQString heightStr = element.attribute( "height" ).stripWhiteSpace().lower();
256 if ( ! heightStr.isNull() ) {
257 m_height = getSize( heightStr, &m_heightType );
258 }
259 TQString depthStr = element.attribute( "depth" ).stripWhiteSpace().lower();
260 if ( ! depthStr.isNull() ) {
261 m_depth = getSize( depthStr, &m_depthType );
262 }
263 TQString linebreakStr = element.attribute( "linebreak" ).stripWhiteSpace().lower();
264 if ( ! linebreakStr.isNull() ) {
265 if ( linebreakStr == "auto" ) {
266 m_lineBreak = AutoBreak;
267 }
268 else if ( linebreakStr == "newline" ) {
269 m_lineBreak = NewLineBreak;
270 }
271 else if ( linebreakStr == "indentingnewline" ) {
272 m_lineBreak = IndentingNewLineBreak;
273 }
274 else if ( linebreakStr == "nobreak" ) {
275 m_lineBreak = NoBreak;
276 }
277 else if ( linebreakStr == "goodbreak" ) {
278 m_lineBreak = GoodBreak;
279 }
280 else if ( linebreakStr == "badbreak" ) {
281 m_lineBreak = BadBreak;
282 }
283 }
284 return true;
285}
286
287void SpaceElement::writeMathMLAttributes( TQDomElement& element ) const
288{
289 switch ( m_widthType ) {
290 case AbsoluteSize:
291 element.setAttribute( "width", TQString( "%1pt" ).arg( m_width ) );
292 break;
293 case RelativeSize:
294 element.setAttribute( "width", TQString( "%1%" ).arg( m_width * 100.0 ) );
295 break;
296 case PixelSize:
297 element.setAttribute( "width", TQString( "%1px" ).arg( m_width ) );
298 break;
299 case NegativeVeryVeryThinMathSpace:
300 element.setAttribute( "width", "negativeveryverythinmathspace" );
301 break;
302 case NegativeVeryThinMathSpace:
303 element.setAttribute( "width", "negativeverythinmathspace" );
304 break;
305 case NegativeThinMathSpace:
306 element.setAttribute( "width", "negativethinmathspace" );
307 break;
308 case NegativeMediumMathSpace:
309 element.setAttribute( "width", "negativemediummathspace" );
310 break;
311 case NegativeThickMathSpace:
312 element.setAttribute( "width", "negativethickmathspace" );
313 break;
314 case NegativeVeryThickMathSpace:
315 element.setAttribute( "width", "negativeverythickmathspace" );
316 break;
317 case NegativeVeryVeryThickMathSpace:
318 element.setAttribute( "width", "negativeveryverythickmathspace" );
319 break;
320 case VeryVeryThinMathSpace:
321 element.setAttribute( "width", "veryverythinmathspace" );
322 break;
323 case VeryThinMathSpace:
324 element.setAttribute( "width", "verythinmathspace" );
325 break;
326 case ThinMathSpace:
327 element.setAttribute( "width", "thinmathspace" );
328 break;
329 case MediumMathSpace:
330 element.setAttribute( "width", "mediummathspace" );
331 break;
332 case ThickMathSpace:
333 element.setAttribute( "width", "thickmathspace" );
334 break;
335 case VeryThickMathSpace:
336 element.setAttribute( "width", "verythickmathspace" );
337 break;
338 case VeryVeryThickMathSpace:
339 element.setAttribute( "width", "veryverythickmathspace" );
340 break;
341 default:
342 break;
343 }
344 switch ( m_heightType ) {
345 case AbsoluteSize:
346 element.setAttribute( "height", TQString( "%1pt" ).arg( m_height ) );
347 break;
348 case RelativeSize:
349 element.setAttribute( "height", TQString( "%1%" ).arg( m_height * 100.0 ) );
350 break;
351 case PixelSize:
352 element.setAttribute( "height", TQString( "%1px" ).arg( m_height ) );
353 break;
354 default:
355 break;
356 }
357 switch ( m_depthType ) {
358 case AbsoluteSize:
359 element.setAttribute( "depth", TQString( "%1pt" ).arg( m_depth ) );
360 break;
361 case RelativeSize:
362 element.setAttribute( "depth", TQString( "%1%" ).arg( m_depth * 100.0 ) );
363 break;
364 case PixelSize:
365 element.setAttribute( "depth", TQString( "%1px" ).arg( m_depth ) );
366 break;
367 default:
368 break;
369 }
370 switch ( m_lineBreak ) {
371 case AutoBreak:
372 element.setAttribute( "linebreak", "auto" );
373 break;
374 case NewLineBreak:
375 element.setAttribute( "linebreak", "newline" );
376 break;
377 case IndentingNewLineBreak:
378 element.setAttribute( "linebreak", "indentingnewline" );
379 break;
380 case NoBreak:
381 element.setAttribute( "linebreak", "nobreak" );
382 break;
383 case GoodBreak:
384 element.setAttribute( "linebreak", "goodbreak" );
385 break;
386 case BadBreak:
387 element.setAttribute( "linebreak", "badbreak" );
388 break;
389 default:
390 break;
391 }
392}
393
395{
396 switch ( m_widthType ) {
397 case NegativeVeryVeryThinMathSpace:
398 case NegativeVeryThinMathSpace:
399 case NegativeThinMathSpace:
400 case NegativeMediumMathSpace:
401 case NegativeThickMathSpace:
402 case NegativeVeryThickMathSpace:
403 case NegativeVeryVeryThickMathSpace:
404 return "\\!";
405 case VeryVeryThinMathSpace:
406 case VeryThinMathSpace:
407 case ThinMathSpace:
408 return "\\,";
409 case MediumMathSpace:
410 return "\\>";
411 case ThickMathSpace:
412 return "\\;";
413 case VeryThickMathSpace:
414 case VeryVeryThickMathSpace:
415 return "\\quad ";
416 case AbsoluteSize:
417 case RelativeSize:
418 case PixelSize:
419 if ( m_width < 0 ) {
420 return "\\!";
421 }
422 else {
423 return "\\,";
424 }
425 default:
426 break;
427 }
428 return "";
429}
430
431KFORMULA_NAMESPACE_END
Basis of every formula element.
virtual bool readAttributesFromMathMLDom(const TQDomElement &element)
Reads our attributes from the MathML element.
virtual bool readContentFromDom(TQDomNode &node)
Reads our content from the node.
virtual void registerTab(BasicElement *)
Callback for the tabs among our children.
virtual bool readAttributesFromDom(TQDomElement element)
Reads our attributes from the element.
double getSize(const TQString &str, SizeType *st)
Utility function that sets the size type and returns the size value from a MathML attribute string wi...
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.
int layoutUnitToPixelX(int lupix) const
The "layout unit pixel" -> "[zoomed] view pixel" conversions.
A element that represents a space.
virtual void writeDom(TQDomElement element)
Appends our attributes to the dom element.
virtual TQString toLatex()
Moves the cursor away from the given child.
virtual bool readAttributesFromDom(TQDomElement element)
Reads our attributes from the element.
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 bool readContentFromDom(TQDomNode &node)
Reads our content from the node.
virtual bool readAttributesFromMathMLDom(const TQDomElement &element)
Reads our attributes from the MathML element.
virtual void draw(TQPainter &painter, const LuPixelRect &r, const ContextStyle &context, ContextStyle::TextStyle tstyle, ContextStyle::IndexStyle istyle, StyleAttributes &style, const LuPixelPoint &parentOrigin)
Draws the whole element including its children.