lib

KoBorder.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2000, 2001 Thomas Zander <zander@kde.org>
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 "KoBorder.h"
21#include <tqdom.h>
22#include <kdebug.h>
23#include "KoZoomHandler.h"
24#include "KoTextFormat.h"
25#include "KoRichText.h" // for KoTextFormat
26#include "KoTextParag.h"
27#include <float.h>
28
29static const struct BorderStyle {
30 TQt::PenStyle penStyle;
31 TQCString oasisName;
32 TQCString uiStringStyle;
33} s_borderStyles[] = {
34 { TQt::SolidLine, "solid", "_________" }, // SOLID
35 { TQt::DashLine, "dashed", "___ ___ __" }, // DASH
36 { TQt::DotLine, "dotted", "_ _ _ _ _ _" }, // DOT
37 { TQt::DashDotLine, "dot-dash", "___ _ ___ _" }, // DASH_DOT
38 { TQt::DashDotDotLine, "dot-dot-dash", "___ _ _ ___" }, // DASH_DOT_DOT
39 { TQt::SolidLine, "double", "===========" } // DOUBLE_LINE
40};
41
42KoBorder::KoBorder()
43 : color(), m_style( SOLID )
44{
45 setPenWidth( 1 );
46}
47
48KoBorder::KoBorder( const TQColor & c, BorderStyle s, double width )
49 : color( c ), m_style( s )
50{
51 setPenWidth( width );
52}
53
54bool KoBorder::operator==( const KoBorder _brd ) const {
55 return ( m_style == _brd.m_style && color == _brd.color && ptPenWidth == _brd.ptPenWidth );
56}
57
58bool KoBorder::operator!=( const KoBorder _brd ) const {
59 return ( m_style != _brd.m_style || color != _brd.color || ptPenWidth != _brd.ptPenWidth );
60}
61
62void KoBorder::setStyle(BorderStyle _style)
63{
64 m_style = _style;
65 setPenWidth( ptPenWidth );
66}
67
68void KoBorder::setPenWidth(double _w)
69{
70 ptPenWidth = _w;
71 if ( m_style == KoBorder::DOUBLE_LINE && _w > 0 )
72 ptWidth = 2 * ptPenWidth + 1;
73 else
74 ptWidth = _w;
75}
76
77TQPen KoBorder::borderPen( const KoBorder & _brd, int width, TQColor defaultColor )
78{
79 TQPen pen( _brd.color, width );
80 if ( !_brd.color.isValid() )
81 pen.setColor( defaultColor );
82
83 pen.setStyle( s_borderStyles[ _brd.m_style ].penStyle );
84
85 return pen;
86}
87
88// KOffice-1.3 file format (deprecated)
89KoBorder KoBorder::loadBorder( const TQDomElement & elem )
90{
91 KoBorder bd;
92 if ( elem.hasAttribute("red") )
93 {
94 int r = elem.attribute("red").toInt();
95 int g = elem.attribute("green").toInt();
96 int b = elem.attribute("blue").toInt();
97 bd.color.setRgb( r, g, b );
98 }
99 bd.m_style = static_cast<BorderStyle>( elem.attribute("style").toInt() );
100 bd.setPenWidth( elem.attribute("width").toDouble() );
101 return bd;
102}
103
104void KoBorder::loadFoBorder( const TQString& border )
105{
106 //string like "0.088cm solid #800000"
107
108 if (border.isEmpty() || border=="none" || border=="hidden") { // in fact no border
109 setPenWidth( 0 );
110 return;
111 }
112
113 // ## isn't it faster to use TQStringList::split than parse it 3 times?
114 TQString _width = border.section(' ', 0, 0);
115 TQCString _style = border.section(' ', 1, 1).latin1();
116 TQString _color = border.section(' ', 2, 2);
117
118 //TODO: let the user choose a more precise border width (in the current unit)
119 double const penWidth = KoUnit::parseValue( _width, 1.0 );
120 //kdDebug() << "penWidth:" << penWidth << endl;
121 if ( penWidth < 1.5 )
122 setPenWidth( 1.0 );
123 else if ( penWidth < 2.5 )
124 setPenWidth( 2.0 );
125 else if ( penWidth < 3.5 )
126 setPenWidth( 3.0 );
127 else if ( penWidth < 4.5 )
128 setPenWidth( 4.0 );
129 else if ( penWidth < 5.5 )
130 setPenWidth( 5.0 );
131 else if ( penWidth < 6.5 )
132 setPenWidth( 6.0 );
133 else if ( penWidth < 7.5 )
134 setPenWidth( 7.0 );
135 else if ( penWidth < 8.5 )
136 setPenWidth( 8.0 );
137 else if ( penWidth < 9.5 )
138 setPenWidth( 9.0 );
139 else
140 setPenWidth( 10.0 );
141
142 m_style = SOLID;
143 for ( uint i = 0; i < sizeof( s_borderStyles ) / sizeof *s_borderStyles; ++i ) {
144 if ( _style == s_borderStyles[i].oasisName )
145 m_style = static_cast<BorderStyle>( i );
146 }
147
148 if ( _color.isEmpty() )
149 color = TQColor();
150 else
151 color.setNamedColor( _color );
152}
153
154TQString KoBorder::saveFoBorder() const
155{
156 if ( TQABS( ptPenWidth ) < 1E-10 ) // i.e. ptPenWidth == 0
157 return "none";
158 //string like "2pt solid #800000"
159 TQString str = TQString::number( ptPenWidth, 'g', DBL_DIG );
160 str += "pt ";
161 str += s_borderStyles[ m_style ].oasisName;
162 if ( color.isValid() ) {
163 str += ' ';
164 str += color.name();
165 }
166 return str;
167}
168
169// KOffice-1.3 file format (deprecated)
170void KoBorder::save( TQDomElement & elem ) const
171{
172 if (color.isValid()) {
173 elem.setAttribute("red", color.red());
174 elem.setAttribute("green", color.green());
175 elem.setAttribute("blue", color.blue());
176 }
177 elem.setAttribute("style", static_cast<int>( m_style ));
178 elem.setAttribute("width", ptPenWidth);
179}
180
181KoBorder::BorderStyle KoBorder::getStyle( const TQString &style )
182{
183 for ( uint i = 0; i < sizeof( s_borderStyles ) / sizeof *s_borderStyles; ++i ) {
184 if ( style == s_borderStyles[i].uiStringStyle.data() )
185 return static_cast<BorderStyle>( i );
186 }
187 // default
188 return KoBorder::SOLID;
189}
190
191TQString KoBorder::getStyle( const BorderStyle &style )
192{
193 return s_borderStyles[style].uiStringStyle;
194}
195
196int KoBorder::zoomWidthX( double ptWidth, KoZoomHandler * zoomHandler, int minborder )
197{
198 // If a border was set, then zoom it and apply a minimum of 1, so that it's always visible.
199 // If no border was set, apply minborder ( 0 for paragraphs, 1 for frames )
200 return ptWidth > 0 ? TQMAX( 1, zoomHandler->zoomItX( ptWidth ) /*applies tqRound*/ ) : minborder;
201}
202
203int KoBorder::zoomWidthY( double ptWidth, KoZoomHandler * zoomHandler, int minborder )
204{
205 // If a border was set, then zoom it and apply a minimum of 1, so that it's always visible.
206 // If no border was set, apply minborder ( 0 for paragraphs, 1 for frames )
207 return ptWidth > 0 ? TQMAX( 1, zoomHandler->zoomItY( ptWidth ) /*applies tqRound*/ ) : minborder;
208}
209
210void KoBorder::drawBorders( TQPainter& painter, KoZoomHandler * zoomHandler, const TQRect& rect, const KoBorder& leftBorder, const KoBorder& rightBorder, const KoBorder& topBorder, const KoBorder& bottomBorder, int minborder, const TQPen& defaultPen, bool drawTopBorder /* = true */, bool drawBottomBorder /* = true */)
211{
212 int topBorderWidth = zoomWidthY( topBorder.width(), zoomHandler, minborder );
213 int bottomBorderWidth = zoomWidthY( bottomBorder.width(), zoomHandler, minborder );
214 int leftBorderWidth = zoomWidthX( leftBorder.width(), zoomHandler, minborder );
215 int rightBorderWidth = zoomWidthX( rightBorder.width(), zoomHandler, minborder );
216
217 int topBorderPenWidth = zoomWidthY( topBorder.penWidth(), zoomHandler, minborder );
218 int bottomBorderPenWidth = zoomWidthY( bottomBorder.penWidth(), zoomHandler, minborder );
219 int leftBorderPenWidth = zoomWidthX( leftBorder.penWidth(), zoomHandler, minborder );
220 int rightBorderPenWidth = zoomWidthX( rightBorder.penWidth(), zoomHandler, minborder );
221
222 // Wide pen don't draw the last pixel, so add one to the bottom and right coords
223 int lastPixelAdj = 1;
224
225 //kdDebug(32500) << "KoBorder::drawBorders widths: top=" << topBorderWidth << " bottom=" << bottomBorderWidth
226 // << " left=" << leftBorderWidth << " right=" << rightBorderWidth << endl;
227
228 //kdDebug(32500) << " penWidths: top=" << topBorderPenWidth << " bottom=" << bottomBorderPenWidth
229 // << " left=" << leftBorderPenWidth << " right=" << rightBorderPenWidth << endl;
230
231 TQColor defaultColor = KoTextFormat::defaultTextColor( &painter );
232
233 if ( topBorderWidth > 0 && drawTopBorder )
234 {
235 if ( topBorder.penWidth() > 0 )
236 painter.setPen( KoBorder::borderPen( topBorder, topBorderPenWidth, defaultColor ) );
237 else
238 painter.setPen( defaultPen );
239 int y = rect.top() - topBorderWidth + topBorderPenWidth/2;
240 if ( topBorder.m_style==KoBorder::DOUBLE_LINE)
241 {
242 painter.drawLine( rect.left()-leftBorderWidth, y, rect.right()+2*(rightBorderPenWidth+lastPixelAdj), y );
243 y += topBorderPenWidth + 1;
244 painter.drawLine( rect.left()-leftBorderPenWidth, y, rect.right()+rightBorderPenWidth+lastPixelAdj, y );
245 }
246 else
247 {
248 painter.drawLine( rect.left()-leftBorderWidth, y, rect.right()+rightBorderWidth+lastPixelAdj, y );
249 }
250 }
251 if ( bottomBorderWidth > 0 && drawBottomBorder )
252 {
253 if ( bottomBorder.penWidth() > 0 )
254 painter.setPen( KoBorder::borderPen( bottomBorder, bottomBorderPenWidth, defaultColor ) );
255 else
256 painter.setPen( defaultPen );
257 //kdDebug(32500) << "bottomBorderWidth=" << bottomBorderWidth << " bottomBorderWidth/2=" << (int)bottomBorderWidth/2 << endl;
258 int y = rect.bottom() + bottomBorderPenWidth/2 + 1;
259 //kdDebug(32500) << " -> bottom=" << rect.bottom() << " y=" << y << endl;
260 if ( bottomBorder.m_style==KoBorder::DOUBLE_LINE)
261 {
262 painter.drawLine( rect.left()-leftBorderPenWidth, y, rect.right()+rightBorderPenWidth+lastPixelAdj, y );
263 y += bottomBorderPenWidth + 1;
264 painter.drawLine( rect.left()-leftBorderWidth, y, rect.right()+2*(rightBorderPenWidth+lastPixelAdj), y );
265 }
266 else
267 {
268 painter.drawLine( rect.left()-leftBorderWidth, y, rect.right()+rightBorderWidth+lastPixelAdj, y );
269 }
270 }
271 if ( leftBorderWidth > 0 )
272 {
273 if ( leftBorder.penWidth() > 0 )
274 painter.setPen( KoBorder::borderPen( leftBorder, leftBorderPenWidth, defaultColor ) );
275 else
276 painter.setPen( defaultPen );
277 int x = rect.left() - leftBorderWidth + leftBorderPenWidth/2;
278 if ( leftBorder.m_style==KoBorder::DOUBLE_LINE)
279 {
280 painter.drawLine( x, rect.top()-topBorderWidth, x, rect.bottom()+2*(bottomBorderPenWidth+lastPixelAdj) );
281 x += leftBorderPenWidth + 1;
282 painter.drawLine( x, rect.top()-topBorderPenWidth, x, rect.bottom()+bottomBorderPenWidth+lastPixelAdj );
283 }
284 else
285 {
286 int yTop = rect.top() - topBorderWidth;
287 int yBottom = rect.bottom() + bottomBorderWidth;
288 /*kdDebug(32500) << " pen=" << painter.pen() << " rect=" << rect << " topBorderWidth=" << topBorderWidth
289 << " painting from " << x << "," << yTop
290 << " to " << x << "," << yBottom << endl;*/
291 painter.drawLine( x, yTop, x, yBottom+lastPixelAdj );
292 }
293 }
294 if ( rightBorderWidth > 0 )
295 {
296 if ( rightBorder.penWidth() > 0 )
297 painter.setPen( KoBorder::borderPen( rightBorder, rightBorderPenWidth, defaultColor ) );
298 else
299 painter.setPen( defaultPen );
300 int x = rect.right() + rightBorderPenWidth/2 + 1;
301 if ( rightBorder.m_style==KoBorder::DOUBLE_LINE)
302 {
303 painter.drawLine( x, rect.top()-topBorderPenWidth, x, rect.bottom()+bottomBorderPenWidth+lastPixelAdj );
304 x += rightBorderPenWidth + 1;
305 painter.drawLine( x, rect.top()-topBorderWidth, x, rect.bottom()+2*(bottomBorderPenWidth+lastPixelAdj) );
306
307 }
308 else
309 {
310 int yTop = rect.top()-topBorderWidth;
311 int yBottom = rect.bottom()+bottomBorderWidth+lastPixelAdj;
312 /*kdDebug(32500) << " pen=" << painter.pen() << " rect=" << rect << " topBorderWidth=" << topBorderWidth
313 << " painting from " << x << "," << yTop
314 << " to " << x << "," << yBottom << endl;*/
315 painter.drawLine( x, yTop, x, yBottom );
316 }
317 }
318}
This class represents a border - for anything, like paragraph, or frame.
Definition KoBorder.h:34
static TQColor defaultTextColor(TQPainter *painter)
Call this when a text color is set to 'invalid', meaning 'whatever the default for the color scheme i...
static double parseValue(TQString value, double defaultVal=0.0)
parse common KOffice and OO values, like "10cm", "5mm" to pt
Definition KoUnit.cpp:148
This class handles the zooming and DPI stuff (conversions between pt values and pixels).