diff --git a/build/plugins/32bit/.gitignore b/build/obs-plugins/32bit/.gitignore similarity index 100% rename from build/plugins/32bit/.gitignore rename to build/obs-plugins/32bit/.gitignore diff --git a/build/plugins/64bit/.gitignore b/build/obs-plugins/64bit/.gitignore similarity index 100% rename from build/plugins/64bit/.gitignore rename to build/obs-plugins/64bit/.gitignore diff --git a/libobs/util/platform-windows.c b/libobs/util/platform-windows.c index 570e1750e..b10abceba 100644 --- a/libobs/util/platform-windows.c +++ b/libobs/util/platform-windows.c @@ -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); diff --git a/obs/forms/NameDialog.ui b/obs/forms/NameDialog.ui index ffb6e8dfb..4f1cee217 100644 --- a/obs/forms/NameDialog.ui +++ b/obs/forms/NameDialog.ui @@ -35,9 +35,21 @@ + + + 0 + 0 + + + + + 0 + 0 + + diff --git a/obs/forms/OBSBasic.ui b/obs/forms/OBSBasic.ui index 814a01787..46ef8c98e 100644 --- a/obs/forms/OBSBasic.ui +++ b/obs/forms/OBSBasic.ui @@ -324,7 +324,7 @@ - 4 + 5 0 diff --git a/obs/forms/OBSBasicSettings.ui b/obs/forms/OBSBasicSettings.ui index 593cd67a5..7b51ee2fb 100644 --- a/obs/forms/OBSBasicSettings.ui +++ b/obs/forms/OBSBasicSettings.ui @@ -342,7 +342,7 @@ - + 0 @@ -365,6 +365,9 @@ 30 + + 3 + 10 @@ -491,6 +494,22 @@ + + + + + 0 + 0 + + + + color: rgb(255, 0, 4); + + + + + + @@ -534,7 +553,7 @@ fpsType currentIndexChanged(int) - stackedWidget + fpsTypes setCurrentIndex(int) diff --git a/obs/platform.hpp b/obs/platform.hpp index d05264afd..bd04a81cf 100644 --- a/obs/platform.hpp +++ b/obs/platform.hpp @@ -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) {} }; diff --git a/obs/qt-wrappers.hpp b/obs/qt-wrappers.hpp index 254a3129d..9863a3520 100644 --- a/obs/qt-wrappers.hpp +++ b/obs/qt-wrappers.hpp @@ -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; diff --git a/obs/settings-basic-general.cpp b/obs/settings-basic-general.cpp deleted file mode 100644 index 0fade9bc2..000000000 --- a/obs/settings-basic-general.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/****************************************************************************** - Copyright (C) 2013 by Hugh Bailey - - 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 . -******************************************************************************/ - -#include - -#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( - 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; -} diff --git a/obs/settings-basic-video.cpp b/obs/settings-basic-video.cpp deleted file mode 100644 index fa7f8f663..000000000 --- a/obs/settings-basic-video.cpp +++ /dev/null @@ -1,431 +0,0 @@ -/****************************************************************************** - Copyright (C) 2013 by Hugh Bailey - - 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 . -******************************************************************************/ - -#include - -#include "obs-app.hpp" -#include "settings-basic.hpp" -#include "window-basic-settings.hpp" -#include "wx-wrappers.hpp" -#include "platform.hpp" - -#include -#include -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 monitors; - GetMonitors(monitors); - unordered_set 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); -} diff --git a/obs/window-basic-settings.cpp b/obs/window-basic-settings.cpp index 987d8cec2..a7c230bb4 100644 --- a/obs/window-basic-settings.cpp +++ b/obs/window-basic-settings.cpp @@ -15,27 +15,428 @@ along with this program. If not, see . ******************************************************************************/ +#include +#include +#include +#include +#include +#include + #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 + +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 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; } diff --git a/obs/window-basic-settings.hpp b/obs/window-basic-settings.hpp index 2517a28e5..0a1e347d2 100644 --- a/obs/window-basic-settings.hpp +++ b/obs/window-basic-settings.hpp @@ -17,6 +17,7 @@ #pragma once +#include #include #include @@ -29,11 +30,62 @@ class OBSBasicSettings : public QDialog { private: std::unique_ptr 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); diff --git a/vs/2013/obs-ffmpeg/obs-ffmpeg.vcxproj b/vs/2013/obs-ffmpeg/obs-ffmpeg.vcxproj index 9669c4e97..86513b4ee 100644 --- a/vs/2013/obs-ffmpeg/obs-ffmpeg.vcxproj +++ b/vs/2013/obs-ffmpeg/obs-ffmpeg.vcxproj @@ -102,7 +102,7 @@ avcodec.lib;avformat.lib;swscale.lib;avutil.lib;libobs.lib;%(AdditionalDependencies) - copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/32bit/$(TargetName)$(TargetExt)" + copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/obs-plugins/32bit/$(TargetName)$(TargetExt)" @@ -121,7 +121,7 @@ avcodec.lib;avformat.lib;swscale.lib;avutil.lib;libobs.lib;%(AdditionalDependencies) - copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/64bit/$(TargetName)$(TargetExt)" + copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/obs-plugins/64bit/$(TargetName)$(TargetExt)" @@ -144,7 +144,7 @@ avcodec.lib;avformat.lib;swscale.lib;avutil.lib;libobs.lib;%(AdditionalDependencies) - copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/32bit/$(TargetName)$(TargetExt)" + copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/obs-plugins/32bit/$(TargetName)$(TargetExt)" @@ -167,7 +167,7 @@ avcodec.lib;avformat.lib;swscale.lib;avutil.lib;libobs.lib;%(AdditionalDependencies) - copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/64bit/$(TargetName)$(TargetExt)" + copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/obs-plugins/64bit/$(TargetName)$(TargetExt)" diff --git a/vs/2013/test-input/test-input.vcxproj b/vs/2013/test-input/test-input.vcxproj index 0d9dff498..8cb322f51 100644 --- a/vs/2013/test-input/test-input.vcxproj +++ b/vs/2013/test-input/test-input.vcxproj @@ -107,7 +107,7 @@ pthreads.lib;libobs.lib;%(AdditionalDependencies) - copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/32bit/$(TargetName)$(TargetExt)" + copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/obs-plugins/32bit/$(TargetName)$(TargetExt)" @@ -127,7 +127,7 @@ pthreads.lib;libobs.lib;%(AdditionalDependencies) - copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/64bit/$(TargetName)$(TargetExt)" + copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/obs-plugins/64bit/$(TargetName)$(TargetExt)" @@ -151,7 +151,7 @@ pthreads.lib;libobs.lib;%(AdditionalDependencies) - copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/32bit/$(TargetName)$(TargetExt)" + copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/obs-plugins/32bit/$(TargetName)$(TargetExt)" @@ -175,7 +175,7 @@ pthreads.lib;libobs.lib;%(AdditionalDependencies) - copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/64bit/$(TargetName)$(TargetExt)" + copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/obs-plugins/64bit/$(TargetName)$(TargetExt)"