feat: 十六进制编辑区注册的菜单支持编辑器上下文;用户交互优化;

This commit is contained in:
寂静的羽夏 2025-07-26 19:34:51 +08:00
parent af15ffc8aa
commit 6678c7b9ff
24 changed files with 1351 additions and 1001 deletions

View File

@ -25,6 +25,7 @@ option(BUILD_TEST_PLUGIN OFF)
option(BUILD_SHARED_MEM_EXT OFF) option(BUILD_SHARED_MEM_EXT OFF)
add_definitions(-DAS_NO_THREADS) add_definitions(-DAS_NO_THREADS)
add_definitions(-DWING_SYSTEM_NAME="${CMAKE_SYSTEM_NAME}")
if(BUILD_TEST_PLUGIN) if(BUILD_TEST_PLUGIN)
add_subdirectory(TestPlugin) add_subdirectory(TestPlugin)
@ -308,7 +309,9 @@ set(CLASS_SRC
src/class/changedstringlist.h src/class/changedstringlist.h
src/class/changedstringlist.cpp src/class/changedstringlist.cpp
src/class/editorviewcontext.h src/class/editorviewcontext.h
src/class/editorviewcontext.cpp) src/class/editorviewcontext.cpp
src/class/consolehighlighanim.h
src/class/consolehighlighanim.cpp)
set(INTERNAL_PLG_SRC set(INTERNAL_PLG_SRC
src/class/wingangelapi.h src/class/wingangelapi.cpp src/class/wingangelapi.h src/class/wingangelapi.cpp

View File

@ -31,6 +31,7 @@ TestHexExt::TestHexExt() : WingHex::IWingHexEditorPlugin() {
a->setChecked(true); a->setChecked(true);
connect(a, &QAction::toggled, this, &TestHexExt::setColVisible); connect(a, &QAction::toggled, this, &TestHexExt::setColVisible);
m_context->addAction(a); m_context->addAction(a);
m_aVisCol = a;
} }
bool TestHexExt::init(const std::unique_ptr<QSettings> &set) { bool TestHexExt::init(const std::unique_ptr<QSettings> &set) {
@ -52,7 +53,8 @@ TestHexExt::registeredRibbonTools() const {
} }
QMargins TestHexExt::contentMargins(WingHex::HexEditorContext *context) const { QMargins TestHexExt::contentMargins(WingHex::HexEditorContext *context) const {
if (!_visCol) { auto visCol = context->property("TestHexExt.colVis").toBool();
if (!visCol) {
return {}; return {};
} }
auto lines = context->documentLines(); auto lines = context->documentLines();
@ -65,9 +67,23 @@ QMargins TestHexExt::contentMargins(WingHex::HexEditorContext *context) const {
return {int(colLen) + 1, 0, 0, 0}; return {int(colLen) + 1, 0, 0, 0};
} }
void TestHexExt::prepareCallEditorContext(WingHex::HexEditorContext *context) {
_curContext = context;
auto b = isShowLinePannel(context);
m_aVisCol->blockSignals(true);
m_aVisCol->setChecked(b);
m_aVisCol->blockSignals(false);
}
void TestHexExt::finishCallEditorContext(WingHex::HexEditorContext *context) {
Q_UNUSED(context);
_curContext = nullptr;
}
void TestHexExt::onPaintEvent(QPainter *painter, const QWidget *w, void TestHexExt::onPaintEvent(QPainter *painter, const QWidget *w,
WingHex::HexEditorContext *context) { WingHex::HexEditorContext *context) {
if (!_visCol) { auto visCol = isShowLinePannel(context);
if (!visCol) {
return; return;
} }
painter->save(); painter->save();
@ -104,4 +120,17 @@ void TestHexExt::onPaintEvent(QPainter *painter, const QWidget *w,
painter->restore(); painter->restore();
} }
void TestHexExt::setColVisible(bool b) { _visCol = b; } bool TestHexExt::isShowLinePannel(WingHex::HexEditorContext *context) {
auto pp = context->property("TestHexExt.colVis");
if (pp.isNull()) {
context->setProperty("TestHexExt.colVis", true);
return true;
}
return pp.toBool();
}
void TestHexExt::setColVisible(bool b) {
if (_curContext) {
_curContext->setProperty("TestHexExt.colVis", b);
}
}

View File

@ -52,16 +52,26 @@ public:
virtual QMargins virtual QMargins
contentMargins(WingHex::HexEditorContext *context) const override; contentMargins(WingHex::HexEditorContext *context) const override;
public:
virtual void
prepareCallEditorContext(WingHex::HexEditorContext *context) override;
virtual void
finishCallEditorContext(WingHex::HexEditorContext *context) override;
public: public:
virtual void onPaintEvent(QPainter *painter, const QWidget *w, virtual void onPaintEvent(QPainter *painter, const QWidget *w,
WingHex::HexEditorContext *context) override; WingHex::HexEditorContext *context) override;
private:
bool isShowLinePannel(WingHex::HexEditorContext *context);
private slots: private slots:
void setColVisible(bool b); void setColVisible(bool b);
private: private:
QMenu *m_context; QMenu *m_context;
bool _visCol = true; QAction *m_aVisCol;
WingHex::HexEditorContext *_curContext = nullptr;
}; };
#endif // TESTHEXEXT_H #endif // TESTHEXEXT_H

@ -1 +1 @@
Subproject commit fad774858664d6a137c21b0c2af73ca209cc2f47 Subproject commit 4492bf2aaba267b80ec324c456f0584dcd0efc03

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

147
main.cpp
View File

@ -1,8 +1,118 @@
#include "class/appmanager.h" #include "class/appmanager.h"
#include "class/languagemanager.h"
#include "class/settingmanager.h" #include "class/settingmanager.h"
#include "class/wingmessagebox.h"
#include "define.h" #include "define.h"
#include <QDebug>
#include <QProcessEnvironment>
#include <QSettings>
void loadEnvConfig(int argc, char *argv[]) {
QFileInfo info(argv[0]);
QDir appDir(info.absoluteDir());
if (!appDir.exists(QStringLiteral("config.ini"))) {
return;
}
auto path = appDir.absoluteFilePath(QStringLiteral("config.ini"));
QSettings set(path, QSettings::IniFormat);
// General
for (auto &kv : set.childKeys()) {
qputenv(qPrintable(kv), set.value(kv).toByteArray());
}
auto groups = set.childGroups();
auto evaluate = [](const QProcessEnvironment &env,
const QString &statement) {
// Parse and evaluate statements:
// $NAME -> check existence
// $NAME=VALUE -> ignore-case full match
// $NAME==VALUE -> case-sensitive full match
// $NAME:=VALUE -> ignore-case contains
// $NAME::=VALUE -> case-sensitive contains
// VALUE: unless pure digits, must be enclosed in "" or ''
static const QRegularExpression re(
R"(^\$([A-Za-z_][A-Za-z0-9_]*)(?:\s*(==|::=|:=|=)\s*(\d+|"[^"]*"|'[^']*'))?$)");
auto match = re.match(statement);
if (!match.hasMatch()) {
qWarning("[main::loadEnvConfig] Invalid syntax: %s",
qUtf8Printable(statement));
return false;
}
auto name = match.captured(1);
auto op = match.captured(2);
auto value = match.captured(3);
// Existence check: no operator provided
if (op.isEmpty()) {
return env.contains(name);
}
if (!value.isEmpty() &&
((value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith('\'') && value.endsWith('\'')))) {
value.removeFirst().removeLast();
}
auto var = env.value(name);
// Evaluate based on operator
if (op == QStringLiteral(":=") || op == QStringLiteral("::=")) {
const QStringList items = var.split(QDir::listSeparator());
for (const QString &item : items) {
if (op == QStringLiteral(":=")) {
if (item.contains(value, Qt::CaseInsensitive)) {
return true;
}
} else {
if (item.contains(value, Qt::CaseSensitive)) {
return true;
}
}
}
return false;
}
if (op == "=") {
return QString::compare(var, value, Qt::CaseInsensitive) == 0;
} else if (op == "==") {
return var == value;
} else {
qWarning("[main::loadEnvConfig] Unknown operator: %s",
qUtf8Printable(op));
}
return false;
};
auto env = QProcessEnvironment::systemEnvironment();
constexpr auto syslen = std::char_traits<char>::length(WING_SYSTEM_NAME);
if (syslen) {
set.beginGroup(WING_SYSTEM_NAME);
for (auto &kv : set.childKeys()) {
qputenv(qPrintable(kv), set.value(kv).toByteArray());
}
set.endGroup();
}
for (auto &g : groups) {
if (evaluate(env, g)) {
set.beginGroup(g);
for (auto &kv : set.childKeys()) {
qputenv(qPrintable(kv), set.value(kv).toByteArray());
}
set.endGroup();
}
}
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
/* 有关对在 QT5 的 Win 平台禁用高 dpi 支持 /* 有关对在 QT5 的 Win 平台禁用高 dpi 支持
* *
@ -18,23 +128,13 @@ int main(int argc, char *argv[]) {
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif #endif
loadEnvConfig(argc, argv);
QApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); QApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
#ifdef Q_OS_LINUX QApplication::setApplicationName(QStringLiteral(APP_NAME));
// fix wayland issue (a workaround): floating dock not work QApplication::setOrganizationName(QStringLiteral(APP_ORG));
// reference: QApplication::setApplicationVersion(QStringLiteral(WINGHEX_VERSION));
// https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/
// issues/714#issuecomment-2802752677
auto denv = qgetenv("XDG_SESSION_TYPE");
if (denv.isEmpty() ||
denv.compare(QByteArrayLiteral("wayland"), Qt::CaseInsensitive) == 0) {
qputenv("QT_QPA_PLATFORM", "xcb");
}
#endif
QApplication::setApplicationName(APP_NAME);
QApplication::setOrganizationName(APP_ORG);
QApplication::setApplicationVersion(WINGHEX_VERSION);
try { try {
AppManager a(argc, argv); AppManager a(argc, argv);
@ -61,5 +161,22 @@ int main(int argc, char *argv[]) {
return a.exec(); return a.exec();
} catch (CrashCode errCode) { } catch (CrashCode errCode) {
return int(errCode); return int(errCode);
} catch (const std::bad_alloc &) {
auto &lang = LanguageManager::instance();
auto df = lang.defaultLocale();
// this exception can only occur when your memory are too limit or
// you are writing more than 2GB with QByteArray on 32-bit operating
// system.
if (QLocale::China == df.territory()) {
WingMessageBox::critical(
nullptr, QStringLiteral(APP_NAME),
QStringLiteral("崩溃啦!发生内存溢出异常!"));
} else {
WingMessageBox::critical(
nullptr, QStringLiteral(APP_NAME),
QStringLiteral("WingHexExplorer2 is out of memory. Crashed!"));
}
return int(CrashCode::OutofMemory);
} }
} }

60
mkinstaller/config.ini Normal file
View File

@ -0,0 +1,60 @@
; ========= 羽云十六进制编辑器2应用环境配置文件说明 ==========
;
; 如果区块名开头没有 $ 则认为普通区块General 会在所有的操作系统生效
; 如果你想在某些操作系统生效可以指定区块名为Windows, Linux 和 Darwin
; 对于 Linux 系统,如果包含 uname 工具,则区块名为 uname -s 的输出结果
;
; ================= 配置文件区块扩展语法说明 =================
;
; 语句格式:
; $NAME [OPERATOR VALUE]
;
; 各字段说明:
; $ • 语句起始标记,必需
;
; NAME • 环境变量名
; • 以字母或“_”开头后续可包含字母、数字或“_”
;
; OPERATOR • 可选运算符:
; = 忽略大小写全匹配
; == 区分大小写全匹配
; := 忽略大小写子串包含
; ::= 区分大小写子串包含
;
; VALUE • 可选比较值,仅在 OPERATOR 存在时使用
; • 格式必须是:
; — 纯数字(例如 12345
; — 或用双引号包裹的字符串("text"
; — 或用单引号包裹的字符串('text'
;
; 存在性检查:
; 若仅写 “$NAME”无 OPERATOR 和 VALUE即检查该环境变量是否已定义
;
; --------------------- 示例 ---------------------
; $XDG_SESSION_TYPE="wayland"
; → 忽略大小写地检查 XDG_SESSION_TYPE 是否等于 “wayland”
;
; $PATH:="/usr/local/bin"
; → 忽略大小写地检查 PATH 中是否包含 “/usr/local/bin”
;
; $HOME==12345
; → 区分大小写地检查 HOME 是否等于数字 12345
;
; $LD_LIBRARY_PATH::="/lib64"
; → 区分大小写地检查 LD_LIBRARY_PATH 中是否包含 “/lib64”
;
; $HOME
; → 检查 HOME 是否已定义(存在性检查)
; =====================================================
[General]
WING_DISABLE_PLUGIN_SYSTEM=0
WING_DISABLE_EXTDRV=0
WING_DISABLE_PLUGIN=0
WING_DEBUG=0
[$XDG_SESSION_TYPE="wayland"]
QT_QPA_PLATFORM=xcb

View File

@ -497,7 +497,6 @@ QList<CodeInfoTip> AsCompletion::parseDocument() {
// first preprocess the code // first preprocess the code
AsPreprocesser prepc(engine); AsPreprocesser prepc(engine);
prepc.setIsCodeCompleteMode(true);
prepc.setIncludeCallback(&AsCompletion::includeCallBack, this); prepc.setIncludeCallback(&AsCompletion::includeCallBack, this);
auto r = prepc.loadSectionFromMemory(QStringLiteral("ASCOMPLETION"), auto r = prepc.loadSectionFromMemory(QStringLiteral("ASCOMPLETION"),

View File

@ -186,13 +186,15 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
QStack<std::optional<bool>> m_condtionStack; QStack<std::optional<bool>> m_condtionStack;
bool isEndLine = true;
while (pos < modifiedScript.size()) { while (pos < modifiedScript.size()) {
auto SECTION = sectionname.toUtf8(); auto SECTION = sectionname.toUtf8();
asUINT len = 0; asUINT len = 0;
asETokenClass t = engine->ParseToken(modifiedScript.data() + pos, asETokenClass t = engine->ParseToken(modifiedScript.data() + pos,
modifiedScript.size() - pos, &len); modifiedScript.size() - pos, &len);
if (t == asTC_UNKNOWN && modifiedScript[pos] == '#' && if (isEndLine && t == asTC_UNKNOWN && modifiedScript[pos] == '#' &&
(pos + 1 < modifiedScript.size())) { (pos + 1 < modifiedScript.size())) {
int start = pos++; int start = pos++;
@ -217,12 +219,7 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
if (std::any_of(modifiedScript.data() + pos, if (std::any_of(modifiedScript.data() + pos,
modifiedScript.data() + pos + len, modifiedScript.data() + pos + len,
[](char ch) { return ch == '\n'; })) { [](char ch) { return ch == '\n'; })) {
if (_isCodeCompleteMode) { auto str = tr("IfDefNoWord");
pos = modifiedScript.indexOf('\n', pos);
continue;
}
auto str = QObject::tr("IfDefNoWord");
engine->WriteMessage(SECTION, engine->WriteMessage(SECTION,
getLineCount(modifiedScript, pos), getLineCount(modifiedScript, pos),
1, asMSGTYPE_ERROR, str.toUtf8()); 1, asMSGTYPE_ERROR, str.toUtf8());
@ -234,16 +231,6 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
} }
if (isIfDef || isIfnDef) { if (isIfDef || isIfnDef) {
if (_isCodeCompleteMode) {
auto pos = modifiedScript.indexOf('\n', start);
if (pos < 0) {
overwriteCode(modifiedScript, start,
modifiedScript.size() - start - 1);
} else {
overwriteCode(modifiedScript, start, pos - start);
}
continue;
}
if (t == asTC_IDENTIFIER) { if (t == asTC_IDENTIFIER) {
QByteArray word = modifiedScript.sliced(pos, len); QByteArray word = modifiedScript.sliced(pos, len);
@ -267,23 +254,13 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
qDebug().noquote() << modifiedScript; qDebug().noquote() << modifiedScript;
#endif #endif
} else { } else {
auto str = QObject::tr("IfDefInvalidWord"); auto str = tr("IfDefInvalidWord");
engine->WriteMessage(SECTION, engine->WriteMessage(SECTION,
getLineCount(modifiedScript, pos), getLineCount(modifiedScript, pos),
1, asMSGTYPE_ERROR, str.toUtf8()); 1, asMSGTYPE_ERROR, str.toUtf8());
return asERROR; return asERROR;
} }
} else if (isIf) { } else if (isIf) {
if (_isCodeCompleteMode) {
auto pos = modifiedScript.indexOf('\n', start);
if (pos < 0) {
overwriteCode(modifiedScript, start,
modifiedScript.size() - start - 1);
} else {
overwriteCode(modifiedScript, start, pos - start);
}
continue;
}
// evalutate the string // evalutate the string
auto npos = modifiedScript.indexOf('\n', pos); auto npos = modifiedScript.indexOf('\n', pos);
QByteArray codes; QByteArray codes;
@ -303,7 +280,7 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
ok); ok);
if (ret < 0) { if (ret < 0) {
auto str = QObject::tr("CalIfFailed"); auto str = tr("CalIfFailed");
engine->WriteMessage(SECTION, engine->WriteMessage(SECTION,
getLineCount(modifiedScript, pos), getLineCount(modifiedScript, pos),
1, asMSGTYPE_ERROR, str.toUtf8()); 1, asMSGTYPE_ERROR, str.toUtf8());
@ -324,20 +301,6 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
QByteArray word = modifiedScript.sliced(pos, len); QByteArray word = modifiedScript.sliced(pos, len);
pos += len; pos += len;
if (_isCodeCompleteMode) {
defineWord(word, {});
auto pos = modifiedScript.indexOf('\n', start);
if (pos < 0) {
overwriteCode(modifiedScript, start,
modifiedScript.size() - start -
1);
} else {
overwriteCode(modifiedScript, start,
pos - start);
}
continue;
}
t = engine->ParseToken(modifiedScript.data() + pos, t = engine->ParseToken(modifiedScript.data() + pos,
modifiedScript.size() - pos, modifiedScript.size() - pos,
&len); &len);
@ -366,7 +329,7 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
defineWord(word, v); defineWord(word, v);
} break; } break;
default: default:
auto str = QObject::tr("UnexceptedToken"); auto str = tr("UnexceptedToken");
engine->WriteMessage( engine->WriteMessage(
SECTION, SECTION,
getLineCount(modifiedScript, pos), 1, getLineCount(modifiedScript, pos), 1,
@ -381,42 +344,20 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
// ensure end line // ensure end line
if (endLinePassFailed(modifiedScript, pos)) { if (endLinePassFailed(modifiedScript, pos)) {
auto str = QObject::tr("UnexceptedToken"); auto str = tr("UnexceptedToken");
engine->WriteMessage( engine->WriteMessage(
SECTION, getLineCount(modifiedScript, pos), 1, SECTION, getLineCount(modifiedScript, pos), 1,
asMSGTYPE_ERROR, str.toUtf8()); asMSGTYPE_ERROR, str.toUtf8());
return asERROR; return asERROR;
} }
} else { } else {
if (_isCodeCompleteMode) { auto str = tr("InvalidDef");
auto pos = modifiedScript.indexOf('\n', start);
if (pos < 0) {
overwriteCode(modifiedScript, start,
modifiedScript.size() - start -
1);
} else {
overwriteCode(modifiedScript, start,
pos - start);
}
continue;
}
auto str = QObject::tr("InvalidDef");
engine->WriteMessage(SECTION, engine->WriteMessage(SECTION,
getLineCount(modifiedScript, pos), getLineCount(modifiedScript, pos),
1, asMSGTYPE_ERROR, str.toUtf8()); 1, asMSGTYPE_ERROR, str.toUtf8());
return asERROR; return asERROR;
} }
} else if (isUnDef) { } else if (isUnDef) {
if (_isCodeCompleteMode) {
auto pos = modifiedScript.indexOf('\n', start);
if (pos < 0) {
overwriteCode(modifiedScript, start,
modifiedScript.size() - start - 1);
} else {
overwriteCode(modifiedScript, start, pos - start);
}
continue;
}
if (t == asTC_IDENTIFIER) { if (t == asTC_IDENTIFIER) {
QByteArray word = modifiedScript.sliced(pos, len); QByteArray word = modifiedScript.sliced(pos, len);
@ -427,13 +368,13 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
constexpr auto PREFIX = "__"; constexpr auto PREFIX = "__";
if (word.startsWith(PREFIX) && word.endsWith(PREFIX)) { if (word.startsWith(PREFIX) && word.endsWith(PREFIX)) {
// Warning // Warning
auto str = QObject::tr("ReservedMarcoType"); auto str = tr("ReservedMarcoType");
engine->WriteMessage( engine->WriteMessage(
SECTION, getLineCount(modifiedScript, pos), 1, SECTION, getLineCount(modifiedScript, pos), 1,
asMSGTYPE_WARNING, str.toUtf8()); asMSGTYPE_WARNING, str.toUtf8());
} else { } else {
if (!definedWords.remove(word)) { if (!definedWords.remove(word)) {
auto str = QObject::tr("MarcoNotFound:") + word; auto str = tr("MarcoNotFound:") + word;
engine->WriteMessage( engine->WriteMessage(
SECTION, getLineCount(modifiedScript, pos), SECTION, getLineCount(modifiedScript, pos),
1, asMSGTYPE_WARNING, str.toUtf8()); 1, asMSGTYPE_WARNING, str.toUtf8());
@ -442,14 +383,14 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
// ensure end line // ensure end line
if (endLinePassFailed(modifiedScript, pos)) { if (endLinePassFailed(modifiedScript, pos)) {
auto str = QObject::tr("UnexceptedToken"); auto str = tr("UnexceptedToken");
engine->WriteMessage( engine->WriteMessage(
SECTION, getLineCount(modifiedScript, pos), 1, SECTION, getLineCount(modifiedScript, pos), 1,
asMSGTYPE_ERROR, str.toUtf8()); asMSGTYPE_ERROR, str.toUtf8());
return asERROR; return asERROR;
} }
} else { } else {
auto str = QObject::tr("InvalidDef"); auto str = tr("InvalidDef");
engine->WriteMessage(SECTION, engine->WriteMessage(SECTION,
getLineCount(modifiedScript, pos), getLineCount(modifiedScript, pos),
1, asMSGTYPE_ERROR, str.toUtf8()); 1, asMSGTYPE_ERROR, str.toUtf8());
@ -457,12 +398,8 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
} }
} }
} else if (token == "else") { } else if (token == "else") {
if (_isCodeCompleteMode) {
overwriteCode(modifiedScript, start, pos - start);
continue;
}
if (m_condtionStack.isEmpty()) { if (m_condtionStack.isEmpty()) {
auto str = QObject::tr("NoMatchingIf"); auto str = tr("NoMatchingIf");
engine->WriteMessage(SECTION, engine->WriteMessage(SECTION,
getLineCount(modifiedScript, pos), 1, getLineCount(modifiedScript, pos), 1,
asMSGTYPE_ERROR, str.toUtf8()); asMSGTYPE_ERROR, str.toUtf8());
@ -478,14 +415,14 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
// ensure end line // ensure end line
if (endLinePassFailed(modifiedScript, pos - 1)) { if (endLinePassFailed(modifiedScript, pos - 1)) {
auto str = QObject::tr("UnexceptedToken"); auto str = tr("UnexceptedToken");
engine->WriteMessage( engine->WriteMessage(
SECTION, getLineCount(modifiedScript, pos), 1, SECTION, getLineCount(modifiedScript, pos), 1,
asMSGTYPE_ERROR, str.toUtf8()); asMSGTYPE_ERROR, str.toUtf8());
return asERROR; return asERROR;
} }
} else { } else {
auto str = QObject::tr("DupElseDef"); auto str = tr("DupElseDef");
engine->WriteMessage(SECTION, engine->WriteMessage(SECTION,
getLineCount(modifiedScript, pos), getLineCount(modifiedScript, pos),
1, asMSGTYPE_ERROR, str.toUtf8()); 1, asMSGTYPE_ERROR, str.toUtf8());
@ -496,13 +433,9 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
qDebug().noquote() << modifiedScript; qDebug().noquote() << modifiedScript;
#endif #endif
} else if (token == "endif") { } else if (token == "endif") {
if (_isCodeCompleteMode) {
overwriteCode(modifiedScript, start, pos - start);
continue;
}
// Only remove the #endif if there was a matching #if // Only remove the #endif if there was a matching #if
if (m_condtionStack.isEmpty()) { if (m_condtionStack.isEmpty()) {
auto str = QObject::tr("NoMatchingIf"); auto str = tr("NoMatchingIf");
engine->WriteMessage(SECTION, engine->WriteMessage(SECTION,
getLineCount(modifiedScript, pos), 1, getLineCount(modifiedScript, pos), 1,
asMSGTYPE_ERROR, str.toUtf8()); asMSGTYPE_ERROR, str.toUtf8());
@ -514,7 +447,7 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
// ensure end line // ensure end line
if (endLinePassFailed(modifiedScript, pos)) { if (endLinePassFailed(modifiedScript, pos)) {
auto str = QObject::tr("UnexceptedToken"); auto str = tr("UnexceptedToken");
engine->WriteMessage(SECTION, engine->WriteMessage(SECTION,
getLineCount(modifiedScript, pos), 1, getLineCount(modifiedScript, pos), 1,
asMSGTYPE_ERROR, str.toUtf8()); asMSGTYPE_ERROR, str.toUtf8());
@ -524,67 +457,71 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
qDebug().noquote() << modifiedScript; qDebug().noquote() << modifiedScript;
#endif #endif
} }
} else {
if (!_isCodeCompleteMode) {
if (t == asTC_IDENTIFIER) {
// define replace
auto word = modifiedScript.sliced(pos, len);
if (word == PROMISE_AWAIT) {
auto npos = pos + len;
asUINT total = 0;
auto t = engine->ParseToken(
modifiedScript.data() + npos,
modifiedScript.size() - npos, &total);
if (t == asTC_WHITESPACE) {
npos += total;
t = engine->ParseToken(modifiedScript.data() + npos,
modifiedScript.size() - npos,
&total);
if (t == asTC_IDENTIFIER) {
// ok
auto word = modifiedScript.sliced(npos, total);
auto data = "(" + word +
")." PROMISE_YIELD
"()." PROMISE_UNWRAP "()";
auto oldLen = npos - pos + word.length();
modifiedScript.replace(pos, oldLen, data);
pos = npos;
pos += data.length() - oldLen + word.length();
continue;
}
}
auto str = QObject::tr("UnexceptedToken"); isEndLine = true;
engine->WriteMessage(SECTION, } else {
getLineCount(modifiedScript, pos), if (t == asTC_IDENTIFIER) {
1, asMSGTYPE_ERROR, str.toUtf8()); // define replace
return asERROR; auto word = modifiedScript.sliced(pos, len);
} else if (word == "__LINE__") { if (word == PROMISE_AWAIT) {
auto data = QByteArray::number( auto npos = pos + len;
getLineCount(modifiedScript, pos)); asUINT total = 0;
modifiedScript.replace(pos, len, data); auto t = engine->ParseToken(modifiedScript.data() + npos,
pos += data.length(); modifiedScript.size() - npos,
continue; &total);
} else if (word == "__SECTION__") { if (t == asTC_WHITESPACE) {
auto data = SECTION; npos += total;
data.prepend('"').append('"'); t = engine->ParseToken(modifiedScript.data() + npos,
modifiedScript.replace(pos, len, data); modifiedScript.size() - npos,
pos += data.length(); &total);
continue; if (t == asTC_IDENTIFIER) {
} else if (word == "__SECTION_BASE__") { // ok
auto data = QFileInfo(SECTION).baseName().toUtf8(); auto word = modifiedScript.sliced(npos, total);
data.prepend('"').append('"'); auto data = "(" + word +
modifiedScript.replace(pos, len, data); ")." PROMISE_YIELD "()." PROMISE_UNWRAP
pos += data.length(); "()";
continue; auto oldLen = npos - pos + word.length();
} else { modifiedScript.replace(pos, oldLen, data);
auto rword = findReplaceResult(word); pos = npos;
if (word != rword) { pos += data.length() - oldLen + word.length();
modifiedScript.replace(pos, len, rword); continue;
len = rword.length();
} }
} }
auto str = tr("UnexceptedToken");
engine->WriteMessage(SECTION,
getLineCount(modifiedScript, pos), 1,
asMSGTYPE_ERROR, str.toUtf8());
return asERROR;
} else if (word == "__LINE__") {
auto data =
QByteArray::number(getLineCount(modifiedScript, pos));
modifiedScript.replace(pos, len, data);
pos += data.length();
continue;
} else if (word == "__SECTION__") {
auto data = SECTION;
data.prepend('"').append('"');
modifiedScript.replace(pos, len, data);
pos += data.length();
continue;
} else if (word == "__SECTION_BASE__") {
auto data = QFileInfo(SECTION).baseName().toUtf8();
data.prepend('"').append('"');
modifiedScript.replace(pos, len, data);
pos += data.length();
continue;
} else {
auto rword = findReplaceResult(word);
if (word != rword) {
modifiedScript.replace(pos, len, rword);
len = rword.length();
}
} }
} else if (t == asTC_WHITESPACE) {
isEndLine = std::any_of(modifiedScript.data() + pos,
modifiedScript.data() + pos + len,
[](char ch) { return ch == '\n'; });
} }
pos += len; pos += len;
} }
@ -644,11 +581,11 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
// line breaks // line breaks
auto p = includefile.indexOf('\n'); auto p = includefile.indexOf('\n');
if (p >= 0) { if (p >= 0) {
auto str = auto str = tr("Invalid file name for #include; "
QObject::tr("Invalid file name for #include; " "it contains a line-break: ") +
"it contains a line-break: ") + QStringLiteral("'") +
QStringLiteral("'") + includefile.left(p) + includefile.left(p) +
QStringLiteral("'"); QStringLiteral("'");
engine->WriteMessage( engine->WriteMessage(
sectionname.toUtf8(), sectionname.toUtf8(),
getLineCount(modifiedScript, pos), 1, getLineCount(modifiedScript, pos), 1,
@ -690,12 +627,11 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
auto p = includefile.indexOf('\n'); auto p = includefile.indexOf('\n');
auto ws = includefile.indexOf(' '); auto ws = includefile.indexOf(' ');
if (!includefile.isEmpty() && p >= 0 && ws >= 0) { if (!includefile.isEmpty() && p >= 0 && ws >= 0) {
auto str = auto str = tr("Invalid file name for #include; "
QObject::tr( "it contains a line-break: ") +
"Invalid file name for #include; " QStringLiteral("'") +
"it contains a line-break: ") + includefile.left(p) +
QStringLiteral("'") + includefile.left(p) + QStringLiteral("'");
QStringLiteral("'");
engine->WriteMessage( engine->WriteMessage(
sectionname.toUtf8(), sectionname.toUtf8(),
getLineCount(modifiedScript, pos), 1, getLineCount(modifiedScript, pos), 1,
@ -710,10 +646,9 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
pos - start); pos - start);
} }
} else { } else {
auto str = auto str = tr("Invalid file name for #include; "
QObject::tr("Invalid file name for #include; " "it contains a line-break or "
"it contains a line-break or " "unpaired symbol");
"unpaired symbol");
engine->WriteMessage(sectionname.toUtf8(), 0, 0, engine->WriteMessage(sectionname.toUtf8(), 0, 0,
asMSGTYPE_ERROR, str.toUtf8()); asMSGTYPE_ERROR, str.toUtf8());
} }
@ -734,20 +669,17 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
// to avoid compiler error // to avoid compiler error
overwriteCode(modifiedScript, start, pos - start); overwriteCode(modifiedScript, start, pos - start);
if (!_isCodeCompleteMode) { int r = pragmaCallback
int r = pragmaCallback ? pragmaCallback(pragmaText, this, sectionname,
? pragmaCallback(pragmaText, this, pragmaParam)
sectionname, pragmaParam) : -1;
: -1; if (r < 0) {
if (r < 0) { engine->WriteMessage(
engine->WriteMessage( sectionname.toUtf8(),
sectionname.toUtf8(), getLineCount(modifiedScript, pos), 1,
getLineCount(modifiedScript, pos), 1, asMSGTYPE_ERROR,
asMSGTYPE_ERROR, tr("Invalid #pragma directive").toUtf8());
QObject::tr("Invalid #pragma directive") return r;
.toUtf8());
return r;
}
} }
} }
} }
@ -810,8 +742,7 @@ int AsPreprocesser::loadScriptSection(const QString &filename) {
if (!f.open(QFile::ReadOnly)) { if (!f.open(QFile::ReadOnly)) {
// Write a message to the engine's message callback // Write a message to the engine's message callback
auto msg = QObject::tr("Failed to open script file ") + auto msg = tr("Failed to open script file ") + QStringLiteral("'") +
QStringLiteral("'") +
QFileInfo(filename).absoluteFilePath() + QStringLiteral("'"); QFileInfo(filename).absoluteFilePath() + QStringLiteral("'");
engine->WriteMessage(filename.toUtf8(), 0, 0, asMSGTYPE_ERROR, engine->WriteMessage(filename.toUtf8(), 0, 0, asMSGTYPE_ERROR,
msg.toUtf8()); msg.toUtf8());
@ -1022,12 +953,6 @@ QByteArray AsPreprocesser::findReplaceResult(const QByteArray &v) {
return r; return r;
} }
bool AsPreprocesser::isCodeCompleteMode() const { return _isCodeCompleteMode; }
void AsPreprocesser::setIsCodeCompleteMode(bool newIsCodeCompleteMode) {
_isCodeCompleteMode = newIsCodeCompleteMode;
}
QHash<QString, QByteArray> AsPreprocesser::definedMacros() const { QHash<QString, QByteArray> AsPreprocesser::definedMacros() const {
return definedWords; return definedWords;
} }

View File

@ -35,6 +35,7 @@
#pragma warning(disable : 4786) #pragma warning(disable : 4786)
#endif #endif
#include <QApplication>
#include <QEventLoop> #include <QEventLoop>
#include <QMap> #include <QMap>
#include <QSet> #include <QSet>
@ -74,6 +75,7 @@ typedef int (*PRAGMACALLBACK_t)(const QByteArray &pragmaText,
* * #ifndef <word> * * #ifndef <word>
*/ */
class AsPreprocesser { class AsPreprocesser {
Q_DECLARE_TR_FUNCTIONS(AsPreprocesser)
public: public:
explicit AsPreprocesser(asIScriptEngine *engine); explicit AsPreprocesser(asIScriptEngine *engine);
virtual ~AsPreprocesser(); virtual ~AsPreprocesser();
@ -113,9 +115,6 @@ public:
QString sectionName(unsigned int idx) const; QString sectionName(unsigned int idx) const;
bool isCodeCompleteMode() const;
void setIsCodeCompleteMode(bool newIsCodeCompleteMode);
QHash<QString, QByteArray> definedMacros() const; QHash<QString, QByteArray> definedMacros() const;
protected: protected:
@ -155,9 +154,6 @@ protected:
QStringList includedScripts; QStringList includedScripts;
QHash<QString, QByteArray> definedWords; QHash<QString, QByteArray> definedWords;
private:
bool _isCodeCompleteMode = false;
}; };
#endif // ASPREPROCESSER_H #endif // ASPREPROCESSER_H

View File

@ -0,0 +1,98 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** This program is free software: you can redistribute it and/or modify it under
** the terms of the GNU Affero General Public License as published by the Free
** Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
** details.
**
** You should have received a copy of the GNU Affero General Public License
** along with this program. If not, see <https://www.gnu.org/licenses/>.
** =============================================================================
*/
#include "consolehighlighanim.h"
#include <QApplication>
#include <QPalette>
#include <QWidget>
ConsoleHighlighAnim::ConsoleHighlighAnim(QObject *parent)
: QObject(parent), m_highlightColor(qApp->palette().highlight().color()),
m_alpha(0), _w(nullptr), _anim(nullptr) {
_anim = new QPropertyAnimation(this, QByteArrayLiteral("alpha"), this);
_anim->setStartValue(10);
_anim->setEndValue(100);
_anim->setDuration(1000);
_anim->setEasingCurve(QEasingCurve::InOutQuad);
_anim->setLoopCount(5);
connect(_anim, &QPropertyAnimation::finished, this, [this]() {
if (_w) {
_w->setStyleSheet({});
}
});
}
int ConsoleHighlighAnim::getAlpha() const { return m_alpha; }
void ConsoleHighlighAnim::setAlpha(int newAlpha) {
if (m_alpha == newAlpha)
return;
m_alpha = newAlpha;
auto clsname = _w->metaObject()->className();
auto ss = QStringLiteral("background-color: rgba(%1, %2, %3, %4);")
.arg(m_highlightColor.red())
.arg(m_highlightColor.green())
.arg(m_highlightColor.blue())
.arg(m_alpha);
if (clsname) {
ss.prepend('{').prepend(clsname).append('}');
}
if (_w) {
_w->setStyleSheet(ss);
}
Q_EMIT alphaChanged();
}
QWidget *ConsoleHighlighAnim::widget() const { return _w; }
void ConsoleHighlighAnim::setWidget(QWidget *newW) {
if (_w) {
_w->setStyleSheet({});
}
_w = newW;
auto ss = QStringLiteral("background-color: rgba(%1, %2, %3, %4);")
.arg(m_highlightColor.red())
.arg(m_highlightColor.green())
.arg(m_highlightColor.blue())
.arg(m_alpha);
if (_w) {
_w->setStyleSheet(ss);
}
}
void ConsoleHighlighAnim::start() {
if (_w == nullptr) {
return;
}
if (_anim->state() == QPropertyAnimation::Stopped) {
_anim->start();
}
}
void ConsoleHighlighAnim::stop() {
if (_anim->state() == QPropertyAnimation::Running) {
_anim->stop();
if (_w) {
_w->setStyleSheet({});
}
}
}

View File

@ -0,0 +1,55 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** This program is free software: you can redistribute it and/or modify it under
** the terms of the GNU Affero General Public License as published by the Free
** Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
** details.
**
** You should have received a copy of the GNU Affero General Public License
** along with this program. If not, see <https://www.gnu.org/licenses/>.
** =============================================================================
*/
#ifndef CONSOLEHIGHLIGHANIM_H
#define CONSOLEHIGHLIGHANIM_H
#include <QColor>
#include <QObject>
#include <QPropertyAnimation>
class ConsoleHighlighAnim : public QObject {
Q_OBJECT
Q_PROPERTY(int alpha READ getAlpha WRITE setAlpha NOTIFY alphaChanged FINAL)
public:
explicit ConsoleHighlighAnim(QObject *parent = nullptr);
public:
int getAlpha() const;
void setAlpha(int newAlpha);
QWidget *widget() const;
void setWidget(QWidget *newW);
public:
void start();
// 停止动画并清除样式
void stop();
signals:
void alphaChanged();
private:
QColor m_highlightColor;
int m_alpha;
QWidget *_w;
QPropertyAnimation *_anim;
};
#endif // CONSOLEHIGHLIGHANIM_H

View File

@ -18,10 +18,14 @@
#include "editorviewcontext.h" #include "editorviewcontext.h"
EditorViewContext::EditorViewContext(QHexView *view) EditorViewContext::EditorViewContext(QHexView *view)
: WingHex::HexEditorContext(), _view(view) { : WingHex::HexEditorContext(view), _view(view) {
Q_ASSERT(view); Q_ASSERT(view);
} }
QString EditorViewContext::docFileName() const {
return _view->windowFilePath();
}
QFontMetricsF EditorViewContext::fontMetrics() const { QFontMetricsF EditorViewContext::fontMetrics() const {
return _view->fontMetrics(); return _view->fontMetrics();
} }

View File

@ -27,6 +27,7 @@ public:
// HexEditorPalette interface // HexEditorPalette interface
public: public:
virtual QString docFileName() const override;
virtual QFontMetricsF fontMetrics() const override; virtual QFontMetricsF fontMetrics() const override;
virtual QColor headerColor() const override; virtual QColor headerColor() const override;
virtual QColor addressColor() const override; virtual QColor addressColor() const override;

View File

@ -4063,12 +4063,7 @@ void PluginSystem::try2LoadHexExtPlugin() {
_manHexInfo = m; _manHexInfo = m;
{ registerHexContextMenu(p);
auto menu = p->registeredHexContextMenu();
if (menu) {
_win->m_hexContextMenu.append(menu);
}
}
registerRibbonTools(p->registeredRibbonTools()); registerRibbonTools(p->registeredRibbonTools());
registeredSettingPages(QVariant::fromValue(p), registeredSettingPages(QVariant::fromValue(p),
p->registeredSettingPages()); p->registeredSettingPages());
@ -4142,6 +4137,30 @@ void PluginSystem::registerEvents(IWingPlugin *plg) {
} }
} }
void PluginSystem::registerHexContextMenu(IWingHexEditorInterface *inter) {
Q_ASSERT(inter);
auto menu = inter->registeredHexContextMenu();
if (menu) {
_win->m_hexContextMenu.append(menu);
connect(menu, &QMenu::aboutToShow, this, [menu, inter]() {
auto pp = menu->property("__CONTEXT__");
auto ptr =
reinterpret_cast<HexEditorContext *>(pp.value<quintptr>());
if (ptr) {
inter->prepareCallEditorContext(ptr);
}
});
connect(menu, &QMenu::triggered, this, [menu, inter]() {
auto pp = menu->property("__CONTEXT__");
auto ptr =
reinterpret_cast<HexEditorContext *>(pp.value<quintptr>());
if (ptr) {
inter->finishCallEditorContext(ptr);
}
});
}
}
void PluginSystem::applyFunctionTables(QObject *plg, const CallTable &fns) { void PluginSystem::applyFunctionTables(QObject *plg, const CallTable &fns) {
plg->setProperty("__CALL_TABLE__", QVariant::fromValue(fns)); plg->setProperty("__CALL_TABLE__", QVariant::fromValue(fns));
plg->setProperty("__CALL_POINTER__", quintptr(this)); plg->setProperty("__CALL_POINTER__", quintptr(this));
@ -4217,13 +4236,7 @@ void PluginSystem::loadPlugin(IWingPlugin *p, PluginInfo &meta,
// ensure call only once // ensure call only once
registerRibbonTools(p->registeredRibbonTools()); registerRibbonTools(p->registeredRibbonTools());
registerPluginDockWidgets(p); registerPluginDockWidgets(p);
registerHexContextMenu(p);
{
auto menu = p->registeredHexContextMenu();
if (menu) {
_win->m_hexContextMenu.append(menu);
}
}
{ {
auto vieww = p->registeredEditorViewWidgets(); auto vieww = p->registeredEditorViewWidgets();

View File

@ -224,6 +224,8 @@ private:
private: private:
void registerEvents(IWingPlugin *plg); void registerEvents(IWingPlugin *plg);
void registerHexContextMenu(IWingHexEditorInterface *inter);
void applyFunctionTables(QObject *plg, const CallTable &fns); void applyFunctionTables(QObject *plg, const CallTable &fns);
bool isPluginLoaded(const WingDependency &d); bool isPluginLoaded(const WingDependency &d);

View File

@ -333,8 +333,9 @@ ErrFile EditorView::newFile(size_t index) {
removeMonitorPaths(); removeMonitorPaths();
auto istr = QString::number(index); auto istr = QString::number(index);
m_fileName = tr("Untitled") + istr; auto fname = tr("Untitled") + istr;
this->setWindowTitle(m_fileName); m_hex->setWindowFilePath(fname);
this->setWindowTitle(fname);
m_docType = DocumentType::File; m_docType = DocumentType::File;
m_isWorkSpace = false; m_isWorkSpace = false;
m_isNewFile = true; m_isNewFile = true;
@ -371,7 +372,8 @@ ErrFile EditorView::openFile(const QString &filename) {
m_hex->setKeepSize(true); m_hex->setKeepSize(true);
m_docType = DocumentType::File; m_docType = DocumentType::File;
m_fileName = info.absoluteFilePath(); auto fName = info.absoluteFilePath();
m_hex->setWindowFilePath(fName);
m_isNewFile = false; m_isNewFile = false;
p->setDocSaved(); p->setDocSaved();
@ -379,8 +381,8 @@ ErrFile EditorView::openFile(const QString &filename) {
connectDocSavedFlag(this); connectDocSavedFlag(this);
auto tab = this->tabWidget(); auto tab = this->tabWidget();
tab->setIcon(Utilities::getIconFromFile(style(), m_fileName)); tab->setIcon(Utilities::getIconFromFile(style(), fName));
tab->setToolTip(m_fileName); tab->setToolTip(fName);
addMonitorPath(); addMonitorPath();
} }
@ -435,7 +437,7 @@ ErrFile EditorView::openExtFile(const QString &ext, const QString &file) {
_file = file; _file = file;
m_docType = DocumentType::Extension; m_docType = DocumentType::Extension;
m_fileName = fileName; m_hex->setWindowFilePath(fileName);
m_isNewFile = false; m_isNewFile = false;
p->setDocSaved(); p->setDocSaved();
@ -513,7 +515,7 @@ ErrFile EditorView::save(const QString &workSpaceName, const QString &path,
return this->cloneParent()->save(workSpaceName, path, isExport, return this->cloneParent()->save(workSpaceName, path, isExport,
workSpaceAttr); workSpaceAttr);
} }
auto fileName = path.isEmpty() ? m_fileName : path; auto fileName = path.isEmpty() ? m_hex->windowFilePath() : path;
auto doc = m_hex->document(); auto doc = m_hex->document();
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
@ -589,7 +591,8 @@ ErrFile EditorView::save(const QString &workSpaceName, const QString &path,
} }
} }
if (!doc->isDocSaved() || m_fileName != fileName || isNewFile()) { if (!doc->isDocSaved() || m_hex->windowFilePath() != fileName ||
isNewFile()) {
if (m_docType == DocumentType::Extension) { if (m_docType == DocumentType::Extension) {
if (_dev->isOpen()) { if (_dev->isOpen()) {
_dev->close(); _dev->close();
@ -611,7 +614,8 @@ ErrFile EditorView::save(const QString &workSpaceName, const QString &path,
if (doc->saveTo(&file, !isExport)) { if (doc->saveTo(&file, !isExport)) {
file.close(); file.close();
if (!isExport) { if (!isExport) {
m_fileName = QFileInfo(fileName).absoluteFilePath(); m_hex->setWindowFilePath(
QFileInfo(fileName).absoluteFilePath());
if (isNewFile()) { if (isNewFile()) {
auto buffer = new QFileBuffer; auto buffer = new QFileBuffer;
@ -660,7 +664,7 @@ ErrFile EditorView::reload() {
switch (documentType()) { switch (documentType()) {
case DocumentType::File: case DocumentType::File:
return openFile(m_fileName); return openFile(m_hex->windowFilePath());
case DocumentType::Extension: case DocumentType::Extension:
return openExtFile(_ext, _file); return openExtFile(_ext, _file);
default: default:
@ -741,13 +745,14 @@ void EditorView::connectDocSavedFlag(EditorView *editor) {
connect(editor->m_hex->document().get(), &QHexDocument::documentSaved, this, connect(editor->m_hex->document().get(), &QHexDocument::documentSaved, this,
[=](bool b) { [=](bool b) {
QString fileName; QString fileName;
auto fName = m_hex->windowFilePath();
if (editor->isNewFile()) { if (editor->isNewFile()) {
fileName = m_fileName; fileName = fName;
} else if (editor->isExtensionFile()) { } else if (editor->isExtensionFile()) {
auto idx = m_fileName.indexOf('}'); auto idx = fName.indexOf('}');
fileName = m_fileName.mid(idx); fileName = fName.mid(idx);
} else { } else {
fileName = QFileInfo(m_fileName).fileName(); fileName = QFileInfo(fName).fileName();
} }
QString content; QString content;
@ -770,7 +775,7 @@ void EditorView::connectDocSavedFlag(EditorView *editor) {
auto tab = this->tabWidget(); auto tab = this->tabWidget();
if (tab->icon().isNull()) { if (tab->icon().isNull()) {
tab->setIcon( tab->setIcon(
Utilities::getIconFromFile(style(), m_fileName)); Utilities::getIconFromFile(style(), fName));
} }
} }
}); });
@ -784,7 +789,7 @@ void EditorView::removeMonitorPaths() {
_watcher.removePaths(files); _watcher.removePaths(files);
} }
void EditorView::addMonitorPath() { _watcher.addPath(m_fileName); } void EditorView::addMonitorPath() { _watcher.addPath(m_hex->windowFilePath()); }
BookMarksModel *EditorView::bookmarksModel() const { return m_bookmarks; } BookMarksModel *EditorView::bookmarksModel() const { return m_bookmarks; }
@ -2144,12 +2149,12 @@ EditorView *EditorView::clone() {
connect(ev, &EditorView::sigOnMetadata, this, &EditorView::sigOnMetadata); connect(ev, &EditorView::sigOnMetadata, this, &EditorView::sigOnMetadata);
connect(ev, &EditorView::sigOnBookMark, this, &EditorView::sigOnBookMark); connect(ev, &EditorView::sigOnBookMark, this, &EditorView::sigOnBookMark);
auto doc = this->m_hex->document(); auto doc = m_hex->document();
ev->m_cloneParent = this; ev->m_cloneParent = this;
ev->m_hex->setDocument(doc, ev->m_hex->cursor()); ev->m_hex->setDocument(doc, ev->m_hex->cursor());
ev->m_fileName = this->m_fileName; ev->m_hex->setWindowFilePath(m_hex->windowFilePath());
ev->setWindowTitle(this->windowTitle() + QStringLiteral(" : ") + ev->setWindowTitle(this->windowTitle() + QStringLiteral(" : ") +
QString::number(cloneIndex + 1)); QString::number(cloneIndex + 1));
@ -2234,7 +2239,7 @@ QString EditorView::fileName() const {
if (isCloneFile()) { if (isCloneFile()) {
return this->cloneParent()->fileName(); return this->cloneParent()->fileName();
} }
return m_fileName; return m_hex->windowFilePath();
} }
bool EditorView::eventFilter(QObject *watched, QEvent *event) { bool EditorView::eventFilter(QObject *watched, QEvent *event) {
@ -2247,3 +2252,5 @@ bool EditorView::eventFilter(QObject *watched, QEvent *event) {
} }
return ads::CDockWidget::eventFilter(watched, event); return ads::CDockWidget::eventFilter(watched, event);
} }
EditorViewContext *EditorView::editorContext() const { return _context; }

View File

@ -217,6 +217,8 @@ public:
void applySettings(); void applySettings();
EditorViewContext *editorContext() const;
private: private:
inline qsizetype findAvailCloneIndex(); inline qsizetype findAvailCloneIndex();
@ -570,7 +572,6 @@ private:
QMenu *m_menu = nullptr; QMenu *m_menu = nullptr;
QHash<QString, WingEditorViewWidget *> m_others; QHash<QString, WingEditorViewWidget *> m_others;
QString m_fileName;
bool m_isNewFile = true; bool m_isNewFile = true;
QByteArray m_md5; QByteArray m_md5;

View File

@ -6,7 +6,8 @@ enum class CrashCode : int {
LanguageFile, LanguageFile,
PluginSetting, PluginSetting,
ScriptInitFailed, ScriptInitFailed,
GenericCallNotSupported GenericCallNotSupported,
OutofMemory
}; };
namespace AsUserDataType { namespace AsUserDataType {

View File

@ -465,6 +465,9 @@ void MainWindow::buildUpDockSystem(QWidget *container) {
swapEditor(m_curEditor, editview); swapEditor(m_curEditor, editview);
_editorLock.unlock(); _editorLock.unlock();
} else { } else {
for (auto &menu : m_hexContextMenu) {
menu->setProperty("__CONTEXT__", {});
}
m_findresult->setModel(_findEmptyResult); m_findresult->setModel(_findEmptyResult);
m_bookmarks->setModel(_bookMarkEmpty); m_bookmarks->setModel(_bookMarkEmpty);
m_metadatas->setModel(_metadataEmpty); m_metadatas->setModel(_metadataEmpty);
@ -1083,10 +1086,13 @@ ads::CDockAreaWidget *
MainWindow::buildUpScriptBgOutputDock(ads::CDockManager *dock, MainWindow::buildUpScriptBgOutputDock(ads::CDockManager *dock,
ads::DockWidgetArea area, ads::DockWidgetArea area,
ads::CDockAreaWidget *areaw) { ads::CDockAreaWidget *areaw) {
m_bgScriptOutput = new QPlainTextEdit(this); m_bgScriptOutput = new QPlainTextEdit(this);
m_bgScriptOutput->setPlaceholderText(tr("BgScriptOutputHere")); m_bgScriptOutput->setPlaceholderText(tr("BgScriptOutputHere"));
m_bgScriptOutput->setReadOnly(true); m_bgScriptOutput->setReadOnly(true);
_hlAnim = new ConsoleHighlighAnim(m_bgScriptOutput);
auto a = newAction( auto a = newAction(
ICONRES(QStringLiteral("mStr")), tr("SelectAll"), ICONRES(QStringLiteral("mStr")), tr("SelectAll"),
[this]() { m_bgScriptOutput->selectAll(); }, QKeySequence::SelectAll); [this]() { m_bgScriptOutput->selectAll(); }, QKeySequence::SelectAll);
@ -1116,6 +1122,13 @@ MainWindow::buildUpScriptBgOutputDock(ads::CDockManager *dock,
auto dw = buildDockWidget(dock, QStringLiteral("BgScriptOutput"), auto dw = buildDockWidget(dock, QStringLiteral("BgScriptOutput"),
tr("BgScriptOutput"), m_bgScriptOutput); tr("BgScriptOutput"), m_bgScriptOutput);
_hlAnim->setWidget(dw->tabWidget());
auto e = new EventFilter(QEvent::Show, dw);
connect(e, &EventFilter::eventTriggered, this,
[this]() { _hlAnim->stop(); });
m_bgScriptOutput->installEventFilter(e);
return dock->addDockWidget(area, dw, areaw); return dock->addDockWidget(area, dw, areaw);
} }
@ -3333,7 +3346,6 @@ void MainWindow::swapEditor(EditorView *old, EditorView *cur) {
doc->disconnect(m_aShowMetaComment); doc->disconnect(m_aShowMetaComment);
} }
Q_ASSERT(cur);
auto hexeditor = cur->hexEditor(); auto hexeditor = cur->hexEditor();
auto needReload = cur->property("__RELOAD__").toBool(); auto needReload = cur->property("__RELOAD__").toBool();
if (needReload) { if (needReload) {
@ -3434,6 +3446,10 @@ void MainWindow::swapEditor(EditorView *old, EditorView *cur) {
m_metadatas->selectionModel()->hasSelection()); m_metadatas->selectionModel()->hasSelection());
}); });
for (auto &menu : m_hexContextMenu) {
menu->setProperty("__CONTEXT__", quintptr(cur->editorContext()));
}
_undoView->setStack(doc->undoStack()); _undoView->setStack(doc->undoStack());
m_curEditor = cur; m_curEditor = cur;
@ -3959,6 +3975,10 @@ void MainWindow::onOutputBgScriptOutput(
lastInfo.first = message.type; lastInfo.first = message.type;
lastInfo.second = qMakePair(message.row, message.col); lastInfo.second = qMakePair(message.row, message.col);
if (!m_bgScriptOutput->isVisible()) {
_hlAnim->start();
}
} }
void MainWindow::closeEvent(QCloseEvent *event) { void MainWindow::closeEvent(QCloseEvent *event) {

View File

@ -44,6 +44,7 @@
#include "Qt-Advanced-Docking-System/src/DockManager.h" #include "Qt-Advanced-Docking-System/src/DockManager.h"
#include "Qt-Advanced-Docking-System/src/DockWidget.h" #include "Qt-Advanced-Docking-System/src/DockWidget.h"
#include "WingPlugin/iwingplugin.h" #include "WingPlugin/iwingplugin.h"
#include "class/consolehighlighanim.h"
#include "class/recentfilemanager.h" #include "class/recentfilemanager.h"
#include "control/editorview.h" #include "control/editorview.h"
#include "control/qtableviewext.h" #include "control/qtableviewext.h"
@ -479,6 +480,8 @@ private:
ScriptingConsole *m_scriptConsole = nullptr; ScriptingConsole *m_scriptConsole = nullptr;
QPlainTextEdit *m_bgScriptOutput = nullptr; QPlainTextEdit *m_bgScriptOutput = nullptr;
ConsoleHighlighAnim *_hlAnim = nullptr;
bool m_isfinding = false; bool m_isfinding = false;
ads::CDockWidget *m_find = nullptr; ads::CDockWidget *m_find = nullptr;
QMenu *m_menuFind = nullptr; QMenu *m_menuFind = nullptr;

View File

@ -2741,12 +2741,12 @@ ads--CDockWidgetTab[activeTab="true"]
ads--CDockWidgetTab QLabel ads--CDockWidgetTab QLabel
{ {
background-color: #1b1d20; background-color: transparent;
} }
ads--CDockWidgetTab[activeTab="true"] QLabel ads--CDockWidgetTab[activeTab="false"]:hover
{ {
background-color: #202326; background-color: rgba(61, 173, 232, 0.1);
} }
ads--CDockContainerWidget > QSplitter{ ads--CDockContainerWidget > QSplitter{

View File

@ -2741,12 +2741,12 @@ ads--CDockWidgetTab[activeTab="true"]
ads--CDockWidgetTab QLabel ads--CDockWidgetTab QLabel
{ {
background-color: #d9d8d7; background-color: transparent;
} }
ads--CDockWidgetTab[activeTab="true"] QLabel ads--CDockWidgetTab[activeTab="false"]:hover
{ {
background-color: #eff0f1; background-color: rgba(61, 173, 232, 0.2);
} }
ads--CDockContainerWidget > QSplitter{ ads--CDockContainerWidget > QSplitter{