o Removed the PageViewOverlay class (a hack that permitted transparent

selection) in favour of a new common selection code that uses internal
compositing engine.
o Added 'copy GFX' (in addition to the already existant 'copy text') with
a popup that asks user wether to copy to clipboard or save the image to
a file. (note: maybe a merge between selection tools (text/gfx) is
possible).
o The Zoom Tool is now a mouse mode, not a zoom mode.
o Tuned PageViewMessage class and added tips somewhere.
o Reorganized some actions and cleanup in mouse mode related code.
o Updated plans (roadmap to HEAD and new things) in TODO.
o And.. well, de don't deal with gardening anymore :-) Thanks Michael!
CCMAIL: brade@kde.org

svn path=/branches/kpdf_experiments/kdegraphics/kpdf/; revision=360144
This commit is contained in:
Enrico Ros 2004-11-03 17:35:48 +00:00
parent 03bbbaf2c4
commit 89cd5a2fa6
8 changed files with 311 additions and 308 deletions

View file

@ -7,18 +7,13 @@ Legend:
(*) - Some parts of this item are already done
In progress on the branch (first item comes first):
-> common layer for selections (zoom outline, select&copy text, select&copy screen)
-> FIX: rework PageView (QScrollView) to gain speed and reduce memory consumption [90% done]
the current behavior, using a large scrollview and the clipper is *Very* bad, wasting
repaints everywhere, even in widgets that get hidden. Need to solve this on its roots, a paintEvent patch
solves this but is a bad way to solve this.
-> ADD: reading aids (accessibility) [settings config done while now]
-> ADD: reading aids (accessibility) [settings config done while now, 20% done]
-> ADD: click over image allows "save image" (and display rect around image too) [50% done]
-> ADD: viewport changes the right way when clicking links [30% done]
Things to do in order to merge in HEAD (first item has highest priority):
-> memory manager with different profiles (mem/cpu tradeoff: {memory saving, normal, memory aggressive})
-> fix viewport restoring after zoom
-> fix viewport restoring after zoom (not, fix zoom globally)
-> link thumbnails view with document
-> this may be postponed after merge: implementing async document generator using Albert's generator thread
-> this may be postponed after merge: albert: printing in a good way
@ -42,12 +37,13 @@ More items (first items will enter 'In progress list' first):
-> automatic online dictionaries / translators (BR80338)
-> add OCR for building TextPages out of pure graphical (aka scanned) pages
-> merge head copyright headers (by albert)
-> merge head xpdf changes for --enable-final (by adrian de groot/albert)
-> merge head support for show menubar in rmb (by albert)
-> wrong zoom buttons order (BR74248) (check consistancy with kdvi/kghostview/.. (not konq))
Done (newest feature comes firts):
-> ADD: composted renderer framework
-> ADD: gfx capturing tool
-> ADD: composited renderer framework (in addition to a fast light one)
-> FIX: pageview repaint done internally (speed boost and reduced memory consumption)
-> ADD: KConfigXT settings framework and Accessibility config (acc. code mostly not done)
-> FIX: workaround for scrollview bug 1/2 (painting hidden widgets under certain circumstances)
-> ADD: zoom into a rect defined by mouse (aka zoom to window)

View file

@ -98,7 +98,7 @@
</widget>
<widget class="QCheckBox">
<property name="name">
<cstring>kcfg_TempUseComposting</cstring>
<cstring>kcfg_TempUseCompositing</cstring>
</property>
<property name="text">
<string>USE COMPOSITE</string>

View file

@ -69,7 +69,7 @@
</entry>
</group>
<group name="Temp" >
<entry key="TempUseComposting" type="Bool" >
<entry key="TempUseCompositing" type="Bool" >
<default>false</default>
</entry>
<entry key="TempDrawBoundaries" type="Bool" >

View file

@ -12,14 +12,14 @@
</Menu>
<Menu name="view"><text>&amp;View</text>
<Separator/>
<Action name="zoom_in"/>
<Action name="zoom_out"/>
<Action name="zoom_in"/>
<Action name="zoom_fit_width"/>
<Action name="zoom_fit_page"/>
<Action name="zoom_fit_rect"/>
<Separator/>
<Action name="view_twopages"/>
<Action name="view_continous"/>
<Action name="view_twopages"/>
</Menu>
<Menu name="go"><text>&amp;Go</text>
<Action name="first_page"/>
@ -38,19 +38,19 @@
<Action name="previous_page"/>
<Action name="next_page"/>
<Separator/>
<Action name="zoom_in"/>
<Action name="zoom_to" />
<Action name="zoom_out"/>
<Action name="zoom_fit_rect"/>
<Action name="zoom_to" />
<Action name="zoom_in"/>
<!--Action name="zoom_fit_width"/-->
<!--Action name="zoom_fit_page"/-->
<Merge/>
<Separator/>
<Action name="view_twopages"/>
<Action name="view_continous"/>
<Action name="view_twopages"/>
<Separator/>
<Action name="mouse_drag"/>
<Action name="mouse_select"/>
<Action name="mouse_zoom"/>
<Action name="mouse_select_text"/>
<Action name="mouse_select_gfx"/>
<Action name="mouse_draw"/>
</ToolBar>
</kpartgui>

View file

@ -28,7 +28,9 @@
#include <kactioncollection.h>
#include <kpopupmenu.h>
#include <klocale.h>
#include <kfiledialog.h>
#include <kimageeffect.h>
#include <kimageio.h>
#include <math.h>
#include <stdlib.h>
@ -58,13 +60,13 @@ public:
bool mouseOnLink;
bool mouseOnActiveRect;
QRect mouseSelectionRect;
PageViewItem * mouseSelectionItem;
// other stuff
QTimer * delayTimer;
QTimer * scrollTimer;
int scrollIncrement;
bool dirtyLayout;
PageViewOverlay * overlayWindow; //in pageviewutils.h
PageViewMessage * messageWindow; //in pageviewutils.h
// actions
@ -73,7 +75,6 @@ public:
KToggleAction * aZoomFitWidth;
KToggleAction * aZoomFitPage;
KToggleAction * aZoomFitText;
KToggleAction * aZoomFitRect;
KToggleAction * aViewTwoPages;
KToggleAction * aViewContinous;
};
@ -103,11 +104,11 @@ PageView::PageView( QWidget *parent, KPDFDocument *document )
d->mouseMode = MouseNormal;
d->mouseOnLink = false;
d->mouseOnActiveRect = false;
d->mouseSelectionItem = 0;
d->delayTimer = 0;
d->scrollTimer = 0;
d->scrollIncrement = 0;
d->dirtyLayout = false;
d->overlayWindow = 0;
d->messageWindow = new PageViewMessage(this);
// widget setup: setup focus, accept drops and track mouse
@ -155,9 +156,6 @@ void PageView::setupActions( KActionCollection * ac )
d->aZoomFitText = new KToggleAction( i18n("Fit to &Text"), "viewmagfit", 0, ac, "zoom_fit_text" );
connect( d->aZoomFitText, SIGNAL( toggled( bool ) ), SLOT( slotFitToTextToggled( bool ) ) );
d->aZoomFitRect = new KToggleAction( i18n("Zoom to Rect"), "viewmag", 0, ac, "zoom_fit_rect" );
connect( d->aZoomFitRect, SIGNAL( toggled( bool ) ), SLOT( slotFitToRectToggled( bool ) ) );
// View-Layout actions
d->aViewTwoPages = new KToggleAction( i18n("Two Pages"), "view_left_right", 0, ac, "view_twopages" );
connect( d->aViewTwoPages, SIGNAL( toggled( bool ) ), SLOT( slotTwoPagesToggled( bool ) ) );
@ -169,11 +167,17 @@ void PageView::setupActions( KActionCollection * ac )
// Mouse-Mode actions
KToggleAction * mn = new KRadioAction( i18n("Normal"), "mouse", 0, this, SLOT( slotSetMouseNormal() ), ac, "mouse_drag" );
mn->setExclusiveGroup("MouseType");
mn->setExclusiveGroup( "MouseType" );
mn->setChecked( true );
KToggleAction *ms = new KRadioAction( i18n("Select"), "frame_edit", 0, this, SLOT( slotSetMouseSelect() ), ac, "mouse_select" );
ms->setExclusiveGroup("MouseType");
KToggleAction * mz = new KRadioAction( i18n("Zoom Tool"), "viewmag", 0, this, SLOT( slotSetMouseZoom() ), ac, "mouse_zoom" );
mz->setExclusiveGroup( "MouseType" );
KToggleAction * mst = new KRadioAction( i18n("Select Text"), "frame_edit", 0, this, SLOT( slotSetMouseSelText() ), ac, "mouse_select_text" );
mst->setExclusiveGroup( "MouseType" );
KToggleAction * msg = new KRadioAction( i18n("Select Graphics"), "frame_image", 0, this, SLOT( slotSetMouseSelGfx() ), ac, "mouse_select_gfx" );
msg->setExclusiveGroup( "MouseType" );
d->aMouseEdit = new KRadioAction( i18n("Draw"), "edit", 0, this, SLOT( slotSetMouseDraw() ), ac, "mouse_draw" );
d->aMouseEdit->setExclusiveGroup("MouseType");
@ -324,7 +328,7 @@ void PageView::viewportPaintEvent( QPaintEvent * pe )
continue;
}
if ( Settings::tempUseComposting() )
if ( Settings::tempUseCompositing() )
{
// create pixmap and open a painter over it
QPixmap doubleBuffer( contentsRect.size() );
@ -333,13 +337,7 @@ void PageView::viewportPaintEvent( QPaintEvent * pe )
pixmapPainter.translate( -contentsRect.left(), -contentsRect.top() );
// 1) Layer 0: paint items and clear bg on unpainted rects
QRegion remaining( contentsRect );
paintItems( &pixmapPainter, contentsRect, remaining );
QMemArray<QRect> backRects = remaining.rects();
uint backRectsNumber = backRects.count();
for ( uint jr = 0; jr < backRectsNumber; jr++ )
pixmapPainter.fillRect( backRects[ jr ], Qt::gray );
paintItems( &pixmapPainter, contentsRect );
// 2) Layer 1: pixmap manipulated areas
// 3) Layer 2: paint (blend) transparent selection
if ( !selectionRect.isNull() && selectionRect.intersects( contentsRect ) )
@ -391,15 +389,10 @@ void PageView::viewportPaintEvent( QPaintEvent * pe )
pixmapPainter.end();
screenPainter.drawPixmap( contentsRect.left(), contentsRect.top(), doubleBuffer );
}
else // not using COMPOSTING
else // not using COMPOSITING
{
// 1) Layer 0: paint items and clear bg on unpainted rects
QRegion remaining( contentsRect );
paintItems( &screenPainter, contentsRect, remaining );
QMemArray<QRect> backRects = remaining.rects();
uint backRectsNumber = backRects.count();
for ( uint jr = 0; jr < backRectsNumber; jr++ )
screenPainter.fillRect( backRects[ jr ], Qt::gray );
paintItems( &screenPainter, contentsRect );
// 2) Layer 1: opaque manipulated ares (filled / contours)
// 3) Layer 2: paint opaque selection
if ( !d->mouseSelectionRect.isNull() )
@ -486,21 +479,6 @@ void PageView::contentsMouseMoveEvent( QMouseEvent * e )
{
bool leftButton = e->state() & LeftButton;
// handle 'Zoom To Area', in every mouse mode
if ( leftButton && d->zoomMode == ZoomRect && !d->mouseStartPos.isNull() )
{
// create zooming a window (overlay mode)
if ( !d->overlayWindow )
{
d->overlayWindow = new PageViewOverlay( viewport(), PageViewOverlay::Zoom );
d->overlayWindow->setBeginCorner( d->mouseStartPos.x() - contentsX(), d->mouseStartPos.y() - contentsY() );
}
// set rect's 2nd corner
d->overlayWindow->setEndCorner( e->x() - contentsX(), e->y() - contentsY() );
return;
}
switch ( d->mouseMode )
{
case MouseNormal:
@ -521,7 +499,7 @@ void PageView::contentsMouseMoveEvent( QMouseEvent * e )
}
}
}
else
else // only hovering the page
{
// detect the underlaying page (if present)
PageViewItem * pageItem = pickItemOnPoint( e->x(), e->y() );
@ -549,37 +527,12 @@ void PageView::contentsMouseMoveEvent( QMouseEvent * e )
}
break;
case MouseSelection:
case MouseZoom:
case MouseSelText:
case MouseSelGfx:
// set second corner of selection in selection pageItem
if ( leftButton && d->activeItem && !d->mouseSelectionRect.isNull() )
{
const QRect & itemRect = d->activeItem->geometry();
// clip selection inside the page
int x = QMAX( QMIN( e->x(), itemRect.right() ), itemRect.left() ),
y = QMAX( QMIN( e->y(), itemRect.bottom() ), itemRect.top() );
// if selection changed update rect
if ( d->mouseSelectionRect.right() != x || d->mouseSelectionRect.bottom() != y )
{
// send incremental paint events
QRect oldRect = d->mouseSelectionRect.normalize();
d->mouseSelectionRect.setRight( x );
d->mouseSelectionRect.setBottom( y );
QRect newRect = d->mouseSelectionRect.normalize();
// generate diff region: [ OLD.unite(NEW) - OLD.intersect(NEW) ]
QRegion compoundRegion = QRegion( oldRect ).unite( newRect );
if ( oldRect.intersects( newRect ) )
{
QRect intersection = oldRect.intersect( newRect );
intersection.addCoords( 1, 1, -1, -1 );
if ( intersection.width() > 20 && intersection.height() > 20 )
compoundRegion -= intersection;
}
// tassellate region with rects and enqueue paint events
QMemArray<QRect> rects = compoundRegion.rects();
for ( uint i = 0; i < rects.count(); i++ )
updateContents( rects[i] );
}
}
if ( leftButton && !d->mouseSelectionRect.isNull() )
selectionEndPoint( e->x(), e->y() );
break;
case MouseEdit: // ? update graphics ?
@ -591,14 +544,6 @@ void PageView::contentsMousePressEvent( QMouseEvent * e )
{
bool leftButton = e->button() & LeftButton;
// handle 'Zoom To Area', in every mouse mode
if ( leftButton && d->zoomMode == ZoomRect )
{
d->mouseStartPos = e->pos();
d->mouseGrabPos = QPoint();
return;
}
// handle mode dependant mouse press actions
switch ( d->mouseMode )
{
@ -614,25 +559,22 @@ void PageView::contentsMousePressEvent( QMouseEvent * e )
emit rightClick();
break;
case MouseSelection: // set first corner of the selection rect
case MouseZoom:
case MouseSelGfx:
if ( leftButton )
selectionStart( e->x(), e->y(), false );
break;
case MouseSelText: // set first corner of the selection rect
if ( leftButton )
{
PageViewItem * item = pickItemOnPoint( e->x(), e->y() );
if ( item )
{
// pick current page as the active one
d->activeItem = item;
d->mouseSelectionRect.setRect( e->x(), e->y(), 1, 1 );
// ensures page doesn't scroll
if ( d->scrollTimer )
{
d->scrollIncrement = 0;
d->scrollTimer->stop();
}
}
selectionStart( e->x(), e->y(), false, item );
}
break;
case MouseEdit: // ? place the beginning of [tool] ?
break;
}
@ -643,49 +585,6 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e )
bool leftButton = e->button() & LeftButton,
rightButton = e->button() & RightButton;
// handle 'Zoom To Area', in every mouse mode
if ( leftButton && d->overlayWindow )
{
// find out new zoom ratio
QRect selRect = d->overlayWindow->selectedRect();
float zoom = QMIN( (float)visibleWidth() / (float)selRect.width(),
(float)visibleHeight() / (float)selRect.height() );
// get normalized view center (relative to the contentsRect)
// coeffs (1.0 and 1.5) are for correcting the asymmetic page border
// that makes the page not perfectly centered on the viewport
double nX = ( contentsX() - 1.0 + selRect.left() + (double)selRect.width() / 2.0 ) / (double)contentsWidth();
double nY = ( contentsY() - 1.5 + selRect.top() + (double)selRect.height() / 2.0 ) / (double)contentsHeight();
// zoom up to 400%
if ( d->zoomFactor <= 4.0 || zoom <= 1.0 )
{
d->zoomFactor *= zoom;
if ( d->zoomFactor > 4.0 )
d->zoomFactor = 4.0;
updateZoom( ZoomRefreshCurrent );
}
// recenter view
center( (int)(nX * contentsWidth()), (int)(nY * contentsHeight()) );
// hide message box and delete overlay window
d->messageWindow->hide();
delete d->overlayWindow;
d->overlayWindow = 0;
// reset start position
d->mouseStartPos = QPoint();
return;
}
// if in ZoomRect mode, right click zooms out
if ( rightButton && d->zoomMode == ZoomRect )
{
updateZoom( ZoomOut );
updateZoom( ZoomRect );
return;
}
PageViewItem * pageItem = pickItemOnPoint( e->x(), e->y() );
switch ( d->mouseMode )
{
@ -719,8 +618,12 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e )
m_popup->insertItem( SmallIcon("bookmark_add"), i18n("Add Bookmark"), 1 );
m_popup->insertItem( SmallIcon("viewmagfit"), i18n("Fit Page"), 2 );
m_popup->insertItem( SmallIcon("pencil"), i18n("Edit"), 3 );
//implement this function before remove this line
m_popup->setItemEnabled( 3, false );
if ( d->mouseOnActiveRect )
{
m_popup->insertItem( SmallIcon("filesave"), i18n("Save Image ..."), 4 );
m_popup->setItemEnabled( 4, false );
}
switch ( m_popup->exec(e->globalPos()) )
{
case 1:
@ -743,28 +646,122 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e )
d->mouseStartPos = QPoint();
break;
case MouseSelection:
if ( leftButton && d->activeItem && !d->mouseSelectionRect.isNull() )
case MouseZoom:
// handle 'Zoom To Area', in every mouse mode FIXME
if ( leftButton && !d->mouseSelectionRect.isNull() )
{
// find out new zoom ratio
const QRect & selRect = d->mouseSelectionRect;
float zoom = QMIN( (float)visibleWidth() / (float)selRect.width(),
(float)visibleHeight() / (float)selRect.height() );
// get normalized view center (relative to the contentsRect)
// coeffs (1.0 and 1.5) are for correcting the asymmetic page border
// that makes the page not perfectly centered on the viewport
double nX = ( contentsX() - 1.0 + selRect.left() + (double)selRect.width() / 2.0 ) / (double)contentsWidth();
double nY = ( contentsY() - 1.5 + selRect.top() + (double)selRect.height() / 2.0 ) / (double)contentsHeight();
// zoom up to 400%
if ( d->zoomFactor <= 4.0 || zoom <= 1.0 )
{
d->zoomFactor *= zoom;
if ( d->zoomFactor > 4.0 )
d->zoomFactor = 4.0;
updateZoom( ZoomRefreshCurrent );
}
// recenter view
center( (int)(nX * contentsWidth()), (int)(nY * contentsHeight()) );
// hide message box and delete overlay window
selectionClear();
return;
}
// if in ZoomRect mode, right click zooms out
if ( rightButton )
{
updateZoom( ZoomOut );
return;
}
break;
case MouseSelText:
if ( leftButton && !d->mouseSelectionRect.isNull() )
{
// request the textpage if there isn't one
const KPDFPage * kpdfPage = d->activeItem->page();
const KPDFPage * kpdfPage = d->mouseSelectionItem->page();
if ( !kpdfPage->hasSearchPage() )
d->document->requestTextPage( kpdfPage->number() );
// copy text into the clipboard
QClipboard *cb = QApplication::clipboard();
QRect relativeRect = d->mouseSelectionRect.normalize();
relativeRect.moveBy( -d->activeItem->geometry().left(), -d->activeItem->geometry().top() );
const QString & selection = kpdfPage->getTextInRect( relativeRect, d->activeItem->zoomFactor() );
relativeRect.moveBy( -d->mouseSelectionItem->geometry().left(),
-d->mouseSelectionItem->geometry().top() );
const QString & selection = kpdfPage->getTextInRect( relativeRect, d->mouseSelectionItem->zoomFactor() );
cb->setText( selection, QClipboard::Clipboard );
if ( cb->supportsSelection() )
cb->setText( selection, QClipboard::Selection );
// clear widget selection and invalidate rect
if ( !d->mouseSelectionRect.isNull() )
updateContents( d->mouseSelectionRect.normalize() );
d->mouseSelectionRect.setCoords( 0, 0, -1, -1 );
selectionClear();
// user friendly message
if ( selection.length() < 1 )
d->messageWindow->display( i18n( "No characters copied to clipboard." ), PageViewMessage::Error );
else
d->messageWindow->display( i18n( "%1 characters copied to clipboard." ).arg( selection.length() ) );
}
break;
case MouseSelGfx:
if ( leftButton && !d->mouseSelectionRect.isNull() )
{
QRect relativeRect = d->mouseSelectionRect.normalize();
if ( relativeRect.width() > 2 && relativeRect.height() > 2 )
{
// grab rendered page into the pixmap
QPixmap copyPix( relativeRect.width(), relativeRect.height() );
QPainter copyPainter( &copyPix );
copyPainter.translate( -relativeRect.left(), -relativeRect.top() );
paintItems( &copyPainter, relativeRect );
// popup that ask to copy or save image
KPopupMenu * m_popup = new KPopupMenu( this, "rmb popup" );
m_popup->insertTitle( i18n( "Copy Image [%1x%2]" ).arg( copyPix.width() ).arg( copyPix.height() ) );
m_popup->insertItem( SmallIcon("editcopy"), i18n("Copy to Clipboard"), 1 );
m_popup->insertItem( SmallIcon("filesave"), i18n("Save to File ..."), 2 );
switch ( m_popup->exec(e->globalPos()) )
{
case 1:{
// save pixmap to clipboard
QClipboard *cb = QApplication::clipboard();
cb->setPixmap( copyPix, QClipboard::Clipboard );
if ( cb->supportsSelection() )
cb->setPixmap( copyPix, QClipboard::Selection );
d->messageWindow->display( i18n( "Image [%1x%2] copied to clipboard." ).arg( copyPix.width() ).arg( copyPix.height() ) );
}break;
case 2:
// save pixmap to file
QString fileName = KFileDialog::getSaveFileName( QString::null, "image/png image/jpeg", this );
if ( !fileName.isNull() )
{
QString type( KImageIO::type( fileName ) );
if ( type.isNull() )
type = "PNG";
copyPix.save( fileName, type.latin1() );
d->messageWindow->display( i18n( "Image [%1x%2] saved to %3 file." ).arg( copyPix.width() ).arg( copyPix.height() ).arg( type ) );
}
else
d->messageWindow->display( i18n( "File not saved." ), PageViewMessage::Warning );
break;
}
delete m_popup;
}
// clear widget selection and invalidate rect
selectionClear();
}
break;
@ -813,7 +810,7 @@ void PageView::dropEvent( QDropEvent * ev )
}
//END widget events
void PageView::paintItems( QPainter * p, const QRect & contentsRect, QRegion & remainingArea )
void PageView::paintItems( QPainter * p, const QRect & contentsRect )
{
// when checking if an Item is contained in contentsRect, instead of
// growing PageViewItems rects (for keeping outline into account), we
@ -821,6 +818,9 @@ void PageView::paintItems( QPainter * p, const QRect & contentsRect, QRegion & r
QRect checkRect = contentsRect;
checkRect.addCoords( -3, -3, 1, 1 );
// create a region from wich we'll subtract painted rects
QRegion remainingArea( contentsRect );
QValueVector< PageViewItem * >::iterator pIt = d->pages.begin(), pEnd = d->pages.end();
for ( ; pIt != pEnd; ++pIt )
{
@ -867,7 +867,7 @@ void PageView::paintItems( QPainter * p, const QRect & contentsRect, QRegion & r
QRect pixmapRect = contentsRect.intersect( pixmapGeometry );
pixmapRect.moveBy( -pixmapGeometry.left(), -pixmapGeometry.top() );
// accessibility setting (TODO ADD COMPOSTING for PAGE RECOLORING)
// accessibility setting (TODO ADD COMPOSITING for PAGE RECOLORING)
if ( Settings::renderMode() == Settings::EnumRenderMode::Inverted )
p->setRasterOp( Qt::NotCopyROP );
@ -881,6 +881,12 @@ void PageView::paintItems( QPainter * p, const QRect & contentsRect, QRegion & r
p->restore();
}
}
// paint with background color the unpainted area
QMemArray<QRect> backRects = remainingArea.rects();
uint backRectsNumber = backRects.count();
for ( uint jr = 0; jr < backRectsNumber; jr++ )
p->fillRect( backRects[ jr ], Qt::gray );
}
void PageView::updateItemSize( PageViewItem * item, int colWidth, int rowHeight )
@ -932,23 +938,61 @@ PageViewItem * PageView::pickItemOnPoint( int x, int y )
return item;
}
void PageView::selectionStart( int x, int y, bool /*aboveAll*/, PageViewItem * pageLock)
{
// pick current page as the active one
d->mouseSelectionItem = pageLock;
d->mouseSelectionRect.setRect( x, y, 1, 1 );
// ensures page doesn't scroll
if ( d->scrollTimer )
{
d->scrollIncrement = 0;
d->scrollTimer->stop();
}
}
void PageView::selectionEndPoint( int x, int y )
{
// clip selection to the current page (if set)
if ( d->mouseSelectionItem )
{
const QRect & itemRect = d->mouseSelectionItem->geometry();
x = QMAX( QMIN( x, itemRect.right() ), itemRect.left() ),
y = QMAX( QMIN( y, itemRect.bottom() ), itemRect.top() );
}
// if selection changed update rect
if ( d->mouseSelectionRect.right() != x || d->mouseSelectionRect.bottom() != y )
{
// send incremental paint events
QRect oldRect = d->mouseSelectionRect.normalize();
d->mouseSelectionRect.setRight( x );
d->mouseSelectionRect.setBottom( y );
QRect newRect = d->mouseSelectionRect.normalize();
// generate diff region: [ OLD.unite(NEW) - OLD.intersect(NEW) ]
QRegion compoundRegion = QRegion( oldRect ).unite( newRect );
if ( oldRect.intersects( newRect ) )
{
QRect intersection = oldRect.intersect( newRect );
intersection.addCoords( 1, 1, -1, -1 );
if ( intersection.width() > 20 && intersection.height() > 20 )
compoundRegion -= intersection;
}
// tassellate region with rects and enqueue paint events
QMemArray<QRect> rects = compoundRegion.rects();
for ( uint i = 0; i < rects.count(); i++ )
updateContents( rects[i] );
}
}
void PageView::selectionClear()
{
updateContents( d->mouseSelectionRect.normalize() );
d->mouseSelectionRect.setCoords( 0, 0, -1, -1 );
d->mouseSelectionItem = 0;
}
void PageView::updateZoom( ZoomMode newZoomMode )
{
// handle zoomRect case, showing message window too
if ( newZoomMode == ZoomRect )
{
d->zoomMode = ZoomRect;
d->aZoomFitWidth->setChecked( false );
d->aZoomFitPage->setChecked( false );
d->aZoomFitText->setChecked( false );
if ( !Settings::hideOSD() )
d->messageWindow->display( i18n( "Select Zooming Area. Right-Click to zoom out." ), PageViewMessage::Info );
return;
}
// if zoomMode is changing from ZoomRect, hide info popup
if ( d->zoomMode == ZoomRect )
d->messageWindow->hide();
if ( newZoomMode == ZoomFixed )
{
if ( d->aZoom->currentItem() == 0 )
@ -961,7 +1005,7 @@ void PageView::updateZoom( ZoomMode newZoomMode )
KAction * checkedZoomAction = 0;
switch ( newZoomMode )
{
default:{ //ZoomFixed case
case ZoomFixed:{ //ZoomFixed case
QString z = d->aZoom->currentText();
newFactor = KGlobal::locale()->readNumber( z.remove( z.find( '%' ), 1 ) ) / 100.0;
}break;
@ -1006,7 +1050,6 @@ void PageView::updateZoom( ZoomMode newZoomMode )
d->aZoomFitWidth->setChecked( checkedZoomAction == d->aZoomFitWidth );
d->aZoomFitPage->setChecked( checkedZoomAction == d->aZoomFitPage );
d->aZoomFitText->setChecked( checkedZoomAction == d->aZoomFitText );
d->aZoomFitRect->setChecked( false );
}
}
@ -1288,12 +1331,6 @@ void PageView::slotFitToTextToggled( bool on )
if ( on ) updateZoom( ZoomFitText );
}
void PageView::slotFitToRectToggled( bool on )
{
if ( on ) updateZoom( ZoomRect );
else updateZoom( ZoomFixed );
}
void PageView::slotTwoPagesToggled( bool on )
{
uint newColumns = on ? 2 : 1;
@ -1318,17 +1355,32 @@ void PageView::slotContinousToggled( bool on )
void PageView::slotSetMouseNormal()
{
d->mouseMode = MouseNormal;
d->messageWindow->hide();
}
void PageView::slotSetMouseSelect()
void PageView::slotSetMouseZoom()
{
d->mouseMode = MouseSelection;
d->mouseMode = MouseZoom;
d->messageWindow->display( i18n( "Select Zooming Area. Right-Click to zoom out." ), PageViewMessage::Info );
}
void PageView::slotSetMouseSelText()
{
d->mouseMode = MouseSelText;
d->messageWindow->display( i18n( "Draw a rectangle around the text to copy." ), PageViewMessage::Info, 2000 );
}
void PageView::slotSetMouseSelGfx()
{
d->mouseMode = MouseSelGfx;
d->messageWindow->display( i18n( "Draw a rectangle around the graphics to copy." ), PageViewMessage::Info, 2000 );
}
void PageView::slotSetMouseDraw()
{
d->mouseMode = MouseEdit;
d->aMouseEdit->setChecked( true );
d->messageWindow->hide();
}
void PageView::slotScrollUp()

View file

@ -45,8 +45,8 @@ class PageView : public QScrollView, public KPDFDocumentObserver
// Zoom mode ( last 4 are internally used only! )
enum ZoomMode { ZoomFixed, ZoomFitWidth, ZoomFitPage, ZoomFitText,
ZoomIn, ZoomOut, ZoomRefreshCurrent, ZoomRect };
enum MouseMode { MouseNormal, MouseSelection, MouseEdit };
ZoomIn, ZoomOut, ZoomRefreshCurrent };
enum MouseMode { MouseNormal, MouseZoom, MouseSelText, MouseSelGfx, MouseEdit };
// create actions that interact with this widget
void setupActions( KActionCollection * collection );
@ -79,11 +79,15 @@ class PageView : public QScrollView, public KPDFDocumentObserver
private:
// draw items on the opened qpainter
void paintItems( QPainter * p, const QRect & clipRect, QRegion & remainingArea );
void paintItems( QPainter * p, const QRect & clipRect );
// update item width and height using current zoom parameters
void updateItemSize( PageViewItem * item, int columnWidth, int rowHeight );
// return the widget placed on a certain point or 0 if clicking on empty space
PageViewItem * pickItemOnPoint( int x, int y );
// start / modify / clear selection rectangle
void selectionStart( int x, int y, bool aboveAll = false, PageViewItem * pageLock = 0 );
void selectionEndPoint( int x, int y );
void selectionClear();
// update internal zoom values and end in a slotRelayoutPages();
void updateZoom( ZoomMode newZm );
// update the text on the label using global zoom value or current page's one
@ -107,11 +111,12 @@ class PageView : public QScrollView, public KPDFDocumentObserver
void slotFitToWidthToggled( bool );
void slotFitToPageToggled( bool );
void slotFitToTextToggled( bool );
void slotFitToRectToggled( bool );
void slotTwoPagesToggled( bool );
void slotContinousToggled( bool );
void slotSetMouseNormal();
void slotSetMouseSelect();
void slotSetMouseZoom();
void slotSetMouseSelText();
void slotSetMouseSelGfx();
void slotSetMouseDraw();
void slotScrollUp();
void slotScrollDown();

View file

@ -17,7 +17,8 @@
// local includes
#include "pageviewutils.h"
#include "page.h"
#include "settings.h"
PageViewMessage::PageViewMessage( QWidget * parent )
: QWidget( parent, "pageViewMessage" ), m_timer( 0 )
@ -32,6 +33,12 @@ PageViewMessage::PageViewMessage( QWidget * parent )
void PageViewMessage::display( const QString & message, Icon icon, int durationMs )
// give to Caesar what Caesar owns: code taken from Amarok's osd.h/.cpp
{
if ( Settings::hideOSD() )
{
hide();
return;
}
// determine text rectangle
QRect textRect = fontMetrics().boundingRect( message );
textRect.moveBy( -textRect.left(), -textRect.top() );
@ -108,7 +115,8 @@ void PageViewMessage::display( const QString & message, Icon icon, int durationM
connect( m_timer, SIGNAL( timeout() ), SLOT( hide() ) );
}
m_timer->start( durationMs, true );
}
} else if ( m_timer )
m_timer->stop();
}
void PageViewMessage::paintEvent( QPaintEvent * e )
@ -126,77 +134,55 @@ void PageViewMessage::mousePressEvent( QMouseEvent * /*e*/ )
// window placed in overlay when selecting a window to zoom into
PageViewOverlay::PageViewOverlay( QWidget * parent, OverlayOperation /*op*/ )
: QWidget( parent, "overlayWindow", WNoAutoErase | WPaintUnclipped )
PageViewItem::PageViewItem( const KPDFPage * page )
: m_page( page ), m_zoomFactor( 1.0 )
{
// grab underlying contents
QPoint topLeft = mapToGlobal( QPoint( 0, 0 ) );
m_backPixmap = QPixmap::grabWindow( qt_xrootwin(), topLeft.x(), topLeft.y(), parent->width(), parent->height() );
// resize window
setBackgroundMode( Qt::NoBackground );
resize( parent->width(), parent->height() );
show();
}
void PageViewOverlay::setBeginCorner( int x, int y )
const KPDFPage * PageViewItem::page() const
{
m_startX = x;
m_startY = y;
return m_page;
}
void PageViewOverlay::setEndCorner( int x, int y )
int PageViewItem::pageNumber() const
{
// set previous area to be redrawn
if ( !m_currentRect.isNull() )
update(m_currentRect);
// update current area and schedule for redrawing
m_currentRect.setRect( m_startX, m_startY, x - m_startX, y - m_startY );
update(m_currentRect = m_currentRect.normalize());
return m_page->number();
}
const QRect & PageViewOverlay::selectedRect()
const QRect& PageViewItem::geometry() const
{
return m_currentRect;
return m_geometry;
}
void PageViewOverlay::paintEvent( QPaintEvent * )
int PageViewItem::width() const
{
QColor blendColor = palette().active().highlight();
QPainter p( this );
// draw uncovered background (subtracting current from old rect)
QMemArray<QRect> transparentRects = QRegion( m_oldRect ).subtract( m_currentRect ).rects();
for ( uint i = 0; i < transparentRects.count(); i++ )
{
QRect r = transparentRects[i];
p.drawPixmap( r.topLeft(), m_backPixmap, r );
}
// draw opaque rects (subtracting old from current rect)
m_oldRect.addCoords( 1, 1, -1, -1 );
QMemArray<QRect> opaqueRects = QRegion( m_currentRect ).subtract( m_oldRect ).rects();
for ( uint i = 0; i < opaqueRects.count(); i++ )
{
QRect r = opaqueRects[i];
// skip rectangles covered by the border from painting
if ( r.width() <= 1 || r.height() <= 1 )
continue;
QPixmap blendedPixmap( r.width(), r.height() );
copyBlt( &blendedPixmap, 0,0, &m_backPixmap, r.left(),r.top(), r.width(),r.height() );
QImage blendedImage = blendedPixmap.convertToImage();
KImageEffect::blend( blendColor.dark(140), blendedImage, 0.2 );
p.drawPixmap( r.left(),r.top(), blendedImage, 0,0,r.width(),r.height() );
}
// draw border
if ( m_currentRect.width() > 20 && m_currentRect.height() > 20 )
p.setPen( blendColor );
else
p.setPen( Qt::red );
p.drawRect( m_currentRect );
m_oldRect = m_currentRect;
return m_geometry.width();
}
int PageViewItem::height() const
{
return m_geometry.height();
}
double PageViewItem::zoomFactor() const
{
return m_zoomFactor;
}
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;
}
void PageViewItem::moveTo( int x, int y )
{
m_geometry.moveLeft( x );
m_geometry.moveTop( y );
}

View file

@ -18,40 +18,29 @@
class QTimer;
class PageView;
#include "page.h"
class KPDFPage;
/**
* @short PageViewItem represents graphically a kpdfpage into the PageView.
*
* It has methods for settings Item's geometry and other visual properties such
* as the individual zoom factor.
*/
class PageViewItem
{
public:
PageViewItem( const KPDFPage * page )
: m_page( page ), m_zoomFactor( 1.0 )
{
// do something
}
PageViewItem( const KPDFPage * page );
void setWHZ( int w, int h, double z )
{
m_geometry.setWidth( w );
m_geometry.setHeight( h );
m_zoomFactor = z;
}
double zoomFactor() { return m_zoomFactor; }
const KPDFPage * page() const;
int pageNumber() const;
const QRect& geometry() const;
int width() const;
int height() const;
double zoomFactor() const;
int pageNumber() const { return m_page->number(); }
const KPDFPage * page() const { return m_page; }
const QRect& geometry() const { return m_geometry; }
int width() const { return m_geometry.width(); }
int height() const { return m_geometry.height(); }
void setGeometry( int x, int y, int width, int height )
{
m_geometry.setRect( x, y, width, height );
}
void moveTo( int x, int y )
{
m_geometry.moveLeft( x );
m_geometry.moveTop( y );
}
void setGeometry( int x, int y, int width, int height );
void setWHZ( int w, int h, double zoom );
void moveTo( int x, int y );
private:
const KPDFPage * m_page;
@ -69,7 +58,7 @@ class PageViewMessage : public QWidget
PageViewMessage( QWidget * parent );
enum Icon { None, Info, Warning, Error };
void display( const QString & message, Icon icon, int durationMs = -1 );
void display( const QString & message, Icon icon = Info, int durationMs = 4000 );
protected:
void paintEvent( QPaintEvent * e );
@ -80,29 +69,4 @@ class PageViewMessage : public QWidget
QTimer * m_timer;
};
/**
* @short The overlay widget draws transparent selections over the page.
*/
class PageViewOverlay : public QWidget
{
public:
enum OverlayOperation { Zoom, SnapShot };
PageViewOverlay( QWidget * parent, OverlayOperation op );
void setBeginCorner( int x, int y );
void setEndCorner( int x, int y );
const QRect & selectedRect();
protected:
void paintEvent( QPaintEvent * e );
private:
QPixmap m_backPixmap;
QRect m_oldRect;
QRect m_currentRect;
int m_startX;
int m_startY;
};
#endif