Finish the rest of the settings dialog code

- Move over the last of the original settings dialog code to QT.  It was
  actually a bit easier to write in the QT version.  wxWidgets was
  definitely not ideal for that because the pages would fully
  create/destroy every time.

- [Win32] Fix os_dlopen so that it only appends .dll if not present

- [MacOS] Fix name dialog text edit widget issue (it would be better if
  we could just use the list widget for editing labels, will have to
  look in to that in the future)

- Tweak the settings UI a bit more and make 30 FPS default

- Add a macro to convert a QString to a UTF-8 const char * string

- Rename build/plugins to build/obs-plugins

- Remove the last of the wxWidgets code
This commit is contained in:
jp9000 2014-01-26 15:36:15 -07:00
parent cc44c93fbf
commit a5372e9757
14 changed files with 508 additions and 589 deletions

View file

@ -53,7 +53,8 @@ void *os_dlopen(const char *path)
HMODULE h_library = NULL;
dstr_init_copy(&dll_name, path);
dstr_cat(&dll_name, ".dll");
if (!dstr_find(&dll_name, ".dll"))
dstr_cat(&dll_name, ".dll");
os_utf8_to_wcs(dll_name.array, 0, &wpath);
h_library = LoadLibraryW(wpath);

View file

@ -35,9 +35,21 @@
</item>
<item alignment="Qt::AlignBottom">
<widget class="QWidget" name="widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="1">
<widget class="QLineEdit" name="userText">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true"/>
</property>

View file

@ -324,7 +324,7 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_10">
<property name="spacing">
<number>4</number>
<number>5</number>
</property>
<property name="leftMargin">
<number>0</number>

View file

@ -342,7 +342,7 @@
</widget>
</item>
<item row="5" column="1">
<widget class="QStackedWidget" name="stackedWidget">
<widget class="QStackedWidget" name="fpsTypes">
<property name="currentIndex">
<number>0</number>
</property>
@ -365,6 +365,9 @@
<property name="currentText">
<string notr="true">30</string>
</property>
<property name="currentIndex">
<number>3</number>
</property>
<item>
<property name="text">
<string notr="true">10</string>
@ -491,6 +494,22 @@
</widget>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="errorText">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(255, 0, 4);</string>
</property>
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
@ -534,7 +553,7 @@
<connection>
<sender>fpsType</sender>
<signal>currentIndexChanged(int)</signal>
<receiver>stackedWidget</receiver>
<receiver>fpsTypes</receiver>
<slot>setCurrentIndex(int)</slot>
<hints>
<hint type="sourcelabel">

View file

@ -25,7 +25,9 @@
struct MonitorInfo {
int32_t x, y;
uint32_t cx, cy;
MonitorInfo(int32_t x, int32_t y, uint32_t cx, uint32_t cy)
inline MonitorInfo() {}
inline MonitorInfo(int32_t x, int32_t y, uint32_t cx, uint32_t cy)
: x(x), y(y), cx(cx), cy(cy)
{}
};

View file

@ -18,6 +18,7 @@
#pragma once
#define QT_UTF8(str) QString::fromUtf8(str)
#define QT_TO_UTF8(str) str.toUtf8().constData()
class QWidget;
struct gs_window;

View file

