Start of improved applet drag & drop. What works now is:

* dragging an applet creates a top level window so the applet won't appear behind the panel 
when dragging, as is the case now.
* dragging leaves a semi transparent version of the applet at the original location, so it's
clear to the user where the applet came from and where it will go when the drag is cancelled.

There are still some open issues, I'm working on those...


svn path=/trunk/KDE/kdebase/workspace/libs/plasma/; revision=806484
This commit is contained in:
Rob Scheepmaker 2008-05-11 13:56:35 +00:00
parent bb55e8eb78
commit 1172ef79e9
5 changed files with 123 additions and 31 deletions

View File

@ -700,23 +700,43 @@ QList<QAction*> Applet::contextualActions()
void Applet::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QPainter *p;
QPixmap pixmap(size().toSize());
QGraphicsView* qgv = qobject_cast<QGraphicsView*>(widget->parent());
bool ghost = (qgv && (qgv == d->ghostView));
if (ghost) {
// The applet has to be displayed semi transparent. Create a pixmap and a painter on
// that pixmap where the applet can draw on so we can draw the result transparently
// at the end.
kDebug() << "Painting ghosted...";
pixmap.fill(Qt::transparent);
p = new QPainter();
p->begin(&pixmap);
} else {
p = painter;
}
if (d->shadow && d->shadow->shadowedSize() != boundingRect().size()) {
//kDebug() << "sizes are " << d->shadow->shadowedSize() << boundingRect().size();
d->shadow->generate();
}
painter->save();
p->save();
if (transform().isRotating()) {
painter->setRenderHint(QPainter::SmoothPixmapTransform);
painter->setRenderHint(QPainter::Antialiasing);
p->setRenderHint(QPainter::SmoothPixmapTransform);
p->setRenderHint(QPainter::Antialiasing);
}
if (d->background &&
formFactor() != Plasma::Vertical &&
formFactor() != Plasma::Horizontal) {
//kDebug() << "option rect is" << option->rect;
d->background->paintPanel(painter, option->rect, QPointF(0,0));
d->background->paintPanel(p, option->rect, QPointF(0,0));
}
if (!d->failed) {
@ -731,17 +751,29 @@ void Applet::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QW
Containment::StyleOption coption(*option);
coption.view = v;
paintInterface(painter, &coption, contentsRect);
paintInterface(p, &coption, contentsRect);
}
painter->restore();
p->restore();
return;
}
//kDebug() << "paint interface of" << (QObject*) this;
paintInterface(painter, option, contentsRect);
paintInterface(p, option, contentsRect);
}
p->restore();
if (ghost) {
// Lets display the pixmap that we've just drawn... transparently.
p->setCompositionMode(QPainter::CompositionMode_DestinationIn);
p->fillRect(pixmap.rect(), QColor(0, 0, 0, (0.3 * 255)));
p->end();
delete p;
kDebug() << "draw the pixmap!";
painter->drawPixmap(0, 0, pixmap);
}
painter->restore();
}
void Applet::paintInterface(QPainter *painter, const QStyleOptionGraphicsItem *option,
@ -800,6 +832,17 @@ void Applet::setAspectRatioMode(Plasma::AspectRatioMode mode)
d->aspectRatioMode = mode;
}
QGraphicsView * Applet::ghostView()
{
return d->ghostView;
}
void Applet::setGhostView( QGraphicsView * view )
{
d->ghostView = view;
update();
}
void Applet::registerAsDragHandle( QGraphicsItem * item )
{
if (!item) {

View File

@ -230,6 +230,19 @@ class PLASMA_EXPORT Applet : public QGraphicsWidget
*/
void setAspectRatioMode(Plasma::AspectRatioMode);
/**
* @return The view where the applet appears ghosted.
*/
QGraphicsView * ghostView();
/**
* Sets a view which displays the applet semi transparent.
*
* @param view The view where the applet should appear 'ghosted'. Set to
* 0 to don't ghost the applet anywhere.
*/
void setGhostView(QGraphicsView * view);
/**
* Returns a list of all known applets.
*

View File

@ -85,6 +85,7 @@ public:
KConfigGroup *mainConfig;
Plasma::Constraints pendingConstraints;
Plasma::AspectRatioMode aspectRatioMode;
QGraphicsView* ghostView;
ImmutabilityType immutability;
int constraintsTimerId;
bool hasConfigurationInterface : 1;

View File

@ -28,6 +28,7 @@
#include <KColorScheme>
#include <KGlobalSettings>
#include <KIcon>
#include <KWindowSystem>
#include <cmath>
#include <math.h>
@ -57,7 +58,8 @@ AppletHandle::AppletHandle(Containment *parent, Applet *applet)
m_scaleWidth(1.0),
m_scaleHeight(1.0),
m_buttonsOnRight(false),
m_pendingFade(false)
m_pendingFade(false),
m_topview(0)
{
KColorScheme colorScheme(QPalette::Active, KColorScheme::View, Theme::defaultTheme()->colorScheme());
m_gradientColor = colorScheme.background(KColorScheme::NormalBackground).color();
@ -270,6 +272,10 @@ void AppletHandle::mousePressEvent(QGraphicsSceneMouseEvent *event)
setZValue(m_applet->zValue());
}
event->accept();
//set mousePos to the position in the applet, in screencoords, so it becomes easy
//to reposition the toplevel view to the correct position.
m_mousePos = event->screenPos() - m_applet->view()->mapToGlobal(
m_applet->view()->mapFromScene(m_applet->pos()));
update();
return;
}
@ -333,6 +339,12 @@ void AppletHandle::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
}
break;
case MoveButton: {
if (m_topview) {
m_topview->hide();
delete m_topview;
m_topview = 0;
m_applet->setGhostView(0);
}
//find out if we were dropped on a panel or something
QWidget *w = QApplication::topLevelAt(event->screenPos());
kDebug() << "move to widget" << w;
@ -340,14 +352,21 @@ void AppletHandle::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
Plasma::View *v = qobject_cast<Plasma::View *>(w);
if (v) {
Containment *c = v->containment();
//XXX the dashboard view won't give us a containment. if it did, this could
QPoint pos = v->mapFromGlobal(event->screenPos() - m_mousePos);
//XXX the dashboard view won't give us a
//containment. if it did, this could
//break shit.
if (c && c != m_containment) {
//we actually have been dropped on another containment, so move there
//we actually have been dropped on another
//containment, so move there
//we have a screenpos, we need a scenepos
//FIXME how reliable is this transform?
QPoint pos = v->mapFromGlobal(event->screenPos());
switchContainment(c, v->mapToScene(pos));
} else {
//just update the position
kDebug() << "just update the position";
m_applet->setPos(v->mapToScene(pos));
}
}
}
@ -392,25 +411,37 @@ void AppletHandle::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
QPointF delta = curPos-lastPos;
if (m_pressedButton == MoveButton) {
setPos(pos()+delta);
// test for containment change
if (!m_containment->sceneBoundingRect().contains(event->scenePos())) {
// see which containment it belongs to
Corona * corona = qobject_cast<Corona*>(scene());
if (corona) {
QList<Containment*> containments = corona->containments();
for (int i = 0; i < containments.size(); ++i) {
if (containments[i]->sceneBoundingRect().contains(event->scenePos())) {
// add the applet to the new containment
// and take it from the old one
//kDebug() << "moving to other containment with position" << pos() << event->scenePos();
//kDebug() << "position before reparenting" << pos() << scenePos();
switchContainment(containments[i], scenePos());
break;
}
}
}
if (!m_topview) { //create a new toplevel view
m_topview = new View(m_applet->containment(), -1, 0);
m_topview->setTrackContainmentChanges(false);
m_topview->setWindowFlags(Qt::Widget | Qt::FramelessWindowHint
| Qt::WindowStaysOnTopHint);
KWindowSystem::setState(m_topview->winId(), NET::SkipTaskbar | NET::SkipPager);
m_topview->setWallpaperEnabled(false);
//TODO: when zoomed out, this doesn't work correctly
m_topview->setSceneRect(m_applet->sceneBoundingRect());
// Calculate the size of the applet in screen coordinates.
QPointF bottomRight = m_applet->pos();
bottomRight.setX(bottomRight.x() + m_applet->size().width());
bottomRight.setY(bottomRight.y() + m_applet->size().height());
QPoint tL = m_applet->view()->mapToGlobal(m_applet->view()->mapFromScene(
m_applet->pos()));
QPoint bR = m_applet->view()->mapToGlobal(m_applet->view()->mapFromScene(
bottomRight));
m_topview->resize(bR.x() - tL.x(), bR.y() - tL.y());
m_topview->show();
m_applet->setGhostView(m_applet->containment()->view());
}
m_topview->move((event->screenPos() - m_mousePos));
} else if (m_pressedButton == RotateButton ||
m_pressedButton == ResizeButton) {
if (_k_distanceForPoint(delta) <= 1.0) {
@ -510,6 +541,7 @@ void AppletHandle::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
}
}
//pos relative to scene
void AppletHandle::switchContainment(Containment *containment, const QPointF &pos)
{
@ -665,7 +697,6 @@ void AppletHandle::calculateSize()
}
m_rect.adjust(-HANDLE_WIDTH, -HANDLE_WIDTH, HANDLE_WIDTH, HANDLE_WIDTH);
if (m_applet->pos().x() <= ((HANDLE_WIDTH * 2) + ICON_SIZE)) {
m_rect.adjust(0.0, 0.0, ICON_SIZE, 0.0);
m_buttonsOnRight = true;

View File

@ -31,6 +31,7 @@ namespace Plasma
{
class Applet;
class Containment;
class View;
class AppletHandle : public QObject, public QGraphicsItem
{
@ -96,6 +97,9 @@ class AppletHandle : public QObject, public QGraphicsItem
QTimer *m_hoverTimer;
bool m_buttonsOnRight;
bool m_pendingFade;
View *m_topview;
QPoint m_mousePos; //the position of the mousecursor relative to the
//applets position.
};
}