Fix and install smb2rdc action
[kdenetwork.git] / krdc / floatingtoolbar.cpp
blob59875704a9413ba3033f36a8e338117f1f55d3e4
1 /****************************************************************************
2 **
3 ** Copyright (C) 2007 Urs Wolfer <uwolfer @ kde.org>
4 ** Parts of this file have been take from okular:
5 ** Copyright (C) 2004-2005 Enrico Ros <eros.kde@email.it>
6 **
7 ** This file is part of KDE.
8 **
9 ** This program is free software; you can redistribute it and/or modify
10 ** it under the terms of the GNU General Public License as published by
11 ** the Free Software Foundation; either version 2 of the License, or
12 ** (at your option) any later version.
14 ** This program is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ** GNU General Public License for more details.
19 ** You should have received a copy of the GNU General Public License
20 ** along with this program; see the file COPYING. If not, write to
21 ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 ** Boston, MA 02110-1301, USA.
24 ****************************************************************************/
26 #include "floatingtoolbar.h"
28 #include <KDebug>
30 #include <QApplication>
31 #include <QBitmap>
32 #include <QMouseEvent>
33 #include <QLinkedList>
34 #include <QPainter>
35 #include <QPaintEvent>
36 #include <QTimer>
37 #include <QToolButton>
38 #include <QWheelEvent>
40 #include <math.h>
42 static const int iconSize = 22;
43 static const int buttonSize = 28;
44 static const int toolBarGridSize = 28;
45 static const int toolBarRBMargin = 2;
46 static const qreal toolBarOpacity = 0.8;
47 static const int visiblePixelWhenAutoHidden = 3;
48 static const int autoHideTimeout = 2000;
50 class FloatingToolBarPrivate
52 public:
53 FloatingToolBarPrivate(FloatingToolBar *qq)
54 : q(qq) {
57 // rebuild contents and reposition then widget
58 void buildToolBar();
59 void reposition();
60 // compute the visible and hidden positions along current side
61 QPoint getInnerPoint() const;
62 QPoint getOuterPoint() const;
64 FloatingToolBar *q;
66 QWidget *anchorWidget;
67 FloatingToolBar::Side anchorSide;
69 QTimer *animTimer;
70 QTimer *autoHideTimer;
71 QPoint currentPosition;
72 QPoint endPosition;
73 bool hiding;
74 bool toDelete;
75 bool visible;
76 bool sticky;
77 qreal opacity;
79 QPixmap backgroundPixmap;
80 QLinkedList<QToolButton*> buttons;
83 FloatingToolBar::FloatingToolBar(QWidget *parent, QWidget *anchorWidget)
84 : QWidget(parent), d(new FloatingToolBarPrivate(this))
86 setMouseTracking(true);
88 d->anchorWidget = anchorWidget;
89 d->anchorSide = Left;
90 d->hiding = false;
91 d->toDelete = false;
92 d->visible = false;
93 d->sticky = false;
94 d->opacity = toolBarOpacity;
96 d->animTimer = new QTimer(this);
97 connect(d->animTimer, SIGNAL(timeout()), this, SLOT(slotAnimate()));
99 d->autoHideTimer = new QTimer(this);
100 connect(d->autoHideTimer, SIGNAL(timeout()), this, SLOT(hide()));
101 d->autoHideTimer->start(autoHideTimeout);
103 // apply a filter to get notified when anchor changes geometry
104 d->anchorWidget->installEventFilter(this);
107 FloatingToolBar::~FloatingToolBar()
109 delete d;
112 void FloatingToolBar::addAction(QAction *action)
114 QToolButton *button = new QToolButton(this);
115 button->setDefaultAction(action);
116 button->setCheckable(true);
117 button->setAutoRaise(true);
118 button->resize(buttonSize, buttonSize);
119 button->setIconSize(QSize(iconSize, iconSize));
121 d->buttons.append(button);
123 button->setMouseTracking(true);
124 button->installEventFilter(this);
126 // rebuild toolbar shape and contents
127 d->reposition();
130 void FloatingToolBar::setSide(Side side)
132 d->anchorSide = side;
134 d->reposition();
137 void FloatingToolBar::setSticky(bool sticky)
139 d->sticky = sticky;
141 if (sticky)
142 d->autoHideTimer->stop();
143 else
144 d->autoHideTimer->start(autoHideTimeout);
147 void FloatingToolBar::showAndAnimate()
149 d->hiding = false;
151 show();
153 // start scrolling in
154 d->animTimer->start(20);
157 void FloatingToolBar::hideAndDestroy()
159 // set parameters for sliding out
160 d->hiding = true;
161 d->toDelete = true;
162 d->endPosition = d->getOuterPoint();
164 // start scrolling out
165 d->animTimer->start(20);
168 void FloatingToolBar::hide()
170 if (d->visible) {
171 QPoint diff;
172 switch (d->anchorSide) {
173 case Left:
174 diff = QPoint(visiblePixelWhenAutoHidden, 0);
175 break;
176 case Right:
177 diff = QPoint(-visiblePixelWhenAutoHidden, 0);
178 break;
179 case Top:
180 diff = QPoint(0, visiblePixelWhenAutoHidden);
181 break;
182 case Bottom:
183 diff = QPoint(0, -visiblePixelWhenAutoHidden);
184 break;
186 d->hiding = true;
187 d->endPosition = d->getOuterPoint() + diff;
190 // start scrolling out
191 d->animTimer->start(20);
194 bool FloatingToolBar::eventFilter(QObject *obj, QEvent *e)
196 // if anchorWidget changed geometry reposition toolbar
197 if (obj == d->anchorWidget && e->type() == QEvent::Resize) {
198 d->animTimer->stop();
199 if (d->hiding && d->toDelete)
200 deleteLater();
201 else
202 d->reposition();
205 // keep toolbar visible when mouse is on it
206 if (e->type() == QEvent::MouseMove && d->autoHideTimer->isActive())
207 d->autoHideTimer->start(autoHideTimeout);
209 return false;
212 void FloatingToolBar::paintEvent(QPaintEvent *e)
214 // paint the internal pixmap over the widget
215 QPainter p(this);
216 p.setOpacity(d->opacity);
217 p.drawImage(e->rect().topLeft(), d->backgroundPixmap.toImage(), e->rect());
220 void FloatingToolBar::mousePressEvent(QMouseEvent *e)
222 if (e->button() == Qt::LeftButton)
223 setCursor(Qt::SizeAllCursor);
226 void FloatingToolBar::mouseMoveEvent(QMouseEvent *e)
228 // keep toolbar visible when mouse is on it
229 if (d->autoHideTimer->isActive())
230 d->autoHideTimer->start(autoHideTimeout);
232 // show the toolbar again when it is auto-hidden
233 if (!d->visible && !d->animTimer->isActive()) {
234 d->hiding = false;
235 show();
236 d->endPosition = QPoint();
237 d->reposition();
239 d->animTimer->start(20);
241 return;
244 if ((QApplication::mouseButtons() & Qt::LeftButton) != Qt::LeftButton)
245 return;
247 // compute the nearest side to attach the widget to
248 QPoint parentPos = mapToParent(e->pos());
249 float nX = (float)parentPos.x() / (float)d->anchorWidget->width();
250 float nY = (float)parentPos.y() / (float)d->anchorWidget->height();
251 if (nX > 0.3 && nX < 0.7 && nY > 0.3 && nY < 0.7)
252 return;
253 bool LT = nX < (1.0 - nY);
254 bool LB = nX < (nY);
255 Side side = LT ? (LB ? Left : Top) : (LB ? Bottom : Right);
257 // check if side changed
258 if (side == d->anchorSide)
259 return;
261 d->anchorSide = side;
262 d->reposition();
263 emit orientationChanged((int)side);
266 void FloatingToolBar::mouseReleaseEvent(QMouseEvent *e)
268 if (e->button() == Qt::LeftButton)
269 setCursor(Qt::ArrowCursor);
272 void FloatingToolBar::wheelEvent(QWheelEvent *e)
274 e->accept();
276 qreal diff = e->delta() / 100.0 / 15.0;
277 // kDebug(5010) << diff;
278 if (((d->opacity <= 1) && (diff > 0)) || ((d->opacity >= 0) && (diff < 0)))
279 d->opacity += diff;
281 update();
284 void FloatingToolBarPrivate::buildToolBar()
286 int buttonsNumber = buttons.count();
287 int parentWidth = anchorWidget->width();
288 int parentHeight = anchorWidget->height();
289 int myCols = 1;
290 int myRows = 1;
292 // 1. find out columns and rows we're going to use
293 bool topLeft = anchorSide == FloatingToolBar::Left || anchorSide == FloatingToolBar::Top;
294 bool vertical = anchorSide == FloatingToolBar::Left || anchorSide == FloatingToolBar::Right;
295 if (vertical) {
296 myCols = 1 + (buttonsNumber * toolBarGridSize) /
297 (parentHeight - toolBarGridSize);
298 myRows = (int)ceil((float)buttonsNumber / (float)myCols);
299 } else {
300 myRows = 1 + (buttonsNumber * toolBarGridSize) /
301 (parentWidth - toolBarGridSize);
302 myCols = (int)ceil((float)buttonsNumber / (float)myRows);
305 // 2. compute widget size (from rows/cols)
306 int myWidth = myCols * toolBarGridSize;
307 int myHeight = myRows * toolBarGridSize;
308 int xOffset = (toolBarGridSize - buttonSize) / 2;
309 int yOffset = (toolBarGridSize - buttonSize) / 2;
311 if (vertical) {
312 myHeight += 16;
313 myWidth += 4;
314 yOffset += 12;
315 if (anchorSide == FloatingToolBar::Right)
316 xOffset += 4;
317 } else {
318 myWidth += 16;
319 myHeight += 4;
320 xOffset += 12;
321 if (anchorSide == FloatingToolBar::Bottom)
322 yOffset += 4;
325 bool prevUpdates = q->updatesEnabled();
326 q->setUpdatesEnabled(false);
328 // 3. resize pixmap, mask and widget
329 QBitmap mask(myWidth + 1, myHeight + 1);
330 backgroundPixmap = QPixmap(myWidth + 1, myHeight + 1);
331 backgroundPixmap.fill(Qt::transparent);
332 q->resize(myWidth + 1, myHeight + 1);
334 // 4. create and set transparency mask
335 QPainter maskPainter(&mask);
336 mask.fill(Qt::white);
337 maskPainter.setBrush(Qt::black);
338 if (vertical)
339 maskPainter.drawRoundRect(topLeft ? -10 : 0, 0, myWidth + 10, myHeight, 2000 / (myWidth + 10), 2000 / myHeight);
340 else
341 maskPainter.drawRoundRect(0, topLeft ? -10 : 0, myWidth, myHeight + 10, 2000 / myWidth, 2000 / (myHeight + 10));
342 maskPainter.end();
343 q->setMask(mask);
345 // 5. draw background
346 QPainter bufferPainter(&backgroundPixmap);
347 bufferPainter.translate(0.5, 0.5);
348 QPalette pal = q->palette();
349 // 5.1. draw horizontal/vertical gradient
350 QLinearGradient grad;
351 switch (anchorSide) {
352 case FloatingToolBar::Left:
353 grad = QLinearGradient(0, 1, myWidth + 1, 1);
354 break;
355 case FloatingToolBar::Right:
356 grad = QLinearGradient(myWidth + 1, 1, 0, 1);
357 break;
358 case FloatingToolBar::Top:
359 grad = QLinearGradient(1, 0, 1, myHeight + 1);
360 break;
361 case FloatingToolBar::Bottom:
362 grad = QLinearGradient(1, myHeight + 1, 0, 1);
363 break;
365 grad.setColorAt(0, pal.color(QPalette::Active, QPalette::Button));
366 grad.setColorAt(1, pal.color(QPalette::Active, QPalette::Light));
367 bufferPainter.setBrush(QBrush(grad));
368 // 5.2. draw rounded border
369 bufferPainter.setPen( pal.color(QPalette::Active, QPalette::Dark).lighter(40));
370 bufferPainter.setRenderHints(QPainter::Antialiasing);
371 if (vertical)
372 bufferPainter.drawRoundRect(topLeft ? -10 : 0, 0, myWidth + 10, myHeight, 2000 / (myWidth + 10), 2000 / myHeight);
373 else
374 bufferPainter.drawRoundRect(0, topLeft ? -10 : 0, myWidth, myHeight + 10, 2000 / myWidth, 2000 / (myHeight + 10));
375 // 5.3. draw handle
376 bufferPainter.translate(-0.5, -0.5);
377 bufferPainter.setPen(pal.color(QPalette::Active, QPalette::Mid));
378 if (vertical) {
379 int dx = anchorSide == FloatingToolBar::Left ? 2 : 4;
380 bufferPainter.drawLine(dx, 6, dx + myWidth - 8, 6);
381 bufferPainter.drawLine(dx, 9, dx + myWidth - 8, 9);
382 bufferPainter.setPen(pal.color(QPalette::Active, QPalette::Light));
383 bufferPainter.drawLine(dx + 1, 7, dx + myWidth - 7, 7);
384 bufferPainter.drawLine(dx + 1, 10, dx + myWidth - 7, 10);
385 } else {
386 int dy = anchorSide == FloatingToolBar::Top ? 2 : 4;
387 bufferPainter.drawLine(6, dy, 6, dy + myHeight - 8);
388 bufferPainter.drawLine(9, dy, 9, dy + myHeight - 8);
389 bufferPainter.setPen(pal.color(QPalette::Active, QPalette::Light));
390 bufferPainter.drawLine(7, dy + 1, 7, dy + myHeight - 7);
391 bufferPainter.drawLine(10, dy + 1, 10, dy + myHeight - 7);
394 // 6. reposition buttons (in rows/col grid)
395 int gridX = 0;
396 int gridY = 0;
397 QLinkedList<QToolButton*>::const_iterator it = buttons.begin(), end = buttons.end();
398 for (; it != end; ++it) {
399 QToolButton *button = *it;
400 button->move(gridX * toolBarGridSize + xOffset,
401 gridY * toolBarGridSize + yOffset);
402 button->show();
403 if (++gridX == myCols) {
404 gridX = 0;
405 gridY++;
409 q->setUpdatesEnabled(prevUpdates);
412 void FloatingToolBarPrivate::reposition()
414 // note: hiding widget here will gives better gfx, but ends drag operation
415 // rebuild widget and move it to its final place
416 buildToolBar();
417 if (!visible) {
418 currentPosition = getOuterPoint();
419 endPosition = getInnerPoint();
420 } else {
421 currentPosition = getInnerPoint();
422 endPosition = getOuterPoint();
424 q->move(currentPosition);
426 // repaint all buttons (to update background)
427 QLinkedList<QToolButton*>::const_iterator it = buttons.begin(), end = buttons.end();
428 for (; it != end; ++it)
429 (*it)->update();
432 QPoint FloatingToolBarPrivate::getInnerPoint() const
434 // returns the final position of the widget
435 if (anchorSide == FloatingToolBar::Left)
436 return QPoint(0, (anchorWidget->height() - q->height()) / 2);
437 if (anchorSide == FloatingToolBar::Top)
438 return QPoint((anchorWidget->width() - q->width()) / 2, 0);
439 if (anchorSide == FloatingToolBar::Right)
440 return QPoint(anchorWidget->width() - q->width() + toolBarRBMargin, (anchorWidget->height() - q->height()) / 2);
441 return QPoint((anchorWidget->width() - q->width()) / 2, anchorWidget->height() - q->height() + toolBarRBMargin);
444 QPoint FloatingToolBarPrivate::getOuterPoint() const
446 // returns the point from which the transition starts
447 if (anchorSide == FloatingToolBar::Left)
448 return QPoint(-q->width(), (anchorWidget->height() - q->height()) / 2);
449 if (anchorSide == FloatingToolBar::Top)
450 return QPoint((anchorWidget->width() - q->width()) / 2, -q->height());
451 if (anchorSide == FloatingToolBar::Right)
452 return QPoint(anchorWidget->width() + toolBarRBMargin, (anchorWidget->height() - q->height()) / 2);
453 return QPoint((anchorWidget->width() - q->width()) / 2, anchorWidget->height() + toolBarRBMargin);
456 void FloatingToolBar::slotAnimate()
458 // move currentPosition towards endPosition
459 int dX = d->endPosition.x() - d->currentPosition.x();
460 int dY = d->endPosition.y() - d->currentPosition.y();
461 dX = dX / 6 + qMax(-1, qMin(1, dX));
462 dY = dY / 6 + qMax(-1, qMin(1, dY));
463 d->currentPosition.setX(d->currentPosition.x() + dX);
464 d->currentPosition.setY(d->currentPosition.y() + dY);
466 move(d->currentPosition);
468 // handle arrival to the end
469 if (d->currentPosition == d->endPosition) {
470 d->animTimer->stop();
471 if (d->hiding) {
472 d->visible = false;
473 if (d->toDelete)
474 deleteLater();
475 } else
476 d->visible = true;
480 #include "floatingtoolbar.moc"