From: Peter Penz Date: Wed, 9 Apr 2008 20:12:43 +0000 (+0000) Subject: Provide tooltips. Per default tooltips are turned off because the information sidebar... X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/commitdiff_plain/9d4250e10ada4e2410722951dbd406263b61041c Provide tooltips. Per default tooltips are turned off because the information sidebar is turned on already. Thanks a lot to Konstantin Heil and Fredrik Höglund for the code :-) CCMAIL: konst.heil@stud.uni-heidelberg.de CCMAIL: fredrik@kde.org svn path=/trunk/KDE/kdebase/apps/; revision=795324 --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 77323bb45..b59d6bb1d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,9 +27,13 @@ set(dolphinprivate_LIB_SRCS dolphinview.cpp dolphinviewactionhandler.cpp iconmanager.cpp + ktooltip.cpp + kballoontipdelegate.cpp + kformattedballoontipdelegate.cpp renamedialog.cpp selectiontoggle.cpp selectionmanager.cpp + tooltipmanager.cpp viewproperties.cpp ) @@ -193,4 +197,4 @@ install(TARGETS kcm_dolphin DESTINATION ${PLUGIN_INSTALL_DIR} ) install( FILES dolphin.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} ) install( FILES dolphin_directoryviewpropertysettings.kcfg dolphin_generalsettings.kcfg dolphin_columnmodesettings.kcfg dolphin_iconsmodesettings.kcfg dolphin_detailsmodesettings.kcfg DESTINATION ${KCFG_INSTALL_DIR} ) install( FILES dolphinui.rc DESTINATION ${DATA_INSTALL_DIR}/dolphin ) -install( FILES kcmdolphin.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) \ No newline at end of file +install( FILES kcmdolphin.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) diff --git a/src/dolphincolumnwidget.cpp b/src/dolphincolumnwidget.cpp index 972098bab..e7993b975 100644 --- a/src/dolphincolumnwidget.cpp +++ b/src/dolphincolumnwidget.cpp @@ -29,6 +29,7 @@ #include "dolphin_generalsettings.h" #include "draganddrophelper.h" #include "selectionmanager.h" +#include "tooltipmanager.h" #include #include @@ -135,6 +136,10 @@ DolphinColumnWidget::DolphinColumnWidget(QWidget* parent, m_iconManager = new IconManager(this, m_proxyModel); m_iconManager->setShowPreview(m_view->m_controller->dolphinView()->showPreview()); + if (DolphinSettings::instance().generalSettings()->showToolTips()) { + new ToolTipManager(this, m_proxyModel); + } + m_dirLister->openUrl(url, KDirLister::NoFlags); connect(KGlobalSettings::self(), SIGNAL(kdisplayFontChanged()), diff --git a/src/dolphinview.cpp b/src/dolphinview.cpp index 7b0ac8947..12d6be0d2 100644 --- a/src/dolphinview.cpp +++ b/src/dolphinview.cpp @@ -57,6 +57,7 @@ #include "dolphin_generalsettings.h" #include "iconmanager.h" #include "renamedialog.h" +#include "tooltipmanager.h" #include "viewproperties.h" DolphinView::DolphinView(QWidget* parent, @@ -121,10 +122,6 @@ DolphinView::DolphinView(QWidget* parent, applyViewProperties(url); m_topLayout->addWidget(itemView()); - - if (DolphinSettings::instance().generalSettings()->showToolTips()) { - // TODO: instantiate ToolTipManager here... - } } DolphinView::~DolphinView() @@ -1088,6 +1085,10 @@ void DolphinView::createView() m_iconManager = new IconManager(view, m_proxyModel); m_iconManager->setShowPreview(m_showPreview); + if (DolphinSettings::instance().generalSettings()->showToolTips()) { + new ToolTipManager(view, m_proxyModel); + } + m_topLayout->insertWidget(1, view); connect(view->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), diff --git a/src/kballoontipdelegate.cpp b/src/kballoontipdelegate.cpp new file mode 100644 index 000000000..84e0a63e0 --- /dev/null +++ b/src/kballoontipdelegate.cpp @@ -0,0 +1,164 @@ +/*************************************************************************** + * Copyright (C) 2008 by Fredrik Höglund * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#include "kballoontipdelegate.h" +#include +#include +#include + +QSize KBalloonTipDelegate::sizeHint(const KStyleOptionToolTip *option, const KToolTipItem *item) const +{ + QSize size; + size.rwidth() = option->fontMetrics.width(item->text()); + size.rheight() = option->fontMetrics.lineSpacing(); + + QIcon icon = item->icon(); + if (!icon.isNull()) { + const QSize iconSize = icon.actualSize(option->decorationSize); + size.rwidth() += iconSize.width() + 4; + size.rheight() = qMax(size.height(), iconSize.height()); + } + + int margin = 2 * 10 + (option->activeCorner != KStyleOptionToolTip::NoCorner ? 10 : 0); + return size + QSize(margin, margin); +} + +static inline void arc(QPainterPath &path, qreal cx, qreal cy, qreal radius, qreal angle, qreal sweeplength) +{ + path.arcTo(cx-radius, cy-radius, radius * 2, radius * 2, angle, sweeplength); +} + +QPainterPath KBalloonTipDelegate::createPath(const KStyleOptionToolTip *option, QRect *contents) const +{ + QPainterPath path; + QRect rect = option->rect.adjusted(0, 0, -1, -1); + qreal radius = 10; + + switch (option->activeCorner) + { + case KStyleOptionToolTip::TopLeftCorner: + rect.adjust(10, 10, 0, 0); + path.moveTo(option->rect.topLeft()); + path.lineTo(rect.left() + radius, rect.top()); + arc(path, rect.right() - radius, rect.top() + radius, radius, 90, -90); + arc(path, rect.right() - radius, rect.bottom() - radius, radius, 0, -90); + arc(path, rect.left() + radius, rect.bottom() - radius, radius, 270, -90); + path.lineTo(rect.left(), rect.top() + radius); + path.closeSubpath(); + break; + + case KStyleOptionToolTip::TopRightCorner: + rect.adjust(0, 10, -10, 0); + path.moveTo(option->rect.topRight()); + path.lineTo(rect.right(), rect.top() + radius); + arc(path, rect.right() - radius, rect.bottom() - radius, radius, 0, -90); + arc(path, rect.left() + radius, rect.bottom() - radius, radius, 270, -90); + arc(path, rect.left() + radius, rect.top() + radius, radius, 180, -90); + path.lineTo(rect.right() - radius, rect.top()); + path.closeSubpath(); + break; + + case KStyleOptionToolTip::BottomLeftCorner: + rect.adjust(10, 0, 0, -10); + path.moveTo(option->rect.bottomLeft()); + path.lineTo(rect.left(), rect.bottom() - radius); + arc(path, rect.left() + radius, rect.top() + radius, radius, 180, -90); + arc(path, rect.right() - radius, rect.top() + radius, radius, 90, -90); + arc(path, rect.right() - radius, rect.bottom() - radius, radius, 0, -90); + path.lineTo(rect.left() + radius, rect.bottom()); + path.closeSubpath(); + break; + + case KStyleOptionToolTip::BottomRightCorner: + rect.adjust(0, 0, -10, -10); + path.moveTo(option->rect.bottomRight()); + path.lineTo(rect.right() - radius, rect.bottom()); + arc(path, rect.left() + radius, rect.bottom() - radius, radius, 270, -90); + arc(path, rect.left() + radius, rect.top() + radius, radius, 180, -90); + arc(path, rect.right() - radius, rect.top() + radius, radius, 90, -90); + path.lineTo(rect.right(), rect.bottom() - radius); + path.closeSubpath(); + break; + + default: + path.moveTo(rect.left(), rect.top() + radius); + arc(path, rect.left() + radius, rect.top() + radius, radius, 180, -90); + arc(path, rect.right() - radius, rect.top() + radius, radius, 90, -90); + arc(path, rect.right() - radius, rect.bottom() - radius, radius, 0, -90); + arc(path, rect.left() + radius, rect.bottom() - radius, radius, 270, -90); + path.closeSubpath(); + break; + } + + if (contents) + *contents = rect.adjusted(10, 10, -10, -10); + + return path; +} + +void KBalloonTipDelegate::paint(QPainter *painter, const KStyleOptionToolTip *option, const KToolTipItem *item) const +{ + QRect contents; + QPainterPath path = createPath(option, &contents); + bool alpha = haveAlphaChannel(); + + if (alpha) { + painter->setRenderHint(QPainter::Antialiasing); + painter->translate(.5, .5); + } + +#if QT_VERSION >= 0x040400 + painter->setBrush(option->palette.brush(QPalette::ToolTipBase)); +#else + painter->setBrush(option->palette.brush(QPalette::Base)); +#endif + painter->drawPath(path); + + if (alpha) + painter->translate(-.5, -.5); + + QIcon icon = item->icon(); + if (!icon.isNull()) { + const QSize iconSize = icon.actualSize(option->decorationSize); + painter->drawPixmap(contents.topLeft(), icon.pixmap(iconSize)); + contents.adjust(iconSize.width() + 4, 0, 0, 0); + } + + painter->drawText(contents, Qt::AlignLeft | Qt::AlignVCenter, item->text()); +} + + +QRegion KBalloonTipDelegate::inputShape(const KStyleOptionToolTip *option) const +{ + QBitmap bitmap(option->rect.size()); + bitmap.fill(Qt::color0); + + QPainter p(&bitmap); + p.setPen(QPen(Qt::color1, 1)); + p.setBrush(Qt::color1); + p.drawPath(createPath(option)); + + return QRegion(bitmap); +} + +QRegion KBalloonTipDelegate::shapeMask(const KStyleOptionToolTip *option) const +{ + return inputShape(option); +} + diff --git a/src/kballoontipdelegate.h b/src/kballoontipdelegate.h new file mode 100644 index 000000000..0baec17f4 --- /dev/null +++ b/src/kballoontipdelegate.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2008 by Fredrik Höglund * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#ifndef KBALLOONTIPDELEGATE_H +#define KBALLOONTIPDELEGATE_H + +#include "ktooltip.h" + +class KBalloonTipDelegate : public KToolTipDelegate +{ +public: + KBalloonTipDelegate() {} + ~KBalloonTipDelegate() {} + + QSize sizeHint(const KStyleOptionToolTip *option, const KToolTipItem *item) const; + void paint(QPainter *painter, const KStyleOptionToolTip *option, const KToolTipItem *item) const; + QRegion inputShape(const KStyleOptionToolTip *option) const; + QRegion shapeMask(const KStyleOptionToolTip *option) const; + +private: + QPainterPath createPath(const KStyleOptionToolTip *option, QRect *contentRect = 0) const; +}; + +#endif diff --git a/src/kformattedballoontipdelegate.cpp b/src/kformattedballoontipdelegate.cpp new file mode 100644 index 000000000..bb3f658df --- /dev/null +++ b/src/kformattedballoontipdelegate.cpp @@ -0,0 +1,109 @@ +/******************************************************************************* + * Copyright (C) 2008 by Fredrik Höglund * + * Copyright (C) 2008 by Konstantin Heil * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + *******************************************************************************/ + +#include "kformattedballoontipdelegate.h" +#include +#include + +QSize KFormattedBalloonTipDelegate::sizeHint(const KStyleOptionToolTip *option, const KToolTipItem *item) const +{ + QTextDocument doc; + doc.setHtml(item->text()); + QIcon icon = item->icon(); + QSize is = (icon.isNull()) ? QSize(0,0) : QSize(icon.actualSize(option->decorationSize).width(),0); + return doc.size().toSize()+is+QSize(20,20); +} + +void KFormattedBalloonTipDelegate::paint(QPainter *painter, const KStyleOptionToolTip *option, const KToolTipItem *item) const +{ + QRect contents; + QPainterPath path = createPath(option, &contents); + bool alpha = haveAlphaChannel(); + + if (alpha) { + painter->setRenderHint(QPainter::Antialiasing); + painter->translate(.5, .5); + } + +#if QT_VERSION >= 0x040400 + painter->setBrush(option->palette.brush(QPalette::ToolTipBase)); +#else + painter->setBrush(option->palette.brush(QPalette::Base)); +#endif + painter->drawPath(path); + + QIcon icon = item->icon(); + if (!icon.isNull()) { + const QSize iconSize = icon.actualSize(option->decorationSize); + painter->drawPixmap(contents.topLeft(), icon.pixmap(iconSize)); + contents.adjust(iconSize.width() + 4, 0, 0, 0); + } + + QTextDocument doc; + doc.setHtml(item->text()); + QBitmap bitmap(doc.size().toSize()); + bitmap.fill(Qt::color0); + QPainter p(&bitmap); + doc.drawContents(&p); + + painter->drawPixmap(contents, bitmap, QRect(QPoint(0,0), bitmap.size())); +} + +QRegion KFormattedBalloonTipDelegate::inputShape(const KStyleOptionToolTip *option) const +{ + QBitmap bitmap(option->rect.size()+QSize(20,20)); + bitmap.fill(Qt::color0); + + QPainter p(&bitmap); + p.setPen(QPen(Qt::color1, 1)); + p.setBrush(Qt::color1); + p.drawPath(createPath(option, &QRect())); + + return QRegion(bitmap); +} + +QRegion KFormattedBalloonTipDelegate::shapeMask(const KStyleOptionToolTip *option) const +{ + return inputShape(option); +} + +static inline void arc(QPainterPath &path, qreal cx, qreal cy, qreal radius, qreal angle, qreal sweeplength) +{ + path.arcTo(cx-radius, cy-radius, radius * 2, radius * 2, angle, sweeplength); +} + +QPainterPath KFormattedBalloonTipDelegate::createPath(const KStyleOptionToolTip *option, QRect *contents) const +{ + QPainterPath path; + QRect rect = option->rect.adjusted(0, 0, -1, -1); + qreal radius = 10; + + path.moveTo(rect.left(), rect.top() + radius); + arc(path, rect.left() + radius, rect.top() + radius, radius, 180, -90); + arc(path, rect.right() - radius, rect.top() + radius, radius, 90, -90); + arc(path, rect.right() - radius, rect.bottom() - radius, radius, 0, -90); + arc(path, rect.left() + radius, rect.bottom() - radius, radius, 270, -90); + path.closeSubpath(); + + if (contents) + *contents = rect.adjusted(10, 10, -10, -10); + + return path; +} diff --git a/src/kformattedballoontipdelegate.h b/src/kformattedballoontipdelegate.h new file mode 100644 index 000000000..c4448b8c3 --- /dev/null +++ b/src/kformattedballoontipdelegate.h @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (C) 2008 by Fredrik Höglund * + * Copyright (C) 2008 by Konstantin Heil * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + *******************************************************************************/ + +#ifndef KFORMATTEDBALLOONTIPDELEGATE_H +#define KFORMATTEDBALLOONTIPDELEGATE_H + +#include "ktooltip.h" +#include + +class KFormattedBalloonTipDelegate : public KToolTipDelegate +{ +public: + KFormattedBalloonTipDelegate() {} + ~KFormattedBalloonTipDelegate() {} + + QSize sizeHint(const KStyleOptionToolTip *option, const KToolTipItem *item) const; + void paint(QPainter *painter, const KStyleOptionToolTip *option, const KToolTipItem *item) const; + QRegion inputShape(const KStyleOptionToolTip *option) const; + QRegion shapeMask(const KStyleOptionToolTip *option) const; + + QPainterPath createPath(const KStyleOptionToolTip *option, QRect *contents) const; +}; + +#endif diff --git a/src/ktooltip.cpp b/src/ktooltip.cpp new file mode 100644 index 000000000..bf607d0ec --- /dev/null +++ b/src/ktooltip.cpp @@ -0,0 +1,547 @@ +/*************************************************************************** + * Copyright (C) 2008 by Fredrik Höglund * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#include "ktooltip.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_WS_X11 +# include +# include +# include +# include +#endif + +#include "ktooltip_p.h" + + + +class KToolTipItemPrivate +{ +public: + QMap map; + int type; +}; + +KToolTipItem::KToolTipItem(const QString &text, int type) + : d(new KToolTipItemPrivate) +{ + d->map[Qt::DisplayRole] = text; + d->type = type; +} + +KToolTipItem::KToolTipItem(const QIcon &icon, const QString &text, int type) + : d(new KToolTipItemPrivate) +{ + d->map[Qt::DecorationRole] = icon; + d->map[Qt::DisplayRole] = text; + d->type = type; +} + +KToolTipItem::~KToolTipItem() +{ +} + +int KToolTipItem::type() const +{ + return d->type; +} + +QString KToolTipItem::text() const +{ + return data(Qt::DisplayRole).toString(); +} + +QIcon KToolTipItem::icon() const +{ + return qvariant_cast(data(Qt::DecorationRole)); +} + +QVariant KToolTipItem::data(int role) const +{ + return d->map.value(role); +} + +void KToolTipItem::setData(int role, const QVariant &data) +{ + d->map[role] = data; +} + + + +// ---------------------------------------------------------------------------- + + +KStyleOptionToolTip::KStyleOptionToolTip() + : fontMetrics(QApplication::font()) +{ +} + + +// ---------------------------------------------------------------------------- + + + +KToolTipDelegate::KToolTipDelegate() : QObject() +{ +} + +KToolTipDelegate::~KToolTipDelegate() +{ +} + +QSize KToolTipDelegate::sizeHint(const KStyleOptionToolTip *option, const KToolTipItem *item) const +{ + QSize size; + size.rwidth() = option->fontMetrics.width(item->text()); + size.rheight() = option->fontMetrics.lineSpacing(); + + QIcon icon = item->icon(); + if (!icon.isNull()) { + const QSize iconSize = icon.actualSize(option->decorationSize); + size.rwidth() += iconSize.width() + 4; + size.rheight() = qMax(size.height(), iconSize.height()); + } + + return size + QSize(20, 20); + +} + +void KToolTipDelegate::paint(QPainter *painter, const KStyleOptionToolTip *option, + const KToolTipItem *item) const +{ + bool haveAlpha = haveAlphaChannel(); + painter->setRenderHint(QPainter::Antialiasing); + + QPainterPath path; + if (haveAlpha) + path.addRoundRect(option->rect.adjusted(0, 0, -1, -1), 25); + else + path.addRect(option->rect.adjusted(0, 0, -1, -1)); + +#if QT_VERSION >= 0x040400 + QColor color = option->palette.color(QPalette::ToolTipBase); +#else + QColor color = option->palette.color(QPalette::Base); +#endif + QColor from = color.lighter(105); + QColor to = color.darker(120); + + QLinearGradient gradient(0, 0, 0, 1); + gradient.setCoordinateMode(QGradient::ObjectBoundingMode); + gradient.setColorAt(0, from); + gradient.setColorAt(1, to); + + painter->translate(.5, .5); + painter->setPen(QPen(Qt::black, 1)); + painter->setBrush(gradient); + painter->drawPath(path); + painter->translate(-.5, -.5); + + if (haveAlpha) { + QLinearGradient mask(0, 0, 0, 1); + gradient.setCoordinateMode(QGradient::ObjectBoundingMode); + gradient.setColorAt(0, QColor(0, 0, 0, 192)); + gradient.setColorAt(1, QColor(0, 0, 0, 72)); + painter->setCompositionMode(QPainter::CompositionMode_DestinationIn); + painter->fillRect(option->rect, gradient); + painter->setCompositionMode(QPainter::CompositionMode_SourceOver); + } + + QRect textRect = option->rect.adjusted(10, 10, -10, -10); + + QIcon icon = item->icon(); + if (!icon.isNull()) { + const QSize iconSize = icon.actualSize(option->decorationSize); + painter->drawPixmap(textRect.topLeft(), icon.pixmap(iconSize)); + textRect.adjust(iconSize.width() + 4, 0, 0, 0); + } + painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, item->text()); +} + +QRegion KToolTipDelegate::inputShape(const KStyleOptionToolTip *option) const +{ + return QRegion(option->rect); +} + +QRegion KToolTipDelegate::shapeMask(const KStyleOptionToolTip *option) const +{ + return QRegion(option->rect); +} + +bool KToolTipDelegate::haveAlphaChannel() const +{ + return KToolTipManager::instance()->haveAlphaChannel(); +} + + + +// ---------------------------------------------------------------------------- + + + +class KAbstractToolTipLabel +{ +public: + KAbstractToolTipLabel() {} + virtual ~KAbstractToolTipLabel() {} + + virtual void showTip(const QPoint &pos, const KToolTipItem *item) = 0; + virtual void moveTip(const QPoint &pos) = 0; + virtual void hideTip() = 0; + +protected: + KStyleOptionToolTip styleOption() const; + KToolTipDelegate *delegate() const; +}; + +KStyleOptionToolTip KAbstractToolTipLabel::styleOption() const +{ + KStyleOptionToolTip option; + KToolTipManager::instance()->initStyleOption(&option); + return option; +} + +KToolTipDelegate *KAbstractToolTipLabel::delegate() const +{ + return KToolTipManager::instance()->delegate(); +} + + +// ---------------------------------------------------------------------------- + + + +class QWidgetLabel : public QWidget, public KAbstractToolTipLabel +{ +public: + QWidgetLabel() : QWidget(0, Qt::ToolTip) {} + void showTip(const QPoint &pos, const KToolTipItem *item); + void moveTip(const QPoint &pos); + void hideTip(); + +private: + void paintEvent(QPaintEvent*); + QSize sizeHint() const; + +private: + const KToolTipItem *currentItem; +}; + +void QWidgetLabel::showTip(const QPoint &pos, const KToolTipItem *item) +{ + currentItem = item; + move(pos); + show(); +} + +void QWidgetLabel::hideTip() +{ + hide(); + currentItem = 0; +} + +void QWidgetLabel::moveTip(const QPoint &pos) +{ + move(pos); +} + +void QWidgetLabel::paintEvent(QPaintEvent*) +{ + KStyleOptionToolTip option = styleOption(); + option.rect = rect(); + + setMask(delegate()->shapeMask(&option)); + + QPainter p(this); + p.setFont(option.font); + p.setPen(QPen(option.palette.brush(QPalette::Text), 0)); + delegate()->paint(&p, &option, currentItem); +} + +QSize QWidgetLabel::sizeHint() const +{ + if (!currentItem) + return QSize(); + + KStyleOptionToolTip option = styleOption(); + return delegate()->sizeHint(&option, currentItem); +} + + + +// ---------------------------------------------------------------------------- + + + +#ifdef Q_WS_X11 + +// X11 specific label that displays the tip in an ARGB window. +class ArgbLabel : public KAbstractToolTipLabel +{ +public: + ArgbLabel(Visual *visual, int depth); + ~ArgbLabel(); + + void showTip(const QPoint &pos, const KToolTipItem *item); + void moveTip(const QPoint &pos); + void hideTip(); + +private: + Window window; + Colormap colormap; + Picture picture; + bool mapped; +}; + +ArgbLabel::ArgbLabel(Visual *visual, int depth) +{ + Display *dpy = QX11Info::display(); + Window root = QX11Info::appRootWindow(); + colormap = XCreateColormap(dpy, QX11Info::appRootWindow(), visual, AllocNone); + + XSetWindowAttributes attr; + attr.border_pixel = 0; + attr.background_pixel = 0; + attr.colormap = colormap; + attr.override_redirect = True; + + window = XCreateWindow(dpy, root, 0, 0, 1, 1, 0, depth, InputOutput, visual, + CWBorderPixel | CWBackPixel | CWColormap | + CWOverrideRedirect, &attr); + + // ### TODO: Set the WM hints so KWin can identify this window as a + // tooltip. + + XRenderPictFormat *format = XRenderFindVisualFormat(dpy, visual); + picture = XRenderCreatePicture(dpy, window, format, 0, 0); + + mapped = false; +} + +ArgbLabel::~ArgbLabel() +{ + Display *dpy = QX11Info::display(); + XRenderFreePicture(dpy, picture); + XDestroyWindow(dpy, window); + XFreeColormap(dpy, colormap); +} + +void ArgbLabel::showTip(const QPoint &pos, const KToolTipItem *item) +{ + Display *dpy = QX11Info::display(); + KStyleOptionToolTip option = styleOption(); + const QSize size = delegate()->sizeHint(&option, item); + option.rect = QRect(QPoint(), size); + + QPixmap pixmap(size); + pixmap.fill(Qt::transparent); + + QPainter p(&pixmap); + p.setFont(option.font); + p.setPen(QPen(option.palette.brush(QPalette::Text), 0)); + delegate()->paint(&p, &option, item); + + // Resize, position and show the window. + XMoveResizeWindow(dpy, window, pos.x(), pos.y(), size.width(), size.height()); + + if (KToolTipManager::instance()->haveAlphaChannel()) { + const QRegion region = delegate()->inputShape(&option); + XShapeCombineRegion(dpy, window, ShapeInput, 0, 0, region.handle(), ShapeSet); + } else { + const QRegion region = delegate()->shapeMask(&option); + XShapeCombineRegion(dpy, window, ShapeBounding, 0, 0, region.handle(), ShapeSet); + } + + XMapWindow(dpy, window); + + // Blit the pixmap with the tip contents to the window. + // Since the window is override-redirect and an ARGB32 window, + // which always has an offscreen pixmap, there's no need to + // wait for an Expose event, or to process those. + XRenderComposite(dpy, PictOpSrc, pixmap.x11PictureHandle(), None, + picture, 0, 0, 0, 0, 0, 0, size.width(), size.height()); + + mapped = true; +} + +void ArgbLabel::moveTip(const QPoint &pos) +{ + if (mapped) + XMoveWindow(QX11Info::display(), window, pos.x(), pos.y()); +} + +void ArgbLabel::hideTip() +{ + if (mapped) { + Display *dpy = QX11Info::display(); + XUnmapWindow(dpy, window); + mapped = false; + } +} + +#endif // Q_WS_X11 + + + + +// ---------------------------------------------------------------------------- + + + + +KToolTipManager *KToolTipManager::s_instance = 0; + +KToolTipManager::KToolTipManager() + : label(0), currentItem(0) +{ +#ifdef Q_WS_X11 + Display *dpy = QX11Info::display(); + int screen = DefaultScreen(dpy); + int depth = DefaultDepth(dpy, screen); + Visual *visual = DefaultVisual(dpy, screen); + net_wm_cm_s0 = XInternAtom(dpy, "_NET_WM_CM_S0", False); + haveArgbVisual = false; + + int nvi; + XVisualInfo templ; + templ.screen = screen; + templ.depth = 32; + templ.c_class = TrueColor; + XVisualInfo *xvi = XGetVisualInfo(dpy, VisualScreenMask | VisualDepthMask | + VisualClassMask, &templ, &nvi); + + for (int i = 0; i < nvi; ++i) + { + XRenderPictFormat *format = XRenderFindVisualFormat(dpy, xvi[i].visual); + if (format->type == PictTypeDirect && format->direct.alphaMask) + { + visual = xvi[i].visual; + depth = xvi[i].depth; + haveArgbVisual = true; + break; + } + } + + if (haveArgbVisual) + label = new ArgbLabel(visual, depth); + else +#endif + label = new QWidgetLabel(); +} + +KToolTipManager::~KToolTipManager() +{ + delete label; + delete currentItem; +} + +void KToolTipManager::showTip(const QPoint &pos, KToolTipItem *item) +{ + hideTip(); + label->showTip(pos, item); + currentItem = item; +} + +void KToolTipManager::hideTip() +{ + label->hideTip(); + delete currentItem; + currentItem = 0; +} + +void KToolTipManager::initStyleOption(KStyleOptionToolTip *option) const +{ + option->direction = QApplication::layoutDirection(); + option->fontMetrics = QFontMetrics(QToolTip::font()); + option->activeCorner = KStyleOptionToolTip::TopLeftCorner; + option->palette = QToolTip::palette(); + option->font = QToolTip::font(); + option->rect = QRect(); + option->state = QStyle::State_None; + option->decorationSize = QSize(32, 32); +} + +bool KToolTipManager::haveAlphaChannel() const +{ +#ifdef Q_WS_X11 + // ### This is a synchronous call - ideally we'd use a selection + // watcher to avoid it. + return haveArgbVisual && + XGetSelectionOwner(QX11Info::display(), net_wm_cm_s0) != None; +#else + return false; +#endif +} + +void KToolTipManager::setDelegate(KToolTipDelegate *delegate) +{ + m_delegate = delegate; +} + +KToolTipDelegate *KToolTipManager::delegate() const +{ + return m_delegate; +} + + + +// ---------------------------------------------------------------------------- + + + +namespace KToolTip +{ + void showText(const QPoint &pos, const QString &text, QWidget *widget, const QRect &rect) + { + Q_UNUSED(widget) + Q_UNUSED(rect) + KToolTipItem *item = new KToolTipItem(text); + KToolTipManager::instance()->showTip(pos, item); + } + + void showText(const QPoint &pos, const QString &text, QWidget *widget) + { + showText(pos, text, widget, QRect()); + } + + void showTip(const QPoint &pos, KToolTipItem *item) + { + KToolTipManager::instance()->showTip(pos, item); + } + + void hideTip() + { + KToolTipManager::instance()->hideTip(); + } + + void setToolTipDelegate(KToolTipDelegate *delegate) + { + KToolTipManager::instance()->setDelegate(delegate); + } +} + diff --git a/src/ktooltip.h b/src/ktooltip.h new file mode 100644 index 000000000..bb8389df9 --- /dev/null +++ b/src/ktooltip.h @@ -0,0 +1,197 @@ +/*************************************************************************** + * Copyright (C) 2008 by Fredrik Höglund * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#ifndef KTOOLTIP_H +#define KTOOLTIP_H + +#include +#include +#include +#include +#include +#include + +class QString; +class QIcon; +class QSize; +class QPainter; +class QRegion; + +class KToolTipItemPrivate; + +/** + * KToolTipItem contains the data to be displayed in a tooltip. + * + * Custom data can be stored as QVariants in the object by calling + * setData() with a custom item role, and retrieved and displayed + * by a tooltip delegate by calling data(). + * + * The default tooltip delegate uses Qt::DecorationRole and + * Qt::DisplayRole. + * + * To display the tooltip, call KToolTip::showTip() with a pointer + * to the KToolTipItem. + * + * You can reimplement the setData() and/or data() methods in this + * class to implement on-demand loading of data. + */ +class KToolTipItem +{ +public: + enum ItemType { DefaultType, UserType = 1000 }; + + /** + * Creates a KToolTipItem with @p text and no icon. + */ + KToolTipItem(const QString &text, int type = DefaultType); + + /** + * Creates a KToolTipItem with an @p icon and @p text. + */ + KToolTipItem(const QIcon &icon, const QString &text, int type = DefaultType); + + /** + * Destroys the KToolTipItem. + */ + virtual ~KToolTipItem(); + + /** + * Returns the item type. + */ + int type() const; + + QString text() const; + QIcon icon() const; + + virtual QVariant data(int role) const; + virtual void setData(int role, const QVariant &data); + +private: + KToolTipItemPrivate * const d; +}; + + +class KStyleOptionToolTip +{ +public: + KStyleOptionToolTip(); + enum Corner { TopLeftCorner, TopRightCorner, BottomLeftCorner, BottomRightCorner, NoCorner }; + + Qt::LayoutDirection direction; + QFontMetrics fontMetrics; + QPalette palette; + QRect rect; + QStyle::State state; + QFont font; + QSize decorationSize; + Corner activeCorner; +}; + +/** + * KToolTipDelegate is responsible for providing the size hint and + * painting the tooltips. + */ +class KToolTipDelegate : public QObject +{ +public: + KToolTipDelegate(); + virtual ~KToolTipDelegate(); + + virtual QSize sizeHint(const KStyleOptionToolTip *option, const KToolTipItem *item) const; + + /** + * If haveAlphaChannel() returns true, the paint device will be filled with + * Qt::transparent when this function is called, otherwise the content is + * undefined. + */ + virtual void paint(QPainter *painter, const KStyleOptionToolTip *option, + const KToolTipItem *item) const; + + /** + * Reimplement this function to specify the region of the tooltip + * that accepts input. Any mouse events that occur outside this + * region will be sent to the widget below the tooltip. + * + * The default implemenation returns a region containing the + * bounding rect of the tooltip. + * + * This function will only be called if haveAlphaChannel() + * returns true. + */ + virtual QRegion inputShape(const KStyleOptionToolTip *option) const; + + /** + * Reimplement this function to specify a shape mask for the tooltip. + * + * The default implemenation returns a region containing the + * bounding rect of the tooltip. + * + * This function will only be called if haveAlphaChannel() + * returns false. + */ + virtual QRegion shapeMask(const KStyleOptionToolTip *option) const; + +protected: + /** + * Returns true if the tooltip has an alpha channel, and false + * otherwise. + * + * Implementors should assume that this condition may change at + * any time during the runtime of the application, as compositing + * can be enabled or disabled in the window manager. + */ + bool haveAlphaChannel() const; + +#if 0 +private Q_SLOTS: + /** + * Schedules a repaint of the tooltip item. + * This slot can be connected to a timer to animate the tooltip. + */ + void update(const KToolTipItem *item); +#endif +}; + + +/** + * KToolTip provides customizable tooltips that can have animations as well as an alpha + * channel, allowing for dynamic transparency effects. + * + * ARGB tooltips work on X11 even when the application isn't using the ARGB visual. + */ +namespace KToolTip +{ + void showText(const QPoint &pos, const QString &text, QWidget *widget, const QRect &rect); + void showText(const QPoint &pos, const QString &text, QWidget *widget = 0); + + /** + * Shows the tip @p item at the global position indicated by @p pos. + * + * Ownership of the item is transferred to KToolTip. The item will be deleted + * automatically when it is hidden. + * + * The tip is shown immediately when this function is called. + */ + void showTip(const QPoint &pos, KToolTipItem *item); + void hideTip(); + + void setToolTipDelegate(KToolTipDelegate *delegate); +} + +#endif diff --git a/src/ktooltip_p.h b/src/ktooltip_p.h new file mode 100644 index 000000000..16ca85293 --- /dev/null +++ b/src/ktooltip_p.h @@ -0,0 +1,63 @@ +/*************************************************************************** + * Copyright (C) 2008 by Fredrik Höglund * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#ifndef KTOOLTIP_P_H +#define KTOOLTIP_P_H + +class KAbstractToolTipLabel; +class KStyleOptionToolTip; +class KToolTipDelegate; + +class KToolTipManager +{ +public: + ~KToolTipManager(); + + static KToolTipManager *instance() { + if (!s_instance) + s_instance = new KToolTipManager(); + + return s_instance; + } + + void showTip(const QPoint &pos, KToolTipItem *item); + void hideTip(); + + void initStyleOption(KStyleOptionToolTip *option) const; + bool haveAlphaChannel() const; + + void setDelegate(KToolTipDelegate *delegate); + KToolTipDelegate *delegate() const; + +private: + KToolTipManager(); + + KAbstractToolTipLabel *label; + KToolTipItem *currentItem; + KToolTipDelegate *m_delegate; + +#ifdef Q_WS_X11 + bool haveArgbVisual; + Atom net_wm_cm_s0; +#endif + + static KToolTipManager *s_instance; +}; + +#endif diff --git a/src/tooltipmanager.cpp b/src/tooltipmanager.cpp new file mode 100644 index 000000000..6af3bb8b6 --- /dev/null +++ b/src/tooltipmanager.cpp @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (C) 2008 by Konstantin Heil * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + *******************************************************************************/ + +#include "tooltipmanager.h" + +#include "dolphinmodel.h" +#include "dolphinsortfilterproxymodel.h" +#include "ktooltip.h" +#include "kicon.h" + +#include + +ToolTipManager::ToolTipManager(QAbstractItemView* parent, + DolphinSortFilterProxyModel* model) : + QObject(parent), + m_view(parent), + m_dolphinModel(0), + m_proxyModel(model), + m_timer(0), + m_item(), + m_pos(), + m_delegate() +{ + KToolTip::setToolTipDelegate(&m_delegate); + + m_dolphinModel = static_cast(m_proxyModel->sourceModel()); + connect(parent, SIGNAL(entered(const QModelIndex&)), + this, SLOT(requestToolTip(const QModelIndex&))); + connect(parent, SIGNAL(viewportEntered()), + this, SLOT(hideToolTip())); + + m_timer = new QTimer(this); + m_timer->setSingleShot(true); + connect(m_timer, SIGNAL(timeout()), + this, SLOT(showToolTip())); + + m_view->viewport()->installEventFilter(this); +} + +ToolTipManager::~ToolTipManager() +{ +} + +bool ToolTipManager::eventFilter(QObject* watched, QEvent* event) +{ + if ((watched == m_view->viewport()) && (event->type() == QEvent::Leave)) { + hideToolTip(); + } + + return QObject::eventFilter(watched, event); +} + +void ToolTipManager::requestToolTip(const QModelIndex& index) +{ + KToolTip::hideTip(); + + const QRect rect = m_view->visualRect(index); + m_pos = m_view->viewport()->mapToGlobal(rect.bottomRight()); + + const QModelIndex dirIndex = m_proxyModel->mapToSource(index); + m_item = m_dolphinModel->itemForIndex(dirIndex); + + m_timer->start(500); +} + +void ToolTipManager::hideToolTip() +{ + m_timer->stop(); + KToolTip::hideTip(); +} + +void ToolTipManager::showToolTip() +{ + KToolTipItem* tip = new KToolTipItem(KIcon(m_item.iconName()), m_item.getToolTipText()); + KToolTip::showTip(m_pos, tip); +} + +#include "tooltipmanager.moc" diff --git a/src/tooltipmanager.h b/src/tooltipmanager.h new file mode 100644 index 000000000..8223b5bc8 --- /dev/null +++ b/src/tooltipmanager.h @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (C) 2008 by Konstantin Heil * + * * + * 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, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + *******************************************************************************/ + +#ifndef TOOLTIPMANAGER_H +#define TOOLTIPMANAGER_H + +#include +#include + +#include +#include + +class DolphinModel; +class DolphinSortFilterProxyModel; +class QAbstractItemView; +class QModelIndex; +class QTimer; + +/** + * @brief Manages the tooltips for an item view. + * + * When hovering an item, a tooltip is shown after + * a short timeout. The tooltip is hidden again when the + * viewport is hovered or the item view has been left. + */ +class ToolTipManager : public QObject +{ + Q_OBJECT + +public: + explicit ToolTipManager(QAbstractItemView* parent, + DolphinSortFilterProxyModel* model); + virtual ~ToolTipManager(); + +protected: + virtual bool eventFilter(QObject* watched, QEvent* event); + +private slots: + void requestToolTip(const QModelIndex& index); + void hideToolTip(); + void showToolTip(); + +private: + QAbstractItemView* m_view; + DolphinModel* m_dolphinModel; + DolphinSortFilterProxyModel* m_proxyModel; + + QTimer* m_timer; + KFileItem m_item; + QPoint m_pos; + KFormattedBalloonTipDelegate m_delegate; +}; + +#endif