QxtGlobalShortcut/src/widgets/qxttooltip.cpp
Israel Lins Albuquerque 51ee678a81 MacOs: compilation faults
- replacing Q_WS_MAC => Q_OS_MAC
  - incomplete migration to Qt5
2014-02-14 15:09:25 -03:00

385 lines
11 KiB
C++

#include "qxttooltip.h"
/****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of the LibQxt project nor the
** names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/
#include "qxttooltip_p.h"
#include <QStyleOptionFrame>
#include <QDesktopWidget>
#include <QStylePainter>
#include <QApplication>
#include <QVBoxLayout>
#include <QMouseEvent>
#include <QKeyEvent>
#include <QToolTip>
#include <QPalette>
#include <QTimer>
#include <QFrame>
#include <QStyle>
#include <QHash>
static const Qt::WindowFlags FLAGS = Qt::ToolTip;
QxtToolTipPrivate* QxtToolTipPrivate::self = 0;
QxtToolTipPrivate* QxtToolTipPrivate::instance()
{
if (!self)
self = new QxtToolTipPrivate();
return self;
}
QxtToolTipPrivate::QxtToolTipPrivate() : QWidget(qApp->desktop(), FLAGS)
{
setWindowFlags(FLAGS);
vbox = new QVBoxLayout(this);
setPalette(QToolTip::palette());
setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, 0, this) / 255.0);
layout()->setMargin(style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth, 0, this));
qApp->installEventFilter(this);
}
QxtToolTipPrivate::~QxtToolTipPrivate()
{
qApp->removeEventFilter(this); // not really necessary but rather for completeness :)
self = 0;
}
void QxtToolTipPrivate::show(const QPoint& pos, QWidget* tooltip, QWidget* parent, const QRect& rect)
{
Q_ASSERT(tooltip && parent);
if (!isVisible())
{
int scr = 0;
if (QApplication::desktop()->isVirtualDesktop())
scr = QApplication::desktop()->screenNumber(pos);
else
scr = QApplication::desktop()->screenNumber(this);
setParent(QApplication::desktop()->screen(scr));
setWindowFlags(FLAGS);
setToolTip(tooltip);
currentParent = parent;
currentRect = rect;
move(calculatePos(scr, pos));
QWidget::show();
}
}
void QxtToolTipPrivate::setToolTip(QWidget* tooltip)
{
for (int i = 0; i < vbox->count(); ++i)
{
QLayoutItem* item = layout()->takeAt(i);
if (item->widget())
item->widget()->hide();
}
vbox->addWidget(tooltip);
tooltip->show();
}
void QxtToolTipPrivate::enterEvent(QEvent* event)
{
Q_UNUSED(event);
hideLater();
}
void QxtToolTipPrivate::paintEvent(QPaintEvent* event)
{
Q_UNUSED(event);
QStylePainter painter(this);
QStyleOptionFrame opt;
opt.initFrom(this);
painter.drawPrimitive(QStyle::PE_PanelTipLabel, opt);
}
bool QxtToolTipPrivate::eventFilter(QObject* object, QEvent* event)
{
switch (event->type())
{
case QEvent::KeyPress:
case QEvent::KeyRelease:
{
// accept only modifiers
const QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
const int key = keyEvent->key();
const Qt::KeyboardModifiers mods = keyEvent->modifiers();
if ((mods & Qt::KeyboardModifierMask) ||
(key == Qt::Key_Shift || key == Qt::Key_Control ||
key == Qt::Key_Alt || key == Qt::Key_Meta))
break;
}
case QEvent::Leave:
case QEvent::WindowActivate:
case QEvent::WindowDeactivate:
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
case QEvent::FocusIn:
case QEvent::FocusOut:
case QEvent::Wheel:
hideLater();
break;
case QEvent::MouseMove:
{
const QPoint pos = static_cast<QMouseEvent*>(event)->pos();
if (!currentRect.isNull() && !currentRect.contains(pos))
{
hideLater();
}
break;
}
case QEvent::ToolTip:
{
// eat appropriate tooltip events
QWidget* widget = static_cast<QWidget*>(object);
if (tooltips.contains(widget))
{
QHelpEvent* helpEvent = static_cast<QHelpEvent*>(event);
const QRect area = tooltips.value(widget).second;
if (area.isNull() || area.contains(helpEvent->pos()))
{
show(helpEvent->globalPos(), tooltips.value(widget).first, widget, area);
return true;
}
}
}
default:
break;
}
return false;
}
void QxtToolTipPrivate::hideLater()
{
currentRect = QRect();
if (isVisible())
QTimer::singleShot(0, this, SLOT(hide()));
}
QPoint QxtToolTipPrivate::calculatePos(int scr, const QPoint& eventPos) const
{
#ifdef Q_OS_MAC
QRect screen = QApplication::desktop()->availableGeometry(scr);
#else
QRect screen = QApplication::desktop()->screenGeometry(scr);
#endif
QPoint p = eventPos;
p += QPoint(2,
#ifdef Q_WS_WIN
24
#else
16
#endif
);
QSize s = sizeHint();
if (p.x() + s.width() > screen.x() + screen.width())
p.rx() -= 4 + s.width();
if (p.y() + s.height() > screen.y() + screen.height())
p.ry() -= 24 + s.height();
if (p.y() < screen.y())
p.setY(screen.y());
if (p.x() + s.width() > screen.x() + screen.width())
p.setX(screen.x() + screen.width() - s.width());
if (p.x() < screen.x())
p.setX(screen.x());
if (p.y() + s.height() > screen.y() + screen.height())
p.setY(screen.y() + screen.height() - s.height());
return p;
}
/*!
\class QxtToolTip
\inmodule QxtWidgets
\brief The QxtToolTip class provides means for showing any arbitrary widget as a tooltip.
QxtToolTip provides means for showing any arbitrary widget as a tooltip.
\bold {Note:} The rich text support of QToolTip already makes it possible to
show heavily customized tooltips with lists, tables, embedded images
and such. However, for example dynamically created images like
thumbnails cause problems. Basically the only way is to dump the
thumbnail to a temporary file to be able to embed it into HTML. This
is where QxtToolTip steps in. A generated thumbnail may simply be set
on a QLabel which is then shown as a tooltip. Yet another use case
is a tooltip with dynamically changing content.
\image qxttooltip.png "QxtToolTip in action."
\warning Added tooltip widgets remain in the memory for the lifetime
of the application or until they are removed/deleted. Do NOT flood your
application up with lots of complex tooltip widgets or it will end up
being a resource hog. QToolTip is sufficient for most of the cases!
*/
/*!
\internal
*/
QxtToolTip::QxtToolTip()
{
}
/*!
Shows the \a tooltip at \a pos for \a parent at \a rect.
\sa hide()
*/
void QxtToolTip::show(const QPoint& pos, QWidget* tooltip, QWidget* parent, const QRect& rect)
{
QxtToolTipPrivate::instance()->show(pos, tooltip, parent, rect);
}
/*!
Hides the tooltip.
\sa show()
*/
void QxtToolTip::hide()
{
QxtToolTipPrivate::instance()->hide();
}
/*!
Returns the tooltip for \a parent.
\sa setToolTip()
*/
QWidget* QxtToolTip::toolTip(QWidget* parent)
{
Q_ASSERT(parent);
QWidget* tooltip = 0;
if (!QxtToolTipPrivate::instance()->tooltips.contains(parent))
qWarning("QxtToolTip::toolTip: Unknown parent");
else
tooltip = QxtToolTipPrivate::instance()->tooltips.value(parent).first;
return tooltip;
}
/*!
Sets the \a tooltip to be shown for \a parent.
An optional \a rect may also be passed.
\sa toolTip()
*/
void QxtToolTip::setToolTip(QWidget* parent, QWidget* tooltip, const QRect& rect)
{
Q_ASSERT(parent);
if (tooltip)
{
// set
tooltip->hide();
QxtToolTipPrivate::instance()->tooltips[parent] = qMakePair(QPointer<QWidget>(tooltip), rect);
}
else
{
// remove
if (!QxtToolTipPrivate::instance()->tooltips.contains(parent))
qWarning("QxtToolTip::setToolTip: Unknown parent");
else
QxtToolTipPrivate::instance()->tooltips.remove(parent);
}
}
/*!
Returns the rect on which tooltip is shown for \a parent.
\sa setToolTipRect()
*/
QRect QxtToolTip::toolTipRect(QWidget* parent)
{
Q_ASSERT(parent);
QRect rect;
if (!QxtToolTipPrivate::instance()->tooltips.contains(parent))
qWarning("QxtToolTip::toolTipRect: Unknown parent");
else
rect = QxtToolTipPrivate::instance()->tooltips.value(parent).second;
return rect;
}
/*!
Sets the \a rect on which tooltip is shown for \a parent.
\sa toolTipRect()
*/
void QxtToolTip::setToolTipRect(QWidget* parent, const QRect& rect)
{
Q_ASSERT(parent);
if (!QxtToolTipPrivate::instance()->tooltips.contains(parent))
qWarning("QxtToolTip::setToolTipRect: Unknown parent");
else
QxtToolTipPrivate::instance()->tooltips[parent].second = rect;
}
/*!
Returns the margin of the tooltip.
\sa setMargin()
*/
int QxtToolTip::margin()
{
return QxtToolTipPrivate::instance()->layout()->margin();
}
/*!
Sets the \a margin of the tooltip.
The default value is QStyle::PM_ToolTipLabelFrameWidth.
\sa margin()
*/
void QxtToolTip::setMargin(int margin)
{
QxtToolTipPrivate::instance()->layout()->setMargin(margin);
}
/*!
Returns the opacity level of the tooltip.
\sa QWidget::windowOpacity()
*/
qreal QxtToolTip::opacity()
{
return QxtToolTipPrivate::instance()->windowOpacity();
}
/*!
Sets the opacity \a level of the tooltip.
The default value is QStyle::SH_ToolTipLabel_Opacity.
\sa QWidget::setWindowOpacity()
*/
void QxtToolTip::setOpacity(qreal level)
{
QxtToolTipPrivate::instance()->setWindowOpacity(level);
}