pageviewutils.cpp 25.1 KB
Newer Older
1
/***************************************************************************
2
 *   Copyright (C) 2004-2005 by Enrico Ros <eros.kde@email.it>             *
3 4 5 6 7 8 9
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 ***************************************************************************/

Albert Astals Cid's avatar
Albert Astals Cid committed
10 11
#include "pageviewutils.h"

12
// qt/kde includes
13
#include <qapplication.h>
14
#include <qbitmap.h>
15
#include <qbrush.h>
16
#include <qimage.h>
17 18
#include <qlabel.h>
#include <qlayout.h>
19
#include <qpainter.h>
Albert Astals Cid's avatar
Albert Astals Cid committed
20
#include <qevent.h>
21
#include <qstyle.h>
22
#include <qtimer.h>
23
#include <qtoolbutton.h>
Albert Astals Cid's avatar
Albert Astals Cid committed
24 25
#include <kacceleratormanager.h>
#include <kiconloader.h>
26 27 28 29
#include <klocale.h>

// system includes
#include <math.h>
30 31

// local includes
32
#include "formwidgets.h"
33
#include "guiutils.h"
34
#include "core/page.h"
35
#include "settings.h"
36

37 38 39
/*********************/
/** PageViewItem     */
/*********************/
40

41
PageViewItem::PageViewItem( const Okular::Page * page )
42 43
    : m_page( page ), m_zoomFactor( 1.0 ), m_visible( true ),
    m_formsVisible( false )
44 45 46
{
}

47 48 49 50 51 52 53
PageViewItem::~PageViewItem()
{
    QHash<QString, FormWidgetIface*>::iterator it = m_formWidgets.begin(), itEnd = m_formWidgets.end();
    for ( ; it != itEnd; ++it )
        delete *it;
}

54
const Okular::Page * PageViewItem::page() const
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
{
    return m_page;
}

int PageViewItem::pageNumber() const
{
    return m_page->number();
}

const QRect& PageViewItem::geometry() const
{
    return m_geometry;
}

int PageViewItem::width() const
{
    return m_geometry.width();
}

int PageViewItem::height() const
{
    return m_geometry.height();
}

double PageViewItem::zoomFactor() const
{
    return m_zoomFactor;
}

84 85 86 87 88
bool PageViewItem::isVisible() const
{
    return m_visible;
}

89 90 91 92 93
QHash<QString, FormWidgetIface*>& PageViewItem::formWidgets()
{
    return m_formWidgets;
}

94 95 96 97 98 99 100 101 102 103
void PageViewItem::setGeometry( int x, int y, int width, int height )
{
    m_geometry.setRect( x, y, width, height );
}

void PageViewItem::setWHZ( int w, int h, double z )
{
    m_geometry.setWidth( w );
    m_geometry.setHeight( h );
    m_zoomFactor = z;
104
    foreach(FormWidgetIface *fwi, m_formWidgets)
105
    {
106 107
        Okular::NormalizedRect r = fwi->rect();
        fwi->setWidthHeight( qRound( fabs( r.right - r.left ) * w ), qRound( fabs( r.bottom - r.top ) * h ) );
108
    }
109 110 111 112 113 114
}

void PageViewItem::moveTo( int x, int y )
{
    m_geometry.moveLeft( x );
    m_geometry.moveTop( y );
115 116 117 118
    QHash<QString, FormWidgetIface*>::iterator it = m_formWidgets.begin(), itEnd = m_formWidgets.end();
    for ( ; it != itEnd; ++it )
    {
        Okular::NormalizedRect r = (*it)->rect();
119
        (*it)->moveTo( qRound( x + m_geometry.width() * r.left ) + 1, qRound( y + m_geometry.height() * r.top ) + 1 );
120
    }
121 122
}

123 124
void PageViewItem::setVisible( bool visible )
{
125
    setFormWidgetsVisible( visible && m_formsVisible );
126 127 128
    m_visible = visible;
}

129 130 131 132
void PageViewItem::invalidate()
{
    m_geometry.setRect( 0, 0, 0, 0 );
}
133

