/* * Copyright (C) 2007 by Aaron Seigo * Copyright (C) 2007 by Matt Broadstone * Copyright (C) 2006-2007 Fredrik Höglund * * 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 #include #include #include #include #include #include #include #include #include #include #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 m_animation; }; struct Margin { qreal left, right, top, bottom; }; class IconWidgetPrivate : public ActionWidgetInterface { 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 haloRects; QTimer *iconChangeTimer; QList 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