lib

KoRuler.cpp

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