Just like any other presentation application, now you can draw red paths on a page during the presentation mode.

Like that kind of applications, the drawings are erased when switching page and when exiting the presentation, and there is a button to explicitely clear the page.

svn path=/trunk/playground/graphics/okular/; revision=600982
remotes/origin/KDE/4.0
Pino Toscano 20 years ago
parent fdbd0101a4
commit 4130ba5e49
  1. 175
      ui/presentationwidget.cpp
  2. 10
      ui/presentationwidget.h

@ -36,6 +36,7 @@
// local includes
#include "presentationwidget.h"
#include "annotationtools.h"
#include "pagepainter.h"
#include "core/generator.h"
#include "core/page.h"
@ -58,8 +59,8 @@ struct PresentationFrame
PresentationWidget::PresentationWidget( QWidget * parent, Okular::Document * doc )
: QDialog( parent, Qt::FramelessWindowHint ),
m_pressedLink( 0 ), m_handCursor( false ), m_document( doc ), m_frameIndex( -1 ),
m_topBar( 0 ), m_pagesEdit( 0 )
m_pressedLink( 0 ), m_handCursor( false ), m_drawingEngine( 0 ), m_document( doc ),
m_frameIndex( -1 ), m_topBar( 0 ), m_pagesEdit( 0 )
{
setModal( true );
setAttribute( Qt::WA_DeleteOnClose );
@ -103,6 +104,9 @@ PresentationWidget::~PresentationWidget()
// remove this widget from document observer
m_document->removeObserver( this );
m_document->removePageAnnotations( m_document->viewport().pageNumber, m_currentPageDrawings );
delete m_drawingEngine;
// delete frames
QVector< PresentationFrame * >::iterator fIt = m_frames.begin(), fEnd = m_frames.end();
for ( ; fIt != fEnd; ++fIt )
@ -173,8 +177,8 @@ void PresentationWidget::notifyViewportChanged( bool /*smoothMove*/ )
void PresentationWidget::notifyPageChanged( int pageNumber, int changedFlags )
{
// check if it's the last requested pixmap. if so update the widget.
if ( (changedFlags & DocumentObserver::Pixmap) && pageNumber == m_frameIndex )
generatePage();
if ( (changedFlags & ( DocumentObserver::Pixmap | DocumentObserver::Annotations ) ) && pageNumber == m_frameIndex )
generatePage( changedFlags & DocumentObserver::Annotations );
}
bool PresentationWidget::canUnloadPixmap( int pageNumber )
@ -256,6 +260,17 @@ void PresentationWidget::wheelEvent( QWheelEvent * e )
void PresentationWidget::mousePressEvent( QMouseEvent * e )
{
if ( m_drawingEngine )
{
QRect r = routeMouseDrawingEvent( e );
if ( r.isValid() )
{
m_drawingRect |= r.translated( m_frames[ m_frameIndex ]->geometry.topLeft() );
update( m_drawingRect );
}
return;
}
// pressing left button
if ( e->button() == Qt::LeftButton )
{
@ -280,6 +295,25 @@ void PresentationWidget::mousePressEvent( QMouseEvent * e )
void PresentationWidget::mouseReleaseEvent( QMouseEvent * e )
{
if ( m_drawingEngine )
{
QRect r = routeMouseDrawingEvent( e );
(void)r;
if ( m_drawingEngine->creationCompleted() )
{
QList< Okular::Annotation * > annots = m_drawingEngine->end();
// manually disable and re-enable the pencil mode, so we can do
// cleaning of the actual drawer and create a new one just after
// that - that gives continuous drawing
togglePencilMode( false );
togglePencilMode( true );
foreach( Okular::Annotation * ann, annots )
m_document->addPageAnnotation( m_frameIndex, ann );
m_currentPageDrawings << annots;
}
return;
}
// if releasing on the same link we pressed over, execute it
if ( m_pressedLink && e->button() == Qt::LeftButton )
{
@ -297,7 +331,7 @@ void PresentationWidget::mouseMoveEvent( QMouseEvent * e )
return;
// update cursor and tooltip if hovering a link
if ( Okular::Settings::slidesCursor() != Okular::Settings::EnumSlidesCursor::Hidden )
if ( !m_drawingEngine && Okular::Settings::slidesCursor() != Okular::Settings::EnumSlidesCursor::Hidden )
testCursorOnLink( e->x(), e->y() );
if ( !m_topBar->isHidden() )
@ -311,12 +345,23 @@ void PresentationWidget::mouseMoveEvent( QMouseEvent * e )
}
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 ( ( QApplication::mouseButtons() & Qt::LeftButton ) && m_overlayGeometry.contains( e->pos() ) )
overlayClick( e->pos() );
if ( m_drawingEngine && e->buttons() != Qt::NoButton )
{
QRect r = routeMouseDrawingEvent( e );
{
m_drawingRect |= r.translated( m_frames[ m_frameIndex ]->geometry.topLeft() );
update( m_drawingRect );
}
}
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 ( ( QApplication::mouseButtons() & Qt::LeftButton ) && m_overlayGeometry.contains( e->pos() ) )
overlayClick( e->pos() );
}
}
}
@ -344,6 +389,12 @@ void PresentationWidget::paintEvent( QPaintEvent * pe )
m_topBar->addWidget( m_pagesEdit );
connect( m_pagesEdit, SIGNAL( returnPressed() ), this, SLOT( slotPageChanged() ) );
m_topBar->addAction( KIcon( layoutDirection() == Qt::RightToLeft ? "1leftarrow" : "1rightarrow" ), i18n("Next Page"), this, SLOT( slotNextPage() ) );
m_topBar->addSeparator();
QAction * drawingAct = m_topBar->addAction( KIcon( "pencil" ), i18n( "Toggle Drawing Mode" ) );
drawingAct->setCheckable( true );
connect( drawingAct, SIGNAL( toggled( bool ) ), this, SLOT( togglePencilMode( bool ) ) );
QAction * eraseDrawingAct = m_topBar->addAction( KIcon( "eraser" ), i18n( "Erase Drawings" ) );
connect( eraseDrawingAct, SIGNAL( triggered() ), this, SLOT( clearDrawings() ) );
QWidget *spacer = new QWidget(m_topBar);
spacer->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::MinimumExpanding );
m_topBar->addWidget( spacer );
@ -402,6 +453,14 @@ void PresentationWidget::paintEvent( QPaintEvent * pe )
// copy the rendered pixmap to the screen
painter.drawPixmap( r.topLeft(), m_lastRenderedPixmap, r );
}
if ( m_drawingEngine && m_drawingRect.intersects( pe->rect() ) )
{
const QRect & geom = m_frames[ m_frameIndex ]->geometry;
painter.save();
painter.translate( geom.topLeft() );
m_drawingEngine->paint( &painter, geom.width(), geom.height(), m_drawingRect.intersect( pe->rect() ) );
painter.restore();
}
painter.end();
}
// </widget events>
@ -512,10 +571,14 @@ void PresentationWidget::changePage( int newPage )
// set a new viewport in document if page number differs
if ( m_frameIndex != -1 && m_frameIndex != m_document->viewport().pageNumber )
{
// remove the drawing on the old page before switching
clearDrawings();
m_document->setViewportPage( m_frameIndex, PRESENTATION_ID );
}
}
void PresentationWidget::generatePage()
void PresentationWidget::generatePage( bool disableTransition )
{
if ( m_lastRenderedPixmap.isNull() )
m_lastRenderedPixmap = QPixmap( m_width, m_height );
@ -538,12 +601,20 @@ void PresentationWidget::generatePage()
#endif
// start transition on pages that have one
const Okular::PageTransition * transition = m_frameIndex != -1 ?
m_frames[ m_frameIndex ]->page->getTransition() : 0;
if ( transition )
initTransition( transition );
else {
Okular::PageTransition trans = defaultTransition();
if ( !disableTransition )
{
const Okular::PageTransition * transition = m_frameIndex != -1 ?
m_frames[ m_frameIndex ]->page->getTransition() : 0;
if ( transition )
initTransition( transition );
else {
Okular::PageTransition trans = defaultTransition();
initTransition( &trans );
}
}
else
{
Okular::PageTransition trans = defaultTransition( Okular::Settings::EnumSlidesTransition::Replace );
initTransition( &trans );
}
@ -618,7 +689,7 @@ void PresentationWidget::generateContentsPage( int pageNum, QPainter & p )
geom.translate( -geom.left(), -geom.top() );
// draw the page using the shared PagePainter class
int flags = PagePainter::Accessibility;
int flags = PagePainter::Accessibility | PagePainter::Annotations;
PagePainter::paintPageOnPainter( &p, frame->page, PRESENTATION_ID, flags,
geom.width(), geom.height(), geom );
@ -749,6 +820,41 @@ void PresentationWidget::generateOverlay()
}
QRect PresentationWidget::routeMouseDrawingEvent( QMouseEvent * e )
{
const QRect & geom = m_frames[ m_frameIndex ]->geometry;
const Okular::Page * page = m_frames[ m_frameIndex ]->page;
AnnotatorEngine::EventType eventType = AnnotatorEngine::Press;
if ( e->type() == QEvent::MouseMove )
eventType = AnnotatorEngine::Move;
else if ( e->type() == QEvent::MouseButtonRelease )
eventType = AnnotatorEngine::Release;
// find out the pressed button
AnnotatorEngine::Button button = AnnotatorEngine::None;
Qt::MouseButtons buttonState = ( eventType == AnnotatorEngine::Move ) ? e->buttons() : e->button();
if ( buttonState == Qt::LeftButton )
button = AnnotatorEngine::Left;
else if ( buttonState == Qt::RightButton )
button = AnnotatorEngine::Right;
static bool hasclicked = false;
if ( eventType == AnnotatorEngine::Press )
hasclicked = true;
double nX = ( (double)e->x() - (double)geom.left() ) / (double)geom.width();
double nY = ( (double)e->y() - (double)geom.top() ) / (double)geom.height();
QRect ret;
if ( hasclicked && nX >= 0 && nX < 1 && nY >= 0 && nY < 1 )
ret = m_drawingEngine->event( eventType, button, nX, nY, geom.width(), geom.height(), page );
if ( eventType == AnnotatorEngine::Release )
hasclicked = false;
return ret;
}
void PresentationWidget::slotNextPage()
{
@ -856,6 +962,37 @@ void PresentationWidget::slotPageChanged()
changePage( p - 1 );
}
void PresentationWidget::togglePencilMode( bool on )
{
if ( on )
{
// FIXME this should not be recreated every time
QDomDocument doc( "engine" );
QDomElement root = doc.createElement( "engine" );
root.setAttribute( "color", "#FF0000" );
doc.appendChild( root );
QDomElement annElem = doc.createElement( "annotation" );
root.appendChild( annElem );
annElem.setAttribute( "type", "Ink" );
annElem.setAttribute( "color", "#FF0000" );
annElem.setAttribute( "width", "2" );
m_drawingEngine = new SmoothPathEngine( root );
}
else
{
delete m_drawingEngine;
m_drawingEngine = 0;
m_drawingRect = QRect();
}
}
void PresentationWidget::clearDrawings()
{
m_document->removePageAnnotations( m_document->viewport().pageNumber, m_currentPageDrawings );
m_currentPageDrawings.clear();
}
const Okular::PageTransition PresentationWidget::defaultTransition() const
{
return defaultTransition( Okular::Settings::slidesTransition() );

@ -21,9 +21,11 @@ class QLineEdit;
class QToolBar;
class QTimer;
class KActionCollection;
class AnnotatorEngine;
class PresentationFrame;
namespace Okular {
struct Annotation;
class Document;
class Page;
class Link;
@ -66,13 +68,14 @@ class PresentationWidget : public QDialog, public Okular::DocumentObserver
void testCursorOnLink( int x, int y );
void overlayClick( const QPoint & position );
void changePage( int newPage );
void generatePage();
void generatePage( bool disableTransition = false );
void generateIntroPage( QPainter & p );
void generateContentsPage( int page, QPainter & p );
void generateOverlay();
void initTransition( const Okular::PageTransition *transition );
const Okular::PageTransition defaultTransition() const;
const Okular::PageTransition defaultTransition( int ) const;
QRect routeMouseDrawingEvent( QMouseEvent * );
// cache stuff
int m_width;
@ -82,6 +85,9 @@ class PresentationWidget : public QDialog, public Okular::DocumentObserver
QRect m_overlayGeometry;
const Okular::Link * m_pressedLink;
bool m_handCursor;
QList< Okular::Annotation * > m_currentPageDrawings;
AnnotatorEngine * m_drawingEngine;
QRect m_drawingRect;
// transition related
QTimer * m_transitionTimer;
@ -108,6 +114,8 @@ class PresentationWidget : public QDialog, public Okular::DocumentObserver
void slotTransitionStep();
void slotDelayedEvents();
void slotPageChanged();
void togglePencilMode( bool );
void clearDrawings();
};
#endif

Loading…
Cancel
Save