3 Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
10 1. Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #define DEBUG_KP_VIEW_SCROLLABLE_CONTAINER 0
30 #include <kpViewScrollableContainer.h>
44 #include <kpPixmapFX.h>
46 #include <kpWidgetMapper.h>
49 // (Pulled from out of Thurston's hat)
50 static const int DragScrollLeftTopMargin
= 0;
51 static const int DragScrollRightBottomMargin
= 16; // scrollbarish
52 static const int DragScrollInterval
= 150;
53 static const int DragScrollInitialInterval
= DragScrollInterval
* 2;
54 static const int DragScrollNumPixels
= 10;
55 static const int DragDistanceFromRectMaxFor1stMultiplier
= 50;
56 static const int DragDistanceFromRectMaxFor2ndMultiplier
= 100;
58 static const int GripHandleSize
= 7;
61 const int kpGrip::Size
= 7;
64 kpGrip::kpGrip (GripType type
, QWidget
*parent
)
67 m_startPoint (KP_INVALID_POINT
),
68 m_currentPoint (KP_INVALID_POINT
),
69 m_shouldReleaseMouseButtons (false)
71 setCursor (cursorForType (m_type
));
73 setMouseTracking (true); // mouseMoveEvent's even when no mousebtn down
84 kpGrip::GripType
kpGrip::type () const
91 QCursor
kpGrip::cursorForType (GripType type
)
96 return Qt::SizeVerCursor
;
97 break; // one day you'll forget
100 return Qt::SizeHorCursor
;
101 break; // one day you'll forget
103 case kpGrip::BottomRight
:
104 return Qt::SizeFDiagCursor
;
105 break; // one day you'll forget
108 return Qt::ArrowCursor
;
113 QRect
kpGrip::hotRect (bool toGlobal
) const
121 const int handleX
= (width () - GripHandleSize
) / 2;
122 ret
= QRect (handleX
, 0,
123 GripHandleSize
, height ());
128 const int handleY
= (height () - GripHandleSize
) / 2;
129 ret
= QRect (0, handleY
,
130 width (), GripHandleSize
);
133 case kpGrip::BottomRight
:
142 return (toGlobal
? QRect (mapToGlobal (ret
.topLeft ()),
143 mapToGlobal (ret
.bottomRight ()))
149 bool kpGrip::isDrawing () const
151 return (m_startPoint
!= KP_INVALID_POINT
);
156 QString
kpGrip::haventBegunDrawUserMessage () const
158 return i18n ("Left drag the handle to resize the image.");
163 QString
kpGrip::userMessage () const
165 return m_userMessage
;
169 void kpGrip::setUserMessage (const QString
&message
)
171 // Don't do NOP checking here since another grip might have changed
172 // the message so an apparent NOP for this grip is not a NOP in the
173 // global sense (kpViewScrollableContainer::slotGripStatusMessageChanged()).
175 m_userMessage
= message
;
176 emit
statusMessageChanged (message
);
181 void kpGrip::updatePixmap ()
183 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
184 kDebug () << "kpGrip::updatePixmap() rect=" << rect ();
186 if (width () <= 0 || height () <= 0)
189 QPixmap
pixmap (width (), height ());
190 kpPixmapFX::ensureTransparentAt (&pixmap
, pixmap
.rect ());
192 const QRect hr
= hotRect ();
193 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
194 kDebug () << "\thotRect=" << hr
;
198 const QColor col
= palette ().color (QPalette::Highlight
);
199 if (col
.alpha () > 0)
201 // Note that we nuke the color's alpha (QColor::rgb()) since
202 // kpPixmapFX methods can't handle it.
203 kpPixmapFX::fillRect (&pixmap
,
204 hr
.x (), hr
.y (), hr
.width (), hr
.height (),
205 kpColor (col
.rgb ()));
209 // You have a crazy color palette with a transparent highlight
210 // color. Our pixmap is fully transparent already so nothing
216 setMask (pixmap
.mask ());
221 void kpGrip::cancel ()
223 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
224 kDebug () << "kpGrip::cancel()";
226 if (m_currentPoint
== KP_INVALID_POINT
)
229 m_startPoint
= KP_INVALID_POINT
;
230 m_currentPoint
= KP_INVALID_POINT
;
232 setUserMessage (i18n ("Resize Image: Let go of all the mouse buttons."));
233 setCursor (Qt::ArrowCursor
);
234 m_shouldReleaseMouseButtons
= true;
237 emit
cancelledDraw ();
241 // protected virtual [base QWidget]
242 void kpGrip::keyReleaseEvent (QKeyEvent
*e
)
244 if (m_startPoint
!= KP_INVALID_POINT
&&
245 e
->key () == Qt::Key_Escape
)
251 // protected virtual [base QWidget]
252 void kpGrip::mousePressEvent (QMouseEvent
*e
)
254 if (m_startPoint
== KP_INVALID_POINT
&&
255 (e
->buttons () & Qt::MouseButtonMask
) == Qt::LeftButton
)
257 m_startPoint
= e
->pos ();
258 m_currentPoint
= e
->pos ();
262 setUserMessage (i18n ("Resize Image: Right click to cancel."));
263 setCursor (cursorForType (m_type
));
267 if (m_startPoint
!= KP_INVALID_POINT
)
273 QPoint
kpGrip::viewDeltaPoint () const
275 if (m_startPoint
== KP_INVALID_POINT
)
276 return KP_INVALID_POINT
;
278 const QPoint point
= mapFromGlobal (QCursor::pos ());
280 // TODO: this is getting out of sync with m_currentPoint
282 return QPoint (((m_type
& kpGrip::Right
) ? point
.x () - m_startPoint
.x () : 0),
283 ((m_type
& kpGrip::Bottom
) ? point
.y () - m_startPoint
.y () : 0));
288 void kpGrip::mouseMovedTo (const QPoint
&point
, bool dueToDragScroll
)
290 if (m_startPoint
== KP_INVALID_POINT
)
293 m_currentPoint
= point
;
295 emit
continuedDraw (((m_type
& kpGrip::Right
) ? point
.x () - m_startPoint
.x () : 0),
296 ((m_type
& kpGrip::Bottom
) ? point
.y () - m_startPoint
.y () : 0),
300 // protected virtual [base QWidget]
301 void kpGrip::mouseMoveEvent (QMouseEvent
*e
)
303 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
304 kDebug () << "kpGrip::mouseMoveEvent() m_startPoint=" << m_startPoint
305 << " stateAfter: buttons=" << (int *) (int) e
->buttons ()
309 if (m_startPoint
== KP_INVALID_POINT
)
311 if ((e
->buttons () & Qt::MouseButtonMask
) == 0)
312 setUserMessage (haventBegunDrawUserMessage ());
316 mouseMovedTo (e
->pos (), false/*not due to drag scroll*/);
319 // protected virtual [base QWidget]
320 void kpGrip::mouseReleaseEvent (QMouseEvent
*e
)
322 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
323 kDebug () << "kpGrip::mouseReleaseEvent() m_startPoint=" << m_startPoint
324 << " stateAfter: buttons=" << (int *) (int) e
->buttons ()
328 if (m_startPoint
!= KP_INVALID_POINT
)
330 const int dx
= m_currentPoint
.x () - m_startPoint
.x (),
331 dy
= m_currentPoint
.y () - m_startPoint
.y ();
333 m_currentPoint
= KP_INVALID_POINT
;
334 m_startPoint
= KP_INVALID_POINT
;
337 emit
endedDraw ((m_type
& kpGrip::Right
) ? dx
: 0,
338 (m_type
& kpGrip::Bottom
) ? dy
: 0);
341 if ((e
->buttons () & Qt::MouseButtonMask
) == 0)
343 m_shouldReleaseMouseButtons
= false;
344 setUserMessage (QString::null
); //krazy:exclude=nullstrassigment for old broken gcc
345 setCursor (cursorForType (m_type
));
348 emit
releasedAllButtons ();
353 // protected virtual [base QWidget]
354 void kpGrip::resizeEvent (QResizeEvent
*)
356 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
357 kDebug () << "kpGrip::resizeEvent()";
363 // protected virtual [base QWidget]
364 void kpGrip::enterEvent (QEvent
* /*e*/)
366 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
367 kDebug () << "kpGrip::enterEvent()"
368 << " m_startPoint=" << m_startPoint
369 << " shouldReleaseMouseButtons="
370 << m_shouldReleaseMouseButtons
<< endl
;
373 if (m_startPoint
== KP_INVALID_POINT
&&
374 !m_shouldReleaseMouseButtons
)
376 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
377 kDebug () << "\tsending message";
379 setUserMessage (haventBegunDrawUserMessage ());
383 // protected virtual [base QWidget]
384 void kpGrip::leaveEvent (QEvent
* /*e*/)
386 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
387 kDebug () << "kpGrip::leaveEvent()"
388 << " m_startPoint=" << m_startPoint
389 << " shouldReleaseMouseButtons="
390 << m_shouldReleaseMouseButtons
<< endl
;
392 if (m_startPoint
== KP_INVALID_POINT
&&
393 !m_shouldReleaseMouseButtons
)
395 setUserMessage (QString::null
); //krazy:exclude=nullstrassigment for old broken gcc
400 // protected virtual [base QWidget]
401 void kpGrip::paintEvent (QPaintEvent
*e
)
403 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 0
404 kDebug () << "kpGrip::paintEvent(" << e
->rect () << ")";
406 QLabel::paintEvent (e
);
410 // TODO: Are we checking for m_view == 0 often enough? Also an issue in KDE 3.
411 kpViewScrollableContainer::kpViewScrollableContainer (kpMainWindow
*parent
)
412 : Q3ScrollView ((QWidget
*) parent
),
413 m_mainWindow (parent
),
414 m_contentsXSoon (-1), m_contentsYSoon (-1),
416 m_bottomGrip (new kpGrip (kpGrip::Bottom
, viewport ())),
417 m_rightGrip (new kpGrip (kpGrip::Right
, viewport ())),
418 m_bottomRightGrip (new kpGrip (kpGrip::BottomRight
, viewport ())),
419 m_docResizingGrip (0),
420 m_dragScrollTimer (new QTimer (this)),
422 m_scrollTimerRunOnce (false),
423 m_resizeRoundedLastViewX (-1), m_resizeRoundedLastViewY (-1),
424 m_resizeRoundedLastViewDX (0), m_resizeRoundedLastViewDY (0),
425 m_haveMovedFromOriginalDocSize (false)
428 m_bottomGrip
->setObjectName ("Bottom Grip");
429 m_rightGrip
->setObjectName ("Right Grip");
430 m_bottomRightGrip
->setObjectName ("BottomRight Grip");
432 // HITODO: drawResizeLines() uses this feature -- it therefore
433 // flickers and only works on X11. Fix drawResizeLines()
434 // to remove the need for these attributes.
435 viewport ()->setAttribute (Qt::WA_PaintOutsidePaintEvent
);
436 viewport ()->setAttribute (Qt::WA_PaintUnclipped
);
438 m_bottomGrip
->setFixedHeight (kpGrip::Size
);
439 m_bottomGrip
->hide ();
440 addChild (m_bottomGrip
);
441 connectGripSignals (m_bottomGrip
);
443 m_rightGrip
->setFixedWidth (kpGrip::Size
);
444 m_rightGrip
->hide ();
445 addChild (m_rightGrip
);
446 connectGripSignals (m_rightGrip
);
448 m_bottomRightGrip
->setFixedSize (kpGrip::Size
, kpGrip::Size
);
449 m_bottomRightGrip
->hide ();
450 addChild (m_bottomRightGrip
);
451 connectGripSignals (m_bottomRightGrip
);
454 connect (this, SIGNAL (contentsMoving (int, int)),
455 this, SLOT (slotContentsMoving (int, int)));
457 connect (m_dragScrollTimer
, SIGNAL (timeout ()),
458 this, SLOT (slotDragScroll ()));
461 kpViewScrollableContainer::~kpViewScrollableContainer ()
467 int kpViewScrollableContainer::contentsXSoon ()
469 if (m_contentsXSoon
< 0)
472 return m_contentsXSoon
;
476 int kpViewScrollableContainer::contentsYSoon ()
478 if (m_contentsYSoon
< 0)
481 return m_contentsYSoon
;
486 void kpViewScrollableContainer::connectGripSignals (kpGrip
*grip
)
488 connect (grip
, SIGNAL (beganDraw ()),
489 this, SLOT (slotGripBeganDraw ()));
490 connect (grip
, SIGNAL (continuedDraw (int, int, bool)),
491 this, SLOT (slotGripContinuedDraw (int, int, bool)));
492 connect (grip
, SIGNAL (cancelledDraw ()),
493 this, SLOT (slotGripCancelledDraw ()));
494 connect (grip
, SIGNAL (endedDraw (int, int)),
495 this, SLOT (slotGripEndedDraw (int, int)));
497 connect (grip
, SIGNAL (statusMessageChanged (const QString
&)),
498 this, SLOT (slotGripStatusMessageChanged (const QString
&)));
500 connect (grip
, SIGNAL (releasedAllButtons ()),
501 this, SLOT (recalculateStatusMessage ()));
506 QSize
kpViewScrollableContainer::newDocSize () const
508 return newDocSize (m_resizeRoundedLastViewDX
,
509 m_resizeRoundedLastViewDY
);
513 bool kpViewScrollableContainer::haveMovedFromOriginalDocSize () const
515 return m_haveMovedFromOriginalDocSize
;
519 QString
kpViewScrollableContainer::statusMessage () const
521 return m_gripStatusMessage
;
525 void kpViewScrollableContainer::clearStatusMessage ()
527 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 1
528 kDebug () << "kpViewScrollableContainer::clearStatusMessage()";
530 m_bottomRightGrip
->setUserMessage (QString::null
); //krazy:exclude=nullstrassigment for old broken gcc
531 m_bottomGrip
->setUserMessage (QString::null
); //krazy:exclude=nullstrassigment for old broken gcc
532 m_rightGrip
->setUserMessage (QString::null
); //krazy:exclude=nullstrassigment for old broken gcc
536 QSize
kpViewScrollableContainer::newDocSize (int viewDX
, int viewDY
) const
541 if (!docResizingGrip ())
544 const int docX
= (int) m_view
->transformViewToDocX (m_view
->width () + viewDX
);
545 const int docY
= (int) m_view
->transformViewToDocY (m_view
->height () + viewDY
);
547 return QSize (qMax (1, docX
), qMax (1, docY
));
552 void kpViewScrollableContainer::calculateDocResizingGrip ()
554 if (m_bottomRightGrip
->isDrawing ())
555 m_docResizingGrip
= m_bottomRightGrip
;
556 else if (m_bottomGrip
->isDrawing ())
557 m_docResizingGrip
= m_bottomGrip
;
558 else if (m_rightGrip
->isDrawing ())
559 m_docResizingGrip
= m_rightGrip
;
561 m_docResizingGrip
= 0;
565 kpGrip
*kpViewScrollableContainer::docResizingGrip () const
567 return m_docResizingGrip
;
572 int kpViewScrollableContainer::bottomResizeLineWidth () const
574 if (!docResizingGrip ())
580 if (docResizingGrip ()->type () & kpGrip::Bottom
)
581 return qMax (m_view
->zoomLevelY () / 100, 1);
587 int kpViewScrollableContainer::rightResizeLineWidth () const
589 if (!docResizingGrip ())
595 if (docResizingGrip ()->type () & kpGrip::Right
)
596 return qMax (m_view
->zoomLevelX () / 100, 1);
603 QRect
kpViewScrollableContainer::bottomResizeLineRect () const
605 if (m_resizeRoundedLastViewX
< 0 || m_resizeRoundedLastViewY
< 0)
608 QRect visibleArea
= QRect(QPoint(contentsX(),contentsY()), viewport()->size());
610 return QRect (QPoint (0,
611 m_resizeRoundedLastViewY
),
612 QPoint (m_resizeRoundedLastViewX
- 1,
613 m_resizeRoundedLastViewY
+ bottomResizeLineWidth () - 1)).intersected(visibleArea
);
617 QRect
kpViewScrollableContainer::rightResizeLineRect () const
619 if (m_resizeRoundedLastViewX
< 0 || m_resizeRoundedLastViewY
< 0)
622 QRect visibleArea
= QRect(QPoint(contentsX(),contentsY()), viewport()->size());
624 return QRect (QPoint (m_resizeRoundedLastViewX
,
626 QPoint (m_resizeRoundedLastViewX
+ rightResizeLineWidth () - 1,
627 m_resizeRoundedLastViewY
- 1)).intersected(visibleArea
);
631 QRect
kpViewScrollableContainer::bottomRightResizeLineRect () const
633 if (m_resizeRoundedLastViewX
< 0 || m_resizeRoundedLastViewY
< 0)
636 QRect visibleArea
= QRect(QPoint(contentsX(),contentsY()), viewport()->size());
638 return QRect (QPoint (m_resizeRoundedLastViewX
,
639 m_resizeRoundedLastViewY
),
640 QPoint (m_resizeRoundedLastViewX
+ rightResizeLineWidth () - 1,
641 m_resizeRoundedLastViewY
+ bottomResizeLineWidth () - 1)).intersected(visibleArea
);
645 // TODO: are these 2 correct? Remember that viewport()->x() == 1, viewport()->y() == 1
648 QPoint
kpViewScrollableContainer::mapViewToViewport (const QPoint
&viewPoint
)
650 return viewPoint
- QPoint (contentsX (), contentsY ());
654 QRect
kpViewScrollableContainer::mapViewToViewport (const QRect
&viewRect
)
656 if (!viewRect
.isValid ())
659 QRect ret
= viewRect
;
660 ret
.translate (-contentsX (), -contentsY ());
666 QRect
kpViewScrollableContainer::mapViewportToGlobal (const QRect
&viewportRect
)
668 return kpWidgetMapper::toGlobal (viewport (), viewportRect
);
672 QRect
kpViewScrollableContainer::mapViewToGlobal (const QRect
&viewRect
)
674 return mapViewportToGlobal (mapViewToViewport (viewRect
));
679 void kpViewScrollableContainer::repaintWidgetAtResizeLineViewRect (
680 QWidget
*widget
, const QRect
&resizeLineViewRect
)
682 const QRect resizeLineGlobalRect
= mapViewToGlobal (resizeLineViewRect
);
683 const QRect widgetGlobalRect
= kpWidgetMapper::toGlobal (widget
,
686 const QRect redrawGlobalRect
=
687 resizeLineGlobalRect
.intersect (widgetGlobalRect
);
689 const QRect redrawWidgetRect
=
690 kpWidgetMapper::fromGlobal (widget
, redrawGlobalRect
);
693 if (redrawWidgetRect
.isValid ())
695 widget
->repaint (redrawWidgetRect
);
700 void kpViewScrollableContainer::repaintWidgetAtResizeLines (QWidget
*widget
)
702 repaintWidgetAtResizeLineViewRect (widget
, rightResizeLineRect ());
703 repaintWidgetAtResizeLineViewRect (widget
, bottomResizeLineRect ());
704 repaintWidgetAtResizeLineViewRect (widget
, bottomRightResizeLineRect ());
708 void kpViewScrollableContainer::eraseResizeLines ()
710 if (m_resizeRoundedLastViewX
>= 0 && m_resizeRoundedLastViewY
>= 0)
712 repaintWidgetAtResizeLines (viewport ());
713 repaintWidgetAtResizeLines (m_view
);
715 repaintWidgetAtResizeLines (m_bottomGrip
);
716 repaintWidgetAtResizeLines (m_rightGrip
);
717 repaintWidgetAtResizeLines (m_bottomRightGrip
);
723 void kpViewScrollableContainer::drawResizeLines ()
725 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 0
726 kDebug () << "kpViewScrollableContainer::drawResizeLines()"
727 << " lastViewX=" << m_resizeRoundedLastViewX
728 << " lastViewY=" << m_resizeRoundedLastViewY
733 // TODO: If XRENDER is disabled, this painting with Qt::WA_PaintUnclipped
734 // seems to trigger a harmless, asynchronous error:
736 // X Error: RenderBadPicture (invalid Picture parameter) 180
737 // Extension: 153 (RENDER)
738 // Minor opcode: 5 (RenderChangePicture)
741 // I don't know what code is _directly_ triggering that error -- running
742 // KolourPaint with "-sync" doesn't seem to make the error synchronous.
744 // The API doc for Qt::WA_PaintUnclipped says "This flag is only
745 // supported for widgets for which the WA_PaintOnScreen". We don't
746 // actually enable "WA_PaintOnScreen" (which looks quite scary), so that
747 // might be part of the cause.
748 #define FILL_NOT_RECT(rect) \
749 kpPixmapFX::widgetFillNOTRect (viewport (), \
750 rect.x (), rect.y (), rect.width (), rect.height (), \
751 kpColor::Black/*1st hint color if "Raster NOT" not supported*/, \
752 kpColor::White/*2nd hint color if "Raster NOT" not supported*/)
754 const QRect rightRect
= rightResizeLineRect ();
755 if (rightRect
.isValid ())
756 FILL_NOT_RECT (mapViewToViewport (rightRect
));
758 const QRect bottomRect
= bottomResizeLineRect ();
759 if (bottomRect
.isValid ())
760 FILL_NOT_RECT (mapViewToViewport (bottomRect
));
762 const QRect bottomRightRect
= bottomRightResizeLineRect ();
763 if (bottomRightRect
.isValid ())
764 FILL_NOT_RECT (mapViewToViewport (bottomRightRect
));
771 void kpViewScrollableContainer::updateResizeLines (int viewX
, int viewY
,
772 int viewDX
, int viewDY
)
774 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 0
775 kDebug () << "kpViewScrollableContainer::updateResizeLines("
776 << viewX
<< "," << viewY
<< ")"
777 << " oldViewX=" << m_resizeRoundedLastViewX
778 << " oldViewY=" << m_resizeRoundedLastViewY
779 << " viewDX=" << viewDX
780 << " viewDY=" << viewDY
787 if (viewX
>= 0 && viewY
>= 0)
789 m_resizeRoundedLastViewX
= (int) m_view
->transformDocToViewX ((int) m_view
->transformViewToDocX (viewX
));
790 m_resizeRoundedLastViewY
= (int) m_view
->transformDocToViewY ((int) m_view
->transformViewToDocY (viewY
));
792 m_resizeRoundedLastViewDX
= viewDX
;
793 m_resizeRoundedLastViewDY
= viewDY
;
797 m_resizeRoundedLastViewX
= -1;
798 m_resizeRoundedLastViewY
= -1;
800 m_resizeRoundedLastViewDX
= 0;
801 m_resizeRoundedLastViewDY
= 0;
804 // TODO: This is suboptimal since if another window pops up on top of
805 // KolourPaint then disappears, the lines are not redrawn
806 // (although this doesn't happen very frequently since we grab the
807 // keyboard and mouse when resizing):
809 // e.g. sleep 5 && gedit & sleep 10 && killall gedit
811 // Should be done in the paintEvent's of every child of the
818 void kpViewScrollableContainer::slotGripBeganDraw ()
823 calculateDocResizingGrip ();
825 m_haveMovedFromOriginalDocSize
= false;
827 updateResizeLines (m_view
->width (), m_view
->height (),
828 0/*viewDX*/, 0/*viewDY*/);
830 emit
beganDocResize ();
834 void kpViewScrollableContainer::slotGripContinuedDraw (int inViewDX
, int inViewDY
,
835 bool dueToDragScroll
)
837 int viewDX
= inViewDX
,
840 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
841 kDebug () << "kpViewScrollableContainer::slotGripContinuedDraw("
842 << viewDX
<< "," << viewDY
<< ") size="
843 << newDocSize (viewDX
, viewDY
)
844 << " dueToDragScroll=" << dueToDragScroll
851 if (!dueToDragScroll
&&
852 beginDragScroll (QPoint (), QPoint (), m_view
->zoomLevelX ()))
854 const QPoint newViewDeltaPoint
= docResizingGrip ()->viewDeltaPoint ();
855 viewDX
= newViewDeltaPoint
.x ();
856 viewDY
= newViewDeltaPoint
.y ();
857 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
858 kDebug () << "\tdrag scrolled - new view delta point="
864 m_haveMovedFromOriginalDocSize
= true;
866 updateResizeLines (qMax (1, qMax (m_view
->width () + viewDX
, (int) m_view
->transformDocToViewX (1))),
867 qMax (1, qMax (m_view
->height () + viewDY
, (int) m_view
->transformDocToViewY (1))),
870 emit
continuedDocResize (newDocSize ());
874 void kpViewScrollableContainer::slotGripCancelledDraw ()
876 m_haveMovedFromOriginalDocSize
= false;
878 updateResizeLines (-1, -1, 0, 0);
880 calculateDocResizingGrip ();
882 emit
cancelledDocResize ();
888 void kpViewScrollableContainer::slotGripEndedDraw (int viewDX
, int viewDY
)
890 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
891 kDebug () << "kpViewScrollableContainer::slotGripEndedDraw("
892 << viewDX
<< "," << viewDY
<< ") size="
893 << newDocSize (viewDX
, viewDY
)
900 const QSize newSize
= newDocSize (viewDX
, viewDY
);
902 m_haveMovedFromOriginalDocSize
= false;
904 // must erase lines before view size changes
905 updateResizeLines (-1, -1, 0, 0);
907 calculateDocResizingGrip ();
909 emit
endedDocResize (newSize
);
916 void kpViewScrollableContainer::slotGripStatusMessageChanged (const QString
&string
)
918 if (string
== m_gripStatusMessage
)
921 m_gripStatusMessage
= string
;
922 emit
statusMessageChanged (string
);
927 void kpViewScrollableContainer::recalculateStatusMessage ()
929 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
930 kDebug () << "kpViewScrollabelContainer::recalculateStatusMessage()";
931 kDebug () << "\tQCursor::pos=" << QCursor::pos ()
932 << " global visibleRect="
933 << kpWidgetMapper::toGlobal (this,
934 QRect (0, 0, visibleWidth (), visibleHeight ()))
935 << " brGrip.hotRect=" << m_bottomRightGrip
->hotRect (true)
936 << " bGrip.hotRect=" << m_bottomGrip
->hotRect (true)
937 << " rGrip.hotRect=" << m_rightGrip
->hotRect (true)
941 // HACK: After dragging to a new size, handles move so that they are now
942 // under the mouse pointer but no mouseMoveEvent() is generated for
943 // any grip. This also handles the case of canceling over any
946 if (kpWidgetMapper::toGlobal (this,
947 QRect (0, 0, visibleWidth (), visibleHeight ()))
948 .contains (QCursor::pos ()))
950 if (!m_bottomRightGrip
->isHidden () &&
951 m_bottomRightGrip
->hotRect (true/*to global*/)
952 .contains (QCursor::pos ()))
954 m_bottomRightGrip
->setUserMessage (i18n ("Left drag the handle to resize the image."));
956 else if (!m_bottomGrip
->isHidden () &&
957 m_bottomGrip
->hotRect (true/*to global*/)
958 .contains (QCursor::pos ()))
960 m_bottomGrip
->setUserMessage (i18n ("Left drag the handle to resize the image."));
962 else if (!m_rightGrip
->isHidden () &&
963 m_rightGrip
->hotRect (true/*to global*/)
964 .contains (QCursor::pos ()))
966 m_rightGrip
->setUserMessage (i18n ("Left drag the handle to resize the image."));
970 clearStatusMessage ();
975 clearStatusMessage ();
981 void kpViewScrollableContainer::slotContentsMoving (int x
, int y
)
983 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
984 kDebug () << "kpViewScrollableContainer::slotContentsMoving("
985 << x
<< "," << y
<< ")"
986 << " contentsX=" << contentsX ()
987 << " contentsY=" << contentsY () << endl
;
990 m_contentsXSoon
= x
, m_contentsYSoon
= y
;
991 emit
contentsMovingSoon (m_contentsXSoon
, m_contentsYSoon
);
993 // Reduce flicker - don't let QScrollView scroll to-be-erased lines
996 QTimer::singleShot (0, this, SLOT (slotContentsMoved ()));
1000 void kpViewScrollableContainer::slotContentsMoved ()
1002 m_contentsXSoon
= m_contentsYSoon
= -1;
1004 kpGrip
*grip
= docResizingGrip ();
1005 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
1006 kDebug () << "kpViewScrollableContainer::slotContentsMoved()"
1008 << " contentsX=" << contentsX ()
1009 << " contentsY=" << contentsY () << endl
;
1014 grip
->mouseMovedTo (grip
->mapFromGlobal (QCursor::pos ()),
1015 true/*moved due to drag scroll*/);
1020 void kpViewScrollableContainer::disconnectViewSignals ()
1022 disconnect (m_view
, SIGNAL (sizeChanged (const QSize
&)),
1023 this, SLOT (updateGrips ()));
1024 disconnect (m_view
, SIGNAL (destroyed ()),
1025 this, SLOT (slotViewDestroyed ()));
1029 void kpViewScrollableContainer::connectViewSignals ()
1031 connect (m_view
, SIGNAL (sizeChanged (const QSize
&)),
1032 this, SLOT (updateGrips ()));
1033 connect (m_view
, SIGNAL (destroyed ()),
1034 this, SLOT (slotViewDestroyed ()));
1038 // public virtual [base QScrollView]
1039 void kpViewScrollableContainer::addChild (QWidget
*widget
, int x
, int y
)
1041 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
1042 kDebug () << "kpViewScrollableContainer::addChild(" << widget
1043 << "," << x
<< "," << y
<< endl
;
1046 Q3ScrollView::addChild (widget
, x
, y
);
1048 kpView
*view
= dynamic_cast <kpView
*> (widget
);
1049 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
1050 kDebug () << "\tcast to kpView: " << view
;
1060 kpView
*kpViewScrollableContainer::view () const
1066 void kpViewScrollableContainer::setView (kpView
*view
)
1068 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
1069 kDebug () << "kpViewScrollableContainer::setView(" << view
<< ")";
1077 disconnectViewSignals ();
1086 connectViewSignals ();
1092 void kpViewScrollableContainer::updateGrips ()
1094 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
1095 kDebug () << "kpViewScrollableContainer::updateGrips() m_view="
1097 << " (size=" << (m_view
? m_view
->size () : QSize ()) << ")"
1103 m_bottomGrip
->setFixedWidth (m_view
->width ());
1104 moveChild (m_bottomGrip
, 0, m_view
->height ());
1106 m_rightGrip
->setFixedHeight (m_view
->height ());
1107 moveChild (m_rightGrip
, m_view
->width (), 0);
1109 moveChild (m_bottomRightGrip
, m_view
->width (), m_view
->height ());
1110 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
1111 kDebug () << "\tbottomRightGrip=" << m_bottomRightGrip
->pos ();
1115 m_bottomGrip
->setHidden (m_view
== 0);
1116 m_rightGrip
->setHidden (m_view
== 0);
1117 m_bottomRightGrip
->setHidden (m_view
== 0);
1119 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
1120 kDebug () << "\tcontentsRect=" << contentsRect ()
1121 << " visibleRect=" << visibleRect ()
1122 << " viewportRect=" << viewport ()->rect ()
1128 resizeContents (m_view
->width () + m_rightGrip
->width (),
1129 m_view
->height () + m_bottomGrip
->height ());
1133 resizeContents (0, 0);
1136 recalculateStatusMessage ();
1140 void kpViewScrollableContainer::slotViewDestroyed ()
1142 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
1143 kDebug () << "kpViewScrollableContainer::slotViewDestroyed() m_view="
1153 bool kpViewScrollableContainer::beginDragScroll (const QPoint
&/*docPoint*/,
1154 const QPoint
&/*lastDocPoint*/,
1159 *didSomething
= false;
1161 m_zoomLevel
= zoomLevel
;
1163 const QPoint p
= mapFromGlobal (QCursor::pos ());
1165 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
1166 kDebug () << "kpViewScrollableContainer::beginDragScroll() p=" << p
1167 << " dragScrollTimerRunOnce=" << m_scrollTimerRunOnce
1171 bool stopDragScroll
= true;
1172 bool scrolled
= false;
1174 if (!noDragScrollRect ().contains (p
))
1176 if (m_dragScrollTimer
->isActive ())
1178 if (m_scrollTimerRunOnce
)
1180 scrolled
= slotDragScroll ();
1185 m_scrollTimerRunOnce
= false;
1186 m_dragScrollTimer
->start (DragScrollInitialInterval
);
1189 stopDragScroll
= false;
1193 m_dragScrollTimer
->stop ();
1196 *didSomething
= scrolled
;
1202 bool kpViewScrollableContainer::beginDragScroll (const QPoint
&docPoint
,
1203 const QPoint
&lastDocPoint
,
1206 return beginDragScroll (docPoint
, lastDocPoint
, zoomLevel
,
1207 0/*don't want scrolled notification*/);
1212 bool kpViewScrollableContainer::endDragScroll ()
1214 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
1215 kDebug () << "kpViewScrollableContainer::endDragScroll()";
1218 if (m_dragScrollTimer
->isActive ())
1220 m_dragScrollTimer
->stop ();
1230 static const int distanceFromRectToMultiplier (int dist
)
1234 else if (dist
< DragDistanceFromRectMaxFor1stMultiplier
)
1236 else if (dist
< DragDistanceFromRectMaxFor2ndMultiplier
)
1244 bool kpViewScrollableContainer::slotDragScroll (bool *didSomething
)
1246 bool scrolled
= false;
1249 *didSomething
= false;
1252 const QRect rect
= noDragScrollRect ();
1253 const QPoint pos
= mapFromGlobal (QCursor::pos ());
1255 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
1256 for (int i
= 0; i
< 10; i
++)
1257 kDebug () << QString ();
1259 kDebug () << "kpViewScrollableContainer::slotDragScroll()"
1260 << " noDragScrollRect=" << rect
1262 << " contentsX=" << contentsX ()
1263 << " contentsY=" << contentsY () << endl
;
1267 int dxMultiplier
= 0, dyMultiplier
= 0;
1269 if (pos
.x () < rect
.left ())
1271 dx
= -DragScrollNumPixels
;
1272 dxMultiplier
= distanceFromRectToMultiplier (rect
.left () - pos
.x ());
1274 else if (pos
.x () > rect
.right ())
1276 dx
= +DragScrollNumPixels
;
1277 dxMultiplier
= distanceFromRectToMultiplier (pos
.x () - rect
.right ());
1280 if (pos
.y () < rect
.top ())
1282 dy
= -DragScrollNumPixels
;
1283 dyMultiplier
= distanceFromRectToMultiplier (rect
.top () - pos
.y ());
1285 else if (pos
.y () > rect
.bottom ())
1287 dy
= +DragScrollNumPixels
;
1288 dyMultiplier
= distanceFromRectToMultiplier (pos
.y () - rect
.bottom ());
1291 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 1
1292 kDebug () << "kpViewScrollableContainer::slotDragScroll()"
1293 << " dx=" << dx
<< " * " << dxMultiplier
1294 << " dy=" << dy
<< " * " << dyMultiplier
1295 << " zoomLevel=" << m_zoomLevel
1299 dx
*= dxMultiplier
;// * qMax (1, m_zoomLevel / 100);
1300 dy
*= dyMultiplier
;// * qMax (1, m_zoomLevel / 100);
1304 const int oldContentsX
= contentsX (),
1305 oldContentsY
= contentsY ();
1309 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 1
1310 kDebug () << "\tafter scrollBy():"
1311 << " contentsX=" << contentsX ()
1312 << " contentsY=" << contentsY () << endl
;
1315 scrolled
= (oldContentsX
!= contentsX () ||
1316 oldContentsY
!= contentsY ());
1320 QRegion region
= QRect (contentsX (), contentsY (),
1321 visibleWidth (), visibleHeight ());
1322 region
-= QRect (oldContentsX
, oldContentsY
,
1323 visibleWidth (), visibleHeight ());
1325 // Repaint newly exposed region immediately to reduce tearing
1328 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 1
1329 kDebug () << "\t\tscrolled - repaint new region:" << region
;
1331 m_view
->repaint (region
);
1332 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 1
1333 kDebug () << "\t\tscrolled - repainted";
1340 m_dragScrollTimer
->start (DragScrollInterval
);
1341 m_scrollTimerRunOnce
= true;
1345 *didSomething
= scrolled
;
1348 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 1
1349 for (int i
= 0; i
< 10; i
++)
1350 kDebug () << QString ();
1356 // protected virtual [base QScrollView]
1357 void kpViewScrollableContainer::contentsDragMoveEvent (QDragMoveEvent
*e
)
1359 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
1360 kDebug () << "kpViewScrollableContainer::contentsDragMoveEvent"
1365 Q3ScrollView::contentsDragMoveEvent (e
);
1369 bool kpViewScrollableContainer::slotDragScroll ()
1371 return slotDragScroll (0/*don't want scrolled notification*/);
1375 // protected virtual [base QScrollView]
1376 void kpViewScrollableContainer::contentsMouseMoveEvent (QMouseEvent
*e
)
1378 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
1379 kDebug () << "kpViewScrollableContainer::contentsMouseMoveEvent"
1384 Q3ScrollView::contentsMouseMoveEvent (e
);
1387 // protected virtual [base QScrollView]
1388 void kpViewScrollableContainer::mouseMoveEvent (QMouseEvent
*e
)
1390 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
1391 kDebug () << "kpViewScrollableContainer::mouseMoveEvent"
1396 Q3ScrollView::mouseMoveEvent (e
);
1400 // protected virtual [base QScrollView]
1401 void kpViewScrollableContainer::contentsWheelEvent (QWheelEvent
*e
)
1406 m_view
->wheelEvent (e
);
1408 if (!e
->isAccepted ())
1409 Q3ScrollView::contentsWheelEvent (e
);
1413 QRect
kpViewScrollableContainer::noDragScrollRect () const
1415 return QRect (DragScrollLeftTopMargin
, DragScrollLeftTopMargin
,
1416 width () - DragScrollLeftTopMargin
- DragScrollRightBottomMargin
,
1417 height () - DragScrollLeftTopMargin
- DragScrollRightBottomMargin
);
1420 // protected virtual [base QScrollView]
1421 bool kpViewScrollableContainer::eventFilter (QObject
*watchedObject
, QEvent
*event
)
1423 return Q3ScrollView::eventFilter (watchedObject
, event
);
1426 // protected virtual [base QScrollView]
1427 void kpViewScrollableContainer::viewportPaintEvent (QPaintEvent
*e
)
1429 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
1430 kDebug () << "kpViewScrollableContainer::viewportPaintEvent("
1435 Q3ScrollView::viewportPaintEvent (e
);
1437 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
1438 kDebug () << "done";
1442 // protected virtual [base QFrame]
1443 void kpViewScrollableContainer::paintEvent (QPaintEvent
*e
)
1445 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
1446 kDebug () << "kpViewScrollableContainer::paintEvent("
1451 Q3ScrollView::paintEvent (e
);
1453 #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
1454 kDebug () << "done";
1458 // protected virtual [base QScrollView]
1459 void kpViewScrollableContainer::resizeEvent (QResizeEvent
*e
)
1461 Q3ScrollView::resizeEvent (e
);
1467 #include <kpViewScrollableContainer.moc>