@ -1,138 +0,0 @@
/******************************************************************************
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include <util/bmem.h>
#include "obs-app.hpp"
#include "settings-basic.hpp"
#include "window-basic-settings.hpp"
#include "wx-wrappers.hpp"
#include "platform.hpp"
using namespace std;
class BasicGenData : public BasicSettingsData {
ConfigFile localeIni;
WXConnector languageBoxConnector;
void LanguageChanged(wxCommandEvent &event);
int AddLanguage(const char *tag);
void FillLanguageList(const char *currentLang);
public:
BasicGenData(OBSBasicSettings *window);
virtual void Apply();
};
class LanguageInfo : public wxClientData {
public:
const char *tag;
const char *name;
const char *subLang;
bool isDefault;
inline LanguageInfo(config_t config, const char *tag)
: wxClientData (),
tag (tag),
name (config_get_string(config, tag, "Name")),
subLang (config_get_string(config, tag, "SubLang")),
isDefault (config_get_bool(config, tag, "DefaultSubLang"))
{
}
};
int BasicGenData::AddLanguage(const char *tag)
{
LanguageInfo *info = new LanguageInfo(localeIni, tag);
return window->languageList->Append(wxString(info->name, wxConvUTF8),
info);
}
void BasicGenData::FillLanguageList(const char *currentLang)
{
window->languageList->Clear();
size_t numSections = config_num_sections(localeIni);
for (size_t i = 0; i < numSections; i++) {
const char *lang = config_get_section(localeIni, i);
int idx = AddLanguage(lang);
if (strcmp(lang, currentLang) == 0)
window->languageList->SetSelection(idx);
}
}
BasicGenData::BasicGenData(OBSBasicSettings *window)
: BasicSettingsData (window)
{
string path;
if (!GetDataFilePath("locale/locale.ini", path))
throw "Could not find locale/locale.ini path";
if (localeIni.Open(path.c_str(), CONFIG_OPEN_EXISTING) != 0)
throw "Could not open locale.ini";
const char *currentLang = config_get_string(GetGlobalConfig(),
"General", "Language");
FillLanguageList(currentLang);
languageBoxConnector.Connect(
window->languageList,
wxEVT_COMBOBOX,
wxCommandEventHandler(BasicGenData::LanguageChanged),
NULL,
this);
window->generalChangedText->Hide();
}
void BasicGenData::LanguageChanged(wxCommandEvent &event)
{
SetChanged();
window->generalChangedText->SetLabel(
WXStr("Settings.General.ProgramRestart"));
window->generalChangedText->Show();
}
void BasicGenData::Apply()
{
int sel = window->languageList->GetSelection();
if (sel == wxNOT_FOUND)
return;
LanguageInfo *info = static_cast<LanguageInfo*>(
window->languageList->GetClientObject(sel));
config_set_string(GetGlobalConfig(), "General", "Language", info->tag);
config_save(GetGlobalConfig());
SetSaved();
}
BasicSettingsData *CreateBasicGeneralSettings(OBSBasicSettings *window)
{
BasicSettingsData *data = NULL;
try {
data = new BasicGenData(window);
} catch (const char *error) {
blog(LOG_ERROR, "CreateBasicGeneralSettings failed: %s", error);
}
return data;
}

View file

@ -1,431 +0,0 @@
/******************************************************************************
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include <util/lexer.h>
#include "obs-app.hpp"
#include "settings-basic.hpp"
#include "window-basic-settings.hpp"
#include "wx-wrappers.hpp"
#include "platform.hpp"
#include <sstream>
#include <unordered_set>
using namespace std;
class BasicVideoData : public BasicSettingsData {
ConnectorList connections;
int AddRes(uint32_t cx, uint32_t cy);
void LoadOther();
void LoadResolutionData();
void LoadFPSData();
void LoadFPSCommon();
void LoadFPSInteger();
void LoadFPSFraction();
void LoadFPSNanoseconds();
void ResetScaleList(uint32_t cx, uint32_t cy);
void RendererChanged(wxCommandEvent &event);
void BaseResChanged(wxCommandEvent &event);
void OutputResChanged(wxCommandEvent &event);
void FPSChanged(wxCommandEvent &event);
void SaveOther();
void SaveFPSData();
void SaveFPSCommon();
void SaveFPSInteger();
void SaveFPSFraction();
void SaveFPSNanoseconds();
virtual void SetChanged()
{
BasicSettingsData::SetChanged();
window->videoChangedText->Show();
}
public:
BasicVideoData(OBSBasicSettings *window);
virtual void Apply();
};
struct BaseLexer {
lexer lex;
public:
inline BaseLexer() {lexer_init(&lex);}
inline ~BaseLexer() {lexer_free(&lex);}
operator lexer*() {return &lex;}
};
/* parses "[width]x[height]", string, i.e. 1024x768 */
static bool ConvertTextRes(wxComboBox *combo, uint32_t &cx, uint32_t &cy)
{
string str = combo->GetValue().ToStdString();
BaseLexer lex;
lexer_start(lex, str.c_str());
base_token token;
/* parse width */
if (!lexer_getbasetoken(lex, &token, IGNORE_WHITESPACE))
return false;
if (token.type != BASETOKEN_DIGIT)
return false;
cx = std::stoul(token.text.array);
/* parse 'x' */
if (!lexer_getbasetoken(lex, &token, IGNORE_WHITESPACE))
return false;
if (strref_cmpi(&token.text, "x") != 0)
return false;
/* parse height */
if (!lexer_getbasetoken(lex, &token, IGNORE_WHITESPACE))
return false;
if (token.type != BASETOKEN_DIGIT)
return false;
cy = std::stoul(token.text.array);
/* shouldn't be any more tokens after this */
if (lexer_getbasetoken(lex, &token, IGNORE_WHITESPACE))
return false;
return true;
}
int BasicVideoData::AddRes(uint32_t cx, uint32_t cy)
{
stringstream res;
res << cx << "x" << cy;
return window->baseResList->Append(res.str());
}
void BasicVideoData::LoadOther()
{
const char *renderer = config_get_string(GetGlobalConfig(), "Video",
"Renderer");
window->rendererList->Clear();
window->rendererList->Append("OpenGL");
#ifdef _WIN32
window->rendererList->Append("Direct3D 11");
#endif
int sel = window->rendererList->FindString(renderer);
if (sel == wxNOT_FOUND)
sel = 0;
window->rendererList->SetSelection(sel);
}
static uint64_t append_uint32_t(uint64_t first, uint64_t second)
{
return (first << 32) | second;
}
void BasicVideoData::LoadResolutionData()
{
window->baseResList->Clear();
uint32_t cx = config_get_uint(GetGlobalConfig(), "Video", "BaseCX");
uint32_t cy = config_get_uint(GetGlobalConfig(), "Video", "BaseCY");
vector<MonitorInfo> monitors;
GetMonitors(monitors);
unordered_set<uint64_t> resolutions;
for (size_t i = 0; i < monitors.size(); i++) {
uint64_t res = append_uint32_t(monitors[i].cx, monitors[i].cy);
if(resolutions.emplace(res).second)
AddRes(monitors[i].cx, monitors[i].cy);
}
stringstream res;
res << cx << "x" << cy;
window->baseResList->SetValue(res.str());
ResetScaleList(cx, cy);
cx = config_get_uint(GetGlobalConfig(), "Video", "OutputCX");
cy = config_get_uint(GetGlobalConfig(), "Video", "OutputCY");
res.str(string());
res.clear();
res << cx << "x" << cy;
window->outputResList->SetValue(res.str());
}
void BasicVideoData::LoadFPSData()
{
const char *fpsType = config_get_string(GetGlobalConfig(), "Video",
"FPSType");
LoadFPSCommon();
LoadFPSInteger();
LoadFPSFraction();
LoadFPSNanoseconds();
if (!fpsType)
return;
else if (strcmp(fpsType, "Common") == 0)
window->fpsTypeList->SetSelection(0);
else if (strcmp(fpsType, "Integer") == 0)
window->fpsTypeList->SetSelection(1);
else if (strcmp(fpsType, "Fraction") == 0)
window->fpsTypeList->SetSelection(2);
else if (strcmp(fpsType, "Nanoseconds") == 0)
window->fpsTypeList->SetSelection(3);
}
void BasicVideoData::LoadFPSCommon()
{
const char *val = config_get_string(GetGlobalConfig(), "Video",
"FPSCommon");
int sel = window->fpsCommonList->FindString(val);
if (sel == wxNOT_FOUND)
sel = window->fpsCommonList->FindString("30");
window->fpsCommonList->SetSelection(sel);
}
void BasicVideoData::LoadFPSInteger()
{
window->fpsTypeList->SetSelection(1);
int val = config_get_int(GetGlobalConfig(), "Video", "FPSInt");
window->fpsIntegerScroller->SetValue(val);
}
void BasicVideoData::LoadFPSFraction()
{
window->fpsTypeList->SetSelection(2);
int num = config_get_int(GetGlobalConfig(), "Video", "FPSNum");
int den = config_get_int(GetGlobalConfig(), "Video", "FPSDen");
window->fpsNumeratorScroller->SetValue(num);
window->fpsDenominatorScroller->SetValue(den);
}
void BasicVideoData::LoadFPSNanoseconds()
{
window->fpsTypeList->SetSelection(3);
int val = config_get_int(GetGlobalConfig(), "Video", "FPSNS");
window->fpsNanosecondsScroller->SetValue(val);
}
/* some nice default output resolution vals */
static const double vals[] =
{
1.0,
1.25,
(1.0/0.75),
1.5,
(1.0/0.6),
1.75,
2.0,
2.25,
2.5,
2.75,
3.0
};
static const size_t numVals = sizeof(vals)/sizeof(double);
void BasicVideoData::ResetScaleList(uint32_t cx, uint32_t cy)
{
window->outputResList->Clear();
for (size_t i = 0; i < numVals; i++) {
stringstream res;
res << uint32_t(double(cx) / vals[i]);
res << "x";
res << uint32_t(double(cy) / vals[i]);
window->outputResList->Append(res.str());
}
if (numVals) {
stringstream str;
str << cx << "x" << cy;
window->outputResList->SetValue(str.str());
}
}
#define ADD_CONNECT(control, event, func) \
connections.Add(window->control, event, \
wxCommandEventHandler(BasicVideoData::func), \
NULL, this)
BasicVideoData::BasicVideoData(OBSBasicSettings *window)
: BasicSettingsData(window)
{
LoadResolutionData();
LoadFPSData();
LoadOther();
/* load connectors after loading data to prevent them from triggering */
ADD_CONNECT(baseResList, wxEVT_TEXT, BaseResChanged);
ADD_CONNECT(outputResList, wxEVT_TEXT, OutputResChanged);
ADD_CONNECT(rendererList, wxEVT_COMBOBOX, RendererChanged);
ADD_CONNECT(fpsCommonList, wxEVT_COMBOBOX, FPSChanged);
ADD_CONNECT(fpsIntegerScroller, wxEVT_SPINCTRL, FPSChanged);
ADD_CONNECT(fpsNumeratorScroller, wxEVT_SPINCTRL, FPSChanged);
ADD_CONNECT(fpsDenominatorScroller, wxEVT_SPINCTRL, FPSChanged);
ADD_CONNECT(fpsNanosecondsScroller, wxEVT_SPINCTRL, FPSChanged);
ADD_CONNECT(fpsIntegerScroller, wxEVT_TEXT, FPSChanged);
ADD_CONNECT(fpsNumeratorScroller, wxEVT_TEXT, FPSChanged);
ADD_CONNECT(fpsDenominatorScroller, wxEVT_TEXT, FPSChanged);
ADD_CONNECT(fpsNanosecondsScroller, wxEVT_TEXT, FPSChanged);
ADD_CONNECT(fpsTypeList, wxEVT_CHOICEBOOK_PAGE_CHANGED,
FPSChanged);
window->videoChangedText->Hide();
}
void BasicVideoData::RendererChanged(wxCommandEvent &event)
{
SetChanged();
window->videoChangedText->SetLabel(WXStr("Settings.ProgramRestart"));
window->videoChangedText->Show();
}
void BasicVideoData::FPSChanged(wxCommandEvent &event)
{
SetChanged();
}
void BasicVideoData::BaseResChanged(wxCommandEvent &event)
{
uint32_t cx, cy;
if (!ConvertTextRes(window->baseResList, cx, cy)) {
window->videoChangedText->SetLabel(
WXStr("Settings.Video.InvalidResolution"));
window->videoChangedText->Show();
return;
}
SetChanged();
ResetScaleList(cx, cy);
}
void BasicVideoData::OutputResChanged(wxCommandEvent &event)
{
uint32_t cx, cy;
if (!ConvertTextRes(window->outputResList, cx, cy)) {
window->videoChangedText->SetLabel(
WXStr("Settings.Video.InvalidResolution"));
window->videoChangedText->Show();
return;
}
SetChanged();
}
void BasicVideoData::SaveOther()
{
int sel = window->rendererList->GetSelection();
if (sel == wxNOT_FOUND)
return;
wxString renderer = window->rendererList->GetString(sel);
config_set_string(GetGlobalConfig(), "Video", "Renderer",
renderer.c_str());
}
void BasicVideoData::SaveFPSData()
{
int id = window->fpsTypeList->GetCurrentPage()->GetId();
const char *type;
switch (id) {
case ID_FPSPANEL_COMMON: type = "Common"; break;
case ID_FPSPANEL_INTEGER: type = "Integer"; break;
case ID_FPSPANEL_FRACTION: type = "Fraction"; break;
case ID_FPSPANEL_NANOSECONDS: type = "Nanoseconds"; break;
}
config_set_string(GetGlobalConfig(), "Video", "FPSType", type);
SaveFPSCommon();
SaveFPSInteger();
SaveFPSFraction();
SaveFPSNanoseconds();
}
void BasicVideoData::SaveFPSCommon()
{
int sel = window->fpsCommonList->GetSelection();
wxString str = window->fpsCommonList->GetString(sel);
config_set_string(GetGlobalConfig(), "Video", "FPSCommon", str.c_str());
}
void BasicVideoData::SaveFPSInteger()
{
int val = window->fpsIntegerScroller->GetValue();
config_set_int(GetGlobalConfig(), "Video", "FPSInt", val);
}
void BasicVideoData::SaveFPSFraction()
{
int num = window->fpsNumeratorScroller->GetValue();
int den = window->fpsDenominatorScroller->GetValue();
config_set_int(GetGlobalConfig(), "Video", "FPSNum", num);
config_set_int(GetGlobalConfig(), "Video", "FPSDen", den);
}
void BasicVideoData::SaveFPSNanoseconds()
{
int val = window->fpsNanosecondsScroller->GetValue();
config_set_int(GetGlobalConfig(), "Video", "FPSNS", val);
}
void BasicVideoData::Apply()
{
uint32_t cx, cy;
if (!ConvertTextRes(window->baseResList, cx, cy)) {
config_set_uint(GetGlobalConfig(), "Video", "BaseCX", cx);
config_set_uint(GetGlobalConfig(), "Video", "BaseCY", cy);
}
if (ConvertTextRes(window->outputResList, cx, cy)) {
config_set_uint(GetGlobalConfig(), "Video", "OutputCX", cx);
config_set_uint(GetGlobalConfig(), "Video", "OutputCY", cy);
}
SaveOther();
SaveFPSData();
config_save(GetGlobalConfig());
/* TODO: If resolutiosn/fps were chaned, reset video */
SetSaved();
}
BasicSettingsData *CreateBasicVideoSettings(OBSBasicSettings *window)
{
return new BasicVideoData(window);
}

View file

@ -15,27 +15,428 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include <util/util.hpp>
#include <util/lexer.h>
#include <sstream>
#include <QLineEdit>
#include <QMessageBox>
#include <QCloseEvent>
#include "obs-app.hpp"
#include "platform.hpp"
#include "qt-wrappers.hpp"
#include "window-basic-settings.hpp"
OBSBasicSettings::OBSBasicSettings(QWidget *parent)
: QDialog (parent),
ui (new Ui::OBSBasicSettings)
#include <util/platform.h>
using namespace std;
struct BaseLexer {
lexer lex;
public:
inline BaseLexer() {lexer_init(&lex);}
inline ~BaseLexer() {lexer_free(&lex);}
operator lexer*() {return &lex;}
};
/* parses "[width]x[height]", string, i.e. 1024x768 */
static bool ConvertResText(const char *res, uint32_t &cx, uint32_t &cy)
{
BaseLexer lex;
base_token token;
lexer_start(lex, res);
/* parse width */
if (!lexer_getbasetoken(lex, &token, IGNORE_WHITESPACE))
return false;
if (token.type != BASETOKEN_DIGIT)
return false;
cx = std::stoul(token.text.array);
/* parse 'x' */
if (!lexer_getbasetoken(lex, &token, IGNORE_WHITESPACE))
return false;
if (strref_cmpi(&token.text, "x") != 0)
return false;
/* parse height */
if (!lexer_getbasetoken(lex, &token, IGNORE_WHITESPACE))
return false;
if (token.type != BASETOKEN_DIGIT)
return false;
cy = std::stoul(token.text.array);
/* shouldn't be any more tokens after this */
if (lexer_getbasetoken(lex, &token, IGNORE_WHITESPACE))
return false;
return true;
}
OBSBasicSettings::OBSBasicSettings(QWidget *parent)
: QDialog (parent),
ui (new Ui::OBSBasicSettings),
generalChanged (false),
outputsChanged (false),
audioChanged (false),
videoChanged (false),
pageIndex (0),
loading (true)
{
string path;
ui->setupUi(this);
/*ui->language = config_get_string(GetGlobalConfig(), "General",
"Language");*/
if (!GetDataFilePath("locale/locale.ini", path))
throw "Could not find locale/locale.ini path";
if (localeIni.Open(path.c_str(), CONFIG_OPEN_EXISTING) != 0)
throw "Could not open locale.ini";
LoadSettings(false);
}
void OBSBasicSettings::LoadLanguageList()
{
const char *currentLang = config_get_string(GetGlobalConfig(),
"General", "Language");
ui->language->clear();
size_t numSections = config_num_sections(localeIni);
for (size_t i = 0; i < numSections; i++) {
const char *tag = config_get_section(localeIni, i);
const char *name = config_get_string(localeIni, tag, "Name");
int idx = ui->language->count();
ui->language->addItem(QT_UTF8(name), QT_UTF8(tag));
if (strcmp(tag, currentLang) == 0)
ui->language->setCurrentIndex(idx);
}
ui->language->model()->sort(0);
}
void OBSBasicSettings::LoadGeneralSettings()
{
loading = true;
LoadLanguageList();
loading = false;
}
void OBSBasicSettings::LoadRendererList()
{
const char *renderer = config_get_string(GetGlobalConfig(), "Video",
"Renderer");
#ifdef _WIN32
ui->renderer->addItem(QT_UTF8("Direct3D 11"));
#endif
ui->renderer->addItem(QT_UTF8("OpenGL"));
int idx = ui->renderer->findText(QT_UTF8(renderer));
if (idx == -1)
idx = 0;
ui->renderer->setCurrentIndex(idx);
}
Q_DECLARE_METATYPE(MonitorInfo);
static string ResString(uint32_t cx, uint32_t cy)
{
stringstream res;
res << cx << "x" << cy;
return res.str();
}
/* some nice default output resolution vals */
static const double vals[] =
{
1.0,
1.25,
(1.0/0.75),
1.5,
(1.0/0.6),
1.75,
2.0,
2.25,
2.5,
2.75,
3.0
};
static const size_t numVals = sizeof(vals)/sizeof(double);
void OBSBasicSettings::ResetDownscales(uint32_t cx, uint32_t cy)
{
for (size_t idx = 0; idx < numVals; idx++) {
uint32_t downscaleCX = uint32_t(double(cx) / vals[idx]);
uint32_t downscaleCY = uint32_t(double(cy) / vals[idx]);
string res = ResString(downscaleCX, downscaleCY);
ui->outputResolution->addItem(res.c_str());
}
ui->outputResolution->lineEdit()->setText(ResString(cx, cy).c_str());
}
void OBSBasicSettings::LoadResolutionLists()
{
uint32_t cx = config_get_uint(GetGlobalConfig(), "Video", "BaseCX");
uint32_t cy = config_get_uint(GetGlobalConfig(), "Video", "BaseCY");
vector<MonitorInfo> monitors;
ui->baseResolution->clear();
ui->outputResolution->clear();
GetMonitors(monitors);
for (MonitorInfo &monitor : monitors) {
string res = ResString(monitor.cx, monitor.cy);
ui->baseResolution->addItem(res.c_str());
}
ResetDownscales(cx, cy);
cx = config_get_uint(GetGlobalConfig(), "Video", "OutputCX");
cy = config_get_uint(GetGlobalConfig(), "Video", "OutputCY");
ui->outputResolution->lineEdit()->setText(ResString(cx, cy).c_str());
}
static inline void LoadFPSCommon(Ui::OBSBasicSettings *ui)
{
const char *val = config_get_string(GetGlobalConfig(), "Video",
"FPSCommon");
int idx = ui->fpsCommon->findText(val);
if (idx == -1) idx = 3;
ui->fpsCommon->setCurrentIndex(idx);
}
static inline void LoadFPSInteger(Ui::OBSBasicSettings *ui)
{
int val = config_get_int(GetGlobalConfig(), "Video", "FPSInt");
ui->fpsInteger->setValue(val);
}
static inline void LoadFPSFraction(Ui::OBSBasicSettings *ui)
{
int num = config_get_int(GetGlobalConfig(), "Video", "FPSNum");
int den = config_get_int(GetGlobalConfig(), "Video", "FPSDen");
ui->fpsNumerator->setValue(num);
ui->fpsDenominator->setValue(den);
}
void OBSBasicSettings::LoadFPSData()
{
LoadFPSCommon(ui.get());
LoadFPSInteger(ui.get());
LoadFPSFraction(ui.get());
int fpsType = config_get_int(GetGlobalConfig(), "Video", "FPSType");
if (fpsType < 0 || fpsType > 2) fpsType = 0;
ui->fpsType->setCurrentIndex(fpsType);
ui->fpsTypes->setCurrentIndex(fpsType);
}
void OBSBasicSettings::LoadVideoSettings()
{
loading = true;
LoadRendererList();
LoadResolutionLists();
LoadFPSData();
loading = false;
}
void OBSBasicSettings::LoadSettings(bool changedOnly)
{
if (!changedOnly || generalChanged)
LoadGeneralSettings();
//if (!changedOnly || outputChanged)
// LoadOutputSettings();
//if (!changedOnly || audioChanged)
// LoadOutputSettings();
if (!changedOnly || videoChanged)
LoadVideoSettings();
}
void OBSBasicSettings::SaveGeneralSettings()
{
int languageIndex = ui->language->currentIndex();
QVariant langData = ui->language->itemData(languageIndex);
string language = langData.toString().toStdString();
config_set_string(GetGlobalConfig(), "General", "Language",
language.c_str());
}
void OBSBasicSettings::SaveVideoSettings()
{
QString renderer = ui->renderer->currentText();
QString baseResolution = ui->baseResolution->currentText();
QString outputResolution = ui->outputResolution->currentText();
int fpsType = ui->fpsType->currentIndex();
QString fpsCommon = ui->fpsCommon->currentText();
int fpsInteger = ui->fpsInteger->value();
int fpsNumerator = ui->fpsNumerator->value();
int fpsDenominator = ui->fpsDenominator->value();
uint32_t cx, cy;
/* ------------------- */
config_set_string(GetGlobalConfig(), "Video", "Renderer",
QT_TO_UTF8(renderer));
if (ConvertResText(QT_TO_UTF8(baseResolution), cx, cy)) {
config_set_int(GetGlobalConfig(), "Video", "BaseCX", cx);
config_set_int(GetGlobalConfig(), "Video", "BaseCY", cy);
}
if (ConvertResText(QT_TO_UTF8(outputResolution), cx, cy)) {
config_set_int(GetGlobalConfig(), "Video", "OutputCX", cx);
config_set_int(GetGlobalConfig(), "Video", "OutputCY", cy);
}
config_set_int(GetGlobalConfig(), "Video", "FPSType", fpsType);
config_set_string(GetGlobalConfig(), "Video", "FPSCommon",
QT_TO_UTF8(fpsCommon));
config_set_int(GetGlobalConfig(), "Video", "FPSInt", fpsInteger);
config_set_int(GetGlobalConfig(), "Video", "FPSNum", fpsNumerator);
config_set_int(GetGlobalConfig(), "Video", "FPSDen", fpsDenominator);
}
void OBSBasicSettings::SaveSettings()
{
if (generalChanged)
SaveGeneralSettings();
//if (outputChanged)
// SaveOutputSettings();
//if (audioChanged)
// SaveAudioSettings();
if (videoChanged)
SaveVideoSettings();
config_save(GetGlobalConfig());
}
bool OBSBasicSettings::QueryChanges()
{
QMessageBox::StandardButton button;
button = QMessageBox::question(this,
QTStr("Settings.ConfirmTitle"),
QTStr("Settings.Confirm"),
QMessageBox::Yes | QMessageBox::No |
QMessageBox::Cancel);
if (button == QMessageBox::Cancel)
return false;
else if (button == QMessageBox::Yes)
SaveSettings();
else
LoadSettings(true);
ClearChanged();
return true;
}
void OBSBasicSettings::closeEvent(QCloseEvent *event)
{
if (Changed() && !QueryChanges())
event->ignore();
}
void OBSBasicSettings::on_listWidget_currentRowChanged(int row)
void OBSBasicSettings::on_listWidget_itemSelectionChanged()
{
int row = ui->listWidget->currentRow();
if (loading || row == pageIndex)
return;
if (Changed() && !QueryChanges()) {
ui->listWidget->setCurrentRow(pageIndex);
return;
}
pageIndex = row;
}
void OBSBasicSettings::on_buttonBox_clicked(QAbstractButton *button)
{
QDialogButtonBox::ButtonRole val = ui->buttonBox->buttonRole(button);
if (val == QDialogButtonBox::ApplyRole ||
val == QDialogButtonBox::AcceptRole) {
SaveSettings();
ClearChanged();
}
if (val == QDialogButtonBox::AcceptRole ||
val == QDialogButtonBox::RejectRole) {
ClearChanged();
close();
}
}
static bool ValidResolutions(Ui::OBSBasicSettings *ui)
{
QString baseRes = ui->baseResolution->lineEdit()->text();
QString outputRes = ui->outputResolution->lineEdit()->text();
uint32_t cx, cy;
if (!ConvertResText(QT_TO_UTF8(baseRes), cx, cy) ||
!ConvertResText(QT_TO_UTF8(outputRes), cx, cy)) {
ui->errorText->setText(
QTStr("Settings.Video.InvalidResolution"));
return false;
}
ui->errorText->setText("");
return true;
}
void OBSBasicSettings::on_language_currentIndexChanged(int index)
{
if (!loading)
generalChanged = true;
}
void OBSBasicSettings::on_renderer_currentIndexChanged(int index)
{
if (!loading) {
videoChanged = true;
ui->errorText->setText(
QTStr("Settings.ProgramRestart"));
}
}
void OBSBasicSettings::on_fpsType_currentIndexChanged(int index)
{
if (!loading)
videoChanged = true;
}
void OBSBasicSettings::on_baseResolution_editTextChanged(const QString &text)
{
if (!loading && ValidResolutions(ui.get()))
videoChanged = true;
}
void OBSBasicSettings::on_outputResolution_editTextChanged(const QString &text)
{
if (!loading && ValidResolutions(ui.get()))
videoChanged = true;
}

