diff options
Diffstat (limited to 'src/widgets/tqscrollview.cpp')
-rw-r--r-- | src/widgets/tqscrollview.cpp | 2847 |
1 files changed, 2847 insertions, 0 deletions
diff --git a/src/widgets/tqscrollview.cpp b/src/widgets/tqscrollview.cpp new file mode 100644 index 000000000..603110592 --- /dev/null +++ b/src/widgets/tqscrollview.cpp @@ -0,0 +1,2847 @@ +/**************************************************************************** +** +** Implementation of TQScrollView class +** +** Created : 950524 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the widgets module of the TQt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.TQPL +** included in the packaging of this file. Licensees holding valid TQt +** Commercial licenses may use this file in accordance with the TQt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "tqwidget.h" +#ifndef TQT_NO_SCROLLVIEW +#include "tqscrollbar.h" +#include "tqobjectlist.h" +#include "tqpainter.h" +#include "tqpixmap.h" +#include "ntqcursor.h" +#include "ntqfocusdata.h" +#include "tqscrollview.h" +#include "tqptrdict.h" +#include "ntqapplication.h" +#include "tqtimer.h" +#include "tqstyle.h" +#include "ntqlistview.h" +#ifdef TQ_WS_MAC +# include "qt_mac.h" +#endif + +static const int coord_limit = 4000; +static const int autoscroll_margin = 16; +static const int initialScrollTime = 30; +static const int initialScrollAccel = 5; + +struct TQSVChildRec { + TQSVChildRec(TQWidget* c, int xx, int yy) : + child(c), + x(xx), y(yy) + { + } + + void hideOrShow(TQScrollView* sv, TQWidget* clipped_viewport); + void moveTo(TQScrollView* sv, int xx, int yy, TQWidget* clipped_viewport) + { + if ( x != xx || y != yy ) { + x = xx; + y = yy; + hideOrShow(sv,clipped_viewport); + } + } + TQWidget* child; + int x, y; +}; + +void TQSVChildRec::hideOrShow(TQScrollView* sv, TQWidget* clipped_viewport) +{ + if ( clipped_viewport ) { + if ( x+child->width() < sv->contentsX()+clipped_viewport->x() + || x > sv->contentsX()+clipped_viewport->width() + || y+child->height() < sv->contentsY()+clipped_viewport->y() + || y > sv->contentsY()+clipped_viewport->height() ) { + child->move(clipped_viewport->width(), + clipped_viewport->height()); + } else { + child->move(x-sv->contentsX()-clipped_viewport->x(), + y-sv->contentsY()-clipped_viewport->y()); + } + } else { + child->move(x-sv->contentsX(), y-sv->contentsY()); + } +} + +class TQViewportWidget : public TQWidget +{ + TQ_OBJECT + +public: + TQViewportWidget( TQScrollView* parent=0, const char* name=0, WFlags f = 0 ) + : TQWidget( parent, name, f ) {} +}; + +class TQClipperWidget : public TQWidget +{ + TQ_OBJECT + +public: + TQClipperWidget( TQWidget * parent=0, const char * name=0, WFlags f=0 ) + : TQWidget ( parent,name,f) {} +}; + +#include "tqscrollview.moc" + +class TQScrollViewData { +public: + TQScrollViewData(TQScrollView* parent, int vpwflags) : + hbar( new TQScrollBar( TQScrollBar::Horizontal, parent, "qt_hbar" ) ), + vbar( new TQScrollBar( TQScrollBar::Vertical, parent, "qt_vbar" ) ), + viewport( new TQViewportWidget( parent, "qt_viewport", vpwflags ) ), + clipped_viewport( 0 ), + flags( vpwflags ), + vx( 0 ), vy( 0 ), vwidth( 1 ), vheight( 1 ), +#ifndef TQT_NO_DRAGANDDROP + autoscroll_timer( parent, "scrollview autoscroll timer" ), + drag_autoscroll( TRUE ), +#endif + scrollbar_timer( parent, "scrollview scrollbar timer" ), + inresize( FALSE ), use_cached_size_hint( TRUE ) + { + l_marg = r_marg = t_marg = b_marg = 0; + viewport->polish(); + viewport->setBackgroundMode( TQWidget::PaletteDark ); + viewport->setBackgroundOrigin( TQWidget::WidgetOrigin ); + vMode = TQScrollView::Auto; + hMode = TQScrollView::Auto; + corner = 0; + defaultCorner = new TQWidget( parent, "qt_default_corner" ); + defaultCorner->hide(); + vbar->setSteps( 20, 1/*set later*/ ); + hbar->setSteps( 20, 1/*set later*/ ); + policy = TQScrollView::Default; + signal_choke = FALSE; + static_bg = FALSE; + fake_scroll = FALSE; + hbarPressed = FALSE; + vbarPressed = FALSE; + } + ~TQScrollViewData(); + + TQSVChildRec* rec(TQWidget* w) { return childDict.find(w); } + TQSVChildRec* ancestorRec(TQWidget* w); + TQSVChildRec* addChildRec(TQWidget* w, int x, int y ) + { + TQSVChildRec *r = new TQSVChildRec(w,x,y); + children.append(r); + childDict.insert(w, r); + return r; + } + void deleteChildRec(TQSVChildRec* r) + { + childDict.remove(r->child); + children.removeRef(r); + delete r; + } + + void hideOrShowAll(TQScrollView* sv, bool isScroll = FALSE ); + void moveAllBy(int dx, int dy); + bool anyVisibleChildren(); + void autoMove(TQScrollView* sv); + void autoResize(TQScrollView* sv); + void autoResizeHint(TQScrollView* sv); + void viewportResized( int w, int h ); + + TQScrollBar* hbar; + TQScrollBar* vbar; + bool hbarPressed; + bool vbarPressed; + TQViewportWidget* viewport; + TQClipperWidget* clipped_viewport; + int flags; + TQPtrList<TQSVChildRec> children; + TQPtrDict<TQSVChildRec> childDict; + TQWidget* corner, *defaultCorner; + int vx, vy, vwidth, vheight; // for drawContents-style usage + int l_marg, r_marg, t_marg, b_marg; + TQScrollView::ResizePolicy policy; + TQScrollView::ScrollBarMode vMode; + TQScrollView::ScrollBarMode hMode; +#ifndef TQT_NO_DRAGANDDROP + TQPoint cpDragStart; + TQTimer autoscroll_timer; + int autoscroll_time; + int autoscroll_accel; + bool drag_autoscroll; +#endif + TQTimer scrollbar_timer; + + uint static_bg : 1; + uint fake_scroll : 1; + + // This variable allows ensureVisible to move the contents then + // update both the sliders. Otherwise, updating the sliders would + // cause two image scrolls, creating ugly flashing. + // + uint signal_choke : 1; + + // This variables indicates in updateScrollBars() that we are + // in a resizeEvent() and thus don't want to flash scrollbars + uint inresize : 1; + uint use_cached_size_hint : 1; + TQSize cachedSizeHint; + + inline int contentsX() const { return -vx; } + inline int contentsY() const { return -vy; } + inline int contentsWidth() const { return vwidth; } +}; + +inline TQScrollViewData::~TQScrollViewData() +{ + children.setAutoDelete( TRUE ); +} + +TQSVChildRec* TQScrollViewData::ancestorRec(TQWidget* w) +{ + if ( clipped_viewport ) { + while (w->parentWidget() != clipped_viewport) { + w = w->parentWidget(); + if (!w) return 0; + } + } else { + while (w->parentWidget() != viewport) { + w = w->parentWidget(); + if (!w) return 0; + } + } + return rec(w); +} + +void TQScrollViewData::hideOrShowAll(TQScrollView* sv, bool isScroll ) +{ + if ( !clipped_viewport ) + return; + if ( clipped_viewport->x() <= 0 + && clipped_viewport->y() <= 0 + && clipped_viewport->width()+clipped_viewport->x() >= + viewport->width() + && clipped_viewport->height()+clipped_viewport->y() >= + viewport->height() ) { + // clipped_viewport still covers viewport + if( static_bg ) + clipped_viewport->repaint( TRUE ); + else if ( ( !isScroll && !clipped_viewport->testWFlags( TQt::WStaticContents) ) + || static_bg ) + TQApplication::postEvent( clipped_viewport, + new TQPaintEvent( clipped_viewport->clipRegion(), + !clipped_viewport->testWFlags(TQt::WResizeNoErase) ) ); + } else { + // Re-center + int nx = ( viewport->width() - clipped_viewport->width() ) / 2; + int ny = ( viewport->height() - clipped_viewport->height() ) / 2; + clipped_viewport->move(nx,ny); + clipped_viewport->update(); + } + for (TQSVChildRec *r = children.first(); r; r=children.next()) { + r->hideOrShow(sv, clipped_viewport); + } +} + +void TQScrollViewData::moveAllBy(int dx, int dy) +{ + if ( clipped_viewport && !static_bg ) { + clipped_viewport->move( clipped_viewport->x()+dx, + clipped_viewport->y()+dy ); + } else { + for (TQSVChildRec *r = children.first(); r; r=children.next()) { + r->child->move(r->child->x()+dx,r->child->y()+dy); + } + if ( static_bg ) + viewport->repaint( TRUE ); + } +} + +bool TQScrollViewData::anyVisibleChildren() +{ + for (TQSVChildRec *r = children.first(); r; r=children.next()) { + if (r->child->isVisible()) return TRUE; + } + return FALSE; +} + +void TQScrollViewData::autoMove(TQScrollView* sv) +{ + if ( policy == TQScrollView::AutoOne ) { + TQSVChildRec* r = children.first(); + if (r) + sv->setContentsPos(-r->child->x(),-r->child->y()); + } +} + +void TQScrollViewData::autoResize(TQScrollView* sv) +{ + if ( policy == TQScrollView::AutoOne ) { + TQSVChildRec* r = children.first(); + if (r) + sv->resizeContents(r->child->width(),r->child->height()); + } +} + +void TQScrollViewData::autoResizeHint(TQScrollView* sv) +{ + if ( policy == TQScrollView::AutoOne ) { + TQSVChildRec* r = children.first(); + if (r) { + TQSize s = r->child->sizeHint(); + if ( s.isValid() ) + r->child->resize(s); + } + } else if ( policy == TQScrollView::AutoOneFit ) { + TQSVChildRec* r = children.first(); + if (r) { + TQSize sh = r->child->sizeHint(); + sh = sh.boundedTo( r->child->maximumSize() ); + sv->resizeContents( sh.width(), sh.height() ); + } + } +} + +void TQScrollViewData::viewportResized( int w, int h ) +{ + if ( policy == TQScrollView::AutoOneFit ) { + TQSVChildRec* r = children.first(); + if (r) { + TQSize sh = r->child->sizeHint(); + sh = sh.boundedTo( r->child->maximumSize() ); + r->child->resize( TQMAX(w,sh.width()), TQMAX(h,sh.height()) ); + } + + } +} + + +/*! + \class TQScrollView tqscrollview.h + \brief The TQScrollView widget provides a scrolling area with on-demand scroll bars. + + \ingroup abstractwidgets + \mainclass + + The TQScrollView is a large canvas - potentially larger than the + coordinate system normally supported by the underlying window + system. This is important because it is quite easy to go beyond + these limitations (e.g. many web pages are more than 32000 pixels + high). Additionally, the TQScrollView can have TQWidgets positioned + on it that scroll around with the drawn content. These sub-widgets + can also have positions outside the normal coordinate range (but + they are still limited in size). + + To provide content for the widget, inherit from TQScrollView, + reimplement drawContents() and use resizeContents() to set the + size of the viewed area. Use addChild() and moveChild() to + position widgets on the view. + + To use TQScrollView effectively it is important to understand its + widget structure in the three styles of use: a single large child + widget, a large panning area with some widgets and a large panning + area with many widgets. + + \section1 Using One Big Widget + + \img tqscrollview-vp2.png + + The first, simplest usage of TQScrollView (depicted above), is + appropriate for scrolling areas that are never more than about + 4000 pixels in either dimension (this is about the maximum + reliable size on X11 servers). In this usage, you just make one + large child in the TQScrollView. The child should be a child of the + viewport() of the scrollview and be added with addChild(): + \code + TQScrollView* sv = new TQScrollView(...); + TQVBox* big_box = new TQVBox(sv->viewport()); + sv->addChild(big_box); + \endcode + You can go on to add arbitrary child widgets to the single child + in the scrollview as you would with any widget: + \code + TQLabel* child1 = new TQLabel("CHILD", big_box); + TQLabel* child2 = new TQLabel("CHILD", big_box); + TQLabel* child3 = new TQLabel("CHILD", big_box); + ... + \endcode + + Here the TQScrollView has four children: the viewport(), the + verticalScrollBar(), the horizontalScrollBar() and a small + cornerWidget(). The viewport() has one child: the big TQVBox. The + TQVBox has the three TQLabel objects as child widgets. When the view + is scrolled, the TQVBox is moved; its children move with it as + child widgets normally do. + + \section1 Using a Very Big View with Some Widgets + + \img tqscrollview-vp.png + + The second usage of TQScrollView (depicted above) is appropriate + when few, if any, widgets are on a very large scrolling area that + is potentially larger than 4000 pixels in either dimension. In + this usage you call resizeContents() to set the size of the area + and reimplement drawContents() to paint the contents. You may also + add some widgets by making them children of the viewport() and + adding them with addChild() (this is the same as the process for + the single large widget in the previous example): + \code + TQScrollView* sv = new TQScrollView(...); + TQLabel* child1 = new TQLabel("CHILD", sv->viewport()); + sv->addChild(child1); + TQLabel* child2 = new TQLabel("CHILD", sv->viewport()); + sv->addChild(child2); + TQLabel* child3 = new TQLabel("CHILD", sv->viewport()); + sv->addChild(child3); + \endcode + Here, the TQScrollView has the same four children: the viewport(), + the verticalScrollBar(), the horizontalScrollBar() and a small + cornerWidget(). The viewport() has the three TQLabel objects as + child widgets. When the view is scrolled, the scrollview moves the + child widgets individually. + + \section1 Using a Very Big View with Many Widgets + + \target enableclipper + \img tqscrollview-cl.png + + The final usage of TQScrollView (depicted above) is appropriate + when many widgets are on a very large scrolling area that is + potentially larger than 4000 pixels in either dimension. In this + usage you call resizeContents() to set the size of the area and + reimplement drawContents() to paint the contents. You then call + enableClipper(TRUE) and add widgets, again by making them children + of the viewport(), and adding them with addChild(): + \code + TQScrollView* sv = new TQScrollView(...); + sv->enableClipper(TRUE); + TQLabel* child1 = new TQLabel("CHILD", sv->viewport()); + sv->addChild(child1); + TQLabel* child2 = new TQLabel("CHILD", sv->viewport()); + sv->addChild(child2); + TQLabel* child3 = new TQLabel("CHILD", sv->viewport()); + sv->addChild(child3); + \endcode + + Here, the TQScrollView has four children: the clipper() (not the + viewport() this time), the verticalScrollBar(), the + horizontalScrollBar() and a small cornerWidget(). The clipper() + has one child: the viewport(). The viewport() has the same three + labels as child widgets. When the view is scrolled the viewport() + is moved; its children move with it as child widgets normally do. + + \target allviews + \section1 Details Relevant for All Views + + Normally you will use the first or third method if you want any + child widgets in the view. + + Note that the widget you see in the scrolled area is the + viewport() widget, not the TQScrollView itself. So to turn mouse + tracking on, for example, use viewport()->setMouseTracking(TRUE). + + To enable drag-and-drop, you would setAcceptDrops(TRUE) on the + TQScrollView (because drag-and-drop events propagate to the + parent). But to work out the logical position in the view, you + would need to map the drop co-ordinate from being relative to the + TQScrollView to being relative to the contents; use the function + viewportToContents() for this. + + To handle mouse events on the scrolling area, subclass scrollview + as you would subclass other widgets, but rather than + reimplementing mousePressEvent(), reimplement + contentsMousePressEvent() instead. The contents specific event + handlers provide translated events in the coordinate system of the + scrollview. If you reimplement mousePressEvent(), you'll get + called only when part of the TQScrollView is clicked: and the only + such part is the "corner" (if you don't set a cornerWidget()) and + the frame; everything else is covered up by the viewport, clipper + or scroll bars. + + When you construct a TQScrollView, some of the widget flags apply + to the viewport() instead of being sent to the TQWidget constructor + for the TQScrollView. This applies to \c WNoAutoErase, \c + WStaticContents, and \c WPaintClever. See \l TQt::WidgetFlags for + documentation about these flags. Here are some examples: + + \list + + \i An image-manipulation widget would use \c + WNoAutoErase|WStaticContents because the widget draws all pixels + itself, and when its size increases, it only needs a paint event + for the new part because the old part remains unchanged. + + \i A scrolling game widget in which the background scrolls as the + characters move might use \c WNoAutoErase (in addition to \c + WStaticContents) so that the window system background does not + flash in and out during scrolling. + + \i A word processing widget might use \c WNoAutoErase and repaint + itself line by line to get a less-flickery resizing. If the widget + is in a mode in which no text justification can take place, it + might use \c WStaticContents too, so that it would only get a + repaint for the newly visible parts. + + \endlist + + Child widgets may be moved using addChild() or moveChild(). Use + childX() and childY() to get the position of a child widget. + + A widget may be placed in the corner between the vertical and + horizontal scrollbars with setCornerWidget(). You can get access + to the scrollbars using horizontalScrollBar() and + verticalScrollBar(), and to the viewport with viewport(). The + scroll view can be scrolled using scrollBy(), ensureVisible(), + setContentsPos() or center(). + + The visible area is given by visibleWidth() and visibleHeight(), + and the contents area by contentsWidth() and contentsHeight(). The + contents may be repainted using one of the repaintContents() or + updateContents() functions. + + Coordinate conversion is provided by contentsToViewport() and + viewportToContents(). + + The contentsMoving() signal is emitted just before the contents + are moved to a new position. + + \warning TQScrollView currently does not erase the background when + resized, i.e. you must always clear the background manually in + scrollview subclasses. This will change in a future version of TQt + and we recommend specifying the WNoAutoErase flag explicitly. + + <img src=tqscrollview-m.png> <img src=tqscrollview-w.png> +*/ + + +/*! + \enum TQScrollView::ResizePolicy + + This enum type is used to control a TQScrollView's reaction to + resize events. + + \value Default the TQScrollView selects one of the other settings + automatically when it has to. In this version of TQt, TQScrollView + changes to \c Manual if you resize the contents with + resizeContents() and to \c AutoOne if a child is added. + + \value Manual the contents stays the size set by resizeContents(). + + \value AutoOne if there is only one child widget the contents stays + the size of that widget. Otherwise the behavior is undefined. + + \value AutoOneFit if there is only one child widget the contents stays + the size of that widget's sizeHint(). If the scrollview is resized + larger than the child's sizeHint(), the child will be resized to + fit. If there is more than one child, the behavior is undefined. + +*/ +//#### The widget will be resized to its sizeHint() when a LayoutHint event +//#### is received + +/*! + Constructs a TQScrollView called \a name with parent \a parent and + widget flags \a f. + + The widget flags \c WStaticContents, \c WNoAutoErase and \c + WPaintClever are propagated to the viewport() widget. The other + widget flags are propagated to the parent constructor as usual. +*/ + +TQScrollView::TQScrollView( TQWidget *parent, const char *name, WFlags f ) : + TQFrame( parent, name, f & (~WStaticContents) & (~WResizeNoErase) ) +{ + WFlags flags = WResizeNoErase | (f&WPaintClever) | (f&WRepaintNoErase) | (f&WStaticContents); + d = new TQScrollViewData( this, flags ); + +#ifndef TQT_NO_DRAGANDDROP + connect( &d->autoscroll_timer, TQ_SIGNAL( timeout() ), + this, TQ_SLOT( doDragAutoScroll() ) ); +#endif + + connect( d->hbar, TQ_SIGNAL( valueChanged(int) ), + this, TQ_SLOT( hslide(int) ) ); + connect( d->vbar, TQ_SIGNAL( valueChanged(int) ), + this, TQ_SLOT( vslide(int) ) ); + + connect( d->hbar, TQ_SIGNAL(sliderPressed()), this, TQ_SLOT(hbarIsPressed()) ); + connect( d->hbar, TQ_SIGNAL(sliderReleased()), this, TQ_SLOT(hbarIsReleased()) ); + connect( d->vbar, TQ_SIGNAL(sliderPressed()), this, TQ_SLOT(vbarIsPressed()) ); + connect( d->vbar, TQ_SIGNAL(sliderReleased()), this, TQ_SLOT(vbarIsReleased()) ); + + + d->viewport->installEventFilter( this ); + + connect( &d->scrollbar_timer, TQ_SIGNAL( timeout() ), + this, TQ_SLOT( updateScrollBars() ) ); + + setFrameStyle( TQFrame::StyledPanel | TQFrame::Sunken ); + setLineWidth( style().pixelMetric(TQStyle::PM_DefaultFrameWidth, this) ); + setSizePolicy( TQSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Expanding ) ); +} + + +/*! + Destroys the TQScrollView. Any children added with addChild() will + be deleted. +*/ +TQScrollView::~TQScrollView() +{ + // Be careful not to get all those useless events... + if ( d->clipped_viewport ) + d->clipped_viewport->removeEventFilter( this ); + else + d->viewport->removeEventFilter( this ); + + // order is important + // ~TQWidget may cause a WM_ERASEBKGND on Windows + delete d->vbar; + d->vbar = 0; + delete d->hbar; + d->hbar = 0; + delete d->viewport; + d->viewport = 0; + delete d; + d = 0; +} + +/*! + \fn void TQScrollView::horizontalSliderPressed() + + This signal is emitted whenever the user presses the horizontal slider. +*/ +/*! + \fn void TQScrollView::horizontalSliderReleased() + + This signal is emitted whenever the user releases the horizontal slider. +*/ +/*! + \fn void TQScrollView::verticalSliderPressed() + + This signal is emitted whenever the user presses the vertical slider. +*/ +/*! + \fn void TQScrollView::verticalSliderReleased() + + This signal is emitted whenever the user releases the vertical slider. +*/ +void TQScrollView::hbarIsPressed() +{ + d->hbarPressed = TRUE; + emit( horizontalSliderPressed() ); +} + +void TQScrollView::hbarIsReleased() +{ + d->hbarPressed = FALSE; + emit( horizontalSliderReleased() ); +} + +/*! + Returns TRUE if horizontal slider is pressed by user; otherwise returns FALSE. +*/ +bool TQScrollView::isHorizontalSliderPressed() +{ + return d->hbarPressed; +} + +void TQScrollView::vbarIsPressed() +{ + d->vbarPressed = TRUE; + emit( verticalSliderPressed() ); +} + +void TQScrollView::vbarIsReleased() +{ + d->vbarPressed = FALSE; + emit( verticalSliderReleased() ); +} + +/*! + Returns TRUE if vertical slider is pressed by user; otherwise returns FALSE. +*/ +bool TQScrollView::isVerticalSliderPressed() +{ + return d->vbarPressed; +} + +/*! + \reimp +*/ +void TQScrollView::styleChange( TQStyle& old ) +{ + TQWidget::styleChange( old ); + updateScrollBars(); + d->cachedSizeHint = TQSize(); +} + +/*! + \reimp +*/ +void TQScrollView::fontChange( const TQFont &old ) +{ + TQWidget::fontChange( old ); + updateScrollBars(); + d->cachedSizeHint = TQSize(); +} + +void TQScrollView::hslide( int pos ) +{ + if ( !d->signal_choke ) { + moveContents( -pos, -d->contentsY() ); + TQApplication::syncX(); + } +} + +void TQScrollView::vslide( int pos ) +{ + if ( !d->signal_choke ) { + moveContents( -d->contentsX(), -pos ); + TQApplication::syncX(); + } +} + +/*! + Called when the horizontal scroll bar geometry changes. This is + provided as a protected function so that subclasses can do + interesting things such as providing extra buttons in some of the + space normally used by the scroll bars. + + The default implementation simply gives all the space to \a hbar. + The new geometry is given by \a x, \a y, \a w and \a h. + + \sa setVBarGeometry() +*/ +void TQScrollView::setHBarGeometry(TQScrollBar& hbar, + int x, int y, int w, int h) +{ + hbar.setGeometry( x, y, w, h ); +} + +/*! + Called when the vertical scroll bar geometry changes. This is + provided as a protected function so that subclasses can do + interesting things such as providing extra buttons in some of the + space normally used by the scroll bars. + + The default implementation simply gives all the space to \a vbar. + The new geometry is given by \a x, \a y, \a w and \a h. + + \sa setHBarGeometry() +*/ +void TQScrollView::setVBarGeometry( TQScrollBar& vbar, + int x, int y, int w, int h) +{ + vbar.setGeometry( x, y, w, h ); +} + + +/*! + Returns the viewport size for size (\a x, \a y). + + The viewport size depends on \a (x, y) (the size of the contents), + the size of this widget and the modes of the horizontal and + vertical scroll bars. + + This function permits widgets that can trade vertical and + horizontal space for each other to control scroll bar appearance + better. For example, a word processor or web browser can control + the width of the right margin accurately, whether or not there + needs to be a vertical scroll bar. +*/ + +TQSize TQScrollView::viewportSize( int x, int y ) const +{ + int fw = frameWidth(); + int lmarg = fw+d->l_marg; + int rmarg = fw+d->r_marg; + int tmarg = fw+d->t_marg; + int bmarg = fw+d->b_marg; + + int w = width(); + int h = height(); + + bool needh, needv; + bool showh, showv; + int hsbExt = horizontalScrollBar()->sizeHint().height(); + int vsbExt = verticalScrollBar()->sizeHint().width(); + + if ( d->policy != AutoOne || d->anyVisibleChildren() ) { + // Do we definitely need the scrollbar? + needh = w-lmarg-rmarg < x; + needv = h-tmarg-bmarg < y; + + // Do we intend to show the scrollbar? + if (d->hMode == AlwaysOn) + showh = TRUE; + else if (d->hMode == AlwaysOff) + showh = FALSE; + else + showh = needh; + + if (d->vMode == AlwaysOn) + showv = TRUE; + else if (d->vMode == AlwaysOff) + showv = FALSE; + else + showv = needv; + + // Given other scrollbar will be shown, NOW do we need one? + if ( showh && h-vsbExt-tmarg-bmarg < y ) { + if (d->vMode == Auto) + showv=TRUE; + } + if ( showv && w-hsbExt-lmarg-rmarg < x ) { + if (d->hMode == Auto) + showh=TRUE; + } + } else { + // Scrollbars not needed, only show scrollbar that are always on. + showh = d->hMode == AlwaysOn; + showv = d->vMode == AlwaysOn; + } + + return TQSize( w-lmarg-rmarg - (showv ? vsbExt : 0), + h-tmarg-bmarg - (showh ? hsbExt : 0) ); +} + + +/*! + Updates scroll bars: all possibilities are considered. You should + never need to call this in your code. +*/ +void TQScrollView::updateScrollBars() +{ + if(!horizontalScrollBar() && !verticalScrollBar()) + return; + + // I support this should use viewportSize()... but it needs + // so many of the temporary variables from viewportSize. hm. + int fw = frameWidth(); + int lmarg = fw+d->l_marg; + int rmarg = fw+d->r_marg; + int tmarg = fw+d->t_marg; + int bmarg = fw+d->b_marg; + + int w = width(); + int h = height(); + + int portw, porth; + + bool needh; + bool needv; + bool showh; + bool showv; + bool showc = FALSE; + + int hsbExt = horizontalScrollBar()->sizeHint().height(); + int vsbExt = verticalScrollBar()->sizeHint().width(); + + TQSize oldVisibleSize( visibleWidth(), visibleHeight() ); + + if ( d->policy != AutoOne || d->anyVisibleChildren() ) { + // Do we definitely need the scrollbar? + needh = w-lmarg-rmarg < d->contentsWidth(); + if ( d->inresize ) + needh = !horizontalScrollBar()->isHidden(); + needv = h-tmarg-bmarg < contentsHeight(); + + // Do we intend to show the scrollbar? + if (d->hMode == AlwaysOn) + showh = TRUE; + else if (d->hMode == AlwaysOff) + showh = FALSE; + else + showh = needh; + + if (d->vMode == AlwaysOn) + showv = TRUE; + else if (d->vMode == AlwaysOff) + showv = FALSE; + else + showv = needv; + +#ifdef TQ_WS_MAC + bool mac_need_scroll = FALSE; + if(!parentWidget()) { + mac_need_scroll = TRUE; + } else { + TQWidget *tlw = topLevelWidget(); + TQPoint tlw_br = TQPoint(tlw->width(), tlw->height()), + my_br = posInWindow(this) + TQPoint(w, h); + if(my_br.x() >= tlw_br.x() - 3 && my_br.y() >= tlw_br.y() - 3) + mac_need_scroll = TRUE; + } + if(mac_need_scroll) { + WindowAttributes attr; + GetWindowAttributes((WindowPtr)handle(), &attr); + mac_need_scroll = (attr & kWindowResizableAttribute); + } + if(mac_need_scroll) { + showc = TRUE; + if(d->vMode == Auto) + showv = TRUE; + if(d->hMode == Auto) + showh = TRUE; + } +#endif + + // Given other scrollbar will be shown, NOW do we need one? + if ( showh && h-vsbExt-tmarg-bmarg < contentsHeight() ) { + needv=TRUE; + if (d->vMode == Auto) + showv=TRUE; + } + if ( showv && !d->inresize && w-hsbExt-lmarg-rmarg < d->contentsWidth() ) { + needh=TRUE; + if (d->hMode == Auto) + showh=TRUE; + } + } else { + // Scrollbars not needed, only show scrollbar that are always on. + needh = needv = FALSE; + showh = d->hMode == AlwaysOn; + showv = d->vMode == AlwaysOn; + } + + bool sc = d->signal_choke; + d->signal_choke=TRUE; + + // Hide unneeded scrollbar, calculate viewport size + if ( showh ) { + porth=h-hsbExt-tmarg-bmarg; + } else { + if (!needh) + d->hbar->setValue(0); + d->hbar->hide(); + porth=h-tmarg-bmarg; + } + if ( showv ) { + portw=w-vsbExt-lmarg-rmarg; + } else { + if (!needv) + d->vbar->setValue(0); + d->vbar->hide(); + portw=w-lmarg-rmarg; + } + + // Configure scrollbars that we will show + if ( needv ) { + d->vbar->setRange( 0, contentsHeight()-porth ); + d->vbar->setSteps( TQScrollView::d->vbar->lineStep(), porth ); + } else { + d->vbar->setRange( 0, 0 ); + } + if ( needh ) { + d->hbar->setRange( 0, TQMAX(0, d->contentsWidth()-portw) ); + d->hbar->setSteps( TQScrollView::d->hbar->lineStep(), portw ); + } else { + d->hbar->setRange( 0, 0 ); + } + + // Position the scrollbars, viewport and corner widget. + int bottom; + bool reverse = TQApplication::reverseLayout(); + int xoffset = ( reverse && (showv || cornerWidget() )) ? vsbExt : 0; + int xpos = reverse ? 0 : w - vsbExt; + bool frameContentsOnly = + style().styleHint(TQStyle::SH_ScrollView_FrameOnlyAroundContents); + + if( ! frameContentsOnly ) { + if ( reverse ) + xpos += fw; + else + xpos -= fw; + } + if ( showh ) { + int right = ( showc || showv || cornerWidget() ) ? w-vsbExt : w; + if ( ! frameContentsOnly ) + setHBarGeometry( *d->hbar, fw + xoffset, h-hsbExt-fw, + right-fw-fw, hsbExt ); + else + setHBarGeometry( *d->hbar, 0 + xoffset, h-hsbExt, right, + hsbExt ); + bottom=h-hsbExt; + } else { + bottom=h; + } + if ( showv ) { + clipper()->setGeometry( lmarg + xoffset, tmarg, + w-vsbExt-lmarg-rmarg, + bottom-tmarg-bmarg ); + d->viewportResized( w-vsbExt-lmarg-rmarg, bottom-tmarg-bmarg ); + if ( ! frameContentsOnly ) + changeFrameRect(TQRect(0, 0, w, h) ); + else + changeFrameRect(TQRect(xoffset, 0, w-vsbExt, bottom)); + if (showc || cornerWidget()) { + if ( ! frameContentsOnly ) + setVBarGeometry( *d->vbar, xpos, + fw, vsbExt, + h-hsbExt-fw-fw ); + else + setVBarGeometry( *d->vbar, xpos, 0, + vsbExt, + h-hsbExt ); + } + else { + if ( ! frameContentsOnly ) + setVBarGeometry( *d->vbar, xpos, + fw, vsbExt, + bottom-fw-fw ); + else + setVBarGeometry( *d->vbar, xpos, 0, + vsbExt, bottom ); + } + } else { + if ( ! frameContentsOnly ) + changeFrameRect(TQRect(0, 0, w, h)); + else + changeFrameRect(TQRect(0, 0, w, bottom)); + clipper()->setGeometry( lmarg, tmarg, + w-lmarg-rmarg, bottom-tmarg-bmarg ); + d->viewportResized( w-lmarg-rmarg, bottom-tmarg-bmarg ); + } + + TQWidget *corner = d->corner; + if ( !d->corner ) + corner = d->defaultCorner; + if ( ! frameContentsOnly ) + corner->setGeometry( xpos, + h-hsbExt-fw, + vsbExt, + hsbExt ); + else + corner->setGeometry( xpos, + h-hsbExt, + vsbExt, + hsbExt ); + + d->signal_choke=sc; + + if ( d->contentsX()+visibleWidth() > d->contentsWidth() ) { + int x; +#if 0 + if ( reverse ) + x =TQMIN(0,d->contentsWidth()-visibleWidth()); + else +#endif + x =TQMAX(0,d->contentsWidth()-visibleWidth()); + d->hbar->setValue(x); + // Do it even if it is recursive + moveContents( -x, -d->contentsY() ); + } + if ( d->contentsY()+visibleHeight() > contentsHeight() ) { + int y=TQMAX(0,contentsHeight()-visibleHeight()); + d->vbar->setValue(y); + // Do it even if it is recursive + moveContents( -d->contentsX(), -y ); + } + + // Finally, show the scroll bars + if ( showh && ( d->hbar->isHidden() || !d->hbar->isVisible() ) ) + d->hbar->show(); + if ( showv && ( d->vbar->isHidden() || !d->vbar->isVisible() ) ) + d->vbar->show(); + + d->signal_choke=TRUE; + d->vbar->setValue( d->contentsY() ); + d->hbar->setValue( d->contentsX() ); + d->signal_choke=FALSE; + + TQSize newVisibleSize( visibleWidth(), visibleHeight() ); + if ( d->clipped_viewport && oldVisibleSize != newVisibleSize ) { + TQResizeEvent e( newVisibleSize, oldVisibleSize ); + viewportResizeEvent( &e ); + } +} + + +/*! + \reimp +*/ +void TQScrollView::show() +{ + if ( isVisible() ) + return; + TQWidget::show(); + updateScrollBars(); + d->hideOrShowAll(this); +} + +/*! + \reimp + */ +void TQScrollView::resize( int w, int h ) +{ + TQWidget::resize( w, h ); +} + +/*! + \reimp +*/ +void TQScrollView::resize( const TQSize& s ) +{ + resize( s.width(), s.height() ); +} + +/*! + \reimp +*/ +void TQScrollView::resizeEvent( TQResizeEvent* event ) +{ + TQFrame::resizeEvent( event ); + +#if 0 + if ( TQApplication::reverseLayout() ) { + d->fake_scroll = TRUE; + scrollBy( -event->size().width() + event->oldSize().width(), 0 ); + d->fake_scroll = FALSE; + } +#endif + + bool inresize = d->inresize; + d->inresize = TRUE; + updateScrollBars(); + d->inresize = inresize; + d->scrollbar_timer.start( 0, TRUE ); + + d->hideOrShowAll(this); +} + + + +/*! + \reimp +*/ +void TQScrollView::mousePressEvent( TQMouseEvent * e) //#### remove for 4.0 +{ + e->ignore(); +} + +/*! + \reimp +*/ +void TQScrollView::mouseReleaseEvent( TQMouseEvent *e ) //#### remove for 4.0 +{ + e->ignore(); +} + + +/*! + \reimp +*/ +void TQScrollView::mouseDoubleClickEvent( TQMouseEvent *e ) //#### remove for 4.0 +{ + e->ignore(); +} + +/*! + \reimp +*/ +void TQScrollView::mouseMoveEvent( TQMouseEvent *e ) //#### remove for 4.0 +{ + e->ignore(); +} + +/*! + \reimp +*/ +#ifndef TQT_NO_WHEELEVENT +void TQScrollView::wheelEvent( TQWheelEvent *e ) +{ + TQWheelEvent ce( viewport()->mapFromGlobal( e->globalPos() ), + e->globalPos(), e->delta(), e->state(), e->orientation()); + viewportWheelEvent(&ce); + if ( !ce.isAccepted() ) { + if ( e->orientation() == Horizontal && horizontalScrollBar() && horizontalScrollBar()->isEnabled() ) + TQApplication::sendEvent( horizontalScrollBar(), e); + else if (e->orientation() == Vertical && verticalScrollBar() && verticalScrollBar()->isEnabled() ) + TQApplication::sendEvent( verticalScrollBar(), e); + } else { + e->accept(); + } +} +#endif + +/*! + \reimp +*/ +void TQScrollView::contextMenuEvent( TQContextMenuEvent *e ) +{ + if ( e->reason() != TQContextMenuEvent::Keyboard ) { + e->ignore(); + return; + } + + TQContextMenuEvent ce( e->reason(), viewport()->mapFromGlobal( e->globalPos() ), + e->globalPos(), e->state() ); + viewportContextMenuEvent( &ce ); + if ( ce.isAccepted() ) + e->accept(); + else + e->ignore(); +} + +TQScrollView::ScrollBarMode TQScrollView::vScrollBarMode() const +{ + return d->vMode; +} + + +/*! + \enum TQScrollView::ScrollBarMode + + This enum type describes the various modes of TQScrollView's scroll + bars. + + \value Auto TQScrollView shows a scroll bar when the content is + too large to fit and not otherwise. This is the default. + + \value AlwaysOff TQScrollView never shows a scroll bar. + + \value AlwaysOn TQScrollView always shows a scroll bar. + + (The modes for the horizontal and vertical scroll bars are + independent.) +*/ + + +/*! + \property TQScrollView::vScrollBarMode + \brief the mode for the vertical scroll bar + + The default mode is \c TQScrollView::Auto. + + \sa hScrollBarMode +*/ +void TQScrollView::setVScrollBarMode( ScrollBarMode mode ) +{ + if (d->vMode != mode) { + d->vMode = mode; + updateScrollBars(); + } +} + + +/*! + \property TQScrollView::hScrollBarMode + \brief the mode for the horizontal scroll bar + + The default mode is \c TQScrollView::Auto. + + \sa vScrollBarMode +*/ +TQScrollView::ScrollBarMode TQScrollView::hScrollBarMode() const +{ + return d->hMode; +} + +void TQScrollView::setHScrollBarMode( ScrollBarMode mode ) +{ + if (d->hMode != mode) { + d->hMode = mode; + updateScrollBars(); + } +} + + +/*! + Returns the widget in the corner between the two scroll bars. + + By default, no corner widget is present. +*/ +TQWidget* TQScrollView::cornerWidget() const +{ + return d->corner; +} + +/*! + Sets the widget in the \a corner between the two scroll bars. + + You will probably also want to set at least one of the scroll bar + modes to \c AlwaysOn. + + Passing 0 shows no widget in the corner. + + Any previous \a corner widget is hidden. + + You may call setCornerWidget() with the same widget at different + times. + + All widgets set here will be deleted by the TQScrollView when it is + destroyed unless you separately reparent the widget after setting + some other corner widget (or 0). + + Any \e newly set widget should have no current parent. + + By default, no corner widget is present. + + \sa setVScrollBarMode(), setHScrollBarMode() +*/ +void TQScrollView::setCornerWidget(TQWidget* corner) +{ + TQWidget* oldcorner = d->corner; + if (oldcorner != corner) { + if (oldcorner) oldcorner->hide(); + d->corner = corner; + + if ( corner && corner->parentWidget() != this ) { + // #### No clean way to get current WFlags + corner->reparent( this, (((TQScrollView*)corner))->getWFlags(), + TQPoint(0,0), FALSE ); + } + + updateScrollBars(); + if ( corner ) corner->show(); + } +} + + +void TQScrollView::setResizePolicy( ResizePolicy r ) +{ + d->policy = r; +} + +/*! + \property TQScrollView::resizePolicy + \brief the resize policy + + The default is \c Default. + + \sa ResizePolicy +*/ +TQScrollView::ResizePolicy TQScrollView::resizePolicy() const +{ + return d->policy; +} + +/*! + \reimp +*/ +void TQScrollView::setEnabled( bool enable ) +{ + TQFrame::setEnabled( enable ); +} + +/*! + Removes the \a child widget from the scrolled area. Note that this + happens automatically if the \a child is deleted. +*/ +void TQScrollView::removeChild(TQWidget* child) +{ + if ( !d || !child ) // First check in case we are destructing + return; + + TQSVChildRec *r = d->rec(child); + if ( r ) d->deleteChildRec( r ); +} + +/*! + \reimp +*/ +void TQScrollView::removeChild(TQObject* child) +{ + TQFrame::removeChild(child); +} + +/*! + Inserts the widget, \a child, into the scrolled area positioned at + (\a x, \a y). The position defaults to (0, 0). If the child is + already in the view, it is just moved. + + You may want to call enableClipper(TRUE) if you add a large number + of widgets. +*/ +void TQScrollView::addChild(TQWidget* child, int x, int y) +{ + if ( !child ) { +#if defined(QT_CHECK_NULL) + tqWarning( "TQScrollView::addChild(): Cannot add null child" ); +#endif + return; + } + child->polish(); + child->setBackgroundOrigin(WidgetOrigin); + + if ( child->parentWidget() == viewport() ) { + // May already be there + TQSVChildRec *r = d->rec(child); + if (r) { + r->moveTo(this,x,y,d->clipped_viewport); + if ( d->policy > Manual ) { + d->autoResizeHint(this); + d->autoResize(this); // #### better to just deal with this one widget! + } + return; + } + } + + if ( d->children.isEmpty() && d->policy != Manual ) { + if ( d->policy == Default ) + setResizePolicy( AutoOne ); + child->installEventFilter( this ); + } else if ( d->policy == AutoOne ) { + child->removeEventFilter( this ); //#### ????? + setResizePolicy( Manual ); + } + if ( child->parentWidget() != viewport() ) { + child->reparent( viewport(), 0, TQPoint(0,0), FALSE ); + } + d->addChildRec(child,x,y)->hideOrShow(this, d->clipped_viewport); + + if ( d->policy > Manual ) { + d->autoResizeHint(this); + d->autoResize(this); // #### better to just deal with this one widget! + } +} + +/*! + Repositions the \a child widget to (\a x, \a y). This function is + the same as addChild(). +*/ +void TQScrollView::moveChild(TQWidget* child, int x, int y) +{ + addChild(child,x,y); +} + +/*! + Returns the X position of the given \a child widget. Use this + rather than TQWidget::x() for widgets added to the view. + + This function returns 0 if \a child has not been added to the view. +*/ +int TQScrollView::childX(TQWidget* child) +{ + TQSVChildRec *r = d->rec(child); + return r ? r->x : 0; +} + +/*! + Returns the Y position of the given \a child widget. Use this + rather than TQWidget::y() for widgets added to the view. + + This function returns 0 if \a child has not been added to the view. +*/ +int TQScrollView::childY(TQWidget* child) +{ + TQSVChildRec *r = d->rec(child); + return r ? r->y : 0; +} + +/*! \fn bool TQScrollView::childIsVisible(TQWidget*) + \obsolete + + Returns TRUE if \a child is visible. This is equivalent + to child->isVisible(). +*/ + +/*! \fn void TQScrollView::showChild(TQWidget* child, bool y) + \obsolete + + Sets the visibility of \a child. Equivalent to + TQWidget::show() or TQWidget::hide(). +*/ + +/*! + This event filter ensures the scroll bars are updated when a + single contents widget is resized, shown, hidden or destroyed; it + passes mouse events to the TQScrollView. The event is in \a e and + the object is in \a obj. +*/ + +bool TQScrollView::eventFilter( TQObject *obj, TQEvent *e ) +{ + if ( !d ) + return FALSE; // we are destructing + if ( obj == d->viewport || obj == d->clipped_viewport ) { + switch ( e->type() ) { + /* Forward many events to viewport...() functions */ + case TQEvent::Paint: + viewportPaintEvent( (TQPaintEvent*)e ); + break; + case TQEvent::Resize: + if ( !d->clipped_viewport ) + viewportResizeEvent( (TQResizeEvent *)e ); + break; + case TQEvent::MouseButtonPress: + viewportMousePressEvent( (TQMouseEvent*)e ); + if ( ((TQMouseEvent*)e)->isAccepted() ) + return TRUE; + break; + case TQEvent::MouseButtonRelease: + viewportMouseReleaseEvent( (TQMouseEvent*)e ); + if ( ((TQMouseEvent*)e)->isAccepted() ) + return TRUE; + break; + case TQEvent::MouseButtonDblClick: + viewportMouseDoubleClickEvent( (TQMouseEvent*)e ); + if ( ((TQMouseEvent*)e)->isAccepted() ) + return TRUE; + break; + case TQEvent::MouseMove: + viewportMouseMoveEvent( (TQMouseEvent*)e ); + if ( ((TQMouseEvent*)e)->isAccepted() ) + return TRUE; + break; +#ifndef TQT_NO_DRAGANDDROP + case TQEvent::DragEnter: + viewportDragEnterEvent( (TQDragEnterEvent*)e ); + break; + case TQEvent::DragMove: { + if ( d->drag_autoscroll ) { + TQPoint vp = ((TQDragMoveEvent*) e)->pos(); + TQRect inside_margin( autoscroll_margin, autoscroll_margin, + visibleWidth() - autoscroll_margin * 2, + visibleHeight() - autoscroll_margin * 2 ); + if ( !inside_margin.contains( vp ) ) { + startDragAutoScroll(); + // Keep sending move events + ( (TQDragMoveEvent*)e )->accept( TQRect(0,0,0,0) ); + } + } + viewportDragMoveEvent( (TQDragMoveEvent*)e ); + } break; + case TQEvent::DragLeave: + stopDragAutoScroll(); + viewportDragLeaveEvent( (TQDragLeaveEvent*)e ); + break; + case TQEvent::Drop: + stopDragAutoScroll(); + viewportDropEvent( (TQDropEvent*)e ); + break; +#endif // TQT_NO_DRAGANDDROP + case TQEvent::ContextMenu: + viewportContextMenuEvent( (TQContextMenuEvent*)e ); + if ( ((TQContextMenuEvent*)e)->isAccepted() ) + return TRUE; + break; + case TQEvent::ChildRemoved: + removeChild((TQWidget*)((TQChildEvent*)e)->child()); + break; + case TQEvent::LayoutHint: + d->autoResizeHint(this); + break; + case TQEvent::WindowActivate: + case TQEvent::WindowDeactivate: + return TRUE; + default: + break; + } + } else if ( d && d->rec((TQWidget*)obj) ) { // must be a child + if ( e->type() == TQEvent::Resize ) + d->autoResize(this); + else if ( e->type() == TQEvent::Move ) + d->autoMove(this); + } + return TQFrame::eventFilter( obj, e ); // always continue with standard event processing +} + +/*! + This event handler is called whenever the TQScrollView receives a + mousePressEvent(): the press position in \a e is translated to be a point + on the contents. +*/ +void TQScrollView::contentsMousePressEvent( TQMouseEvent* e ) +{ + e->ignore(); +} + +/*! + This event handler is called whenever the TQScrollView receives a + mouseReleaseEvent(): the release position in \a e is translated to be a + point on the contents. +*/ +void TQScrollView::contentsMouseReleaseEvent( TQMouseEvent* e ) +{ + e->ignore(); +} + +/*! + This event handler is called whenever the TQScrollView receives a + mouseDoubleClickEvent(): the click position in \a e is translated to be a + point on the contents. + + The default implementation generates a normal mouse press event. +*/ +void TQScrollView::contentsMouseDoubleClickEvent( TQMouseEvent* e ) +{ + contentsMousePressEvent(e); // try mouse press event +} + +/*! + This event handler is called whenever the TQScrollView receives a + mouseMoveEvent(): the mouse position in \a e is translated to be a point + on the contents. +*/ +void TQScrollView::contentsMouseMoveEvent( TQMouseEvent* e ) +{ + e->ignore(); +} + +#ifndef TQT_NO_DRAGANDDROP + +/*! + This event handler is called whenever the TQScrollView receives a + dragEnterEvent(): the drag position is translated to be a point + on the contents. +*/ +void TQScrollView::contentsDragEnterEvent( TQDragEnterEvent * ) +{ +} + +/*! + This event handler is called whenever the TQScrollView receives a + dragMoveEvent(): the drag position is translated to be a point on + the contents. +*/ +void TQScrollView::contentsDragMoveEvent( TQDragMoveEvent * ) +{ +} + +/*! + This event handler is called whenever the TQScrollView receives a + dragLeaveEvent(): the drag position is translated to be a point + on the contents. +*/ +void TQScrollView::contentsDragLeaveEvent( TQDragLeaveEvent * ) +{ +} + +/*! + This event handler is called whenever the TQScrollView receives a + dropEvent(): the drop position is translated to be a point on the + contents. +*/ +void TQScrollView::contentsDropEvent( TQDropEvent * ) +{ +} + +#endif // TQT_NO_DRAGANDDROP + +/*! + This event handler is called whenever the TQScrollView receives a + wheelEvent() in \a{e}: the mouse position is translated to be a + point on the contents. +*/ +#ifndef TQT_NO_WHEELEVENT +void TQScrollView::contentsWheelEvent( TQWheelEvent * e ) +{ + e->ignore(); +} +#endif +/*! + This event handler is called whenever the TQScrollView receives a + contextMenuEvent() in \a{e}: the mouse position is translated to + be a point on the contents. +*/ +void TQScrollView::contentsContextMenuEvent( TQContextMenuEvent *e ) +{ + e->ignore(); +} + +/*! + This is a low-level painting routine that draws the viewport + contents. Reimplement this if drawContents() is too high-level + (for example, if you don't want to open a TQPainter on the + viewport). The paint event is passed in \a pe. +*/ +void TQScrollView::viewportPaintEvent( TQPaintEvent* pe ) +{ + TQWidget* vp = viewport(); + + TQPainter p(vp); + TQRect r = pe->rect(); + + if ( d->clipped_viewport ) { + TQRect rr( + -d->clipped_viewport->x(), -d->clipped_viewport->y(), + d->viewport->width(), d->viewport->height() + ); + r &= rr; + if ( r.isValid() ) { + int ex = r.x() + d->clipped_viewport->x() + d->contentsX(); + int ey = r.y() + d->clipped_viewport->y() + d->contentsY(); + int ew = r.width(); + int eh = r.height(); + drawContentsOffset(&p, + d->contentsX()+d->clipped_viewport->x(), + d->contentsY()+d->clipped_viewport->y(), + ex, ey, ew, eh); + } + } else { + r &= d->viewport->rect(); + int ex = r.x() + d->contentsX(); + int ey = r.y() + d->contentsY(); + int ew = r.width(); + int eh = r.height(); + drawContentsOffset(&p, d->contentsX(), d->contentsY(), ex, ey, ew, eh); + } +} + + +/*! + To provide simple processing of events on the contents, this + function receives all resize events sent to the viewport. + + \sa TQWidget::resizeEvent() +*/ +void TQScrollView::viewportResizeEvent( TQResizeEvent* ) +{ +} + +/*! \internal + + To provide simple processing of events on the contents, this + function receives all mouse press events sent to the viewport, + translates the event and calls contentsMousePressEvent(). + + \sa contentsMousePressEvent(), TQWidget::mousePressEvent() +*/ +void TQScrollView::viewportMousePressEvent( TQMouseEvent* e ) +{ + TQMouseEvent ce(e->type(), viewportToContents(e->pos()), + e->globalPos(), e->button(), e->state()); + contentsMousePressEvent(&ce); + if ( !ce.isAccepted() ) + e->ignore(); +} + +/*!\internal + + To provide simple processing of events on the contents, this function + receives all mouse release events sent to the viewport, translates + the event and calls contentsMouseReleaseEvent(). + + \sa TQWidget::mouseReleaseEvent() +*/ +void TQScrollView::viewportMouseReleaseEvent( TQMouseEvent* e ) +{ + TQMouseEvent ce(e->type(), viewportToContents(e->pos()), + e->globalPos(), e->button(), e->state()); + contentsMouseReleaseEvent(&ce); + if ( !ce.isAccepted() ) + e->ignore(); +} + +/*!\internal + + To provide simple processing of events on the contents, this function + receives all mouse double click events sent to the viewport, + translates the event and calls contentsMouseDoubleClickEvent(). + + \sa TQWidget::mouseDoubleClickEvent() +*/ +void TQScrollView::viewportMouseDoubleClickEvent( TQMouseEvent* e ) +{ + TQMouseEvent ce(e->type(), viewportToContents(e->pos()), + e->globalPos(), e->button(), e->state()); + contentsMouseDoubleClickEvent(&ce); + if ( !ce.isAccepted() ) + e->ignore(); +} + +/*!\internal + + To provide simple processing of events on the contents, this function + receives all mouse move events sent to the viewport, translates the + event and calls contentsMouseMoveEvent(). + + \sa TQWidget::mouseMoveEvent() +*/ +void TQScrollView::viewportMouseMoveEvent( TQMouseEvent* e ) +{ + TQMouseEvent ce(e->type(), viewportToContents(e->pos()), + e->globalPos(), e->button(), e->state()); + contentsMouseMoveEvent(&ce); + if ( !ce.isAccepted() ) + e->ignore(); +} + +#ifndef TQT_NO_DRAGANDDROP + +/*!\internal + + To provide simple processing of events on the contents, this function + receives all drag enter events sent to the viewport, translates the + event and calls contentsDragEnterEvent(). + + \sa TQWidget::dragEnterEvent() +*/ +void TQScrollView::viewportDragEnterEvent( TQDragEnterEvent* e ) +{ + e->setPoint(viewportToContents(e->pos())); + contentsDragEnterEvent(e); + e->setPoint(contentsToViewport(e->pos())); +} + +/*!\internal + + To provide simple processing of events on the contents, this function + receives all drag move events sent to the viewport, translates the + event and calls contentsDragMoveEvent(). + + \sa TQWidget::dragMoveEvent() +*/ +void TQScrollView::viewportDragMoveEvent( TQDragMoveEvent* e ) +{ + e->setPoint(viewportToContents(e->pos())); + contentsDragMoveEvent(e); + e->setPoint(contentsToViewport(e->pos())); +} + +/*!\internal + + To provide simple processing of events on the contents, this function + receives all drag leave events sent to the viewport and calls + contentsDragLeaveEvent(). + + \sa TQWidget::dragLeaveEvent() +*/ +void TQScrollView::viewportDragLeaveEvent( TQDragLeaveEvent* e ) +{ + contentsDragLeaveEvent(e); +} + +/*!\internal + + To provide simple processing of events on the contents, this function + receives all drop events sent to the viewport, translates the event + and calls contentsDropEvent(). + + \sa TQWidget::dropEvent() +*/ +void TQScrollView::viewportDropEvent( TQDropEvent* e ) +{ + e->setPoint(viewportToContents(e->pos())); + contentsDropEvent(e); + e->setPoint(contentsToViewport(e->pos())); +} + +#endif // TQT_NO_DRAGANDDROP + +/*!\internal + + To provide simple processing of events on the contents, this function + receives all wheel events sent to the viewport, translates the + event and calls contentsWheelEvent(). + + \sa TQWidget::wheelEvent() +*/ +#ifndef TQT_NO_WHEELEVENT +void TQScrollView::viewportWheelEvent( TQWheelEvent* e ) +{ + /* + Different than standard mouse events, because wheel events might + be sent to the focus widget if the widget-under-mouse doesn't want + the event itself. + */ + TQWheelEvent ce( viewportToContents(e->pos()), + e->globalPos(), e->delta(), e->state(), e->orientation()); + contentsWheelEvent(&ce); + if ( ce.isAccepted() ) + e->accept(); + else + e->ignore(); +} +#endif + +/*! \internal + + To provide simple processing of events on the contents, this function + receives all context menu events sent to the viewport, translates the + event and calls contentsContextMenuEvent(). +*/ +void TQScrollView::viewportContextMenuEvent( TQContextMenuEvent *e ) +{ + TQContextMenuEvent ce(e->reason(), viewportToContents(e->pos()), e->globalPos(), e->state() ); + contentsContextMenuEvent( &ce ); + if ( ce.isAccepted() ) + e->accept(); + else + e->ignore(); +} + +/*! + Returns the component horizontal scroll bar. It is made available + to allow accelerators, autoscrolling, etc. + + It should not be used for other purposes. + + This function never returns 0. +*/ +TQScrollBar* TQScrollView::horizontalScrollBar() const +{ + return d->hbar; +} + +/*! + Returns the component vertical scroll bar. It is made available to + allow accelerators, autoscrolling, etc. + + It should not be used for other purposes. + + This function never returns 0. +*/ +TQScrollBar* TQScrollView::verticalScrollBar() const { + return d->vbar; +} + + +/*! + Scrolls the content so that the point \a (x, y) is visible with at + least 50-pixel margins (if possible, otherwise centered). +*/ +void TQScrollView::ensureVisible( int x, int y ) +{ + ensureVisible(x, y, 50, 50); +} + +/*! + \overload + + Scrolls the content so that the point \a (x, y) is visible with at + least the \a xmargin and \a ymargin margins (if possible, + otherwise centered). +*/ +void TQScrollView::ensureVisible( int x, int y, int xmargin, int ymargin ) +{ + int pw=visibleWidth(); + int ph=visibleHeight(); + + int cx=-d->contentsX(); + int cy=-d->contentsY(); + int cw=d->contentsWidth(); + int ch=contentsHeight(); + + if ( pw < xmargin*2 ) + xmargin=pw/2; + if ( ph < ymargin*2 ) + ymargin=ph/2; + + if ( cw <= pw ) { + xmargin=0; + cx=0; + } + if ( ch <= ph ) { + ymargin=0; + cy=0; + } + + if ( x < -cx+xmargin ) + cx = -x+xmargin; + else if ( x >= -cx+pw-xmargin ) + cx = -x+pw-xmargin; + + if ( y < -cy+ymargin ) + cy = -y+ymargin; + else if ( y >= -cy+ph-ymargin ) + cy = -y+ph-ymargin; + + if ( cx > 0 ) + cx=0; + else if ( cx < pw-cw && cw>pw ) + cx=pw-cw; + + if ( cy > 0 ) + cy=0; + else if ( cy < ph-ch && ch>ph ) + cy=ph-ch; + + setContentsPos( -cx, -cy ); +} + +/*! + Scrolls the content so that the point \a (x, y) is in the top-left + corner. +*/ +void TQScrollView::setContentsPos( int x, int y ) +{ +#if 0 + // bounds checking... + if ( TQApplication::reverseLayout() ) + if ( x > d->contentsWidth() - visibleWidth() ) x = d->contentsWidth() - visibleWidth(); + else +#endif + if ( x < 0 ) x = 0; + if ( y < 0 ) y = 0; + // Choke signal handling while we update BOTH sliders. + d->signal_choke=TRUE; + moveContents( -x, -y ); + d->vbar->setValue( y ); + d->hbar->setValue( x ); + d->signal_choke=FALSE; +} + +/*! + Scrolls the content by \a dx to the left and \a dy upwards. +*/ +void TQScrollView::scrollBy( int dx, int dy ) +{ + setContentsPos( TQMAX( d->contentsX()+dx, 0 ), TQMAX( d->contentsY()+dy, 0 ) ); +} + +/*! + Scrolls the content so that the point \a (x, y) is in the center + of visible area. +*/ +void TQScrollView::center( int x, int y ) +{ + ensureVisible( x, y, 32000, 32000 ); +} + +/*! + \overload + + Scrolls the content so that the point \a (x, y) is visible with + the \a xmargin and \a ymargin margins (as fractions of visible + the area). + + For example: + \list + \i Margin 0.0 allows (x, y) to be on the edge of the visible area. + \i Margin 0.5 ensures that (x, y) is in middle 50% of the visible area. + \i Margin 1.0 ensures that (x, y) is in the center of the the visible area. + \endlist +*/ +void TQScrollView::center( int x, int y, float xmargin, float ymargin ) +{ + int pw=visibleWidth(); + int ph=visibleHeight(); + ensureVisible( x, y, int( xmargin/2.0*pw+0.5 ), int( ymargin/2.0*ph+0.5 ) ); +} + + +/*! + \fn void TQScrollView::contentsMoving(int x, int y) + + This signal is emitted just before the contents are moved to + position \a (x, y). + + \sa contentsX(), contentsY() +*/ + +/*! + Moves the contents by \a (x, y). +*/ +void TQScrollView::moveContents(int x, int y) +{ + if ( -x+visibleWidth() > d->contentsWidth() ) +#if 0 + if( TQApplication::reverseLayout() ) + x=TQMAX(0,-d->contentsWidth()+visibleWidth()); + else +#endif + x=TQMIN(0,-d->contentsWidth()+visibleWidth()); + if ( -y+visibleHeight() > contentsHeight() ) + y=TQMIN(0,-contentsHeight()+visibleHeight()); + + int dx = x - d->vx; + int dy = y - d->vy; + + if (!dx && !dy) + return; // Nothing to do + + emit contentsMoving( -x, -y ); + + d->vx = x; + d->vy = y; + + if ( d->clipped_viewport || d->static_bg ) { + // Cheap move (usually) + d->moveAllBy(dx,dy); + } else if ( /*dx && dy ||*/ + ( TQABS(dy) * 5 > visibleHeight() * 4 ) || + ( TQABS(dx) * 5 > visibleWidth() * 4 ) + ) + { + // Big move + if ( viewport()->isUpdatesEnabled() ) + viewport()->update(); + d->moveAllBy(dx,dy); + } else if ( !d->fake_scroll || d->contentsWidth() > visibleWidth() ) { + // Small move + clipper()->scroll(dx,dy); + } + d->hideOrShowAll(this, TRUE ); +} + +/*! + \property TQScrollView::contentsX + \brief the X coordinate of the contents that are at the left edge of + the viewport. +*/ +int TQScrollView::contentsX() const +{ + return d->contentsX(); +} + +/*! + \property TQScrollView::contentsY + \brief the Y coordinate of the contents that are at the top edge of + the viewport. +*/ +int TQScrollView::contentsY() const +{ + return d->contentsY(); +} + +/*! + \property TQScrollView::contentsWidth + \brief the width of the contents area +*/ +int TQScrollView::contentsWidth() const +{ + return d->contentsWidth(); +} + +/*! + \property TQScrollView::contentsHeight + \brief the height of the contents area +*/ +int TQScrollView::contentsHeight() const +{ + return d->vheight; +} + +/*! + Sets the size of the contents area to \a w pixels wide and \a h + pixels high and updates the viewport accordingly. +*/ +void TQScrollView::resizeContents( int w, int h ) +{ + int ow = d->vwidth; + int oh = d->vheight; + d->vwidth = w; + d->vheight = h; + + d->scrollbar_timer.start( 0, TRUE ); + + if ( d->children.isEmpty() && d->policy == Default ) + setResizePolicy( Manual ); + + if ( ow > w ) { + // Swap + int t=w; + w=ow; + ow=t; + } + // Refresh area ow..w + if ( ow < visibleWidth() && w >= 0 ) { + if ( ow < 0 ) + ow = 0; + if ( w > visibleWidth() ) + w = visibleWidth(); + clipper()->update( d->contentsX()+ow, 0, w-ow, visibleHeight() ); + } + + if ( oh > h ) { + // Swap + int t=h; + h=oh; + oh=t; + } + // Refresh area oh..h + if ( oh < visibleHeight() && h >= 0 ) { + if ( oh < 0 ) + oh = 0; + if ( h > visibleHeight() ) + h = visibleHeight(); + clipper()->update( 0, d->contentsY()+oh, visibleWidth(), h-oh); + } +} + +/*! + Calls update() on a rectangle defined by \a x, \a y, \a w, \a h, + translated appropriately. If the rectangle is not visible, nothing + is repainted. + + \sa repaintContents() +*/ +void TQScrollView::updateContents( int x, int y, int w, int h ) +{ + if ( testWState(WState_Visible|WState_BlockUpdates) != WState_Visible ) + return; + + TQWidget* vp = viewport(); + + // Translate + x -= d->contentsX(); + y -= d->contentsY(); + + // Clip to TQCOORD space + if ( x < 0 ) { + w += x; + x = 0; + } + if ( y < 0 ) { + h += y; + y = 0; + } + + if ( w < 0 || h < 0 ) + return; + if ( x > visibleWidth() || y > visibleHeight() ) + return; + + if ( w > visibleWidth() ) + w = visibleWidth(); + if ( h > visibleHeight() ) + h = visibleHeight(); + + if ( d->clipped_viewport ) { + // Translate clipper() to viewport() + x -= d->clipped_viewport->x(); + y -= d->clipped_viewport->y(); + } + + vp->update( x, y, w, h ); +} + +/*! + \overload + + Updates the contents in rectangle \a r +*/ +void TQScrollView::updateContents( const TQRect& r ) +{ + updateContents(r.x(), r.y(), r.width(), r.height()); +} + +/*! + \overload +*/ +void TQScrollView::updateContents() +{ + updateContents( d->contentsX(), d->contentsY(), visibleWidth(), visibleHeight() ); +} + +/*! + \overload + + Repaints the contents of rectangle \a r. If \a erase is TRUE the + background is cleared using the background color. +*/ +void TQScrollView::repaintContents( const TQRect& r, bool erase ) +{ + repaintContents(r.x(), r.y(), r.width(), r.height(), erase); +} + + +/*! + \overload + + Repaints the contents. If \a erase is TRUE the background is + cleared using the background color. +*/ +void TQScrollView::repaintContents( bool erase ) +{ + repaintContents( d->contentsX(), d->contentsY(), visibleWidth(), visibleHeight(), erase ); +} + + +/*! + Calls repaint() on a rectangle defined by \a x, \a y, \a w, \a h, + translated appropriately. If the rectangle is not visible, nothing + is repainted. If \a erase is TRUE the background is cleared using + the background color. + + \sa updateContents() +*/ +void TQScrollView::repaintContents( int x, int y, int w, int h, bool erase ) +{ + if ( testWState(WState_Visible|WState_BlockUpdates) != WState_Visible ) + return; + + TQWidget* vp = viewport(); + + // Translate logical to clipper() + x -= d->contentsX(); + y -= d->contentsY(); + + // Clip to TQCOORD space + if ( x < 0 ) { + w += x; + x = 0; + } + if ( y < 0 ) { + h += y; + y = 0; + } + + if ( w < 0 || h < 0 ) + return; + if ( w > visibleWidth() ) + w = visibleWidth(); + if ( h > visibleHeight() ) + h = visibleHeight(); + + if ( d->clipped_viewport ) { + // Translate clipper() to viewport() + x -= d->clipped_viewport->x(); + y -= d->clipped_viewport->y(); + } + + vp->repaint( x, y, w, h, erase ); +} + + +/*! + For backward-compatibility only. It is easier to use + drawContents(TQPainter*,int,int,int,int). + + The default implementation translates the painter appropriately + and calls drawContents(TQPainter*,int,int,int,int). See + drawContents() for an explanation of the parameters \a p, \a + offsetx, \a offsety, \a clipx, \a clipy, \a clipw and \a cliph. +*/ +void TQScrollView::drawContentsOffset(TQPainter* p, int offsetx, int offsety, int clipx, int clipy, int clipw, int cliph) +{ + p->translate(-offsetx,-offsety); + drawContents(p, clipx, clipy, clipw, cliph); +} + +/*! + \fn void TQScrollView::drawContents(TQPainter* p, int clipx, int clipy, int clipw, int cliph) + + Reimplement this function if you are viewing a drawing area rather + than a widget. + + The function should draw the rectangle (\a clipx, \a clipy, \a + clipw, \a cliph) of the contents using painter \a p. The clip + rectangle is in the scrollview's coordinates. + + For example: + \code + { + // Fill a 40000 by 50000 rectangle at (100000,150000) + + // Calculate the coordinates... + int x1 = 100000, y1 = 150000; + int x2 = x1+40000-1, y2 = y1+50000-1; + + // Clip the coordinates so X/Windows will not have problems... + if (x1 < clipx) x1=clipx; + if (y1 < clipy) y1=clipy; + if (x2 > clipx+clipw-1) x2=clipx+clipw-1; + if (y2 > clipy+cliph-1) y2=clipy+cliph-1; + + // Paint using the small coordinates... + if ( x2 >= x1 && y2 >= y1 ) + p->fillRect(x1, y1, x2-x1+1, y2-y1+1, red); + } + \endcode + + The clip rectangle and translation of the painter \a p is already + set appropriately. +*/ +void TQScrollView::drawContents(TQPainter*, int, int, int, int) +{ +} + + +/*! + \reimp +*/ +void TQScrollView::frameChanged() +{ + // slight ugle-hack - the listview header needs readjusting when + // changing the frame + if (TQListView *lv = ::tqt_cast<TQListView *>(this)) + lv->triggerUpdate(); + TQFrame::frameChanged(); + updateScrollBars(); +} + + +/*! + Returns the viewport widget of the scrollview. This is the widget + containing the contents widget or which is the drawing area. +*/ +TQWidget* TQScrollView::viewport() const +{ + if ( d->clipped_viewport ) + return d->clipped_viewport; + return d->viewport; +} + +/*! + Returns the clipper widget. Contents in the scrollview are + ultimately clipped to be inside the clipper widget. + + You should not need to use this function. + + \sa visibleWidth(), visibleHeight() +*/ +TQWidget* TQScrollView::clipper() const +{ + return d->viewport; +} + +/*! + \property TQScrollView::visibleWidth + \brief the horizontal amount of the content that is visible +*/ +int TQScrollView::visibleWidth() const +{ + return clipper()->width(); +} + +/*! + \property TQScrollView::visibleHeight + \brief the vertical amount of the content that is visible +*/ +int TQScrollView::visibleHeight() const +{ + return clipper()->height(); +} + + +void TQScrollView::changeFrameRect(const TQRect& r) +{ + TQRect oldr = frameRect(); + if (oldr != r) { + TQRect cr = contentsRect(); + TQRegion fr( frameRect() ); + fr = fr.subtract( contentsRect() ); + setFrameRect( r ); + if ( isVisible() ) { + cr = cr.intersect( contentsRect() ); + fr = fr.unite( frameRect() ); + fr = fr.subtract( cr ); + if ( !fr.isEmpty() ) + TQApplication::postEvent( this, new TQPaintEvent( fr, FALSE ) ); + } + } +} + + +/*! + Sets the margins around the scrolling area to \a left, \a top, \a + right and \a bottom. This is useful for applications such as + spreadsheets with "locked" rows and columns. The marginal space is + \e inside the frameRect() and is left blank; reimplement + drawFrame() or put widgets in the unused area. + + By default all margins are zero. + + \sa frameChanged() +*/ +void TQScrollView::setMargins(int left, int top, int right, int bottom) +{ + if ( left == d->l_marg && + top == d->t_marg && + right == d->r_marg && + bottom == d->b_marg ) + return; + + d->l_marg = left; + d->t_marg = top; + d->r_marg = right; + d->b_marg = bottom; + updateScrollBars(); +} + + +/*! + Returns the left margin. + + \sa setMargins() +*/ +int TQScrollView::leftMargin() const +{ + return d->l_marg; +} + + +/*! + Returns the top margin. + + \sa setMargins() +*/ +int TQScrollView::topMargin() const +{ + return d->t_marg; +} + + +/*! + Returns the right margin. + + \sa setMargins() +*/ +int TQScrollView::rightMargin() const +{ + return d->r_marg; +} + + +/*! + Returns the bottom margin. + + \sa setMargins() +*/ +int TQScrollView::bottomMargin() const +{ + return d->b_marg; +} + +/*! + \reimp +*/ +bool TQScrollView::focusNextPrevChild( bool next ) +{ + // Makes sure that the new focus widget is on-screen, if + // necessary by scrolling the scroll view. + + // first set things up for the scan + TQFocusData *f = focusData(); + TQWidget *startingPoint = f->home(); + TQWidget *candidate = 0; + TQWidget *w = next ? f->next() : f->prev(); + TQSVChildRec *r; + extern bool tqt_tab_all_widgets; + uint focus_flag = tqt_tab_all_widgets ? TabFocus : StrongFocus; + + // then scan for a possible focus widget candidate + while( !candidate && w != startingPoint ) { + if ( w != startingPoint && + (w->focusPolicy() & focus_flag) == focus_flag + && w->isEnabled() &&!w->focusProxy() && w->isVisible() ) + candidate = w; + w = next ? f->next() : f->prev(); + } + + // if we could not find one, maybe super or parentWidget() can? + if ( !candidate ) + return TQFrame::focusNextPrevChild( next ); + + // we've found one. + r = d->ancestorRec( candidate ); + if ( r && ( r->child == candidate || + candidate->isVisibleTo( r->child ) ) ) { + TQPoint cp = r->child->mapToGlobal(TQPoint(0,0)); + TQPoint cr = candidate->mapToGlobal(TQPoint(0,0)) - cp; + ensureVisible( r->x+cr.x()+candidate->width()/2, + r->y+cr.y()+candidate->height()/2, + candidate->width()/2, + candidate->height()/2 ); + } + + candidate->setFocus(); + return TRUE; +} + + + +/*! + When a large numbers of child widgets are in a scrollview, + especially if they are close together, the scrolling performance + can suffer greatly. If \a y is TRUE the scrollview will use an + extra widget to group child widgets. + + Note that you may only call enableClipper() prior to adding + widgets. + + For a full discussion, see this class's \link #enableclipper + detailed description\endlink. +*/ +void TQScrollView::enableClipper(bool y) +{ + if ( !d->clipped_viewport == !y ) + return; + if ( d->children.count() ) + tqFatal("May only call TQScrollView::enableClipper() before adding widgets"); + if ( y ) { + d->clipped_viewport = new TQClipperWidget(clipper(), "qt_clipped_viewport", d->flags); + d->clipped_viewport->setGeometry(-coord_limit/2,-coord_limit/2, + coord_limit,coord_limit); + d->clipped_viewport->setBackgroundMode( d->viewport->backgroundMode() ); + d->viewport->setBackgroundMode(NoBackground); // no exposures for this + d->viewport->removeEventFilter( this ); + d->clipped_viewport->installEventFilter( this ); + d->clipped_viewport->show(); + } else { + delete d->clipped_viewport; + d->clipped_viewport = 0; + } +} + +/*! + Sets the scrollview to have a static background if \a y is TRUE, + or a scrolling background if \a y is FALSE. By default, the + background is scrolling. + + Be aware that this mode is quite slow, as a full repaint of the + visible area has to be triggered on every contents move. + + \sa hasStaticBackground() +*/ +void TQScrollView::setStaticBackground(bool y) +{ + d->static_bg = y; +} + +/*! + Returns TRUE if TQScrollView uses a static background; otherwise + returns FALSE. + + \sa setStaticBackground() +*/ +bool TQScrollView::hasStaticBackground() const +{ + return d->static_bg; +} + +/*! + \overload + + Returns the point \a p translated to a point on the viewport() + widget. +*/ +TQPoint TQScrollView::contentsToViewport( const TQPoint& p ) const +{ + if ( d->clipped_viewport ) { + return TQPoint( p.x() - d->contentsX() - d->clipped_viewport->x(), + p.y() - d->contentsY() - d->clipped_viewport->y() ); + } else { + return TQPoint( p.x() - d->contentsX(), + p.y() - d->contentsY() ); + } +} + +/*! + \overload + + Returns the point on the viewport \a vp translated to a point in + the contents. +*/ +TQPoint TQScrollView::viewportToContents( const TQPoint& vp ) const +{ + if ( d->clipped_viewport ) { + return TQPoint( vp.x() + d->contentsX() + d->clipped_viewport->x(), + vp.y() + d->contentsY() + d->clipped_viewport->y() ); + } else { + return TQPoint( vp.x() + d->contentsX(), + vp.y() + d->contentsY() ); + } +} + + +/*! + Translates a point (\a x, \a y) in the contents to a point (\a vx, + \a vy) on the viewport() widget. +*/ +void TQScrollView::contentsToViewport( int x, int y, int& vx, int& vy ) const +{ + const TQPoint v = contentsToViewport(TQPoint(x,y)); + vx = v.x(); + vy = v.y(); +} + +/*! + Translates a point (\a vx, \a vy) on the viewport() widget to a + point (\a x, \a y) in the contents. +*/ +void TQScrollView::viewportToContents( int vx, int vy, int& x, int& y ) const +{ + const TQPoint c = viewportToContents(TQPoint(vx,vy)); + x = c.x(); + y = c.y(); +} + +/*! + \reimp +*/ +TQSize TQScrollView::sizeHint() const +{ + if ( d->use_cached_size_hint && d->cachedSizeHint.isValid() ) + return d->cachedSizeHint; + + constPolish(); + int f = 2 * frameWidth(); + int h = fontMetrics().height(); + TQSize sz( f, f ); + if ( d->policy > Manual ) { + TQSVChildRec *r = d->children.first(); + if ( r ) { + TQSize cs = r->child->sizeHint(); + if ( cs.isValid() ) + sz += cs.boundedTo( r->child->maximumSize() ); + else + sz += r->child->size(); + } + } else { + sz += TQSize( d->contentsWidth(), contentsHeight() ); + } + if (d->vMode == AlwaysOn) + sz.setWidth(sz.width() + d->vbar->sizeHint().width()); + if (d->hMode == AlwaysOn) + sz.setHeight(sz.height() + d->hbar->sizeHint().height()); + return sz.expandedTo( TQSize(12 * h, 8 * h) ) + .boundedTo( TQSize(36 * h, 24 * h) ); +} + + +/*! + \reimp +*/ +TQSize TQScrollView::minimumSizeHint() const +{ + int h = fontMetrics().height(); + if ( h < 10 ) + h = 10; + int f = 2 * frameWidth(); + return TQSize( (6 * h) + f, (4 * h) + f ); +} + + +/*! + \reimp + + (Implemented to get rid of a compiler warning.) +*/ +void TQScrollView::drawContents( TQPainter * ) +{ +} + +#ifndef TQT_NO_DRAGANDDROP + +/*! + \internal +*/ +void TQScrollView::startDragAutoScroll() +{ + if ( !d->autoscroll_timer.isActive() ) { + d->autoscroll_time = initialScrollTime; + d->autoscroll_accel = initialScrollAccel; + d->autoscroll_timer.start( d->autoscroll_time ); + } +} + + +/*! + \internal +*/ +void TQScrollView::stopDragAutoScroll() +{ + d->autoscroll_timer.stop(); +} + + +/*! + \internal +*/ +void TQScrollView::doDragAutoScroll() +{ + TQPoint p = d->viewport->mapFromGlobal( TQCursor::pos() ); + + if ( d->autoscroll_accel-- <= 0 && d->autoscroll_time ) { + d->autoscroll_accel = initialScrollAccel; + d->autoscroll_time--; + d->autoscroll_timer.start( d->autoscroll_time ); + } + int l = TQMAX( 1, ( initialScrollTime- d->autoscroll_time ) ); + + int dx = 0, dy = 0; + if ( p.y() < autoscroll_margin ) { + dy = -l; + } else if ( p.y() > visibleHeight() - autoscroll_margin ) { + dy = +l; + } + if ( p.x() < autoscroll_margin ) { + dx = -l; + } else if ( p.x() > visibleWidth() - autoscroll_margin ) { + dx = +l; + } + if ( dx || dy ) { + scrollBy(dx,dy); + } else { + stopDragAutoScroll(); + } +} + + +/*! + \property TQScrollView::dragAutoScroll + \brief whether autoscrolling in drag move events is enabled + + If this property is set to TRUE (the default), the TQScrollView + automatically scrolls the contents in drag move events if the user + moves the cursor close to a border of the view. Of course this + works only if the viewport accepts drops. Specifying FALSE + disables this autoscroll feature. + + \warning Enabling this property might not be enough to + effectively turn on autoscrolling. If you put a custom widget in + the TQScrollView, you might need to call TQDragEvent::ignore() on + the event in the dragEnterEvent() and dragMoveEvent() + reimplementations. +*/ + +void TQScrollView::setDragAutoScroll( bool b ) +{ + d->drag_autoscroll = b; +} + +bool TQScrollView::dragAutoScroll() const +{ + return d->drag_autoscroll; +} + +#endif // TQT_NO_DRAGANDDROP + +/*!\internal + */ +void TQScrollView::setCachedSizeHint( const TQSize &sh ) const +{ + if ( isVisible() && !d->cachedSizeHint.isValid() ) + d->cachedSizeHint = sh; +} + +/*!\internal + */ +void TQScrollView::disableSizeHintCaching() +{ + d->use_cached_size_hint = FALSE; +} + +/*!\internal + */ +TQSize TQScrollView::cachedSizeHint() const +{ + return d->use_cached_size_hint ? d->cachedSizeHint : TQSize(); +} + +#endif // TQT_NO_SCROLLVIEW |