add more spacing
[personal-kdebase.git] / workspace / plasma / containments / mid-panel / panel.cpp
blob774029639fc389ad99d8d1086c2eb20847042c95
1 /*
2 * Copyright 2007 by Alex Merry <alex.merry@kdemail.net>
3 * Copyright 2008 by Alexis Ménard <darktears31@gmail.com>
4 * Copyright 2008 by Aaron Seigo <aseigo@kde.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Library General Public License version 2,
8 * or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "panel.h"
23 #include <limits>
25 #include <QApplication>
26 #include <QGraphicsLinearLayout>
27 #include <QPainter>
28 #include <QBitmap>
29 #include <QDesktopWidget>
30 #include <QGridLayout>
31 #include <QLabel>
32 #include <QComboBox>
33 #include <QAction>
34 #include <QGraphicsLayout>
37 #include <KDebug>
38 #include <KIcon>
39 #include <KDialog>
40 #include <KIntNumInput>
41 #include <KMessageBox>
43 #include <Plasma/Corona>
44 #include <Plasma/FrameSvg>
45 #include <Plasma/Theme>
46 #include <Plasma/View>
48 using namespace Plasma;
50 static const int CONTROL_BAR_HEIGHT = 22;
52 Panel::Panel(QObject *parent, const QVariantList &args)
53 : Containment(parent, args),
54 m_configureAction(0)
56 m_background = new Plasma::FrameSvg(this);
57 m_background->setImagePath("widgets/panel-background");
58 m_background->setEnabledBorders(Plasma::FrameSvg::AllBorders);
59 connect(m_background, SIGNAL(repaintNeeded()), this, SLOT(backgroundChanged()));
60 setZValue(150);
61 setContainmentType(Containment::PanelContainment);
63 QSize size = QSize(args.count() ? args[0].toInt() : 1024, 22);
64 kDebug() << "**********" << size;
65 resize(size);
66 setMinimumSize(size);
67 setMaximumSize(size);
68 setDrawWallpaper(false);
70 connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), this, SLOT(themeUpdated()));
71 connect(this, SIGNAL(appletAdded(Plasma::Applet*,QPointF)),
72 this, SLOT(layoutApplet(Plasma::Applet*,QPointF)));
73 connect(this, SIGNAL(appletRemoved(Plasma::Applet*)),
74 this, SLOT(appletRemoved(Plasma::Applet*)));
77 Panel::~Panel()
81 void Panel::init()
83 Containment::init();
86 QList<QAction*> Panel::contextualActions()
88 if (!m_configureAction) {
89 m_configureAction = new QAction(i18n("Panel Settings"), this);
90 m_configureAction->setIcon(KIcon("configure"));
91 connect(m_configureAction, SIGNAL(triggered()), this, SIGNAL(toolBoxToggled()));
94 QList<QAction*> actions;
95 actions << action("add widgets") << m_configureAction;
96 return actions;
99 void Panel::backgroundChanged()
101 constraintsEvent(Plasma::LocationConstraint);
104 void Panel::layoutApplet(Plasma::Applet* applet, const QPointF &pos)
106 // this gets called whenever an applet is added, and we add it to our layout
107 QGraphicsLinearLayout *lay = dynamic_cast<QGraphicsLinearLayout*>(layout());
109 if (!lay) {
110 return;
113 Plasma::FormFactor f = formFactor();
114 int insertIndex = -1;
116 //Enlarge the panel if possible
117 if (f == Plasma::Horizontal) {
118 resize(size().width() + applet->preferredWidth(), size().height());
119 } else {
120 resize(size().width(), size().height() + applet->preferredHeight());
122 layout()->setMaximumSize(size());
124 //if pos is (-1,-1) insert at the end of the panel
125 if (pos != QPoint(-1, -1)) {
126 for (int i = 0; i < lay->count(); ++i) {
127 QRectF siblingGeometry = lay->itemAt(i)->geometry();
128 if (f == Plasma::Horizontal) {
129 qreal middle = (siblingGeometry.left() + siblingGeometry.right()) / 2.0;
130 if (pos.x() < middle) {
131 insertIndex = i;
132 break;
133 } else if (pos.x() <= siblingGeometry.right()) {
134 insertIndex = i + 1;
135 break;
137 } else { // Plasma::Vertical
138 qreal middle = (siblingGeometry.top() + siblingGeometry.bottom()) / 2.0;
139 if (pos.y() < middle) {
140 insertIndex = i;
141 break;
142 } else if (pos.y() <= siblingGeometry.bottom()) {
143 insertIndex = i + 1;
144 break;
150 if (insertIndex == -1) {
151 lay->addItem(applet);
152 } else {
153 lay->insertItem(insertIndex, applet);
156 connect(applet, SIGNAL(sizeHintChanged(Qt::SizeHint)), this, SLOT(updateSize()));
159 void Panel::appletRemoved(Plasma::Applet* applet)
161 //shrink the panel if possible
162 if (formFactor() == Plasma::Horizontal) {
163 resize(size().width() - applet->size().width(), size().height());
164 } else {
165 resize(size().width(), size().height() - applet->size().height());
167 layout()->setMaximumSize(size());
170 void Panel::updateSize()
172 Plasma::Applet *applet = qobject_cast<Plasma::Applet *>(sender());
174 if (applet) {
175 if (formFactor() == Plasma::Horizontal) {
176 const int delta = applet->preferredWidth() - applet->size().width();
177 //setting the preferred width when delta = 0 and preferredWidth() < minimumWidth()
178 // leads to the same thing as setPreferredWidth(minimumWidth())
179 if (delta != 0) {
180 setPreferredWidth(preferredWidth() + delta);
182 } else if (formFactor() == Plasma::Vertical) {
183 const int delta = applet->preferredHeight() - applet->size().height();
184 if (delta != 0) {
185 setPreferredHeight(preferredHeight() + delta);
189 resize(preferredSize());
193 void Panel::updateBorders()
195 FrameSvg::EnabledBorders enabledBorders = FrameSvg::AllBorders;
197 kDebug() << "!!!!!!!!!!!!!!!! location be:" << location();
198 switch (location()) {
199 case BottomEdge:
200 enabledBorders = FrameSvg::TopBorder;
201 break;
202 case TopEdge:
203 enabledBorders = FrameSvg::BottomBorder;
204 break;
205 case LeftEdge:
206 enabledBorders = FrameSvg::RightBorder;
207 break;
208 case RightEdge:
209 enabledBorders = FrameSvg::LeftBorder;
210 break;
211 default:
212 break;
215 qreal topHeight = 0;
216 qreal bottomHeight = 0;
217 qreal leftWidth = 0;
218 qreal rightWidth = 0;
220 //activate borders and fetch sizes again
221 m_background->setEnabledBorders(enabledBorders);
222 m_background->getMargins(leftWidth, topHeight, rightWidth, bottomHeight);
224 //calculation of extra margins has to be done after getMargins
225 if (formFactor() == Vertical) {
226 //hardcoded extra margin for the toolbox right now
227 if (immutability() == Mutable) {
228 bottomHeight += 20;
230 //Default to horizontal for now
231 } else {
232 //hardcoded extra margin for the toolbox for now
233 if (immutability() == Mutable) {
234 if (QApplication::layoutDirection() == Qt::RightToLeft) {
235 leftWidth += 20;
236 } else {
237 rightWidth += 20;
243 //invalidate the layout and set again
244 if (layout()) {
245 layout()->setContentsMargins(leftWidth, topHeight, rightWidth, bottomHeight);
246 layout()->invalidate();
249 update();
252 void Panel::constraintsEvent(Plasma::Constraints constraints)
254 kDebug() << "constraints updated with" << constraints << "!!!!!!";
256 if (constraints & Plasma::FormFactorConstraint) {
257 Plasma::FormFactor form = formFactor();
258 Qt::Orientation layoutDirection = form == Plasma::Vertical ? Qt::Vertical : Qt::Horizontal;
260 // create our layout!
261 if (layout()) {
262 QGraphicsLayout *lay = layout();
263 QGraphicsLinearLayout * linearLay = dynamic_cast<QGraphicsLinearLayout *>(lay);
264 if (linearLay) {
265 linearLay->setOrientation(layoutDirection);
267 } else {
268 QGraphicsLinearLayout *lay = new QGraphicsLinearLayout(this);
269 lay->setOrientation(layoutDirection);
270 lay->setContentsMargins(0, 0, 0, 0);
271 lay->setSpacing(4);
272 lay->setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding));
273 setLayout(lay);
274 updateBorders();
276 foreach (Applet *applet, applets()) {
277 lay->addItem(applet);
282 //we need to know if the width or height is 100%
283 if (constraints & Plasma::LocationConstraint || constraints & Plasma::SizeConstraint) {
284 QSize size = geometry().size().toSize();
285 QRectF screenRect = screen() >= 0 ? QApplication::desktop()->screenGeometry(screen()) : geometry();
287 if ((formFactor() == Horizontal && size.width() >= screenRect.width()) ||
288 (formFactor() == Vertical && size.height() >= screenRect.height())) {
289 m_background->setElementPrefix(location());
290 } else {
291 m_background->setElementPrefix(QString());
294 m_background->resizeFrame(size);
295 updateBorders();
298 //FIXME: this seems the only way to correctly resize the layout the first time when the
299 // saved panel size is less than the default is to setting a maximum size.
300 // this shouldn't happen. maybe even a qgraphicslayout bug?
301 if (layout() && (constraints & Plasma::SizeConstraint)) {
302 layout()->setMaximumSize(size());
305 if (constraints & Plasma::LocationConstraint) {
306 setFormFactorFromLocation(location());
309 if (constraints & Plasma::ImmutableConstraint) {
310 bool unlocked = immutability() == Plasma::Mutable;
312 if (m_configureAction) {
313 m_configureAction->setEnabled(unlocked);
314 m_configureAction->setVisible(unlocked);
317 updateBorders();
321 void Panel::saveState(KConfigGroup &config) const
323 config.writeEntry("minimumSize", minimumSize());
324 config.writeEntry("maximumSize", maximumSize());
327 void Panel::themeUpdated()
329 //if the theme is changed all the calculations needs to be done again
330 //and resize based on the change in the theme bordersize
332 qreal oldLeftWidth;
333 qreal newLeftWidth;
334 qreal oldTopHeight;
335 qreal newTopHeight;
336 qreal oldRightWidth;
337 qreal newRightWidth;
338 qreal oldBottomHeight;
339 qreal newBottomHeight;
341 layout()->getContentsMargins(&oldLeftWidth, &oldTopHeight, &oldRightWidth, &oldBottomHeight);
342 m_background->getMargins(newLeftWidth, newTopHeight, newRightWidth, newBottomHeight);
344 QSize newSize(size().width()-(oldLeftWidth - newLeftWidth)-(oldRightWidth - newRightWidth),
345 size().height()-(oldTopHeight - newTopHeight)-(oldBottomHeight - newBottomHeight));
347 resize(newSize);
349 if (formFactor() == Plasma::Vertical) {
350 setMaximumWidth(newSize.width());
351 setMinimumWidth(newSize.width());
352 } else {
353 setMaximumHeight(newSize.height());
354 setMinimumHeight(newSize.height());
357 updateBorders();
360 void Panel::paintInterface(QPainter *painter,
361 const QStyleOptionGraphicsItem *option,
362 const QRect& contentsRect)
364 Q_UNUSED(contentsRect)
366 //FIXME: this background drawing is bad and ugly =)
367 // draw the background untransformed (saves lots of per-pixel-math)
368 painter->save();
369 painter->resetTransform();
371 const Containment::StyleOption *containmentOpt = qstyleoption_cast<const Containment::StyleOption *>(option);
373 QRect viewGeom;
374 if (containmentOpt) {
375 viewGeom = containmentOpt->view->geometry();
378 // blit the background (saves all the per-pixel-products that blending does)
379 painter->setCompositionMode(QPainter::CompositionMode_Source);
380 painter->setRenderHint(QPainter::Antialiasing);
382 m_background->paintFrame(painter, option->exposedRect, option->exposedRect);
384 if (containmentOpt && containmentOpt->view) {
385 containmentOpt->view->setMask(m_background->mask());
388 // restore transformation and composition mode
389 painter->restore();
392 void Panel::setFormFactorFromLocation(Plasma::Location loc) {
393 switch (loc) {
394 case BottomEdge:
395 case TopEdge:
396 //kDebug() << "setting horizontal form factor";
397 setFormFactor(Plasma::Horizontal);
398 break;
399 case RightEdge:
400 case LeftEdge:
401 //kDebug() << "setting vertical form factor";
402 setFormFactor(Plasma::Vertical);
403 break;
404 case Floating:
405 //TODO: implement a form factor for floating panels
406 kDebug() << "Floating is unimplemented.";
407 break;
408 default:
409 kDebug() << "invalid location!!";
413 K_EXPORT_PLASMA_APPLET(panel, Panel)
415 #include "panel.moc"