From 6d5e0b18f5995780b9dbaf242fc342fc0caa035b Mon Sep 17 00:00:00 2001 From: "Aaron J. Seigo" Date: Thu, 10 Jul 2008 01:35:51 +0000 Subject: [PATCH] fix various handle regressions, including: * move applet or resize it then move with handle and it pops to a new location * handles unhover too soon * handles don't show on the correct side always * handles are not visually associated well enough with the target applet * icons are hard to see BUG:166149 svn path=/trunk/KDE/kdebase/workspace/libs/plasma/; revision=830264 --- applethandle.cpp | 151 ++++++++++++++++++++++++++++++++--------------- applethandle_p.h | 6 +- containment.cpp | 7 ++- 3 files changed, 113 insertions(+), 51 deletions(-) diff --git a/applethandle.cpp b/applethandle.cpp index 343f98521..750abcc99 100644 --- a/applethandle.cpp +++ b/applethandle.cpp @@ -47,7 +47,7 @@ namespace Plasma qreal _k_angleForPoints(const QPointF ¢er, const QPointF &pt1, const QPointF &pt2); -AppletHandle::AppletHandle(Containment *parent, Applet *applet) +AppletHandle::AppletHandle(Containment *parent, Applet *applet, const QPointF &hoverPos) : QObject(), QGraphicsItem(parent), m_pressedButton(NoButton), @@ -62,12 +62,15 @@ AppletHandle::AppletHandle(Containment *parent, Applet *applet) m_scaleHeight(1.0), m_buttonsOnRight(false), m_pendingFade(false), - m_topview(0) + m_topview(0), + m_entryPos(hoverPos) { KColorScheme colorScheme(QPalette::Active, KColorScheme::View, Theme::defaultTheme()->colorScheme()); m_gradientColor = colorScheme.background(KColorScheme::NormalBackground).color(); QTransform originalMatrix = m_applet->transform(); + m_applet->resetTransform(); + QRectF rect(m_applet->contentsRect()); QPointF center = rect.center(); originalMatrix.translate(center.x(), center.y()); @@ -79,9 +82,6 @@ AppletHandle::AppletHandle(Containment *parent, Applet *applet) QPointF(1, 0), QPointF(cosine, sine)); - m_applet->resetTransform(); - - calculateSize(); m_applet->setParentItem(this); rect = QRectF(m_applet->pos(), m_applet->size()); @@ -91,6 +91,7 @@ AppletHandle::AppletHandle(Containment *parent, Applet *applet) matrix.rotateRadians(m_angle); matrix.translate(-center.x(), -center.y()); setTransform(matrix); + m_hoverTimer = new QTimer(this); m_hoverTimer->setSingleShot(true); m_hoverTimer->setInterval(333); @@ -165,6 +166,31 @@ QPainterPath AppletHandle::shape() const } } +QPainterPath handleRect(const QRectF &rect, int radius, bool onRight) +{ + QPainterPath path; + if (onRight) { + // make the left side straight + path.moveTo(rect.left(), rect.top()); // Top left + path.lineTo(rect.right() - radius, rect.top()); // Top side + path.quadTo(rect.right(), rect.top(), rect.right(), rect.top() + radius); // Top right corner + path.lineTo(rect.right(), rect.bottom() - radius); // Right side + path.quadTo(rect.right(), rect.bottom(), rect.right() - radius, rect.bottom()); // Bottom right corner + path.lineTo(rect.left(), rect.bottom()); // Bottom side + } else { + // make the right side straight + path.moveTo(QPointF(rect.left(), rect.top() + radius)); + path.quadTo(rect.left(), rect.top(), rect.left() + radius, rect.top()); // Top left corner + path.lineTo(rect.right(), rect.top()); // Top side + path.lineTo(rect.right(), rect.bottom()); // Right side + path.lineTo(rect.left() + radius, rect.bottom()); // Bottom side + path.quadTo(rect.left(), rect.bottom(), rect.left(), rect.bottom() - radius); // Bottom left corner + } + + path.closeSubpath(); + return path; +} + void AppletHandle::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option); @@ -174,11 +200,11 @@ void AppletHandle::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti painter->setOpacity(m_opacity); painter->save(); - painter->setOpacity(m_opacity * 0.3); + painter->setOpacity(m_opacity * 0.8); painter->setPen(Qt::NoPen); painter->setRenderHints(QPainter::Antialiasing); - QPainterPath path = PaintUtils::roundedRectangle(m_rect, 10); + QPainterPath path = handleRect(m_rect, 10, m_buttonsOnRight); painter->strokePath(path, m_gradientColor); painter->fillPath(path, m_gradientColor.lighter()); painter->restore(); @@ -222,10 +248,7 @@ void AppletHandle::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti painter->drawPixmap(basePoint + shiftC, KIcon("configure").pixmap(ICON_SIZE, ICON_SIZE)); } - //add one step to let space so the user can move the applet - basePoint += step; - - basePoint += separator; + basePoint = m_rect.bottomLeft() + QPointF((HANDLE_WIDTH - ICON_SIZE) / 2, 0) - step; painter->drawPixmap(basePoint + shiftD, KIcon("edit-delete").pixmap(ICON_SIZE, ICON_SIZE)); painter->restore(); @@ -239,29 +262,26 @@ AppletHandle::ButtonType AppletHandle::mapToButton(const QPointF &point) const QPointF separator = step + QPointF(0, ICON_MARGIN); //end duplicate code - QPolygonF activeArea = QPolygonF(QRectF(basePoint, QSizeF(ICON_SIZE, ICON_SIZE))); + QRectF activeArea = QRectF(basePoint, QSizeF(ICON_SIZE, ICON_SIZE)); - if (activeArea.containsPoint(point, Qt::OddEvenFill)) { + if (activeArea.contains(point)) { return ResizeButton; } activeArea.translate(step); - if (activeArea.containsPoint(point, Qt::OddEvenFill)) { + if (activeArea.contains(point)) { return RotateButton; } if (m_applet && m_applet->hasConfigurationInterface()) { activeArea.translate(step); - if (activeArea.containsPoint(point, Qt::OddEvenFill)) { + if (activeArea.contains(point)) { return ConfigureButton; } } - //add one step to let space so the user can move the applet - activeArea.translate(step); - - activeArea.translate(separator); - if (activeArea.containsPoint(point, Qt::OddEvenFill)) { + activeArea.moveTop(m_rect.bottom() - activeArea.height() - ICON_MARGIN); + if (activeArea.contains(point)) { return RemoveButton; } @@ -290,6 +310,10 @@ void AppletHandle::mousePressEvent(QGraphicsSceneMouseEvent *event) m_applet->raise(); setZValue(m_applet->zValue()); } + + if (m_pressedButton == MoveButton) { + m_pos = pos(); + } event->accept(); update(); @@ -328,7 +352,7 @@ void AppletHandle::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) //kDebug() << "button pressed:" << m_pressedButton << ", fade pending?" << m_pendingFade; if (m_pendingFade) { - startFading(FadeOut); + startFading(FadeOut, m_entryPos); m_pendingFade = false; } @@ -397,7 +421,7 @@ void AppletHandle::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) } } else { // test for containment change - kDebug() << "testing for containment change, sceneBoundingRect = " << m_containment->sceneBoundingRect(); + //kDebug() << "testing for containment change, sceneBoundingRect = " << m_containment->sceneBoundingRect(); if (!m_containment->sceneBoundingRect().contains(m_applet->scenePos())) { // see which containment it belongs to Corona * corona = qobject_cast(scene()); @@ -412,9 +436,9 @@ void AppletHandle::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) if (containments[i]->sceneBoundingRect().contains(pos)) { //kDebug() << "new containment = " << containments[i]; - kDebug() << "rect = " << containments[i]->sceneBoundingRect(); + //kDebug() << "rect = " << containments[i]->sceneBoundingRect(); // add the applet to the new containment and take it from the old one - kDebug() << "moving to other containment with position" << pos;; + //kDebug() << "moving to other containment with position" << pos;; switchContainment(containments[i], pos); break; } @@ -485,7 +509,7 @@ void AppletHandle::mouseMoveEvent(QGraphicsSceneMouseEvent *event) QRect screenRect = QRect(event->screenPos() - m_mousePos, m_applet->screenRect().size()); - kDebug() << "screenRect = " << screenRect; + //kDebug() << "screenRect = " << screenRect; if (!m_topview) { //create a new toplevel view m_topview = new View(m_containment, -1, 0); @@ -671,10 +695,15 @@ void AppletHandle::hoverEnterEvent(QGraphicsSceneHoverEvent *event) m_hoverTimer->start(); } +void AppletHandle::hoverMoveEvent(QGraphicsSceneHoverEvent *event) +{ + Q_UNUSED(event); + m_leaveTimer->stop(); +} + void AppletHandle::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) { Q_UNUSED(event); - //kDebug() << "hover leave" << m_pressedButton; m_hoverTimer->stop(); if (m_pressedButton != NoButton) { @@ -697,13 +726,9 @@ bool AppletHandle::sceneEventFilter(QGraphicsItem *watched, QEvent *event) void AppletHandle::fadeAnimation(qreal progress) { - qreal endOpacity = 1.0; - if (m_anim == FadeOut) { - endOpacity = 0.0; - } - + qreal endOpacity = (m_anim == FadeIn) ? 1.0 : 0.0; m_opacity += (endOpacity - m_opacity) * progress; - + //kDebug() << "progress" << progress << "m_opacity" << m_opacity << endOpacity; if (progress >= 1.0 && m_anim == FadeOut) { emit disappearDone(this); } @@ -713,12 +738,12 @@ void AppletHandle::fadeAnimation(qreal progress) void AppletHandle::fadeIn() { - startFading(FadeIn); + startFading(FadeIn, m_entryPos); } void AppletHandle::leaveTimeout() { - startFading(FadeOut); + startFading(FadeOut, m_entryPos); } void AppletHandle::appletDestroyed() @@ -734,28 +759,61 @@ void AppletHandle::appletResized() update(); } -void AppletHandle::startFading(FadeType anim) +void AppletHandle::startFading(FadeType anim, const QPointF &hoverPos) { if (m_animId != 0) { Animator::self()->stopCustomAnimation(m_animId); } - m_anim = anim; + m_hoverTimer->stop(); + m_leaveTimer->stop(); + + m_entryPos = hoverPos; qreal time = 250; - if (anim == FadeOut && m_hoverTimer->isActive()) { + if (!m_applet || (anim == FadeOut && m_hoverTimer->isActive())) { // fading out before we've started fading in - m_hoverTimer->stop(); fadeAnimation(1.0); return; } if (anim == FadeIn) { + //kDebug() << m_entryPos.x() << m_applet->pos().x(); + prepareGeometryChange(); + bool wasOnRight = m_buttonsOnRight; + m_buttonsOnRight = m_entryPos.x() > (m_applet->size().width() / 2); + calculateSize(); + QPolygonF region = mapToParent(m_rect).intersected(parentWidget()->boundingRect()); + //kDebug() << region << m_rect << mapToParent(m_rect) << parentWidget()->boundingRect(); + if (region != mapToParent(m_rect)) { + // switch sides + //kDebug() << "switch sides"; + m_buttonsOnRight = !m_buttonsOnRight; + calculateSize(); + QPolygonF region2 = mapToParent(m_rect).intersected(parentWidget()->boundingRect()); + if (region2 != mapToParent(m_rect)) { + // ok, both sides failed to be perfect... which one is more perfect? + QRectF f1 = region.boundingRect(); + QRectF f2 = region2.boundingRect(); + //kDebug() << "still not a perfect world" << f2.width() << f2.height() << f1.width() << f1.height(); + if ((f2.width() * f2.height()) < (f1.width() * f1.height())) { + //kDebug() << "we did better the first time"; + m_buttonsOnRight = !m_buttonsOnRight; + calculateSize(); + } + } + } + + if (wasOnRight != m_buttonsOnRight && m_anim == FadeIn && anim == FadeIn && m_opacity <= 1) { + m_opacity = 0.0; + } + time *= 1.0 - m_opacity; } else { time *= m_opacity; } + m_anim = anim; m_animId = Animator::self()->customAnimation(40, (int)time, Animator::EaseInOutCurve, this, "fadeAnimation"); } @@ -763,7 +821,7 @@ void AppletHandle::startFading(FadeType anim) void AppletHandle::forceDisappear() { setAcceptsHoverEvents(false); - startFading(FadeOut); + startFading(FadeOut, m_entryPos); } void AppletHandle::calculateSize() @@ -777,24 +835,25 @@ void AppletHandle::calculateSize() } int top = m_applet->contentsRect().top(); - if (requiredHeight > m_applet->size().height()) { + + if (requiredHeight > m_applet->contentsRect().height()) { top += (m_applet->contentsRect().height() - requiredHeight) / 2.0; + } else { + requiredHeight = m_applet->contentsRect().height(); } - - if (m_applet->pos().x() <= (HANDLE_WIDTH * 2)) { + + if (m_buttonsOnRight) { //put the rect on the right of the applet m_rect = QRectF(m_applet->size().width(), top, HANDLE_WIDTH, requiredHeight); - - m_buttonsOnRight = true; } else { //put the rect on the left of the applet - m_rect = QRectF(- HANDLE_WIDTH, top, HANDLE_WIDTH, requiredHeight); + m_rect = QRectF(-HANDLE_WIDTH, top, HANDLE_WIDTH, requiredHeight); } m_rect = m_applet->mapToParent(m_rect).boundingRect(); m_totalRect = m_rect.united(m_applet->geometry()); } -} +} // Plasma Namespace #include "applethandle_p.moc" diff --git a/applethandle_p.h b/applethandle_p.h index 13a09218c..ef7c1d263 100644 --- a/applethandle_p.h +++ b/applethandle_p.h @@ -40,7 +40,7 @@ class AppletHandle : public QObject, public QGraphicsItem enum FadeType { FadeIn, FadeOut }; enum ButtonType { NoButton, MoveButton, RotateButton, ConfigureButton, RemoveButton, ResizeButton }; - AppletHandle(Containment *parent, Applet *applet); + AppletHandle(Containment *parent, Applet *applet, const QPointF &hoverPos); virtual ~AppletHandle(); Applet *applet() const; @@ -48,13 +48,14 @@ class AppletHandle : public QObject, public QGraphicsItem QRectF boundingRect() const; QPainterPath shape() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); - void startFading(FadeType anim); + void startFading(FadeType anim, const QPointF &hoverPos); protected: void mousePressEvent(QGraphicsSceneMouseEvent *event); void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); void mouseMoveEvent(QGraphicsSceneMouseEvent *event); void hoverEnterEvent(QGraphicsSceneHoverEvent *event); + void hoverMoveEvent(QGraphicsSceneHoverEvent *event); void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); QVariant itemChange(GraphicsItemChange change, const QVariant &value); bool sceneEventFilter(QGraphicsItem *watched, QEvent *event); @@ -105,6 +106,7 @@ class AppletHandle : public QObject, public QGraphicsItem View *m_topview; QPoint m_mousePos; //mousepos relative to applet + QPointF m_entryPos; //where the hover in event occurred QPointF m_pos; //current position of applet in sceneCoords qreal m_zValue; //current zValue of the applet, so it can be restored after drag. }; diff --git a/containment.cpp b/containment.cpp index fd416c579..3e9adf641 100644 --- a/containment.cpp +++ b/containment.cpp @@ -843,13 +843,14 @@ bool Containment::sceneEventFilter(QGraphicsItem *watched, QEvent *event) case QEvent::GraphicsSceneHoverEnter: //kDebug() << "got hoverenterEvent" << immutability() << " " << applet->immutability(); if (immutability() == Mutable && applet->immutability() == Mutable) { + QGraphicsSceneHoverEvent *he = static_cast(event); if (d->handles.contains(applet)) { - d->handles[applet]->startFading(AppletHandle::FadeIn); + d->handles[applet]->startFading(AppletHandle::FadeIn, he->pos()); } else { //kDebug() << "generated applet handle"; //TODO: there should be a small delay on showing these. they pop up too quickly/easily // right now - AppletHandle *handle = new AppletHandle(this, applet); + AppletHandle *handle = new AppletHandle(this, applet, he->pos()); d->handles[applet] = handle; connect(handle, SIGNAL(disappearDone(AppletHandle*)), this, SLOT(handleDisappeared(AppletHandle*))); @@ -863,7 +864,7 @@ bool Containment::sceneEventFilter(QGraphicsItem *watched, QEvent *event) if (d->handles.contains(applet)) { QGraphicsSceneHoverEvent *he = static_cast(event); if (!d->handles[applet]->boundingRect().contains(d->handles[applet]->mapFromScene(he->scenePos()))) { - d->handles[applet]->startFading(AppletHandle::FadeOut); + d->handles[applet]->startFading(AppletHandle::FadeOut, he->pos()); } } default: