Add tree-structured config dialog (#489)

This commit is contained in:
Xaltonon 2018-05-13 00:52:49 -07:00 committed by xarkes
parent 58226dda0e
commit 21400952f2
12 changed files with 409 additions and 246 deletions

View File

@ -140,6 +140,7 @@ SOURCES += \
dialogs/preferences/PreferencesDialog.cpp \
dialogs/preferences/GeneralOptionsWidget.cpp \
dialogs/preferences/GraphOptionsWidget.cpp \
dialogs/preferences/PreferenceCategory.cpp \
widgets/QuickFilterView.cpp \
widgets/ClassesWidget.cpp \
widgets/ResourcesWidget.cpp \
@ -210,6 +211,7 @@ HEADERS += \
widgets/GraphView.h \
dialogs/preferences/PreferencesDialog.h \
dialogs/preferences/GeneralOptionsWidget.h \
dialogs/preferences/PreferenceCategory.h \
dialogs/preferences/GraphOptionsWidget.h \
widgets/QuickFilterView.h \
widgets/ClassesWidget.h \

View File

@ -23,9 +23,6 @@ AsmOptionsWidget::AsmOptionsWidget(PreferencesDialog */*dialog*/, QWidget *paren
updateAsmOptionsFromVars();
connect(Core(), SIGNAL(asmOptionsChanged()), this, SLOT(updateAsmOptionsFromVars()));
//connect(dialog, SIGNAL(saveAsDefault()), this, SLOT(saveAsDefault()));
//connect(dialog, SIGNAL(resetToDefault()), this, SLOT(resetToDefault()));
}
AsmOptionsWidget::~AsmOptionsWidget() {}

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>545</width>
<height>710</height>
<height>450</height>
</rect>
</property>
<property name="windowTitle">
@ -15,214 +15,242 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="esilCheckBox">
<property name="text">
<string>Show ESIL instead of assembly (asm.esil)</string>
<widget class="QTabWidget" name="asmOptionsTab">
<property name="currentIndex">
<number>0</number>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="pseudoCheckBox">
<property name="text">
<string>Show pseudocode instead of assembly (asm.pseudo)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="offsetCheckBox">
<property name="text">
<string>Show offsets (asm.offset)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="describeCheckBox">
<property name="text">
<string>Show opcode description (asm.describe)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="stackpointerCheckBox">
<property name="text">
<string>Show stack pointer (asm.stackptr)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="slowCheckBox">
<property name="text">
<string>Slow Analysis (asm.slow)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="linesCheckBox">
<property name="text">
<string>Show jump lines (asm.lines)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="fcnlinesCheckBox">
<property name="text">
<string>Show function boundary lines (asm.fcnlines)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="flgoffCheckBox">
<property name="text">
<string>Show offset before flags (asm.flgoff)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="emuCheckBox">
<property name="text">
<string>Run ESIL emulation analysis (asm.emu)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cmtrightCheckBox">
<property name="text">
<string>Show comments at right of assembly (asm.cmt.right)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="varsumCheckBox">
<property name="text">
<string>Show variables summary instead of full list (asm.varsum)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="sizeCheckBox">
<property name="text">
<string>Show size of opcodes in disassembly (asm.size)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="bytesCheckBox">
<property name="text">
<string>Show bytes (asm.bytes)</string>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>16</number>
</property>
<item>
<widget class="QCheckBox" name="bytespaceCheckBox">
<property name="text">
<string>Separate bytes with whitespace (asm.bytespace)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="lbytesCheckBox">
<property name="text">
<string>Align bytes to the left (asm.lbytes)</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_3">
<property name="leftMargin">
<number>16</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="nbytesLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Number of bytes to display (asm.nbytes):</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="nbytesSpinBox">
<property name="enabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QComboBox" name="syntaxComboBox"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="syntaxLabel">
<property name="text">
<string>Syntax (asm.syntax):</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="caseComboBox">
<widget class="QWidget" name="asmStyleTab">
<attribute name="title">
<string>Style</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<property name="text">
<string>Lowercase</string>
</property>
<widget class="QCheckBox" name="esilCheckBox">
<property name="text">
<string>Show ESIL instead of assembly (asm.esil)</string>
</property>
</widget>
</item>
<item>
<property name="text">
<string>Uppercase (asm.ucase)</string>
</property>
<widget class="QCheckBox" name="pseudoCheckBox">
<property name="text">
<string>Show pseudocode instead of assembly (asm.pseudo)</string>
</property>
</widget>
</item>
<item>
<property name="text">
<string>Capitalize (asm.capitalize)</string>
</property>
<widget class="QCheckBox" name="offsetCheckBox">
<property name="text">
<string>Show offsets (asm.offset)</string>
</property>
</widget>
</item>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="asmTabsLabel">
<property name="text">
<string>Tabs in assembly (asm.tabs):</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="asmTabsSpinBox">
<property name="maximum">
<number>100</number>
</property>
<property name="singleStep">
<number>5</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="bblineCheckBox">
<property name="text">
<string>Show empty line after every basic block (asm.bbline)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="varsubCheckBox">
<property name="text">
<string>Substitute variables (asm.varsub)</string>
</property>
<item>
<widget class="QCheckBox" name="describeCheckBox">
<property name="text">
<string>Show opcode description (asm.describe)</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QComboBox" name="syntaxComboBox"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="syntaxLabel">
<property name="text">
<string>Syntax (asm.syntax):</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="caseComboBox">
<item>
<property name="text">
<string>Lowercase</string>
</property>
</item>
<item>
<property name="text">
<string>Uppercase (asm.ucase)</string>
</property>
</item>
<item>
<property name="text">
<string>Capitalize (asm.capitalize)</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>16</number>
</property>
<item>
<widget class="QCheckBox" name="bytespaceCheckBox">
<property name="text">
<string>Separate bytes with whitespace (asm.bytespace)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="lbytesCheckBox">
<property name="text">
<string>Align bytes to the left (asm.lbytes)</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="asmTabsLabel">
<property name="text">
<string>Tabs in assembly (asm.tabs):</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="asmTabsSpinBox">
<property name="maximum">
<number>100</number>
</property>
<property name="singleStep">
<number>5</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="bblineCheckBox">
<property name="text">
<string>Show empty line after every basic block (asm.bbline)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cmtrightCheckBox">
<property name="text">
<string>Show comments at right of assembly (asm.cmt.right)</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Metadata</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QCheckBox" name="stackpointerCheckBox">
<property name="text">
<string>Show stack pointer (asm.stackptr)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="slowCheckBox">
<property name="text">
<string>Slow Analysis (asm.slow)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="linesCheckBox">
<property name="text">
<string>Show jump lines (asm.lines)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="fcnlinesCheckBox">
<property name="text">
<string>Show function boundary lines (asm.fcnlines)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="flgoffCheckBox">
<property name="text">
<string>Show offset before flags (asm.flgoff)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="emuCheckBox">
<property name="text">
<string>Run ESIL emulation analysis (asm.emu)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="sizeCheckBox">
<property name="text">
<string>Show size of opcodes in disassembly (asm.size)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="bytesCheckBox">
<property name="text">
<string>Show bytes (asm.bytes)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="varsumCheckBox">
<property name="text">
<string>Show variables summary instead of full list (asm.varsum)</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_3">
<property name="leftMargin">
<number>16</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="nbytesLabel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Number of bytes to display (asm.nbytes):</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="nbytesSpinBox">
<property name="enabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="varsubCheckBox">
<property name="text">
<string>Substitute variables (asm.varsub)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="varsubOnlyCheckBox">
<property name="text">
<string>Substitute entire variable expressions with names (asm.varsub_only)</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
@ -230,28 +258,8 @@
<property name="leftMargin">
<number>16</number>
</property>
<item>
<widget class="QCheckBox" name="varsubOnlyCheckBox">
<property name="text">
<string>Substitute entire variable expressions with names (asm.varsub_only)</string>
</property>
</widget>
</item>
</layout>
</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>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">

View File

@ -0,0 +1,57 @@
#include "PreferenceCategory.h"
PreferenceCategory::PreferenceCategory(const QString &name, const QIcon &icon)
: name(name), icon(icon), widget(nullptr), children{}
{
}
PreferenceCategory::PreferenceCategory(const QString &name, QWidget *widget, const QIcon &icon)
: name(name), icon(icon), widget(widget), children{}
{
}
PreferenceCategory::PreferenceCategory(const QString &name, QWidget *widget, const QIcon &icon,
const QList<PreferenceCategory> &children)
: name(name), icon(icon), widget(widget), children(children)
{
}
PreferenceCategory::PreferenceCategory(const QString &name, const QIcon &icon,
const QList<PreferenceCategory> &children)
: name(name), icon(icon), widget(nullptr), children(children)
{
}
void PreferenceCategory::addItem(QTreeWidget &tree, QStackedWidget &panel)
{
QTreeWidgetItem *w = new QTreeWidgetItem({name});
tree.addTopLevelItem(w);
for (auto &c : children)
c.addItem(*w, panel);
w->setExpanded(true);
w->setIcon(0, icon);
if (widget) {
panel.addWidget(widget);
w->setData(0, Qt::UserRole, panel.count());
}
}
void PreferenceCategory::addItem(QTreeWidgetItem &tree, QStackedWidget &panel)
{
QTreeWidgetItem *w = new QTreeWidgetItem({name});
tree.addChild(w);
for (auto &c : children)
c.addItem(*w, panel);
w->setExpanded(true);
w->setIcon(0, icon);
if (widget) {
panel.addWidget(widget);
w->setData(0, Qt::UserRole, panel.count());
}
}

View File

@ -0,0 +1,28 @@
#ifndef PREFERENCECATEGORY_H
#define PREFERENCECATEGORY_H
#include <QString>
#include <QTreeWidget>
#include <QStackedWidget>
class PreferenceCategory
{
public:
PreferenceCategory(const QString &name, const QIcon &icon);
PreferenceCategory(const QString &name, QWidget *widget, const QIcon &icon);
PreferenceCategory(const QString &name, QWidget *widget, const QIcon &icon,
const QList<PreferenceCategory> &children);
PreferenceCategory(const QString &name, const QIcon &icon,
const QList<PreferenceCategory> &children);
void addItem(QTreeWidget &tree, QStackedWidget &panel);
void addItem(QTreeWidgetItem &tree, QStackedWidget &panel);
private:
const QString name;
const QIcon icon;
QWidget *widget;
QList<PreferenceCategory> children;
};
#endif //PREFERENCECATEGORY_H

View File

@ -1,4 +1,3 @@
#include <QDialogButtonBox>
#include "PreferencesDialog.h"
@ -8,6 +7,8 @@
#include "AsmOptionsWidget.h"
#include "GraphOptionsWidget.h"
#include "PreferenceCategory.h"
#include "utils/Helpers.h"
#include "utils/Configuration.h"
@ -19,11 +20,39 @@ PreferencesDialog::PreferencesDialog(QWidget *parent)
setAttribute(Qt::WA_DeleteOnClose);
ui->setupUi(this);
#define ADD_TAB(c) { auto w = new c(this); ui->tabWidget->addTab(w, w->windowTitle()); }
ADD_TAB(GeneralOptionsWidget)
ADD_TAB(AsmOptionsWidget)
ADD_TAB(GraphOptionsWidget)
#undef ADD_TAB
QList<PreferenceCategory> prefs
{
{
"General",
new GeneralOptionsWidget(this),
QIcon(":/img/icons/preferences.png")
},
{
"Assembly",
new AsmOptionsWidget(this),
QIcon(":/img/icons/assembly.png"),
{
{
"Graph",
new GraphOptionsWidget(this),
QIcon(":/img/icons/graph.png")
},
}
},
};
for (auto &c : prefs)
c.addItem(*ui->configCategories, *ui->configPanel);
connect(ui->configCategories,
SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
this, SLOT(changePage(QTreeWidgetItem*, QTreeWidgetItem*)));
connect(ui->saveButtons,
SIGNAL(accepted()),
this, SLOT(close()));
QTreeWidgetItem *defitem = ui->configCategories->topLevelItem(0);
ui->configCategories->setCurrentItem(defitem, 0);
}
PreferencesDialog::~PreferencesDialog()
@ -34,10 +63,21 @@ void PreferencesDialog::showSection(PreferencesDialog::Section section)
{
switch (section) {
case Section::General:
ui->tabWidget->setCurrentIndex(0);
ui->configPanel->setCurrentIndex(0);
break;
case Section::Disassembly:
ui->tabWidget->setCurrentIndex(1);
ui->configPanel->setCurrentIndex(1);
break;
}
}
void PreferencesDialog::changePage(QTreeWidgetItem *current, QTreeWidgetItem *previous)
{
if (!current)
current = previous;
int index = current->data(0, Qt::UserRole).toInt();
if (index)
ui->configPanel->setCurrentIndex(index-1);
}

