00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "dialog.h"
00024
00025 #include <QPainter>
00026 #include <QSvgRenderer>
00027 #include <QResizeEvent>
00028 #include <QMouseEvent>
00029 #ifdef Q_WS_X11
00030 #include <QX11Info>
00031 #endif
00032 #include <QBitmap>
00033 #include <QtGui/QVBoxLayout>
00034 #include <QtGui/QGraphicsSceneEvent>
00035 #include <QtGui/QGraphicsView>
00036 #include <QtGui/QGraphicsWidget>
00037
00038 #include <kdebug.h>
00039 #include <netwm.h>
00040
00041 #include "plasma/applet.h"
00042 #include "plasma/extender.h"
00043 #include "plasma/private/extender_p.h"
00044 #include "plasma/framesvg.h"
00045 #include "plasma/theme.h"
00046
00047 #ifdef Q_WS_X11
00048 #include <X11/Xlib.h>
00049 #endif
00050
00051 const int resizeAreaMargin = 20;
00052
00053 namespace Plasma
00054 {
00055
00056 class DialogPrivate
00057 {
00058 public:
00059 DialogPrivate(Dialog *dialog)
00060 : q(dialog),
00061 background(0),
00062 view(0),
00063 widget(0),
00064 resizeCorners(Dialog::NoCorner),
00065 resizeStartCorner(Dialog::NoCorner)
00066 {
00067 }
00068
00069 ~DialogPrivate()
00070 {
00071 }
00072
00073 void themeUpdated();
00074 void adjustView();
00075
00076 Plasma::Dialog *q;
00081 Plasma::FrameSvg *background;
00082 QGraphicsView *view;
00083 QGraphicsWidget *widget;
00084 Dialog::ResizeCorners resizeCorners;
00085 QMap<Dialog::ResizeCorner, QRect> resizeAreas;
00086 Dialog::ResizeCorner resizeStartCorner;
00087 };
00088
00089 void DialogPrivate::themeUpdated()
00090 {
00091 const int topHeight = background->marginSize(Plasma::TopMargin);
00092 const int leftWidth = background->marginSize(Plasma::LeftMargin);
00093 const int rightWidth = background->marginSize(Plasma::RightMargin);
00094 const int bottomHeight = background->marginSize(Plasma::BottomMargin);
00095
00096
00097 Extender *extender = qobject_cast<Extender*>(widget);
00098 if (extender) {
00099 switch (extender->d->applet->location()) {
00100 case BottomEdge:
00101 background->setEnabledBorders(FrameSvg::LeftBorder | FrameSvg::TopBorder
00102 | FrameSvg::RightBorder);
00103 q->setContentsMargins(0, topHeight, 0, 0);
00104 break;
00105 case TopEdge:
00106 background->setEnabledBorders(FrameSvg::LeftBorder | FrameSvg::BottomBorder
00107 | FrameSvg::RightBorder);
00108 q->setContentsMargins(0, 0, 0, bottomHeight);
00109 break;
00110 case LeftEdge:
00111 background->setEnabledBorders(FrameSvg::TopBorder | FrameSvg::BottomBorder
00112 | FrameSvg::RightBorder);
00113 q->setContentsMargins(0, topHeight, 0, bottomHeight);
00114 break;
00115 case RightEdge:
00116 background->setEnabledBorders(FrameSvg::TopBorder | FrameSvg::BottomBorder
00117 | FrameSvg::LeftBorder);
00118 q->setContentsMargins(0, topHeight, 0, bottomHeight);
00119 break;
00120 default:
00121 background->setEnabledBorders(FrameSvg::AllBorders);
00122 q->setContentsMargins(leftWidth, topHeight, rightWidth, bottomHeight);
00123 }
00124 } else {
00125 q->setContentsMargins(leftWidth, topHeight, rightWidth, bottomHeight);
00126 }
00127 q->update();
00128 }
00129
00130 void DialogPrivate::adjustView()
00131 {
00132 if (view && widget) {
00133 QSize prevSize = q->size();
00134 kDebug() << "Widget size:" << widget->size()
00135 << "| Widget size hint:" << widget->effectiveSizeHint(Qt::PreferredSize)
00136 << "| Widget minsize hint:" << widget->minimumSize()
00137 << "| Widget maxsize hint:" << widget->maximumSize()
00138 << "| Widget bounding rect:" << widget->boundingRect();
00139
00140 int left, top, right, bottom;
00141 q->getContentsMargins(&left, &top, &right, &bottom);
00142
00143 q->setMinimumSize(qMin(int(widget->minimumSize().width()) + left + right, QWIDGETSIZE_MAX),
00144 qMin(int(widget->minimumSize().height()) + top + bottom, QWIDGETSIZE_MAX));
00145 q->setMaximumSize(qMin(int(widget->maximumSize().width()) + left + right, QWIDGETSIZE_MAX),
00146 qMin(int(widget->maximumSize().height()) + top + bottom, QWIDGETSIZE_MAX));
00147 q->resize(qMin(int(widget->size().width()) + left + right, QWIDGETSIZE_MAX),
00148 qMin(int(widget->size().height()) + top + bottom, QWIDGETSIZE_MAX));
00149 q->updateGeometry();
00150
00151
00152
00153 QRectF sceneRect(widget->sceneBoundingRect());
00154
00155 sceneRect.setWidth(qMax(qreal(1), sceneRect.width()));
00156 sceneRect.setHeight(qMax(qreal(1), sceneRect.height()));
00157 view->setSceneRect(sceneRect);
00158
00159 view->resize(widget->size().toSize());
00160 view->centerOn(widget);
00161
00162 if (q->size() != prevSize) {
00163
00164 emit q->dialogResized();
00165 }
00166 }
00167 }
00168
00169 Dialog::Dialog(QWidget *parent, Qt::WindowFlags f)
00170 : QWidget(parent, f),
00171 d(new DialogPrivate(this))
00172 {
00173 setWindowFlags(Qt::FramelessWindowHint);
00174 d->background = new FrameSvg(this);
00175 d->background->setImagePath("dialogs/background");
00176 d->background->setEnabledBorders(FrameSvg::AllBorders);
00177 d->background->resizeFrame(size());
00178
00179 QPalette pal = palette();
00180 pal.setColor(backgroundRole(), Qt::transparent);
00181 setPalette(pal);
00182
00183 connect(d->background, SIGNAL(repaintNeeded()), this, SLOT(update()));
00184
00185 connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(themeUpdated()));
00186 d->themeUpdated();
00187
00188 setMouseTracking(true);
00189 }
00190
00191 Dialog::~Dialog()
00192 {
00193 delete d;
00194 }
00195
00196 void Dialog::paintEvent(QPaintEvent *e)
00197 {
00198 QPainter p(this);
00199 p.setRenderHint(QPainter::Antialiasing);
00200 p.setClipRect(e->rect());
00201 p.setCompositionMode(QPainter::CompositionMode_Source);
00202 d->background->paintFrame(&p);
00203
00204
00205 d->resizeAreas.clear();
00206 if (d->resizeCorners & Dialog::NorthEast) {
00207 d->resizeAreas[Dialog::NorthEast] = QRect(rect().right() - resizeAreaMargin, 0,
00208 resizeAreaMargin, resizeAreaMargin);
00209 }
00210
00211 if (d->resizeCorners & Dialog::NorthWest) {
00212 d->resizeAreas[Dialog::NorthWest] = QRect(0, 0, resizeAreaMargin, resizeAreaMargin);
00213 }
00214
00215 if (d->resizeCorners & Dialog::SouthEast) {
00216 d->resizeAreas[Dialog::SouthEast] = QRect(rect().right() - resizeAreaMargin,
00217 rect().bottom() - resizeAreaMargin,
00218 resizeAreaMargin, resizeAreaMargin);
00219 }
00220
00221 if (d->resizeCorners & Dialog::SouthWest) {
00222 d->resizeAreas[Dialog::SouthWest] = QRect(0, rect().bottom() - resizeAreaMargin,
00223 resizeAreaMargin, resizeAreaMargin);
00224 }
00225 }
00226
00227 void Dialog::mouseMoveEvent(QMouseEvent *event)
00228 {
00229 if (d->resizeAreas[Dialog::NorthEast].contains(event->pos()) && d->resizeCorners & Dialog::NorthEast) {
00230 setCursor(Qt::SizeBDiagCursor);
00231 } else if (d->resizeAreas[Dialog::NorthWest].contains(event->pos()) && d->resizeCorners & Dialog::NorthWest) {
00232 setCursor(Qt::SizeFDiagCursor);
00233 } else if (d->resizeAreas[Dialog::SouthEast].contains(event->pos()) && d->resizeCorners & Dialog::SouthEast) {
00234 setCursor(Qt::SizeFDiagCursor);
00235 } else if (d->resizeAreas[Dialog::SouthWest].contains(event->pos()) && d->resizeCorners & Dialog::SouthWest) {
00236 setCursor(Qt::SizeBDiagCursor);
00237 } else if (!(event->buttons() & Qt::LeftButton)) {
00238 unsetCursor();
00239 }
00240
00241
00242 if (d->resizeStartCorner != Dialog::NoCorner) {
00243 int newWidth;
00244 int newHeight;
00245 QPoint position;
00246
00247 switch(d->resizeStartCorner) {
00248 case Dialog::NorthEast:
00249 newWidth = qMin(maximumWidth(), qMax(minimumWidth(), event->x()));
00250 newHeight = qMin(maximumHeight(), qMax(minimumHeight(), height() - event->y()));
00251 position = QPoint(x(), y() + height() - newHeight);
00252 break;
00253 case Dialog::NorthWest:
00254 newWidth = qMin(maximumWidth(), qMax(minimumWidth(), width() - event->x()));
00255 newHeight = qMin(maximumHeight(), qMax(minimumHeight(), height() - event->y()));
00256 position = QPoint(x() + width() - newWidth, y() + height() - newHeight);
00257 break;
00258 case Dialog::SouthWest:
00259 newWidth = qMin(maximumWidth(), qMax(minimumWidth(), width() - event->x()));
00260 newHeight = qMin(maximumHeight(), qMax(minimumHeight(), event->y()));
00261 position = QPoint(x() + width() - newWidth, y());
00262 break;
00263 case Dialog::SouthEast:
00264 newWidth = qMin(maximumWidth(), qMax(minimumWidth(), event->x()));
00265 newHeight = qMin(maximumHeight(), qMax(minimumHeight(), event->y()));
00266 position = QPoint(x(), y());
00267 break;
00268 default:
00269 newWidth = qMin(maximumWidth(), qMax(minimumWidth(), width()));
00270 newHeight = qMin(maximumHeight(), qMax(minimumHeight(), height()));
00271 position = QPoint(x(), y());
00272 break;
00273 }
00274
00275 setGeometry(QRect(position, QSize(newWidth, newHeight)));
00276 }
00277
00278 QWidget::mouseMoveEvent(event);
00279 }
00280
00281 void Dialog::mousePressEvent(QMouseEvent *event)
00282 {
00283 if (d->resizeAreas[Dialog::NorthEast].contains(event->pos()) && d->resizeCorners & Dialog::NorthEast) {
00284 d->resizeStartCorner = Dialog::NorthEast;
00285
00286 } else if (d->resizeAreas[Dialog::NorthWest].contains(event->pos()) && d->resizeCorners & Dialog::NorthWest) {
00287 d->resizeStartCorner = Dialog::NorthWest;
00288
00289 } else if (d->resizeAreas[Dialog::SouthEast].contains(event->pos()) && d->resizeCorners & Dialog::SouthEast) {
00290 d->resizeStartCorner = Dialog::SouthEast;
00291
00292 } else if (d->resizeAreas[Dialog::SouthWest].contains(event->pos()) && d->resizeCorners & Dialog::SouthWest) {
00293 d->resizeStartCorner = Dialog::SouthWest;
00294
00295 } else {
00296 d->resizeStartCorner = Dialog::NoCorner;
00297 }
00298
00299 QWidget::mousePressEvent(event);
00300 }
00301
00302 void Dialog::mouseReleaseEvent(QMouseEvent *event)
00303 {
00304 if (d->resizeStartCorner != Dialog::NoCorner) {
00305 d->resizeStartCorner = Dialog::NoCorner;
00306 unsetCursor();
00307 emit dialogResized();
00308 }
00309
00310 QWidget::mouseReleaseEvent(event);
00311 }
00312
00313 void Dialog::keyPressEvent(QKeyEvent *event)
00314 {
00315 if (event->key() == Qt::Key_Escape) {
00316 hide();
00317 }
00318 }
00319
00320 bool Dialog::event(QEvent *event)
00321 {
00322 if (event->type() == QEvent::Paint) {
00323 QPainter p(this);
00324 p.setCompositionMode(QPainter::CompositionMode_Source);
00325 p.fillRect(rect(), Qt::transparent);
00326 }
00327
00328 return QWidget::event(event);
00329 }
00330
00331 void Dialog::resizeEvent(QResizeEvent *e)
00332 {
00333 d->background->resizeFrame(e->size());
00334
00335 setMask(d->background->mask());
00336
00337 if (d->resizeStartCorner != Dialog::NoCorner && d->view && d->widget) {
00338 d->widget->resize(d->view->size());
00339
00340 d->view->setSceneRect(d->widget->mapToScene(d->widget->boundingRect()).boundingRect());
00341 d->view->centerOn(d->widget);
00342 }
00343 }
00344
00345 void Dialog::setGraphicsWidget(QGraphicsWidget *widget)
00346 {
00347 if (d->widget) {
00348 d->widget->removeEventFilter(this);
00349 }
00350
00351 d->widget = widget;
00352
00353 if (widget) {
00354 if (!layout()) {
00355 QVBoxLayout *lay = new QVBoxLayout(this);
00356 lay->setMargin(0);
00357 lay->setSpacing(0);
00358 }
00359
00360 d->themeUpdated();
00361
00362 if (!d->view) {
00363 d->view = new QGraphicsView(this);
00364 d->view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00365 d->view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00366 d->view->setFrameShape(QFrame::NoFrame);
00367 d->view->viewport()->setAutoFillBackground(false);
00368 layout()->addWidget(d->view);
00369 }
00370
00371 d->view->setScene(widget->scene());
00372 d->adjustView();
00373
00374 adjustSize();
00375
00376 widget->installEventFilter(this);
00377 } else {
00378 delete d->view;
00379 d->view = 0;
00380 }
00381 }
00382
00383 QGraphicsWidget *Dialog::graphicsWidget()
00384 {
00385 return d->widget;
00386 }
00387
00388 bool Dialog::eventFilter(QObject *watched, QEvent *event)
00389 {
00390 if (d->resizeStartCorner == Dialog::NoCorner && watched == d->widget &&
00391 (event->type() == QEvent::GraphicsSceneResize || event->type() == QEvent::GraphicsSceneMove)) {
00392 d->adjustView();
00393 }
00394
00395 return QWidget::eventFilter(watched, event);
00396 }
00397
00398 void Dialog::hideEvent(QHideEvent * event)
00399 {
00400 Q_UNUSED(event);
00401 emit dialogVisible(false);
00402 }
00403
00404 void Dialog::showEvent(QShowEvent * event)
00405 {
00406 Q_UNUSED(event);
00407
00408
00409 if (d->widget && d->view && d->widget->size().toSize() != d->view->size()) {
00410 d->widget->resize(d->view->size());
00411
00412 d->view->setSceneRect(d->widget->mapToScene(d->widget->boundingRect()).boundingRect());
00413 d->view->centerOn(d->widget);
00414 }
00415
00416 emit dialogVisible(true);
00417 }
00418
00419 void Dialog::setResizeHandleCorners(ResizeCorners corners)
00420 {
00421 d->resizeCorners = corners;
00422 update();
00423 }
00424
00425 Dialog::ResizeCorners Dialog::resizeCorners() const
00426 {
00427 return d->resizeCorners;
00428 }
00429
00430 bool Dialog::inControlArea(const QPoint &point)
00431 {
00432 foreach (const QRect &r, d->resizeAreas) {
00433 if (r.contains(point)) {
00434 return true;
00435 }
00436 }
00437 return false;
00438 }
00439
00440 }
00441 #include "dialog.moc"