Commit 210a0d44 authored by Piotr Szymanski's avatar Piotr Szymanski

- backport links in presentations

svn path=/trunk/playground/graphics/oKular/kpdf/; revision=435938
parent 931271f9
......@@ -470,7 +470,7 @@ void PDFGenerator::generatePixmap( PixmapRequest * request )
bool genTextPage = !page->hasSearchPage() && (request->width == page->width()) &&
(request->height == page->height());
// generate links and image rects if rendering pages on pageview
bool genObjectRects = request->id == PAGEVIEW_ID;
bool genObjectRects = request->id & (PAGEVIEW_ID | PRESENTATION_ID);
// 0. LOCK [waits for the thread end]
docLock.lock();
......@@ -2225,7 +2225,7 @@ void PDFPixmapGeneratorThread::run()
( height == page->height() );
// generate links and image rects if rendering pages on pageview
bool genObjectRects = d->currentRequest->id == PAGEVIEW_ID;
bool genObjectRects = d->currentRequest->id & (PAGEVIEW_ID | PRESENTATION_ID);
// 0. LOCK s[tart locking XPDF thread unsafe classes]
d->generator->docLock.lock();
......
......@@ -11,13 +11,14 @@
#include <qtimer.h>
#include <qimage.h>
#include <qpainter.h>
#include <qtooltip.h>
#include <qapplication.h>
#include <qdesktopwidget.h>
#include <kapplication.h>
#include <kcursor.h>
#include <ktoolbar.h>
#include <kdebug.h>
#include <klocale.h>
#include <kdebug.h>
#include <kiconloader.h>
#include <kimageeffect.h>
#include <kmessagebox.h>
......@@ -32,6 +33,7 @@
#include "pagepainter.h"
#include "core/generator.h"
#include "core/page.h"
#include "core/link.h"
#include "conf/settings.h"
......@@ -49,7 +51,8 @@ struct PresentationFrame
PresentationWidget::PresentationWidget( QWidget * parent, KPDFDocument * doc )
: QDialog( parent, "presentationWidget", true, WDestructiveClose | WStyle_NoBorder), m_document( doc ), m_frameIndex( -1 )
: QDialog( parent, "presentationWidget", true, WDestructiveClose | WStyle_NoBorder),
m_pressedLink( 0 ), m_handCursor( false ), m_document( doc ), m_frameIndex( -1 )
{
// set look and geometry
setBackgroundMode( Qt::NoBackground );
......@@ -222,32 +225,62 @@ void PresentationWidget::mousePressEvent( QMouseEvent * e )
// pressing left button
if ( e->button() == Qt::LeftButton )
{
// if pressing on a link, skip other checks
if ( ( m_pressedLink = getLink( e->x(), e->y() ) ) )
return;
// handle clicking on top-right overlay
if ( m_overlayGeometry.contains( e->pos() ) )
{
overlayClick( e->pos() );
else
slotNextPage();
return;
}
// if no other actions, go to next page
slotNextPage();
}
// pressing right button
else if ( e->button() == Qt::RightButton )
slotPrevPage();
}
void PresentationWidget::mouseReleaseEvent( QMouseEvent * e )
{
// if releasing on the same link we pressed over, execute it
if ( m_pressedLink && e->button() == Qt::LeftButton )
{
const KPDFLink * link = getLink( e->x(), e->y() );
if ( link == m_pressedLink )
m_document->processLink( link );
m_pressedLink = 0;
}
}
void PresentationWidget::mouseMoveEvent( QMouseEvent * e )
{
if (m_width == -1) return;
// hide a shown bar when exiting the area
// safety check
if ( m_width == -1 )
return;
// update cursor and tooltip if hovering a link
if ( Settings::slidesCursor() != Settings::EnumSlidesCursor::Hidden )
testCursorOnLink( e->x(), e->y() );
if ( m_topBar->isShown() )
{
// hide a shown bar when exiting the area
if ( e->y() > ( m_topBar->height() + 1 ) )
m_topBar->hide();
}
// show a hidden bar if mouse reaches the top of the screen
else if ( !e->y() )
m_topBar->show();
// change page if dragging the mouse over the 'wheel'
else if ( e->state() == Qt::LeftButton && m_overlayGeometry.contains( e->pos() ) )
else
{
// show the bar if reaching top 2 pixels
if ( e->y() <= (geometry().top() + 1) )
m_topBar->show();
// handle "dragging the wheel" if clicking on its geometry
else if ( e->state() == Qt::LeftButton && m_overlayGeometry.contains( e->pos() ) )
overlayClick( e->pos() );
}
}
void PresentationWidget::paintEvent( QPaintEvent * pe )
......@@ -326,6 +359,63 @@ void PresentationWidget::paintEvent( QPaintEvent * pe )
// </widget events>
const KPDFLink * PresentationWidget::getLink( int x, int y, QRect * geometry ) const
{
// no links on invalid pages
if ( geometry && !geometry->isNull() )
geometry->setRect( 0, 0, -1, -1 );
if ( m_frameIndex < 0 || m_frameIndex >= (int)m_frames.size() )
return 0;
// get frame, page and geometry
const PresentationFrame * frame = m_frames[ m_frameIndex ];
const KPDFPage * page = frame->page;
const QRect & frameGeometry = frame->geometry;
// compute normalized x and y
double nx = (double)(x - frameGeometry.left()) / (double)frameGeometry.width();
double ny = (double)(y - frameGeometry.top()) / (double)frameGeometry.height();
// no links outside the pages
if ( nx < 0 || nx > 1 || ny < 0 || ny > 1 )
return 0;
// check if 1) there is an object and 2) it's a link
const ObjectRect * object = page->getObjectRect( ObjectRect::Link, nx, ny );
if ( !object )
return 0;
// compute link geometry if destination rect present
if ( geometry )
{
*geometry = object->geometry( frameGeometry.width(), frameGeometry.height() );
geometry->moveBy( frameGeometry.left(), frameGeometry.top() );
}
// return the link pointer
return (KPDFLink *)object->pointer();
}
void PresentationWidget::testCursorOnLink( int x, int y )
{
// get rect
QRect linkRect;
const KPDFLink * link = getLink( x, y, &linkRect );
// only react on changes (in/out from a link)
if ( (link && !m_handCursor) || (!link && m_handCursor) )
{
// change cursor shape
m_handCursor = link != 0;
setCursor( m_handCursor ? KCursor::handCursor() : KCursor::arrowCursor() );
// set tooltip over link's rect
QString tip = link ? link->linkTip() : "";
if ( m_handCursor && !tip.isEmpty() )
QToolTip::add( this, linkRect, tip );
}
}
void PresentationWidget::overlayClick( const QPoint & position )
{
// clicking the progress indicator
......@@ -357,12 +447,20 @@ void PresentationWidget::changePage( int newPage )
// notifyPixmapChanged call or else we can proceed to pixmap generation
if ( !frame->page->hasPixmap( PRESENTATION_ID, pixW, pixH ) )
{
// operation will take long: set busy cursor
QApplication::setOverrideCursor( KCursor::workingCursor() );
// request the pixmap
QValueList< PixmapRequest * > request;
request.push_back( new PixmapRequest( PRESENTATION_ID, m_frameIndex, pixW, pixH, PRESENTATION_PRIO ) );
m_document->requestPixmaps( request );
// restore cursor
QApplication::restoreOverrideCursor();
}
else
{
// make the background pixmap
generatePage();
}
}
void PresentationWidget::generatePage()
......@@ -396,6 +494,13 @@ void PresentationWidget::generatePage()
KPDFPageTransition trans = defaultTransition();
initTransition( &trans );
}
// update cursor + tooltip
if ( Settings::slidesCursor() != Settings::EnumSlidesCursor::Hidden )
{
QPoint p = mapFromGlobal( QCursor::pos() );
testCursorOnLink( p.x(), p.y() );
}
}
void PresentationWidget::generateIntroPage( QPainter & p )
......@@ -478,12 +583,14 @@ void PresentationWidget::generateContentsPage( int pageNum, QPainter & p )
}
}
// from Arthur - Qt4 - (is defined elsewhere as 'qt_div_255' to not break final compilation)
inline int qt_div255(int x) { return (x + (x>>8) + 0x80) >> 8; }
void PresentationWidget::generateOverlay()
{
#ifdef ENABLE_PROGRESS_OVERLAY
// calculate overlay geometry and resize pixmap if needed
int side = m_width / 16;
m_overlayGeometry.setRect( m_width - side, 0, side, side );
m_overlayGeometry.setRect( m_width - side - 4, 4, side, side );
if ( m_lastRenderedOverlay.width() != side )
m_lastRenderedOverlay.resize( side, side );
......@@ -497,13 +604,14 @@ void PresentationWidget::generateOverlay()
// draw PIE SLICES in blue levels (the levels will then be the alpha component)
int pages = m_document->pages();
if ( pages > 36 )
if ( pages > 28 )
{ // draw continuous slices
int degrees = (int)( 360 * (float)(m_frameIndex + 1) / (float)pages );
pixmapPainter.setPen( 0x20 );
pixmapPainter.setBrush( 0x10 );
pixmapPainter.setPen( 0x05 );
pixmapPainter.setBrush( 0x40 );
pixmapPainter.drawPie( 2, 2, side - 4, side - 4, 90*16, (360-degrees)*16 );
pixmapPainter.setBrush( 0xC0 );
pixmapPainter.setPen( 0x40 );
pixmapPainter.setBrush( 0xF0 );
pixmapPainter.drawPie( 2, 2, side - 4, side - 4, 90*16, -degrees*16 );
}
else
......@@ -513,7 +621,7 @@ void PresentationWidget::generateOverlay()
{
float newCoord = -90 + 360 * (float)(i + 1) / (float)pages;
pixmapPainter.setPen( i <= m_frameIndex ? 0x40 : 0x05 );
pixmapPainter.setBrush( i <= m_frameIndex ? 0xC0 : 0x10 );
pixmapPainter.setBrush( i <= m_frameIndex ? 0xF0 : 0x40 );
pixmapPainter.drawPie( 2, 2, side - 4, side - 4,
(int)( -16*(oldCoord + 1) ), (int)( -16*(newCoord - (oldCoord + 2)) ) );
oldCoord = newCoord;
......@@ -534,17 +642,52 @@ void PresentationWidget::generateOverlay()
// end drawing pixmap and halve image
pixmapPainter.end();
side /= 2;
QImage image( doublePixmap.convertToImage().smoothScale( side, side ) );
QImage image( doublePixmap.convertToImage().smoothScale( side / 2, side / 2 ) );
image.setAlphaBuffer( true );
// FIXME: obey palette (highlighe colors), but only after dropping an
// inverse shadow that will make contrast with the wheel
int red = 52, green = 115, blue = 178,
pixels = image.width() * image.height();
unsigned int * data = (unsigned int *)image.bits();
for( int i = 0; i < pixels; ++i )
data[i] = qRgba( red, green, blue, data[i] & 0xFF );
// draw circular shadow using the same technique
doublePixmap.fill( Qt::black );
pixmapPainter.begin( &doublePixmap );
pixmapPainter.setPen( 0x40 );
pixmapPainter.setBrush( 0x80 );
pixmapPainter.drawEllipse( 0, 0, side, side );
pixmapPainter.end();
QImage shadow( doublePixmap.convertToImage().smoothScale( side / 2, side / 2 ) );
// generate a 2 colors pixmap using mixing shadow (made with highlight color)
// and image (made with highlightedText color)
QColor color = palette().active().highlightedText();
int red = color.red(), green = color.green(), blue = color.blue();
color = palette().active().highlight();
int sRed = color.red(), sGreen = color.green(), sBlue = color.blue();
// pointers
unsigned int * data = (unsigned int *)image.bits(),
* shadowData = (unsigned int *)shadow.bits(),
pixels = image.width() * image.height();
// cache data (reduce computation time to 26%!)
int c1 = -1, c2 = -1, cR = 0, cG = 0, cB = 0, cA = 0;
// foreach pixel
for( unsigned int i = 0; i < pixels; ++i )
{
// alpha for shadow and image
int shadowAlpha = shadowData[i] & 0xFF,
srcAlpha = data[i] & 0xFF;
// cache values
if ( srcAlpha != c1 || shadowAlpha != c2 )
{
c1 = srcAlpha;
c2 = shadowAlpha;
// fuse color components and alpha value of image over shadow
data[i] = qRgba(
cR = qt_div255( srcAlpha * red + (255 - srcAlpha) * sRed ),
cG = qt_div255( srcAlpha * green + (255 - srcAlpha) * sGreen ),
cB = qt_div255( srcAlpha * blue + (255 - srcAlpha) * sBlue ),
cA = qt_div255( srcAlpha * srcAlpha + (255 - srcAlpha) * shadowAlpha )
);
}
else
data[i] = qRgba( cR, cG, cB, cA );
}
m_lastRenderedOverlay.convertFromImage( image );
// start the autohide timer
......
......@@ -22,6 +22,7 @@ class QTimer;
class KPDFDocument;
class KPDFPage;
class KPDFLink;
class PresentationFrame;
/**
......@@ -49,10 +50,13 @@ class PresentationWidget : public QDialog, public DocumentObserver
void keyPressEvent( QKeyEvent * e );
void wheelEvent( QWheelEvent * e );
void mousePressEvent( QMouseEvent * e );
void mouseReleaseEvent( QMouseEvent * e );
void mouseMoveEvent( QMouseEvent * e );
void paintEvent( QPaintEvent * e );
private:
const KPDFLink * getLink( int x, int y, QRect * geometry = 0 ) const;
void testCursorOnLink( int x, int y );
void overlayClick( const QPoint & position );
void changePage( int newPage );
void generatePage();
......@@ -69,6 +73,8 @@ class PresentationWidget : public QDialog, public DocumentObserver
QPixmap m_lastRenderedPixmap;
QPixmap m_lastRenderedOverlay;
QRect m_overlayGeometry;
const KPDFLink * m_pressedLink;
bool m_handCursor;
// transition related
QTimer * m_transitionTimer;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment