Compare commits

...

7 Commits

124 changed files with 5977 additions and 1689 deletions

View File

@ -7,7 +7,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Run clang-format style check for C/C++/Protobuf programs.
uses: jidicula/clang-format-action@v4.13.0
uses: jidicula/clang-format-action@v4.14.0
with:
clang-format-version: '12'
fallback-style: 'LLVM' # optional

View File

@ -9,6 +9,6 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4
- name: cmake-format lint
uses: neg-c/cmake-format-action@v0.1.1
uses: neg-c/cmake-format-action@v0.1.3
with:
inplace: true

View File

@ -0,0 +1,63 @@
name: CMake build release for linux
on:
push:
branches:
- release
env:
BUILD_TYPE: Release
jobs:
build-release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: 'recursive'
token: ${{ secrets.CONTRIBUTORS_TOKEN }}
- name: Install Qt
# Installs the Qt SDK
uses: jurplel/install-qt-action@v3
with:
version: 6.8.1
host: 'linux'
target: 'desktop'
arch: 'linux_gcc_64'
cache: true
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/build/package
- name: Build
# Build your program with the given configuration
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --target install
- name: Install Packing Tools
run: sudo apt install fakeroot patchelf -y
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: '3.8'
cache: 'pip'
- name: Install Python packages
run: pip install -r ${{github.workspace}}/mkinstaller/linuxdeploy/requirements.txt
- name: Deploy WingHexExplorer2
run: python ${{github.workspace}}/mkinstaller/linuxdeploy/deploy.py ${{github.workspace}}/build
- name: +x for ld-linux if it has
run: sudo ${{github.workspace}}/mkinstaller/linuxdeploy/add-ld-x.sh ${{github.workspace}}/build/package
- name: Create installer
run: bash ${{github.workspace}}/mkinstaller/linuxdeploy/build.sh ${{github.workspace}}/build/package
- uses: actions/upload-artifact@v4
with:
name: WingHexExplorer2-linux-release-build-cache
path: ${{github.workspace}}/mkinstaller/linuxdeploy/build

View File

@ -0,0 +1,66 @@
name: CMake build release for win
on:
push:
branches:
- release
env:
BUILD_TYPE: Release
jobs:
build-release:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
with:
submodules: 'recursive'
token: ${{ secrets.CONTRIBUTORS_TOKEN }}
- name: Install Qt
# Installs the Qt SDK
uses: jurplel/install-qt-action@v3
with:
version: 6.6.2
host: 'windows'
target: 'desktop'
arch: 'win64_msvc2019_64'
cache: true
- name: Add Chinese support file for InnoSetup
run: |
$sourcePath = "${{github.workspace}}/mkinstaller/innoSetup/ChineseSimplified.isl"
$destinationPath = "C:\Program Files (x86)\Inno Setup 6\Languages\ChineseSimplified.isl"
Start-Process powershell -ArgumentList "Copy-Item -Path '$sourcePath' -Destination '$destinationPath' -Force" -Verb runAs
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
- name: Build
# Build your program with the given configuration
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: '3.8'
cache: 'pip'
- name: Install Python packages
run: pip install -r ${{github.workspace}}/mkinstaller/innoSetup/requirements.txt
- name: Deploy WingHexExplorer2
run: python ${{github.workspace}}/mkinstaller/innoSetup/mkinnopak.py --no-build "${{github.workspace}}/build"
- name: Compile .ISS to .EXE Installer
uses: Minionguyjpro/Inno-Setup-Action@v1.2.2
with:
path: build/package/WingHexExplorer2/mkiss.iss
options: /O${{github.workspace}}/mkinstaller/innoSetup
- uses: actions/upload-artifact@v4
with:
name: WingHexExplorer2-win-release-build-cache
path: ${{github.workspace}}/mkinstaller/innoSetup/*.exe

View File

@ -1,6 +1,12 @@
name: CMake build check
on: [push, pull_request]
on:
push:
branches:
- main
pull_request:
branches:
- main
env:
BUILD_TYPE: Release

3
.gitmodules vendored
View File

@ -10,3 +10,6 @@
[submodule "3rdparty/SingleApplication"]
path = 3rdparty/SingleApplication
url = git@github.com:itay-grudev/SingleApplication.git
[submodule "3rdparty/json"]
path = 3rdparty/json
url = git@github.com:nlohmann/json.git

@ -1 +1 @@
Subproject commit d259eab41fd08fbde83cf1a7b01f4def6a09e895
Subproject commit 57ef77e4793ca14f448f485f52392ab0eefe968b

View File

@ -23,6 +23,7 @@ QConsoleWidget::QConsoleWidget(QWidget *parent)
: QEditor(false, parent), mode_(Output) {
iodevice_ = new QConsoleIODevice(this, this);
m_doc->setProperty("console", QVariant::fromValue(inpos_));
setFlag(QEditor::AutoCloseChars, true);
setAcceptDrops(false);
setUndoRedoEnabled(false);
setCursorMirrorEnabled(false);
@ -58,6 +59,13 @@ QString QConsoleWidget::getCommandLine() {
return code.replace(QChar::ParagraphSeparator, QChar::LineFeed);
}
void QConsoleWidget::paste() {
auto text = qApp->clipboard()->text();
if (canPaste()) {
m_cursor.insertText(text.replace('\n', ' '));
}
}
void QConsoleWidget::handleReturnKey() {
QString code = getCommandLine();

View File

@ -34,6 +34,7 @@ public:
QString getCommandLine();
public slots:
virtual void paste() override;
// write to StandardOutput
void writeStdOut(const QString &s);

View File

@ -1,15 +1,7 @@
#include "qhexcursor.h"
#include <QWidget>
void QHexCursor::setSelection(qsizetype offset, qsizetype length) {
auto lld = lldiv(offset, m_position.lineWidth);
m_position.line = lld.quot;
m_position.column = int(lld.rem);
moveTo(m_position);
lld = lldiv(offset + length - 1, m_position.lineWidth);
m_selection.line = lld.quot;
m_selection.column = int(lld.rem);
}
#include <QtConcurrent/QtConcurrentMap>
QHexCursor::QHexCursor(QObject *parent)
: QObject(parent), m_insertionmode(QHexCursor::OverwriteMode) {
@ -20,104 +12,168 @@ QHexCursor::QHexCursor(QObject *parent)
m_selection.line = m_selection.column = 0;
m_position.nibbleindex = m_selection.nibbleindex = 1;
setLineWidth(DEFAULT_HEX_LINE_LENGTH);
}
const QHexPosition &QHexCursor::selectionStart() const {
if (m_position.line < m_selection.line)
return m_position;
if (m_position.line == m_selection.line) {
if (m_position.column < m_selection.column)
return m_position;
}
return m_selection;
const QHexPosition &QHexCursor::selectionStart(qsizetype index) const {
return m_sels.at(index).start;
}
const QHexPosition &QHexCursor::selectionEnd() const {
if (m_position.line > m_selection.line)
return m_position;
if (m_position.line == m_selection.line) {
if (m_position.column > m_selection.column)
return m_position;
}
return m_selection;
const QHexPosition &QHexCursor::selectionEnd(qsizetype index) const {
return m_sels.at(index).end;
}
const QHexPosition &QHexCursor::position() const { return m_position; }
qsizetype QHexCursor::selectionCount() const { return m_sels.size(); }
const QHexSelection &QHexCursor::selection(qsizetype index) const {
return m_sels.at(index);
}
QHexCursor::InsertionMode QHexCursor::insertionMode() const {
return m_insertionmode;
}
qsizetype QHexCursor::selectionLength() const {
return this->selectionEnd() - this->selectionStart() + 1;
qsizetype QHexCursor::selectionLength(qsizetype index) const {
return m_sels.at(index).length();
}
qsizetype QHexCursor::currentLine() const { return m_position.line; }
int QHexCursor::currentColumn() const { return m_position.column; }
int QHexCursor::currentNibble() const { return m_position.nibbleindex; }
qsizetype QHexCursor::selectionLine() const { return m_selection.line; }
qsizetype QHexCursor::selectionColumn() const { return m_selection.column; }
int QHexCursor::selectionNibble() const { return m_selection.nibbleindex; }
qsizetype QHexCursor::currentSelectionLength() const {
if (hasPreviewSelection() && m_preMode != SelectionRemove) {
return qAbs(m_position - m_selection);
}
qsizetype len = 0;
auto res = QtConcurrent::blockingMappedReduced(
m_sels, &QHexSelection::length,
QOverload<
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
const qsizetype &
#else
QVector<qsizetype>::parameter_type
#endif
>::of(&QVector<qsizetype>::append));
for (auto &item : res) {
len += item;
}
return len;
}
qsizetype QHexCursor::currentLine() const { return m_selection.line; }
int QHexCursor::currentColumn() const { return m_selection.column; }
int QHexCursor::currentNibble() const { return m_selection.nibbleindex; }
bool QHexCursor::isLineSelected(qsizetype line) const {
if (!this->hasSelection())
return false;
auto first = std::min(m_position.line, m_selection.line);
auto last = std::max(m_position.line, m_selection.line);
if (isLineSelected(previewSelection(), line)) {
return true;
}
if ((line < first) || (line > last))
return false;
for (auto &sel : m_sels) {
if (isLineSelected(sel, line)) {
return true;
}
}
return true;
return false;
}
bool QHexCursor::hasSelection() const { return m_position != m_selection; }
bool QHexCursor::hasSelection() const {
return hasPreviewSelection() || hasInternalSelection();
}
void QHexCursor::clearSelection() {
bool QHexCursor::hasInternalSelection() const { return !m_sels.isEmpty(); }
void QHexCursor::clearPreviewSelection() {
m_selection = m_position;
emit positionChanged();
m_preMode = SelectionNormal;
}
void QHexCursor::moveTo(const QHexPosition &pos) {
this->moveTo(pos.line, pos.column, pos.nibbleindex);
void QHexCursor::clearSelection() { m_sels.clear(); }
void QHexCursor::moveTo(const QHexPosition &pos, bool clearSelection) {
this->moveTo(pos.line, pos.column, pos.nibbleindex, clearSelection);
}
void QHexCursor::select(const QHexPosition &pos) {
this->select(pos.line, pos.column, pos.nibbleindex);
void QHexCursor::select(const QHexPosition &pos,
QHexCursor::SelectionModes mode) {
this->select(pos.line, pos.column, pos.nibbleindex, mode);
}
void QHexCursor::moveTo(qsizetype line, int column, int nibbleindex) {
m_selection.line = line;
m_selection.column = column;
m_selection.nibbleindex = nibbleindex;
this->select(line, column, nibbleindex);
}
void QHexCursor::select(qsizetype line, int column, int nibbleindex) {
void QHexCursor::moveTo(qsizetype line, int column, int nibbleindex,
bool clearSelection) {
m_position.line = line;
m_position.column = qMax(0, column); // fix the bug by wingsummer
m_position.nibbleindex = nibbleindex;
m_selection = m_position;
if (clearSelection) {
m_sels.clear();
}
emit positionChanged();
}
void QHexCursor::moveTo(qsizetype offset) {
auto line = offset / m_lineWidth;
this->moveTo(line, int(offset - (line * m_lineWidth)));
void QHexCursor::select(qsizetype line, int column, int nibbleindex,
SelectionModes modes) {
if (modes.testFlag(SelectionPreview)) {
m_selection.line = line;
m_selection.column = qMax(0, column); // fix the bug by wingsummer
m_selection.nibbleindex = nibbleindex;
modes.setFlag(SelectionPreview, false);
m_preMode = SelectionMode(int(modes));
} else {
QHexSelection sel;
sel.start = m_position;
sel.end.line = line;
sel.end.column = column;
sel.end.nibbleindex = nibbleindex;
sel.normalize();
switch (modes) {
case SelectionAdd:
mergeAdd(sel);
break;
case SelectionNormal:
m_sels.clear();
m_sels.append(sel);
break;
case SelectionRemove:
mergeRemove(sel);
break;
}
}
emit positionChanged();
emit selectionChanged();
}
void QHexCursor::setPos(qsizetype offset, int nibbleindex) {
void QHexCursor::moveTo(qsizetype offset, bool clearSelection) {
auto line = offset / m_lineWidth;
this->moveTo(line, int(offset - (line * m_lineWidth)), nibbleindex);
this->moveTo(line, int(offset - (line * m_lineWidth)), clearSelection);
}
void QHexCursor::select(qsizetype length) {
this->select(
m_position.line,
std::min(m_lineWidth - 1, int(m_position.column + length - 1)));
void QHexCursor::setPos(qsizetype offset, int nibbleindex,
bool clearSelection) {
auto line = offset / m_lineWidth;
this->moveTo(line, int(offset - (line * m_lineWidth)), nibbleindex,
clearSelection);
}
void QHexCursor::select(qsizetype length, QHexCursor::SelectionModes mode) {
this->select(m_position.line,
std::min(m_lineWidth - 1, int(m_position.column + length - 1)),
1, mode);
}
void QHexCursor::selectOffset(qsizetype offset, qsizetype length) {
@ -137,6 +193,11 @@ void QHexCursor::setLineWidth(quint8 width) {
m_lineWidth = width;
m_position.lineWidth = width;
m_selection.lineWidth = width;
for (auto &sel : m_sels) {
sel.start.lineWidth = width;
sel.end.lineWidth = width;
}
}
void QHexCursor::switchInsertionMode() {
@ -147,3 +208,100 @@ void QHexCursor::switchInsertionMode() {
emit insertionModeChanged();
}
bool QHexCursor::hasPreviewSelection() const {
return m_selection != m_position;
}
void QHexCursor::mergeRemove(const QHexSelection &sel) {
Q_ASSERT(sel.isNormalized());
QList<QHexSelection> buffer;
QMutex locker;
QtConcurrent::blockingMap(m_sels,
[&buffer, &locker, &sel](QHexSelection &s) {
auto r = s.removeSelection(sel);
if (r.has_value()) {
QMutexLocker l(&locker);
buffer.append(r.value());
}
});
// clean up invalid selections
auto cleanup = [](const QHexSelection &s) { return s.start == s.end; };
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
m_sels.removeIf(cleanup);
#else
m_sels.erase(std::remove_if(m_sels.begin(), m_sels.end(), cleanup));
#endif
QtConcurrent::blockingMap(
buffer, [&locker, this](QHexSelection &s) { mergeAdd(s, &locker); });
}
void QHexCursor::mergeAdd(const QHexSelection &sel, QMutex *locker) {
bool merged = false;
Q_ASSERT(sel.isNormalized());
for (auto p = m_sels.begin(); p != m_sels.end(); ++p) {
merged = p->mergeSelection(sel, locker);
if (merged) {
break;
}
}
if (!merged) {
m_sels.append(sel);
}
}
bool QHexCursor::isLineSelected(const QHexSelection &sel,
qsizetype line) const {
auto first = std::min(sel.start.line, sel.end.line);
auto last = std::max(sel.start.line, sel.end.line);
if ((line >= first) && (line <= last))
return true;
return false;
}
QHexSelection QHexCursor::previewSelection() const {
QHexSelection sel;
sel.start = m_position;
sel.end = m_selection;
return sel;
}
void QHexCursor::setPreviewSelectionMode(SelectionMode mode) {
m_preMode = mode;
}
QHexCursor::SelectionMode QHexCursor::previewSelectionMode() const {
return m_preMode;
}
void QHexCursor::mergePreviewSelection() {
auto ss = QHexSelection{m_position, m_selection}.normalized();
switch (m_preMode) {
case SelectionNormal:
if (m_sels.isEmpty()) {
m_sels.append(ss);
}
break;
case SelectionAdd:
mergeAdd(ss);
break;
case SelectionRemove:
mergeRemove(ss);
break;
case SelectionSingle:
m_sels.clear();
m_sels.append(ss);
break;
case SelectionPreview:
// should not go here
break;
}
clearPreviewSelection();
}

View File

@ -1,23 +1,40 @@
#ifndef QHEXCURSOR_H
#define QHEXCURSOR_H
#include <QMutex>
#include <QObject>
#include <optional>
#define DEFAULT_HEX_LINE_LENGTH 0x10
#define DEFAULT_AREA_IDENTATION 0x01
struct QHexPosition {
qsizetype line;
int column;
quint8 lineWidth;
int nibbleindex;
qsizetype line = -1;
int column = -1;
quint8 lineWidth = 0;
int nibbleindex = -1;
QHexPosition() = default;
inline qsizetype offset() const {
return static_cast<qsizetype>(line * lineWidth) + column;
}
inline int operator-(const QHexPosition &rhs) const {
return int(this->offset() - rhs.offset());
inline qsizetype operator-(const QHexPosition &rhs) const {
return this->offset() - rhs.offset();
}
inline void operator++() {
this->column++;
if (this->column >= lineWidth) {
this->line++;
this->column = 0;
}
}
inline void operator--() {
this->column--;
if (this->column < 0) {
this->line--;
this->column = lineWidth - 1;
}
}
inline bool operator==(const QHexPosition &rhs) const {
return (line == rhs.line) && (column == rhs.column) &&
@ -27,6 +44,135 @@ struct QHexPosition {
return (line != rhs.line) || (column != rhs.column) ||
(nibbleindex != rhs.nibbleindex);
}
inline bool operator<(const QHexPosition &rhs) const {
return this->offset() < rhs.offset();
}
inline bool operator>(const QHexPosition &rhs) const {
return this->offset() > rhs.offset();
}
inline bool operator<=(const QHexPosition &rhs) const {
return this->offset() <= rhs.offset();
}
inline bool operator>=(const QHexPosition &rhs) const {
return this->offset() >= rhs.offset();
}
};
struct QHexSelection {
QHexPosition start;
QHexPosition end;
void normalize(QMutex *locker = nullptr) {
if (locker) {
locker->lock();
}
if (end < start) {
std::swap(start, end);
}
if (locker) {
locker->unlock();
}
}
qsizetype length() const { return qAbs(end - start) + 1; }
bool contains(const QHexSelection &sel) const {
Q_ASSERT(isNormalized());
return this->start <= sel.start && this->end >= sel.end;
}
bool isLineSelected(qsizetype line) const {
Q_ASSERT(isNormalized());
if (this->start.line == line || this->end.line == line) {
return true;
}
return this->start.line < line && line < this->end.line;
}
bool isNormalized() const { return end >= start; }
QHexSelection normalized() const {
QHexSelection sel = *this;
if (end < start) {
std::swap(sel.start, sel.end);
}
return sel;
}
bool isIntersected(const QHexSelection &sel) const {
Q_ASSERT(isNormalized());
return !(sel.end < this->start || sel.start > this->end);
}
void intersect(const QHexSelection &sel, QMutex *locker = nullptr) {
Q_ASSERT(isNormalized());
auto s = sel.normalized();
if (locker) {
locker->lock();
}
this->start = qMax(this->start, s.start);
this->end = qMin(this->end, s.end);
if (locker) {
locker->unlock();
}
}
Q_REQUIRED_RESULT std::optional<QHexSelection>
removeSelection(const QHexSelection &sel, QMutex *locker = nullptr) {
Q_ASSERT(isNormalized());
Q_ASSERT(sel.isNormalized());
if (locker) {
locker->lock();
}
if (sel.start <= this->start) {
if (sel.end >= this->start) {
if (sel.end < this->end) {
this->start = sel.end;
++this->start;
} else {
// makes it invalid, delete later
this->end = this->start;
}
}
} else if (sel.start > this->start && sel.start < this->end) {
this->end = sel.start;
--this->end;
if (sel.end < this->end) {
// break into two ranges
QHexSelection sel;
sel.start = sel.end;
sel.end = this->end;
if (locker) {
locker->unlock();
}
return sel;
}
}
if (locker) {
locker->unlock();
}
return {};
}
bool mergeSelection(const QHexSelection &sel, QMutex *locker = nullptr) {
Q_ASSERT(isNormalized());
if (isIntersected(sel)) {
if (locker) {
locker->lock();
}
this->start = qMin(this->start, sel.start);
this->end = qMax(this->end, sel.end);
if (locker) {
locker->unlock();
}
return true;
}
return false;
}
};
class QHexCursor : public QObject {
@ -35,50 +181,89 @@ class QHexCursor : public QObject {
public:
enum InsertionMode { OverwriteMode, InsertMode };
enum SelectionMode {
SelectionNormal = 0,
SelectionAdd = 1,
SelectionRemove = 2,
SelectionSingle = 4,
SelectionPreview = 16 // a flag
};
Q_DECLARE_FLAGS(SelectionModes, SelectionMode)
public:
explicit QHexCursor(QObject *parent = nullptr);
public:
const QHexPosition &selectionStart() const;
const QHexPosition &selectionEnd() const;
const QHexPosition &position() const;
void setSelection(qsizetype offset,
qsizetype length); // added by wingsummer
qsizetype selectionCount() const;
const QHexSelection &selection(qsizetype index) const;
const QHexPosition &selectionStart(qsizetype index) const;
const QHexPosition &selectionEnd(qsizetype index) const;
InsertionMode insertionMode() const;
qsizetype selectionLength() const;
qsizetype currentLine() const;
int currentColumn() const;
int currentNibble() const;
qsizetype selectionLine() const;
qsizetype selectionColumn() const;
int selectionNibble() const;
qsizetype selectionLength(qsizetype index) const;
qsizetype currentSelectionLength() const;
bool atEnd() const;
bool isLineSelected(qsizetype line) const;
bool hasSelection() const;
bool hasInternalSelection() const;
void clearPreviewSelection();
void clearSelection();
public:
void moveTo(const QHexPosition &pos);
void moveTo(qsizetype line, int column, int nibbleindex = 1);
void moveTo(qsizetype offset);
void setPos(qsizetype offset, int nibbleindex);
// 和 moveTo 其实一样,只是为了不冲突
void select(const QHexPosition &pos);
void select(qsizetype line, int column, int nibbleindex = 1);
void select(qsizetype length);
void moveTo(const QHexPosition &pos, bool clearSelection = false);
void moveTo(qsizetype line, int column, int nibbleindex = 1,
bool clearSelection = false);
void moveTo(qsizetype offset, bool clearSelection = false);
void setPos(qsizetype offset, int nibbleindex, bool clearSelection = false);
void select(const QHexPosition &pos,
QHexCursor::SelectionModes mode = SelectionNormal);
void select(qsizetype line, int column, int nibbleindex = 1,
QHexCursor::SelectionModes mode = SelectionNormal);
void select(qsizetype length,
QHexCursor::SelectionModes mode = SelectionNormal);
void selectOffset(qsizetype offset, qsizetype length);
void setInsertionMode(InsertionMode mode);
void setLineWidth(quint8 width);
void switchInsertionMode();
bool hasPreviewSelection() const;
QHexSelection previewSelection() const;
void setPreviewSelectionMode(SelectionMode mode);
SelectionMode previewSelectionMode() const;
void mergePreviewSelection();
private:
void mergeRemove(const QHexSelection &sel);
void mergeAdd(const QHexSelection &sel, QMutex *locker = nullptr);
bool isLineSelected(const QHexSelection &sel, qsizetype line) const;
signals:
void positionChanged();
void insertionModeChanged();
void selectionChanged();
private:
InsertionMode m_insertionmode;
quint8 m_lineWidth;
QHexPosition m_position, m_selection;
SelectionMode m_preMode;
QList<QHexSelection> m_sels;
};
#endif // QHEXCURSOR_H

View File

@ -476,6 +476,12 @@ void QHexDocument::redo() {
emit documentChanged();
}
void QHexDocument::beginMarco(const QString &text) {
m_undostack->beginMacro(text);
}
void QHexDocument::endMarco() { m_undostack->endMacro(); }
void QHexDocument::Insert(QHexCursor *cursor, qsizetype offset, uchar b,
int nibbleindex) {
if (m_keepsize || m_readonly || m_islocked)

View File

@ -104,6 +104,9 @@ public slots:
void undo();
void redo();
void beginMarco(const QString &text);
void endMarco();
void Insert(QHexCursor *cursor, qsizetype offset, uchar b, int nibbleindex);
void Insert(QHexCursor *cursor, qsizetype offset, const QByteArray &data,
int nibbleindex);

View File

@ -177,6 +177,10 @@ bool QHexMetadata::lineHasMetadata(qsizetype line) const {
qsizetype QHexMetadata::size() const { return m_metadata.size(); }
void QHexMetadata::beginMarco(const QString &text) { m_undo->beginMacro(text); }
void QHexMetadata::endMarco() { m_undo->endMacro(); }
void QHexMetadata::clear() {
m_linemeta.clear();
m_metadata.clear();

View File

@ -31,7 +31,8 @@ constexpr inline bool QNothrowHashable_v = QNothrowHashable<T>::value;
} // namespace QtPrivate
template <typename... T>
constexpr qhash_result_t qHashMulti(size_t seed, const T &...args) noexcept(
constexpr qhash_result_t
qHashMulti(qhash_result_t seed, const T &...args) noexcept(
std::conjunction_v<QtPrivate::QNothrowHashable<T>...>) {
QtPrivate::QHashCombine hash;
return ((seed = hash(seed, args)), ...), seed;
@ -85,6 +86,9 @@ public:
/*============================*/
// added by wingsummer
void beginMarco(const QString &text);
void endMarco();
void ModifyMetadata(QHexMetadataItem newmeta, QHexMetadataItem oldmeta);
void RemoveMetadatas(const QList<QHexMetadataItem> &items);
void RemoveMetadata(QHexMetadataItem item);

View File

