lib

KoBorder.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2000, 2001 Thomas Zander <zander@kde.org>
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 "KoBorder.h"
00021 #include <qdom.h>
00022 #include <kdebug.h>
00023 #include "KoZoomHandler.h"
00024 #include "KoTextFormat.h"
00025 #include "KoRichText.h" // for KoTextFormat
00026 #include "KoTextParag.h"
00027 #include <float.h>
00028 
00029 static const struct BorderStyle {
00030     QPen::PenStyle penStyle;
00031     QCString oasisName;
00032     QCString uiStringStyle;
00033 } s_borderStyles[] = {
00034     { QPen::SolidLine, "solid", "_________" }, // SOLID
00035     { QPen::DashLine, "dashed", "___ ___ __" }, // DASH
00036     { QPen::DotLine, "dotted", "_ _ _ _ _ _" }, // DOT
00037     { QPen::DashDotLine, "dot-dash", "___ _ ___ _" }, // DASH_DOT
00038     { QPen::DashDotDotLine, "dot-dot-dash", "___ _ _ ___" }, // DASH_DOT_DOT
00039     { QPen::SolidLine, "double", "===========" } // DOUBLE_LINE
00040 };
00041 
00042 KoBorder::KoBorder()
00043     : color(), m_style( SOLID )
00044 {
00045     setPenWidth( 1 );
00046 }
00047 
00048 KoBorder::KoBorder( const QColor & c, BorderStyle s, double width )
00049     : color( c ), m_style( s )
00050 {
00051     setPenWidth( width );
00052 }
00053 
00054 bool KoBorder::operator==( const KoBorder _brd ) const {
00055     return ( m_style == _brd.m_style && color == _brd.color && ptPenWidth == _brd.ptPenWidth );
00056 }
00057 
00058 bool KoBorder::operator!=( const KoBorder _brd ) const {
00059     return ( m_style != _brd.m_style || color != _brd.color || ptPenWidth != _brd.ptPenWidth );
00060 }
00061 
00062 void KoBorder::setStyle(BorderStyle _style)
00063 {
00064     m_style = _style;
00065     setPenWidth( ptPenWidth );
00066 }
00067 
00068 void KoBorder::setPenWidth(double _w)
00069 {
00070     ptPenWidth = _w;
00071     if ( m_style == KoBorder::DOUBLE_LINE && _w > 0 )
00072         ptWidth = 2 * ptPenWidth + 1;
00073     else
00074         ptWidth = _w;
00075 }
00076 
00077 QPen KoBorder::borderPen( const KoBorder & _brd, int width, QColor defaultColor )
00078 {
00079     QPen pen( _brd.color, width );
00080     if ( !_brd.color.isValid() )
00081         pen.setColor( defaultColor );
00082 
00083     pen.setStyle( s_borderStyles[ _brd.m_style ].penStyle );
00084 
00085     return pen;
00086 }
00087 
00088 // KOffice-1.3 file format (deprecated)
00089 KoBorder KoBorder::loadBorder( const QDomElement & elem )
00090 {
00091     KoBorder bd;
00092     if ( elem.hasAttribute("red") )
00093     {
00094         int r = elem.attribute("red").toInt();
00095         int g = elem.attribute("green").toInt();
00096         int b = elem.attribute("blue").toInt();
00097         bd.color.setRgb( r, g, b );
00098     }
00099     bd.m_style = static_cast<BorderStyle>( elem.attribute("style").toInt() );
00100     bd.setPenWidth( elem.attribute("width").toDouble() );
00101     return bd;
00102 }
00103 
00104 void KoBorder::loadFoBorder( const QString& border )
00105 {
00106     //string like "0.088cm solid #800000"
00107 
00108     if (border.isEmpty() || border=="none" || border=="hidden") { // in fact no border
00109         setPenWidth( 0 );
00110         return;
00111     }
00112 
00113     // ## isn't it faster to use QStringList::split than parse it 3 times?
00114     QString _width = border.section(' ', 0, 0);
00115     QCString _style = border.section(' ', 1, 1).latin1();
00116     QString _color = border.section(' ', 2, 2);
00117 
00118     //TODO: let the user choose a more precise border width (in the current unit)
00119     double const penWidth = KoUnit::parseValue( _width, 1.0 );
00120     //kdDebug() << "penWidth:" << penWidth << endl;
00121     if ( penWidth < 1.5 )
00122         setPenWidth( 1.0 );
00123     else if ( penWidth < 2.5 )
00124         setPenWidth( 2.0 );
00125     else if ( penWidth < 3.5 )
00126         setPenWidth( 3.0 );
00127     else if ( penWidth < 4.5 )
00128         setPenWidth( 4.0 );
00129     else if ( penWidth < 5.5 )
00130         setPenWidth( 5.0 );
00131     else if ( penWidth < 6.5 )
00132         setPenWidth( 6.0 );
00133     else if ( penWidth < 7.5 )
00134         setPenWidth( 7.0 );
00135     else if ( penWidth < 8.5 )
00136         setPenWidth( 8.0 );
00137     else if ( penWidth < 9.5 )
00138         setPenWidth( 9.0 );
00139     else
00140         setPenWidth( 10.0 );
00141 
00142     m_style = SOLID;
00143     for ( uint i = 0; i < sizeof( s_borderStyles ) / sizeof *s_borderStyles; ++i ) {
00144         if ( _style == s_borderStyles[i].oasisName )
00145             m_style = static_cast<BorderStyle>( i );
00146     }
00147 
00148     if ( _color.isEmpty() )
00149         color = QColor();
00150     else
00151         color.setNamedColor( _color );
00152 }
00153 
00154 QString KoBorder::saveFoBorder() const
00155 {
00156     if ( QABS( ptPenWidth ) < 1E-10 ) // i.e. ptPenWidth == 0
00157         return "none";
00158     //string like "2pt solid #800000"
00159     QString str = QString::number( ptPenWidth, 'g', DBL_DIG );
00160     str += "pt ";
00161     str += s_borderStyles[ m_style ].oasisName;
00162     if ( color.isValid() ) {
00163         str += ' ';
00164         str += color.name();
00165     }
00166     return str;
00167 }
00168 
00169 // KOffice-1.3 file format (deprecated)
00170 void KoBorder::save( QDomElement & elem ) const
00171 {
00172     if (color.isValid()) {
00173         elem.setAttribute("red", color.red());
00174         elem.setAttribute("green", color.green());
00175         elem.setAttribute("blue", color.blue());
00176     }
00177     elem.setAttribute("style", static_cast<int>( m_style ));
00178     elem.setAttribute("width", ptPenWidth);
00179 }
00180 
00181 KoBorder::BorderStyle KoBorder::getStyle( const QString &style )
00182 {
00183     for ( uint i = 0; i < sizeof( s_borderStyles ) / sizeof *s_borderStyles; ++i ) {
00184         if ( style == s_borderStyles[i].uiStringStyle.data() )
00185             return static_cast<BorderStyle>( i );
00186     }
00187     // default
00188     return KoBorder::SOLID;
00189 }
00190 
00191 QString KoBorder::getStyle( const BorderStyle &style )
00192 {
00193     return s_borderStyles[style].uiStringStyle;
00194 }
00195 
00196 int KoBorder::zoomWidthX( double ptWidth, KoZoomHandler * zoomHandler, int minborder )
00197 {
00198     // If a border was set, then zoom it and apply a minimum of 1, so that it's always visible.
00199     // If no border was set, apply minborder ( 0 for paragraphs, 1 for frames )
00200     return ptWidth > 0 ? QMAX( 1, zoomHandler->zoomItX( ptWidth ) /*applies qRound*/ ) : minborder;
00201 }
00202 
00203 int KoBorder::zoomWidthY( double ptWidth, KoZoomHandler * zoomHandler, int minborder )
00204 {
00205     // If a border was set, then zoom it and apply a minimum of 1, so that it's always visible.
00206     // If no border was set, apply minborder ( 0 for paragraphs, 1 for frames )
00207     return ptWidth > 0 ? QMAX( 1, zoomHandler->zoomItY( ptWidth ) /*applies qRound*/ ) : minborder;
00208 }
00209 
00210 void KoBorder::drawBorders( QPainter& painter, KoZoomHandler * zoomHandler, const QRect& rect, const KoBorder& leftBorder, const KoBorder& rightBorder, const KoBorder& topBorder, const KoBorder& bottomBorder, int minborder, const QPen& defaultPen, bool drawTopBorder /* = true */, bool drawBottomBorder /* = true */)
00211 {
00212     int topBorderWidth = zoomWidthY( topBorder.width(), zoomHandler, minborder );
00213     int bottomBorderWidth = zoomWidthY( bottomBorder.width(), zoomHandler, minborder );
00214     int leftBorderWidth = zoomWidthX( leftBorder.width(), zoomHandler, minborder );
00215     int rightBorderWidth = zoomWidthX( rightBorder.width(), zoomHandler, minborder );
00216 
00217     int topBorderPenWidth = zoomWidthY( topBorder.penWidth(), zoomHandler, minborder );
00218     int bottomBorderPenWidth = zoomWidthY( bottomBorder.penWidth(), zoomHandler, minborder );
00219     int leftBorderPenWidth = zoomWidthX( leftBorder.penWidth(), zoomHandler, minborder );
00220     int rightBorderPenWidth = zoomWidthX( rightBorder.penWidth(), zoomHandler, minborder );
00221 
00222     // Wide pen don't draw the last pixel, so add one to the bottom and right coords
00223     int lastPixelAdj = 1;
00224 
00225     //kdDebug(32500) << "KoBorder::drawBorders widths: top=" << topBorderWidth << " bottom=" << bottomBorderWidth
00226     //               << " left=" << leftBorderWidth << " right=" << rightBorderWidth << endl;
00227 
00228     //kdDebug(32500) << "                   penWidths: top=" << topBorderPenWidth << " bottom=" << bottomBorderPenWidth
00229     //               << " left=" << leftBorderPenWidth << " right=" << rightBorderPenWidth << endl;
00230 
00231     QColor defaultColor = KoTextFormat::defaultTextColor( &painter );
00232 
00233     if ( topBorderWidth > 0 && drawTopBorder )
00234     {
00235         if ( topBorder.penWidth() > 0 )
00236             painter.setPen( KoBorder::borderPen( topBorder, topBorderPenWidth, defaultColor ) );
00237         else
00238             painter.setPen( defaultPen );
00239         int y = rect.top() - topBorderWidth + topBorderPenWidth/2;
00240         if ( topBorder.m_style==KoBorder::DOUBLE_LINE)
00241         {
00242             painter.drawLine( rect.left()-leftBorderWidth, y, rect.right()+2*(rightBorderPenWidth+lastPixelAdj), y );
00243             y += topBorderPenWidth + 1;
00244             painter.drawLine( rect.left()-leftBorderPenWidth, y, rect.right()+rightBorderPenWidth+lastPixelAdj, y );
00245         }
00246         else
00247         {
00248             painter.drawLine( rect.left()-leftBorderWidth, y, rect.right()+rightBorderWidth+lastPixelAdj, y );
00249         }
00250     }
00251     if ( bottomBorderWidth > 0 && drawBottomBorder )
00252     {
00253         if ( bottomBorder.penWidth() > 0 )
00254             painter.setPen( KoBorder::borderPen( bottomBorder, bottomBorderPenWidth, defaultColor ) );
00255         else
00256             painter.setPen( defaultPen );
00257     //kdDebug(32500) << "bottomBorderWidth=" << bottomBorderWidth << " bottomBorderWidth/2=" << (int)bottomBorderWidth/2 << endl;
00258         int y = rect.bottom() + bottomBorderPenWidth/2 + 1;
00259     //kdDebug(32500) << "   -> bottom=" << rect.bottom() << " y=" << y << endl;
00260         if ( bottomBorder.m_style==KoBorder::DOUBLE_LINE)
00261         {
00262             painter.drawLine( rect.left()-leftBorderPenWidth, y, rect.right()+rightBorderPenWidth+lastPixelAdj, y );
00263             y += bottomBorderPenWidth + 1;
00264             painter.drawLine( rect.left()-leftBorderWidth, y, rect.right()+2*(rightBorderPenWidth+lastPixelAdj), y );
00265         }
00266         else
00267         {
00268             painter.drawLine( rect.left()-leftBorderWidth, y, rect.right()+rightBorderWidth+lastPixelAdj, y );
00269         }
00270     }
00271     if ( leftBorderWidth > 0 )
00272     {
00273         if ( leftBorder.penWidth() > 0 )
00274             painter.setPen( KoBorder::borderPen( leftBorder, leftBorderPenWidth, defaultColor ) );
00275         else
00276             painter.setPen( defaultPen );
00277         int x = rect.left() - leftBorderWidth + leftBorderPenWidth/2;
00278         if ( leftBorder.m_style==KoBorder::DOUBLE_LINE)
00279         {
00280             painter.drawLine( x, rect.top()-topBorderWidth, x, rect.bottom()+2*(bottomBorderPenWidth+lastPixelAdj) );
00281             x += leftBorderPenWidth + 1;
00282             painter.drawLine( x, rect.top()-topBorderPenWidth, x, rect.bottom()+bottomBorderPenWidth+lastPixelAdj );
00283         }
00284         else
00285         {
00286             int yTop = rect.top() - topBorderWidth;
00287             int yBottom = rect.bottom() + bottomBorderWidth;
00288             /*kdDebug(32500) << " pen=" << painter.pen() << " rect=" << rect << " topBorderWidth=" << topBorderWidth
00289                            << " painting from " << x << "," << yTop
00290                            << " to " << x << "," << yBottom << endl;*/
00291             painter.drawLine( x, yTop, x, yBottom+lastPixelAdj );
00292         }
00293     }
00294     if ( rightBorderWidth > 0 )
00295     {
00296         if ( rightBorder.penWidth() > 0 )
00297             painter.setPen( KoBorder::borderPen( rightBorder, rightBorderPenWidth, defaultColor ) );
00298         else
00299             painter.setPen( defaultPen );
00300         int x = rect.right() + rightBorderPenWidth/2 + 1;
00301         if ( rightBorder.m_style==KoBorder::DOUBLE_LINE)
00302         {
00303             painter.drawLine( x, rect.top()-topBorderPenWidth, x, rect.bottom()+bottomBorderPenWidth+lastPixelAdj );
00304             x += rightBorderPenWidth + 1;
00305             painter.drawLine( x, rect.top()-topBorderWidth, x, rect.bottom()+2*(bottomBorderPenWidth+lastPixelAdj) );
00306 
00307         }
00308         else
00309         {
00310             int yTop = rect.top()-topBorderWidth;
00311             int yBottom = rect.bottom()+bottomBorderWidth+lastPixelAdj;
00312             /*kdDebug(32500) << " pen=" << painter.pen() << " rect=" << rect << " topBorderWidth=" << topBorderWidth
00313                            << " painting from " << x << "," << yTop
00314                            << " to " << x << "," << yBottom << endl;*/
00315             painter.drawLine( x, yTop, x, yBottom );
00316         }
00317     }
00318 }
KDE Home | KDE Accessibility Home | Description of Access Keys