Plasma
dialog.cpp
Go to the documentation of this file.
00001 /* 00002 * Copyright 2008 by Alessandro Diaferia <alediaferia@gmail.com> 00003 * Copyright 2007 by Alexis Ménard <darktears31@gmail.com> 00004 * Copyright 2007 Sebastian Kuegler <sebas@kde.org> 00005 * Copyright 2006 Aaron Seigo <aseigo@kde.org> 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, 00020 * Boston, MA 02110-1301 USA 00021 */ 00022 00023 #include "dialog.h" 00024 #include "private/dialog_p.h" 00025 00026 #include <QPainter> 00027 #include <QSvgRenderer> 00028 #include <QResizeEvent> 00029 #include <QMouseEvent> 00030 #ifdef Q_WS_X11 00031 #include <QX11Info> 00032 #endif 00033 #include <QBitmap> 00034 #include <QTimer> 00035 #include <QtGui/QVBoxLayout> 00036 #include <QtGui/QGraphicsSceneEvent> 00037 #include <QtGui/QGraphicsView> 00038 #include <QtGui/QGraphicsWidget> 00039 #include <QApplication> 00040 #include <QDesktopWidget> 00041 #include <QVarLengthArray> 00042 #include <QGraphicsLayout> 00043 00044 #include <kdebug.h> 00045 #include <kwindowsystem.h> 00046 #include <netwm.h> 00047 00048 #include "plasma/applet.h" 00049 #include "plasma/animator.h" 00050 #include "plasma/containment.h" 00051 #include "plasma/corona.h" 00052 #include "plasma/extenders/extender.h" 00053 #include "plasma/private/extender_p.h" 00054 #include "plasma/framesvg.h" 00055 #include "plasma/theme.h" 00056 #include "plasma/widgets/scrollwidget.h" 00057 #include "plasma/windoweffects.h" 00058 00059 #ifdef Q_WS_X11 00060 #include <X11/Xlib.h> 00061 #endif 00062 00063 namespace Plasma 00064 { 00065 00066 void DialogPrivate::scheduleBorderCheck(bool triggeredByResize) 00067 { 00068 //kDebug(); 00069 if (triggeredByResize) { 00070 resizeChecksWithBorderCheck = true; 00071 00072 // to keep the UI as fluid as possible, we call checkBorders 00073 // immediately when there is a resize, and therefore stop any 00074 // move-triggered scheduled calls to it. this keeps things 00075 // looking reasonable during resize while avoiding as many 00076 // calls to checkBorders as possible 00077 if (moveTimer) { 00078 moveTimer->stop(); 00079 } 00080 00081 checkBorders(); 00082 return; 00083 } 00084 00085 if (!moveTimer) { 00086 moveTimer = new QTimer(q); 00087 moveTimer->setSingleShot(true); 00088 QObject::connect(moveTimer, SIGNAL(timeout()), q, SLOT(checkBorders())); 00089 } 00090 00091 moveTimer->start(triggeredByResize ? 0 : 200); 00092 } 00093 00094 void DialogPrivate::themeChanged() 00095 { 00096 checkBorders(false); 00097 00098 const bool translucency = Plasma::Theme::defaultTheme()->windowTranslucencyEnabled(); 00099 // WA_NoSystemBackground is going to fail combined with sliding popups, but is needed 00100 // when we aren't compositing 00101 q->setAttribute(Qt::WA_NoSystemBackground, !translucency); 00102 updateMask(); 00103 q->update(); 00104 } 00105 00106 void DialogPrivate::updateMask() 00107 { 00108 const bool translucency = Plasma::Theme::defaultTheme()->windowTranslucencyEnabled(); 00109 WindowEffects::enableBlurBehind(q->winId(), translucency, 00110 translucency ? background->mask() : QRegion()); 00111 if (translucency) { 00112 q->clearMask(); 00113 } else { 00114 q->setMask(background->mask()); 00115 } 00116 } 00117 00118 void DialogPrivate::checkBorders() 00119 { 00120 checkBorders(true); 00121 } 00122 00123 void DialogPrivate::delayedAdjustSize() 00124 { 00125 q->syncToGraphicsWidget(); 00126 } 00127 00128 void DialogPrivate::checkBorders(bool updateMaskIfNeeded) 00129 { 00130 if (resizeChecksWithBorderCheck) { 00131 background->resizeFrame(q->size()); 00132 } 00133 00134 QGraphicsWidget *graphicsWidget = graphicsWidgetPtr.data(); 00135 const FrameSvg::EnabledBorders currentBorders = background->enabledBorders(); 00136 FrameSvg::EnabledBorders borders = FrameSvg::AllBorders; 00137 00138 Extender *extender = qobject_cast<Extender*>(graphicsWidget); 00139 Plasma::Applet *applet = appletPtr.data(); 00140 00141 //used to remove borders at the edge of the desktop 00142 QRect avail; 00143 QRect screenGeom; 00144 QDesktopWidget *desktop = QApplication::desktop(); 00145 Plasma::Corona *c = 0; 00146 if (applet) { 00147 c = qobject_cast<Plasma::Corona *>(applet->scene()); 00148 } else if (graphicsWidget) { 00149 c = qobject_cast<Plasma::Corona *>(graphicsWidget->scene()); 00150 } 00151 if (c) { 00152 QRegion r = c->availableScreenRegion(desktop->screenNumber(q)); 00153 QRect maxRect; 00154 foreach (QRect rect, r.rects()) { 00155 if (rect.width() > maxRect.width() && rect.height() > maxRect.height()) { 00156 maxRect = rect; 00157 } 00158 } 00159 avail = maxRect; 00160 screenGeom = c->screenGeometry(desktop->screenNumber(q)); 00161 } else { 00162 avail = desktop->availableGeometry(desktop->screenNumber(q)); 00163 screenGeom = desktop->screenGeometry(desktop->screenNumber(q)); 00164 } 00165 00166 QRect dialogGeom = q->geometry(); 00167 00168 qreal topHeight(0); 00169 qreal leftWidth(0); 00170 qreal rightWidth(0); 00171 qreal bottomHeight(0); 00172 00173 //decide about disabling the border attached to the panel 00174 if (applet) { 00175 background->getMargins(leftWidth, topHeight, rightWidth, bottomHeight); 00176 00177 switch (applet->location()) { 00178 case BottomEdge: 00179 if (applet->containment() && 00180 dialogGeom.bottom() + 2 >= screenGeom.bottom() - applet->containment()->size().height() && 00181 dialogGeom.width() <= applet->containment()->size().width()) { 00182 borders &= ~FrameSvg::BottomBorder; 00183 leftWidth = 0; 00184 rightWidth = 0; 00185 bottomHeight = 0; 00186 } 00187 break; 00188 00189 case TopEdge: 00190 if (applet->containment() && 00191 dialogGeom.top() <= screenGeom.top() + applet->containment()->size().height() && 00192 dialogGeom.width() <= applet->containment()->size().width()) { 00193 borders &= ~FrameSvg::TopBorder; 00194 topHeight = 0; 00195 leftWidth = 0; 00196 rightWidth = 0; 00197 } 00198 break; 00199 00200 case LeftEdge: 00201 if (applet->containment() && 00202 dialogGeom.left() <= screenGeom.left() + applet->containment()->size().width() && 00203 dialogGeom.height() <= applet->containment()->size().height()) { 00204 borders &= ~FrameSvg::LeftBorder; 00205 leftWidth = 0; 00206 rightWidth = 0; 00207 } 00208 break; 00209 00210 case RightEdge: 00211 if (applet->containment() && 00212 dialogGeom.right() + 2 >= screenGeom.right() - applet->containment()->size().width() && 00213 dialogGeom.height() <= applet->containment()->size().height()) { 00214 borders &= ~FrameSvg::RightBorder; 00215 leftWidth = 0; 00216 rightWidth = 0; 00217 } 00218 break; 00219 00220 default: 00221 break; 00222 } 00223 } 00224 00225 //decide if to disable the other borders 00226 if (q->isVisible()) { 00227 if (dialogGeom.left() <= avail.left()) { 00228 borders &= ~FrameSvg::LeftBorder; 00229 } 00230 if (dialogGeom.top() <= avail.top()) { 00231 borders &= ~FrameSvg::TopBorder; 00232 } 00233 //FIXME: that 2 pixels offset has probably something to do with kwin 00234 if (dialogGeom.right() + 2 > avail.right()) { 00235 borders &= ~FrameSvg::RightBorder; 00236 } 00237 if (dialogGeom.bottom() + 2 > avail.bottom()) { 00238 borders &= ~FrameSvg::BottomBorder; 00239 } 00240 } 00241 00242 background->setEnabledBorders(borders); 00243 00244 if (extender) { 00245 FrameSvg::EnabledBorders disabledBorders = FrameSvg::NoBorder; 00246 if (!(borders & FrameSvg::LeftBorder)) { 00247 disabledBorders |= FrameSvg::LeftBorder; 00248 } 00249 if (!(borders & FrameSvg::RightBorder)) { 00250 disabledBorders |= FrameSvg::RightBorder; 00251 } 00252 extender->d->setDisabledBordersHint(disabledBorders); 00253 00254 //if there is a scrollbar, reserve a margin to not draw it over the shadow 00255 qreal left, top, right, bottom; 00256 background->getMargins(left, top, right, bottom); 00257 if (extender->d->scrollWidget->viewportGeometry().height() < extender->d->scrollWidget->contentsSize().height()) { 00258 if (QApplication::layoutDirection() == Qt::RightToLeft) { 00259 leftWidth = left; 00260 } else { 00261 rightWidth = right; 00262 } 00263 } 00264 } else { 00265 background->getMargins(leftWidth, topHeight, rightWidth, bottomHeight); 00266 } 00267 00268 //kDebug() << leftWidth << topHeight << rightWidth << bottomHeight; 00269 q->setContentsMargins(leftWidth, topHeight, rightWidth, bottomHeight); 00270 00271 if (resizeChecksWithBorderCheck) { 00272 updateResizeCorners(); 00273 updateMask(); 00274 q->update(); 00275 } else if (currentBorders != borders) { 00276 if (updateMaskIfNeeded) { 00277 updateMask(); 00278 } 00279 00280 q->update(); 00281 } 00282 00283 resizeChecksWithBorderCheck = false; 00284 } 00285 00286 void Dialog::syncToGraphicsWidget() 00287 { 00288 d->adjustViewTimer->stop(); 00289 QGraphicsWidget *graphicsWidget = d->graphicsWidgetPtr.data(); 00290 if (d->view && graphicsWidget && d->resizeStartCorner != -1) { 00291 const int prevStartCorner = d->resizeStartCorner; 00292 d->resizeStartCorner = -1; 00293 QSize prevSize = size(); 00294 /* 00295 kDebug() << "Widget size:" << graphicsWidget->size() 00296 << "| Widget size hint:" << graphicsWidget->effectiveSizeHint(Qt::PreferredSize) 00297 << "| Widget minsize hint:" << graphicsWidget->minimumSize() 00298 << "| Widget maxsize hint:" << graphicsWidget->maximumSize() 00299 << "| Widget bounding rect:" << graphicsWidget->sceneBoundingRect(); 00300 */ 00301 //set the sizehints correctly: 00302 int left, top, right, bottom; 00303 getContentsMargins(&left, &top, &right, &bottom); 00304 00305 QDesktopWidget *desktop = QApplication::desktop(); 00306 QSize maxSize = desktop->availableGeometry(desktop->screenNumber(this)).size(); 00307 00308 graphicsWidget->setMaximumSize(maxSize - QSize(left + right, top + bottom).boundedTo(graphicsWidget->effectiveSizeHint(Qt::MaximumSize).toSize())); 00309 00310 setMinimumSize(0, 0); 00311 setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); 00312 00313 QSize newSize(qMin(int(graphicsWidget->size().width()) + left + right, maxSize.width()), 00314 qMin(int(graphicsWidget->size().height()) + top + bottom, maxSize.height())); 00315 00316 const QSizeF minimum = graphicsWidget->effectiveSizeHint(Qt::MinimumSize); 00317 QSize newMinimumSize(qMin(int(minimum.width()) + left + right, maxSize.width()), 00318 qMin(int(minimum.height()) + top + bottom, maxSize.height())); 00319 00320 00321 QSize newMaximumSize(qMin(int(graphicsWidget->maximumSize().width()) + left + right, maxSize.width()), 00322 qMin(int(graphicsWidget->maximumSize().height()) + top + bottom, maxSize.height())); 00323 00324 00325 Plasma::Applet *applet = d->appletPtr.data(); 00326 if (applet) { 00327 QRect currentGeometry(geometry()); 00328 currentGeometry.setSize(newSize); 00329 if (applet->location() == Plasma::TopEdge || 00330 applet->location() == Plasma::LeftEdge) { 00331 currentGeometry.setSize(newSize); 00332 } else if (applet->location() == Plasma::RightEdge) { 00333 currentGeometry.moveTopRight(geometry().topRight()); 00334 //BottomEdge and floating 00335 } else { 00336 currentGeometry.moveBottomLeft(geometry().bottomLeft()); 00337 } 00338 setGeometry(currentGeometry); 00339 } else { 00340 resize(newSize); 00341 } 00342 00343 setMinimumSize(newMinimumSize); 00344 setMaximumSize(newMaximumSize); 00345 00346 00347 updateGeometry(); 00348 00349 //reposition and resize the view. 00350 //force a valid rect, otherwise it will take up the whole scene 00351 QRectF sceneRect(graphicsWidget->sceneBoundingRect()); 00352 00353 sceneRect.setWidth(qMax(qreal(1), sceneRect.width())); 00354 sceneRect.setHeight(qMax(qreal(1), sceneRect.height())); 00355 d->view->setSceneRect(sceneRect); 00356 00357 //d->view->resize(graphicsWidget->size().toSize()); 00358 d->view->centerOn(graphicsWidget); 00359 00360 if (size() != prevSize) { 00361 //the size of the dialog has changed, emit the signal: 00362 emit dialogResized(); 00363 } 00364 00365 d->resizeStartCorner = prevStartCorner; 00366 } 00367 } 00368 00369 int DialogPrivate::calculateWidthForHeightAndRatio(int height, qreal ratio) 00370 { 00371 switch (aspectRatioMode) { 00372 case KeepAspectRatio: 00373 return qRound(height * ratio); 00374 break; 00375 case Square: 00376 return height; 00377 break; 00378 case ConstrainedSquare: 00379 return height; 00380 break; 00381 default: 00382 return -1; 00383 } 00384 } 00385 00386 Dialog::Dialog(QWidget *parent, Qt::WindowFlags f) 00387 : QWidget(parent, f | Qt::FramelessWindowHint), 00388 d(new DialogPrivate(this)) 00389 { 00390 setMouseTracking(true); 00391 setAttribute(Qt::WA_TranslucentBackground); 00392 d->background = new FrameSvg(this); 00393 d->background->setImagePath("dialogs/background"); 00394 d->background->setEnabledBorders(FrameSvg::AllBorders); 00395 d->background->resizeFrame(size()); 00396 connect(d->background, SIGNAL(repaintNeeded()), this, SLOT(themeChanged())); 00397 00398 QPalette pal = palette(); 00399 pal.setColor(backgroundRole(), Qt::transparent); 00400 setPalette(pal); 00401 WindowEffects::overrideShadow(winId(), true); 00402 00403 d->adjustViewTimer = new QTimer(this); 00404 d->adjustViewTimer->setSingleShot(true); 00405 connect(d->adjustViewTimer, SIGNAL(timeout()), this, SLOT(syncToGraphicsWidget())); 00406 00407 d->adjustSizeTimer = new QTimer(this); 00408 d->adjustSizeTimer->setSingleShot(true); 00409 connect(d->adjustSizeTimer, SIGNAL(timeout()), this, SLOT(delayedAdjustSize())); 00410 00411 d->themeChanged(); 00412 } 00413 00414 Dialog::~Dialog() 00415 { 00416 delete d; 00417 } 00418 00419 void Dialog::paintEvent(QPaintEvent *e) 00420 { 00421 QPainter p(this); 00422 p.setCompositionMode(QPainter::CompositionMode_Source); 00423 d->background->paintFrame(&p, e->rect(), e->rect()); 00424 } 00425 00426 void Dialog::mouseMoveEvent(QMouseEvent *event) 00427 { 00428 if (event->modifiers() == Qt::AltModifier) { 00429 unsetCursor(); 00430 } else if (d->resizeAreas[Dialog::NorthEast].contains(event->pos())) { 00431 setCursor(Qt::SizeBDiagCursor); 00432 } else if (d->resizeAreas[Dialog::NorthWest].contains(event->pos())) { 00433 setCursor(Qt::SizeFDiagCursor); 00434 } else if (d->resizeAreas[Dialog::SouthEast].contains(event->pos())) { 00435 setCursor(Qt::SizeFDiagCursor); 00436 } else if (d->resizeAreas[Dialog::SouthWest].contains(event->pos())) { 00437 setCursor(Qt::SizeBDiagCursor); 00438 } else if (!(event->buttons() & Qt::LeftButton)) { 00439 unsetCursor(); 00440 } 00441 00442 // here we take care of resize.. 00443 if (d->resizeStartCorner != Dialog::NoCorner) { 00444 int newWidth; 00445 int newHeight; 00446 QPoint position; 00447 00448 qreal aspectRatio = (qreal)width() / (qreal)height(); 00449 00450 switch(d->resizeStartCorner) { 00451 case Dialog::NorthEast: 00452 newHeight = qMin(maximumHeight(), qMax(minimumHeight(), height() - event->y())); 00453 newWidth = d->calculateWidthForHeightAndRatio(newHeight, aspectRatio); 00454 if (newWidth == -1) { 00455 newWidth = qMin(maximumWidth(), qMax(minimumWidth(), event->x())); 00456 } 00457 position = QPoint(x(), y() + height() - newHeight); 00458 break; 00459 case Dialog::NorthWest: 00460 newHeight = qMin(maximumHeight(), qMax(minimumHeight(), height() - event->y())); 00461 newWidth = d->calculateWidthForHeightAndRatio(newHeight, aspectRatio); 00462 if (newWidth == -1) { 00463 newWidth = qMin(maximumWidth(), qMax(minimumWidth(), width() - event->x())); 00464 } 00465 position = QPoint(x() + width() - newWidth, y() + height() - newHeight); 00466 break; 00467 case Dialog::SouthWest: 00468 newHeight = qMin(maximumHeight(), qMax(minimumHeight(), event->y())); 00469 newWidth = d->calculateWidthForHeightAndRatio(newHeight, aspectRatio); 00470 if (newWidth == -1) { 00471 newWidth = qMin(maximumWidth(), qMax(minimumWidth(), width() - event->x())); 00472 } 00473 position = QPoint(x() + width() - newWidth, y()); 00474 break; 00475 case Dialog::SouthEast: 00476 newHeight = qMin(maximumHeight(), qMax(minimumHeight(), event->y())); 00477 newWidth = d->calculateWidthForHeightAndRatio(newHeight, aspectRatio); 00478 if (newWidth == -1) { 00479 newWidth = qMin(maximumWidth(), qMax(minimumWidth(), event->x())); 00480 } 00481 position = QPoint(x(), y()); 00482 break; 00483 default: 00484 newHeight = qMin(maximumHeight(), qMax(minimumHeight(), height())); 00485 newWidth = d->calculateWidthForHeightAndRatio(newHeight, aspectRatio); 00486 if (newWidth == -1) { 00487 newWidth = qMin(maximumWidth(), qMax(minimumWidth(), width())); 00488 } 00489 position = QPoint(x(), y()); 00490 break; 00491 } 00492 00493 if ((newWidth >= minimumSize().width()) && (newHeight >= minimumSize().height())) { 00494 setGeometry(QRect(position, QSize(newWidth, newHeight))); 00495 } 00496 } 00497 00498 QWidget::mouseMoveEvent(event); 00499 } 00500 00501 void Dialog::mousePressEvent(QMouseEvent *event) 00502 { 00503 if (d->resizeAreas[Dialog::NorthEast].contains(event->pos())) { 00504 d->resizeStartCorner = Dialog::NorthEast; 00505 } else if (d->resizeAreas[Dialog::NorthWest].contains(event->pos())) { 00506 d->resizeStartCorner = Dialog::NorthWest; 00507 } else if (d->resizeAreas[Dialog::SouthEast].contains(event->pos())) { 00508 d->resizeStartCorner = Dialog::SouthEast; 00509 } else if (d->resizeAreas[Dialog::SouthWest].contains(event->pos())) { 00510 d->resizeStartCorner = Dialog::SouthWest; 00511 } else { 00512 d->resizeStartCorner = Dialog::NoCorner; 00513 } 00514 00515 QWidget::mousePressEvent(event); 00516 } 00517 00518 void Dialog::mouseReleaseEvent(QMouseEvent *event) 00519 { 00520 if (d->resizeStartCorner != Dialog::NoCorner) { 00521 d->resizeStartCorner = Dialog::NoCorner; 00522 unsetCursor(); 00523 emit dialogResized(); 00524 } 00525 00526 QWidget::mouseReleaseEvent(event); 00527 } 00528 00529 void Dialog::keyPressEvent(QKeyEvent *event) 00530 { 00531 if (event->key() == Qt::Key_Escape) { 00532 hide(); 00533 } 00534 } 00535 00536 bool Dialog::event(QEvent *event) 00537 { 00538 if (event->type() == QEvent::Paint) { 00539 QPainter p(this); 00540 p.setCompositionMode(QPainter::CompositionMode_Source); 00541 p.fillRect(rect(), Qt::transparent); 00542 } 00543 00544 return QWidget::event(event); 00545 } 00546 00547 void Dialog::resizeEvent(QResizeEvent *event) 00548 { 00549 Q_UNUSED(event) 00550 //kDebug(); 00551 d->scheduleBorderCheck(true); 00552 00553 if (d->resizeStartCorner != -1 && d->view && d->graphicsWidgetPtr) { 00554 QGraphicsWidget *graphicsWidget = d->graphicsWidgetPtr.data(); 00555 graphicsWidget->resize(d->view->size()); 00556 00557 QRectF sceneRect(graphicsWidget->sceneBoundingRect()); 00558 sceneRect.setWidth(qMax(qreal(1), sceneRect.width())); 00559 sceneRect.setHeight(qMax(qreal(1), sceneRect.height())); 00560 d->view->setSceneRect(sceneRect); 00561 d->view->centerOn(graphicsWidget); 00562 } 00563 } 00564 00565 void DialogPrivate::updateResizeCorners() 00566 { 00567 const int resizeAreaMargin = 20; 00568 const QRect r = q->rect(); 00569 const FrameSvg::EnabledBorders borders = background->enabledBorders(); 00570 00571 // IMPLEMENTATION NOTE: we set resize corners for the corners set, but also 00572 // for the complimentary corners if we've cut out an edge of our SVG background 00573 // which implies we are up against an immovable edge (e.g. a screen edge) 00574 00575 resizeAreas.clear(); 00576 if (resizeCorners & Dialog::NorthEast || 00577 (resizeCorners & Dialog::NorthWest && !(borders & FrameSvg::LeftBorder)) || 00578 (resizeCorners & Dialog::SouthEast && !(borders & FrameSvg::BottomBorder))) { 00579 resizeAreas[Dialog::NorthEast] = QRect(r.right() - resizeAreaMargin, 0, 00580 resizeAreaMargin, resizeAreaMargin); 00581 } 00582 00583 if (resizeCorners & Dialog::NorthWest || 00584 (resizeCorners & Dialog::NorthEast && !(borders & FrameSvg::RightBorder)) || 00585 (resizeCorners & Dialog::SouthWest && !(borders & FrameSvg::BottomBorder))) { 00586 resizeAreas[Dialog::NorthWest] = QRect(0, 0, resizeAreaMargin, resizeAreaMargin); 00587 } 00588 00589 if (resizeCorners & Dialog::SouthEast || 00590 (resizeCorners & Dialog::SouthWest && !(borders & FrameSvg::LeftBorder)) || 00591 (resizeCorners & Dialog::NorthEast && !(borders & FrameSvg::TopBorder))) { 00592 resizeAreas[Dialog::SouthEast] = QRect(r.right() - resizeAreaMargin, 00593 r.bottom() - resizeAreaMargin, 00594 resizeAreaMargin, resizeAreaMargin); 00595 } 00596 00597 if (resizeCorners & Dialog::SouthWest || 00598 (resizeCorners & Dialog::SouthEast && !(borders & FrameSvg::RightBorder)) || 00599 (resizeCorners & Dialog::NorthWest && !(borders & FrameSvg::TopBorder))) { 00600 resizeAreas[Dialog::SouthWest] = QRect(0, r.bottom() - resizeAreaMargin, 00601 resizeAreaMargin, resizeAreaMargin); 00602 } 00603 } 00604 00605 void Dialog::setGraphicsWidget(QGraphicsWidget *widget) 00606 { 00607 if (d->graphicsWidgetPtr) { 00608 d->graphicsWidgetPtr.data()->removeEventFilter(this); 00609 } 00610 00611 d->graphicsWidgetPtr = widget; 00612 00613 if (widget) { 00614 Plasma::Corona *c = qobject_cast<Plasma::Corona *>(widget->scene()); 00615 if (c) { 00616 c->addOffscreenWidget(widget); 00617 } 00618 00619 if (!layout()) { 00620 QVBoxLayout *lay = new QVBoxLayout(this); 00621 lay->setMargin(0); 00622 lay->setSpacing(0); 00623 } 00624 00625 d->checkBorders(); 00626 00627 if (!d->view) { 00628 d->view = new QGraphicsView(this); 00629 d->view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 00630 d->view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 00631 d->view->setFrameShape(QFrame::NoFrame); 00632 d->view->viewport()->setAutoFillBackground(false); 00633 layout()->addWidget(d->view); 00634 } 00635 00636 d->view->setScene(widget->scene()); 00637 00638 //try to have the proper size -before- showing the dialog 00639 d->view->centerOn(widget); 00640 if (widget->layout()) { 00641 widget->layout()->activate(); 00642 } 00643 static_cast<QGraphicsLayoutItem *>(widget)->updateGeometry(); 00644 widget->resize(widget->size().expandedTo(widget->effectiveSizeHint(Qt::MinimumSize))); 00645 00646 syncToGraphicsWidget(); 00647 00648 //d->adjustSizeTimer->start(150); 00649 00650 widget->installEventFilter(this); 00651 d->view->installEventFilter(this); 00652 } else { 00653 delete d->view; 00654 d->view = 0; 00655 } 00656 } 00657 00658 //KDE5 FIXME: should be const 00659 QGraphicsWidget *Dialog::graphicsWidget() 00660 { 00661 return d->graphicsWidgetPtr.data(); 00662 } 00663 00664 bool Dialog::eventFilter(QObject *watched, QEvent *event) 00665 { 00666 if (d->resizeStartCorner == Dialog::NoCorner && watched == d->graphicsWidgetPtr.data() && 00667 (event->type() == QEvent::GraphicsSceneResize || event->type() == QEvent::GraphicsSceneMove)) { 00668 d->adjustViewTimer->start(150); 00669 } 00670 00671 // when moving the cursor with a 45° angle from the outside 00672 // to the inside passing over a resize angle the cursor changes its 00673 // shape to a resize cursor. As a side effect this is the only case 00674 // when the cursor immediately enters the view without giving 00675 // the dialog the chance to restore the original cursor shape. 00676 if (event->type() == QEvent::Enter && watched == d->view) { 00677 unsetCursor(); 00678 } 00679 00680 return QWidget::eventFilter(watched, event); 00681 } 00682 00683 void Dialog::hideEvent(QHideEvent * event) 00684 { 00685 Q_UNUSED(event); 00686 emit dialogVisible(false); 00687 } 00688 00689 void Dialog::showEvent(QShowEvent * event) 00690 { 00691 Q_UNUSED(event); 00692 00693 //check if the widget size is still synced with the view 00694 d->checkBorders(); 00695 d->updateResizeCorners(); 00696 00697 QGraphicsWidget *graphicsWidget = d->graphicsWidgetPtr.data(); 00698 if (graphicsWidget && 00699 ((d->view && graphicsWidget->size().toSize() != d->view->size()) || 00700 d->oldGraphicsWidgetMinimumSize != graphicsWidget->minimumSize() || 00701 d->oldGraphicsWidgetMaximumSize != graphicsWidget->maximumSize())) { 00702 //here have to be done immediately, ideally should have to be done -before- shwing, but is not possible to catch show() so early 00703 syncToGraphicsWidget(); 00704 d->oldGraphicsWidgetMinimumSize = graphicsWidget->minimumSize().toSize(); 00705 d->oldGraphicsWidgetMaximumSize = graphicsWidget->maximumSize().toSize(); 00706 } 00707 00708 if (d->view) { 00709 d->view->setFocus(); 00710 } 00711 00712 if (graphicsWidget) { 00713 graphicsWidget->setFocus(); 00714 } 00715 00716 emit dialogVisible(true); 00717 WindowEffects::overrideShadow(winId(), true); 00718 } 00719 00720 void Dialog::focusInEvent(QFocusEvent *event) 00721 { 00722 Q_UNUSED(event) 00723 00724 if (d->view) { 00725 d->view->setFocus(); 00726 } 00727 00728 QGraphicsWidget *graphicsWidget = d->graphicsWidgetPtr.data(); 00729 if (graphicsWidget) { 00730 graphicsWidget->setFocus(); 00731 } 00732 } 00733 00734 void Dialog::moveEvent(QMoveEvent *event) 00735 { 00736 Q_UNUSED(event) 00737 //kDebug(); 00738 d->scheduleBorderCheck(); 00739 } 00740 00741 void Dialog::setResizeHandleCorners(ResizeCorners corners) 00742 { 00743 if ((d->resizeCorners != corners) && (aspectRatioMode() != FixedSize)) { 00744 d->resizeCorners = corners; 00745 d->updateResizeCorners(); 00746 } 00747 } 00748 00749 Dialog::ResizeCorners Dialog::resizeCorners() const 00750 { 00751 return d->resizeCorners; 00752 } 00753 00754 void Dialog::animatedHide(Plasma::Direction direction) 00755 { 00756 if (!KWindowSystem::compositingActive()) { 00757 hide(); 00758 return; 00759 } 00760 00761 Location location = Desktop; 00762 switch (direction) { 00763 case Down: 00764 location = BottomEdge; 00765 break; 00766 case Right: 00767 location = RightEdge; 00768 break; 00769 case Left: 00770 location = LeftEdge; 00771 break; 00772 case Up: 00773 location = TopEdge; 00774 break; 00775 default: 00776 break; 00777 } 00778 00779 Plasma::WindowEffects::slideWindow(this, location); 00780 hide(); 00781 } 00782 00783 void Dialog::animatedShow(Plasma::Direction direction) 00784 { 00785 if (!KWindowSystem::compositingActive()) { 00786 show(); 00787 return; 00788 } 00789 00790 //copied to not add new api 00791 Location location = Desktop; 00792 switch (direction) { 00793 case Up: 00794 location = BottomEdge; 00795 break; 00796 case Left: 00797 location = RightEdge; 00798 break; 00799 case Right: 00800 location = LeftEdge; 00801 break; 00802 case Down: 00803 location = TopEdge; 00804 break; 00805 default: 00806 break; 00807 } 00808 00809 if (KWindowSystem::compositingActive()) { 00810 Plasma::WindowEffects::slideWindow(this, location); 00811 } 00812 00813 show(); 00814 } 00815 00816 bool Dialog::inControlArea(const QPoint &point) 00817 { 00818 foreach (const QRect &r, d->resizeAreas) { 00819 if (r.contains(point)) { 00820 return true; 00821 } 00822 } 00823 return false; 00824 } 00825 00826 Plasma::AspectRatioMode Dialog::aspectRatioMode() const 00827 { 00828 return d->aspectRatioMode; 00829 } 00830 00831 void Dialog::setAspectRatioMode(Plasma::AspectRatioMode mode) 00832 { 00833 if (mode == FixedSize) { 00834 setResizeHandleCorners(NoCorner); 00835 } 00836 00837 d->aspectRatioMode = mode; 00838 } 00839 00840 } 00841 #include "dialog.moc"
KDE 4.6 API Reference