karbon

vgradient.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2002 - 2005, The Karbon Developers
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include <tqdom.h>
21#include <tqbuffer.h>
22
23#include "vdocument.h"
24#include "vglobal.h"
25#include "vgradient.h"
26
27#include <KoGenStyles.h>
28#include <KoXmlWriter.h>
29#include <KoXmlNS.h>
30
31int VGradient::VColorStopList::compareItems( TQPtrCollection::Item item1, TQPtrCollection::Item item2 )
32{
33 float r1 = ( (VColorStop*)item1 )->rampPoint;
34 float r2 = ( (VColorStop*)item2 )->rampPoint;
35
36 return ( r1 == r2 ? 0 : r1 < r2 ? -1 : 1 );
37} // VGradient::VColorStopList::compareItems
38
39VGradient::VGradient( VGradientType type )
40 : m_type( type )
41{
42 m_colorStops.setAutoDelete( true );
43
44 // set up dummy gradient
45 VColor color;
46
47 color.set( 1.0, 0.0, 0.0 );
48 addStop( color, 0.0, 0.5 );
49
50 color.set( 1.0, 1.0, 0.0 );
51 addStop( color, 1.0, 0.5 );
52
53 setOrigin( KoPoint( 0, 0 ) );
54 setVector( KoPoint( 0, 50 ) );
55 setRepeatMethod( VGradient::reflect );
56}
57
58VGradient::VGradient( const VGradient& gradient )
59{
60 m_colorStops.setAutoDelete( true );
61
62 m_origin = gradient.m_origin;
63 m_focalPoint = gradient.m_focalPoint;
64 m_vector = gradient.m_vector;
65 m_type = gradient.m_type;
66 m_repeatMethod = gradient.m_repeatMethod;
67
68 m_colorStops.clear();
69 TQPtrVector<VColorStop> cs = gradient.colorStops();
70 for( uint i = 0; i < cs.count(); i++ )
71 m_colorStops.append( new VColorStop( *cs[i] ) );
72 m_colorStops.sort();
73} // VGradient::VGradient
74
75VGradient& VGradient::operator=( const VGradient& gradient )
76{
77 m_colorStops.setAutoDelete( true );
78
79 if ( this == &gradient )
80 return *this;
81
82 m_origin = gradient.m_origin;
83 m_focalPoint = gradient.m_focalPoint;
84 m_vector = gradient.m_vector;
85 m_type = gradient.m_type;
86 m_repeatMethod = gradient.m_repeatMethod;
87
88 m_colorStops.clear();
89 TQPtrVector<VColorStop> cs = gradient.colorStops();
90 for( uint i = 0; i < cs.count(); i++ )
91 m_colorStops.append( new VColorStop( *cs[i] ) );
92 m_colorStops.sort();
93
94 return *this;
95} // VGradient::operator=
96
97const TQPtrVector<VColorStop> VGradient::colorStops() const
98{
99 TQPtrVector<VColorStop> v;
100 m_colorStops.toVector( &v );
101 v.setAutoDelete( false );
102 return v;
103} // VGradient::colorStops()
104
105void
106VGradient::clearStops()
107{
108 m_colorStops.clear();
109}
110
111void
112VGradient::addStop( const VColorStop& colorStop )
113{
114 m_colorStops.inSort( new VColorStop( colorStop ) );
115} // VGradient::addStop
116
117void
118VGradient::addStop( const VColor &color, float rampPoint, float midPoint )
119{
120 // Clamping between 0.0 and 1.0
121 rampPoint = kMax( 0.0f, rampPoint );
122 rampPoint = kMin( 1.0f, rampPoint );
123 // Clamping between 0.0 and 1.0
124 midPoint = kMax( 0.0f, midPoint );
125 midPoint = kMin( 1.0f, midPoint );
126
127 // Work around stops with the same position
128 VColorStop *v;
129 for(v = m_colorStops.first(); v; v = m_colorStops.next())
130 {
131 if(rampPoint == v->rampPoint)
132 rampPoint += 0.001f;
133 }
134 m_colorStops.inSort( new VColorStop( rampPoint, midPoint, color ) );
135}
136
137void VGradient::removeStop( const VColorStop& colorstop )
138{
139 m_colorStops.remove( &colorstop );
140} // VGradient::removeStop
141
142void
143VGradient::save( TQDomElement& element ) const
144{
145 TQDomElement me = element.ownerDocument().createElement( "GRADIENT" );
146
147 me.setAttribute( "originX", m_origin.x() );
148 me.setAttribute( "originY", m_origin.y() );
149 me.setAttribute( "focalX", m_focalPoint.x() );
150 me.setAttribute( "focalY", m_focalPoint.y() );
151 me.setAttribute( "vectorX", m_vector.x() );
152 me.setAttribute( "vectorY", m_vector.y() );
153 me.setAttribute( "type", m_type );
154 me.setAttribute( "repeatMethod", m_repeatMethod );
155
156 // save stops
157 VColorStop* colorstop;
158 TQPtrList<VColorStop>& colorStops = const_cast<VColorStopList&>( m_colorStops );
159 for( colorstop = colorStops.first(); colorstop; colorstop = colorStops.next() )
160 {
161 TQDomElement stop = element.ownerDocument().createElement( "COLORSTOP" );
162 colorstop->color.save( stop );
163 stop.setAttribute( "ramppoint", colorstop->rampPoint );
164 stop.setAttribute( "midpoint", colorstop->midPoint );
165 me.appendChild( stop );
166 }
167
168 element.appendChild( me );
169}
170
171TQString
172VGradient::saveOasis( KoGenStyles &mainStyles ) const
173{
174 bool radial = m_type == VGradient::radial;
175 KoGenStyle gradientStyle( radial ? VDocument::STYLE_RADIAL_GRADIENT : VDocument::STYLE_LINEAR_GRADIENT /*no family name*/);
176 if( radial )
177 {
178 gradientStyle.addAttribute( "draw:style", "radial" );
179 gradientStyle.addAttributePt( "svg:cx", m_origin.x() );
180 gradientStyle.addAttributePt( "svg:cy", m_origin.y() );
181 double dx = m_vector.x() - m_origin.x();
182 double dy = m_vector.y() - m_origin.y();
183 gradientStyle.addAttributePt( "svg:r", sqrt( dx * dx + dy * dy ) );
184 gradientStyle.addAttributePt( "svg:fx", m_focalPoint.x() );
185 gradientStyle.addAttributePt( "svg:fy", m_focalPoint.y() );
186 }
187 else
188 {
189 gradientStyle.addAttribute( "draw:style", "linear" );
190 gradientStyle.addAttributePt( "svg:x1", m_origin.x() );
191 gradientStyle.addAttributePt( "svg:y1", m_origin.y() );
192 gradientStyle.addAttributePt( "svg:x2", m_vector.x() );
193 gradientStyle.addAttributePt( "svg:y2", m_vector.y() );
194 }
195 if( m_repeatMethod == VGradient::repeat )
196 gradientStyle.addAttribute( "svg:spreadMethod", "repeat" );
197 else if( m_repeatMethod == VGradient::reflect )
198 gradientStyle.addAttribute( "svg:spreadMethod", "reflect" );
199 else
200 gradientStyle.addAttribute( "svg:spreadMethod", "pad" );
201 TQBuffer buffer;
202 buffer.open( IO_WriteOnly );
203 KoXmlWriter elementWriter( &buffer ); // TODO pass indentation level
204
205 // save stops
206 VColorStop* colorstop;
207 TQPtrList<VColorStop>& colorStops = const_cast<VColorStopList&>( m_colorStops );
208 for( colorstop = colorStops.first(); colorstop; colorstop = colorStops.next() )
209 {
210 elementWriter.startElement( "svg:stop" );
211 elementWriter.addAttribute( "svg:offset", TQString( "%1" ).arg( colorstop->rampPoint ) );
212 elementWriter.addAttribute( "svg:color", TQColor( colorstop->color ).name() );
213 if( colorstop->color.opacity() < 1 )
214 elementWriter.addAttribute( "svg:stop-opacity", TQString( "%1" ).arg( colorstop->color.opacity() ) );
215 elementWriter.endElement();
216 }
217
218 TQString elementContents = TQString::fromUtf8( buffer.buffer(), buffer.buffer().size() );
219 gradientStyle.addChildElement( "svg:stop", elementContents );
220 return mainStyles.lookup( gradientStyle, "gradient" );
221}
222
223void
224VGradient::loadOasis( const TQDomElement &object, KoStyleStack &/*stack*/, VObject* parent )
225{
226 kdDebug(38000) << "namespaceURI: " << object.namespaceURI() << endl;
227 kdDebug(38000) << "localName: " << object.localName() << endl;
228
229 KoRect bb;
230
231 if( parent )
232 bb = parent->boundingBox();
233
234 if( object.namespaceURI() == KoXmlNS::draw && object.localName() == "gradient" )
235 {
236 m_repeatMethod = VGradient::reflect;
237 TQString strType = object.attributeNS( KoXmlNS::draw, "style", TQString() );
238 if( strType == "radial" )
239 {
240 m_type = VGradient::radial;
241 // TODO : find out whether Oasis works with boundingBox only?
242 double cx = KoUnit::parseValue( object.attributeNS( KoXmlNS::draw, "cx", TQString() ).remove("%") );
243 m_origin.setX( bb.bottomLeft().x() + bb.width() * 0.01 * cx );
244 double cy = KoUnit::parseValue( object.attributeNS( KoXmlNS::draw, "cy", TQString() ).remove("%") );
245 m_origin.setY( bb.bottomLeft().y() - bb.height() * 0.01 * cy );
246 m_focalPoint = m_origin;
247 m_vector = bb.topRight();
248 }
249 else if( strType == "linear" )
250 {
251 m_type = VGradient::linear;
252 double angle = 90 + object.attributeNS( KoXmlNS::draw, "angle", "0" ).toDouble();
253 double radius = 0.5 * sqrt( bb.width()*bb.width() + bb.height()*bb.height() );
254 double sx = cos( angle * VGlobal::pi / 180 ) * radius;
255 double sy = sin( angle * VGlobal::pi / 180 ) * radius;
256 m_origin.setX( bb.center().x() + sx );
257 m_origin.setY( bb.center().y() + sy );
258 m_vector.setX( bb.center().x() - sx );
259 m_vector.setY( bb.center().y() - sy );
260 m_focalPoint = m_origin;
261 }
262 else return;
263
264 VColor startColor( TQColor( object.attributeNS( KoXmlNS::draw, "start-color", TQString() ) ) );
265 VColor endColor( TQColor( object.attributeNS( KoXmlNS::draw, "end-color", TQString() ) ) );
266
267 double startOpacity = 0.01 * object.attributeNS( KoXmlNS::draw, "start-intensity", "100" ).remove("%").toDouble();
268 double endOpacity = 0.01 * object.attributeNS( KoXmlNS::draw, "end-intensity", "100" ).remove("%").toDouble();
269
270 startColor.setOpacity( startOpacity );
271 endColor.setOpacity( endOpacity );
272 m_colorStops.clear();
273 addStop( startColor, 0.0, 0.5 );
274 addStop( endColor, 1.0, 0.0 );
275 m_colorStops.sort();
276
277 }
278 else if( object.namespaceURI() == KoXmlNS::svg )
279 {
280 if( object.localName() == "linearGradient" )
281 {
282 m_type = VGradient::linear;
283 m_origin.setX( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "x1", TQString() ) ) );
284 m_origin.setY( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "y1", TQString() ) ) );
285 m_vector.setX( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "x2", TQString() ) ) );
286 m_vector.setY( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "y2", TQString() ) ) );
287 m_focalPoint = m_origin;
288 }
289 else if( object.localName() == "radialGradient" )
290 {
291 m_type = VGradient::radial;
292 m_origin.setX( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "cx", TQString() ) ) );
293 m_origin.setY( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "cy", TQString() ) ) );
294 double r = KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "r", TQString() ) );
295 m_vector.setX( m_origin.x() + r );
296 m_vector.setY( m_origin.y() );
297 m_focalPoint.setX( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "fx", TQString() ) ) );
298 m_focalPoint.setY( KoUnit::parseValue( object.attributeNS( KoXmlNS::svg, "fy", TQString() ) ) );
299 }
300
301 TQString strSpread( object.attributeNS( KoXmlNS::svg, "spreadMethod", "pad" ) );
302 if( strSpread == "repeat" )
303 m_repeatMethod = VGradient::repeat;
304 else if( strSpread == "reflect" )
305 m_repeatMethod = VGradient::reflect;
306 else
307 m_repeatMethod = VGradient::none;
308
309 m_colorStops.clear();
310
311 // load stops
312 TQDomNodeList list = object.childNodes();
313 for( uint i = 0; i < list.count(); ++i )
314 {
315 if( list.item( i ).isElement() )
316 {
317 TQDomElement colorstop = list.item( i ).toElement();
318
319 if( colorstop.namespaceURI() == KoXmlNS::svg && colorstop.localName() == "stop" )
320 {
321 VColor color( TQColor( colorstop.attributeNS( KoXmlNS::svg, "color", TQString() ) ) );
322 color.setOpacity( colorstop.attributeNS( KoXmlNS::svg, "stop-opacity", "1.0" ).toDouble() );
323 addStop( color, colorstop.attributeNS( KoXmlNS::svg, "offset", "0.0" ).toDouble(), 0.5 );
324 }
325 }
326 }
327 m_colorStops.sort();
328 }
329}
330
331void
332VGradient::load( const TQDomElement& element )
333{
334 m_origin.setX( element.attribute( "originX", "0.0" ).toDouble() );
335 m_origin.setY( element.attribute( "originY", "0.0" ).toDouble() );
336 m_focalPoint.setX( element.attribute( "focalX", "0.0" ).toDouble() );
337 m_focalPoint.setY( element.attribute( "focalY", "0.0" ).toDouble() );
338 m_vector.setX( element.attribute( "vectorX", "0.0" ).toDouble() );
339 m_vector.setY( element.attribute( "vectorY", "0.0" ).toDouble() );
340 m_type = (VGradientType)element.attribute( "type", 0 ).toInt();
341 m_repeatMethod = (VGradientRepeatMethod)element.attribute( "repeatMethod", 0 ).toInt();
342
343 m_colorStops.clear();
344
345 // load stops
346 TQDomNodeList list = element.childNodes();
347 for( uint i = 0; i < list.count(); ++i )
348 {
349 if( list.item( i ).isElement() )
350 {
351 TQDomElement colorstop = list.item( i ).toElement();
352
353 if( colorstop.tagName() == "COLORSTOP" )
354 {
355 VColor color;
356 color.load( colorstop.firstChild().toElement() );
357 addStop( color, colorstop.attribute( "ramppoint", "0.0" ).toDouble(), colorstop.attribute( "midpoint", "0.5" ).toDouble() );
358 }
359 }
360 }
361 m_colorStops.sort();
362}
363
364void
365VGradient::transform( const TQWMatrix &m )
366{
367 m_origin = m_origin.transform( m );
368 m_focalPoint = m_focalPoint.transform( m );
369 m_vector = m_vector.transform( m );
370}
This class keeps track of color properties.
Definition vcolor.h:41
void set(float v1)
Sets the first color component.
Definition vcolor.h:91
void setOpacity(float opacity)
Sets the color opacity.
Definition vcolor.h:138
void load(const TQDomElement &element)
Load this color's state from xml and initialize it accordingly.
Definition vcolor.cpp:321
float opacity() const
Returns the color opacity.
Definition vcolor.h:131
void save(TQDomElement &element) const
Save this color's state to xml.
Definition vcolor.cpp:297
The base class for all karbon objects.
Definition vobject.h:50
virtual const KoRect & boundingBox() const
Calculates the tightest bounding box around the object.
Definition vobject.h:111