1
#include "psitiplabel.h"
3
#include <QApplication>
4
#include <QAbstractTextDocumentLayout>
7
#include <QStyleOption>
8
#include <QStylePainter>
13
#include "psirichtext.h"
15
PsiTipLabel *PsiTipLabel::instance_ = 0;
17
PsiTipLabel* PsiTipLabel::instance()
22
PsiTipLabel::PsiTipLabel(QWidget* parent)
23
: QFrame(parent, Qt::ToolTip)
30
void PsiTipLabel::init(const QString& text)
35
qApp->installEventFilter(this);
37
setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, 0, this) / 255.0);
38
setPalette(QToolTip::palette());
41
void PsiTipLabel::setText(const QString& text)
46
if (Qt::mightBeRichText(theText_)) {
48
PsiRichText::install(doc);
49
PsiRichText::setText(doc, theText_);
52
doc->setPlainText(theText_);
57
void PsiTipLabel::initUi()
59
margin = 1 + style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth, 0, this);
60
setFrameStyle(QFrame::NoFrame);
62
// doc = new QTextDocument(this);
63
// QTextDocumentLayout is private in Qt4
64
// and it's impossible to set wrapping mode directly.
65
// So we create this QTextEdit instance and use its QTextDocument,
66
// just because QTextEdit can set the wrapping mode.
67
// Yes, this is crazy...
68
QTextEdit *edit = new QTextEdit(this);
70
edit->setWordWrapMode(QTextOption::WordWrap);
71
doc = edit->document();
72
doc->setUndoRedoEnabled(false);
73
doc->setDefaultFont(font());
79
void PsiTipLabel::startHideTimer()
81
hideTimer.start(10000, this);
84
QString PsiTipLabel::theText() const
89
QSize PsiTipLabel::sizeForWidth(int w) const
93
int hextra = 2 * margin;
101
PsiRichText::ensureTextLayouted(doc, w);
102
const qreal oldTextWidth = doc->textWidth();
105
br = QRect(QPoint(0, 0), doc->size().toSize());
106
doc->setTextWidth(oldTextWidth);
108
QFontMetrics fm(font());
109
QSize extra(hextra + 1, vextra);
111
// Make it look good with the default ToolTip font on Mac, which has a small descent.
112
if (fm.descent() == 2 && fm.ascent() >= 11)
115
const QSize contentsSize(br.width() + hextra, br.height() + vextra);
119
QSize PsiTipLabel::sizeHint() const
121
QTextFrameFormat fmt = doc->rootFrame()->frameFormat();
123
doc->rootFrame()->setFrameFormat(fmt);
124
// PsiRichText::ensureTextLayouted(doc, -1);
127
// br = QRect(QPoint(0, 0), doc->size().toSize());
128
// this way helps to fight empty space on the right:
129
QSize docSize = QSize(doc->idealWidth(), doc->size().toSize().height());
131
QFontMetrics fm(font());
132
QSize extra(2*margin + 2, 2*margin + 1); // "+" for tip's frame
133
// Make it look good with the default ToolTip font on Mac, which has a small descent.
134
if (fm.descent() == 2 && fm.ascent() >= 11)
137
return docSize + extra;
140
QSize PsiTipLabel::minimumSizeHint() const
143
// qWarning("PsiTipLabel::minimumSizeHint");
145
// QSize sh = sizeForWidth(-1);
146
// QSize msh(-1, -1);
148
// msh.rheight() = sizeForWidth(QWIDGETSIZE_MAX).height(); // height for one line
149
// msh.rwidth() = sizeForWidth(0).width(); // wrap ? size of biggest word : min doc size
150
// if (sh.height() < msh.height())
151
// msh.rheight() = sh.height();
156
void PsiTipLabel::paintEvent(QPaintEvent *)
158
QStylePainter p(this);
159
QStyleOptionFrame opt;
161
p.drawPrimitive(QStyle::PE_PanelTipLabel, opt);
164
// stolen from QLabel::paintEvent
165
QPainter painter(this);
167
QRect cr = contentsRect();
168
cr.adjust(margin, margin, -margin, -margin);
170
PsiRichText::ensureTextLayouted(doc, width() - 2*margin);
171
QAbstractTextDocumentLayout *layout = doc->documentLayout();
172
// QRect lr = rect();
175
QAbstractTextDocumentLayout::PaintContext context;
177
// Adjust the palette
178
context.palette = palette();
179
if (foregroundRole() != QPalette::Text && isEnabled())
180
context.palette.setColor(QPalette::Text, context.palette.color(foregroundRole()));
183
painter.translate(lr.x() + 1, lr.y() + 1);
184
painter.setClipRect(lr.translated(-lr.x() - 1, -lr.y() - 1));
185
layout->draw(&painter, context);
189
PsiTipLabel::~PsiTipLabel()
194
void PsiTipLabel::hideTip()
197
// timer based deletion to prevent animation
198
deleteTimer.start(250, this);
201
void PsiTipLabel::enterEvent(QEvent*)
206
void PsiTipLabel::timerEvent(QTimerEvent *e)
208
if (e->timerId() == hideTimer.timerId())
210
else if (e->timerId() == deleteTimer.timerId())
214
bool PsiTipLabel::eventFilter(QObject *, QEvent *e)
217
case QEvent::KeyPress:
218
case QEvent::KeyRelease: {
219
int key = static_cast<QKeyEvent *>(e)->key();
220
Qt::KeyboardModifiers mody = static_cast<QKeyEvent *>(e)->modifiers();
222
if ((mody & Qt::KeyboardModifierMask)
223
|| (key == Qt::Key_Shift || key == Qt::Key_Control
224
|| key == Qt::Key_Alt || key == Qt::Key_Meta))
228
case QEvent::WindowActivate:
229
case QEvent::WindowDeactivate:
230
case QEvent::MouseButtonPress:
231
case QEvent::MouseButtonRelease:
232
case QEvent::MouseButtonDblClick:
233
case QEvent::FocusIn:
234
case QEvent::FocusOut: