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
This commit is contained in:
Aaron J. Seigo 2008-07-10 01:35:51 +00:00
parent c89d4239d7
commit 6d5e0b18f5
3 changed files with 113 additions and 51 deletions

View File

@ -47,7 +47,7 @@ namespace Plasma
qreal _k_angleForPoints(const QPointF &center, const QPointF &pt1, const QPointF &pt2); qreal _k_angleForPoints(const QPointF &center, const QPointF &pt1, const QPointF &pt2);
AppletHandle::AppletHandle(Containment *parent, Applet *applet) AppletHandle::AppletHandle(Containment *parent, Applet *applet, const QPointF &hoverPos)
: QObject(), : QObject(),
QGraphicsItem(parent), QGraphicsItem(parent),
m_pressedButton(NoButton), m_pressedButton(NoButton),
@ -62,12 +62,15 @@ AppletHandle::AppletHandle(Containment *parent, Applet *applet)
m_scaleHeight(1.0), m_scaleHeight(1.0),
m_buttonsOnRight(false), m_buttonsOnRight(false),
m_pendingFade(false), m_pendingFade(false),
m_topview(0) m_topview(0),
m_entryPos(hoverPos)
{ {
KColorScheme colorScheme(QPalette::Active, KColorScheme::View, Theme::defaultTheme()->colorScheme()); KColorScheme colorScheme(QPalette::Active, KColorScheme::View, Theme::defaultTheme()->colorScheme());
m_gradientColor = colorScheme.background(KColorScheme::NormalBackground).color(); m_gradientColor = colorScheme.background(KColorScheme::NormalBackground).color();
QTransform originalMatrix = m_applet->transform(); QTransform originalMatrix = m_applet->transform();
m_applet->resetTransform();
QRectF rect(m_applet->contentsRect()); QRectF rect(m_applet->contentsRect());
QPointF center = rect.center(); QPointF center = rect.center();
originalMatrix.translate(center.x(), center.y()); originalMatrix.translate(center.x(), center.y());
@ -79,9 +82,6 @@ AppletHandle::AppletHandle(Containment *parent, Applet *applet)
QPointF(1, 0), QPointF(1, 0),
QPointF(cosine, sine)); QPointF(cosine, sine));
m_applet->resetTransform();
calculateSize();
m_applet->setParentItem(this); m_applet->setParentItem(this);
rect = QRectF(m_applet->pos(), m_applet->size()); rect = QRectF(m_applet->pos(), m_applet->size());
@ -91,6 +91,7 @@ AppletHandle::AppletHandle(Containment *parent, Applet *applet)
matrix.rotateRadians(m_angle); matrix.rotateRadians(m_angle);
matrix.translate(-center.x(), -center.y()); matrix.translate(-center.x(), -center.y());
setTransform(matrix); setTransform(matrix);
m_hoverTimer = new QTimer(this); m_hoverTimer = new QTimer(this);
m_hoverTimer->setSingleShot(true); m_hoverTimer->setSingleShot(true);
m_hoverTimer->setInterval(333); 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) void AppletHandle::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{ {
Q_UNUSED(option); Q_UNUSED(option);
@ -174,11 +200,11 @@ void AppletHandle::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti
painter->setOpacity(m_opacity); painter->setOpacity(m_opacity);
painter->save(); painter->save();
painter->setOpacity(m_opacity * 0.3); painter->setOpacity(m_opacity * 0.8);
painter->setPen(Qt::NoPen); painter->setPen(Qt::NoPen);
painter->setRenderHints(QPainter::Antialiasing); 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->strokePath(path, m_gradientColor);
painter->fillPath(path, m_gradientColor.lighter()); painter->fillPath(path, m_gradientColor.lighter());
painter->restore(); 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)); 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 = m_rect.bottomLeft() + QPointF((HANDLE_WIDTH - ICON_SIZE) / 2, 0) - step;
basePoint += step;
basePoint += separator;
painter->drawPixmap(basePoint + shiftD, KIcon("edit-delete").pixmap(ICON_SIZE, ICON_SIZE)); painter->drawPixmap(basePoint + shiftD, KIcon("edit-delete").pixmap(ICON_SIZE, ICON_SIZE));
painter->restore(); painter->restore();
@ -239,29 +262,26 @@ AppletHandle::ButtonType AppletHandle::mapToButton(const QPointF &point) const
QPointF separator = step + QPointF(0, ICON_MARGIN); QPointF separator = step + QPointF(0, ICON_MARGIN);
//end duplicate code //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; return ResizeButton;
} }
activeArea.translate(step); activeArea.translate(step);
if (activeArea.containsPoint(point, Qt::OddEvenFill)) { if (activeArea.contains(point)) {
return RotateButton; return RotateButton;
} }
if (m_applet && m_applet->hasConfigurationInterface()) { if (m_applet && m_applet->hasConfigurationInterface()) {
activeArea.translate(step); activeArea.translate(step);
if (activeArea.containsPoint(point, Qt::OddEvenFill)) { if (activeArea.contains(point)) {
return ConfigureButton; return ConfigureButton;
} }
} }
//add one step to let space so the user can move the applet activeArea.moveTop(m_rect.bottom() - activeArea.height() - ICON_MARGIN);
activeArea.translate(step); if (activeArea.contains(point)) {
activeArea.translate(separator);
if (activeArea.containsPoint(point, Qt::OddEvenFill)) {
return RemoveButton; return RemoveButton;
} }
@ -290,6 +310,10 @@ void AppletHandle::mousePressEvent(QGraphicsSceneMouseEvent *event)
m_applet->raise(); m_applet->raise();
setZValue(m_applet->zValue()); setZValue(m_applet->zValue());
} }
if (m_pressedButton == MoveButton) {
m_pos = pos();
}
event->accept(); event->accept();
update(); update();
@ -328,7 +352,7 @@ void AppletHandle::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
//kDebug() << "button pressed:" << m_pressedButton << ", fade pending?" << m_pendingFade; //kDebug() << "button pressed:" << m_pressedButton << ", fade pending?" << m_pendingFade;
if (m_pendingFade) { if (m_pendingFade) {
startFading(FadeOut); startFading(FadeOut, m_entryPos);
m_pendingFade = false; m_pendingFade = false;
} }
@ -397,7 +421,7 @@ void AppletHandle::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
} }
} else { } else {
// test for containment change // 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())) { if (!m_containment->sceneBoundingRect().contains(m_applet->scenePos())) {
// see which containment it belongs to // see which containment it belongs to
Corona * corona = qobject_cast<Corona*>(scene()); Corona * corona = qobject_cast<Corona*>(scene());
@ -412,9 +436,9 @@ void AppletHandle::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
if (containments[i]->sceneBoundingRect().contains(pos)) { if (containments[i]->sceneBoundingRect().contains(pos)) {
//kDebug() << "new containment = " << containments[i]; //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 // 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); switchContainment(containments[i], pos);
break; break;
} }
@ -485,7 +509,7 @@ void AppletHandle::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
QRect screenRect = QRect(event->screenPos() - m_mousePos, QRect screenRect = QRect(event->screenPos() - m_mousePos,
m_applet->screenRect().size()); m_applet->screenRect().size());
kDebug() << "screenRect = " << screenRect; //kDebug() << "screenRect = " << screenRect;
if (!m_topview) { //create a new toplevel view if (!m_topview) { //create a new toplevel view
m_topview = new View(m_containment, -1, 0); m_topview = new View(m_containment, -1, 0);
@ -671,10 +695,15 @@ void AppletHandle::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
m_hoverTimer->start(); m_hoverTimer->start();
} }
void AppletHandle::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event);
m_leaveTimer->stop();
}
void AppletHandle::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) void AppletHandle::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{ {
Q_UNUSED(event); Q_UNUSED(event);
//kDebug() << "hover leave" << m_pressedButton;
m_hoverTimer->stop(); m_hoverTimer->stop();
if (m_pressedButton != NoButton) { if (m_pressedButton != NoButton) {
@ -697,13 +726,9 @@ bool AppletHandle::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
void AppletHandle::fadeAnimation(qreal progress) void AppletHandle::fadeAnimation(qreal progress)
{ {
qreal endOpacity = 1.0; qreal endOpacity = (m_anim == FadeIn) ? 1.0 : 0.0;
if (m_anim == FadeOut) {
endOpacity = 0.0;
}
m_opacity += (endOpacity - m_opacity) * progress; m_opacity += (endOpacity - m_opacity) * progress;
//kDebug() << "progress" << progress << "m_opacity" << m_opacity << endOpacity;
if (progress >= 1.0 && m_anim == FadeOut) { if (progress >= 1.0 && m_anim == FadeOut) {
emit disappearDone(this); emit disappearDone(this);
} }
@ -713,12 +738,12 @@ void AppletHandle::fadeAnimation(qreal progress)
void AppletHandle::fadeIn() void AppletHandle::fadeIn()
{ {
startFading(FadeIn); startFading(FadeIn, m_entryPos);
} }
void AppletHandle::leaveTimeout() void AppletHandle::leaveTimeout()
{ {
startFading(FadeOut); startFading(FadeOut, m_entryPos);
} }
void AppletHandle::appletDestroyed() void AppletHandle::appletDestroyed()
@ -734,28 +759,61 @@ void AppletHandle::appletResized()
update(); update();
} }
void AppletHandle::startFading(FadeType anim) void AppletHandle::startFading(FadeType anim, const QPointF &hoverPos)
{ {
if (m_animId != 0) { if (m_animId != 0) {
Animator::self()->stopCustomAnimation(m_animId); Animator::self()->stopCustomAnimation(m_animId);
} }
m_anim = anim; m_hoverTimer->stop();
m_leaveTimer->stop();
m_entryPos = hoverPos;
qreal time = 250; 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 // fading out before we've started fading in
m_hoverTimer->stop();
fadeAnimation(1.0); fadeAnimation(1.0);
return; return;
} }
if (anim == FadeIn) { 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; time *= 1.0 - m_opacity;
} else { } else {
time *= m_opacity; time *= m_opacity;
} }
m_anim = anim;
m_animId = Animator::self()->customAnimation(40, (int)time, Animator::EaseInOutCurve, this, "fadeAnimation"); m_animId = Animator::self()->customAnimation(40, (int)time, Animator::EaseInOutCurve, this, "fadeAnimation");
} }
@ -763,7 +821,7 @@ void AppletHandle::startFading(FadeType anim)
void AppletHandle::forceDisappear() void AppletHandle::forceDisappear()
{ {
setAcceptsHoverEvents(false); setAcceptsHoverEvents(false);
startFading(FadeOut); startFading(FadeOut, m_entryPos);
} }
void AppletHandle::calculateSize() void AppletHandle::calculateSize()
@ -777,24 +835,25 @@ void AppletHandle::calculateSize()
} }
int top = m_applet->contentsRect().top(); 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; 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 //put the rect on the right of the applet
m_rect = QRectF(m_applet->size().width(), top, HANDLE_WIDTH, requiredHeight); m_rect = QRectF(m_applet->size().width(), top, HANDLE_WIDTH, requiredHeight);
m_buttonsOnRight = true;
} else { } else {
//put the rect on the left of the applet //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_rect = m_applet->mapToParent(m_rect).boundingRect();
m_totalRect = m_rect.united(m_applet->geometry()); m_totalRect = m_rect.united(m_applet->geometry());
} }
} } // Plasma Namespace
#include "applethandle_p.moc" #include "applethandle_p.moc"

View File

@ -40,7 +40,7 @@ class AppletHandle : public QObject, public QGraphicsItem
enum FadeType { FadeIn, FadeOut }; enum FadeType { FadeIn, FadeOut };
enum ButtonType { NoButton, MoveButton, RotateButton, ConfigureButton, RemoveButton, ResizeButton }; enum ButtonType { NoButton, MoveButton, RotateButton, ConfigureButton, RemoveButton, ResizeButton };
AppletHandle(Containment *parent, Applet *applet); AppletHandle(Containment *parent, Applet *applet, const QPointF &hoverPos);
virtual ~AppletHandle(); virtual ~AppletHandle();
Applet *applet() const; Applet *applet() const;
@ -48,13 +48,14 @@ class AppletHandle : public QObject, public QGraphicsItem
QRectF boundingRect() const; QRectF boundingRect() const;
QPainterPath shape() const; QPainterPath shape() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
void startFading(FadeType anim); void startFading(FadeType anim, const QPointF &hoverPos);
protected: protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event); void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
void mouseMoveEvent(QGraphicsSceneMouseEvent *event); void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
void hoverEnterEvent(QGraphicsSceneHoverEvent *event); void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
QVariant itemChange(GraphicsItemChange change, const QVariant &value); QVariant itemChange(GraphicsItemChange change, const QVariant &value);
bool sceneEventFilter(QGraphicsItem *watched, QEvent *event); bool sceneEventFilter(QGraphicsItem *watched, QEvent *event);
@ -105,6 +106,7 @@ class AppletHandle : public QObject, public QGraphicsItem
View *m_topview; View *m_topview;
QPoint m_mousePos; //mousepos relative to applet 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 QPointF m_pos; //current position of applet in sceneCoords
qreal m_zValue; //current zValue of the applet, so it can be restored after drag. qreal m_zValue; //current zValue of the applet, so it can be restored after drag.
}; };

View File

@ -843,13 +843,14 @@ bool Containment::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
case QEvent::GraphicsSceneHoverEnter: case QEvent::GraphicsSceneHoverEnter:
//kDebug() << "got hoverenterEvent" << immutability() << " " << applet->immutability(); //kDebug() << "got hoverenterEvent" << immutability() << " " << applet->immutability();
if (immutability() == Mutable && applet->immutability() == Mutable) { if (immutability() == Mutable && applet->immutability() == Mutable) {
QGraphicsSceneHoverEvent *he = static_cast<QGraphicsSceneHoverEvent*>(event);
if (d->handles.contains(applet)) { if (d->handles.contains(applet)) {
d->handles[applet]->startFading(AppletHandle::FadeIn); d->handles[applet]->startFading(AppletHandle::FadeIn, he->pos());
} else { } else {
//kDebug() << "generated applet handle"; //kDebug() << "generated applet handle";
//TODO: there should be a small delay on showing these. they pop up too quickly/easily //TODO: there should be a small delay on showing these. they pop up too quickly/easily
// right now // right now
AppletHandle *handle = new AppletHandle(this, applet); AppletHandle *handle = new AppletHandle(this, applet, he->pos());
d->handles[applet] = handle; d->handles[applet] = handle;
connect(handle, SIGNAL(disappearDone(AppletHandle*)), connect(handle, SIGNAL(disappearDone(AppletHandle*)),
this, SLOT(handleDisappeared(AppletHandle*))); this, SLOT(handleDisappeared(AppletHandle*)));
@ -863,7 +864,7 @@ bool Containment::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
if (d->handles.contains(applet)) { if (d->handles.contains(applet)) {
QGraphicsSceneHoverEvent *he = static_cast<QGraphicsSceneHoverEvent *>(event); QGraphicsSceneHoverEvent *he = static_cast<QGraphicsSceneHoverEvent *>(event);
if (!d->handles[applet]->boundingRect().contains(d->handles[applet]->mapFromScene(he->scenePos()))) { 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: default: