• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

Plasma

  • plasma
  • widgets
toolbutton.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2008 Marco Martin <notmart@gmail.com>
3 *
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.
8 *
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
13 *
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.
18 */
19
20#include "toolbutton.h"
21
22#include <QDir>
23#include <QPainter>
24#include <QPropertyAnimation>
25#include <QStyleOptionGraphicsItem>
26#include <QToolButton>
27
28#include <kcolorutils.h>
29#include <kicon.h>
30#include <kiconeffect.h>
31#include <kmimetype.h>
32
33#include "animator.h"
34#include "framesvg.h"
35#include "paintutils.h"
36#include "private/actionwidgetinterface_p.h"
37#include "private/themedwidgetinterface_p.h"
38#include "theme.h"
39
40namespace Plasma
41{
42
43class ToolButtonPrivate : public ActionWidgetInterface<ToolButton>
44{
45public:
46 ToolButtonPrivate(ToolButton *toolButton)
47 : ActionWidgetInterface<ToolButton>(toolButton),
48 background(0),
49 svg(0),
50 underMouse(false)
51 {
52 }
53
54 ~ToolButtonPrivate()
55 {
56 delete svg;
57 }
58
59 void setPixmap()
60 {
61 if (imagePath.isEmpty()) {
62 delete svg;
63 svg = 0;
64 return;
65 }
66
67 KMimeType::Ptr mime = KMimeType::findByPath(absImagePath);
68 QPixmap pm;
69
70 if (mime->is("image/svg+xml") || mime->is("image/svg+xml-compressed")) {
71 if (!svg || svg->imagePath() != absImagePath) {
72 delete svg;
73 svg = new Svg();
74 svg->setImagePath(imagePath);
75 QObject::connect(svg, SIGNAL(repaintNeeded()), q, SLOT(setPixmap()));
76 if (!svgElement.isNull()) {
77 svg->setContainsMultipleImages(true);
78 }
79 }
80
81 //QPainter p(&pm);
82 if (!svgElement.isNull() && svg->hasElement(svgElement)) {
83 QSizeF elementSize = svg->elementSize(svgElement);
84 float scale = pm.width() / qMax(elementSize.width(), elementSize.height());
85
86 svg->resize(svg->size() * scale);
87 pm = svg->pixmap(svgElement);
88 } else {
89 svg->resize(pm.size());
90 pm = svg->pixmap();
91 }
92 } else {
93 delete svg;
94 svg = 0;
95 pm = QPixmap(absImagePath);
96 }
97
98 static_cast<QToolButton*>(q->widget())->setIcon(KIcon(pm));
99 }
100
101 void syncActiveRect();
102 void syncBorders();
103 void animationUpdate(qreal progress);
104
105 FrameSvg *background;
106 QPropertyAnimation *animation;
107 qreal opacity;
108 QRectF activeRect;
109
110 QString imagePath;
111 QString absImagePath;
112 Svg *svg;
113 QString svgElement;
114 bool underMouse;
115};
116
117void ToolButtonPrivate::syncActiveRect()
118{
119 background->setElementPrefix("normal");
120
121 qreal left, top, right, bottom;
122 background->getMargins(left, top, right, bottom);
123
124 background->setElementPrefix("active");
125 qreal activeLeft, activeTop, activeRight, activeBottom;
126 background->getMargins(activeLeft, activeTop, activeRight, activeBottom);
127
128 activeRect = QRectF(QPointF(0, 0), q->size());
129 activeRect.adjust(left - activeLeft, top - activeTop,
130 -(right - activeRight), -(bottom - activeBottom));
131
132 background->setElementPrefix("normal");
133}
134
135void ToolButtonPrivate::syncBorders()
136{
137 //set margins from the normal element
138 qreal left, top, right, bottom;
139
140 background->setElementPrefix("normal");
141 background->getMargins(left, top, right, bottom);
142 q->setContentsMargins(left, top, right, bottom);
143
144 //calc the rect for the over effect
145 syncActiveRect();
146}
147
148void ToolButtonPrivate::animationUpdate(qreal progress)
149{
150 opacity = progress;
151
152 // explicit update
153 q->update();
154}
155
156ToolButton::ToolButton(QGraphicsWidget *parent)
157 : QGraphicsProxyWidget(parent),
158 d(new ToolButtonPrivate(this))
159{
160 d->background = new FrameSvg(this);
161 d->background->setImagePath("widgets/button");
162 d->background->setCacheAllRenderedFrames(true);
163 d->background->setElementPrefix("normal");
164
165 QToolButton *native = new QToolButton;
166 connect(native, SIGNAL(clicked()), this, SIGNAL(clicked()));
167 connect(native, SIGNAL(pressed()), this, SIGNAL(pressed()));
168 connect(native, SIGNAL(released()), this, SIGNAL(released()));
169 setWidget(native);
170 native->setWindowIcon(QIcon());
171 native->setAttribute(Qt::WA_NoSystemBackground);
172 native->setAutoRaise(true);
173
174 d->syncBorders();
175 setAcceptHoverEvents(true);
176 connect(d->background, SIGNAL(repaintNeeded()), SLOT(syncBorders()));
177
178 d->animation = new QPropertyAnimation(this, "animationUpdate");
179 d->animation->setStartValue(0);
180 d->animation->setEndValue(1);
181
182 d->initTheming();
183}
184
185ToolButton::~ToolButton()
186{
187 delete d->animation;
188 delete d;
189}
190
191void ToolButton::setAnimationUpdate(qreal progress)
192{
193 d->animationUpdate(progress);
194}
195
196qreal ToolButton::animationUpdate() const
197{
198 return d->opacity;
199}
200
201void ToolButton::setAction(QAction *action)
202{
203 d->setAction(action);
204}
205
206QAction *ToolButton::action() const
207{
208 return d->action;
209}
210
211void ToolButton::setAutoRaise(bool raise)
212{
213 nativeWidget()->setAutoRaise(raise);
214}
215
216bool ToolButton::autoRaise() const
217{
218 return nativeWidget()->autoRaise();
219}
220
221void ToolButton::setText(const QString &text)
222{
223 static_cast<QToolButton*>(widget())->setText(text);
224 updateGeometry();
225}
226
227QString ToolButton::text() const
228{
229 return static_cast<QToolButton*>(widget())->text();
230}
231
232void ToolButton::setImage(const QString &path)
233{
234 if (d->imagePath == path) {
235 return;
236 }
237
238 delete d->svg;
239 d->svg = 0;
240 d->imagePath = path;
241
242 bool absolutePath = !path.isEmpty() &&
243 #ifdef Q_WS_WIN
244 !QDir::isRelativePath(path)
245 #else
246 (path[0] == '/' || path.startsWith(QLatin1String(":/")))
247 #endif
248 ;
249
250 if (absolutePath) {
251 d->absImagePath = path;
252 } else {
253 //TODO: package support
254 d->absImagePath = Theme::defaultTheme()->imagePath(path);
255 }
256
257 d->setPixmap();
258}
259
260void ToolButton::setImage(const QString &path, const QString &elementid)
261{
262 d->svgElement = elementid;
263 setImage(path);
264}
265
266void ToolButton::setIcon(const QIcon &icon)
267{
268 nativeWidget()->setIcon(icon);
269}
270
271QIcon ToolButton::icon() const
272{
273 return nativeWidget()->icon();
274}
275
276QString ToolButton::image() const
277{
278 return d->imagePath;
279}
280
281void ToolButton::setDown(bool down)
282{
283 nativeWidget()->setDown(down);
284}
285
286bool ToolButton::isDown() const
287{
288 return nativeWidget()->isDown();
289}
290
291void ToolButton::setStyleSheet(const QString &stylesheet)
292{
293 widget()->setStyleSheet(stylesheet);
294}
295
296QString ToolButton::styleSheet()
297{
298 return widget()->styleSheet();
299}
300
301QToolButton *ToolButton::nativeWidget() const
302{
303 return static_cast<QToolButton*>(widget());
304}
305
306void ToolButton::resizeEvent(QGraphicsSceneResizeEvent *event)
307{
308 d->setPixmap();
309
310 if (d->background) {
311 //resize all four panels
312 d->background->setElementPrefix("pressed");
313 d->background->resizeFrame(size());
314 d->background->setElementPrefix("focus");
315 d->background->resizeFrame(size());
316
317 d->syncActiveRect();
318
319 d->background->setElementPrefix("active");
320 d->background->resizeFrame(d->activeRect.size());
321
322 d->background->setElementPrefix("normal");
323 d->background->resizeFrame(size());
324 }
325
326 QGraphicsProxyWidget::resizeEvent(event);
327}
328
329void ToolButton::paint(QPainter *painter,
330 const QStyleOptionGraphicsItem *option,
331 QWidget *widget)
332{
333 if (!styleSheet().isNull() || Theme::defaultTheme()->useNativeWidgetStyle()) {
334 QGraphicsProxyWidget::paint(painter, option, widget);
335 return;
336 }
337
338 QToolButton *button = nativeWidget();
339
340 QStyleOptionToolButton buttonOpt;
341 buttonOpt.initFrom(button);
342 buttonOpt.icon = button->icon();
343 buttonOpt.text = button->text();
344 buttonOpt.iconSize = button->iconSize();
345 buttonOpt.toolButtonStyle = button->toolButtonStyle();
346
347 bool animationState = (d->animation->state() == QAbstractAnimation::Running)? \
348 1:0;
349 if (button->isEnabled() && (animationState || !button->autoRaise() || d->underMouse || (buttonOpt.state & QStyle::State_On) || button->isChecked() || button->isDown())) {
350 if (button->isDown() || (buttonOpt.state & QStyle::State_On) || button->isChecked()) {
351 d->background->setElementPrefix("pressed");
352 } else {
353 d->background->setElementPrefix("normal");
354 }
355 d->background->resizeFrame(size());
356
357 if (animationState) {
358 QPixmap buffer = d->background->framePixmap();
359
360 QPainter bufferPainter(&buffer);
361 bufferPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
362 QColor alphaColor(Qt::black);
363 alphaColor.setAlphaF(qMin(qreal(0.95), d->opacity));
364 bufferPainter.fillRect(buffer.rect(), alphaColor);
365 bufferPainter.end();
366
367 painter->drawPixmap(QPoint(0,0), buffer);
368
369 buttonOpt.palette.setColor(QPalette::ButtonText, KColorUtils::mix(Plasma::Theme::defaultTheme()->color(Plasma::Theme::ButtonTextColor), Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor), 1-d->opacity));
370 } else {
371 d->background->paintFrame(painter);
372 buttonOpt.palette.setColor(QPalette::ButtonText, Plasma::Theme::defaultTheme()->color(Plasma::Theme::ButtonTextColor));
373 }
374
375 } else {
376 buttonOpt.palette.setColor(QPalette::ButtonText, Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
377 }
378
379 buttonOpt.font = font();
380
381 painter->setFont(buttonOpt.font);
382 button->style()->drawControl(QStyle::CE_ToolButtonLabel, &buttonOpt, painter, button);
383}
384
385void ToolButton::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
386{
387 d->underMouse = true;
388 if (nativeWidget()->isDown() || !nativeWidget()->autoRaise()) {
389 return;
390 }
391
392 const int FadeInDuration = 75;
393
394 if (d->animation->state() != QAbstractAnimation::Stopped) {
395 d->animation->stop();
396 }
397 d->animation->setDuration(FadeInDuration);
398 d->animation->setDirection(QAbstractAnimation::Forward);
399 d->animation->start();
400
401 d->background->setElementPrefix("active");
402
403 QGraphicsProxyWidget::hoverEnterEvent(event);
404}
405
406void ToolButton::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
407{
408 d->underMouse = false;
409 if (nativeWidget()->isDown() || !nativeWidget()->autoRaise()) {
410 return;
411 }
412
413 const int FadeOutDuration = 150;
414
415 if (d->animation->state() != QAbstractAnimation::Stopped) {
416 d->animation->stop();
417 }
418
419 d->animation->setDuration(FadeOutDuration);
420 d->animation->setDirection(QAbstractAnimation::Backward);
421 d->animation->start();
422
423 d->background->setElementPrefix("active");
424
425 QGraphicsProxyWidget::hoverLeaveEvent(event);
426}
427
428void ToolButton::changeEvent(QEvent *event)
429{
430 d->changeEvent(event);
431
432 if (event->type() == QEvent::EnabledChange && !isEnabled()) {
433 d->underMouse = false;
434 }
435
436 QGraphicsProxyWidget::changeEvent(event);
437}
438
439QVariant ToolButton::itemChange(GraphicsItemChange change, const QVariant &value)
440{
441 //If the widget is hidden while it's hovered and then we show it again
442 //we have to disable the hover otherwise it will remain hovered.
443 if (change == ItemVisibleHasChanged){
444 d->underMouse = false;
445 }
446
447 return QGraphicsProxyWidget::itemChange(change, value);
448}
449
450QSizeF ToolButton::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const
451{
452 QSizeF hint = QGraphicsProxyWidget::sizeHint(which, constraint);
453
454 return hint;
455}
456
457} // namespace Plasma
458
459#include <toolbutton.moc>
460
animator.h
Plasma::FrameSvg
Provides an SVG with borders.
Definition: framesvg.h:77
Plasma::Theme::imagePath
Q_INVOKABLE QString imagePath(const QString &name) const
Retrieve the path for an SVG image in the current theme.
Definition: theme.cpp:794
Plasma::Theme::defaultTheme
static Theme * defaultTheme()
Singleton pattern accessor.
Definition: theme.cpp:544
Plasma::Theme::TextColor
@ TextColor
the text color to be used by items resting on the background
Definition: theme.h:63
Plasma::Theme::ButtonTextColor
@ ButtonTextColor
Definition: theme.h:67
Plasma::ToolButton::clicked
void clicked()
Plasma::ToolButton::isDown
bool isDown() const
Definition: toolbutton.cpp:286
Plasma::ToolButton::nativeWidget
QToolButton * nativeWidget
Definition: toolbutton.h:48
Plasma::ToolButton::setImage
void setImage(const QString &path)
Sets the path to an image to display.
Definition: toolbutton.cpp:232
Plasma::ToolButton::setText
void setText(const QString &text)
Sets the display text for this ToolButton.
Definition: toolbutton.cpp:221
Plasma::ToolButton::pressed
void pressed()
Plasma::ToolButton::icon
QIcon icon() const
Definition: toolbutton.cpp:271
Plasma::ToolButton::action
QAction * action
Definition: toolbutton.h:49
Plasma::ToolButton::down
bool down
Definition: toolbutton.h:50
Plasma::ToolButton::autoRaise
bool autoRaise
Definition: toolbutton.h:45
Plasma::ToolButton::released
void released()
Plasma::ToolButton::styleSheet
QString styleSheet
Definition: toolbutton.h:47
Plasma::ToolButton::text
QString text
Definition: toolbutton.h:44
QGraphicsProxyWidget
QGraphicsWidget
QStyleOptionGraphicsItem
QWidget
framesvg.h
Plasma::AnimationScriptEngine::animation
QScriptValue animation(const QString &anim)
Definition: animationscriptengine.cpp:55
Plasma
Namespace for everything in libplasma.
Definition: abstractdialogmanager.cpp:25
paintutils.h
theme.h
toolbutton.h
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal