Compare commits
7 Commits
8e76d29707
...
c0be5c4b23
Author | SHA1 | Date |
---|---|---|
|
c0be5c4b23 | |
|
f0a3ede44f | |
|
735298d850 | |
|
e47b96b563 | |
|
893f3112c7 | |
|
1452874ac5 | |
|
862a6717ec |
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -1,6 +1,12 @@
|
|||
name: CMake build check
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
|
|
|
@ -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
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ public:
|
|||
QString getCommandLine();
|
||||
|
||||
public slots:
|
||||
virtual void paste() override;
|
||||
|
||||
// write to StandardOutput
|
||||
void writeStdOut(const QString &s);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit a006a7a48bb30a247f0344b788c62c2806edd90b
|
|
@ -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();
|
||||
|
|
|
@ -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 = {});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit f93657fa82bdd37dba68ea962d5e9b2cf4fd4d60
|
||||
Subproject commit ba8e8a32fc6e909ad0a2c152e36b6660c01fdad5
|
|
@ -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()
|
||||
|
|
After Width: | Height: | Size: 124 KiB |
22
README.md
|
@ -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
|
||||
|
||||
  本软件是基于 QT 编写的十六进制编辑器,采用 C++ 进行开发,提供强大而免费的十六进制编辑器。目前只有 010 Editor 具有强大的十六进制编辑功能,但它是商用的。关注我开发动态的应该知道我开发了在 Windows 上用 C# 开发的`WingSummer.WingCloudHexExplorer`,目的是方便专业人士修改分析 PE 文件,并可作为学习 PE 结构的重要辅助工具。还有我已经开发了只针对 Deepin 平台适配的`WingHexExplorer`,目前功能已基本完善了。除了在大文件搜索功能有问题,其他已经可以稳定使用了,我决定不再维护`WingHexExplorer`,我将移植重置这个项目。
|
||||
|
||||
  为什么要开发这个项目?`WingHexExplorer2`和原来的版本有什么不同?首先,窗体界面是我自己基于开源项目进行修改,重新实现了自己的界面,保证在跨平台的 UI 一致性。虽然功能和系统原生相比还是有点缺陷,也只是算美中不足了。
|
||||
|
||||
  该项目终极目标是实现一个功能强大、轻量级且跨平台(只针对 PC 平台)的十六进制编辑器。当然,实现这个目标仅仅靠我是不能够实现的,这也是我开源的目的之一。我只维护我使用的操作系统平台,只对我使用的平台出现的我能够修复的 Bug 在我有空闲的时间进行及时的响应。
|
||||
|
||||
  如果你发现该项目的功能并没有满足你的需求。请看看`TODO.txt`里面有没有说明。如果没有,可以通过`issue`进行提出。我会评估提出的需求是共性的。如果是特别私有的需求,我将不会实现。如果你实在想加入,请自行实现插件,也欢迎来开源。提建议的时候不要天马行空,注意本软件只提供最基本的十六进制编辑和浏览服务,比如 010 Editor 里面的模版和脚本等服务,还需大家一起通过插件来实现!希望大家不要只提需求,更要提出建设性建议和解决方案,共同维护开源社区。具体详情将会在后面进行介绍。
