/* * xSF - Core configuration handler * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] * * Partially based on the vio*sf framework */ #include #include #include #include #include "windowsh_wrapper.h" #include #include "XSFApp.h" #include "XSFConfig.h" #include "XSFConfigDialog.h" #include "XSFFile.h" #include "XSFPlayer.h" #include "convert.h" enum { idPlayInfinitely = 500, idDefaultLength, idDefaultFade, idSkipSilenceOnStartSec, idDetectSilenceSec, idVolume, idReplayGain, idClipProtect, idSampleRate, idTitleFormat, idResetDefaults, idInfoTitle = 600, idInfoArtist, idInfoGame, idInfoYear, idInfoGenre, idInfoCopyright, idInfoComment }; XSFConfig::XSFConfig() : playInfinitely(false), skipSilenceOnStartSec(0), detectSilenceSec(0), defaultLength(0), defaultFade(0), volume(0.0), volumeType(VolumeType::None), peakType(PeakType::None), sampleRate(0), titleFormat(""), infoDialog(), supportedSampleRates(), configIO(XSFConfigIO::Create()) { } const std::string &XSFConfig::CommonNameWithVersion() { static const auto commonNameWithVersion = XSFConfig::commonName + " v" + XSFConfig::versionNumber; return commonNameWithVersion; } std::wstring XSFConfig::GetTextFromWindow(HWND hwnd) { auto length = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0); auto value = std::vector(length + 1); length = SendMessageW(hwnd, WM_GETTEXT, length + 1, reinterpret_cast(&value[0])); return std::wstring(value.begin(), value.begin() + length); } void XSFConfig::LoadConfig() { this->playInfinitely = this->configIO->GetValue("PlayInfinitely", XSFConfig::initPlayInfinitely); this->skipSilenceOnStartSec = ConvertFuncs::StringToMS(this->configIO->GetValue("SkipSilenceOnStartSec", XSFConfig::initSkipSilenceOnStartSec)); this->detectSilenceSec = ConvertFuncs::StringToMS(this->configIO->GetValue("DetectSilenceSec", XSFConfig::initDetectSilenceSec)); this->defaultLength = ConvertFuncs::StringToMS(this->configIO->GetValue("DefaultLength", XSFConfig::initDefaultLength)); this->defaultFade = ConvertFuncs::StringToMS(this->configIO->GetValue("DefaultFade", XSFConfig::initDefaultFade)); this->volume = this->configIO->GetValue("Volume", XSFConfig::initVolume); this->volumeType = this->configIO->GetValue("VolumeType", XSFConfig::initVolumeType); this->peakType = this->configIO->GetValue("PeakType", XSFConfig::initPeakType); this->sampleRate = this->configIO->GetValue("SampleRate", XSFConfig::initSampleRate); this->titleFormat = this->configIO->GetValue("TitleFormat", XSFConfig::initTitleFormat); this->LoadSpecificConfig(); } void XSFConfig::SaveConfig() { this->configIO->SetValue("PlayInfinitely", this->playInfinitely); this->configIO->SetValue("SkipSilenceOnStartSec", ConvertFuncs::MSToString(this->skipSilenceOnStartSec)); this->configIO->SetValue("DetectSilenceSec", ConvertFuncs::MSToString(this->detectSilenceSec)); this->configIO->SetValue("DefaultLength", ConvertFuncs::MSToString(this->defaultLength)); this->configIO->SetValue("DefaultFade", ConvertFuncs::MSToString(this->defaultFade)); this->configIO->SetValue("Volume", this->volume); this->configIO->SetValue("VolumeType", this->volumeType); this->configIO->SetValue("PeakType", this->peakType); this->configIO->SetValue("SampleRate", this->sampleRate); this->configIO->SetValue("TitleFormat", this->titleFormat); this->SaveSpecificConfig(); } void XSFConfig::GenerateDialogs() { // NOTE: Eventually this will be done away with when I decide to make an actual info dialog box using wxWidgets. this->infoDialog = DialogBuilder().IsPopup().WithBorder().WithDialogFrame().WithDialogModalFrame().WithSystemMenu().WithFont(L"MS Shell Dlg", 8); this->infoDialog.AddLabelControl(DialogLabelBuilder(L"Title:").WithSize(50, 8).WithRelativePositionToParent(RelativePosition::PositionType::FromTopLeft, Point(7, 10)).IsRightJustified()); this->infoDialog.AddEditBoxControl(DialogEditBoxBuilder().WithSize(200, 14).WithRelativePositionToSibling(RelativePosition::PositionType::FromTopRight, Point(5, -3)).IsLeftJustified().WithAutoHScroll().WithBorder(). WithTabStop().WithID(idInfoTitle)); this->infoDialog.AddLabelControl(DialogLabelBuilder(L"Artist:").WithSize(50, 8).WithRelativePositionToSibling(RelativePosition::PositionType::FromBottomLeft, Point(0, 10), 2).IsRightJustified()); this->infoDialog.AddEditBoxControl(DialogEditBoxBuilder().WithSize(200, 14).WithRelativePositionToSibling(RelativePosition::PositionType::FromTopRight, Point(5, -3)).IsLeftJustified().WithAutoHScroll().WithBorder(). WithTabStop().WithID(idInfoArtist)); this->infoDialog.AddLabelControl(DialogLabelBuilder(L"Game:").WithSize(50, 8).WithRelativePositionToSibling(RelativePosition::PositionType::FromBottomLeft, Point(0, 10), 2).IsRightJustified()); this->infoDialog.AddEditBoxControl(DialogEditBoxBuilder().WithSize(200, 14).WithRelativePositionToSibling(RelativePosition::PositionType::FromTopRight, Point(5, -3)).IsLeftJustified().WithAutoHScroll().WithBorder(). WithTabStop().WithID(idInfoGame)); this->infoDialog.AddLabelControl(DialogLabelBuilder(L"Year:").WithSize(50, 8).WithRelativePositionToSibling(RelativePosition::PositionType::FromBottomLeft, Point(0, 10), 2).IsRightJustified()); this->infoDialog.AddEditBoxControl(DialogEditBoxBuilder().WithSize(25, 14).WithRelativePositionToSibling(RelativePosition::PositionType::FromTopRight, Point(5, -3)).IsLeftJustified().WithAutoHScroll().WithBorder(). WithTabStop().WithID(idInfoYear)); this->infoDialog.AddLabelControl(DialogLabelBuilder(L"Genre:").WithSize(25, 8).WithRelativePositionToSibling(RelativePosition::PositionType::FromTopRight, Point(5, 3)).IsRightJustified()); this->infoDialog.AddEditBoxControl(DialogEditBoxBuilder().WithSize(140, 14).WithRelativePositionToSibling(RelativePosition::PositionType::FromTopRight, Point(5, -3)).IsLeftJustified().WithAutoHScroll().WithBorder(). WithTabStop().WithID(idInfoGenre)); this->infoDialog.AddLabelControl(DialogLabelBuilder(L"Copyright:").WithSize(50, 8).WithRelativePositionToSibling(RelativePosition::PositionType::FromBottomLeft, Point(0, 10), 4).IsRightJustified()); this->infoDialog.AddEditBoxControl(DialogEditBoxBuilder().WithSize(200, 14).WithRelativePositionToSibling(RelativePosition::PositionType::FromTopRight, Point(5, -3)).IsLeftJustified().WithAutoHScroll().WithBorder(). WithTabStop().WithID(idInfoCopyright)); this->infoDialog.AddLabelControl(DialogLabelBuilder(L"Comment:").WithSize(50, 8).WithRelativePositionToSibling(RelativePosition::PositionType::FromBottomLeft, Point(0, 10), 2).IsRightJustified()); this->infoDialog.AddEditBoxControl(DialogEditBoxBuilder().WithSize(200, 54).WithRelativePositionToSibling(RelativePosition::PositionType::FromTopRight, Point(5, -3)).IsLeftJustified().WithAutoVScroll().WithBorder(). WithTabStop().WithID(idInfoComment).WithVerticalScrollbar().WithWantReturn().IsMultiline()); this->infoDialog.AddButtonControl(DialogButtonBuilder(L"OK").WithSize(50, 14).WithRelativePositionToSibling(RelativePosition::PositionType::FromBottomRight, Point(-104, 7)).WithID(IDOK).IsDefault().WithTabStop()); this->infoDialog.AddButtonControl(DialogButtonBuilder(L"Cancel").WithSize(50, 14).WithRelativePositionToSibling(RelativePosition::PositionType::FromTopRight, Point(4, 0)).WithID(IDCANCEL).WithTabStop()); this->infoDialog.AutoSize(); } INT_PTR CALLBACK XSFConfig::InfoDialogProcStatic(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { XSFConfig *thisPtr = nullptr; if (uMsg == WM_INITDIALOG) { thisPtr = reinterpret_cast(lParam); SetWindowLongPtr(hwndDlg, DWLP_USER, reinterpret_cast(thisPtr)); } else thisPtr = reinterpret_cast(GetWindowLongPtr(hwndDlg, DWLP_USER)); if (thisPtr) return thisPtr->InfoDialogProc(hwndDlg, uMsg, wParam, lParam); else return false; } extern XSFFile *xSFFileInInfo; INT_PTR CALLBACK XSFConfig::InfoDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM) { switch (uMsg) { case WM_CLOSE: EndDialog(hwndDlg, IDCANCEL); break; case WM_INITDIALOG: SetWindowTextW(hwndDlg, xSFFileInInfo->GetFilepath().wstring().c_str()); SetWindowTextW(GetDlgItem(hwndDlg, idInfoTitle), ConvertFuncs::StringToWString(xSFFileInInfo->GetTagValue("title")).c_str()); SetWindowTextW(GetDlgItem(hwndDlg, idInfoArtist), ConvertFuncs::StringToWString(xSFFileInInfo->GetTagValue("artist")).c_str()); SetWindowTextW(GetDlgItem(hwndDlg, idInfoGame), ConvertFuncs::StringToWString(xSFFileInInfo->GetTagValue("game")).c_str()); SetWindowTextW(GetDlgItem(hwndDlg, idInfoYear), ConvertFuncs::StringToWString(xSFFileInInfo->GetTagValue("year")).c_str()); SetWindowTextW(GetDlgItem(hwndDlg, idInfoGenre), ConvertFuncs::StringToWString(xSFFileInInfo->GetTagValue("genre")).c_str()); SetWindowTextW(GetDlgItem(hwndDlg, idInfoCopyright), ConvertFuncs::StringToWString(xSFFileInInfo->GetTagValue("copyright")).c_str()); SetWindowTextW(GetDlgItem(hwndDlg, idInfoComment), ConvertFuncs::StringToWString(xSFFileInInfo->GetTagValue("comment")).c_str()); break; case WM_COMMAND: switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDOK: xSFFileInInfo->SetTag("title", this->GetTextFromWindow(GetDlgItem(hwndDlg, idInfoTitle))); xSFFileInInfo->SetTag("artist", this->GetTextFromWindow(GetDlgItem(hwndDlg, idInfoArtist))); xSFFileInInfo->SetTag("game", this->GetTextFromWindow(GetDlgItem(hwndDlg, idInfoGame))); xSFFileInInfo->SetTag("year", this->GetTextFromWindow(GetDlgItem(hwndDlg, idInfoYear))); xSFFileInInfo->SetTag("genre", this->GetTextFromWindow(GetDlgItem(hwndDlg, idInfoGenre))); xSFFileInInfo->SetTag("copyright", this->GetTextFromWindow(GetDlgItem(hwndDlg, idInfoCopyright))); xSFFileInInfo->SetTag("comment", this->GetTextFromWindow(GetDlgItem(hwndDlg, idInfoComment))); if (!xSFFileInInfo->GetTagExists("utf8")) xSFFileInInfo->SetTag("utf8", "1"); EndDialog(hwndDlg, IDOK); break; case IDCANCEL: EndDialog(hwndDlg, IDCANCEL); break; default: return false; } break; default: return false; } return true; } extern std::unique_ptr xSFApp; void XSFConfig::CallConfigDialog(HWND hwndParent) { xSFApp->ConfigDialog(hwndParent, this); } void XSFConfig::CallInfoDialog(HINSTANCE hInstance, HWND hwndParent) { DialogBoxIndirectParamW(hInstance, this->infoDialog.GenerateTemplate(), hwndParent, XSFConfig::InfoDialogProcStatic, reinterpret_cast(this)); } void XSFConfig::InitializeConfigDialog(XSFConfigDialog *dialog) { dialog->playInfinitely = this->playInfinitely; dialog->defaultPlayLength = ConvertFuncs::MSToString(this->defaultLength); dialog->defaultFadeoutLength = ConvertFuncs::MSToString(this->defaultFade); dialog->skipSilenceOnStart = ConvertFuncs::MSToString(this->skipSilenceOnStartSec); dialog->detectSilence = ConvertFuncs::MSToString(this->detectSilenceSec); dialog->volume = this->volume; dialog->replayGain = ConvertFuncs::ToIntegral(this->volumeType); dialog->clipProtect = ConvertFuncs::ToIntegral(this->peakType); auto found = std::find(this->supportedSampleRates.begin(), this->supportedSampleRates.end(), this->sampleRate); dialog->sampleRate = found == this->supportedSampleRates.end() ? 0 : found - this->supportedSampleRates.begin(); dialog->titleFormat = this->titleFormat; this->InitializeSpecificConfigDialog(dialog); } void XSFConfig::ResetConfigDefaults(XSFConfigDialog *dialog) { dialog->playInfinitely = XSFConfig::initPlayInfinitely; dialog->defaultPlayLength = XSFConfig::initDefaultLength; dialog->defaultFadeoutLength = XSFConfig::initDefaultFade; dialog->skipSilenceOnStart = XSFConfig::initSkipSilenceOnStartSec; dialog->detectSilence = XSFConfig::initDetectSilenceSec; dialog->volume = XSFConfig::initVolume; dialog->replayGain = ConvertFuncs::ToIntegral(XSFConfig::initVolumeType); dialog->clipProtect = ConvertFuncs::ToIntegral(XSFConfig::initPeakType); auto found = std::find(this->supportedSampleRates.begin(), this->supportedSampleRates.end(), XSFConfig::initSampleRate); dialog->sampleRate = found == this->supportedSampleRates.end() ? 0 : found - this->supportedSampleRates.begin(); dialog->titleFormat = XSFConfig::initTitleFormat; this->ResetSpecificConfigDefaults(dialog); } void XSFConfig::SaveConfigDialog(XSFConfigDialog *dialog) { this->playInfinitely = dialog->playInfinitely; this->defaultLength = ConvertFuncs::StringToMS(dialog->defaultPlayLength); this->defaultFade = ConvertFuncs::StringToMS(dialog->defaultFadeoutLength); this->skipSilenceOnStartSec = ConvertFuncs::StringToMS(dialog->skipSilenceOnStart); this->detectSilenceSec = ConvertFuncs::StringToMS(dialog->detectSilence); this->volume = dialog->volume; this->volumeType = static_cast(dialog->replayGain); this->peakType = static_cast(dialog->clipProtect); this->sampleRate = this->supportedSampleRates[dialog->sampleRate]; this->titleFormat = dialog->titleFormat.ToStdString(); this->SaveSpecificConfigDialog(dialog); } void XSFConfig::CopyConfigToMemory(XSFPlayer *xSFPlayer, bool preLoad) { if (preLoad) xSFPlayer->SetSampleRate(this->sampleRate); this->CopySpecificConfigToMemory(xSFPlayer, preLoad); } void XSFConfig::SetHInstance(HINSTANCE hInstance) { this->configIO->SetHInstance(hInstance); } HINSTANCE XSFConfig::GetHInstance() const { return this->configIO->GetHInstance(); } const std::vector &XSFConfig::GetSupportedSampleRates() const { return this->supportedSampleRates; } bool XSFConfig::GetPlayInfinitely() const { return this->playInfinitely; } unsigned long XSFConfig::GetSkipSilenceOnStartSec() const { return this->skipSilenceOnStartSec; } unsigned long XSFConfig::GetDetectSilenceSec() const { return this->detectSilenceSec; } unsigned long XSFConfig::GetDefaultLength() const { return this->defaultLength; } unsigned long XSFConfig::GetDefaultFade() const { return this->defaultFade; } double XSFConfig::GetVolume() const { return this->volume; } VolumeType XSFConfig::GetVolumeType() const { return this->volumeType; } PeakType XSFConfig::GetPeakType() const { return this->peakType; } const std::string &XSFConfig::GetTitleFormat() const { return this->titleFormat; }