View File

@ -4,6 +4,7 @@
#include <QDialog>
#include <QPushButton>
#include <QTreeWidget>
#include <memory>
#include "Cutter.h"
@ -24,9 +25,8 @@ public:
void showSection(Section section);
/*signals:
void saveAsDefault();
void resetToDefault();*/
public slots:
void changePage(QTreeWidgetItem *current, QTreeWidgetItem *previous);
private:
std::unique_ptr<Ui::PreferencesDialog> ui;

View File

@ -2,20 +2,48 @@
<ui version="4.0">
<class>PreferencesDialog</class>
<widget class="QDialog" name="PreferencesDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>683</width>
<height>496</height>
</rect>
</property>
<property name="windowTitle">
<string>Preferences</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QTabWidget" name="tabWidget"/>
<widget class="QTreeWidget" name="configCategories">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Expanding"/>
</property>
<property name="maximumSize">
<size>
<width>175</width>
<height>16777215</height>
</size>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<column>
</column>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QStackedWidget" name="configPanel">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding"/>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="saveButtons">
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>

BIN
src/img/icons/assembly.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 B

BIN
src/img/icons/graph.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 736 B

View File

@ -56,6 +56,9 @@
<file>img/icons/spin_light.svg</file>
<file>img/icons/import_light.svg</file>
<file>img/icons/home.svg</file>
<file>img/icons/preferences.png</file>
<file>img/icons/graph.png</file>
<file>img/icons/assembly.png</file>
<file>fonts/Anonymous Pro.ttf</file>
<file>fonts/Inconsolata-Regular.ttf</file>
<file>img/cutter_plain.svg</file>