1
0
Fork 0

GUI: Implemented a custom QLineEdit (#704)

Fixes the ascii / unicode line edit behavior.
Allows overwrite mode by pressing the INSERT key.
This commit is contained in:
Atvaark 2016-06-03 10:43:22 +02:00 committed by Duncan Ogilvie
parent 8c0d2102e8
commit b6425a9c40
11 changed files with 346 additions and 67 deletions

View File

@ -11,28 +11,28 @@ HexEditDialog::HexEditDialog(QWidget* parent) : QDialog(parent), ui(new Ui::HexE
setModal(true); //modal window
//setup text fields
QFont font("Monospace", 8, QFont::Normal, false);
font.setFixedPitch(true);
font.setStyleHint(QFont::Monospace);
ui->lineEditAscii->setFont(font);
ui->lineEditUnicode->setFont(font);
ui->lineEditAscii->setEncoding(HexLineEdit::Encoding::Ascii);
ui->lineEditUnicode->setEncoding(HexLineEdit::Encoding::Unicode);
ui->chkEntireBlock->hide();
connect(Bridge::getBridge(), SIGNAL(repaintGui()), this, SLOT(updateStyle()));
updateStyle();
mDataInitialized = false;
//setup hex editor
mHexEdit = new QHexEdit(this);
mHexEdit->setEditFont(ConfigFont("HexEdit"));
mHexEdit->setHorizontalSpacing(6);
mHexEdit->setOverwriteMode(true);
mHexEdit->setTextColor(ConfigColor("HexEditTextColor"));
mHexEdit->setWildcardColor(ConfigColor("HexEditWildcardColor"));
mHexEdit->setBackgroundColor(ConfigColor("HexEditBackgroundColor"));
mHexEdit->setSelectionColor(ConfigColor("HexEditSelectionColor"));
connect(mHexEdit, SIGNAL(dataChanged()), this, SLOT(dataChangedSlot()));
ui->scrollArea->setWidget(mHexEdit);
mHexEdit->widget()->setFocus();
mHexEdit->setTabOrder(ui->btnUnicode2Hex, mHexEdit->widget());
connect(mHexEdit, SIGNAL(dataChanged()), this, SLOT(dataChangedSlot()));
connect(mHexEdit, SIGNAL(dataEdited()), this, SLOT(dataEditedSlot()));
connect(Config(), SIGNAL(colorsUpdated()), this, SLOT(updateStyle()));
connect(Bridge::getBridge(), SIGNAL(repaintGui()), this, SLOT(updateStyle()));
updateStyle();
}
HexEditDialog::~HexEditDialog()
@ -58,77 +58,76 @@ void HexEditDialog::updateStyle()
QString style = QString("QLineEdit { border-style: outset; border-width: 1px; border-color: %1; color: %1; background-color: %2 }").arg(ConfigColor("HexEditTextColor").name(), ConfigColor("HexEditBackgroundColor").name());
ui->lineEditAscii->setStyleSheet(style);
ui->lineEditUnicode->setStyleSheet(style);
mHexEdit->setTextColor(ConfigColor("HexEditTextColor"));
mHexEdit->setWildcardColor(ConfigColor("HexEditWildcardColor"));
mHexEdit->setBackgroundColor(ConfigColor("HexEditBackgroundColor"));
mHexEdit->setSelectionColor(ConfigColor("HexEditSelectionColor"));
}
void HexEditDialog::on_btnAscii2Hex_clicked()
{
QString text = ui->lineEditAscii->text();
QByteArray data;
for(int i = 0; i < text.length(); i++)
data.append(text[i].toLatin1());
if(ui->chkKeepSize->isChecked()) //keep size
{
int dataSize = mHexEdit->data().size();
if(dataSize < data.size())
data.resize(dataSize);
else if(dataSize > data.size())
data.append(QByteArray(dataSize - data.size(), 0));
}
QByteArray data = ui->lineEditAscii->data();
data = resizeData(data);
ui->lineEditUnicode->setData(data);
mHexEdit->setData(data);
}
void HexEditDialog::on_btnUnicode2Hex_clicked()
{
QByteArray data = QTextCodec::codecForName("UTF-16")->makeEncoder(QTextCodec::IgnoreHeader)->fromUnicode(ui->lineEditUnicode->text());
if(ui->chkKeepSize->isChecked()) //keep size
{
int dataSize = mHexEdit->data().size();
if(dataSize < data.size())
data.resize(dataSize);
else if(dataSize > data.size())
data.append(QByteArray(dataSize - data.size(), 0));
}
QByteArray data = ui->lineEditUnicode->data();
data = resizeData(data);
ui->lineEditAscii->setData(data);
mHexEdit->setData(data);
}
void HexEditDialog::on_chkKeepSize_toggled(bool checked)
{
mHexEdit->setKeepSize(checked);
ui->lineEditAscii->setKeepSize(checked);
ui->lineEditUnicode->setKeepSize(checked);
}
void HexEditDialog::dataChangedSlot()
{
QByteArray data = mHexEdit->data();
QString ascii;
for(int i = 0; i < data.size(); i++)
// Allows initialization of the data by calling setData() on mHexEdit.
if(!mDataInitialized)
{
QChar ch(data.constData()[i]);
if(ch.isPrint())
ascii += ch.toLatin1();
else
ascii += '.';
QByteArray data = mHexEdit->data();
ui->lineEditAscii->setData(data);
ui->lineEditUnicode->setData(data);
mDataInitialized = true;
}
QString unicode;
for(int i = 0, j = 0; i < data.size(); i += 2, j++)
{
QChar wch(((wchar_t*)data.constData())[j]);
if(wch.isPrint())
unicode += wch;
else
unicode += '.';
}
ui->lineEditAscii->setText(ascii);
ui->lineEditUnicode->setText(unicode);
}
void HexEditDialog::on_lineEditAscii_textEdited(const QString & arg1)
void HexEditDialog::dataEditedSlot()
{
QByteArray data = mHexEdit->data();
ui->lineEditAscii->setData(data);
ui->lineEditUnicode->setData(data);
}
void HexEditDialog::on_lineEditAscii_dataEdited()
{
Q_UNUSED(arg1);
on_btnAscii2Hex_clicked();
}
void HexEditDialog::on_lineEditUnicode_textEdited(const QString & arg1)
void HexEditDialog::on_lineEditUnicode_dataEdited()
{
Q_UNUSED(arg1);
on_btnUnicode2Hex_clicked();
}
QByteArray HexEditDialog::resizeData(QByteArray & data)
{
// truncate or pad the data
if(mHexEdit->keepSize())
{
int dataSize = mHexEdit->data().size();
if(dataSize < data.size())
data.resize(dataSize);
else if(dataSize > data.size())
data.append(QByteArray(dataSize - data.size(), 0));
}
return data;
}

