diff --git a/doomsday/client/client.pro b/doomsday/client/client.pro index 3793376f50..5c5f663d7e 100644 --- a/doomsday/client/client.pro +++ b/doomsday/client/client.pro @@ -393,6 +393,7 @@ DENG_HEADERS += \ include/ui/widgets/consolewidget.h \ include/ui/widgets/cvarchoicewidget.h \ include/ui/widgets/cvarlineeditwidget.h \ + include/ui/widgets/cvarnativepathwidget.h \ include/ui/widgets/cvarsliderwidget.h \ include/ui/widgets/cvartogglewidget.h \ include/ui/widgets/gamefilterwidget.h \ @@ -727,6 +728,7 @@ SOURCES += \ src/ui/widgets/consolewidget.cpp \ src/ui/widgets/cvarchoicewidget.cpp \ src/ui/widgets/cvarlineeditwidget.cpp \ + src/ui/widgets/cvarnativepathwidget.cpp \ src/ui/widgets/cvarsliderwidget.cpp \ src/ui/widgets/cvartogglewidget.cpp \ src/ui/widgets/gamefilterwidget.cpp \ diff --git a/doomsday/client/include/ui/widgets/cvarnativepathwidget.h b/doomsday/client/include/ui/widgets/cvarnativepathwidget.h new file mode 100644 index 0000000000..c377d88e31 --- /dev/null +++ b/doomsday/client/include/ui/widgets/cvarnativepathwidget.h @@ -0,0 +1,48 @@ +/** @file cvarnativepathwidget.h Console variable native path widget. + * + * @authors Copyright (c) 2014 Jaakko Keränen + * + * @par License + * GPL: http://www.gnu.org/licenses/gpl.html + * + * 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 + */ + +#ifndef DENG_CLIENT_CVARNATIVEPATHWIDGET_H +#define DENG_CLIENT_CVARNATIVEPATHWIDGET_H + +#include +#include "icvarwidget.h" + +/** + * Console variable that contains a native path. + */ +class CVarNativePathWidget : public de::AuxButtonWidget, public ICVarWidget +{ + Q_OBJECT + +public: + CVarNativePathWidget(char const *cvarPath); + + char const *cvarPath() const; + +public slots: + void updateFromCVar(); + void chooseUsingNativeFileDialog(); + +protected slots: + void setCVarValueFromWidget(); + +private: + DENG2_PRIVATE(d) +}; + +#endif // DENG_CLIENT_CVARNATIVEPATHWIDGET_H diff --git a/doomsday/client/src/clientapp.cpp b/doomsday/client/src/clientapp.cpp index f18e4b2988..a68b9d8323 100644 --- a/doomsday/client/src/clientapp.cpp +++ b/doomsday/client/src/clientapp.cpp @@ -257,15 +257,16 @@ DENG2_PIMPL(ClientApp) .define(SReg::IntCVar, "net-dev", 0); audioSettings - .define(SReg::IntCVar, "sound-volume", 255 * 2/3) - .define(SReg::IntCVar, "music-volume", 255 * 2/3) - .define(SReg::FloatCVar, "sound-reverb-volume", 0.5f) - .define(SReg::IntCVar, "sound-info", 0) - .define(SReg::IntCVar, "sound-rate", 11025) - .define(SReg::IntCVar, "sound-16bit", 0) - .define(SReg::IntCVar, "sound-3d", 0) - .define(SReg::IntCVar, "sound-overlap-stop", 0) - .define(SReg::IntCVar, "music-source", MUSP_EXT); + .define(SReg::IntCVar, "sound-volume", 255 * 2/3) + .define(SReg::IntCVar, "music-volume", 255 * 2/3) + .define(SReg::FloatCVar, "sound-reverb-volume", 0.5f) + .define(SReg::IntCVar, "sound-info", 0) + .define(SReg::IntCVar, "sound-rate", 11025) + .define(SReg::IntCVar, "sound-16bit", 0) + .define(SReg::IntCVar, "sound-3d", 0) + .define(SReg::IntCVar, "sound-overlap-stop", 0) + .define(SReg::IntCVar, "music-source", MUSP_EXT) + .define(SReg::StringCVar, "music-soundfont", ""); } #ifdef UNIX diff --git a/doomsday/client/src/ui/dialogs/audiosettingsdialog.cpp b/doomsday/client/src/ui/dialogs/audiosettingsdialog.cpp index 1c36d21e28..85d6f90173 100644 --- a/doomsday/client/src/ui/dialogs/audiosettingsdialog.cpp +++ b/doomsday/client/src/ui/dialogs/audiosettingsdialog.cpp @@ -20,6 +20,7 @@ #include "ui/widgets/cvarsliderwidget.h" #include "ui/widgets/cvartogglewidget.h" #include "ui/widgets/cvarchoicewidget.h" +#include "ui/widgets/cvarnativepathwidget.h" #include "clientapp.h" #include "de_audio.h" @@ -40,6 +41,7 @@ DENG_GUI_PIMPL(AudioSettingsDialog) CVarToggleWidget *sound16bit; CVarChoiceWidget *sampleRate; CVarChoiceWidget *musicSource; + CVarNativePathWidget *musicSoundfont; CVarToggleWidget *soundInfo; GridPopupWidget *devPopup; @@ -47,14 +49,15 @@ DENG_GUI_PIMPL(AudioSettingsDialog) { ScrollAreaWidget &area = self.area(); - area.add(sfxVolume = new CVarSliderWidget("sound-volume")); - area.add(musicVolume = new CVarSliderWidget("music-volume")); - area.add(reverbVolume = new CVarSliderWidget("sound-reverb-volume")); - area.add(sound3D = new CVarToggleWidget("sound-3d")); - area.add(overlapStop = new CVarToggleWidget("sound-overlap-stop")); - area.add(sound16bit = new CVarToggleWidget("sound-16bit")); - area.add(sampleRate = new CVarChoiceWidget("sound-rate")); - area.add(musicSource = new CVarChoiceWidget("music-source")); + area.add(sfxVolume = new CVarSliderWidget ("sound-volume")); + area.add(musicVolume = new CVarSliderWidget ("music-volume")); + area.add(reverbVolume = new CVarSliderWidget ("sound-reverb-volume")); + area.add(sound3D = new CVarToggleWidget ("sound-3d")); + area.add(overlapStop = new CVarToggleWidget ("sound-overlap-stop")); + area.add(sound16bit = new CVarToggleWidget ("sound-16bit")); + area.add(sampleRate = new CVarChoiceWidget ("sound-rate")); + area.add(musicSource = new CVarChoiceWidget ("music-source")); + area.add(musicSoundfont = new CVarNativePathWidget("music-soundfont")); // Display volumes on a 0...100 scale. sfxVolume ->setDisplayFactor(100.0 / 255.0); @@ -71,15 +74,13 @@ DENG_GUI_PIMPL(AudioSettingsDialog) void fetch() { - sfxVolume->updateFromCVar(); - musicVolume->updateFromCVar(); - reverbVolume->updateFromCVar(); - sound3D->updateFromCVar(); - overlapStop->updateFromCVar(); - sound16bit->updateFromCVar(); - soundInfo->updateFromCVar(); - sampleRate->updateFromCVar(); - musicSource->updateFromCVar(); + foreach(Widget *w, self.area().childWidgets() + devPopup->content().childWidgets()) + { + if(ICVarWidget *cv = w->maybeAs()) + { + cv->updateFromCVar(); + } + } } }; @@ -88,28 +89,29 @@ AudioSettingsDialog::AudioSettingsDialog(String const &name) { heading().setText(tr("Audio Settings")); - LabelWidget *sfxVolLabel = LabelWidget::newWithText(tr("SFX Volume:"), &area()); - LabelWidget *musicVolLabel = LabelWidget::newWithText(tr("Music Volume:"), &area()); - LabelWidget *rvbVolLabel = LabelWidget::newWithText(tr("Reverb Strength:"), &area()); + auto *sfxVolLabel = LabelWidget::newWithText(tr("SFX Volume:"), &area()); + auto *musicVolLabel = LabelWidget::newWithText(tr("Music Volume:"), &area()); + auto *rvbVolLabel = LabelWidget::newWithText(tr("Reverb Strength:"), &area()); d->sound3D->setText(tr("3D Effects & Reverb")); d->overlapStop->setText(tr("One Sound per Emitter")); d->sound16bit->setText(tr("16-bit Resampling")); - LabelWidget *rateLabel = LabelWidget::newWithText(tr("Resampling:"), &area()); + auto *rateLabel = LabelWidget::newWithText(tr("Resampling:"), &area()); d->sampleRate->items() << new ChoiceItem(tr("1x @ 11025 Hz"), 11025) << new ChoiceItem(tr("2x @ 22050 Hz"), 22050) << new ChoiceItem(tr("4x @ 44100 Hz"), 44100); - LabelWidget *musSrcLabel = LabelWidget::newWithText(tr("Preferred Music:"), &area()); + auto *musSrcLabel = LabelWidget::newWithText(tr("Preferred Music:"), &area()); d->musicSource->items() << new ChoiceItem(tr("MUS lumps"), MUSP_MUS) << new ChoiceItem(tr("External files"), MUSP_EXT) << new ChoiceItem(tr("CD"), MUSP_CD); + auto *sfLabel = LabelWidget::newWithText(tr("Sound Font:"), &area()); // Layout. GridLayout layout(area().contentRule().left(), area().contentRule().top()); @@ -120,9 +122,10 @@ AudioSettingsDialog::AudioSettingsDialog(String const &name) << *rvbVolLabel << *d->reverbVolume << Const(0) << *d->sound3D << Const(0) << *d->overlapStop - << *musSrcLabel << *d->musicSource << *rateLabel << *d->sampleRate - << Const(0) << *d->sound16bit; + << Const(0) << *d->sound16bit + << *musSrcLabel << *d->musicSource + << *sfLabel << *d->musicSoundfont; area().setContentSize(layout.width(), layout.height()); diff --git a/doomsday/client/src/ui/widgets/cvarnativepathwidget.cpp b/doomsday/client/src/ui/widgets/cvarnativepathwidget.cpp new file mode 100644 index 0000000000..f927f44dfe --- /dev/null +++ b/doomsday/client/src/ui/widgets/cvarnativepathwidget.cpp @@ -0,0 +1,108 @@ +/** @file cvarnativepathwidget.cpp Console variable with a native path. + * + * @authors Copyright (c) 2014 Jaakko Keränen + * + * @par License + * LGPL: http://www.gnu.org/licenses/lgpl.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 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 Lesser + * General Public License for more details. You should have received a copy of + * the GNU Lesser General Public License along with this program; if not, see: + * http://www.gnu.org/licenses + */ + +#include "ui/widgets/cvarnativepathwidget.h" +#include "ui/clientwindow.h" + +#include +#include + +using namespace de; + +DENG2_PIMPL_NOREF(CVarNativePathWidget) +{ + char const *cvar; + NativePath path; + + cvar_t *var() const + { + cvar_t *cv = Con_FindVariable(cvar); + DENG2_ASSERT(cv != 0); + return cv; + } + + String labelText() const + { + if(path.isEmpty()) + { + return String(_E(l)) + tr("(not set)") + _E(.); + } + return path.fileName(); + } +}; + +CVarNativePathWidget::CVarNativePathWidget(char const *cvarPath) + : d(new Instance) +{ + d->cvar = cvarPath; + updateFromCVar(); + + auxiliary().setText(tr("Browse")); + + //connect(this, SIGNAL(pressed()), this, SLOT(chooseUsingNativeFileDialog())); + connect(&auxiliary(), SIGNAL(pressed()), this, SLOT(chooseUsingNativeFileDialog())); +} + +char const *CVarNativePathWidget::cvarPath() const +{ + return d->cvar; +} + +void CVarNativePathWidget::updateFromCVar() +{ + d->path = CVar_String(d->var()); + setText(d->labelText()); +} + +void CVarNativePathWidget::chooseUsingNativeFileDialog() +{ + auto &win = ClientWindow::main(); + +#ifndef MACOSX + // Switch temporarily to windowed mode. + win.saveState(); + int windowedMode[] = { + ClientWindow::Fullscreen, false, + ClientWindow::End + }; + win.changeAttributes(windowedMode); +#endif + + // Use a native dialog to pick the path. + QDir dir(d->path); + if(d->path.isEmpty()) dir = QDir::home(); + QFileDialog dlg(&win, tr("Select File for \"%1\"").arg(d->cvar), dir.absolutePath()); + dlg.setFileMode(QFileDialog::ExistingFile); + dlg.setOption(QFileDialog::ReadOnly, true); + dlg.setLabelText(QFileDialog::Accept, tr("Select")); + if(dlg.exec()) + { + d->path = dlg.selectedFiles().at(0); + setCVarValueFromWidget(); + setText(d->labelText()); + } + +#ifndef MACOSX + win.restoreState(); +#endif +} + +void CVarNativePathWidget::setCVarValueFromWidget() +{ + CVar_SetString(d->var(), d->path.toString().toUtf8()); +}