|
||||
  本软件是基于 QT 编写的十六进制编辑器,采用 C++ 进行开发,提供强大而免费的十六进制编辑器。该项目终极目标是实现一个功能强大、轻量级且跨平台(只针对 PC 平台)的十六进制编辑器。当然,实现这个目标仅仅靠我是不能够实现的,这也是我开源的目的之一。我只维护我使用的操作系统平台,只对我使用的平台出现的我能够修复的 Bug 在我有空闲的时间进行及时的响应。具体细节请看我的博客园的 [相关说明](https://www.cnblogs.com/wingsummer/p/18286419) 。
|
||||
|
||||
### 协议
|
||||
|
||||
  本软件遵循`AGPL-3.0`协议,请勿用于该协议之外的用途。我的初衷是让 Linux 的生态更加完整,早日让祖国推动操作系统国产化,软件跨平台只是顺带。我不希望“吸血鬼”们利益归自己,脏活累活给开源,都那么理所当然,开源就是这么被败坏的。我不希望因为版权的事情牵扯了大量的精力。
|
||||
  本软件遵循`AGPL-3.0`协议,请勿用于该协议之外的用途。我不希望因为版权的事情牵扯了大量的精力。
|
||||
|
||||
  如果你想将本软件的代码用于闭源的商业代码,想要解除`GPL`系列的必须开源的限制,请必须亲自咨询我,商讨商业授权相关事宜。
|
||||
|
||||
  对于插件开发相关的,对应的开源协议就不一样了。只针对本仓库下的`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>
|
||||
|
||||
## 有关仓库
|
||||
|
|
21
README_en.md
|
@ -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>
|
||||
|
|
13
TODO.txt
|
@ -1,13 +0,0 @@
|
|||
v2.0.0 版本规划(不知道啥时候会完成,很可能会鸽):
|
||||
|
||||
1. 增加 AngelScript 脚本编辑器的词法相关支持,比如更好的语法高亮以及增加智能提示等。
|
||||
2. 增加对内置的 AngelScript 脚本编辑器设置功能,增加语法片段管理器和支持。
|
||||
3. 对程序的操作细节优化,增加更多的提醒。
|
||||
4. 完善 AngelScript 脚本模块标准库。
|
||||
5. 为 AngelScript 增加宏的条件编译,拓展宏的功能。
|
||||
6. 使用文档和开发文档。
|
||||
|
||||
v3.0.0 版本规划:
|
||||
|
||||
1. 在有标注的情况下,增删字节之后标注会跟随动态调整。
|
||||
2. 尝试增加 AngelScript 对 QT 用户界面组件的绑定尝试,可以通过脚本实现插件。
|
|
@ -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)
|
|
@ -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" : ""
|
||||
}
|
|
@ -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.
|
|
@ -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")
|
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 5.6 KiB |
|
@ -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>
|
|
@ -0,0 +1,6 @@
|
|||
<RCC>
|
||||
<qresource prefix="/images/TestPlugin">
|
||||
<file>images/btn.png</file>
|
||||
<file>images/test.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
|
@ -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() {}
|
|
@ -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
|
|
@ -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>
|
|
@ -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 {};
|
||||
}
|
|
@ -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
|
After Width: | Height: | Size: 14 KiB |
|
@ -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
|
||||
|
|
|
@ -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> 。
|
|
@ -1,15 +0,0 @@
|
|||
|
||||
## 代码贡献者
|
||||
|
||||
  维护一个好用的工具并不是一个人能做到了,更重要的是大家共同维护,如下是对本仓库代码有贡献的同志,特此感谢:
|
||||
|
||||
* oPengLuo (大大的力量)
|
||||
|
||||
|
||||
## 赞助鸣谢
|
||||
|
||||
  感谢以下同志的赞助,我会尽量持续做成一个好用且功能强大的且跨平台的 PC 端的十六进制编辑器(时间先后顺序):
|
||||
|
||||
| 赞助者 | 备注 |
|
||||
| :----: | :--------------------: |
|
||||
| *欢 | 来自 Deepin 的一位道友 |
|
52
main.cpp
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
colorama==0.4.6
|
|
@ -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您要继续吗?
|
|
@ -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
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
colorama==0.4.6
|
|
@ -0,0 +1,15 @@
|
|||
## 文件说明
|
||||
|
||||
该目录的工具用于打包 Linux 通用安装包,方便没有编译环境的用户使用该软件,与此同时可以保证较好的通用性。
|
||||
|
||||
该工具包打包好的程序已经在 DeepinV23 、KDE Neon 测试过,未发现有啥问题。
|
||||
|
||||
如果你要尝试手动打包,首先需要配置好 CMake 的`CMAKE_PREFIX_INSTALL`到你要打包的目录,注意启用`install`,然后编译,完毕后会安装到打包目录中。
|
||||
|
||||
然后首先部署(deploy)一下,执行`deploy.py`这个脚本,要把你 **编译目录** 作为参数,注意是你编译的目录,而不是打包目录。该脚本会自行解析并定位到你的打包目录的。如果正常运行的话,你会得到如下输出:
|
||||
|
||||

|
||||
|
||||
这个警告尤其注意,它在你打包目录的`lib`目录下,你必须将警告中的文件加上可执行权限,否则部署之后的程序因该文件没有可执行权限导致无法执行。 **为啥不放到自动化脚本是因为修改权限需要 root,除非你用桌面的文件属性设置。**
|
||||
|
||||
完成部署之后,你就可以打包了,执行`build.sh`这个脚本,要把你 **打包的目录** 作为参数,执行完之后,它会在打包工具目录下创建`build`目录生成一个文件名格式与`WingHexExplorer2-vx.x.x-xxx-installer.run`类似的文件和一个`payload.tar.gz`文件,前者是安装包,后者是生成安装包中间产物,是对你打包目录进行压缩的一个压缩包。
|
|
@ -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[@]}"
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
After Width: | Height: | Size: 51 KiB |
|
@ -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__
|
|
@ -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
|
|
@ -0,0 +1,3 @@
|
|||
[Paths]
|
||||
Plugins= plugins
|
||||
Libraries= lib
|
|
@ -0,0 +1 @@
|
|||
colorama==0.4.6
|
|
@ -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;
|
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 20 KiB |
|
@ -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>
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
colorama==0.4.6
|
||||
psutil==6.1.0
|
|
@ -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">
|
||||
|
|
BIN
screenshot.png
Before Width: | Height: | Size: 550 KiB After Width: | Height: | Size: 4.3 MiB |
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
// ==================================================
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(); },
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|