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.
koffice/lib/kformula/spaceelement.cpp

432 lines
14 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>
Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
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 <kprinter.h>
#include "contextstyle.h"
#include "elementvisitor.h"
#include "spaceelement.h"
KFORMULA_NAMESPACE_BEGIN
SpaceElement::SpaceElement( SpaceWidth space, bool tab, BasicElement* parent )
: BasicElement( parent ),
m_tab( tab ),
m_widthType( NoSize ),
m_heightType( NoSize ),
m_depthType( NoSize ),
m_lineBreak( NoBreakType )
{
// Backwards compatibility with KFO format
switch ( space ) {
case NEGTHIN:
m_widthType = NegativeThinMathSpace;
break;
case THIN:
m_widthType = ThinMathSpace;
break;
case MEDIUM:
m_widthType = MediumMathSpace;
break;
case THICK:
m_widthType = ThickMathSpace;
break;
case QUAD:
m_widthType = VeryVeryThickMathSpace;
break;
}
}
SpaceElement::SpaceElement( const SpaceElement& other )
: BasicElement( other ),
m_widthType( other.m_widthType ),
m_width( other.m_width ),
m_heightType( other.m_heightType ),
m_height( other.m_height ),
m_depthType( other.m_depthType ),
m_depth( other.m_depth ),
m_lineBreak( other.m_lineBreak )
{
}
bool SpaceElement::accept( ElementVisitor* visitor )
{
return visitor->visit( this );
}
void SpaceElement::calcSizes( const ContextStyle& context,
ContextStyle::TextStyle tstyle,
ContextStyle::IndexStyle /*istyle*/,
StyleAttributes& style )
{
double factor = style.sizeFactor();
luPt mySize = context.getAdjustedSize( tstyle, factor );
TQFont font = context.getDefaultFont();
font.setPointSize( mySize );
TQFontMetrics fm( font );
TQChar w = 'M';
LuPixelRect hbound = fm.boundingRect( w );
TQChar h = 'x';
LuPixelRect vbound = fm.boundingRect( h );
double width = style.getSpace( m_widthType, m_width );
if ( m_widthType == AbsoluteSize ) {
width = m_width / context.layoutUnitPtToPt( context.getBaseSize() );
}
else if ( m_widthType == PixelSize ) {
width = context.pixelYToPt( m_width ) / context.layoutUnitPtToPt( context.getBaseSize() );
}
double height = style.getSpace( m_heightType, m_height );
if ( m_heightType == AbsoluteSize ) {
height = m_height / context.layoutUnitPtToPt( context.getBaseSize() );
}
else if ( m_heightType == PixelSize ) {
height = context.pixelYToPt( m_height ) / context.layoutUnitPtToPt( context.getBaseSize() );
}
double depth = style.getSpace( m_depthType, m_depth );
if ( m_depthType == AbsoluteSize ) {
depth = m_depth / context.layoutUnitPtToPt( context.getBaseSize() );
}
else if ( m_depthType == PixelSize ) {
depth = context.pixelYToPt( m_depth ) / context.layoutUnitPtToPt( context.getBaseSize() );
}
setWidth( hbound.width() * width );
setHeight( vbound.height() * height + vbound.height() * depth );
setBaseline( vbound.height() * height );
if ( m_tab ) {
getParent()->registerTab( this );
}
}
void SpaceElement::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());
// there is such a thing as negative space!
//if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
// return;
if ( context.edit() ) {
painter.setPen( context.getEmptyColor() );
painter.drawLine( context.layoutUnitToPixelX( myPos.x() ),
context.layoutUnitToPixelY( myPos.y()+getHeight() ),
context.layoutUnitToPixelX( myPos.x()+getWidth()-1 ),
context.layoutUnitToPixelY( myPos.y()+getHeight() ) );
painter.drawLine( context.layoutUnitToPixelX( myPos.x() ),
context.layoutUnitToPixelY( myPos.y()+getHeight() ),
context.layoutUnitToPixelX( myPos.x() ),
context.layoutUnitToPixelY( myPos.y()+getHeight()-getHeight()/5 ) );
painter.drawLine( context.layoutUnitToPixelX( myPos.x()+getWidth()-1 ),
context.layoutUnitToPixelY( myPos.y()+getHeight() ),
context.layoutUnitToPixelX( myPos.x()+getWidth()-1 ),
context.layoutUnitToPixelY( myPos.y()+getHeight()-getHeight()/5 ) );
}
}
void SpaceElement::writeDom(TQDomElement element)
{
BasicElement::writeDom(element);
switch ( m_widthType ) {
case NegativeVeryVeryThinMathSpace:
case NegativeVeryThinMathSpace:
case NegativeThinMathSpace:
case NegativeMediumMathSpace:
case NegativeThickMathSpace:
case NegativeVeryThickMathSpace:
case NegativeVeryVeryThickMathSpace:
element.setAttribute( "WIDTH", "negthin" );
break;
case VeryVeryThinMathSpace:
case VeryThinMathSpace:
case ThinMathSpace:
element.setAttribute( "WIDTH", "thin" );
break;
case MediumMathSpace:
element.setAttribute( "WIDTH", "medium" );
break;
case ThickMathSpace:
element.setAttribute( "WIDTH", "thick" );
break;
case VeryThickMathSpace:
case VeryVeryThickMathSpace:
element.setAttribute( "WIDTH", "quad" );
break;
case AbsoluteSize:
case RelativeSize:
case PixelSize:
if ( m_width < 0 ) {
element.setAttribute( "WIDTH", "negthin" );
}
else {
element.setAttribute( "WIDTH", "thin" );
}
default:
break;
}
if ( m_tab ) {
element.setAttribute( "TAB", "true" );
}
}
bool SpaceElement::readAttributesFromDom( TQDomElement element )
{
if ( !BasicElement::readAttributesFromDom( element ) ) {
return false;
}
TQString widthStr = element.attribute( "WIDTH" );
if( !widthStr.isNull() ) {
if ( widthStr.lower() == "quad" ) {
m_widthType = VeryVeryThickMathSpace;
}
else if ( widthStr.lower() == "thick" ) {
m_widthType = ThickMathSpace;
}
else if ( widthStr.lower() == "medium" ) {
m_widthType = MediumMathSpace;
}
else if ( widthStr.lower() == "negthin" ) {
m_widthType = NegativeThinMathSpace;
}
else {
m_widthType = ThinMathSpace;
}
}
else {
return false;
}
TQString tabStr = element.attribute( "TAB" );
m_tab = !tabStr.isNull();
return true;
}
bool SpaceElement::readContentFromDom(TQDomNode& node)
{
return BasicElement::readContentFromDom( node );
}
bool SpaceElement::readAttributesFromMathMLDom(const TQDomElement& element)
{
if ( ! BasicElement::readAttributesFromMathMLDom( element ) ) {
return false;
}
TQString widthStr = element.attribute( "width" ).stripWhiteSpace().lower();
if ( ! widthStr.isNull() ) {
m_width = getSize( widthStr, &m_widthType );
if ( m_widthType == NoSize ) {
m_widthType = getSpace( widthStr );
}
}
TQString heightStr = element.attribute( "height" ).stripWhiteSpace().lower();
if ( ! heightStr.isNull() ) {
m_height = getSize( heightStr, &m_heightType );
}
TQString depthStr = element.attribute( "depth" ).stripWhiteSpace().lower();
if ( ! depthStr.isNull() ) {
m_depth = getSize( depthStr, &m_depthType );
}
TQString linebreakStr = element.attribute( "linebreak" ).stripWhiteSpace().lower();
if ( ! linebreakStr.isNull() ) {
if ( linebreakStr == "auto" ) {
m_lineBreak = AutoBreak;
}
else if ( linebreakStr == "newline" ) {
m_lineBreak = NewLineBreak;
}
else if ( linebreakStr == "indentingnewline" ) {
m_lineBreak = IndentingNewLineBreak;
}
else if ( linebreakStr == "nobreak" ) {
m_lineBreak = NoBreak;
}
else if ( linebreakStr == "goodbreak" ) {
m_lineBreak = GoodBreak;
}
else if ( linebreakStr == "badbreak" ) {
m_lineBreak = BadBreak;
}
}
return true;
}
void SpaceElement::writeMathMLAttributes( TQDomElement& element ) const
{
switch ( m_widthType ) {
case AbsoluteSize:
element.setAttribute( "width", TQString( "%1pt" ).arg( m_width ) );
break;
case RelativeSize:
element.setAttribute( "width", TQString( "%1%" ).arg( m_width * 100.0 ) );
break;
case PixelSize:
element.setAttribute( "width", TQString( "%1px" ).arg( m_width ) );
break;
case NegativeVeryVeryThinMathSpace:
element.setAttribute( "width", "negativeveryverythinmathspace" );
break;
case NegativeVeryThinMathSpace:
element.setAttribute( "width", "negativeverythinmathspace" );
break;
case NegativeThinMathSpace:
element.setAttribute( "width", "negativethinmathspace" );
break;
case NegativeMediumMathSpace:
element.setAttribute( "width", "negativemediummathspace" );
break;
case NegativeThickMathSpace:
element.setAttribute( "width", "negativethickmathspace" );
break;
case NegativeVeryThickMathSpace:
element.setAttribute( "width", "negativeverythickmathspace" );
break;
case NegativeVeryVeryThickMathSpace:
element.setAttribute( "width", "negativeveryverythickmathspace" );
break;
case VeryVeryThinMathSpace:
element.setAttribute( "width", "veryverythinmathspace" );
break;
case VeryThinMathSpace:
element.setAttribute( "width", "verythinmathspace" );
break;
case ThinMathSpace:
element.setAttribute( "width", "thinmathspace" );
break;
case MediumMathSpace:
element.setAttribute( "width", "mediummathspace" );
break;
case ThickMathSpace:
element.setAttribute( "width", "thickmathspace" );
break;
case VeryThickMathSpace:
element.setAttribute( "width", "verythickmathspace" );
break;
case VeryVeryThickMathSpace:
element.setAttribute( "width", "veryverythickmathspace" );
break;
default:
break;
}
switch ( m_heightType ) {
case AbsoluteSize:
element.setAttribute( "height", TQString( "%1pt" ).arg( m_height ) );
break;
case RelativeSize:
element.setAttribute( "height", TQString( "%1%" ).arg( m_height * 100.0 ) );
break;
case PixelSize:
element.setAttribute( "height", TQString( "%1px" ).arg( m_height ) );
break;
default:
break;
}
switch ( m_depthType ) {
case AbsoluteSize:
element.setAttribute( "depth", TQString( "%1pt" ).arg( m_depth ) );
break;
case RelativeSize:
element.setAttribute( "depth", TQString( "%1%" ).arg( m_depth * 100.0 ) );
break;
case PixelSize:
element.setAttribute( "depth", TQString( "%1px" ).arg( m_depth ) );
break;
default:
break;
}
switch ( m_lineBreak ) {
case AutoBreak:
element.setAttribute( "linebreak", "auto" );
break;
case NewLineBreak:
element.setAttribute( "linebreak", "newline" );
break;
case IndentingNewLineBreak:
element.setAttribute( "linebreak", "indentingnewline" );
break;
case NoBreak:
element.setAttribute( "linebreak", "nobreak" );
break;
case GoodBreak:
element.setAttribute( "linebreak", "goodbreak" );
break;
case BadBreak:
element.setAttribute( "linebreak", "badbreak" );
break;
default:
break;
}
}
TQString SpaceElement::toLatex()
{
switch ( m_widthType ) {
case NegativeVeryVeryThinMathSpace:
case NegativeVeryThinMathSpace:
case NegativeThinMathSpace:
case NegativeMediumMathSpace:
case NegativeThickMathSpace:
case NegativeVeryThickMathSpace:
case NegativeVeryVeryThickMathSpace:
return "\\!";
case VeryVeryThinMathSpace:
case VeryThinMathSpace:
case ThinMathSpace:
return "\\,";
case MediumMathSpace:
return "\\>";
case ThickMathSpace:
return "\\;";
case VeryThickMathSpace:
case VeryVeryThickMathSpace:
return "\\quad ";
case AbsoluteSize:
case RelativeSize:
case PixelSize:
if ( m_width < 0 ) {
return "\\!";
}
else {
return "\\,";
}
default:
break;
}
return "";
}
KFORMULA_NAMESPACE_END