134
bool PageViewItem::setFormWidgetsVisible( bool visible )
135
{
136 137 138 139 140
    m_formsVisible = visible;

    if ( !m_visible )
        return false;

141
    bool somehadfocus = false;
142 143
    QHash<QString, FormWidgetIface*>::iterator it = m_formWidgets.begin(), itEnd = m_formWidgets.end();
    for ( ; it != itEnd; ++it )
144 145 146 147
    {
        bool hadfocus = (*it)->setVisibility( visible );
        somehadfocus = somehadfocus || hadfocus;
    }
148
    return somehadfocus;
149 150
}

151 152 153
/*********************/
/** PageViewMessage  */
/*********************/
154

155
PageViewMessage::PageViewMessage( QWidget * parent )
Pino Toscano's avatar
Pino Toscano committed
156
    : QWidget( parent ), m_timer( 0 )
157
{
Pino Toscano's avatar
Pino Toscano committed
158
    setObjectName( "pageViewMessage" );
Albert Astals Cid's avatar
Albert Astals Cid committed
159
    setFocusPolicy( Qt::NoFocus );
160 161 162 163
    setAttribute( Qt::WA_OpaquePaintEvent );
    QPalette pal = palette();
    pal.setColor( QPalette::Active, QPalette::Window, QApplication::palette().color( QPalette::Active, QPalette::Window ) );
    setPalette( pal );
164
    // if the layout is LtR, we can safely place it in the right position
165
    if ( layoutDirection() == Qt::LeftToRight )
166
        move( 10, 10 );
167 168 169 170 171
    resize( 0, 0 );
    hide();
}

void PageViewMessage::display( const QString & message, Icon icon, int durationMs )
172
// give Caesar what belongs to Caesar: code taken from Amarok's osd.h/.cpp
173
// "redde (reddite, pl.) cesari quae sunt cesaris", just btw.  :)
174
{
175
    if ( !Okular::Settings::showOSD() )
176 177 178 179 180
    {
        hide();
        return;
    }

181 182
    bool isRTL = layoutDirection() == Qt::RightToLeft;

183 184
    // determine text rectangle
    QRect textRect = fontMetrics().boundingRect( message );
Pino Toscano's avatar
Pino Toscano committed
185 186
    textRect.translate( -textRect.left(), -textRect.top() );
    textRect.adjust( 0, 0, 2, 2 );
187 188 189
    int width = textRect.width(),
        height = textRect.height(),
        textXOffset = 0,
190
        iconXOffset = 0,
191
        shadowOffset = 1;
192 193 194 195 196 197 198

    // load icon (if set) and update geometry
    QPixmap symbol;
    if ( icon != None )
    {
        switch ( icon )
        {
199
            case Annotation:
Pino Toscano's avatar
Pino Toscano committed
200
                symbol = SmallIcon( "draw-freehand" );
201
                break;
202
            case Find:
203
                symbol = SmallIcon( "zoom-original" );
204
                break;
205
            case Error:
206
                symbol = SmallIcon( "dialog-error" );
207 208
                break;
            case Warning:
209
                symbol = SmallIcon( "dialog-warning" );
210 211
                break;
            default:
212
                symbol = SmallIcon( "dialog-information" );
213 214
                break;
        }
215
        if ( isRTL )
216 217 218 219 220 221 222 223
        {
            iconXOffset = 2 + textRect.width();
        }
        else
        {
            textXOffset = 2 + symbol.width();
        }
        width += 2 + symbol.width();
Pino Toscano's avatar
Pino Toscano committed
224
        height = qMax( height, symbol.height() );
225 226 227 228
    }
    QRect geometry( 0, 0, width + 10, height + 8 );

    // resize pixmap, mask and widget
229
    QBitmap mask( geometry.size() + QSize( 1, 1 ) );
Pino Toscano's avatar
Pino Toscano committed
230
    m_pixmap = QPixmap( geometry.size() + QSize( 1, 1 ) );
231
    resize( geometry.size() + QSize( 1, 1 ) );
232 233 234

    // create and set transparency mask
    QPainter maskPainter( &mask);
Albert Astals Cid's avatar
Albert Astals Cid committed
235 236
    mask.fill( Qt::white );
    maskPainter.setBrush( Qt::black );
237
    maskPainter.drawRoundRect( geometry, 1600 / geometry.width(), 1600 / geometry.height() );
238
    maskPainter.end();
239 240 241
    setMask( mask );

    // draw background
242
    QPalette pal = palette();
243 244
    QPainter bufferPainter( &m_pixmap );
    bufferPainter.setPen( Qt::black );
245
    bufferPainter.setBrush( pal.color( QPalette::Window ) );
246 247 248 249
    bufferPainter.drawRoundRect( geometry, 1600 / geometry.width(), 1600 / geometry.height() );

    // draw icon if present
    if ( !symbol.isNull() )
250
        bufferPainter.drawPixmap( 5 + iconXOffset, 4, symbol, 0, 0, symbol.width(), symbol.height() );
251 252

    // draw shadow and text
253
    int yText = geometry.height() - height / 2;
254
    bufferPainter.setPen( pal.color( QPalette::Window ).dark( 115 ) );
255
    bufferPainter.drawText( 5 + textXOffset + shadowOffset, yText + 1, message );
256
    bufferPainter.setPen( pal.color( QPalette::WindowText ) );
257
    bufferPainter.drawText( 5 + textXOffset, yText, message );
258

259 260
    // if the layout is RtL, we can move it to the right place only after we
    // know how much size it will take
261
    if ( isRTL )
262 263
        move( parentWidget()->width() - geometry.width() - 10 - 1, 10 );

264 265 266 267 268 269 270 271 272 273
    // show widget and schedule a repaint
    show();
    update();

    // close the message window after given mS
    if ( durationMs > 0 )
    {
        if ( !m_timer )
        {
            m_timer = new QTimer( this );
274
            m_timer->setSingleShot( true );
275 276
            connect( m_timer, SIGNAL( timeout() ), SLOT( hide() ) );
        }
277
        m_timer->start( durationMs );
278 279
    } else if ( m_timer )
        m_timer->stop();
280 281 282 283
}

