• Skip to content
  • Skip to link menu
KDE 4.4 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

Plasma

appletoverlay.cpp

Go to the documentation of this file.
00001 /*
00002  *   Copyright 2009 Marco Martin <notmart@gmail.com>
00003  *
00004  *   This program is free software; you can redistribute it and/or modify
00005  *   it under the terms of the GNU Library General Public License as
00006  *   published by the Free Software Foundation; either version 2, or
00007  *   (at your option) any later version.
00008  *
00009  *   This program is distributed in the hope that it will be useful,
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *   GNU General Public License for more details
00013  *
00014  *   You should have received a copy of the GNU Library General Public
00015  *   License along with this program; if not, write to the
00016  *   Free Software Foundation, Inc.,
00017  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00018  */
00019 
00020 #include "appletoverlay.h"
00021 #include "newspaper.h"
00022 #include "../common/appletmovespacer.h"
00023 
00024 #include <QGraphicsSceneMouseEvent>
00025 #include <QGraphicsLinearLayout>
00026 #include <QPainter>
00027 #include <QTimer>
00028 
00029 #include <KGlobalSettings>
00030 #include <KIconLoader>
00031 
00032 #include <Plasma/Applet>
00033 #include <Plasma/Svg>
00034 #include <Plasma/FrameSvg>
00035 #include <Plasma/PaintUtils>
00036 #include <Plasma/ScrollWidget>
00037 
00038 AppletOverlay::AppletOverlay(QGraphicsWidget *parent, Newspaper *newspaper)
00039     : QGraphicsWidget(parent),
00040       m_applet(0),
00041       m_newspaper(newspaper),
00042       m_spacer(0),
00043       m_spacerLayout(0),
00044       m_spacerIndex(0),
00045       m_scrollDown(false),
00046       m_clickDrag(false)
00047 {
00048     setAcceptHoverEvents(true);
00049     setAcceptDrops(true);
00050     setZValue(900);
00051     m_scrollTimer = new QTimer(this);
00052     m_scrollTimer->setSingleShot(false);
00053     connect(m_scrollTimer, SIGNAL(timeout()), this, SLOT(scrollTimeout()));
00054 
00055     m_icons = new Plasma::Svg(this);
00056     m_icons->setImagePath("widgets/configuration-icons");
00057     m_icons->setContainsMultipleImages(true);
00058 }
00059 
00060 AppletOverlay::~AppletOverlay()
00061 {
00062 }
00063 
00064 void AppletOverlay::appletDestroyed()
00065 {
00066     m_applet = 0;
00067 }
00068 
00069 void AppletOverlay::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
00070 {
00071     Q_UNUSED(widget)
00072 
00073     QColor c = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor);
00074     c.setAlphaF(0.15);
00075 
00076     painter->fillRect(option->exposedRect, c);
00077 
00078     if (m_applet) {
00079         QRectF geom = m_applet->contentsRect();
00080         geom.translate(m_applet->pos());
00081         //FIXME: calculate the offset ONE time, mmkay?
00082         QPointF offset = m_newspaper->m_mainWidget->pos() + m_newspaper->m_scrollWidget->pos();
00083         geom.moveTopLeft(geom.topLeft() + offset);
00084         geom = geom.intersected(m_newspaper->m_scrollWidget->geometry());
00085         c = Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor);
00086         c.setAlphaF(0.30);
00087         QPainterPath p = Plasma::PaintUtils::roundedRectangle(geom, 4);
00088         painter->save();
00089         painter->setRenderHint(QPainter::Antialiasing, true);
00090         painter->fillPath(p, c);
00091         painter->restore();
00092         QRect iconRect(0, 0, KIconLoader::SizeLarge, KIconLoader::SizeLarge);
00093         iconRect.moveCenter(geom.center().toPoint());
00094         m_icons->paint(painter, iconRect, "move");
00095     }
00096 }
00097 
00098 void AppletOverlay::mousePressEvent(QGraphicsSceneMouseEvent *event)
00099 {
00100     if (event->button() != Qt::LeftButton) {
00101         //Hack to make scene::itemAt() work
00102         int z = zValue();
00103         setZValue(-100);
00104         //FIXME:here we don't have a screen pos in the event
00105         m_newspaper->showContextMenu(event->pos(), event->pos().toPoint());
00106         setZValue(z);
00107         return;
00108     }
00109 
00110     if (m_clickDrag) {
00111         m_clickDrag = false;
00112         m_origin = QPoint();
00113         return;
00114     }
00115 
00116     if (m_applet) {
00117         m_origin = event->pos();
00118         showSpacer(event->pos());
00119         if (m_spacerLayout) {
00120             m_spacerLayout->removeItem(m_applet);
00121             m_applet->raise();
00122         }
00123         if (m_spacer) {
00124             m_spacer->setMinimumHeight(m_applet->size().height());
00125         }
00126     }
00127 }
00128 
00129 void AppletOverlay::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
00130 {
00131     if (m_clickDrag) {
00132         //Cheat and pretend a mousemoveevent is arrived
00133         QGraphicsSceneMouseEvent me;
00134         me.setPos(event->pos());
00135         me.setLastPos(event->lastPos());
00136         mouseMoveEvent(&me);
00137         return;
00138     }
00139 
00140     QPointF offset = m_newspaper->m_mainWidget->pos() + m_newspaper->m_scrollWidget->pos();
00141     disconnect(m_applet, SIGNAL(destroyed()), this, SLOT(appletDestroyed()));
00142     m_applet = 0;
00143 
00144     Plasma::Applet *oldApplet;
00145 
00146     //FIXME: is there a way more efficient than this linear one? scene()itemAt() won't work because it would always be == this
00147     foreach (Plasma::Applet *applet, m_newspaper->applets()) {
00148         if (applet->geometry().contains(event->pos()-offset)) {
00149             m_applet = applet;
00150             connect(applet, SIGNAL(destroyed()), this, SLOT(appletDestroyed()));
00151             break;
00152         }
00153     }
00154     if (m_applet != oldApplet) {
00155         update();
00156     }
00157 }
00158 
00159 void AppletOverlay::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
00160 {
00161     if (m_spacer) {
00162         QPointF delta = event->pos()-event->lastPos();
00163         m_applet->moveBy(delta.x(), delta.y());
00164         showSpacer(event->pos());
00165     }
00166 
00167     if (m_newspaper->orientation() == Qt::Vertical) {
00168         if (m_newspaper->m_scrollWidget->pos().y() + event->pos().y() > m_newspaper->m_scrollWidget->size().height()*0.70) {
00169             m_scrollTimer->start(50);
00170             m_scrollDown = true;
00171         } else if (m_newspaper->m_scrollWidget->pos().y() + event->pos().y() < m_newspaper->m_scrollWidget->size().height()*0.30) {
00172             m_scrollTimer->start(50);
00173             m_scrollDown = false;
00174         } else {
00175             m_scrollTimer->stop();
00176         }
00177     } else {
00178         if (m_newspaper->m_scrollWidget->pos().x() + event->pos().x() > m_newspaper->m_scrollWidget->size().width()*0.70) {
00179             m_scrollTimer->start(50);
00180             m_scrollDown = true;
00181         } else if (m_newspaper->m_scrollWidget->pos().x() + event->pos().x() < m_newspaper->m_scrollWidget->size().width()*0.30) {
00182             m_scrollTimer->start(50);
00183             m_scrollDown = false;
00184         } else {
00185             m_scrollTimer->stop();
00186         }
00187     }
00188 
00189     update();
00190 }
00191 
00192 void AppletOverlay::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
00193 {
00194     Q_UNUSED(event)
00195 
00196     m_scrollTimer->stop();
00197 
00198     QPoint delta = event->pos().toPoint() - m_origin.toPoint();
00199     if (m_origin != QPointF() && delta.manhattanLength() < KGlobalSettings::dndEventDelay()) {
00200         m_clickDrag = true;
00201         m_origin = QPointF();
00202         return;
00203     }
00204 
00205     if (m_spacer && m_spacerLayout) {
00206         m_spacerLayout->insertItem(m_spacerIndex, m_applet);
00207         m_spacerLayout->removeItem(m_spacer);
00208     }
00209 
00210     delete m_spacer;
00211     m_spacer = 0;
00212     m_spacerLayout = 0;
00213     m_spacerIndex = 0;
00214 }
00215 
00216 void AppletOverlay::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
00217 {
00218     showSpacer(event->pos());
00219     m_newspaper->m_dragging = true;
00220     event->accept();
00221 }
00222 
00223 void AppletOverlay::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
00224 {
00225     if (event->pos().y() > size().height()*0.70) {
00226         m_scrollTimer->start(50);
00227         m_scrollDown = true;
00228     } else if (event->pos().y() < size().height()*0.30) {
00229         m_scrollTimer->start(50);
00230         m_scrollDown = false;
00231     } else {
00232         m_scrollTimer->stop();
00233     }
00234 
00235     showSpacer(event->pos());
00236 }
00237 
00238 void AppletOverlay::dropEvent(QGraphicsSceneDragDropEvent *event)
00239 {
00240     m_newspaper->dropEvent(event);
00241     m_newspaper->m_dragging = false;
00242 
00243     if (m_spacerLayout) {
00244         m_spacerLayout->removeItem(m_spacer);
00245     }
00246 
00247     if (m_spacer) {
00248         m_spacer->deleteLater();
00249     }
00250 
00251     m_spacer = 0;
00252     m_spacerLayout = 0;
00253     m_spacerIndex = 0;
00254 }
00255 
00256 void AppletOverlay::spacerRequestedDrop(QGraphicsSceneDragDropEvent *event)
00257 {
00258     dropEvent(event);
00259 }
00260 
00261 void AppletOverlay::showSpacer(const QPointF &pos)
00262 {
00263     if (!scene()) {
00264         return;
00265     }
00266 
00267     QPointF translatedPos = pos - m_newspaper->m_mainWidget->pos() - m_newspaper->m_scrollWidget->pos();
00268 
00269     QGraphicsLinearLayout *lay = 0;
00270 
00271     for (int i = 0; i < m_newspaper->m_mainLayout->count(); ++i) {
00272         QGraphicsLinearLayout *candidateLay = dynamic_cast<QGraphicsLinearLayout *>(m_newspaper->m_mainLayout->itemAt(i));
00273 
00274         //normally should never happen
00275         if (!candidateLay) {
00276             continue;
00277         }
00278 
00279         if (m_newspaper->m_orientation == Qt::Horizontal) {
00280             if (pos.y() < candidateLay->geometry().bottom()) {
00281                 lay = candidateLay;
00282                 break;
00283             }
00284         //vertical
00285         } else {
00286             if (pos.x() < candidateLay->geometry().right()) {
00287                 lay = candidateLay;
00288                 break;
00289             }
00290         }
00291     }
00292 
00293     //couldn't decide: is the last column empty?
00294     if (!lay) {
00295         QGraphicsLinearLayout *candidateLay = dynamic_cast<QGraphicsLinearLayout *>(m_newspaper->m_mainLayout->itemAt(m_newspaper->m_mainLayout->count()-1));
00296 
00297         if (candidateLay && candidateLay->count() <= 2) {
00298             lay = candidateLay;
00299         }
00300     }
00301 
00302     //give up, make a new column
00303     if (!lay) {
00304         lay = m_newspaper->addColumn();
00305     }
00306 
00307     if (pos == QPoint()) {
00308         if (m_spacer) {
00309             lay->removeItem(m_spacer);
00310             m_spacer->hide();
00311         }
00312         return;
00313     }
00314 
00315     //lucky case: the spacer is already in the right position
00316     if (m_spacer && m_spacer->geometry().contains(translatedPos)) {
00317         return;
00318     }
00319 
00320     int insertIndex = -1;
00321 
00322     for (int i = 0; i < lay->count(); ++i) {
00323         QRectF siblingGeometry = lay->itemAt(i)->geometry();
00324 
00325         if (m_newspaper->m_orientation == Qt::Horizontal) {
00326             qreal middle = siblingGeometry.center().x();
00327             if (translatedPos.x() < middle) {
00328                 insertIndex = i;
00329                 break;
00330             } else if (translatedPos.x() <= siblingGeometry.right()) {
00331                 insertIndex = i + 1;
00332                 break;
00333             }
00334         } else { // Vertical
00335             qreal middle = siblingGeometry.center().y();
00336 
00337             if (translatedPos.y() < middle) {
00338                 insertIndex = i;
00339                 break;
00340             } else if (translatedPos.y() <= siblingGeometry.bottom()) {
00341                 insertIndex = i + 1;
00342                 break;
00343             }
00344         }
00345     }
00346 
00347     if (m_spacerLayout == lay && m_spacerIndex < insertIndex) {
00348         --insertIndex;
00349     }
00350     if (lay->count() > 1 && insertIndex >= lay->count() - 1) {
00351         --insertIndex;
00352     }
00353 
00354     m_spacerIndex = insertIndex;
00355     if (insertIndex != -1) {
00356         if (!m_spacer) {
00357             m_spacer = new AppletMoveSpacer(this);
00358             connect (m_spacer, SIGNAL(dropRequested(QGraphicsSceneDragDropEvent *)), 
00359                      this, SLOT(spacerRequestedDrop(QGraphicsSceneDragDropEvent *)));
00360         }
00361         if (m_spacerLayout) {
00362             m_spacerLayout->removeItem(m_spacer);
00363         }
00364         m_spacer->show();
00365         lay->insertItem(insertIndex, m_spacer);
00366         m_spacerLayout = lay;
00367     }
00368 }
00369 
00370 void AppletOverlay::scrollTimeout()
00371 {
00372     if (!m_applet) {
00373         return;
00374     }
00375 
00376     if (m_newspaper->orientation() == Qt::Vertical) {
00377         if (m_scrollDown) {
00378             if (m_newspaper->m_mainWidget->geometry().bottom() > m_newspaper->m_scrollWidget->geometry().bottom()) {
00379                 m_newspaper->m_mainWidget->moveBy(0, -10);
00380                 m_applet->moveBy(0, 10);
00381             }
00382         } else {
00383             if (m_newspaper->m_mainWidget->pos().y() < 0) {
00384                 m_newspaper->m_mainWidget->moveBy(0, 10);
00385                 m_applet->moveBy(0, -10);
00386             }
00387         }
00388     } else {
00389         if (m_scrollDown) {
00390             if (m_newspaper->m_mainWidget->geometry().right() > m_newspaper->m_scrollWidget->geometry().right()) {
00391                 m_newspaper->m_mainWidget->moveBy(-10, 0);
00392                 m_applet->moveBy(10, 0);
00393             }
00394         } else {
00395             if (m_newspaper->m_mainWidget->pos().x() < 0) {
00396                 m_newspaper->m_mainWidget->moveBy(10, 0);
00397                 m_applet->moveBy(-10, 0);
00398             }
00399         }
00400     }
00401 }
00402 
00403 #include <appletoverlay.moc>
00404 

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •     Animators
  •     Applets
  •     Engines
  • Solid Modules
  • System Settings
  •   SystemSettingsView
Generated for API Reference by doxygen 1.5.9-20090814
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal