Back to index

texmacs  1.0.7.15
QTMScrollView.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003  * MODULE     : QTMScrollView.cpp
00004  * DESCRIPTION: QT Texmacs abstract scroll view widget
00005  * COPYRIGHT  : (C) 2009 Massimiliano Gubinelli
00006  *******************************************************************************
00007  * This software falls under the GNU general public license version 3 or later.
00008  * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009  * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010  ******************************************************************************/
00011 
00012 #include "QTMScrollView.hpp"
00013 
00014 #include <QScrollBar>
00015 #include <QPainter>
00016 #include <QBoxLayout>
00017 
00018 #include <QPaintEvent>
00019 
00020 
00021 /* Remarks on QTMScrollView
00022  *
00023  * The current structure of the central texmacs widget (the canvas) is the 
00024  * following: the canvas is a derived class of QTMScrollView which beign
00025  * a QAbstractScrollArea owns a central widget called the "viewport".
00026  * QAbstractScrollArea coordinate the viewport with the scrollbars and maintain
00027  * informations like the real extent of the working surface and the current 
00028  * origin which can be acted upon via the scrollbars. This setup has been 
00029  * augmented via another widget child of the viewport which we call the 
00030  * "surface". The only purpose of this widget is to provide automatic centering
00031  * of the working area inside the viewport. To support this we "un-wired" the
00032  * event redirection build-in in QAbstractScrollArea (from the viewport widget 
00033  * to the QAbstractScrollArea) and re-wired event redirection from the surface
00034  * to the QTMScrollView. All relevants events like resize, I/O events and the 
00035  * like which are sent to the surface are resent to the QTMScrollView for 
00036  * handling. This allow to concentrate all the logic in only one object.
00037  * See QTMSurface::event for info about the redirected events
00038  *
00039  */
00040 
00041 
00042 
00043 class QTMSurface : public QWidget {
00044   QTMScrollView *sv;
00045 public:
00046   QTMSurface(QWidget *parent) 
00047     : QWidget (parent), 
00048       sv (qobject_cast<QTMScrollView*>(parentWidget()->parentWidget())) 
00049   {}
00050 protected:
00051   virtual bool event(QEvent *event) {
00052     return (sv && sv->surfaceEvent(event) ? true : QWidget::event(event));
00053   }  
00054 };
00055 
00056 
00057 QTMScrollView::QTMScrollView ( QWidget *_parent )
00058 : QAbstractScrollArea (_parent), p_extents(QRect(0,0,0,0))  {
00059 
00060   QWidget *_viewport = QAbstractScrollArea::viewport();
00061   _viewport->setBackgroundRole(QPalette::Mid);
00062   _viewport->setAutoFillBackground(true);
00063 
00064   p_surface = new QTMSurface (_viewport);
00065   p_surface->setAttribute(Qt::WA_NoSystemBackground);
00066   p_surface->setAttribute(Qt::WA_StaticContents); 
00067   p_surface->setAttribute(Qt::WA_MacNoClickThrough);
00068   p_surface->setAutoFillBackground(false);
00069   p_surface->setBackgroundRole(QPalette::NoRole);
00070   p_surface->setAttribute(Qt::WA_OpaquePaintEvent);
00071   p_surface->setGeometry(_viewport->geometry());
00072   p_surface->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
00073 
00074   QHBoxLayout *layout = new QHBoxLayout();
00075   layout->addWidget(p_surface, 0, Qt::AlignHCenter);
00076   layout->setContentsMargins(0,0,0,0);
00077   _viewport->setLayout(layout);
00078   
00079 }
00080 
00081 
00082 QWidget* QTMScrollView::surface() {
00083   return p_surface;
00084 }
00085 
00086 QTMScrollView::~QTMScrollView (void) { }
00087 
00088 void 
00089 QTMScrollView::setOrigin ( QPoint newOrigin ) {
00090   if (newOrigin.x() != p_origin.x()) {
00091     QAbstractScrollArea::horizontalScrollBar()->setSliderPosition(newOrigin.x());
00092   }
00093   if (newOrigin.y() != p_origin.y()) {
00094        QAbstractScrollArea::verticalScrollBar()->setSliderPosition(newOrigin.y());
00095   } 
00096 }
00097 
00098 void 
00099 QTMScrollView::setExtents ( QRect newExtents ) {
00100   if (p_extents != newExtents) {
00101     p_extents = newExtents;
00102     if (p_extents.width() < 0) p_extents.setWidth(0);
00103     if (p_extents.height() < 0) p_extents.setHeight(0);
00104     updateScrollBars();
00105   }
00106 }
00107 
00108 void 
00109 QTMScrollView::ensureVisible ( int cx, int cy, int mx, int my ) {
00110        QWidget *_viewport = QAbstractScrollArea::viewport();
00111        int w = _viewport->width();
00112        int h = _viewport->height();
00113   
00114        int dx = - p_origin.x();
00115        int dy = - p_origin.y();
00116        int cw = p_extents.width();
00117        int ch = p_extents.height();
00118   
00119        if (w < mx * 2) mx = w / 2;
00120        if (h < my * 2) my = h / 2;
00121   
00122        if (cw <= w) { mx = 0; dx = 0; }
00123   
00124        if (ch <= h) { my = 0; dy = 0; }
00125   
00126        if (cx < mx - dx) dx = mx - cx;
00127        else if (cx >= w - mx - dx) dx  = w - mx - cx;
00128   
00129        if (cy < my - dy) dy = my - cy;
00130        else if (cy >= h - my - dy) dy  = h - my - cy;
00131   
00132        if (dx > 0) dx = 0;
00133        else if (dx < w - cw && cw > w) dx = w - cw;
00134   
00135        if (dy > 0) dy = 0;
00136        else if (dy < h - ch && ch > h) dy = h - ch;
00137   
00138        setOrigin (QPoint(-dx, -dy));
00139 }
00140 
00141 void 
00142 QTMScrollView::updateScrollBars (void) {
00143        QWidget *_viewport = QAbstractScrollArea::viewport();
00144        int w = _viewport->width()  ; // -2
00145        int h = _viewport->height() ; // -2
00146   
00147        QScrollBar *_hScrollBar = QAbstractScrollArea::horizontalScrollBar();
00148        int cw = (p_extents.width() > w ? p_extents.width() - w : 0);
00149        if (_hScrollBar->sliderPosition() > cw)
00150               _hScrollBar->setSliderPosition(cw);
00151        _hScrollBar->setRange(0, cw);
00152        _hScrollBar->setSingleStep((w >> 4) + 1);
00153        _hScrollBar->setPageStep(w);
00154   
00155   QRect r = (p_extents.width() > w) ? QRect(0,0,w,h) 
00156     : QRect ((w-p_extents.width())/2,0,p_extents.width(),h);
00157 //  surface()->setGeometry(r);
00158   surface()->setMinimumWidth(r.width());
00159   
00160        QScrollBar *_vScrollBar = QAbstractScrollArea::verticalScrollBar();
00161        int ch = (p_extents.height() > h ? p_extents.height() - h : 0);
00162        if (_vScrollBar->sliderPosition() > ch)
00163               _vScrollBar->setSliderPosition(ch);
00164        _vScrollBar->setRange(0, ch);
00165        _vScrollBar->setSingleStep((h >> 4) + 1);
00166        _vScrollBar->setPageStep(h);
00167   
00168   
00169   // we may need a relayout if the surface width is changed
00170   updateGeometry();
00171 }
00172 
00173 #if 0
00174 // this code is wrong
00175 void
00176 QTMScrollView::wheelEvent ( QWheelEvent *wheelEvent ) {
00177        if (wheelEvent->modifiers()
00178       & (Qt::ShiftModifier | Qt::ControlModifier)) {
00179               setOrigin(QPoint(p_origin.x() + wheelEvent->delta(), p_origin.y()));
00180        }
00181        else QAbstractScrollArea::wheelEvent(wheelEvent);
00182 }
00183 #endif
00184 
00185 void
00186 QTMScrollView::scrollContentsBy ( int dx, int dy ) {
00187        if (dx) p_origin.setX(p_origin.x() - dx);
00188        if (dy) p_origin.setY(p_origin.y() - dy);
00189 }
00190 
00191 bool 
00192 QTMScrollView::viewportEvent(QEvent *e)
00193 {
00194   switch (e->type()) {
00195     case QEvent::Resize:
00196     case QEvent::Paint:
00197     case QEvent::MouseButtonPress:
00198     case QEvent::MouseButtonRelease:
00199     case QEvent::MouseButtonDblClick:
00200 #if QT_VERSION >= 0x040600
00201     case QEvent::TouchBegin:
00202     case QEvent::TouchUpdate:
00203     case QEvent::TouchEnd:
00204 #endif
00205     case QEvent::MouseMove:
00206     case QEvent::ContextMenu:
00207     case QEvent::Wheel:
00208     case QEvent::Drop:
00209     case QEvent::DragEnter:
00210     case QEvent::DragMove:
00211     case QEvent::DragLeave:
00212 //      return QFrame::event(e);
00213       return false; // let the viewport widget handle the event
00214     case QEvent::LayoutRequest:
00215 #if QT_VERSION >= 0x040600
00216 #ifndef QT_NO_GESTURES
00217     case QEvent::Gesture:
00218     case QEvent::GestureOverride:
00219       return event(e);
00220 #endif
00221 #endif
00222     default:
00223       break;
00224   }
00225   return false; // let the viewport widget handle the event
00226 }
00227 
00228 bool 
00229 QTMScrollView::surfaceEvent(QEvent *e)
00230 {
00231   switch (e->type()) {
00232     case QEvent::Resize:
00233     case QEvent::Paint:
00234     case QEvent::MouseButtonPress:
00235     case QEvent::MouseButtonRelease:
00236     case QEvent::MouseButtonDblClick:
00237 #if QT_VERSION >= 0x040600
00238     case QEvent::TouchBegin:
00239     case QEvent::TouchUpdate:
00240     case QEvent::TouchEnd:
00241 #endif
00242     case QEvent::MouseMove:
00243     case QEvent::ContextMenu:
00244     case QEvent::Wheel:
00245     case QEvent::Drop:
00246     case QEvent::DragEnter:
00247     case QEvent::DragMove:
00248     case QEvent::DragLeave:
00249       return QFrame::event(e);
00250     case QEvent::LayoutRequest:
00251 #if QT_VERSION >= 0x040600
00252 #ifndef QT_NO_GESTURES
00253     case QEvent::Gesture:
00254     case QEvent::GestureOverride:
00255       return event(e);
00256 #endif
00257 #endif
00258     default:
00259       break;
00260   }
00261   return false; // let the surface widget handle the event
00262 }
00263 
00264 bool QTMScrollView::event (QEvent *event) {
00265   switch (event->type()) {
00266     case QEvent::Resize:
00267     {
00268       bool res = QAbstractScrollArea::event(event);
00269       updateScrollBars();
00270       return res;
00271     }
00272     default:
00273       break;
00274   }
00275   return QAbstractScrollArea::event(event);
00276 }
00277