void PageViewMessage::paintEvent( QPaintEvent * e )
{
284
    // paint the internal pixmap over the widget
Tobias Koenig's avatar
Tobias Koenig committed
285 286
    QPainter p( this );
    p.drawPixmap( e->rect().topLeft(), m_pixmap, e->rect() );
287 288
}

289
void PageViewMessage::mousePressEvent( QMouseEvent * /*e*/ )
290 291 292 293 294
{
    if ( m_timer )
        m_timer->stop();
    hide();
}
295 296


297 298 299 300 301
/************************/
/** PageViewTopMessage  */
/************************/

PageViewTopMessage::PageViewTopMessage( QWidget * parent )
302
    : QWidget( parent )
303 304 305 306 307 308
{
    setAutoFillBackground( true );
    QPalette pal = palette();
    pal.setColor( QPalette::Active, QPalette::Window, Qt::yellow );
    pal.setColor( QPalette::Inactive, QPalette::Window, Qt::yellow );
    pal.setColor( QPalette::Disabled, QPalette::Window, Qt::yellow );
309
    pal.setColor( QPalette::WindowText, Qt::black );
310 311 312
    setPalette( pal );
    QHBoxLayout * lay = new QHBoxLayout( this );
    lay->setMargin( 4 );
313 314 315
    m_icon = new QLabel( this );
    lay->addWidget( m_icon );
    m_icon->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
316 317 318 319
    m_label = new QLabel( this );
    lay->addWidget( m_label );
    m_label->setWordWrap( true );
    connect( m_label, SIGNAL( linkActivated( const QString& ) ), this, SIGNAL( action() ) );
320
    m_button = new QToolButton( this );
321
    m_button->setVisible( false );
322
    lay->addWidget( m_button );
323 324 325 326 327 328 329
    QToolButton * closeButton = new QToolButton( this );
    lay->addWidget( closeButton );
    closeButton->setAutoRaise( true );
    closeButton->setIcon( closeButton->style()->standardIcon( QStyle::SP_TitleBarCloseButton ) );
    closeButton->setIconSize( QSize( 32, 32 ) );
    closeButton->setToolTip( i18n( "Close this message" ) );
    connect( closeButton, SIGNAL( clicked() ), this, SLOT( hide() ) );
330
    setIconSize( 32 );
331 332 333
    hide();
}

