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

Plasma

panel.cpp

Go to the documentation of this file.
00001 /*
00002 *   Copyright 2007 by Alex Merry <huntedhacker@tiscali.co.uk>
00003 *   Copyright 2008 by Alexis Ménard <darktears31@gmail.com>
00004 *
00005 *   This program is free software; you can redistribute it and/or modify
00006 *   it under the terms of the GNU Library General Public License version 2,
00007 *   or (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 "panel.h"
00021 
00022 #include <limits>
00023 
00024 #include <QApplication>
00025 #include <QGraphicsLinearLayout>
00026 #include <QPainter>
00027 #include <QBitmap>
00028 #include <QDesktopWidget>
00029 #include <QGridLayout>
00030 #include <QLabel>
00031 #include <QComboBox>
00032 #include <QAction>
00033 #include <QGraphicsLayout>
00034 
00035 
00036 #include <KDebug>
00037 #include <KIcon>
00038 #include <KDialog>
00039 #include <KIntNumInput>
00040 #include <KMessageBox>
00041 
00042 #include <plasma/corona.h>
00043 #include <plasma/panelsvg.h>
00044 #include <plasma/theme.h>
00045 #include <plasma/view.h>
00046 
00047 using namespace Plasma;
00048 
00049 Panel::Panel(QObject *parent, const QVariantList &args)
00050     : Containment(parent, args),
00051       m_configureAction(0),
00052       m_addPanelAction(0),
00053       m_currentSize(QSize(QApplication::desktop()->screenGeometry(screen()).width(), 38)),
00054       m_lastViewGeom()
00055 {
00056     m_background = new Plasma::PanelSvg(this);
00057     m_background->setImagePath("widgets/panel-background");
00058     m_background->setEnabledBorders(Plasma::PanelSvg::AllBorders);
00059     connect(m_background, SIGNAL(repaintNeeded()), this, SLOT(backgroundChanged()));
00060     setZValue(150);
00061     setContainmentType(Containment::PanelContainment);
00062     resize(m_currentSize);
00063     setMinimumSize(m_currentSize);
00064     setMaximumSize(m_currentSize);
00065 
00066     connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(themeUpdated()));
00067     connect(this, SIGNAL(appletAdded(Plasma::Applet*,QPointF)),
00068             this, SLOT(layoutApplet(Plasma::Applet*,QPointF)));
00069     connect(this, SIGNAL(appletRemoved(Plasma::Applet*)),
00070             this, SLOT(appletRemoved(Plasma::Applet*)));
00071 }
00072 
00073 Panel::~Panel()
00074 {
00075 }
00076 
00077 void Panel::init()
00078 {
00079     Containment::init();
00080     //FIXME: This should be enabled, but in that case proxywidgets won't get rendered
00081     //setFlag(ItemClipsChildrenToShape, true);
00082 
00083     KConfigGroup cg = config("Configuration");
00084     setMinimumSize(cg.readEntry("minimumSize", m_currentSize));
00085     setMaximumSize(cg.readEntry("maximumSize", m_currentSize));
00086 }
00087 
00088 QList<QAction*> Panel::contextualActions()
00089 {
00090     if (!m_configureAction) {
00091         m_configureAction = new QAction(i18n("Panel Settings"), this);
00092         m_configureAction->setIcon(KIcon("configure"));
00093         connect(m_configureAction, SIGNAL(triggered()), this, SIGNAL(toolBoxToggled()));
00094 
00095         m_addPanelAction = new QAction(i18n("Add Panel"), this);
00096         connect(m_addPanelAction, SIGNAL(triggered(bool)), this, SLOT(addPanel()));
00097         m_addPanelAction->setIcon(KIcon("list-add"));
00098         constraintsEvent(Plasma::ImmutableConstraint);
00099     }
00100 
00101     QList<QAction*> actions;
00102     actions << action("add widgets") << m_addPanelAction << action("lock widgets") << m_configureAction << action("remove");
00103     return actions;
00104 }
00105 
00106 void Panel::backgroundChanged()
00107 {
00108     constraintsEvent(Plasma::LocationConstraint);
00109 }
00110 
00111 void Panel::layoutApplet(Plasma::Applet* applet, const QPointF &pos)
00112 {
00113     // this gets called whenever an applet is added, and we add it to our layout
00114     QGraphicsLinearLayout *lay = dynamic_cast<QGraphicsLinearLayout*>(layout());
00115 
00116     if (!lay) {
00117         return;
00118     }
00119 
00120     Plasma::FormFactor f = formFactor();
00121     int insertIndex = -1;
00122 
00123     //Enlarge the panel if possible
00124     if (f == Plasma::Horizontal) {
00125         resize(size().width() + applet->preferredWidth(), size().height());
00126     } else {
00127         resize(size().width(), size().height() + applet->preferredHeight());
00128     }
00129     layout()->setMaximumSize(size());
00130 
00131     //if pos is (-1,-1) insert at the end of the panel
00132     if (pos != QPoint(-1, -1)) {
00133         for (int i = 0; i < lay->count(); ++i) {
00134             QRectF siblingGeometry = lay->itemAt(i)->geometry();
00135             if (f == Plasma::Horizontal) {
00136                 qreal middle = (siblingGeometry.left() + siblingGeometry.right()) / 2.0;
00137                 if (pos.x() < middle) {
00138                     insertIndex = i;
00139                     break;
00140                 } else if (pos.x() <= siblingGeometry.right()) {
00141                     insertIndex = i + 1;
00142                     break;
00143                 }
00144             } else { // Plasma::Vertical
00145                 qreal middle = (siblingGeometry.top() + siblingGeometry.bottom()) / 2.0;
00146                 if (pos.y() < middle) {
00147                     insertIndex = i;
00148                     break;
00149                 } else if (pos.y() <= siblingGeometry.bottom()) {
00150                     insertIndex = i + 1;
00151                     break;
00152                 }
00153             }
00154         }
00155     }
00156 
00157     if (insertIndex == -1) {
00158         lay->addItem(applet);
00159     } else {
00160         lay->insertItem(insertIndex, applet);
00161     }
00162 }
00163 
00164 void Panel::appletRemoved(Plasma::Applet* applet)
00165 {
00166     //shrink the panel if possible
00167     if (formFactor() == Plasma::Horizontal) {
00168         resize(size().width() - applet->size().width(), size().height());
00169     } else {
00170         resize(size().width(), size().height() - applet->size().height());
00171     }
00172     layout()->setMaximumSize(size());
00173 }
00174 
00175 void Panel::addPanel()
00176 {
00177     if (corona()) {
00178         // make a panel at the top
00179         Containment* panel = corona()->addContainment("panel");
00180         panel->showConfigurationInterface();
00181 
00182         panel->setScreen(screen());
00183         panel->setLocation(Plasma::TopEdge);
00184 
00185         // trigger an instant layout so we immediately have a proper geometry 
00186         // rather than waiting around for the event loop
00187         panel->updateConstraints(Plasma::StartupCompletedConstraint);
00188         panel->flushPendingConstraintsEvents();
00189     }
00190 }
00191 
00192 void Panel::updateBorders(const QRect &geom)
00193 {
00194     Plasma::Location loc = location();
00195     PanelSvg::EnabledBorders enabledBorders = PanelSvg::AllBorders;
00196 
00197     int s = screen();
00198     //kDebug() << loc << s << formFactor() << geometry();
00199 
00200     qreal topHeight = m_background->marginSize(Plasma::TopMargin);
00201     qreal bottomHeight = m_background->marginSize(Plasma::BottomMargin);
00202     qreal leftWidth = m_background->marginSize(Plasma::LeftMargin);
00203     qreal rightWidth = m_background->marginSize(Plasma::RightMargin);
00204 
00205     //remove unwanted borders
00206     if (s < 0) {
00207         // do nothing in this case, we want all the borders
00208     } else if (loc == BottomEdge || loc == TopEdge) {
00209         QRect r = QApplication::desktop()->screenGeometry(s);
00210 
00211         if (loc == BottomEdge) {
00212             enabledBorders ^= PanelSvg::BottomBorder;
00213             bottomHeight = 0;
00214         } else {
00215             enabledBorders ^= PanelSvg::TopBorder;
00216             topHeight = 0;
00217         }
00218 
00219         if (geom.x() <= r.x()) {
00220             enabledBorders ^= PanelSvg::LeftBorder;
00221             leftWidth = 0;
00222         }
00223         if (geom.right() >= r.right()) {
00224             enabledBorders ^= PanelSvg::RightBorder;
00225             rightWidth = 0;
00226         }
00227 
00228         //kDebug() << "top/bottom: Width:" << width << ", height:" << height;
00229     } else if (loc == LeftEdge || loc == RightEdge) {
00230         QRect r = QApplication::desktop()->screenGeometry(s);
00231 
00232         if (loc == RightEdge) {
00233             enabledBorders ^= PanelSvg::RightBorder;
00234             rightWidth = 0;
00235         } else {
00236             enabledBorders ^= PanelSvg::LeftBorder;
00237             leftWidth = 0;
00238         }
00239         if (geom.y() <= r.y()) {
00240             enabledBorders ^= PanelSvg::TopBorder;
00241             topHeight = 0;
00242         }
00243         if (geom.bottom() >= r.bottom()) {
00244             enabledBorders ^= PanelSvg::BottomBorder;
00245             bottomHeight = 0;
00246         }
00247 
00248         //kDebug() << "left/right: Width:" << width << ", height:" << height;
00249     } else {
00250         kDebug() << "no location!?";
00251     }
00252 
00253     //activate borders and fetch sizes again
00254     m_background->setEnabledBorders(enabledBorders);
00255     m_background->getMargins(leftWidth, topHeight, rightWidth, bottomHeight);
00256 
00257     //calculation of extra margins has to be done after getMargins
00258     if (formFactor() == Vertical) {
00259         //hardcoded extra margin for the toolbox right now
00260         if (immutability() == Mutable) {
00261             bottomHeight += 20;
00262         }
00263     //Default to horizontal for now
00264     } else {
00265         //hardcoded extra margin for the toolbox for now
00266         if (immutability() == Mutable) {
00267             if (QApplication::layoutDirection() == Qt::RightToLeft) {
00268                 leftWidth += 20;
00269             } else {
00270                 rightWidth += 20;
00271             }
00272         }
00273     }
00274 
00275 
00276     //invalidate the layout and set again
00277     if (layout()) {
00278         layout()->setContentsMargins(leftWidth, topHeight, rightWidth, bottomHeight);
00279         layout()->invalidate();
00280     }
00281 
00282     update();
00283 }
00284 
00285 void Panel::constraintsEvent(Plasma::Constraints constraints)
00286 {
00287     kDebug() << "constraints updated with" << constraints << "!!!!!!";
00288 
00289     if (constraints & Plasma::FormFactorConstraint) {
00290         Plasma::FormFactor form = formFactor();
00291 
00292         // create our layout!
00293         if (form == Plasma::Horizontal || Plasma::Vertical) {
00294             if (layout()) {
00295                 QGraphicsLayout *lay = layout();
00296                 QGraphicsLinearLayout * linearLay = dynamic_cast<QGraphicsLinearLayout *>(lay);
00297                 if (linearLay) {
00298                     linearLay->setOrientation(form == Plasma::Horizontal ? Qt::Horizontal :
00299                                                                            Qt::Vertical);
00300                 }
00301             } else {
00302                 QGraphicsLinearLayout *lay = new QGraphicsLinearLayout(this);
00303                 lay->setOrientation(form == Plasma::Horizontal ? Qt::Horizontal : Qt::Vertical);
00304                 lay->setContentsMargins(0, 0, 0, 0);
00305                 lay->setSpacing(4);
00306                 lay->setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding));
00307                 setLayout(lay);
00308                 updateBorders(geometry().toRect());
00309 
00310                 foreach (Applet *applet, applets()) {
00311                     lay->addItem(applet);
00312                 }
00313             }
00314         }
00315     }
00316 
00317     //we need to know if the width or height is 100%
00318     if (constraints & Plasma::LocationConstraint || constraints & Plasma::SizeConstraint) {
00319         m_currentSize = geometry().size().toSize();
00320         QRectF screenRect = screen() >= 0 ? QApplication::desktop()->screenGeometry(screen()) :
00321             geometry();
00322 
00323         if ((formFactor() == Horizontal && m_currentSize.width() >= screenRect.width()) || 
00324                 (formFactor() == Vertical && m_currentSize.height() >= screenRect.height())) {
00325             m_background->setElementPrefix(location());
00326         } else {
00327             m_background->setElementPrefix(QString());
00328         }
00329 
00330         m_background->resizePanel(m_currentSize);
00331     }
00332 
00333     //FIXME: this seems the only way to correctly resize the layout the first time when the
00334     // saved panel size is less than the default is to setting a maximum size.
00335     // this shouldn't happen. maybe even a qgraphicslayout bug?
00336     if (layout() && (constraints & Plasma::SizeConstraint)) {
00337         layout()->setMaximumSize(size());
00338     }
00339 
00340     if (constraints & Plasma::LocationConstraint) {
00341         setFormFactorFromLocation(location());
00342     }
00343 
00344     if (constraints & Plasma::ImmutableConstraint) {
00345         bool unlocked = immutability() == Plasma::Mutable;
00346 
00347         if (m_addPanelAction) {
00348             m_addPanelAction->setEnabled(unlocked);
00349             m_addPanelAction->setVisible(unlocked);
00350         }
00351 
00352         if (m_configureAction) {
00353             m_configureAction->setEnabled(unlocked);
00354             m_configureAction->setVisible(unlocked);
00355         }
00356 
00357         QGraphicsView *panelView = view();
00358         if (panelView) {
00359             updateBorders(panelView->geometry());
00360         }
00361     }
00362 }
00363 
00364 void Panel::saveState(KConfigGroup &config) const
00365 {
00366     config.writeEntry("minimumSize", minimumSize());
00367     config.writeEntry("maximumSize", maximumSize());
00368 }
00369 
00370 void Panel::themeUpdated()
00371 {
00372     //if the theme is changed all the calculations needs to be done again
00373     //and resize based on the change in the theme bordersize
00374 
00375     qreal oldLeftWidth;
00376     qreal newLeftWidth;
00377     qreal oldTopHeight;
00378     qreal newTopHeight;
00379     qreal oldRightWidth;
00380     qreal newRightWidth;
00381     qreal oldBottomHeight;
00382     qreal newBottomHeight;
00383 
00384     layout()->getContentsMargins(&oldLeftWidth, &oldTopHeight, &oldRightWidth, &oldBottomHeight);
00385     m_background->getMargins(newLeftWidth, newTopHeight, newRightWidth, newBottomHeight);
00386 
00387     QSize newSize(size().width()-(oldLeftWidth - newLeftWidth)-(oldRightWidth - newRightWidth),
00388            size().height()-(oldTopHeight - newTopHeight)-(oldBottomHeight - newBottomHeight));
00389 
00390     resize(newSize);
00391 
00392     if (formFactor() == Plasma::Vertical) {
00393         setMaximumWidth(newSize.width());
00394         setMinimumWidth(newSize.width());
00395     } else {
00396         setMaximumHeight(newSize.height());
00397         setMinimumHeight(newSize.height());
00398     }
00399 
00400     updateBorders(geometry().toRect());
00401 }
00402 
00403 void Panel::paintInterface(QPainter *painter,
00404                            const QStyleOptionGraphicsItem *option,
00405                            const QRect& contentsRect)
00406 {
00407     //FIXME: this background drawing is bad and ugly =)
00408     // draw the background untransformed (saves lots of per-pixel-math)
00409     painter->save();
00410     painter->resetTransform();
00411 
00412     const Containment::StyleOption *containmentOpt = qstyleoption_cast<const Containment::StyleOption *>(option);
00413     
00414     QRect viewGeom;
00415     if (containmentOpt) {
00416         viewGeom = containmentOpt->view->geometry();
00417     }
00418 
00419     if (viewGeom != m_lastViewGeom) {
00420         m_lastViewGeom = viewGeom;
00421         updateBorders(viewGeom);
00422     }
00423 
00424     // blit the background (saves all the per-pixel-products that blending does)
00425     painter->setCompositionMode(QPainter::CompositionMode_Source);
00426     painter->setRenderHint(QPainter::Antialiasing);
00427 
00428     m_background->paintPanel(painter, contentsRect);
00429 
00430     if (containmentOpt && containmentOpt->view) {
00431         containmentOpt->view->setMask(m_background->mask());
00432     }
00433 
00434     // restore transformation and composition mode
00435     painter->restore();
00436 }
00437 
00438 void Panel::setFormFactorFromLocation(Plasma::Location loc) {
00439     switch (loc) {
00440         case BottomEdge:
00441         case TopEdge:
00442             //kDebug() << "setting horizontal form factor";
00443             setFormFactor(Plasma::Horizontal);
00444             break;
00445         case RightEdge:
00446         case LeftEdge:
00447             //kDebug() << "setting vertical form factor";
00448             setFormFactor(Plasma::Vertical);
00449             break;
00450         case Floating:
00451             //TODO: implement a form factor for floating panels
00452             kDebug() << "Floating is unimplemented.";
00453             break;
00454         default:
00455             kDebug() << "invalid location!!";
00456     }
00457 }
00458 
00459 K_EXPORT_PLASMA_APPLET(panel, Panel)
00460 
00461 #include "panel.moc"
00462 

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
  •   libplasma
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.4
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