forked from Public-Mirror/Textractor
consolidate features and add context menu to edge
This commit is contained in:
parent
5df90e2c01
commit
45279d26dc
@ -17,20 +17,16 @@
|
|||||||
#include <QAbstractNativeEventFilter>
|
#include <QAbstractNativeEventFilter>
|
||||||
|
|
||||||
extern const char* EXTRA_WINDOW_INFO;
|
extern const char* EXTRA_WINDOW_INFO;
|
||||||
extern const char* SENTENCE_TOO_BIG;
|
|
||||||
extern const char* MAX_SENTENCE_SIZE;
|
|
||||||
extern const char* TOPMOST;
|
extern const char* TOPMOST;
|
||||||
extern const char* OPACITY;
|
extern const char* OPACITY;
|
||||||
extern const char* SHOW_ORIGINAL;
|
extern const char* SHOW_ORIGINAL;
|
||||||
extern const char* SHOW_ORIGINAL_INFO;
|
extern const char* ORIGINAL_AFTER_TRANSLATION;
|
||||||
extern const char* SHOW_ORIGINAL_AFTER_TRANSLATION;
|
|
||||||
extern const char* SIZE_LOCK;
|
extern const char* SIZE_LOCK;
|
||||||
extern const char* POSITION_LOCK;
|
extern const char* POSITION_LOCK;
|
||||||
extern const char* CENTERED_TEXT;
|
extern const char* CENTERED_TEXT;
|
||||||
extern const char* AUTO_RESIZE_WINDOW_HEIGHT;
|
extern const char* AUTO_RESIZE_WINDOW_HEIGHT;
|
||||||
extern const char* CLICK_THROUGH;
|
extern const char* CLICK_THROUGH;
|
||||||
extern const char* HIDE_TEXT_MOUSEOVER;
|
extern const char* HIDE_MOUSEOVER;
|
||||||
extern const char* HIDE_TEXT;
|
|
||||||
extern const char* DICTIONARY;
|
extern const char* DICTIONARY;
|
||||||
extern const char* DICTIONARY_INSTRUCTIONS;
|
extern const char* DICTIONARY_INSTRUCTIONS;
|
||||||
extern const char* BG_COLOR;
|
extern const char* BG_COLOR;
|
||||||
@ -38,15 +34,11 @@ extern const char* TEXT_COLOR;
|
|||||||
extern const char* TEXT_OUTLINE;
|
extern const char* TEXT_OUTLINE;
|
||||||
extern const char* OUTLINE_COLOR;
|
extern const char* OUTLINE_COLOR;
|
||||||
extern const char* OUTLINE_SIZE;
|
extern const char* OUTLINE_SIZE;
|
||||||
extern const char* OUTLINE_LAST_SIZE;
|
|
||||||
extern const char* OUTLINE_SIZE_INFO;
|
extern const char* OUTLINE_SIZE_INFO;
|
||||||
extern const char* FONT;
|
extern const char* FONT;
|
||||||
extern const char* SAVE_SETTINGS;
|
|
||||||
|
|
||||||
constexpr auto DICTIONARY_SAVE_FILE = u8"SavedDictionary.txt";
|
constexpr auto DICTIONARY_SAVE_FILE = u8"SavedDictionary.txt";
|
||||||
const qreal COLOR_ALFAF_HIDE_WINDOW = 0.05;
|
|
||||||
constexpr int CLICK_THROUGH_HOTKEY = 0xc0d0;
|
constexpr int CLICK_THROUGH_HOTKEY = 0xc0d0;
|
||||||
constexpr int HIDE_TEXT_HOTKEY = 0xc0d1;
|
|
||||||
|
|
||||||
QColor colorPrompt(QWidget* parent, QColor default, const QString& title, bool customOpacity = true)
|
QColor colorPrompt(QWidget* parent, QColor default, const QString& title, bool customOpacity = true)
|
||||||
{
|
{
|
||||||
@ -57,9 +49,6 @@ QColor colorPrompt(QWidget* parent, QColor default, const QString& title, bool c
|
|||||||
|
|
||||||
struct PrettyWindow : QDialog, Localizer
|
struct PrettyWindow : QDialog, Localizer
|
||||||
{
|
{
|
||||||
QString savedSentence = "";
|
|
||||||
bool hideTextMouseover=false, hideText=false;
|
|
||||||
|
|
||||||
PrettyWindow(const char* name)
|
PrettyWindow(const char* name)
|
||||||
{
|
{
|
||||||
ui.setupUi(this);
|
ui.setupUi(this);
|
||||||
@ -74,13 +63,19 @@ struct PrettyWindow : QDialog, Localizer
|
|||||||
SetTextColor(settings.value(TEXT_COLOR, TextColor()).value<QColor>());
|
SetTextColor(settings.value(TEXT_COLOR, TextColor()).value<QColor>());
|
||||||
outliner->color = settings.value(OUTLINE_COLOR, outliner->color).value<QColor>();
|
outliner->color = settings.value(OUTLINE_COLOR, outliner->color).value<QColor>();
|
||||||
outliner->size = settings.value(OUTLINE_SIZE, outliner->size).toDouble();
|
outliner->size = settings.value(OUTLINE_SIZE, outliner->size).toDouble();
|
||||||
|
autoHide = settings.value(HIDE_MOUSEOVER, autoHide).toBool();
|
||||||
menu.addAction(FONT, this, &PrettyWindow::RequestFont);
|
menu.addAction(FONT, this, &PrettyWindow::RequestFont);
|
||||||
menu.addAction(BG_COLOR, [this] { SetBackgroundColor(colorPrompt(this, backgroundColor, BG_COLOR)); });
|
menu.addAction(BG_COLOR, [this] { SetBackgroundColor(colorPrompt(this, backgroundColor, BG_COLOR)); });
|
||||||
menu.addAction(TEXT_COLOR, [this] { SetTextColor(colorPrompt(this, TextColor(), TEXT_COLOR)); });
|
menu.addAction(TEXT_COLOR, [this] { SetTextColor(colorPrompt(this, TextColor(), TEXT_COLOR)); });
|
||||||
QAction* outlineAction = menu.addAction(TEXT_OUTLINE, this, &PrettyWindow::SetOutline);
|
QAction* outlineAction = menu.addAction(TEXT_OUTLINE, this, &PrettyWindow::SetOutline);
|
||||||
outlineAction->setCheckable(true);
|
outlineAction->setCheckable(true);
|
||||||
outlineAction->setChecked(outliner->size >= 0);
|
outlineAction->setChecked(outliner->size >= 0);
|
||||||
connect(ui.display, &QLabel::customContextMenuRequested, [this](QPoint point) { menu.exec(mapToGlobal(point)); });
|
QAction* autoHideAction = menu.addAction(HIDE_MOUSEOVER, this, [this](bool autoHide) { settings.setValue(HIDE_MOUSEOVER, this->autoHide = autoHide); });
|
||||||
|
autoHideAction->setCheckable(true);
|
||||||
|
autoHideAction->setChecked(autoHide);
|
||||||
|
connect(this, &QDialog::customContextMenuRequested, [this](QPoint point) { menu.exec(mapToGlobal(point)); });
|
||||||
|
connect(ui.display, &QLabel::customContextMenuRequested, [this](QPoint point) { menu.exec(ui.display->mapToGlobal(point)); });
|
||||||
|
startTimer(50);
|
||||||
}
|
}
|
||||||
|
|
||||||
~PrettyWindow()
|
~PrettyWindow()
|
||||||
@ -90,30 +85,27 @@ struct PrettyWindow : QDialog, Localizer
|
|||||||
|
|
||||||
Ui::ExtraWindow ui;
|
Ui::ExtraWindow ui;
|
||||||
|
|
||||||
|
protected:
|
||||||
void SetBackgroundColorHideText()
|
void timerEvent(QTimerEvent*) override
|
||||||
{
|
{
|
||||||
if (hideText)
|
if (autoHide && !hidden && geometry().contains(QCursor::pos()))
|
||||||
{
|
{
|
||||||
QColor color = settings.value(BG_COLOR, backgroundColor).value<QColor>();
|
if (backgroundColor.alphaF() > 0.05) backgroundColor.setAlphaF(0.05);
|
||||||
if (!color.isValid()) return;
|
if (outliner->color.alphaF() > 0.05) outliner->color.setAlphaF(0.05);
|
||||||
color.setAlphaF(COLOR_ALFAF_HIDE_WINDOW);
|
QColor hiddenTextColor = TextColor();
|
||||||
backgroundColor = color;
|
if (hiddenTextColor.alphaF() > 0.05) hiddenTextColor.setAlphaF(0.05);
|
||||||
repaint();
|
ui.display->setPalette(QPalette(hiddenTextColor, {}, {}, {}, {}, {}, {}));
|
||||||
ui.display->setText("");
|
hidden = true;
|
||||||
}
|
}
|
||||||
else
|
else if (hidden)
|
||||||
{
|
{
|
||||||
QColor color = settings.value(BG_COLOR, backgroundColor).value<QColor>();
|
backgroundColor.setAlpha(settings.value(BG_COLOR).value<QColor>().alpha());
|
||||||
if (!color.isValid()) return;
|
outliner->color.setAlpha(settings.value(OUTLINE_COLOR).value<QColor>().alpha());
|
||||||
if (color.alpha() == 0) color.setAlpha(1);
|
ui.display->setPalette(QPalette(settings.value(TEXT_COLOR).value<QColor>(), {}, {}, {}, {}, {}, {}));
|
||||||
backgroundColor = color;
|
hidden = false;
|
||||||
repaint();
|
|
||||||
ui.display->setText(savedSentence);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
|
||||||
QMenu menu{ ui.display };
|
QMenu menu{ ui.display };
|
||||||
Settings settings{ this };
|
Settings settings{ this };
|
||||||
|
|
||||||
@ -157,13 +149,9 @@ private:
|
|||||||
{
|
{
|
||||||
QColor color = colorPrompt(this, outliner->color, OUTLINE_COLOR);
|
QColor color = colorPrompt(this, outliner->color, OUTLINE_COLOR);
|
||||||
if (color.isValid()) outliner->color = color;
|
if (color.isValid()) outliner->color = color;
|
||||||
outliner->size = QInputDialog::getDouble(this, OUTLINE_SIZE, OUTLINE_SIZE_INFO, settings.value(OUTLINE_LAST_SIZE, outliner->size).toDouble(), 0, INT_MAX, 2, nullptr, Qt::WindowCloseButtonHint);
|
outliner->size = QInputDialog::getDouble(this, OUTLINE_SIZE, OUTLINE_SIZE_INFO, -outliner->size, 0, INT_MAX, 2, nullptr, Qt::WindowCloseButtonHint);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
settings.setValue(OUTLINE_LAST_SIZE, outliner->size);
|
|
||||||
outliner->size = -1;
|
|
||||||
}
|
}
|
||||||
|
else outliner->size = -outliner->size;
|
||||||
settings.setValue(OUTLINE_COLOR, outliner->color.name(QColor::HexArgb));
|
settings.setValue(OUTLINE_COLOR, outliner->color.name(QColor::HexArgb));
|
||||||
settings.setValue(OUTLINE_SIZE, outliner->size);
|
settings.setValue(OUTLINE_SIZE, outliner->size);
|
||||||
}
|
}
|
||||||
@ -173,6 +161,7 @@ private:
|
|||||||
QPainter(this).fillRect(rect(), backgroundColor);
|
QPainter(this).fillRect(rect(), backgroundColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool autoHide = false, hidden = false;
|
||||||
QColor backgroundColor{ palette().window().color() };
|
QColor backgroundColor{ palette().window().color() };
|
||||||
struct Outliner : QGraphicsEffect
|
struct Outliner : QGraphicsEffect
|
||||||
{
|
{
|
||||||
@ -193,29 +182,8 @@ private:
|
|||||||
painter->drawPixmap(offset, pixmap);
|
painter->drawPixmap(offset, pixmap);
|
||||||
}
|
}
|
||||||
QColor color{ Qt::black };
|
QColor color{ Qt::black };
|
||||||
double size = -1;
|
double size = -0.5;
|
||||||
}* outliner;
|
}* outliner;
|
||||||
|
|
||||||
void enterEvent(QEvent* event)
|
|
||||||
{
|
|
||||||
if (hideTextMouseover)
|
|
||||||
{
|
|
||||||
hideText = true;
|
|
||||||
SetBackgroundColorHideText();
|
|
||||||
}
|
|
||||||
QWidget::enterEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void leaveEvent(QEvent* event)
|
|
||||||
{
|
|
||||||
if (hideTextMouseover)
|
|
||||||
{
|
|
||||||
hideText = false;
|
|
||||||
SetBackgroundColorHideText();
|
|
||||||
}
|
|
||||||
QWidget::leaveEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExtraWindow : public PrettyWindow, QAbstractNativeEventFilter
|
class ExtraWindow : public PrettyWindow, QAbstractNativeEventFilter
|
||||||
@ -225,18 +193,15 @@ public:
|
|||||||
{
|
{
|
||||||
ui.display->setTextFormat(Qt::PlainText);
|
ui.display->setTextFormat(Qt::PlainText);
|
||||||
if (settings.contains(WINDOW) && QApplication::screenAt(settings.value(WINDOW).toRect().bottomRight())) setGeometry(settings.value(WINDOW).toRect());
|
if (settings.contains(WINDOW) && QApplication::screenAt(settings.value(WINDOW).toRect().bottomRight())) setGeometry(settings.value(WINDOW).toRect());
|
||||||
maxSentenceSize = settings.value(MAX_SENTENCE_SIZE, maxSentenceSize).toInt();
|
|
||||||
|
|
||||||
for (auto [name, default, slot] : Array<const char*, bool, void(ExtraWindow::*)(bool)>{
|
for (auto [name, default, slot] : Array<const char*, bool, void(ExtraWindow::*)(bool)>{
|
||||||
{ TOPMOST, false, &ExtraWindow::SetTopmost },
|
{ TOPMOST, false, &ExtraWindow::SetTopmost },
|
||||||
{ SIZE_LOCK, false, &ExtraWindow::SetLock },
|
{ SIZE_LOCK, false, &ExtraWindow::SetSizeLock },
|
||||||
{ POSITION_LOCK, false, &ExtraWindow::SetPositionLock },
|
{ POSITION_LOCK, false, &ExtraWindow::SetPositionLock },
|
||||||
{ CENTERED_TEXT, false, &ExtraWindow::SetCenteredText },
|
{ CENTERED_TEXT, false, &ExtraWindow::SetCenteredText },
|
||||||
{ AUTO_RESIZE_WINDOW_HEIGHT, false, &ExtraWindow::SetAutoResizeHeight },
|
{ AUTO_RESIZE_WINDOW_HEIGHT, false, &ExtraWindow::SetAutoResize },
|
||||||
{ HIDE_TEXT, false, &ExtraWindow::SetHideText },
|
|
||||||
{ HIDE_TEXT_MOUSEOVER, false, &ExtraWindow::SetHideTextMouseover },
|
|
||||||
{ SHOW_ORIGINAL, true, &ExtraWindow::SetShowOriginal },
|
{ SHOW_ORIGINAL, true, &ExtraWindow::SetShowOriginal },
|
||||||
{ SHOW_ORIGINAL_AFTER_TRANSLATION, true, &ExtraWindow::SetShowOriginalAfterTranslation },
|
{ ORIGINAL_AFTER_TRANSLATION, true, &ExtraWindow::SetShowOriginalAfterTranslation },
|
||||||
{ DICTIONARY, false, &ExtraWindow::SetUseDictionary },
|
{ DICTIONARY, false, &ExtraWindow::SetUseDictionary },
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
@ -245,26 +210,16 @@ public:
|
|||||||
auto action = menu.addAction(name, this, slot);
|
auto action = menu.addAction(name, this, slot);
|
||||||
action->setCheckable(true);
|
action->setCheckable(true);
|
||||||
action->setChecked(default);
|
action->setChecked(default);
|
||||||
if (slot == &ExtraWindow::SetHideTextMouseover)
|
|
||||||
hideTextMouseoveAction = action;
|
|
||||||
if (slot == &ExtraWindow::SetHideText)
|
|
||||||
hideTextAction = action;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.addAction(CLICK_THROUGH, this, &ExtraWindow::ToggleClickThrough);
|
menu.addAction(CLICK_THROUGH, this, &ExtraWindow::ToggleClickThrough);
|
||||||
|
|
||||||
menu.addAction(MAX_SENTENCE_SIZE, this, [this]
|
|
||||||
{
|
|
||||||
settings.setValue(MAX_SENTENCE_SIZE, maxSentenceSize = QInputDialog::getInt(this, MAX_SENTENCE_SIZE, "", maxSentenceSize, 0, INT_MAX, 1, nullptr, Qt::WindowCloseButtonHint));
|
|
||||||
});
|
|
||||||
ui.display->installEventFilter(this);
|
ui.display->installEventFilter(this);
|
||||||
ui.display->setMouseTracking(true);
|
|
||||||
qApp->installNativeEventFilter(this);
|
qApp->installNativeEventFilter(this);
|
||||||
|
|
||||||
QMetaObject::invokeMethod(this, [this]
|
QMetaObject::invokeMethod(this, [this]
|
||||||
{
|
{
|
||||||
RegisterHotKey((HWND)winId(), HIDE_TEXT_HOTKEY, MOD_ALT | MOD_SHIFT | MOD_NOREPEAT, 0x48);
|
RegisterHotKey((HWND)winId(), CLICK_THROUGH_HOTKEY, MOD_SHIFT | MOD_NOREPEAT, 0x58);
|
||||||
RegisterHotKey((HWND)winId(), CLICK_THROUGH_HOTKEY, MOD_ALT | MOD_SHIFT | MOD_NOREPEAT, 0x54);
|
|
||||||
show();
|
show();
|
||||||
AddSentence(EXTRA_WINDOW_INFO);
|
AddSentence(EXTRA_WINDOW_INFO);
|
||||||
}, Qt::QueuedConnection);
|
}, Qt::QueuedConnection);
|
||||||
@ -277,23 +232,49 @@ public:
|
|||||||
|
|
||||||
void AddSentence(QString sentence)
|
void AddSentence(QString sentence)
|
||||||
{
|
{
|
||||||
if (sentence.size() > maxSentenceSize) sentence = SENTENCE_TOO_BIG;
|
|
||||||
if (showOriginal){
|
|
||||||
if (showOriginalAfterTranslation && sentence.contains(u8"\x200b \n"))
|
|
||||||
sentence = sentence.split(u8"\x200b \n")[1] + "\n" + sentence.split(u8"\x200b \n")[0];
|
|
||||||
} else
|
|
||||||
if (sentence.contains(u8"\x200b \n")) sentence = sentence.split(u8"\x200b \n")[1];
|
|
||||||
sanitize(sentence);
|
sanitize(sentence);
|
||||||
sentence.chop(std::distance(std::remove(sentence.begin(), sentence.end(), QChar::Tabulation), sentence.end()));
|
sentence.chop(std::distance(std::remove(sentence.begin(), sentence.end(), QChar::Tabulation), sentence.end()));
|
||||||
sentenceHistory.push_back(sentence);
|
sentenceHistory.push_back(sentence);
|
||||||
if (sentenceHistory.size() > maxHistoryIndex) sentenceHistory.erase(sentenceHistory.begin());
|
if (sentenceHistory.size() > 1000) sentenceHistory.erase(sentenceHistory.begin());
|
||||||
historyIndex = sentenceHistory.size() - 1;
|
historyIndex = sentenceHistory.size() - 1;
|
||||||
savedSentence = sentence;
|
DisplaySentence();
|
||||||
if (!hideText) ui.display->setText(sentence);
|
|
||||||
AutoResize(sentence);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void DisplaySentence()
|
||||||
|
{
|
||||||
|
QString sentence = sentenceHistory[historyIndex];
|
||||||
|
if (sentence.contains(u8"\x200b \n"))
|
||||||
|
if (!showOriginal) sentence = sentence.split(u8"\x200b \n")[1];
|
||||||
|
else if (showOriginalAfterTranslation) sentence = sentence.split(u8"\x200b \n")[1] + "\n" + sentence.split(u8"\x200b \n")[0];
|
||||||
|
|
||||||
|
if (autoResize)
|
||||||
|
{
|
||||||
|
ui.display->resize(
|
||||||
|
ui.display->width(),
|
||||||
|
QFontMetrics(ui.display->font(), ui.display).boundingRect(0, 0, ui.display->width(), INT_MAX, Qt::TextWordWrap, sentence).height()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (locked)
|
||||||
|
{
|
||||||
|
QFontMetrics fontMetrics(ui.display->font(), ui.display);
|
||||||
|
int low = 0, high = sentence.size(), last = 0;
|
||||||
|
while (low < high)
|
||||||
|
{
|
||||||
|
int mid = (low + high) / 2;
|
||||||
|
if (fontMetrics.boundingRect(0, 0, ui.display->width(), INT_MAX, Qt::TextWordWrap, sentence.left(mid)).height() < ui.display->height())
|
||||||
|
{
|
||||||
|
last = mid;
|
||||||
|
low = mid + 1;
|
||||||
|
}
|
||||||
|
else high = mid;
|
||||||
|
}
|
||||||
|
sentence = sentence.left(last);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.display->setText(sentence);
|
||||||
|
}
|
||||||
|
|
||||||
void SetTopmost(bool topmost)
|
void SetTopmost(bool topmost)
|
||||||
{
|
{
|
||||||
for (auto window : { winId(), dictionaryWindow.winId() })
|
for (auto window : { winId(), dictionaryWindow.winId() })
|
||||||
@ -306,97 +287,34 @@ private:
|
|||||||
settings.setValue(POSITION_LOCK, this->locked = locked);
|
settings.setValue(POSITION_LOCK, this->locked = locked);
|
||||||
};
|
};
|
||||||
|
|
||||||
void SetLock(bool locked)
|
void SetSizeLock(bool locked)
|
||||||
{
|
{
|
||||||
setSizeGripEnabled(!locked);
|
setSizeGripEnabled(!locked);
|
||||||
settings.setValue(SIZE_LOCK, locked);
|
settings.setValue(SIZE_LOCK, locked);
|
||||||
};
|
};
|
||||||
|
|
||||||
void SetCenteredText(bool centeredCenter)
|
void SetCenteredText(bool centeredText)
|
||||||
{
|
{
|
||||||
if (centeredCenter)
|
ui.display->setAlignment(centeredText ? Qt::AlignHCenter : Qt::AlignLeft);
|
||||||
ui.display->setAlignment(Qt::AlignCenter);
|
settings.setValue(CENTERED_TEXT, this->centeredText = centeredText);
|
||||||
else
|
|
||||||
ui.display->setAlignment(Qt::AlignLeft);
|
|
||||||
|
|
||||||
settings.setValue(CENTERED_TEXT, this->centeredCenter = centeredCenter);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void SetAutoResizeHeight(bool autoResizeHeight)
|
void SetAutoResize(bool autoResize)
|
||||||
{
|
{
|
||||||
settings.setValue(AUTO_RESIZE_WINDOW_HEIGHT, this->autoResizeHeight = autoResizeHeight);
|
settings.setValue(AUTO_RESIZE_WINDOW_HEIGHT, this->autoResize = autoResize);
|
||||||
if (autoResizeHeight) AutoResize(savedSentence);
|
DisplaySentence();
|
||||||
};
|
|
||||||
|
|
||||||
void AutoResize(QString sentence)
|
|
||||||
{
|
|
||||||
if (!autoResizeHeight) return;
|
|
||||||
|
|
||||||
QFontMetrics fontMetrics(ui.display->font(), ui.display);
|
|
||||||
auto boundingRect = fontMetrics.boundingRect(0, 0, width()-20, INT_MAX, Qt::TextWordWrap, sentence);
|
|
||||||
int newHeight = boundingRect.height() + 30;
|
|
||||||
int currHeight = height();
|
|
||||||
|
|
||||||
if (newHeight != currHeight) {
|
|
||||||
QSize s = size();
|
|
||||||
s.setWidth(width());
|
|
||||||
s.setHeight(newHeight);
|
|
||||||
resize(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToggleClickThrough()
|
|
||||||
{
|
|
||||||
if (clickThrough = !clickThrough)
|
|
||||||
{
|
|
||||||
setAttribute(Qt::WA_TransparentForMouseEvents, true);
|
|
||||||
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
|
|
||||||
} else {
|
|
||||||
setAttribute(Qt::WA_TransparentForMouseEvents , false);
|
|
||||||
//setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint); // doesn't work
|
|
||||||
setWindowFlags(Qt::FramelessWindowHint);
|
|
||||||
SetTopmost(settings.value(TOPMOST, false).toBool());
|
|
||||||
}
|
|
||||||
show();
|
|
||||||
};
|
|
||||||
|
|
||||||
void SetHideTextMouseover(bool hideTextMouseover)
|
|
||||||
{
|
|
||||||
this->hideTextMouseover = hideTextMouseover;
|
|
||||||
if (hideTextMouseover && this->hideText)
|
|
||||||
{
|
|
||||||
this->hideText = false;
|
|
||||||
hideTextAction->setChecked(false);
|
|
||||||
SetBackgroundColorHideText();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void SetHideText(bool hideText)
|
|
||||||
{
|
|
||||||
this->hideText = hideText;
|
|
||||||
if (this->hideTextMouseover)
|
|
||||||
{
|
|
||||||
this->hideTextMouseover = false;
|
|
||||||
hideTextMouseoveAction->setChecked(false);
|
|
||||||
}
|
|
||||||
SetBackgroundColorHideText();
|
|
||||||
};
|
|
||||||
|
|
||||||
void ToggleHideText()
|
|
||||||
{
|
|
||||||
hideTextAction->setChecked(!hideText);
|
|
||||||
SetHideText(!hideText);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void SetShowOriginal(bool showOriginal)
|
void SetShowOriginal(bool showOriginal)
|
||||||
{
|
{
|
||||||
if (!showOriginal && settings.value(SHOW_ORIGINAL, false).toBool()) QMessageBox::information(this, SHOW_ORIGINAL, SHOW_ORIGINAL_INFO);
|
|
||||||
settings.setValue(SHOW_ORIGINAL, this->showOriginal = showOriginal);
|
settings.setValue(SHOW_ORIGINAL, this->showOriginal = showOriginal);
|
||||||
|
DisplaySentence();
|
||||||
};
|
};
|
||||||
|
|
||||||
void SetShowOriginalAfterTranslation(bool showOriginalAfterTranslation)
|
void SetShowOriginalAfterTranslation(bool showOriginalAfterTranslation)
|
||||||
{
|
{
|
||||||
settings.setValue(SHOW_ORIGINAL_AFTER_TRANSLATION, this->showOriginalAfterTranslation = showOriginalAfterTranslation);
|
settings.setValue(ORIGINAL_AFTER_TRANSLATION, this->showOriginalAfterTranslation = showOriginalAfterTranslation);
|
||||||
|
DisplaySentence();
|
||||||
};
|
};
|
||||||
|
|
||||||
void SetUseDictionary(bool useDictionary)
|
void SetUseDictionary(bool useDictionary)
|
||||||
@ -413,27 +331,40 @@ private:
|
|||||||
settings.setValue(DICTIONARY, this->useDictionary = useDictionary);
|
settings.setValue(DICTIONARY, this->useDictionary = useDictionary);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComputeDictionaryPosition(QPoint mouse)
|
void ToggleClickThrough()
|
||||||
|
{
|
||||||
|
clickThrough = !clickThrough;
|
||||||
|
for (auto window : { winId(), dictionaryWindow.winId() })
|
||||||
|
{
|
||||||
|
unsigned exStyle = GetWindowLongPtrW((HWND)window, GWL_EXSTYLE);
|
||||||
|
if (clickThrough) exStyle |= WS_EX_TRANSPARENT;
|
||||||
|
else exStyle &= ~WS_EX_TRANSPARENT;
|
||||||
|
SetWindowLongPtrW((HWND)window, GWL_EXSTYLE, exStyle);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void ShowDictionary(QPoint mouse)
|
||||||
{
|
{
|
||||||
QString sentence = ui.display->text();
|
QString sentence = ui.display->text();
|
||||||
const QFont& font = ui.display->font();
|
const QFont& font = ui.display->font();
|
||||||
if (cachedDisplayInfo.CompareExchange(ui.display))
|
if (cachedDisplayInfo.CompareExchange(ui.display))
|
||||||
{
|
{
|
||||||
QFontMetrics fontMetrics(font, ui.display);
|
QFontMetrics fontMetrics(font, ui.display);
|
||||||
|
int flags = Qt::TextWordWrap | (ui.display->alignment() & (Qt::AlignLeft | Qt::AlignHCenter));
|
||||||
textPositionMap.clear();
|
textPositionMap.clear();
|
||||||
for (int i = 0, height = 0, lineBreak = 0; i < sentence.size(); ++i)
|
for (int i = 0, height = 0, lineBreak = 0; i < sentence.size(); ++i)
|
||||||
{
|
{
|
||||||
int block = 1;
|
int block = 1;
|
||||||
for (int charHeight = fontMetrics.boundingRect(0, 0, 1, INT_MAX, Qt::TextWordWrap, sentence.mid(i, 1)).height();
|
for (int charHeight = fontMetrics.boundingRect(0, 0, 1, INT_MAX, flags, 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);
|
i + block < sentence.size() && fontMetrics.boundingRect(0, 0, 1, INT_MAX, flags, 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));
|
auto boundingRect = fontMetrics.boundingRect(0, 0, ui.display->width(), INT_MAX, flags, sentence.left(i + block));
|
||||||
if (boundingRect.height() > height)
|
if (boundingRect.height() > height)
|
||||||
{
|
{
|
||||||
height = boundingRect.height();
|
height = boundingRect.height();
|
||||||
lineBreak = i;
|
lineBreak = i;
|
||||||
}
|
}
|
||||||
textPositionMap.push_back({
|
textPositionMap.push_back({
|
||||||
fontMetrics.boundingRect(0, 0, ui.display->width(), INT_MAX, Qt::TextWordWrap, sentence.mid(lineBreak, i - lineBreak + 1)).width(),
|
fontMetrics.boundingRect(0, 0, ui.display->width(), INT_MAX, flags, sentence.mid(lineBreak, i - lineBreak + 1)).right() + 1,
|
||||||
height
|
height
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -454,31 +385,23 @@ private:
|
|||||||
{
|
{
|
||||||
auto msg = (MSG*)message;
|
auto msg = (MSG*)message;
|
||||||
if (msg->message == WM_HOTKEY)
|
if (msg->message == WM_HOTKEY)
|
||||||
{
|
if (msg->wParam == CLICK_THROUGH_HOTKEY) return ToggleClickThrough(), true;
|
||||||
switch (msg->wParam)
|
|
||||||
{
|
|
||||||
case HIDE_TEXT_HOTKEY:
|
|
||||||
{
|
|
||||||
ToggleHideText();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case CLICK_THROUGH_HOTKEY:
|
|
||||||
{
|
|
||||||
ToggleClickThrough();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool eventFilter(QObject*, QEvent* event) override
|
bool eventFilter(QObject*, QEvent* event) override
|
||||||
{
|
{
|
||||||
if (useDictionary && event->type() == QEvent::MouseMove) ComputeDictionaryPosition(((QMouseEvent*)event)->localPos().toPoint());
|
if (event->type() == QEvent::MouseButtonPress) mousePressEvent((QMouseEvent*)event);
|
||||||
if (event->type() == QEvent::MouseButtonPress) dictionaryWindow.hide();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void timerEvent(QTimerEvent* event) override
|
||||||
|
{
|
||||||
|
if (useDictionary && QCursor::pos() != oldPos && (!dictionaryWindow.isVisible() || !dictionaryWindow.geometry().contains(QCursor::pos())))
|
||||||
|
ShowDictionary(ui.display->mapFromGlobal(QCursor::pos()));
|
||||||
|
PrettyWindow::timerEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
void mousePressEvent(QMouseEvent* event) override
|
void mousePressEvent(QMouseEvent* event) override
|
||||||
{
|
{
|
||||||
dictionaryWindow.hide();
|
dictionaryWindow.hide();
|
||||||
@ -494,14 +417,12 @@ private:
|
|||||||
void wheelEvent(QWheelEvent* event) override
|
void wheelEvent(QWheelEvent* event) override
|
||||||
{
|
{
|
||||||
int scroll = event->angleDelta().y();
|
int scroll = event->angleDelta().y();
|
||||||
if (scroll > 0 && historyIndex > 0) ui.display->setText(sentenceHistory[--historyIndex]);
|
if (scroll > 0 && historyIndex > 0) --historyIndex;
|
||||||
if (scroll < 0 && historyIndex + 1 < sentenceHistory.size()) ui.display->setText(sentenceHistory[++historyIndex]);
|
if (scroll < 0 && historyIndex + 1 < sentenceHistory.size()) ++historyIndex;
|
||||||
AutoResize(sentenceHistory[historyIndex]);
|
DisplaySentence();
|
||||||
}
|
}
|
||||||
|
|
||||||
QAction *hideTextMouseoveAction, *hideTextAction;
|
bool locked, centeredText, autoResize, showOriginal, showOriginalAfterTranslation, useDictionary, clickThrough;
|
||||||
bool locked, centeredCenter, autoResizeHeight, showOriginal, showOriginalAfterTranslation, useDictionary, clickThrough;
|
|
||||||
int maxSentenceSize = 1000;
|
|
||||||
QPoint oldPos;
|
QPoint oldPos;
|
||||||
|
|
||||||
class
|
class
|
||||||
@ -509,10 +430,11 @@ private:
|
|||||||
public:
|
public:
|
||||||
bool CompareExchange(QLabel* display)
|
bool CompareExchange(QLabel* display)
|
||||||
{
|
{
|
||||||
if (display->text() == text && display->font() == font && display->width() == width) return false;
|
if (display->text() == text && display->font() == font && display->width() == width && display->alignment() == alignment) return false;
|
||||||
text = display->text();
|
text = display->text();
|
||||||
font = display->font();
|
font = display->font();
|
||||||
width = display->width();
|
width = display->width();
|
||||||
|
alignment = display->alignment();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -520,12 +442,12 @@ private:
|
|||||||
QString text;
|
QString text;
|
||||||
QFont font;
|
QFont font;
|
||||||
int width;
|
int width;
|
||||||
|
Qt::Alignment alignment;
|
||||||
} cachedDisplayInfo;
|
} cachedDisplayInfo;
|
||||||
std::vector<QPoint> textPositionMap;
|
std::vector<QPoint> textPositionMap;
|
||||||
|
|
||||||
std::vector<QString> sentenceHistory;
|
std::vector<QString> sentenceHistory;
|
||||||
int historyIndex = 0;
|
int historyIndex = 0;
|
||||||
const int maxHistoryIndex = 20;
|
|
||||||
|
|
||||||
class DictionaryWindow : public PrettyWindow
|
class DictionaryWindow : public PrettyWindow
|
||||||
{
|
{
|
||||||
|
@ -10,6 +10,9 @@
|
|||||||
<height>300</height>
|
<height>300</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="contextMenuPolicy">
|
||||||
|
<enum>Qt::CustomContextMenu</enum>
|
||||||
|
</property>
|
||||||
<layout class="QHBoxLayout">
|
<layout class="QHBoxLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="display">
|
<widget class="QLabel" name="display">
|
||||||
|
19
text.cpp
19
text.cpp
@ -156,7 +156,6 @@ const char* AUTO_START = u8"Start automatically";
|
|||||||
const wchar_t* ERROR_START_CHROME = L"failed to start Chrome or to connect to it";
|
const wchar_t* ERROR_START_CHROME = L"failed to start Chrome or to connect to it";
|
||||||
const char* EXTRA_WINDOW_INFO = u8R"(Right click to change settings
|
const char* EXTRA_WINDOW_INFO = u8R"(Right click to change settings
|
||||||
Click and drag on window edges to move, or the bottom right corner to resize)";
|
Click and drag on window edges to move, or the bottom right corner to resize)";
|
||||||
const char* SENTENCE_TOO_BIG = u8"Sentence too large to display";
|
|
||||||
const char* MAX_SENTENCE_SIZE = u8"Max sentence size";
|
const char* MAX_SENTENCE_SIZE = u8"Max sentence size";
|
||||||
const char* TOPMOST = u8"Always on top";
|
const char* TOPMOST = u8"Always on top";
|
||||||
const char* DICTIONARY = u8"Dictionary";
|
const char* DICTIONARY = u8"Dictionary";
|
||||||
@ -178,21 +177,19 @@ This file must be encoded in UTF-8.)";
|
|||||||
const char* SHOW_ORIGINAL = u8"Original text";
|
const char* SHOW_ORIGINAL = u8"Original text";
|
||||||
const char* SHOW_ORIGINAL_INFO = u8R"(Original text will not be shown
|
const char* SHOW_ORIGINAL_INFO = u8R"(Original text will not be shown
|
||||||
Only works if this extension is used directly after a translation extension)";
|
Only works if this extension is used directly after a translation extension)";
|
||||||
const char* SHOW_ORIGINAL_AFTER_TRANSLATION = u8"Show original text after translation";
|
const char* ORIGINAL_AFTER_TRANSLATION = u8"Original text after translation";
|
||||||
const char* SIZE_LOCK = u8"Size lock";
|
const char* SIZE_LOCK = u8"Size lock";
|
||||||
const char* POSITION_LOCK = u8"Position lock";
|
const char* POSITION_LOCK = u8"Position lock";
|
||||||
const char* CENTERED_TEXT = u8"Centered text";
|
const char* CENTERED_TEXT = u8"Centered text";
|
||||||
const char* AUTO_RESIZE_WINDOW_HEIGHT = u8"Auto resize window height";
|
const char* AUTO_RESIZE_WINDOW_HEIGHT = u8"Auto resize window height";
|
||||||
const char* CLICK_THROUGH = u8"Click through\tAlt+Shift+T";
|
const char* CLICK_THROUGH = u8"Click through\tShift+X";
|
||||||
const char* HIDE_TEXT_MOUSEOVER = u8"Hide text mouseover";
|
const char* HIDE_MOUSEOVER = u8"Hide while mouse on top";
|
||||||
const char* HIDE_TEXT = u8"Hide text\tAlt+Shift+H";
|
|
||||||
const char* OPACITY = u8"Opacity";
|
const char* OPACITY = u8"Opacity";
|
||||||
const char* BG_COLOR = u8"Background color";
|
const char* BG_COLOR = u8"Background color";
|
||||||
const char* TEXT_COLOR = u8"Text color";
|
const char* TEXT_COLOR = u8"Text color";
|
||||||
const char* TEXT_OUTLINE = u8"Text outline";
|
const char* TEXT_OUTLINE = u8"Text outline";
|
||||||
const char* OUTLINE_COLOR = u8"Outline color";
|
const char* OUTLINE_COLOR = u8"Outline color";
|
||||||
const char* OUTLINE_SIZE = u8"Outline size";
|
const char* OUTLINE_SIZE = u8"Outline size";
|
||||||
const char* OUTLINE_LAST_SIZE = u8"Last used outline size";
|
|
||||||
const char* OUTLINE_SIZE_INFO = u8"Size in pixels (recommended to stay below 20% of the font size)";
|
const char* OUTLINE_SIZE_INFO = u8"Size in pixels (recommended to stay below 20% of the font size)";
|
||||||
const char* FONT = u8"Font";
|
const char* FONT = u8"Font";
|
||||||
const char* LUA_INTRO = u8R"(--[[
|
const char* LUA_INTRO = u8R"(--[[
|
||||||
@ -434,7 +431,6 @@ Clic y arrastra los bordes de la ventana para moverla, o en la esquina inferior
|
|||||||
API_KEY = u8"API key";
|
API_KEY = u8"API key";
|
||||||
EXTRA_WINDOW_INFO = u8R"(右键修改设置
|
EXTRA_WINDOW_INFO = u8R"(右键修改设置
|
||||||
在窗口边缘点击并拖拽来移动,或在右下角点击并拖拽来调整大小)";
|
在窗口边缘点击并拖拽来移动,或在右下角点击并拖拽来调整大小)";
|
||||||
SENTENCE_TOO_BIG = u8"文本过长无法显示";
|
|
||||||
MAX_SENTENCE_SIZE = u8"最大文本长度";
|
MAX_SENTENCE_SIZE = u8"最大文本长度";
|
||||||
TOPMOST = u8"窗口总是置顶";
|
TOPMOST = u8"窗口总是置顶";
|
||||||
DICTIONARY = u8"字典";
|
DICTIONARY = u8"字典";
|
||||||
@ -609,7 +605,6 @@ padding: длина добавочных данных перед строкой
|
|||||||
API_KEY = u8"Ключ API";
|
API_KEY = u8"Ключ API";
|
||||||
EXTRA_WINDOW_INFO = u8R"(Правый клик для изменения настроек
|
EXTRA_WINDOW_INFO = u8R"(Правый клик для изменения настроек
|
||||||
Нажмите и перетащите за края - для перемещения, или за правый-нижний угол - для изменения размера)";
|
Нажмите и перетащите за края - для перемещения, или за правый-нижний угол - для изменения размера)";
|
||||||
SENTENCE_TOO_BIG = u8"Предложение слишком длинное для отображения";
|
|
||||||
MAX_SENTENCE_SIZE = u8"Максимальная длина предложения";
|
MAX_SENTENCE_SIZE = u8"Максимальная длина предложения";
|
||||||
TOPMOST = u8"Поверх всех окон";
|
TOPMOST = u8"Поверх всех окон";
|
||||||
DICTIONARY = u8"Словарь";
|
DICTIONARY = u8"Словарь";
|
||||||
@ -868,7 +863,6 @@ esempio: Textractor -p4466 -p"My Game.exe" sta tentando di inniettare i processi
|
|||||||
API_KEY = u8"Chiave API";
|
API_KEY = u8"Chiave API";
|
||||||
EXTRA_WINDOW_INFO = u8R"(Tasto destro per cambiare le impostazioni
|
EXTRA_WINDOW_INFO = u8R"(Tasto destro per cambiare le impostazioni
|
||||||
Clicca e trascina i bordi della finestra per muoverla, oppure nell'angolo in basso a destra per ridimensionare)";
|
Clicca e trascina i bordi della finestra per muoverla, oppure nell'angolo in basso a destra per ridimensionare)";
|
||||||
SENTENCE_TOO_BIG = u8"Sentenza troppo grande da visualizzare";
|
|
||||||
MAX_SENTENCE_SIZE = u8"Dimensione massima sentenza";
|
MAX_SENTENCE_SIZE = u8"Dimensione massima sentenza";
|
||||||
TOPMOST = u8"Sempre in primo piano";
|
TOPMOST = u8"Sempre in primo piano";
|
||||||
DICTIONARY = u8"Dizionario";
|
DICTIONARY = u8"Dizionario";
|
||||||
@ -891,21 +885,19 @@ Questo file deve essere codificato in UTF-8.)";
|
|||||||
SHOW_ORIGINAL = u8"Testo originale";
|
SHOW_ORIGINAL = u8"Testo originale";
|
||||||
SHOW_ORIGINAL_INFO = u8R"(Testo originale non sarà mostrato
|
SHOW_ORIGINAL_INFO = u8R"(Testo originale non sarà mostrato
|
||||||
Funziona solo se questa estenzione è usata direttamente dopo un'estensione di traduzione)";
|
Funziona solo se questa estenzione è usata direttamente dopo un'estensione di traduzione)";
|
||||||
SHOW_ORIGINAL_AFTER_TRANSLATION = u8"Mostra testo originale dopo traduzione";
|
ORIGINAL_AFTER_TRANSLATION = u8"Mostra testo originale dopo traduzione";
|
||||||
SIZE_LOCK = u8"Lock delle dimensione";
|
SIZE_LOCK = u8"Lock delle dimensione";
|
||||||
POSITION_LOCK = u8"Lock delle posizione";
|
POSITION_LOCK = u8"Lock delle posizione";
|
||||||
CENTERED_TEXT = u8"Testo centrato";
|
CENTERED_TEXT = u8"Testo centrato";
|
||||||
AUTO_RESIZE_WINDOW_HEIGHT = u8"Auto resize altezza finestra";
|
AUTO_RESIZE_WINDOW_HEIGHT = u8"Auto resize altezza finestra";
|
||||||
CLICK_THROUGH = u8"Clicca attraverso\tAlt+Shift+T";
|
CLICK_THROUGH = u8"Clicca attraverso\tAlt+Shift+T";
|
||||||
HIDE_TEXT_MOUSEOVER = u8"Nascondi testo mouseover";
|
HIDE_MOUSEOVER = u8"Nascondi testo mouseover";
|
||||||
HIDE_TEXT = u8"Nascondi testo\tAlt+Shift+H";
|
|
||||||
OPACITY = u8"Opacità";
|
OPACITY = u8"Opacità";
|
||||||
BG_COLOR = u8"Colore dello sfondo";
|
BG_COLOR = u8"Colore dello sfondo";
|
||||||
TEXT_COLOR = u8"Colore del testo";
|
TEXT_COLOR = u8"Colore del testo";
|
||||||
TEXT_OUTLINE = u8"Contorno del testo";
|
TEXT_OUTLINE = u8"Contorno del testo";
|
||||||
OUTLINE_COLOR = u8"Colore del contorno";
|
OUTLINE_COLOR = u8"Colore del contorno";
|
||||||
OUTLINE_SIZE = u8"Dimensione del contorno";
|
OUTLINE_SIZE = u8"Dimensione del contorno";
|
||||||
OUTLINE_LAST_SIZE = u8"Ultima dimensione del contorno utilizzata";
|
|
||||||
OUTLINE_SIZE_INFO = u8"Dimensione in pixel (consigliato di rimanere sotto il 20% della dimensione del font)";
|
OUTLINE_SIZE_INFO = u8"Dimensione in pixel (consigliato di rimanere sotto il 20% della dimensione del font)";
|
||||||
FONT = u8"Font";
|
FONT = u8"Font";
|
||||||
LUA_INTRO = u8R"(--[[
|
LUA_INTRO = u8R"(--[[
|
||||||
@ -1296,7 +1288,6 @@ example: Textractor -p4466 -p"My Game.exe" tries to inject processes with id 446
|
|||||||
API_KEY = u8"API key";
|
API_KEY = u8"API key";
|
||||||
EXTRA_WINDOW_INFO = u8R"(Clic droit pour modifier les paramètres
|
EXTRA_WINDOW_INFO = u8R"(Clic droit pour modifier les paramètres
|
||||||
Cliquez et faites glisser sur les bords de la fenêtre pour vous déplacer ou dans le coin inférieur droit pour redimensionner)";
|
Cliquez et faites glisser sur les bords de la fenêtre pour vous déplacer ou dans le coin inférieur droit pour redimensionner)";
|
||||||
SENTENCE_TOO_BIG = u8"Phrase trop grande pour être affichée";
|
|
||||||
MAX_SENTENCE_SIZE = u8"Taille maximale de la phrase";
|
MAX_SENTENCE_SIZE = u8"Taille maximale de la phrase";
|
||||||
TOPMOST = u8"Toujours au dessus";
|
TOPMOST = u8"Toujours au dessus";
|
||||||
DICTIONARY = u8"Dictionnaire";
|
DICTIONARY = u8"Dictionnaire";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user