00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "applethandle_p.h"
00021
00022 #include <QApplication>
00023 #include <QtGui/QGraphicsSceneMouseEvent>
00024 #include <QtGui/QLinearGradient>
00025 #include <QtGui/QPainter>
00026 #include <QtGui/QApplication>
00027
00028 #include <KColorScheme>
00029 #include <KGlobalSettings>
00030 #include <KIcon>
00031
00032 #include <cmath>
00033 #include <math.h>
00034
00035 #include "plasma/view.h"
00036 #include "applet.h"
00037 #include "containment.h"
00038 #include "corona.h"
00039 #include "applet.h"
00040 #include "theme.h"
00041
00042 namespace Plasma
00043 {
00044
00045 qreal _k_angleForPoints(const QPointF ¢er, const QPointF &pt1, const QPointF &pt2);
00046
00047 AppletHandle::AppletHandle(Containment *parent, Applet *applet)
00048 : QObject(),
00049 QGraphicsItem(parent),
00050 m_pressedButton(NoButton),
00051 m_containment(parent),
00052 m_applet(applet),
00053 m_opacity(0.0),
00054 m_anim(FadeIn),
00055 m_animId(0),
00056 m_angle(0.0),
00057 m_tempAngle(0.0),
00058 m_scaleWidth(1.0),
00059 m_scaleHeight(1.0),
00060 m_buttonsOnRight(false),
00061 m_pendingFade(false)
00062 {
00063 KColorScheme colors(QPalette::Active, KColorScheme::View, Theme::self()->colors());
00064 m_gradientColor = colors.background(KColorScheme::NormalBackground).color();
00065
00066 QTransform originalMatrix = m_applet->transform();
00067 QRectF rect(m_applet->boundingRect());
00068 QPointF center = rect.center();
00069 originalMatrix.translate(center.x(), center.y());
00070
00071 qreal cosine = originalMatrix.m11();
00072 qreal sine = originalMatrix.m12();
00073
00074 m_angle = _k_angleForPoints(QPointF(0, 0),
00075 QPointF(1, 0),
00076 QPointF(cosine, sine));
00077
00078 m_applet->resetTransform();
00079
00080 calculateSize();
00081 m_applet->setParentItem(this);
00082
00083 rect = QRectF(m_applet->pos(), m_applet->size());
00084 center = rect.center();
00085 QTransform matrix;
00086 matrix.translate(center.x(), center.y());
00087 matrix.rotateRadians(m_angle);
00088 matrix.translate(-center.x(), -center.y());
00089 setTransform(matrix);
00090
00091 m_hoverTimer = new QTimer(this);
00092 m_hoverTimer->setSingleShot(true);
00093 m_hoverTimer->setInterval(300);
00094
00095 connect(m_hoverTimer, SIGNAL(timeout()), this, SLOT(fadeIn()));
00096 connect(m_applet, SIGNAL(destroyed(QObject*)), this, SLOT(appletDestroyed()));
00097
00098 setAcceptsHoverEvents(true);
00099 m_hoverTimer->start();
00100 }
00101
00102 AppletHandle::~AppletHandle()
00103 {
00104 if (m_applet) {
00105 m_applet->removeSceneEventFilter(this);
00106
00107 QRectF rect = QRectF(m_applet->pos(), m_applet->size());
00108 QPointF center = m_applet->mapFromParent(rect.center());
00109
00110 QPointF newPos = transform().inverted().map(m_applet->pos());
00111 m_applet->setPos(mapToParent(newPos));
00112
00113 QTransform matrix;
00114 matrix.translate(center.x(), center.y());
00115 matrix.rotateRadians(m_angle);
00116 matrix.translate(-center.x(), -center.y());
00117 m_applet->setTransform(matrix);
00118
00119 m_applet->setParentItem(m_containment);
00120
00121 m_applet->update();
00122 }
00123 }
00124
00125 Applet *AppletHandle::applet() const
00126 {
00127 return m_applet;
00128 }
00129
00130 QRectF Plasma::AppletHandle::boundingRect() const
00131 {
00132 return m_rect;
00133 }
00134
00135 void AppletHandle::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
00136 {
00137 Q_UNUSED(option);
00138 Q_UNUSED(widget);
00139
00140 painter->save();
00141 painter->setOpacity(m_opacity);
00142
00143 painter->save();
00144 painter->setOpacity(m_opacity * 0.4);
00145 painter->setPen(Qt::NoPen);
00146 painter->setRenderHints(QPainter::Antialiasing);
00147 QLinearGradient gr(boundingRect().topLeft(), boundingRect().bottomRight());
00148 gr.setColorAt(0, m_gradientColor);
00149 gr.setColorAt(0.1, KColorScheme::shade(m_gradientColor, KColorScheme::LightShade));
00150 gr.setColorAt(1, KColorScheme::shade(m_gradientColor, KColorScheme::DarkShade));
00151 painter->setBrush(gr);
00152 painter->drawPath(Plasma::roundedRectangle(boundingRect(), 10));
00153 painter->restore();
00154
00155 QPointF point = m_rect.topLeft();
00156
00157 if (m_buttonsOnRight) {
00158 point += QPointF(m_rect.width() - ICON_SIZE - HANDLE_WIDTH, HANDLE_WIDTH);
00159 } else {
00160 point+= QPointF(HANDLE_WIDTH / 2, HANDLE_WIDTH);
00161 }
00162
00163 QPointF shiftC;
00164 QPointF shiftD;
00165 QPointF shiftR;
00166 QPointF shiftM;
00167
00168 switch(m_pressedButton)
00169 {
00170 case ConfigureButton:
00171 shiftC = QPointF(2, 2);
00172 break;
00173 case RemoveButton:
00174 shiftD = QPointF(2, 2);
00175 break;
00176 case RotateButton:
00177 shiftR = QPointF(2, 2);
00178 break;
00179 case ResizeButton:
00180 shiftM = QPointF(2, 2);
00181 break;
00182 default:
00183 break;
00184 }
00185
00186 painter->drawPixmap(point + shiftM, KIcon("transform-move").pixmap(ICON_SIZE, ICON_SIZE));
00187
00188 point += QPointF(0.0, ICON_SIZE + ICON_MARGIN);
00189 painter->drawPixmap(point + shiftR, KIcon("transform-rotate").pixmap(ICON_SIZE, ICON_SIZE));
00190
00191 if (m_applet && m_applet->hasConfigurationInterface()) {
00192 point += QPointF(0.0, ICON_SIZE + ICON_MARGIN);
00193 painter->drawPixmap(point + shiftC, KIcon("configure").pixmap(ICON_SIZE, ICON_SIZE));
00194 }
00195
00196 point += QPointF(0.0, ICON_SIZE + ICON_MARGIN * 2);
00197 painter->drawPixmap(point + shiftD, KIcon("edit-delete").pixmap(ICON_SIZE, ICON_SIZE));
00198
00199 painter->restore();
00200 }
00201
00202 AppletHandle::ButtonType AppletHandle::mapToButton(const QPointF &point) const
00203 {
00204 QPointF basePoint = m_rect.topLeft();
00205
00206 if (m_buttonsOnRight) {
00207 basePoint+= QPointF(m_rect.width() - ICON_SIZE, HANDLE_WIDTH);
00208 } else {
00209 basePoint+= QPointF(HANDLE_WIDTH, HANDLE_WIDTH);
00210 }
00211
00212 QPolygonF activeArea = QPolygonF(QRectF(basePoint, QSizeF(ICON_SIZE, ICON_SIZE)));
00213
00214 if (activeArea.containsPoint(point, Qt::OddEvenFill)) {
00215 return ResizeButton;
00216 }
00217
00218 activeArea.translate(QPointF(0.0, ICON_SIZE + ICON_MARGIN));
00219 if (activeArea.containsPoint(point, Qt::OddEvenFill)) {
00220 return RotateButton;
00221 }
00222
00223 if (m_applet && m_applet->hasConfigurationInterface()) {
00224 activeArea.translate(QPointF(0.0, ICON_SIZE + ICON_MARGIN));
00225 if (activeArea.containsPoint(point, Qt::OddEvenFill)) {
00226 return ConfigureButton;
00227 }
00228 }
00229
00230 activeArea.translate(QPointF(0.0, ICON_SIZE + ICON_MARGIN * 2));
00231 if (activeArea.containsPoint(point, Qt::OddEvenFill)) {
00232 return RemoveButton;
00233 }
00234
00235 return MoveButton;
00236
00237 }
00238
00239 void AppletHandle::mousePressEvent(QGraphicsSceneMouseEvent *event)
00240 {
00241 if (m_pendingFade) {
00242
00243 return;
00244 }
00245
00246 if (event->button() == Qt::LeftButton) {
00247 m_pressedButton = mapToButton(event->pos());
00248
00249 if (m_pressedButton != NoButton) {
00250 m_applet->installSceneEventFilter(this);
00251 }
00252 event->accept();
00253 update();
00254 return;
00255 }
00256
00257 QGraphicsItem::mousePressEvent(event);
00258 }
00259
00260 void AppletHandle::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
00261 {
00262
00263 if (m_applet) {
00264 m_applet->removeSceneEventFilter(this);
00265 }
00266
00267 if (m_pendingFade) {
00268 startFading(FadeOut);
00269 m_pendingFade = false;
00270 return;
00271 }
00272
00273 ButtonType releasedAtButton = mapToButton(event->pos());
00274
00275 if (m_applet && event->button() == Qt::LeftButton) {
00276 switch (m_pressedButton) {
00277 case ResizeButton:
00278 case RotateButton: {
00279 if (m_scaleWidth > 0 && m_scaleHeight > 0) {
00280 QRectF rect(m_applet->boundingRect());
00281 const qreal newWidth = rect.width() * m_scaleWidth;
00282 const qreal newHeight = rect.height() * m_scaleHeight;
00283 m_applet->resetTransform();
00284 m_applet->resize(newWidth, newHeight);
00285 scale(1.0/m_scaleWidth, 1.0/m_scaleHeight);
00286 moveBy((rect.width() - newWidth) / 2, (rect.height() - newHeight) / 2);
00287 m_scaleWidth = m_scaleHeight = 0;
00288 }
00289 QRectF rect = QRectF(m_applet->pos(), m_applet->size());
00290 QPointF center = rect.center();
00291
00292 m_angle += m_tempAngle;
00293 m_tempAngle = 0;
00294
00295 QTransform matrix;
00296 matrix.translate(center.x(), center.y());
00297 matrix.rotateRadians(m_angle);
00298 matrix.translate(-center.x(), -center.y());
00299
00300 setTransform(matrix);
00301 m_applet->update();
00302 break;
00303 }
00304 case ConfigureButton:
00305
00306 if (m_pressedButton == releasedAtButton) {
00307 m_containment->emitLaunchActivated();
00308 m_applet->showConfigurationInterface();
00309 }
00310 break;
00311 case RemoveButton:
00312 if (m_pressedButton == releasedAtButton) {
00313 forceDisappear();
00314 Phase::self()->animateItem(m_applet, Phase::Disappear);
00315 }
00316 break;
00317 case MoveButton: {
00318
00319 QWidget *w = QApplication::topLevelAt(event->screenPos());
00320 kDebug() << "move to widget" << w;
00321 if (w) {
00322 Plasma::View *v = qobject_cast<Plasma::View *>(w);
00323 if (v) {
00324 Containment *c = v->containment();
00325
00326
00327 if (c && c != m_containment) {
00328
00329
00330
00331 QPoint pos = v->mapFromGlobal(event->screenPos());
00332 switchContainment(c, v->mapToScene(pos));
00333 }
00334 }
00335 }
00336 break;
00337 }
00338 default:
00339 break;
00340 }
00341 }
00342
00343 m_pressedButton = NoButton;
00344 update();
00345 }
00346
00347 qreal _k_distanceForPoint(QPointF point)
00348 {
00349 return std::sqrt(point.x()*point.x()+point.y()*point.y());
00350 }
00351
00352 qreal _k_angleForPoints(const QPointF ¢er, const QPointF &pt1, const QPointF &pt2)
00353 {
00354 QPointF vec1 = pt1 - center;
00355 QPointF vec2 = pt2 - center;
00356
00357 qreal alpha = std::atan2(vec1.y(), vec1.x());
00358 qreal beta = std::atan2(vec2.y(), vec2.x());
00359
00360 return beta - alpha;
00361 }
00362
00363 void AppletHandle::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
00364 {
00365 static const qreal snapAngle = M_PI_2 ;
00366
00367 if (!m_applet) {
00368 QGraphicsItem::mouseMoveEvent(event);
00369 return;
00370 }
00371
00372 QPointF curPos = transform().map(event->pos());
00373 QPointF lastPos = transform().map(event->lastPos());
00374 QPointF delta = curPos-lastPos;
00375
00376 if (m_pressedButton == MoveButton) {
00377 setPos(pos()+delta);
00378
00379 if (!m_containment->sceneBoundingRect().contains(event->scenePos())) {
00380
00381 Corona * corona = qobject_cast<Corona*>(scene());
00382 if (corona) {
00383 QList<Containment*> containments = corona->containments();
00384 for (int i = 0; i < containments.size(); ++i) {
00385 if (containments[i]->sceneBoundingRect().contains(event->scenePos())) {
00386
00387
00388
00389
00390 switchContainment(containments[i], scenePos());
00391 break;
00392 }
00393 }
00394 }
00395 }
00396 } else if (m_pressedButton == RotateButton ||
00397 m_pressedButton == ResizeButton) {
00398 if (_k_distanceForPoint(delta) <= 1.0) {
00399 return;
00400 }
00401
00402 QPointF pressPos = mapFromScene(event->buttonDownScenePos(Qt::LeftButton));
00403
00404 QRectF rect = QRectF(m_applet->pos(), m_applet->size());
00405 QPointF center = rect.center();
00406
00407 if (m_pressedButton == RotateButton) {
00408 m_tempAngle = _k_angleForPoints(center, pressPos, event->pos());
00409
00410 if (fabs(remainder(m_angle+m_tempAngle, snapAngle)) < 0.15) {
00411 m_tempAngle = m_tempAngle - remainder(m_angle+m_tempAngle, snapAngle);
00412 }
00413
00414 m_scaleWidth = m_scaleHeight = 1.0;
00415 } else {
00416 qreal w = m_applet->size().width();
00417 qreal h = m_applet->size().height();
00418 QSizeF min = m_applet->minimumSize();
00419 QSizeF max = m_applet->maximumSize();
00420
00421
00422
00423 if (min.isEmpty()) {
00424 min = m_applet->boundingRect().size() - m_applet->contentRect().size();
00425 min += QSizeF(16, 16);
00426 }
00427
00428 if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
00429
00430 qreal newScaleWidth = 0;
00431 qreal newScaleHeight = 0;
00432
00433 QPointF startDistance(pressPos - center);
00434 QPointF currentDistance(event->pos() - center);
00435 newScaleWidth = currentDistance.x() / startDistance.x();
00436 newScaleHeight = currentDistance.y() / startDistance.y();
00437
00438 if (qAbs(w - (newScaleWidth * w)) <= KGlobalSettings::dndEventDelay()) {
00439 newScaleWidth = 1.0;
00440 }
00441 if (qAbs(h - (newScaleHeight * h)) <= KGlobalSettings::dndEventDelay()) {
00442 newScaleHeight = 1.0;
00443 }
00444
00445 if (newScaleHeight * h < min.height()) {
00446 m_scaleHeight = min.height() / h;
00447 } else if (newScaleHeight * h > max.height()) {
00448 m_scaleHeight = max.height() / h;
00449 } else {
00450 m_scaleHeight = newScaleHeight;
00451 }
00452 if (newScaleWidth * w < min.width()) {
00453 m_scaleWidth = min.width() / w;
00454 } else if (newScaleWidth * w > max.width()) {
00455 m_scaleWidth = max.width() / w;
00456 } else {
00457 m_scaleWidth = newScaleWidth;
00458 }
00459 } else {
00460
00461 qreal newScale = 0;
00462
00463 newScale = _k_distanceForPoint(event->pos()-center) / _k_distanceForPoint(pressPos-center);
00464 if (qAbs(h - (newScale * h)) <= KGlobalSettings::dndEventDelay()) {
00465 newScale = 1.0;
00466 }
00467
00468 if (newScale * w < min.width() || newScale * h < min.height()) {
00469 m_scaleWidth = m_scaleHeight = qMax(min.width() / w, min.height() / h);
00470 } else if (newScale * w > max.width() && newScale * h > max.height()) {
00471 m_scaleWidth = m_scaleHeight = qMin(max.width() / w, max.height() / h);
00472 } else {
00473 m_scaleHeight = m_scaleWidth = newScale;
00474 }
00475 }
00476 }
00477
00478 QTransform matrix;
00479 matrix.translate(center.x(), center.y());
00480 matrix.rotateRadians(m_angle+m_tempAngle);
00481 matrix.scale(m_scaleWidth, m_scaleHeight);
00482 matrix.translate(-center.x(), -center.y());
00483 setTransform(matrix);
00484 } else {
00485 QGraphicsItem::mouseMoveEvent(event);
00486 }
00487 }
00488
00489
00490 void AppletHandle::switchContainment(Containment *containment, const QPointF &pos)
00491 {
00492 Applet *applet=m_applet;
00493 switch (containment->containmentType()) {
00494 case Containment::PanelContainment:
00495 kDebug() << "panel";
00496
00497 forceDisappear();
00498 m_applet=0;
00499 applet->disconnect(this);
00500 containment->addApplet(applet, containment->mapFromScene(pos));
00501 break;
00502 default:
00503 kDebug() << "desktop";
00504 m_containment = containment;
00505 containment->addApplet(m_applet);
00506 setParentItem(containment);
00507 m_applet->setParentItem(this);
00508 setPos(containment->mapFromScene(pos));
00509
00510 }
00511 update();
00512 }
00513
00514 QVariant AppletHandle::itemChange(GraphicsItemChange change, const QVariant &value)
00515 {
00516 if (change == ItemPositionHasChanged && m_applet) {
00517 m_applet->constraintsUpdated(Plasma::LocationConstraint);
00518 }
00519 return QGraphicsItem::itemChange(change, value);
00520 }
00521
00522 void AppletHandle::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
00523 {
00524 Q_UNUSED(event);
00525
00526 m_hoverTimer->start();
00527 }
00528
00529 void AppletHandle::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
00530 {
00531 Q_UNUSED(event);
00532
00533 m_hoverTimer->stop();
00534
00535 if (m_pressedButton != NoButton) {
00536 m_pendingFade = true;
00537 } else {
00538 startFading(FadeOut);
00539 }
00540 }
00541
00542 bool AppletHandle::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
00543 {
00544 if (watched == m_applet && event->type() == QEvent::GraphicsSceneHoverLeave) {
00545 hoverLeaveEvent(static_cast<QGraphicsSceneHoverEvent*>(event));
00546 return true;
00547 }
00548
00549 return false;
00550 }
00551
00552 void AppletHandle::fadeAnimation(qreal progress)
00553 {
00554 qreal endOpacity = 1.0;
00555 if (m_anim==FadeOut) {
00556 endOpacity = 0.0;
00557 }
00558
00559 m_opacity += (endOpacity-m_opacity)*progress;
00560
00561 if (progress>=1.0 && m_anim==FadeOut) {
00562 emit disappearDone(this);
00563 }
00564
00565 update();
00566 }
00567
00568 void AppletHandle::fadeIn()
00569 {
00570 startFading(FadeIn);
00571 }
00572
00573 void AppletHandle::appletDestroyed()
00574 {
00575 m_applet = 0;
00576 deleteLater();
00577 }
00578
00579 void AppletHandle::appletResized()
00580 {
00581 prepareGeometryChange();
00582 calculateSize();
00583 update();
00584 }
00585
00586 void AppletHandle::startFading(FadeType anim)
00587 {
00588 if (m_animId != 0) {
00589 Phase::self()->stopCustomAnimation(m_animId);
00590 }
00591
00592 qreal time = 250;
00593 m_hoverTimer->stop();
00594
00595 if (m_applet) {
00596 m_applet->removeSceneEventFilter(this);
00597 }
00598
00599 if (anim == FadeIn) {
00600 time *= 1.0-m_opacity;
00601 } else {
00602 m_hoverTimer->stop();
00603 time *= m_opacity;
00604 }
00605
00606 m_anim = anim;
00607 m_animId = Phase::self()->customAnimation(40, (int)time, Phase::EaseInOutCurve, this, "fadeAnimation");
00608 }
00609
00610 void AppletHandle::forceDisappear()
00611 {
00612 setAcceptsHoverEvents(false);
00613 startFading(FadeOut);
00614 }
00615
00616 void AppletHandle::calculateSize()
00617 {
00618 m_rect = m_applet->boundingRect();
00619 m_rect = m_applet->mapToParent(m_rect).boundingRect();
00620
00621 const int requiredHeight = (HANDLE_WIDTH * 2) + m_applet->hasConfigurationInterface() ?
00622 ((ICON_SIZE + ICON_MARGIN) * 4) :
00623 ((ICON_SIZE + ICON_MARGIN) * 3) +
00624 ICON_MARGIN;
00625 if (m_rect.height() < requiredHeight) {
00626 float delta = requiredHeight - m_rect.height();
00627 delta = delta/2.0;
00628 if (delta > 0.0) {
00629 m_rect.adjust(0.0, -delta, 0.0, delta);
00630 }
00631 }
00632
00633 m_rect.adjust(-HANDLE_WIDTH, -HANDLE_WIDTH, HANDLE_WIDTH, HANDLE_WIDTH);
00634
00635 if (m_applet->pos().x() <= ((HANDLE_WIDTH * 2) + ICON_SIZE)) {
00636 m_rect.adjust(0.0, 0.0, ICON_SIZE, 0.0);
00637 m_buttonsOnRight = true;
00638 } else {
00639 m_rect.adjust(- ICON_SIZE, 0.0, 0.0, 0.0);
00640 }
00641 }
00642
00643 }
00644
00645 #include "applethandle_p.moc"