WIP: Color scheme feature (#709)

* shiny commit
* removes extra displaying of custom schemes
This commit is contained in:
optizone8 2018-10-10 09:37:24 +00:00 committed by xarkes
parent b298ce8325
commit cd4b86fa69
13 changed files with 1097 additions and 22 deletions

View File

@ -195,7 +195,9 @@ SOURCES += \
dialogs/AttachProcDialog.cpp \
widgets/RegisterRefsWidget.cpp \
dialogs/SetToDataDialog.cpp \
dialogs/SetFunctionVarTypes.cpp
dialogs/SetFunctionVarTypes.cpp \
widgets/ColorSchemePrefWidget.cpp \
utils/ColorSchemeFileSaver.cpp
HEADERS += \
Cutter.h \
@ -291,7 +293,9 @@ HEADERS += \
widgets/RegisterRefsWidget.h \
dialogs/SetToDataDialog.h \
utils/InitialOptions.h \
dialogs/SetFunctionVarTypes.h
dialogs/SetFunctionVarTypes.h \
utils/ColorSchemeFileSaver.h \
widgets/ColorSchemePrefWidget.h
FORMS += \
dialogs/AboutDialog.ui \
@ -346,7 +350,8 @@ FORMS += \
dialogs/AttachProcDialog.ui \
widgets/RegisterRefsWidget.ui \
dialogs/SetToDataDialog.ui \
dialogs/SetFunctionVarTypes.ui
dialogs/SetFunctionVarTypes.ui \
widgets/ColorSchemePrefWidget.ui
RESOURCES += \
resources.qrc \

View File

@ -182,6 +182,9 @@ void MainWindow::initUI()
this->visualNavbar->setMovable(false);
addToolBarBreak(Qt::TopToolBarArea);
addToolBar(visualNavbar);
QObject::connect(configuration, &Configuration::colorsUpdated, [this]() {
this->visualNavbar->updateGraphicsScene();
});
/*
* Dock Widgets

View File

@ -1,14 +1,19 @@
#include <QDir>
#include <QLabel>
#include <QFontDialog>
#include <QInputDialog>
#include "GeneralOptionsWidget.h"
#include "ui_GeneralOptionsWidget.h"
#include <QComboBox>
#include "PreferencesDialog.h"
#include "GeneralOptionsWidget.h"
#include "ui_GeneralOptionsWidget.h"
#include "utils/Helpers.h"
#include "utils/Configuration.h"
#include "utils/ColorSchemeFileSaver.h"
#include "widgets/ColorSchemePrefWidget.h"
GeneralOptionsWidget::GeneralOptionsWidget(PreferencesDialog *dialog, QWidget *parent)
: QDialog(parent),
ui(new Ui::GeneralOptionsWidget)
@ -20,7 +25,11 @@ GeneralOptionsWidget::GeneralOptionsWidget(PreferencesDialog *dialog, QWidget *p
updateThemeFromConfig();
connect(Config(), &Configuration::fontsUpdated, this, &GeneralOptionsWidget::updateFontFromConfig);
//connect(Config(), SIGNAL(colorsUpdated()), this, SLOT(updateThemeFromConfig()));
connect(ui.get()->colorComboBox, &QComboBox::currentTextChanged, [&](const QString & name) {
static_cast<ColorSchemePrefWidget *>(ui.get()->colorSchemePrefWidget)->setNewScheme(name);
});
static_cast<ColorSchemePrefWidget *>
(ui.get()->colorSchemePrefWidget)->setNewScheme(Config()->getCurrentTheme());
}
GeneralOptionsWidget::~GeneralOptionsWidget() {}
@ -63,7 +72,8 @@ void GeneralOptionsWidget::on_fontSelectionButton_clicked()
{
QFont currentFont = Config()->getFont();
bool ok;
QFont newFont = QFontDialog::getFont(&ok, currentFont, this, QString(), QFontDialog::DontUseNativeDialog);
QFont newFont = QFontDialog::getFont(&ok, currentFont, this, QString(),
QFontDialog::DontUseNativeDialog);
if (ok) {
Config()->setFont(newFont);
}
@ -81,3 +91,26 @@ void GeneralOptionsWidget::on_colorComboBox_currentIndexChanged(int index)
QString theme = ui->colorComboBox->itemText(index);
Config()->setColorTheme(theme);
}
void GeneralOptionsWidget::on_copyButton_clicked()
{
QString newSchemeName;
do {
newSchemeName = QInputDialog::getText(this, tr("Enter scheme name"),
tr("Name:"), QLineEdit::Normal,
QDir::home().dirName());
} while (ColorSchemeFileWorker().isNameEngaged(newSchemeName) && !newSchemeName.isEmpty());
if (newSchemeName.isEmpty())
return;
ColorSchemeFileWorker().copy(Config()->getCurrentTheme(), newSchemeName);
Config()->setColorTheme(newSchemeName);
ui.get()->colorSchemePrefWidget->setNewScheme(newSchemeName);
updateThemeFromConfig();
ui.get()->colorComboBox->setCurrentIndex(ui.get()->colorComboBox->findText(newSchemeName));
}
void GeneralOptionsWidget::on_deleteButton_clicked()
{
ColorSchemeFileWorker().deleteScheme(Config()->getCurrentTheme());
}

View File

@ -32,6 +32,8 @@ private slots:
void on_fontSelectionButton_clicked();
void on_themeComboBox_currentIndexChanged(int index);
void on_colorComboBox_currentIndexChanged(int index);
void on_copyButton_clicked();
void on_deleteButton_clicked();
};

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>442</width>
<height>225</height>
<height>268</height>
</rect>
</property>
<property name="windowTitle">
@ -91,17 +91,57 @@
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="colorComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QComboBox" name="colorComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="copyButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Copy</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="deleteButton">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="ColorSchemePrefWidget" name="colorSchemePrefWidget" native="true"/>
</item>
</layout>
<action name="actionSaveAsDefault">
<property name="text">
@ -109,6 +149,14 @@
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>ColorSchemePrefWidget</class>
<extends>QWidget</extends>
<header>widgets/ColorSchemePrefWidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,174 @@
#include "utils/ColorSchemeFileSaver.h"
#include <QDir>
#include <QDebug>
#include <QColor>
#include <QJsonArray>
#include <QJsonObject>
#include <QStandardPaths>
#include "utils/Configuration.h"
static const QStringList cutterSpecificOptions = {
"gui.main",
"highlight",
"gui.imports",
"highlightPC",
"highlightWord",
"gui.navbar.err",
"gui.navbar.sym",
"gui.dataoffset",
"gui.navbar.code",
"gui.navbar.empty",
"angui.navbar.str",
"gui.disass_selected",
"gui.breakpoint_background"
};
ColorSchemeFileSaver::ColorSchemeFileSaver(QObject *parent) : QObject (parent)
{
QDir currDir;
QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
dirs.removeOne(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation));
currDir = QDir(dirs.at(0)).filePath("radare2");
// currDir.entryList(QDir::Dirs, QDir::Name) returns { current dir, upper dir, dirs ... }
// so it takes first (and only) dir using .at(2)
currDir = currDir.filePath(currDir.entryList(QDir::Dirs,
QDir::Name).at(2) + QDir::separator() + "cons");
standardR2ThemesLocationPath = currDir.absolutePath();
customR2ThemesLocationPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) +
QDir::separator() +
"radare2" + QDir::separator() +
"cons";
if (!QDir(customR2ThemesLocationPath).exists()) {
QDir().mkpath(customR2ThemesLocationPath);
}
}
QFile::FileError ColorSchemeFileSaver::copy(const QString &srcThemeName,
const QString &copyThemeName) const
{
QFile fIn(standardR2ThemesLocationPath + QDir::separator() + srcThemeName);
QFile fOut(customR2ThemesLocationPath + QDir::separator() + copyThemeName);
if (srcThemeName != "default" && !fIn.open(QFile::ReadOnly)) {
fIn.setFileName(customR2ThemesLocationPath + QDir::separator() + srcThemeName);
if (!fIn.open(QFile::ReadOnly)) {
return fIn.error();
}
}
if (!fOut.open(QFile::WriteOnly | QFile::Truncate)) {
fIn.close();
return fOut.error();
}
QStringList options = Core()->cmdj("ecj").object().keys();
options << cutterSpecificOptions;
QStringList src;
if (srcThemeName == "default") {
QString theme = Config()->getCurrentTheme();
Core()->cmd("ecd");
QJsonObject _obj = Core()->cmdj("ecj").object();
Core()->cmd(QString("eco %1").arg(theme));
QColor back = Config()->getColor(standardBackgroundOptionName);
_obj[standardBackgroundOptionName] = QJsonArray({back.red(), back.green(), back.blue()});
for (auto &it : _obj.keys()) {
QJsonArray rgb = _obj[it].toArray();
src.push_back("ec " + it + " " +
QColor(rgb[0].toInt(), rgb[1].toInt(), rgb[2].toInt()).name().replace("#", "rgb:"));
}
} else {
src = QString(fIn.readAll()).split('\n');
}
for (auto &it : src) {
if (it.isEmpty()) {
continue;
}
fOut.write(it.toUtf8() + '\n');
if (it.length() > 2 && it.left(2) == "#~") {
options.removeOne(it.split(' ')[0].remove("#~").toUtf8());
} else {
options.removeOne(it.split(' ').at(1));
}
}
for (auto &it : options) {
if (cutterSpecificOptions.contains(it)) {
fOut.write("#~");
} else {
fOut.write("ec ");
}
fOut.write(QString(it + " rgb:%1\n").
arg(Config()->getColor(it).name().remove("#")).toUtf8());
}
fOut.close();
fIn.close();
return QFile::FileError::NoError;
}
QFile::FileError ColorSchemeFileSaver::save(const QString &scheme, const QString &schemeName) const
{
QFile fOut(customR2ThemesLocationPath + QDir::separator() + schemeName);
if (!fOut.open(QFile::WriteOnly | QFile::Truncate))
return fOut.error();
fOut.write(scheme.toUtf8());
fOut.close();
return QFile::FileError::NoError;
}
bool ColorSchemeFileSaver::isCustomScheme(const QString &schemeName) const
{
for (auto &it : QDir(customR2ThemesLocationPath).entryInfoList())
if (it.fileName() == schemeName)
return true;
return false;
}
bool ColorSchemeFileSaver::isNameEngaged(const QString &name) const
{
return QFile::exists(standardR2ThemesLocationPath + QDir::separator() + name) ||
QFile::exists(customR2ThemesLocationPath + QDir::separator() + name);
}
QMap<QString, QColor> ColorSchemeFileSaver::getCutterSpecific() const
{
QFile f(customR2ThemesLocationPath + QDir::separator() + Config()->getCurrentTheme());
if (!f.open(QFile::ReadOnly))
return QMap<QString, QColor>();
QMap<QString, QColor> ret;
QStringList data = QString(f.readAll()).split('\n');
for (auto &it : data) {
if (it.length() > 2 && it.left(2) == "#~") {
QStringList currLine = it.split(' ');
ret.insert(currLine[0].remove("#~"), currLine[1].replace("rgb:", "#"));
}
}
f.close();
return ret;
}
QStringList ColorSchemeFileSaver::getCustomSchemes() const
{
QStringList sl;
sl = QDir(customR2ThemesLocationPath).entryList(QDir::Files, QDir::Name);
sl.removeOne(".");
sl.removeOne("..");
return sl;
}
void ColorSchemeFileSaver::deleteScheme(const QString &schemeName) const
{
if (!isCustomScheme(schemeName))
return;
QFile::remove(customR2ThemesLocationPath + QDir::separator() + schemeName);
}

View File

@ -0,0 +1,47 @@
#ifndef COLORSCHEMEFILESAVER_H
#define COLORSCHEMEFILESAVER_H
#include <QFile>
#include <QColor>
#include <QObject>
constexpr const char *standardBackgroundOptionName = "gui.background";
constexpr const char *standardTextOptionName = "btext";
#define ColorSchemeFileWorker() (ColorSchemeFileSaver::instance())
class ColorSchemeFileSaver : public QObject
{
Q_OBJECT
public:
static ColorSchemeFileSaver &instance()
{
static ColorSchemeFileSaver ex;
return ex;
}
virtual ~ColorSchemeFileSaver() {}
QFile::FileError copy(const QString &srcSchemeName, const QString &copySchemeName) const;
QFile::FileError save(const QString &scheme, const QString &schemeName) const;
bool isCustomScheme(const QString &schemeName) const;
bool isNameEngaged(const QString &name) const;
QMap<QString, QColor> getCutterSpecific() const;
QStringList getCustomSchemes() const;
void deleteScheme(const QString &schemeName) const;
private:
QString standardR2ThemesLocationPath;
QString customR2ThemesLocationPath;
ColorSchemeFileSaver(QObject *parent = nullptr);
ColorSchemeFileSaver(const ColorSchemeFileSaver &root) = delete;
ColorSchemeFileSaver &operator=(const ColorSchemeFileSaver &) = delete;
};
#endif // COLORSCHEMEFILESAVER_H

View File

@ -5,6 +5,8 @@
#include <QFile>
#include <QApplication>
#include "utils/ColorSchemeFileSaver.h"
Configuration *Configuration::mPtr = nullptr;
/*!
@ -216,7 +218,7 @@ void Configuration::setFont(const QFont &font)
void Configuration::setTheme(int theme)
{
s.setValue("ColorPalette", theme);
switch(theme){
switch (theme) {
case 0:
loadDefaultTheme();
break;
@ -268,11 +270,18 @@ void Configuration::setColorTheme(QString theme)
QJsonObject colorsObject = colors.object();
QJsonObject::iterator it;
for (it = colorsObject.begin(); it != colorsObject.end(); it++) {
if (it.key().contains("gui"))
continue;
QJsonArray rgb = it.value().toArray();
s.setValue("colors." + it.key(), QColor(rgb[0].toInt(), rgb[1].toInt(), rgb[2].toInt()));
}
QMap<QString, QColor> cutterSpecific = ColorSchemeFileWorker().getCutterSpecific();
for (auto &it : cutterSpecific.keys())
setColor(it, cutterSpecific[it]);
if (!ColorSchemeFileWorker().isCustomScheme(theme)) {
setTheme(getTheme());
}
emit colorsUpdated();
}
@ -294,7 +303,7 @@ QVariant Configuration::getConfigVar(const QString &key)
{
QHash<QString, QVariant>::const_iterator it = asmOptions.find(key);
if (it != asmOptions.end()) {
switch(it.value().type()) {
switch (it.value().type()) {
case QVariant::Type::Bool:
return Core()->getConfigb(key);
case QVariant::Type::Int:

View File

@ -49,7 +49,7 @@ public:
}
QString getDirProjects();
void setDirProjects(const QString& dir);
void setDirProjects(const QString &dir);
void setNewFileLastClicked(int lastClicked);
int getNewFileLastClicked();

View File

@ -0,0 +1,529 @@
#include "utils/Configuration.h"
#include "utils/Configuration.h"
#include "ColorSchemePrefWidget.h"
#include "ui_ColorSchemePrefWidget.h"
#include "utils/ColorSchemeFileSaver.h"
#include <QMap>
#include <QFile>
#include <QDebug>
#include <QPainter>
#include <QJsonArray>
#include <QMouseEvent>
#include <QApplication>
#include <QColorDialog>
#include <QJsonDocument>
struct OptionIfo {
QString info;
QString displayingtext;
bool isUsedStandardTextColor;
};
static const QMap<QString, OptionIfo> optionInfoMap = {
{
"comment", {
QObject::tr("Color of comment generated by radare2"),
QObject::tr("Comment"), false
}
},
{
"usrcmt", {
QObject::tr("Comment created by user"),
QObject::tr("Color of user Comment"), false
}
},
{
"args", {
QObject::tr("Color of function arguments"),
QObject::tr("Arguments"), false
}
},
{
"fname", {
QObject::tr("Color of names of functions"),
QObject::tr("Function name"), false
}
},
{
"floc", {
QObject::tr("Color of function location"),
QObject::tr("Function location"), false
}
},
{
"fline", {
QObject::tr(""),
QObject::tr("fline"), false
}
},
{
"flag", {
QObject::tr("Color of flags (similar to bookmarks for offset)"),
QObject::tr("Flag"), false
}
},
{ "label", { QObject::tr(""), QObject::tr("Label"), false } },
{ "help", { QObject::tr(""), QObject::tr("Help"), false } },
{ "flow", { QObject::tr(""), QObject::tr("flow"), false } },
{ "flow2", { QObject::tr(""), QObject::tr("flow2"), false } },
{ "prompt", { QObject::tr("Info"), QObject::tr("prompt"), false } },
{
"offset", {
QObject::tr("Color of offsets"),
QObject::tr("Offset"), false
}
},
{ "input", { QObject::tr("Info"), QObject::tr("input"), false } },
{
"invalid", {
QObject::tr("Invalid opcode color"),
QObject::tr("invalid"), false
}
},
{ "other", { QObject::tr(""), QObject::tr("other"), false } },
{
"b0x00", {
QObject::tr("0x00 opcode color"),
QObject::tr("b0x00"), false
}
},
{
"b0x7f", {
QObject::tr("0x7f opcode color"),
QObject::tr("b0x7f"), false
}
},
{
"b0xff", {
QObject::tr("0xff opcode color"),
QObject::tr("b0xff"), false
}
},
{
"math", {
QObject::tr("arithmetic color (+, -, *, / etc.)"),
QObject::tr("math"), false
}
},
{ "bin", { QObject::tr(""), QObject::tr("bin"), false } },
{ "btext", { QObject::tr(""), QObject::tr("btext"), false } },
{ "push", { QObject::tr("push opcode color"), QObject::tr("push"), false } },
{ "pop", { QObject::tr("pop opcode color"), QObject::tr("pop"), false } },
{ "crypto", { QObject::tr("Cryptographic color"), QObject::tr("crypto"), false } },
{
"jmp", {
QObject::tr("jmp instructions color"),
QObject::tr("jmp"), false
}
},
{
"cjmp", {
QObject::tr(""),
QObject::tr("cjmp"), false
}
},
{
"call", {
QObject::tr("call instructions color (ccall, rcall, call etc)"),
QObject::tr("call"), false
}
},
{ "nop", { QObject::tr("nop opcode color"), QObject::tr("nop"), false } },
{
"ret", {
QObject::tr("ret opcode color"),
QObject::tr("ret"), false
}
},
{
"trap", {
QObject::tr("Color of interrputs"),
QObject::tr("Interrputs"), false
}
},
{ "swi", { QObject::tr("swi opcode color"), QObject::tr("swi"), false } },
{ "cmp", { QObject::tr("cmp opcode color"), QObject::tr("cmp"), false } },
{ "reg", { QObject::tr("Registers color"), QObject::tr("Register"), false } },
{ "creg", { QObject::tr("Info"), QObject::tr("creg"), false } },
{ "num", { QObject::tr("Numeric constants color"), QObject::tr("Numbers"), false } },
{
"mov", {
QObject::tr("mov instructions color (mov, movd, movw etc"),
QObject::tr("mov"), false
}
},
{
"func_var", {
QObject::tr("Function variable color"),
QObject::tr("Function variable"), false
}
},
{
"func_var_type", {
QObject::tr("Function variable (local or argument) type color"),
QObject::tr("Variable type"), false
}
},
{
"func_var_addr", {
QObject::tr("Function variable address color"),
QObject::tr("Variable address"), false
}
},
{ "widget_bg", { QObject::tr(""), QObject::tr("widget_bg"), false } },
{ "widget_sel", { QObject::tr(""), QObject::tr("widget_sel"), false } },
{ "ai.read", { QObject::tr(""), QObject::tr("ai.read"), false } },
{ "ai.write", { QObject::tr(""), QObject::tr("ai.write"), false } },
{ "ai.exec", { QObject::tr(""), QObject::tr("ai.exec"), false } },
{ "ai.seq", { QObject::tr(""), QObject::tr("ai.seq"), false } },
{ "ai.ascii", { QObject::tr(""), QObject::tr("ai.ascii"), false } },
{ "graph.box", { QObject::tr(""), QObject::tr("graph.box"), false } },
{ "graph.box2", { QObject::tr(""), QObject::tr("graph.box2"), false } },
{ "graph.box3", { QObject::tr(""), QObject::tr("graph.box3"), false } },
{ "graph.box4", { QObject::tr(""), QObject::tr("graph.box4"), false } },
{
"graph.true", {
QObject::tr("In graph view jump arrow true"),
QObject::tr("Arrow true"), false
}
},
{
"graph.false", {
QObject::tr("In graph view jump arrow false"),
QObject::tr("Arrow false"), false
}
},
{
"graph.trufae", {
QObject::tr("In graph view jump arrow (no condition)"),
QObject::tr("Arrow"), false
}
},
{ "graph.current", { QObject::tr(""), QObject::tr("graph.current"), false } },
{ "graph.traced", { QObject::tr(""), QObject::tr("graph.traced"), false } },
{ "gui.cflow", { QObject::tr(""), QObject::tr("gui.cflow"), true } },
{ "gui.dataoffset", { QObject::tr(""), QObject::tr("gui.dataoffset"), true } },
{
"gui.background", {
QObject::tr("General background color"),
QObject::tr("Background"), true
}
},
{
"gui.alt_background", {
QObject::tr(""),
QObject::tr("Alt. background"), true
}
},
{
"gui.disass_selected", {
QObject::tr("Background of current graph node"),
QObject::tr("Current graph node"), true
}
},
{ "gui.border", { QObject::tr(""), QObject::tr("gui.border"), true } },
// TODO: find out different
{
"linehl", {
QObject::tr("Selected line background color"),
QObject::tr("Line highlight"), true
}
},
{
"highlight", {
QObject::tr("Selected line background color"),
QObject::tr("Line highlight"), true
}
},
// TODO: find out different
{
"highlightWord", {
QObject::tr("Highlighted word text color"),
QObject::tr("Word higlight"), true
}
},
{
"wordhl", {
QObject::tr("Highlighted word text color"),
QObject::tr("Word higlight"), true
}
},
{
"gui.main", {
QObject::tr("Color of main function color"),
QObject::tr("Main"), true
}
},
{ "gui.imports", { QObject::tr(""), QObject::tr("gui.imports"), true } },
{ "highlightPC", { QObject::tr(""), QObject::tr("highlightPC"), true } },
{ "gui.navbar.err", { QObject::tr(""), QObject::tr("gui.navbar.err"), true } },
{ "gui.navbar.sym", { QObject::tr(""), QObject::tr("gui.navbar.sym"), true } },
{ "gui.dataoffset", { QObject::tr(""), QObject::tr("gui.dataoffset"), true } },
{
"gui.navbar.code", {
QObject::tr("Code section color in navigation bar"),
QObject::tr("Navbar code"), true
}
},
{
"gui.navbar.empty", {
QObject::tr("Empty section color in navigation bar"),
QObject::tr("Navbar empty"), true
}
},
{ "angui.navbar.str", { QObject::tr(""), QObject::tr("angui.navbar.str"), true } },
{ "gui.breakpoint_background", { QObject::tr(""), QObject::tr("Breakpoint background"), true } }
};
void ColorOptionDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
painter->setPen(QPen(Qt::OpaqueMode));
painter->setBrush(QBrush(backgroundColor));
painter->drawRect(option.rect);
QPalette pal;
QStyleOptionViewItem op = option;
op.palette = pal;
op.displayAlignment = Qt::AlignCenter;
if (option.state & QStyle::State_Selected) {
QLinearGradient lgrd = QLinearGradient(option.rect.topLeft(), option.rect.bottomRight());
QColor highlighted = QApplication::palette().highlight().color(),
highlightedOpaque = highlighted;
highlightedOpaque.setAlpha(0);
lgrd.setColorAt(0.00, highlighted);
lgrd.setColorAt(0.25, highlightedOpaque);
lgrd.setColorAt(0.75, highlightedOpaque);
lgrd.setColorAt(1.00, highlighted);
painter->setBrush(lgrd);
painter->drawRect(option.rect);
op.state &= ~ QStyle::State_Selected;
}
op.state &= ~ QStyle::State_Editing;
pal = option.palette;
QColor txtColor;
ColorOption co = index.data(Qt::UserRole).value<ColorOption>();
txtColor = co.color;
if (optionInfoMap[co.optionName].isUsedStandardTextColor)
txtColor = textColor;
pal.setColor(QPalette::Text, txtColor);
op.palette = pal;
QStyledItemDelegate::paint(painter, op, index);
}
void ColorOptionDelegate::setBackgroundColor(const QColor &c)
{
backgroundColor = c;
}
void ColorOptionDelegate::setTextColor(const QColor &c)
{
textColor = c;
}
ColorViewButton::ColorViewButton(QWidget *parent) : QFrame (parent)
{
setLineWidth(3);
setFrameShape(QFrame::Panel);
setFrameShadow(QFrame::Raised);
setColor(palette().background().color());
setMaximumWidth(100);
}
void ColorViewButton::setColor(const QColor &c)
{
setStyleSheet(QString("background-color:%1;").arg(c.name().toLower()));
repaint();
}
void ColorViewButton::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() != Qt::LeftButton)
return;
emit clicked();
}
PreferencesListView::PreferencesListView(QWidget *parent) :
QListView (parent)
{
setModel(new ColorSettingsModel(static_cast<QObject *>(this)));
static_cast<ColorSettingsModel *>(this->model())->updateScheme();
setStandardColors();
}
void PreferencesListView::setStandardColors()
{
delegate = new ColorOptionDelegate(this);
ColorSettingsModel *model = static_cast<ColorSettingsModel *>(this->model());
delegate->setBackgroundColor(model->getBackroundColor());
delegate->setTextColor(model->getTextColor());
// I can't free last delegate, but PreferencesListView will delete it,
// because every delegate is its child.
setItemDelegate(static_cast<QAbstractItemDelegate *>(delegate));
}
void PreferencesListView::currentChanged(const QModelIndex &current,
const QModelIndex &previous)
{
emit indexChanged(current);
QListView::currentChanged(current, previous);
}
ColorSchemePrefWidget::ColorSchemePrefWidget(QWidget *parent) : QWidget (parent),
ui (new Ui::ColorSchemePrefWidget), isEditable (false)
{
ui->setupUi(this);
connect(ui->colorViewFore, &ColorViewButton::clicked, this, &ColorSchemePrefWidget::newColor);
connect(ui->preferencesListView, &PreferencesListView::indexChanged, this,
&ColorSchemePrefWidget::indexChanged);
connect(ui->preferencesListView, &PreferencesListView::indexChanged, [this](const QModelIndex & i) {
ui->infoBoard->setText(optionInfoMap[i.data(Qt::UserRole).value<ColorOption>().optionName].info);
});
}
ColorSchemePrefWidget::~ColorSchemePrefWidget()
{
apply();
delete ui;
}
void ColorSchemePrefWidget::apply()
{
if (!isEditable)
return;
ColorSettingsModel *model = static_cast<ColorSettingsModel *>(ui->preferencesListView->model());
QString scheme = "";
ColorOption curr;
QMap<QString, QColor> cutterSpecific = ColorSchemeFileWorker().getCutterSpecific();
for (int i = 0; i < model->rowCount(); i++) {
curr = model->data(model->index(i), Qt::UserRole).value<ColorOption>();
if (cutterSpecific.contains(curr.optionName)) {
scheme += "#~";
} else {
scheme += "ec ";
}
scheme += curr.optionName + " rgb:" + curr.color.name().remove("#").toLower() + "\n";
}
ColorSchemeFileWorker().save(scheme, Config()->getCurrentTheme());
Config()->setColorTheme(Config()->getCurrentTheme());
}
void ColorSchemePrefWidget::newColor()
{
if (ui->preferencesListView->currentIndex().row() == -1 || !isEditable)
return;
ColorOption currCO = ui->preferencesListView->model()->data(ui->preferencesListView->currentIndex(),
Qt::UserRole).value<ColorOption>();
QColorDialog d;
d.setCurrentColor(currCO.color);
d.exec();
static_cast<ColorSettingsModel *>(ui->preferencesListView->model())->setColor(currCO.optionName,
d.selectedColor());
static_cast<ColorViewButton *>(QObject::sender())->setColor(d.selectedColor());
if (currCO.optionName == standardBackgroundOptionName) {
static_cast<PreferencesListView *>(ui->preferencesListView)->setStandardColors();
} else {
static_cast<PreferencesListView *>(ui->preferencesListView)->setStandardColors();
}
}
void ColorSchemePrefWidget::indexChanged(const QModelIndex &ni)
{
ui->colorViewFore->setColor(ni.data(Qt::UserRole).value<ColorOption>().color);
}
void ColorSchemePrefWidget::setNewScheme(const QString &schemeName)
{
isEditable = ColorSchemeFileWorker().isCustomScheme(schemeName);
static_cast<ColorSettingsModel *>(ui->preferencesListView->model())->updateScheme();
}
ColorSettingsModel::ColorSettingsModel(QObject *parent) : QAbstractListModel (parent) { }
QVariant ColorSettingsModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole)
return QVariant::fromValue(m_data.at(index.row()).displayingText);
if (role == Qt::UserRole)
return QVariant::fromValue(m_data.at(index.row()));
return QVariant();
}
void ColorSettingsModel::setColor(const QString &option, const QColor &color)
{
int row = 0;
for (auto &it : m_data) {
if (it.optionName == option) {
it.color = color;
emit dataChanged(index(row), index(row));
return;
}
row++;
}
}
QColor ColorSettingsModel::getBackroundColor() const
{
if (!ColorSchemeFileWorker().isCustomScheme(Config()->getCurrentTheme())) {
return Config()->getColor(standardBackgroundOptionName);
}
for (auto &it : m_data)
if (it.optionName == standardBackgroundOptionName)
return it.color;
return QColor();
}
QColor ColorSettingsModel::getTextColor() const
{
if (!ColorSchemeFileWorker().isCustomScheme(Config()->getCurrentTheme())) {
return Config()->getColor(standardTextOptionName);
}
for (auto &it : m_data)
if (it.optionName == standardTextOptionName)
return it.color;
return QColor();
}
void ColorSettingsModel::updateScheme()
{
m_data.clear();
QJsonObject obj = Core()->cmdj("ecj").object();
m_data.reserve(obj.size());
for (auto &it : obj.keys()) {
QJsonArray rgb = obj[it].toArray();
m_data.push_back({it, optionInfoMap[it].displayingtext, QColor(rgb[0].toInt(), rgb[1].toInt(), rgb[2].toInt())});
}
QMap<QString, QColor> cutterSpecific = ColorSchemeFileWorker().getCutterSpecific();
for (auto &it : cutterSpecific.keys())
m_data.push_back({it, optionInfoMap[it].displayingtext, cutterSpecific[it]});
qobject_cast<PreferencesListView *>(parent())->setStandardColors();
}

View File

@ -0,0 +1,127 @@
#ifndef COLORSCHEMEPREFWIDGET_H
#define COLORSCHEMEPREFWIDGET_H
#include <QFrame>
#include <QListView>
#include <QJsonObject>
#include <QAbstractListModel>
#include <QStyledItemDelegate>
namespace Ui {
class ColorSchemePrefWidget;
}
class ColorSchemePrefWidget : public QWidget
{
Q_OBJECT
public:
ColorSchemePrefWidget(QWidget *parent = nullptr);
virtual ~ColorSchemePrefWidget();
public slots:
void apply();
void setNewScheme(const QString &schemeName);
private slots:
void newColor();
void indexChanged(const QModelIndex &ni);
private:
Ui::ColorSchemePrefWidget *ui;
bool isEditable;
};
//===============SERVICE STUFF BELOW===============
class ColorViewButton : public QFrame
{
Q_OBJECT
public:
ColorViewButton(QWidget *parent = nullptr);
virtual ~ColorViewButton() override {}
public slots:
void setColor(const QColor &c);
protected slots:
void mouseReleaseEvent(QMouseEvent *event) override;
signals:
void clicked();
};
struct ColorOption {
QString optionName;
QString displayingText;
QColor color;
};
Q_DECLARE_METATYPE(ColorOption);
class ColorSettingsModel : public QAbstractListModel
{
Q_OBJECT
public:
ColorSettingsModel(QObject *parent = nullptr);
virtual ~ColorSettingsModel() override {}
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
void setColor(const QString &option,
const QColor &color);
QColor getBackroundColor() const;
QColor getTextColor() const;
int rowCount(const QModelIndex &parent = QModelIndex()) const override { return m_data.size(); }
void updateScheme();
private:
QList<ColorOption> m_data;
};
class ColorOptionDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
ColorOptionDelegate(QObject *parent = nullptr) : QStyledItemDelegate (parent) {}
~ColorOptionDelegate() override {}
void paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
void setBackgroundColor(const QColor &c);
void setTextColor(const QColor &c);
private:
QColor backgroundColor;
QColor textColor;
};
class PreferencesListView : public QListView
{
Q_OBJECT
public:
PreferencesListView(QWidget *parent = nullptr);
virtual ~PreferencesListView() override {}
void setStandardColors();
protected slots:
void currentChanged(const QModelIndex &current,
const QModelIndex &previous) override;
signals:
void indexChanged(const QModelIndex &ni);
private:
ColorOptionDelegate *delegate;
};
#endif // COLORSCHEMEPREFWIDGET_H

View File

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ColorSchemePrefWidget</class>
<widget class="QWidget" name="ColorSchemePrefWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>670</width>
<height>306</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="PreferencesListView" name="preferencesListView"/>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="ColorViewButton" name="colorViewFore">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="setDefFore">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Set Default</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="infoBoard">
<property name="text">
<string/>
</property>
</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>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>PreferencesListView</class>
<extends>QListView</extends>
<header>widgets/ColorSchemePrefWidget.h</header>
</customwidget>
<customwidget>
<class>ColorViewButton</class>
<extends>QFrame</extends>
<header>widgets/ColorSchemePrefWidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -25,11 +25,11 @@ public:
public slots:
void paintEvent(QPaintEvent *event) override;
void updateGraphicsScene();
private slots:
void fetchAndPaintData();
void fetchStats();
void updateGraphicsScene();
void drawCursor();
void on_seekChanged(RVA addr);