lib Library API Documentation

koRuler.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@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., 59 Temple Place - Suite 330,
00017    Boston, MA 02111-1307, USA.
00018 */
00019 
00020 // Description: Ruler (header)
00021 
00022 /******************************************************************/
00023 
00024 #include "koRuler.h"
00025 #include <klocale.h>
00026 #include <kdebug.h>
00027 #include <kiconloader.h>
00028 #include <qcursor.h>
00029 #include <qpainter.h>
00030 #include <qpopupmenu.h>
00031 #include <qtooltip.h>
00032 #include <koPageLayout.h>
00033 
00034 class KoRulerPrivate {
00035 public:
00036     KoRulerPrivate() {
00037     }
00038     ~KoRulerPrivate() {}
00039 
00040     QWidget *canvas;
00041     int flags;
00042     int oldMx, oldMy;
00043     bool whileMovingBorderLeft, whileMovingBorderRight;
00044     bool whileMovingBorderTop, whileMovingBorderBottom;
00045     QPixmap pmFirst, pmLeft;
00046     KoPageLayout layout;
00047     KoTabChooser *tabChooser;
00048     KoTabulatorList tabList;
00049     // Do we have to remove a certain tab in the DC Event?
00050     KoTabulator removeTab;
00051     // The tab we're moving / clicking on - basically only valid between press and release time
00052     KoTabulator currTab;
00053     // The action we're currently doing - basically only valid between press and release time
00054     KoRuler::Action action;
00055     QPopupMenu *rb_menu;
00056     int mRemoveTab, mPageLayout; // menu item ids
00057     int frameEnd;
00058     double i_right;
00059     bool m_bReadWrite;
00060     bool doubleClickedIndent;
00061     bool rtl;
00062     bool mousePressed;
00063 };
00064 
00065 // Equality test for tab positions in particular
00066 static inline bool equals( double a, double b )  {
00067     return kAbs( a - b ) < 1E-4;
00068 }
00069 
00070 
00071 /******************************************************************/
00072 /* Class: KoRuler                                                 */
00073 /******************************************************************/
00074 
00075 const int KoRuler::F_TABS = 1;
00076 const int KoRuler::F_INDENTS = 2;
00077 const int KoRuler::F_HELPLINES = 4;
00078 const int KoRuler::F_NORESIZE = 8;
00079 
00080 /*================================================================*/
00081 KoRuler::KoRuler( QWidget *_parent, QWidget *_canvas, Orientation _orientation,
00082                  const KoPageLayout& _layout, int _flags, KoUnit::Unit _unit, KoTabChooser *_tabChooser )
00083     : QFrame( _parent ), buffer( width(), height() ), m_zoom(1.0), m_1_zoom(1.0),
00084       m_unit( _unit )
00085 {
00086     setWFlags( WResizeNoErase | WRepaintNoErase );
00087     setFrameStyle( Box | Raised );
00088 
00089     d=new KoRulerPrivate();
00090 
00091     d->tabChooser = _tabChooser;
00092 
00093     d->canvas = _canvas;
00094     orientation = _orientation;
00095     d->layout = _layout;
00096     d->flags = _flags;
00097 
00098     d->m_bReadWrite=true;
00099     d->doubleClickedIndent=false;
00100     diffx = 0;
00101     diffy = 0;
00102     i_left=0.0;
00103     i_first=0.0;
00104     d->i_right=0.0;
00105 
00106     setMouseTracking( true );
00107     d->mousePressed = false;
00108     d->action = A_NONE;
00109 
00110     d->oldMx = 0;
00111     d->oldMy = 0;
00112     d->rtl = false;
00113 
00114     showMPos = false;
00115     mposX = 0;
00116     mposY = 0;
00117     gridSize=0.0;
00118     hasToDelete = false;
00119     d->whileMovingBorderLeft = d->whileMovingBorderRight = d->whileMovingBorderTop = d->whileMovingBorderBottom = false;
00120 
00121     d->pmFirst = UserIcon( "koRulerFirst" );
00122     d->pmLeft = UserIcon( "koRulerLeft" );
00123     d->currTab.type = T_INVALID;
00124 
00125     d->removeTab.type = T_INVALID;
00126     if ( orientation == Qt::Horizontal ) {
00127         frameStart = qRound( zoomIt(d->layout.ptLeft) );
00128         d->frameEnd = qRound( zoomIt(d->layout.ptWidth - d->layout.ptRight) );
00129     } else {
00130         frameStart = qRound( zoomIt(d->layout.ptTop) );
00131         d->frameEnd = qRound( zoomIt(d->layout.ptHeight - d->layout.ptBottom) );
00132     }
00133     m_bFrameStartSet = false;
00134 
00135     setupMenu();
00136 
00137     // For compatibility, emitting doubleClicked shall emit openPageLayoutDia
00138     connect( this, SIGNAL( doubleClicked() ), this, SIGNAL( openPageLayoutDia() ) );
00139 }
00140 
00141 /*================================================================*/
00142 KoRuler::~KoRuler()
00143 {
00144     delete d->rb_menu;
00145     delete d;
00146 }
00147 
00148 void KoRuler::setPageLayoutMenuItemEnabled(bool b)
00149 {
00150     d->rb_menu->setItemEnabled(d->mPageLayout, b);
00151 }
00152 
00153 /*================================================================*/
00154 void KoRuler::setMousePos( int mx, int my )
00155 {
00156     if ( !showMPos || ( mx == mposX && my == mposY ) ) return;
00157 
00158     QPainter p( this );
00159     p.setRasterOp( Qt::NotROP );
00160 
00161     if ( orientation == Qt::Horizontal ) {
00162         if ( hasToDelete )
00163             p.drawLine( mposX, 1, mposX, height() - 1 );
00164         p.drawLine( mx, 1, mx, height() - 1 );
00165         hasToDelete = true;
00166     }
00167     else {
00168         if ( hasToDelete )
00169             p.drawLine( 1, mposY, width() - 1, mposY );
00170         p.drawLine( 1, my, width() - 1, my );
00171         hasToDelete = true;
00172     }
00173     p.end();
00174 
00175     mposX = mx;
00176     mposY = my;
00177 }
00178 
00179 // distance between the main lines (those with a number)
00180 double KoRuler::lineDistance() const
00181 {
00182     switch( m_unit ) {
00183     case KoUnit::U_INCH:
00184         return INCH_TO_POINT( m_zoom ); // every inch
00185     case KoUnit::U_PT:
00186         return 100.0 * m_zoom; // every 100 pt
00187     case KoUnit::U_MM:
00188     case KoUnit::U_CM:
00189     case KoUnit::U_DM:
00190         return CM_TO_POINT ( m_zoom ); // every cm
00191     case KoUnit::U_PI:
00192         return PI_TO_POINT ( 10.0 * m_zoom ); // every 10 pica
00193     case KoUnit::U_DD:
00194         return DD_TO_POINT( m_zoom ); // every diderot
00195     case KoUnit::U_CC:
00196         return CC_TO_POINT( 10.0 * m_zoom ); // every 10 cicero
00197     }
00198     // should never end up here
00199     return 100.0 * m_zoom;
00200 }
00201 
00202 /*================================================================*/
00203 void KoRuler::drawHorizontal( QPainter *_painter )
00204 {
00205     // Use a double-buffer pixmap
00206     QPainter p( &buffer );
00207     p.fillRect( 0, 0, width(), height(), QBrush( colorGroup().brush( QColorGroup::Background ) ) );
00208 
00209     int totalw = qRound( zoomIt(d->layout.ptWidth) );
00210     QString str;
00211     QFont font; // Use the global KDE font. Let's hope it's appropriate.
00212     font.setPointSize( 8 );
00213     QFontMetrics fm( font );
00214 
00215     p.setBrush( colorGroup().brush( QColorGroup::Base ) );
00216 
00217     // Draw white rect
00218     QRect r;
00219     if ( !d->whileMovingBorderLeft )
00220         r.setLeft( -diffx + frameStart );
00221     else
00222         r.setLeft( d->oldMx );
00223     r.setTop( 0 );
00224     if ( !d->whileMovingBorderRight )
00225         r.setWidth(d->frameEnd-frameStart);
00226     else
00227         r.setRight( d->oldMx );
00228     r.setBottom( height() );
00229 
00230     p.drawRect( r );
00231     p.setFont( font );
00232 
00233     // Draw the numbers
00234     double dist = lineDistance();
00235     int maxwidth = 0;
00236 
00237     for ( double i = 0.0;i <= (double)totalw;i += dist ) {
00238         str = QString::number( KoUnit::toUserValue( i / m_zoom, m_unit ) );
00239         int textwidth = fm.width( str );
00240         maxwidth = QMAX( maxwidth, textwidth );
00241     }
00242 
00243     // Make sure that the ruler stays readable at lower zoom levels
00244     while( dist <= maxwidth ) {
00245         dist += lineDistance();
00246     }
00247 
00248     for ( double i = 0.0;i <= (double)totalw;i += dist ) {
00249         str = QString::number( KoUnit::toUserValue( i / m_zoom, m_unit ) );
00250         int textwidth = fm.width( str );
00251         maxwidth = QMAX( maxwidth, textwidth );
00252         p.drawText( qRound(i) - diffx - qRound(textwidth * 0.5),
00253                     qRound(( height() - fm.height() ) * 0.5),
00254                     textwidth, height(), AlignLeft | AlignTop, str );
00255     }
00256 
00257     // Draw the medium-sized lines
00258     // Only if we have enough space (i.e. not at 33%)
00259     if ( dist > maxwidth + 2 )
00260     {
00261         for ( double i = dist * 0.5;i <= (double)totalw;i += dist ) {
00262             int ii=qRound(i);
00263             p.drawLine( ii - diffx, 5, ii - diffx, height() - 5 );
00264         }
00265     }
00266 
00267     // Draw the small lines
00268     // Only if we have enough space (i.e. not at 33%)
00269     if ( dist * 0.5 > maxwidth + 2 )
00270     {
00271         for ( double i = dist * 0.25;i <= (double)totalw;i += dist * 0.5 ) {
00272             int ii=qRound(i);
00273             p.drawLine( ii - diffx, 7, ii - diffx, height() - 7 );
00274         }
00275     }
00276 
00277     // Draw ending bar (at page width)
00278     int constant=zoomIt(1);
00279     p.drawLine( totalw - diffx + constant, 1, totalw - diffx + constant, height() - 1 );
00280     p.setPen( colorGroup().color( QColorGroup::Base ) );
00281     p.drawLine( totalw - diffx, 1, totalw - diffx, height() - 1 );
00282 
00283     // Draw starting bar (at 0)
00284     p.setPen( colorGroup().color( QColorGroup::Text ) );
00285     p.drawLine( -diffx, 1, -diffx, height() - 1 );
00286     p.setPen( colorGroup().color( QColorGroup::Base ) );
00287     p.drawLine( -diffx - constant, 1, -diffx - constant, height() - 1 );
00288 
00289     // Draw the indents triangles
00290     if ( d->flags & F_INDENTS ) {
00291         int top = 2;
00292         double halfPixmapWidth = d->pmFirst.width() * 0.5;
00293         // Cumulate i_first with correct indent
00294         double firstLineIdent = i_first + ( d->rtl ? d->i_right : i_left );
00295         p.drawPixmap( qRound( static_cast<double>(r.left()) + applyRtlAndZoom( firstLineIdent ) - halfPixmapWidth ),
00296                       top, d->pmFirst );
00297 
00298         int bottom = height() - d->pmLeft.height() - 2;
00299         halfPixmapWidth = d->pmLeft.width() * 0.5;
00300         p.drawPixmap( qRound( static_cast<double>(r.left()) + zoomIt(i_left) - halfPixmapWidth ),
00301                       bottom, d->pmLeft );
00302         p.drawPixmap( qRound( static_cast<double>(r.right()) - zoomIt(d->i_right) - halfPixmapWidth ),
00303                       bottom, d->pmLeft );
00304     }
00305 
00306     // Show the mouse position
00307     if ( d->action == A_NONE && showMPos ) {
00308         p.setPen( colorGroup().color( QColorGroup::Text ) );
00309         p.drawLine( mposX, 1, mposX, height() - 1 );
00310     }
00311     hasToDelete = false;
00312 
00313     // Draw the tabs
00314     if ( d->tabChooser && ( d->flags & F_TABS ) && !d->tabList.isEmpty() )
00315         drawTabs( p );
00316 
00317     p.end();
00318     _painter->drawPixmap( 0, 0, buffer );
00319 }
00320 
00321 /*================================================================*/
00322 void KoRuler::drawTabs( QPainter &_painter )
00323 {
00324     int ptPos = 0;
00325 
00326     _painter.setPen( QPen( colorGroup().color( QColorGroup::Text ), 2, SolidLine ) );
00327     // Check if we're in a mousemove event, removing a tab.
00328     // In that case, we'll have to skip drawing that one.
00329     bool willRemove = d->mousePressed && willRemoveTab( d->oldMy ) && d->currTab.type != T_INVALID;
00330 
00331     KoTabulatorList::ConstIterator it = d->tabList.begin();
00332     for ( ; it != d->tabList.end() ; it++ ) {
00333         if ( willRemove && equals( d->currTab.ptPos, (*it).ptPos ) )
00334             continue;
00335         ptPos = qRound(applyRtlAndZoom((*it).ptPos)) - diffx + frameStart;
00336         switch ( (*it).type ) {
00337         case T_LEFT: {
00338             ptPos -= 4;
00339             _painter.drawLine( ptPos + 4, height() - 4, ptPos + 20 - 4, height() - 4 );
00340             _painter.drawLine( ptPos + 5, 4, ptPos + 5, height() - 4 );
00341         } break;
00342         case T_CENTER: {
00343             ptPos -= 10;
00344             _painter.drawLine( ptPos + 4, height() - 4, ptPos + 20 - 4, height() - 4 );
00345             _painter.drawLine( ptPos + 20 / 2, 4, ptPos + 20 / 2, height() - 4 );
00346         } break;
00347         case T_RIGHT: {
00348             ptPos -= 16;
00349             _painter.drawLine( ptPos + 4, height() - 4, ptPos + 20 - 4, height() - 4 );
00350             _painter.drawLine( ptPos + 20 - 5, 4, ptPos + 20 - 5, height() - 4 );
00351         } break;
00352         case T_DEC_PNT: {
00353             ptPos -= 10;
00354             _painter.drawLine( ptPos + 4, height() - 4, ptPos + 20 - 4, height() - 4 );
00355             _painter.drawLine( ptPos + 20 / 2, 4, ptPos + 20 / 2, height() - 4 );
00356             _painter.fillRect( ptPos + 20 / 2 + 2, height() - 9, 3, 3,
00357                                colorGroup().color( QColorGroup::Text ) );
00358         } break;
00359         default: break;
00360         }
00361     }
00362 }
00363 
00364 /*================================================================*/
00365 void KoRuler::drawVertical( QPainter *_painter )
00366 {
00367     QPainter p( &buffer );
00368     p.fillRect( 0, 0, width(), height(), QBrush( colorGroup().brush( QColorGroup::Background ) ) );
00369 
00370     int totalh = qRound( zoomIt(d->layout.ptHeight) );
00371     // Clip rect - this gives basically always a rect like (2,2,width-2,height-2)
00372     QRect paintRect = _painter->clipRegion( QPainter::CoordPainter ).boundingRect();
00373     // Ruler rect
00374     QRect rulerRect( 0, -diffy, width(), totalh );
00375 
00376     if ( paintRect.intersects( rulerRect ) )  {
00377         QString str;
00378         QFont font; // Use the global KDE font. Let's hope it's appropriate.
00379         font.setPointSize( 8 ); // Hardcode the size? (Werner)
00380         QFontMetrics fm( font );
00381 
00382         p.setBrush( colorGroup().brush( QColorGroup::Base ) );
00383 
00384         // Draw white rect
00385         QRect r;
00386         if ( !d->whileMovingBorderTop )
00387             r.setTop( -diffy + frameStart );
00388         else
00389             r.setTop( d->oldMy );
00390         r.setLeft( 0 );
00391         if ( !d->whileMovingBorderBottom )
00392             r.setHeight(d->frameEnd-frameStart);
00393         else
00394             r.setBottom( d->oldMy );
00395         r.setRight( width() );
00396 
00397         p.drawRect( r );
00398         p.setFont( font );
00399 
00400         // Draw the numbers
00401         double dist = lineDistance();
00402         int maxheight = 0;
00403 
00404         for ( double i = 0.0;i <= (double)totalh;i += dist ) {
00405             str = QString::number( KoUnit::toUserValue( i / m_zoom, m_unit ) );
00406             int textwidth = fm.width( str );
00407             maxheight = QMAX( maxheight, textwidth );
00408         }
00409 
00410         // Make sure that the ruler stays readable at lower zoom levels
00411         while( dist <= maxheight ) {
00412             dist += lineDistance();
00413         }
00414 
00415         for ( double i = 0.0;i <= (double)totalh;i += dist ) {
00416             str = QString::number( KoUnit::toUserValue( i / m_zoom, m_unit ) );
00417             int textheight = fm.height();
00418             int textwidth = fm.width( str );
00419             maxheight = QMAX( maxheight, textwidth );
00420             p.save();
00421             p.translate( qRound(( width() - textheight ) * 0.5),
00422                          qRound(i) - diffy + qRound(textwidth * 0.5) );
00423             p.rotate( -90 );
00424             p.drawText( 0, 0, textwidth + 1, textheight, AlignLeft | AlignTop, str );
00425             p.restore();
00426         }
00427 
00428         // Draw the medium-sized lines
00429         if ( dist > maxheight + 2 )
00430         {
00431             for ( double i = dist * 0.5;i <= (double)totalh;i += dist ) {
00432                 int ii=qRound(i);
00433                 p.drawLine( 5, ii - diffy, width() - 5, ii - diffy );
00434             }
00435         }
00436 
00437         // Draw the small lines
00438         if ( dist * 0.5 > maxheight + 2 )
00439         {
00440             for ( double i = dist * 0.25;i <=(double)totalh;i += dist *0.5 ) {
00441                 int ii=qRound(i);
00442                 p.drawLine( 7, ii - diffy, width() - 7, ii - diffy );
00443             }
00444         }
00445 
00446         // Draw ending bar (at page height)
00447         p.drawLine( 1, totalh - diffy + 1, width() - 1, totalh - diffy + 1 );
00448         p.setPen( colorGroup().color( QColorGroup::Base ) );
00449         p.drawLine( 1, totalh - diffy, width() - 1, totalh - diffy );
00450 
00451         // Draw starting bar (at 0)
00452         p.setPen( colorGroup().color( QColorGroup::Text ) );
00453         p.drawLine( 1, -diffy, width() - 1, -diffy );
00454         p.setPen( colorGroup().color( QColorGroup::Base ) );
00455         p.drawLine( 1, -diffy - 1, width() - 1, -diffy - 1 );
00456     }
00457 
00458     // Show the mouse position
00459     if ( d->action == A_NONE && showMPos ) {
00460         p.setPen( colorGroup().color( QColorGroup::Text ) );
00461         p.drawLine( 1, mposY, width() - 1, mposY );
00462     }
00463     hasToDelete = false;
00464 
00465     p.end();
00466     _painter->drawPixmap( 0, 0, buffer );
00467 }
00468 
00469 void KoRuler::mousePressEvent( QMouseEvent *e )
00470 {
00471     if( !d->m_bReadWrite)
00472         return;
00473 
00474     d->oldMx = e->x();
00475     d->oldMy = e->y();
00476     d->mousePressed = true;
00477     d->removeTab.type = T_INVALID;
00478 
00479     switch ( e->button() ) {
00480     case RightButton:
00481         if(d->currTab.type == T_INVALID || !(d->flags & F_TABS))
00482             d->rb_menu->setItemEnabled(d->mRemoveTab, false);
00483         else
00484             d->rb_menu->setItemEnabled(d->mRemoveTab, true);
00485         d->rb_menu->popup( QCursor::pos() );
00486         d->action = A_NONE;
00487         d->mousePressed = false;
00488         return;
00489     case MidButton:
00490         // MMB shall do like double-click (it opens a dialog).
00491         handleDoubleClick();
00492         return;
00493     case LeftButton:
00494         if ( d->action == A_BR_RIGHT || d->action == A_BR_LEFT ) {
00495             if ( d->action == A_BR_RIGHT )
00496                 d->whileMovingBorderRight = true;
00497             else
00498                 d->whileMovingBorderLeft = true;
00499 
00500             if ( d->canvas )
00501                 drawLine(d->oldMx, -1);
00502             update();
00503         } else if ( d->action == A_BR_TOP || d->action == A_BR_BOTTOM ) {
00504             if ( d->action == A_BR_TOP )
00505                 d->whileMovingBorderTop = true;
00506             else
00507                 d->whileMovingBorderBottom = true;
00508 
00509             if ( d->canvas ) {
00510                 QPainter p( d->canvas );
00511                 p.setRasterOp( Qt::NotROP );
00512                 p.drawLine( 0, d->oldMy, d->canvas->width(), d->oldMy );
00513                 p.end();
00514             }
00515             update();
00516         } else if ( d->action == A_FIRST_INDENT || d->action == A_LEFT_INDENT || d->action == A_RIGHT_INDENT ) {
00517             if ( d->canvas )
00518                 drawLine(d->oldMx, -1);
00519         } else if ( d->action == A_TAB ) {
00520             if ( d->canvas && d->currTab.type != T_INVALID ) {
00521                 drawLine( qRound( applyRtlAndZoom(d->currTab.ptPos) ) + frameStart - diffx, -1 );
00522             }
00523         } else if ( d->tabChooser && ( d->flags & F_TABS ) && d->tabChooser->getCurrTabType() != 0 ) {
00524             int left = frameStart - diffx;
00525             int right = d->frameEnd - diffx;
00526 
00527             if( e->x()-left < 0 || right-e->x() < 0 )
00528                 return;
00529             KoTabulator tab;
00530             tab.filling = TF_BLANK;
00531             tab.ptWidth = 0.5;
00532             switch ( d->tabChooser->getCurrTabType() ) {
00533             case KoTabChooser::TAB_LEFT:
00534                 tab.type = T_LEFT;
00535                 break;
00536             case KoTabChooser::TAB_CENTER:
00537                 tab.type = T_CENTER;
00538                 break;
00539             case KoTabChooser::TAB_RIGHT:
00540                 tab.type = T_RIGHT;
00541                 break;
00542             case KoTabChooser::TAB_DEC_PNT:
00543                 tab.type = T_DEC_PNT;
00544                 tab.alignChar = KGlobal::locale()->decimalSymbol()[0];
00545                 break;
00546             default: break;
00547             }
00548             tab.ptPos = unZoomItRtl( e->x() + diffx - frameStart );
00549 
00550             KoTabulatorList::Iterator it=d->tabList.begin();
00551             while ( it!=d->tabList.end() && tab > (*it) )
00552         ++it;
00553 
00554             d->tabList.insert(it, tab);
00555 
00556             d->action = A_TAB;
00557             d->removeTab = tab;
00558             d->currTab = tab;
00559 
00560             emit tabListChanged( d->tabList );
00561             update();
00562         }
00563         else if ( d->flags & F_HELPLINES )
00564         {
00565         setCursor( orientation == Qt::Horizontal ?
00566                Qt::sizeVerCursor : Qt::sizeHorCursor );
00567             d->action = A_HELPLINES;
00568         }
00569     default:
00570         break;
00571     }
00572 }
00573 
00574 void KoRuler::mouseReleaseEvent( QMouseEvent *e )
00575 {
00576     d->mousePressed = false;
00577 
00578     // Hacky, but necessary to prevent multiple tabs with the same coordinates (Werner)
00579     bool fakeMovement=false;
00580     if(d->removeTab.type != T_INVALID) {
00581         mouseMoveEvent(e);
00582         fakeMovement=true;
00583     }
00584 
00585     if ( d->action == A_BR_RIGHT || d->action == A_BR_LEFT ) {
00586         d->whileMovingBorderRight = false;
00587         d->whileMovingBorderLeft = false;
00588 
00589         if ( d->canvas )
00590             drawLine(d->oldMx, -1);
00591         update();
00592         emit newPageLayout( d->layout );
00593     } else if ( d->action == A_BR_TOP || d->action == A_BR_BOTTOM ) {
00594         d->whileMovingBorderTop = false;
00595         d->whileMovingBorderBottom = false;
00596 
00597         if ( d->canvas ) {
00598             QPainter p( d->canvas );
00599             p.setRasterOp( Qt::NotROP );
00600             p.drawLine( 0, d->oldMy, d->canvas->width(), d->oldMy );
00601             p.end();
00602         }
00603         update();
00604         emit newPageLayout( d->layout );
00605     } else if ( d->action == A_FIRST_INDENT ) {
00606         if ( d->canvas )
00607             drawLine(d->oldMx, -1);
00608         update();
00609         emit newFirstIndent( i_first );
00610     } else if ( d->action == A_LEFT_INDENT ) {
00611         if ( d->canvas )
00612             drawLine(d->oldMx, -1);
00613         update();
00614         emit newLeftIndent( i_left );
00615     } else if ( d->action == A_RIGHT_INDENT ) {
00616         if ( d->canvas )
00617             drawLine(d->oldMx, -1);
00618         update();
00619         emit newRightIndent( d->i_right );
00620     } else if ( d->action == A_TAB ) {
00621         if ( d->canvas && !fakeMovement ) {
00622             drawLine( qRound( applyRtlAndZoom( d->currTab.ptPos ) ) + frameStart - diffx, -1);
00623         }
00624         if ( willRemoveTab( e->y() ) )
00625         {
00626             d->tabList.remove(d->currTab);
00627         }
00628         qHeapSort( d->tabList );
00629 
00630         // Delete the new tabulator if it is placed on top of another.
00631         KoTabulatorList::ConstIterator tmpTab=d->tabList.begin();
00632         int count=0;
00633         while(tmpTab!=d->tabList.end()) {
00634             if( equals( (*tmpTab).ptPos, d->currTab.ptPos ) ) {
00635                 count++;
00636                 if(count > 1) {
00637                     d->tabList.remove(d->currTab);
00638                     break;
00639                 }
00640             }
00641             tmpTab++;
00642         }
00643         //searchTab( e->x() ); // DF: why set currTab here?
00644         emit tabListChanged( d->tabList );
00645         update();
00646     }
00647     else if( d->action == A_HELPLINES )
00648     {
00649         emit addHelpline( e->pos(), orientation == Qt::Horizontal);
00650         setCursor( ArrowCursor );
00651     }
00652     d->currTab.type = T_INVALID; // added (DF)
00653 }
00654 
00655 void KoRuler::mouseMoveEvent( QMouseEvent *e )
00656 {
00657     hasToDelete = false;
00658 
00659     int pw = d->frameEnd - frameStart;
00660     int ph = qRound(zoomIt(d->layout.ptHeight));
00661     int left = frameStart - diffx;
00662     int top = qRound(zoomIt(d->layout.ptTop));
00663     top -= diffy;
00664     int right = d->frameEnd - diffx;
00665     int bottom = qRound(zoomIt(d->layout.ptBottom));
00666     bottom = ph - bottom - diffy;
00667     // Cumulate first-line-indent
00668     int ip_first = qRound( zoomIt( i_first + ( d->rtl ? d->i_right : i_left) ) );
00669     int ip_left = qRound(zoomIt(i_left));
00670     int ip_right = qRound(zoomIt(d->i_right));
00671 
00672     int mx = e->x();
00673     mx = mx+diffx < 0 ? 0 : mx;
00674     int my = e->y();
00675     my = my+diffy < 0 ? 0 : my;
00676 
00677     QToolTip::remove( this);
00678     switch ( orientation ) {
00679         case Qt::Horizontal: {
00680             if ( !d->mousePressed ) {
00681                 setCursor( ArrowCursor );
00682                 d->action = A_NONE;
00684                 // At the moment, moving the left and right border indicators
00685                 // is disabled when setFrameStartEnd has been called (i.e. in KWord)
00686                 // Changing the layout margins directly from it would be utterly wrong
00687                 // (just try the 2-columns modes...). What needs to be done is:
00688                 // emitting a signal frameResized in mouseReleaseEvent, when a left/right
00689                 // border has been moved, and in kword we need to update the margins from
00690                 // there, if the left border of the 1st column or the right border of the
00691                 // last column was moved... and find what to do with the other borders.
00692                 // And for normal frames, resize the frame without touching the page layout.
00693                 // All that is too much for now -> disabling.
00694                 if ( !m_bFrameStartSet )
00695                 {
00696                     if ( mx > left - 5 && mx < left + 5 ) {
00697                         setCursor( Qt::sizeHorCursor );
00698                         d->action = A_BR_LEFT;
00699                     } else if ( mx > right - 5 && mx < right + 5 ) {
00700                         setCursor( Qt::sizeHorCursor );
00701                         d->action = A_BR_RIGHT;
00702                     }
00703                 }
00704                 if ( d->flags & F_INDENTS ) {
00705                     int firstX = d->rtl ? right - ip_first : left + ip_first;
00706                     if ( mx > firstX - 5 && mx < firstX + 5 &&
00707                          my >= 2 && my <= d->pmFirst.size().height() + 2 ) {
00708                         QToolTip::add( this, i18n("First line indent") );
00709                         setCursor( ArrowCursor );
00710                         d->action = A_FIRST_INDENT;
00711                     } else if ( mx > left + ip_left - 5 && mx < left + ip_left + 5 &&
00712                                 my >= height() - d->pmLeft.size().height() - 2 && my <= height() - 2 ) {
00713                         QToolTip::add( this, i18n("Left indent") );
00714                         setCursor( ArrowCursor );
00715                         d->action = A_LEFT_INDENT;
00716                     } else if ( mx > right - ip_right - 5 && mx < right - ip_right + 5 &&
00717                                 my >= height() - d->pmLeft.size().height() - 2 && my <= height() - 2 ) {
00718                         QToolTip::add( this, i18n("Right indent") );
00719                         setCursor( ArrowCursor );
00720                         d->action = A_RIGHT_INDENT;
00721                     }
00722                 }
00723                 if ( d->flags & F_TABS )
00724                     searchTab(mx);
00725             } else {
00726                 // Calculate the new value.
00727                 int newPos=mx;
00728                 if( newPos!=right && gridSize!=0.0 && (e->state() & ShiftButton)==0) { // apply grid.
00729                     double grid=zoomIt(gridSize * 16);
00730                     newPos=qRound( ((newPos * 16 / grid) * grid) / 16 );
00731                 }
00732                 if(newPos-left < 0) newPos=left;
00733                 else if (right-newPos < 0) newPos=right;
00734                 double newValue = unZoomIt(static_cast<double>(newPos) - frameStart + diffx);
00735 
00736                 switch ( d->action ) {
00737                     case A_BR_LEFT: {
00738                         if ( d->canvas && mx < right-10 && mx+diffx-2 > 0) {
00739                             drawLine( d->oldMx, mx );
00740                             d->layout.ptLeft = unZoomIt(static_cast<double>(mx + diffx));
00741                             if( ip_left > right-left-15 ) {
00742                                 ip_left=right-left-15;
00743                                 ip_left=ip_left<0 ? 0 : ip_left;
00744                                 i_left=unZoomIt( ip_left );
00745                                 emit newLeftIndent( i_left );
00746                             }
00747                             if ( ip_right > right-left-15 ) {
00748                                 ip_right=right-left-15;
00749                                 ip_right=ip_right<0? 0 : ip_right;
00750                                 d->i_right=unZoomIt( ip_right );
00751                                 emit newRightIndent( d->i_right );
00752                             }
00753                             d->oldMx = mx;
00754                             d->oldMy = my;
00755                             update();
00756                         }
00757                         else
00758                             return;
00759                     } break;
00760                     case A_BR_RIGHT: {
00761                         if ( d->canvas && mx > left+10 && mx+diffx <= pw-2) {
00762                             drawLine( d->oldMx, mx );
00763                             d->layout.ptRight = unZoomIt(static_cast<double>(pw - ( mx + diffx )));
00764                             if( ip_left > right-left-15 ) {
00765                                 ip_left=right-left-15;
00766                                 ip_left=ip_left<0 ? 0 : ip_left;
00767                                 i_left=unZoomIt( ip_left );
00768                                 emit newLeftIndent( i_left );
00769                             }
00770                             if ( ip_right > right-left-15 ) {
00771                                 ip_right=right-left-15;
00772                                 ip_right=ip_right<0? 0 : ip_right;
00773                                 d->i_right=unZoomIt( ip_right );
00774                                 emit newRightIndent( d->i_right );
00775                             }
00776                             d->oldMx = mx;
00777                             d->oldMy = my;
00778                             update();
00779                         }
00780                         else
00781                             return;
00782                     } break;
00783                     case A_FIRST_INDENT: {
00784                         if ( d->canvas ) {
00785                             if (d->rtl)
00786                                 newValue = unZoomIt(pw) - newValue - d->i_right;
00787                             else
00788                                 newValue -= i_left;
00789                             if(newValue == i_first) break;
00790                             drawLine( d->oldMx, newPos);
00791                             d->oldMx=newPos;
00792                             i_first = newValue;
00793                             update();
00794                         }
00795                     } break;
00796                     case A_LEFT_INDENT: {
00797                         if ( d->canvas ) {
00798                             //if (d->rtl) newValue = unZoomIt(pw) - newValue;
00799                             if(newValue == i_left) break;
00800 
00801                             drawLine( d->oldMx, newPos);
00802                             i_left = newValue;
00803                             d->oldMx = newPos;
00804                             update();
00805                         }
00806                     } break;
00807                     case A_RIGHT_INDENT: {
00808                         if ( d->canvas ) {
00809                             double rightValue = unZoomIt(right - newPos);
00810                             //if (d->rtl) rightValue = unZoomIt(pw) - rightValue;
00811                             if(rightValue == d->i_right) break;
00812 
00813                             drawLine( d->oldMx, newPos);
00814                             d->i_right=rightValue;
00815                             d->oldMx = newPos;
00816                             update();
00817                         }
00818                     } break;
00819                     case A_TAB: {
00820                         if ( d->canvas) {
00821                             if (d->rtl) newValue = unZoomIt(pw) - newValue;
00822                             if(newValue == d->currTab.ptPos) break; // no change
00823                             QPainter p( d->canvas );
00824                             p.setRasterOp( Qt::NotROP );
00825                             // prevent 1st drawLine when we just created a new tab
00826                             // (it's a NOT line)
00827                             double pt;
00828                             int pt_fr;
00829                             if( d->currTab != d->removeTab )
00830                             {
00831                                 pt = applyRtlAndZoom(d->currTab.ptPos);
00832                                 pt_fr = qRound(pt) + frameStart - diffx;
00833                                 p.drawLine( pt_fr, 0, pt_fr, d->canvas->height() );
00834                             }
00835 
00836                             KoTabulatorList::Iterator it = d->tabList.find( d->currTab );
00837                             Q_ASSERT( it != d->tabList.end() );
00838                             if ( it != d->tabList.end() )
00839                                 (*it).ptPos = newValue;
00840                             d->currTab.ptPos = newValue;
00841 
00842                             pt = applyRtlAndZoom( newValue );
00843                             pt_fr = qRound(pt) + frameStart - diffx;
00844                             p.drawLine( pt_fr, 0, pt_fr, d->canvas->height() );
00845 
00846                             p.end();
00847                             d->oldMx = mx;
00848                             d->oldMy = my;
00849                             d->removeTab.type = T_INVALID;
00850                             update();
00851                         }
00852                     } break;
00853                     default: break;
00854                 }
00855             }
00856             if( d->action == A_HELPLINES )
00857             {
00858                 emit moveHelpLines( e->pos(), orientation == Qt::Horizontal);
00859             }
00860 
00861             return;
00862         } break;
00863         case Qt::Vertical: {
00864             if ( !d->mousePressed ) {
00865                 setCursor( ArrowCursor );
00866                 d->action = A_NONE;
00867                 if ( d->flags & F_NORESIZE )
00868                     break;
00869                 if ( my > top - 5 && my < top + 5 ) {
00870                     QToolTip::add( this, i18n("Top margin") );
00871                     setCursor( Qt::sizeVerCursor );
00872                     d->action = A_BR_TOP;
00873                 } else if ( my > bottom - 5 && my < bottom + 5 ) {
00874                     QToolTip::add( this, i18n("Bottom margin") );
00875                     setCursor( Qt::sizeVerCursor );
00876                     d->action = A_BR_BOTTOM;
00877                 }
00878             } else {
00879                 switch ( d->action ) {
00880                     case A_BR_TOP: {
00881                         if ( d->canvas && my < bottom-20 && my+diffy-2 > 0) {
00882                             QPainter p( d->canvas );
00883                             p.setRasterOp( Qt::NotROP );
00884                             p.drawLine( 0, d->oldMy, d->canvas->width(), d->oldMy );
00885                             p.drawLine( 0, my, d->canvas->width(), my );
00886                             p.end();
00887                             d->layout.ptTop = unZoomIt(static_cast<double>(my + diffy));
00888                             d->oldMx = mx;
00889                             d->oldMy = my;
00890                             update();
00891                         }
00892                         else
00893                             return;
00894                     } break;
00895                     case A_BR_BOTTOM: {
00896                         if ( d->canvas && my > top+20 && my+diffy < ph-2) {
00897                             QPainter p( d->canvas );
00898                             p.setRasterOp( Qt::NotROP );
00899                             p.drawLine( 0, d->oldMy, d->canvas->width(), d->oldMy );
00900                             p.drawLine( 0, my, d->canvas->width(), my );
00901                             p.end();
00902                             d->layout.ptBottom = unZoomIt(static_cast<double>(ph - ( my + diffy )));
00903                             d->oldMx = mx;
00904                             d->oldMy = my;
00905                             update();
00906                         }
00907                         else
00908                             return;
00909                     } break;
00910                     default: break;
00911                 }
00912             }
00913         } break;
00914     }
00915     if( d->action == A_HELPLINES )
00916     {
00917         emit moveHelpLines( e->pos(), orientation == Qt::Horizontal);
00918     }
00919 
00920     d->oldMx = mx;
00921     d->oldMy = my;
00922 }
00923 
00924 void KoRuler::resizeEvent( QResizeEvent *e )
00925 {
00926     QFrame::resizeEvent( e );
00927     buffer.resize( size() );
00928 }
00929 
00930 void KoRuler::mouseDoubleClickEvent( QMouseEvent* )
00931 {
00932     handleDoubleClick();
00933 }
00934 
00935 void KoRuler::handleDoubleClick()
00936 {
00937     if ( !d->m_bReadWrite )
00938         return;
00939 
00940     d->doubleClickedIndent = false;
00941     if ( d->tabChooser && ( d->flags & F_TABS ) ) {
00942         // Double-click and mousePressed inserted a tab -> need to remove it
00943         if ( d->tabChooser->getCurrTabType() != 0 && d->removeTab.type != T_INVALID && !d->tabList.isEmpty()) {
00944             uint c = d->tabList.count();
00945             d->tabList.remove( d->removeTab );
00946             Q_ASSERT( d->tabList.count() < c );
00947 
00948             d->removeTab.type = T_INVALID;
00949             d->currTab.type = T_INVALID;
00950             emit tabListChanged( d->tabList );
00951             setCursor( ArrowCursor );
00952             update();
00953             // --- we didn't click on a tab, fall out to indents test ---
00954         } else if ( d->action == A_TAB ) {
00955             // Double-click on a tab
00956             emit doubleClicked( d->currTab.ptPos ); // usually paragraph dialog
00957             return;
00958         }
00959     }
00960 
00961     // When Binary Compatibility is broken this will hopefully emit a
00962     // doubleClicked(int) to differentiate between double-clicking an
00963     // indent and double-clicking the ruler
00964     if ( d->flags & F_INDENTS ) {
00965         if ( d->action == A_LEFT_INDENT || d->action == A_RIGHT_INDENT || d->action == A_FIRST_INDENT ) {
00966             d->doubleClickedIndent = true;
00967             emit doubleClicked(); // usually paragraph dialog
00968             return;
00969         }
00970     }
00971 
00972     // Double-clicked nothing
00973     d->action = A_NONE;
00974     emit doubleClicked(); // usually page layout dialog
00975 }
00976 
00977 void KoRuler::setTabList( const KoTabulatorList & _tabList )
00978 {
00979     d->tabList = _tabList;
00980     qHeapSort(d->tabList);   // "Trust no one." as opposed to "In David we trust."
00981 
00982     // Note that d->currTab and d->removeTab could now point to
00983     // tabs which don't exist in d->tabList
00984 
00985     update();
00986 }
00987 
00988 double KoRuler::makeIntern( double _v )
00989 {
00990     return KoUnit::fromUserValue( _v, m_unit );
00991 }
00992 
00993 void KoRuler::setupMenu()
00994 {
00995     d->rb_menu = new QPopupMenu();
00996     Q_CHECK_PTR( d->rb_menu );
00997     for ( uint i = 0 ; i <= KoUnit::U_LASTUNIT ; ++i )
00998     {
00999         KoUnit::Unit unit = static_cast<KoUnit::Unit>( i );
01000         d->rb_menu->insertItem( KoUnit::unitDescription( unit ), i /*as id*/ );
01001         if ( m_unit == unit )
01002             d->rb_menu->setItemChecked( i, true );
01003     }
01004     connect( d->rb_menu, SIGNAL( activated( int ) ), SLOT( slotMenuActivated( int ) ) );
01005 
01006     d->rb_menu->insertSeparator();
01007     d->mPageLayout=d->rb_menu->insertItem(i18n("Page Layout..."), this, SLOT(pageLayoutDia()));
01008     d->rb_menu->insertSeparator();
01009     d->mRemoveTab=d->rb_menu->insertItem(i18n("Remove Tabulator"), this, SLOT(rbRemoveTab()));
01010     d->rb_menu->setItemEnabled( d->mRemoveTab, false );
01011 }
01012 
01013 void KoRuler::uncheckMenu()
01014 {
01015     for ( uint i = 0 ; i <= KoUnit::U_LASTUNIT ; ++i )
01016         d->rb_menu->setItemChecked( i, false );
01017 }
01018 
01019 void KoRuler::setUnit( const QString& _unit )
01020 {
01021     setUnit( KoUnit::unit( _unit ) );
01022 }
01023 
01024 void KoRuler::setUnit( KoUnit::Unit unit )
01025 {
01026     m_unit = unit;
01027     uncheckMenu();
01028     d->rb_menu->setItemChecked( m_unit, true );
01029     update();
01030 }
01031 
01032 void KoRuler::setZoom( const double& zoom )
01033 {
01034     if(zoom==m_zoom)
01035         return;
01036     if(zoom < 1E-4) // Don't do 0 or negative values
01037         return;
01038     m_zoom=zoom;
01039     m_1_zoom=1/m_zoom;
01040     update();
01041 }
01042 
01043 bool KoRuler::willRemoveTab( int y ) const
01044 {
01045     return (y < -50 || y > height() + 25) && d->currTab.type != T_INVALID;
01046 }
01047 
01048 void KoRuler::rbRemoveTab() {
01049 
01050     d->tabList.remove( d->currTab );
01051     d->currTab.type = T_INVALID;
01052     emit tabListChanged( d->tabList );
01053     update();
01054 }
01055 
01056 void KoRuler::setReadWrite(bool _readWrite)
01057 {
01058     d->m_bReadWrite=_readWrite;
01059 }
01060 
01061 void KoRuler::searchTab(int mx) {
01062 
01063     int pos;
01064     d->currTab.type = T_INVALID;
01065     KoTabulatorList::ConstIterator it = d->tabList.begin();
01066     for ( ; it != d->tabList.end() ; ++it ) {
01067         pos = qRound(applyRtlAndZoom((*it).ptPos)) - diffx + frameStart;
01068         if ( mx > pos - 5 && mx < pos + 5 ) {
01069             setCursor( Qt::sizeHorCursor );
01070             d->action = A_TAB;
01071             d->currTab = *it;
01072             break;
01073         }
01074     }
01075 }
01076 
01077 void KoRuler::drawLine(int oldX, int newX) {
01078 
01079     QPainter p( d->canvas );
01080     p.setRasterOp( Qt::NotROP );
01081     p.drawLine( oldX, 0, oldX, d->canvas->height() );
01082     if(newX!=-1)
01083         p.drawLine( newX, 0, newX, d->canvas->height() );
01084     p.end();
01085 }
01086 
01087 void KoRuler::showMousePos( bool _showMPos )
01088 {
01089     showMPos = _showMPos;
01090     hasToDelete = false;
01091     mposX = -1;
01092     mposY = -1;
01093     update();
01094 }
01095 
01096 void KoRuler::setOffset( int _diffx, int _diffy )
01097 {
01098     //kdDebug() << "KoRuler::setOffset " << _diffx << "," << _diffy << endl;
01099     diffx = _diffx;
01100     diffy = _diffy;
01101     update();
01102 }
01103 
01104 void KoRuler::setFrameStartEnd( int _frameStart, int _frameEnd )
01105 {
01106     if ( _frameStart != frameStart || _frameEnd != d->frameEnd || !m_bFrameStartSet )
01107     {
01108         frameStart = _frameStart;
01109         d->frameEnd = _frameEnd;
01110         // Remember that setFrameStartEnd was called. This activates a slightly
01111         // different mode (when moving start and end positions).
01112         m_bFrameStartSet = true;
01113         update();
01114     }
01115 }
01116 
01117 void KoRuler::setRightIndent( double _right )
01118 {
01119     d->i_right = makeIntern( _right );
01120     update();
01121 }
01122 
01123 void KoRuler::setDirection( bool rtl )
01124 {
01125     d->rtl = rtl;
01126     update();
01127 }
01128 
01129 void KoRuler::changeFlags(int _flags)
01130 {
01131     d->flags = _flags;
01132 }
01133 
01134 int KoRuler::flags() const
01135 {
01136     return d->flags;
01137 }
01138 
01139 bool KoRuler::doubleClickedIndent() const
01140 {
01141     return d->doubleClickedIndent;
01142 }
01143 
01144 double KoRuler::applyRtlAndZoom( double value ) const
01145 {
01146     int frameWidth = d->frameEnd - frameStart;
01147     return d->rtl ? ( frameWidth - zoomIt( value ) ) : zoomIt( value );
01148 }
01149 
01150 double KoRuler::unZoomItRtl( int pixValue ) const
01151 {
01152     int frameWidth = d->frameEnd - frameStart;
01153     return d->rtl ? ( unZoomIt( (double)(frameWidth - pixValue) ) ) : unZoomIt( (double)pixValue );
01154 }
01155 
01156 void KoRuler::slotMenuActivated( int i )
01157 {
01158     if ( i >= 0 && i <= KoUnit::U_LASTUNIT )
01159     {
01160         KoUnit::Unit unit = static_cast<KoUnit::Unit>(i);
01161         setUnit( unit );
01162         emit unitChanged( unit );
01163     }
01164 }
01165 
01166 QSize KoRuler::minimumSizeHint() const
01167 {
01168     QSize size;
01169     QFont font; // Use the global KDE font. Let's hope it's appropriate.
01170     font.setPointSize( 8 );
01171     QFontMetrics fm( font );
01172 
01173     size.setWidth( fm.height() + 4 );
01174     size.setHeight( fm.height() + 4 );
01175 
01176     return size;
01177 }
01178 
01179 QSize KoRuler::sizeHint() const
01180 {
01181     return minimumSizeHint();
01182 }
01183 
01184 void KoRuler::setPageLayout( const KoPageLayout& _layout )
01185 {
01186     d->layout = _layout;
01187     update();
01188 }
01189 
01190 #include "koRuler.moc"
KDE Logo
This file is part of the documentation for lib Library Version 1.4.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Mon Feb 13 09:40:05 2006 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003