From cd68959ad163530c542b77fe9e7102dbe615189b Mon Sep 17 00:00:00 2001 From: skyjake Date: Tue, 3 Sep 2013 21:19:58 +0300 Subject: [PATCH] UI|Control Panel|Client: Added Input Settings, removed old "Input" page A new config variable (Config.input.mouse.syncSensitivity) controls whether the X and Y axis sensitivities are always the same when modifying them in Input Settings. Added an option to span cells in GridLayout, and sliders use double values for extra precision. Sliders also support applying a factor to the displayed values (does not affect the actual values). --- doomsday/client/client.pro | 10 +- .../include/ui/dialogs/inputsettingsdialog.h | 45 +++++ .../client/include/ui/framework/gridlayout.h | 2 +- .../include/ui/widgets/cvarsliderwidget.h | 2 - .../client/include/ui/widgets/sliderwidget.h | 20 +- .../client/include/ui/widgets/taskbarwidget.h | 1 + doomsday/client/modules/appconfig.de | 5 + .../src/ui/dialogs/inputsettingsdialog.cpp | 185 ++++++++++++++++++ .../client/src/ui/framework/gridlayout.cpp | 26 +-- doomsday/client/src/ui/ui_panel.cpp | 70 ++++--- .../src/ui/widgets/cvarsliderwidget.cpp | 7 +- .../client/src/ui/widgets/sliderwidget.cpp | 84 +++++--- .../client/src/ui/widgets/taskbarwidget.cpp | 18 +- 13 files changed, 382 insertions(+), 93 deletions(-) create mode 100644 doomsday/client/include/ui/dialogs/inputsettingsdialog.h create mode 100644 doomsday/client/src/ui/dialogs/inputsettingsdialog.cpp diff --git a/doomsday/client/client.pro b/doomsday/client/client.pro index 1be11e8b7e..604b1dd730 100644 --- a/doomsday/client/client.pro +++ b/doomsday/client/client.pro @@ -354,7 +354,9 @@ DENG_HEADERS += \ include/ui/dialogs/aboutdialog.h \ include/ui/dialogs/audiosettingsdialog.h \ include/ui/dialogs/coloradjustmentdialog.h \ + include/ui/dialogs/inputsettingsdialog.h \ include/ui/dialogs/messagedialog.h \ + include/ui/dialogs/networksettingsdialog.h \ include/ui/dialogs/videosettingsdialog.h \ include/ui/fi_main.h \ include/ui/finaleinterpreter.h \ @@ -473,8 +475,7 @@ INCLUDEPATH += \ HEADERS += \ $$DENG_API_HEADERS \ - $$DENG_HEADERS \ - include/ui/dialogs/networksettingsdialog.h + $$DENG_HEADERS # Platform-specific sources. win32 { @@ -686,7 +687,9 @@ SOURCES += \ src/ui/dialogs/aboutdialog.cpp \ src/ui/dialogs/audiosettingsdialog.cpp \ src/ui/dialogs/coloradjustmentdialog.cpp \ + src/ui/dialogs/inputsettingsdialog.cpp \ src/ui/dialogs/messagedialog.cpp \ + src/ui/dialogs/networksettingsdialog.cpp \ src/ui/dialogs/videosettingsdialog.cpp \ src/ui/fi_main.cpp \ src/ui/finaleinterpreter.cpp \ @@ -787,8 +790,7 @@ SOURCES += \ src/world/surface.cpp \ src/world/thinkers.cpp \ src/world/vertex.cpp \ - src/world/world.cpp \ - src/ui/dialogs/networksettingsdialog.cpp + src/world/world.cpp !deng_nosdlmixer:!deng_nosdl { HEADERS += include/audio/sys_audiod_sdlmixer.h diff --git a/doomsday/client/include/ui/dialogs/inputsettingsdialog.h b/doomsday/client/include/ui/dialogs/inputsettingsdialog.h new file mode 100644 index 0000000000..18e7f56532 --- /dev/null +++ b/doomsday/client/include/ui/dialogs/inputsettingsdialog.h @@ -0,0 +1,45 @@ +/** @file inputsettingsdialog.h Dialog for input settings. + * + * @authors Copyright (c) 2013 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_INPUTSETTINGSDIALOG_H +#define DENG_CLIENT_INPUTSETTINGSDIALOG_H + +#include "ui/widgets/dialogwidget.h" + +/** + * Dialog for modifying input settings. + */ +class InputSettingsDialog : public DialogWidget +{ + Q_OBJECT + +public: + InputSettingsDialog(de::String const &name = "inputsettings"); + +public slots: + void resetToDefaults(); + +protected slots: + void mouseTogglesChanged(); + void mouseSensitivityChanged(double value); + +private: + DENG2_PRIVATE(d) +}; + +#endif // DENG_CLIENT_INPUTSETTINGSDIALOG_H diff --git a/doomsday/client/include/ui/framework/gridlayout.h b/doomsday/client/include/ui/framework/gridlayout.h index 4164651e6c..66b06ccb47 100644 --- a/doomsday/client/include/ui/framework/gridlayout.h +++ b/doomsday/client/include/ui/framework/gridlayout.h @@ -58,7 +58,7 @@ class GridLayout GridLayout &operator << (GuiWidget &widget) { return append(widget); } GridLayout &operator << (de::Rule const &empty) { return append(empty); } - GridLayout &append(GuiWidget &widget); + GridLayout &append(GuiWidget &widget, int cellSpan = 1); GridLayout &append(de::Rule const &empty); /** diff --git a/doomsday/client/include/ui/widgets/cvarsliderwidget.h b/doomsday/client/include/ui/widgets/cvarsliderwidget.h index 61f6bf06fd..8c20c5d234 100644 --- a/doomsday/client/include/ui/widgets/cvarsliderwidget.h +++ b/doomsday/client/include/ui/widgets/cvarsliderwidget.h @@ -33,8 +33,6 @@ class CVarSliderWidget : public SliderWidget public slots: void updateFromCVar(); - -protected slots: void setCVarValueFromWidget(); private: diff --git a/doomsday/client/include/ui/widgets/sliderwidget.h b/doomsday/client/include/ui/widgets/sliderwidget.h index a8b9562201..fea56321f0 100644 --- a/doomsday/client/include/ui/widgets/sliderwidget.h +++ b/doomsday/client/include/ui/widgets/sliderwidget.h @@ -37,11 +37,21 @@ class SliderWidget : public GuiWidget void setRange(de::Rangei const &intRange, int step = 0); void setRange(de::Rangef const &floatRange, float step = 0); + void setRange(de::Ranged const &doubleRange, de::ddouble step = 0); void setPrecision(int precisionDecimals); - void setValue(float value); + void setValue(de::ddouble value); - de::Rangef range() const; - float value() const; + /** + * Displayed values are multiplied by this factor when displayed. + * Does not affect the real value of the slider. + * + * @param factor Display multiplier. + */ + void setDisplayFactor(de::ddouble factor); + + de::Ranged range() const; + de::ddouble value() const; + de::ddouble displayFactor() const; // Events. void viewResized(); @@ -53,8 +63,8 @@ public slots: void setValueFromText(QString text); signals: - void valueChanged(float value); - void valueChangedByUser(float value); + void valueChanged(double value); + void valueChangedByUser(double value); protected: void glInit(); diff --git a/doomsday/client/include/ui/widgets/taskbarwidget.h b/doomsday/client/include/ui/widgets/taskbarwidget.h index 0cf745d8d8..d1e11500d0 100644 --- a/doomsday/client/include/ui/widgets/taskbarwidget.h +++ b/doomsday/client/include/ui/widgets/taskbarwidget.h @@ -61,6 +61,7 @@ public slots: void showUpdaterSettings(); void showVideoSettings(); void showAudioSettings(); + void showInputSettings(); void showNetworkSettings(); signals: diff --git a/doomsday/client/modules/appconfig.de b/doomsday/client/modules/appconfig.de index 01ee99719d..c2c788a7f8 100644 --- a/doomsday/client/modules/appconfig.de +++ b/doomsday/client/modules/appconfig.de @@ -29,6 +29,11 @@ def setDefaults(d) # Applies the client's defaults. # - d: Record where to set the values. + # Input defaults. + record d.input + record d.input.mouse + d.input.mouse.syncSensitivity = True + try import DisplayMode diff --git a/doomsday/client/src/ui/dialogs/inputsettingsdialog.cpp b/doomsday/client/src/ui/dialogs/inputsettingsdialog.cpp new file mode 100644 index 0000000000..7d1b8510da --- /dev/null +++ b/doomsday/client/src/ui/dialogs/inputsettingsdialog.cpp @@ -0,0 +1,185 @@ +/** @file inputettingsdialog.cpp Dialog for input settings. + * + * @authors Copyright (c) 2013 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 + */ + +#include "ui/dialogs/inputsettingsdialog.h" +#include "ui/widgets/cvarsliderwidget.h" +#include "ui/widgets/cvartogglewidget.h" +#include "ui/widgets/variabletogglewidget.h" + +#include "con_main.h" +#include "SignalAction" +#include + +using namespace de; +using namespace ui; + +DENG_GUI_PIMPL(InputSettingsDialog) +{ + VariableToggleWidget *syncMouse; + CVarSliderWidget *mouseSensiX; + CVarSliderWidget *mouseSensiY; + ToggleWidget *mouseDisableX; + ToggleWidget *mouseDisableY; + ToggleWidget *mouseInvertX; + ToggleWidget *mouseInvertY; + CVarToggleWidget *joyEnable; + + Instance(Public *i) : Base(i) + { + ScrollAreaWidget &area = self.area(); + + area.add(syncMouse = new VariableToggleWidget(App::config()["input.mouse.syncSensitivity"])); + area.add(mouseSensiX = new CVarSliderWidget("input-mouse-x-scale")); + area.add(mouseSensiY = new CVarSliderWidget("input-mouse-y-scale")); + area.add(mouseDisableX = new ToggleWidget); + area.add(mouseDisableY = new ToggleWidget); + area.add(mouseInvertX = new ToggleWidget); + area.add(mouseInvertY = new ToggleWidget); + area.add(joyEnable = new CVarToggleWidget("input-joy")); + } + + void fetch() + { + mouseSensiX->updateFromCVar(); + mouseSensiY->updateFromCVar(); + joyEnable->updateFromCVar(); + + mouseDisableX->setActive(Con_GetInteger("input-mouse-x-flags") & IDA_DISABLED); + mouseDisableY->setActive(Con_GetInteger("input-mouse-y-flags") & IDA_DISABLED); + mouseInvertX->setActive(Con_GetInteger("input-mouse-x-flags") & IDA_INVERT); + mouseInvertY->setActive(Con_GetInteger("input-mouse-y-flags") & IDA_INVERT); + + enableOrDisable(); + } + + void enableOrDisable() + { + mouseSensiX->disable(mouseDisableX->isActive()); + mouseSensiY->disable(mouseDisableY->isActive()); + mouseInvertX->disable(mouseDisableX->isActive()); + mouseInvertY->disable(mouseDisableY->isActive()); + } + + void updateMouseFlags() + { + Con_SetInteger("input-mouse-x-flags", + (mouseDisableX->isActive()? IDA_DISABLED : 0) | + (mouseInvertX->isActive()? IDA_INVERT : 0)); + + Con_SetInteger("input-mouse-y-flags", + (mouseDisableY->isActive()? IDA_DISABLED : 0) | + (mouseInvertY->isActive()? IDA_INVERT : 0)); + + enableOrDisable(); + } +}; + +InputSettingsDialog::InputSettingsDialog(String const &name) + : DialogWidget(name, WithHeading), d(new Instance(this)) +{ + heading().setText(tr("Input Settings")); + + d->syncMouse->setText(tr("Uniform Mouse Axis Sensitivity")); + + LabelWidget *mouseXLabel = new LabelWidget; + mouseXLabel->setText(_E(b) + tr("Mouse X")); + area().add(mouseXLabel); + + LabelWidget *mouseYLabel = new LabelWidget; + mouseYLabel->setText(_E(b) + tr("Mouse Y")); + area().add(mouseYLabel); + + mouseXLabel->margins().setTop(style().rules().rule("gap")); + mouseYLabel->margins().setTop(style().rules().rule("gap")); + + // The sensitivity cvars are unlimited. + d->mouseSensiX->setRange(Rangef(.00005f, .0075f)); + d->mouseSensiX->setDisplayFactor(1000); + d->mouseSensiY->setRange(Rangef(.00005f, .0075f)); + d->mouseSensiY->setDisplayFactor(1000); + + connect(d->mouseSensiX, SIGNAL(valueChangedByUser(double)), this, SLOT(mouseSensitivityChanged(double))); + connect(d->mouseSensiY, SIGNAL(valueChangedByUser(double)), this, SLOT(mouseSensitivityChanged(double))); + + d->mouseInvertX->setText(tr("Invert Axis")); + d->mouseDisableX->setText(tr("Disable Axis")); + + d->mouseInvertY->setText(tr("Invert Axis")); + d->mouseDisableY->setText(tr("Disable Axis")); + + connect(d->mouseInvertX, SIGNAL(stateChangedByUser(ToggleWidget::ToggleState)), this, SLOT(mouseTogglesChanged())); + connect(d->mouseInvertY, SIGNAL(stateChangedByUser(ToggleWidget::ToggleState)), this, SLOT(mouseTogglesChanged())); + connect(d->mouseDisableX, SIGNAL(stateChangedByUser(ToggleWidget::ToggleState)), this, SLOT(mouseTogglesChanged())); + connect(d->mouseDisableY, SIGNAL(stateChangedByUser(ToggleWidget::ToggleState)), this, SLOT(mouseTogglesChanged())); + + d->joyEnable->setText(tr("Joystick Enabled")); + + // Layout. + GridLayout layout(area().contentRule().left(), area().contentRule().top()); + layout.setGridSize(2, 0); + //layout.setColumnAlignment(0, ui::AlignRight); + layout.append(*d->joyEnable, 2) + .append(*d->syncMouse, 2); + layout << *mouseXLabel << *mouseYLabel + << *d->mouseSensiX << *d->mouseSensiY + << *d->mouseInvertX << *d->mouseInvertY + << *d->mouseDisableX << *d->mouseDisableY; + + area().setContentSize(layout.width(), layout.height()); + + buttons().items() + << new DialogButtonItem(DialogWidget::Default | DialogWidget::Accept, tr("Close")) + << new DialogButtonItem(DialogWidget::Action, tr("Reset to Defaults"), + new SignalAction(this, SLOT(resetToDefaults()))); + + d->fetch(); +} + +void InputSettingsDialog::resetToDefaults() +{ + Con_SetFloat ("input-mouse-x-scale", .001f); + Con_SetFloat ("input-mouse-y-scale", .001f); + Con_SetInteger("input-mouse-x-flags", 0 ); + Con_SetInteger("input-mouse-y-flags", 0 ); + Con_SetInteger("input-joy", 1 ); + + d->fetch(); +} + +void InputSettingsDialog::mouseTogglesChanged() +{ + d->updateMouseFlags(); +} + +void InputSettingsDialog::mouseSensitivityChanged(double value) +{ + // Keep mouse axes synced? + if(d->syncMouse->isActive()) + { + if(sender() == d->mouseSensiX) + { + d->mouseSensiY->setValue(value); + d->mouseSensiY->setCVarValueFromWidget(); + } + else + { + d->mouseSensiX->setValue(value); + d->mouseSensiX->setCVarValueFromWidget(); + } + } +} diff --git a/doomsday/client/src/ui/framework/gridlayout.cpp b/doomsday/client/src/ui/framework/gridlayout.cpp index 451d2748f7..8791845adc 100644 --- a/doomsday/client/src/ui/framework/gridlayout.cpp +++ b/doomsday/client/src/ui/framework/gridlayout.cpp @@ -251,21 +251,21 @@ DENG2_PIMPL(GridLayout) /** * Ends the current column or row, if it is full. */ - void end() + void end(int cellSpan) { DENG2_ASSERT(current != 0); // Advance to next cell. if(mode == ColumnFirst) { - ++cell.x; + cell.x += cellSpan; - if(maxCols > 0 && cell.x == maxCols) + if(maxCols > 0 && cell.x >= maxCols) { cell.x = 0; cell.y++; sumInto(baseY, current->height()); - if(rowPad) sumInto(baseY, *rowPad); + if(rowPad) sumInto(baseY, *rowPad * cellSpan); // This one is finished. delete current; current = 0; @@ -273,14 +273,14 @@ DENG2_PIMPL(GridLayout) } else { - ++cell.y; + cell.y += cellSpan; - if(maxRows > 0 && cell.y == maxRows) + if(maxRows > 0 && cell.y >= maxRows) { cell.y = 0; cell.x++; sumInto(baseX, current->width()); - if(colPad) sumInto(baseX, *colPad); + if(colPad) sumInto(baseX, *colPad * cellSpan); // This one is finished. delete current; current = 0; @@ -294,7 +294,7 @@ DENG2_PIMPL(GridLayout) * @param widget Widget. * @param space Empty cell. */ - void append(GuiWidget *widget, Rule const *space) + void append(GuiWidget *widget, Rule const *space, int cellSpan = 1) { DENG2_ASSERT(!(widget && space)); DENG2_ASSERT(widget || space); @@ -325,12 +325,12 @@ DENG2_PIMPL(GridLayout) // Update the column and row maximum width/height. if(mode == ColumnFirst) { - updateMaximum(cols, cell.x, widget? widget->rule().width() : *space); + if(cellSpan == 1) updateMaximum(cols, cell.x, widget? widget->rule().width() : *space); if(widget) updateMaximum(rows, cell.y, widget->rule().height()); } else { - updateMaximum(rows, cell.y, widget? widget->rule().height() : *space); + if(cellSpan == 1) updateMaximum(rows, cell.y, widget? widget->rule().height() : *space); if(widget) updateMaximum(cols, cell.x, widget->rule().width()); } @@ -357,7 +357,7 @@ DENG2_PIMPL(GridLayout) } } - end(); + end(cellSpan); needTotalUpdate = true; } @@ -484,9 +484,9 @@ void GridLayout::setRowPadding(Rule const &gap) changeRef(d->rowPad, gap); } -GridLayout &GridLayout::append(GuiWidget &widget) +GridLayout &GridLayout::append(GuiWidget &widget, int cellSpan) { - d->append(&widget, 0); + d->append(&widget, 0, cellSpan); return *this; } diff --git a/doomsday/client/src/ui/ui_panel.cpp b/doomsday/client/src/ui/ui_panel.cpp index 1cf3364ae7..51a8d26db4 100644 --- a/doomsday/client/src/ui/ui_panel.cpp +++ b/doomsday/client/src/ui/ui_panel.cpp @@ -38,7 +38,7 @@ // MACROS ------------------------------------------------------------------ -#define NUM_CP_BUTTONS 7 +#define NUM_CP_BUTTONS 6 #define NUMITEMS(x) (sizeof(x)/sizeof(uidata_listitem_t)) //#define RES(x, y) ((x) | ((y) << 16)) #define CPID_FRAME (UIF_ID0 | UIF_ID1) @@ -103,13 +103,13 @@ cvarbutton_t cvarbuttons[] = { //{0, "con-dump"}, //{0, "con-fps"}, //{0, "con-text-shadow"}, - {0, "ui-panel-help"}, - {0, "ui-panel-tips"}, - {0, "input-mouse-filter"}, - {0, "input-joy"}, - {0, "net-nosleep"}, - {0, "net-dev"}, - {0, "net-queue-show"}, +// {0, "ui-panel-help"}, +// {0, "ui-panel-tips"}, +// {0, "input-mouse-filter"}, +// {0, "input-joy"}, +// {0, "net-nosleep"}, +// {0, "net-dev"}, +// {0, "net-queue-show"}, //{0, "sound-16bit"}, //{0, "sound-3d"}, //{0, "sound-info"}, @@ -142,10 +142,10 @@ cvarbutton_t cvarbuttons[] = { {0, "rend-info-tris"}, {0, "rend-shadow"}, {0, "rend-fakeradio"}, - {0, "input-mouse-x-flags", "Invert", "Invert", IDA_INVERT }, - {0, "input-mouse-x-flags", "Disable", "Disable", IDA_DISABLED }, - {0, "input-mouse-y-flags", "Invert", "Invert", IDA_INVERT }, - {0, "input-mouse-y-flags", "Disable", "Disable", IDA_DISABLED }, +// {0, "input-mouse-x-flags", "Invert", "Invert", IDA_INVERT }, +// {0, "input-mouse-x-flags", "Disable", "Disable", IDA_DISABLED }, +// {0, "input-mouse-y-flags", "Invert", "Invert", IDA_INVERT }, +// {0, "input-mouse-y-flags", "Disable", "Disable", IDA_DISABLED }, {0, 0} }; @@ -267,11 +267,11 @@ uidata_list_t lst_resolution = { //uidata_slider_t sld_keywait1 = { 50, 1000, 0, 1, false, (void*) "input-key-delay1" }; //uidata_slider_t sld_keywait2 = { 20, 1000, 0, 1, false, (void*) "input-key-delay2" }; +#if 0 uidata_slider_t sld_mouse_x_scale = { 0, .01f, 0, .00005f, true, (void*) "input-mouse-x-scale" }; uidata_slider_t sld_mouse_y_scale = { 0, .01f, 0, .00005f, true, (void*) "input-mouse-y-scale" }; uidata_slider_t sld_client_pos_interval = { 0, 70, 0, 1, false, (void*) "client-pos-interval" }; -#if 0 uidata_slider_t sld_server_frame_interval = { 0, 35, 0, 1, false, (void*) "server-frame-interval" }; uidata_slider_t sld_sound_volume = { 0, 255, 0, 1, false, (void*) "sound-volume" }; @@ -364,13 +364,13 @@ ui_object_t ob_panel[] = { // { UI_BUTTON2, 1, UIF_LEFT_ALIGN, 10, 210, 240, 60, "Video", UIButton_Drawer, UIButton_Responder, 0, CP_ChooseGroup, &panel_buttons[0] }, // { UI_BUTTON2, 1, UIF_LEFT_ALIGN, 10, 210, 240, 60, "Audio", UIButton_Drawer, UIButton_Responder, 0, CP_ChooseGroup, &panel_buttons[0] }, - { UI_BUTTON2, 1, UIF_LEFT_ALIGN, 10, 210, 240, 60, "Input", UIButton_Drawer, UIButton_Responder, 0, CP_ChooseGroup, &panel_buttons[0] }, - { UI_BUTTON2, 1, UIF_LEFT_ALIGN, 10, 275, 240, 60, "Graphics", UIButton_Drawer, UIButton_Responder, 0, CP_ChooseGroup, &panel_buttons[1] }, - { UI_BUTTON2, 1, UIF_LEFT_ALIGN, 40, 340, 210, 60, "Lights", UIButton_Drawer, UIButton_Responder, 0, CP_ChooseGroup, &panel_buttons[2] }, - { UI_BUTTON2, 1, UIF_LEFT_ALIGN, 40, 405, 210, 60, "Halos", UIButton_Drawer, UIButton_Responder, 0, CP_ChooseGroup, &panel_buttons[3] }, - { UI_BUTTON2, 1, UIF_LEFT_ALIGN, 40, 467, 210, 60, "Textures", UIButton_Drawer, UIButton_Responder, 0, CP_ChooseGroup, &panel_buttons[4] }, - { UI_BUTTON2, 1, UIF_LEFT_ALIGN, 40, 529, 210, 60, "Objects", UIButton_Drawer, UIButton_Responder, 0, CP_ChooseGroup, &panel_buttons[5] }, - { UI_BUTTON2, 1, UIF_LEFT_ALIGN, 40, 591, 210, 60, "Particles", UIButton_Drawer, UIButton_Responder, 0, CP_ChooseGroup, &panel_buttons[6] }, +// { UI_BUTTON2, 1, UIF_LEFT_ALIGN, 10, 210, 240, 60, "Input", UIButton_Drawer, UIButton_Responder, 0, CP_ChooseGroup, &panel_buttons[0] }, + { UI_BUTTON2, 1, UIF_LEFT_ALIGN, 10, 210, 240, 60, "Graphics", UIButton_Drawer, UIButton_Responder, 0, CP_ChooseGroup, &panel_buttons[0] }, + { UI_BUTTON2, 1, UIF_LEFT_ALIGN, 40, 275, 210, 60, "Lights", UIButton_Drawer, UIButton_Responder, 0, CP_ChooseGroup, &panel_buttons[1] }, + { UI_BUTTON2, 1, UIF_LEFT_ALIGN, 40, 340, 210, 60, "Halos", UIButton_Drawer, UIButton_Responder, 0, CP_ChooseGroup, &panel_buttons[2] }, + { UI_BUTTON2, 1, UIF_LEFT_ALIGN, 40, 405, 210, 60, "Textures", UIButton_Drawer, UIButton_Responder, 0, CP_ChooseGroup, &panel_buttons[3] }, + { UI_BUTTON2, 1, UIF_LEFT_ALIGN, 40, 467, 210, 60, "Objects", UIButton_Drawer, UIButton_Responder, 0, CP_ChooseGroup, &panel_buttons[4] }, + { UI_BUTTON2, 1, UIF_LEFT_ALIGN, 40, 529, 210, 60, "Particles", UIButton_Drawer, UIButton_Responder, 0, CP_ChooseGroup, &panel_buttons[5] }, // { UI_BUTTON2, 1, UIF_LEFT_ALIGN, 10, 653, 240, 60, "Network", UIButton_Drawer, UIButton_Responder, 0, CP_ChooseGroup, &panel_buttons[7] }, // { UI_BUTTON2, 1, UIF_LEFT_ALIGN, 10, 715, 240, 60, "Console", UIButton_Drawer, UIButton_Responder, 0, CP_ChooseGroup, &panel_buttons[8] }, { UI_BUTTON, 0, UIF_NEVER_FADE, 10, 940, 240, 60, "Close Panel (Esc)", UIButton_Drawer, UIButton_Responder, 0, CP_ClosePanel }, @@ -427,6 +427,7 @@ ui_object_t ob_panel[] = { UI_BUTTON2, 0, 0, 680, 680, 70, 55, "sound-info", UIButton_Drawer, UIButton_Responder, 0, CP_CvarButton }, #endif +#if 0 { UI_META, 2 }, { UI_TEXT, 0, 0, 280, 0, 0, 50, "Input Options", UIText_BrightDrawer }, { UI_TEXT, 0, 0, 300, 70, 0, 55, "Mouse X sensitivity", UIText_Drawer }, @@ -442,16 +443,11 @@ ui_object_t ob_panel[] = { UI_META, 2, 0, 0, 60 }, { UI_TEXT, 0, 0, 300, 250, 0, 55, "Enable joystick", UIText_Drawer }, { UI_BUTTON2, 0, 0, 680, 250, 70, 55, "input-joy", UIButton_Drawer, UIButton_Responder, 0, CP_CvarButton }, -#if 0 - { UI_TEXT, 0, 0, 300, 430, 0, 55, "Key repeat delay (ms)", UIText_Drawer }, - { UI_SLIDER, 0, 0, 680, 430, 300, 55, "", UISlider_Drawer, UISlider_Responder, UISlider_Ticker, CP_CvarSlider, &sld_keywait1 }, - { UI_TEXT, 0, 0, 300, 490, 0, 55, "Key repeat rate (ms)", UIText_Drawer }, - { UI_SLIDER, 0, 0, 680, 490, 300, 55, "", UISlider_Drawer, UISlider_Responder, UISlider_Ticker, CP_CvarSlider, &sld_keywait2 }, #endif - { UI_META, 3 }, + { UI_META, 2 }, { UI_TEXT, 0, 0, 280, 0, 0, 50, "Graphics Options", UIText_BrightDrawer }, - { UI_META, 3, 0, 0, -60 }, + { UI_META, 2, 0, 0, -60 }, { UI_TEXT, 0, UIF_FADE_AWAY, 300, 130, 0, 55, "Field Of View angle", UIText_Drawer }, { UI_SLIDER, 0, UIF_FADE_AWAY, 680, 130, 300, 55, "", UISlider_Drawer, UISlider_Responder, UISlider_Ticker, CP_CvarSlider, &sld_fov }, { UI_BUTTON, 0, UIF_FADE_AWAY, 680, 190, 70, 60, "95", UIButton_Drawer, UIButton_Responder, 0, CP_QuickFOV }, @@ -460,7 +456,7 @@ ui_object_t ob_panel[] = { UI_BUTTON, 0, UIF_FADE_AWAY, 905, 190, 70, 60, "125", UIButton_Drawer, UIButton_Responder, 0, CP_QuickFOV }, { UI_TEXT, 0, 0, 300, 255, 0, 55, "Mirror player weapon models", UIText_Drawer }, { UI_BUTTON2, 0, 0, 680, 255, 70, 55, "rend-model-mirror-hud", UIButton_Drawer, UIButton_Responder, 0, CP_CvarButton }, - { UI_META, 3, 0, 0, 60 }, + { UI_META, 2, 0, 0, 60 }, { UI_TEXT, 0, UIF_FADE_AWAY, 300, 255, 0, 55, "Sky sphere radius", UIText_Drawer }, { UI_SLIDER, 0, UIF_FADE_AWAY, 680, 255, 300, 55, "", UISlider_Drawer, UISlider_Responder, UISlider_Ticker, CP_CvarSlider, &sld_sky_distance }, { UI_TEXT, 0, 0, 300, 315, 0, 55, "Objects cast shadows", UIText_Drawer }, @@ -476,7 +472,7 @@ ui_object_t ob_panel[] = { UI_TEXT, 0, UIF_FADE_AWAY, 300, 615, 0, 55, "Radiosity shadow darkness", UIText_Drawer }, { UI_SLIDER, 0, UIF_FADE_AWAY, 680, 615, 300, 55, "", UISlider_Drawer, UISlider_Responder, UISlider_Ticker, CP_CvarSlider, &sld_fakeradio_dark }, - { UI_META, 4 }, + { UI_META, 3 }, { UI_TEXT, 0, 0, 280, 0, 0, 50, "Graphics Options: Lights", UIText_BrightDrawer }, { UI_TEXT, 0, 0, 300, 70, 0, 55, "Enable dynamic lights", UIText_Drawer }, { UI_BUTTON2, 0, 0, 680, 70, 70, 55, "rend-light", UIButton_Drawer, UIButton_Responder, 0, CP_CvarButton }, @@ -490,7 +486,7 @@ ui_object_t ob_panel[] = { UI_SLIDER, 0, UIF_FADE_AWAY, 680, 370, 300, 55, "", UISlider_Drawer, UISlider_Responder, UISlider_Ticker, CP_CvarSlider, &sld_light_radmax }, { UI_TEXT, 0, UIF_FADE_AWAY, 300, 430, 0, 55, "Maximum number of dynamic lights", UIText_Drawer }, { UI_SLIDER, 0, UIF_FADE_AWAY, 680, 430, 300, 55, "", UISlider_Drawer, UISlider_Responder, UISlider_Ticker, CP_CvarSlider, &sld_light_max }, - { UI_META, 4, 0, 0, -120 }, + { UI_META, 3, 0, 0, -120 }, { UI_TEXT, 0, UIF_FADE_AWAY, 300, 610, 0, 55, "Ambient light level", UIText_Drawer }, { UI_SLIDER, 0, UIF_FADE_AWAY, 680, 610, 300, 55, "", UISlider_Drawer, UISlider_Responder, UISlider_Ticker, CP_CvarSlider, &sld_light_ambient }, { UI_TEXT, 0, UIF_FADE_AWAY, 300, 670, 0, 55, "Light range compression", UIText_Drawer }, @@ -508,13 +504,13 @@ ui_object_t ob_panel[] = { UI_TEXT, 0, 0, 300, 1030, 0, 55, "Enable decorations", UIText_Drawer }, { UI_BUTTON2, 0, 0, 680, 1030, 70, 55, "rend-light-decor", UIButton_Drawer, UIButton_Responder, 0, CP_CvarButton }, - { UI_META, 5 }, + { UI_META, 4 }, { UI_TEXT, 0, 0, 280, 0, 0, 50, "Graphics Options: Halos", UIText_BrightDrawer }, { UI_TEXT, 0, UIF_FADE_AWAY, 300, 70, 0, 55, "Number of flares per halo", UIText_Drawer }, { UI_SLIDER, 0, UIF_FADE_AWAY, 680, 70, 300, 55, "", UISlider_Drawer, UISlider_Responder, UISlider_Ticker, CP_CvarSlider, &sld_halo }, { UI_TEXT, 0, UIF_FADE_AWAY, 300, 130, 0, 55, "Use realistic halos", UIText_Drawer }, { UI_BUTTON2, 0, UIF_FADE_AWAY, 680, 130, 70, 55, "rend-halo-realistic", UIButton_Drawer, UIButton_Responder, 0, CP_CvarButton }, - { UI_META, 5, 0, 0, 60 }, + { UI_META, 4, 0, 0, 60 }, { UI_TEXT, 0, UIF_FADE_AWAY, 300, 130, 0, 55, "Halo brightness", UIText_Drawer }, { UI_SLIDER, 0, UIF_FADE_AWAY, 680, 130, 300, 55, "", UISlider_Drawer, UISlider_Responder, UISlider_Ticker, CP_CvarSlider, &sld_halo_bright }, { UI_TEXT, 0, UIF_FADE_AWAY, 300, 190, 0, 55, "Halo size factor", UIText_Drawer }, @@ -532,7 +528,7 @@ ui_object_t ob_panel[] = { UI_TEXT, 0, UIF_FADE_AWAY, 300, 550, 0, 55, "Z magnification divisor", UIText_Drawer }, { UI_SLIDER, 0, UIF_FADE_AWAY, 680, 550, 300, 55, "", UISlider_Drawer, UISlider_Responder, UISlider_Ticker, CP_CvarSlider, &sld_halo_zmagdiv }, - { UI_META, 6 }, + { UI_META, 5 }, { UI_TEXT, 0, 0, 280, 0, 0, 50, "Graphics Options: Textures", UIText_BrightDrawer }, { UI_TEXT, 0, 0, 300, 70, 0, 55, "Enable textures", UIText_Drawer }, { UI_BUTTON2, 0, 0, 680, 70, 70, 55, "rend-tex", UIButton_Drawer, UIButton_Responder, 0, CP_CvarButton }, @@ -542,14 +538,14 @@ ui_object_t ob_panel[] = { UI_BUTTON2, 0, 0, 880, 130, 95, 55, "rend-model-shiny-multitex", UIButton_Drawer, UIButton_Responder, 0, CP_CvarButton }, { UI_TEXT, 0, 0, 300, 190, 0, 55, "Smooth texture animation", UIText_Drawer }, { UI_BUTTON2, 0, 0, 680, 190, 70, 55, "rend-tex-anim-smooth", UIButton_Drawer, UIButton_Responder, 0, CP_CvarButton }, - { UI_META, 6, 0, 0, 120 }, + { UI_META, 5, 0, 0, 120 }, { UI_TEXT, 0, 0, 300, 130, 0, 55, "Mipmapping filter", UIText_Drawer }, { UI_LIST, 0, 0, 680, 130, 300, 175, "", UIList_Drawer, UIList_Responder, UIList_Ticker, CP_CvarList, &lst_mipmap }, { UI_TEXT, 0, 0, 300, 310, 0, 55, "Texture quality", UIText_Drawer }, { UI_SLIDER, 0, 0, 680, 310, 300, 55, "", UISlider_Drawer, UISlider_Responder, UISlider_Ticker, CP_CvarSlider, &sld_tex_quality }, { UI_TEXT, 0, 0, 300, 370, 0, 55, "Smart texture filtering", UIText_Drawer }, { UI_BUTTON2, 0, 0, 680, 370, 70, 55, "rend-tex-filter-smart", UIButton_Drawer, UIButton_Responder, 0, CP_CvarButton }, - { UI_META, 6, 0, 0, 180 }, + { UI_META, 5, 0, 0, 180 }, { UI_TEXT, 0, 0, 300, 370, 0, 55, "Bilinear filtering", UIText_Drawer }, { UI_BUTTON2, 0, 0, 680, 370, 95, 55, "rend-tex-filter-sprite", UIButton_Drawer, UIButton_Responder, 0, CP_CvarButton }, { UI_BUTTON2, 0, 0, 780, 370, 95, 55, "rend-tex-filter-mag", UIButton_Drawer, UIButton_Responder, 0, CP_CvarButton }, @@ -563,7 +559,7 @@ ui_object_t ob_panel[] = { UI_TEXT, 0, UIF_FADE_AWAY, 300, 610, 0, 55, "Detail texture contrast", UIText_Drawer }, { UI_SLIDER, 0, UIF_FADE_AWAY, 680, 610, 300, 55, "", UISlider_Drawer, UISlider_Responder, UISlider_Ticker, CP_CvarSlider, &sld_detail_strength }, - { UI_META, 7 }, + { UI_META, 6 }, { UI_TEXT, 0, 0, 280, 0, 0, 50, "Graphics Options: Objects", UIText_BrightDrawer }, { UI_TEXT, 0, 0, 300, 70, 0, 55, "Enable 3D models", UIText_Drawer }, { UI_BUTTON2, 0, 0, 680, 70, 70, 55, "rend-model", UIButton_Drawer, UIButton_Responder, 0, CP_CvarButton }, @@ -592,7 +588,7 @@ ui_object_t ob_panel[] = { UI_TEXT, 0, 0, 300, 850, 0, 55, "Smooth actor movement", UIText_Drawer }, { UI_LIST, 0, 0, 680, 850, 300, 115, "", UIList_Drawer, UIList_Responder, UIList_Ticker, CP_CvarList, &lst_smooth_move }, - { UI_META, 8 }, + { UI_META, 7 }, { UI_TEXT, 0, 0, 280, 0, 0, 50, "Graphics Options: Particles", UIText_BrightDrawer }, { UI_TEXT, 0, 0, 300, 70, 0, 55, "Enable particle effects", UIText_Drawer }, { UI_BUTTON2, 0, 0, 680, 70, 70, 55, "rend-particle", UIButton_Drawer, UIButton_Responder, 0, CP_CvarButton }, diff --git a/doomsday/client/src/ui/widgets/cvarsliderwidget.cpp b/doomsday/client/src/ui/widgets/cvarsliderwidget.cpp index 7e9ddadd21..1403b9deae 100644 --- a/doomsday/client/src/ui/widgets/cvarsliderwidget.cpp +++ b/doomsday/client/src/ui/widgets/cvarsliderwidget.cpp @@ -39,7 +39,7 @@ CVarSliderWidget::CVarSliderWidget(char const *cvarPath) : d(new Instance) d->cvar = cvarPath; updateFromCVar(); - connect(this, SIGNAL(valueChangedByUser(float)), this, SLOT(setCVarValueFromWidget())); + connect(this, SIGNAL(valueChangedByUser(double)), this, SLOT(setCVarValueFromWidget())); } void CVarSliderWidget::updateFromCVar() @@ -50,7 +50,10 @@ void CVarSliderWidget::updateFromCVar() cvar_t *var = d->var(); if(var->type == CVT_FLOAT) { - setRange(Rangef(var->min, var->max), step); + if(!(var->flags & (CVF_NO_MIN | CVF_NO_MAX))) + { + setRange(Rangef(var->min, var->max), step); + } setValue(CVar_Float(var)); setPrecision(2); } diff --git a/doomsday/client/src/ui/widgets/sliderwidget.cpp b/doomsday/client/src/ui/widgets/sliderwidget.cpp index 06324637bc..49ad652d68 100644 --- a/doomsday/client/src/ui/widgets/sliderwidget.cpp +++ b/doomsday/client/src/ui/widgets/sliderwidget.cpp @@ -23,6 +23,7 @@ #include #include +#include using namespace de; using namespace ui; @@ -42,7 +43,7 @@ class ValuePopup : public PopupWidget connect(_edit, SIGNAL(enterPressed(QString)), this, SLOT(close())); _edit->rule().setInput(Rule::Width, slider.style().rules().rule("slider.editor")); - _edit->setText(QString::number(slider.value(), 'g', 4)); + _edit->setText(QString::number(slider.value() * slider.displayFactor(), 'g', 4)); } LineEditWidget &editor() const @@ -67,10 +68,11 @@ class ValuePopup : public PopupWidget DENG_GUI_PIMPL(SliderWidget) { - float value; - Rangef range; - float step; + ddouble value; + Ranged range; + ddouble step; int precision; + ddouble displayFactor; enum State { Inert, @@ -79,7 +81,7 @@ DENG_GUI_PIMPL(SliderWidget) }; State state; Vector2i grabFrom; - float grabValue; + ddouble grabValue; // Visualization. bool animating; @@ -105,6 +107,7 @@ DENG_GUI_PIMPL(SliderWidget) range(0, 0), step(0), precision(0), + displayFactor(1), state(Inert), animating(false), uMvpMatrix("uMvpMatrix", GLUniform::Mat4), @@ -171,7 +174,7 @@ DENG_GUI_PIMPL(SliderWidget) Rectanglei sliderValueRect() const { Rectanglei const area = sliderRect(); - float i = range.size() > 0? (pos - range.start) / range.size() : 0; + ddouble i = range.size() > 0? (pos - range.start) / range.size() : 0; return Rectanglei::fromSize(Vector2i(area.topLeft.x + (area.width() - endLabelSize) * i, area.topLeft.y), @@ -339,15 +342,15 @@ DENG_GUI_PIMPL(SliderWidget) void updateValueLabel() { - labels[Value].setText(QString::number(value, 'f', precision)); + labels[Value].setText(QString::number(value * displayFactor, 'f', precision)); } - void setValue(float v) + void setValue(ddouble v) { // Round to nearest step. if(step > 0) { - v = de::roundf((v - range.start) / step) * step; + v = de::round((v - range.start) / step) * step; } v = range.clamp(v); @@ -359,7 +362,7 @@ DENG_GUI_PIMPL(SliderWidget) updateValueLabel(); animating = true; - pos.setValue(value, 0.1); + pos.setValue(float(value), 0.1); self.requestGeometry(); emit self.valueChanged(v); @@ -368,8 +371,8 @@ DENG_GUI_PIMPL(SliderWidget) void updateRangeLabels() { - labels[Start].setText(QString::number(range.start)); - labels[End].setText(QString::number(range.end)); + labels[Start].setText(QString::number(range.start * displayFactor)); + labels[End].setText(QString::number(range.end * displayFactor)); } void startGrab(MouseEvent const &ev) @@ -389,12 +392,22 @@ DENG_GUI_PIMPL(SliderWidget) //qDebug() << "delta" << (ev.pos() - grabFrom).asText(); Rectanglei const area = sliderRect(); - float unitsPerPixel = range.size() / (area.width() - endLabelSize); + ddouble unitsPerPixel = range.size() / (area.width() - endLabelSize); setValue(grabValue + (ev.pos().x - grabFrom.x) * unitsPerPixel); emit self.valueChangedByUser(value); } + /// Amount to step when clicking a label. + ddouble clickStep() const + { + if(step > 0) + { + return step; + } + return 1.0 / std::pow(10.0, precision) / displayFactor; + } + void endGrab(MouseEvent const &ev) { if(state == Grabbed) @@ -402,20 +415,25 @@ DENG_GUI_PIMPL(SliderWidget) setState(Inert); updateHover(ev.pos()); } - else if(step > 0) + else { Rectanglei const rect = contentRect(); + qDebug() << "click step:" << clickStep() << "value:" << value << "range:" + << range.asText() << "new value:" << value - clickStep(); + // Maybe a click on the start/end label? if(rect.contains(ev.pos())) { if(ev.pos().x < rect.left() + endLabelSize) { - setValue(value - step); + setValue(value - clickStep()); + emit self.valueChangedByUser(value); } else if(ev.pos().x > rect.right() - endLabelSize) { - setValue(value + step); + setValue(value + clickStep()); + emit self.valueChangedByUser(value); } } } @@ -439,17 +457,17 @@ SliderWidget::SliderWidget(String const &name) void SliderWidget::setRange(Rangei const &intRange, int step) { - d->range = Rangef(intRange.start, intRange.end); - d->step = step; - - d->updateRangeLabels(); - d->setValue(d->value); - d->pos.finish(); + setRange(Ranged(intRange.start, intRange.end), ddouble(step)); } void SliderWidget::setRange(Rangef const &floatRange, float step) { - d->range = floatRange; + setRange(Ranged(floatRange.start, floatRange.end), ddouble(step)); +} + +void SliderWidget::setRange(Ranged const &doubleRange, ddouble step) +{ + d->range = doubleRange; d->step = step; d->updateRangeLabels(); @@ -463,21 +481,33 @@ void SliderWidget::setPrecision(int precisionDecimals) d->updateValueLabel(); } -void SliderWidget::setValue(float value) +void SliderWidget::setValue(ddouble value) { d->setValue(value); } -Rangef SliderWidget::range() const +void SliderWidget::setDisplayFactor(ddouble factor) +{ + d->displayFactor = factor; + d->updateRangeLabels(); + d->updateValueLabel(); +} + +Ranged SliderWidget::range() const { return d->range; } -float SliderWidget::value() const +ddouble SliderWidget::value() const { return d->value; } +ddouble SliderWidget::displayFactor() const +{ + return d->displayFactor; +} + void SliderWidget::viewResized() { GuiWidget::viewResized(); @@ -567,7 +597,7 @@ bool SliderWidget::handleEvent(Event const &event) void SliderWidget::setValueFromText(QString text) { - setValue(text.toDouble()); + setValue(text.toDouble() / d->displayFactor); emit valueChangedByUser(d->value); } diff --git a/doomsday/client/src/ui/widgets/taskbarwidget.cpp b/doomsday/client/src/ui/widgets/taskbarwidget.cpp index c298dabe76..908ba9fac5 100644 --- a/doomsday/client/src/ui/widgets/taskbarwidget.cpp +++ b/doomsday/client/src/ui/widgets/taskbarwidget.cpp @@ -25,6 +25,7 @@ #include "ui/dialogs/aboutdialog.h" #include "ui/dialogs/videosettingsdialog.h" #include "ui/dialogs/audiosettingsdialog.h" +#include "ui/dialogs/inputsettingsdialog.h" #include "ui/dialogs/networksettingsdialog.h" #include "GuiRootWidget" #include "CommandAction" @@ -54,8 +55,9 @@ static uint POS_UNLOAD = 1; static uint POS_GAME_SEPARATOR = 2; static uint POS_VIDEO_SETTINGS = 3; static uint POS_AUDIO_SETTINGS = 4; -static uint POS_NETWORK_SETTINGS = 5; -static uint POS_UPDATER_SETTINGS = 6; +static uint POS_INPUT_SETTINGS = 5; +static uint POS_NETWORK_SETTINGS = 6; +static uint POS_UPDATER_SETTINGS = 7; DENG_GUI_PIMPL(TaskBarWidget), public IGameChangeObserver @@ -170,6 +172,8 @@ public IGameChangeObserver itemWidget(item)->hitRule(), ui::Left); + // Mutual, automatic closing. + connect(dlg, SIGNAL(accepted(int)), mainMenu, SLOT(close())); connect(mainMenu, SIGNAL(closed()), dlg, SLOT(close())); } } @@ -273,6 +277,8 @@ TaskBarWidget::TaskBarWidget() : GuiWidget("taskbar"), d(new Instance(this)) new SignalAction(this, SLOT(showVideoSettings()))) << new ui::ActionItem(ui::Item::ShownAsButton, tr("Audio Settings"), new SignalAction(this, SLOT(showAudioSettings()))) + << new ui::ActionItem(ui::Item::ShownAsButton, tr("Input Settings"), + new SignalAction(this, SLOT(showInputSettings()))) << new ui::ActionItem(ui::Item::ShownAsButton, tr("Network Settings"), new SignalAction(this, SLOT(showNetworkSettings()))) << new ui::ActionItem(ui::Item::ShownAsButton, tr("Updater Settings"), @@ -532,6 +538,14 @@ void TaskBarWidget::showAudioSettings() dlg->open(); } +void TaskBarWidget::showInputSettings() +{ + InputSettingsDialog *dlg = new InputSettingsDialog; + d->setupItemSubDialog(POS_INPUT_SETTINGS, dlg); + root().add(dlg); + dlg->open(); +} + void TaskBarWidget::showNetworkSettings() { NetworkSettingsDialog *dlg = new NetworkSettingsDialog;