karbon

vgradient.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2002 - 2005, The Karbon Developers
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include <qdom.h>
00021 #include <qbuffer.h>
00022 
00023 #include "vdocument.h"
00024 #include "vglobal.h"
00025 #include "vgradient.h"
00026 
00027 #include <KoGenStyles.h>
00028 #include <KoXmlWriter.h>
00029 #include <KoXmlNS.h>
00030 
00031 int VGradient::VColorStopList::compareItems( QPtrCollection::Item item1, QPtrCollection::Item item2 )
00032 {
00033     float r1 = ( (VColorStop*)item1 )->rampPoint;
00034     float r2 = ( (VColorStop*)item2 )->rampPoint;
00035 
00036     return ( r1 == r2 ? 0 : r1 < r2 ? -1 : 1 );
00037 } // VGradient::VColorStopList::compareItems
00038 
00039 VGradient::VGradient( VGradientType type )
00040     : m_type( type )
00041 {
00042     m_colorStops.setAutoDelete( true );
00043 
00044     // set up dummy gradient
00045     VColor color;
00046 
00047     color.set( 1.0, 0.0, 0.0 );
00048     addStop( color, 0.0, 0.5 );
00049 
00050     color.set( 1.0, 1.0, 0.0 );
00051     addStop( color, 1.0, 0.5 );
00052 
00053     setOrigin( KoPoint( 0, 0 ) );
00054     setVector( KoPoint( 0, 50 ) );
00055     setRepeatMethod( VGradient::reflect );
00056 }
00057 
00058 VGradient::VGradient( const VGradient& gradient )
00059 {
00060     m_colorStops.setAutoDelete( true );
00061 
00062     m_origin    = gradient.m_origin;
00063     m_focalPoint    = gradient.m_focalPoint;
00064     m_vector    = gradient.m_vector;
00065     m_type      = gradient.m_type;
00066     m_repeatMethod  = gradient.m_repeatMethod;
00067 
00068     m_colorStops.clear();
00069     QPtrVector<VColorStop> cs = gradient.colorStops();
00070     for( uint i = 0; i < cs.count(); i++ )
00071         m_colorStops.append( new VColorStop( *cs[i] ) );
00072     m_colorStops.sort();
00073 } // VGradient::VGradient
00074 
00075 VGradient& VGradient::operator=( const VGradient& gradient )
00076 {
00077     m_colorStops.setAutoDelete( true );
00078 
00079     if ( this == &gradient )
00080         return *this;
00081 
00082     m_origin    = gradient.m_origin;
00083     m_focalPoint    = gradient.m_focalPoint;
00084     m_vector    = gradient.m_vector;
00085     m_type      = gradient.m_type;
00086     m_repeatMethod  = gradient.m_repeatMethod;
00087 
00088     m_colorStops.clear();
00089     QPtrVector<VColorStop> cs = gradient.colorStops();
00090     for( uint i = 0; i < cs.count(); i++ )
00091         m_colorStops.append( new VColorStop( *cs[i] ) );
00092     m_colorStops.sort();
00093 
00094     return *this;
00095 } // VGradient::operator=
00096 
00097 const QPtrVector<VColorStop> VGradient::colorStops() const
00098 { 
00099     QPtrVector<VColorStop> v;
00100     m_colorStops.toVector( &v );
00101     v.setAutoDelete( false );
00102     return v;
00103 } // VGradient::colorStops()
00104 
00105 void
00106 VGradient::clearStops()
00107 {
00108     m_colorStops.clear();
00109 }
00110 
00111 void
00112 VGradient::addStop( const VColorStop& colorStop )
00113 {
00114     m_colorStops.inSort( new VColorStop( colorStop ) );
00115 } // VGradient::addStop
00116 
00117 void
00118 VGradient::addStop( const VColor &color, float rampPoint, float midPoint )
00119 {
00120     // Clamping between 0.0 and 1.0
00121     rampPoint = kMax( 0.0f, rampPoint );
00122     rampPoint = kMin( 1.0f, rampPoint );
00123     // Clamping between 0.0 and 1.0
00124     midPoint = kMax( 0.0f, midPoint );
00125     midPoint = kMin( 1.0f, midPoint );
00126 
00127     // Work around stops with the same position
00128     VColorStop *v;
00129     for(v = m_colorStops.first(); v; v = m_colorStops.next())
00130     {
00131         if(rampPoint == v->rampPoint)
00132             rampPoint += 0.001f;
00133     } 
00134     m_colorStops.inSort( new VColorStop( rampPoint, midPoint, color ) );
00135 }
00136 
00137 void VGradient::removeStop( const VColorStop& colorstop )
00138 {
00139     m_colorStops.remove( &colorstop );
00140 } // VGradient::removeStop
00141 
00142 void
00143 VGradient::save( QDomElement& element ) const
00144 {
00145     QDomElement me = element.ownerDocument().createElement( "GRADIENT" );
00146 
00147     me.setAttribute( "originX", m_origin.x() );
00148     me.setAttribute( "originY", m_origin.y() );
00149     me.setAttribute( "focalX", m_focalPoint.x() );
00150     me.setAttribute( "focalY", m_focalPoint.y() );
00151     me.setAttribute( "vectorX", m_vector.x() );
00152     me.setAttribute( "vectorY", m_vector.y() );
00153     me.setAttribute( "type", m_type );
00154     me.setAttribute( "repeatMethod", m_repeatMethod );
00155 
00156     // save stops
00157     VColorStop* colorstop;
00158     QPtrList<VColorStop>& colorStops = const_cast<VColorStopList&>( m_colorStops );
00159     for( colorstop = colorStops.first(); colorstop; colorstop = colorStops.next() )
00160     {
00161         QDomElement stop = element.ownerDocument().createElement( "COLORSTOP" );
00162         colorstop->color.save( stop );
00163         stop.setAttribute( "ramppoint", colorstop->rampPoint );
00164         stop.setAttribute( "midpoint", colorstop->midPoint );
00165         me.appendChild( stop );
00166     }
00167 
00168     element.appendChild( me );
00169 }
00170 
00171 QString
00172 VGradient::saveOasis( KoGenStyles &mainStyles ) const
00173 {
00174     bool radial = m_type == VGradient::radial;
00175     KoGenStyle gradientStyle( radial ? VDocument::STYLE_RADIAL_GRADIENT : VDocument::STYLE_LINEAR_GRADIENT /*no family name*/);
00176     if( radial )
00177     {
00178         gradientStyle.addAttribute( "draw:style", "radial" );
00179         gradientStyle.addAttributePt( "svg:cx", m_origin.x() );
00180         gradientStyle.addAttributePt( "svg:cy", m_origin.y() );
00181         double dx = m_vector.x() - m_origin.x();
00182         double dy = m_vector.y() - m_origin.y();
00183         gradientStyle.addAttributePt( "svg:r",  sqrt( dx * dx + dy * dy ) );
00184         gradientStyle.addAttributePt( "svg:fx", m_focalPoint.x() );
00185         gradientStyle.addAttributePt( "svg:fy", m_focalPoint.y() );
00186     }
00187     else
00188     {
00189         gradientStyle.addAttribute( "draw:style", "linear" );
00190         gradientStyle.addAttributePt( "svg:x1", m_origin.x() );
00191         gradientStyle.addAttributePt( "svg:y1", m_origin.y() );
00192         gradientStyle.addAttributePt( "svg:x2", m_vector.x() );
00193         gradientStyle.addAttributePt( "svg:y2", m_vector.y() );
00194     }
00195     if( m_repeatMethod == VGradient::repeat )
00196         gradientStyle.addAttribute( "svg:spreadMethod", "repeat" );
00197     else if( m_repeatMethod == VGradient::reflect )
00198         gradientStyle.addAttribute( "svg:spreadMethod", "reflect" );
00199     else
00200         gradientStyle.addAttribute( "svg:spreadMethod", "pad" );
00201     QBuffer buffer;
00202     buffer.open( IO_WriteOnly );
00203     KoXmlWriter elementWriter( &buffer );  // TODO pass indentation level
00204 
00205     // save stops
00206     VColorStop* colorstop;
00207     QPtrList<VColorStop>& colorStops = const_cast<VColorStopList&>( m_colorStops );
00208     for( colorstop = colorStops.first(); colorstop; colorstop = colorStops.next() )
00209     {
00210         elementWriter.startElement( "svg:stop" );
00211         elementWriter.addAttribute( "svg:offset", QString( "%1" ).arg( colorstop->rampPoint ) );
00212         elementWriter.addAttribute( "svg:color", QColor( colorstop->color ).name() );
00213         if( colorstop->color.opacity() < 1 )
00214             elementWriter.addAttribute( "svg:stop-opacity", QString( "%1" ).arg( colorstop->color.opacity() ) );
00215         elementWriter.endElement();
00216     }
00217 
00218     QString elementContents = QString::fromUtf8( buffer.buffer(), buffer.buffer().size() );
00219     gradientStyle.addChildElement( "svg:stop", elementContents );
00220     return mainStyles.lookup( gradientStyle, "gradient" );
00221 }
00222 
00223 void
00224 VGradient::loadOasis( const QDomElement &object, KoStyleStack &/*stack*/, VObject* parent )
00225 {
00226     kdDebug(38000) << "namespaceURI: " << object.namespaceURI() << endl;
00227     kdDebug(38000) << "localName: " << object.localName() << endl;
00228 
00229     KoRect bb;
00230     
00231     if( parent )
00232         bb =  parent->boundingBox();
00233 
00234     if( object.namespaceURI() == KoXmlNS::draw && object.localName() == "gradient" )
00235     {
00236         m_repeatMethod = VGradient::reflect;
00237         QString strType = object.attributeNS( KoXmlNS::draw, "style", QString::null );
00238         if( strType == "radial" )
00239         {
00240             m_type = VGradient::radial;
00241             // TODO : find out whether Oasis works with boundingBox only?
00242             double cx = KoUnit::parseValue( object.attributeNS( KoXmlNS::draw, "cx", QString::null ).remove("%") );
00243             m_origin.setX( bb.bottomLeft().x() + bb.width() * 0.01 * cx );
00244             double cy = KoUnit::parseValue( object.attributeNS( KoXmlNS::draw, "cy", QString::null ).remove("%") );
00245             m_origin.setY(  bb.bottomLeft().y() - bb.height() * 0.01 * cy );
00246             m_focalPoint = m_origin;
00247             m_vector = bb.topRight();
00248         }
00249         else if( strType == "linear" )
00250         {
00251             m_type = VGradient::linear;
00252             double angle = 90 + object.attributeNS( KoXmlNS::draw, "angle", "0" ).toDouble();
00253             double radius = 0.5 * sqrt( bb.width()*bb.width() + bb.height()*bb.height() );
00254             double sx = cos( angle * VGlobal::pi / 180 ) * radius;
00255             double sy = sin( angle * VGlobal::pi / 180 ) * radius;
00256             m_origin.setX( bb.center().x() + sx );
00257             m_origin.setY( bb.center().y() + sy );
00258             m_vector.setX( bb.center().x() - sx );
00259             m_vector.setY( bb.center().y() - sy );
00260             m_focalPoint = m_origin;
00261         }
00262         else return;
00263 
00264         VColor startColor( QColor( object.attributeNS( KoXmlNS::draw, "start-color", QString::null ) ) );
00265         VColor endColor( QColor( object.attributeNS( KoXmlNS::draw, "end-color", QString::null ) ) );
00266 
00267         double startOpacity = 0.01 * object.attributeNS( KoXmlNS::draw, "start-intensity", "100" ).remove("%").toDouble();
00268         double endOpacity = 0.01 * object.attributeNS( KoXmlNS::draw, "end-intensity", "100" ).remove("%").toDouble();
00269 
00270         startColor.setOpacity( startOpacity );
00271         endColor.setOpacity( endOpacity );
00272         m_colorStops.clear();
00273         addStop( startColor, 0.0, 0.5 );
00274         addStop( endColor, 1.0, 0.0 );
00275         m_colorStops.sort();
00276         
00277     }
00278     else if( object.namespaceURI() == KoXmlNS::svg )
00279     {
00280         if( object.localName() == "linearGradient" )
00281         {
00282             m_type = VGradient::linear;
00283             m_origin.setX( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "x1", QString::null ) ) );
00284             m_origin.setY( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "y1", QString::null ) ) );
00285             m_vector.setX( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "x2", QString::null ) ) );
00286             m_vector.setY( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "y2", QString::null ) ) );
00287             m_focalPoint = m_origin;
00288         }
00289         else if( object.localName() == "radialGradient" )
00290         {
00291             m_type = VGradient::radial;
00292             m_origin.setX( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "cx", QString::null ) ) );
00293             m_origin.setY( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "cy", QString::null ) ) );
00294             double r = KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "r", QString::null ) );
00295             m_vector.setX( m_origin.x() + r );
00296             m_vector.setY( m_origin.y() );
00297             m_focalPoint.setX( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "fx", QString::null ) ) );
00298             m_focalPoint.setY( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "fy", QString::null ) ) );
00299         }
00300 
00301         QString strSpread( object.attributeNS( KoXmlNS::svg, "spreadMethod", "pad" ) );
00302         if( strSpread == "repeat" )
00303             m_repeatMethod = VGradient::repeat;
00304         else if( strSpread == "reflect" )
00305             m_repeatMethod = VGradient::reflect;
00306         else
00307             m_repeatMethod = VGradient::none;
00308     
00309         m_colorStops.clear();
00310     
00311         // load stops
00312         QDomNodeList list = object.childNodes();
00313         for( uint i = 0; i < list.count(); ++i )
00314         {
00315             if( list.item( i ).isElement() )
00316             {
00317                 QDomElement colorstop = list.item( i ).toElement();
00318     
00319                 if( colorstop.namespaceURI() == KoXmlNS::svg && colorstop.localName() == "stop" )
00320                 {
00321                     VColor color( QColor( colorstop.attributeNS( KoXmlNS::svg, "color", QString::null ) ) );
00322                     color.setOpacity( colorstop.attributeNS( KoXmlNS::svg, "stop-opacity", "1.0" ).toDouble() );
00323                     addStop( color, colorstop.attributeNS( KoXmlNS::svg, "offset", "0.0" ).toDouble(), 0.5 );
00324                 }
00325             }
00326         }
00327         m_colorStops.sort();
00328     }
00329 }
00330 
00331 void
00332 VGradient::load( const QDomElement& element )
00333 {
00334     m_origin.setX( element.attribute( "originX", "0.0" ).toDouble() );
00335     m_origin.setY( element.attribute( "originY", "0.0" ).toDouble() );
00336     m_focalPoint.setX( element.attribute( "focalX", "0.0" ).toDouble() );
00337     m_focalPoint.setY( element.attribute( "focalY", "0.0" ).toDouble() );
00338     m_vector.setX( element.attribute( "vectorX", "0.0" ).toDouble() );
00339     m_vector.setY( element.attribute( "vectorY", "0.0" ).toDouble() );
00340     m_type = (VGradientType)element.attribute( "type", 0 ).toInt();
00341     m_repeatMethod = (VGradientRepeatMethod)element.attribute( "repeatMethod", 0 ).toInt();
00342 
00343     m_colorStops.clear();
00344 
00345     // load stops
00346     QDomNodeList list = element.childNodes();
00347     for( uint i = 0; i < list.count(); ++i )
00348     {
00349         if( list.item( i ).isElement() )
00350         {
00351             QDomElement colorstop = list.item( i ).toElement();
00352 
00353             if( colorstop.tagName() == "COLORSTOP" )
00354             {
00355                 VColor color;
00356                 color.load( colorstop.firstChild().toElement() );
00357                 addStop( color, colorstop.attribute( "ramppoint", "0.0" ).toDouble(), colorstop.attribute( "midpoint", "0.5" ).toDouble() );
00358             }
00359         }
00360     }
00361     m_colorStops.sort();
00362 }
00363 
00364 void
00365 VGradient::transform( const QWMatrix &m )
00366 {
00367     m_origin    = m_origin.transform( m );
00368     m_focalPoint    = m_focalPoint.transform( m );
00369     m_vector    = m_vector.transform( m );
00370 }
KDE Home | KDE Accessibility Home | Description of Access Keys