#include "common/Configuration.h" #include "common/Configuration.h" #include "ColorSchemePrefWidget.h" #include "ui_ColorSchemePrefWidget.h" #include "common/ColorSchemeFileSaver.h" #include #include #include #include #include #include #include #include #include struct OptionIfo { QString info; QString displayingtext; bool isUsedStandardTextColor; }; static const QMap 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(); 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(this))); static_cast(this->model())->updateScheme(); setStandardColors(); } void PreferencesListView::setStandardColors() { delegate = new ColorOptionDelegate(this); ColorSettingsModel *model = static_cast(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(delegate)); } void PreferencesListView::currentChanged(const QModelIndex ¤t, 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().optionName].info); }); } ColorSchemePrefWidget::~ColorSchemePrefWidget() { apply(); delete ui; } void ColorSchemePrefWidget::apply() { if (!isEditable) return; ColorSettingsModel *model = static_cast(ui->preferencesListView->model()); QString scheme = ""; ColorOption curr; QMap cutterSpecific = ColorSchemeFileWorker().getCutterSpecific(); for (int i = 0; i < model->rowCount(); i++) { curr = model->data(model->index(i), Qt::UserRole).value(); 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(); QColorDialog d; d.setCurrentColor(currCO.color); d.exec(); static_cast(ui->preferencesListView->model())->setColor(currCO.optionName, d.selectedColor()); static_cast(QObject::sender())->setColor(d.selectedColor()); if (currCO.optionName == standardBackgroundOptionName) { static_cast(ui->preferencesListView)->setStandardColors(); } else { static_cast(ui->preferencesListView)->setStandardColors(); } } void ColorSchemePrefWidget::indexChanged(const QModelIndex &ni) { ui->colorViewFore->setColor(ni.data(Qt::UserRole).value().color); } void ColorSchemePrefWidget::setNewScheme(const QString &schemeName) { isEditable = ColorSchemeFileWorker().isCustomScheme(schemeName); static_cast(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 cutterSpecific = ColorSchemeFileWorker().getCutterSpecific(); for (auto &it : cutterSpecific.keys()) m_data.push_back({it, optionInfoMap[it].displayingtext, cutterSpecific[it]}); qobject_cast(parent())->setStandardColors(); }