334
void PageViewTopMessage::setup( const QString & message, const KIcon& icon )
335 336 337
{
    m_label->setText( message );
    resize( minimumSizeHint() );
338 339 340 341 342 343 344 345
    if ( icon.isNull() )
    {
        m_icon->setPixmap( QPixmap() );
    }
    else
    {
        m_icon->setPixmap( icon.pixmap( m_icon->size() ) );
    }
346 347
}

348 349 350 351 352
void PageViewTopMessage::setIconSize( int size )
{
    m_icon->resize( size, size );
}

353 354 355
void PageViewTopMessage::setActionButton( QAction * action )
{
    m_button->setDefaultAction( action );
356
    m_button->setVisible( action != 0 );
357
}
358

359 360 361 362
/*********************/
/** PageViewToolBar  */
/*********************/

363
ToolBarButton::ToolBarButton( QWidget * parent, const AnnotationToolItem &item )
Pino Toscano's avatar
Pino Toscano committed
364
    : QToolButton( parent ), m_id( item.id ), m_isText( item.isText )
365
{
Pino Toscano's avatar
Pino Toscano committed
366
    setCheckable( true );
367
    setAutoRaise( true );
368
    resize( buttonSize, buttonSize );
369
    setIconSize( QSize( iconSize, iconSize ) );
370
    setIcon( KIcon( item.pixmap, GuiUtils::iconLoader() ) );
371 372
    // set shortcut if defined
    if ( !item.shortcut.isEmpty() )
373
        setShortcut( QKeySequence( item.shortcut ) );
374 375
    else
        KAcceleratorManager::setNoAccel( this );
Albert Astals Cid's avatar
Albert Astals Cid committed
376

377
    // if accel is set display it along name
378
    QString accelString = shortcut().toString( QKeySequence::NativeText );
379
    if ( !accelString.isEmpty() )
380
        setToolTip( QString("%1 [%2]").arg( item.text ).arg( accelString ) );
381
    else
Pino Toscano's avatar
Pino Toscano committed
382
        setToolTip( item.text );
383 384 385 386 387 388
}

/* PageViewToolBar */

static const int toolBarGridSize = 40;

Christian Ehrlicher's avatar
Christian Ehrlicher committed
389
class ToolBarPrivate
390
{
Christian Ehrlicher's avatar
Christian Ehrlicher committed
391
public:
392 393 394 395 396 397 398 399 400 401 402
    ToolBarPrivate( PageViewToolBar * qq )
        : q( qq )
    {
    }

    // rebuild contents and reposition then widget
    void buildToolBar();
    void reposition();
    // compute the visible and hidden positions along current side
    QPoint getInnerPoint() const;
    QPoint getOuterPoint() const;
403
    void selectButton( ToolBarButton * button );
404 405 406

    PageViewToolBar * q;

407 408 409 410 411 412 413 414 415
    // anchored widget and side
    QWidget * anchorWidget;
    PageViewToolBar::Side anchorSide;

    // slide in/out stuff
    QTimer * animTimer;
    QPoint currentPosition;
    QPoint endPosition;
    bool hiding;
416
    bool visible;
417 418 419

    // background pixmap and buttons
    QPixmap backgroundPixmap;
Albert Astals Cid's avatar
Albert Astals Cid committed
420
    QLinkedList< ToolBarButton * > buttons;
421 422 423
};

PageViewToolBar::PageViewToolBar( QWidget * parent, QWidget * anchorWidget )
424
    : QWidget( parent ), d( new ToolBarPrivate( this ) )
425
{
Pino Toscano's avatar
Pino Toscano committed
426 427
    setAttribute( Qt::WA_OpaquePaintEvent, true );

428 429 430 431
    // initialize values of the private data storage structure
    d->anchorWidget = anchorWidget;
    d->anchorSide = Left;
    d->hiding = false;
432
    d->visible = false;
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447

    // create the animation timer
    d->animTimer = new QTimer( this );
    connect( d->animTimer, SIGNAL( timeout() ), this, SLOT( slotAnimate() ) );

    // apply a filter to get notified when anchor changes geometry
    d->anchorWidget->installEventFilter( this );
}

PageViewToolBar::~PageViewToolBar()
{
    // delete the private data storage structure
    delete d;
}

