/* This file is part of the KDE project Copyright (C) 2001 Wilco Greven Copyright (C) 2002-2004 Stefan Kebekus Copyright (C) 2004-2005 Wilfried Huss This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include "pageView.h" #include "pageNumber.h" PageView::PageView( TQWidget* parent, const char* name ) : TQScrollView( parent, name, WStaticContents | WNoAutoErase) { moveTool = true; widgetList = 0; viewport()->setFocusPolicy(TQWidget::StrongFocus); setResizePolicy(TQScrollView::Manual); setVScrollBarMode(TQScrollView::Auto); setHScrollBarMode(TQScrollView::Auto); viewport()->setBackgroundMode(Qt::NoBackground); setResizePolicy(Manual); setDragAutoScroll(false); enableClipper(true); nrCols = 1; nrRows = 1; continuousViewmode = true; fullScreen = false; connect(this, TQT_SIGNAL(contentsMoving(int, int)), this, TQT_SLOT(calculateCurrentPageNumber(int, int))); } void PageView::addChild( TQPtrVector *wdgList ) { if( wdgList == 0 ) { kdError(1223) << "PageView::addChild(...) called with invalid arguments" << endl; return; } widgetList = wdgList; layoutPages(); } bool PageView::atTop() const { return verticalScrollBar()->value() == verticalScrollBar()->minValue(); } bool PageView::atBottom() const { return verticalScrollBar()->value() == verticalScrollBar()->maxValue(); } bool PageView::readUp() { if( atTop() ) return false; else { // Coordinate of the top of the viewport int top = contentsY(); DocumentWidget* widget = 0; // Find the widget(s) that intersect the top of the viewport // TODO: It would be better to use a binary search. for(Q_UINT16 i=0; isize(); i++) { widget = widgetList->at(i); if (childY(widget) < top && childY(widget) + widget->height() > top) { // Draw scrollguide widget->drawScrollGuide(top - childY(widget)); } } int newValue = QMAX( verticalScrollBar()->value() - (int)(height() * 0.9), verticalScrollBar()->minValue() ); verticalScrollBar()->setValue( newValue ); return true; } } bool PageView::readDown() { if( atBottom() ) return false; else { // Coordinate of the bottom of the viewport int bottom = contentsY() + visibleHeight(); DocumentWidget* widget = 0; // Find the widget(s) that intersect the bottom of the viewport // TODO: It would be better to use a binary search. for(Q_UINT16 i=0; isize(); i++) { widget = widgetList->at(i); if (childY(widget) < bottom && childY(widget) + widget->height() > bottom) { // Draw scrollguide widget->drawScrollGuide(bottom - childY(widget)); } } int newValue = QMIN( verticalScrollBar()->value() + (int)(height() * 0.9), verticalScrollBar()->maxValue() ); verticalScrollBar()->setValue( newValue ); return true; } } void PageView::scrollRight() { horizontalScrollBar()->addLine(); } void PageView::scrollLeft() { horizontalScrollBar()->subtractLine(); } void PageView::scrollDown() { verticalScrollBar()->addLine(); } void PageView::scrollUp() { verticalScrollBar()->subtractLine(); } void PageView::scrollBottom() { verticalScrollBar()->setValue( verticalScrollBar()->maxValue() ); } void PageView::scrollTop() { verticalScrollBar()->setValue( verticalScrollBar()->minValue() ); } void PageView::keyPressEvent( TQKeyEvent* e ) { switch ( e->key() ) { case Key_Up: scrollUp(); break; case Key_Down: scrollDown(); break; case Key_Left: scrollLeft(); break; case Key_Right: scrollRight(); break; default: e->ignore(); return; } e->accept(); } void PageView::contentsMousePressEvent( TQMouseEvent* e ) { if (e->button() == LeftButton) { if (moveTool) { setCursor(Qt::SizeAllCursor); dragGrabPos = e->globalPos(); } else { // we are in selection mode } } else { setCursor(Qt::arrowCursor); } } void PageView::contentsMouseReleaseEvent( TQMouseEvent* ) { setCursor(Qt::arrowCursor); } void PageView::contentsMouseMoveEvent( TQMouseEvent* e ) { TQPoint newPos = e->globalPos(); if (e->state() == LeftButton && moveTool) { TQPoint delta = dragGrabPos - newPos; scrollBy(delta.x(), delta.y()); } dragGrabPos = newPos; } void PageView::viewportResizeEvent( TQResizeEvent* e ) { TQScrollView::viewportResizeEvent( e ); if (!widgetList) return; layoutPages(); emit viewSizeChanged( viewport()->size() ); } void PageView::setNrColumns( Q_UINT8 cols ) { nrCols = cols; } void PageView::setNrRows( Q_UINT8 rows ) { nrRows = rows; } void PageView::setContinuousViewMode(bool continuous) { continuousViewmode = continuous; } bool PageView::singlePageFullScreenMode() { return (nrCols == 1 && nrRows == 1 && !continuousViewmode && fullScreen); } void PageView::slotShowScrollbars(bool status) { if (status == true) { setVScrollBarMode(TQScrollView::Auto); setHScrollBarMode(TQScrollView::Auto); } else { setVScrollBarMode(TQScrollView::AlwaysOff); setHScrollBarMode(TQScrollView::AlwaysOff); } } void PageView::setFullScreenMode(bool fullScreen) { this -> fullScreen = fullScreen; if (fullScreen == true) { setVScrollBarMode(TQScrollView::AlwaysOff); setHScrollBarMode(TQScrollView::AlwaysOff); oldFrameStyle = frameStyle(); setFrameStyle(TQFrame::NoFrame); backgroundColor = viewport()->paletteBackgroundColor(); if (singlePageFullScreenMode()) { viewport()->setPaletteBackgroundColor( Qt::black ) ; } } else { viewport()->setPaletteBackgroundColor( backgroundColor ) ; setFrameStyle(oldFrameStyle); } } void PageView::layoutPages(bool zoomChanged) { // Paranoid safety check if (widgetList == 0) return; // If there are no widgets, e.g. because the last widget has been // removed, the matter is easy: set the contents size to 0. If there // are no widgets because previously existing widgets were removed // (we detect that by looking at the contentsWidth and -Height). if (widgetList->isEmpty()) { if ((contentsWidth() != 0) || (contentsHeight() != 0)) { TQScrollView::resizeContents(0,0); } return; } // Ok, now we are in a situation where we do have some widgets that // shall be centered. int distance = distanceBetweenWidgets; if (singlePageFullScreenMode()) { // In single page fullscreen mode we don't want a margin around the pages distance = 0; } TQMemArray colWidth(nrCols); for(Q_UINT8 i=0; isize()+2*nrCols-2) / nrCols; } else { numRows = (Q_INT16)ceil(((double)widgetList->size()) / nrCols); } TQMemArray rowHeight(numRows); for(Q_UINT16 i=0; isize(); i++) { Q_UINT8 col; Q_UINT16 row; if (nrCols == 2) { // In two-column display, start with the right column col = (i+1+nrCols) % nrCols; row = (i+1+nrCols) / nrCols - 1; } else { col = (i+nrCols) % nrCols; row = (i+nrCols) / nrCols - 1; } colWidth[col] = QMAX(colWidth[col], (Q_UINT32)widgetList->at(i)->pageSize().width()); rowHeight[row] = QMAX(rowHeight[row], (Q_UINT32)widgetList->at(i)->pageSize().height()); } // Calculate the total width and height of the display Q_UINT32 totalHeight = 0; for(Q_UINT16 i=0; i totalWidth ) centeringLeft = ( newViewportSize.width() - totalWidth )/2; Q_UINT32 centeringTop = 0; if( (Q_UINT32)newViewportSize.height() > totalHeight ) centeringTop = ( newViewportSize.height() - totalHeight)/2; // Resize the viewport if (((Q_UINT32)contentsWidth() != totalWidth) || ((Q_UINT32)contentsHeight() != totalHeight)) { // Calculate the point in the coordinates of the contents which is currently at the center of the viewport. TQPoint midPoint = TQPoint(visibleWidth() / 2 + contentsX(), visibleHeight() / 2 + contentsY()); double midPointRatioX = (double)(midPoint.x()) / contentsWidth(); double midPointRatioY = (double)(midPoint.y()) / contentsHeight(); resizeContents(totalWidth,totalHeight); // If the zoom changed recenter the former midPoint if (zoomChanged) center((int)(contentsWidth() * midPointRatioX), (int)(contentsHeight() * midPointRatioY)); } // Finally, calculate the left and top coordinates of each row and // column, respectively TQMemArray colLeft(nrCols); colLeft[0] = distance; for(Q_UINT8 i=1; i rowTop(numRows); rowTop[0] = distance; for(Q_UINT16 i=1; isize(); i++) { Q_UINT8 col; Q_UINT16 row; if (nrCols == 2) { // In two column-mode start with the right column. col = (i+nrCols-1) % nrCols; row = (i+nrCols-1) / nrCols; } else { col = (i+nrCols) % nrCols; row = i / nrCols; } if (nrCols == 2) { // in 2-column mode right justify the first column, and leftjustify the second column int width = widgetList->at(i)->width(); int left; if (col == 0) left = centeringLeft + colLeft[col] + colWidth[col]-width + distance/2; else left = centeringLeft + colLeft[col]; moveChild( widgetList->at(i), left, centeringTop+rowTop[row]); } else { // in single column and overview mode center the widgets int widgetWidth = widgetList->at(i)->width(); int left = centeringLeft + colLeft[col] + ((int)colWidth[col]-widgetWidth)/2; moveChild(widgetList->at(i), left, centeringTop+rowTop[row]); } } calculateCurrentPageNumber(); } void PageView::contentsWheelEvent ( TQWheelEvent * e ) { emit(wheelEventReceived(e)); } void PageView::moveViewportToWidget(TQWidget* widget, int y) { int verticalPos = 0; int verticalPosTop = 0; if (y != 0) { verticalPosTop = childY(widget) + y - visibleHeight()/2; verticalPos = childY(widget) + y; } else { verticalPos = childY(widget) - distanceBetweenWidgets; verticalPosTop = verticalPos; } if (nrCols == 1) { // In single column viewmodes, we change the vertical position only, to make it // easier to work with high zoomlevels where not the whole pagewidth is visible. // TODO: Smarter algorithm also for continuous facing viewmode. int top = (int)(contentsY() + 0.1 * visibleHeight()); int bottom = (int)(contentsY() + 0.9 * visibleHeight()); // Move the viewport if the target is currently not visible, or lies at the edge // of the viewport. If y = 0 always move the top of the targetpage to the top edge // of the viewport. if (verticalPos < top || verticalPos > bottom || y == 0) { setContentsPos(contentsX(), verticalPosTop); } } else { setContentsPos(childX(widget) - distanceBetweenWidgets, verticalPosTop); } } void PageView::viewportPaintEvent(TQPaintEvent* e) { // Region from which rectangles occupied by child widgets will by substracted. TQRegion backgroundArea(e->rect()); if (widgetList != 0) { for (unsigned int i = 0; i < widgetList->count(); i++) { DocumentWidget* item = widgetList->at(i); // Check if the Widget needs to be updated. if (!item->geometry().intersects(e->rect())) continue; TQRect widgetGeometry = item->geometry(); // Draw the widget. if (e->rect().intersects(widgetGeometry)) { TQRect widgetRect = e->rect().intersect(widgetGeometry); widgetRect.moveBy(-widgetGeometry.left(), -widgetGeometry.top()); item->update(widgetRect); } // Substract the painted area. backgroundArea -= widgetGeometry.intersect(e->rect()); } } // Paint the background. TQPainter p(viewport()); TQMemArray backgroundRects = backgroundArea.rects(); for (unsigned int i = 0; i < backgroundRects.count(); i++) p.fillRect(backgroundRects[i], colorGroup().mid()); } void PageView::calculateCurrentPageNumber(int x, int y) { // Safety check if (widgetList == 0) return; TQRect viewportRect(x, y, visibleWidth(), visibleHeight()); //kdDebug() << "viewportRect(" << viewportRect.x() << ", " << viewportRect.y() << ", " // << viewportRect.width() << ", " << viewportRect.height() << ")" << endl; int maxVisiblePixels = 0; DocumentWidget* _currentWidget = 0; for (Q_UINT16 i = 0; i < widgetList->size(); i++) { DocumentWidget* documentWidget = widgetList->at(i); // Safety check if (documentWidget == 0) continue; // Check if the Widget is visible int cx = childX(documentWidget); int cy = childY(documentWidget); TQRect widgetRect(cx, cy, documentWidget->width(), documentWidget->height()); bool isVisible = widgetRect.intersects(viewportRect); if (!isVisible) continue; // Calculate the number of visible pixels of the widget TQRect visibleRect = widgetRect.intersect(viewportRect); int visiblePixels = visibleRect.width() * visibleRect.height(); //kdDebug() << visiblePixels << " pixels are visible of page " << documentWidget->getPageNumber() << endl; // If a bigger part of this widget as of the previous widgets is visible make it the current widget. if (maxVisiblePixels < visiblePixels) { maxVisiblePixels = visiblePixels; _currentWidget = documentWidget; } } // No page is visible if (_currentWidget == 0) return; // Return the number of the current page emit currentPageChanged(_currentWidget->getPageNumber()); } void PageView::calculateCurrentPageNumber() { calculateCurrentPageNumber(contentsX(), contentsY()); } void PageView::slotEnableMoveTool(bool enable) { moveTool = enable; } #include "pageView.moc"