View File

@ -28,11 +28,15 @@ private slots:
void on_btnUnicode2Hex_clicked();
void on_chkKeepSize_toggled(bool checked);
void dataChangedSlot();
void on_lineEditAscii_textEdited(const QString & arg1);
void on_lineEditUnicode_textEdited(const QString & arg1);
void dataEditedSlot();
void on_lineEditAscii_dataEdited();
void on_lineEditUnicode_dataEdited();
private:
Ui::HexEditDialog* ui;
bool mDataInitialized;
QByteArray resizeData(QByteArray & data);
};
#endif // HEXEDITDIALOG_H

View File

@ -46,7 +46,7 @@
</property>
</widget>
</widget>
<widget class="QLineEdit" name="lineEditUnicode">
<widget class="HexLineEdit" name="lineEditUnicode">
<property name="geometry">
<rect>
<x>10</x>
@ -68,7 +68,7 @@
<bool>false</bool>
</property>
</widget>
<widget class="QLineEdit" name="lineEditAscii">
<widget class="HexLineEdit" name="lineEditAscii">
<property name="geometry">
<rect>
<x>10</x>
@ -217,6 +217,13 @@
</property>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>HexLineEdit</class>
<extends>QLineEdit</extends>
<header>HexLineEdit.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>lineEditAscii</tabstop>
<tabstop>btnAscii2Hex</tabstop>