448
void PageViewToolBar::setItems( const QLinkedList<AnnotationToolItem> &items )
449 450 451 452
{
    // delete buttons if already present
    if ( !d->buttons.isEmpty() )
    {
Albert Astals Cid's avatar
Albert Astals Cid committed
453
        QLinkedList< ToolBarButton * >::iterator it = d->buttons.begin(), end = d->buttons.end();
454 455 456 457 458 459
        for ( ; it != end; ++it )
            delete *it;
        d->buttons.clear();
    }

    // create new buttons for given items
460
    QLinkedList<AnnotationToolItem>::const_iterator it = items.begin(), end = items.end();
461 462
    for ( ; it != end; ++it )
    {
463
        ToolBarButton * button = new ToolBarButton( this, *it );
464
        connect( button, SIGNAL( clicked() ), this, SLOT( slotButtonClicked() ) );
465 466 467 468
        d->buttons.append( button );
    }

    // rebuild toolbar shape and contents
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483
    d->reposition();
}

void PageViewToolBar::setSide( Side side )
{
    d->anchorSide = side;

    d->reposition();
}

void PageViewToolBar::showAndAnimate()
{
    // set parameters for sliding in
    d->hiding = false;

484 485
    show();

486
#ifdef OKULAR_ANIMATE_REVIEW_TOOBAR
487 488
    // start scrolling in
    d->animTimer->start( 20 );
489 490 491 492 493 494 495
#else
    d->currentPosition = d->endPosition;

    move( d->currentPosition );

    d->visible = true;
#endif
496 497 498 499 500 501
}

void PageViewToolBar::hideAndDestroy()
{
    // set parameters for sliding out
    d->hiding = true;
502
    d->endPosition = d->getOuterPoint();
503

504
#ifdef OKULAR_ANIMATE_REVIEW_TOOBAR
505 506
    // start scrolling out
    d->animTimer->start( 20 );
507 508 509 510 511 512 513 514
#else
    d->currentPosition = d->endPosition;

    move( d->currentPosition );

    d->visible = false;
    deleteLater();
#endif
515 516
}

517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
void PageViewToolBar::selectButton( int id )
{
    ToolBarButton * button = 0;
    if ( id >= 0 && id < d->buttons.count() )
        button = *(d->buttons.begin() + id);
    else
    {
        QLinkedList< ToolBarButton * >::const_iterator it = d->buttons.begin(), end = d->buttons.end();
        for ( ; !button && it != end; ++it )
            if ( (*it)->isChecked() )
                button = *it;
        if ( button )
            button->setChecked( false );
    }
    d->selectButton( button );
}

534 535 536 537 538 539 540 541 542
bool PageViewToolBar::eventFilter( QObject * obj, QEvent * e )
{
    // if anchorWidget changed geometry reposition toolbar
    if ( obj == d->anchorWidget && e->type() == QEvent::Resize )
    {
        d->animTimer->stop();
        if ( d->hiding )
            deleteLater();
        else
543
            d->reposition();
544 545 546 547 548 549 550 551 552
    }

    // don't block event
    return false;
}

void PageViewToolBar::paintEvent( QPaintEvent * e )
{
    // paint the internal pixmap over the widget
Tobias Koenig's avatar
Tobias Koenig committed
553 554
    QPainter p( this );
    p.drawPixmap( e->rect().topLeft(), d->backgroundPixmap, e->rect() );
555 556 557 558 559 560
}

void PageViewToolBar::mousePressEvent( QMouseEvent * e )
{
    // set 'dragging' cursor
    if ( e->button() == Qt::LeftButton )
Pino Toscano's avatar
Pino Toscano committed
561
        setCursor( Qt::SizeAllCursor );
562 563 564 565
}

void PageViewToolBar::mouseMoveEvent( QMouseEvent * e )
{
566
    if ( ( QApplication::mouseButtons() & Qt::LeftButton ) != Qt::LeftButton )
567 568 569 570 571 572 573 574 575 576 577 578
        return;

    // compute the nearest side to attach the widget to
    QPoint parentPos = mapToParent( e->pos() );
    float nX = (float)parentPos.x() / (float)d->anchorWidget->width(),
          nY = (float)parentPos.y() / (float)d->anchorWidget->height();
    if ( nX > 0.3 && nX < 0.7 && nY > 0.3 && nY < 0.7 )
        return;
    bool LT = nX < (1.0 - nY);
    bool LB = nX < (nY);
    Side side = LT ? ( LB ? Left : Top ) : ( LB ? Bottom : Right );

579 580 581
    // check if side changed
    if ( side == d->anchorSide )
        return;
582

583
    d->anchorSide = side;
584
    d->reposition();
585
    emit orientationChanged( (int)side );
586 587 588 589 590 591
}

void PageViewToolBar::mouseReleaseEvent( QMouseEvent * e )
{
    // set normal cursor
    if ( e->button() == Qt::LeftButton )
Pino Toscano's avatar
Pino Toscano committed
592
        setCursor( Qt::ArrowCursor );
593 594
}

595
void ToolBarPrivate::buildToolBar()
596
{
597 598 599
    int buttonsNumber = buttons.count(),
        parentWidth = anchorWidget->width(),
        parentHeight = anchorWidget->height(),
600 601 602 603
        myCols = 1,
        myRows = 1;

    // 1. find out columns and rows we're going to use
604 605
    bool topLeft = anchorSide == PageViewToolBar::Left || anchorSide == PageViewToolBar::Top;
    bool vertical = anchorSide == PageViewToolBar::Left || anchorSide == PageViewToolBar::Right;
606 607 608 609
    if ( vertical )
    {
        myCols = 1 + (buttonsNumber * toolBarGridSize) /
                 (parentHeight - toolBarGridSize);
Enrico Ros's avatar
Enrico Ros committed
610
        myRows = (int)ceil( (float)buttonsNumber / (float)myCols );
611 612 613 614 615
    }
    else
    {
        myRows = 1 + (buttonsNumber * toolBarGridSize) /
                 (parentWidth - toolBarGridSize);
Enrico Ros's avatar
Enrico Ros committed
616
        myCols = (int)ceil( (float)buttonsNumber / (float)myRows );
617 618 619 620 621 622 623 624 625 626 627 628 629
    }

    // 2. compute widget size (from rows/cols)
    int myWidth = myCols * toolBarGridSize,
        myHeight = myRows * toolBarGridSize,
        xOffset = (toolBarGridSize - ToolBarButton::buttonSize) / 2,
        yOffset = (toolBarGridSize - ToolBarButton::buttonSize) / 2;

    if ( vertical )
    {
        myHeight += 16;
        myWidth += 4;
        yOffset += 12;
630
        if ( anchorSide == PageViewToolBar::Right )
631 632 633 634 635 636 637
            xOffset += 4;
    }
    else
    {
        myWidth += 16;
        myHeight += 4;
        xOffset += 12;
638
        if ( anchorSide == PageViewToolBar::Bottom )
639 640 641
            yOffset += 4;
    }

642 643
    bool prevUpdates = q->updatesEnabled();
    q->setUpdatesEnabled( false );
Pino Toscano's avatar
Pino Toscano committed
644

645
    // 3. resize pixmap, mask and widget
646
    QBitmap mask( myWidth + 1, myHeight + 1 );
647 648
    backgroundPixmap = QPixmap( myWidth + 1, myHeight + 1 );
    q->resize( myWidth + 1, myHeight + 1 );
649 650 651

    // 4. create and set transparency mask
    QPainter maskPainter( &mask);
Pino Toscano's avatar
Pino Toscano committed
652 653
    mask.fill( Qt::white );
    maskPainter.setBrush( Qt::black );
654 655 656 657
    if ( vertical )
        maskPainter.drawRoundRect( topLeft ? -10 : 0, 0, myWidth + 10, myHeight, 2000 / (myWidth + 10), 2000 / myHeight );
    else
        maskPainter.drawRoundRect( 0, topLeft ? -10 : 0, myWidth, myHeight + 10, 2000 / myWidth, 2000 / (myHeight + 10) );
658
    maskPainter.end();
659
    q->setMask( mask );
660 661

    // 5. draw background
662 663
    QPainter bufferPainter( &backgroundPixmap );
    QPalette pal = q->palette();
664
    // 5.1. draw horizontal/vertical gradient
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683
    QLinearGradient grad;
    switch ( anchorSide )
    {
        case PageViewToolBar::Left:
            grad = QLinearGradient( 0, 1, myWidth + 1, 1 );
            break;
        case PageViewToolBar::Right:
            grad = QLinearGradient( myWidth + 1, 1, 0, 1 );
            break;
        case PageViewToolBar::Top:
            grad = QLinearGradient( 1, 0, 1, myHeight + 1 );
            break;
        case PageViewToolBar::Bottom:
            grad = QLinearGradient( 1, myHeight + 1, 0, 1 );
            break;
    }
    grad.setColorAt( 0, pal.color( QPalette::Active, QPalette::Button ) );
    grad.setColorAt( 1, pal.color( QPalette::Active, QPalette::Light ) );
    bufferPainter.fillRect( 0, 0, myWidth + 1, myHeight + 1, grad );
684
    // 5.2. draw rounded border
685
    bufferPainter.setPen( pal.color( QPalette::Active, QPalette::Dark ) );
Urs Wolfer's avatar
Urs Wolfer committed
686
    bufferPainter.setRenderHints( QPainter::Antialiasing );
687 688 689 690 691
    if ( vertical )
        bufferPainter.drawRoundRect( topLeft ? -10 : 0, 0, myWidth + 10, myHeight, 2000 / (myWidth + 10), 2000 / myHeight );
    else
        bufferPainter.drawRoundRect( 0, topLeft ? -10 : 0, myWidth, myHeight + 10, 2000 / myWidth, 2000 / (myHeight + 10) );
    // 5.3. draw handle
692
    bufferPainter.setPen( pal.color( QPalette::Active, QPalette::Mid ) );
693 694
    if ( vertical )
    {
695
        int dx = anchorSide == PageViewToolBar::Left ? 2 : 4;
696 697
        bufferPainter.drawLine( dx, 6, dx + myWidth - 8, 6 );
        bufferPainter.drawLine( dx, 9, dx + myWidth - 8, 9 );
698
        bufferPainter.setPen( pal.color( QPalette::Active, QPalette::Light ) );
699 700 701 702 703
        bufferPainter.drawLine( dx + 1, 7, dx + myWidth - 7, 7 );
        bufferPainter.drawLine( dx + 1, 10, dx + myWidth - 7, 10 );
    }
    else
    {
704
        int dy = anchorSide == PageViewToolBar::Top ? 2 : 4;
705 706
        bufferPainter.drawLine( 6, dy, 6, dy + myHeight - 8 );
        bufferPainter.drawLine( 9, dy, 9, dy + myHeight - 8 );
707
        bufferPainter.setPen( pal.color( QPalette::Active, QPalette::Light ) );
708 709 710 711 712 713 714
        bufferPainter.drawLine( 7, dy + 1, 7, dy + myHeight - 7 );
        bufferPainter.drawLine( 10, dy + 1, 10, dy + myHeight - 7 );
    }

    // 6. reposition buttons (in rows/col grid)
    int gridX = 0,
        gridY = 0;
715
    QLinkedList< ToolBarButton * >::const_iterator it = buttons.begin(), end = buttons.end();
716 717 718 719 720
    for ( ; it != end; ++it )
    {
        ToolBarButton * button = *it;
        button->move( gridX * toolBarGridSize + xOffset,
                      gridY * toolBarGridSize + yOffset );
721
        button->show();
722 723 724 725 726 727
        if ( ++gridX == myCols )
        {
            gridX = 0;
            gridY++;
        }
    }
Pino Toscano's avatar
Pino Toscano committed
728

729
    q->setUpdatesEnabled( prevUpdates );
730 731
}

