not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / plasma / shells / desktop / panelcontroller.cpp
blobe024d3a4251bcf8165b05e2138f1222143815d38
1 /*
2 * Copyright 2008 Marco Martin <notmart@gmail.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as
6 * published by the Free Software Foundation; either version 2, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 #include "panelcontroller.h"
22 #include <QAction>
23 #include <QApplication>
24 #include <QBoxLayout>
25 #include <QVBoxLayout>
26 #include <QDesktopWidget>
27 #include <QFrame>
28 #include <QLabel>
29 #include <QMouseEvent>
30 #include <QPainter>
31 #include <QToolButton>
33 #include <KColorUtils>
34 #include <KIconLoader>
35 #include <KIcon>
36 #include <KWindowSystem>
38 #include <Plasma/Containment>
39 #include <Plasma/Corona>
40 #include <Plasma/PaintUtils>
41 #include <Plasma/Theme>
42 #include <Plasma/FrameSvg>
43 #include <Plasma/Dialog>
45 #include "plasmaapp.h"
46 #include "positioningruler.h"
47 #include "toolbutton.h"
49 #include <kephal/screens.h>
51 class PanelController::ButtonGroup: public QFrame
53 public:
54 ButtonGroup(QWidget *parent)
55 : QFrame(parent)
57 background = new Plasma::FrameSvg(this);
58 background->setImagePath("widgets/frame");
59 background->setElementPrefix("plain");
62 void paintEvent(QPaintEvent *event)
64 Q_UNUSED(event)
66 QPainter painter(this);
67 background->resizeFrame(size());
68 background->paintFrame(&painter);
71 Plasma::FrameSvg *background;
75 class PanelController::Private
77 public:
78 Private(PanelController *panelControl)
79 : q(panelControl),
80 containment(0),
81 orientation(Qt::Horizontal),
82 location(Plasma::BottomEdge),
83 extLayout(0),
84 layout(0),
85 dragging(NoElement),
86 startDragPos(0,0),
87 leftAlignTool(0),
88 centerAlignTool(0),
89 rightAlignTool(0),
90 drawMoveHint(false)
94 ToolButton *addTool(QAction *action, QWidget *parent, Qt::ToolButtonStyle style = Qt::ToolButtonTextBesideIcon)
96 ToolButton *tool = new ToolButton(parent);
97 tool->setToolButtonStyle(style);
98 tool->setAction(action);
99 actionWidgets.append(tool);
101 return tool;
104 ToolButton *addTool(const QString iconName, const QString iconText, QWidget *parent, Qt::ToolButtonStyle style = Qt::ToolButtonTextBesideIcon, bool checkButton = false)
106 //TODO take advantage of setDefaultAction using the containment's actions if possible
107 ToolButton *tool = new ToolButton(parent);
109 KIcon icon = KIcon(iconName);
110 if (!icon.isNull() && !iconName.isNull()) {
111 tool->setIcon(icon);
114 tool->setText(iconText);
115 tool->setToolButtonStyle(style);
117 if (style == Qt::ToolButtonIconOnly) {
118 tool->setToolTip(iconText);
121 tool->setCheckable(checkButton);
122 tool->setAutoExclusive(checkButton);
124 return tool;
127 void resizeFrameHeight(const int newHeight)
129 if (!containment) {
130 return;
133 switch (location) {
134 case Plasma::LeftEdge:
135 case Plasma::RightEdge:
136 containment->resize(QSize(newHeight, (int)containment->size().height()));
137 containment->setMinimumSize(QSize(newHeight, (int)containment->minimumSize().height()));
138 containment->setMaximumSize(QSize(newHeight, (int)containment->maximumSize().height()));
139 break;
140 case Plasma::TopEdge:
141 case Plasma::BottomEdge:
142 default:
143 containment->resize(QSize((int)containment->size().width(), newHeight));
144 containment->setMinimumSize(QSize((int)containment->minimumSize().width(), newHeight));
145 containment->setMaximumSize(QSize((int)containment->maximumSize().width(), newHeight));
146 break;
150 void rulersMoved(int offset, int minLength, int maxLength)
152 if (!containment) {
153 return;
156 QSize preferredSize(containment->preferredSize().toSize());
158 switch (location) {
159 case Plasma::LeftEdge:
160 case Plasma::RightEdge:
161 containment->resize(QSize((int)containment->size().width(), qBound(minLength, preferredSize.height(), maxLength)));
162 containment->setMinimumSize(QSize((int)containment->minimumSize().width(), minLength));
163 containment->setMaximumSize(QSize((int)containment->maximumSize().width(), maxLength));
164 break;
165 case Plasma::TopEdge:
166 case Plasma::BottomEdge:
167 default:
168 containment->resize(QSize(qBound(minLength, preferredSize.width(), maxLength), (int)containment->size().height()));
169 containment->setMinimumSize(QSize(minLength, (int)containment->minimumSize().height()));
170 containment->setMaximumSize(QSize(maxLength, (int)containment->maximumSize().height()));
171 break;
174 emit q->offsetChanged(offset);
177 void alignToggled(bool toggle)
179 if (!toggle) {
180 return;
183 if (q->sender() == leftAlignTool) {
184 emit q->alignmentChanged(Qt::AlignLeft);
185 ruler->setAlignment(Qt::AlignLeft);
186 } else if (q->sender() == centerAlignTool) {
187 emit q->alignmentChanged(Qt::AlignCenter);
188 ruler->setAlignment(Qt::AlignCenter);
189 } else if (q->sender() == rightAlignTool) {
190 emit q->alignmentChanged(Qt::AlignRight);
191 ruler->setAlignment(Qt::AlignRight);
194 emit q->offsetChanged(0);
195 ruler->setOffset(0);
198 void panelVisibilityModeChanged(bool toggle)
200 if (!toggle) {
201 return;
204 if (q->sender() == normalPanelTool) {
205 emit q->panelVisibilityModeChanged(PanelView::NormalPanel);
206 } else if (q->sender() == autoHideTool) {
207 emit q->panelVisibilityModeChanged(PanelView::AutoHide);
208 } else if (q->sender() == underWindowsTool) {
209 emit q->panelVisibilityModeChanged(PanelView::LetWindowsCover);
213 void settingsPopup()
215 if (optionsDialog->isVisible()) {
216 optionsDialog->hide();
217 } else {
218 KWindowSystem::setState(optionsDialog->winId(), NET::SkipTaskbar | NET::SkipPager | NET::Sticky);
219 QPoint pos = q->mapToGlobal(settingsTool->pos());
220 optionsDialog->layout()->activate();
221 optionsDialog->resize(optionsDialog->sizeHint());
222 QSize s = optionsDialog->size();
224 switch (location) {
225 case Plasma::BottomEdge:
226 pos = QPoint(pos.x(), pos.y() - s.height());
227 break;
228 case Plasma::TopEdge:
229 pos = QPoint(pos.x(), pos.y() + settingsTool->size().height());
230 break;
231 case Plasma::LeftEdge:
232 pos = QPoint(pos.x() + settingsTool->size().width(), pos.y());
233 break;
234 case Plasma::RightEdge:
235 pos = QPoint(pos.x() - s.width(), pos.y());
236 break;
237 default:
238 if (pos.y() - s.height() > 0) {
239 pos = QPoint(pos.x(), pos.y() - s.height());
240 } else {
241 pos = QPoint(pos.x(), pos.y() + settingsTool->size().height());
245 QRect screenRect = Kephal::ScreenUtils::screenGeometry(containment->screen());
247 if (pos.rx() + s.width() > screenRect.right()) {
248 pos.rx() -= ((pos.rx() + s.width()) - screenRect.right());
251 if (pos.ry() + s.height() > screenRect.bottom()) {
252 pos.ry() -= ((pos.ry() + s.height()) - screenRect.bottom());
255 pos.rx() = qMax(0, pos.rx());
256 optionsDialog->move(pos);
257 optionsDialog->show();
261 void syncRuler()
263 QRect screenGeom =
264 Kephal::ScreenUtils::screenGeometry(containment->screen());
266 switch (location) {
267 case Plasma::LeftEdge:
268 case Plasma::RightEdge:
269 ruler->setAvailableLength(screenGeom.height());
270 ruler->setMaxLength(qMin((int)containment->maximumSize().height(), screenGeom.height()));
271 ruler->setMinLength(containment->minimumSize().height());
272 break;
273 case Plasma::TopEdge:
274 case Plasma::BottomEdge:
275 default:
276 ruler->setAvailableLength(screenGeom.width());
277 ruler->setMaxLength(qMin((int)containment->maximumSize().width(), screenGeom.width()));
278 ruler->setMinLength(containment->minimumSize().width());
279 break;
283 void maximizePanel()
285 const int length = ruler->availableLength();
286 rulersMoved(0, length, length);
287 ruler->setOffset(0);
288 ruler->setMaxLength(length);
289 ruler->setMinLength(length);
292 enum DragElement { NoElement = 0,
293 ResizeButtonElement,
294 MoveButtonElement
297 PanelController *q;
298 Plasma::Containment *containment;
299 Qt::Orientation orientation;
300 Plasma::Location location;
301 QBoxLayout *extLayout;
302 QBoxLayout *layout;
303 QLabel *alignLabel;
304 QLabel *modeLabel;
305 DragElement dragging;
306 QPoint startDragPos;
307 Plasma::FrameSvg *background;
308 Plasma::Dialog *optionsDialog;
309 QBoxLayout *optDialogLayout;
310 ToolButton *settingsTool;
311 Plasma::Svg *iconSvg;
313 ToolButton *moveTool;
314 ToolButton *sizeTool;
316 //Alignment buttons
317 ToolButton *leftAlignTool;
318 ToolButton *centerAlignTool;
319 ToolButton *rightAlignTool;
321 //Panel mode buttons
322 ToolButton *normalPanelTool;
323 ToolButton *autoHideTool;
324 ToolButton *underWindowsTool;
325 ToolButton *expandTool;
327 //Widgets for actions
328 QList<QWidget *> actionWidgets;
330 PositioningRuler *ruler;
332 bool drawMoveHint;
334 static const int minimumHeight = 10;
337 PanelController::PanelController(QWidget* parent)
338 : QWidget(0),
339 d(new Private(this))
341 Q_UNUSED(parent)
343 QPalette pal = palette();
344 pal.setBrush(backgroundRole(), Qt::transparent);
345 setPalette(pal);
347 d->background = new Plasma::FrameSvg(this);
348 d->background->setImagePath("dialogs/background");
349 d->background->setContainsMultipleImages(true);
351 d->iconSvg = new Plasma::Svg(this);
352 d->iconSvg->setImagePath("widgets/configuration-icons");
353 d->iconSvg->setContainsMultipleImages(true);
354 d->iconSvg->resize(KIconLoader::SizeSmall, KIconLoader::SizeSmall);
356 //setWindowFlags(Qt::Popup);
357 setWindowFlags(Qt::FramelessWindowHint);
358 KWindowSystem::setState(winId(), NET::SkipTaskbar | NET::SkipPager | NET::Sticky);
359 setAttribute(Qt::WA_DeleteOnClose);
360 setFocus(Qt::ActiveWindowFocusReason);
362 //layout setup
363 d->extLayout = new QBoxLayout(QBoxLayout::TopToBottom, this);
364 setLayout(d->extLayout);
366 d->background->setEnabledBorders(Plasma::FrameSvg::TopBorder);
367 d->extLayout->setContentsMargins(0, d->background->marginSize(Plasma::TopMargin), 0, 0);
369 d->layout = new QBoxLayout(QBoxLayout::LeftToRight);
370 d->layout->setContentsMargins(4, 4, 4, 4);
371 if (QApplication::layoutDirection() == Qt::RightToLeft) {
372 d->layout->setDirection(QBoxLayout::RightToLeft);
373 } else {
374 d->layout->setDirection(QBoxLayout::LeftToRight);
376 d->layout->setSpacing(4);
378 d->layout->addStretch();
379 d->extLayout->addLayout(d->layout);
381 //Add buttons
383 //alignment
384 //first the container
385 QFrame *alignFrame = new ButtonGroup(this);
386 QVBoxLayout *alignLayout = new QVBoxLayout(alignFrame);
389 d->alignLabel = new QLabel(i18n("Panel Alignment"), this);
390 alignLayout->addWidget(d->alignLabel);
392 d->leftAlignTool = d->addTool("format-justify-left", i18n("Left"), alignFrame, Qt::ToolButtonTextBesideIcon, true);
393 d->leftAlignTool->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
394 alignLayout->addWidget(d->leftAlignTool);
395 d->leftAlignTool->setChecked(true);
396 connect(d->leftAlignTool, SIGNAL(toggled(bool)), this, SLOT(alignToggled(bool)));
398 d->centerAlignTool = d->addTool("format-justify-center", i18n("Center"), alignFrame, Qt::ToolButtonTextBesideIcon, true);
399 d->centerAlignTool->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
400 alignLayout->addWidget(d->centerAlignTool);
401 connect(d->centerAlignTool, SIGNAL(clicked(bool)), this, SLOT(alignToggled(bool)));
403 d->rightAlignTool = d->addTool("format-justify-right", i18n("Right"), alignFrame, Qt::ToolButtonTextBesideIcon, true);
404 d->rightAlignTool->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
405 alignLayout->addWidget(d->rightAlignTool);
406 connect(d->rightAlignTool, SIGNAL(clicked(bool)), this, SLOT(alignToggled(bool)));
409 //Panel mode
410 //first the container
411 QFrame *modeFrame = new ButtonGroup(this);
412 QVBoxLayout *modeLayout = new QVBoxLayout(modeFrame);
414 d->modeLabel = new QLabel(i18n("Visibility"), this);
415 modeLayout->addWidget(d->modeLabel);
417 d->normalPanelTool = d->addTool("checkmark", i18n("Always visible"), modeFrame, Qt::ToolButtonTextBesideIcon, true);
418 d->normalPanelTool->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
419 modeLayout->addWidget(d->normalPanelTool);
420 connect(d->normalPanelTool, SIGNAL(toggled(bool)), this, SLOT(panelVisibilityModeChanged(bool)));
422 d->autoHideTool = d->addTool("video-display", i18n("Auto hide"), modeFrame, Qt::ToolButtonTextBesideIcon, true);
423 d->autoHideTool->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
424 modeLayout->addWidget(d->autoHideTool);
425 connect(d->autoHideTool, SIGNAL(toggled(bool)), this, SLOT(panelVisibilityModeChanged(bool)));
427 d->underWindowsTool = d->addTool("view-fullscreen", i18n("Windows can cover"), modeFrame, Qt::ToolButtonTextBesideIcon, true);
428 d->underWindowsTool->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
429 modeLayout->addWidget(d->underWindowsTool);
430 connect(d->underWindowsTool, SIGNAL(toggled(bool)), this, SLOT(panelVisibilityModeChanged(bool)));
432 d->layout->addStretch();
433 d->moveTool = d->addTool(QString(), i18n("Screen Edge"), this);
434 d->moveTool->setIcon(d->iconSvg->pixmap("move"));
435 d->moveTool->installEventFilter(this);
436 d->moveTool->setCursor(Qt::SizeAllCursor);
437 d->layout->addWidget(d->moveTool);
439 d->sizeTool = d->addTool(QString(), i18n("Height"), this);
440 d->sizeTool->installEventFilter(this);
441 d->sizeTool->setCursor(Qt::SizeVerCursor);
442 d->layout->addWidget(d->sizeTool);
443 d->layout->addStretch();
445 //other buttons
446 d->layout->addSpacing(20);
448 //Settings popup menu
449 d->settingsTool = d->addTool("configure", i18n("More Settings"), this);
450 d->layout->addWidget(d->settingsTool);
451 connect(d->settingsTool, SIGNAL(pressed()), this, SLOT(settingsPopup()));
452 d->optionsDialog = new Plasma::Dialog(0); // don't pass in a parent; breaks with some lesser WMs
453 d->optionsDialog->installEventFilter(this);
454 KWindowSystem::setState(d->optionsDialog->winId(), NET::SkipTaskbar | NET::SkipPager | NET::Sticky);
455 d->optDialogLayout = new QVBoxLayout(d->optionsDialog);
456 d->optDialogLayout->setMargin(0);
457 d->optDialogLayout->addWidget(alignFrame);
458 d->optDialogLayout->addWidget(modeFrame);
461 d->expandTool = d->addTool(QString(), i18n("Maximize Panel"), this);
462 d->expandTool->setIcon(d->iconSvg->pixmap("size-horizontal"));
463 d->expandTool->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
464 d->optDialogLayout->addWidget(d->expandTool);
465 connect(d->expandTool, SIGNAL(clicked()), this, SLOT(maximizePanel()));
467 ToolButton *closeControllerTool = d->addTool("window-close", i18n("Close this configuration window"), this, Qt::ToolButtonIconOnly, false);
468 d->layout->addWidget(closeControllerTool);
469 connect(closeControllerTool, SIGNAL(clicked()), this, SLOT(hide()));
471 d->ruler = new PositioningRuler(this);
472 connect(d->ruler, SIGNAL(rulersMoved(int, int, int)), this, SLOT(rulersMoved(int, int, int)));
473 d->extLayout->addWidget(d->ruler);
475 connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), SLOT(themeChanged()));
476 themeChanged();
479 PanelController::~PanelController()
481 //TODO: should we try and only call this when something has actually been
482 // altered that we care about?
483 PlasmaApp::self()->corona()->requestConfigSync();
484 delete d->optionsDialog;
485 d->optionsDialog = 0;
486 delete d;
489 void PanelController::setContainment(Plasma::Containment *containment)
491 if (!containment) {
492 return;
495 d->containment = containment;
497 QWidget *child;
498 while (!d->actionWidgets.isEmpty()) {
499 child = d->actionWidgets.first();
500 //try to remove from both layouts
501 d->layout->removeWidget(child);
502 d->optDialogLayout->removeWidget(child);
503 d->actionWidgets.removeFirst();
504 child->deleteLater();
507 int insertIndex = d->layout->count() - 3;
509 QAction *action = containment->action("add widgets");
510 if (action) {
511 ToolButton *addWidgetTool = d->addTool(action, this);
512 d->layout->insertWidget(insertIndex, addWidgetTool);
513 ++insertIndex;
514 connect(addWidgetTool, SIGNAL(clicked()), this, SLOT(hide()));
517 action = containment->action("lock widgets");
518 if (action) {
519 ToolButton *lockWidgetsTool = d->addTool(action, this);
520 d->layout->insertWidget(insertIndex, lockWidgetsTool);
521 ++insertIndex;
522 connect(lockWidgetsTool, SIGNAL(clicked()), this, SLOT(hide()));
525 action = containment->action("remove");
526 if (action) {
527 ToolButton *removePanelTool = d->addTool(action, this);
528 removePanelTool->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
529 d->optDialogLayout->insertWidget(insertIndex, removePanelTool);
530 connect(removePanelTool, SIGNAL(clicked()), this, SLOT(hide()));
533 d->syncRuler();
536 QSize PanelController::sizeHint() const
538 QRect screenGeom =
539 Kephal::ScreenUtils::screenGeometry(d->containment->screen());
541 switch (d->location) {
542 case Plasma::LeftEdge:
543 case Plasma::RightEdge:
544 return QSize(QWidget::sizeHint().width(), screenGeom.height());
545 break;
546 case Plasma::TopEdge:
547 case Plasma::BottomEdge:
548 default:
549 return QSize(screenGeom.width(), QWidget::sizeHint().height());
550 break;
554 QPoint PanelController::positionForPanelGeometry(const QRect &panelGeom) const
556 QRect screenGeom =
557 Kephal::ScreenUtils::screenGeometry(d->containment->screen());
559 switch (d->location) {
560 case Plasma::LeftEdge:
561 return QPoint(panelGeom.right(), screenGeom.top());
562 break;
563 case Plasma::RightEdge:
564 return QPoint(panelGeom.left() - width(), screenGeom.top());
565 break;
566 case Plasma::TopEdge:
567 return QPoint(screenGeom.left(), panelGeom.bottom());
568 break;
569 case Plasma::BottomEdge:
570 default:
571 return QPoint(screenGeom.left(), panelGeom.top() - height());
572 break;
576 void PanelController::setLocation(const Plasma::Location &loc)
578 if (d->location == loc) {
579 return;
582 d->location = loc;
583 d->ruler->setLocation(loc);
584 QRect screenGeom =
585 Kephal::ScreenUtils::screenGeometry(d->containment->screen());
587 switch (loc) {
588 case Plasma::LeftEdge:
589 d->layout->setDirection(QBoxLayout::TopToBottom);
590 //The external layout gwts auto flipped when QApplication::layoutDirection() changes
591 //and it shouldn't, the internal one no and it should, so i must manually invert both
592 if (QApplication::layoutDirection() == Qt::RightToLeft) {
593 d->extLayout->setDirection(QBoxLayout::LeftToRight);
594 } else {
595 d->extLayout->setDirection(QBoxLayout::RightToLeft);
597 d->background->setEnabledBorders(Plasma::FrameSvg::RightBorder);
598 d->extLayout->setContentsMargins(0, 0, d->background->marginSize(Plasma::RightMargin), 0);
600 break;
601 case Plasma::RightEdge:
602 d->layout->setDirection(QBoxLayout::TopToBottom);
603 if (QApplication::layoutDirection() == Qt::RightToLeft) {
604 d->extLayout->setDirection(QBoxLayout::RightToLeft);
605 } else {
606 d->extLayout->setDirection(QBoxLayout::LeftToRight);
608 d->background->setEnabledBorders(Plasma::FrameSvg::LeftBorder);
609 d->extLayout->setContentsMargins(d->background->marginSize(Plasma::LeftMargin), 0, 0, 0);
611 break;
612 case Plasma::TopEdge:
613 if (QApplication::layoutDirection() == Qt::RightToLeft) {
614 d->layout->setDirection(QBoxLayout::RightToLeft);
615 } else {
616 d->layout->setDirection(QBoxLayout::LeftToRight);
618 d->extLayout->setDirection(QBoxLayout::BottomToTop);
619 d->background->setEnabledBorders(Plasma::FrameSvg::BottomBorder);
620 d->extLayout->setContentsMargins(0, 0, 0, d->background->marginSize(Plasma::BottomMargin));
622 break;
623 case Plasma::BottomEdge:
624 default:
625 if (QApplication::layoutDirection() == Qt::RightToLeft) {
626 d->layout->setDirection(QBoxLayout::RightToLeft);
627 } else {
628 d->layout->setDirection(QBoxLayout::LeftToRight);
630 d->extLayout->setDirection(QBoxLayout::TopToBottom);
631 d->background->setEnabledBorders(Plasma::FrameSvg::TopBorder);
632 d->extLayout->setContentsMargins(0, d->background->marginSize(Plasma::TopMargin), 0, 0);
634 break;
637 switch (loc) {
638 case Plasma::LeftEdge:
639 case Plasma::RightEdge:
640 d->sizeTool->setCursor(Qt::SizeHorCursor);
641 d->sizeTool->setText(i18n("Width"));
642 d->sizeTool->setIcon(d->iconSvg->pixmap("size-horizontal"));
643 d->expandTool->setIcon(d->iconSvg->pixmap("size-vertical"));
644 d->leftAlignTool->setText(i18n("Top"));
645 d->rightAlignTool->setText(i18n("Bottom"));
647 d->ruler->setAvailableLength(screenGeom.height());
649 break;
650 case Plasma::TopEdge:
651 case Plasma::BottomEdge:
652 default:
653 d->sizeTool->setCursor(Qt::SizeVerCursor);
654 d->sizeTool->setText(i18n("Height"));
655 d->sizeTool->setIcon(d->iconSvg->pixmap("size-vertical"));
656 d->expandTool->setIcon(d->iconSvg->pixmap("size-horizontal"));
657 d->leftAlignTool->setText(i18n("Left"));
658 d->rightAlignTool->setText(i18n("Right"));
660 d->ruler->setAvailableLength(screenGeom.width());
663 d->ruler->setMaximumSize(d->ruler->sizeHint());
665 d->syncRuler();
668 Plasma::Location PanelController::location() const
670 return d->location;
673 void PanelController::setOffset(int newOffset)
675 if (newOffset != d->ruler->offset()) {
676 d->ruler->setOffset(newOffset);
680 int PanelController::offset() const
682 return d->ruler->offset();
685 void PanelController::setAlignment(const Qt::Alignment &newAlignment)
687 if (newAlignment != d->ruler->alignment()) {
688 if (newAlignment == Qt::AlignLeft) {
689 d->leftAlignTool->setChecked(true);
690 } else if (newAlignment == Qt::AlignCenter) {
691 d->centerAlignTool->setChecked(true);
692 } else if (newAlignment == Qt::AlignRight) {
693 d->rightAlignTool->setChecked(true);
696 d->ruler->setAlignment(newAlignment);
700 Qt::Alignment PanelController::alignment() const
702 return d->ruler->alignment();
705 void PanelController::setVisibilityMode(PanelView::VisibilityMode mode)
707 switch (mode) {
708 case PanelView::AutoHide:
709 d->autoHideTool->setChecked(true);
710 break;
711 case PanelView::LetWindowsCover:
712 d->underWindowsTool->setChecked(true);
713 break;
714 case PanelView::NormalPanel:
715 default:
716 d->normalPanelTool->setChecked(true);
717 break;
721 PanelView::VisibilityMode PanelController::panelVisibilityMode() const
723 if (d->underWindowsTool->isChecked()) {
724 return PanelView::LetWindowsCover;
725 } else if (d->autoHideTool->isChecked()) {
726 return PanelView::AutoHide;
727 } else {
728 return PanelView::NormalPanel;
732 void PanelController::themeChanged()
734 QColor color = Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor);
735 QPalette p = d->alignLabel->palette();
736 p.setColor(QPalette::Normal, QPalette::WindowText, color);
737 p.setColor(QPalette::Inactive, QPalette::WindowText, color);
738 d->alignLabel->setPalette(p);
739 d->modeLabel->setPalette(p);
741 d->sizeTool->setIcon(d->iconSvg->pixmap("move"));
743 switch (d->location) {
744 case Plasma::LeftEdge:
745 case Plasma::RightEdge:
746 d->sizeTool->setIcon(d->iconSvg->pixmap("size-horizontal"));
747 break;
748 case Plasma::TopEdge:
749 case Plasma::BottomEdge:
750 default:
751 d->sizeTool->setIcon(d->iconSvg->pixmap("size-vertical"));
755 void PanelController::paintEvent(QPaintEvent *event)
757 Q_UNUSED(event)
759 QPainter painter(this);
760 painter.setCompositionMode(QPainter::CompositionMode_Source );
762 d->background->resizeFrame(size());
763 d->background->paintFrame(&painter);
766 bool PanelController::eventFilter(QObject *watched, QEvent *event)
768 if (watched == d->optionsDialog && event->type() == QEvent::WindowDeactivate) {
769 if (!d->settingsTool->underMouse()) {
770 d->optionsDialog->hide();
772 if (!isActiveWindow()) {
773 close();
775 return true;
776 } else if (watched == d->moveTool) {
777 if (event->type() == QEvent::MouseButtonPress) {
778 d->dragging = Private::MoveButtonElement;
779 } else if (event->type() == QEvent::MouseButtonRelease) {
780 d->dragging = Private::NoElement;
781 } else if (event->type() == QEvent::MouseMove) {
782 QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
783 mouseMoveFilter(mouseEvent);
785 } else if (watched == d->sizeTool) {
786 if (event->type() == QEvent::MouseButtonPress) {
787 QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
788 d->startDragPos = mouseEvent->pos();
789 d->dragging = Private::ResizeButtonElement;
790 } else if (event->type() == QEvent::MouseButtonRelease) {
791 //resets properties saved during the drag
792 d->startDragPos = QPoint(0, 0);
793 d->dragging = Private::NoElement;
794 setCursor(Qt::ArrowCursor);
795 } else if (event->type() == QEvent::MouseMove) {
796 QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
797 mouseMoveFilter(mouseEvent);
801 return false;
804 void PanelController::mouseMoveFilter(QMouseEvent *event)
806 if (d->dragging == Private::NoElement || !d->containment) {
807 return;
810 QRect screenGeom = Kephal::ScreenUtils::screenGeometry(d->containment->screen());
812 if (d->dragging == Private::MoveButtonElement) {
813 //only move when the mouse cursor is out of the controller to avoid an endless reposition cycle
814 if (geometry().contains(event->globalPos())) {
815 return;
818 if (!screenGeom.contains(event->globalPos())) {
819 //move panel to new screen if dragged there
820 int targetScreen = Kephal::ScreenUtils::screenId(event->globalPos());
821 //kDebug() << "Moving panel from screen" << d->containment->screen() << "to screen" << targetScreen;
822 d->containment->setScreen(targetScreen);
823 return;
826 //create a dead zone so you can go across the middle without having it hop to one side
827 float dzFactor = 0.35;
828 QPoint offset = QPoint(screenGeom.width()*dzFactor,screenGeom.height()*dzFactor);
829 QRect deadzone = QRect(screenGeom.topLeft()+offset, screenGeom.bottomRight()-offset);
830 if (deadzone.contains(event->globalPos())) {
831 //kDebug() << "In the deadzone:" << deadzone;
832 return;
835 const Plasma::Location oldLocation = d->containment->location();
836 Plasma::Location newLocation = oldLocation;
837 float screenAspect = float(screenGeom.height())/screenGeom.width();
839 /* Use diagonal lines so we get predictable behavior when moving the panel
840 * y=topleft.y+(x-topleft.x)*aspectratio topright < bottomleft
841 * y=bottomleft.y-(x-topleft.x)*aspectratio topleft < bottomright
843 if (event->globalY() < screenGeom.y()+(event->globalX()-screenGeom.x())*screenAspect) {
844 if (event->globalY() < screenGeom.bottomLeft().y()-(event->globalX()-screenGeom.x())*screenAspect) {
845 if (d->containment->location() == Plasma::TopEdge) {
846 return;
847 } else {
848 newLocation = Plasma::TopEdge;
850 } else if (d->containment->location() == Plasma::RightEdge) {
851 return;
852 } else {
853 newLocation = Plasma::RightEdge;
855 } else {
856 if (event->globalY() < screenGeom.bottomLeft().y()-(event->globalX()-screenGeom.x())*screenAspect) {
857 if (d->containment->location() == Plasma::LeftEdge) {
858 return;
859 } else {
860 newLocation = Plasma::LeftEdge;
862 } else if(d->containment->location() == Plasma::BottomEdge) {
863 return;
864 } else {
865 newLocation = Plasma::BottomEdge;
870 //If the orientation changed swap width and height
871 if (oldLocation != newLocation) {
872 emit locationChanged(newLocation);
875 return;
878 //Resize handle moved
879 switch (location()) {
880 case Plasma::LeftEdge: {
881 int newX = mapToGlobal(event->pos()).x() - d->startDragPos.x();
882 if (newX - d->minimumHeight > screenGeom.left() &&
883 newX - screenGeom.left() <= screenGeom.width()/3) {
884 move(newX, pos().y());
885 d->resizeFrameHeight(geometry().left() - screenGeom.left());
887 break;
889 case Plasma::RightEdge: {
890 int newX = mapToGlobal(event->pos()).x() - d->startDragPos.x();
891 if (newX + width() + d->minimumHeight < screenGeom.right() &&
892 newX + width() - screenGeom.left() >= 2*(screenGeom.width()/3)) {
893 move(newX, pos().y());
894 d->resizeFrameHeight(screenGeom.right() - geometry().right());
896 break;
898 case Plasma::TopEdge: {
899 int newY = mapToGlobal(event->pos()).y() - d->startDragPos.y();
900 if ( newY - d->minimumHeight > screenGeom.top() &&
901 newY - screenGeom.top()<= screenGeom.height()/3) {
902 move(pos().x(), newY);
903 d->resizeFrameHeight(geometry().top() - screenGeom.top());
905 break;
907 case Plasma::BottomEdge:
908 default: {
909 int newY = mapToGlobal(event->pos()).y() - d->startDragPos.y();
910 if ( newY + height() + d->minimumHeight < screenGeom.bottom() &&
911 newY + height() - screenGeom.top() >= 2*(screenGeom.height()/3)) {
912 move(pos().x(), newY);
913 d->resizeFrameHeight(screenGeom.bottom() - geometry().bottom());
915 break;
920 void PanelController::focusOutEvent(QFocusEvent * event)
922 Q_UNUSED(event)
923 if (!d->optionsDialog->isActiveWindow()) {
924 d->optionsDialog->hide();
925 close();
929 #include "panelcontroller.moc"