X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/e3a83e67a27db0fdf40bc4a96d4613fcbe5cb3d9..7eeb8dba6aeba09aa3dfa7fa5f0b00840d4d8317:/src/tooltips/ktooltip.cpp diff --git a/src/tooltips/ktooltip.cpp b/src/tooltips/ktooltip.cpp index d5aa0f7b7..99114106f 100644 --- a/src/tooltips/ktooltip.cpp +++ b/src/tooltips/ktooltip.cpp @@ -18,548 +18,85 @@ ***************************************************************************/ #include "ktooltip.h" - -#include -#include -#include -#include -#include -#include +#include "ktooltipwindow_p.h" +#include +#include #include -#include -#include - -#ifdef Q_WS_X11 -# include -# include -# include -# include -#endif - -#include "ktooltip_p.h" - - -// compile with XShape older than 1.0 -#ifndef ShapeInput -const int ShapeInput = 2; -#endif - - -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() -{ - delete d; -} - -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; - KToolTipManager::instance()->update(); -} - - - -// ---------------------------------------------------------------------------- - - -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)); - - QColor color = option->palette.color(QPalette::ToolTipBase); - 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 +class KToolTipManager { public: - KAbstractToolTipLabel() {} - virtual ~KAbstractToolTipLabel() {} + ~KToolTipManager(); - virtual void showTip(const QPoint &pos, const KToolTipItem *item) = 0; - virtual void moveTip(const QPoint &pos) = 0; - virtual void hideTip() = 0; + static KToolTipManager* instance(); -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(); - void showTip(const QPoint &pos, const KToolTipItem *item); - void moveTip(const QPoint &pos); + void showTip(const QPoint& pos, QWidget* content); void hideTip(); private: - void paintEvent(QPaintEvent*); - QSize sizeHint() const; + KToolTipManager(); -private: - const KToolTipItem *currentItem; + KToolTipWindow* m_window; + static KToolTipManager *s_instance; }; -QWidgetLabel::QWidgetLabel() : QWidget(0, Qt::ToolTip) -{ - if (KToolTipManager::instance()->haveAlphaChannel()) { - setAttribute(Qt::WA_TranslucentBackground); - } -} - -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; -} +KToolTipManager *KToolTipManager::s_instance = 0; -void ArgbLabel::moveTip(const QPoint &pos) +KToolTipManager::KToolTipManager() : + m_window(0) { - if (mapped) - XMoveWindow(QX11Info::display(), window, pos.x(), pos.y()); } -void ArgbLabel::hideTip() +KToolTipManager::~KToolTipManager() { - if (mapped) { - Display *dpy = QX11Info::display(); - XUnmapWindow(dpy, window); - mapped = false; - } + delete m_window; + m_window = 0; } -#endif // Q_WS_X11 - - - - -// ---------------------------------------------------------------------------- - - - - -KToolTipManager *KToolTipManager::s_instance = 0; - -KToolTipManager::KToolTipManager() - : label(0), currentItem(0), m_delegate(0) +KToolTipManager* KToolTipManager::instance() { -#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 (s_instance == 0) { + s_instance = new KToolTipManager(); } - if (haveArgbVisual) - label = new ArgbLabel(visual, depth); - else -#endif - label = new QWidgetLabel(); + return s_instance; } -KToolTipManager::~KToolTipManager() -{ - delete label; - delete currentItem; -} - -void KToolTipManager::showTip(const QPoint &pos, KToolTipItem *item) +void KToolTipManager::showTip(const QPoint& pos, QWidget* content) { hideTip(); - label->showTip(pos, item); - currentItem = item; - m_tooltipPos = pos; + Q_ASSERT(m_window == 0); + m_window = new KToolTipWindow(content); + m_window->move(pos); + m_window->show(); } 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; -} - -void KToolTipManager::update() -{ - if (currentItem == 0) - return; - label->showTip(m_tooltipPos, currentItem); -} - -KToolTipDelegate *KToolTipManager::delegate() const -{ - return m_delegate; + if (m_window != 0) { + m_window->hide(); + m_window->deleteLater(); + m_window = 0; + } } - - -// ---------------------------------------------------------------------------- - - - namespace KToolTip { - void showText(const QPoint &pos, const QString &text, QWidget *widget, const QRect &rect) + void showText(const QPoint& pos, const QString& text) { - Q_UNUSED(widget) - Q_UNUSED(rect) - KToolTipItem *item = new KToolTipItem(text); - KToolTipManager::instance()->showTip(pos, item); + QLabel* label = new QLabel(text); + label->setForegroundRole(QPalette::ToolTipText); + showTip(pos, label); } - void showText(const QPoint &pos, const QString &text, QWidget *widget) + void showTip(const QPoint& pos, QWidget* content) { - showText(pos, text, widget, QRect()); - } - - void showTip(const QPoint &pos, KToolTipItem *item) - { - KToolTipManager::instance()->showTip(pos, item); + KToolTipManager::instance()->showTip(pos, content); } void hideTip() { KToolTipManager::instance()->hideTip(); } - - void setToolTipDelegate(KToolTipDelegate *delegate) - { - KToolTipManager::instance()->setDelegate(delegate); - } }