@ -429,8 +429,31 @@ void QHexRenderer::applySelection(QTextCursor &textcursor, qsizetype line,
if (!m_cursor->isLineSelected(line))
return;
const QHexPosition &startsel = m_cursor->selectionStart();
const QHexPosition &endsel = m_cursor->selectionEnd();
auto total = m_cursor->selectionCount();
for (int i = 0; i < total; ++i) {
applySelection(m_cursor->selection(i), textcursor, line, factor, false,
false);
}
if (m_cursor->hasPreviewSelection()) {
applySelection(
m_cursor->previewSelection().normalized(), textcursor, line, factor,
m_cursor->previewSelectionMode() == QHexCursor::SelectionRemove,
m_cursor->previewSelectionMode() == QHexCursor::SelectionNormal &&
m_cursor->hasInternalSelection());
}
}
void QHexRenderer::applySelection(const QHexSelection &selection,
QTextCursor &textcursor, qsizetype line,
Factor factor, bool strikeOut,
bool hasSelection) const {
if (!selection.isLineSelected(line)) {
return;
}
const QHexPosition &startsel = selection.start;
const QHexPosition &endsel = selection.end;
if (startsel.line == endsel.line) {
textcursor.setPosition(startsel.column * factor);
@ -455,8 +478,13 @@ void QHexRenderer::applySelection(QTextCursor &textcursor, qsizetype line,
textcursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, 1);
QTextCharFormat charformat;
charformat.setBackground(m_selBackgroundColor);
charformat.setForeground(m_selectionColor);
charformat.setBackground(strikeOut || hasSelection
? m_selBackgroundColor.darker()
: m_selBackgroundColor);
charformat.setForeground(strikeOut ? m_selectionColor.darker()
: m_selectionColor);
charformat.setFontStrikeOut(strikeOut);
charformat.setFontItalic(strikeOut);
textcursor.mergeCharFormat(charformat);
}
@ -543,7 +571,7 @@ void QHexRenderer::drawHex(QPainter *painter, const QRect &linerect,
textcursor.insertText(this->hexString(line, &rawline));
if (line == this->documentLastLine())
textcursor.insertText(" ");
textcursor.insertText(QStringLiteral(" "));
QRect hexrect = linerect;
hexrect.setX(this->getHexColumnX() + this->borderSize());

View File

@ -120,8 +120,13 @@ private:
Factor factor) const;
void applyMetadata(QTextCursor &textcursor, qsizetype line,
Factor factor) const;
void applySelection(QTextCursor &textcursor, qsizetype line,
Factor factor) const;
void applySelection(const QHexSelection &selection, QTextCursor &textcursor,
qsizetype line, Factor factor, bool strikeOut,
bool hasSelection) const;
void applyBookMark(QTextCursor &textcursor, qsizetype line,
Factor factor); // added by wingsummer
void applyCursorAscii(QTextCursor &textcursor, qsizetype line) const;

View File

@ -44,7 +44,13 @@ qsizetype QHexView::currentRow() { return m_cursor->currentLine(); }
qsizetype QHexView::currentColumn() { return m_cursor->currentColumn(); }
qsizetype QHexView::currentOffset() { return m_cursor->position().offset(); }
qsizetype QHexView::selectlength() { return m_cursor->selectionLength(); }
qsizetype QHexView::currentSelectionLength() {
return m_cursor->currentSelectionLength();
}
qsizetype QHexView::selectionCount() { return m_cursor->selectionCount(); }
bool QHexView::hasSelection() { return m_cursor->hasSelection(); }
bool QHexView::asciiVisible() { return m_renderer->stringVisible(); }
@ -100,13 +106,15 @@ void QHexView::getStatus() {
}
void QHexView::establishSignal(QHexDocument *doc) {
connect(doc, &QHexDocument::documentChanged, this, [&]() {
connect(doc, &QHexDocument::documentChanged, this, [this]() {
this->adjustScrollBars();
this->viewport()->update();
});
connect(m_cursor, &QHexCursor::positionChanged, this,
&QHexView::moveToSelection);
connect(m_cursor, &QHexCursor::selectionChanged, this,
[this]() { this->viewport()->update(); });
connect(m_cursor, &QHexCursor::insertionModeChanged, this,
&QHexView::renderCurrentLine);
connect(doc, &QHexDocument::canUndoChanged, this,
@ -283,9 +291,6 @@ qsizetype QHexView::searchBackward(qsizetype begin, const QByteArray &ba) {
qsizetype startPos;
if (begin < 0) {
startPos = m_cursor->position().offset() - 1;
if (m_cursor->hasSelection()) {
startPos = m_cursor->selectionStart().offset() - 1;
}
} else {
startPos = begin;
}
@ -296,10 +301,17 @@ bool QHexView::RemoveSelection(int nibbleindex) {
if (!m_cursor->hasSelection())
return false;
auto res = m_document->Remove(m_cursor, m_cursor->selectionStart().offset(),
m_cursor->selectionLength(), nibbleindex);
if (res)
m_cursor->clearSelection();
auto total = m_cursor->selectionCount();
bool res = true;
m_document->beginMarco(QStringLiteral(""));
for (int i = 0; i < total; ++i) {
res &=
m_document->Remove(m_cursor, m_cursor->selectionStart(i).offset(),
m_cursor->selectionLength(i), nibbleindex);
}
m_document->endMarco();
m_cursor->clearSelection();
return res;
}
@ -307,10 +319,16 @@ bool QHexView::removeSelection() {
if (!m_cursor->hasSelection())
return false;
auto res = m_document->remove(m_cursor->selectionStart().offset(),
m_cursor->selectionLength());
if (res)
m_cursor->clearSelection();
// We essure selections are ordered by desending
// by selection-start, so it's safe to remove
auto total = m_cursor->selectionCount();
bool res = true;
for (int i = 0; i < total; ++i) {
res &= m_document->remove(m_cursor->selectionStart(i).offset(),
m_cursor->selectionLength(i));
}
m_cursor->clearSelection();
return res;
}
@ -318,12 +336,27 @@ bool QHexView::atEnd() const {
return m_cursor->position().offset() >= m_document->length();
}
QByteArray QHexView::selectedBytes() const {
if (!m_cursor->hasSelection())
return QByteArray();
QByteArray QHexView::selectedBytes(qsizetype index) const {
return m_document->read(m_cursor->selectionStart(index).offset(),
m_cursor->currentSelectionLength());
}
return m_document->read(m_cursor->selectionStart().offset(),
m_cursor->selectionLength());
QByteArray QHexView::previewSelectedBytes() const {
auto sel = m_cursor->previewSelection().normalized();
return m_document->read(sel.start.offset(), sel.length());
}
QByteArrayList QHexView::selectedBytes() const {
if (!m_cursor->hasSelection())
return {};
QByteArrayList res;
auto total = m_cursor->selectionCount();
for (int i = 0; i < total; ++i) {
res << m_document->read(m_cursor->selectionStart(i).offset(),
m_cursor->selectionLength(i));
}
return res;
}
void QHexView::paste(bool hex) {
@ -412,7 +445,7 @@ bool QHexView::copy(bool hex) {
QClipboard *c = qApp->clipboard();
auto len = m_cursor->selectionLength();
auto len = currentSelectionLength();
// 如果拷贝字节超过 ? MB 阻止
if (len > 1024 * 1024 * m_copylimit) {
@ -420,7 +453,7 @@ bool QHexView::copy(bool hex) {
return false;
}
QByteArray bytes = this->selectedBytes();
QByteArray bytes = this->selectedBytes().join();
if (hex)
bytes = bytes.toHex(' ').toUpper();
@ -521,8 +554,18 @@ void QHexView::mousePressEvent(QMouseEvent *e) {
m_renderer->selectArea(abspos);
if (m_renderer->editableArea(m_renderer->selectedArea()))
m_cursor->moveTo(position);
if (m_renderer->editableArea(m_renderer->selectedArea())) {
auto m = getSelectionMode();
bool clearSelection = false;
if (m == QHexCursor::SelectionNormal) {
clearSelection = m_cursor->selectionCount() <= 1 ||
e->modifiers().testFlag(Qt::ControlModifier);
} else if (m == QHexCursor::SelectionSingle) {
clearSelection = true;
}
m_cursor->moveTo(position, clearSelection);
}
e->accept();
}
@ -546,7 +589,9 @@ void QHexView::mouseMoveEvent(QMouseEvent *e) {
if (!m_renderer->hitTest(abspos, &position, this->firstVisibleLine()))
return;
cursor->select(position.line, position.column, 0);
cursor->select(position.line, position.column, 0,
QHexCursor::SelectionModes(
getSelectionMode() | QHexCursor::SelectionPreview));
e->accept();
}
@ -567,6 +612,13 @@ void QHexView::mouseReleaseEvent(QMouseEvent *e) {
return;
if (!m_blinktimer->isActive())
m_blinktimer->start();
if (m_cursor->hasPreviewSelection()) {
auto sel = m_cursor->previewSelection();
m_cursor->mergePreviewSelection();
m_cursor->moveTo(sel.end);
}
e->accept();
}
@ -706,7 +758,7 @@ void QHexView::moveNext(bool select) {
if (select)
cur->select(line, std::min(m_renderer->hexLineWidth() - 1, int(column)),
nibbleindex);
nibbleindex, QHexCursor::SelectionAdd);
else
cur->moveTo(line, std::min(m_renderer->hexLineWidth() - 1, int(column)),
nibbleindex);
@ -749,6 +801,34 @@ void QHexView::movePrevious(bool select) {
cur->moveTo(line, std::max(0, column), nibbleindex);
}
QHexCursor::SelectionMode QHexView::getSelectionMode() const {
auto mods = qApp->keyboardModifiers();
bool pressedShift = mods.testFlag(Qt::ShiftModifier);
bool pressedAlt = mods.testFlag(Qt::AltModifier);
bool pressedControl = mods.testFlag(Qt::ControlModifier);
if (pressedAlt && pressedShift) {
pressedShift = false;
pressedAlt = false;
pressedControl = true;
}
if (pressedControl) {
return QHexCursor::SelectionSingle;
}
if (pressedShift) {
return QHexCursor::SelectionAdd;
}
if (pressedAlt) {
return QHexCursor::SelectionRemove;
}
return QHexCursor::SelectionNormal;
}
void QHexView::renderCurrentLine() {
if (m_document)
this->renderLine(m_cursor->currentLine());
@ -896,7 +976,7 @@ bool QHexView::processMove(QHexCursor *cur, QKeyEvent *e) {
if (e->matches(QKeySequence::MoveToEndOfDocument))
cur->moveTo(m_renderer->documentLastLine(),
m_renderer->documentLastColumn());
int(m_renderer->documentLastColumn()));
else
cur->select(m_renderer->documentLastLine(),
m_renderer->documentLastColumn());
@ -911,7 +991,7 @@ bool QHexView::processMove(QHexCursor *cur, QKeyEvent *e) {
if (e->matches(QKeySequence::MoveToEndOfLine)) {
if (cur->currentLine() == m_renderer->documentLastLine())
cur->moveTo(cur->currentLine(),
m_renderer->documentLastColumn());
int(m_renderer->documentLastColumn()));
else
cur->moveTo(cur->currentLine(), m_renderer->hexLineWidth() - 1,
0);

View File

@ -51,7 +51,10 @@ public:
qsizetype currentRow();
qsizetype currentColumn();
qsizetype currentOffset();
qsizetype selectlength();
qsizetype currentSelectionLength();
qsizetype selectionCount();
bool hasSelection();
void setAsciiVisible(bool b);
bool asciiVisible();
@ -101,7 +104,9 @@ public:
bool removeSelection();
bool atEnd() const;
QByteArray selectedBytes() const;
QByteArray selectedBytes(qsizetype index) const;
QByteArray previewSelectedBytes() const;
QByteArrayList selectedBytes() const;
bool cut(bool hex);
bool copy(bool hex = false);
@ -168,6 +173,8 @@ private:
void moveNext(bool select = false);
void movePrevious(bool select = false);
QHexCursor::SelectionMode getSelectionMode() const;
private:
bool processMove(QHexCursor *cur, QKeyEvent *e);
bool processTextInput(QHexCursor *cur, QKeyEvent *e);

View File

@ -60,6 +60,12 @@ RibbonTabContent *Ribbon::addTab(const QString &tabName) {
return ribbonTabContent;
}
void Ribbon::addTab(RibbonTabContent *tabContent, const QString &tabName) {
if (tabContent) {
QTabWidget::addTab(tabContent, tabName);
}
}
RibbonTabContent *Ribbon::addTab(const QIcon &tabIcon, const QString &tabName) {
// Note: superclass QTabWidget also has a function addTab()
RibbonTabContent *ribbonTabContent = new RibbonTabContent;

View File

@ -29,6 +29,11 @@ public:
/// \param[in] tabName Name of the tab
RibbonTabContent *addTab(const QString &tabName);
/// Add a tab to the ribbon.
///
/// \param[in] tabContent pointer of the tab
void addTab(RibbonTabContent *tabContent, const QString &tabName);
/// Add a tab to the ribbon.
///
/// \param[in] tabIcon Icon of the tab

1
3rdparty/json vendored Submodule

@ -0,0 +1 @@
Subproject commit a006a7a48bb30a247f0344b788c62c2806edd90b

View File

@ -3150,7 +3150,9 @@ void QDocumentCursorHandle::setColumnMemory(bool y) {
clearFlag(ColumnMemory);
}
bool QDocumentCursorHandle::movePosition(int count, int op, int m) {
bool QDocumentCursorHandle::movePosition(int count,
QDocumentCursor::MoveOperation op,
QDocumentCursor::MoveMode m) {
if (!m_doc)
return false;
@ -3158,7 +3160,6 @@ bool QDocumentCursorHandle::movePosition(int count, int op, int m) {
int &line = m_begLine;
int &offset = m_begOffset;
static QRegularExpression wordStart("\\b\\w+$"), wordEnd("^\\w+\\b");
if (!(m & QDocumentCursor::KeepAnchor)) {
m_endLine = -1;
@ -3574,35 +3575,67 @@ bool QDocumentCursorHandle::movePosition(int count, int op, int m) {
}
case QDocumentCursor::StartOfWord: {
int x = m_doc->line(line).text().left(offset).indexOf(wordStart);
if (x != -1) {
offset = x;
auto txt = m_doc->line(line).text().left(offset);
auto len = txt.length();
qsizetype index = 0;
if (txt.back().isSpace()) {
for (qsizetype i = len - 1; i >= 0; --i) {
if (!txt.at(i).isSpace()) {
index = i + 1;
break;
}
}
} else {
qDebug("failed to find SOW");
return false;
for (qsizetype i = len - 1; i >= 0; --i) {
if (!txt.at(i).isLetterOrNumber()) {
index = i + 1;
break;
}
}
}
// if (x >= 0) {
offset = index;
// } else {
// qDebug("failed to find SOW");
// return false;
// }
refreshColumnMemory();
break;
}
case QDocumentCursor::EndOfWord: {
auto match = wordEnd.match(m_doc->line(line).text());
auto x = match.capturedEnd();
// int x = wordEnd.indexIn(m_doc->line(line).text(), offset,
// QRegExp::CaretAtOffset);
if (x == offset) {
offset += wordEnd.captureCount();
auto txt = m_doc->line(line).text().mid(offset);
qsizetype index = 0;
auto len = txt.length();
if (txt.front().isSpace()) {
for (qsizetype i = 0; i < len; ++i) {
if (!txt.at(i).isSpace()) {
index = i;
break;
}
}
} else {
qDebug("failed to find EOW");
return false;
for (qsizetype i = 0; i < len; ++i) {
if (!txt.at(i).isLetterOrNumber()) {
index = i;
break;
}
}
}
// static QRegularExpression regex("\\b\\w+");
// auto match = regex.match(txt, offset);
// if (match.hasMatch()) {
offset += index;
// } else {
// qDebug("failed to find EOW");
// return false;
// }
refreshColumnMemory();
break;
@ -3915,7 +3948,7 @@ void QDocumentCursorHandle::replaceSelectedText(const QString &text) {
int begline, begcol;
beginBoundary(begline, begcol);
bool atStart = (begline == m_begLine && begcol == m_begOffset);
// bool atStart = (begline == m_begLine && begcol == m_begOffset);
if (text.isEmpty()) {
removeSelectedText();

View File

@ -90,7 +90,8 @@ public:
int position() const;
void shift(int offset);
bool movePosition(int offset, int op, int m);
bool movePosition(int offset, QDocumentCursor::MoveOperation op,
QDocumentCursor::MoveMode m);
void insertText(const QString &s, bool keepAnchor = false,
const QString &sfmtID = {});

View File

@ -2368,11 +2368,6 @@ void QEditor::createSimpleBasicContextMenu(bool shortcut, bool extTool) {
\internal
*/
void QEditor::keyPressEvent(QKeyEvent *e) {
if (flag(ReadOnly)) {
e->ignore();
return;
}
for (auto &b : m_bindings)
if (b->keyPressEvent(e, this))
return;
@ -2438,9 +2433,17 @@ void QEditor::keyPressEvent(QKeyEvent *e) {
copy();
break;
} else if (e->matches(QKeySequence::Paste)) {
if (flag(ReadOnly)) {
e->ignore();
return;
}
paste();
break;
} else if (e->matches(QKeySequence::Cut)) {
if (flag(ReadOnly)) {
e->ignore();
return;
}
cut();
break;
} else if (e->matches(QKeySequence::Print)) {
@ -2897,6 +2900,7 @@ void QEditor::mouseDoubleClickEvent(QMouseEvent *e) {
repaintCursor();
viewport()->repaint();
} else {
// qDebug("invalid cursor");
}
@ -3615,10 +3619,11 @@ bool QEditor::processCursor(QDocumentCursor &c, QKeyEvent *e, bool &b) {
if (flag(FoldedCursor))
return false;
if (hasSelection)
if (hasSelection) {
c.removeSelectedText();
else
} else {
c.deletePreviousChar();
}
break;
@ -3688,9 +3693,46 @@ bool QEditor::processCursor(QDocumentCursor &c, QKeyEvent *e, bool &b) {
text.replace("\t", QString(m_doc->tabStop(), ' '));
}
c.beginEditBlock();
insertText(c, text);
c.endEditBlock();
if (flag(AutoCloseChars)) {
// auto close: {} [] () "" ''
if (isAutoCloseChar(text)) {
QString content =
text + m_cursor.selectedText() + getPairedCloseChar(text);
c.replaceSelectedText(content);
c.clearSelection();
} else {
if (text == QStringLiteral("\"") ||
text == QStringLiteral("'")) {
if (c.selectionStart().lineNumber() ==
c.selectionEnd().lineNumber()) {
if (c.hasSelection()) {
QString content =
text + m_cursor.selectedText() + text;
c.replaceSelectedText(content);
c.clearSelection();
} else {
auto ch = c.nextChar();
if (ch == QChar('"') || ch == QChar('\'')) {
c.movePosition(1);
} else {
c.beginEditBlock();
insertText(c, text + text);
c.endEditBlock();
c.movePosition(-1);
}
}
}
} else {
c.beginEditBlock();
insertText(c, text);
c.endEditBlock();
}
}
} else {
c.beginEditBlock();
insertText(c, text);
c.endEditBlock();
}
break;
}
@ -3767,9 +3809,9 @@ void QEditor::insertText(QDocumentCursor &c, const QString &text,
if ((lines.count() == 1) || !flag(AdjustIndent)) {
preInsert(c, lines.first());
if (flag(ReplaceTabs)) {
// TODO : replace tabs by spaces properly
}
// if (flag(ReplaceTabs)) {
// // replace tabs by spaces properly
// }
c.insertText(text, false, sfmtID);
} else {
@ -4258,6 +4300,25 @@ bool QEditor::unindent(const QDocumentCursor &cur) {
return true;
}
bool QEditor::isAutoCloseChar(const QString &ch) {
// auto close: {} [] ()
return ch == QStringLiteral("{") || ch == QStringLiteral("[") ||
ch == QStringLiteral("(");
}
QString QEditor::getPairedCloseChar(const QString &ch) {
// auto close: {} [] ()
if (ch == QStringLiteral("{")) {
return QStringLiteral("}");
} else if (ch == QStringLiteral("[")) {
return QStringLiteral("]");
} else if (ch == QStringLiteral("(")) {
return QStringLiteral(")");
} else {
return {};
}
}
/*!
\internal
\brief Copy the selection to the clipboard

View File

@ -411,6 +411,10 @@ public:
private:
bool unindent(const QDocumentCursor &cur);
bool isAutoCloseChar(const QString &ch);
QString getPairedCloseChar(const QString &ch);
protected slots:
void documentWidthChanged(int newWidth);
void documentHeightChanged(int newWidth);

2
3rdparty/qwindowkit vendored

@ -1 +1 @@
Subproject commit f93657fa82bdd37dba68ea962d5e9b2cf4fd4d60
Subproject commit ba8e8a32fc6e909ad0a2c152e36b6660c01fdad5

View File

@ -8,7 +8,7 @@ set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(PROJECT_VERSION "2.0.0-WIP")
set(PROJECT_VERSION "2.0.0-beta")
find_package(
QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Network Concurrent
@ -17,6 +17,13 @@ find_package(
Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network Concurrent
PrintSupport Xml LinguistTools)
install(CODE "set(CMAKE_INSTALL_LOCAL_ONLY TRUE)" ALL_COMPONENTS)
option(BUILD_TEST_PLUGIN OFF)
if(BUILD_TEST_PLUGIN)
add_subdirectory(TestPlugin)
endif()
add_definitions(-DWINGHEX_VERSION="${PROJECT_VERSION}"
-DAPP_ORG="WingCloudStudio" -DAPP_NAME="${PROJECT_NAME}")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/WINGHEX_VERSION" ${PROJECT_VERSION})
@ -63,6 +70,7 @@ add_subdirectory(3rdparty/qcodeedit2)
add_subdirectory(3rdparty/Qt-Advanced-Docking-System)
add_subdirectory(3rdparty/AngelScript/sdk/angelscript/projects/cmake)
add_subdirectory(3rdparty/QJsonModel)
add_subdirectory(3rdparty/json)
set(ANGEL_SCRIPT_ADDON_ROOT
"${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/AngelScript/sdk/add_on")
@ -241,7 +249,9 @@ set(CLASS_SRC
src/class/clangformatmanager.h
src/class/clangformatmanager.cpp
src/class/aspreprocesser.h
src/class/aspreprocesser.cpp)
src/class/aspreprocesser.cpp
src/class/layoutmanager.h
src/class/layoutmanager.cpp)
if(WINGHEX_USE_FRAMELESS)
set(WIDGET_FRAME_SRC
@ -305,7 +315,9 @@ set(SCRIPT_ADDON_SRC
src/scriptaddon/scriptregex.h
src/scriptaddon/scriptregex.cpp
src/scriptaddon/scriptcolor.h
src/scriptaddon/scriptcolor.cpp)
src/scriptaddon/scriptcolor.cpp
src/scriptaddon/scriptjson.cpp
src/scriptaddon/scriptjson.h)
set(CODEEDIT_WIDGET
src/qcodeeditwidget/qgotolinepanel.h
@ -379,11 +391,8 @@ foreach(TS_FILE IN LISTS TS_FILES)
set(QM_DIR "${CMAKE_CURRENT_BINARY_DIR}/.tmp/${TS_DIR}")
set(QM_OUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/${TS_DIR}")
set(LANG_NEED_COPY_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/${TS_DIR}")
set(LANG_NEED_COPY
"${LANG_NEED_COPY_PREFIX}/about.md"
"${LANG_NEED_COPY_PREFIX}/components.md"
"${LANG_NEED_COPY_PREFIX}/credits.md"
"${LANG_NEED_COPY_PREFIX}/devs.md")
set(LANG_NEED_COPY "${LANG_NEED_COPY_PREFIX}/about.md"
"${LANG_NEED_COPY_PREFIX}/devs.md")
add_custom_target(
copy_lang_files
COMMAND ${CMAKE_COMMAND} -E copy ${LANG_NEED_COPY} ${QM_DIR}
@ -391,8 +400,7 @@ foreach(TS_FILE IN LISTS TS_FILES)
set(LANG_PAK "${QM_DIR}/${LANG_PAK_NAME}")
set(LANG_COMPRESS_CONTENT "winghex.qm" "about.md" "components.md"
"credits.md" "devs.md")
set(LANG_COMPRESS_CONTENT "winghex.qm" "about.md" "devs.md")
add_custom_target(
pak_lang_files
@ -419,6 +427,7 @@ set(PROJECT_SOURCES
main.cpp
src/utilities.h
src/dbghelper.h
src/define.h
${QCONSOLEWIDGET_SRC}
${QPATHEDIT_SRC}
${WIDGET_FRAME_SRC}
@ -484,6 +493,7 @@ if(WINGHEX_USE_FRAMELESS)
QCodeEditor2
QJsonModel
angelscript
nlohmann_json::nlohmann_json
qt${QT_VERSION_MAJOR}advanceddocking)
else()
target_link_libraries(
@ -500,6 +510,7 @@ else()
QCodeEditor2
QJsonModel
angelscript
nlohmann_json::nlohmann_json
qt${QT_VERSION_MAJOR}advanceddocking)
endif()
@ -525,3 +536,20 @@ set_target_properties(
if(QT_VERSION_MAJOR EQUAL 6)
qt_finalize_executable(WingHexExplorer2)
endif()
if(${QT_VERSION_MAJOR} EQUAL 6)
if(Qt6Widgets_VERSION VERSION_GREATER_EQUAL 6.5.0)
install(
TARGETS WingHexExplorer2
BUNDLE DESTINATION .
RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX})
# Generate the deployment script.
qt6_generate_deploy_app_script(
TARGET WingHexExplorer2 OUTPUT_SCRIPT deploy_script
NO_UNSUPPORTED_PLATFORM_ERROR)
# Call the deployment script on "cmake --install".
install(SCRIPT ${deploy_script})
endif()
endif()

BIN
Donate.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

View File

@ -31,7 +31,6 @@
</p>
<p align="center">
<img src="https://github.com/Wing-summer/WingHexExplorer2/actions/workflows/qt-build-test.yml/badge.svg" />
<img src="https://github.com/Wing-summer/WingHexExplorer2/actions/workflows/clang-format-check.yml/badge.svg" />
<img src="https://github.com/Wing-summer/WingHexExplorer2/actions/workflows/cmake-format-check.yml/badge.svg" />
<img src="https://github.com/Wing-summer/WingHexExplorer2/actions/workflows/conventional-commit-check-push.yml/badge.svg" />
@ -100,20 +99,16 @@
## WingHexExplorer2
&emsp;&emsp;本软件是基于 QT 编写的十六进制编辑器,采用 C++ 进行开发,提供强大而免费的十六进制编辑器。目前只有 010 Editor 具有强大的十六进制编辑功能,但它是商用的。关注我开发动态的应该知道我开发了在 Windows 上用 C# 开发的`WingSummer.WingCloudHexExplorer`,目的是方便专业人士修改分析 PE 文件,并可作为学习 PE 结构的重要辅助工具。还有我已经开发了只针对 Deepin 平台适配的`WingHexExplorer`,目前功能已基本完善了。除了在大文件搜索功能有问题,其他已经可以稳定使用了,我决定不再维护`WingHexExplorer`,我将移植重置这个项目。
&emsp;&emsp;为什么要开发这个项目?`WingHexExplorer2`和原来的版本有什么不同?首先,窗体界面是我自己基于开源项目进行修改,重新实现了自己的界面,保证在跨平台的 UI 一致性。虽然功能和系统原生相比还是有点缺陷,也只是算美中不足了。
&emsp;&emsp;该项目终极目标是实现一个功能强大、轻量级且跨平台(只针对 PC 平台)的十六进制编辑器。当然,实现这个目标仅仅靠我是不能够实现的,这也是我开源的目的之一。我只维护我使用的操作系统平台,只对我使用的平台出现的我能够修复的 Bug 在我有空闲的时间进行及时的响应。
&emsp;&emsp;如果你发现该项目的功能并没有满足你的需求。请看看`TODO.txt`里面有没有说明。如果没有,可以通过`issue`进行提出。我会评估提出的需求是共性的。如果是特别私有的需求,我将不会实现。如果你实在想加入,请自行实现插件,也欢迎来开源。提建议的时候不要天马行空,注意本软件只提供最基本的十六进制编辑和浏览服务,比如 010 Editor 里面的模版和脚本等服务,还需大家一起通过插件来实现!希望大家不要只提需求,更要提出建设性建议和解决方案,共同维护开源社区。具体详情将会在后面进行介绍。
&emsp;&emsp;本软件是基于 QT 编写的十六进制编辑器,采用 C++ 进行开发,提供强大而免费的十六进制编辑器。该项目终极目标是实现一个功能强大、轻量级且跨平台(只针对 PC 平台)的十六进制编辑器。当然,实现这个目标仅仅靠我是不能够实现的,这也是我开源的目的之一。我只维护我使用的操作系统平台,只对我使用的平台出现的我能够修复的 Bug 在我有空闲的时间进行及时的响应。具体细节请看我的博客园的 [相关说明](https://www.cnblogs.com/wingsummer/p/18286419) 。
### 协议
&emsp;&emsp;本软件遵循`AGPL-3.0`协议,请勿用于该协议之外的用途。我的初衷是让 Linux 的生态更加完整,早日让祖国推动操作系统国产化,软件跨平台只是顺带。我不希望“吸血鬼”们利益归自己,脏活累活给开源,都那么理所当然,开源就是这么被败坏的。我不希望因为版权的事情牵扯了大量的精力。
&emsp;&emsp;本软件遵循`AGPL-3.0`协议,请勿用于该协议之外的用途。我不希望因为版权的事情牵扯了大量的精力。
&emsp;&emsp;如果你想将本软件的代码用于闭源的商业代码,想要解除`GPL`系列的必须开源的限制,请必须亲自咨询我,商讨商业授权相关事宜。
&emsp;&emsp;对于插件开发相关的,对应的开源协议就不一样了。只针对本仓库下的`src/plugin/iwingplugin.h`和`src/plugin/settingpage.h`遵守`BSD 3-Clause`协议,以允许想要做闭源和商业开发。对于本仓库下的`TestPlugin`的代码(除`TranslationUtils.cmake`这一个文件遵守`BSD 3-Clause`)遵守`MIT`协议。
### 使用声明
1. 本软件源代码不得私自应用于闭源商业用途除非你完整开源GPL协议的要求。如果要将软件仓库的代码商用闭源必须找我购买商业授权签订合同价格私聊非诚勿扰。
@ -161,15 +156,8 @@
<p align="center">
<img alt="支付宝" src="支付宝捐助.jpg" height=50% width=50%>
<img alt="捐助" src="Donate.jpg" />
<p align="center">感谢支持</p>
</p>
<p align="center">
<img alt="微信" src="微信捐助.png" height=50% width=50%>
<p align="center">感谢支持</p>
</p>
## 有关仓库

View File

@ -31,7 +31,6 @@
</p>
<p align="center">
<img src="https://github.com/Wing-summer/WingHexExplorer2/actions/workflows/qt-build-test.yml/badge.svg" />
<img src="https://github.com/Wing-summer/WingHexExplorer2/actions/workflows/clang-format-check.yml/badge.svg" />
<img src="https://github.com/Wing-summer/WingHexExplorer2/actions/workflows/cmake-format-check.yml/badge.svg" />
<img src="https://github.com/Wing-summer/WingHexExplorer2/actions/workflows/conventional-commit-check-push.yml/badge.svg" />
@ -100,20 +99,16 @@ The repository code compiles with Qt 5.15.2 and 6.6.2 on the latest versions of
## WingHexExplorer2
This software is a hexadecimal editor written in QT and developed in C++, providing a powerful and free hexadecimal editor. Currently, only 010 Editor has powerful hexadecimal editing functions, but it is commercial. Those who follow my development activities should know that I developed `WingSummer.WingCloudHexExplorer` developed in C# on Windows, with the purpose of facilitating professionals to modify and analyze PE files, and can be used as an important auxiliary tool for learning PE structure. In addition, I have developed `WingHexExplorer` adapted only for the Deepin platform, and its functions are basically complete. Except for the problem with the large file search function, the others can be used stably. I decided not to maintain `WingHexExplorer` anymore, and I will port and reset this project.
Why developping this project? What is the difference between `WingHexExplorer2` and the original version? First of all, the interface is modified by myself based on the open source project, and I re-implemented my own interface to ensure the UI consistency across platforms. Although the functions are still a little problem compared to the original system, it is just a flaw in the ointment.
The ultimate goal of this project is to create a powerful, lightweight, and cross-platform (only for PC) hex editor. Of course, I cannot achieve this goal by myself, which is one of the purposes of my open source. I only maintain the operating system platform I use, and only respond to the bugs that I can fix on the platform I use in my free time.
If you find that the functions of this project do not meet your needs. Please check if there is any description in `TODO.txt`. If not, you can raise it through `issue`. I will evaluate whether the requirements raised are common. If it is a particularly private requirement, I will not implement it. If you really want to join, please implement the plug-in yourself, and you are also welcome to open source. Don't be fanciful when making suggestions. Please note that this software only provides the most basic hexadecimal editing and browsing services, such as templates and scripts in 010 Editor, which still need everyone to work together through plugins to achieve! I hope that everyone will not only raise requirements, but also put forward constructive suggestions and solutions to jointly maintain the open source community. Specific details will be introduced later.
This software is a hexadecimal editor written in QT and developed in C++, providing a powerful and free hexadecimal editor. The ultimate goal of this project is to create a powerful, lightweight, and cross-platform (only for PC) hex editor. Of course, I cannot achieve this goal by myself, which is one of the purposes of my open source. I only maintain the operating system platform I use, and only respond to the bugs that I can fix on the platform I use in my free time. More details will be seen in my [CNBlog](https://www.cnblogs.com/wingsummer/p/18286419) .
### License
This software complies with the `AGPL-3.0` agreement. Please do not use it for purposes other than this agreement. My original intention was to make the Linux ecosystem more complete and to promote the localization of the operating system as soon as possible. Cross-platform software is just a by-product. I don't want the "vampires" to take the profits for themselves and do the dirty work for open source. It's all so natural. This is how open source is corrupted. I don't want to be involved in a lot of energy because of copyright issues.
This software complies with the `AGPL-3.0` agreement. Please do not use it for purposes other than this agreement. Selfishness knows no bound. I don't want to be involved in a lot of energy because of copyright issues.
If you want to use the code of this software for closed-source commercial code and want to lift the restriction of the `GPL` series that it must be open source, please consult me in person to discuss commercial licensing matters.
For plugin development, the corresponding open source agreements are different. Only `src/plugin/iwingplugin.h` and `src/plugin/settingpage.h` in this repository comply with the `BSD 3-Clause` agreement to allow closed-source and commercial development. The code of `TestPlugin` in this repository (except the file `TranslationUtils.cmake` which complies with `BSD 3-Clause`) complies with the `MIT` agreement.
### Usage Statement
1. The source code of this software shall not be used for closed-source commercial purposes unless you open source it completely (as required by the GPL agreement). If you want to commercially close the code of the software warehouse, you must contact me to purchase a commercial license and sign a contract. Please contact me for the price. Please do not disturb me if you are not serious.
@ -161,13 +156,7 @@ Without standing on the shoulders of giants, it will not have powerful and stabl
<p align="center">
<img alt="Alipay" src="支付宝捐助.jpg" height=50% width=50%>
<p align="center">Thanks for your support</p>
</p>
<p align="center">
<img alt="Wechat" src="微信捐助.png" height=50% width=50%>
<img alt="Donate" src="Donate.jpg" />
<p align="center">Thanks for your support</p>
</p>

View File

@ -1,13 +0,0 @@
v2.0.0 版本规划(不知道啥时候会完成,很可能会鸽):
1. 增加 AngelScript 脚本编辑器的词法相关支持,比如更好的语法高亮以及增加智能提示等。
2. 增加对内置的 AngelScript 脚本编辑器设置功能,增加语法片段管理器和支持。
3. 对程序的操作细节优化,增加更多的提醒。
4. 完善 AngelScript 脚本模块标准库。
5. 为 AngelScript 增加宏的条件编译,拓展宏的功能。
6. 使用文档和开发文档。
v3.0.0 版本规划:
1. 在有标注的情况下,增删字节之后标注会跟随动态调整。
2. 尝试增加 AngelScript 对 QT 用户界面组件的绑定尝试,可以通过脚本实现插件。

103
TestPlugin/CMakeLists.txt Normal file
View File

@ -0,0 +1,103 @@
cmake_minimum_required(VERSION 3.16)
project(TestPlugin)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Test mode, please configure the main program directory to facilitate debugging
# 便
# vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
option(TEST_MODE TRUE)
# Set the location where the SDK is stored. Only iwingplugin.h and settingpage.h
# are required.
# SDK iwingplugin.h settingpage.h
# vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
set(WINGHEX_SDK "${CMAKE_CURRENT_SOURCE_DIR}/../src/plugin")
set(PLUGIN_INTERFACE_FOUND FALSE)
set(PLUGIN_SETPAGE_FOUND FALSE)
if(EXISTS "${WINGHEX_SDK}/iwingplugin.h")
set(PLUGIN_INTERFACE_FOUND TRUE)
endif()
if(EXISTS "${WINGHEX_SDK}/settingpage.h")
set(PLUGIN_SETPAGE_FOUND TRUE)
endif()
if(PLUGIN_INTERFACE_FOUND AND PLUGIN_SETPAGE_FOUND)
message(STATUS "${WINGHEX_SDK} is valid SDK path")
else()
message(FATAL_ERROR "Invalid SDK path!")
endif()
set(WINGHEX_SDK_HEADER "${WINGHEX_SDK}/iwingplugin.h"
"${WINGHEX_SDK}/settingpage.h")
include_directories(${WINGHEX_SDK})
# For Qt
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets LinguistTools)
find_package(
Qt${QT_VERSION_MAJOR}
COMPONENTS Widgets LinguistTools
REQUIRED)
set(TS_FILES "${CMAKE_CURRENT_SOURCE_DIR}/lang/TestPlugin_zh_CN.ts")
set(TRANSLATION_PATH ${CMAKE_CURRENT_SOURCE_DIR})
if(${QT_VERSION_MAJOR} EQUAL 5)
qt5_create_translation(QM_FILES ${TRANSLATION_PATH} ${TS_FILES} OPTIONS
-no-obsolete)
elseif(${QT_VERSION_MAJOR} EQUAL 6)
qt6_create_translation(QM_FILES ${TRANSLATION_PATH} ${TS_FILES} OPTIONS
-no-obsolete)
else()
message(FATAL_ERROR "Unsupported QT version")
endif()
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/TranslationUtils.cmake)
add_plugin_translations_resource(QM_RES TestPlugin ${QM_FILES})
add_library(
TestPlugin SHARED
${WINGHEX_SDK_HEADER}
testplugin.h
testplugin.cpp
TestPlugin.json
testform.h
testform.cpp
testform.ui
${QM_FILES}
${QM_RES}
resources.qrc)
set_target_properties(TestPlugin PROPERTIES SUFFIX ".wingplg")
if(TEST_MODE)
# If you want to be able to debug easily every time you compile, please set
# this variable. Because this test plugin is a subproject of the main
# project, use CMAKE_BINARY_DIR
# 便 CMAKE_BINARY_DIR
# vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
set(WINGHEX_PATH "${CMAKE_BINARY_DIR}")
set(WINGHEX_PLUGIN_PATH "${WINGHEX_PATH}/plugin")
add_custom_command(
TARGET TestPlugin
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory ${WINGHEX_PLUGIN_PATH}
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:TestPlugin>
${WINGHEX_PLUGIN_PATH})
endif()
target_link_libraries(TestPlugin PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)

View File

@ -0,0 +1,13 @@
{
"Id" : "testplugin",
"Name" : "TestPlugin",
"Version" : "0.0.1",
"CompatVersion" : "0.0.1",
"Vendor" : "WingCloudStudio",
"VendorId" : "wingcloudstudio",
"Copyright" : "wingsummer",
"License" : "AGPL-3.0",
"Description" : "A Test Plugin for WingHexExplorer2",
"Url" : "https://github.com/Wing-summer/WingHexExplorer2",
"DocumentationUrl" : ""
}

View File

@ -0,0 +1,29 @@
BSD 3-Clause License
Copyright (c) 2019-2022, Pedro López-Cabanillas
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,51 @@
# ==============================================================================
# Copyright (C) 2024-2027 WingSummer
#
# You can redistribute this file and/or modify it under the terms of the BSD
# 3-Clause.
#
# THIS FILE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# =============================================================================
if(NOT TARGET Qt${QT_VERSION_MAJOR}::lconvert)
message(
FATAL_ERROR
"The package \"Qt${QT_VERSION_MAJOR}LinguistTools\" is required.")
endif()
set(Qt_LCONVERT_EXECUTABLE Qt${QT_VERSION_MAJOR}::lconvert)
function(ADD_PLUGIN_TRANSLATIONS_RESOURCE res_file target)
set(_qm_files ${ARGN})
set(_res_file ${CMAKE_CURRENT_BINARY_DIR}/app_translations.qrc)
file(
WRITE ${_res_file}
"<!DOCTYPE RCC><RCC version=\"1.0\">\n <qresource prefix=\"/PLGLANG/${target}\">\n"
)
foreach(_lang ${_qm_files})
get_filename_component(_filename ${_lang} NAME)
file(APPEND ${_res_file} " <file>${_filename}</file>\n")
endforeach()
file(APPEND ${_res_file} " </qresource>\n</RCC>\n")
set(${res_file}
${_res_file}
PARENT_SCOPE)
endfunction()
add_custom_target(
lupdate
COMMAND ${Qt${QT_VERSION_MAJOR}_LUPDATE_EXECUTABLE} -recursive
${PROJECT_SOURCE_DIR} -ts *.ts
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMENT "Updating translations")

BIN
TestPlugin/images/btn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
TestPlugin/images/test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@ -0,0 +1,121 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="zh_CN">
<context>
<name>TestForm</name>
<message>
<location filename="../testform.ui" line="20"/>
<source>TestForm</source>
<translation></translation>
</message>
<message>
<location filename="../testform.ui" line="30"/>
<source>Basic</source>
<translation></translation>
</message>
<message>
<location filename="../testform.ui" line="36"/>
<source>Log</source>
<translation></translation>
</message>
<message>
<location filename="../testform.ui" line="77"/>
<source>Level</source>
<translation></translation>
</message>
<message>
<location filename="../testform.ui" line="87"/>
<location filename="../testform.ui" line="180"/>
<source>Text</source>
<translation> </translation>
</message>
<message>
<location filename="../testform.ui" line="110"/>
<location filename="../testform.ui" line="203"/>
<source>Send</source>
<translation></translation>
</message>
<message>
<location filename="../testform.ui" line="117"/>
<location filename="../testform.ui" line="210"/>
<source>Clear</source>
<translation></translation>
</message>
<message>
<location filename="../testform.ui" line="129"/>
<source>Toast</source>
<translation></translation>
</message>
<message>
<location filename="../testform.ui" line="170"/>
<source>Icon</source>
<translation></translation>
</message>
<message>
<location filename="../testform.ui" line="236"/>
<source>Reader</source>
<translation></translation>
</message>
<message>
<location filename="../testform.ui" line="241"/>
<source>Controller</source>
<translation></translation>
</message>
<message>
<location filename="../testform.ui" line="246"/>
<source>MessageBox</source>
<translation></translation>
</message>
<message>
<location filename="../testform.ui" line="251"/>
<source>InputBox</source>
<translation></translation>
</message>
<message>
<location filename="../testform.ui" line="256"/>
<source>FileDialog</source>
<translation></translation>
</message>
<message>
<location filename="../testform.ui" line="261"/>
<source>ColorDialog</source>
<translation></translation>
</message>
<message>
<location filename="../testform.ui" line="266"/>
<source>DataVisual</source>
<translation></translation>
</message>
</context>
<context>
<name>TestPlugin</name>
<message>
<location filename="../testplugin.cpp" line="56"/>
<source>Test</source>
<translation></translation>
</message>
<message>
<location filename="../testplugin.cpp" line="68"/>
<location filename="../testplugin.cpp" line="77"/>
<location filename="../testplugin.cpp" line="82"/>
<location filename="../testplugin.cpp" line="110"/>
<source>TestPlugin</source>
<translation></translation>
</message>
<message>
<location filename="../testplugin.cpp" line="86"/>
<source>Button - </source>
<translation> - </translation>
</message>
<message>
<location filename="../testplugin.cpp" line="90"/>
<source>Click</source>
<translation></translation>
</message>
<message>
<location filename="../testplugin.cpp" line="117"/>
<source>A Test Plugin for WingHexExplorer2.</source>
<translation>2</translation>
</message>
</context>
</TS>

6
TestPlugin/resources.qrc Normal file
View File

@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/images/TestPlugin">
<file>images/btn.png</file>
<file>images/test.png</file>
</qresource>
</RCC>

77
TestPlugin/testform.cpp Normal file
View File

@ -0,0 +1,77 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
** copies of the Software, and to permit persons to whom the Software is
** furnished to do so.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
** THE SOFTWARE.
** =============================================================================
*/
#include "testform.h"
#include "ui_testform.h"
#include <QMetaEnum>
TestForm::TestForm(WingHex::IWingPlugin *plg, QWidget *parent)
: QWidget(parent), ui(new Ui::TestForm), _plg(plg) {
ui->setupUi(this);
initLogCombo();
initStyleCombo();
}
TestForm::~TestForm() { delete ui; }
void TestForm::initLogCombo() {
auto e = QMetaEnum::fromType<Level>();
for (int i = LEVEL_BEGIN; i < LEVEL_END; ++i) {
ui->cbLogLevel->addItem(e.key(i));
}
}
void TestForm::initStyleCombo() {
auto style = this->style();
auto e = QMetaEnum::fromType<QStyle::StandardPixmap>();
for (int i = 0; i < QStyle::StandardPixmap::NStandardPixmap; ++i) {
auto icon = style->standardIcon(QStyle::StandardPixmap(i));
if (!icon.isNull()) {
ui->cbToastIcon->addItem(icon, e.key(i));
}
}
}
void TestForm::on_btnSendLog_clicked() {
auto txt = ui->leLogText->text();
switch (Level(ui->cbLogLevel->currentIndex())) {
case q1ERROR:
emit _plg->error(txt);
break;
case q2WARN:
emit _plg->warn(txt);
break;
case q3INFO:
emit _plg->info(txt);
break;
case q4DEBUG:
emit _plg->debug(txt);
break;
case q5TRACE:
emit _plg->trace(txt);
break;
default:
break;
}
}
void TestForm::on_btnSendToast_clicked() {}

69
TestPlugin/testform.h Normal file
View File

@ -0,0 +1,69 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
** copies of the Software, and to permit persons to whom the Software is
** furnished to do so.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
** THE SOFTWARE.
** =============================================================================
*/
#ifndef TESTFORM_H
#define TESTFORM_H
#include "iwingplugin.h"
#include <QWidget>
namespace Ui {
class TestForm;
}
class TestForm : public QWidget {
Q_OBJECT
public:
// copy from LogError
enum Level : int {
q1ERROR,
q2WARN,
q3INFO,
q4DEBUG,
q5TRACE,
LEVEL_BEGIN = q1ERROR,
LEVEL_LAST = q5TRACE,
LEVEL_END = LEVEL_LAST + 1
};
Q_ENUM(Level)
public:
explicit TestForm(WingHex::IWingPlugin *plg, QWidget *parent = nullptr);
~TestForm();
private slots:
void on_btnSendLog_clicked();
void on_btnSendToast_clicked();
private:
void initLogCombo();
void initStyleCombo();
private:
Ui::TestForm *ui;
WingHex::IWingPlugin *_plg;
};
#endif // TESTFORM_H

308
TestPlugin/testform.ui Normal file
View File

@ -0,0 +1,308 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TestForm</class>
<widget class="QWidget" name="TestForm">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>600</width>
<height>400</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>600</width>
<height>400</height>
</size>
</property>
<property name="windowTitle">
<string>TestForm</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Basic</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Log</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>5</number>
</property>
<property name="leftMargin">
<number>8</number>
</property>
<property name="topMargin">
<number>8</number>
</property>
<property name="rightMargin">
<number>8</number>
</property>
<property name="bottomMargin">
<number>8</number>
</property>
<item>
<layout class="QFormLayout" name="formLayout">
<property name="horizontalSpacing">
<number>8</number>
</property>
<property name="verticalSpacing">
<number>8</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Level</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="cbLogLevel"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Text</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="leLogText"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<item>
<widget class="QPushButton" name="btnSendLog">
<property name="text">
<string>Send</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnClearSend">
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Toast</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<property name="spacing">
<number>5</number>
</property>
<property name="leftMargin">
<number>8</number>
</property>
<property name="topMargin">
<number>8</number>
</property>
<property name="rightMargin">
<number>8</number>
</property>
<property name="bottomMargin">
<number>8</number>
</property>
<item>
<layout class="QFormLayout" name="formLayout_3">
<property name="horizontalSpacing">
<number>8</number>
</property>
<property name="verticalSpacing">
<number>8</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Icon</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="cbToastIcon"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Text</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="leToastText"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<item>
<widget class="QPushButton" name="btnSendToast">
<property name="text">
<string>Send</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnClearText">
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Reader</string>
</attribute>
</widget>
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>Controller</string>
</attribute>
</widget>
<widget class="QWidget" name="tab_4">
<attribute name="title">
<string>MessageBox</string>
</attribute>
</widget>
<widget class="QWidget" name="tab_5">
<attribute name="title">
<string>InputBox</string>
</attribute>
</widget>
<widget class="QWidget" name="tab_6">
<attribute name="title">
<string>FileDialog</string>
</attribute>
</widget>
<widget class="QWidget" name="tab_7">
<attribute name="title">
<string>ColorDialog</string>
</attribute>
</widget>
<widget class="QWidget" name="tab_8">
<attribute name="title">
<string>DataVisual</string>
</attribute>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>btnClearSend</sender>
<signal>clicked()</signal>
<receiver>leLogText</receiver>
<slot>clear()</slot>
<hints>
<hint type="sourcelabel">
<x>371</x>
<y>122</y>
</hint>
<hint type="destinationlabel">
<x>372</x>
<y>100</y>
</hint>
</hints>
</connection>
<connection>
<sender>btnClearText</sender>
<signal>clicked()</signal>
<receiver>leToastText</receiver>
<slot>clear()</slot>
<hints>
<hint type="sourcelabel">
<x>461</x>
<y>249</y>
</hint>
<hint type="destinationlabel">
<x>468</x>
<y>229</y>
</hint>
</hints>
</connection>
</connections>
</ui>

147
TestPlugin/testplugin.cpp Normal file
View File

@ -0,0 +1,147 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
** copies of the Software, and to permit persons to whom the Software is
** furnished to do so.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
** THE SOFTWARE.
** =============================================================================
*/
#include "testplugin.h"
#include "testform.h"
TestPlugin::TestPlugin() : puid(QStringLiteral("TestPlugin2")) {
// 在构造函数中,所有的 API 都无法调用。插件的翻译文件也不会自动加载。
// 在构造函数中,仅适合做一些为初始化准备的操作。
// 插件的语言文件会在初始化前自动加载,如果初始化失败则会被卸载
// 初始化会传递一个配置类,插件系统会统一管理放到统一的地方,使用 INI 保存
// 你可以自行管理,但不建议,统一管理方便使用者备份和转移插件配置
}
TestPlugin::~TestPlugin() {}
int TestPlugin::sdkVersion() const { return WingHex::SDKVERSION; }
const QString TestPlugin::signature() const { return WingHex::WINGSUMMER; }
bool TestPlugin::init(const std::unique_ptr<QSettings> &set) {
auto v = set->value("Test", 0).toInt();
// 如果你之前启动过且正常推出,这个值一定是 5
qDebug() << v;
// 和日志与 UI 相关的接口此时可用,剩余的 API 初始化成功才可用
_tform = emit createDialog(new TestForm(this));
using TBInfo = WingHex::WingRibbonToolBoxInfo;
TBInfo::RibbonCatagories cats;
auto tb = new QToolButton;
// 这里有一个约定,对于含有图片的,前缀应为:/images/插件的 PUID
// 其他资源,前缀应为:/res/插件的 PUID 或 /resources/插件的 PUID
// 如果想省劲,可以统一为 /插件的 PUID但别一个 / 完事。
// 这很容易发生资源文件冲突!!!
tb->setIcon(QIcon(QStringLiteral(":/images/TestPlugin/images/test.png")));
tb->setText(tr("Test"));
connect(tb, &QToolButton::clicked, this, [=] {
if (_tform) {
_tform->show();
_tform->raise();
}
});
{
WingHex::WingRibbonToolBoxInfo rtinfo;
rtinfo.catagory = cats.PLUGIN;
TBInfo::Toolbox tbtb;
tbtb.name = tr("TestPlugin");
tbtb.tools = {tb};
rtinfo.toolboxs = {tbtb};
_rtbinfo.append(rtinfo);
}
{
WingHex::WingRibbonToolBoxInfo rtinfo;
rtinfo.catagory = QStringLiteral("TestPlugin");
rtinfo.displayName = tr("TestPlugin");
QIcon btnIcon(QStringLiteral(":/images/TestPlugin/images/btn.png"));
for (int i = 0; i < 3; ++i) {
TBInfo::Toolbox tbtb;
tbtb.name = tr("TestPlugin") + QStringLiteral("(%1)").arg(i);
for (int y = 0; y < 5; ++y) {
auto tb = new QToolButton;
tb->setIcon(btnIcon);
tb->setText(tr("Button - ") +
QStringLiteral("(%1, %2)").arg(i).arg(y));
connect(tb, &QToolButton::clicked, this, [this] {
auto tb = qobject_cast<QToolButton *>(sender());
emit msgbox.information(nullptr, tr("Click"), tb->text());
});
tbtb.tools.append(tb);
}
rtinfo.toolboxs.append(tbtb);
}
_rtbinfo.append(rtinfo);
}
return true;
}
void TestPlugin::unload(std::unique_ptr<QSettings> &set) {
// 设个数字,那就是 5 测试一下配置是否正常工作
set->setValue("Test", 5);
_tform->close();
_tform->deleteLater();
}
const QString TestPlugin::pluginName() const { return tr("TestPlugin"); }
const QString TestPlugin::pluginAuthor() const { return WingHex::WINGSUMMER; }
uint TestPlugin::pluginVersion() const { return WingHex::SDKVERSION; }
const QString TestPlugin::pluginComment() const {
return tr("A Test Plugin for WingHexExplorer2.");
}
QList<WingHex::WingDockWidgetInfo> TestPlugin::registeredDockWidgets() const {
return {};
}
QMenu *TestPlugin::registeredHexContextMenu() const { return _tmenu; }
QList<WingHex::WingRibbonToolBoxInfo>
TestPlugin::registeredRibbonTools() const {
return _rtbinfo;
}
QHash<WingHex::SettingPage *, bool> TestPlugin::registeredSettingPages() const {
return {};
}
QList<WingHex::PluginPage *> TestPlugin::registeredPages() const { return {}; }
QList<WingHex::WingEditorViewWidget *>
TestPlugin::registeredEditorViewWidgets() const {
return {};
}
QString TestPlugin::getPuid() const { return puid; }
QHash<QString, WingHex::IWingPlugin::ScriptFnInfo>
TestPlugin::registeredScriptFn() {
return {};
}

82
TestPlugin/testplugin.h Normal file
View File

@ -0,0 +1,82 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
** copies of the Software, and to permit persons to whom the Software is
** furnished to do so.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
** THE SOFTWARE.
** =============================================================================
*/
#ifndef TESTPLUGIN_H
#define TESTPLUGIN_H
#include "iwingplugin.h"
class TestPlugin final : public WingHex::IWingPlugin {
Q_OBJECT
// 可选:用于自定义插件唯一标帜,请不要随意取名,否则很可能会和其他插件冲突导致无法加载
// 如果不注明,则是插件的类名作为唯一标帜,所以也不要随意给插件类起名字
// 当然,你可以在构造函数中,使用 setProperty("puid", yourID) 来实现自定义
Q_PROPERTY(QString puid READ getPuid CONSTANT FINAL)
// 这两行是必须,只有后面的 "TestPlugin.json" 你根据需要修改,
// 具体可见 QT 文档,剩下直接 CV 大法
Q_PLUGIN_METADATA(IID "com.wingsummer.iwingplugin" FILE "TestPlugin.json")
Q_INTERFACES(WingHex::IWingPlugin)
public:
explicit TestPlugin();
virtual ~TestPlugin();
// IWingPlugin interface (必须)
public:
virtual int sdkVersion() const override;
virtual const QString signature() const override;
virtual bool init(const std::unique_ptr<QSettings> &set) override;
virtual void unload(std::unique_ptr<QSettings> &set) override;
virtual const QString pluginName() const override;
virtual const QString pluginAuthor() const override;
virtual uint pluginVersion() const override;
virtual const QString pluginComment() const override;
// IWingPlugin interface (可选)
public:
// 有关注册开头register 开头)的函数,插件系统不保证有且只调用一次
// 所以最好不要为了偷懒,在实现里面 new 和做相应操作
virtual QList<WingHex::WingDockWidgetInfo>
registeredDockWidgets() const override;
virtual QMenu *registeredHexContextMenu() const override;
virtual QList<WingHex::WingRibbonToolBoxInfo>
registeredRibbonTools() const override;
virtual QHash<WingHex::SettingPage *, bool>
registeredSettingPages() const override;
virtual QList<WingHex::PluginPage *> registeredPages() const override;
virtual QList<WingHex::WingEditorViewWidget *>
registeredEditorViewWidgets() const override;
virtual QHash<QString, ScriptFnInfo> registeredScriptFn() override;
private:
QString getPuid() const;
private:
QDialog *_tform = nullptr;
QMenu *_tmenu = nullptr;
const QString puid;
QList<WingHex::WingRibbonToolBoxInfo> _rtbinfo;
};
#endif // TESTPLUGIN_H

BIN
images/layoutexport.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -3,6 +3,9 @@
如有 Bug, 欢迎反馈到 [Github](https://github.com/Wing-summer/WingHexExplorer2/issues) 上,如果你访问这有困难的话,也可以反馈到 [Gitee](https://gitee.com/wing-cloud/WingHexExplorer2/issues) 上。如果实在不行,可以通过我的 [博客园](https://www.cnblogs.com/wingsummer) 上公告栏的任意一种联系方式来告诉我。不过我还是希望你反馈到 Github 上方便我写递交注释的。
开源不易,也欢迎赞助或者参与代码和文档贡献,我默认会将您放入鸣谢标签的内容进行鸣谢。
开源不易,也欢迎赞助或者参与代码和文档贡献,我默认会将您放入仓库首页进行鸣谢:
* Github 上:[软件贡献者](https://github.com/Wing-summer/WingHexExplorer2?tab=readme-ov-file#%E4%BB%A3%E7%A0%81%E8%B4%A1%E7%8C%AE%E8%80%85) | [文档贡献者](https://github.com/Wing-summer/WingHexExplorer2/wiki/README)
* Gitee 上:[软件贡献者](https://gitee.com/wing-cloud/WingHexExplorer2#%E4%BB%A3%E7%A0%81%E8%B4%A1%E7%8C%AE%E8%80%85) | [文档贡献者](https://gitee.com/wing-cloud/WingHexExplorer2/wikis/README)
许可证AGPL-3.0

View File

@ -1,62 +0,0 @@
不站在大佬的肩膀上,软件也不会具有强大而稳定的功能。**本软件使用的开源基础项目的源代码未经我修改的部分,全部遵守原作者的开源协议;我修改的部分,如没有特殊说明,全部遵守本仓库的协议。**
#### QHexView
本软件基于`QHexView`作为十六进制编辑器为基础进行开发,本人在改组件基础上添加新功能和进行代码的深度定制。如下是原仓库的必要说明,详情请点击 [此链接](https://github.com/Dax89/QHexView/tree/master)。
#### QHexEdit2
起初我打算使用`QHexEdit2`作为十六进制编辑器为基础进行开发,该组件虽然轻松打开超大文件,但是它的编辑功能能用是能用,但有很多大大小小的 Bug ,我还逐一修了修,但发现仅仅我的力量和时间是杯水车薪。然后我找到了`QHexView`,也就是上面所属的组件,但它有一个致命的缺陷,无法打开超大文件,被我放弃掉了,后来我尝试用了它,发现开发者在开发改组件是下了足够大的功夫的,编辑十分流畅。最近看到`QHexView`贡献者们想搞一个`QHexView 5.0`,对代码进行了重构,但并没有实现任何功能,差不多是个空空的框架,不过从接口看出更强大的易用性,这个是原组件所不具有的,这花费我比较多的时间来阅读源代码,并向外扩展接口以适应我的开发需求。
然后我想,既然`QHexEdit2`具有强大的打开文件的能力,而`QHexView`不具备,但它具有强大的编辑界面,于是乎,我移植`QHexEdit2`的打开超大文件的代码到`QHexView`当中,并做好了适配和功能增强。原仓库的链接: <https://github.com/Simsys/qhexedit2> ,原协议为`GPL`。
#### Qt-Advanced-Docking-System
QT Advanced Docking System 允许你使用完整的特色窗户对接系统创建可自定义的布局类似于许多流行的集成开发环境IDE例如Visual Studio。该库功能十分强大为了增强软件的易用性就采用这个库。我略微修改了构建文件以方便直接嵌入到我的项目当中也方便更新组件。
原仓库的链接: <https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System> ,原协议为`LGPL`。
#### QCodeEditor2
一个文本编辑器,功能强大。该项目用来开发以及调试针对羽云编辑器的`AngelScript`脚本。该组件来源于`edyuk`开源项目,采用`GPL`协议,不过这玩意在`Github`上也没有,只有在 [SourceForge](https://sourceforge.net/projects/edyuk) 有它的身影。我对其进行了一些定制和小`Bug`的修复。
#### QCodeModel2
该组件来源于`edyuk`这一个项目,用于代码解析。本项目的代码分析和代码智能提示也是基于该项目中的`C++`分析器相关代码修改而来,来源同`QCodeEditor2`。
#### QWingRibbon
虽然这个带`Wing`这个玩意,但并不是完全是我写的,这个是基于`Qt-Ribbon-Widget`魔改来的。之所以换名字是改动的有点多,打算自己维护一个自己的用来给该编辑器使用的。
原仓库的链接: <https://github.com/martijnkoopman/Qt-Ribbon-Widget> ,原协议为`LGPL`。
#### SingleApplication
保留应用程序的主实例并终止每个后续实例。它可以(如果启用)生成第二(与主实例无关)实例,并且可以从第二实例向主实例发送数据。简而言之就是实现程序单例的库。原仓库的链接: <https://github.com/itay-grudev/SingleApplication> ,它的协议为`MIT`,多了一个额外限制,具体看其协议。
#### QPathEdit
以优化和简单的方式获取本地文件和文件夹路径的一个 QT 组件。原仓库的链接: <https://github.com/Skycoder42/QPathEdit> ,原协议为`MIT`。
#### QWindowKit
该组件是用户界面的基础,用于在不同操作系统平台提供较为统一的用户界面体验。原仓库的链接: <https://github.com/stdware/qwindowkit> ,原协议为`Apache v2.0`。
#### AngelScript
让 C++ 成为具有惊人功能的脚本语言!这个功能强大,且不需要外部依赖,直接编译进去就行,不像之前版本必须携带一个`Python`解释器和库,不太方便编译。
镜像库: <https://github.com/codecat/angelscript-mirror> ,原协议为`zlib license`,还是比较宽松的开源协议。
#### QConsoleWidget
一个轻量的控制台组件,协议为`MIT`,仓库链接:<https://github.com/gapost/qconsolewidget>
#### QColorPicker
一个颜色选择组件,协议为`MIT`,仓库链接:<https://github.com/arsdever/qcolorpicker>
#### QtJsonModel
QJsonModel 是一个基于 QAbstractItemModel 的 Qt6/C++17 的 JSON 树模型类。在该项目用于插件和脚本给予宿主进行树形可视化的基础支持组件。我对其增加了 Qt5 的支持并且写了一个合适的 CMake 文件。原协议为`MIT`,修改不多遵守这个就行了。仓库链接:<https://github.com/dridk/QJsonmodel>

View File

@ -1,15 +0,0 @@
## 代码贡献者
&emsp;&emsp;维护一个好用的工具并不是一个人能做到了,更重要的是大家共同维护,如下是对本仓库代码有贡献的同志,特此感谢:
* oPengLuo (大大的力量)
## 赞助鸣谢
&emsp;&emsp;感谢以下同志的赞助,我会尽量持续做成一个好用且功能强大的且跨平台的 PC 端的十六进制编辑器(时间先后顺序):
| 赞助者 | 备注 |
| :----: | :--------------------: |
| *欢 | 来自 Deepin 的一位道友 |

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,8 @@
#include "class/appmanager.h"
#include "class/settingmanager.h"
#include "define.h"
int main(int argc, char *argv[]) {
/* 有关对在 QT5 的 Win 平台禁用高 dpi 支持
*
@ -16,28 +18,36 @@ int main(int argc, char *argv[]) {
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif
QGuiApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
QApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
AppManager a(argc, argv);
auto w = a.mainWindow();
QApplication::setApplicationName(APP_NAME);
QApplication::setOrganizationName(APP_ORG);
QApplication::setApplicationVersion(WINGHEX_VERSION);
auto &set = SettingManager::instance();
switch (set.defaultWinState()) {
case Qt::WindowNoState:
w->show();
Utilities::moveToCenter(w);
break;
case Qt::WindowMinimized:
w->showMinimized();
break;
case Qt::WindowActive:
case Qt::WindowMaximized:
w->showMaximized();
break;
case Qt::WindowFullScreen:
w->showFullScreen();
break;
try {
AppManager a(argc, argv);
auto w = a.mainWindow();
auto &set = SettingManager::instance();
switch (set.defaultWinState()) {
case Qt::WindowNoState:
w->show();
Utilities::moveToCenter(w);
break;
case Qt::WindowMinimized:
w->showMinimized();
break;
case Qt::WindowActive:
case Qt::WindowMaximized:
w->showMaximized();
break;
case Qt::WindowFullScreen:
w->showFullScreen();
break;
}
return a.exec();
} catch (CrashCode errCode) {
return int(errCode);
}
return a.exec();
}

View File

@ -8,7 +8,7 @@ Type=Application
StartupNotify=false
Terminal=false
Icon=/opt/WingHexExplorer2/share/icon.png
StartupWMClass=WingHexExplorer
StartupWMClass=WingHexExplorer2
Comment=a free and powerful opensource hexeditor based on QT
Comment[zh_CN]=一个基于 QT 的自由和强大的开源十六进制编辑器
MimeType=application/x-winghex;text/plain;application/octet-stream;

View File

@ -202,7 +202,7 @@ Homepage: https://www.cnblogs.com/wingsummer/
print(Fore.GREEN + ">> Copying License and other materials..." + Style.RESET_ALL)
material_files = ["LICENSE", "authorband.svg",
"licenseband.svg", "screenshot.png", "README.md", "TODO.txt"]
"licenseband.svg", "screenshot.png", "README.md"]
for f in material_files:
shutil.copyfile(os.path.join(projectbase, f),

View File

@ -0,0 +1 @@
colorama==0.4.6

View File

@ -0,0 +1,396 @@
; *** Inno Setup version 6.1.0+ Chinese Simplified messages ***
;
; To download user-contributed translations of this file, go to:
; https://jrsoftware.org/files/istrans/
;
; Note: When translating this text, do not add periods (.) to the end of
; messages that didn't have them already, because on those messages Inno
; Setup adds the periods automatically (appending a period would result in
; two periods being displayed).
;
; Maintained by Zhenghan Yang
; Email: 847320916@QQ.com
; Translation based on network resource
; The latest Translation is on https://github.com/kira-96/Inno-Setup-Chinese-Simplified-Translation
;
[LangOptions]
; The following three entries are very important. Be sure to read and
; understand the '[LangOptions] section' topic in the help file.
LanguageName=简体中文
; If Language Name display incorrect, uncomment next line
; LanguageName=<7B80><4F53><4E2D><6587>
; About LanguageID, to reference link:
; https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/a9eac961-e77d-41a6-90a5-ce1a8b0cdb9c
LanguageID=$0804
; About CodePage, to reference link:
; https://docs.microsoft.com/en-us/windows/win32/intl/code-page-identifiers
LanguageCodePage=936
; If the language you are translating to requires special font faces or
; sizes, uncomment any of the following entries and change them accordingly.
;DialogFontName=
;DialogFontSize=8
;WelcomeFontName=Verdana
;WelcomeFontSize=12
;TitleFontName=Arial
;TitleFontSize=29
;CopyrightFontName=Arial
;CopyrightFontSize=8
[Messages]
; *** 应用程序标题
SetupAppTitle=安装
SetupWindowTitle=安装 - %1
UninstallAppTitle=卸载
UninstallAppFullTitle=%1 卸载
; *** Misc. common
InformationTitle=信息
ConfirmTitle=确认
ErrorTitle=错误
; *** SetupLdr messages
SetupLdrStartupMessage=现在将安装 %1。您想要继续吗
LdrCannotCreateTemp=无法创建临时文件。安装程序已中止
LdrCannotExecTemp=无法执行临时目录中的文件。安装程序已中止
HelpTextNote=
; *** 启动错误消息
LastErrorMessage=%1。%n%n错误 %2: %3
SetupFileMissing=安装目录中缺少文件 %1。请修正这个问题或者获取程序的新副本。
SetupFileCorrupt=安装文件已损坏。请获取程序的新副本。
SetupFileCorruptOrWrongVer=安装文件已损坏,或是与这个安装程序的版本不兼容。请修正这个问题或获取新的程序副本。
InvalidParameter=无效的命令行参数:%n%n%1
SetupAlreadyRunning=安装程序正在运行。
WindowsVersionNotSupported=此程序不支持当前计算机运行的 Windows 版本。
WindowsServicePackRequired=此程序需要 %1 服务包 %2 或更高版本。
NotOnThisPlatform=此程序不能在 %1 上运行。
OnlyOnThisPlatform=此程序只能在 %1 上运行。
OnlyOnTheseArchitectures=此程序只能安装到为下列处理器架构设计的 Windows 版本中:%n%n%1
WinVersionTooLowError=此程序需要 %1 版本 %2 或更高。
WinVersionTooHighError=此程序不能安装于 %1 版本 %2 或更高。
AdminPrivilegesRequired=在安装此程序时您必须以管理员身份登录。
PowerUserPrivilegesRequired=在安装此程序时您必须以管理员身份或有权限的用户组身份登录。
SetupAppRunningError=安装程序发现 %1 当前正在运行。%n%n请先关闭正在运行的程序然后点击“确定”继续或点击“取消”退出。
UninstallAppRunningError=卸载程序发现 %1 当前正在运行。%n%n请先关闭正在运行的程序然后点击“确定”继续或点击“取消”退出。
; *** 启动问题
PrivilegesRequiredOverrideTitle=选择安装程序模式
PrivilegesRequiredOverrideInstruction=选择安装模式
PrivilegesRequiredOverrideText1=%1 可以为所有用户安装(需要管理员权限),或仅为您安装。
PrivilegesRequiredOverrideText2=%1 只能为您安装,或为所有用户安装(需要管理员权限)。
PrivilegesRequiredOverrideAllUsers=为所有用户安装(&A)
PrivilegesRequiredOverrideAllUsersRecommended=为所有用户安装(&A) (建议选项)
PrivilegesRequiredOverrideCurrentUser=只为我安装(&M)
PrivilegesRequiredOverrideCurrentUserRecommended=只为我安装(&M) (建议选项)
; *** 其他错误
ErrorCreatingDir=安装程序无法创建目录“%1”
ErrorTooManyFilesInDir=无法在目录“%1”中创建文件因为里面包含太多文件
; *** 安装程序公共消息
ExitSetupTitle=退出安装程序
ExitSetupMessage=安装程序尚未完成。如果现在退出,将不会安装该程序。%n%n您之后可以再次运行安装程序完成安装。%n%n现在退出安装程序吗
AboutSetupMenuItem=关于安装程序(&A)...
AboutSetupTitle=关于安装程序
AboutSetupMessage=%1 版本 %2%n%3%n%n%1 主页:%n%4
AboutSetupNote=
TranslatorNote=简体中文翻译由Kira(847320916@qq.com)维护。项目地址https://github.com/kira-96/Inno-Setup-Chinese-Simplified-Translation
; *** 按钮
ButtonBack=< 上一步(&B)
ButtonNext=下一步(&N) >
ButtonInstall=安装(&I)
ButtonOK=确定
ButtonCancel=取消
ButtonYes=是(&Y)
ButtonYesToAll=全是(&A)
ButtonNo=否(&N)
ButtonNoToAll=全否(&O)
ButtonFinish=完成(&F)
ButtonBrowse=浏览(&B)...
ButtonWizardBrowse=浏览(&R)...
ButtonNewFolder=新建文件夹(&M)
; *** “选择语言”对话框消息
SelectLanguageTitle=选择安装语言
SelectLanguageLabel=选择安装时使用的语言。
; *** 公共向导文字
ClickNext=点击“下一步”继续,或点击“取消”退出安装程序。
BeveledLabel=
BrowseDialogTitle=浏览文件夹
BrowseDialogLabel=在下面的列表中选择一个文件夹,然后点击“确定”。
NewFolderName=新建文件夹
; *** “欢迎”向导页
WelcomeLabel1=欢迎使用 [name] 安装向导
WelcomeLabel2=现在将安装 [name/ver] 到您的电脑中。%n%n建议您在继续安装前关闭所有其他应用程序。
; *** “密码”向导页
WizardPassword=密码
PasswordLabel1=这个安装程序有密码保护。
PasswordLabel3=请输入密码,然后点击“下一步”继续。密码区分大小写。
PasswordEditLabel=密码(&P)
IncorrectPassword=您输入的密码不正确,请重新输入。
; *** “许可协议”向导页
WizardLicense=许可协议
LicenseLabel=请在继续安装前阅读以下重要信息。
LicenseLabel3=请仔细阅读下列许可协议。在继续安装前您必须同意这些协议条款。
LicenseAccepted=我同意此协议(&A)
LicenseNotAccepted=我不同意此协议(&D)
; *** “信息”向导页
WizardInfoBefore=信息
InfoBeforeLabel=请在继续安装前阅读以下重要信息。
InfoBeforeClickLabel=准备好继续安装后,点击“下一步”。
WizardInfoAfter=信息
InfoAfterLabel=请在继续安装前阅读以下重要信息。
InfoAfterClickLabel=准备好继续安装后,点击“下一步”。
; *** “用户信息”向导页
WizardUserInfo=用户信息
UserInfoDesc=请输入您的信息。
UserInfoName=用户名(&U)
UserInfoOrg=组织(&O)
UserInfoSerial=序列号(&S)
UserInfoNameRequired=您必须输入用户名。
; *** “选择目标目录”向导页
WizardSelectDir=选择目标位置
SelectDirDesc=您想将 [name] 安装在哪里?
SelectDirLabel3=安装程序将安装 [name] 到下面的文件夹中。
SelectDirBrowseLabel=点击“下一步”继续。如果您想选择其他文件夹,点击“浏览”。
DiskSpaceGBLabel=至少需要有 [gb] GB 的可用磁盘空间。
DiskSpaceMBLabel=至少需要有 [mb] MB 的可用磁盘空间。
CannotInstallToNetworkDrive=安装程序无法安装到一个网络驱动器。
CannotInstallToUNCPath=安装程序无法安装到一个 UNC 路径。
InvalidPath=您必须输入一个带驱动器卷标的完整路径,例如:%n%nC:\APP%n%n或UNC路径%n%n\\server\share
InvalidDrive=您选定的驱动器或 UNC 共享不存在或不能访问。请选择其他位置。
DiskSpaceWarningTitle=磁盘空间不足
DiskSpaceWarning=安装程序至少需要 %1 KB 的可用空间才能安装,但选定驱动器只有 %2 KB 的可用空间。%n%n您一定要继续吗
DirNameTooLong=文件夹名称或路径太长。
InvalidDirName=文件夹名称无效。
BadDirName32=文件夹名称不能包含下列任何字符:%n%n%1
DirExistsTitle=文件夹已存在
DirExists=文件夹:%n%n%1%n%n已经存在。您一定要安装到这个文件夹中吗
DirDoesntExistTitle=文件夹不存在
DirDoesntExist=文件夹:%n%n%1%n%n不存在。您想要创建此文件夹吗
; *** “选择组件”向导页
WizardSelectComponents=选择组件
SelectComponentsDesc=您想安装哪些程序组件?
SelectComponentsLabel2=选中您想安装的组件;取消您不想安装的组件。然后点击“下一步”继续。
FullInstallation=完全安装
; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language)
CompactInstallation=简洁安装
CustomInstallation=自定义安装
NoUninstallWarningTitle=组件已存在
NoUninstallWarning=安装程序检测到下列组件已安装在您的电脑中:%n%n%1%n%n取消选中这些组件不会卸载它们。%n%n确定要继续吗
ComponentSize1=%1 KB
ComponentSize2=%1 MB
ComponentsDiskSpaceGBLabel=当前选择的组件需要至少 [gb] GB 的磁盘空间。
ComponentsDiskSpaceMBLabel=当前选择的组件需要至少 [mb] MB 的磁盘空间。
; *** “选择附加任务”向导页
WizardSelectTasks=选择附加任务
SelectTasksDesc=您想要安装程序执行哪些附加任务?
SelectTasksLabel2=选择您想要安装程序在安装 [name] 时执行的附加任务,然后点击“下一步”。
; *** “选择开始菜单文件夹”向导页
WizardSelectProgramGroup=选择开始菜单文件夹
SelectStartMenuFolderDesc=安装程序应该在哪里放置程序的快捷方式?
SelectStartMenuFolderLabel3=安装程序将在下列“开始”菜单文件夹中创建程序的快捷方式。
SelectStartMenuFolderBrowseLabel=点击“下一步”继续。如果您想选择其他文件夹,点击“浏览”。
MustEnterGroupName=您必须输入一个文件夹名。
GroupNameTooLong=文件夹名或路径太长。
InvalidGroupName=无效的文件夹名字。
BadGroupName=文件夹名不能包含下列任何字符:%n%n%1
NoProgramGroupCheck2=不创建开始菜单文件夹(&D)
; *** “准备安装”向导页
WizardReady=准备安装
ReadyLabel1=安装程序准备就绪,现在可以开始安装 [name] 到您的电脑。
ReadyLabel2a=点击“安装”继续此安装程序。如果您想重新考虑或修改任何设置,点击“上一步”。
ReadyLabel2b=点击“安装”继续此安装程序。
ReadyMemoUserInfo=用户信息:
ReadyMemoDir=目标位置:
ReadyMemoType=安装类型:
ReadyMemoComponents=已选择组件:
ReadyMemoGroup=开始菜单文件夹:
ReadyMemoTasks=附加任务:
; *** TDownloadWizardPage wizard page and DownloadTemporaryFile
DownloadingLabel=正在下载附加文件...
ButtonStopDownload=停止下载(&S)
StopDownload=您确定要停止下载吗?
ErrorDownloadAborted=下载已中止
ErrorDownloadFailed=下载失败:%1 %2
ErrorDownloadSizeFailed=获取下载大小失败:%1 %2
ErrorFileHash1=校验文件哈希失败:%1
ErrorFileHash2=无效的文件哈希:预期 %1实际 %2
ErrorProgress=无效的进度:%1 / %2
ErrorFileSize=文件大小错误:预期 %1实际 %2
; *** “正在准备安装”向导页
WizardPreparing=正在准备安装
PreparingDesc=安装程序正在准备安装 [name] 到您的电脑。
PreviousInstallNotCompleted=先前的程序安装或卸载未完成,您需要重启您的电脑以完成。%n%n在重启电脑后再次运行安装程序以完成 [name] 的安装。
CannotContinue=安装程序不能继续。请点击“取消”退出。
ApplicationsFound=以下应用程序正在使用将由安装程序更新的文件。建议您允许安装程序自动关闭这些应用程序。
ApplicationsFound2=以下应用程序正在使用将由安装程序更新的文件。建议您允许安装程序自动关闭这些应用程序。安装完成后,安装程序将尝试重新启动这些应用程序。
CloseApplications=自动关闭应用程序(&A)
DontCloseApplications=不要关闭应用程序(&D)
ErrorCloseApplications=安装程序无法自动关闭所有应用程序。建议您在继续之前,关闭所有在使用需要由安装程序更新的文件的应用程序。
PrepareToInstallNeedsRestart=安装程序必须重启您的计算机。计算机重启后,请再次运行安装程序以完成 [name] 的安装。%n%n是否立即重新启动
; *** “正在安装”向导页
WizardInstalling=正在安装
InstallingLabel=安装程序正在安装 [name] 到您的电脑,请稍候。
; *** “安装完成”向导页
FinishedHeadingLabel=[name] 安装完成
FinishedLabelNoIcons=安装程序已在您的电脑中安装了 [name]。
FinishedLabel=安装程序已在您的电脑中安装了 [name]。您可以通过已安装的快捷方式运行此应用程序。
ClickFinish=点击“完成”退出安装程序。
FinishedRestartLabel=为完成 [name] 的安装,安装程序必须重新启动您的电脑。要立即重启吗?
FinishedRestartMessage=为完成 [name] 的安装,安装程序必须重新启动您的电脑。%n%n要立即重启吗
ShowReadmeCheck=是,我想查阅自述文件
YesRadio=是,立即重启电脑(&Y)
NoRadio=否,稍后重启电脑(&N)
; used for example as 'Run MyProg.exe'
RunEntryExec=运行 %1
; used for example as 'View Readme.txt'
RunEntryShellExec=查阅 %1
; *** “安装程序需要下一张磁盘”提示
ChangeDiskTitle=安装程序需要下一张磁盘
SelectDiskLabel2=请插入磁盘 %1 并点击“确定”。%n%n如果这个磁盘中的文件可以在下列文件夹之外的文件夹中找到请输入正确的路径或点击“浏览”。
PathLabel=路径(&P)
FileNotInDir2=“%2”中找不到文件“%1”。请插入正确的磁盘或选择其他文件夹。
SelectDirectoryLabel=请指定下一张磁盘的位置。
; *** 安装状态消息
SetupAborted=安装程序未完成安装。%n%n请修正这个问题并重新运行安装程序。
AbortRetryIgnoreSelectAction=选择操作
AbortRetryIgnoreRetry=重试(&T)
AbortRetryIgnoreIgnore=忽略错误并继续(&I)
AbortRetryIgnoreCancel=关闭安装程序
; *** 安装状态消息
StatusClosingApplications=正在关闭应用程序...
StatusCreateDirs=正在创建目录...
StatusExtractFiles=正在解压缩文件...
StatusCreateIcons=正在创建快捷方式...
StatusCreateIniEntries=正在创建 INI 条目...
StatusCreateRegistryEntries=正在创建注册表条目...
StatusRegisterFiles=正在注册文件...
StatusSavingUninstall=正在保存卸载信息...
StatusRunProgram=正在完成安装...
StatusRestartingApplications=正在重启应用程序...
StatusRollback=正在撤销更改...
; *** 其他错误
ErrorInternal2=内部错误:%1
ErrorFunctionFailedNoCode=%1 失败
ErrorFunctionFailed=%1 失败;错误代码 %2
ErrorFunctionFailedWithMessage=%1 失败;错误代码 %2.%n%3
ErrorExecutingProgram=无法执行文件:%n%1
; *** 注册表错误
ErrorRegOpenKey=打开注册表项时出错:%n%1\%2
ErrorRegCreateKey=创建注册表项时出错:%n%1\%2
ErrorRegWriteKey=写入注册表项时出错:%n%1\%2
; *** INI 错误
ErrorIniEntry=在文件“%1”中创建 INI 条目时出错。
; *** 文件复制错误
FileAbortRetryIgnoreSkipNotRecommended=跳过此文件(&S) (不推荐)
FileAbortRetryIgnoreIgnoreNotRecommended=忽略错误并继续(&I) (不推荐)
SourceIsCorrupted=源文件已损坏
SourceDoesntExist=源文件“%1”不存在
ExistingFileReadOnly2=无法替换现有文件,它是只读的。
ExistingFileReadOnlyRetry=移除只读属性并重试(&R)
ExistingFileReadOnlyKeepExisting=保留现有文件(&K)
ErrorReadingExistingDest=尝试读取现有文件时出错:
FileExistsSelectAction=选择操作
FileExists2=文件已经存在。
FileExistsOverwriteExisting=覆盖已存在的文件(&O)
FileExistsKeepExisting=保留现有的文件(&K)
FileExistsOverwriteOrKeepAll=为所有冲突文件执行此操作(&D)
ExistingFileNewerSelectAction=选择操作
ExistingFileNewer2=现有的文件比安装程序将要安装的文件还要新。
ExistingFileNewerOverwriteExisting=覆盖已存在的文件(&O)
ExistingFileNewerKeepExisting=保留现有的文件(&K) (推荐)
ExistingFileNewerOverwriteOrKeepAll=为所有冲突文件执行此操作(&D)
ErrorChangingAttr=尝试更改下列现有文件的属性时出错:
ErrorCreatingTemp=尝试在目标目录创建文件时出错:
ErrorReadingSource=尝试读取下列源文件时出错:
ErrorCopying=尝试复制下列文件时出错:
ErrorReplacingExistingFile=尝试替换现有文件时出错:
ErrorRestartReplace=重启并替换失败:
ErrorRenamingTemp=尝试重命名下列目标目录中的一个文件时出错:
ErrorRegisterServer=无法注册 DLL/OCX%1
ErrorRegSvr32Failed=RegSvr32 失败;退出代码 %1
ErrorRegisterTypeLib=无法注册类库:%1
; *** 卸载显示名字标记
; used for example as 'My Program (32-bit)'
UninstallDisplayNameMark=%1 (%2)
; used for example as 'My Program (32-bit, All users)'
UninstallDisplayNameMarks=%1 (%2, %3)
UninstallDisplayNameMark32Bit=32 位
UninstallDisplayNameMark64Bit=64 位
UninstallDisplayNameMarkAllUsers=所有用户
UninstallDisplayNameMarkCurrentUser=当前用户
; *** 安装后错误
ErrorOpeningReadme=尝试打开自述文件时出错。
ErrorRestartingComputer=安装程序无法重启电脑,请手动重启。
; *** 卸载消息
UninstallNotFound=文件“%1”不存在。无法卸载。
UninstallOpenError=文件“%1”不能被打开。无法卸载。
UninstallUnsupportedVer=此版本的卸载程序无法识别卸载日志文件“%1”的格式。无法卸载
UninstallUnknownEntry=卸载日志中遇到一个未知条目 (%1)
ConfirmUninstall=您确认要完全移除 %1 及其所有组件吗?
UninstallOnlyOnWin64=仅允许在 64 位 Windows 中卸载此程序。
OnlyAdminCanUninstall=仅使用管理员权限的用户能完成此卸载。
UninstallStatusLabel=正在从您的电脑中移除 %1请稍候。
UninstalledAll=已顺利从您的电脑中移除 %1。
UninstalledMost=%1 卸载完成。%n%n有部分内容未能被删除但您可以手动删除它们。
UninstalledAndNeedsRestart=为完成 %1 的卸载,需要重启您的电脑。%n%n立即重启电脑吗
UninstallDataCorrupted=文件“%1”已损坏。无法卸载
; *** 卸载状态消息
ConfirmDeleteSharedFileTitle=删除共享的文件吗?
ConfirmDeleteSharedFile2=系统表示下列共享的文件已不有其他程序使用。您希望卸载程序删除这些共享的文件吗?%n%n如果删除这些文件但仍有程序在使用这些文件则这些程序可能出现异常。如果您不能确定请选择“否”在系统中保留这些文件以免引发问题。
SharedFileNameLabel=文件名:
SharedFileLocationLabel=位置:
WizardUninstalling=卸载状态
StatusUninstalling=正在卸载 %1...
; *** Shutdown block reasons
ShutdownBlockReasonInstallingApp=正在安装 %1。
ShutdownBlockReasonUninstallingApp=正在卸载 %1。
; The custom messages below aren't used by Setup itself, but if you make
; use of them in your scripts, you'll want to translate them.
[CustomMessages]
NameAndVersion=%1 版本 %2
AdditionalIcons=附加快捷方式:
CreateDesktopIcon=创建桌面快捷方式(&D)
CreateQuickLaunchIcon=创建快速启动栏快捷方式(&Q)
ProgramOnTheWeb=%1 网站
UninstallProgram=卸载 %1
LaunchProgram=运行 %1
AssocFileExtension=将 %2 文件扩展名与 %1 建立关联(&A)
AssocingFileExtension=正在将 %2 文件扩展名与 %1 建立关联...
AutoStartProgramGroupDescription=启动:
AutoStartProgram=自动启动 %1
AddonHostProgramNotFound=您选择的文件夹中无法找到 %1。%n%n您要继续吗

View File

@ -40,16 +40,28 @@ def run_command_interactive(command):
def main():
parser = argparse.ArgumentParser(
prog="mkdeb.py", description="A deb installer maker for WingHexExplorer2")
parser.add_argument(
"folder", help="A folder that has contained the binary build")
parser.add_argument("-c", "--cc", help="where ISCC.exe locates", default="C:\Program Files (x86)\Inno Setup 6\ISCC.exe")
parser.add_argument("-o", "--output", help="where to put the installer")
"folder", help="A folder that has contained the binary build", type=str
)
parser.add_argument(
"-c", "--cc", help="Where ISCC.exe locates", default=r"C:\Program Files (x86)\Inno Setup 6\ISCC.exe", type=str
)
parser.add_argument(
"-o", "--output", help="Where to put the installer", type=str
)
parser.add_argument(
"--build", action="store_true", help="Build the installer"
)
parser.add_argument(
"--no-build", dest="build", action="store_false", help="Skip building the installer"
)
parser.set_defaults(build=True)
args = parser.parse_args()
# checking build toolkits
if (os.path.exists(args.cc) == False):
if (args.build and os.path.exists(args.cc) == False):
print(Fore.RED +
"[Error] InnoSetup is not installed on your system." + Style.RESET_ALL)
exit(-5)
@ -110,7 +122,13 @@ def main():
os.mkdir(exeDebPath)
# check
exemain_src = os.path.join(projectdeb, exe_name)
exemain_src = ""
if(os.path.exists(os.path.join(projectdeb, "WingHexExplorer2.sln"))):
exemain_src = os.path.join(projectdeb, "Release", exe_name) # only support Release for MSVC sln build (GitAction)
else:
exemain_src = os.path.join(projectdeb, exe_name)
if (os.path.exists(exemain_src) == False):
print(
Fore.RED + "[Error] WingHexExplorer2.exe is not found!" + Style.RESET_ALL)
@ -142,7 +160,7 @@ def main():
print(Fore.GREEN + ">> Copying License and other materials..." + Style.RESET_ALL)
material_files = ["LICENSE", "authorband.svg",
"licenseband.svg", "screenshot.png", "README.md", "TODO.txt"]
"licenseband.svg", "screenshot.png", "README.md"]
for f in material_files:
shutil.copyfile(os.path.join(projectbase, f),
@ -177,7 +195,7 @@ def main():
#define MyAppExeName "{exe_name}"
#define MyAppLicenseFile "{os.path.join(exeDebPath, "LICENSE")}"
#define MyAppExePath "{os.path.join(exeDebPath, exe_name)}"
#define MyOutputBaseFilename "{package_name}_Setup_{version}_{platform.machine()}"
#define MyOutputBaseFilename "{package_name}_Setup_v{version}_{platform.machine()}"
"""
iss_content += r"""
@ -248,12 +266,14 @@ Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChang
with codecs.open(script_src,'w', "utf-8-sig") as iss:
iss.write(iss_content)
if args.build == False:
exit(0)
print(Fore.GREEN + ">> Copying finished, running ISCC building..." + Style.RESET_ALL)
pak_out = ""
if args.output is None:
pak_out = exeDebPath
pak_out = os.path.join(exeDebPath,"..")
else:
pak_out = args.output

View File

@ -0,0 +1 @@
colorama==0.4.6

View File

@ -0,0 +1,15 @@
## 文件说明
该目录的工具用于打包 Linux 通用安装包,方便没有编译环境的用户使用该软件,与此同时可以保证较好的通用性。
该工具包打包好的程序已经在 DeepinV23 、KDE Neon 测试过,未发现有啥问题。
如果你要尝试手动打包,首先需要配置好 CMake 的`CMAKE_PREFIX_INSTALL`到你要打包的目录,注意启用`install`,然后编译,完毕后会安装到打包目录中。
然后首先部署deploy一下执行`deploy.py`这个脚本,要把你 **编译目录** 作为参数,注意是你编译的目录,而不是打包目录。该脚本会自行解析并定位到你的打包目录的。如果正常运行的话,你会得到如下输出:
![screenshot](deployshot.png)
这个警告尤其注意,它在你打包目录的`lib`目录下,你必须将警告中的文件加上可执行权限,否则部署之后的程序因该文件没有可执行权限导致无法执行。 **为啥不放到自动化脚本是因为修改权限需要 root除非你用桌面的文件属性设置。**
完成部署之后,你就可以打包了,执行`build.sh`这个脚本,要把你 **打包的目录** 作为参数,执行完之后,它会在打包工具目录下创建`build`目录生成一个文件名格式与`WingHexExplorer2-vx.x.x-xxx-installer.run`类似的文件和一个`payload.tar.gz`文件,前者是安装包,后者是生成安装包中间产物,是对你打包目录进行压缩的一个压缩包。

View File

@ -0,0 +1,19 @@
#!/usr/bin/env bash
SCRIPT_DIR="/opt/WingHexExplorer2"
cd "$SCRIPT_DIR" || exit 1
ABS_PATHS=()
# Iterate through each argument
for path in "$@"; do
abs_path=$(realpath "$path" 2>/dev/null)
if [ -z "$abs_path" ]; then
abs_path=$(readlink -f "$path" 2>/dev/null || echo "$path")
fi
ABS_PATHS+=("$abs_path")
done
env LD_LIBRARY_PATH="$SCRIPT_DIR/lib" "$SCRIPT_DIR/WingHexExplorer2" "${ABS_PATHS[@]}"

View File

@ -0,0 +1,35 @@
#!/usr/bin/env bash
F_RED="\e[31m"
A_DEFAULT="\033[0m"
BUILD_PATH="$1"
if [ "$(id -u)" -ne 0 ]; then
echo -e "$F_RED Please run this script as root or using sudo! $A_DEFAULT"
exit 1
fi
if [ ! -d "$BUILD_PATH" ]; then
echo -e "$F_RED Not exists: $BUILD_PATH$A_DEFAULT"
exit 1
fi
LD_FILE="$BUILD_PATH/LD_PATH"
ld_file=$(<"$LD_FILE")
if [ -z "$ld_file" ]; then
echo -e "$F_RED LD_PATH not exists. Ignoring... $A_DEFAULT"
exit 0
fi
ld_path="$BUILD_PATH/lib/$ld_file"
if [ ! -e "$ld_path" ]; then
echo -e "$F_RED LD_PATH is INVALID $A_DEFAULT"
exit 1
fi
chattr +x "$ld_path"
exit 0

View File

@ -0,0 +1,66 @@
#!/usr/bin/env bash
F_RED="\e[31m"
F_GREEN="\e[32m"
A_DEFAULT="\033[0m"
SCRIPT_DIR=$(dirname "$(realpath "$0")")
cd "$SCRIPT_DIR" || exit
if [ "$#" -ne 1 ]; then
echo "$F_GREEN Usage: $0 <Path>$A_DEFAULT"
exit 1
fi
BUILD_PATH="$1"
if [ ! -d "$BUILD_PATH" ]; then
echo -e "$F_RED Not exists: $BUILD_PATH$A_DEFAULT"
fi
if [ ! -d build ]; then
mkdir build
fi
cd build || exit 1
VERSION_FILE="$BUILD_PATH/VERSION"
LD_FILE="$BUILD_PATH/LD_PATH"
version=$(<"$VERSION_FILE")
ld_file=$(<"$LD_FILE")
if [ -z "$version" ]; then
echo -e "$F_RED VERSION file not exists $A_DEFAULT"
exit 1
fi
if [ -n "$ld_file" ]; then
ld_path="$BUILD_PATH/lib/$ld_file"
if [ ! -e "$ld_path" ]; then
echo -e "$F_RED LD_PATH is INVALID $A_DEFAULT"
exit 1
fi
if [ ! -x "$ld_path" ]; then
echo -e "$F_RED $ld_file is not EXECUTABLE !!! $A_DEFAULT"
exit 1
fi
fi
rm "$LD_FILE"
rm "$VERSION_FILE"
set -e
fakeroot tar czvf payload.tar.gz -C "$BUILD_PATH" .
arch=$(uname -m)
PACKAGE_NAME="WingHexExplorer2-v$version-$arch-installer.run"
cat "$SCRIPT_DIR/installheader.sh" payload.tar.gz >"$PACKAGE_NAME"
echo -e "$F_GREEN>> $PACKAGE_NAME was created under build.$A_DEFAULT"
exit 0

228
mkinstaller/linuxdeploy/deploy.py Executable file
View File

@ -0,0 +1,228 @@
#! /usr/bin/env python3
# -*- coding:utf-8 -*-
# @Time : 2024/12/15
# @Author : 寂静的羽夏(wingsummer)
# @FileName: deploy.py
import argparse
import os
import shutil
import hashlib
import subprocess
from colorama import Fore, Style
PACKAGE_NAME = "WingHexExplorer2"
def run_command_interactive(command):
"""
Run a command interactively, printing its stdout in real-time.
:param command: List of command arguments (e.g., ["your_command", "arg1", "arg2"])
:return: The return code of the command
"""
process = subprocess.Popen(
command,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, # Capture both stdout and stderr
text=True # Ensure the output is in text mode
)
while True:
output = process.stdout.readline()
if output == "" and process.poll() is not None:
break
if output:
print(Fore.GREEN + output.strip() + Style.RESET_ALL)
return_code = process.wait()
return return_code
def create_dir(dir):
if not os.path.exists(dir):
os.mkdir(dir)
def remove(path):
""" param <path> could either be relative or absolute. """
if os.path.isfile(path) or os.path.islink(path):
os.remove(path) # remove the file
elif os.path.isdir(path):
shutil.rmtree(path) # remove dir and all contains
def is_empty(path):
if os.path.exists(path) and not os.path.isfile(path):
# Checking if the directory is empty or not
if not os.listdir(path):
return True
else:
return False
else:
return False
def main():
parser = argparse.ArgumentParser(
prog="deploy.py", description=f"A deploying tool for {PACKAGE_NAME}")
parser.add_argument(
"folder", help="A folder that has contained the binary build")
args = parser.parse_args()
# start parsing build directory
build_path = os.path.abspath(args.folder)
installer_path = os.path.dirname(os.path.abspath(__file__))
projectbase = os.path.abspath(os.path.join(installer_path, "../.."))
cmake_cache = os.path.join(build_path, "CMakeCache.txt")
if (os.path.exists(build_path) == False):
print(
Fore.RED + "[Error] Not found a CMake build directory!" + Style.RESET_ALL)
exit(-1)
if (os.path.exists(cmake_cache) == False):
print(
Fore.RED + "[Error] This is not a CMake build directory!" + Style.RESET_ALL)
exit(-1)
installer_path_exec = ""
with open(cmake_cache, 'r') as cmake_config:
while (True):
line = cmake_config.readline()
if not line:
break
if (line.startswith("CMAKE_INSTALL_PREFIX:PATH")):
set = line.split('=', 1)
installer_path_exec = set[1].strip('\n')
pass
print(Fore.GREEN + ">> Checking patchelf..." + Style.RESET_ALL)
ret = run_command_interactive(["patchelf", "--version"])
if (ret != 0):
print(
Fore.RED + "[Error] patchelf is needed for deploying!" + Style.RESET_ALL)
exit(-2)
print(Fore.GREEN + ">> Checking file integrity..." + Style.RESET_ALL)
version_file_src = os.path.join(build_path, "WINGHEX_VERSION")
if (os.path.exists(version_file_src) == False):
print(
Fore.RED + "[Error] WINGHEX_VERSION file not found, maybe not a CMake build directory!" + Style.RESET_ALL)
exit(-1)
version_qt_src = os.path.join(build_path, "QT_VERSION")
if (os.path.exists(version_qt_src) == False):
print(
Fore.RED + "[Error] QT_VERSION file not found, maybe not a CMake build directory!" + Style.RESET_ALL)
exit(-1)
# check wether it has been installed
if (os.path.exists(installer_path_exec) == False):
print(
Fore.RED + "[Error] Installing directory not exists!" + Style.RESET_ALL)
exit(-1)
install_content = ["bin", "lib", "plugins",
"translations", PACKAGE_NAME]
for item in install_content:
if (os.path.exists(os.path.join(installer_path_exec, item)) == False):
print(
Fore.RED + "[Error] Installing contents have been damaged!" + Style.RESET_ALL)
exit(-1)
# ok, start deploying
remove(os.path.join(installer_path_exec, "bin"))
exemain_src = os.path.join(installer_path_exec, PACKAGE_NAME)
print(Fore.GREEN + ">> Deploying..." + Style.RESET_ALL)
create_dir(os.path.join(installer_path_exec, "plugin"))
create_dir(os.path.join(installer_path_exec, "scripts"))
create_dir(os.path.join(installer_path_exec, "aslib"))
shutil.copyfile(version_file_src, os.path.join(
installer_path_exec, "VERSION"))
shutil.copytree(os.path.join(installer_path, "share"),
os.path.join(installer_path_exec, "share"), dirs_exist_ok=True)
shutil.copytree(os.path.join(build_path, "lang"),
os.path.join(installer_path_exec, "lang"), dirs_exist_ok=True)
# copying deployment files
deploy_files = ["qt.conf", "uninstall.sh",
"purge.sh", f"{PACKAGE_NAME}.sh"]
for item in deploy_files:
shutil.copy2(os.path.join(installer_path, item),
os.path.join(installer_path_exec, item))
# finally, copy other files
print(Fore.GREEN + ">> Copying License and other materials..." + Style.RESET_ALL)
material_files = ["LICENSE", "authorband.svg",
"licenseband.svg", "screenshot.png", "README.md"]
for f in material_files:
shutil.copyfile(os.path.join(projectbase, f),
os.path.join(installer_path_exec, f))
shutil.copyfile(os.path.join(projectbase, "images", "author.jpg"),
os.path.join(installer_path_exec, "author.jpg"))
# in the end, start patching
ld_execs = [filename for filename in os.listdir(os.path.join(
installer_path_exec, "lib")) if filename.startswith("ld-linux")]
ld_count = len(ld_execs)
if (ld_count > 1):
print(
Fore.RED + "[Error] dynamic linker/loader can not be determined!" + Style.RESET_ALL)
exit(-3)
ld_exec = ""
if (ld_count == 1):
ld_exec = ld_execs[0]
ret = run_command_interactive(
["patchelf", "--set-interpreter", f"./lib/{ld_exec}", exemain_src])
if (ret != 0):
print(
Fore.RED + "[Error] patchelf error!" + Style.RESET_ALL)
exit(-4)
print(Fore.GREEN + ">> Calculating checksum..." + Style.RESET_ALL)
# calculate the md5 checksum
with open(exemain_src, 'rb') as file_to_check:
data = file_to_check.read()
md5_returned = hashlib.md5(data).hexdigest().upper()
print(Fore.GREEN + ">> Get MD5: " + md5_returned + Style.RESET_ALL)
with open(os.path.join(installer_path_exec, "md5sums"), 'w') as md5_file:
md5_file.write(md5_returned)
print(Fore.GREEN + ">> Deployment finished..." + Style.RESET_ALL)
if(ld_count == 1):
ld_path = os.path.join(installer_path_exec, "lib", ld_exec)
if (os.access(ld_path, os.X_OK) == False):
print(Fore.YELLOW + f"[Warn] {ld_exec} has no executable permission! You should set it for running a deployed program!" + Style.RESET_ALL)
with open(os.path.join(installer_path_exec, "LD_PATH"), "w") as ld_file:
ld_file.write(ld_exec)
exit(0)
if __name__ == "__main__":
main()
else:
print(
Fore.RED + "[Error] Please run this script in main mode" + Style.RESET_ALL)

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

View File

@ -0,0 +1,57 @@
#!/usr/bin/env bash
F_RED="\e[31m"
F_GREEN="\e[32m"
A_DEFAULT="\033[0m"
set -e
echo -e "$F_GREEN"
echo "======================================================"
echo " A Self Extracting Installer for WingHexExplorer2 "
echo " License: AGPL-3.0"
echo " Author: Wingsummer"
echo "======================================================"
echo -e "$A_DEFAULT"
if [ "$(id -u)" -ne 0 ]; then
echo -e "$F_RED Please run this script as root or using sudo! $A_DEFAULT"
exit 1
fi
# don't try to modified this path
INSTALL_PATH="/opt/WingHexExplorer2"
if [ -d "$INSTALL_PATH" ]; then
rm -rf "$INSTALL_PATH"
fi
mkdir -p "$INSTALL_PATH"
ARCHIVE=$(awk '/^__ARCHIVE_BELOW__/ {print NR + 1; exit 0; }' "$0")
tail -n+"$ARCHIVE" "$0" | tar xzv -C "$INSTALL_PATH"
echo -e "$F_GREEN"
echo ">> Registering componments of WingHexExplorer2!"
echo -e "$A_DEFAULT"
mv $INSTALL_PATH/share/com.wingsummer.winghexexplorer2.desktop /usr/share/applications/com.wingsummer.winghexexplorer2.desktop
xdg-mime install $INSTALL_PATH/share/x-winghex.xml
xdg-mime default /usr/share/applications/com.wingsummer.winghexexplorer2.desktop application/x-winghex
xdg-icon-resource install --context mimetypes --size 32 $INSTALL_PATH/share/winghexpro32.png application-x-winghex
xdg-icon-resource install --context mimetypes --size 64 $INSTALL_PATH/share/winghexpro64.png application-x-winghex
xdg-icon-resource install --context mimetypes --size 128 $INSTALL_PATH/share/winghexpro128.png application-x-winghex
update-mime-database /usr/share/mime
xdg-icon-resource forceupdate
gtk-update-icon-cache /usr/share/icons/hicolor
update-desktop-database /usr/share/applications
echo -e "$F_GREEN"
echo ">> WingHexExplorer2 is installed on your computer!"
echo -e "$A_DEFAULT"
exit 0
__ARCHIVE_BELOW__

109
mkinstaller/linuxdeploy/purge.sh Executable file
View File

@ -0,0 +1,109 @@
#!/usr/bin/env bash
F_RED="\e[31m"
F_GREEN="\e[32m"
A_DEFAULT="\033[0m"
CFG_PATH=".config/WingCloudStudio"
AUTO_START=".config/autostart"
CONF_FILE="WingHexExplorer2.conf"
CONTENT_PATH=".local/share/WingCloudStudio"
DESKTOP_FILE_NAME="com.wingsummer.winghexexplorer2.desktop"
PACKAGE_NAME="WingHexExplorer2"
# Function to check if a directory is empty
is_empty() {
local dir="$1"
if [ -d "$dir" ] && [ -z "$(ls -A "$dir")" ]; then
return 0 # True (empty)
else
return 1 # False (not empty)
fi
}
# Function to remove a file or directory safely
remove() {
local target="$1"
if [ -e "$target" ]; then
rm -rf "$target"
echo -e "$F_GREEN >> Removed: $target$A_DEFAULT"
fi
}
# Function to clear user data
clear_usrdata() {
local usr="$1"
local usr_path
if [ "$usr" = "root" ]; then
usr_path="/root"
else
usr_path="/home/$usr"
fi
local desktop_file="${usr_path}/${AUTO_START}/${DESKTOP_FILE_NAME}"
remove "$desktop_file"
local cfgpath="${usr_path}/${CFG_PATH}"
remove "${cfgpath}/${CONF_FILE}"
if is_empty "$cfgpath"; then
remove "$cfgpath"
fi
cfgpath="${usr_path}/${CONTENT_PATH}/${PACKAGE_NAME}"
remove "$cfgpath"
cfgpath="${usr_path}/${CONTENT_PATH}"
if is_empty "$cfgpath"; then
remove "$cfgpath"
fi
echo -e "$F_GREEN >> Purged $usr...$A_DEFAULT"
}
# Function to purge all data
purge() {
# Loop through user directories
for p in /home/*; do
local usr
usr=$(basename "$p")
if [ "$usr" = "lost+found" ]; then
continue
fi
clear_usrdata "$usr"
done
# Handle root user
clear_usrdata "root"
echo -e "$F_GREEN >> Clean-up finished...$A_DEFAULT"
}
if [ "$(id -u)" -ne 0 ]; then
echo -e "$F_RED Please run this script as root or using sudo! $A_DEFAULT"
exit 1
fi
read -r -p "Are you sure you want to purge all contents? (y/N): " CONFIRM
if [[ "$CONFIRM" =~ ^[Yy]$ ]]; then
xdg-mime uninstall /opt/WingHexExplorer2/share/x-winghex.xml
xdg-icon-resource uninstall --context mimetypes --size 32 application-x-winghex
xdg-icon-resource uninstall --context mimetypes --size 64 application-x-winghex
xdg-icon-resource uninstall --context mimetypes --size 128 application-x-winghex
update-mime-database /usr/share/mime
xdg-icon-resource forceupdate
update-icon-caches /usr/share/icons/hicolor
# remove desktop-icon
update-desktop-database /usr/share/applications
# remove all contents
rm /usr/share/applications/com.wingsummer.winghexexplorer2.desktop
purge
rm -r /opt/WingHexExplorer2
echo -e "$F_GREEN Uninstallation is finished... $A_DEFAULT"
else
echo -e "$F_GREEN Uninstallation canceled. $A_DEFAULT"
fi

View File

@ -0,0 +1,3 @@
[Paths]
Plugins= plugins
Libraries= lib

View File

@ -0,0 +1 @@
colorama==0.4.6

View File

@ -0,0 +1,14 @@
[Desktop Entry]
Name=WingHexExplorer2
Name[zh_CN]=羽云十六进制编辑器
Categories=Utility;
Exec=/opt/WingHexExplorer2/WingHexExplorer2.sh %F
Encoding=UTF-8
Type=Application
StartupNotify=false
Terminal=false
Icon=/opt/WingHexExplorer2/share/icon.png
StartupWMClass=WingHexExplorer2
Comment=a free and powerful opensource hexeditor based on QT
Comment[zh_CN]=一个基于 QT 的自由和强大的开源十六进制编辑器
MimeType=application/x-winghex;text/plain;application/octet-stream;

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="application/x-winghex">
<glob pattern="*.wingpro"/>
<icon name="application-x-winghex"/>
<comment>WingHexExplorer WorkSpace</comment>
<comment xml:lang="zh_CN">羽云十六进制编辑器项目文件</comment>
</mime-type>
</mime-info>

View File

@ -0,0 +1,34 @@
#!/usr/bin/env bash
F_RED="\e[31m"
F_GREEN="\e[32m"
A_DEFAULT="\033[0m"
if [ "$(id -u)" -ne 0 ]; then
echo -e "$F_RED Please run this script as root or using sudo! $A_DEFAULT"
exit 1
fi
read -r -p "Are you sure you want to uninstall and delete all contents? (y/N): " CONFIRM
if [[ "$CONFIRM" =~ ^[Yy]$ ]]; then
xdg-mime uninstall /opt/WingHexExplorer2/share/x-winghex.xml
xdg-icon-resource uninstall --context mimetypes --size 32 application-x-winghex
xdg-icon-resource uninstall --context mimetypes --size 64 application-x-winghex
xdg-icon-resource uninstall --context mimetypes --size 128 application-x-winghex
update-mime-database /usr/share/mime
xdg-icon-resource forceupdate
update-icon-caches /usr/share/icons/hicolor
# remove desktop-icon
update-desktop-database /usr/share/applications
# remove all contents
rm /usr/share/applications/com.wingsummer.winghexexplorer2.desktop
rm -r /opt/WingHexExplorer2
echo -e "$F_GREEN Uninstallation is finished... $A_DEFAULT"
else
echo -e "$F_GREEN Uninstallation canceled. $A_DEFAULT"
fi

View File

@ -8,7 +8,7 @@ Type=Application
StartupNotify=false
Terminal=false
Icon=/opt/WingHexExplorer2/share/icon.png
StartupWMClass=WingHexExplorer
StartupWMClass=WingHexExplorer2
Comment=a free and powerful opensource hexeditor based on QT
Comment[zh_CN]=一个基于 QT 的自由和强大的开源十六进制编辑器
MimeType=application/x-winghex;text/plain;application/octet-stream;

View File

@ -131,7 +131,7 @@ def update(build_path):
print(Fore.GREEN + ">> Copying License and other materials..." + Style.RESET_ALL)
material_files = ["LICENSE", "authorband.svg",
"licenseband.svg", "screenshot.png", "README.md", "TODO.txt"]
"licenseband.svg", "screenshot.png", "README.md"]
for f in material_files:
shutil.copyfile(os.path.join(projectbase, f),

View File

@ -0,0 +1,2 @@
colorama==0.4.6
psutil==6.1.0

View File

@ -41,6 +41,7 @@
<file>images/info.png</file>
<file>images/jmp.png</file>
<file>images/layout.png</file>
<file>images/layoutexport.png</file>
<file>images/lock.png</file>
<file>images/log.png</file>
<file>images/mAddr.png</file>
@ -107,6 +108,7 @@
<file>images/workspace.png</file>
<file>images/writable.png</file>
<file>src/TESTCODE.as</file>
<file>src/components.md</file>
<file>src/translist.md</file>
</qresource>
<qresource prefix="/qpathedit/icons">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 550 KiB

After

Width:  |  Height:  |  Size: 4.3 MiB

View File

@ -24,9 +24,7 @@
AngelObjString::AngelObjString() {}
QString AngelObjString::stringToString(void *obj, int expandMembers,
asDebugger *dbg) {
Q_UNUSED(expandMembers);
QString AngelObjString::stringToString(void *obj, asDebugger *dbg) {
Q_UNUSED(dbg);
// We know the received object is a string
@ -47,32 +45,27 @@ QString AngelObjString::stringToString(void *obj, int expandMembers,
}
}
QString AngelObjString::arrayToString(void *obj, int expandMembers,
asDebugger *dbg) {
QString AngelObjString::arrayToString(void *obj, asDebugger *dbg) {
CScriptArray *arr = reinterpret_cast<CScriptArray *>(obj);
QString str;
QTextStream s(&str);
s << tr("(len=") << arr->GetSize() << QStringLiteral(")");
if (expandMembers > 0) {
s << QStringLiteral(" [");
for (asUINT n = 0; n < arr->GetSize(); n++) {
s << dbg->toString(arr->At(n), arr->GetElementTypeId(),
expandMembers - 1,
arr->GetArrayObjectType()->GetEngine());
if (n < arr->GetSize() - 1)
s << ", ";
}
s << QStringLiteral("]");
s << QStringLiteral(" [");
for (asUINT n = 0; n < arr->GetSize(); n++) {
s << dbg->toString(arr->At(n), arr->GetElementTypeId(),
arr->GetArrayObjectType()->GetEngine());
if (n < arr->GetSize() - 1)
s << ", ";
}
s << QStringLiteral("]");
return str;
}
QString AngelObjString::charToString(void *obj, int expandMembers,
asDebugger *dbg) {
Q_UNUSED(expandMembers);
QString AngelObjString::charToString(void *obj, asDebugger *dbg) {
Q_UNUSED(dbg);
// We know the received object is a char
@ -80,39 +73,36 @@ QString AngelObjString::charToString(void *obj, int expandMembers,
return QString(*val);
}
QString AngelObjString::dictionaryToString(void *obj, int expandMembers,
asDebugger *dbg) {
QString AngelObjString::dictionaryToString(void *obj, asDebugger *dbg) {
CScriptDictionary *dic = reinterpret_cast<CScriptDictionary *>(obj);
QString str;
QTextStream s(&str);
s << tr("(len=") << dic->GetSize() << ")";
if (expandMembers > 0) {
s << " [";
asUINT n = 0;
for (CScriptDictionary::CIterator it = dic->begin(); it != dic->end();
it++, n++) {
s << "[" << it.GetKey() << "] = ";
s << " [";
asUINT n = 0;
for (CScriptDictionary::CIterator it = dic->begin(); it != dic->end();
it++, n++) {
s << "[" << it.GetKey() << "] = ";
// Get the type and address of the value
const void *val = it.GetAddressOfValue();
int typeId = it.GetTypeId();
// Get the type and address of the value
const void *val = it.GetAddressOfValue();
int typeId = it.GetTypeId();
// Use the engine from the currently active context (if none is
// active, the debugger will use the engine held inside it by
// default, but in an environment where there multiple engines this
// might not be the correct instance).
asIScriptContext *ctx = asGetActiveContext();
// Use the engine from the currently active context (if none is
// active, the debugger will use the engine held inside it by
// default, but in an environment where there multiple engines this
// might not be the correct instance).
asIScriptContext *ctx = asGetActiveContext();
s << dbg->toString(const_cast<void *>(val), typeId,
expandMembers - 1, ctx ? ctx->GetEngine() : 0);
s << dbg->toString(const_cast<void *>(val), typeId,
ctx ? ctx->GetEngine() : 0);
if (n < dic->GetSize() - 1)
s << ", ";
}
s << "]";
if (n < dic->GetSize() - 1)
s << ", ";
}
s << "]";
return str;
}

View File

@ -29,15 +29,13 @@ class AngelObjString : public QObject {
public:
// for debugger use
static QString stringToString(void *obj, int expandMembers,
asDebugger *dbg);
static QString stringToString(void *obj, asDebugger *dbg);
static QString arrayToString(void *obj, int expandMembers, asDebugger *dbg);
static QString arrayToString(void *obj, asDebugger *dbg);
static QString charToString(void *obj, int expandMembers, asDebugger *dbg);
static QString charToString(void *obj, asDebugger *dbg);
static QString dictionaryToString(void *obj, int expandMembers,
asDebugger *dbg);
static QString dictionaryToString(void *obj, asDebugger *dbg);
public:
// ==================================================

View File

@ -27,11 +27,13 @@
#define QPTR_WRAP(decl) "uint " decl
#define QPTR "uint"
#define QSIZETYPE "int"
#define QUSIZETYPE "uint"
#elif Q_PROCESSOR_WORDSIZE == 8
#define QSIZETYPE_WRAP(decl) "int64 " decl
#define QPTR_WRAP(decl) "uint64 " decl
#define QPTR "uint64"
#define QSIZETYPE "int64"
#define QUSIZETYPE "uint64"
#else
#error "Processor with unexpected word size"
#endif

View File

@ -22,6 +22,7 @@
#include "angelscript.h"
#include "clangformatmanager.h"
#include "dbghelper.h"
#include "define.h"
#include "dialog/mainwindow.h"
#include "dialog/splashdialog.h"
#include "languagemanager.h"
@ -37,10 +38,6 @@ AppManager::AppManager(int &argc, char *argv[])
: SingleApplication(argc, argv, true) {
ASSERT_SINGLETON;
setApplicationName(APP_NAME);
setOrganizationName(APP_ORG);
setApplicationVersion(WINGHEX_VERSION);
auto args = arguments();
if (isSecondary()) {
QByteArray buffer;
@ -51,6 +48,7 @@ AppManager::AppManager(int &argc, char *argv[])
}
}
sendMessage(buffer);
throw CrashCode::AlreadyStart;
}
#ifndef ANGELSCRIPT_H
@ -64,7 +62,7 @@ AppManager::AppManager(int &argc, char *argv[])
if (strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY")) {
WingMessageBox::critical(nullptr, qAppName(),
tr("GenericCallNotFullySupported"));
exit(-1);
throw CrashCode::GenericCallNotSupported;
}
Logger::instance();
@ -93,19 +91,28 @@ AppManager::AppManager(int &argc, char *argv[])
return;
}
_w->show();
_w->raise();
_w->activateWindow();
_w->raise();
});
connect(this, &SingleApplication::receivedMessage, this,
[this](quint32 instanceId, QByteArray message) {
Q_UNUSED(instanceId);
QDataStream out(&message, QIODevice::WriteOnly);
Q_ASSERT(_w);
if (!_w->isEnabled()) {
return;
}
QDataStream out(&message, QIODevice::ReadOnly);
while (!out.atEnd()) {
QString param;
out >> param;
openFile(param);
}
_w->show();
_w->activateWindow();
_w->raise();
});
if (splash)

View File

@ -22,9 +22,7 @@
#include <QFileInfo>
#include <QObject>
asBuilder::asBuilder(asIScriptEngine *engine) : AsPreprocesser(engine) {
module = nullptr;
}
asBuilder::asBuilder(asIScriptEngine *engine) : AsPreprocesser(engine) {}
int asBuilder::StartNewModule(const char *moduleName) {
module = engine->GetModule(moduleName, asGM_ALWAYS_CREATE);

View File

@ -29,16 +29,16 @@ public:
explicit asBuilder(asIScriptEngine *engine);
// Start a new module
int StartNewModule(const char *moduleName);
virtual int StartNewModule(const char *moduleName);
// Build the added script sections
int Build();
virtual int Build();
// Returns the current module
asIScriptModule *GetModule();
protected:
asIScriptModule *module;
asIScriptModule *module = nullptr;
};
#endif // ASBUILDER_H

View File

@ -194,8 +194,8 @@ asDebugger::localVariables(asIScriptContext *ctx) {
VariablesInfo var;
var.name = func->GetVarDecl(n);
var.value = toString(ctx->GetAddressOfVar(n), typeId,
_expandMembers, ctx->GetEngine());
var.value =
toString(ctx->GetAddressOfVar(n), typeId, ctx->GetEngine());
vars << var;
}
}
@ -226,8 +226,8 @@ asDebugger::globalVariables(asIScriptContext *ctx) {
VariablesInfo var;
var.name = mod->GetGlobalVarDeclaration(n);
var.value = toString(mod->GetAddressOfGlobalVar(n), typeId,
_expandMembers, ctx->GetEngine());
var.value =
toString(mod->GetAddressOfGlobalVar(n), typeId, ctx->GetEngine());
}
return vars;
@ -244,9 +244,7 @@ void asDebugger::listMemberProperties(asIScriptContext *ctx) {
QTextStream s(&str);
s << QStringLiteral("this = ")
<< toString(ptr, ctx->GetThisTypeId(), _expandMembers,
ctx->GetEngine())
<< Qt::endl;
<< toString(ptr, ctx->GetThisTypeId(), ctx->GetEngine()) << Qt::endl;
}
}
@ -318,7 +316,7 @@ bool asDebugger::checkBreakPoint(asIScriptContext *ctx) {
return false;
}
QString asDebugger::toString(void *value, asUINT typeId, int expandMembersLevel,
QString asDebugger::toString(void *value, asUINT typeId,
asIScriptEngine *engine) {
if (value == nullptr)
return QStringLiteral("<null>");
@ -378,8 +376,9 @@ QString asDebugger::toString(void *value, asUINT typeId, int expandMembersLevel,
asIScriptObject *obj = (asIScriptObject *)value;
// Print the address of the object
s << QStringLiteral("{") << obj << QStringLiteral("}");
// s << QStringLiteral("{") << obj << QStringLiteral("}");
s << QStringLiteral("{");
// Print the members
if (obj && _expandMembers > 0) {
asITypeInfo *type = obj->GetObjectType();
@ -389,12 +388,18 @@ QString asDebugger::toString(void *value, asUINT typeId, int expandMembersLevel,
else
s << QStringLiteral(", ");
s << type->GetPropertyDeclaration(n) << QStringLiteral(" = ")
<< toString(obj->GetAddressOfProperty(n),
obj->GetPropertyTypeId(n), _expandMembers - 1,
type->GetEngine());
const char *name = nullptr;
type->GetProperty(n, &name);
if (name) {
s << name /*type->GetPropertyDeclaration(n)*/
<< QStringLiteral(" = ")
<< toString(obj->GetAddressOfProperty(n),
obj->GetPropertyTypeId(n), type->GetEngine());
}
}
}
s << QStringLiteral("}");
} else {
// Dereference handles, so we can see what it points to
if (typeId & asTYPEID_OBJHANDLE)
@ -404,8 +409,8 @@ QString asDebugger::toString(void *value, asUINT typeId, int expandMembersLevel,
// possible to see when handles point to the same object
if (engine) {
asITypeInfo *type = engine->GetTypeInfoById(typeId);
if (type->GetFlags() & asOBJ_REF)
s << QStringLiteral("{") << value << QStringLiteral("}");
// if (type->GetFlags() & asOBJ_REF)
// s << QStringLiteral("{") << value << QStringLiteral("}");
if (value) {
// Check if there is a registered to-string callback
@ -426,7 +431,7 @@ QString asDebugger::toString(void *value, asUINT typeId, int expandMembersLevel,
// Invoke the callback to get the string representation of
// this type
s << it.value()(value, _expandMembers, this);
s << it.value()(value, this);
}
}
} else
@ -614,7 +619,7 @@ QString asDebugger::printValue(const QString &expr, asIScriptContext *ctx,
error = WatchExpError::NotEndAfterSymbol;
return {};
} else {
return toString(ptr, typeId, _expandMembers, engine);
return toString(ptr, typeId, engine);
}
} else {
error = WatchExpError::NoMatchingSymbol;

View File

@ -85,12 +85,7 @@ public:
virtual ~asDebugger();
// Register callbacks to handle to-string conversions of application types
// The expandMembersLevel is a counter for how many recursive levels the
// members should be expanded. If the object that is being converted to a
// string has members of its own the callback should call the debugger's
// ToString passing in expandMembersLevel - 1.
typedef QString (*ToStringCallback)(void *obj, int expandMembersLevel,
asDebugger *dbg);
typedef QString (*ToStringCallback)(void *obj, asDebugger *dbg);
void registerToStringCallback(const asITypeInfo *ti,
ToStringCallback callback);
@ -114,7 +109,7 @@ public:
// Line callback invoked by context
void lineCallback(asIScriptContext *ctx);
QString toString(void *value, asUINT typeId, int expandMembersLevel,
QString toString(void *value, asUINT typeId,
asIScriptEngine *engine = nullptr);
GCStatistic gcStatistics();
@ -151,7 +146,7 @@ private:
QString file;
int line = -1;
int col = -1;
int stackCount = -1;
asUINT stackCount = 0;
};
private:

View File

@ -18,6 +18,7 @@
#include "languagemanager.h"
#include "class/settingmanager.h"
#include "define.h"
#include "wingmessagebox.h"
#include <QApplication>
@ -134,7 +135,7 @@ bool LanguageManager::unpackTr(const QString &filename) {
QZipReader reader(filename);
if (reader.count() != 5) {
if (reader.count() != 3) {
return false;
}
@ -145,10 +146,6 @@ bool LanguageManager::unpackTr(const QString &filename) {
_data.trFiles = reader.fileData(file.filePath);
} else if (file.filePath == QStringLiteral("about.md")) {
_data.about = reader.fileData(file.filePath);
} else if (file.filePath == QStringLiteral("components.md")) {
_data.component = reader.fileData(file.filePath);
} else if (file.filePath == QStringLiteral("credits.md")) {
_data.credit = reader.fileData(file.filePath);
} else if (file.filePath == QStringLiteral("devs.md")) {
_data.dev = reader.fileData(file.filePath);
}
@ -157,7 +154,6 @@ bool LanguageManager::unpackTr(const QString &filename) {
reader.close();
return !_data.trFiles.isEmpty() && !_data.about.isEmpty() &&
!_data.component.isEmpty() && !_data.credit.isEmpty() &&
!_data.dev.isEmpty();
}
@ -178,11 +174,29 @@ void LanguageManager::abortAndExit() {
"Please try reinstalling the software to "
"solve the problem."));
}
qApp->exit(-1);
throw CrashCode::LanguageFile;
}
QLocale LanguageManager::defaultLocale() const { return _defaultLocale; }
QTranslator *LanguageManager::try2LoadPluginLang(const QString &plgID) {
QDir langDir(QStringLiteral(":/PLGLANG"));
if (!langDir.cd(plgID)) {
return nullptr;
}
auto translator = new QTranslator(this);
if (translator->load(_defaultLocale, plgID, QStringLiteral("_"),
langDir.absolutePath())) {
if (qApp->installTranslator(translator)) {
return translator;
}
}
translator->deleteLater();
return nullptr;
}
LanguageManager::LanguageData LanguageManager::data() const { return _data; }
QStringList LanguageManager::langsDisplay() const { return m_langsDisplay; }

View File

@ -22,6 +22,7 @@
#include <QLocale>
#include <QObject>
#include <QStringList>
#include <QTranslator>
class LanguageManager : public QObject {
Q_OBJECT
@ -30,9 +31,7 @@ public:
struct LanguageData {
QByteArray trFiles;
QString about;
QString component;
QString dev;
QString credit;
};
public:
@ -44,6 +43,8 @@ public:
QLocale defaultLocale() const;
QTranslator *try2LoadPluginLang(const QString &plgID);
private:
LanguageManager();

View File

@ -0,0 +1,84 @@
/*==============================================================================
** 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 "layoutmanager.h"
#include "dbghelper.h"
#include "languagemanager.h"
#include "utilities.h"
LayoutManager &LayoutManager::instance() {
static LayoutManager ins;
return ins;
}
const QHash<QString, QByteArray> LayoutManager::layouts() const {
return _layouts;
}
QByteArray LayoutManager::layout(const QString &v) const {
return _layouts.value(v);
}
qsizetype LayoutManager::layoutCount() const { return _layouts.size(); }
LayoutManager::LayoutManager() {
ASSERT_SINGLETON;
QDir pdir(Utilities::getAppDataPath());
auto lname = QStringLiteral("layouts");
if (!pdir.exists(lname)) {
pdir.mkdir(lname);
return;
}
if (!pdir.cd(lname)) {
return;
}
// read translation names
auto trf = QStringLiteral("metatr.ini");
if (pdir.exists(trf)) {
process(pdir, std::make_unique<QSettings>(pdir.absoluteFilePath(trf),
QSettings::IniFormat));
} else {
process(pdir, nullptr);
}
}
void LayoutManager::process(const QDir &dir,
const std::unique_ptr<QSettings> &set) {
auto name = LanguageManager::instance().defaultLocale().name();
auto sep = QStringLiteral("/");
for (auto &l : dir.entryInfoList({"*.wing-layout"}, QDir::Files)) {
QString k;
if (set) {
k = set->value(name + sep + l.baseName()).toString();
}
if (k.isEmpty()) {
k = l.baseName();
}
QFile f(l.absoluteFilePath());
if (f.open(QFile::ReadOnly)) {
auto b = f.readAll();
if (!b.isEmpty()) {
_layouts.insert(k.trimmed(), b);
}
}
}
}

50
src/class/layoutmanager.h Normal file
View File

@ -0,0 +1,50 @@
/*==============================================================================
** 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 LAYOUTMANAGER_H
#define LAYOUTMANAGER_H
#include <QDir>
#include <QHash>
#include <QSettings>
#include <QString>
#include <memory>
class LayoutManager {
public:
static LayoutManager &instance();
public:
const QHash<QString, QByteArray> layouts() const;
QByteArray layout(const QString &v) const;
qsizetype layoutCount() const;
private:
LayoutManager();
void process(const QDir &dir, const std::unique_ptr<QSettings> &set);
private:
QHash<QString, QByteArray> _layouts;
Q_DISABLE_COPY_MOVE(LayoutManager)
};
#endif // LAYOUTMANAGER_H

View File

@ -32,7 +32,7 @@
*/
QAsParser::QAsParser(asIScriptEngine *engine)
: asBuilder(engine), _engine(engine) {
: AsPreprocesser(engine), _engine(engine) {
addGlobalFunctionCompletion(engine);
addClassCompletion(engine);
addEnumCompletion(engine);
@ -169,20 +169,20 @@ QByteArray QAsParser::getFnRetTypeString(asIScriptFunction *fn,
}
bool QAsParser::parse(const QString &filename) {
if (StartNewModule("as_parser") != 0) {
return false;
}
// if (StartNewModule("as_parser") != 0) {
// return false;
// }
ClearAll();
auto ret = LoadScriptSection(filename);
if (ret != 0) {
return false;
}
ClearAll();
auto mod = dynamic_cast<asCModule *>(GetModule());
Q_ASSERT(mod);
asCParser parser(mod->m_builder);
// auto mod = dynamic_cast<asCModule *>(GetModule());
// Q_ASSERT(mod);
// asCParser parser(mod->m_builder);
// m_code.reset(new asCScriptCode);
// m_code->SetCode("as_parser", modifiedScript.data(), true);
@ -191,24 +191,6 @@ bool QAsParser::parse(const QString &filename) {
// auto pnodes = parser.GetScriptNode();
// QList<QCodeNode *> qnodes;
// do {
// auto node = asNode2CodeNode(pnodes);
// auto p = pnodes->firstChild;
// while (p) {
// auto cnode = asNode2CodeNode(pnodes);
// cnode->parent = node;
// node->children.append(cnode);
// p = pnodes->next;
// }
// qnodes.append(node);
// pnodes = pnodes->next;
// } while (pnodes != nullptr);
return true;
}

View File

@ -18,15 +18,19 @@
#ifndef _QAS_PARSER_H_
#define _QAS_PARSER_H_
#include "class/asbuilder.h"
#include "angelscript.h"
#include "class/aspreprocesser.h"
#include <QByteArray>
#include <QHash>
#include <QList>
#include <QScopedPointer>
class asCScriptCode;
class asCScriptNode;
class QCodeNode;
class QAsParser : protected asBuilder {
class QAsParser : protected AsPreprocesser {
public:
explicit QAsParser(asIScriptEngine *engine);
virtual ~QAsParser();

View File

@ -17,7 +17,6 @@
#include "scriptconsolemachine.h"
#include "AngelScript/sdk/add_on/scripthelper/scripthelper.h"
#include <QRegularExpression>
#include <QTextStream>
@ -196,4 +195,85 @@ bool ScriptConsoleMachine::execString(asIScriptEngine *engine,
}
}
int ScriptConsoleMachine::ExecuteString(asIScriptEngine *engine,
const char *code, asIScriptModule *mod,
asIScriptContext *ctx) {
return ExecuteString(engine, code, 0, asTYPEID_VOID, mod, ctx);
}
ScriptObjModel *ScriptConsoleMachine::model() const { return _model; }
int ScriptConsoleMachine::ExecuteString(asIScriptEngine *engine,
const char *code, void *ref,
int refTypeId, asIScriptModule *mod,
asIScriptContext *ctx) {
// Wrap the code in a function so that it can be compiled and executed
std::string funcCode = " ExecuteString() {\n";
funcCode += code;
funcCode += "\n}";
// Determine the return type based on the type of the ref arg
funcCode = engine->GetTypeDeclaration(refTypeId, true) + funcCode;
// GetModule will free unused types, so to be on the safe side we'll
// hold on to a reference to the type
asITypeInfo *type = 0;
if (refTypeId & asTYPEID_MASK_OBJECT) {
type = engine->GetTypeInfoById(refTypeId);
if (type)
type->AddRef();
}
// If no module was provided, get a dummy from the engine
asIScriptModule *execMod =
mod ? mod : engine->GetModule("ExecuteString", asGM_ALWAYS_CREATE);
// Now it's ok to release the type
if (type)
type->Release();
// Compile the function that can be executed
asIScriptFunction *func = 0;
int r = execMod->CompileFunction("ExecuteString", funcCode.c_str(), -1, 0,
&func);
if (r < 0)
return r;
// If no context was provided, request a new one from the engine
asIScriptContext *execCtx = ctx ? ctx : engine->RequestContext();
r = execCtx->Prepare(func);
if (r >= 0) {
// Execute the function
r = execCtx->Execute();
// Unless the provided type was void retrieve it's value
if (ref != 0 && refTypeId != asTYPEID_VOID) {
if (refTypeId & asTYPEID_OBJHANDLE) {
// Expect the pointer to be null to start with
assert(*reinterpret_cast<void **>(ref) == 0);
*reinterpret_cast<void **>(ref) = *reinterpret_cast<void **>(
execCtx->GetAddressOfReturnValue());
engine->AddRefScriptObject(*reinterpret_cast<void **>(ref),
engine->GetTypeInfoById(refTypeId));
} else if (refTypeId & asTYPEID_MASK_OBJECT) {
// Use the registered assignment operator to do a value
// assign. This assumes that the ref is pointing to a valid
// object instance.
engine->AssignScriptObject(ref,
execCtx->GetAddressOfReturnValue(),
engine->GetTypeInfoById(refTypeId));
} else {
// Copy the primitive value
memcpy(ref, execCtx->GetAddressOfReturnValue(),
engine->GetSizeOfPrimitiveType(refTypeId));
}
}
}
// Clean up
func->Release();
if (!ctx)
engine->ReturnContext(execCtx);
return r;
}

View File

@ -41,6 +41,14 @@ protected:
private:
bool execString(asIScriptEngine *engine, const QString &code);
// copy from helper
int ExecuteString(asIScriptEngine *engine, const char *code,
asIScriptModule *mod, asIScriptContext *ctx);
int ExecuteString(asIScriptEngine *engine, const char *code, void *ref,
int refTypeId, asIScriptModule *mod,
asIScriptContext *ctx);
private:
ScriptObjModel *_model = nullptr;

View File

@ -26,8 +26,10 @@
#include "AngelScript/sdk/add_on/scriptmath/scriptmath.h"
#include "AngelScript/sdk/add_on/scriptmath/scriptmathcomplex.h"
#include "AngelScript/sdk/add_on/weakref/weakref.h"
#include "class/asbuilder.h"
#include "plugin/pluginsystem.h"
#include "scriptaddon/scriptcolor.h"
#include "scriptaddon/scriptjson.h"
#include "scriptaddon/scriptqstring.h"
#include "scriptaddon/scriptregex.h"
@ -82,6 +84,7 @@ bool ScriptMachine::configureEngine(asIScriptEngine *engine) {
RegisterScriptGrid(engine);
RegisterScriptHandle(engine);
RegisterColor(engine);
RegisterScriptJson(engine);
RegisterExceptionRoutines(engine);
_rtypes.resize(RegisteredType::tMAXCOUNT);
@ -225,7 +228,7 @@ void ScriptMachine::exceptionCallback(asIScriptContext *context) {
void ScriptMachine::print(void *ref, int typeId) {
MessageInfo info;
info.message = _debugger->toString(ref, typeId, 3, _engine);
info.message = _debugger->toString(ref, typeId, _engine);
emit onOutput(MessageType::Print, info);
}
@ -415,11 +418,15 @@ void ScriptMachine::messageCallback(const asSMessageInfo *msg, void *param) {
}
auto ins = static_cast<ScriptMachine *>(param);
auto m = processTranslation(msg->message, ins);
if (m.isEmpty()) {
return;
}
MessageInfo info;
info.row = msg->row;
info.col = msg->col;
info.section = msg->section;
info.message = processTranslation(msg->message);
info.message = m;
emit ins->onOutput(t, info);
}
@ -470,6 +477,8 @@ asIScriptContext *ScriptMachine::requestContextCallback(asIScriptEngine *engine,
void ScriptMachine::returnContextCallback(asIScriptEngine *engine,
asIScriptContext *ctx, void *param) {
Q_UNUSED(engine);
// We can also check for possible script exceptions here if so desired
// Unprepare the context to free any objects it may still hold (e.g. return
@ -487,6 +496,11 @@ void ScriptMachine::returnContextCallback(asIScriptEngine *engine,
int ScriptMachine::pragmaCallback(const QByteArray &pragmaText,
AsPreprocesser *builder, void *userParam) {
Q_UNUSED(pragmaText);
Q_UNUSED(builder);
Q_UNUSED(userParam);
// Maybe I will use these codes next time
// asIScriptEngine *engine = builder->GetEngine();
// Filter the pragmaText so only what is of interest remains
@ -521,6 +535,8 @@ int ScriptMachine::pragmaCallback(const QByteArray &pragmaText,
int ScriptMachine::includeCallback(const QString &include, bool quotedInclude,
const QString &from, AsPreprocesser *builder,
void *userParam) {
Q_UNUSED(userParam);
QFileInfo info(include);
bool isAbsolute = info.isAbsolute();
bool hasNoExt = info.suffix().isEmpty();
@ -553,7 +569,8 @@ int ScriptMachine::includeCallback(const QString &include, bool quotedInclude,
return builder->AddSectionFromFile(inc);
}
QString ScriptMachine::processTranslation(const char *content) {
QString ScriptMachine::processTranslation(const char *content,
ScriptMachine *machine) {
static QHash<QRegularExpression, TranslateFunc> exps{
{QRegularExpression(QStringLiteral("^'(.*?)' is already declared")),
[](const QStringList &contents) -> QString {
@ -767,7 +784,9 @@ QString ScriptMachine::processTranslation(const char *content) {
.arg(contents.at(1), contents.at(2));
}},
{QRegularExpression(QStringLiteral("^Instead found '(.*?)'")),
[](const QStringList &contents) -> QString {
[machine](const QStringList &contents) -> QString {
if (machine->m_insteadFoundDisabled)
return {};
return tr("Instead found '%1'").arg(contents.at(1));
}},
{QRegularExpression(
@ -1546,6 +1565,14 @@ void ScriptMachine::translation() {
tr("Too many nested calls");
}
bool ScriptMachine::insteadFoundDisabled() const {
return m_insteadFoundDisabled;
}
void ScriptMachine::setInsteadFoundDisabled(bool newInsteadFoundDisabled) {
m_insteadFoundDisabled = newInsteadFoundDisabled;
}
asIScriptEngine *ScriptMachine::engine() const { return _engine; }
asIScriptContext *ScriptMachine::immediateContext() const {

View File

@ -19,7 +19,7 @@
#define SCRIPTMACHINE_H
#include "AngelScript/sdk/angelscript/include/angelscript.h"
#include "class/asbuilder.h"
#include "class/aspreprocesser.h"
#include "asdebugger.h"
#include "class/ascontextmgr.h"
@ -29,7 +29,7 @@
class ScriptMachine : public QObject {
Q_OBJECT
private:
typedef QString (*TranslateFunc)(const QStringList &contents);
using TranslateFunc = std::function<QString(const QStringList &)>;
public:
enum class MessageType { Info, Warn, Error, Print };
@ -94,6 +94,9 @@ public:
asIScriptEngine *engine() const;
bool insteadFoundDisabled() const;
void setInsteadFoundDisabled(bool newInsteadFoundDisabled);
public slots:
virtual bool executeCode(const QString &code);
virtual bool executeScript(const QString &script, bool isInDebug = false);
@ -132,7 +135,8 @@ private:
const QString &from, AsPreprocesser *builder,
void *userParam);
static QString processTranslation(const char *content);
static QString processTranslation(const char *content,
ScriptMachine *machine);
void exceptionCallback(asIScriptContext *context);
@ -154,6 +158,8 @@ private:
std::function<QString(void)> _getInputFn;
asIScriptContext *_immediateContext = nullptr;
bool m_insteadFoundDisabled = false;
};
Q_DECLARE_METATYPE(ScriptMachine::MessageInfo)

View File

@ -55,12 +55,15 @@ int WingAngelAPI::sdkVersion() const { return WingHex::SDKVERSION; }
const QString WingAngelAPI::signature() const { return WingHex::WINGSUMMER; }
bool WingAngelAPI::init(const QList<WingHex::WingPluginInfo> &loadedplugin) {
Q_UNUSED(loadedplugin);
bool WingAngelAPI::init(const std::unique_ptr<QSettings> &set) {
Q_UNUSED(set);
return true;
}
void WingAngelAPI::unload() { this->disconnect(); }
void WingAngelAPI::unload(std::unique_ptr<QSettings> &set) {
Q_UNUSED(set);
this->disconnect();
}
const QString WingAngelAPI::pluginName() const {
return tr("AngelScriptService");
@ -380,6 +383,7 @@ void WingAngelAPI::installColorDialogAPI(asIScriptEngine *engine) {
void WingAngelAPI::installHexBaseType(asIScriptEngine *engine) {
registerAngelType<WingHex::ErrFile>(engine, "ErrFile");
registerAngelType<WingHex::SelectionMode>(engine, "SelectionMode");
int r = engine->RegisterTypedef("byte", "uint8");
Q_ASSERT(r >= 0);
@ -405,23 +409,6 @@ void WingAngelAPI::installHexBaseType(asIScriptEngine *engine) {
Q_ASSERT(r >= 0);
Q_UNUSED(r);
// BookMark
r = engine->RegisterObjectType("BookMark", sizeof(WingHex::BookMark),
asOBJ_VALUE | asOBJ_POD |
asGetTypeTraits<WingHex::BookMark>());
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectProperty("BookMark", QSIZETYPE_WRAP("pos"),
asOFFSET(WingHex::BookMark, pos));
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectProperty("BookMark", "string comment",
asOFFSET(WingHex::BookMark, comment));
Q_ASSERT(r >= 0);
Q_UNUSED(r);
// HexPosition
r = engine->RegisterObjectType("HexPosition", sizeof(WingHex::HexPosition),
asOBJ_VALUE | asOBJ_POD |
@ -471,42 +458,6 @@ void WingAngelAPI::installHexBaseType(asIScriptEngine *engine) {
asCALL_THISCALL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
// HexMetadataItem
r = engine->RegisterObjectType(
"HexMetadataItem", sizeof(WingHex::HexMetadataItem),
asOBJ_VALUE | asOBJ_POD | asGetTypeTraits<WingHex::HexMetadataItem>());
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectProperty(
"HexMetadataItem", QSIZETYPE_WRAP("begin"),
asOFFSET(WingHex::HexMetadataItem, begin));
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectProperty("HexMetadataItem", QSIZETYPE_WRAP("end"),
asOFFSET(WingHex::HexMetadataItem, end));
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectProperty(
"HexMetadataItem", "color foreground",
asOFFSET(WingHex::HexMetadataItem, foreground));
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectProperty(
"HexMetadataItem", "color background",
asOFFSET(WingHex::HexMetadataItem, background));
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectProperty(
"HexMetadataItem", "string comment",
asOFFSET(WingHex::HexMetadataItem, comment));
Q_ASSERT(r >= 0);
Q_UNUSED(r);
}
void WingAngelAPI::installHexReaderAPI(asIScriptEngine *engine) {
@ -541,10 +492,6 @@ void WingAngelAPI::installHexReaderAPI(asIScriptEngine *engine) {
engine, std::bind(&WingHex::WingPlugin::Reader::currentPos, reader),
"HexPosition currentPos()");
registerAPI<WingHex::HexPosition(void)>(
engine, std::bind(&WingHex::WingPlugin::Reader::selectionPos, reader),
"HexPosition selectionPos()");
registerAPI<bool(void)>(
engine, std::bind(&WingHex::WingPlugin::Reader::stringVisible, reader),
"bool stringVisible()");
@ -606,9 +553,34 @@ void WingAngelAPI::installHexReaderAPI(asIScriptEngine *engine) {
engine, std::bind(&WingHex::WingPlugin::Reader::selectedLength, reader),
QSIZETYPE_WRAP("selectedLength()"));
registerAPI<CScriptArray *(void)>(
engine, std::bind(&WingAngelAPI::_HexReader_selectedBytes, this),
"array<byte>@ selectedBytes()");
registerAPI<CScriptArray *(qsizetype)>(
engine,
std::bind(&WingAngelAPI::_HexReader_selectedBytes, this,
std::placeholders::_1),
"array<byte>@ selectedBytes(" QSIZETYPE " index)");
registerAPI<CScriptArray *()>(
engine, std::bind(&WingAngelAPI::_HexReader_selectionBytes, this),
"array<array<byte>>@ selectionBytes()");
registerAPI<WingHex::HexPosition(qsizetype)>(
engine,
std::bind(&WingHex::WingPlugin::Reader::selectionStart, reader,
std::placeholders::_1),
"HexPosition selectionStart(" QSIZETYPE " index)");
registerAPI<WingHex::HexPosition(qsizetype)>(
engine,
std::bind(&WingHex::WingPlugin::Reader::selectionEnd, reader,
std::placeholders::_1),
"HexPosition selectionEnd(" QSIZETYPE " index)");
registerAPI<qsizetype(qsizetype)>(
engine,
std::bind(&WingHex::WingPlugin::Reader::selectionLength, reader,
std::placeholders::_1),
QSIZETYPE_WRAP("selectionLength(" QSIZETYPE " index)"));
registerAPI<qsizetype()>(
engine, std::bind(&WingHex::WingPlugin::Reader::selectionCount, reader),
QSIZETYPE_WRAP("selectionCount()"));
registerAPI<quintptr(void)>(
engine, std::bind(&WingHex::WingPlugin::Reader::addressBase, reader),
@ -706,12 +678,6 @@ void WingAngelAPI::installHexReaderAPI(asIScriptEngine *engine) {
std::placeholders::_1),
"bool lineHasMetadata(" QSIZETYPE " line)");
registerAPI<CScriptArray *(qsizetype)>(
engine,
std::bind(&WingAngelAPI::_HexReader_getMetadatas, this,
std::placeholders::_1),
"array<HexMetadataItem>@ getMetadatas(" QSIZETYPE " offset)");
registerAPI<bool(qsizetype)>(
engine,
std::bind(&WingHex::WingPlugin::Reader::lineHasBookMark, reader,
@ -724,22 +690,12 @@ void WingAngelAPI::installHexReaderAPI(asIScriptEngine *engine) {
std::placeholders::_1),
"array<" QSIZETYPE ">@ getsBookmarkPos(" QSIZETYPE " pos)");
registerAPI<WingHex::BookMark(qsizetype)>(
engine,
std::bind(&WingHex::WingPlugin::Reader::bookMark, reader,
std::placeholders::_1),
"BookMark bookMark(" QSIZETYPE " pos)");
registerAPI<QString(qsizetype)>(
engine,
std::bind(&WingHex::WingPlugin::Reader::bookMarkComment, reader,
std::placeholders::_1),
"string bookMarkComment(" QSIZETYPE " pos)");
registerAPI<CScriptArray *()>(
engine, std::bind(&WingAngelAPI::_HexReader_getBookMarks, this),
"array<BookMark>@ getBookMarks()");
registerAPI<bool(qsizetype)>(
engine,
std::bind(&WingHex::WingPlugin::Reader::existBookMark, reader,
@ -1002,27 +958,29 @@ void WingAngelAPI::installHexControllerAPI(asIScriptEngine *engine) {
engine, std::bind(&WingHex::WingPlugin::Controller::removeAll, ctl),
"bool removeAll()");
registerAPI<bool(qsizetype, qsizetype, int)>(
registerAPI<bool(qsizetype, qsizetype, int, bool)>(
engine,
std::bind(QOverload<qsizetype, qsizetype, int>::of(
std::bind(QOverload<qsizetype, qsizetype, int, bool>::of(
&WingHex::WingPlugin::Controller::moveTo),
ctl, std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3),
std::placeholders::_3, std::placeholders::_4),
"bool moveTo(" QSIZETYPE " line, " QSIZETYPE
" column, int nibbleindex = -1)");
" column, int nibbleindex = -1, bool clearSelection = true)");
registerAPI<bool(qsizetype)>(
registerAPI<bool(qsizetype, bool)>(
engine,
std::bind(
QOverload<qsizetype>::of(&WingHex::WingPlugin::Controller::moveTo),
ctl, std::placeholders::_1),
"bool moveTo(" QSIZETYPE " offset)");
std::bind(QOverload<qsizetype, bool>::of(
&WingHex::WingPlugin::Controller::moveTo),
ctl, std::placeholders::_1, std::placeholders::_2),
"bool moveTo(" QSIZETYPE " offset, bool clearSelection = true)");
registerAPI<bool(qsizetype, qsizetype)>(
registerAPI<bool(qsizetype, qsizetype, WingHex::SelectionMode)>(
engine,
std::bind(&WingHex::WingPlugin::Controller::select, ctl,
std::placeholders::_1, std::placeholders::_2),
"bool select(" QSIZETYPE " offset, " QSIZETYPE " len)");
std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3),
"bool select(" QSIZETYPE " offset, " QSIZETYPE
" len, SelectionMode mode = SelectionMode::Add)");
registerAPI<bool(bool)>(
engine,
@ -1033,14 +991,14 @@ void WingAngelAPI::installHexControllerAPI(asIScriptEngine *engine) {
registerAPI<bool(qsizetype, qsizetype, const QColor &, const QColor &,
const QString &)>(
engine,
std::bind(QOverload<qsizetype, qsizetype, const QColor &,
std::bind(QOverload<qsizetype, WingHex::qusizetype, const QColor &,
const QColor &, const QString &>::
of(&WingHex::WingPlugin::Controller::metadata),
ctl, std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3, std::placeholders::_4,
std::placeholders::_5),
"bool metadata(" QSIZETYPE " begin, " QSIZETYPE
" end, color &in fgcolor, color &in bgcolor, string &in comment)");
"bool metadata(" QSIZETYPE " begin, " QUSIZETYPE
" length, color &in fgcolor, color &in bgcolor, string &in comment)");
registerAPI<bool(qsizetype)>(
engine,
@ -1052,29 +1010,29 @@ void WingAngelAPI::installHexControllerAPI(asIScriptEngine *engine) {
engine, std::bind(&WingHex::WingPlugin::Controller::clearMetadata, ctl),
"bool clearMetadata()");
registerAPI<bool(qsizetype, qsizetype, const QColor &)>(
registerAPI<bool(qsizetype, WingHex::qusizetype, const QColor &)>(
engine,
std::bind(&WingHex::WingPlugin::Controller::foreground, ctl,
std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3),
"bool foreground(" QSIZETYPE " begin, " QSIZETYPE
" end, color &in fgcolor)");
"bool foreground(" QSIZETYPE " begin, " QUSIZETYPE
" length, color &in fgcolor)");
registerAPI<bool(qsizetype, qsizetype, const QColor &)>(
registerAPI<bool(qsizetype, WingHex::qusizetype, const QColor &)>(
engine,
std::bind(&WingHex::WingPlugin::Controller::background, ctl,
std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3),
"bool background(" QSIZETYPE " begin, " QSIZETYPE
" end, color &in bgcolor)");
"bool background(" QSIZETYPE " begin, " QUSIZETYPE
" length, color &in bgcolor)");
registerAPI<bool(qsizetype, qsizetype, const QString &)>(
registerAPI<bool(qsizetype, WingHex::qusizetype, const QString &)>(
engine,
std::bind(&WingHex::WingPlugin::Controller::comment, ctl,
std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3),
"bool comment(" QSIZETYPE " begin, " QSIZETYPE
" end, string &in comment)");
"bool comment(" QSIZETYPE " begin, " QUSIZETYPE
" length, string &in comment)");
registerAPI<bool(bool)>(
engine,
@ -1410,7 +1368,10 @@ bool WingAngelAPI::read2Ref(qsizetype offset, void *ref, int typeId) {
auto id = obj->GetPropertyTypeId(n);
auto data = obj->GetAddressOfProperty(n);
auto size = getAsTypeSize(id, data);
read2Ref(offset, data, id);
auto ret = read2Ref(offset, data, id);
if (!ret) {
return false;
}
if (size > 0) {
offset += size;
}
@ -1426,7 +1387,7 @@ bool WingAngelAPI::read2Ref(qsizetype offset, void *ref, int typeId) {
if (engine) {
asITypeInfo *type = engine->GetTypeInfoByName("string");
if (value) {
// TODO support other type, now only string
// only string supported
if (type->GetTypeId() == (typeId & ~asTYPEID_OBJHANDLE)) {
*reinterpret_cast<QString *>(value) =
emit reader.readString(offset);
@ -1440,6 +1401,220 @@ bool WingAngelAPI::read2Ref(qsizetype offset, void *ref, int typeId) {
}
}
bool WingAngelAPI::write2Ref(qsizetype offset, void *ref, int typeId) {
asIScriptContext *ctx = asGetActiveContext();
if (ctx) {
asIScriptEngine *engine = ctx->GetEngine();
if (typeId == asTYPEID_VOID)
return false;
else if (typeId == asTYPEID_BOOL)
emit controller.writeInt8(offset,
*reinterpret_cast<bool *>(ref) ? 1 : 0);
else if (typeId == asTYPEID_INT8 || typeId == asTYPEID_UINT8)
emit controller.writeInt8(offset, *reinterpret_cast<qint8 *>(ref));
else if (typeId == asTYPEID_INT16 || typeId == asTYPEID_UINT16)
emit controller.writeInt16(offset,
*reinterpret_cast<qint16 *>(ref));
else if (typeId == asTYPEID_INT32 || typeId == asTYPEID_UINT32)
emit controller.writeInt32(offset,
*reinterpret_cast<qint32 *>(ref));
else if (typeId == asTYPEID_INT64 || typeId == asTYPEID_UINT64)
emit controller.writeInt64(offset,
*reinterpret_cast<qint64 *>(ref));
else if (typeId == asTYPEID_FLOAT)
emit controller.writeFloat(offset, *reinterpret_cast<float *>(ref));
else if (typeId == asTYPEID_DOUBLE)
emit controller.writeDouble(offset,
*reinterpret_cast<double *>(ref));
else if ((typeId & asTYPEID_MASK_OBJECT) == 0)
emit controller.writeInt32(offset, *reinterpret_cast<int *>(ref));
else if (typeId & asTYPEID_SCRIPTOBJECT) {
// Dereference handles, so we can see what it points to
void *value = ref;
if (typeId & asTYPEID_OBJHANDLE)
value = *(void **)value;
asIScriptObject *obj = (asIScriptObject *)value;
if (obj) {
for (asUINT n = 0; n < obj->GetPropertyCount(); n++) {
auto id = obj->GetPropertyTypeId(n);
auto data = obj->GetAddressOfProperty(n);
auto size = getAsTypeSize(id, data);
auto ret = write2Ref(offset, data, id);
if (!ret) {
return false;
}
if (size > 0) {
offset += size;
}
}
}
} else {
// Dereference handles, so we can see what it points to
void *value = ref;
if (typeId & asTYPEID_OBJHANDLE)
value = *(void **)value;
if (engine) {
asITypeInfo *type = engine->GetTypeInfoById(typeId);
if (value) {
// only string supported
if (type->GetTypeId() == (typeId & ~asTYPEID_OBJHANDLE)) {
emit controller.writeString(
offset, *reinterpret_cast<QString *>(value));
}
}
}
}
return true;
} else {
return false;
}
}
bool WingAngelAPI::insert2Ref(qsizetype offset, void *ref, int typeId) {
asIScriptContext *ctx = asGetActiveContext();
if (ctx) {
asIScriptEngine *engine = ctx->GetEngine();
if (typeId == asTYPEID_VOID)
return false;
else if (typeId == asTYPEID_BOOL)
emit controller.insertInt8(offset,
*reinterpret_cast<bool *>(ref) ? 1 : 0);
else if (typeId == asTYPEID_INT8 || typeId == asTYPEID_UINT8)
emit controller.insertInt8(offset, *reinterpret_cast<qint8 *>(ref));
else if (typeId == asTYPEID_INT16 || typeId == asTYPEID_UINT16)
emit controller.insertInt16(offset,
*reinterpret_cast<qint16 *>(ref));
else if (typeId == asTYPEID_INT32 || typeId == asTYPEID_UINT32)
emit controller.insertInt32(offset,
*reinterpret_cast<qint32 *>(ref));
else if (typeId == asTYPEID_INT64 || typeId == asTYPEID_UINT64)
emit controller.insertInt64(offset,
*reinterpret_cast<qint64 *>(ref));
else if (typeId == asTYPEID_FLOAT)
emit controller.insertFloat(offset,
*reinterpret_cast<float *>(ref));
else if (typeId == asTYPEID_DOUBLE)
emit controller.insertDouble(offset,
*reinterpret_cast<double *>(ref));
else if ((typeId & asTYPEID_MASK_OBJECT) == 0)
emit controller.insertInt32(offset, *reinterpret_cast<int *>(ref));
else if (typeId & asTYPEID_SCRIPTOBJECT) {
// Dereference handles, so we can see what it points to
void *value = ref;
if (typeId & asTYPEID_OBJHANDLE)
value = *(void **)value;
asIScriptObject *obj = (asIScriptObject *)value;
if (obj) {
for (asUINT n = 0; n < obj->GetPropertyCount(); n++) {
auto id = obj->GetPropertyTypeId(n);
auto data = obj->GetAddressOfProperty(n);
auto size = getAsTypeSize(id, data);
auto ret = insert2Ref(offset, data, id);
if (!ret) {
return false;
}
if (size > 0) {
offset += size;
}
}
}
} else {
// Dereference handles, so we can see what it points to
void *value = ref;
if (typeId & asTYPEID_OBJHANDLE)
value = *(void **)value;
if (engine) {
asITypeInfo *type = engine->GetTypeInfoById(typeId);
if (value) {
// TODO support other type, now only string
if (type->GetTypeId() == (typeId & ~asTYPEID_OBJHANDLE)) {
emit controller.insertString(
offset, *reinterpret_cast<QString *>(value));
}
}
}
}
return true;
} else {
return false;
}
}
bool WingAngelAPI::append2Ref(void *ref, int typeId) {
asIScriptContext *ctx = asGetActiveContext();
if (ctx) {
asIScriptEngine *engine = ctx->GetEngine();
if (typeId == asTYPEID_VOID)
return false;
else if (typeId == asTYPEID_BOOL)
emit controller.appendInt8(*reinterpret_cast<bool *>(ref) ? 1 : 0);
else if (typeId == asTYPEID_INT8 || typeId == asTYPEID_UINT8)
emit controller.appendInt8(*reinterpret_cast<qint8 *>(ref));
else if (typeId == asTYPEID_INT16 || typeId == asTYPEID_UINT16)
emit controller.appendInt16(*reinterpret_cast<qint16 *>(ref));
else if (typeId == asTYPEID_INT32 || typeId == asTYPEID_UINT32)
emit controller.appendInt32(*reinterpret_cast<qint32 *>(ref));
else if (typeId == asTYPEID_INT64 || typeId == asTYPEID_UINT64)
emit controller.appendInt64(*reinterpret_cast<qint64 *>(ref));
else if (typeId == asTYPEID_FLOAT)
emit controller.appendFloat(*reinterpret_cast<float *>(ref));
else if (typeId == asTYPEID_DOUBLE)
emit controller.appendDouble(*reinterpret_cast<double *>(ref));
else if ((typeId & asTYPEID_MASK_OBJECT) == 0)
emit controller.appendInt32(*reinterpret_cast<int *>(ref));
else if (typeId & asTYPEID_SCRIPTOBJECT) {
// Dereference handles, so we can see what it points to
void *value = ref;
if (typeId & asTYPEID_OBJHANDLE)
value = *(void **)value;
asIScriptObject *obj = (asIScriptObject *)value;
if (obj) {
for (asUINT n = 0; n < obj->GetPropertyCount(); n++) {
auto id = obj->GetPropertyTypeId(n);
auto data = obj->GetAddressOfProperty(n);
auto ret = append2Ref(data, id);
if (!ret) {
return false;
}
}
}
} else {
// Dereference handles, so we can see what it points to
void *value = ref;
if (typeId & asTYPEID_OBJHANDLE)
value = *(void **)value;
if (engine) {
asITypeInfo *type = engine->GetTypeInfoById(typeId);
if (value) {
// only string supported
if (type->GetTypeId() == (typeId & ~asTYPEID_OBJHANDLE)) {
emit controller.appendString(
*reinterpret_cast<QString *>(value));
}
}
}
}
return true;
} else {
return false;
}
}
qsizetype WingAngelAPI::getAsTypeSize(int typeId, void *data) {
if (typeId == asTYPEID_VOID)
return false;
@ -1899,9 +2074,41 @@ CScriptArray *WingAngelAPI::_FileDialog_getOpenFileNames(
"array<string>");
}
CScriptArray *WingAngelAPI::_HexReader_selectedBytes() {
return byteArrayWrapperFunction(
[this]() -> QByteArray { return emit reader.selectedBytes(); });
CScriptArray *WingAngelAPI::_HexReader_selectedBytes(qsizetype index) {
return byteArrayWrapperFunction([this, index]() -> QByteArray {
return emit reader.selectedBytes(index);
});
}
CScriptArray *WingAngelAPI::_HexReader_selectionBytes() {
// context, which can be used to obtain a pointer to the
// engine.
asIScriptContext *ctx = asGetActiveContext();
if (ctx) {
asIScriptEngine *engine = ctx->GetEngine();
auto ret = emit reader.selectionBytes();
// The script array needs to know its type to properly handle the
// elements. Note that the object type should be cached to avoid
// performance issues if the function is called frequently.
asITypeInfo *arrt = engine->GetTypeInfoByDecl("array<array<byte>>");
asITypeInfo *t = engine->GetTypeInfoByDecl("array<byte>");
Q_ASSERT(arrt && t);
auto array = CScriptArray::Create(arrt, ret.size());
for (qsizetype i = 0; i < ret.size(); ++i) {
auto buffer = ret.at(i);
auto conarr = CScriptArray::Create(t, ret.size());
for (qsizetype i = 0; i < ret.size(); ++i) {
auto v = ret.at(buffer.at(i));
conarr->SetValue(i, &v);
}
array->SetValue(i, conarr);
}
return array;
} else {
return nullptr;
}
}
CScriptArray *WingAngelAPI::_HexReader_readBytes(qsizetype offset,
@ -1916,206 +2123,15 @@ bool WingAngelAPI::_HexReader_read(qsizetype offset, void *ref, int typeId) {
}
bool WingAngelAPI::_HexReader_write(qsizetype offset, void *ref, int typeId) {
asIScriptContext *ctx = asGetActiveContext();
if (ctx) {
asIScriptEngine *engine = ctx->GetEngine();
if (typeId == asTYPEID_VOID)
return false;
else if (typeId == asTYPEID_BOOL)
emit controller.writeInt8(offset,
*reinterpret_cast<bool *>(ref) ? 1 : 0);
else if (typeId == asTYPEID_INT8 || typeId == asTYPEID_UINT8)
emit controller.writeInt8(offset, *reinterpret_cast<qint8 *>(ref));
else if (typeId == asTYPEID_INT16 || typeId == asTYPEID_UINT16)
emit controller.writeInt16(offset,
*reinterpret_cast<qint16 *>(ref));
else if (typeId == asTYPEID_INT32 || typeId == asTYPEID_UINT32)
emit controller.writeInt32(offset,
*reinterpret_cast<qint32 *>(ref));
else if (typeId == asTYPEID_INT64 || typeId == asTYPEID_UINT64)
emit controller.writeInt64(offset,
*reinterpret_cast<qint64 *>(ref));
else if (typeId == asTYPEID_FLOAT)
emit controller.writeFloat(offset, *reinterpret_cast<float *>(ref));
else if (typeId == asTYPEID_DOUBLE)
emit controller.writeDouble(offset,
*reinterpret_cast<double *>(ref));
else if ((typeId & asTYPEID_MASK_OBJECT) == 0)
emit controller.writeInt32(offset, *reinterpret_cast<int *>(ref));
else if (typeId & asTYPEID_SCRIPTOBJECT) {
// Dereference handles, so we can see what it points to
void *value = ref;
if (typeId & asTYPEID_OBJHANDLE)
value = *(void **)value;
if (engine) {
asITypeInfo *t = engine->GetTypeInfoById(typeId);
for (int n = t->GetEnumValueCount(); n-- > 0;) {
int enumVal;
t->GetEnumValueByIndex(n, &enumVal);
if (enumVal == *(int *)value) {
emit controller.writeInt32(offset, enumVal);
break;
}
}
}
} else {
// Dereference handles, so we can see what it points to
void *value = ref;
if (typeId & asTYPEID_OBJHANDLE)
value = *(void **)value;
if (engine) {
asITypeInfo *type = engine->GetTypeInfoById(typeId);
if (value) {
// TODO support other type, now only string
if (type->GetTypeId() == (typeId & ~asTYPEID_OBJHANDLE)) {
emit controller.writeString(
offset, *reinterpret_cast<QString *>(value));
}
}
}
}
return true;
} else {
return false;
}
return write2Ref(offset, ref, typeId);
}
bool WingAngelAPI::_HexReader_insert(qsizetype offset, void *ref, int typeId) {
asIScriptContext *ctx = asGetActiveContext();
if (ctx) {
asIScriptEngine *engine = ctx->GetEngine();
if (typeId == asTYPEID_VOID)
return false;
else if (typeId == asTYPEID_BOOL)
emit controller.insertInt8(offset,
*reinterpret_cast<bool *>(ref) ? 1 : 0);
else if (typeId == asTYPEID_INT8 || typeId == asTYPEID_UINT8)
emit controller.insertInt8(offset, *reinterpret_cast<qint8 *>(ref));
else if (typeId == asTYPEID_INT16 || typeId == asTYPEID_UINT16)
emit controller.insertInt16(offset,
*reinterpret_cast<qint16 *>(ref));
else if (typeId == asTYPEID_INT32 || typeId == asTYPEID_UINT32)
emit controller.insertInt32(offset,
*reinterpret_cast<qint32 *>(ref));
else if (typeId == asTYPEID_INT64 || typeId == asTYPEID_UINT64)
emit controller.insertInt64(offset,
*reinterpret_cast<qint64 *>(ref));
else if (typeId == asTYPEID_FLOAT)
emit controller.insertFloat(offset,
*reinterpret_cast<float *>(ref));
else if (typeId == asTYPEID_DOUBLE)
emit controller.insertDouble(offset,
*reinterpret_cast<double *>(ref));
else if ((typeId & asTYPEID_MASK_OBJECT) == 0)
emit controller.insertInt32(offset, *reinterpret_cast<int *>(ref));
else if (typeId & asTYPEID_SCRIPTOBJECT) {
// Dereference handles, so we can see what it points to
void *value = ref;
if (typeId & asTYPEID_OBJHANDLE)
value = *(void **)value;
if (engine) {
asITypeInfo *t = engine->GetTypeInfoById(typeId);
for (int n = t->GetEnumValueCount(); n-- > 0;) {
int enumVal;
t->GetEnumValueByIndex(n, &enumVal);
if (enumVal == *(int *)value) {
emit controller.insertInt32(offset, enumVal);
break;
}
}
}
} else {
// Dereference handles, so we can see what it points to
void *value = ref;
if (typeId & asTYPEID_OBJHANDLE)
value = *(void **)value;
if (engine) {
asITypeInfo *type = engine->GetTypeInfoById(typeId);
if (value) {
// TODO support other type, now only string
if (type->GetTypeId() == (typeId & ~asTYPEID_OBJHANDLE)) {
emit controller.insertString(
offset, *reinterpret_cast<QString *>(value));
}
}
}
}
return true;
} else {
return false;
}
return insert2Ref(offset, ref, typeId);
}
bool WingAngelAPI::_HexReader_append(void *ref, int typeId) {
asIScriptContext *ctx = asGetActiveContext();
if (ctx) {
asIScriptEngine *engine = ctx->GetEngine();
if (typeId == asTYPEID_VOID)
return false;
else if (typeId == asTYPEID_BOOL)
emit controller.appendInt8(*reinterpret_cast<bool *>(ref) ? 1 : 0);
else if (typeId == asTYPEID_INT8 || typeId == asTYPEID_UINT8)
emit controller.appendInt8(*reinterpret_cast<qint8 *>(ref));
else if (typeId == asTYPEID_INT16 || typeId == asTYPEID_UINT16)
emit controller.appendInt16(*reinterpret_cast<qint16 *>(ref));
else if (typeId == asTYPEID_INT32 || typeId == asTYPEID_UINT32)
emit controller.appendInt32(*reinterpret_cast<qint32 *>(ref));
else if (typeId == asTYPEID_INT64 || typeId == asTYPEID_UINT64)
emit controller.appendInt64(*reinterpret_cast<qint64 *>(ref));
else if (typeId == asTYPEID_FLOAT)
emit controller.appendFloat(*reinterpret_cast<float *>(ref));
else if (typeId == asTYPEID_DOUBLE)
emit controller.appendDouble(*reinterpret_cast<double *>(ref));
else if ((typeId & asTYPEID_MASK_OBJECT) == 0)
emit controller.appendInt32(*reinterpret_cast<int *>(ref));
else if (typeId & asTYPEID_SCRIPTOBJECT) {
// Dereference handles, so we can see what it points to
void *value = ref;
if (typeId & asTYPEID_OBJHANDLE)
value = *(void **)value;
if (engine) {
asITypeInfo *t = engine->GetTypeInfoById(typeId);
for (int n = t->GetEnumValueCount(); n-- > 0;) {
int enumVal;
t->GetEnumValueByIndex(n, &enumVal);
if (enumVal == *(int *)value) {
emit controller.appendInt32(enumVal);
break;
}
}
}
} else {
// Dereference handles, so we can see what it points to
void *value = ref;
if (typeId & asTYPEID_OBJHANDLE)
value = *(void **)value;
if (engine) {
asITypeInfo *type = engine->GetTypeInfoById(typeId);
if (value) {
// TODO support other type, now only string
if (type->GetTypeId() == (typeId & ~asTYPEID_OBJHANDLE)) {
emit controller.appendString(
*reinterpret_cast<QString *>(value));
}
}
}
}
return true;
} else {
return false;
}
return append2Ref(ref, typeId);
}
qsizetype WingAngelAPI::_HexReader_searchForward(qsizetype begin,
@ -2191,14 +2207,6 @@ CScriptArray *WingAngelAPI::_HexReader_findAllBytes(qsizetype begin,
}
}
CScriptArray *WingAngelAPI::_HexReader_getMetadatas(qsizetype offset) {
return retarrayWrapperFunction(
[this, offset]() -> QList<WingHex::HexMetadataItem> {
return emit reader.getMetadatas(offset);
},
"array<HexMetadataItem>");
}
CScriptArray *WingAngelAPI::_HexReader_getsBookmarkPos(qsizetype line) {
return retarrayWrapperFunction(
[this, line]() -> QList<qsizetype> {
@ -2207,14 +2215,6 @@ CScriptArray *WingAngelAPI::_HexReader_getsBookmarkPos(qsizetype line) {
"array<" QSIZETYPE ">");
}
CScriptArray *WingAngelAPI::_HexReader_getBookMarks() {
return retarrayWrapperFunction(
[this]() -> QList<WingHex::BookMark> {
return emit reader.getBookMarks();
},
"array<BookMark>");
}
CScriptArray *WingAngelAPI::_HexReader_getSupportedEncodings() {
return retarrayWrapperFunction(
[this]() -> QStringList { return emit reader.getSupportedEncodings(); },

View File

@ -39,9 +39,8 @@ public:
public:
virtual int sdkVersion() const override;
virtual const QString signature() const override;
virtual bool
init(const QList<WingHex::WingPluginInfo> &loadedplugin) override;
virtual void unload() override;
virtual bool init(const std::unique_ptr<QSettings> &set) override;
virtual void unload(std::unique_ptr<QSettings> &set) override;
virtual const QString pluginName() const override;
virtual const QString pluginAuthor() const override;
virtual uint pluginVersion() const override;
@ -89,6 +88,12 @@ private:
bool read2Ref(qsizetype offset, void *ref, int typeId);
bool write2Ref(qsizetype offset, void *ref, int typeId);
bool insert2Ref(qsizetype offset, void *ref, int typeId);
bool append2Ref(void *ref, int typeId);
qsizetype getAsTypeSize(int typeId, void *data);
template <typename T>
@ -132,7 +137,9 @@ private:
QString *selectedFilter,
QFileDialog::Options options);
CScriptArray *_HexReader_selectedBytes();
CScriptArray *_HexReader_selectedBytes(qsizetype index);
CScriptArray *_HexReader_selectionBytes();
CScriptArray *_HexReader_readBytes(qsizetype offset, qsizetype len);
@ -152,12 +159,8 @@ private:
CScriptArray *_HexReader_findAllBytes(qsizetype begin, qsizetype end,
const CScriptArray &ba);
CScriptArray *_HexReader_getMetadatas(qsizetype offset);
CScriptArray *_HexReader_getsBookmarkPos(qsizetype line);
CScriptArray *_HexReader_getBookMarks();
CScriptArray *_HexReader_getSupportedEncodings();
bool _HexController_writeBytes(qsizetype offset, const CScriptArray &ba);

15
src/components.md Normal file
View File

@ -0,0 +1,15 @@
* [QHexView](https://github.com/Dax89/QHexView/tree/master) (MIT, **FORK** -> AGPL-3.0)
* [QHexEdit2](https://github.com/Simsys/qhexedit2) (GPL, **FORK**)
* [Qt-Advanced-Docking-System](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System) (LGPL)
* [QCodeEditor2](https://sourceforge.net/projects/edyuk) (GPL, **FORK**)
* [QWingRibbon](https://github.com/martijnkoopman/Qt-Ribbon-Widget) (LGPL, **FORK**)
* [SingleApplication](https://github.com/itay-grudev/SingleApplication) (MIT)
* [QPathEdit](https://github.com/Skycoder42/QPathEdit) (MIT)
* [QWindowKit](https://github.com/stdware/qwindowkit) (Apache v2.0)
* [AngelScript](https://github.com/codecat/angelscript-mirror) (zlib license)
* [QConsoleWidget](https://github.com/gapost/qconsolewidget) (MIT, **FORK** -> AGPL-3.0)
* [QColorPicker](https://github.com/arsdever/qcolorpicker) (MIT)
* [QtJsonModel](https://github.com/dridk/QJsonmodel) (MIT)
* [nlohmann/json](https://github.com/nlohmann/json) (MIT)
* [Qt](https://www.qt.io/) (LGPL)

Some files were not shown because too many files have changed in this diff Show More