make dictionary mouseover and make extra window larger to start
This commit is contained in:
parent
b61272a5e6
commit
2d2a3dedb9
@ -10,6 +10,7 @@
|
||||
#include <QMenu>
|
||||
#include <QPainter>
|
||||
#include <QGraphicsEffect>
|
||||
#include <QFontMetrics>
|
||||
#include <QMouseEvent>
|
||||
#include <QWheelEvent>
|
||||
|
||||
@ -155,7 +156,7 @@ public:
|
||||
PrettyWindow("Extra Window")
|
||||
{
|
||||
ui.display->setTextFormat(Qt::PlainText);
|
||||
setGeometry(settings.value(WINDOW, geometry()).toRect());
|
||||
if (settings.contains(WINDOW) && QGuiApplication::screenAt(settings.value(WINDOW).toRect().bottomRight())) setGeometry(settings.value(WINDOW).toRect());
|
||||
|
||||
for (auto [name, default, slot] : Array<const char*, bool, void(ExtraWindow::*)(bool)>{
|
||||
{ TOPMOST, false, &ExtraWindow::setTopmost },
|
||||
@ -171,6 +172,7 @@ public:
|
||||
action->setChecked(default);
|
||||
}
|
||||
ui.display->installEventFilter(this);
|
||||
ui.display->setMouseTracking(true);
|
||||
|
||||
QMetaObject::invokeMethod(this, [this]
|
||||
{
|
||||
@ -188,6 +190,7 @@ public:
|
||||
{
|
||||
if (!showOriginal) sentence = sentence.section('\n', sentence.count('\n') / 2 + 1);
|
||||
sanitize(sentence);
|
||||
sentence.chop(std::distance(std::remove(sentence.begin(), sentence.end(), QChar::Tabulation), sentence.end()));
|
||||
sentenceHistory.push_back(sentence);
|
||||
historyIndex = sentenceHistory.size() - 1;
|
||||
ui.display->setText(sentence);
|
||||
@ -226,14 +229,42 @@ private:
|
||||
settings.setValue(DICTIONARY, this->useDictionary = useDictionary);
|
||||
}
|
||||
|
||||
void computeDictionaryPosition(QPoint mouse)
|
||||
{
|
||||
if (cachedDisplayInfo.compareExchange(ui.display))
|
||||
{
|
||||
QString sentence = ui.display->text();
|
||||
QFontMetrics fontMetrics(ui.display->font(), ui.display);
|
||||
textPositionMap.clear();
|
||||
for (int i = 0, height = 0, lineBreak = 0; i < sentence.size(); ++i)
|
||||
{
|
||||
int block = 1;
|
||||
for (int charHeight = fontMetrics.boundingRect(0, 0, 1, INT_MAX, Qt::TextWordWrap, sentence.mid(i, 1)).height();
|
||||
i + block < sentence.size() && fontMetrics.boundingRect(0, 0, 1, INT_MAX, Qt::TextWordWrap, sentence.mid(i, block + 1)).height() < charHeight * 1.5; ++block);
|
||||
auto boundingRect = fontMetrics.boundingRect(0, 0, ui.display->width(), INT_MAX, Qt::TextWordWrap, sentence.left(i + block));
|
||||
if (boundingRect.height() > height)
|
||||
{
|
||||
height = boundingRect.height();
|
||||
lineBreak = i;
|
||||
}
|
||||
textPositionMap.push_back({
|
||||
fontMetrics.boundingRect(0, 0, ui.display->width(), INT_MAX, Qt::TextWordWrap, sentence.mid(lineBreak, i - lineBreak + 1)).width(),
|
||||
height
|
||||
});
|
||||
}
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < textPositionMap.size(); ++i) if (textPositionMap[i].y() > mouse.y() && textPositionMap[i].x() > mouse.x()) break;
|
||||
if (i == textPositionMap.size() || (mouse - textPositionMap[i]).manhattanLength() > ui.display->font().pointSize() * 2) return;
|
||||
if (ui.display->text().mid(i) == dictionaryWindow.term) return dictionaryWindow.ShowDefinition();
|
||||
dictionaryWindow.ui.display->setFixedWidth(ui.display->width() / 2);
|
||||
dictionaryWindow.setTerm(ui.display->text().mid(i));
|
||||
dictionaryWindow.move(ui.display->mapToGlobal(mouse + QPoint(2, 2)));
|
||||
}
|
||||
|
||||
bool eventFilter(QObject*, QEvent* event) override
|
||||
{
|
||||
if (useDictionary && event->type() == QEvent::MouseButtonRelease && ui.display->hasSelectedText())
|
||||
{
|
||||
dictionaryWindow.ui.display->setFixedWidth(ui.display->width());
|
||||
dictionaryWindow.setTerm(ui.display->text().mid(ui.display->selectionStart()));
|
||||
dictionaryWindow.move({ x(), y() - dictionaryWindow.height() });
|
||||
}
|
||||
if (useDictionary && event->type() == QEvent::MouseMove) computeDictionaryPosition(((QMouseEvent*)event)->localPos().toPoint());
|
||||
if (event->type() == QEvent::MouseButtonPress) dictionaryWindow.hide();
|
||||
return false;
|
||||
}
|
||||
@ -259,6 +290,26 @@ private:
|
||||
|
||||
bool locked, showOriginal, useDictionary;
|
||||
QPoint oldPos;
|
||||
|
||||
class
|
||||
{
|
||||
public:
|
||||
bool compareExchange(QLabel* display)
|
||||
{
|
||||
if (display->text() == text && display->font() == font && display->width() == width) return false;
|
||||
text = display->text();
|
||||
font = display->font();
|
||||
width = display->width();
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
QString text;
|
||||
QFont font;
|
||||
int width;
|
||||
} cachedDisplayInfo;
|
||||
std::vector<QPoint> textPositionMap;
|
||||
|
||||
std::vector<QString> sentenceHistory;
|
||||
int historyIndex = 0;
|
||||
|
||||
@ -312,11 +363,12 @@ private:
|
||||
|
||||
void setTerm(QString term)
|
||||
{
|
||||
this->term = term;
|
||||
UpdateDictionary();
|
||||
definitions.clear();
|
||||
definitionIndex = 0;
|
||||
std::unordered_set<std::string_view> definitionSet;
|
||||
for (QByteArray utf8term = term.left(200).toUtf8(); !utf8term.isEmpty(); utf8term.chop(1))
|
||||
for (QByteArray utf8term = term.left(500).toUtf8(); !utf8term.isEmpty(); utf8term.chop(1))
|
||||
for (auto [it, end] = std::equal_range(dictionary.begin(), dictionary.end(), DictionaryEntry{ utf8term }); it != end; ++it)
|
||||
if (definitionSet.emplace(it->definition).second)
|
||||
definitions.push_back(QStringLiteral("<h3>%1 (%3/%4)</h3>%2").arg(utf8term, it->definition));
|
||||
@ -326,7 +378,7 @@ private:
|
||||
|
||||
void ShowDefinition()
|
||||
{
|
||||
if (definitions.empty()) return;
|
||||
if (definitions.empty()) return hide();
|
||||
ui.display->setText(definitions[definitionIndex]);
|
||||
adjustSize();
|
||||
resize(width(), 1);
|
||||
@ -340,6 +392,7 @@ private:
|
||||
bool operator<(DictionaryEntry other) const { return strcmp(term, other.term) < 0; }
|
||||
};
|
||||
std::vector<DictionaryEntry> dictionary;
|
||||
QString term;
|
||||
|
||||
private:
|
||||
void wheelEvent(QWheelEvent* event) override
|
||||
@ -347,9 +400,7 @@ private:
|
||||
int scroll = event->angleDelta().y();
|
||||
if (scroll > 0 && definitionIndex > 0) definitionIndex -= 1;
|
||||
if (scroll < 0 && definitionIndex + 1 < definitions.size()) definitionIndex += 1;
|
||||
int oldHeight = height();
|
||||
ShowDefinition();
|
||||
move(x(), y() + oldHeight - height());
|
||||
}
|
||||
|
||||
std::filesystem::file_time_type dictionaryFileLastWrite;
|
||||
|
@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<width>800</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -27,6 +27,9 @@
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignTop</set>
|
||||
</property>
|
||||
|
3
text.cpp
3
text.cpp
@ -127,11 +127,10 @@ const char* DICTIONARY_INSTRUCTIONS = u8R"(This file is used only for the "Dicti
|
||||
It uses a custom format specific to Textractor and is not meant to be written manually.
|
||||
You should look for a dictionary in this format online (https://github.com/Artikash/Textractor-Dictionaries/releases is a good place to start).
|
||||
Alternatively, if you're a programmer, you can write a script to convert a dictionary from another format with the info below.
|
||||
Once you have a dictionary, to look up some text in Extra Window, select it. All matching definitions will be shown.
|
||||
Once you have a dictionary, to look up some text in Extra Window, hover over it. All matching definitions will be shown. Scroll to change definitions.
|
||||
Definitions are formatted like this:|TERM|Hola|TERM|hola|TERM|Bonjour|TERM|bonjour|DEFINITION|hello|END|
|
||||
The definition can include rich text (https://doc.qt.io/qt-5/richtext-html-subset.html) which will be formatted properly.
|
||||
All text in this file outside of a definition is ignored.
|
||||
Terms longer than 50 characters may not be shown (for performance reasons that should be fixed soon).
|
||||
This file must be encoded in UTF-8.)";
|
||||
const char* SHOW_ORIGINAL = u8"Original text";
|
||||
const char* SHOW_ORIGINAL_INFO = u8R"(Original text will not be shown
|
||||
|
Loading…
Reference in New Issue
Block a user