You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
282 lines
8.1 KiB
282 lines
8.1 KiB
/* |
|
Inspired by konq_filetip.cc |
|
|
|
SPDX-FileCopyrightText: 2003-2007 Craig Drummond <craig@kde.org> |
|
SPDX-FileCopyrightText: 1998, 1999 Torben Weis <weis@kde.org> |
|
SPDX-FileCopyrightText: 2000, 2001, 2002 David Faure <faure@kde.org> |
|
SPDX-FileCopyrightText: 2004 Martin Koller <m.koller@surfeu.at> |
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later |
|
*/ |
|
|
|
#include "CharTip.h" |
|
#include "FontPreview.h" |
|
#include "UnicodeCategories.h" |
|
#include <QApplication> |
|
#include <QBoxLayout> |
|
#include <QEvent> |
|
#include <QLabel> |
|
#include <QPixmap> |
|
#include <QResizeEvent> |
|
#include <QScreen> |
|
#include <QTimer> |
|
#include <QToolTip> |
|
|
|
namespace KFI |
|
{ |
|
EUnicodeCategory getCategory(quint32 ucs2) |
|
{ |
|
for (int i = 0; UNICODE_INVALID != constUnicodeCategoryList[i].category; ++i) { |
|
if (constUnicodeCategoryList[i].start <= ucs2 && constUnicodeCategoryList[i].end >= ucs2) { |
|
return constUnicodeCategoryList[i].category; |
|
} |
|
} |
|
|
|
return UNICODE_UNASSIGNED; |
|
} |
|
|
|
static QString toStr(EUnicodeCategory cat) |
|
{ |
|
switch (cat) { |
|
case UNICODE_CONTROL: |
|
return i18n("Other, Control"); |
|
case UNICODE_FORMAT: |
|
return i18n("Other, Format"); |
|
case UNICODE_UNASSIGNED: |
|
return i18n("Other, Not Assigned"); |
|
case UNICODE_PRIVATE_USE: |
|
return i18n("Other, Private Use"); |
|
case UNICODE_SURROGATE: |
|
return i18n("Other, Surrogate"); |
|
case UNICODE_LOWERCASE_LETTER: |
|
return i18n("Letter, Lowercase"); |
|
case UNICODE_MODIFIER_LETTER: |
|
return i18n("Letter, Modifier"); |
|
case UNICODE_OTHER_LETTER: |
|
return i18n("Letter, Other"); |
|
case UNICODE_TITLECASE_LETTER: |
|
return i18n("Letter, Titlecase"); |
|
case UNICODE_UPPERCASE_LETTER: |
|
return i18n("Letter, Uppercase"); |
|
case UNICODE_COMBINING_MARK: |
|
return i18n("Mark, Spacing Combining"); |
|
case UNICODE_ENCLOSING_MARK: |
|
return i18n("Mark, Enclosing"); |
|
case UNICODE_NON_SPACING_MARK: |
|
return i18n("Mark, Non-Spacing"); |
|
case UNICODE_DECIMAL_NUMBER: |
|
return i18n("Number, Decimal Digit"); |
|
case UNICODE_LETTER_NUMBER: |
|
return i18n("Number, Letter"); |
|
case UNICODE_OTHER_NUMBER: |
|
return i18n("Number, Other"); |
|
case UNICODE_CONNECT_PUNCTUATION: |
|
return i18n("Punctuation, Connector"); |
|
case UNICODE_DASH_PUNCTUATION: |
|
return i18n("Punctuation, Dash"); |
|
case UNICODE_CLOSE_PUNCTUATION: |
|
return i18n("Punctuation, Close"); |
|
case UNICODE_FINAL_PUNCTUATION: |
|
return i18n("Punctuation, Final Quote"); |
|
case UNICODE_INITIAL_PUNCTUATION: |
|
return i18n("Punctuation, Initial Quote"); |
|
case UNICODE_OTHER_PUNCTUATION: |
|
return i18n("Punctuation, Other"); |
|
case UNICODE_OPEN_PUNCTUATION: |
|
return i18n("Punctuation, Open"); |
|
case UNICODE_CURRENCY_SYMBOL: |
|
return i18n("Symbol, Currency"); |
|
case UNICODE_MODIFIER_SYMBOL: |
|
return i18n("Symbol, Modifier"); |
|
case UNICODE_MATH_SYMBOL: |
|
return i18n("Symbol, Math"); |
|
case UNICODE_OTHER_SYMBOL: |
|
return i18n("Symbol, Other"); |
|
case UNICODE_LINE_SEPARATOR: |
|
return i18n("Separator, Line"); |
|
case UNICODE_PARAGRAPH_SEPARATOR: |
|
return i18n("Separator, Paragraph"); |
|
case UNICODE_SPACE_SEPARATOR: |
|
return i18n("Separator, Space"); |
|
default: |
|
return ""; |
|
} |
|
} |
|
|
|
CCharTip::CCharTip(CFontPreview *parent) |
|
: QFrame(nullptr, Qt::ToolTip | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint) |
|
, m_parent(parent) |
|
{ |
|
m_pixmapLabel = new QLabel(this); |
|
m_label = new QLabel(this); |
|
m_timer = new QTimer(this); |
|
|
|
QBoxLayout *layout = new QBoxLayout(QBoxLayout::LeftToRight, this); |
|
layout->setContentsMargins(8, 8, 8, 8); |
|
layout->setSpacing(0); |
|
layout->addWidget(m_pixmapLabel); |
|
layout->addWidget(m_label); |
|
|
|
setPalette(QToolTip::palette()); |
|
setFrameShape(QFrame::Box); |
|
setFrameShadow(QFrame::Plain); |
|
hide(); |
|
} |
|
|
|
CCharTip::~CCharTip() |
|
{ |
|
} |
|
|
|
void CCharTip::setItem(const CFcEngine::TChar &ch) |
|
{ |
|
hideTip(); |
|
|
|
m_item = ch; |
|
m_timer->disconnect(this); |
|
connect(m_timer, &QTimer::timeout, this, &CCharTip::showTip); |
|
m_timer->setSingleShot(true); |
|
m_timer->start(300); |
|
} |
|
|
|
void CCharTip::showTip() |
|
{ |
|
if (!m_parent->underMouse()) { |
|
return; |
|
} |
|
|
|
static const int constPixSize = 96; |
|
|
|
EUnicodeCategory cat(getCategory(m_item.ucs4)); |
|
QString details("<table>"); |
|
|
|
details += "<tr><td align=\"right\"><b>" + i18n("Category") + " </b></td><td>" + toStr(cat) + "</td></tr>"; |
|
details += "<tr><td align=\"right\"><b>" + i18n("UCS-4") + " </b></td><td>" + "U+" + QStringLiteral("%1").arg(m_item.ucs4, 4, 16) + " </td></tr>"; |
|
|
|
QString str(QString::fromUcs4(&(m_item.ucs4), 1)); |
|
details += "<tr><td align=\"right\"><b>" + i18n("UTF-16") + " </b></td><td>"; |
|
|
|
const ushort *utf16(str.utf16()); |
|
|
|
for (int i = 0; utf16[i]; ++i) { |
|
if (i) { |
|
details += ' '; |
|
} |
|
details += QStringLiteral("0x%1").arg(utf16[i], 4, 16); |
|
} |
|
details += "</td></tr>"; |
|
details += "<tr><td align=\"right\"><b>" + i18n("UTF-8") + " </b></td><td>"; |
|
|
|
QByteArray utf8(str.toUtf8()); |
|
|
|
for (int i = 0; i < utf8.size(); ++i) { |
|
if (i) { |
|
details += ' '; |
|
} |
|
details += QStringLiteral("0x%1").arg((unsigned char)(utf8.constData()[i]), 2, 16); |
|
} |
|
details += "</td></tr>"; |
|
|
|
// Note: the "<b></b> below is just to stop Qt converting the xml entry into |
|
// a character! |
|
if ((0x0001 <= m_item.ucs4 && m_item.ucs4 <= 0xD7FF) || (0xE000 <= m_item.ucs4 && m_item.ucs4 <= 0xFFFD) |
|
|| (0x10000 <= m_item.ucs4 && m_item.ucs4 <= 0x10FFFF)) { |
|
details += |
|
"<tr><td align=\"right\"><b>" + i18n("XML Decimal Entity") + " </b></td><td>" + "&#<b></b>" + QString::number(m_item.ucs4) + ";</td></tr>"; |
|
} |
|
|
|
details += "</table>"; |
|
m_label->setText(details); |
|
|
|
QList<CFcEngine::TRange> range; |
|
range.append(CFcEngine::TRange(m_item.ucs4, 0)); |
|
|
|
QColor bgnd(Qt::white); |
|
bgnd.setAlpha(0); |
|
|
|
QImage img = m_parent->engine()->draw(m_parent->m_fontName, |
|
m_parent->m_styleInfo, |
|
m_parent->m_currentFace - 1, |
|
palette().text().color(), |
|
bgnd, |
|
constPixSize, |
|
constPixSize, |
|
false, |
|
range, |
|
nullptr); |
|
|
|
if (!img.isNull()) { |
|
m_pixmapLabel->setPixmap(QPixmap::fromImage(img)); |
|
} else { |
|
m_pixmapLabel->setPixmap(QPixmap()); |
|
} |
|
|
|
m_timer->disconnect(this); |
|
connect(m_timer, &QTimer::timeout, this, &CCharTip::hideTip); |
|
m_timer->setSingleShot(true); |
|
m_timer->start(15000); |
|
|
|
qApp->installEventFilter(this); |
|
reposition(); |
|
show(); |
|
} |
|
|
|
void CCharTip::hideTip() |
|
{ |
|
m_timer->stop(); |
|
qApp->removeEventFilter(this); |
|
hide(); |
|
} |
|
|
|
void CCharTip::reposition() |
|
{ |
|
QRect rect(m_item); |
|
|
|
rect.moveTopRight(m_parent->mapToGlobal(rect.topRight())); |
|
|
|
QPoint pos(rect.center()); |
|
QRect desk(QApplication::screenAt(rect.center())->geometry()); |
|
|
|
if ((rect.center().x() + width()) > desk.right()) { |
|
if (pos.x() - width() < 0) { |
|
pos.setX(0); |
|
} else { |
|
pos.setX(pos.x() - width()); |
|
} |
|
} |
|
// should the tooltip be shown above or below the ivi ? |
|
if (rect.bottom() + height() > desk.bottom()) { |
|
pos.setY(rect.top() - height()); |
|
} else { |
|
pos.setY(rect.bottom() + 1); |
|
} |
|
|
|
move(pos); |
|
update(); |
|
} |
|
|
|
void CCharTip::resizeEvent(QResizeEvent *event) |
|
{ |
|
QFrame::resizeEvent(event); |
|
reposition(); |
|
} |
|
|
|
bool CCharTip::eventFilter(QObject *, QEvent *e) |
|
{ |
|
switch (e->type()) { |
|
case QEvent::Leave: |
|
case QEvent::MouseButtonPress: |
|
case QEvent::MouseButtonRelease: |
|
case QEvent::KeyPress: |
|
case QEvent::KeyRelease: |
|
case QEvent::FocusIn: |
|
case QEvent::FocusOut: |
|
case QEvent::Wheel: |
|
hideTip(); |
|
default: |
|
break; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
}
|
|
|