|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the Qt3Support module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "qwidget.h" |
|
43 #ifndef QT_NO_SCROLLVIEW |
|
44 #include "qscrollbar.h" |
|
45 #include "qpainter.h" |
|
46 #include "qpixmap.h" |
|
47 #include "qcursor.h" |
|
48 #include "q3scrollview.h" |
|
49 #include "q3ptrdict.h" |
|
50 #include "qapplication.h" |
|
51 #include "qtimer.h" |
|
52 #include "qstyle.h" |
|
53 #include "q3ptrlist.h" |
|
54 #include "qevent.h" |
|
55 #include "q3listview.h" |
|
56 #ifdef Q_WS_MAC |
|
57 # include "private/qt_mac_p.h" |
|
58 #endif |
|
59 |
|
60 QT_BEGIN_NAMESPACE |
|
61 |
|
62 using namespace Qt; |
|
63 |
|
64 static const int coord_limit = 4000; |
|
65 static const int autoscroll_margin = 16; |
|
66 static const int initialScrollTime = 30; |
|
67 static const int initialScrollAccel = 5; |
|
68 |
|
69 struct QSVChildRec { |
|
70 QSVChildRec(QWidget* c, int xx, int yy) : |
|
71 child(c), |
|
72 x(xx), y(yy) |
|
73 { |
|
74 } |
|
75 |
|
76 void hideOrShow(Q3ScrollView* sv, QWidget* clipped_viewport); |
|
77 void moveTo(Q3ScrollView* sv, int xx, int yy, QWidget* clipped_viewport) |
|
78 { |
|
79 if (x != xx || y != yy) { |
|
80 x = xx; |
|
81 y = yy; |
|
82 hideOrShow(sv,clipped_viewport); |
|
83 } |
|
84 } |
|
85 QWidget* child; |
|
86 int x, y; |
|
87 }; |
|
88 |
|
89 void QSVChildRec::hideOrShow(Q3ScrollView* sv, QWidget* clipped_viewport) |
|
90 { |
|
91 if (clipped_viewport) { |
|
92 if (x+child->width() < sv->contentsX()+clipped_viewport->x() |
|
93 || x > sv->contentsX()+clipped_viewport->width() |
|
94 || y+child->height() < sv->contentsY()+clipped_viewport->y() |
|
95 || y > sv->contentsY()+clipped_viewport->height()) { |
|
96 child->move(clipped_viewport->width(), |
|
97 clipped_viewport->height()); |
|
98 } else { |
|
99 child->move(x-sv->contentsX()-clipped_viewport->x(), |
|
100 y-sv->contentsY()-clipped_viewport->y()); |
|
101 } |
|
102 } else { |
|
103 child->move(x-sv->contentsX(), y-sv->contentsY()); |
|
104 } |
|
105 } |
|
106 |
|
107 class QAbstractScrollAreaWidget : public QWidget |
|
108 { |
|
109 Q_OBJECT |
|
110 |
|
111 public: |
|
112 QAbstractScrollAreaWidget(Q3ScrollView* parent=0, const char* name=0, Qt::WindowFlags f = 0) |
|
113 : QWidget(parent, name, f) |
|
114 { |
|
115 setAutoFillBackground(true); |
|
116 } |
|
117 }; |
|
118 |
|
119 class QClipperWidget : public QWidget |
|
120 { |
|
121 Q_OBJECT |
|
122 |
|
123 public: |
|
124 QClipperWidget(QWidget * parent=0, const char * name=0, Qt::WindowFlags f=0) |
|
125 : QWidget (parent,name,f) {} |
|
126 }; |
|
127 |
|
128 QT_BEGIN_INCLUDE_NAMESPACE |
|
129 #include "q3scrollview.moc" |
|
130 QT_END_INCLUDE_NAMESPACE |
|
131 |
|
132 class Q3ScrollViewData { |
|
133 public: |
|
134 Q3ScrollViewData(Q3ScrollView* parent, int vpwflags) : |
|
135 hbar(new QScrollBar(Qt::Horizontal, parent, "qt_hbar")), |
|
136 vbar(new QScrollBar(Qt::Vertical, parent, "qt_vbar")), |
|
137 viewport(new QAbstractScrollAreaWidget(parent, "qt_viewport", QFlag(vpwflags))), |
|
138 clipped_viewport(0), |
|
139 flags(vpwflags), |
|
140 vx(0), vy(0), vwidth(1), vheight(1), |
|
141 #ifndef QT_NO_DRAGANDDROP |
|
142 autoscroll_timer(parent, "scrollview autoscroll timer"), |
|
143 drag_autoscroll(true), |
|
144 #endif |
|
145 scrollbar_timer(parent, "scrollview scrollbar timer"), |
|
146 inresize(false), use_cached_size_hint(true) |
|
147 { |
|
148 l_marg = r_marg = t_marg = b_marg = 0; |
|
149 viewport->polish(); |
|
150 vMode = Q3ScrollView::Auto; |
|
151 hMode = Q3ScrollView::Auto; |
|
152 corner = 0; |
|
153 vbar->setSteps(20, 1/*set later*/); |
|
154 hbar->setSteps(20, 1/*set later*/); |
|
155 policy = Q3ScrollView::Default; |
|
156 signal_choke = false; |
|
157 static_bg = false; |
|
158 fake_scroll = false; |
|
159 hbarPressed = false; |
|
160 vbarPressed = false; |
|
161 hbar->setLayoutDirection(Qt::LeftToRight); |
|
162 } |
|
163 ~Q3ScrollViewData(); |
|
164 |
|
165 QSVChildRec* rec(QWidget* w) { return childDict.find(w); } |
|
166 QSVChildRec* ancestorRec(QWidget* w); |
|
167 QSVChildRec* addChildRec(QWidget* w, int x, int y) |
|
168 { |
|
169 QSVChildRec *r = new QSVChildRec(w,x,y); |
|
170 children.append(r); |
|
171 childDict.insert(w, r); |
|
172 return r; |
|
173 } |
|
174 void deleteChildRec(QSVChildRec* r) |
|
175 { |
|
176 childDict.remove(r->child); |
|
177 children.removeRef(r); |
|
178 delete r; |
|
179 } |
|
180 |
|
181 void hideOrShowAll(Q3ScrollView* sv, bool isScroll = false); |
|
182 void moveAllBy(int dx, int dy); |
|
183 bool anyVisibleChildren(); |
|
184 void autoMove(Q3ScrollView* sv); |
|
185 void autoResize(Q3ScrollView* sv); |
|
186 void autoResizeHint(Q3ScrollView* sv); |
|
187 void viewportResized(int w, int h); |
|
188 |
|
189 QScrollBar* hbar; |
|
190 QScrollBar* vbar; |
|
191 bool hbarPressed; |
|
192 bool vbarPressed; |
|
193 QAbstractScrollAreaWidget* viewport; |
|
194 QClipperWidget* clipped_viewport; |
|
195 int flags; |
|
196 Q3PtrList<QSVChildRec> children; |
|
197 Q3PtrDict<QSVChildRec> childDict; |
|
198 QWidget* corner; |
|
199 int vx, vy, vwidth, vheight; // for drawContents-style usage |
|
200 int l_marg, r_marg, t_marg, b_marg; |
|
201 Q3ScrollView::ResizePolicy policy; |
|
202 Q3ScrollView::ScrollBarMode vMode; |
|
203 Q3ScrollView::ScrollBarMode hMode; |
|
204 #ifndef QT_NO_DRAGANDDROP |
|
205 QPoint cpDragStart; |
|
206 QTimer autoscroll_timer; |
|
207 int autoscroll_time; |
|
208 int autoscroll_accel; |
|
209 bool drag_autoscroll; |
|
210 #endif |
|
211 QTimer scrollbar_timer; |
|
212 |
|
213 uint static_bg : 1; |
|
214 uint fake_scroll : 1; |
|
215 |
|
216 // This variable allows ensureVisible to move the contents then |
|
217 // update both the sliders. Otherwise, updating the sliders would |
|
218 // cause two image scrolls, creating ugly flashing. |
|
219 // |
|
220 uint signal_choke : 1; |
|
221 |
|
222 // This variables indicates in updateScrollBars() that we are |
|
223 // in a resizeEvent() and thus don't want to flash scroll bars |
|
224 uint inresize : 1; |
|
225 uint use_cached_size_hint : 1; |
|
226 QSize cachedSizeHint; |
|
227 |
|
228 inline int contentsX() const { return -vx; } |
|
229 inline int contentsY() const { return -vy; } |
|
230 inline int contentsWidth() const { return vwidth; } |
|
231 }; |
|
232 |
|
233 inline Q3ScrollViewData::~Q3ScrollViewData() |
|
234 { |
|
235 children.setAutoDelete(true); |
|
236 } |
|
237 |
|
238 QSVChildRec* Q3ScrollViewData::ancestorRec(QWidget* w) |
|
239 { |
|
240 if (clipped_viewport) { |
|
241 while (w->parentWidget() != clipped_viewport) { |
|
242 w = w->parentWidget(); |
|
243 if (!w) return 0; |
|
244 } |
|
245 } else { |
|
246 while (w->parentWidget() != viewport) { |
|
247 w = w->parentWidget(); |
|
248 if (!w) return 0; |
|
249 } |
|
250 } |
|
251 return rec(w); |
|
252 } |
|
253 |
|
254 void Q3ScrollViewData::hideOrShowAll(Q3ScrollView* sv, bool isScroll) |
|
255 { |
|
256 if (!clipped_viewport) |
|
257 return; |
|
258 if (clipped_viewport->x() <= 0 |
|
259 && clipped_viewport->y() <= 0 |
|
260 && clipped_viewport->width()+clipped_viewport->x() >= |
|
261 viewport->width() |
|
262 && clipped_viewport->height()+clipped_viewport->y() >= |
|
263 viewport->height()) { |
|
264 // clipped_viewport still covers viewport |
|
265 if(static_bg) |
|
266 clipped_viewport->repaint(true); |
|
267 else if ((!isScroll && !clipped_viewport->testAttribute(Qt::WA_StaticContents)) || static_bg) |
|
268 clipped_viewport->update(); |
|
269 } else { |
|
270 // Re-center |
|
271 int nx = (viewport->width() - clipped_viewport->width()) / 2; |
|
272 int ny = (viewport->height() - clipped_viewport->height()) / 2; |
|
273 clipped_viewport->move(nx,ny); |
|
274 clipped_viewport->update(); |
|
275 } |
|
276 for (QSVChildRec *r = children.first(); r; r=children.next()) { |
|
277 r->hideOrShow(sv, clipped_viewport); |
|
278 } |
|
279 } |
|
280 |
|
281 void Q3ScrollViewData::moveAllBy(int dx, int dy) |
|
282 { |
|
283 if (clipped_viewport && !static_bg) { |
|
284 clipped_viewport->move(clipped_viewport->x()+dx, |
|
285 clipped_viewport->y()+dy); |
|
286 } else { |
|
287 for (QSVChildRec *r = children.first(); r; r=children.next()) { |
|
288 r->child->move(r->child->x()+dx,r->child->y()+dy); |
|
289 } |
|
290 if (static_bg) |
|
291 viewport->repaint(true); |
|
292 } |
|
293 } |
|
294 |
|
295 bool Q3ScrollViewData::anyVisibleChildren() |
|
296 { |
|
297 for (QSVChildRec *r = children.first(); r; r=children.next()) { |
|
298 if (r->child->isVisible()) return true; |
|
299 } |
|
300 return false; |
|
301 } |
|
302 |
|
303 void Q3ScrollViewData::autoMove(Q3ScrollView* sv) |
|
304 { |
|
305 if (policy == Q3ScrollView::AutoOne) { |
|
306 QSVChildRec* r = children.first(); |
|
307 if (r) |
|
308 sv->setContentsPos(-r->child->x(),-r->child->y()); |
|
309 } |
|
310 } |
|
311 |
|
312 void Q3ScrollViewData::autoResize(Q3ScrollView* sv) |
|
313 { |
|
314 if (policy == Q3ScrollView::AutoOne) { |
|
315 QSVChildRec* r = children.first(); |
|
316 if (r) |
|
317 sv->resizeContents(r->child->width(),r->child->height()); |
|
318 } |
|
319 } |
|
320 |
|
321 void Q3ScrollViewData::autoResizeHint(Q3ScrollView* sv) |
|
322 { |
|
323 if (policy == Q3ScrollView::AutoOne) { |
|
324 QSVChildRec* r = children.first(); |
|
325 if (r) { |
|
326 QSize s = r->child->sizeHint(); |
|
327 if (s.isValid()) |
|
328 r->child->resize(s); |
|
329 } |
|
330 } else if (policy == Q3ScrollView::AutoOneFit) { |
|
331 QSVChildRec* r = children.first(); |
|
332 if (r) { |
|
333 QSize sh = r->child->sizeHint(); |
|
334 sh = sh.boundedTo(r->child->maximumSize()); |
|
335 sv->resizeContents(sh.width(), sh.height()); |
|
336 } |
|
337 } |
|
338 } |
|
339 |
|
340 void Q3ScrollViewData::viewportResized(int w, int h) |
|
341 { |
|
342 if (policy == Q3ScrollView::AutoOneFit) { |
|
343 QSVChildRec* r = children.first(); |
|
344 if (r) { |
|
345 QSize sh = r->child->sizeHint(); |
|
346 sh = sh.boundedTo(r->child->maximumSize()); |
|
347 r->child->resize(QMAX(w,sh.width()), QMAX(h,sh.height())); |
|
348 } |
|
349 |
|
350 } |
|
351 } |
|
352 |
|
353 |
|
354 /*! |
|
355 \class Q3ScrollView |
|
356 \brief The Q3ScrollView widget provides a scrolling area with on-demand scroll bars. |
|
357 |
|
358 \compat |
|
359 |
|
360 The Q3ScrollView is a large canvas - potentially larger than the |
|
361 coordinate system normally supported by the underlying window |
|
362 system. This is important because it is quite easy to go beyond |
|
363 these limitations (e.g. many web pages are more than 32000 pixels |
|
364 high). Additionally, the Q3ScrollView can have QWidgets positioned |
|
365 on it that scroll around with the drawn content. These sub-widgets |
|
366 can also have positions outside the normal coordinate range (but |
|
367 they are still limited in size). |
|
368 |
|
369 To provide content for the widget, inherit from Q3ScrollView, |
|
370 reimplement drawContents() and use resizeContents() to set the |
|
371 size of the viewed area. Use addChild() and moveChild() to |
|
372 position widgets on the view. |
|
373 |
|
374 To use Q3ScrollView effectively it is important to understand its |
|
375 widget structure in the three styles of use: a single large child |
|
376 widget, a large panning area with some widgets and a large panning |
|
377 area with many widgets. |
|
378 |
|
379 \section1 Using One Big Widget |
|
380 |
|
381 \img qscrollview-vp2.png |
|
382 |
|
383 The first, simplest usage of Q3ScrollView (depicted above), is |
|
384 appropriate for scrolling areas that are never more than about |
|
385 4000 pixels in either dimension (this is about the maximum |
|
386 reliable size on X11 servers). In this usage, you just make one |
|
387 large child in the Q3ScrollView. The child should be a child of the |
|
388 viewport() of the scrollview and be added with addChild(): |
|
389 \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 0 |
|
390 You can go on to add arbitrary child widgets to the single child |
|
391 in the scrollview as you would with any widget: |
|
392 \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 1 |
|
393 |
|
394 Here the Q3ScrollView has four children: the viewport(), the |
|
395 verticalScrollBar(), the horizontalScrollBar() and a small |
|
396 cornerWidget(). The viewport() has one child: the QWidget. The |
|
397 QWidget has the three QLabel objects as child widgets. When the view |
|
398 is scrolled, the QWidget is moved; its children move with it as |
|
399 child widgets normally do. |
|
400 |
|
401 \section1 Using a Very Big View with Some Widgets |
|
402 |
|
403 \img qscrollview-vp.png |
|
404 |
|
405 The second usage of Q3ScrollView (depicted above) is appropriate |
|
406 when few, if any, widgets are on a very large scrolling area that |
|
407 is potentially larger than 4000 pixels in either dimension. In |
|
408 this usage you call resizeContents() to set the size of the area |
|
409 and reimplement drawContents() to paint the contents. You may also |
|
410 add some widgets by making them children of the viewport() and |
|
411 adding them with addChild() (this is the same as the process for |
|
412 the single large widget in the previous example): |
|
413 \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 2 |
|
414 Here, the Q3ScrollView has the same four children: the viewport(), |
|
415 the verticalScrollBar(), the horizontalScrollBar() and a small |
|
416 cornerWidget(). The viewport() has the three QLabel objects as |
|
417 child widgets. When the view is scrolled, the scrollview moves the |
|
418 child widgets individually. |
|
419 |
|
420 \section1 Using a Very Big View with Many Widgets |
|
421 |
|
422 \img qscrollview-cl.png |
|
423 |
|
424 The final usage of Q3ScrollView (depicted above) is appropriate |
|
425 when many widgets are on a very large scrolling area that is |
|
426 potentially larger than 4000 pixels in either dimension. In this |
|
427 usage you call resizeContents() to set the size of the area and |
|
428 reimplement drawContents() to paint the contents. You then call |
|
429 enableClipper(true) and add widgets, again by making them children |
|
430 of the viewport(), and adding them with addChild(): |
|
431 \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 3 |
|
432 |
|
433 Here, the Q3ScrollView has four children: the clipper() (not the |
|
434 viewport() this time), the verticalScrollBar(), the |
|
435 horizontalScrollBar() and a small cornerWidget(). The clipper() |
|
436 has one child: the viewport(). The viewport() has the same three |
|
437 labels as child widgets. When the view is scrolled the viewport() |
|
438 is moved; its children move with it as child widgets normally do. |
|
439 |
|
440 \target allviews |
|
441 \section1 Details Relevant for All Views |
|
442 |
|
443 Normally you will use the first or third method if you want any |
|
444 child widgets in the view. |
|
445 |
|
446 Note that the widget you see in the scrolled area is the |
|
447 viewport() widget, not the Q3ScrollView itself. So to turn mouse |
|
448 tracking on, for example, use viewport()->setMouseTracking(true). |
|
449 |
|
450 To enable drag-and-drop, you would setAcceptDrops(true) on the |
|
451 Q3ScrollView (because drag-and-drop events propagate to the |
|
452 parent). But to work out the logical position in the view, you |
|
453 would need to map the drop co-ordinate from being relative to the |
|
454 Q3ScrollView to being relative to the contents; use the function |
|
455 viewportToContents() for this. |
|
456 |
|
457 To handle mouse events on the scrolling area, subclass scrollview |
|
458 as you would subclass other widgets, but rather than |
|
459 reimplementing mousePressEvent(), reimplement |
|
460 contentsMousePressEvent() instead. The contents specific event |
|
461 handlers provide translated events in the coordinate system of the |
|
462 scrollview. If you reimplement mousePressEvent(), you'll get |
|
463 called only when part of the Q3ScrollView is clicked: and the only |
|
464 such part is the "corner" (if you don't set a cornerWidget()) and |
|
465 the frame; everything else is covered up by the viewport, clipper |
|
466 or scroll bars. |
|
467 |
|
468 When you construct a Q3ScrollView, some of the window flags apply |
|
469 to the viewport() instead of being sent to the QWidget constructor |
|
470 for the Q3ScrollView. |
|
471 |
|
472 \list |
|
473 |
|
474 \i An image-manipulation widget would use \c |
|
475 WNoAutoErase|WStaticContents because the widget draws all pixels |
|
476 itself, and when its size increases, it only needs a paint event |
|
477 for the new part because the old part remains unchanged. |
|
478 |
|
479 \i A scrolling game widget in which the background scrolls as the |
|
480 characters move might use \c WNoAutoErase (in addition to \c |
|
481 WStaticContents) so that the window system background does not |
|
482 flash in and out during scrolling. |
|
483 |
|
484 \i A word processing widget might use \c WNoAutoErase and repaint |
|
485 itself line by line to get a less-flickery resizing. If the widget |
|
486 is in a mode in which no text justification can take place, it |
|
487 might use \c WStaticContents too, so that it would only get a |
|
488 repaint for the newly visible parts. |
|
489 |
|
490 \endlist |
|
491 |
|
492 Child widgets may be moved using addChild() or moveChild(). Use |
|
493 childX() and childY() to get the position of a child widget. |
|
494 |
|
495 A widget may be placed in the corner between the vertical and |
|
496 horizontal scroll bars with setCornerWidget(). You can get access |
|
497 to the scroll bars using horizontalScrollBar() and |
|
498 verticalScrollBar(), and to the viewport with viewport(). The |
|
499 scroll view can be scrolled using scrollBy(), ensureVisible(), |
|
500 setContentsPos() or center(). |
|
501 |
|
502 The visible area is given by visibleWidth() and visibleHeight(), |
|
503 and the contents area by contentsWidth() and contentsHeight(). The |
|
504 contents may be repainted using one of the repaintContents() or |
|
505 updateContents() functions. |
|
506 |
|
507 Coordinate conversion is provided by contentsToViewport() and |
|
508 viewportToContents(). |
|
509 |
|
510 The contentsMoving() signal is emitted just before the contents |
|
511 are moved to a new position. |
|
512 |
|
513 \warning Q3ScrollView currently does not erase the background when |
|
514 resized, i.e. you must always clear the background manually in |
|
515 scrollview subclasses. This will change in a future version of Qt |
|
516 and we recommend specifying the \c WNoAutoErase flag explicitly. |
|
517 */ |
|
518 |
|
519 |
|
520 /*! |
|
521 \enum Q3ScrollView::ResizePolicy |
|
522 |
|
523 This enum type is used to control a Q3ScrollView's reaction to |
|
524 resize events. |
|
525 |
|
526 \value Default the Q3ScrollView selects one of the other settings |
|
527 automatically when it has to. In this version of Qt, Q3ScrollView |
|
528 changes to \c Manual if you resize the contents with |
|
529 resizeContents() and to \c AutoOne if a child is added. |
|
530 |
|
531 \value Manual the contents stays the size set by resizeContents(). |
|
532 |
|
533 \value AutoOne if there is only one child widget the contents stays |
|
534 the size of that widget. Otherwise the behavior is undefined. |
|
535 |
|
536 \value AutoOneFit if there is only one child widget the contents stays |
|
537 the size of that widget's sizeHint(). If the scrollview is resized |
|
538 larger than the child's sizeHint(), the child will be resized to |
|
539 fit. If there is more than one child, the behavior is undefined. |
|
540 |
|
541 */ |
|
542 //#### The widget will be resized to its sizeHint() when a LayoutHint event |
|
543 //#### is received |
|
544 |
|
545 /*! |
|
546 Constructs a Q3ScrollView called \a name with parent \a parent and |
|
547 widget flags \a f. |
|
548 |
|
549 The widget flags \c WStaticContents, \c WNoAutoErase and \c |
|
550 WPaintClever are propagated to the viewport() widget. The other |
|
551 widget flags are propagated to the parent constructor as usual. |
|
552 */ |
|
553 |
|
554 Q3ScrollView::Q3ScrollView(QWidget *parent, const char *name, Qt::WindowFlags f) : |
|
555 Q3Frame(parent, name, f & (~WStaticContents) & (~WNoAutoErase) & (~WResizeNoErase)) |
|
556 { |
|
557 WindowFlags flags = WResizeNoErase | (f&WPaintClever) | (f&WRepaintNoErase) | (f&WStaticContents); |
|
558 d = new Q3ScrollViewData(this, flags); |
|
559 |
|
560 #ifndef QT_NO_DRAGANDDROP |
|
561 connect(&d->autoscroll_timer, SIGNAL(timeout()), |
|
562 this, SLOT(doDragAutoScroll())); |
|
563 #endif |
|
564 |
|
565 connect(d->hbar, SIGNAL(valueChanged(int)), |
|
566 this, SLOT(hslide(int))); |
|
567 connect(d->vbar, SIGNAL(valueChanged(int)), |
|
568 this, SLOT(vslide(int))); |
|
569 |
|
570 connect(d->hbar, SIGNAL(sliderPressed()), this, SLOT(hbarIsPressed())); |
|
571 connect(d->hbar, SIGNAL(sliderReleased()), this, SLOT(hbarIsReleased())); |
|
572 connect(d->vbar, SIGNAL(sliderPressed()), this, SLOT(vbarIsPressed())); |
|
573 connect(d->vbar, SIGNAL(sliderReleased()), this, SLOT(vbarIsReleased())); |
|
574 |
|
575 |
|
576 d->viewport->installEventFilter(this); |
|
577 |
|
578 connect(&d->scrollbar_timer, SIGNAL(timeout()), |
|
579 this, SLOT(updateScrollBars())); |
|
580 |
|
581 setFrameStyle(Q3Frame::StyledPanel | Q3Frame::Sunken); |
|
582 setLineWidth(style()->pixelMetric(QStyle::PM_DefaultFrameWidth)); |
|
583 setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); |
|
584 } |
|
585 |
|
586 |
|
587 /*! |
|
588 Destroys the Q3ScrollView. Any children added with addChild() will |
|
589 be deleted. |
|
590 */ |
|
591 Q3ScrollView::~Q3ScrollView() |
|
592 { |
|
593 // Be careful not to get all those useless events... |
|
594 if (d->clipped_viewport) |
|
595 d->clipped_viewport->removeEventFilter(this); |
|
596 else |
|
597 d->viewport->removeEventFilter(this); |
|
598 |
|
599 // order is important |
|
600 // ~QWidget may cause a WM_ERASEBKGND on Windows |
|
601 delete d->vbar; |
|
602 d->vbar = 0; |
|
603 delete d->hbar; |
|
604 d->hbar = 0; |
|
605 delete d->viewport; |
|
606 d->viewport = 0; |
|
607 delete d; |
|
608 d = 0; |
|
609 } |
|
610 |
|
611 /*! |
|
612 \fn void Q3ScrollView::horizontalSliderPressed() |
|
613 |
|
614 This signal is emitted whenever the user presses the horizontal slider. |
|
615 */ |
|
616 /*! |
|
617 \fn void Q3ScrollView::horizontalSliderReleased() |
|
618 |
|
619 This signal is emitted whenever the user releases the horizontal slider. |
|
620 */ |
|
621 /*! |
|
622 \fn void Q3ScrollView::verticalSliderPressed() |
|
623 |
|
624 This signal is emitted whenever the user presses the vertical slider. |
|
625 */ |
|
626 /*! |
|
627 \fn void Q3ScrollView::verticalSliderReleased() |
|
628 |
|
629 This signal is emitted whenever the user releases the vertical slider. |
|
630 */ |
|
631 void Q3ScrollView::hbarIsPressed() |
|
632 { |
|
633 d->hbarPressed = true; |
|
634 emit(horizontalSliderPressed()); |
|
635 } |
|
636 |
|
637 void Q3ScrollView::hbarIsReleased() |
|
638 { |
|
639 d->hbarPressed = false; |
|
640 emit(horizontalSliderReleased()); |
|
641 } |
|
642 |
|
643 /*! |
|
644 Returns true if horizontal slider is pressed by user; otherwise returns false. |
|
645 */ |
|
646 bool Q3ScrollView::isHorizontalSliderPressed() |
|
647 { |
|
648 return d->hbarPressed; |
|
649 } |
|
650 |
|
651 void Q3ScrollView::vbarIsPressed() |
|
652 { |
|
653 d->vbarPressed = true; |
|
654 emit(verticalSliderPressed()); |
|
655 } |
|
656 |
|
657 void Q3ScrollView::vbarIsReleased() |
|
658 { |
|
659 d->vbarPressed = false; |
|
660 emit(verticalSliderReleased()); |
|
661 } |
|
662 |
|
663 /*! |
|
664 Returns true if vertical slider is pressed by user; otherwise returns false. |
|
665 */ |
|
666 bool Q3ScrollView::isVerticalSliderPressed() |
|
667 { |
|
668 return d->vbarPressed; |
|
669 } |
|
670 |
|
671 /*! |
|
672 \internal |
|
673 */ |
|
674 void Q3ScrollView::styleChange(QStyle& old) |
|
675 { |
|
676 QWidget::styleChange(old); |
|
677 updateScrollBars(); |
|
678 d->cachedSizeHint = QSize(); |
|
679 } |
|
680 |
|
681 /*! |
|
682 \internal |
|
683 */ |
|
684 void Q3ScrollView::fontChange(const QFont &old) |
|
685 { |
|
686 QWidget::fontChange(old); |
|
687 updateScrollBars(); |
|
688 d->cachedSizeHint = QSize(); |
|
689 } |
|
690 |
|
691 void Q3ScrollView::hslide(int pos) |
|
692 { |
|
693 if (!d->signal_choke) { |
|
694 moveContents(-pos, -d->contentsY()); |
|
695 QApplication::syncX(); |
|
696 } |
|
697 } |
|
698 |
|
699 void Q3ScrollView::vslide(int pos) |
|
700 { |
|
701 if (!d->signal_choke) { |
|
702 moveContents(-d->contentsX(), -pos); |
|
703 QApplication::syncX(); |
|
704 } |
|
705 } |
|
706 |
|
707 /*! |
|
708 Called when the horizontal scroll bar geometry changes. This is |
|
709 provided as a protected function so that subclasses can do |
|
710 interesting things such as providing extra buttons in some of the |
|
711 space normally used by the scroll bars. |
|
712 |
|
713 The default implementation simply gives all the space to \a hbar. |
|
714 The new geometry is given by \a x, \a y, \a w and \a h. |
|
715 |
|
716 \sa setVBarGeometry() |
|
717 */ |
|
718 void Q3ScrollView::setHBarGeometry(QScrollBar& hbar, |
|
719 int x, int y, int w, int h) |
|
720 { |
|
721 hbar.setGeometry(x, y, w, h); |
|
722 } |
|
723 |
|
724 /*! |
|
725 Called when the vertical scroll bar geometry changes. This is |
|
726 provided as a protected function so that subclasses can do |
|
727 interesting things such as providing extra buttons in some of the |
|
728 space normally used by the scroll bars. |
|
729 |
|
730 The default implementation simply gives all the space to \a vbar. |
|
731 The new geometry is given by \a x, \a y, \a w and \a h. |
|
732 |
|
733 \sa setHBarGeometry() |
|
734 */ |
|
735 void Q3ScrollView::setVBarGeometry(QScrollBar& vbar, |
|
736 int x, int y, int w, int h) |
|
737 { |
|
738 vbar.setGeometry(x, y, w, h); |
|
739 } |
|
740 |
|
741 |
|
742 /*! |
|
743 Returns the viewport size for size (\a x, \a y). |
|
744 |
|
745 The viewport size depends on (\a x, \a y) (the size of the contents), |
|
746 the size of this widget and the modes of the horizontal and |
|
747 vertical scroll bars. |
|
748 |
|
749 This function permits widgets that can trade vertical and |
|
750 horizontal space for each other to control scroll bar appearance |
|
751 better. For example, a word processor or web browser can control |
|
752 the width of the right margin accurately, whether or not there |
|
753 needs to be a vertical scroll bar. |
|
754 */ |
|
755 |
|
756 QSize Q3ScrollView::viewportSize(int x, int y) const |
|
757 { |
|
758 int fw = frameWidth(); |
|
759 int lmarg = fw+d->l_marg; |
|
760 int rmarg = fw+d->r_marg; |
|
761 int tmarg = fw+d->t_marg; |
|
762 int bmarg = fw+d->b_marg; |
|
763 |
|
764 int w = width(); |
|
765 int h = height(); |
|
766 |
|
767 bool needh, needv; |
|
768 bool showh, showv; |
|
769 int hsbExt = horizontalScrollBar()->sizeHint().height(); |
|
770 int vsbExt = verticalScrollBar()->sizeHint().width(); |
|
771 |
|
772 if (d->policy != AutoOne || d->anyVisibleChildren()) { |
|
773 // Do we definitely need the scroll bar? |
|
774 needh = w-lmarg-rmarg < x; |
|
775 needv = h-tmarg-bmarg < y; |
|
776 |
|
777 // Do we intend to show the scroll bar? |
|
778 if (d->hMode == AlwaysOn) |
|
779 showh = true; |
|
780 else if (d->hMode == AlwaysOff) |
|
781 showh = false; |
|
782 else |
|
783 showh = needh; |
|
784 |
|
785 if (d->vMode == AlwaysOn) |
|
786 showv = true; |
|
787 else if (d->vMode == AlwaysOff) |
|
788 showv = false; |
|
789 else |
|
790 showv = needv; |
|
791 |
|
792 // Given other scroll bar will be shown, NOW do we need one? |
|
793 if (showh && h-vsbExt-tmarg-bmarg < y) { |
|
794 if (d->vMode == Auto) |
|
795 showv=true; |
|
796 } |
|
797 if (showv && w-hsbExt-lmarg-rmarg < x) { |
|
798 if (d->hMode == Auto) |
|
799 showh=true; |
|
800 } |
|
801 } else { |
|
802 // Scroll bars not needed, only show scroll bar that are always on. |
|
803 showh = d->hMode == AlwaysOn; |
|
804 showv = d->vMode == AlwaysOn; |
|
805 } |
|
806 |
|
807 return QSize(w-lmarg-rmarg - (showv ? vsbExt : 0), |
|
808 h-tmarg-bmarg - (showh ? hsbExt : 0)); |
|
809 } |
|
810 |
|
811 |
|
812 /*! |
|
813 Updates scroll bars: all possibilities are considered. You should |
|
814 never need to call this in your code. |
|
815 */ |
|
816 void Q3ScrollView::updateScrollBars() |
|
817 { |
|
818 if(!horizontalScrollBar() && !verticalScrollBar()) |
|
819 return; |
|
820 |
|
821 // I support this should use viewportSize()... but it needs |
|
822 // so many of the temporary variables from viewportSize. hm. |
|
823 int fw = frameWidth(); |
|
824 int lmarg = fw+d->l_marg; |
|
825 int rmarg = fw+d->r_marg; |
|
826 int tmarg = fw+d->t_marg; |
|
827 int bmarg = fw+d->b_marg; |
|
828 |
|
829 int w = width(); |
|
830 int h = height(); |
|
831 |
|
832 int portw, porth; |
|
833 |
|
834 bool needh; |
|
835 bool needv; |
|
836 bool showh; |
|
837 bool showv; |
|
838 bool showc = false; |
|
839 |
|
840 int hsbExt = horizontalScrollBar()->sizeHint().height(); |
|
841 int vsbExt = verticalScrollBar()->sizeHint().width(); |
|
842 |
|
843 QSize oldVisibleSize(visibleWidth(), visibleHeight()); |
|
844 |
|
845 if (d->policy != AutoOne || d->anyVisibleChildren()) { |
|
846 // Do we definitely need the scroll bar? |
|
847 needh = w-lmarg-rmarg < d->contentsWidth(); |
|
848 if (d->inresize) |
|
849 needh = !horizontalScrollBar()->isHidden(); |
|
850 needv = h-tmarg-bmarg < contentsHeight(); |
|
851 |
|
852 // Do we intend to show the scroll bar? |
|
853 if (d->hMode == AlwaysOn) |
|
854 showh = true; |
|
855 else if (d->hMode == AlwaysOff) |
|
856 showh = false; |
|
857 else |
|
858 showh = needh; |
|
859 |
|
860 if (d->vMode == AlwaysOn) |
|
861 showv = true; |
|
862 else if (d->vMode == AlwaysOff) |
|
863 showv = false; |
|
864 else |
|
865 showv = needv; |
|
866 |
|
867 #ifdef Q_WS_MAC |
|
868 bool mac_need_scroll = false; |
|
869 if(!parentWidget()) { |
|
870 mac_need_scroll = true; |
|
871 } else { |
|
872 QWidget *tlw = window(); |
|
873 #ifndef QT_MAC_USE_COCOA |
|
874 QPoint tlw_br = QPoint(tlw->width(), tlw->height()), |
|
875 my_br = qt_mac_posInWindow(this) + QPoint(w, h); |
|
876 if(my_br.x() >= tlw_br.x() - 3 && my_br.y() >= tlw_br.y() - 3) |
|
877 #endif |
|
878 mac_need_scroll = true; |
|
879 } |
|
880 if(mac_need_scroll) { |
|
881 #ifndef QT_MAC_USE_COCOA |
|
882 WindowAttributes attr; |
|
883 GetWindowAttributes((WindowPtr)handle(), &attr); |
|
884 mac_need_scroll = (attr & kWindowResizableAttribute); |
|
885 #endif |
|
886 } |
|
887 if(mac_need_scroll) { |
|
888 showc = true; |
|
889 if(d->vMode == Auto) |
|
890 showv = true; |
|
891 if(d->hMode == Auto) |
|
892 showh = true; |
|
893 } |
|
894 #endif |
|
895 |
|
896 // Given other scroll bar will be shown, NOW do we need one? |
|
897 if (showh && h-vsbExt-tmarg-bmarg < contentsHeight()) { |
|
898 needv=true; |
|
899 if (d->vMode == Auto) |
|
900 showv=true; |
|
901 } |
|
902 if (showv && !d->inresize && w-hsbExt-lmarg-rmarg < d->contentsWidth()) { |
|
903 needh=true; |
|
904 if (d->hMode == Auto) |
|
905 showh=true; |
|
906 } |
|
907 } else { |
|
908 // Scrollbars not needed, only show scroll bar that are always on. |
|
909 needh = needv = false; |
|
910 showh = d->hMode == AlwaysOn; |
|
911 showv = d->vMode == AlwaysOn; |
|
912 } |
|
913 |
|
914 bool sc = d->signal_choke; |
|
915 d->signal_choke=true; |
|
916 |
|
917 // Hide unneeded scroll bar, calculate viewport size |
|
918 if (showh) { |
|
919 porth=h-hsbExt-tmarg-bmarg; |
|
920 } else { |
|
921 if (!needh) |
|
922 d->hbar->setValue(0); |
|
923 d->hbar->hide(); |
|
924 porth=h-tmarg-bmarg; |
|
925 } |
|
926 if (showv) { |
|
927 portw=w-vsbExt-lmarg-rmarg; |
|
928 } else { |
|
929 if (!needv) |
|
930 d->vbar->setValue(0); |
|
931 d->vbar->hide(); |
|
932 portw=w-lmarg-rmarg; |
|
933 } |
|
934 |
|
935 // Configure scroll bars that we will show |
|
936 if (needv) { |
|
937 d->vbar->setRange(0, contentsHeight()-porth); |
|
938 d->vbar->setSteps(Q3ScrollView::d->vbar->lineStep(), porth); |
|
939 } else { |
|
940 d->vbar->setRange(0, 0); |
|
941 } |
|
942 if (needh) { |
|
943 d->hbar->setRange(0, QMAX(0, d->contentsWidth()-portw)); |
|
944 d->hbar->setSteps(Q3ScrollView::d->hbar->lineStep(), portw); |
|
945 } else { |
|
946 d->hbar->setRange(0, 0); |
|
947 } |
|
948 |
|
949 // Position the scroll bars, viewport and corner widget. |
|
950 int bottom; |
|
951 bool reverse = QApplication::reverseLayout(); |
|
952 int xoffset = (reverse && (showv || cornerWidget())) ? vsbExt : 0; |
|
953 int xpos = reverse ? 0 : w - vsbExt; |
|
954 bool frameContentsOnly = |
|
955 style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents); |
|
956 |
|
957 if(! frameContentsOnly) { |
|
958 if (reverse) |
|
959 xpos += fw; |
|
960 else |
|
961 xpos -= fw; |
|
962 } |
|
963 if (showh) { |
|
964 int right = (showc || showv || cornerWidget()) ? w-vsbExt : w; |
|
965 if (! frameContentsOnly) |
|
966 setHBarGeometry(*d->hbar, fw + xoffset, h-hsbExt-fw, |
|
967 right-fw-fw, hsbExt); |
|
968 else |
|
969 setHBarGeometry(*d->hbar, 0 + xoffset, h-hsbExt, right, |
|
970 hsbExt); |
|
971 bottom=h-hsbExt; |
|
972 } else { |
|
973 bottom=h; |
|
974 } |
|
975 if (showv) { |
|
976 clipper()->setGeometry(lmarg + xoffset, tmarg, |
|
977 w-vsbExt-lmarg-rmarg, |
|
978 bottom-tmarg-bmarg); |
|
979 d->viewportResized(w-vsbExt-lmarg-rmarg, bottom-tmarg-bmarg); |
|
980 if (! frameContentsOnly) |
|
981 changeFrameRect(QRect(0, 0, w, h)); |
|
982 else |
|
983 changeFrameRect(QRect(xoffset, 0, w-vsbExt, bottom)); |
|
984 if (showc || cornerWidget()) { |
|
985 if (! frameContentsOnly) |
|
986 setVBarGeometry(*d->vbar, xpos, |
|
987 fw, vsbExt, |
|
988 h-hsbExt-fw-fw); |
|
989 else |
|
990 setVBarGeometry(*d->vbar, xpos, 0, |
|
991 vsbExt, |
|
992 h-hsbExt); |
|
993 } |
|
994 else { |
|
995 if (! frameContentsOnly) |
|
996 setVBarGeometry(*d->vbar, xpos, |
|
997 fw, vsbExt, |
|
998 bottom-fw-fw); |
|
999 else |
|
1000 setVBarGeometry(*d->vbar, xpos, 0, |
|
1001 vsbExt, bottom); |
|
1002 } |
|
1003 } else { |
|
1004 if (! frameContentsOnly) |
|
1005 changeFrameRect(QRect(0, 0, w, h)); |
|
1006 else |
|
1007 changeFrameRect(QRect(0, 0, w, bottom)); |
|
1008 clipper()->setGeometry(lmarg, tmarg, |
|
1009 w-lmarg-rmarg, bottom-tmarg-bmarg); |
|
1010 d->viewportResized(w-lmarg-rmarg, bottom-tmarg-bmarg); |
|
1011 } |
|
1012 |
|
1013 QWidget *corner = d->corner; |
|
1014 if (d->corner) { |
|
1015 if (! frameContentsOnly) |
|
1016 corner->setGeometry(xpos, |
|
1017 h-hsbExt-fw, |
|
1018 vsbExt, |
|
1019 hsbExt); |
|
1020 else |
|
1021 corner->setGeometry(xpos, |
|
1022 h-hsbExt, |
|
1023 vsbExt, |
|
1024 hsbExt); |
|
1025 } |
|
1026 |
|
1027 d->signal_choke=sc; |
|
1028 |
|
1029 if (d->contentsX()+visibleWidth() > d->contentsWidth()) { |
|
1030 int x; |
|
1031 #if 0 |
|
1032 if (reverse) |
|
1033 x =QMIN(0,d->contentsWidth()-visibleWidth()); |
|
1034 else |
|
1035 #endif |
|
1036 x =QMAX(0,d->contentsWidth()-visibleWidth()); |
|
1037 d->hbar->setValue(x); |
|
1038 // Do it even if it is recursive |
|
1039 moveContents(-x, -d->contentsY()); |
|
1040 } |
|
1041 if (d->contentsY()+visibleHeight() > contentsHeight()) { |
|
1042 int y=QMAX(0,contentsHeight()-visibleHeight()); |
|
1043 d->vbar->setValue(y); |
|
1044 // Do it even if it is recursive |
|
1045 moveContents(-d->contentsX(), -y); |
|
1046 } |
|
1047 |
|
1048 // Finally, show the scroll bars |
|
1049 if (showh && (d->hbar->isHidden() || !d->hbar->isVisible())) |
|
1050 d->hbar->show(); |
|
1051 if (showv && (d->vbar->isHidden() || !d->vbar->isVisible())) |
|
1052 d->vbar->show(); |
|
1053 |
|
1054 d->signal_choke=true; |
|
1055 d->vbar->setValue(d->contentsY()); |
|
1056 d->hbar->setValue(d->contentsX()); |
|
1057 d->signal_choke=false; |
|
1058 |
|
1059 QSize newVisibleSize(visibleWidth(), visibleHeight()); |
|
1060 if (d->clipped_viewport && oldVisibleSize != newVisibleSize) { |
|
1061 QResizeEvent e(newVisibleSize, oldVisibleSize); |
|
1062 viewportResizeEvent(&e); |
|
1063 } |
|
1064 } |
|
1065 |
|
1066 |
|
1067 /*! |
|
1068 \reimp |
|
1069 */ |
|
1070 void Q3ScrollView::setVisible(bool visible) |
|
1071 { |
|
1072 if (visible && !isVisible()) { |
|
1073 QWidget::setVisible(visible); |
|
1074 updateScrollBars(); |
|
1075 d->hideOrShowAll(this); |
|
1076 } else { |
|
1077 QWidget::setVisible(visible); |
|
1078 } |
|
1079 } |
|
1080 |
|
1081 /*! |
|
1082 \internal |
|
1083 */ |
|
1084 void Q3ScrollView::resize(int w, int h) |
|
1085 { |
|
1086 QWidget::resize(w, h); |
|
1087 } |
|
1088 |
|
1089 /*! |
|
1090 \internal |
|
1091 */ |
|
1092 void Q3ScrollView::resize(const QSize& s) |
|
1093 { |
|
1094 resize(s.width(), s.height()); |
|
1095 } |
|
1096 |
|
1097 /*! |
|
1098 \reimp |
|
1099 */ |
|
1100 void Q3ScrollView::resizeEvent(QResizeEvent* event) |
|
1101 { |
|
1102 Q3Frame::resizeEvent(event); |
|
1103 |
|
1104 #if 0 |
|
1105 if (QApplication::reverseLayout()) { |
|
1106 d->fake_scroll = true; |
|
1107 scrollBy(-event->size().width() + event->oldSize().width(), 0); |
|
1108 d->fake_scroll = false; |
|
1109 } |
|
1110 #endif |
|
1111 |
|
1112 bool inresize = d->inresize; |
|
1113 d->inresize = true; |
|
1114 updateScrollBars(); |
|
1115 d->inresize = inresize; |
|
1116 d->scrollbar_timer.start(0, true); |
|
1117 |
|
1118 d->hideOrShowAll(this); |
|
1119 } |
|
1120 |
|
1121 |
|
1122 |
|
1123 /*! |
|
1124 \reimp |
|
1125 */ |
|
1126 void Q3ScrollView::mousePressEvent(QMouseEvent * e) |
|
1127 { |
|
1128 e->ignore(); |
|
1129 } |
|
1130 |
|
1131 /*! |
|
1132 \reimp |
|
1133 */ |
|
1134 void Q3ScrollView::mouseReleaseEvent(QMouseEvent *e) |
|
1135 { |
|
1136 e->ignore(); |
|
1137 } |
|
1138 |
|
1139 |
|
1140 /*! |
|
1141 \reimp |
|
1142 */ |
|
1143 void Q3ScrollView::mouseDoubleClickEvent(QMouseEvent *e) |
|
1144 { |
|
1145 e->ignore(); |
|
1146 } |
|
1147 |
|
1148 /*! |
|
1149 \reimp |
|
1150 */ |
|
1151 void Q3ScrollView::mouseMoveEvent(QMouseEvent *e) |
|
1152 { |
|
1153 e->ignore(); |
|
1154 } |
|
1155 |
|
1156 /*! |
|
1157 \reimp |
|
1158 */ |
|
1159 #ifndef QT_NO_WHEELEVENT |
|
1160 void Q3ScrollView::wheelEvent(QWheelEvent *e) |
|
1161 { |
|
1162 QWheelEvent ce(viewport()->mapFromGlobal(e->globalPos()), |
|
1163 e->globalPos(), e->delta(), e->state()); |
|
1164 viewportWheelEvent(&ce); |
|
1165 if (!ce.isAccepted()) { |
|
1166 if (e->orientation() == Horizontal && horizontalScrollBar()) |
|
1167 horizontalScrollBar()->event(e); |
|
1168 else if (e->orientation() == Vertical && verticalScrollBar()) |
|
1169 verticalScrollBar()->event(e); |
|
1170 } else { |
|
1171 e->accept(); |
|
1172 } |
|
1173 } |
|
1174 #endif |
|
1175 |
|
1176 /*! |
|
1177 \reimp |
|
1178 */ |
|
1179 void Q3ScrollView::contextMenuEvent(QContextMenuEvent *e) |
|
1180 { |
|
1181 if (e->reason() != QContextMenuEvent::Keyboard) { |
|
1182 e->ignore(); |
|
1183 return; |
|
1184 } |
|
1185 |
|
1186 QContextMenuEvent ce(e->reason(), viewport()->mapFromGlobal(e->globalPos()), |
|
1187 e->globalPos(), e->state()); |
|
1188 viewportContextMenuEvent(&ce); |
|
1189 if (ce.isAccepted()) |
|
1190 e->accept(); |
|
1191 else |
|
1192 e->ignore(); |
|
1193 } |
|
1194 |
|
1195 Q3ScrollView::ScrollBarMode Q3ScrollView::vScrollBarMode() const |
|
1196 { |
|
1197 return d->vMode; |
|
1198 } |
|
1199 |
|
1200 |
|
1201 /*! |
|
1202 \enum Q3ScrollView::ScrollBarMode |
|
1203 |
|
1204 This enum type describes the various modes of Q3ScrollView's scroll |
|
1205 bars. |
|
1206 |
|
1207 \value Auto Q3ScrollView shows a scroll bar when the content is |
|
1208 too large to fit and not otherwise. This is the default. |
|
1209 |
|
1210 \value AlwaysOff Q3ScrollView never shows a scroll bar. |
|
1211 |
|
1212 \value AlwaysOn Q3ScrollView always shows a scroll bar. |
|
1213 |
|
1214 (The modes for the horizontal and vertical scroll bars are |
|
1215 independent.) |
|
1216 */ |
|
1217 |
|
1218 |
|
1219 /*! |
|
1220 \property Q3ScrollView::vScrollBarMode |
|
1221 \brief the mode for the vertical scroll bar |
|
1222 |
|
1223 The default mode is Q3ScrollView::Auto. |
|
1224 |
|
1225 \sa hScrollBarMode |
|
1226 */ |
|
1227 void Q3ScrollView::setVScrollBarMode(ScrollBarMode mode) |
|
1228 { |
|
1229 if (d->vMode != mode) { |
|
1230 d->vMode = mode; |
|
1231 updateScrollBars(); |
|
1232 } |
|
1233 } |
|
1234 |
|
1235 |
|
1236 /*! |
|
1237 \property Q3ScrollView::hScrollBarMode |
|
1238 \brief the mode for the horizontal scroll bar |
|
1239 |
|
1240 The default mode is Q3ScrollView::Auto. |
|
1241 |
|
1242 \sa vScrollBarMode |
|
1243 */ |
|
1244 Q3ScrollView::ScrollBarMode Q3ScrollView::hScrollBarMode() const |
|
1245 { |
|
1246 return d->hMode; |
|
1247 } |
|
1248 |
|
1249 void Q3ScrollView::setHScrollBarMode(ScrollBarMode mode) |
|
1250 { |
|
1251 if (d->hMode != mode) { |
|
1252 d->hMode = mode; |
|
1253 updateScrollBars(); |
|
1254 } |
|
1255 } |
|
1256 |
|
1257 |
|
1258 /*! |
|
1259 Returns the widget in the corner between the two scroll bars. |
|
1260 |
|
1261 By default, no corner widget is present. |
|
1262 */ |
|
1263 QWidget* Q3ScrollView::cornerWidget() const |
|
1264 { |
|
1265 return d->corner; |
|
1266 } |
|
1267 |
|
1268 /*! |
|
1269 Sets the widget in the \a corner between the two scroll bars. |
|
1270 |
|
1271 You will probably also want to set at least one of the scroll bar |
|
1272 modes to \c AlwaysOn. |
|
1273 |
|
1274 Passing 0 shows no widget in the corner. |
|
1275 |
|
1276 Any previous \a corner widget is hidden. |
|
1277 |
|
1278 You may call setCornerWidget() with the same widget at different |
|
1279 times. |
|
1280 |
|
1281 All widgets set here will be deleted by the Q3ScrollView when it is |
|
1282 destroyed unless you separately reparent the widget after setting |
|
1283 some other corner widget (or 0). |
|
1284 |
|
1285 Any \e newly set widget should have no current parent. |
|
1286 |
|
1287 By default, no corner widget is present. |
|
1288 |
|
1289 \sa setVScrollBarMode(), setHScrollBarMode() |
|
1290 */ |
|
1291 void Q3ScrollView::setCornerWidget(QWidget* corner) |
|
1292 { |
|
1293 QWidget* oldcorner = d->corner; |
|
1294 if (oldcorner != corner) { |
|
1295 if (oldcorner) oldcorner->hide(); |
|
1296 d->corner = corner; |
|
1297 if (corner) corner->setParent(this); |
|
1298 updateScrollBars(); |
|
1299 if (corner) corner->show(); |
|
1300 } |
|
1301 } |
|
1302 |
|
1303 |
|
1304 void Q3ScrollView::setResizePolicy(ResizePolicy r) |
|
1305 { |
|
1306 d->policy = r; |
|
1307 } |
|
1308 |
|
1309 /*! |
|
1310 \property Q3ScrollView::resizePolicy |
|
1311 \brief the resize policy |
|
1312 |
|
1313 The default is \c Default. |
|
1314 |
|
1315 \sa ResizePolicy |
|
1316 */ |
|
1317 Q3ScrollView::ResizePolicy Q3ScrollView::resizePolicy() const |
|
1318 { |
|
1319 return d->policy; |
|
1320 } |
|
1321 |
|
1322 /*! |
|
1323 \internal |
|
1324 */ |
|
1325 void Q3ScrollView::setEnabled(bool enable) |
|
1326 { |
|
1327 Q3Frame::setEnabled(enable); |
|
1328 } |
|
1329 |
|
1330 /*! |
|
1331 Removes the \a child widget from the scrolled area. Note that this |
|
1332 happens automatically if the \a child is deleted. |
|
1333 */ |
|
1334 void Q3ScrollView::removeChild(QWidget* child) |
|
1335 { |
|
1336 if (!d || !child) // First check in case we are destructing |
|
1337 return; |
|
1338 |
|
1339 QSVChildRec *r = d->rec(child); |
|
1340 if (r) d->deleteChildRec(r); |
|
1341 } |
|
1342 |
|
1343 /*! |
|
1344 \internal |
|
1345 */ |
|
1346 void Q3ScrollView::removeChild(QObject* child) |
|
1347 { |
|
1348 Q3Frame::removeChild(child); |
|
1349 } |
|
1350 |
|
1351 /*! |
|
1352 Inserts the widget, \a child, into the scrolled area positioned at |
|
1353 (\a x, \a y). The position defaults to (0, 0). If the child is |
|
1354 already in the view, it is just moved. |
|
1355 |
|
1356 You may want to call enableClipper(true) if you add a large number |
|
1357 of widgets. |
|
1358 */ |
|
1359 void Q3ScrollView::addChild(QWidget* child, int x, int y) |
|
1360 { |
|
1361 if (!child) { |
|
1362 #if defined(QT_CHECK_NULL) |
|
1363 qWarning("Q3ScrollView::addChild(): Cannot add null child"); |
|
1364 #endif |
|
1365 return; |
|
1366 } |
|
1367 child->polish(); |
|
1368 child->setBackgroundOrigin(WidgetOrigin); |
|
1369 |
|
1370 if (child->parentWidget() == viewport()) { |
|
1371 // May already be there |
|
1372 QSVChildRec *r = d->rec(child); |
|
1373 if (r) { |
|
1374 r->moveTo(this,x,y,d->clipped_viewport); |
|
1375 if (d->policy > Manual) { |
|
1376 d->autoResizeHint(this); |
|
1377 d->autoResize(this); // #### better to just deal with this one widget! |
|
1378 } |
|
1379 return; |
|
1380 } |
|
1381 } |
|
1382 |
|
1383 if (d->children.isEmpty() && d->policy != Manual) { |
|
1384 if (d->policy == Default) |
|
1385 setResizePolicy(AutoOne); |
|
1386 child->installEventFilter(this); |
|
1387 } else if (d->policy == AutoOne) { |
|
1388 child->removeEventFilter(this); //#### ????? |
|
1389 setResizePolicy(Manual); |
|
1390 } |
|
1391 if (child->parentWidget() != viewport()) { |
|
1392 child->reparent(viewport(), 0, QPoint(0,0), false); |
|
1393 } |
|
1394 d->addChildRec(child,x,y)->hideOrShow(this, d->clipped_viewport); |
|
1395 |
|
1396 if (d->policy > Manual) { |
|
1397 d->autoResizeHint(this); |
|
1398 d->autoResize(this); // #### better to just deal with this one widget! |
|
1399 } |
|
1400 } |
|
1401 |
|
1402 /*! |
|
1403 Repositions the \a child widget to (\a x, \a y). This function is |
|
1404 the same as addChild(). |
|
1405 */ |
|
1406 void Q3ScrollView::moveChild(QWidget* child, int x, int y) |
|
1407 { |
|
1408 addChild(child,x,y); |
|
1409 } |
|
1410 |
|
1411 /*! |
|
1412 Returns the X position of the given \a child widget. Use this |
|
1413 rather than QWidget::x() for widgets added to the view. |
|
1414 |
|
1415 This function returns 0 if \a child has not been added to the view. |
|
1416 */ |
|
1417 int Q3ScrollView::childX(QWidget* child) |
|
1418 { |
|
1419 QSVChildRec *r = d->rec(child); |
|
1420 return r ? r->x : 0; |
|
1421 } |
|
1422 |
|
1423 /*! |
|
1424 Returns the Y position of the given \a child widget. Use this |
|
1425 rather than QWidget::y() for widgets added to the view. |
|
1426 |
|
1427 This function returns 0 if \a child has not been added to the view. |
|
1428 */ |
|
1429 int Q3ScrollView::childY(QWidget* child) |
|
1430 { |
|
1431 QSVChildRec *r = d->rec(child); |
|
1432 return r ? r->y : 0; |
|
1433 } |
|
1434 |
|
1435 /*! \fn bool Q3ScrollView::childIsVisible(QWidget*) |
|
1436 \obsolete |
|
1437 |
|
1438 Returns true if \a child is visible. This is equivalent |
|
1439 to child->isVisible(). |
|
1440 */ |
|
1441 |
|
1442 /*! \fn void Q3ScrollView::showChild(QWidget* child, bool y) |
|
1443 \obsolete |
|
1444 |
|
1445 Sets the visibility of \a child. Equivalent to |
|
1446 QWidget::show() or QWidget::hide(). |
|
1447 */ |
|
1448 |
|
1449 /*! |
|
1450 This event filter ensures the scroll bars are updated when a |
|
1451 single contents widget is resized, shown, hidden or destroyed; it |
|
1452 passes mouse events to the Q3ScrollView. The event is in \a e and |
|
1453 the object is in \a obj. |
|
1454 */ |
|
1455 |
|
1456 bool Q3ScrollView::eventFilter(QObject *obj, QEvent *e) |
|
1457 { |
|
1458 bool disabled = !(qobject_cast<QWidget*>(obj)->isEnabled()); |
|
1459 if (!d) |
|
1460 return false; // we are destructing |
|
1461 if (obj == d->viewport || obj == d->clipped_viewport) { |
|
1462 switch (e->type()) { |
|
1463 /* Forward many events to viewport...() functions */ |
|
1464 case QEvent::Paint: |
|
1465 viewportPaintEvent((QPaintEvent*)e); |
|
1466 break; |
|
1467 case QEvent::Resize: |
|
1468 if (!d->clipped_viewport) |
|
1469 viewportResizeEvent((QResizeEvent *)e); |
|
1470 break; |
|
1471 case QEvent::MouseButtonPress: |
|
1472 if (disabled) |
|
1473 return false; |
|
1474 viewportMousePressEvent((QMouseEvent*)e); |
|
1475 if (((QMouseEvent*)e)->isAccepted()) |
|
1476 return true; |
|
1477 break; |
|
1478 case QEvent::MouseButtonRelease: |
|
1479 if (disabled) |
|
1480 return false; |
|
1481 viewportMouseReleaseEvent((QMouseEvent*)e); |
|
1482 if (((QMouseEvent*)e)->isAccepted()) |
|
1483 return true; |
|
1484 break; |
|
1485 case QEvent::MouseButtonDblClick: |
|
1486 if (disabled) |
|
1487 return false; |
|
1488 viewportMouseDoubleClickEvent((QMouseEvent*)e); |
|
1489 if (((QMouseEvent*)e)->isAccepted()) |
|
1490 return true; |
|
1491 break; |
|
1492 case QEvent::MouseMove: |
|
1493 if (disabled) |
|
1494 return false; |
|
1495 viewportMouseMoveEvent((QMouseEvent*)e); |
|
1496 if (((QMouseEvent*)e)->isAccepted()) |
|
1497 return true; |
|
1498 break; |
|
1499 #ifndef QT_NO_DRAGANDDROP |
|
1500 case QEvent::DragEnter: |
|
1501 if (disabled) |
|
1502 return false; |
|
1503 viewportDragEnterEvent((QDragEnterEvent*)e); |
|
1504 break; |
|
1505 case QEvent::DragMove: { |
|
1506 if (disabled) |
|
1507 return false; |
|
1508 if (d->drag_autoscroll) { |
|
1509 QPoint vp = ((QDragMoveEvent*) e)->pos(); |
|
1510 QRect inside_margin(autoscroll_margin, autoscroll_margin, |
|
1511 visibleWidth() - autoscroll_margin * 2, |
|
1512 visibleHeight() - autoscroll_margin * 2); |
|
1513 if (!inside_margin.contains(vp)) { |
|
1514 startDragAutoScroll(); |
|
1515 // Keep sending move events |
|
1516 ((QDragMoveEvent*)e)->accept(QRect(0,0,0,0)); |
|
1517 } |
|
1518 } |
|
1519 viewportDragMoveEvent((QDragMoveEvent*)e); |
|
1520 } break; |
|
1521 case QEvent::DragLeave: |
|
1522 if (disabled) |
|
1523 return false; |
|
1524 stopDragAutoScroll(); |
|
1525 viewportDragLeaveEvent((QDragLeaveEvent*)e); |
|
1526 break; |
|
1527 case QEvent::Drop: |
|
1528 if (disabled) |
|
1529 return false; |
|
1530 stopDragAutoScroll(); |
|
1531 viewportDropEvent((QDropEvent*)e); |
|
1532 break; |
|
1533 #endif // QT_NO_DRAGANDDROP |
|
1534 #ifndef QT_NO_WHEELEVENT |
|
1535 case QEvent::Wheel: |
|
1536 if (disabled) |
|
1537 return false; |
|
1538 break; |
|
1539 #endif |
|
1540 case QEvent::ContextMenu: |
|
1541 if (disabled) |
|
1542 return false; |
|
1543 viewportContextMenuEvent((QContextMenuEvent*)e); |
|
1544 if (((QContextMenuEvent*)e)->isAccepted()) |
|
1545 return true; |
|
1546 break; |
|
1547 case QEvent::ChildRemoved: |
|
1548 removeChild((QWidget*)((QChildEvent*)e)->child()); |
|
1549 break; |
|
1550 case QEvent::LayoutHint: |
|
1551 d->autoResizeHint(this); |
|
1552 break; |
|
1553 default: |
|
1554 break; |
|
1555 } |
|
1556 } else if (d && d->rec((QWidget*)obj)) { // must be a child |
|
1557 if (e->type() == QEvent::Resize) |
|
1558 d->autoResize(this); |
|
1559 else if (e->type() == QEvent::Move) |
|
1560 d->autoMove(this); |
|
1561 } |
|
1562 return Q3Frame::eventFilter(obj, e); // always continue with standard event processing |
|
1563 } |
|
1564 |
|
1565 /*! |
|
1566 This event handler is called whenever the Q3ScrollView receives a |
|
1567 mousePressEvent(): the press position in \a e is translated to be a point |
|
1568 on the contents. |
|
1569 */ |
|
1570 void Q3ScrollView::contentsMousePressEvent(QMouseEvent* e) |
|
1571 { |
|
1572 e->ignore(); |
|
1573 } |
|
1574 |
|
1575 /*! |
|
1576 This event handler is called whenever the Q3ScrollView receives a |
|
1577 mouseReleaseEvent(): the release position in \a e is translated to be a |
|
1578 point on the contents. |
|
1579 */ |
|
1580 void Q3ScrollView::contentsMouseReleaseEvent(QMouseEvent* e) |
|
1581 { |
|
1582 e->ignore(); |
|
1583 } |
|
1584 |
|
1585 /*! |
|
1586 This event handler is called whenever the Q3ScrollView receives a |
|
1587 mouseDoubleClickEvent(): the click position in \a e is translated to be a |
|
1588 point on the contents. |
|
1589 |
|
1590 The default implementation generates a normal mouse press event. |
|
1591 */ |
|
1592 void Q3ScrollView::contentsMouseDoubleClickEvent(QMouseEvent* e) |
|
1593 { |
|
1594 contentsMousePressEvent(e); // try mouse press event |
|
1595 } |
|
1596 |
|
1597 /*! |
|
1598 This event handler is called whenever the Q3ScrollView receives a |
|
1599 mouseMoveEvent(): the mouse position in \a e is translated to be a point |
|
1600 on the contents. |
|
1601 */ |
|
1602 void Q3ScrollView::contentsMouseMoveEvent(QMouseEvent* e) |
|
1603 { |
|
1604 e->ignore(); |
|
1605 } |
|
1606 |
|
1607 #ifndef QT_NO_DRAGANDDROP |
|
1608 |
|
1609 /*! |
|
1610 This event handler is called whenever the Q3ScrollView receives a |
|
1611 dragEnterEvent(): the drag position is translated to be a point |
|
1612 on the contents. |
|
1613 |
|
1614 The default implementation does nothing. The \a event parameter is |
|
1615 ignored. |
|
1616 */ |
|
1617 void Q3ScrollView::contentsDragEnterEvent(QDragEnterEvent * /* event */) |
|
1618 { |
|
1619 } |
|
1620 |
|
1621 /*! |
|
1622 This event handler is called whenever the Q3ScrollView receives a |
|
1623 dragMoveEvent(): the drag position is translated to be a point on |
|
1624 the contents. |
|
1625 |
|
1626 The default implementation does nothing. The \a event parameter is |
|
1627 ignored. |
|
1628 */ |
|
1629 void Q3ScrollView::contentsDragMoveEvent(QDragMoveEvent * /* event */) |
|
1630 { |
|
1631 } |
|
1632 |
|
1633 /*! |
|
1634 This event handler is called whenever the Q3ScrollView receives a |
|
1635 dragLeaveEvent(): the drag position is translated to be a point |
|
1636 on the contents. |
|
1637 |
|
1638 The default implementation does nothing. The \a event parameter is |
|
1639 ignored. |
|
1640 */ |
|
1641 void Q3ScrollView::contentsDragLeaveEvent(QDragLeaveEvent * /* event */) |
|
1642 { |
|
1643 } |
|
1644 |
|
1645 /*! |
|
1646 This event handler is called whenever the Q3ScrollView receives a |
|
1647 dropEvent(): the drop position is translated to be a point on the |
|
1648 contents. |
|
1649 |
|
1650 The default implementation does nothing. The \a event parameter is |
|
1651 ignored. |
|
1652 */ |
|
1653 |
|
1654 void Q3ScrollView::contentsDropEvent(QDropEvent * /* event */) |
|
1655 { |
|
1656 } |
|
1657 |
|
1658 #endif // QT_NO_DRAGANDDROP |
|
1659 |
|
1660 /*! |
|
1661 This event handler is called whenever the Q3ScrollView receives a |
|
1662 wheelEvent() in \a{e}: the mouse position is translated to be a |
|
1663 point on the contents. |
|
1664 */ |
|
1665 #ifndef QT_NO_WHEELEVENT |
|
1666 void Q3ScrollView::contentsWheelEvent(QWheelEvent * e) |
|
1667 { |
|
1668 e->ignore(); |
|
1669 } |
|
1670 #endif |
|
1671 /*! |
|
1672 This event handler is called whenever the Q3ScrollView receives a |
|
1673 contextMenuEvent() in \a{e}: the mouse position is translated to |
|
1674 be a point on the contents. |
|
1675 */ |
|
1676 void Q3ScrollView::contentsContextMenuEvent(QContextMenuEvent *e) |
|
1677 { |
|
1678 e->ignore(); |
|
1679 } |
|
1680 |
|
1681 /*! |
|
1682 This is a low-level painting routine that draws the viewport |
|
1683 contents. Reimplement this if drawContents() is too high-level |
|
1684 (for example, if you don't want to open a QPainter on the |
|
1685 viewport). The paint event is passed in \a pe. |
|
1686 */ |
|
1687 void Q3ScrollView::viewportPaintEvent(QPaintEvent* pe) |
|
1688 { |
|
1689 QWidget* vp = viewport(); |
|
1690 |
|
1691 QPainter p(vp); |
|
1692 QRect r = pe->rect(); |
|
1693 |
|
1694 if (d->clipped_viewport) { |
|
1695 QRect rr( |
|
1696 -d->clipped_viewport->x(), -d->clipped_viewport->y(), |
|
1697 d->viewport->width(), d->viewport->height() |
|
1698 ); |
|
1699 r &= rr; |
|
1700 if (r.isValid()) { |
|
1701 int ex = r.x() + d->clipped_viewport->x() + d->contentsX(); |
|
1702 int ey = r.y() + d->clipped_viewport->y() + d->contentsY(); |
|
1703 int ew = r.width(); |
|
1704 int eh = r.height(); |
|
1705 drawContentsOffset(&p, |
|
1706 d->contentsX()+d->clipped_viewport->x(), |
|
1707 d->contentsY()+d->clipped_viewport->y(), |
|
1708 ex, ey, ew, eh); |
|
1709 } |
|
1710 } else { |
|
1711 r &= d->viewport->rect(); |
|
1712 int ex = r.x() + d->contentsX(); |
|
1713 int ey = r.y() + d->contentsY(); |
|
1714 int ew = r.width(); |
|
1715 int eh = r.height(); |
|
1716 drawContentsOffset(&p, d->contentsX(), d->contentsY(), ex, ey, ew, eh); |
|
1717 } |
|
1718 } |
|
1719 |
|
1720 |
|
1721 /*! |
|
1722 To provide simple processing of events on the contents, this |
|
1723 function receives all resize events sent to the viewport. |
|
1724 |
|
1725 The default implementation does nothing. The \a event parameter is |
|
1726 ignored. |
|
1727 |
|
1728 \sa QWidget::resizeEvent() |
|
1729 */ |
|
1730 void Q3ScrollView::viewportResizeEvent(QResizeEvent * /* event */) |
|
1731 { |
|
1732 } |
|
1733 |
|
1734 /*! \internal |
|
1735 |
|
1736 To provide simple processing of events on the contents, this |
|
1737 function receives all mouse press events sent to the viewport, |
|
1738 translates the event and calls contentsMousePressEvent(). |
|
1739 |
|
1740 \sa contentsMousePressEvent(), QWidget::mousePressEvent() |
|
1741 */ |
|
1742 void Q3ScrollView::viewportMousePressEvent(QMouseEvent* e) |
|
1743 { |
|
1744 QMouseEvent ce(e->type(), viewportToContents(e->pos()), |
|
1745 e->globalPos(), e->button(), e->state()); |
|
1746 contentsMousePressEvent(&ce); |
|
1747 if (!ce.isAccepted()) |
|
1748 e->ignore(); |
|
1749 } |
|
1750 |
|
1751 /*!\internal |
|
1752 |
|
1753 To provide simple processing of events on the contents, this function |
|
1754 receives all mouse release events sent to the viewport, translates |
|
1755 the event and calls contentsMouseReleaseEvent(). |
|
1756 |
|
1757 \sa QWidget::mouseReleaseEvent() |
|
1758 */ |
|
1759 void Q3ScrollView::viewportMouseReleaseEvent(QMouseEvent* e) |
|
1760 { |
|
1761 QMouseEvent ce(e->type(), viewportToContents(e->pos()), |
|
1762 e->globalPos(), e->button(), e->state()); |
|
1763 contentsMouseReleaseEvent(&ce); |
|
1764 if (!ce.isAccepted()) |
|
1765 e->ignore(); |
|
1766 } |
|
1767 |
|
1768 /*!\internal |
|
1769 |
|
1770 To provide simple processing of events on the contents, this function |
|
1771 receives all mouse double click events sent to the viewport, |
|
1772 translates the event and calls contentsMouseDoubleClickEvent(). |
|
1773 |
|
1774 \sa QWidget::mouseDoubleClickEvent() |
|
1775 */ |
|
1776 void Q3ScrollView::viewportMouseDoubleClickEvent(QMouseEvent* e) |
|
1777 { |
|
1778 QMouseEvent ce(e->type(), viewportToContents(e->pos()), |
|
1779 e->globalPos(), e->button(), e->state()); |
|
1780 contentsMouseDoubleClickEvent(&ce); |
|
1781 if (!ce.isAccepted()) |
|
1782 e->ignore(); |
|
1783 } |
|
1784 |
|
1785 /*!\internal |
|
1786 |
|
1787 To provide simple processing of events on the contents, this function |
|
1788 receives all mouse move events sent to the viewport, translates the |
|
1789 event and calls contentsMouseMoveEvent(). |
|
1790 |
|
1791 \sa QWidget::mouseMoveEvent() |
|
1792 */ |
|
1793 void Q3ScrollView::viewportMouseMoveEvent(QMouseEvent* e) |
|
1794 { |
|
1795 QMouseEvent ce(e->type(), viewportToContents(e->pos()), |
|
1796 e->globalPos(), e->button(), e->state()); |
|
1797 contentsMouseMoveEvent(&ce); |
|
1798 if (!ce.isAccepted()) |
|
1799 e->ignore(); |
|
1800 } |
|
1801 |
|
1802 #ifndef QT_NO_DRAGANDDROP |
|
1803 |
|
1804 /*!\internal |
|
1805 |
|
1806 To provide simple processing of events on the contents, this function |
|
1807 receives all drag enter events sent to the viewport, translates the |
|
1808 event and calls contentsDragEnterEvent(). |
|
1809 |
|
1810 \sa QWidget::dragEnterEvent() |
|
1811 */ |
|
1812 void Q3ScrollView::viewportDragEnterEvent(QDragEnterEvent* e) |
|
1813 { |
|
1814 e->setPoint(viewportToContents(e->pos())); |
|
1815 contentsDragEnterEvent(e); |
|
1816 e->setPoint(contentsToViewport(e->pos())); |
|
1817 } |
|
1818 |
|
1819 /*!\internal |
|
1820 |
|
1821 To provide simple processing of events on the contents, this function |
|
1822 receives all drag move events sent to the viewport, translates the |
|
1823 event and calls contentsDragMoveEvent(). |
|
1824 |
|
1825 \sa QWidget::dragMoveEvent() |
|
1826 */ |
|
1827 void Q3ScrollView::viewportDragMoveEvent(QDragMoveEvent* e) |
|
1828 { |
|
1829 e->setPoint(viewportToContents(e->pos())); |
|
1830 contentsDragMoveEvent(e); |
|
1831 e->setPoint(contentsToViewport(e->pos())); |
|
1832 } |
|
1833 |
|
1834 /*!\internal |
|
1835 |
|
1836 To provide simple processing of events on the contents, this function |
|
1837 receives all drag leave events sent to the viewport and calls |
|
1838 contentsDragLeaveEvent(). |
|
1839 |
|
1840 \sa QWidget::dragLeaveEvent() |
|
1841 */ |
|
1842 void Q3ScrollView::viewportDragLeaveEvent(QDragLeaveEvent* e) |
|
1843 { |
|
1844 contentsDragLeaveEvent(e); |
|
1845 } |
|
1846 |
|
1847 /*!\internal |
|
1848 |
|
1849 To provide simple processing of events on the contents, this function |
|
1850 receives all drop events sent to the viewport, translates the event |
|
1851 and calls contentsDropEvent(). |
|
1852 |
|
1853 \sa QWidget::dropEvent() |
|
1854 */ |
|
1855 void Q3ScrollView::viewportDropEvent(QDropEvent* e) |
|
1856 { |
|
1857 e->setPoint(viewportToContents(e->pos())); |
|
1858 contentsDropEvent(e); |
|
1859 e->setPoint(contentsToViewport(e->pos())); |
|
1860 } |
|
1861 |
|
1862 #endif // QT_NO_DRAGANDDROP |
|
1863 |
|
1864 /*!\internal |
|
1865 |
|
1866 To provide simple processing of events on the contents, this function |
|
1867 receives all wheel events sent to the viewport, translates the |
|
1868 event and calls contentsWheelEvent(). |
|
1869 |
|
1870 \sa QWidget::wheelEvent() |
|
1871 */ |
|
1872 #ifndef QT_NO_WHEELEVENT |
|
1873 void Q3ScrollView::viewportWheelEvent(QWheelEvent* e) |
|
1874 { |
|
1875 /* |
|
1876 Different than standard mouse events, because wheel events might |
|
1877 be sent to the focus widget if the widget-under-mouse doesn't want |
|
1878 the event itself. |
|
1879 */ |
|
1880 QWheelEvent ce(viewportToContents(e->pos()), |
|
1881 e->globalPos(), e->delta(), e->state()); |
|
1882 contentsWheelEvent(&ce); |
|
1883 if (ce.isAccepted()) |
|
1884 e->accept(); |
|
1885 else |
|
1886 e->ignore(); |
|
1887 } |
|
1888 #endif |
|
1889 |
|
1890 /*! \internal |
|
1891 |
|
1892 To provide simple processing of events on the contents, this function |
|
1893 receives all context menu events sent to the viewport, translates the |
|
1894 event and calls contentsContextMenuEvent(). |
|
1895 */ |
|
1896 void Q3ScrollView::viewportContextMenuEvent(QContextMenuEvent *e) |
|
1897 { |
|
1898 QContextMenuEvent ce(e->reason(), viewportToContents(e->pos()), e->globalPos(), e->state()); |
|
1899 contentsContextMenuEvent(&ce); |
|
1900 if (ce.isAccepted()) |
|
1901 e->accept(); |
|
1902 else |
|
1903 e->ignore(); |
|
1904 } |
|
1905 |
|
1906 /*! |
|
1907 Returns the component horizontal scroll bar. It is made available |
|
1908 to allow accelerators, autoscrolling, etc. |
|
1909 |
|
1910 It should not be used for other purposes. |
|
1911 |
|
1912 This function never returns 0. |
|
1913 */ |
|
1914 QScrollBar* Q3ScrollView::horizontalScrollBar() const |
|
1915 { |
|
1916 return d->hbar; |
|
1917 } |
|
1918 |
|
1919 /*! |
|
1920 Returns the component vertical scroll bar. It is made available to |
|
1921 allow accelerators, autoscrolling, etc. |
|
1922 |
|
1923 It should not be used for other purposes. |
|
1924 |
|
1925 This function never returns 0. |
|
1926 */ |
|
1927 QScrollBar* Q3ScrollView::verticalScrollBar() const { |
|
1928 return d->vbar; |
|
1929 } |
|
1930 |
|
1931 |
|
1932 /*! |
|
1933 Scrolls the content so that the point (\a x, \a y) is visible with at |
|
1934 least 50-pixel margins (if possible, otherwise centered). |
|
1935 */ |
|
1936 void Q3ScrollView::ensureVisible(int x, int y) |
|
1937 { |
|
1938 ensureVisible(x, y, 50, 50); |
|
1939 } |
|
1940 |
|
1941 /*! |
|
1942 \overload |
|
1943 |
|
1944 Scrolls the content so that the point (\a x, \a y) is visible with at |
|
1945 least the \a xmargin and \a ymargin margins (if possible, |
|
1946 otherwise centered). |
|
1947 */ |
|
1948 void Q3ScrollView::ensureVisible(int x, int y, int xmargin, int ymargin) |
|
1949 { |
|
1950 int pw=visibleWidth(); |
|
1951 int ph=visibleHeight(); |
|
1952 |
|
1953 int cx=-d->contentsX(); |
|
1954 int cy=-d->contentsY(); |
|
1955 int cw=d->contentsWidth(); |
|
1956 int ch=contentsHeight(); |
|
1957 |
|
1958 if (pw < xmargin*2) |
|
1959 xmargin=pw/2; |
|
1960 if (ph < ymargin*2) |
|
1961 ymargin=ph/2; |
|
1962 |
|
1963 if (cw <= pw) { |
|
1964 xmargin=0; |
|
1965 cx=0; |
|
1966 } |
|
1967 if (ch <= ph) { |
|
1968 ymargin=0; |
|
1969 cy=0; |
|
1970 } |
|
1971 |
|
1972 if (x < -cx+xmargin) |
|
1973 cx = -x+xmargin; |
|
1974 else if (x >= -cx+pw-xmargin) |
|
1975 cx = -x+pw-xmargin; |
|
1976 |
|
1977 if (y < -cy+ymargin) |
|
1978 cy = -y+ymargin; |
|
1979 else if (y >= -cy+ph-ymargin) |
|
1980 cy = -y+ph-ymargin; |
|
1981 |
|
1982 if (cx > 0) |
|
1983 cx=0; |
|
1984 else if (cx < pw-cw && cw>pw) |
|
1985 cx=pw-cw; |
|
1986 |
|
1987 if (cy > 0) |
|
1988 cy=0; |
|
1989 else if (cy < ph-ch && ch>ph) |
|
1990 cy=ph-ch; |
|
1991 |
|
1992 setContentsPos(-cx, -cy); |
|
1993 } |
|
1994 |
|
1995 /*! |
|
1996 Scrolls the content so that the point (\a x, \a y) is in the top-left |
|
1997 corner. |
|
1998 */ |
|
1999 void Q3ScrollView::setContentsPos(int x, int y) |
|
2000 { |
|
2001 #if 0 |
|
2002 // bounds checking... |
|
2003 if (QApplication::reverseLayout()) |
|
2004 if (x > d->contentsWidth() - visibleWidth()) x = d->contentsWidth() - visibleWidth(); |
|
2005 else |
|
2006 #endif |
|
2007 if (x < 0) x = 0; |
|
2008 if (y < 0) y = 0; |
|
2009 // Choke signal handling while we update BOTH sliders. |
|
2010 d->signal_choke=true; |
|
2011 moveContents(-x, -y); |
|
2012 d->vbar->setValue(y); |
|
2013 d->hbar->setValue(x); |
|
2014 d->signal_choke=false; |
|
2015 } |
|
2016 |
|
2017 /*! |
|
2018 Scrolls the content by \a dx to the left and \a dy upwards. |
|
2019 */ |
|
2020 void Q3ScrollView::scrollBy(int dx, int dy) |
|
2021 { |
|
2022 setContentsPos(QMAX(d->contentsX()+dx, 0), QMAX(d->contentsY()+dy, 0)); |
|
2023 } |
|
2024 |
|
2025 /*! |
|
2026 Scrolls the content so that the point (\a x, \a y) is in the center |
|
2027 of visible area. |
|
2028 */ |
|
2029 void Q3ScrollView::center(int x, int y) |
|
2030 { |
|
2031 ensureVisible(x, y, 32000, 32000); |
|
2032 } |
|
2033 |
|
2034 /*! |
|
2035 \overload |
|
2036 |
|
2037 Scrolls the content so that the point (\a x, \a y) is visible with |
|
2038 the \a xmargin and \a ymargin margins (as fractions of visible |
|
2039 the area). |
|
2040 |
|
2041 For example: |
|
2042 \list |
|
2043 \i Margin 0.0 allows (x, y) to be on the edge of the visible area. |
|
2044 \i Margin 0.5 ensures that (x, y) is in middle 50% of the visible area. |
|
2045 \i Margin 1.0 ensures that (x, y) is in the center of the visible area. |
|
2046 \endlist |
|
2047 */ |
|
2048 void Q3ScrollView::center(int x, int y, float xmargin, float ymargin) |
|
2049 { |
|
2050 int pw=visibleWidth(); |
|
2051 int ph=visibleHeight(); |
|
2052 ensureVisible(x, y, int(xmargin/2.0*pw+0.5), int(ymargin/2.0*ph+0.5)); |
|
2053 } |
|
2054 |
|
2055 |
|
2056 /*! |
|
2057 \fn void Q3ScrollView::contentsMoving(int x, int y) |
|
2058 |
|
2059 This signal is emitted just before the contents are moved to |
|
2060 position (\a x, \a y). |
|
2061 |
|
2062 \sa contentsX(), contentsY() |
|
2063 */ |
|
2064 |
|
2065 /*! |
|
2066 Moves the contents by (\a x, \a y). |
|
2067 */ |
|
2068 void Q3ScrollView::moveContents(int x, int y) |
|
2069 { |
|
2070 if (-x+visibleWidth() > d->contentsWidth()) |
|
2071 #if 0 |
|
2072 if(QApplication::reverseLayout()) |
|
2073 x=QMAX(0,-d->contentsWidth()+visibleWidth()); |
|
2074 else |
|
2075 #endif |
|
2076 x=QMIN(0,-d->contentsWidth()+visibleWidth()); |
|
2077 if (-y+visibleHeight() > contentsHeight()) |
|
2078 y=QMIN(0,-contentsHeight()+visibleHeight()); |
|
2079 |
|
2080 int dx = x - d->vx; |
|
2081 int dy = y - d->vy; |
|
2082 |
|
2083 if (!dx && !dy) |
|
2084 return; // Nothing to do |
|
2085 |
|
2086 emit contentsMoving(-x, -y); |
|
2087 |
|
2088 d->vx = x; |
|
2089 d->vy = y; |
|
2090 |
|
2091 if (d->clipped_viewport || d->static_bg) { |
|
2092 // Cheap move (usually) |
|
2093 d->moveAllBy(dx,dy); |
|
2094 } else if (/*dx && dy ||*/ |
|
2095 (QABS(dy) * 5 > visibleHeight() * 4) || |
|
2096 (QABS(dx) * 5 > visibleWidth() * 4) |
|
2097 ) |
|
2098 { |
|
2099 // Big move |
|
2100 if (viewport()->updatesEnabled()) |
|
2101 viewport()->update(); |
|
2102 d->moveAllBy(dx,dy); |
|
2103 } else if (!d->fake_scroll || d->contentsWidth() > visibleWidth()) { |
|
2104 // Small move |
|
2105 clipper()->scroll(dx,dy); |
|
2106 } |
|
2107 d->hideOrShowAll(this, true); |
|
2108 } |
|
2109 |
|
2110 /*! |
|
2111 \property Q3ScrollView::contentsX |
|
2112 \brief the X coordinate of the contents that are at the left edge of |
|
2113 the viewport. |
|
2114 */ |
|
2115 int Q3ScrollView::contentsX() const |
|
2116 { |
|
2117 return d->contentsX(); |
|
2118 } |
|
2119 |
|
2120 /*! |
|
2121 \property Q3ScrollView::contentsY |
|
2122 \brief the Y coordinate of the contents that are at the top edge of |
|
2123 the viewport. |
|
2124 */ |
|
2125 int Q3ScrollView::contentsY() const |
|
2126 { |
|
2127 return d->contentsY(); |
|
2128 } |
|
2129 |
|
2130 /*! |
|
2131 \property Q3ScrollView::contentsWidth |
|
2132 \brief the width of the contents area |
|
2133 */ |
|
2134 int Q3ScrollView::contentsWidth() const |
|
2135 { |
|
2136 return d->contentsWidth(); |
|
2137 } |
|
2138 |
|
2139 /*! |
|
2140 \property Q3ScrollView::contentsHeight |
|
2141 \brief the height of the contents area |
|
2142 */ |
|
2143 int Q3ScrollView::contentsHeight() const |
|
2144 { |
|
2145 return d->vheight; |
|
2146 } |
|
2147 |
|
2148 /*! |
|
2149 Sets the size of the contents area to \a w pixels wide and \a h |
|
2150 pixels high and updates the viewport accordingly. |
|
2151 */ |
|
2152 void Q3ScrollView::resizeContents(int w, int h) |
|
2153 { |
|
2154 int ow = d->vwidth; |
|
2155 int oh = d->vheight; |
|
2156 d->vwidth = w; |
|
2157 d->vheight = h; |
|
2158 |
|
2159 d->scrollbar_timer.start(0, true); |
|
2160 |
|
2161 if (d->children.isEmpty() && d->policy == Default) |
|
2162 setResizePolicy(Manual); |
|
2163 |
|
2164 if (ow > w) { |
|
2165 // Swap |
|
2166 int t=w; |
|
2167 w=ow; |
|
2168 ow=t; |
|
2169 } |
|
2170 // Refresh area ow..w |
|
2171 if (ow < visibleWidth() && w >= 0) { |
|
2172 if (ow < 0) |
|
2173 ow = 0; |
|
2174 if (w > visibleWidth()) |
|
2175 w = visibleWidth(); |
|
2176 clipper()->update(d->contentsX()+ow, 0, w-ow, visibleHeight()); |
|
2177 } |
|
2178 |
|
2179 if (oh > h) { |
|
2180 // Swap |
|
2181 int t=h; |
|
2182 h=oh; |
|
2183 oh=t; |
|
2184 } |
|
2185 // Refresh area oh..h |
|
2186 if (oh < visibleHeight() && h >= 0) { |
|
2187 if (oh < 0) |
|
2188 oh = 0; |
|
2189 if (h > visibleHeight()) |
|
2190 h = visibleHeight(); |
|
2191 clipper()->update(0, d->contentsY()+oh, visibleWidth(), h-oh); |
|
2192 } |
|
2193 } |
|
2194 |
|
2195 /*! |
|
2196 Calls update() on a rectangle defined by \a x, \a y, \a w, \a h, |
|
2197 translated appropriately. If the rectangle is not visible, nothing |
|
2198 is repainted. |
|
2199 |
|
2200 \sa repaintContents() |
|
2201 */ |
|
2202 void Q3ScrollView::updateContents(int x, int y, int w, int h) |
|
2203 { |
|
2204 if (!isVisible() || !updatesEnabled()) |
|
2205 return; |
|
2206 |
|
2207 QWidget* vp = viewport(); |
|
2208 |
|
2209 // Translate |
|
2210 x -= d->contentsX(); |
|
2211 y -= d->contentsY(); |
|
2212 |
|
2213 if (x < 0) { |
|
2214 w += x; |
|
2215 x = 0; |
|
2216 } |
|
2217 if (y < 0) { |
|
2218 h += y; |
|
2219 y = 0; |
|
2220 } |
|
2221 |
|
2222 if (w < 0 || h < 0) |
|
2223 return; |
|
2224 if (x > visibleWidth() || y > visibleHeight()) |
|
2225 return; |
|
2226 |
|
2227 if (w > visibleWidth()) |
|
2228 w = visibleWidth(); |
|
2229 if (h > visibleHeight()) |
|
2230 h = visibleHeight(); |
|
2231 |
|
2232 if (d->clipped_viewport) { |
|
2233 // Translate clipper() to viewport() |
|
2234 x -= d->clipped_viewport->x(); |
|
2235 y -= d->clipped_viewport->y(); |
|
2236 } |
|
2237 |
|
2238 vp->update(x, y, w, h); |
|
2239 } |
|
2240 |
|
2241 /*! |
|
2242 \overload |
|
2243 |
|
2244 Updates the contents in rectangle \a r |
|
2245 */ |
|
2246 void Q3ScrollView::updateContents(const QRect& r) |
|
2247 { |
|
2248 updateContents(r.x(), r.y(), r.width(), r.height()); |
|
2249 } |
|
2250 |
|
2251 /*! |
|
2252 \overload |
|
2253 */ |
|
2254 void Q3ScrollView::updateContents() |
|
2255 { |
|
2256 updateContents(d->contentsX(), d->contentsY(), visibleWidth(), visibleHeight()); |
|
2257 } |
|
2258 |
|
2259 /*! |
|
2260 \overload |
|
2261 |
|
2262 Repaints the contents of rectangle \a r. If \a erase is true the |
|
2263 background is cleared using the background color. |
|
2264 */ |
|
2265 void Q3ScrollView::repaintContents(const QRect& r, bool erase) |
|
2266 { |
|
2267 repaintContents(r.x(), r.y(), r.width(), r.height(), erase); |
|
2268 } |
|
2269 |
|
2270 |
|
2271 /*! |
|
2272 \overload |
|
2273 |
|
2274 Repaints the contents. If \a erase is true the background is |
|
2275 cleared using the background color. |
|
2276 */ |
|
2277 void Q3ScrollView::repaintContents(bool erase) |
|
2278 { |
|
2279 repaintContents(d->contentsX(), d->contentsY(), visibleWidth(), visibleHeight(), erase); |
|
2280 } |
|
2281 |
|
2282 |
|
2283 /*! |
|
2284 Calls repaint() on a rectangle defined by \a x, \a y, \a w, \a h, |
|
2285 translated appropriately. If the rectangle is not visible, nothing |
|
2286 is repainted. If \a erase is true the background is cleared using |
|
2287 the background color. |
|
2288 |
|
2289 \sa updateContents() |
|
2290 */ |
|
2291 void Q3ScrollView::repaintContents(int x, int y, int w, int h, bool /*erase*/) |
|
2292 { |
|
2293 if (!isVisible() || !updatesEnabled()) |
|
2294 return; |
|
2295 |
|
2296 QWidget* vp = viewport(); |
|
2297 |
|
2298 // Translate logical to clipper() |
|
2299 x -= d->contentsX(); |
|
2300 y -= d->contentsY(); |
|
2301 |
|
2302 if (x < 0) { |
|
2303 w += x; |
|
2304 x = 0; |
|
2305 } |
|
2306 if (y < 0) { |
|
2307 h += y; |
|
2308 y = 0; |
|
2309 } |
|
2310 |
|
2311 if (w < 0 || h < 0) |
|
2312 return; |
|
2313 if (w > visibleWidth()) |
|
2314 w = visibleWidth(); |
|
2315 if (h > visibleHeight()) |
|
2316 h = visibleHeight(); |
|
2317 |
|
2318 if (d->clipped_viewport) { |
|
2319 // Translate clipper() to viewport() |
|
2320 x -= d->clipped_viewport->x(); |
|
2321 y -= d->clipped_viewport->y(); |
|
2322 } |
|
2323 |
|
2324 vp->update(x, y, w, h); |
|
2325 } |
|
2326 |
|
2327 |
|
2328 /*! |
|
2329 For backward-compatibility only. It is easier to use |
|
2330 drawContents(QPainter*,int,int,int,int). |
|
2331 |
|
2332 The default implementation translates the painter appropriately |
|
2333 and calls drawContents(QPainter*,int,int,int,int). See |
|
2334 drawContents() for an explanation of the parameters \a p, \a |
|
2335 offsetx, \a offsety, \a clipx, \a clipy, \a clipw and \a cliph. |
|
2336 */ |
|
2337 void Q3ScrollView::drawContentsOffset(QPainter* p, int offsetx, int offsety, int clipx, int clipy, int clipw, int cliph) |
|
2338 { |
|
2339 p->translate(-offsetx,-offsety); |
|
2340 drawContents(p, clipx, clipy, clipw, cliph); |
|
2341 } |
|
2342 |
|
2343 /*! |
|
2344 \fn void Q3ScrollView::drawContents(QPainter* p, int clipx, int clipy, int clipw, int cliph) |
|
2345 |
|
2346 Reimplement this function if you are viewing a drawing area rather |
|
2347 than a widget. |
|
2348 |
|
2349 The function should draw the rectangle (\a clipx, \a clipy, \a |
|
2350 clipw, \a cliph) of the contents using painter \a p. The clip |
|
2351 rectangle is in the scrollview's coordinates. |
|
2352 |
|
2353 For example: |
|
2354 \snippet doc/src/snippets/code/src_qt3support_widgets_q3scrollview.cpp 4 |
|
2355 |
|
2356 The clip rectangle and translation of the painter \a p is already |
|
2357 set appropriately. |
|
2358 */ |
|
2359 void Q3ScrollView::drawContents(QPainter*, int, int, int, int) |
|
2360 { |
|
2361 } |
|
2362 |
|
2363 |
|
2364 /*! |
|
2365 \reimp |
|
2366 */ |
|
2367 void Q3ScrollView::frameChanged() |
|
2368 { |
|
2369 // slight ugle-hack - the listview header needs readjusting when |
|
2370 // changing the frame |
|
2371 if (Q3ListView *lv = qobject_cast<Q3ListView *>(this)) |
|
2372 lv->triggerUpdate(); |
|
2373 Q3Frame::frameChanged(); |
|
2374 updateScrollBars(); |
|
2375 } |
|
2376 |
|
2377 |
|
2378 /*! |
|
2379 Returns the viewport widget of the scrollview. This is the widget |
|
2380 containing the contents widget or which is the drawing area. |
|
2381 */ |
|
2382 QWidget* Q3ScrollView::viewport() const |
|
2383 { |
|
2384 if (d->clipped_viewport) |
|
2385 return d->clipped_viewport; |
|
2386 return d->viewport; |
|
2387 } |
|
2388 |
|
2389 /*! |
|
2390 Returns the clipper widget. Contents in the scrollview are |
|
2391 ultimately clipped to be inside the clipper widget. |
|
2392 |
|
2393 You should not need to use this function. |
|
2394 |
|
2395 \sa visibleWidth(), visibleHeight() |
|
2396 */ |
|
2397 QWidget* Q3ScrollView::clipper() const |
|
2398 { |
|
2399 return d->viewport; |
|
2400 } |
|
2401 |
|
2402 /*! |
|
2403 \property Q3ScrollView::visibleWidth |
|
2404 \brief the horizontal amount of the content that is visible |
|
2405 */ |
|
2406 int Q3ScrollView::visibleWidth() const |
|
2407 { |
|
2408 return clipper()->width(); |
|
2409 } |
|
2410 |
|
2411 /*! |
|
2412 \property Q3ScrollView::visibleHeight |
|
2413 \brief the vertical amount of the content that is visible |
|
2414 */ |
|
2415 int Q3ScrollView::visibleHeight() const |
|
2416 { |
|
2417 return clipper()->height(); |
|
2418 } |
|
2419 |
|
2420 |
|
2421 void Q3ScrollView::changeFrameRect(const QRect& r) |
|
2422 { |
|
2423 QRect oldr = frameRect(); |
|
2424 if (oldr != r) { |
|
2425 QRect cr = contentsRect(); |
|
2426 QRegion fr(frameRect()); |
|
2427 fr = fr.subtracted(contentsRect()); |
|
2428 setFrameRect(r); |
|
2429 if (isVisible()) { |
|
2430 cr = cr.intersected(contentsRect()); |
|
2431 fr = fr.united(frameRect()); |
|
2432 fr = fr.subtracted(cr); |
|
2433 if (!fr.isEmpty()) |
|
2434 update(fr); |
|
2435 } |
|
2436 } |
|
2437 } |
|
2438 |
|
2439 |
|
2440 /*! |
|
2441 Sets the margins around the scrolling area to \a left, \a top, \a |
|
2442 right and \a bottom. This is useful for applications such as |
|
2443 spreadsheets with "locked" rows and columns. The marginal space is |
|
2444 \e inside the frameRect() and is left blank; reimplement |
|
2445 drawFrame() or put widgets in the unused area. |
|
2446 |
|
2447 By default all margins are zero. |
|
2448 |
|
2449 \sa frameChanged() |
|
2450 */ |
|
2451 void Q3ScrollView::setMargins(int left, int top, int right, int bottom) |
|
2452 { |
|
2453 if (left == d->l_marg && |
|
2454 top == d->t_marg && |
|
2455 right == d->r_marg && |
|
2456 bottom == d->b_marg) |
|
2457 return; |
|
2458 |
|
2459 d->l_marg = left; |
|
2460 d->t_marg = top; |
|
2461 d->r_marg = right; |
|
2462 d->b_marg = bottom; |
|
2463 updateScrollBars(); |
|
2464 } |
|
2465 |
|
2466 |
|
2467 /*! |
|
2468 Returns the left margin. |
|
2469 |
|
2470 \sa setMargins() |
|
2471 */ |
|
2472 int Q3ScrollView::leftMargin() const |
|
2473 { |
|
2474 return d->l_marg; |
|
2475 } |
|
2476 |
|
2477 |
|
2478 /*! |
|
2479 Returns the top margin. |
|
2480 |
|
2481 \sa setMargins() |
|
2482 */ |
|
2483 int Q3ScrollView::topMargin() const |
|
2484 { |
|
2485 return d->t_marg; |
|
2486 } |
|
2487 |
|
2488 |
|
2489 /*! |
|
2490 Returns the right margin. |
|
2491 |
|
2492 \sa setMargins() |
|
2493 */ |
|
2494 int Q3ScrollView::rightMargin() const |
|
2495 { |
|
2496 return d->r_marg; |
|
2497 } |
|
2498 |
|
2499 |
|
2500 /*! |
|
2501 Returns the bottom margin. |
|
2502 |
|
2503 \sa setMargins() |
|
2504 */ |
|
2505 int Q3ScrollView::bottomMargin() const |
|
2506 { |
|
2507 return d->b_marg; |
|
2508 } |
|
2509 |
|
2510 /*! |
|
2511 \reimp |
|
2512 */ |
|
2513 bool Q3ScrollView::focusNextPrevChild(bool next) |
|
2514 { |
|
2515 // Makes sure that the new focus widget is on-screen, if |
|
2516 // necessary by scrolling the scroll view. |
|
2517 bool retval = Q3Frame::focusNextPrevChild(next); |
|
2518 if (retval) { |
|
2519 QWidget *w = window()->focusWidget(); |
|
2520 if (isAncestorOf(w)) { |
|
2521 QSVChildRec *r = d->ancestorRec(w); |
|
2522 if (r && (r->child == w || w->isVisibleTo(r->child))) { |
|
2523 QPoint cp = r->child->mapToGlobal(QPoint(0, 0)); |
|
2524 QPoint cr = w->mapToGlobal(QPoint(0, 0)) - cp; |
|
2525 ensureVisible(r->x + cr.x() + w->width()/2, r->y + cr.y() + w->height()/2, |
|
2526 w->width()/2, w->height()/2); |
|
2527 } |
|
2528 } |
|
2529 } |
|
2530 return retval; |
|
2531 } |
|
2532 |
|
2533 |
|
2534 |
|
2535 /*! |
|
2536 When a large numbers of child widgets are in a scrollview, |
|
2537 especially if they are close together, the scrolling performance |
|
2538 can suffer greatly. If \a y is true the scrollview will use an |
|
2539 extra widget to group child widgets. |
|
2540 |
|
2541 Note that you may only call enableClipper() prior to adding |
|
2542 widgets. |
|
2543 */ |
|
2544 void Q3ScrollView::enableClipper(bool y) |
|
2545 { |
|
2546 if (!d->clipped_viewport == !y) |
|
2547 return; |
|
2548 if (d->children.count()) |
|
2549 qFatal("May only call Q3ScrollView::enableClipper() before adding widgets"); |
|
2550 if (y) { |
|
2551 d->clipped_viewport = new QClipperWidget(clipper(), "qt_clipped_viewport", QFlag(d->flags)); |
|
2552 d->clipped_viewport->setGeometry(-coord_limit/2,-coord_limit/2, |
|
2553 coord_limit,coord_limit); |
|
2554 d->clipped_viewport->setBackgroundMode(d->viewport->backgroundMode()); |
|
2555 d->viewport->setBackgroundMode(NoBackground); // no exposures for this |
|
2556 d->viewport->removeEventFilter(this); |
|
2557 d->clipped_viewport->installEventFilter(this); |
|
2558 d->clipped_viewport->show(); |
|
2559 } else { |
|
2560 delete d->clipped_viewport; |
|
2561 d->clipped_viewport = 0; |
|
2562 } |
|
2563 } |
|
2564 |
|
2565 /*! |
|
2566 Sets the scrollview to have a static background if \a y is true, |
|
2567 or a scrolling background if \a y is false. By default, the |
|
2568 background is scrolling. |
|
2569 |
|
2570 Be aware that this mode is quite slow, as a full repaint of the |
|
2571 visible area has to be triggered on every contents move. |
|
2572 |
|
2573 \sa hasStaticBackground() |
|
2574 */ |
|
2575 void Q3ScrollView::setStaticBackground(bool y) |
|
2576 { |
|
2577 d->static_bg = y; |
|
2578 } |
|
2579 |
|
2580 /*! |
|
2581 Returns true if Q3ScrollView uses a static background; otherwise |
|
2582 returns false. |
|
2583 |
|
2584 \sa setStaticBackground() |
|
2585 */ |
|
2586 bool Q3ScrollView::hasStaticBackground() const |
|
2587 { |
|
2588 return d->static_bg; |
|
2589 } |
|
2590 |
|
2591 /*! |
|
2592 \overload |
|
2593 |
|
2594 Returns the point \a p translated to a point on the viewport() |
|
2595 widget. |
|
2596 */ |
|
2597 QPoint Q3ScrollView::contentsToViewport(const QPoint& p) const |
|
2598 { |
|
2599 if (d->clipped_viewport) { |
|
2600 return QPoint(p.x() - d->contentsX() - d->clipped_viewport->x(), |
|
2601 p.y() - d->contentsY() - d->clipped_viewport->y()); |
|
2602 } else { |
|
2603 return QPoint(p.x() - d->contentsX(), |
|
2604 p.y() - d->contentsY()); |
|
2605 } |
|
2606 } |
|
2607 |
|
2608 /*! |
|
2609 \overload |
|
2610 |
|
2611 Returns the point on the viewport \a vp translated to a point in |
|
2612 the contents. |
|
2613 */ |
|
2614 QPoint Q3ScrollView::viewportToContents(const QPoint& vp) const |
|
2615 { |
|
2616 if (d->clipped_viewport) { |
|
2617 return QPoint(vp.x() + d->contentsX() + d->clipped_viewport->x(), |
|
2618 vp.y() + d->contentsY() + d->clipped_viewport->y()); |
|
2619 } else { |
|
2620 return QPoint(vp.x() + d->contentsX(), |
|
2621 vp.y() + d->contentsY()); |
|
2622 } |
|
2623 } |
|
2624 |
|
2625 |
|
2626 /*! |
|
2627 Translates a point (\a x, \a y) in the contents to a point (\a vx, |
|
2628 \a vy) on the viewport() widget. |
|
2629 */ |
|
2630 void Q3ScrollView::contentsToViewport(int x, int y, int& vx, int& vy) const |
|
2631 { |
|
2632 const QPoint v = contentsToViewport(QPoint(x,y)); |
|
2633 vx = v.x(); |
|
2634 vy = v.y(); |
|
2635 } |
|
2636 |
|
2637 /*! |
|
2638 Translates a point (\a vx, \a vy) on the viewport() widget to a |
|
2639 point (\a x, \a y) in the contents. |
|
2640 */ |
|
2641 void Q3ScrollView::viewportToContents(int vx, int vy, int& x, int& y) const |
|
2642 { |
|
2643 const QPoint c = viewportToContents(QPoint(vx,vy)); |
|
2644 x = c.x(); |
|
2645 y = c.y(); |
|
2646 } |
|
2647 |
|
2648 /*! |
|
2649 \reimp |
|
2650 */ |
|
2651 QSize Q3ScrollView::sizeHint() const |
|
2652 { |
|
2653 if (d->use_cached_size_hint && d->cachedSizeHint.isValid()) |
|
2654 return d->cachedSizeHint; |
|
2655 |
|
2656 constPolish(); |
|
2657 int f = 2 * frameWidth(); |
|
2658 int h = fontMetrics().height(); |
|
2659 QSize sz(f, f); |
|
2660 if (d->policy > Manual) { |
|
2661 QSVChildRec *r = d->children.first(); |
|
2662 if (r) { |
|
2663 QSize cs = r->child->sizeHint(); |
|
2664 if (cs.isValid()) |
|
2665 sz += cs.boundedTo(r->child->maximumSize()); |
|
2666 else |
|
2667 sz += r->child->size(); |
|
2668 } |
|
2669 } else { |
|
2670 sz += QSize(d->contentsWidth(), contentsHeight()); |
|
2671 } |
|
2672 if (d->vMode == AlwaysOn) |
|
2673 sz.setWidth(sz.width() + d->vbar->sizeHint().width()); |
|
2674 if (d->hMode == AlwaysOn) |
|
2675 sz.setHeight(sz.height() + d->hbar->sizeHint().height()); |
|
2676 return sz.expandedTo(QSize(12 * h, 8 * h)) |
|
2677 .boundedTo(QSize(36 * h, 24 * h)); |
|
2678 } |
|
2679 |
|
2680 |
|
2681 /*! |
|
2682 \reimp |
|
2683 */ |
|
2684 QSize Q3ScrollView::minimumSizeHint() const |
|
2685 { |
|
2686 int h = fontMetrics().height(); |
|
2687 if (h < 10) |
|
2688 h = 10; |
|
2689 int f = 2 * frameWidth(); |
|
2690 return QSize((6 * h) + f, (4 * h) + f); |
|
2691 } |
|
2692 |
|
2693 |
|
2694 /*! |
|
2695 \reimp |
|
2696 |
|
2697 (Implemented to get rid of a compiler warning.) |
|
2698 */ |
|
2699 void Q3ScrollView::drawContents(QPainter *) |
|
2700 { |
|
2701 } |
|
2702 |
|
2703 #ifndef QT_NO_DRAGANDDROP |
|
2704 |
|
2705 /*! |
|
2706 \internal |
|
2707 */ |
|
2708 void Q3ScrollView::startDragAutoScroll() |
|
2709 { |
|
2710 if (!d->autoscroll_timer.isActive()) { |
|
2711 d->autoscroll_time = initialScrollTime; |
|
2712 d->autoscroll_accel = initialScrollAccel; |
|
2713 d->autoscroll_timer.start(d->autoscroll_time); |
|
2714 } |
|
2715 } |
|
2716 |
|
2717 |
|
2718 /*! |
|
2719 \internal |
|
2720 */ |
|
2721 void Q3ScrollView::stopDragAutoScroll() |
|
2722 { |
|
2723 d->autoscroll_timer.stop(); |
|
2724 } |
|
2725 |
|
2726 |
|
2727 /*! |
|
2728 \internal |
|
2729 */ |
|
2730 void Q3ScrollView::doDragAutoScroll() |
|
2731 { |
|
2732 QPoint p = d->viewport->mapFromGlobal(QCursor::pos()); |
|
2733 |
|
2734 if (d->autoscroll_accel-- <= 0 && d->autoscroll_time) { |
|
2735 d->autoscroll_accel = initialScrollAccel; |
|
2736 d->autoscroll_time--; |
|
2737 d->autoscroll_timer.start(d->autoscroll_time); |
|
2738 } |
|
2739 int l = QMAX(1, (initialScrollTime- d->autoscroll_time)); |
|
2740 |
|
2741 int dx = 0, dy = 0; |
|
2742 if (p.y() < autoscroll_margin) { |
|
2743 dy = -l; |
|
2744 } else if (p.y() > visibleHeight() - autoscroll_margin) { |
|
2745 dy = +l; |
|
2746 } |
|
2747 if (p.x() < autoscroll_margin) { |
|
2748 dx = -l; |
|
2749 } else if (p.x() > visibleWidth() - autoscroll_margin) { |
|
2750 dx = +l; |
|
2751 } |
|
2752 if (dx || dy) { |
|
2753 scrollBy(dx,dy); |
|
2754 } else { |
|
2755 stopDragAutoScroll(); |
|
2756 } |
|
2757 } |
|
2758 |
|
2759 |
|
2760 /*! |
|
2761 \property Q3ScrollView::dragAutoScroll |
|
2762 \brief whether autoscrolling in drag move events is enabled |
|
2763 |
|
2764 If this property is set to true (the default), the Q3ScrollView |
|
2765 automatically scrolls the contents in drag move events if the user |
|
2766 moves the cursor close to a border of the view. Of course this |
|
2767 works only if the viewport accepts drops. Specifying false |
|
2768 disables this autoscroll feature. |
|
2769 */ |
|
2770 |
|
2771 void Q3ScrollView::setDragAutoScroll(bool b) |
|
2772 { |
|
2773 d->drag_autoscroll = b; |
|
2774 } |
|
2775 |
|
2776 bool Q3ScrollView::dragAutoScroll() const |
|
2777 { |
|
2778 return d->drag_autoscroll; |
|
2779 } |
|
2780 |
|
2781 #endif // QT_NO_DRAGANDDROP |
|
2782 |
|
2783 /*!\internal |
|
2784 */ |
|
2785 void Q3ScrollView::setCachedSizeHint(const QSize &sh) const |
|
2786 { |
|
2787 if (isVisible() && !d->cachedSizeHint.isValid()) |
|
2788 d->cachedSizeHint = sh; |
|
2789 } |
|
2790 |
|
2791 /*!\internal |
|
2792 */ |
|
2793 void Q3ScrollView::disableSizeHintCaching() |
|
2794 { |
|
2795 d->use_cached_size_hint = false; |
|
2796 } |
|
2797 |
|
2798 /*!\internal |
|
2799 */ |
|
2800 QSize Q3ScrollView::cachedSizeHint() const |
|
2801 { |
|
2802 return d->use_cached_size_hint ? d->cachedSizeHint : QSize(); |
|
2803 } |
|
2804 |
|
2805 QT_END_NAMESPACE |
|
2806 |
|
2807 #endif // QT_NO_SCROLLVIEW |