plasma-framework/widgets/iconwidget_p.h
Marco Martin 5b49fc05e1 new property: preferredIconSize, aka the final solution to all layout problems
svn path=/trunk/KDE/kdelibs/; revision=1118322
2010-04-24 12:08:13 +00:00

394 lines
12 KiB
C++

/*
* Copyright (C) 2007 by Aaron Seigo <aseigo@kde.org>
* Copyright (C) 2007 by Matt Broadstone <mbroadst@gmail.com>
* Copyright (C) 2006-2007 Fredrik Höglund <fredrik@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, or
* (at your option) any later version.
*
* 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 General Public License for more details
*
* You should have received a copy of the GNU 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.
*/
#ifndef PLASMA_ICONWIDGET_P_H
#define PLASMA_ICONWIDGET_P_H
#include <QtCore/QEvent>
#include <QtCore/QWeakPointer>
#include <QtGui/QApplication>
#include <QtGui/QIcon>
#include <QtGui/QStyleOptionGraphicsItem>
#include <QtGui/QTextLayout>
#include <QtGui/QTextOption>
#include <plasma/plasma_export.h>
#include <plasma/framesvg.h>
#include <plasma/theme.h>
#include <plasma/svg.h>
#include "iconwidget.h"
#include "private/actionwidgetinterface_p.h"
class QAction;
class QPainter;
class QTextLayout;
class QPropertyAnimation;
namespace Plasma
{
class Animation;
class IconHoverAnimation;
class PLASMA_EXPORT IconAction
{
public:
IconAction(IconWidget *icon, QAction *action);
void show();
void hide();
bool isVisible() const;
bool isAnimating() const;
QAction *action() const;
void paint(QPainter *painter) const;
bool event(QEvent::Type type, const QPointF &pos);
void setSelected(bool selected);
bool isSelected() const;
bool isHovered() const;
bool isPressed() const;
void setRect(const QRectF &rect);
QRectF rect() const;
private:
void rebuildPixmap();
IconWidget *m_icon;
QAction *m_action;
QPixmap m_pixmap;
QRectF m_rect;
bool m_hovered;
bool m_pressed;
bool m_selected;
bool m_visible;
QWeakPointer<Animation> m_animation;
};
struct Margin
{
qreal left, right, top, bottom;
};
class IconWidgetPrivate : public ActionWidgetInterface<IconWidget>
{
public:
enum MarginType {
ItemMargin = 0,
TextMargin,
IconMargin,
NMargins
};
enum IconWidgetState {
NoState = 0,
HoverState = 1,
PressedState = 2,
ManualPressedState = 4
};
Q_DECLARE_FLAGS(IconWidgetStates, IconWidgetState)
IconWidgetPrivate(IconWidget *i);
~IconWidgetPrivate();
void changed()
{
emit q->changed();
}
void drawBackground(QPainter *painter, IconWidgetState state);
void drawText(QPainter *painter);
void drawTextItems(QPainter *painter, const QStyleOptionGraphicsItem *option,
const QTextLayout &labelLayout, const QTextLayout &infoLayout) const;
QPixmap decoration(const QStyleOptionGraphicsItem *option, bool useHoverEffect, bool usePressedEffect);
QPointF iconPosition(const QStyleOptionGraphicsItem *option, const QPixmap &pixmap) const;
QSizeF displaySizeHint(const QStyleOptionGraphicsItem *option, const qreal width) const;
QBrush foregroundBrush(const QStyleOptionGraphicsItem *option) const;
QBrush backgroundBrush(const QStyleOptionGraphicsItem *option) const;
QString elidedText(QTextLayout &layout,
const QStyleOptionGraphicsItem *option,
const QSizeF &maxSize) const;
QSizeF layoutText(QTextLayout &layout,
const QStyleOptionGraphicsItem *option,
const QString &text, const QSizeF &constraints) const;
QSizeF layoutText(QTextLayout &layout, const QString &text,
qreal maxWidth) const;
QRectF labelRectangle(const QStyleOptionGraphicsItem *option,
const QPixmap &icon, const QString &string) const;
void layoutTextItems(const QStyleOptionGraphicsItem *option,
const QPixmap &icon, QTextLayout *labelLayout,
QTextLayout *infoLayout, QRectF *textBoundingRect) const;
int maxWordWidth(const QString text) const;
inline void setLayoutOptions(QTextLayout &layout,
const QStyleOptionGraphicsItem *options,
const Qt::Orientation orientation) const;
inline Qt::LayoutDirection iconDirection(const QStyleOptionGraphicsItem *option) const;
enum {
Minibutton = 64,
MinibuttonHover = 128,
MinibuttonPressed = 256
};
enum ActionPosition {
TopLeft = 0,
TopRight,
BottomLeft,
BottomRight,
LastIconPosition = BottomRight
};
// Margin functions
inline void setActiveMargins();
void setVerticalMargin(MarginType type, qreal left, qreal right, qreal top, qreal bottom);
void setHorizontalMargin(MarginType type, qreal left, qreal right, qreal top, qreal bottom);
inline void setVerticalMargin(MarginType type, qreal hor, qreal ver);
inline void setHorizontalMargin(MarginType type, qreal hor, qreal ver);
inline QRectF addMargin(const QRectF &rect, MarginType type) const;
inline QRectF subtractMargin(const QRectF &rect, MarginType type) const;
inline QSizeF addMargin(const QSizeF &size, MarginType type) const;
inline QSizeF subtractMargin(const QSizeF &size, MarginType type) const;
inline QRectF actionRect(ActionPosition position) const;
void actionDestroyed(QObject *obj);
void svgChanged();
void readColors();
void colorConfigChanged();
void iconConfigChanged();
QFont widgetFont() const;
void hoverAnimationFinished();
void init();
void layoutIcons(const QStyleOptionGraphicsItem *option);
void animateMainIcon(bool, const IconWidgetStates state);
IconWidget *q;
QString text;
QString infoText;
Svg *iconSvg;
FrameSvg *background;
QString iconSvgElement;
QPixmap iconSvgPixmap;
QColor textColor;
QColor textBgColor;
QColor shadowColor;
IconHoverAnimation *hoverAnimation;
QSizeF iconSize;
QSizeF preferredIconSize;
QIcon icon;
QIcon oldIcon;
IconWidgetStates states;
Qt::Orientation orientation;
int numDisplayLines;
QSizeF currentSize;
QPointF clickStartPos;
mutable QList<QRect> haloRects;
QTimer *iconChangeTimer;
QList<IconAction*> cornerActions;
Margin verticalMargin[NMargins];
Margin horizontalMargin[NMargins];
Margin *activeMargins;
bool iconSvgElementChanged : 1;
bool invertLayout : 1;
bool drawBg : 1;
bool textBgCustomized : 1;
static const int maxDisplayLines = 5;
static const int iconActionSize = 26;
static const int iconActionMargin = 4;
bool customFont;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(IconWidgetPrivate::IconWidgetStates)
// Inline methods
void IconWidgetPrivate::setLayoutOptions(QTextLayout &layout,
const QStyleOptionGraphicsItem *option,
const Qt::Orientation orientation) const
{
QTextOption textoption;
textoption.setTextDirection(option->direction);
if (orientation == Qt::Horizontal) {
textoption.setAlignment(Qt::Alignment(Qt::AlignLeft|Qt::AlignVCenter));
} else {
textoption.setAlignment(Qt::AlignCenter);
}
textoption.setWrapMode(QTextOption::WordWrap); // NOTE: assumption as well
layout.setFont(widgetFont());
layout.setTextOption(textoption);
}
Qt::LayoutDirection IconWidgetPrivate::iconDirection(const QStyleOptionGraphicsItem *option) const
{
Qt::LayoutDirection direction;
if (invertLayout && orientation == Qt::Horizontal) {
if (option->direction == Qt::LeftToRight) {
direction = Qt::RightToLeft;
} else {
direction = Qt::LeftToRight;
}
} else {
direction = option->direction;
}
return direction;
}
void IconWidgetPrivate::setActiveMargins()
{
//sync here itemmargin with contentsrect, not overly pretty but it's where it's more reliable
qreal left, top, right, bottom;
q->getContentsMargins(&left, &top, &right, &bottom);
if (left || top || right || bottom) {
verticalMargin[ItemMargin].left = horizontalMargin[ItemMargin].left = left;
verticalMargin[ItemMargin].top = horizontalMargin[ItemMargin].top = top;
verticalMargin[ItemMargin].right = horizontalMargin[ItemMargin].right = right;
verticalMargin[ItemMargin].bottom = horizontalMargin[ItemMargin].bottom = bottom;
}
activeMargins = (orientation == Qt::Horizontal ? horizontalMargin : verticalMargin);
}
void IconWidgetPrivate::setVerticalMargin(MarginType type, qreal left, qreal top,
qreal right, qreal bottom)
{
verticalMargin[type].left = left;
verticalMargin[type].right = right;
verticalMargin[type].top = top;
verticalMargin[type].bottom = bottom;
}
void IconWidgetPrivate::setHorizontalMargin(MarginType type, qreal left, qreal top,
qreal right, qreal bottom)
{
horizontalMargin[type].left = left;
horizontalMargin[type].right = right;
horizontalMargin[type].top = top;
horizontalMargin[type].bottom = bottom;
}
void IconWidgetPrivate::setVerticalMargin(MarginType type, qreal horizontal, qreal vertical)
{
setVerticalMargin(type, horizontal, vertical, horizontal, vertical);
}
void IconWidgetPrivate::setHorizontalMargin(MarginType type, qreal horizontal, qreal vertical)
{
setHorizontalMargin(type, horizontal, vertical, horizontal, vertical);
}
QRectF IconWidgetPrivate::addMargin(const QRectF &rect, MarginType type) const
{
Q_ASSERT(activeMargins);
const Margin &m = activeMargins[type];
return rect.adjusted(-m.left, -m.top, m.right, m.bottom);
}
QRectF IconWidgetPrivate::subtractMargin(const QRectF &rect, MarginType type) const
{
Q_ASSERT(activeMargins);
const Margin &m = activeMargins[type];
return rect.adjusted(m.left, m.top, -m.right, -m.bottom);
}
QSizeF IconWidgetPrivate::addMargin(const QSizeF &size, MarginType type) const
{
Q_ASSERT(activeMargins);
const Margin &m = activeMargins[type];
return QSizeF(size.width() + m.left + m.right, size.height() + m.top + m.bottom);
}
QSizeF IconWidgetPrivate::subtractMargin(const QSizeF &size, MarginType type) const
{
Q_ASSERT(activeMargins);
const Margin &m = activeMargins[type];
return QSizeF(size.width() - m.left - m.right, size.height() - m.top - m.bottom);
}
int IconWidgetPrivate::maxWordWidth(const QString text) const
{
QFontMetricsF fm = Plasma::Theme::defaultTheme()->fontMetrics();
QStringList words = text.split(' ');
qreal maxWidth = 0;
foreach (const QString &word, words) {
maxWidth = qMax(maxWidth, fm.width(word));
}
return maxWidth;
}
QRectF IconWidgetPrivate::actionRect(ActionPosition position) const
{
switch (position) {
case TopLeft:
return QRectF(iconActionMargin,
iconActionMargin,
iconActionSize,
iconActionSize);
case TopRight:
return QRectF(currentSize.width() - iconActionSize - iconActionMargin,
iconActionMargin,
iconActionSize,
iconActionSize);
case BottomLeft:
return QRectF(iconActionMargin,
currentSize.height() - iconActionSize - iconActionMargin,
iconActionSize,
iconActionSize);
//BottomRight
default:
return QRectF(currentSize.width() - iconActionSize - iconActionMargin,
currentSize.height() - iconActionSize - iconActionMargin,
iconActionSize,
iconActionSize);
}
}
} // Namespace
#endif