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/tokenstyleelement.cc

625 lines
20 KiB

/* This file is part of the KDE project
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 <tqpainter.h>
#include "basicelement.h"
#include "tokenstyleelement.h"
KFORMULA_NAMESPACE_BEGIN
TokenStyleElement::TokenStyleElement( BasicElement* tqparent ) : SequenceElement( tqparent ),
m_mathSizeType ( NoSize ),
m_charStyle( anyChar ),
m_charFamily( anyFamily ),
m_mathColor( "#000000" ),
m_mathBackground( "#FFFFFF" ),
m_fontSizeType( NoSize ),
m_customMathVariant( false ),
m_customMathColor( false ),
m_customMathBackground( false ),
m_customFontWeight( false ),
m_customFontStyle( false ),
m_customFontFamily( false ),
m_customColor( false )
{
}
void TokenStyleElement::calcSizes( const ContextStyle& context,
ContextStyle::TextStyle tstyle,
ContextStyle::IndexStyle istyle,
StyleAttributes& style )
{
setStyleSize( context, style );
setStyleVariant( style );
setStyleColor( style );
setStyleBackground( style );
inherited::calcSizes( context, tstyle, istyle, style );
resetStyle( style );
}
void TokenStyleElement::draw( TQPainter& painter, const LuPixelRect& r,
const ContextStyle& context,
ContextStyle::TextStyle tstyle,
ContextStyle::IndexStyle istyle,
StyleAttributes& style,
const LuPixelPoint& parentOrigin )
{
setStyleSize( context, style );
setStyleVariant( style );
setStyleColor( style );
setStyleBackground( style );
if ( style.background() != TQt::color0 ) {
painter.fillRect( context.layoutUnitToPixelX( parentOrigin.x() + getX() ),
context.layoutUnitToPixelY( parentOrigin.y() + getY() ),
context.layoutUnitToPixelX( getWidth() ),
context.layoutUnitToPixelY( getHeight() ),
style.background() );
}
inherited::draw( painter, r, context, tstyle, istyle, style, parentOrigin );
resetStyle( style );
}
bool TokenStyleElement::readAttributesFromMathMLDom( const TQDomElement& element )
{
if ( !BasicElement::readAttributesFromMathMLDom( element ) ) {
return false;
}
// MathML Section 3.2.2
TQString variantStr = element.attribute( "mathvariant" );
if ( !variantStr.isNull() ) {
if ( variantStr == "normal" ) {
setCharStyle( normalChar );
setCharFamily( normalFamily );
}
else if ( variantStr == "bold" ) {
setCharStyle( boldChar );
setCharFamily( normalFamily );
}
else if ( variantStr == "italic" ) {
setCharStyle( italicChar );
setCharFamily( normalFamily );
}
else if ( variantStr == "bold-italic" ) {
setCharStyle( boldItalicChar );
setCharFamily( normalFamily );
}
else if ( variantStr == "double-struck" ) {
setCharStyle( normalChar );
setCharFamily( doubleStruckFamily );
}
else if ( variantStr == "bold-fraktur" ) {
setCharStyle( boldChar );
setCharFamily( frakturFamily );
}
else if ( variantStr == "script" ) {
setCharStyle( normalChar );
setCharFamily( scriptFamily );
}
else if ( variantStr == "bold-script" ) {
setCharStyle( boldChar );
setCharFamily( scriptFamily );
}
else if ( variantStr == "fraktur" ) {
setCharStyle( boldChar );
setCharFamily( frakturFamily );
}
else if ( variantStr == "sans-serif" ) {
setCharStyle( normalChar );
setCharFamily( sansSerifFamily );
}
else if ( variantStr == "bold-sans-serif" ) {
setCharStyle( boldChar );
setCharFamily( sansSerifFamily );
}
else if ( variantStr == "sans-serif-italic" ) {
setCharStyle( italicChar );
setCharFamily( sansSerifFamily );
}
else if ( variantStr == "sans-serif-bold-italic" ) {
setCharStyle( boldItalicChar );
setCharFamily( sansSerifFamily );
}
else if ( variantStr == "monospace" ) {
setCharStyle( normalChar );
setCharFamily( monospaceFamily );
}
}
TQString sizeStr = element.attribute( "mathsize" );
if ( !sizeStr.isNull() ) {
if ( sizeStr == "small" ) {
setRelativeSize( 0.8 ); // ### Arbitrary size
}
else if ( sizeStr == "normal" ) {
setRelativeSize( 1.0 );
}
else if ( sizeStr == "big" ) {
setRelativeSize( 1.2 ); // ### Arbitrary size
}
else {
double s = getSize( sizeStr, &m_mathSizeType );
switch ( m_mathSizeType ) {
case AbsoluteSize:
setAbsoluteSize( s );
break;
case RelativeSize:
setRelativeSize( s );
break;
case PixelSize:
setPixelSize( s );
break;
default:
break;
}
}
}
TQString colorStr = element.attribute( "mathcolor" );
if ( !colorStr.isNull() ) {
if ( colorStr[0] != '#' ) {
setMathColor( TQColor( getHtmlColor( colorStr ) ) );
}
else {
setMathColor( TQColor( colorStr ) );
}
}
TQString backgroundStr = element.attribute( "mathbackground" );
if ( !backgroundStr.isNull() ) {
if ( backgroundStr[0] != '#' ) {
setMathBackground( TQColor( getHtmlColor( backgroundStr ) ) );
}
else {
setMathBackground( TQColor( backgroundStr ) );
}
}
// Deprecated attributes. See Section 3.2.2.1
sizeStr = element.attribute( "fontsize" );
if ( ! sizeStr.isNull() ) {
if ( sizeStr == "small" ) {
setRelativeSize( 0.8, true ); // ### Arbitrary size
}
else if ( sizeStr == "normal" ) {
setRelativeSize( 1.0, true );
}
else if ( sizeStr == "big" ) {
setRelativeSize( 1.2, true ); // ### Arbitrary size
}
else {
double s = getSize( sizeStr, &m_fontSizeType );
switch ( m_fontSizeType ) {
case AbsoluteSize:
setAbsoluteSize( s, true );
break;
case RelativeSize:
setRelativeSize( s, true );
break;
case PixelSize:
setPixelSize( s, true );
break;
default:
break;
}
}
}
TQString styleStr = element.attribute( "fontstyle" );
if ( ! styleStr.isNull() ) {
if ( styleStr.lower() == "italic" ) {
setFontStyle( true );
}
else {
setFontStyle( false );
}
}
TQString weightStr = element.attribute( "fontweight" );
if ( ! weightStr.isNull() ) {
if ( weightStr.lower() == "bold" ) {
setFontWeight( true );
}
else {
setFontWeight( false );
}
}
TQString familyStr = element.attribute( "fontfamily" );
if ( ! familyStr.isNull() ) {
setFontFamily( familyStr );
}
colorStr = element.attribute( "color" );
if ( ! colorStr.isNull() ) {
if ( colorStr[0] != '#' ) {
setColor( TQColor( getHtmlColor( colorStr ) ) );
}
else {
setColor( TQColor( colorStr ) );
}
}
return true;
}
void TokenStyleElement::writeMathMLAttributes( TQDomElement& element ) const
{
// mathvariant attribute
if ( customMathVariant() ) {
if ( charFamily() == normalFamily ) {
if ( charStyle() == normalChar ) {
element.setAttribute( "mathvariant", "normal" );
}
else if ( charStyle() == boldChar ) {
element.setAttribute( "mathvariant", "bold" );
}
else if ( charStyle() == italicChar ) {
element.setAttribute( "mathvariant", "italic" );
}
else if ( charStyle() == boldItalicChar ) {
element.setAttribute( "mathvariant", "bold-italic" );
}
else { // anyChar or unknown, it's always an error
kdWarning( DEBUGID ) << "Mathvariant: unknown style for normal family\n";
}
}
else if ( charFamily() == doubleStruckFamily ) {
if ( charStyle() == normalChar ) {
element.setAttribute( "mathvariant", "double-struck" );
}
else { // Shouldn't happen, it's a bug
kdWarning( DEBUGID ) << "Mathvariant: unknown style for double-struck family\n";
}
}
else if ( charFamily() == frakturFamily ) {
if ( charStyle() == normalChar ) {
element.setAttribute( "mathvariant", "fraktur" );
}
else if ( charStyle() == boldChar ) {
element.setAttribute( "mathvariant", "bold-fraktur" );
}
else {
kdWarning( DEBUGID ) << "Mathvariant: unknown style for fraktur family\n";
}
}
else if ( charFamily() == scriptFamily ) {
if ( charStyle() == normalChar ) {
element.setAttribute( "mathvariant", "script" );
}
else if ( charStyle() == boldChar ) {
element.setAttribute( "mathvariant", "bold-script" );
}
else { // Shouldn't happen, it's a bug
kdWarning( DEBUGID ) << "Mathvariant: unknown style for script family\n";
}
}
else if ( charFamily() == sansSerifFamily ) {
if ( charStyle() == normalChar ) {
element.setAttribute( "mathvariant", "sans-serif" );
}
else if ( charStyle() == boldChar ) {
element.setAttribute( "mathvariant", "bold-sans-serif" );
}
else if ( charStyle() == italicChar ) {
element.setAttribute( "mathvariant", "sans-serif-italic" );
}
else if ( charStyle() == boldItalicChar ) {
element.setAttribute( "mathvariant", "sans-serif-bold-italic" );
}
else {
kdWarning( DEBUGID ) << "Mathvariant: unknown style for sans serif family\n";
}
}
else if ( charFamily() == monospaceFamily ) {
if ( charStyle() == normalChar ) {
element.setAttribute( "mathvariant", "monospace" );
}
else {
kdWarning( DEBUGID ) << "Mathvariant: unknown style for monospace family\n";
}
}
else {
kdWarning( DEBUGID ) << "Mathvariant: unknown family\n";
}
}
// mathsize attribute
switch ( m_mathSizeType ) {
case AbsoluteSize:
element.setAttribute( "mathsize", TQString( "%1pt" ).tqarg( m_mathSize ) );
break;
case RelativeSize:
element.setAttribute( "mathsize", TQString( "%1%" ).tqarg( m_mathSize * 100.0 ) );
break;
case PixelSize:
element.setAttribute( "mathsize", TQString( "%1px" ).tqarg( m_mathSize ) );
break;
default:
break;
}
// mathcolor attribute
if ( customMathColor() ) {
element.setAttribute( "mathcolor", mathColor().name() );
}
// mathbackground attribute
if ( customMathBackground() ) {
element.setAttribute( "mathbackground", mathBackground().name() );
}
// Deprecated MathML 1.01 Attributes
// fontsize attribute
switch ( m_fontSizeType ) {
case AbsoluteSize:
element.setAttribute( "fontsize", TQString( "%1pt" ).tqarg( m_fontSize ) );
break;
case RelativeSize:
element.setAttribute( "fontsize", TQString( "%1%" ).tqarg( m_fontSize * 100.0 ) );
break;
case PixelSize:
element.setAttribute( "fontsize", TQString( "%3px" ).tqarg( m_fontSize ) );
break;
default:
break;
}
// fontweight attribute
if ( customFontWeight() ) {
element.setAttribute( "fontweight", fontWeight() ? "bold" : "normal" );
}
// fontstyle attribute
if ( customFontStyle() ) {
element.setAttribute( "fontstyle", fontStyle() ? "italic" : "normal" );
}
// fontfamily attribute
if ( customFontFamily() ) {
element.setAttribute( "fontfamily", fontFamily() );
}
// color attribute
if ( customColor() ) {
element.setAttribute( "color", color().name() );
}
}
void TokenStyleElement::setAbsoluteSize( double s, bool fontsize )
{
kdDebug( DEBUGID) << "Setting absolute size: " << s << endl;
if ( fontsize ) {
m_fontSizeType = AbsoluteSize;
m_fontSize = s;
}
else {
m_mathSizeType = AbsoluteSize;
m_mathSize = s;
}
}
void TokenStyleElement::setRelativeSize( double f, bool fontsize )
{
kdDebug( DEBUGID) << "Setting relative size: " << f << endl;
if ( fontsize ) {
m_fontSizeType = RelativeSize;
m_fontSize = f;
}
else {
m_mathSizeType = RelativeSize;
m_mathSize = f;
}
}
void TokenStyleElement::setPixelSize( double px, bool fontsize )
{
kdDebug( DEBUGID) << "Setting pixel size: " << px << endl;
if ( fontsize ) {
m_fontSizeType = PixelSize;
m_fontSize = px;
}
else {
m_mathSizeType = PixelSize;
m_mathSize = px;
}
}
void TokenStyleElement::setStyleSize( const ContextStyle& context, StyleAttributes& style )
{
style.setSizeFactor( sizeFactor( context, style.sizeFactor() ) );
}
void TokenStyleElement::setStyleVariant( StyleAttributes& style )
{
if ( customMathVariant() || style.customMathVariant() ) {
style.setCustomMathVariant ( true );
style.setCustomFontWeight( false );
style.setCustomFontStyle( false );
style.setCustomFont( false );
if ( customMathVariant() ) {
style.setCharFamily ( charFamily() );
style.setCharStyle( charStyle() );
}
else {
style.setCharFamily( style.charFamily() );
style.setCharStyle( style.charStyle() );
}
}
else {
style.setCustomMathVariant( false );
if ( customFontFamily() ) {
style.setCustomFont( true );
style.setFont( TQFont(fontFamily()) );
}
bool fontweight = false;
if ( customFontWeight() || style.customFontWeight() ) {
style.setCustomFontWeight( true );
if ( customFontWeight() ) {
fontweight = fontWeight();
}
else {
fontweight = style.fontWeight();
}
style.setFontWeight( fontweight );
}
else {
style.setCustomFontWeight( false );
}
bool fontstyle = false;
if ( style.customFontStyle() ) {
style.setCustomFontStyle( true );
fontstyle = style.fontStyle();
style.setFontStyle( fontstyle );
}
else {
style.setCustomFontStyle( false );
}
if ( customFontStyle() ) {
fontstyle = fontStyle();
}
if ( fontweight && fontstyle ) {
style.setCharStyle( boldItalicChar );
}
else if ( fontweight && ! fontstyle ) {
style.setCharStyle( boldChar );
}
else if ( ! fontweight && fontstyle ) {
style.setCharStyle( italicChar );
}
else {
style.setCharStyle( normalChar );
}
}
}
void TokenStyleElement::setStyleColor( StyleAttributes& style )
{
if ( customMathColor() ) {
style.setColor( mathColor() );
}
else if ( customColor() ) {
style.setColor( color() );
}
else {
style.setColor( style.color() );
}
}
void TokenStyleElement::setStyleBackground( StyleAttributes& style )
{
if ( customMathBackground() ) {
style.setBackground( mathBackground() );
}
else {
style.setBackground( style.background() );
}
}
void TokenStyleElement::resetStyle( StyleAttributes& style )
{
style.resetSize();
style.resetCharStyle();
style.resetCharFamily();
style.resetColor();
style.resetBackground();
style.resetFontFamily();
style.resetFontWeight();
style.resetFontStyle();
}
double TokenStyleElement::sizeFactor( const ContextStyle& context, double factor )
{
double basesize = context.layoutUnitPtToPt( context.getBaseSize() );
switch ( m_mathSizeType ) {
case AbsoluteSize:
return m_mathSize / basesize;
case RelativeSize:
return m_mathSize;
case PixelSize:
// 3.2.2 says v-unit instead of h-unit, that's why we use Y and not X
return context.pixelYToPt( m_mathSize ) / basesize;
case NoSize:
switch ( m_fontSizeType ) {
case AbsoluteSize:
return m_fontSize / basesize;
case RelativeSize:
return m_fontSize;
case PixelSize:
return context.pixelYToPt( m_fontSize ) / basesize;
default:
return factor;
}
default:
break;
}
kdWarning( DEBUGID ) << k_funcinfo << " Unknown SizeType\n";
return factor;
}
/**
* Return RGB string from HTML Colors. See HTML Spec, section 6.5
*/
TQString TokenStyleElement::getHtmlColor( const TQString& colorStr ){
TQString colorname = colorStr.lower();
if ( colorname == "black" )
return "#000000";
if ( colorname == "silver" )
return "#C0C0C0";
if ( colorname == "gray" )
return "#808080";
if ( colorname == "white" )
return "#FFFFFF";
if ( colorname == "maroon" )
return "#800000";
if ( colorname == "red" )
return "#FF0000";
if ( colorname == "purple" )
return "#800080";
if ( colorname == "fuchsia" )
return "#FF00FF";
if ( colorname == "green" )
return "#008000";
if ( colorname == "lime" )
return "#00FF00";
if ( colorname == "olive" )
return "#808000";
if ( colorname == "yellow" )
return "#FFFF00";
if ( colorname == "navy" )
return "#000080";
if ( colorname == "blue")
return "#0000FF";
if ( colorname == "teal" )
return "#008080";
if ( colorname == "aqua" )
return "#00FFFF";
kdWarning( DEBUGID ) << "Invalid HTML color: " << colorname << endl;
return "#FFFFFF"; // ### Arbitrary selection of default color
}
KFORMULA_NAMESPACE_END