View File

@ -0,0 +1,180 @@
#include <QTextCodec>
#include "HexLineEdit.h"
#include "ui_HexLineEdit.h"
#include "Bridge.h"
HexLineEdit::HexLineEdit(QWidget* parent) :
QLineEdit(parent),
ui(new Ui::HexLineEdit)
{
ui->setupUi(this);
// setup data
mData = QByteArray();
mEncoding = Encoding::Ascii;
mKeepSize = false;
mOverwriteMode = false;
//setup text fields
QFont font("Monospace", 8, QFont::Normal, false);
font.setFixedPitch(true);
font.setStyleHint(QFont::Monospace);
setFont(font);
connect(this, SIGNAL(textEdited(const QString &)), this, SLOT(updateData(const QString &)));
}
HexLineEdit::~HexLineEdit()
{
delete ui;
}
void HexLineEdit::keyPressEvent(QKeyEvent* event)
{
// Switch between insert/overwrite mode
if(event->key() == Qt::Key_Insert && (event->modifiers() == Qt::NoModifier))
{
mOverwriteMode = !mOverwriteMode;
event->ignore();
return;
}
if(mOverwriteMode)
{
if(!event->text().isEmpty() && event->text().at(0).isPrint())
{
QString keyText;
switch(mEncoding)
{
case Encoding::Ascii:
keyText = event->text().toLatin1();
break;
case Encoding::Unicode:
keyText = event->text();
break;
}
del();
insert(keyText);
event->ignore();
return;
}
}
QLineEdit::keyPressEvent(event);
}
void HexLineEdit::setData(const QByteArray & data)
{
QString text;
switch(mEncoding)
{
case Encoding::Ascii:
for(int i = 0; i < data.size(); i++)
{
QChar ch(data.constData()[i]);
if(ch.isPrint())
text += ch.toLatin1();
else
text += '.';
}
break;
case Encoding::Unicode:
for(int i = 0, j = 0; i < data.size(); i += sizeof(wchar_t), j++)
{
QChar wch(((wchar_t*)data.constData())[j]);
if(wch.isPrint())
text += wch;
else
text += '.';
}
break;
}
mData = toEncodedData(text);
setText(text);
}
QByteArray HexLineEdit::data()
{
return mData;
}
void HexLineEdit::setEncoding(const HexLineEdit::Encoding encoding)
{
mEncoding = encoding;
}
HexLineEdit::Encoding HexLineEdit::encoding()
{
return mEncoding;
}
void HexLineEdit::setKeepSize(const bool enabled)
{
mKeepSize = enabled;
if(enabled)
{
int dataSize = mData.size();
int charSize;
switch(mEncoding)
{
case Encoding::Ascii:
charSize = sizeof(char);
break;
case Encoding::Unicode:
charSize = sizeof(wchar_t);
break;
}
setMaxLength((dataSize / charSize) + (dataSize % charSize));
}
else
{
setMaxLength(32767);
}
}
bool HexLineEdit::keepSize()
{
return mKeepSize;
}
void HexLineEdit::setOverwriteMode(bool overwriteMode)
{
mOverwriteMode = overwriteMode;
}
bool HexLineEdit::overwriteMode()
{
return mOverwriteMode;
}
void HexLineEdit::updateData(const QString & arg1)
{
Q_UNUSED(arg1);
mData = toEncodedData(text());
emit dataEdited();
}
QByteArray HexLineEdit::toEncodedData(const QString & text)
{
QByteArray data;
switch(mEncoding)
{
case Encoding::Ascii:
for(int i = 0; i < text.length(); i++)
data.append(text[i].toLatin1());
break;
case Encoding::Unicode:
data = QTextCodec::codecForName("UTF-16")->makeEncoder(QTextCodec::IgnoreHeader)->fromUnicode(text);
break;
}
return data;
}