View file

@ -17,6 +17,7 @@
#pragma once
#include <util/util.hpp>
#include <QDialog>
#include <memory>
@ -29,11 +30,62 @@ class OBSBasicSettings : public QDialog {
private:
std::unique_ptr<Ui::OBSBasicSettings> ui;
ConfigFile localeIni;
bool generalChanged;
bool outputsChanged;
bool audioChanged;
bool videoChanged;
int pageIndex;
bool loading;
inline bool Changed() const
{
return generalChanged || outputsChanged || audioChanged ||
videoChanged;
}
inline void ClearChanged()
{
generalChanged = false;
outputsChanged = false;
audioChanged = false;
videoChanged = false;
}
bool QueryChanges();
void LoadGeneralSettings();
//void LoadOutputSettings();
//void LoadAudioSettings();
void LoadVideoSettings();
/* general */
void LoadLanguageList();
/* video */
void LoadRendererList();
void ResetDownscales(uint32_t cx, uint32_t cy);
void LoadResolutionLists();
void LoadFPSData();
void LoadSettings(bool changedOnly);
void SaveGeneralSettings();
//void SaveOutputSettings();
//void SaveAudioSettings();
void SaveVideoSettings();
void SaveSettings();
private slots:
void on_listWidget_currentRowChanged(int row);
void on_listWidget_itemSelectionChanged();
void on_buttonBox_clicked(QAbstractButton *button);
void on_language_currentIndexChanged(int index);
void on_renderer_currentIndexChanged(int index);
void on_fpsType_currentIndexChanged(int index);
void on_baseResolution_editTextChanged(const QString &text);
void on_outputResolution_editTextChanged(const QString &text);
protected:
virtual void closeEvent(QCloseEvent *event);

View file

@ -102,7 +102,7 @@
<AdditionalDependencies>avcodec.lib;avformat.lib;swscale.lib;avutil.lib;libobs.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/32bit/$(TargetName)$(TargetExt)"</Command>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/obs-plugins/32bit/$(TargetName)$(TargetExt)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -121,7 +121,7 @@
<AdditionalDependencies>avcodec.lib;avformat.lib;swscale.lib;avutil.lib;libobs.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/64bit/$(TargetName)$(TargetExt)"</Command>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/obs-plugins/64bit/$(TargetName)$(TargetExt)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -144,7 +144,7 @@
<AdditionalDependencies>avcodec.lib;avformat.lib;swscale.lib;avutil.lib;libobs.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/32bit/$(TargetName)$(TargetExt)"</Command>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/obs-plugins/32bit/$(TargetName)$(TargetExt)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -167,7 +167,7 @@
<AdditionalDependencies>avcodec.lib;avformat.lib;swscale.lib;avutil.lib;libobs.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/64bit/$(TargetName)$(TargetExt)"</Command>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/obs-plugins/64bit/$(TargetName)$(TargetExt)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>

View file

@ -107,7 +107,7 @@
<AdditionalDependencies>pthreads.lib;libobs.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/32bit/$(TargetName)$(TargetExt)"</Command>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/obs-plugins/32bit/$(TargetName)$(TargetExt)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -127,7 +127,7 @@
<AdditionalDependencies>pthreads.lib;libobs.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/64bit/$(TargetName)$(TargetExt)"</Command>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/obs-plugins/64bit/$(TargetName)$(TargetExt)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -151,7 +151,7 @@
<AdditionalDependencies>pthreads.lib;libobs.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/32bit/$(TargetName)$(TargetExt)"</Command>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/obs-plugins/32bit/$(TargetName)$(TargetExt)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -175,7 +175,7 @@
<AdditionalDependencies>pthreads.lib;libobs.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/64bit/$(TargetName)$(TargetExt)"</Command>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/obs-plugins/64bit/$(TargetName)$(TargetExt)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />