kde-extraapps/kdeplasma-addons/libs/lancelot/widgets/ExtenderButton.cpp
2015-01-15 17:07:43 +00:00

507 lines
13 KiB
C++

/*
* Copyright (C) 2007, 2008, 2009, 2010 Ivan Cukic <ivan.cukic(at)kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser/Library General Public License version 2,
* or (at your option) any later version, as published by the Free
* Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser/Library General Public License for more details
*
* You should have received a copy of the GNU Lesser/Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "ExtenderButton.h"
#include <QAction>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QIcon>
#include <QRectF>
#include <QTimer>
#include <QPointer>
#include <KDebug>
#define ACTIVATION_TIME 300
#define EXTENDER_Z_VALUE 100000.0
namespace Lancelot {
// Inner class ExtenderObject
class ExtenderObject : public BasicWidget {
public:
ExtenderObject(const Plasma::Svg & icon,
ExtenderButton * parent)
: BasicWidget(icon, "", "")
{
iconInSvg().setUsingRenderingCache(true);
iconInSvg().setContainsMultipleImages(true);
frameCount = 0;
while (iconInSvg().hasElement("frame" + QString::number(frameCount))) {
frameCount++;
}
frameCount--;
setParentItem(parent);
setInnerOrientation(Qt::Vertical);
setAlignment(Qt::AlignCenter);
setZValue(EXTENDER_Z_VALUE);
animate = !Global::self()->config("Animation", "disableAnimations", false)
&& Global::self()->config("Animation", "extenderActivationFeedback", true);
}
L_Override void hoverEnterEvent(QGraphicsSceneHoverEvent * event)
{
timer.start(ACTIVATION_TIME / frameCount, this);
BasicWidget::hoverEnterEvent(event);
}
L_Override void hoverLeaveEvent(QGraphicsSceneHoverEvent * event)
{
timer.stop();
frame = 0;
BasicWidget::hoverLeaveEvent(event);
}
void paint(QPainter * painter,
const QStyleOptionGraphicsItem * option, QWidget * widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
// BasicWidget::paint(painter, option, widget);
if (iconInSvg().isValid()) {
QRectF iconRect = QRectF(QPointF(), iconSize());
QSizeF sizeDiff = size() - iconRect.size();
iconRect.setTopLeft(QPointF(sizeDiff.width() / 2, sizeDiff.height() / 2));
if (animate) {
iconInSvg().paint(painter,
iconRect.left(),
iconRect.top(),
"frame" + QString::number(frame));
} else {
iconInSvg().paint(painter,
iconRect.left(),
iconRect.top(),
"frame" + QString::number(
(frame > 0) ? frameCount : 0
));
}
}
}
L_Override void showEvent(QShowEvent * event)
{
frame = 0;
}
L_Override void timerEvent(QTimerEvent * event)
{
if (event->timerId() == timer.timerId()) {
frame ++;
if (frame > frameCount) {
timer.stop();
frame = 0;
emit clicked();
} else {
if (animate || frame == 1) {
update();
}
}
}
BasicWidget::timerEvent(event);
}
int frameCount;
bool animate;
public:
// Plasma::FrameSvg::EnabledBorders borders;
QBasicTimer timer;
int frame;
friend class ExtenderButton;
};
// ExtenderButton
class ExtenderButton::Private {
public:
Private(ExtenderButton * parent)
: q(parent),
shortcut(NULL),
extenderPosition(NoExtender),
activationMethod(ClickActivate),
checkable(false),
checked(false)
{
if (!extenderIconSvg.isValid()) {
extenderIconSvg.setImagePath("lancelot/extender-button-icon");
}
if (!timer) {
timer = new QTimer();
timer->setInterval(ACTIVATION_TIME);
timer->setSingleShot(true);
}
}
void releaseExtender() {
ExtenderObject * ext = extender(false);
if (ext) {
ext->setVisible(false);
ext->hoverLeaveEvent(NULL);
ext->setParentItem(NULL);
}
disconnectTimer();
}
void disconnectTimer() {
timer->stop();
disconnect(timer, SIGNAL(timeout()), 0, 0);
}
void connectTimer() {
disconnectTimer();
connect(
timer, SIGNAL(timeout()),
q, SLOT(activate())
);
}
ExtenderObject * extender(bool take = true) {
ExtenderObject * result = 0;
if (!m_extenders.contains(q->scene()) ||
!m_extenders[q->scene()]) {
result = new ExtenderObject(extenderIconSvg, NULL);
result->setVisible(false);
result->setIconSize(QSize(16, 16));
m_extenders[q->scene()] = result;
} else {
result = m_extenders[q->scene()];
}
if (result->parentItem() != q) {
if (!take) {
return NULL;
}
result->setParentItem(q);
result->setGroupByName(
q->group()->name() + "-Extender"
);
connectTimer();
disconnect(result, SIGNAL(clicked()), 0, 0);
connect(result, SIGNAL(clicked()),
q, SLOT(activate()));
relayoutExtender();
}
return result;
}
~Private()
{
}
void relayoutExtender()
{
if (!m_extenders.contains(q->scene())
|| !m_extenders[q->scene()]
|| q != m_extenders[q->scene()]->parentItem()) return;
QRectF geometry = QRectF(QPointF(0, 0), q->size());
// extender()->borders = Plasma::FrameSvg::AllBorders;
borders = Plasma::FrameSvg::AllBorders;
switch (extenderPosition) {
case TopExtender:
geometry.setHeight(EXTENDER_SIZE);
geometry.moveTop(- EXTENDER_SIZE);
// borders &= ~ Plasma::FrameSvg::TopBorder;
// extender()->borders &= ~ Plasma::FrameSvg::BottomBorder;
break;
case BottomExtender:
geometry.moveTop(geometry.bottom());
geometry.setHeight(EXTENDER_SIZE);
// borders &= ~ Plasma::FrameSvg::BottomBorder;
// extender()->borders &= ~ Plasma::FrameSvg::TopBorder;
break;
case LeftExtender:
geometry.setWidth(EXTENDER_SIZE);
geometry.moveLeft(- EXTENDER_SIZE);
// borders &= ~ Plasma::FrameSvg::LeftBorder;
// extender()->borders &= ~ Plasma::FrameSvg::RightBorder;
break;
case RightExtender:
geometry.moveLeft(geometry.right());
geometry.setWidth(EXTENDER_SIZE);
// borders &= ~ Plasma::FrameSvg::RightBorder;
// extender()->borders &= ~ Plasma::FrameSvg::LeftBorder;
break;
case NoExtender:
break;
}
extender()->setGeometry(geometry);
extender()->setPreferredSize(geometry.size());
// qreal left, top, right, bottom;
// q->getContentsMargins(&left, &top, &right, &bottom);
}
ExtenderButton * q;
QAction * shortcut;
ExtenderPosition extenderPosition;
ActivationMethod activationMethod;
Plasma::FrameSvg::EnabledBorders borders;
static Plasma::Svg extenderIconSvg;
static QHash < QGraphicsScene *, QPointer < ExtenderObject > > m_extenders;
static QTimer * timer;
bool checkable : 1;
bool checked : 1;
};
Plasma::Svg ExtenderButton::Private::extenderIconSvg;
QHash < QGraphicsScene *, QPointer < ExtenderObject > > ExtenderButton::Private::m_extenders;
QTimer * ExtenderButton::Private::timer = 0;
ExtenderButton::ExtenderButton(QGraphicsItem * parent)
: BasicWidget(parent),
d(new Private(this))
{
setGroupByName("ExtenderButton");
connect(this, SIGNAL(clicked()), this, SLOT(activate()));
}
ExtenderButton::ExtenderButton(QString title,
QString description, QGraphicsItem * parent)
: BasicWidget(title, description, parent),
d(new Private(this))
{
setGroupByName("ExtenderButton");
connect(this, SIGNAL(clicked()), this, SLOT(activate()));
setTitle(title);
}
ExtenderButton::ExtenderButton(QIcon icon, QString title,
QString description, QGraphicsItem * parent)
: BasicWidget(icon, title, description, parent),
d(new Private(this))
{
setGroupByName("ExtenderButton");
connect(this, SIGNAL(clicked()), this, SLOT(activate()));
setTitle(title);
}
ExtenderButton::ExtenderButton(const Plasma::Svg & icon, QString title,
QString description, QGraphicsItem * parent)
: BasicWidget(icon, title, description, parent),
d(new Private(this))
{
setGroupByName("ExtenderButton");
connect(this, SIGNAL(clicked()), this, SLOT(activate()));
setTitle(title);
}
void ExtenderButton::setGroup(Group * g)
{
BasicWidget::setGroup(g);
}
ExtenderButton::~ExtenderButton()
{
if (Private::m_extenders.contains(scene())
&& Private::m_extenders[scene()]->parentItem() == this) {
Private::m_extenders[scene()]->setParentItem(0);
}
delete d;
}
QRectF ExtenderButton::boundingRect() const
{
return QRectF(0, 0, size().width(), size().height());
}
void ExtenderButton::hoverEnterEvent(QGraphicsSceneHoverEvent * event)
{
if (d->extenderPosition != NoExtender) {
d->extender()->setVisible(true);
} else if (d->activationMethod == HoverActivate) {
d->connectTimer();
d->timer->start();
}
BasicWidget::hoverEnterEvent(event);
}
void ExtenderButton::hideEvent(QHideEvent * event)
{
BasicWidget::hideEvent(event);
d->releaseExtender();
}
void ExtenderButton::hoverLeaveEvent(QGraphicsSceneHoverEvent * event)
{
BasicWidget::hoverLeaveEvent(event);
d->releaseExtender();
}
void ExtenderButton::setExtenderPosition(int position)
{
if (d->extenderPosition == position)
return;
d->extenderPosition = (ExtenderPosition) position;
d->relayoutExtender();
}
int ExtenderButton::extenderPosition() const
{
return d->extenderPosition;
}
void ExtenderButton::setActivationMethod(int method)
{
if (d->activationMethod == method)
return;
d->activationMethod = (ActivationMethod) method;
if (d->activationMethod != ExtenderActivate)
setExtenderPosition(NoExtender);
}
int ExtenderButton::activationMethod() const
{
return d->activationMethod;
}
void ExtenderButton::activate()
{
toggle();
hoverLeaveEvent(0);
d->releaseExtender();
update();
emit activated();
}
void ExtenderButton::resizeEvent(QGraphicsSceneResizeEvent * event)
{
BasicWidget::resizeEvent(event);
d->relayoutExtender();
}
void ExtenderButton::paint(QPainter * painter,
const QStyleOptionGraphicsItem * option, QWidget * widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
// if (Plasma::FrameSvg * svg = group()->backgroundSvg()) {
// if (isHovered() && (d->extenderPosition != NoExtender)) {
// svg->setEnabledBorders(d->borders);
// } else {
// svg->setEnabledBorders(Plasma::FrameSvg::AllBorders);
// }
// }
if (d->checked && !isDown()) {
paintBackground(painter, "checked");
} else {
paintBackground(painter);
}
paintForeground(painter);
}
void ExtenderButton::setChecked(bool checked)
{
if (!d->checkable) return;
if (d->checked == checked) return;
d->checked = checked;
update();
emit toggled(d->checked);
}
bool ExtenderButton::isChecked() const
{
return d->checked;
}
void ExtenderButton::toggle()
{
if (!d->checkable) return;
d->checked = !d->checked;
update();
emit toggled(d->checked);
}
void ExtenderButton::setCheckable(bool checkable)
{
if (d->checkable == checkable) return;
d->checkable = checkable;
if (!checkable) {
d->checked = false;
}
update();
}
bool ExtenderButton::isCheckable() const
{
return d->checkable;
}
void ExtenderButton::setShortcutKey(const QString & key)
{
kDebug() << title() << " set the key:" << key;
if (key.isEmpty()) {
delete d->shortcut;
d->shortcut = NULL;
} else if (scene() && scene()->views().size()) {
if (!d->shortcut) {
d->shortcut = new QAction(this);
scene()->views().at(0)->addAction(d->shortcut);
}
d->shortcut->setShortcut(QString(QLatin1String("Alt+")+ key));
connect(d->shortcut, SIGNAL(triggered()),
this, SIGNAL(activated()));
}
}
} // namespace Lancelot