View File

@ -0,0 +1,57 @@
#ifndef HEXLINEEDITT_H
#define HEXLINEEDITT_H
#include <QLineEdit>
#include "Configuration.h"
namespace Ui
{
class HexLineEdit;
}
class HexLineEdit : public QLineEdit
{
Q_OBJECT
public:
enum class Encoding
{
Ascii,
Unicode
};
explicit HexLineEdit(QWidget* parent = 0);
~HexLineEdit();
void keyPressEvent(QKeyEvent* event);
void setData(const QByteArray & data);
QByteArray data();
void setEncoding(const Encoding encoding);
Encoding encoding();
void setKeepSize(const bool enabled);
bool keepSize();
void setOverwriteMode(bool overwriteMode);
bool overwriteMode();
signals:
void dataEdited();
private slots:
void updateData(const QString & arg1);
private:
Ui::HexLineEdit* ui;
QByteArray mData;
Encoding mEncoding;
bool mKeepSize;
bool mOverwriteMode;
QByteArray toEncodedData(const QString & text);
};
#endif // HEXLINEEDITT_H

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>HexLineEdit</class>
<widget class="QLineEdit" name="HexLineEdit">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>361</width>
<height>20</height>
</rect>
</property>
<property name="widgetResizable" stdset="0">
<bool>true</bool>
</property>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -11,7 +11,9 @@ QHexEdit::QHexEdit(QWidget* parent) : QScrollArea(parent)
connect(qHexEdit_p, SIGNAL(currentAddressChanged(int)), this, SIGNAL(currentAddressChanged(int)));
connect(qHexEdit_p, SIGNAL(currentSizeChanged(int)), this, SIGNAL(currentSizeChanged(int)));
connect(qHexEdit_p, SIGNAL(dataChanged()), this, SIGNAL(dataChanged()));
connect(qHexEdit_p, SIGNAL(dataEdited()), this, SIGNAL(dataEdited()));
connect(qHexEdit_p, SIGNAL(overwriteModeChanged(bool)), this, SIGNAL(overwriteModeChanged(bool)));
setFocusPolicy(Qt::NoFocus);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
}

View File

@ -54,6 +54,7 @@ signals:
void currentAddressChanged(int address);
void currentSizeChanged(int size);
void dataChanged();
void dataEdited();
void overwriteModeChanged(bool state);
private:

View File

@ -70,14 +70,15 @@ void QHexEditPrivate::insert(int index, const QByteArray & ba, const QByteArray
{
_undoDataStack->push(new ArrayCommand(&_xData, ArrayCommand::replace, index, ba, ba.length()));
_undoMaskStack->push(new ArrayCommand(&_xMask, ArrayCommand::replace, index, mask, mask.length()));
emit dataChanged();
}
else
{
_undoDataStack->push(new ArrayCommand(&_xData, ArrayCommand::insert, index, ba, ba.length()));
_undoMaskStack->push(new ArrayCommand(&_xMask, ArrayCommand::insert, index, mask, mask.length()));
emit dataChanged();
}
emit dataChanged();
emit dataEdited();
}
}
@ -86,6 +87,7 @@ void QHexEditPrivate::insert(int index, char ch, char mask)
_undoDataStack->push(new CharCommand(&_xData, CharCommand::insert, index, ch));
_undoMaskStack->push(new CharCommand(&_xMask, CharCommand::insert, index, mask));
emit dataChanged();
emit dataEdited();
}
void QHexEditPrivate::remove(int index, int len)
@ -98,13 +100,11 @@ void QHexEditPrivate::remove(int index, int len)
{
_undoDataStack->push(new CharCommand(&_xData, CharCommand::replace, index, char(0)));
_undoMaskStack->push(new CharCommand(&_xMask, CharCommand::replace, index, char(0)));
emit dataChanged();
}
else
{
_undoDataStack->push(new CharCommand(&_xData, CharCommand::remove, index, char(0)));
_undoMaskStack->push(new CharCommand(&_xMask, CharCommand::remove, index, char(0)));
emit dataChanged();
}
}
else
@ -114,15 +114,16 @@ void QHexEditPrivate::remove(int index, int len)
{
_undoDataStack->push(new ArrayCommand(&_xData, ArrayCommand::replace, index, ba, ba.length()));
_undoMaskStack->push(new ArrayCommand(&_xMask, ArrayCommand::replace, index, ba, ba.length()));
emit dataChanged();
}
else
{
_undoDataStack->push(new ArrayCommand(&_xData, ArrayCommand::remove, index, ba, len));
_undoMaskStack->push(new ArrayCommand(&_xMask, ArrayCommand::remove, index, ba, len));
emit dataChanged();
}
}
emit dataChanged();
emit dataEdited();
}
}
@ -132,6 +133,7 @@ void QHexEditPrivate::replace(int index, char ch, char mask)
_undoMaskStack->push(new CharCommand(&_xMask, CharCommand::replace, index, mask));
resetSelection();
emit dataChanged();
emit dataEdited();
}
void QHexEditPrivate::replace(int index, const QByteArray & ba, const QByteArray & mask)
@ -140,6 +142,7 @@ void QHexEditPrivate::replace(int index, const QByteArray & ba, const QByteArray
_undoMaskStack->push(new ArrayCommand(&_xMask, ArrayCommand::replace, index, mask, mask.length()));
resetSelection();
emit dataChanged();
emit dataEdited();
}
void QHexEditPrivate::replace(int pos, int len, const QByteArray & after, const QByteArray & mask)
@ -148,6 +151,7 @@ void QHexEditPrivate::replace(int pos, int len, const QByteArray & after, const
_undoMaskStack->push(new ArrayCommand(&_xMask, ArrayCommand::replace, pos, mask, len));
resetSelection();
emit dataChanged();
emit dataEdited();
}
void QHexEditPrivate::fill(int index, const QByteArray & ba, const QByteArray & mask)
@ -259,6 +263,7 @@ void QHexEditPrivate::redo()
_undoDataStack->redo();
_undoMaskStack->redo();
emit dataChanged();
emit dataEdited();
setCursorPos(_cursorPosition);
update();
}
@ -270,6 +275,7 @@ void QHexEditPrivate::undo()
_undoDataStack->undo();
_undoMaskStack->undo();
emit dataChanged();
emit dataEdited();
setCursorPos(_cursorPosition);
update();
}

View File

@ -51,6 +51,7 @@ signals:
void currentAddressChanged(int address);
void currentSizeChanged(int size);
void dataChanged();
void dataEdited();
void overwriteModeChanged(bool state);
protected:

View File

@ -110,6 +110,7 @@ SOURCES += \
Src/Gui/AppearanceDialog.cpp \
Src/Gui/CloseDialog.cpp \
Src/Gui/HexEditDialog.cpp \
Src/Gui/HexLineEdit.cpp \
Src/QHexEdit/ArrayCommand.cpp \
Src/QHexEdit/QHexEdit.cpp \
Src/QHexEdit/QHexEditPrivate.cpp \
@ -198,6 +199,7 @@ HEADERS += \
Src/Gui/AppearanceDialog.h \
Src/Gui/CloseDialog.h \
Src/Gui/HexEditDialog.h \
Src/Gui/HexLineEdit.h \
Src/QHexEdit/ArrayCommand.h \
Src/QHexEdit/QHexEdit.h \
Src/QHexEdit/QHexEditPrivate.h \
@ -256,6 +258,7 @@ FORMS += \
Src/Gui/AppearanceDialog.ui \
Src/Gui/CloseDialog.ui \
Src/Gui/HexEditDialog.ui \
Src/Gui/HexLineEdit.ui \
Src/Gui/PatchDialog.ui \
Src/Gui/PatchDialogGroupSelector.ui \
Src/Gui/ShortcutsDialog.ui \