dtor first
[personal-kdebase.git] / workspace / plasma / shells / desktop / panelappletoverlay.cpp
blobe32b874616cb225b9ad8e2345180ec18b6a90cc9
1 /*
2 * Copyright 2008 Aaron Seigo <aseigo@kde.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2,
7 * or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 #include "panelappletoverlay.h"
22 #include <QApplication>
23 #include <QGraphicsLinearLayout>
24 #include <QPainter>
25 #include <QTimer>
27 #include <KGlobalSettings>
28 #include <KIcon>
30 #include <Plasma/Applet>
31 #include <Plasma/Containment>
32 #include <Plasma/PaintUtils>
33 #include <Plasma/Theme>
34 #include <Plasma/View>
36 class AppletMoveSpacer : public QGraphicsWidget
38 public:
39 AppletMoveSpacer(Plasma::Applet *applet)
40 : QGraphicsWidget(applet->containment()),
41 m_applet(applet)
45 protected:
46 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget * widget = 0)
48 Q_UNUSED(option)
49 Q_UNUSED(widget)
52 results in odd painting corruption
53 if (collidesWithItem(m_applet, Qt::IntersectsItemBoundingRect)) {
54 painter->fillRect(contentsRect(), Qt::transparent);
55 return;
59 //TODO: make this a pretty gradient?
60 painter->setRenderHint(QPainter::Antialiasing);
61 QPainterPath p = Plasma::PaintUtils::roundedRectangle(contentsRect().adjusted(1, 1, -2, -2), 4);
62 QColor c = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor);
63 c.setAlphaF(0.3);
65 painter->fillPath(p, c);
68 private:
69 QGraphicsWidget *m_applet;
72 PanelAppletOverlay::PanelAppletOverlay(Plasma::Applet *applet, QWidget *parent)
73 : QWidget(parent),
74 m_applet(applet),
75 m_spacer(0),
76 m_layout(static_cast<QGraphicsLinearLayout*>(applet->containment()->layout())), // ++assumptions;
77 m_index(0),
78 m_clickDrag(false)
80 int i = 0;
81 for (; i < m_layout->count(); ++i) {
82 QGraphicsWidget *w = dynamic_cast<QGraphicsWidget*>(m_layout->itemAt(i));
83 if (w == m_applet) {
84 m_index = i;
85 break;
89 syncOrientation();
90 syncGeometry();
92 connect(m_applet, SIGNAL(destroyed(QObject*)), this, SLOT(deleteLater()));
93 connect(m_applet, SIGNAL(geometryChanged()), this, SLOT(delaySyncGeometry()));
96 PanelAppletOverlay::~PanelAppletOverlay()
98 if (m_spacer) {
99 if (m_layout) {
100 m_layout->removeItem(m_spacer);
103 m_spacer->deleteLater();
104 m_spacer = 0;
108 void PanelAppletOverlay::paintEvent(QPaintEvent *event)
110 Q_UNUSED(event)
112 QStyleOption op;
113 op.initFrom(this);
115 bool hovered = op.state & QStyle::State_MouseOver;
116 bool mover = mouseGrabber() == this;
117 if (!hovered || mover) {
118 return;
121 QPainter p(this);
122 KIcon icon("transform-move");
123 int iconSize;
124 QRect iconRect;
126 if (m_orientation == Qt::Horizontal) {
127 iconSize = qMin(qMin(height(), int(m_applet->size().width())), 64);
128 iconRect = QRect(rect().center() - QPoint(iconSize / 2, iconSize / 2), QSize(iconSize, iconSize));
129 } else {
130 iconSize = qMin(qMin(width(), int(m_applet->size().height())), 64);
131 iconRect = QRect(rect().center() - QPoint(iconSize / 2, iconSize / 2), QSize(iconSize, iconSize));
134 p.drawPixmap(iconRect, icon.pixmap(iconSize, iconSize));
137 void PanelAppletOverlay::mousePressEvent(QMouseEvent *event)
139 Q_UNUSED(event)
141 //kDebug() << m_clickDrag;
142 if (m_clickDrag) {
143 setMouseTracking(false);
144 m_clickDrag = false;
145 m_origin = QPoint();
146 return;
149 if (event->button() != Qt::LeftButton) {
150 //kDebug() << "sending even to" << (QWidget*)parent();
151 Plasma::View *view = dynamic_cast<Plasma::View*>(parent());
153 if (view && view->containment()) {
154 view->containment()->showContextMenu(mapToParent(event->pos()), event->globalPos());
157 return;
160 m_clickDrag = false;
161 if (!m_spacer) {
162 m_spacer = new AppletMoveSpacer(m_applet);
163 } else {
164 m_layout->removeItem(m_spacer);
167 m_origin = mapToParent(event->pos());
168 m_spacer->setMinimumSize(m_applet->geometry().size());
169 m_spacer->setMaximumSize(m_applet->geometry().size());
170 m_layout->removeItem(m_applet);
171 m_layout->insertItem(m_index, m_spacer);
172 m_applet->setZValue(m_applet->zValue() + 1);
174 if (m_orientation == Qt::Horizontal) {
175 m_offset = geometry().x() - m_origin.x();
176 } else {
177 m_offset = geometry().y() - m_origin.y();
180 grabMouse();
183 void PanelAppletOverlay::mouseMoveEvent(QMouseEvent *event)
185 if (!m_layout) {
186 return;
189 Plasma::FormFactor f = m_applet->formFactor();
191 if ( ((f != Plasma::Horizontal && f != Plasma::Vertical) && rect().intersects(m_applet->rect().toRect())) ||
192 ((f == Plasma::Horizontal || f == Plasma::Vertical) && !rect().contains(event->globalPos())) ) {
193 Plasma::View *view = Plasma::View::topLevelViewAt(event->globalPos());
194 kDebug() << "checking view" << view << m_applet->view();
196 if (!view) {
197 return;
200 QPointF pos = view->mapFromGlobal(event->globalPos());
201 if (view != m_applet->view()) {
202 Plasma::Containment *c = view->containment();
204 syncOrientation();
205 syncGeometry();
207 if (m_spacer) {
208 m_layout->removeItem(m_spacer);
209 m_spacer->deleteLater();
210 m_spacer = 0;
213 QPointF pos = m_applet->view()->mapFromGlobal(event->globalPos());
214 QRectF g = m_applet->geometry();
215 pos += QPoint(m_offset, m_offset);
216 g.moveTo(pos);
217 m_applet->setGeometry(g);
218 m_layout->removeItem(m_spacer);
219 m_spacer->deleteLater();
220 m_layout = 0;
221 m_spacer = 0;
222 c->addApplet(m_applet, pos, false);
223 releaseMouse();
224 return;
228 if (!m_spacer) {
229 m_spacer = new AppletMoveSpacer(m_applet);
230 m_spacer->setMinimumSize(m_applet->geometry().size());
231 m_spacer->setMaximumSize(m_applet->geometry().size());
232 m_layout->removeItem(m_applet);
233 m_layout->insertItem(m_index, m_spacer);
236 QPoint p = mapToParent(event->pos());
237 QRectF g = m_applet->geometry();
239 //kDebug() << p << g << "<-- movin'?";
240 if (m_orientation == Qt::Horizontal) {
241 g.moveLeft(p.x() + m_offset);
242 } else {
243 g.moveTop(p.y() + m_offset);
246 m_applet->setGeometry(g);
248 // swap items if we pass completely over the next/previous item or cross
249 // more than halfway across it, whichever comes first
250 if (m_orientation == Qt::Horizontal) {
251 //kDebug() << m_prevGeom << g << m_nextGeom;
252 if (m_prevGeom.isValid() && g.left() <= m_prevGeom.left()) {
253 swapWithPrevious();
254 } else if (m_nextGeom.isValid() && g.right() >= m_nextGeom.right()) {
255 swapWithNext();
257 } else if (m_prevGeom.isValid() && g.top() <= m_prevGeom.top()) {
258 swapWithPrevious();
259 } else if (m_nextGeom.isValid() && g.bottom() >= m_nextGeom.bottom()) {
260 swapWithNext();
263 //kDebug() << "=================================";
266 void PanelAppletOverlay::mouseReleaseEvent(QMouseEvent *event)
268 Q_UNUSED(event)
269 if (!m_spacer) {
270 releaseMouse();
271 return;
274 if (!m_origin.isNull()) {
275 //kDebug() << m_clickDrag << m_origin << mapToParent(event->pos());
276 if (m_orientation == Qt::Horizontal) {
277 m_clickDrag = abs(mapToParent(event->pos()).x() - m_origin.x()) < KGlobalSettings::dndEventDelay();
278 } else {
279 m_clickDrag = abs(mapToParent(event->pos()).y() - m_origin.y()) < KGlobalSettings::dndEventDelay();
282 if (m_clickDrag) {
283 //kDebug() << "click dragging." << this << mouseGrabber();
284 setMouseTracking(true);
285 event->setAccepted(false);
286 return;
290 releaseMouse();
291 //kDebug();
292 m_layout->removeItem(m_spacer);
293 m_spacer->deleteLater();
294 m_spacer = 0;
296 m_layout->insertItem(m_index, m_applet);
297 m_applet->setZValue(m_applet->zValue() - 1);
300 void PanelAppletOverlay::enterEvent(QEvent *event)
302 Q_UNUSED(event)
303 update();
306 void PanelAppletOverlay::leaveEvent(QEvent *event)
308 Q_UNUSED(event)
309 update();
312 void PanelAppletOverlay::swapWithPrevious()
314 //kDebug();
315 --m_index;
317 if (m_index > 0) {
318 m_prevGeom = m_layout->itemAt(m_index - 1)->geometry();
319 } else {
320 m_prevGeom = QRectF();
323 m_nextGeom = m_layout->itemAt(m_index + 1)->geometry();
324 m_layout->removeItem(m_spacer);
325 m_layout->insertItem(m_index, m_spacer);
328 void PanelAppletOverlay::swapWithNext()
330 //kDebug();
331 ++m_index;
333 if (m_index < m_layout->count() - 1) {
334 m_nextGeom = m_layout->itemAt(m_index + 1)->geometry();
335 } else {
336 m_nextGeom = QRectF();
339 m_prevGeom = m_layout->itemAt(m_index - 1)->geometry();
340 m_layout->removeItem(m_spacer);
341 m_layout->insertItem(m_index, m_spacer);
344 void PanelAppletOverlay::delaySyncGeometry()
346 // we need to do this because it gets called in a round-about-way
347 // from our own mouseMoveEvent. if we call syncGeometry directly,
348 // we end up with a maze of duplicated and confused mouseMoveEvents
349 // of which only half are real (the other half being caused by the
350 // immediate call to syncGeometry!)
351 QTimer::singleShot(0, this, SLOT(syncGeometry()));
354 void PanelAppletOverlay::syncGeometry()
356 if (!m_layout) {
357 return;
360 //kDebug();
361 setGeometry(m_applet->geometry().toRect());
363 if (m_index > 0) {
364 m_prevGeom = m_layout->itemAt(m_index - 1)->geometry();
365 } else {
366 m_prevGeom = QRectF();
369 //kDebug() << m_index << m_layout->count();
370 if (m_index < m_layout->count() - 1) {
371 m_nextGeom = m_layout->itemAt(m_index + 1)->geometry();
372 } else {
373 m_nextGeom = QRectF();
377 void PanelAppletOverlay::syncOrientation()
379 m_orientation = m_applet->formFactor() == Plasma::Horizontal ? Qt::Horizontal : Qt::Vertical;
382 #include "panelappletoverlay.moc"