Qt: Revamp logging configuration

This commit is contained in:
Vicki Pfau 2019-01-20 21:09:34 -08:00
parent bd8fe4d878
commit 4e39875e7b
19 changed files with 439 additions and 47 deletions

View File

@ -194,13 +194,26 @@ typedef intptr_t ssize_t;
#define TEST_FILL_BITS(SRC, START, END, TEST) ((TEST) ? (FILL_BITS(SRC, START, END)) : (CLEAR_BITS(SRC, START, END)))
#ifdef _MSC_VER
#pragma section(".CRT$XCU",read)
#define ATTRIBUTE_UNUSED
#define ATTRIBUTE_FORMAT(X, Y, Z)
#define ATTRIBUTE_NOINLINE
// Adapted from https://stackoverflow.com/a/2390626
#define _CONSTRUCTOR(FN, PRE) \
static void FN(void); \
__declspec(allocate(".CRT$XCU")) void (*_CONSTRUCTOR_ ## FN)(void) = FN; \
__pragma(comment(linker,"/include:" PRE "_CONSTRUCTOR_" #FN)) \
static void FN(void)
#ifdef _WIN64
#define CONSTRUCTOR(FN) _CONSTRUCTOR(FN, "")
#else
#define CONSTRUCTOR(FN) _CONSTRUCTOR(FN, "_")
#endif
#else
#define ATTRIBUTE_UNUSED __attribute__((unused))
#define ATTRIBUTE_FORMAT(X, Y, Z) __attribute__((format(X, Y, Z)))
#define ATTRIBUTE_NOINLINE __attribute__((noinline))
#define CONSTRUCTOR(FN) static __attribute__((constructor)) void FN(void)
#endif
#define DECL_BITFIELD(NAME, TYPE) typedef TYPE NAME

View File

@ -47,24 +47,23 @@ struct mCoreConfig;
void mLogFilterInit(struct mLogFilter*);
void mLogFilterDeinit(struct mLogFilter*);
void mLogFilterLoad(struct mLogFilter*, const struct mCoreConfig*);
void mLogFilterSave(const struct mLogFilter*, struct mCoreConfig*);
void mLogFilterSet(struct mLogFilter*, const char* category, int levels);
bool mLogFilterTest(struct mLogFilter*, int category, enum mLogLevel level);
void mLogFilterReset(struct mLogFilter*, const char* category);
bool mLogFilterTest(const struct mLogFilter*, int category, enum mLogLevel level);
int mLogFilterLevels(const struct mLogFilter*, int category);
ATTRIBUTE_FORMAT(printf, 3, 4)
void mLog(int category, enum mLogLevel level, const char* format, ...);
#define mLOG(CATEGORY, LEVEL, ...) mLog(_mLOG_CAT_ ## CATEGORY (), mLOG_ ## LEVEL, __VA_ARGS__)
#define mLOG(CATEGORY, LEVEL, ...) mLog(_mLOG_CAT_ ## CATEGORY, mLOG_ ## LEVEL, __VA_ARGS__)
#define mLOG_DECLARE_CATEGORY(CATEGORY) int _mLOG_CAT_ ## CATEGORY (void); extern const char* _mLOG_CAT_ ## CATEGORY ## _ID;
#define mLOG_DECLARE_CATEGORY(CATEGORY) extern int _mLOG_CAT_ ## CATEGORY;
#define mLOG_DEFINE_CATEGORY(CATEGORY, NAME, ID) \
int _mLOG_CAT_ ## CATEGORY (void) { \
static int category = 0; \
if (!category) { \
category = mLogGenerateCategory(NAME, ID); \
} \
return category; \
} \
const char* _mLOG_CAT_ ## CATEGORY ## _ID = ID;
int _mLOG_CAT_ ## CATEGORY; \
CONSTRUCTOR(_mLOG_CAT_ ## CATEGORY ## _INIT) { \
_mLOG_CAT_ ## CATEGORY = mLogGenerateCategory(NAME, ID); \
}
mLOG_DECLARE_CATEGORY(STATUS)

View File

@ -104,7 +104,7 @@ static void _setFilterLevel(const char* key, const char* value, enum mCoreConfig
char* end;
int ivalue = strtol(value, &end, 10);
if (ivalue == 0) {
ivalue = INT_MIN; // Zero is reserved
ivalue = 0x80; // Zero is reserved
}
if (!end) {
return;
@ -113,34 +113,66 @@ static void _setFilterLevel(const char* key, const char* value, enum mCoreConfig
}
void mLogFilterLoad(struct mLogFilter* filter, const struct mCoreConfig* config) {
HashTableClear(&filter->categories);
TableClear(&filter->levels);
mCoreConfigEnumerate(config, "logLevel.", _setFilterLevel, filter);
filter->defaultLevels = mLOG_ALL;
mCoreConfigGetIntValue(config, "logLevel", &filter->defaultLevels);
}
void mLogFilterSave(const struct mLogFilter* filter, struct mCoreConfig* config) {
mCoreConfigSetIntValue(config, "logLevel", filter->defaultLevels);
int i;
for (i = 0; i < _category; ++i) {
char configName[128] = {0};
snprintf(configName, sizeof(configName) - 1, "logLevel.%s", mLogCategoryId(i));
int levels = mLogFilterLevels(filter, i);
if (levels) {
mCoreConfigSetIntValue(config, configName, levels & ~0x80);
} else {
mCoreConfigSetValue(config, configName, NULL);
}
}
}
void mLogFilterSet(struct mLogFilter* filter, const char* category, int levels) {
levels |= 0x80;
HashTableInsert(&filter->categories, category, (void*)(intptr_t) levels);
// Can't do this eagerly because not all categories are initialized immediately
int cat = mLogCategoryById(category);
if (cat >= 0) {
TableInsert(&filter->levels, cat, (void*)(intptr_t) levels);
}
}
bool mLogFilterTest(struct mLogFilter* filter, int category, enum mLogLevel level) {
int value = (intptr_t) TableLookup(&filter->levels, category);
void mLogFilterReset(struct mLogFilter* filter, const char* category) {
HashTableRemove(&filter->categories, category);
// Can't do this eagerly because not all categories are initialized immediately
int cat = mLogCategoryById(category);
if (cat >= 0) {
TableRemove(&filter->levels, cat);
}
}
bool mLogFilterTest(const struct mLogFilter* filter, int category, enum mLogLevel level) {
int value = mLogFilterLevels(filter, category);
if (value) {
return value & level;
}
const char* cat = mLogCategoryId(category);
if (cat) {
value = (intptr_t) HashTableLookup(&filter->categories, cat);
if (value) {
TableInsert(&filter->levels, category, (void*)(intptr_t) value);
return value & level;
}
}
return level & filter->defaultLevels;
}
int mLogFilterLevels(const struct mLogFilter* filter , int category) {
int value = (intptr_t) TableLookup(&filter->levels, category);
if (value) {
return value;
}
const char* cat = mLogCategoryId(category);
if (cat) {
value = (intptr_t) HashTableLookup(&filter->categories, cat);
}
return value;
}
mLOG_DEFINE_CATEGORY(STATUS, "Status", "core.status")

View File

@ -524,7 +524,7 @@ void GBADebug(struct GBA* gba, uint16_t flags) {
strncpy(oolBuf, gba->debugString, sizeof(oolBuf) - 1);
memset(gba->debugString, 0, sizeof(gba->debugString));
oolBuf[0x100] = '\0';
mLog(_mLOG_CAT_GBA_DEBUG(), level, "%s", oolBuf);
mLog(_mLOG_CAT_GBA_DEBUG, level, "%s", oolBuf);
}
gba->debugFlags = GBADebugFlagsClearSend(gba->debugFlags);
}

View File

@ -90,6 +90,7 @@ set(SOURCE_FILES
KeyEditor.cpp
LoadSaveState.cpp
LogController.cpp
LogConfigModel.cpp
LogView.cpp
MapView.cpp
MemoryModel.cpp
@ -104,6 +105,7 @@ set(SOURCE_FILES
PrinterView.cpp
RegisterView.cpp
ROMInfo.cpp
RotatedHeaderView.cpp
SavestateButton.cpp
SensorView.cpp
SettingsView.cpp

View File

@ -82,7 +82,8 @@ public:
Configuration* input() { return mCoreConfigGetInput(&m_config); }
const mCoreConfig* config() { return &m_config; }
const mCoreConfig* config() const { return &m_config; }
mCoreConfig* config() { return &m_config; }
static const QString& configDir();

View File

@ -10,8 +10,9 @@
#include "CoreManager.h"
#include "ConfigController.h"
#include "Display.h"
#include "Window.h"
#include "LogController.h"
#include "VFileDevice.h"
#include "Window.h"
#include <QFileInfo>
#include <QFileOpenEvent>
@ -65,6 +66,8 @@ GBAApp::GBAApp(int& argc, char* argv[], ConfigController* config)
AudioProcessor::setDriver(static_cast<AudioProcessor::Driver>(m_configController->getQtOption("audioDriver").toInt()));
}
LogController::global()->load(m_configController);
connect(this, &GBAApp::aboutToQuit, this, &GBAApp::cleanup);
}

View File

@ -0,0 +1,149 @@
/* Copyright (c) 2013-2019 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "LogConfigModel.h"
#include <algorithm>
using namespace QGBA;
LogConfigModel::LogConfigModel(LogController* controller, QObject* parent)
: QAbstractItemModel(parent)
, m_controller(controller)
{
for (int i = 0; mLogCategoryId(i); ++i) {
int levels = controller->levels(i);
m_cache.append({ i, mLogCategoryName(i), mLogCategoryId(i), levels ? levels : -1 });
}
std::sort(m_cache.begin(), m_cache.end());
m_levels = m_controller->levels();
}
QVariant LogConfigModel::data(const QModelIndex& index, int role) const {
if (role != Qt::CheckStateRole) {
return QVariant();
}
int levels;
if (index.row() == 0) {
levels = m_levels;
} else {
levels = m_cache[index.row() - 1].levels;
}
if (index.column() == 0) {
return levels < 0 ? Qt::Checked : Qt::Unchecked;
} else if (levels < 0 && index.row() > 0) {
return (m_levels >> (index.column() - 1)) & 1 ? Qt::PartiallyChecked : Qt::Unchecked;
} else {
return (levels >> (index.column() - 1)) & 1 ? Qt::Checked : Qt::Unchecked;
}
}
bool LogConfigModel::setData(const QModelIndex& index, const QVariant& value, int role) {
if (role != Qt::CheckStateRole) {
return false;
}
int levels;
if (index.row() == 0) {
levels = m_levels;
} else {
levels = m_cache[index.row() - 1].levels;
}
if (index.column() == 0) {
levels = -1;
} else {
if (levels < 0) {
levels = m_levels;
}
levels ^= 1 << (index.column() - 1);
}
if (index.row() == 0) {
beginResetModel();
m_levels = levels;
endResetModel();
} else {
m_cache[index.row() - 1].levels = levels;
emit dataChanged(createIndex(0, index.row(), nullptr), createIndex(8, index.row(), nullptr));
}
return true;
}
QVariant LogConfigModel::headerData(int section, Qt::Orientation orientation, int role) const {
if (role != Qt::DisplayRole) {
return QVariant();
}
if (orientation == Qt::Horizontal) {
switch (section) {
case 0:
return tr("Default");
case 1:
return tr("Fatal");
case 2:
return tr("Error");
case 3:
return tr("Warning");
case 4:
return tr("Info");
case 5:
return tr("Debug");
case 6:
return tr("Stub");
case 7:
return tr("Game Error");
default:
return QVariant();
}
} else if (section) {
return m_cache[section - 1].name;
} else {
return tr("Default");
}
}
QModelIndex LogConfigModel::index(int row, int column, const QModelIndex& parent) const {
return createIndex(row, column, nullptr);
}
QModelIndex LogConfigModel::parent(const QModelIndex& index) const {
return QModelIndex();
}
int LogConfigModel::columnCount(const QModelIndex& parent) const {
return 8;
}
int LogConfigModel::rowCount(const QModelIndex& parent) const {
return m_cache.size() + 1;
}
Qt::ItemFlags LogConfigModel::flags(const QModelIndex& index) const {
if (!index.isValid()) {
return 0;
}
return Qt::ItemIsUserCheckable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
}
void LogConfigModel::reset() {
beginResetModel();
for (auto& row : m_cache) {
row.levels = m_controller->levels(row.index);
if (!row.levels) {
row.levels = -1;
}
}
m_levels = m_controller->levels();
endResetModel();
}
void LogConfigModel::save(ConfigController* config) {
for (auto& row : m_cache) {
if (row.levels < 0) {
m_controller->clearLevels(row.index);
} else {
m_controller->setLevels(row.levels, row.index);
}
}
m_controller->setLevels(m_levels);
m_controller->save(config);
}

View File

@ -0,0 +1,55 @@
/* Copyright (c) 2013-2019 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#pragma once
#include <QAbstractItemModel>
#include "LogController.h"
namespace QGBA {
class ConfigController;
class LogConfigModel : public QAbstractItemModel {
Q_OBJECT
public:
LogConfigModel(LogController*, QObject* parent = nullptr);
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
virtual QModelIndex index(int row, int column, const QModelIndex& parent) const override;
virtual QModelIndex parent(const QModelIndex& index) const override;
virtual int columnCount(const QModelIndex& parent = QModelIndex()) const override;
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override;
virtual Qt::ItemFlags flags(const QModelIndex& index) const override;
public slots:
void reset();
void save(ConfigController*);
private:
struct ConfigSetting {
int index;
QString name;
const char* id;
int levels;
bool operator<(struct ConfigSetting& other) {
return name < other.name;
}
};
LogController* m_controller;
QList<ConfigSetting> m_cache;
int m_levels;
};
}

View File

@ -5,6 +5,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "LogController.h"
#include "ConfigController.h"
using namespace QGBA;
LogController LogController::s_global(mLOG_ALL);
@ -19,9 +21,9 @@ LogController::LogController(int levels, QObject* parent)
if (this != &s_global) {
connect(&s_global, &LogController::logPosted, this, &LogController::postLog);
connect(this, &LogController::levelsSet, &s_global, &LogController::setLevels);
connect(this, &LogController::levelsEnabled, &s_global, &LogController::enableLevels);
connect(this, &LogController::levelsDisabled, &s_global, &LogController::disableLevels);
connect(this, static_cast<void (LogController::*)(int)>(&LogController::levelsSet), &s_global, static_cast<void (LogController::*)(int)>(&LogController::setLevels));
connect(this, static_cast<void (LogController::*)(int)>(&LogController::levelsEnabled), &s_global, static_cast<void (LogController::*)(int)>(&LogController::enableLevels));
connect(this, static_cast<void (LogController::*)(int)>(&LogController::levelsDisabled), &s_global, static_cast<void (LogController::*)(int)>(&LogController::disableLevels));
}
}
@ -29,10 +31,22 @@ LogController::~LogController() {
mLogFilterDeinit(&m_filter);
}
int LogController::levels(int category) const {
return mLogFilterLevels(&m_filter, category);
}
LogController::Stream LogController::operator()(int category, int level) {
return Stream(this, category, level);
}
void LogController::load(const ConfigController* config) {
mLogFilterLoad(&m_filter, config->config());
}
void LogController::save(ConfigController* config) const {
mLogFilterSave(&m_filter, config->config());
}
void LogController::postLog(int level, int category, const QString& string) {
if (!mLogFilterTest(&m_filter, category, static_cast<mLogLevel>(level))) {
return;
@ -55,6 +69,31 @@ void LogController::disableLevels(int levels) {
emit levelsDisabled(levels);
}
void LogController::setLevels(int levels, int category) {
auto id = mLogCategoryId(category);
mLogFilterSet(&m_filter, id, levels);
emit levelsSet(levels, category);
}
void LogController::enableLevels(int levels, int category) {
auto id = mLogCategoryId(category);
int newLevels = mLogFilterLevels(&m_filter, category) | levels;
mLogFilterSet(&m_filter, id, newLevels);
emit levelsEnabled(levels, category);
}
void LogController::disableLevels(int levels, int category) {
auto id = mLogCategoryId(category);
int newLevels = mLogFilterLevels(&m_filter, category) & ~levels;
mLogFilterSet(&m_filter, id, newLevels);
emit levelsDisabled(levels, category);
}
void LogController::clearLevels(int category) {
auto id = mLogCategoryId(category);
mLogFilterReset (&m_filter, id);
}
LogController* LogController::global() {
return &s_global;
}

View File

@ -14,6 +14,8 @@
namespace QGBA {
class ConfigController;
class LogController : public QObject {
Q_OBJECT
@ -38,24 +40,36 @@ public:
~LogController();
int levels() const { return m_filter.defaultLevels; }
int levels(int category) const;
mLogFilter* filter() { return &m_filter; }
Stream operator()(int category, int level);
static LogController* global();
static QString toString(int level);
static int categoryId(const char*);
void load(const ConfigController*);
void save(ConfigController*) const;
signals:
void logPosted(int level, int category, const QString& log);
void levelsSet(int levels);
void levelsEnabled(int levels);
void levelsDisabled(int levels);
void levelsSet(int levels, int category);
void levelsEnabled(int levels, int category);
void levelsDisabled(int levels, int category);
public slots:
void postLog(int level, int category, const QString& string);
void setLevels(int levels);
void enableLevels(int levels);
void disableLevels(int levels);
void setLevels(int levels, int category);
void enableLevels(int levels, int category);
void disableLevels(int levels, int category);
void clearLevels(int category);
private:
mLogFilter m_filter;
@ -63,6 +77,6 @@ private:
static LogController s_global;
};
#define LOG(C, L) (*LogController::global())(mLOG_ ## L, _mLOG_CAT_ ## C ())
#define LOG(C, L) (*LogController::global())(mLOG_ ## L, _mLOG_CAT_ ## C)
}

View File

@ -43,19 +43,19 @@ LogView::LogView(LogController* log, QWidget* parent)
m_ui.maxLines->setValue(DEFAULT_LINE_LIMIT);
connect(log, &LogController::logPosted, this, &LogView::postLog);
connect(log, &LogController::levelsSet, this, &LogView::setLevels);
connect(log, &LogController::levelsEnabled, [this](int level) {
connect(log, static_cast<void (LogController::*)(int)>(&LogController::levelsSet), this, &LogView::setLevels);
connect(log, static_cast<void (LogController::*)(int)>(&LogController::levelsEnabled), [this](int level) {
bool s = blockSignals(true);
setLevel(level, true);
blockSignals(s);
});
connect(log, &LogController::levelsDisabled, [this](int level) {
connect(log, static_cast<void (LogController::*)(int)>(&LogController::levelsDisabled), [this](int level) {
bool s = blockSignals(true);
setLevel(level, false);
blockSignals(s);
});
connect(this, &LogView::levelsEnabled, log, &LogController::enableLevels);
connect(this, &LogView::levelsDisabled, log, &LogController::disableLevels);
connect(this, &LogView::levelsEnabled, log, static_cast<void (LogController::*)(int)>(&LogController::enableLevels));
connect(this, &LogView::levelsDisabled, log, static_cast<void (LogController::*)(int)>(&LogController::disableLevels));
}
void LogView::postLog(int level, int category, const QString& log) {

View File

@ -0,0 +1,27 @@
/* Copyright (c) 2013-2019 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "RotatedHeaderView.h"
#include <QPainter>
using namespace QGBA;
RotatedHeaderView::RotatedHeaderView(Qt::Orientation orientation, QWidget* parent)
: QHeaderView(orientation, parent)
{
}
void RotatedHeaderView::paintSection(QPainter* painter, const QRect& rect, int logicalIndex) const {
painter->save();
painter->translate(rect.x() + rect.width(), rect.y());
painter->rotate(90);
QHeaderView::paintSection(painter, QRect(0, 0, rect.height(), rect.width()), logicalIndex);
painter->restore();
}
QSize RotatedHeaderView::sectionSizeFromContents(int logicalIndex) const {
return QHeaderView::sectionSizeFromContents(logicalIndex).transposed();
}

View File

@ -0,0 +1,23 @@
/* Copyright (c) 2013-2019 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#pragma once
#include <QHeaderView>
namespace QGBA {
class RotatedHeaderView : public QHeaderView {
Q_OBJECT
public:
RotatedHeaderView(Qt::Orientation orientation, QWidget* parent = nullptr);
protected:
void paintSection(QPainter* painter, const QRect& rect, int logicalIndex) const;
virtual QSize sectionSizeFromContents(int logicalIndex) const override;
};
}

View File

@ -11,6 +11,7 @@
#include "GBAApp.h"
#include "GBAKeyEditor.h"
#include "InputController.h"
#include "RotatedHeaderView.h"
#include "ShaderSelector.h"
#include "ShortcutView.h"
@ -24,9 +25,10 @@ using namespace QGBA;
QList<enum GBModel> SettingsView::s_gbModelList;
#endif
SettingsView::SettingsView(ConfigController* controller, InputController* inputController, ShortcutController* shortcutController, QWidget* parent)
SettingsView::SettingsView(ConfigController* controller, InputController* inputController, ShortcutController* shortcutController, LogController* logController, QWidget* parent)
: QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
, m_controller(controller)
, m_logModel(logController)
{
m_ui.setupUi(this);
@ -293,6 +295,11 @@ SettingsView::SettingsView(ConfigController* controller, InputController* inputC
}
}
m_ui.loggingView->setModel(&m_logModel);
m_ui.loggingView->setHorizontalHeader(new RotatedHeaderView(Qt::Horizontal));
m_ui.loggingView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
m_ui.loggingView->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
ShortcutView* shortcutView = new ShortcutView();
shortcutView->setController(shortcutController);
shortcutView->setInputController(inputController);
@ -430,6 +437,8 @@ void SettingsView::updateConfig() {
emit languageChanged();
}
m_logModel.save(m_controller);
#ifdef M_CORE_GB
GBModel modelGB = s_gbModelList[m_ui.gbModel->currentIndex()];
m_controller->setOption("gb.model", GBModelToName(modelGB));
@ -535,6 +544,8 @@ void SettingsView::reloadConfig() {
m_ui.saveStateSave->setChecked(saveState & SAVESTATE_SAVEDATA);
m_ui.saveStateCheats->setChecked(saveState & SAVESTATE_CHEATS);
m_logModel.reset();
#ifdef M_CORE_GB
QString modelGB = m_controller->getOption("gb.model");
if (!modelGB.isNull()) {

View File

@ -8,6 +8,7 @@
#include <QDialog>
#include "ColorPicker.h"
#include "LogConfigModel.h"
#include <mgba/core/core.h>
@ -28,7 +29,7 @@ class SettingsView : public QDialog {
Q_OBJECT
public:
SettingsView(ConfigController* controller, InputController* inputController, ShortcutController* shortcutController, QWidget* parent = nullptr);
SettingsView(ConfigController* controller, InputController* inputController, ShortcutController* shortcutController, LogController* logController, QWidget* parent = nullptr);
~SettingsView();
void setShaderSelector(ShaderSelector* shaderSelector);
@ -53,6 +54,7 @@ private:
ConfigController* m_controller;
InputController* m_input;
ShaderSelector* m_shader = nullptr;
LogConfigModel m_logModel;
#ifdef M_CORE_GB
uint32_t m_gbColors[12]{};

View File

@ -23,6 +23,13 @@
<property name="sizeConstraint">
<enum>QLayout::SetFixedSize</enum>
</property>
<item row="2" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QListWidget" name="tabs">
<property name="sizePolicy">
@ -65,6 +72,11 @@
<string>Paths</string>
</property>
</item>
<item>
<property name="text">
<string>Logging</string>
</property>
</item>
<item>
<property name="text">
<string>Game Boy</string>
@ -72,17 +84,10 @@
</item>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QStackedWidget" name="stackedWidget">
<property name="currentIndex">
<number>0</number>
<number>5</number>
</property>
<widget class="QWidget" name="av">
<layout class="QFormLayout" name="formLayout">
@ -1205,6 +1210,20 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="logging">
<layout class="QGridLayout" name="a">
<item row="0" column="0">
<widget class="QTableView" name="loggingView">
<attribute name="horizontalHeaderDefaultSectionSize">
<number>0</number>
</attribute>
<attribute name="horizontalHeaderMinimumSectionSize">
<number>0</number>
</attribute>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="gb">
<layout class="QFormLayout" name="formLayout_1">
<item row="0" column="0">

View File

@ -141,6 +141,7 @@ Window::Window(CoreManager* manager, ConfigController* config, int playerId, QWi
connect(&m_inputController, &InputController::profileLoaded, m_shortcutController, &ShortcutController::loadProfile);
m_log.setLevels(mLOG_WARN | mLOG_ERROR | mLOG_FATAL);
m_log.load(m_config);
m_fpsTimer.setInterval(FPS_TIMER_INTERVAL);
m_focusCheck.setInterval(200);
@ -432,7 +433,7 @@ void Window::exportSharkport() {
}
void Window::openSettingsWindow() {
SettingsView* settingsWindow = new SettingsView(m_config, &m_inputController, m_shortcutController);
SettingsView* settingsWindow = new SettingsView(m_config, &m_inputController, m_shortcutController, &m_log);
#if defined(BUILD_GL) || defined(BUILD_GLES2)
if (m_display->supportsShaders()) {
settingsWindow->setShaderSelector(m_shaderView.get());

View File

@ -111,7 +111,9 @@ void TableInsert(struct Table* table, uint32_t key, void* value) {
struct TableList* list;
TABLE_LOOKUP_START(TABLE_COMPARATOR, list, key) {
if (value != lookupResult->value) {
table->deinitializer(lookupResult->value);
if (table->deinitializer) {
table->deinitializer(lookupResult->value);
}
lookupResult->value = value;
}
return;