2
* Copyright (C) 2007, 2008, 2009, 2010 Ivan Cukic <ivan.cukic(at)kde.org>
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU Lesser/Library General Public License version 2,
6
* or (at your option) any later version, as published by the Free
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 Lesser/Library General Public License for more details
14
* You should have received a copy of the GNU Lesser/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 "BasicWidget.h"
23
#include <QApplication>
24
#include <QtGui/QPainter>
26
#include <KGlobalSettings>
28
#include <Plasma/PaintUtils>
32
#include <lancelot/lancelot.h>
34
#define WIDGET_PADDING 8
36
#define max(A, B) ((A) >= (B)) ? (A) : (B)
41
class BasicWidget::Private {
43
Private(BasicWidget * parent, QString title = QString(), QString description = QString())
44
: icon(QIcon()), iconSize(32, 32),
45
innerOrientation(Qt::Horizontal), alignment(Qt::AlignCenter),
46
title(title), description(description)
51
Private(BasicWidget * parent, QIcon icon, QString title, QString description)
52
: icon(icon), iconSize(32, 32),
53
innerOrientation(Qt::Horizontal), alignment(Qt::AlignCenter),
54
title(title), description(description)
59
Private(BasicWidget * parent, const Plasma::Svg & icon, QString title, QString description)
60
: icon(QIcon()), iconSize(32, 32),
61
innerOrientation(Qt::Horizontal), alignment(Qt::AlignCenter),
62
title(title), description(description)
64
iconInSvg.setImagePath(icon.imagePath());
68
void init(BasicWidget * parent)
70
parent->setAcceptsHoverEvents(true);
71
// parent->resize(140, 38);
72
parent->setGroupByName("BasicWidget");
75
int shortcutPosition(QString & text)
80
while ((index = text.indexOf('&', index)) != -1) {
81
if (index == text.size() - 1) {
85
if (text.at(index + 1) != '&') {
90
text.remove(index, 1);
95
void rotatePainterForIcon(QPainter * painter, qreal angle, QRect & iconRect)
97
// TODO: Make this work for other angles
98
if (angle != 90 && angle != -90) return;
100
painter->rotate(angle);
102
iconRect.moveLeft(iconRect.width() / 2);
103
iconRect.moveTop(WIDGET_PADDING - iconRect.height() * 1.5);
107
Plasma::Svg iconInSvg;
109
Qt::Orientation innerOrientation;
111
Qt::Alignment alignment;
117
BasicWidget::BasicWidget(QGraphicsItem * parent)
121
setParentItem(parent);
124
BasicWidget::BasicWidget(QString title, QString description,
125
QGraphicsItem * parent)
127
d(new Private(this, title, description))
129
setParentItem(parent);
132
BasicWidget::BasicWidget(QIcon icon, QString title,
133
QString description, QGraphicsItem * parent)
135
d(new Private(this, icon, title, description))
137
setParentItem(parent);
140
BasicWidget::BasicWidget(const Plasma::Svg & icon, QString title,
141
QString description, QGraphicsItem * parent)
143
d(new Private(this, icon, title, description))
145
setParentItem(parent);
148
BasicWidget::~BasicWidget()
153
void BasicWidget::paint(QPainter * painter,
154
const QStyleOptionGraphicsItem * option, QWidget * widget)
159
paintBackground(painter);
160
paintForeground(painter);
163
// macro for setting the left coordinate of items
164
// relative to the parent and with alignment
165
// taken into consideration
166
#define setLeft(itemRect, parentRect, alignment) \
167
if ((parentRect).width() > (itemRect).width()) { \
168
if ((alignment) & Qt::AlignHCenter) \
169
(itemRect).moveLeft(WIDGET_PADDING + ((parentRect).width() - (itemRect).width()) / 2); \
170
else if ((alignment) & Qt::AlignRight) \
171
(itemRect).moveLeft(WIDGET_PADDING + (parentRect).width() - (itemRect).width()); \
173
(itemRect).setWidth((parentRect).width()); \
174
(itemRect).moveLeft(WIDGET_PADDING); \
177
void BasicWidget::paintForeground(QPainter * painter)
179
bool rtl = QApplication::isRightToLeft();
181
QPainter * _painter = painter;
183
QPixmap foreground(size().toSize().width(), size().toSize().height());
184
foreground.fill(Qt::transparent);
186
// Replacing painter with QImage painter
187
QPainter fpainter(&foreground);
192
fgColor = group()->foregroundColor()->disabled;
193
} else if (isHovered()) {
194
fgColor = group()->foregroundColor()->active;
196
fgColor = group()->foregroundColor()->normal;
198
painter->setPen(QPen(fgColor));
200
QFont titleFont = painter->font();
201
QFont descriptionFont = KGlobalSettings::smallestReadableFont();
203
QRectF widgetRect = QRectF(0, 0, size().width() - 2 * WIDGET_PADDING, size().height() - 2 * WIDGET_PADDING);
206
if (!d->icon.isNull() || d->iconInSvg.isValid()) {
207
iconRect = QRectF(QPointF(), d->iconSize);
208
if (iconRect.width() > geometry().width()) {
209
iconRect.setWidth(geometry().width());
211
if (iconRect.height() > geometry().height()) {
212
iconRect.setHeight(geometry().height());
216
// painter->setFont(titleFont)); // NOT NEEDED
217
QRectF titleRect = painter->boundingRect(widgetRect,
218
Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine, d->title);
220
painter->setFont(descriptionFont);
221
QRectF descriptionRect = painter->boundingRect(widgetRect,
222
Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine, d->description);
224
if (d->innerOrientation == Qt::Vertical || (d->title.isEmpty() && d->description.isEmpty())) {
226
// Modified setLeft macro for icon since we can not cut it if it's larger than needed
227
// setLeft(iconRect, widgetRect, d->alignment);
229
if (d->alignment & Qt::AlignHCenter) {
230
iconRect.moveLeft(WIDGET_PADDING + (widgetRect.width() - iconRect.width()) / 2);
231
} else if (d->alignment & Qt::AlignRight) {
232
iconRect.moveLeft(WIDGET_PADDING + widgetRect.width() - iconRect.width());
235
setLeft(titleRect, widgetRect, d->alignment);
236
setLeft(descriptionRect, widgetRect, d->alignment);
238
qreal top = WIDGET_PADDING, height =
239
iconRect.height() + titleRect.height() + descriptionRect.height();
241
if ((!d->icon.isNull() || d->iconInSvg.isValid()) && !(d->title.isEmpty() && d->description.isEmpty()))
242
height += WIDGET_PADDING;
244
if (d->alignment & Qt::AlignVCenter)
245
top = (widgetRect.height() - height) / 2 + WIDGET_PADDING;
246
if (d->alignment & Qt::AlignBottom)
247
top = widgetRect.height() - height + WIDGET_PADDING;
249
if (!d->icon.isNull() || d->iconInSvg.isValid()) { // using real painter...
251
iconRect.moveTop(top);
252
QRect rect(QPoint(lround(iconRect.left()), lround(iconRect.top())), d->iconSize);
254
d->rotatePainterForIcon(_painter, -rotation(), rect);
256
if (!d->icon.isNull()) {
257
d->icon.paint(_painter, rect);
259
d->iconInSvg.resize(rect.size());
260
d->iconInSvg.paint(_painter, rect.left(), rect.top(), isHovered()?"active":"inactive");
262
top += d->iconSize.height() + WIDGET_PADDING;
264
d->rotatePainterForIcon(_painter, rotation(), rect);
267
if (!d->title.isEmpty()) {
268
titleRect.moveTop(top);
269
painter->setFont(titleFont);
270
// painter->drawText(titleRect,
271
// Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine | Qt::ElideRight, d->title);
272
drawText(painter, titleRect,
273
Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine | Qt::ElideRight, d->title, true);
274
top += titleRect.height();
277
if (!d->description.isEmpty()) {
278
descriptionRect.moveTop(top);
280
painter->setFont(descriptionFont);
281
// painter->drawText(descriptionRect,
282
// Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine | Qt::ElideRight, d->description);
283
drawText(painter, descriptionRect,
284
Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine | Qt::ElideRight, d->description, false);
288
qreal /*left = WIDGET_PADDING,*/ width =
289
iconRect.width() + fmaxf(titleRect.width(), descriptionRect.width()) +
292
if (d->alignment & Qt::AlignTop) {
293
iconRect.moveTop(WIDGET_PADDING);
294
titleRect.moveTop(WIDGET_PADDING);
295
descriptionRect.moveTop(titleRect.bottom());
296
} else if (d->alignment & (Qt::AlignVCenter | Qt::AlignBottom)) {
297
iconRect.moveTop(WIDGET_PADDING +
298
((d->alignment & Qt::AlignVCenter) ? 0.5 : 1) * (widgetRect.height() - iconRect.height()));
299
titleRect.moveTop(WIDGET_PADDING +
300
((d->alignment & Qt::AlignVCenter) ? 0.5 : 1) * (widgetRect.height() -
301
((d->description.isEmpty())?0:descriptionRect.height()) - titleRect.height()));
302
descriptionRect.moveTop(titleRect.bottom());
305
if ((widgetRect.width() < width) || (d->alignment & Qt::AlignLeft)) {
307
iconRect.moveRight(widgetRect.right() + WIDGET_PADDING);
308
titleRect.setWidth(widgetRect.width() - ((!d->icon.isNull() || d->iconInSvg.isValid()) ? iconRect.width() + WIDGET_PADDING : 0));
309
descriptionRect.setWidth(titleRect.width());
311
iconRect.moveLeft(WIDGET_PADDING);
312
titleRect.setWidth(widgetRect.width() - ((!d->icon.isNull() || d->iconInSvg.isValid()) ? iconRect.width() + WIDGET_PADDING : 0));
313
descriptionRect.setWidth(titleRect.width());
315
} else if (d->alignment & Qt::AlignHCenter) {
317
iconRect.moveRight(WIDGET_PADDING + (widgetRect.width() + width) / 2);
319
iconRect.moveLeft(WIDGET_PADDING + (widgetRect.width() - width) / 2);
323
iconRect.moveRight(widgetRect.width() - WIDGET_PADDING - (widgetRect.width() - width));
325
iconRect.moveLeft(WIDGET_PADDING + (widgetRect.width() - width));
330
titleRect.moveRight(- WIDGET_PADDING + iconRect.left());
331
descriptionRect.moveRight(- WIDGET_PADDING + iconRect.left());
333
titleRect.moveLeft(WIDGET_PADDING + iconRect.right());
334
descriptionRect.moveLeft(WIDGET_PADDING + iconRect.right());
337
if (!d->icon.isNull() || d->iconInSvg.isValid()) { // using real painter...
338
QRect rect(QPoint(lround(iconRect.left()), lround(iconRect.top())), d->iconSize);
340
d->rotatePainterForIcon(_painter, -rotation(), rect);
342
if (!d->icon.isNull()) {
345
mode = QIcon::Disabled;
346
} else if (isHovered()) {
347
mode = QIcon::Active;
349
mode = QIcon::Normal;
352
d->icon.paint(_painter, rect, Qt::AlignCenter, mode, QIcon::Off);
354
d->iconInSvg.resize(d->iconSize);
355
d->iconInSvg.paint(_painter, rect.left(), rect.top(), isHovered()?"active":"inactive"); //TODO: add disabled state
358
d->rotatePainterForIcon(_painter, rotation(), rect);
362
if (!d->title.isEmpty()) {
363
painter->setFont(titleFont);
364
// painter->drawText(titleRect,
365
// Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine, d->title);
366
drawText(painter, titleRect,
367
Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine, d->title, true);
370
if (!d->description.isEmpty()) {
372
QPen pen = painter->pen();
373
QColor clr = painter->pen().color();
375
painter->setPen(QPen(clr));
377
painter->setFont(descriptionFont);
378
// painter->drawText(descriptionRect,
379
// Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine, d->description);
380
drawText(painter, descriptionRect,
381
Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine, d->description, false);
385
QLinearGradient gradient;
386
if (QApplication::isRightToLeft()) {
387
gradient = QLinearGradient(
388
QPointF(WIDGET_PADDING, 0),
389
QPointF(WIDGET_PADDING + 20, 0)
391
gradient.setColorAt(0, Qt::transparent);
392
gradient.setColorAt(1, Qt::black);
394
gradient = QLinearGradient(
395
QPointF(size().width() - WIDGET_PADDING - 20, 0),
396
QPointF(size().width() - WIDGET_PADDING, 0)
398
gradient.setColorAt(1, Qt::transparent);
399
gradient.setColorAt(0, Qt::black);
401
painter->setCompositionMode(QPainter::CompositionMode_DestinationIn);
403
0, 0, (int)ceil(size().width()), (int)ceil(size().height()),
407
painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
408
_painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
410
_painter->drawPixmap(0, 0, foreground);
413
void BasicWidget::setIconSize(QSize size)
420
QSize BasicWidget::iconSize() const
425
void BasicWidget::setIcon(QIcon icon)
432
QIcon BasicWidget::icon() const
437
void BasicWidget::setIconInSvg(const Plasma::Svg & icon)
439
d->iconInSvg.setImagePath(icon.imagePath());
444
Plasma::Svg & BasicWidget::iconInSvg() const
449
void BasicWidget::setTitle(const QString & value)
453
QString title(value);
454
int pos = d->shortcutPosition(title);
456
setShortcutKey(title.at(pos));
463
void BasicWidget::setShortcutKey(const QString & key)
468
QString BasicWidget::title() const
473
void BasicWidget::setDescription(const QString & description)
475
d->description = description;
480
QString BasicWidget::description() const
482
return d->description;
485
void BasicWidget::setInnerOrientation(Qt::Orientation position) {
486
d->innerOrientation = position;
491
Qt::Orientation BasicWidget::innerOrientation() const
493
return d->innerOrientation;
496
void BasicWidget::setAlignment(Qt::Alignment alignment)
498
d->alignment = alignment;
502
Qt::Alignment BasicWidget::alignment() const
507
QSizeF BasicWidget::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const
509
QSizeF result = QSizeF();
512
case Qt::MinimumSize:
513
result = d->iconSize;
515
case Qt::MaximumSize:
516
result = MAX_WIDGET_SIZE;
519
// Do we need a more precise sizeHint?
520
// result = d->iconSize + QSizeF(2 * WIDGET_PADDING, 2 * WIDGET_PADDING);
521
result = d->iconSize;
522
QFontMetrics titleMetrics = QFontMetrics(font());
523
QFontMetrics desctiprionMetrics =
524
QFontMetrics(KGlobalSettings::smallestReadableFont());
525
QSizeF textSize = QSizeF(
527
titleMetrics.width(d->title),
528
desctiprionMetrics.width(d->description)
530
(titleMetrics.height()) +
531
(d->description.isEmpty()?0:desctiprionMetrics.height())
534
if (d->innerOrientation == Qt::Horizontal) {
535
result.rwidth() += textSize.width();
537
if (result.height() < textSize.height()) {
538
result.setHeight(textSize.height());
541
result.rheight() += textSize.height();
543
if (result.width() < textSize.width()) {
544
result.setWidth(textSize.width());
547
result += Widget::sizeHint(which, constraint) +
548
QSizeF(3 * WIDGET_PADDING, 2 * WIDGET_PADDING);
551
if (constraint.isValid()) {
552
result = result.boundedTo(constraint);
558
void BasicWidget::drawText(QPainter * painter, const QRectF & rectangle, int flags, const QString & txt, bool shortcutEnabled)
567
int shortcutPosition = d->shortcutPosition(text);
568
if (shortcutPosition > -1 && shortcutEnabled) {
569
text = text.remove(shortcutPosition - 1, 1);
571
shortcutEnabled = false;
574
static const int radius = 2;
575
if (group()->hasProperty("BlurTextShadow")) {
576
QColor textColor = painter->pen().color();
578
if (textColor.valueF() * textColor.alphaF() > 0.4) {
579
shadowColor = Qt::black;
581
shadowColor = Qt::white;
584
QPixmap result = Plasma::PaintUtils::shadowText(
585
text, textColor, shadowColor,
586
QPoint(0, 0), radius);
588
if (group()->hasProperty("TextColorBackground")) {
591
bgColor = group()->backgroundColor()->disabled;
592
} else if (isHovered()) {
593
bgColor = group()->backgroundColor()->active;
595
bgColor = group()->backgroundColor()->normal;
597
painter->setRenderHint(QPainter::Antialiasing);
598
QRectF frect = QRectF(rectangle.topLeft(), result.size());
600
Plasma::PaintUtils::roundedRectangle(
601
frect, 2 * radius), QBrush(bgColor)
605
painter->drawPixmap(rectangle.topLeft(), result);
607
if (shortcutEnabled) {
608
int width = painter->boundingRect(
610
Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine,
611
text.left(shortcutPosition - 1)).width();
612
QPixmap result = Plasma::PaintUtils::shadowText(
613
"_", textColor, shadowColor,
614
QPoint(0, 0), radius);
615
painter->drawPixmap(rectangle.topLeft() + QPoint(width, 0), result);
618
if (group()->hasProperty("TextColorBackground")) {
621
bgColor = group()->backgroundColor()->disabled;
622
} else if (isHovered()) {
623
bgColor = group()->backgroundColor()->active;
625
bgColor = group()->backgroundColor()->normal;
627
painter->setRenderHint(QPainter::Antialiasing);
628
QRectF frect = painter->boundingRect(rectangle,
629
Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine, text);
630
frect.adjust(- radius, - radius, radius, radius);
632
Plasma::PaintUtils::roundedRectangle(
633
frect, 2*radius), QBrush(bgColor)
636
painter->drawText(rectangle,
637
Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine, text);
639
if (shortcutEnabled) {
640
int width = painter->boundingRect(
642
Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine,
643
text.left(shortcutPosition - 1)).width();
645
QRectF(rectangle.topLeft() + QPoint(width, 0), rectangle.size()),
651
} // namespace Lancelot
653
#include "BasicWidget.moc"