00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "desktoptoolbox_p.h"
00022
00023 #include <QGraphicsSceneHoverEvent>
00024 #include <QPainter>
00025 #include <QRadialGradient>
00026 #include <QGraphicsView>
00027 #include <QAction>
00028
00029 #include <kcolorscheme.h>
00030 #include <kdebug.h>
00031
00032 #include <plasma/theme.h>
00033 #include <plasma/paintutils.h>
00034 #include <plasma/framesvg.h>
00035
00036 #include <plasma/applet.h>
00037 #include <plasma/containment.h>
00038 #include <plasma/widgets/iconwidget.h>
00039
00040 namespace Plasma
00041 {
00042
00043 class EmptyGraphicsItem : public QGraphicsItem
00044 {
00045 public:
00046 EmptyGraphicsItem(QGraphicsItem *parent)
00047 : QGraphicsItem(parent),
00048 m_toolbar(false)
00049 {
00050 setAcceptsHoverEvents(true);
00051 m_background = new Plasma::FrameSvg();
00052 m_toolbarBackground = new Plasma::FrameSvg();
00053
00054 m_toolbarBackground->setImagePath("widgets/background");
00055 m_background->setImagePath("widgets/translucentbackground");
00056
00057 m_toolbarBackground->setEnabledBorders(FrameSvg::LeftBorder|FrameSvg::RightBorder|FrameSvg::BottomBorder);
00058 m_background->setEnabledBorders(FrameSvg::AllBorders);
00059 }
00060
00061 ~EmptyGraphicsItem()
00062 {
00063 delete m_background;
00064 delete m_toolbarBackground;
00065 }
00066
00067 QRectF boundingRect() const
00068 {
00069 return QRectF(QPointF(0, 0), m_rect.size());
00070 }
00071
00072 QRectF rect() const
00073 {
00074 return m_rect;
00075 }
00076
00077 void setIsToolbar(bool toolbar)
00078 {
00079 m_toolbar = toolbar;
00080 }
00081
00082 bool isToolbar() const
00083 {
00084 return m_toolbar;
00085 }
00086
00087 void getContentsMargins(qreal &left, qreal &top, qreal &right, qreal &bottom)
00088 {
00089 if (m_toolbar) {
00090 m_toolbarBackground->getMargins(left, top, right, bottom);
00091 } else {
00092 m_background->getMargins(left, top, right, bottom);
00093 }
00094 }
00095
00096 QRectF contentsRect() const
00097 {
00098 qreal left, top, right, bottom;
00099
00100 if (m_toolbar) {
00101 m_toolbarBackground->getMargins(left, top, right, bottom);
00102 } else {
00103 m_background->getMargins(left, top, right, bottom);
00104 }
00105 return m_rect.adjusted(left, top, -right, -bottom);
00106 }
00107
00108 void setRect(const QRectF &rect)
00109 {
00110
00111 prepareGeometryChange();
00112 m_rect = rect;
00113 setPos(m_rect.topLeft());
00114 if (m_toolbar) {
00115 m_toolbarBackground->resizeFrame(m_rect.size());
00116 } else {
00117 m_background->resizeFrame(m_rect.size());
00118 }
00119 }
00120
00121 void paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
00122 {
00123 if (m_toolbar) {
00124 m_toolbarBackground->paintFrame(p);
00125 } else {
00126 m_background->paintFrame(p);
00127 }
00128 }
00129
00130 private:
00131 bool m_toolbar;
00132 QRectF m_rect;
00133 Plasma::FrameSvg *m_toolbarBackground;
00134 Plasma::FrameSvg *m_background;
00135 };
00136
00137
00138 static const int ToolName = 7001;
00139
00140 class DesktopToolBoxPrivate
00141 {
00142 public:
00143 DesktopToolBoxPrivate(DesktopToolBox *toolbox)
00144 : q(toolbox),
00145 containment(0),
00146 icon("plasma"),
00147 toolBacker(0),
00148 animCircleId(0),
00149 animHighlightId(0),
00150 animCircleFrame(0),
00151 animHighlightFrame(0),
00152 hovering(0)
00153 {}
00154
00155
00156 DesktopToolBox *q;
00157 Plasma::FrameSvg *background;
00158 Containment *containment;
00159 KIcon icon;
00160 EmptyGraphicsItem *toolBacker;
00161 int animCircleId;
00162 int animHighlightId;
00163 qreal animCircleFrame;
00164 qreal animHighlightFrame;
00165 QRect shapeRect;
00166 QColor fgColor;
00167 QColor bgColor;
00168 bool hovering : 1;
00169 };
00170
00171 DesktopToolBox::DesktopToolBox(Containment *parent)
00172 : ToolBox(parent),
00173 d(new DesktopToolBoxPrivate(this))
00174 {
00175 d->containment = parent;
00176 setZValue(10000000);
00177 setFlag(ItemClipsToShape, true);
00178 setFlag(ItemClipsChildrenToShape, false);
00179 setFlag(ItemIgnoresTransformations, true);
00180 setIsMovable(true);
00181 assignColors();
00182
00183 d->background = new Plasma::FrameSvg();
00184 d->background->setImagePath("widgets/translucentbackground");
00185
00186 connect(Plasma::Animator::self(), SIGNAL(movementFinished(QGraphicsItem*)),
00187 this, SLOT(toolMoved(QGraphicsItem*)));
00188 connect(this, SIGNAL(toggled()), this, SLOT(toggle()));
00189 connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()),
00190 this, SLOT(assignColors()));
00191 }
00192
00193 DesktopToolBox::~DesktopToolBox()
00194 {
00195 delete d;
00196 }
00197
00198 QRectF DesktopToolBox::boundingRect() const
00199 {
00200 return QRectF(0, 0, size(), size());
00201 }
00202
00203 void DesktopToolBox::assignColors()
00204 {
00205 d->bgColor = Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor);
00206 d->fgColor = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor);
00207 }
00208
00209 void DesktopToolBox::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
00210 {
00211 Q_UNUSED(option)
00212 Q_UNUSED(widget)
00213
00214 if (isToolbar()){
00215 return;
00216 }
00217
00218 QPainterPath p = shape();
00219
00220 QPoint iconPos;
00221 QPointF gradientCenter;
00222 const QRectF rect = boundingRect();
00223 const QSize icons = iconSize();
00224 bool atCorner;
00225
00226 switch (corner()) {
00227 case TopRight:
00228 iconPos = QPoint((int)rect.right() - icons.width() + 2, 2);
00229 gradientCenter = rect.topRight();
00230 atCorner = true;
00231 break;
00232 case Top:
00233 iconPos = QPoint(rect.center().x() - icons.width() / 2, 2);
00234 gradientCenter = QPoint(rect.center().x(), rect.y());
00235 atCorner = false;
00236 d->background->setEnabledBorders(FrameSvg::BottomBorder|FrameSvg::LeftBorder|FrameSvg::RightBorder);
00237 break;
00238 case TopLeft:
00239 iconPos = QPoint(2, 2);
00240 gradientCenter = rect.topLeft();
00241 atCorner = true;
00242 break;
00243 case Left:
00244 iconPos = QPoint(2, rect.center().y() - icons.height() / 2);
00245 gradientCenter = QPointF(rect.left(), rect.center().y());
00246 atCorner = false;
00247 d->background->setEnabledBorders(FrameSvg::BottomBorder|FrameSvg::TopBorder|FrameSvg::RightBorder);
00248 break;
00249 case Right:
00250 iconPos = QPoint((int)rect.right() - icons.width() + 2,
00251 rect.center().y() - icons.height() / 2);
00252 gradientCenter = QPointF(rect.right(), rect.center().y());
00253 atCorner = false;
00254 d->background->setEnabledBorders(FrameSvg::BottomBorder|FrameSvg::TopBorder|FrameSvg::LeftBorder);
00255 break;
00256 case BottomLeft:
00257 iconPos = QPoint(2, rect.bottom() - icons.height() - 2);
00258 gradientCenter = rect.bottomLeft();
00259 atCorner = true;
00260 break;
00261 case Bottom:
00262 iconPos = QPoint(rect.center().x() - icons.width() / 2,
00263 rect.bottom() - icons.height() - 2);
00264 gradientCenter = QPointF(rect.center().x(), rect.bottom());
00265 atCorner = false;
00266 d->background->setEnabledBorders(FrameSvg::TopBorder|FrameSvg::LeftBorder|FrameSvg::RightBorder);
00267 break;
00268 case BottomRight:
00269 default:
00270 iconPos = QPoint((int)rect.right() - icons.width() + 2,
00271 (int)rect.bottom() - icons.height() - 2);
00272 gradientCenter = rect.bottomRight();
00273 atCorner = true;
00274 break;
00275 }
00276
00277 if (atCorner) {
00278 d->bgColor.setAlpha(64);
00279 d->fgColor.setAlpha(64);
00280 QRadialGradient gradient(gradientCenter, size() + d->animCircleFrame);
00281 gradient.setFocalPoint(gradientCenter);
00282 gradient.setColorAt(0, d->bgColor);
00283 gradient.setColorAt(.87, d->bgColor);
00284 gradient.setColorAt(.97, d->fgColor);
00285 d->fgColor.setAlpha(0);
00286 gradient.setColorAt(1, d->fgColor);
00287 painter->save();
00288 painter->setPen(Qt::NoPen);
00289 painter->setRenderHint(QPainter::Antialiasing, true);
00290 painter->setBrush(gradient);
00291 painter->drawPath(p);
00292 painter->restore();
00293 } else {
00294 d->background->resizeFrame(rect.size());
00295 d->background->paintFrame(painter);
00296 }
00297
00298 const qreal progress = d->animHighlightFrame;
00299
00300 if (qFuzzyCompare(qreal(1.0), progress)) {
00301 d->icon.paint(painter, QRect(iconPos, iconSize()));
00302 } else if (qFuzzyCompare(qreal(1.0), 1 + progress)) {
00303 d->icon.paint(painter, QRect(iconPos, iconSize()),
00304 Qt::AlignCenter, QIcon::Disabled, QIcon::Off);
00305 } else {
00306 QPixmap disabled = d->icon.pixmap(iconSize(), QIcon::Disabled, QIcon::Off);
00307 QPixmap enabled = d->icon.pixmap(iconSize());
00308 QPixmap result = PaintUtils::transition(
00309 d->icon.pixmap(iconSize(), QIcon::Disabled, QIcon::Off),
00310 d->icon.pixmap(iconSize()), progress);
00311 painter->drawPixmap(QRect(iconPos, iconSize()), result);
00312 }
00313 }
00314
00315 QPainterPath DesktopToolBox::shape() const
00316 {
00317 const QRectF rect = boundingRect();
00318 const int w = rect.width();
00319 const int h = rect.height();
00320
00321 QPainterPath path;
00322 switch (corner()) {
00323 case BottomLeft:
00324 path.moveTo(rect.bottomLeft());
00325 path.arcTo(QRectF(rect.left() - w, rect.top(), w * 2, h * 2), 0, 90);
00326 break;
00327 case BottomRight:
00328 path.moveTo(rect.bottomRight());
00329 path.arcTo(QRectF(rect.left(), rect.top(), w * 2, h * 2), 90, 90);
00330 break;
00331 case TopRight:
00332 path.moveTo(rect.topRight());
00333 path.arcTo(QRectF(rect.left(), rect.top() - h, w * 2, h * 2), 180, 90);
00334 break;
00335 case TopLeft:
00336 path.arcTo(QRectF(rect.left() - w, rect.top() - h, w * 2, h * 2), 270, 90);
00337 break;
00338 default:
00339 path.addRect(rect);
00340 break;
00341 }
00342
00343 return path;
00344 }
00345
00346 void DesktopToolBox::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
00347 {
00348 if (showing() || d->hovering) {
00349 QGraphicsItem::hoverEnterEvent(event);
00350 return;
00351 }
00352 Plasma::Animator *animdriver = Plasma::Animator::self();
00353 if (d->animHighlightId) {
00354 animdriver->stopCustomAnimation(d->animHighlightId);
00355 }
00356 d->hovering = true;
00357 d->animHighlightId =
00358 animdriver->customAnimation(
00359 10, 240, Plasma::Animator::EaseInCurve, this, "animateHighlight");
00360
00361 QGraphicsItem::hoverEnterEvent(event);
00362 }
00363
00364 void DesktopToolBox::showToolBox()
00365 {
00366 if (showing() && !isToolbar()) {
00367 return;
00368 }
00369
00370
00371 const int iconWidth = 32;
00372 int x;
00373 int y;
00374 switch (corner()) {
00375 case TopRight:
00376 x = (int)boundingRect().right() - iconWidth - 5;
00377 y = (int)boundingRect().top() + 10;
00378 break;
00379 case Top:
00380 x = (int)boundingRect().center().x() - iconWidth;
00381 y = (int)boundingRect().top() + iconWidth + 10;
00382 break;
00383 case TopLeft:
00384 x = (int)boundingRect().left() + iconWidth + 5;
00385 y = (int)boundingRect().top() + 10;
00386 break;
00387 case Left:
00388 x = (int)boundingRect().left() + iconWidth + 5;
00389 y = (int)boundingRect().center().y() - iconWidth;
00390 break;
00391 case Right:
00392 x = (int)boundingRect().right() - iconWidth - 5;
00393 y = (int)boundingRect().center().y() - iconWidth;
00394 break;
00395 case BottomLeft:
00396 x = (int)boundingRect().left() + iconWidth + 5;
00397 y = (int)boundingRect().bottom() - 5;
00398 break;
00399 case Bottom:
00400 x = (int)boundingRect().center().x() - iconWidth;
00401 y = (int)boundingRect().bottom() - iconWidth - 5;
00402 break;
00403 case BottomRight:
00404 default:
00405 x = (int)boundingRect().right() - iconWidth - 5;
00406 y = (int)boundingRect().bottom() - iconWidth - 5;
00407 break;
00408 }
00409
00410 int startY = y;
00411
00412
00413
00414 int maxWidth = 0;
00415 int maxHeight = 0;
00416 int totalWidth = 0;
00417
00418 foreach (QGraphicsItem *tool, QGraphicsItem::children()) {
00419 if (tool == d->toolBacker) {
00420 continue;
00421 }
00422
00423 Plasma::IconWidget *icon = qgraphicsitem_cast<Plasma::IconWidget *>(tool);
00424 if (icon) {
00425 if (viewTransform().m11() != Plasma::scalingFactor(Plasma::OverviewZoom) &&
00426 (viewTransform().m11() == Plasma::scalingFactor(Plasma::DesktopZoom) ||
00427 icon->action() == d->containment->action("add sibling containment") ||
00428 icon->action() == d->containment->action("add widgets"))) {
00429 icon->setText(icon->action()->text());
00430 icon->resize(icon->sizeFromIconSize(22));
00431 } else {
00432 icon->setText(QString());
00433 icon->resize(icon->sizeFromIconSize(22));
00434 }
00435 }
00436
00437 if (tool->isEnabled()) {
00438 tool->show();
00439
00440 y += 5;
00441 QSize toolSize = tool->boundingRect().size().toSize();
00442 totalWidth += toolSize.width() + 5;
00443
00444 maxWidth = qMax(toolSize.width(), maxWidth);
00445 maxHeight = qMax(toolSize.height(), maxHeight);
00446 y += static_cast<int>(tool->boundingRect().height());
00447 }
00448 }
00449
00450 if (corner() == TopRight || corner() == Right || corner() == BottomRight) {
00451 x -= maxWidth;
00452 }
00453
00454 y += 5;
00455
00456 QRectF backerRect = QRectF(QPointF(x, startY), QSizeF(maxWidth + 10, y - startY));
00457
00458 if (!d->toolBacker) {
00459 d->toolBacker = new EmptyGraphicsItem(this);
00460 d->toolBacker->setZValue(zValue() + 1);
00461 }
00462
00463 d->toolBacker->setIsToolbar(isToolbar());
00464
00465 if (isToolbar()) {
00466 QPointF topRight;
00467
00468
00469 if (d->containment) {
00470 topRight = viewTransform().map(mapFromParent(d->containment->boundingRect().bottomRight()));
00471 } else {
00472 topRight = boundingRect().topRight();
00473 }
00474
00475 qreal left, top, right, bottom;
00476 d->toolBacker->getContentsMargins(left, top, right, bottom);
00477 x -= left;
00478
00479 backerRect.setSize(QSize(totalWidth+left+right, maxHeight+top+bottom));
00480 backerRect.moveTopRight(topRight);
00481 } else {
00482
00483
00484
00485 backerRect = mapToParent(backerRect).boundingRect();
00486 QSizeF parentSize = parentWidget()->size();
00487 if (backerRect.x() < 5) {
00488 backerRect.moveLeft(5);
00489 } else if (backerRect.right() > parentSize.width() - 5) {
00490 backerRect.moveRight(parentSize.width() - 5);
00491 }
00492
00493 if (backerRect.y() < 5) {
00494 backerRect.moveTop(5);
00495 } else if (backerRect.bottom() > parentSize.height() - 5) {
00496 backerRect.moveBottom(parentSize.height() - 5);
00497 }
00498
00499
00500 backerRect = mapFromParent(backerRect).boundingRect();
00501 }
00502 x = backerRect.x() + 5;
00503 y = backerRect.y();
00504
00505
00506 Plasma::Animator *animdriver = Plasma::Animator::self();
00507 foreach (QGraphicsItem *tool, QGraphicsItem::children()) {
00508 if (tool == d->toolBacker) {
00509 continue;
00510 }
00511
00512 if (tool->isEnabled()) {
00513 if (isToolbar()) {
00514
00515 x += 5;
00516
00517 tool->show();
00518 tool->setPos(QPoint(x, y));
00519 x += static_cast<int>(tool->boundingRect().width());
00520 } else {
00521
00522 y += 5;
00523
00524 tool->show();
00525 animdriver->moveItem(tool, Plasma::Animator::SlideInMovement, QPoint(x, y));
00526
00527 y += static_cast<int>(tool->boundingRect().height());
00528 }
00529 } else if (tool->isVisible()) {
00530
00531 const int height = static_cast<int>(tool->boundingRect().height());
00532 if (isToolbar()) {
00533 tool->hide();
00534 } else {
00535 animdriver->moveItem(tool, Plasma::Animator::SlideOutMovement, toolPosition(height));
00536 }
00537 }
00538 }
00539
00540
00541 d->toolBacker->setRect(backerRect);
00542 d->toolBacker->show();
00543
00544 if (d->animCircleId) {
00545 animdriver->stopCustomAnimation(d->animCircleId);
00546 }
00547
00548 setShowing(true);
00549 }
00550
00551 void DesktopToolBox::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
00552 {
00553
00554
00555 if (!d->hovering || isToolbar()) {
00556 QGraphicsItem::hoverLeaveEvent(event);
00557 return;
00558 }
00559
00560 hideToolBox();
00561 Plasma::Animator *animdriver = Plasma::Animator::self();
00562 if (d->animHighlightId) {
00563 animdriver->stopCustomAnimation(d->animHighlightId);
00564 }
00565 d->hovering = false;
00566 d->animHighlightId =
00567 animdriver->customAnimation(
00568 10, 240, Plasma::Animator::EaseOutCurve, this, "animateHighlight");
00569
00570 QGraphicsItem::hoverLeaveEvent(event);
00571 }
00572
00573 void DesktopToolBox::hideToolBox()
00574 {
00575 if (!showing()) {
00576 return;
00577 }
00578
00579 Plasma::Animator *animdriver = Plasma::Animator::self();
00580 foreach (QGraphicsItem *tool, QGraphicsItem::children()) {
00581 if (tool == d->toolBacker) {
00582 continue;
00583 }
00584
00585 const int height = static_cast<int>(tool->boundingRect().height());
00586 if (isToolbar()) {
00587 tool->setPos(toolPosition(height));
00588 tool->hide();
00589 } else {
00590 animdriver->moveItem(tool, Plasma::Animator::SlideOutMovement, toolPosition(height));
00591 }
00592 }
00593
00594 if (d->animCircleId) {
00595 animdriver->stopCustomAnimation(d->animCircleId);
00596 }
00597
00598 setShowing(false);
00599
00600 if (d->toolBacker) {
00601 d->toolBacker->hide();
00602 }
00603 }
00604
00605 void DesktopToolBox::animateHighlight(qreal progress)
00606 {
00607 if (d->hovering) {
00608 d->animHighlightFrame = progress;
00609 } else {
00610 d->animHighlightFrame = 1.0 - progress;
00611 }
00612
00613 if (progress >= 1) {
00614 d->animHighlightId = 0;
00615 }
00616
00617 update();
00618 }
00619
00620 void DesktopToolBox::toolMoved(QGraphicsItem *item)
00621 {
00622
00623 if (!showing() &&
00624 QGraphicsItem::children().indexOf(static_cast<Plasma::Applet*>(item)) != -1) {
00625 item->hide();
00626 }
00627 }
00628
00629 void DesktopToolBox::toggle()
00630 {
00631 if (isToolbar()) {
00632 return;
00633 }
00634
00635 if (showing()) {
00636 hideToolBox();
00637 } else {
00638 showToolBox();
00639 }
00640 }
00641
00642 }
00643
00644 #include "desktoptoolbox_p.moc"