732
void ToolBarPrivate::reposition()
733 734 735 736
{
    // note: hiding widget here will gives better gfx, but ends drag operation
    // rebuild widget and move it to its final place
    buildToolBar();
737 738 739 740 741 742 743 744 745 746
    if ( !visible )
    {
        currentPosition = getOuterPoint();
        endPosition = getInnerPoint();
    }
    else
    {
        currentPosition = getInnerPoint();
        endPosition = getOuterPoint();
    }
747
    q->move( currentPosition );
748 749

    // repaint all buttons (to update background)
750
    QLinkedList< ToolBarButton * >::const_iterator it = buttons.begin(), end = buttons.end();
751 752 753 754
    for ( ; it != end; ++it )
        (*it)->update();
}

755
QPoint ToolBarPrivate::getInnerPoint() const
756 757
{
    // returns the final position of the widget
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774
    QPoint newPos;
    switch ( anchorSide )
    {
        case PageViewToolBar::Left:
            newPos = QPoint( 0, ( anchorWidget->height() - q->height() ) / 2 );
            break;
        case PageViewToolBar::Top:
            newPos = QPoint( ( anchorWidget->width() - q->width() ) / 2, 0 );
            break;
        case PageViewToolBar::Right:
            newPos = QPoint( anchorWidget->width() - q->width(), ( anchorWidget->height() - q->height() ) / 2 );
            break;
        case PageViewToolBar::Bottom:
            newPos = QPoint( ( anchorWidget->width() - q->width()) / 2, anchorWidget->height() - q->height() );
            break;
    }
    return newPos + anchorWidget->pos();
775 776
}

777
QPoint ToolBarPrivate::getOuterPoint() const
778 779
{
    // returns the point from which the transition starts
780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796
    QPoint newPos;
    switch ( anchorSide )
    {
        case PageViewToolBar::Left:
            newPos = QPoint( -q->width(), ( anchorWidget->height() - q->height() ) / 2 );
            break;
        case PageViewToolBar::Top:
            newPos = QPoint( ( anchorWidget->width() - q->width() ) / 2, -q->height() );
            break;
        case PageViewToolBar::Right:
            newPos = QPoint( anchorWidget->width(), ( anchorWidget->height() - q->height() ) / 2 );
            break;
        case PageViewToolBar::Bottom:
            newPos = QPoint( ( anchorWidget->width() - q->width() ) / 2, anchorWidget->height() );
            break;
    }
    return newPos + anchorWidget->pos();
797 798 799 800 801 802 803
}

void PageViewToolBar::slotAnimate()
{
    // move currentPosition towards endPosition
    int dX = d->endPosition.x() - d->currentPosition.x(),
        dY = d->endPosition.y() - d->currentPosition.y();
Pino Toscano's avatar
Pino Toscano committed
804 805
    dX = dX / 6 + qMax( -1, qMin( 1, dX) );
    dY = dY / 6 + qMax( -1, qMin( 1, dY) );
806 807 808 809 810 811 812 813 814 815 816
    d->currentPosition.setX( d->currentPosition.x() + dX );
    d->currentPosition.setY( d->currentPosition.y() + dY );

    // move the widget
    move( d->currentPosition );

    // handle arrival to the end
    if ( d->currentPosition == d->endPosition )
    {
        d->animTimer->stop();
        if ( d->hiding )
817 818
        {
            d->visible = false;
819
            deleteLater();
820 821 822 823 824
        }
        else
        {
            d->visible = true;
        }
825 826 827
    }
}

828
void PageViewToolBar::slotButtonClicked()
829
{
830
    ToolBarButton * button = qobject_cast<ToolBarButton *>( sender() );
831 832 833 834 835
    d->selectButton( button );
}

void ToolBarPrivate::selectButton( ToolBarButton * button )
{
836 837
    if ( button )
    {
838
        // deselect other buttons
839
        QLinkedList< ToolBarButton * >::const_iterator it = buttons.begin(), end = buttons.end();
840 841 842
        for ( ; it != end; ++it )
            if ( *it != button )
                (*it)->setChecked( false );
843
        // emit signal (-1 if button has been unselected)
844
        emit q->toolSelected( button->isChecked() ? button->buttonID() : -1 );
845 846 847
    }
}

Pino Toscano's avatar
Pino Toscano committed
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862
void PageViewToolBar::setToolsEnabled( bool on )
{
    QLinkedList< ToolBarButton * >::const_iterator it = d->buttons.begin(), end = d->buttons.end();
    for ( ; it != end; ++it )
        (*it)->setEnabled( on );
}

void PageViewToolBar::setTextToolsEnabled( bool on )
{
    QLinkedList< ToolBarButton * >::const_iterator it = d->buttons.begin(), end = d->buttons.end();
    for ( ; it != end; ++it )
        if ( (*it)->isText() )
            (*it)->setEnabled( on );
}

863
#include "pageviewutils.moc"