/******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2009 Martin Gräßlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, 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 General Public License along with this program. If not, see . *********************************************************************/ //own #include "desktopitemdelegate.h" // tabbox #include "clientitemdelegate.h" #include "clientmodel.h" #include "desktopmodel.h" #include "tabboxconfig.h" // Qt #include // KDE #include #include #include #include #include #include namespace KWin { namespace TabBox { DesktopItemDelegate::DesktopItemDelegate(QObject* parent) : QAbstractItemDelegate(parent) { m_frame = new Plasma::FrameSvg(this); m_frame->setImagePath("widgets/viewitem"); m_frame->setElementPrefix("hover"); m_frame->setCacheAllRenderedFrames(true); m_frame->setEnabledBorders(Plasma::FrameSvg::AllBorders); m_clientDelegate = new ClientItemDelegate(this); } DesktopItemDelegate::~DesktopItemDelegate() { } void DesktopItemDelegate::setConfig(const KWin::TabBox::ItemLayoutConfig& config) { m_config = config; } void DesktopItemDelegate::setLayouts(QMap< QString, ItemLayoutConfig >& layouts) { m_layouts = layouts; } QSize DesktopItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const { Q_UNUSED(option) if (!index.isValid()) return QSize(0, 0); qreal width = 0.0; qreal height = 0.0; for (int i = 0; i < m_config.count(); i++) { QSizeF row = rowSize(index, i); width = qMax(width, row.width()); height += row.height(); } qreal left, top, right, bottom; m_frame->getMargins(left, top, right, bottom); // find icon elements which have a row span for (int i = 0; i < m_config.count(); i++) { ItemLayoutConfigRow row = m_config.row(i); for (int j = 0; j < row.count(); j++) { ItemLayoutConfigRowElement element = row.element(j); if (element.type() == ItemLayoutConfigRowElement::ElementIcon && element.isRowSpan()) height = qMax(height, element.iconSize().height()); } } return QSize(width + left + right, height + top + bottom); } void DesktopItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { if (!index.isValid()) return; qreal left, top, right, bottom; m_frame->getMargins(left, top, right, bottom); qreal y = option.rect.top() + top; for (int i = 0; i < m_config.count(); i++) { qreal rowHeight = rowSize(index, i).height(); qreal x = option.rect.left() + left ; ItemLayoutConfigRow row = m_config.row(i); for (int j = 0; j < row.count(); j++) { ItemLayoutConfigRowElement element = row.element(j); switch(element.type()) { case ItemLayoutConfigRowElement::ElementDesktopName: { x += paintTextElement(painter, option, element, x, y, rowHeight, index.model()->data(index, Qt::DisplayRole).toString()); break; } case ItemLayoutConfigRowElement::ElementIcon: { qreal rectWidth = (qreal)option.rect.width(); qreal maxWidth = qMin(element.width(), rectWidth); if (element.isStretch()) maxWidth = qMax(maxWidth, option.rect.left() + option.rect.width() - x); qreal iconX = x + maxWidth * 0.5 - element.iconSize().width() * 0.5; qreal iconY = y + rowHeight * 0.5 - element.iconSize().height() * 0.5; if (element.isRowSpan()) iconY = option.rect.top() + option.rect.height() * 0.5 - element.iconSize().height() * 0.5; QRectF iconRect = QRectF(iconX, iconY, element.iconSize().width(), element.iconSize().height()); // icon painter->save(); KIcon icon("user-desktop"); QPixmap iconPixmap = icon.pixmap(QSize(64, 64)); if (m_config.isHighlightSelectedIcons() && option.state & QStyle::State_Selected) { KIconEffect *effect = KIconLoader::global()->iconEffect(); iconPixmap = effect->apply(iconPixmap, KIconLoader::Desktop, KIconLoader::ActiveState); } if (m_config.isGrayscaleDeselectedIcons() && !(option.state & QStyle::State_Selected)) { KIconEffect *effect = KIconLoader::global()->iconEffect(); iconPixmap = effect->apply(iconPixmap, KIconLoader::Desktop, KIconLoader::DisabledState); } QRectF sourceRect = QRectF(0.0, 0.0, iconPixmap.width(), iconPixmap.height()); painter->drawPixmap(iconRect, iconPixmap, sourceRect); painter->restore(); x += element.width(); break; } case ItemLayoutConfigRowElement::ElementEmpty: x += element.width(); break; case ItemLayoutConfigRowElement::ElementClientList: { m_clientDelegate->setConfig(m_layouts[ element.clientListLayoutName()]); ClientModel* clientModel = static_cast< ClientModel* >( index.model()->data(index, DesktopModel::ClientModelRole).value< void* >()); TabBoxClientList clients = clientModel->clientList(); qreal partX = 0.0; qreal partY = 0.0; qreal itemWidth = element.width(); if (element.isStretch()) itemWidth = option.rect.x() + option.rect.width() - x; foreach (TabBoxClient * client, clients) { if (!client) continue; QModelIndex clientIndex = clientModel->index(client); QStyleOptionViewItem itemOption = option; itemOption.state = QStyle::State_Item; QSizeF itemSize = m_clientDelegate->sizeHint(itemOption, clientIndex); // TabBoxHandler gives the same config to the client models as used here // so row and column do not represent the actual used layout for this list switch(element.clientListLayoutMode()) { case TabBoxConfig::HorizontalLayout: itemOption.rect = QRect(partX + x, y, itemWidth - partX, rowHeight); partX += qMin(itemWidth - partX, itemSize.width()); break; case TabBoxConfig::VerticalLayout: itemOption.rect = QRect(x, y + partY, itemWidth, itemSize.height()); partY += itemSize.height(); break; case TabBoxConfig::HorizontalVerticalLayout: // TODO: complicated break; default: break; // nothing } if ((partX > itemWidth) || (partX + x > option.rect.x() + option.rect.width())) { partX = itemWidth; break; } if ((partY > rowHeight) || (y + partY > option.rect.y() + option.rect.height())) { partY = rowHeight; break; } m_clientDelegate->paint(painter, itemOption, clientIndex); } x += itemWidth; break; } default: break; // do nothing } } y += rowHeight; } } qreal DesktopItemDelegate::paintTextElement(QPainter* painter, const QStyleOptionViewItem& option, const ItemLayoutConfigRowElement& element, const qreal& x, const qreal& y, const qreal& rowHeight, QString text) const { painter->save(); QFont font = KGlobalSettings::generalFont(); if (element.isSmallTextSize()) font = KGlobalSettings::smallestReadableFont(); font.setBold(element.isBold()); font.setItalic(element.isItalic()); text = element.prefix() + text + element.suffix(); painter->setFont(font); painter->setPen(Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor)); qreal width = element.width(); if (element.isStretch()) { qreal left, top, right, bottom; m_frame->getMargins(left, top, right, bottom); width = option.rect.left() + option.rect.width() - x - right; } text = QFontMetricsF(font).elidedText(text, Qt::ElideRight, width); QRectF rect = QRectF(x, y, width, rowHeight); painter->drawText(rect, element.alignment() | Qt::TextSingleLine, text); painter->restore(); return width; } QSizeF DesktopItemDelegate::rowSize(const QModelIndex& index, int row) const { ItemLayoutConfigRow currentRow = m_config.row(row); qreal rowWidth = 0.0; qreal rowHeight = 0.0; for (int j = 0; j < currentRow.count(); j++) { ItemLayoutConfigRowElement element = currentRow.element(j); switch(element.type()) { case ItemLayoutConfigRowElement::ElementDesktopName: { QSizeF size = textElementSizeHint(index, element, index.model()->data(index, Qt::DisplayRole).toString()); rowWidth += size.width(); rowHeight = qMax(rowHeight, size.height()); break; } case ItemLayoutConfigRowElement::ElementIcon: rowWidth += qMax(element.iconSize().width(), element.width()); if (!element.isRowSpan()) rowHeight = qMax(rowHeight, element.iconSize().height()); break; case ItemLayoutConfigRowElement::ElementEmpty: rowWidth += element.width(); break; case ItemLayoutConfigRowElement::ElementClientList: { m_clientDelegate->setConfig(m_layouts[ element.clientListLayoutName()]); ClientModel* clientModel = static_cast< ClientModel* >( index.model()->data(index, DesktopModel::ClientModelRole).value< void* >()); TabBoxClientList clients = clientModel->clientList(); qreal elementWidth = 0.0; qreal elementHeight = 0.0; foreach (TabBoxClient * client, clients) { if (!client) continue; QModelIndex clientIndex = clientModel->index(client); QStyleOptionViewItem itemOption = QStyleOptionViewItem(); QSizeF itemSize = m_clientDelegate->sizeHint(itemOption, clientIndex); switch(element.clientListLayoutMode()) { case TabBoxConfig::HorizontalLayout: elementWidth += itemSize.width(); elementHeight = qMax(elementHeight, itemSize.height()); break; case TabBoxConfig::VerticalLayout: elementWidth = qMax(elementWidth, itemSize.width()); elementHeight += itemSize.height(); break; case TabBoxConfig::HorizontalVerticalLayout: // TODO: complicated break; default: break; // nothing } } if (element.isStretch()) rowWidth += elementWidth; else rowWidth += qMin(elementWidth, element.width()); rowHeight = qMax(rowHeight, elementHeight); break; } default: break; // do nothing } } return QSizeF(rowWidth, rowHeight); } QSizeF DesktopItemDelegate::textElementSizeHint(const QModelIndex& index, const ItemLayoutConfigRowElement& element, QString text) const { Q_UNUSED(index) QFont font = KGlobalSettings::generalFont(); if (element.isSmallTextSize()) font = KGlobalSettings::smallestReadableFont(); font.setBold(element.isBold()); font.setItalic(element.isItalic()); text = element.prefix() + text + element.suffix(); QFontMetricsF fm(font); qreal width = element.width(); if (element.isStretch()) width = fm.width(text); qreal height = fm.boundingRect(text).height(); return QSizeF(width, height); } } // namespace Tabbox } // namespace KWin