From 99394c997116dd4001b9aee6a71d6408e9d174e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Kera=CC=88nen?= Date: Sun, 23 Sep 2018 22:15:24 +0300 Subject: [PATCH] Menu|All Games: Multiple improvements to menu behavior and appearance --- doomsday/apps/client/src/render/rend_font.cpp | 5 +- .../apps/plugins/common/include/menu/page.h | 5 + .../common/include/menu/widgets/listwidget.h | 4 + .../common/include/menu/widgets/widget.h | 12 +- doomsday/apps/plugins/common/src/hu_menu.cpp | 591 +++++++++++------- .../apps/plugins/common/src/menu/page.cpp | 237 ++++--- .../common/src/menu/widgets/buttonwidget.cpp | 28 +- .../src/menu/widgets/coloreditwidget.cpp | 13 +- .../menu/widgets/cvartextualsliderwidget.cpp | 2 +- .../src/menu/widgets/inlinelistwidget.cpp | 6 +- .../src/menu/widgets/inputbindingwidget.cpp | 2 +- .../common/src/menu/widgets/labelwidget.cpp | 26 +- .../src/menu/widgets/lineeditwidget.cpp | 16 +- .../common/src/menu/widgets/listwidget.cpp | 90 ++- .../common/src/menu/widgets/sliderwidget.cpp | 6 +- .../common/src/menu/widgets/widget.cpp | 41 +- doomsday/apps/plugins/doom/src/d_main.cpp | 2 +- doomsday/apps/plugins/doom64/src/d_main.cpp | 2 +- 18 files changed, 707 insertions(+), 381 deletions(-) diff --git a/doomsday/apps/client/src/render/rend_font.cpp b/doomsday/apps/client/src/render/rend_font.cpp index d9b197a38b..30deeac787 100644 --- a/doomsday/apps/client/src/render/rend_font.cpp +++ b/doomsday/apps/client/src/render/rend_font.cpp @@ -700,7 +700,10 @@ static void textFragmentDrawer(const char* fragment, int x, int y, int alignFlag { // The character itself. DGL_Color4fv(sat->rgba); - drawChar(c, cx, cy + yoff, font, ALIGN_TOPLEFT, DTF_NO_EFFECTS); + if (sat->rgba[CA] > 0.001f) + { + drawChar(c, cx, cy + yoff, font, ALIGN_TOPLEFT, DTF_NO_EFFECTS); + } } if (!noGlitter && glitter > 0) diff --git a/doomsday/apps/plugins/common/include/menu/page.h b/doomsday/apps/plugins/common/include/menu/page.h index f90312538f..f6fe567160 100644 --- a/doomsday/apps/plugins/common/include/menu/page.h +++ b/doomsday/apps/plugins/common/include/menu/page.h @@ -99,9 +99,14 @@ class Page void setOrigin(de::Vector2i const &newOrigin); de::Vector2i origin() const; + Flags flags() const; + de::Rectanglei viewRegion() const; + void setX(int x); void setY(int y); + void setLeftColumnWidth(float columnWidthPercentage = 0.6f); + void setPreviousPage(Page *newPreviousPage); Page *previousPage() const; diff --git a/doomsday/apps/plugins/common/include/menu/widgets/listwidget.h b/doomsday/apps/plugins/common/include/menu/widgets/listwidget.h index aa59faeed9..8395a02439 100644 --- a/doomsday/apps/plugins/common/include/menu/widgets/listwidget.h +++ b/doomsday/apps/plugins/common/include/menu/widgets/listwidget.h @@ -108,6 +108,10 @@ class ListWidget : public Widget */ bool selectItemByValue(int itemIndex, int flags = MNLIST_SIF_NO_ACTION); + bool reorder(int itemIndex, int indexOffset); + + ListWidget &setReorderingEnabled(bool reorderEnabled); + /// @return Index of the currently selected item else -1. int selection() const; diff --git a/doomsday/apps/plugins/common/include/menu/widgets/widget.h b/doomsday/apps/plugins/common/include/menu/widgets/widget.h index bd9d238421..20aabf18ff 100644 --- a/doomsday/apps/plugins/common/include/menu/widgets/widget.h +++ b/doomsday/apps/plugins/common/include/menu/widgets/widget.h @@ -58,6 +58,9 @@ class Widget PositionFixed = 0x100, ///< XY position is fixed and predefined; automatic layout does not apply. LayoutOffset = 0x200, ///< Predefined XY position is applied to the dynamic layout origin. + LeftColumn = 0x400, ///< Widget is laid out to the page's left column. + RightColumn = 0x800, ///< Widget is laid out to the page's right column. + /// @todo We need a new dynamic id mechanism. Id7 = 0x1000000, Id6 = 0x2000000, @@ -83,7 +86,7 @@ class Widget Activated, ///< Becomes "active". Closed, ///< Normally means changed-state to be discarded. FocusLost, ///< Loses selection "focus". - FocusGained ///< Gains selection "focus". + FocusGained, ///< Gains selection "focus". }; typedef void (*ActionCallback) (Widget &, Action); @@ -162,6 +165,9 @@ class Widget Widget &setFlags(Flags flagsToChange, de::FlagOp operation = de::SetFlags); Flags flags() const; + Widget &setLeft() { return setFlags(LeftColumn); } + Widget &setRight() { return setFlags(RightColumn); } + inline bool isActive() const { return flags() & Active; } inline bool isFocused() const { return flags() & Focused; } inline bool isHidden() const { return flags() & Hidden; } @@ -225,6 +231,10 @@ class Widget Widget &setUserValue2(QVariant const &newValue); QVariant const &userValue2() const; + float scrollingFadeout() const; + float scrollingFadeout(int yTop, int yBottom) const; + de::Vector4f selectionFlashColor(const de::Vector4f &noFlashColor) const; + private: DENG2_PRIVATE(d) }; diff --git a/doomsday/apps/plugins/common/src/hu_menu.cpp b/doomsday/apps/plugins/common/src/hu_menu.cpp index b792e3a78e..650dc83d04 100644 --- a/doomsday/apps/plugins/common/src/hu_menu.cpp +++ b/doomsday/apps/plugins/common/src/hu_menu.cpp @@ -653,7 +653,7 @@ void Hu_MenuInitPlayerSetupPage() Vector2i const origin(70, 54); #endif - Page *page = Hu_MenuAddPage(new Page("PlayerSetup", origin, 0, Hu_MenuDrawPlayerSetupPage)); + Page *page = Hu_MenuAddPage(new Page("PlayerSetup", origin, Page::NoScroll, Hu_MenuDrawPlayerSetupPage)); page->setOnActiveCallback(Hu_MenuActivatePlayerSetup); page->setPredefinedFont(MENU_FONT1, FID(GF_FONTA)); page->setPredefinedFont(MENU_FONT2, FID(GF_FONTB)); @@ -741,12 +741,16 @@ void Hu_MenuInitSaveOptionsPage() page->setPredefinedFont(MENU_FONT1, FID(GF_FONTA)); page->setPreviousPage(Hu_MenuPagePtr("Options")); - page->addWidget(new LabelWidget("Confirm quick load/save")); + page->addWidget(new LabelWidget("Confirm quick load/save")) + .setLeft(); page->addWidget(new CVarToggleWidget("game-save-confirm")) + .setRight() .setShortcut('q'); - page->addWidget(new LabelWidget("Confirm reborn load")); + page->addWidget(new LabelWidget("Confirm reborn load")) + .setLeft(); page->addWidget(new CVarToggleWidget("game-save-confirm-loadonreborn")) + .setRight() .setShortcut('r'); page->addWidget(new LabelWidget("Reborn preferences")) @@ -754,8 +758,10 @@ void Hu_MenuInitSaveOptionsPage() .setColor(MENU_COLOR2); page->addWidget(new LabelWidget("Load last save")) + .setLeft() .setGroup(1); page->addWidget(new CVarToggleWidget("game-save-last-loadonreborn")) + .setRight() .setGroup(1) .setShortcut('a'); } @@ -888,24 +894,26 @@ void Hu_MenuInitLoadGameAndSaveGamePages() void Hu_MenuInitOptionsPage() { #if __JHERETIC__ || __JHEXEN__ - Vector2i const origin(110, 63); + Vector2i const origin(110, 45); #else Vector2i const origin(110, 63); #endif - Page *page = Hu_MenuAddPage(new Page("Options", origin, 0, Hu_MenuDrawOptionsPage)); + Page *page = Hu_MenuAddPage(new Page("Options", origin, Page::NoScroll, Hu_MenuDrawOptionsPage)); page->setPredefinedFont(MENU_FONT1, FID(GF_FONTA)); page->setPreviousPage(Hu_MenuPagePtr("Main")); page->addWidget(new ButtonWidget("End Game")) .setShortcut('e') .setFont(MENU_FONT1) + .setGroup(1) .setAction(Widget::Deactivated, Hu_MenuSelectEndGame) .setAction(Widget::FocusGained, Hu_MenuDefaultFocusAction); page->addWidget(new ButtonWidget("Show Taskbar")) .setShortcut('t') .setFont(MENU_FONT1) + .setGroup(1) .setAction(Widget::Deactivated, Hu_MenuSelectControlPanelLink) .setAction(Widget::FocusGained, Hu_MenuDefaultFocusAction); @@ -986,164 +994,182 @@ void Hu_MenuInitGameplayOptionsPage() #endif Page *page = Hu_MenuAddPage(new Page("GameplayOptions", origin)); + page->setLeftColumnWidth(.75f); page->setTitle("Gameplay Options"); page->setPredefinedFont(MENU_FONT1, FID(GF_FONTA)); page->setPreviousPage(Hu_MenuPagePtr("Options")); - page->addWidget(new LabelWidget("Always Run")); - page->addWidget(new CVarToggleWidget("ctl-run")) + page->addWidget(new LabelWidget("Always Run")).setLeft(); + page->addWidget(new CVarToggleWidget("ctl-run")).setRight() .setShortcut('r'); - page->addWidget(new LabelWidget("Use LookSpring")); - page->addWidget(new CVarToggleWidget("ctl-look-spring")) + page->addWidget(new LabelWidget("Use LookSpring")).setLeft(); + page->addWidget(new CVarToggleWidget("ctl-look-spring")).setRight() .setShortcut('l'); - page->addWidget(new LabelWidget("Disable AutoAim")); - page->addWidget(new CVarToggleWidget("ctl-aim-noauto")) + page->addWidget(new LabelWidget("Disable AutoAim")).setLeft(); + page->addWidget(new CVarToggleWidget("ctl-aim-noauto")).setRight() .setShortcut('a'); #if __JDOOM__ || __JHERETIC__ || __JDOOM64__ - page->addWidget(new LabelWidget("Allow Jumping")); - page->addWidget(new CVarToggleWidget("player-jump")) + page->addWidget(new LabelWidget("Allow Jumping")).setLeft(); + page->addWidget(new CVarToggleWidget("player-jump")).setRight() .setShortcut('j'); #endif #if __JDOOM__ - page->addWidget(new LabelWidget("Fast Monsters")); - page->addWidget(new CVarToggleWidget("game-monsters-fast")) + page->addWidget(new LabelWidget("Fast Monsters")).setLeft(); + page->addWidget(new CVarToggleWidget("game-monsters-fast")).setRight() .setShortcut('f'); #endif #if __JDOOM64__ - page->addWidget(new LabelWidget("Weapon Recoil")); - page->addWidget(new CVarToggleWidget("player-weapon-recoil")); + page->addWidget(new LabelWidget("Weapon Recoil")).setLeft(); + page->addWidget(new CVarToggleWidget("player-weapon-recoil")).setRight(); #endif #if __JDOOM__ || __JHERETIC__ || __JDOOM64__ page->addWidget(new LabelWidget("Compatibility")) + .setLeft() .setGroup(1) .setColor(MENU_COLOR2); # if __JDOOM__ || __JDOOM64__ - page->addWidget(new LabelWidget("Any Boss Trigger 666")) + page->addWidget(new LabelWidget("Any Boss Trigger 666")).setLeft() .setGroup(1); - page->addWidget(new CVarToggleWidget("game-anybossdeath666")) + page->addWidget(new CVarToggleWidget("game-anybossdeath666")).setRight() .setGroup(1) .setShortcut('b'); # if !__JDOOM64__ page->addWidget(new LabelWidget("Av Resurrects Ghosts")) + .setLeft() .setGroup(1); page->addWidget(new CVarToggleWidget("game-raiseghosts")) + .setRight() .setGroup(1) .setShortcut('g'); # if __JDOOM__ page->addWidget(new LabelWidget("VileChase uses Av radius")) + .setLeft() .setGroup(1); page->addWidget(new CVarToggleWidget("game-vilechase-usevileradius")) + .setRight() .setGroup(1) .setShortcut('g'); # endif # endif // !__JDOOM64__ page->addWidget(new LabelWidget("PE Limited To 21 Lost Souls")) + .setLeft() .setGroup(1); page->addWidget(new CVarToggleWidget("game-maxskulls")) + .setRight() .setGroup(1) .setShortcut('p'); page->addWidget(new LabelWidget("LS Can Get Stuck Inside Walls")) + .setLeft() .setGroup(1); page->addWidget(new CVarToggleWidget("game-skullsinwalls")) + .setRight() .setGroup(1); # endif // __JDOOM__ || __JDOOM64__ page->addWidget(new LabelWidget("Monsters Fly Over Obstacles")) + .setLeft() .setGroup(1); - page->addWidget(new CVarToggleWidget("game-monsters-floatoverblocking")) + .setRight() .setGroup(1); - page->addWidget(new LabelWidget("Monsters Can Get Stuck In Doors")) + page->addWidget(new LabelWidget("Monsters Can Get Stuck\n In Doors")) + .setLeft() .setGroup(1); - page->addWidget(new CVarToggleWidget("game-monsters-stuckindoors")) + .setRight() .setGroup(1) .setShortcut('d'); - page->addWidget(new LabelWidget("Some Objects Never Hang Over Ledges")) + page->addWidget(new LabelWidget("Some Objects Never Hang\n Over Ledges")) + .setLeft() .setGroup(1); - page->addWidget(new CVarToggleWidget("game-objects-neverhangoverledges")) + .setRight() .setGroup(1) .setShortcut('h'); page->addWidget(new LabelWidget("Objects Fall Under Own Weight")) + .setLeft() .setGroup(1); - page->addWidget(new CVarToggleWidget("game-objects-falloff")) + .setRight() .setGroup(1) .setShortcut('f'); #if __JDOOM__ || __JDOOM64__ - page->addWidget(new LabelWidget("All Crushed Objects Become A Pile Of Gibs")) + page->addWidget(new LabelWidget("All Crushed Objects\n Become A Pile Of Gibs")) + .setLeft() .setGroup(1); - page->addWidget(new CVarToggleWidget("game-objects-gibcrushednonbleeders")) + .setRight() .setGroup(1) .setShortcut('g'); #endif page->addWidget(new LabelWidget("Corpses Slide Down Stairs")) + .setLeft() .setGroup(1); page->addWidget(new CVarToggleWidget("game-corpse-sliding")) + .setRight() .setGroup(1) .setShortcut('s'); - page->addWidget(new LabelWidget("Use Exactly Doom's Clipping Code")) + page->addWidget(new LabelWidget("Use Doom's Clipping\n Code Exactly")) + .setLeft() .setGroup(1); page->addWidget(new CVarToggleWidget("game-objects-clipping")) + .setRight() .setGroup(1) .setShortcut('c'); page->addWidget(new LabelWidget(" ^If Not NorthOnly WallRunning")) + .setLeft() .setGroup(1); - page->addWidget(new CVarToggleWidget("game-player-wallrun-northonly")) + .setRight() .setGroup(1) .setShortcut('w'); # if __JDOOM__ || __JDOOM64__ - page->addWidget(new LabelWidget("Zombie Players Can Exit Maps")) + page->addWidget(new LabelWidget("Zombie Players Can\n Exit Maps")).setLeft() .setGroup(1); - - page->addWidget(new CVarToggleWidget("game-zombiescanexit")) + page->addWidget(new CVarToggleWidget("game-zombiescanexit")).setRight() .setGroup(1) .setShortcut('e'); - page->addWidget(new LabelWidget("Fix Ouch Face")) + page->addWidget(new LabelWidget("Fix Ouch Face")).setLeft() .setGroup(1); - - page->addWidget(new CVarToggleWidget("hud-face-ouchfix")) + page->addWidget(new CVarToggleWidget("hud-face-ouchfix")).setRight() .setGroup(1); - page->addWidget(new LabelWidget("Fix Weapon Slot Display")) + page->addWidget(new LabelWidget("Fix Weapon Slot Display")).setLeft() .setGroup(1); - - page->addWidget(new CVarToggleWidget("hud-status-weaponslots-ownedfix")) + page->addWidget(new CVarToggleWidget("hud-status-weaponslots-ownedfix")).setRight() .setGroup(1); # endif // __JDOOM__ || __JDOOM64__ #endif // __JDOOM__ || __JHERETIC__ || __JDOOM64__ - page->addWidget(new LabelWidget("Vanilla Switch Sound Positioning")) + page->addWidget(new LabelWidget("Vanilla Switch Sound\n Positioning")) + .setLeft() .setGroup(1); - page->addWidget(new CVarToggleWidget("sound-switch-origin")) + .setRight() .setGroup(1) .setShortcut('v'); } @@ -1158,10 +1184,11 @@ void Hu_MenuInitHUDOptionsPage() Page *page = Hu_MenuAddPage(new Page("HudOptions", origin)); page->setTitle("HUD Options"); + page->setLeftColumnWidth(.45f); page->setPredefinedFont(MENU_FONT1, FID(GF_FONTA)); page->setPreviousPage(Hu_MenuPagePtr("Options")); - page->addWidget(new LabelWidget("View Size")); + page->addWidget(new LabelWidget("View Size")).setLeft(); page->addWidget(new CVarSliderWidget("view-size")) #if __JDOOM64__ @@ -1169,108 +1196,43 @@ void Hu_MenuInitHUDOptionsPage() #else .setRange(3, 13, 1) #endif - .setFloatMode(false); - -#if __JDOOM__ - page->addWidget(new LabelWidget("Single Key Display")); - page->addWidget(new CVarToggleWidget("hud-keys-combine")); -#endif - - page->addWidget(new LabelWidget("AutoHide")); - page->addWidget(new CVarTextualSliderWidget("hud-timer", 0, 60, 1)) - .setEmptyText("Disabled") - .setOnethSuffix(" second") - .setNthSuffix(" seconds"); - - page->addWidget(new LabelWidget("UnHide Events")) - .setGroup(1) - .setColor(MENU_COLOR2); - - page->addWidget(new LabelWidget("Receive Damage")) - .setGroup(1); - - page->addWidget(new CVarToggleWidget("hud-unhide-damage")) - .setGroup(1); - - page->addWidget(new LabelWidget("Pickup Health")) - .setGroup(1); - - page->addWidget(new CVarToggleWidget("hud-unhide-pickup-health")) - .setGroup(1); - - page->addWidget(new LabelWidget("Pickup Armor")) - .setGroup(1); - - page->addWidget(new CVarToggleWidget("hud-unhide-pickup-armor")) - .setGroup(1); - - page->addWidget(new LabelWidget("Pickup Powerup")) - .setGroup(1); - - page->addWidget(new CVarToggleWidget("hud-unhide-pickup-powerup")) - .setGroup(1); - - page->addWidget(new LabelWidget("Pickup Weapon")) - .setGroup(1); - - page->addWidget(new CVarToggleWidget("hud-unhide-pickup-weapon")) - .setGroup(1); - - page->addWidget(new LabelWidget) -#if __JHEXEN__ - .setText("Pickup Mana") -#else - .setText("Pickup Ammo") -#endif - .setGroup(1); - - page->addWidget(new CVarToggleWidget("hud-unhide-pickup-ammo")) - .setGroup(1); - - page->addWidget(new LabelWidget("Pickup Key")) - .setGroup(1); - - page->addWidget(new CVarToggleWidget("hud-unhide-pickup-key")) - .setGroup(1); - -#if __JHERETIC__ || __JHEXEN__ - page->addWidget(new LabelWidget("Pickup Item")) - .setGroup(1); - - page->addWidget(new CVarToggleWidget("hud-unhide-pickup-invitem")) - .setGroup(1); -#endif // __JHERETIC__ || __JHEXEN__ + .setFloatMode(false) + .setRight(); page->addWidget(new LabelWidget("Messages")) .setGroup(2) .setColor(MENU_COLOR2); page->addWidget(new LabelWidget("Shown")) + .setLeft() .setGroup(2); - page->addWidget(new CVarToggleWidget("msg-show")) + .setRight() .setGroup(2) .setShortcut('m'); page->addWidget(new LabelWidget("Uptime")) + .setLeft() .setGroup(2); - page->addWidget(new CVarTextualSliderWidget("msg-uptime", 0, 60, 1)) .setEmptyText("Disabled") .setOnethSuffix(" second") .setNthSuffix(" seconds") + .setRight() .setGroup(2); page->addWidget(new LabelWidget("Size")) + .setLeft() .setGroup(2); - page->addWidget(new CVarSliderWidget("msg-scale")) + .setRight() .setGroup(2); page->addWidget(new LabelWidget("Color")) + .setLeft() .setGroup(2); - page->addWidget(new CVarColorEditWidget("msg-color-r", "msg-color-g", "msg-color-b")) + .setRight() .setGroup(2) .setAction(Widget::Deactivated, CVarColorEditWidget_UpdateCVar) .setAction(Widget::Activated, Hu_MenuActivateColorWidget); @@ -1281,8 +1243,8 @@ void Hu_MenuInitHUDOptionsPage() page->addWidget(new LabelWidget("Symbol")) .setGroup(3) + .setLeft() .setShortcut('c'); - page->addWidget(new CVarInlineListWidget("view-cross-type")) .addItems(ListWidget::Items() << new ListWidgetItem("None", 0) << new ListWidgetItem("Cross", 1) @@ -1290,78 +1252,173 @@ void Hu_MenuInitHUDOptionsPage() << new ListWidgetItem("Square", 3) << new ListWidgetItem("Open Square", 4) << new ListWidgetItem("Angle", 5)) - .setGroup(3); + .setGroup(3) + .setRight(); page->addWidget(new LabelWidget("Size")) + .setLeft() .setGroup(3); - page->addWidget(new CVarSliderWidget("view-cross-size")) + .setRight() .setGroup(3); page->addWidget(new LabelWidget("Thickness")) + .setLeft() .setGroup(3); - - page->addWidget(new CVarSliderWidget("view-cross-weight")) + page->addWidget(new CVarSliderWidget("view-cross-width", .5f, 5, .25f)) + .setRight() .setGroup(3); page->addWidget(new LabelWidget("Angle")) + .setLeft() .setGroup(3); - page->addWidget(new CVarSliderWidget("view-cross-angle", 0.0f, 1.0f, 0.0625f)) + .setRight() .setGroup(3); page->addWidget(new LabelWidget("Opacity")) + .setLeft() .setGroup(3); - page->addWidget(new CVarSliderWidget("view-cross-a")) + .setRight() .setGroup(3); - page->addWidget(new LabelWidget("Vitality Color")) + page->addWidget(new LabelWidget("Color")) + .setLeft() .setGroup(3); + page->addWidget(new CVarColorEditWidget("view-cross-r", "view-cross-g", "view-cross-b")) + .setRight() + .setGroup(3) + .setAction(Widget::Deactivated, CVarColorEditWidget_UpdateCVar) + .setAction(Widget::Activated, Hu_MenuActivateColorWidget); + page->addWidget(new LabelWidget("Vitality Color")) + .setLeft() + .setGroup(3); page->addWidget(new CVarToggleWidget("view-cross-vitality")) + .setRight() .setGroup(3); - page->addWidget(new LabelWidget("Vitality Colour (Dead)")) + page->addWidget(new LabelWidget(" When Dead")) + .setLeft() .setGroup(3); - page->addWidget(new CVarColorEditWidget("view-cross-dead-r", "view-cross-dead-g", "view-cross-dead-b")) + .setRight() .setGroup(3) .setAction(Widget::Deactivated, CVarColorEditWidget_UpdateCVar) .setAction(Widget::Activated, Hu_MenuActivateColorWidget); - page->addWidget(new LabelWidget("Vitality Colour (Full Health)")) + page->addWidget(new LabelWidget(" Full Health")) + .setLeft() .setGroup(3); page->addWidget(new CVarColorEditWidget("view-cross-live-r", "view-cross-live-g", "view-cross-live-b")) + .setRight() .setGroup(3) .setAction(Widget::Deactivated, CVarColorEditWidget_UpdateCVar) .setAction(Widget::Activated, Hu_MenuActivateColorWidget); - page->addWidget(new LabelWidget("Color")) - .setGroup(3); - - page->addWidget(new CVarColorEditWidget("view-cross-r", "view-cross-g", "view-cross-b")) - .setGroup(3) - .setAction(Widget::Deactivated, CVarColorEditWidget_UpdateCVar) - .setAction(Widget::Activated, Hu_MenuActivateColorWidget); - #if __JDOOM__ || __JHERETIC__ || __JHEXEN__ page->addWidget(new LabelWidget("Statusbar")) .setGroup(4) .setColor(MENU_COLOR2); page->addWidget(new LabelWidget("Size")) + .setLeft() .setGroup(4); - page->addWidget(new CVarSliderWidget("hud-status-size")) + .setRight() .setGroup(4); page->addWidget(new LabelWidget("Opacity")) + .setLeft() .setGroup(4); - page->addWidget(new CVarSliderWidget("hud-status-alpha")) + .setRight() + .setGroup(4); + +#if __JDOOM__ + page->addWidget(new LabelWidget("Single Key Display")).setLeft(); + page->addWidget(new CVarToggleWidget("hud-keys-combine")).setRight(); +#endif + + page->addWidget(new LabelWidget("AutoHide Status")) + .setLeft() .setGroup(4); + page->addWidget(new CVarTextualSliderWidget("hud-timer", 0, 60, 1)) + .setEmptyText("Disabled") + .setOnethSuffix(" second") + .setNthSuffix(" seconds") + .setRight() + .setGroup(4); + + page->addWidget(new LabelWidget("Status UnHide Events")) + .setGroup(1) + .setColor(MENU_COLOR2); + + page->addWidget(new LabelWidget("Receive Damage")) + .setLeft() + .setGroup(1); + page->addWidget(new CVarToggleWidget("hud-unhide-damage")) + .setRight() + .setGroup(1); + + page->addWidget(new LabelWidget("Pickup Health")) + .setLeft() + .setGroup(1); + page->addWidget(new CVarToggleWidget("hud-unhide-pickup-health")) + .setRight() + .setGroup(1); + + page->addWidget(new LabelWidget("Pickup Armor")) + .setLeft() + .setGroup(1); + page->addWidget(new CVarToggleWidget("hud-unhide-pickup-armor")) + .setRight() + .setGroup(1); + + page->addWidget(new LabelWidget("Pickup Powerup")) + .setLeft() + .setGroup(1); + page->addWidget(new CVarToggleWidget("hud-unhide-pickup-powerup")) + .setRight() + .setGroup(1); + + page->addWidget(new LabelWidget("Pickup Weapon")) + .setLeft() + .setGroup(1); + page->addWidget(new CVarToggleWidget("hud-unhide-pickup-weapon")) + .setRight() + .setGroup(1); + + page->addWidget(new LabelWidget) +#if __JHEXEN__ + .setText("Pickup Mana") +#else + .setText("Pickup Ammo") +#endif + .setGroup(1) + .setLeft(); + page->addWidget(new CVarToggleWidget("hud-unhide-pickup-ammo")) + .setRight() + .setGroup(1); + + page->addWidget(new LabelWidget("Pickup Key")) + .setLeft() + .setGroup(1); + page->addWidget(new CVarToggleWidget("hud-unhide-pickup-key")) + .setRight() + .setGroup(1); + +#if __JHERETIC__ || __JHEXEN__ + page->addWidget(new LabelWidget("Pickup Item")) + .setLeft() + .setGroup(1); + + page->addWidget(new CVarToggleWidget("hud-unhide-pickup-invitem")) + .setRight() + .setGroup(1); +#endif // __JHERETIC__ || __JHEXEN__ #endif // __JDOOM__ || __JHERETIC__ || __JHEXEN__ @@ -1371,17 +1428,19 @@ void Hu_MenuInitHUDOptionsPage() .setColor(MENU_COLOR2); page->addWidget(new LabelWidget("Items")) + .setLeft() .setGroup(5); - page->addWidget(new CVarInlineListWidget("hud-cheat-counter", CCH_ITEMS | CCH_ITEMS_PRCNT)) .addItems(ListWidget::Items() << new ListWidgetItem("Hidden", 0) << new ListWidgetItem("Count", CCH_ITEMS) << new ListWidgetItem("Percent", CCH_ITEMS_PRCNT) << new ListWidgetItem("Count+Percent", CCH_ITEMS | CCH_ITEMS_PRCNT)) + .setRight() .setGroup(5) .setShortcut('i'); page->addWidget(new LabelWidget("Kills")) + .setLeft() .setGroup(5); page->addWidget(new CVarInlineListWidget("hud-cheat-counter", CCH_KILLS | CCH_KILLS_PRCNT)) @@ -1389,30 +1448,34 @@ void Hu_MenuInitHUDOptionsPage() << new ListWidgetItem("Count", CCH_KILLS) << new ListWidgetItem("Percent", CCH_KILLS_PRCNT) << new ListWidgetItem("Count+Percent", CCH_KILLS | CCH_KILLS_PRCNT)) + .setRight() .setGroup(5) .setShortcut('k'); page->addWidget(new LabelWidget("Secrets")) + .setLeft() .setGroup(5); - page->addWidget(new CVarInlineListWidget("hud-cheat-counter", CCH_SECRETS | CCH_SECRETS_PRCNT)) .addItems(ListWidget::Items() << new ListWidgetItem("Hidden", 0) << new ListWidgetItem("Count", CCH_SECRETS) << new ListWidgetItem("Percent", CCH_SECRETS_PRCNT) << new ListWidgetItem("Count+Percent", CCH_SECRETS | CCH_SECRETS_PRCNT)) .setGroup(5) + .setRight() .setShortcut('s'); page->addWidget(new LabelWidget("Automap Only")) + .setLeft() .setGroup(5); - page->addWidget(new CVarToggleWidget("hud-cheat-counter-show-mapopen")) + .setRight() .setGroup(5); page->addWidget(new LabelWidget("Size")) + .setLeft() .setGroup(5); - page->addWidget(new CVarSliderWidget("hud-cheat-counter-scale")) + .setRight() .setGroup(5); #endif // __JDOOM__ || __JDOOM64__ || __JHERETIC__ @@ -1422,15 +1485,17 @@ void Hu_MenuInitHUDOptionsPage() .setColor(MENU_COLOR2); page->addWidget(new LabelWidget("Size")) + .setLeft() .setGroup(6); - page->addWidget(new CVarSliderWidget("hud-scale")) + .setRight() .setGroup(6); page->addWidget(new LabelWidget("Text Color")) + .setLeft() .setGroup(6); - page->addWidget(new CVarColorEditWidget("hud-color-r", "hud-color-g", "hud-color-b", "hud-color-a", Vector4f(), true)) + .setRight() .setGroup(6) .setAction(Widget::Deactivated, CVarColorEditWidget_UpdateCVar) .setAction(Widget::Activated, Hu_MenuActivateColorWidget); @@ -1438,9 +1503,11 @@ void Hu_MenuInitHUDOptionsPage() #if __JHEXEN__ page->addWidget(new LabelWidget("Show Mana")) + .setLeft() .setGroup(6); page->addWidget(new CVarToggleWidget("hud-mana")) + .setRight() .setGroup(6); #endif // __JHEXEN__ @@ -1448,16 +1515,18 @@ void Hu_MenuInitHUDOptionsPage() #if __JDOOM__ || __JDOOM64__ || __JHERETIC__ page->addWidget(new LabelWidget("Show Ammo")) + .setLeft() .setGroup(6); - page->addWidget(new CVarToggleWidget("hud-ammo")) + .setRight() .setGroup(6) .setShortcut('a'); page->addWidget(new LabelWidget("Show Armor")) + .setLeft() .setGroup(6); - page->addWidget(new CVarToggleWidget("hud-armor")) + .setRight() .setGroup(6) .setShortcut('r'); @@ -1466,9 +1535,10 @@ void Hu_MenuInitHUDOptionsPage() #if __JDOOM64__ page->addWidget(new LabelWidget("Show PowerKeys")) + .setLeft() .setGroup(6); - page->addWidget(new CVarToggleWidget("hud-power")) + .setRight() .setGroup(6) .setShortcut('p'); @@ -1477,27 +1547,30 @@ void Hu_MenuInitHUDOptionsPage() #if __JDOOM__ page->addWidget(new LabelWidget("Show Status")) + .setLeft() .setGroup(6); - page->addWidget(new CVarToggleWidget("hud-face")) + .setRight() .setGroup(6) .setShortcut('f'); #endif // __JDOOM__ page->addWidget(new LabelWidget("Show Health")) + .setLeft() .setGroup(6); - page->addWidget(new CVarToggleWidget("hud-health")) + .setRight() .setGroup(6) .setShortcut('h'); #if __JDOOM__ || __JDOOM64__ || __JHERETIC__ page->addWidget(new LabelWidget("Show Keys")) + .setLeft() .setGroup(6); - page->addWidget(new CVarToggleWidget("hud-keys")) + .setRight() .setGroup(6); #endif // __JDOOM__ || __JDOOM64__ || __JHERETIC__ @@ -1505,9 +1578,10 @@ void Hu_MenuInitHUDOptionsPage() #if __JHERETIC__ || __JHEXEN__ page->addWidget(new LabelWidget("Show Ready-Item")) + .setLeft() .setGroup(6); - page->addWidget(new CVarToggleWidget("hud-currentitem")) + .setRight() .setGroup(6); #endif // __JHERETIC__ || __JHEXEN__ @@ -1516,19 +1590,22 @@ void Hu_MenuInitHUDOptionsPage() void Hu_MenuInitAutomapOptionsPage() { #if __JHERETIC__ || __JHEXEN__ - Vector2i const origin(64, 28); + const Vector2i origin(32, 28); #else - Vector2i const origin(70, 40); + const Vector2i origin(70, 40); #endif Page *page = Hu_MenuAddPage(new Page("AutomapOptions", origin)); + page->setLeftColumnWidth(.55f); page->setTitle("Automap Options"); page->setPredefinedFont(MENU_FONT1, FID(GF_FONTA)); page->setPreviousPage(Hu_MenuPagePtr("Options")); - page->addWidget(new LabelWidget("Rotate")); + page->addWidget(new LabelWidget("Rotation")) + .setLeft(); { auto *tgl = new CVarToggleWidget("map-rotate"); + tgl->setRight(); tgl->setShortcut('r'); tgl->setStateChangeCallback([](CVarToggleWidget::State state) { G_SetAutomapRotateMode(state == CVarToggleWidget::Down); @@ -1536,66 +1613,120 @@ void Hu_MenuInitAutomapOptionsPage() page->addWidget(tgl); } - page->addWidget(new LabelWidget("Background Opacity")); - page->addWidget(new CVarSliderWidget("map-opacity")) - .setShortcut('o'); - - page->addWidget(new LabelWidget("Line Opacity")); - page->addWidget(new CVarSliderWidget("map-line-opacity")) - .setShortcut('l'); - - page->addWidget(new LabelWidget("Line Width")); - page->addWidget(new CVarSliderWidget("map-line-width", 0.5f, 8.f)); - -#if !__JDOOM64__ - page->addWidget(new LabelWidget("HUD Display")); +#if !defined (__JDOOM64__) + page->addWidget(new LabelWidget("HUD Display")) + .setLeft(); page->addWidget(new CVarInlineListWidget("map-huddisplay")) .addItems(ListWidget::Items() << new ListWidgetItem("None", 0) << new ListWidgetItem("Current", 1) << new ListWidgetItem("Statusbar", 2)) + .setRight() .setShortcut('h'); #endif - page->addWidget(new LabelWidget("Door Colors")); + page->addWidget(new LabelWidget("Appearance")) + .setGroup(1) + .setColor(MENU_COLOR2); + + page->addWidget(new LabelWidget("Background Opacity")) + .setLeft() + .setGroup(1); + page->addWidget(new CVarSliderWidget("map-opacity")) + .setShortcut('o') + .setRight() + .setGroup(1); + + page->addWidget(new LabelWidget("Line Opacity")) + .setLeft() + .setGroup(1); + page->addWidget(new CVarSliderWidget("map-line-opacity")) + .setShortcut('l') + .setRight() + .setGroup(1); + + page->addWidget(new LabelWidget("Line Width")) + .setLeft() + .setGroup(1); + page->addWidget(new CVarSliderWidget("map-line-width", 0.5f, 8.f)) + .setRight() + .setGroup(1); + + page->addWidget(new LabelWidget("Colored Doors")) + .setLeft() + .setGroup(1); page->addWidget(new CVarToggleWidget("map-door-colors")) - .setShortcut('d'); + .setRight() + .setShortcut('d') + .setGroup(1); - page->addWidget(new LabelWidget("Door Glow")); + page->addWidget(new LabelWidget("Door Glow")) + .setLeft() + .setGroup(1); page->addWidget(new CVarSliderWidget("map-door-glow", 0, 200, 5)) - .setShortcut('g'); + .setRight() + .setShortcut('g') + .setGroup(1); - page->addWidget(new LabelWidget("Use Custom Colors")); + page->addWidget(new LabelWidget("Use Custom Colors")) + .setLeft() + .setGroup(2); page->addWidget(new CVarInlineListWidget("map-customcolors")) .addItems(ListWidget::Items() << new ListWidgetItem("Never", 0) << new ListWidgetItem("Auto", 1) - << new ListWidgetItem("Always", 2)); + << new ListWidgetItem("Always", 2)) + .setRight() + .setGroup(2); - page->addWidget(new LabelWidget("Wall")); + page->addWidget(new LabelWidget("Wall")) + .setLeft() + .setGroup(2); page->addWidget(new CVarColorEditWidget("map-wall-r", "map-wall-g", "map-wall-b")) + .setRight() .setShortcut('w') + .setGroup(2) .setAction(Widget::Activated, Hu_MenuActivateColorWidget); - page->addWidget(new LabelWidget("Floor Height Change")); + page->addWidget(new LabelWidget("Floor Height Change")) + .setLeft() + .setGroup(2); page->addWidget(new CVarColorEditWidget("map-wall-floorchange-r", "map-wall-floorchange-g", "map-wall-floorchange-b")) + .setRight() .setShortcut('f') + .setGroup(2) .setAction(Widget::Activated, Hu_MenuActivateColorWidget); - page->addWidget(new LabelWidget("Ceiling Height Change")); + page->addWidget(new LabelWidget("Ceiling Height Change")) + .setLeft() + .setGroup(2); page->addWidget(new CVarColorEditWidget("map-wall-ceilingchange-r", "map-wall-ceilingchange-g", "map-wall-ceilingchange-b")) + .setRight() + .setGroup(2) .setAction(Widget::Activated, Hu_MenuActivateColorWidget); - page->addWidget(new LabelWidget("Unseen")); + page->addWidget(new LabelWidget("Unseen")) + .setLeft() + .setGroup(2); page->addWidget(new CVarColorEditWidget("map-wall-unseen-r", "map-wall-unseen-g", "map-wall-unseen-b")) + .setRight() + .setGroup(2) .setShortcut('u') .setAction(Widget::Activated, Hu_MenuActivateColorWidget); - page->addWidget(new LabelWidget("Thing")); + page->addWidget(new LabelWidget("Thing")) + .setLeft() + .setGroup(2); page->addWidget(new CVarColorEditWidget("map-mobj-r", "map-mobj-g", "map-mobj-b")) + .setRight() + .setGroup(2) .setShortcut('t') .setAction(Widget::Activated, Hu_MenuActivateColorWidget); - page->addWidget(new LabelWidget("Background")); + page->addWidget(new LabelWidget("Background")) + .setLeft() + .setGroup(2); page->addWidget(new CVarColorEditWidget("map-background-r", "map-background-g", "map-background-b")) + .setRight() + .setGroup(2) .setShortcut('b') .setAction(Widget::Activated, Hu_MenuActivateColorWidget); } @@ -1605,11 +1736,11 @@ static bool compareWeaponPriority(ListWidgetItem const *a, ListWidgetItem const int i = 0, aIndex = -1, bIndex = -1; do { - if(cfg.common.weaponOrder[i] == a->userValue()) + if (cfg.common.weaponOrder[i] == a->userValue()) { aIndex = i; } - if(cfg.common.weaponOrder[i] == b->userValue()) + if (cfg.common.weaponOrder[i] == b->userValue()) { bIndex = i; } @@ -1665,6 +1796,7 @@ void Hu_MenuInitWeaponsPage() }; Page *page = Hu_MenuAddPage(new Page("WeaponOptions", origin)); + page->setLeftColumnWidth(.5f); page->setTitle("Weapons Options"); page->setPredefinedFont(MENU_FONT1, FID(GF_FONTA)); page->setPreviousPage(Hu_MenuPagePtr("Options")); @@ -1673,7 +1805,7 @@ void Hu_MenuInitWeaponsPage() .setColor(MENU_COLOR2); ListWidget::Items weapItems; - for(int i = 0; weaponOrder[i].data < NUM_WEAPON_TYPES; ++i) + for (int i = 0; weaponOrder[i].data < NUM_WEAPON_TYPES; ++i) { char const *itemText = weaponOrder[i].text; if(itemText && (PTR2INT(itemText) > 0 && PTR2INT(itemText) < NUMTEXT)) @@ -1685,6 +1817,7 @@ void Hu_MenuInitWeaponsPage() qSort(weapItems.begin(), weapItems.end(), compareWeaponPriority); page->addWidget(new ListWidget) .addItems(weapItems) + .setReorderingEnabled(true) .setHelpInfo("Use left/right to move weapon up/down") .setShortcut('p') .setColor(MENU_COLOR3) @@ -1696,16 +1829,18 @@ void Hu_MenuInitWeaponsPage() .setColor(MENU_COLOR2); page->addWidget(new LabelWidget("Use Priority Order")) + .setLeft() .setGroup(1); - page->addWidget(new CVarToggleWidget("player-weapon-nextmode")) + .setRight() .setGroup(1) .setShortcut('o'); page->addWidget(new LabelWidget("Sequential")) + .setLeft() .setGroup(1); - page->addWidget(new CVarToggleWidget("player-weapon-cycle-sequential")) + .setRight() .setGroup(1) .setShortcut('s'); @@ -1714,38 +1849,42 @@ void Hu_MenuInitWeaponsPage() .setColor(MENU_COLOR2); page->addWidget(new LabelWidget("Pickup Weapon")) + .setLeft() .setGroup(2); - page->addWidget(new CVarInlineListWidget("player-autoswitch")) .addItems(ListWidget::Items() << new ListWidgetItem("Never", 0) << new ListWidgetItem("If Better", 1) << new ListWidgetItem("Always", 2)) .setGroup(2) + .setRight() .setShortcut('w'); page->addWidget(new LabelWidget(" If Not Firing")) + .setLeft() .setGroup(2); - page->addWidget(new CVarToggleWidget("player-autoswitch-notfiring")) + .setRight() .setGroup(2) .setShortcut('f'); page->addWidget(new LabelWidget("Pickup Ammo")) + .setLeft() .setGroup(2); - page->addWidget(new CVarInlineListWidget("player-autoswitch-ammo")) .addItems(ListWidget::Items() << new ListWidgetItem("Never", 0) << new ListWidgetItem("If Better", 1) << new ListWidgetItem("Always", 2)) .setGroup(2) + .setRight() .setShortcut('a'); #if __JDOOM__ || __JDOOM64__ page->addWidget(new LabelWidget("Pickup Beserk")) + .setLeft() .setGroup(2); - page->addWidget(new CVarToggleWidget("player-autoswitch-berserk")) + .setRight() .setGroup(2) .setShortcut('b'); @@ -1756,50 +1895,65 @@ void Hu_MenuInitWeaponsPage() void Hu_MenuInitInventoryOptionsPage() { Page *page = Hu_MenuAddPage(new Page("InventoryOptions", Vector2i(78, 48))); + page->setLeftColumnWidth(.65f); page->setTitle("Inventory Options"); page->setPredefinedFont(MENU_FONT1, FID(GF_FONTA)); page->setPreviousPage(Hu_MenuPagePtr("Options")); - page->addWidget(new LabelWidget("Select Mode")); + page->addWidget(new LabelWidget("Select Mode")) + .setLeft(); page->addWidget(new CVarToggleWidget("ctl-inventory-mode", 0, "Scroll", "Cursor")) + .setRight() .setShortcut('s'); - page->addWidget(new LabelWidget("Wrap Around")); + page->addWidget(new LabelWidget("Wrap Around")) + .setLeft(); page->addWidget(new CVarToggleWidget("ctl-inventory-wrap")) + .setRight() .setShortcut('w'); - page->addWidget(new LabelWidget("Choose And Use")); + page->addWidget(new LabelWidget("Choose And Use")) + .setLeft(); page->addWidget(new CVarToggleWidget("ctl-inventory-use-immediate")) + .setRight() .setShortcut('c'); - page->addWidget(new LabelWidget("Select Next If Use Failed")); + page->addWidget(new LabelWidget("Select Next If Use Failed")) + .setLeft(); page->addWidget(new CVarToggleWidget("ctl-inventory-use-next")) + .setRight() .setShortcut('n'); - page->addWidget(new LabelWidget("AutoHide")); + page->addWidget(new LabelWidget("AutoHide")) + .setLeft(); page->addWidget(new CVarTextualSliderWidget("hud-inventory-timer", 0, 30, 1.f)) .setEmptyText("Disabled") .setOnethSuffix(" second") .setNthSuffix(" seconds") - .setShortcut('h'); + .setShortcut('h') + .setRight(); page->addWidget(new LabelWidget("Fullscreen HUD")) .setGroup(1) .setColor(MENU_COLOR2); page->addWidget(new LabelWidget("Max Visible Slots")) + .setLeft() .setGroup(1); page->addWidget(new CVarTextualSliderWidget("hud-inventory-slot-max", 0, 16, 1, false)) .setEmptyText("Automatic") + .setRight() .setGroup(1) .setShortcut('v'); page->addWidget(new LabelWidget("Show Empty Slots")) - .setGroup(1); + .setGroup(1) + .setLeft(); page->addWidget(new CVarToggleWidget("hud-inventory-slot-showempty")) .setGroup(1) + .setRight() .setShortcut('e'); } #endif @@ -1815,16 +1969,21 @@ void Hu_MenuInitSoundOptionsPage() #endif Page *page = Hu_MenuAddPage(new Page("SoundOptions", origin)); + page->setLeftColumnWidth(.4f); page->setTitle("Sound Options"); page->setPredefinedFont(MENU_FONT1, FID(GF_FONTA)); page->setPreviousPage(Hu_MenuPagePtr("Options")); - page->addWidget(new LabelWidget("SFX Volume")); - page->addWidget(new CVarSliderWidget("sound-volume", 0, 255, 5, false)) + page->addWidget(new LabelWidget("SFX Volume")) + .setLeft(); + page->addWidget(new CVarSliderWidget("sound-volume", 0, 255, 16, false)) + .setRight() .setShortcut('s'); - page->addWidget(new LabelWidget("Music Volume")); - page->addWidget(new CVarSliderWidget("music-volume", 0, 255, 5, false)) + page->addWidget(new LabelWidget("Music Volume")) + .setLeft(); + page->addWidget(new CVarSliderWidget("music-volume", 0, 255, 16, false)) + .setRight() .setShortcut('m'); } @@ -2122,7 +2281,7 @@ void Hu_MenuTicker(timespan_t ticLength) { cursor.angle += float( 5 * ticLength * TICRATE ); } - else if(cursor.angle != 0) + else if (!fequal(cursor.angle, 0)) { float rewind = float( MENU_CURSOR_REWIND_SPEED * ticLength * TICRATE ); if(cursor.angle <= rewind || cursor.angle >= 360 - rewind) @@ -2215,14 +2374,14 @@ short Hu_MenuMergeEffectWithDrawTextFlags(short f) return ((~cfg.common.menuEffectFlags & DTF_NO_EFFECTS) | (f & ~DTF_NO_EFFECTS)); } -void Hu_MenuDrawFocusCursor(Vector2i const &origin, int focusObjectHeight, float alpha) +void Hu_MenuDrawFocusCursor(Vector2i const &origin, int /*focusObjectHeight*/, float alpha) { #if __JDOOM__ || __JDOOM64__ # define OFFSET_X (-22) # define OFFSET_Y (-2) #elif __JHERETIC__ || __JHEXEN__ # define OFFSET_X (-16) -# define OFFSET_Y (3) +# define OFFSET_Y (1) #endif float const angle = cursor.angle; @@ -2233,9 +2392,9 @@ void Hu_MenuDrawFocusCursor(Vector2i const &origin, int focusObjectHeight, float if(!R_GetPatchInfo(pCursor, &info)) return; - float const scale = de::min((focusObjectHeight * 1.267f) / info.geometry.size.height, 1.f); + float const scale = /*de::min((focusObjectHeight * 1.267f) /*/ 1; //info.geometry.size.height; //, 1.f); Vector2i pos = origin + Vector2i(OFFSET_X, OFFSET_Y) * scale; - pos.y += focusObjectHeight / 2; +// pos.y -= info.geometry.size.height / 2; DGL_MatrixMode(DGL_MODELVIEW); DGL_PushMatrix(); @@ -2966,7 +3125,7 @@ void Hu_MenuSelectHelp(Widget & /*wi*/, Widget::Action action) void Hu_MenuDrawOptionsPage(Page const & /*page*/, Vector2i const &origin) { #if __JHERETIC__ || __JHEXEN__ - Hu_MenuDrawPageTitle("Options", Vector2i(origin.x + 42, origin.y - 38)); + Hu_MenuDrawPageTitle("Options", Vector2i(origin.x + 42, origin.y - 30)); #else DGL_Enable(DGL_TEXTURE_2D); DGL_Color4f(1, 1, 1, mnRendState->pageAlpha); @@ -3016,30 +3175,16 @@ void Hu_MenuUpdateColorWidgetColor(Widget &wi, Widget::Action action) } } -void Hu_MenuChangeWeaponPriority(Widget & /*wi*/, Widget::Action action) +void Hu_MenuChangeWeaponPriority(Widget &wi, Widget::Action action) { - if(action != Widget::Modified) return; - - /*int choice = option >> NUM_WEAPON_TYPES; - - if(option & RIGHT_DIR) + if (action == Widget::Modified) { - if(choice < NUM_WEAPON_TYPES-1) + auto &list = wi.as(); + for (int i = 0; i < list.itemCount(); ++i) { - int temp = cfg.common.weaponOrder[choice+1]; - cfg.common.weaponOrder[choice+1] = cfg.common.weaponOrder[choice]; - cfg.common.weaponOrder[choice] = temp; + cfg.common.weaponOrder[i] = list.itemData(i); } } - else - { - if(choice > 0) - { - int temp = cfg.common.weaponOrder[choice]; - cfg.common.weaponOrder[choice] = cfg.common.weaponOrder[choice-1]; - cfg.common.weaponOrder[choice-1] = temp; - } - }*/ } void Hu_MenuSelectSingleplayer(Widget & /*wi*/, Widget::Action action) diff --git a/doomsday/apps/plugins/common/src/menu/page.cpp b/doomsday/apps/plugins/common/src/menu/page.cpp index c712bd7aa1..aa7c0af8e1 100644 --- a/doomsday/apps/plugins/common/src/menu/page.cpp +++ b/doomsday/apps/plugins/common/src/menu/page.cpp @@ -36,6 +36,8 @@ #include "menu/widgets/labelwidget.h" #include "menu/widgets/mobjpreviewwidget.h" +#include + using namespace de; namespace common { @@ -47,20 +49,23 @@ mn_rendstate_t const *mnRendState = &rs; DENG2_PIMPL(Page) { - String name; ///< Symbolic name/identifier. + String name; ///< Symbolic name/identifier. Children children; - Vector2i origin; - Rectanglei geometry; ///< "Physical" geometry, in fixed 320x200 screen coordinate space. + Vector2i origin; + Rectanglei geometry; ///< "Physical" geometry, in fixed 320x200 screen coordinate space. + Animation scrollOrigin; + Rectanglei viewRegion; + int leftColumnWidth = SCREENWIDTH * 6 / 10; - String title; ///< Title of this page. - Page *previous = nullptr; ///< Previous page. - int focus = -1; ///< Index of the currently focused widget else @c -1 - Flags flags = DefaultFlags; - int timer = 0; + String title; ///< Title of this page. + Page * previous = nullptr; ///< Previous page. + int focus = -1; ///< Index of the currently focused widget else @c -1 + Flags flags = DefaultFlags; + int timer = 0; fontid_t fonts[MENU_FONT_COUNT]; ///< Predefined. Used by all widgets. - uint colors[MENU_COLOR_COUNT]; ///< Predefined. Used by all widgets. + uint colors[MENU_COLOR_COUNT]; ///< Predefined. Used by all widgets. OnActiveCallback onActiveCallback = nullptr; OnDrawCallback drawer = nullptr; @@ -103,18 +108,16 @@ DENG2_PIMPL(Page) */ int lineHeight(int *lineOffset = 0) { - fontid_t oldFont = FR_Font(); - - /// @kludge We cannot yet query line height from the font... + /// @todo Kludge: We cannot yet query line height from the font... + const fontid_t oldFont = FR_Font(); FR_SetFont(self().predefinedFont(MENU_FONT1)); int lh = FR_TextHeight("{case}WyQ"); - if(lineOffset) + if (lineOffset) { *lineOffset = de::max(1.f, .5f + lh * .34f); } // Restore the old font. FR_SetFont(oldFont); - return lh; } @@ -123,101 +126,106 @@ DENG2_PIMPL(Page) geometry.topLeft = Vector2i(0, 0); geometry.setSize(Vector2ui(0, 0)); - if(flags & FixedLayout) + if (children.empty()) return; + + if (flags & FixedLayout) { - for(Widget *wi : children) + for (Widget *wi : children) { - if(wi->isHidden()) continue; - - wi->geometry().moveTopLeft(wi->fixedOrigin()); - geometry |= wi->geometry(); + if (!wi->isHidden()) + { + wi->geometry().moveTopLeft(wi->fixedOrigin()); + geometry |= wi->geometry(); + } } return; } // This page uses a dynamic layout. - int lineOffset; - int const lh = lineHeight(&lineOffset); - - Vector2i origin; - - for(int i = 0; i < children.count(); ) + int lineOffset; + const int lh = lineHeight(&lineOffset); + int prevGroup = children.front()->group(); + Widget * prevWidget = nullptr; + int usedColumns = 0; // column flags for current row + Vector2i origin; + int rowHeight = 0; + + for (auto *wi : children) { - Widget *wi = children[i]; - Widget *nextWi = i + 1 < children.count()? children[i + 1] : 0; - - if(wi->isHidden()) + if (wi->isHidden()) { - // Proceed to the next widget. - i += 1; continue; } // If the widget has a fixed position, we will ignore it while doing // dynamic layout. - if(wi->flags() & Widget::PositionFixed) + if (wi->flags() & Widget::PositionFixed) { wi->geometry().moveTopLeft(wi->fixedOrigin()); geometry |= wi->geometry(); - - // Proceed to the next widget. - i += 1; continue; } + // Extra spacing between object groups. + if (wi->group() != prevGroup) + { + origin.y += lh; + prevGroup = wi->group(); + } + // An additional offset requested? - if(wi->flags() & Widget::LayoutOffset) + if (wi->flags() & Widget::LayoutOffset) { origin += wi->fixedOrigin(); } - wi->geometry().moveTopLeft(origin); + int widgetColumns = (wi->flags() & (Widget::LeftColumn | Widget::RightColumn)); + if (widgetColumns == 0) + { + // Use both columns if neither specified. + widgetColumns = Widget::LeftColumn | Widget::RightColumn; + } - // Orient label plus button/inline-list/textual-slider pairs about a - // vertical dividing line, with the label on the left, other widget - // on the right. - // @todo Do not assume pairing, a widget should designate it's label. - if(is(wi) && nextWi) + // If this column is already used, move to the next row. + if ((usedColumns & widgetColumns) != 0) { - if(!nextWi->isHidden() && - (is(nextWi) || - is(nextWi) || - is(nextWi) || - is(nextWi) || - is(nextWi))) - { - int const margin = lineOffset * 2; + origin.y += rowHeight; + usedColumns = 0; + rowHeight = 0; + } + usedColumns |= widgetColumns; - nextWi->geometry().moveTopLeft(Vector2i(margin + wi->geometry().width(), origin.y)); + wi->geometry().moveTopLeft(origin); + rowHeight = MAX_OF(rowHeight, wi->geometry().height() + lineOffset); - Rectanglei const united = wi->geometry() | nextWi->geometry(); - geometry |= united; - origin.y += united.height() + lineOffset; + if (wi->flags() & Widget::RightColumn) + { + // Move widget to the right side. + wi->geometry().move(Vector2i(leftColumnWidth, 0)); - // Extra spacing between object groups. - if(i + 2 < children.count() && nextWi->group() != children[i + 2]->group()) + if (prevWidget && prevWidget->flags() & Widget::LeftColumn) + { + // Align the shorter widget vertically. + if (prevWidget->geometry().height() < wi->geometry().height()) { - origin.y += lh; + prevWidget->geometry().move(Vector2i( + 0, (wi->geometry().height() - prevWidget->geometry().height()) / 2)); + } + else + { + wi->geometry().move(Vector2i( + 0, (prevWidget->geometry().height() - wi->geometry().height()) / 2)); } - - // Proceed to the next object! - i += 2; - continue; } } geometry |= wi->geometry(); - origin.y += wi->geometry().height() + lineOffset; - - // Extra spacing between object groups. - if(nextWi && nextWi->group() != wi->group()) - { - origin.y += lh; - } - // Proceed to the next object! - i += 1; + prevWidget = wi; } + + // Center horizontally. + this->origin.x = SCREENWIDTH / 2 - geometry.width() / 2; } /// @pre @a wi is a child of this page. @@ -331,6 +339,7 @@ DENG2_PIMPL(Page) } } +#if 0 /** * Determines the size of the menu cursor for a focused widget. If no widget is currently * focused the default cursor size (i.e., the effective line height for @c MENU_FONT1) @@ -340,6 +349,8 @@ DENG2_PIMPL(Page) */ int cursorSizeFor(Widget *focused, int lineHeight) { + return lineHeight; + /* int focusedHeight = focused? focused->geometry().height() : 0; // Ensure the cursor is at least as tall as the effective line height for @@ -348,7 +359,9 @@ DENG2_PIMPL(Page) /// @note Handling this correctly would mean separate physical/visual /// geometries for menu widgets. return de::max(focusedHeight, lineHeight); + */ } +#endif }; Page::Page(String name, Vector2i const &origin, Flags const &flags, @@ -489,31 +502,30 @@ void Page::draw(float alpha, bool showFocusCursor) } Vector2i cursorOrigin; - int focusedHeight = 0; - if(focused) + if (focused) { - focusedHeight = d->cursorSizeFor(focused, d->lineHeight()); - // Determine the origin and dimensions of the cursor. /// @todo Each object should define a focus origin... cursorOrigin.x = -1; - cursorOrigin.y = focused->geometry().topLeft.y; + cursorOrigin.y = focused->geometry().middle().y; + /* /// @kludge /// We cannot yet query the subobjects of the list for these values /// so we must calculate them ourselves, here. - if(ListWidget const *list = maybeAs(focused)) + if (ListWidget const *list = maybeAs(focused)) { - if(focused->isActive() && list->selectionIsVisible()) + if (focused->isActive() && list->selectionIsVisible()) { FR_PushAttrib(); FR_SetFont(predefinedFont(mn_page_fontid_t(focused->font()))); - focusedHeight = FR_CharHeight('A') * (1+MNDATA_LIST_LEADING); - cursorOrigin.y += (list->selection() - list->first()) * focusedHeight; + const int rowHeight = FR_CharHeight('A') * (1+MNDATA_LIST_LEADING); + //cursorOrigin.y += (list->selection() - list->first()) * rowHeight + rowHeight/2; FR_PopAttrib(); } } // kludge end + */ } DGL_MatrixMode(DGL_MODELVIEW); @@ -521,42 +533,43 @@ void Page::draw(float alpha, bool showFocusCursor) DGL_Translatef(d->origin.x, d->origin.y, 0); // Apply page scroll? - if(!(d->flags & NoScroll) && focused) + if (!(d->flags & NoScroll) && focused) { - Rectanglei viewRegion; - // Determine available screen region for the page. - viewRegion.topLeft = Vector2i(0, d->origin.y); - viewRegion.setSize(Vector2ui(SCREENWIDTH, SCREENHEIGHT - 40/*arbitrary but enough for the help message*/)); + d->viewRegion.topLeft = Vector2i(0, 0); //d->origin.y); + d->viewRegion.setSize(Vector2ui(SCREENWIDTH, SCREENHEIGHT - d->origin.y - 35 /*arbitrary but enough for the help message*/)); // Is scrolling in effect? - if(d->geometry.height() > viewRegion.height()) + if (d->geometry.height() > d->viewRegion.height()) { - int const minY = -viewRegion.topLeft.y / 2 + viewRegion.height() / 2; - if(cursorOrigin.y > minY) - { - int const scrollLimitY = d->geometry.height() - viewRegion.height() / 2; - int const scrollOriginY = de::min(cursorOrigin.y, scrollLimitY) - minY; - DGL_Translatef(0, -scrollOriginY, 0); - } + d->scrollOrigin.setValue( + de::min(de::max(0, int(cursorOrigin.y - d->viewRegion.height() / 2)), + int(d->geometry.height() - d->viewRegion.height())), .35); + + DGL_Translatef(0, -d->scrollOrigin, 0); } } + else + { + d->viewRegion = {{0, 0}, {SCREENWIDTH, SCREENHEIGHT}}; + } // Draw all child widgets that aren't hidden. - for(Widget *wi : d->children) + for (Widget *wi : d->children) { - if(wi->isHidden()) continue; - - FR_PushAttrib(); - wi->draw(); - FR_PopAttrib(); + if (!wi->isHidden()) + { + FR_PushAttrib(); + wi->draw(); + FR_PopAttrib(); + } } // How about a focus cursor? /// @todo cursor should be drawn on top of the page drawer. if(showFocusCursor && focused) { - Hu_MenuDrawFocusCursor(cursorOrigin, focusedHeight, alpha); + Hu_MenuDrawFocusCursor(cursorOrigin, 0, alpha); } DGL_MatrixMode(DGL_MODELVIEW); @@ -600,6 +613,20 @@ Vector2i Page::origin() const return d->origin; } +Page::Flags Page::flags() const +{ + return d->flags; +} + +Rectanglei Page::viewRegion() const +{ + if (d->flags & NoScroll) + { + return {{0, 0}, {SCREENWIDTH, SCREENHEIGHT}}; + } + return d->viewRegion.moved({0, int(d->scrollOrigin)}); +} + void Page::setX(int x) { d->origin.x = x; @@ -610,6 +637,11 @@ void Page::setY(int y) d->origin.y = y; } +void Page::setLeftColumnWidth(float columnWidthPercentage) +{ + d->leftColumnWidth = int(SCREENWIDTH * columnWidthPercentage); +} + void Page::setPreviousPage(Page *newPrevious) { d->previous = newPrevious; @@ -770,7 +802,7 @@ int Page::handleCommand(menucommand_e cmd) case MCMD_NAV_UP: case MCMD_NAV_DOWN: // Page navigation requires a focused widget. - if(Widget *focused = focusWidget()) + if (Widget *focused = focusWidget()) { int i = 0, giveFocus = indexOf(focused); do @@ -782,10 +814,11 @@ int Page::handleCommand(menucommand_e cmd) giveFocus = 0; } while(++i < d->children.count() && (d->children[giveFocus]->flags() & (Widget::Disabled | Widget::NoFocus | Widget::Hidden))); - if(giveFocus != indexOf(focusWidget())) + if (giveFocus != indexOf(focusWidget())) { S_LocalSound(cmd == MCMD_NAV_UP? SFX_MENU_NAV_UP : SFX_MENU_NAV_DOWN, NULL); setFocus(d->children[giveFocus]); + d->timer = 0; } } return true; diff --git a/doomsday/apps/plugins/common/src/menu/widgets/buttonwidget.cpp b/doomsday/apps/plugins/common/src/menu/widgets/buttonwidget.cpp index cb064126a9..dc6f5f4a5f 100644 --- a/doomsday/apps/plugins/common/src/menu/widgets/buttonwidget.cpp +++ b/doomsday/apps/plugins/common/src/menu/widgets/buttonwidget.cpp @@ -57,18 +57,21 @@ void ButtonWidget::draw() const Vector4f const &textColor = mnRendState->textColors[color()]; float t = (isFocused()? 1 : 0); - // Flash if focused. - if(isFocused() && cfg.common.menuTextFlashSpeed > 0) - { - float const speed = cfg.common.menuTextFlashSpeed / 2.f; - t = (1 + sin(page().timer() / (float)TICSPERSEC * speed * DD_PI)) / 2; - } + const Vector4f color = selectionFlashColor(textColor); + +// // Flash if focused. +// if (isFocused() && cfg.common.menuTextFlashSpeed > 0) +// { +// float const speed = cfg.common.menuTextFlashSpeed / 2.f; +// t = (1 + sin(page().timer() / (float)TICSPERSEC * speed * DD_PI)) / 2; +// } +// Vector4f const color = de::lerp(textColor, Vector4f(Vector3f(cfg.common.menuTextFlashColor), textColor.w), t); - Vector4f const color = de::lerp(textColor, Vector4f(Vector3f(cfg.common.menuTextFlashColor), textColor.w), t); + const float fadeout = scrollingFadeout(); FR_SetFont(fontId); - FR_SetColorAndAlpha(color.x, color.y, color.z, color.w); - DGL_Color4f(1, 1, 1, color.w); + FR_SetColorAndAlpha(color.x, color.y, color.z, color.w * fadeout); + DGL_Color4f(1, 1, 1, color.w * fadeout); if(d->patch >= 0) { @@ -79,7 +82,12 @@ void ButtonWidget::draw() const } DGL_Enable(DGL_TEXTURE_2D); - WI_DrawPatch(d->patch, replacement, geometry().topLeft, ALIGN_TOPLEFT, 0, Hu_MenuMergeEffectWithDrawTextFlags(0)); + WI_DrawPatch(d->patch, + replacement, + geometry().topLeft, + ALIGN_TOPLEFT, + 0, + Hu_MenuMergeEffectWithDrawTextFlags(0)); DGL_Disable(DGL_TEXTURE_2D); return; diff --git a/doomsday/apps/plugins/common/src/menu/widgets/coloreditwidget.cpp b/doomsday/apps/plugins/common/src/menu/widgets/coloreditwidget.cpp index a2e2179193..048c81ed28 100644 --- a/doomsday/apps/plugins/common/src/menu/widgets/coloreditwidget.cpp +++ b/doomsday/apps/plugins/common/src/menu/widgets/coloreditwidget.cpp @@ -159,7 +159,9 @@ void ColorEditWidget::draw() const x += width; } - DGL_Color4f(1, 1, 1, mnRendState->pageAlpha); + const float fadeout = scrollingFadeout(); + + DGL_Color4f(1, 1, 1, mnRendState->pageAlpha * fadeout); DGL_Enable(DGL_TEXTURE_2D); DGL_SetMaterialUI((world_Material *)P_ToPtr(DMU_MATERIAL, Materials_ResolveUriCString(borderGraphics[0])), DGL_REPEAT, DGL_REPEAT); @@ -224,7 +226,14 @@ void ColorEditWidget::draw() const DGL_Disable(DGL_TEXTURE_2D); DGL_SetNoMaterial(); - DGL_DrawRectf2Color(x, y, w, h, d->color.x, d->color.y, d->color.z, d->color.w * mnRendState->pageAlpha); + DGL_DrawRectf2Color(x, + y, + w, + h, + d->color.x, + d->color.y, + d->color.z, + d->color.w * mnRendState->pageAlpha * fadeout); } int ColorEditWidget::handleCommand(menucommand_e cmd) diff --git a/doomsday/apps/plugins/common/src/menu/widgets/cvartextualsliderwidget.cpp b/doomsday/apps/plugins/common/src/menu/widgets/cvartextualsliderwidget.cpp index bcef9e6628..3454952c06 100644 --- a/doomsday/apps/plugins/common/src/menu/widgets/cvartextualsliderwidget.cpp +++ b/doomsday/apps/plugins/common/src/menu/widgets/cvartextualsliderwidget.cpp @@ -145,7 +145,7 @@ void CVarTextualSliderWidget::draw() const DGL_Enable(DGL_TEXTURE_2D); FR_SetFont(mnRendState->textFonts[font()]); - FR_SetColorAndAlpha(textColor.x, textColor.y, textColor.z, textColor.w); + FR_SetColorAndAlpha(textColor.x, textColor.y, textColor.z, textColor.w * scrollingFadeout()); FR_DrawTextXY3(valueAsText.toUtf8().constData(), 0, 0, ALIGN_TOPLEFT, Hu_MenuMergeEffectWithDrawTextFlags(0)); DGL_Disable(DGL_TEXTURE_2D); diff --git a/doomsday/apps/plugins/common/src/menu/widgets/inlinelistwidget.cpp b/doomsday/apps/plugins/common/src/menu/widgets/inlinelistwidget.cpp index b91bd667f0..e1b3884844 100644 --- a/doomsday/apps/plugins/common/src/menu/widgets/inlinelistwidget.cpp +++ b/doomsday/apps/plugins/common/src/menu/widgets/inlinelistwidget.cpp @@ -39,12 +39,12 @@ InlineListWidget::~InlineListWidget() void InlineListWidget::draw() const { - Item const *item = items()[selection()]; - Vector4f const &textColor = mnRendState->textColors[color()]; + const Item * item = items()[selection()]; + const Vector4f color = selectionFlashColor(mnRendState->textColors[this->color()]); DGL_Enable(DGL_TEXTURE_2D); FR_SetFont(mnRendState->textFonts[font()]); - FR_SetColorAndAlpha(textColor.x, textColor.y, textColor.z, textColor.w); + FR_SetColorAndAlpha(color.x, color.y, color.z, color.w * scrollingFadeout()); FR_DrawTextXY3(item->text().toUtf8().constData(), geometry().topLeft.x, geometry().topLeft.y, ALIGN_TOPLEFT, Hu_MenuMergeEffectWithDrawTextFlags(0)); diff --git a/doomsday/apps/plugins/common/src/menu/widgets/inputbindingwidget.cpp b/doomsday/apps/plugins/common/src/menu/widgets/inputbindingwidget.cpp index 8938f319ae..67902f9ab1 100644 --- a/doomsday/apps/plugins/common/src/menu/widgets/inputbindingwidget.cpp +++ b/doomsday/apps/plugins/common/src/menu/widgets/inputbindingwidget.cpp @@ -265,7 +265,7 @@ void InputBindingWidget::draw() const bindingdrawerdata_t draw; draw.origin.x = geometry().topLeft.x; draw.origin.y = geometry().topLeft.y; - draw.alpha = mnRendState->pageAlpha; + draw.alpha = mnRendState->pageAlpha * scrollingFadeout(); iterateBindings(binds, buf, MIBF_IGNORE_REPEATS, &draw, drawBinding); } diff --git a/doomsday/apps/plugins/common/src/menu/widgets/labelwidget.cpp b/doomsday/apps/plugins/common/src/menu/widgets/labelwidget.cpp index 99afffd26b..de0502393c 100644 --- a/doomsday/apps/plugins/common/src/menu/widgets/labelwidget.cpp +++ b/doomsday/apps/plugins/common/src/menu/widgets/labelwidget.cpp @@ -55,22 +55,26 @@ void LabelWidget::draw() const { fontid_t fontId = mnRendState->textFonts[font()]; Vector4f const &textColor = mnRendState->textColors[color()]; - float t = (isFocused()? 1 : 0); +// float t = (isFocused()? 1 : 0); - // Flash if focused. - if(isFocused() && cfg.common.menuTextFlashSpeed > 0) - { - float const speed = cfg.common.menuTextFlashSpeed / 2.f; - t = (1 + sin(page().timer() / (float)TICSPERSEC * speed * DD_PI)) / 2; - } +// // Flash if focused. +// if(isFocused() && cfg.common.menuTextFlashSpeed > 0) +// { +// float const speed = cfg.common.menuTextFlashSpeed / 2.f; +// t = (1 + sin(page().timer() / (float)TICSPERSEC * speed * DD_PI)) / 2; +// } + +// Vector4f const color = de::lerp(textColor, Vector4f(Vector3f(cfg.common.menuTextFlashColor), textColor.w), t); - Vector4f const color = de::lerp(textColor, Vector4f(Vector3f(cfg.common.menuTextFlashColor), textColor.w), t); + const Vector4f color = selectionFlashColor(textColor); - DGL_Color4f(1, 1, 1, color.w); + const float fadeout = scrollingFadeout(); + + DGL_Color4f(1, 1, 1, color.w * fadeout); FR_SetFont(fontId); - FR_SetColorAndAlpha(color.x, color.y, color.z, color.w); + FR_SetColorAndAlpha(color.x, color.y, color.z, color.w * fadeout); - if(d->patch) + if (d->patch) { String replacement; if(!(d->flags & MNTEXT_NO_ALTTEXT)) diff --git a/doomsday/apps/plugins/common/src/menu/widgets/lineeditwidget.cpp b/doomsday/apps/plugins/common/src/menu/widgets/lineeditwidget.cpp index cf2f970882..97f857b4ed 100644 --- a/doomsday/apps/plugins/common/src/menu/widgets/lineeditwidget.cpp +++ b/doomsday/apps/plugins/common/src/menu/widgets/lineeditwidget.cpp @@ -131,28 +131,34 @@ void LineEditWidget::draw() const DGL_Enable(DGL_TEXTURE_2D); FR_SetFont(fontId); + const float fadeout = scrollingFadeout(); + //int const numVisCharacters = de::clamp(0, useText.isNull()? 0 : useText.length(), d->maxVisibleChars); drawEditBackground(origin + Vector2i(MNDATA_EDIT_BACKGROUND_OFFSET_X, MNDATA_EDIT_BACKGROUND_OFFSET_Y), - geometry().width(), mnRendState->pageAlpha); + geometry().width(), mnRendState->pageAlpha * fadeout); //if(string) { - float t = 0; +// float t = 0; + Vector4f color = Vector4f(Vector3f(cfg.common.menuTextColors[MNDATA_EDIT_TEXT_COLORIDX]), 1.f); // Flash if focused? - if(!isActive() && isFocused() && cfg.common.menuTextFlashSpeed > 0) + if (!isActive()) /* && isFocused() && cfg.common.menuTextFlashSpeed > 0) { float const speed = cfg.common.menuTextFlashSpeed / 2.f; t = (1 + sin(page().timer() / (float)TICSPERSEC * speed * DD_PI)) / 2; + }*/ + { + color = selectionFlashColor(color); } - Vector4f color = de::lerp(Vector3f(cfg.common.menuTextColors[MNDATA_EDIT_TEXT_COLORIDX]), Vector3f(cfg.common.menuTextFlashColor), t); +// Vector4f color = de::lerp(Vector3f(cfg.common.menuTextColors[MNDATA_EDIT_TEXT_COLORIDX]), Vector3f(cfg.common.menuTextFlashColor), t); color *= light; color.w = textOpacity; // Draw the text: - FR_SetColorAndAlpha(color.x, color.y, color.z, color.w); + FR_SetColorAndAlpha(color.x, color.y, color.z, color.w * fadeout); FR_DrawTextXY3(useText.toUtf8().constData(), origin.x, origin.y, ALIGN_TOPLEFT, Hu_MenuMergeEffectWithDrawTextFlags(0)); // Are we drawing a cursor? diff --git a/doomsday/apps/plugins/common/src/menu/widgets/listwidget.cpp b/doomsday/apps/plugins/common/src/menu/widgets/listwidget.cpp index 57b4ac688f..5f648e85a5 100644 --- a/doomsday/apps/plugins/common/src/menu/widgets/listwidget.cpp +++ b/doomsday/apps/plugins/common/src/menu/widgets/listwidget.cpp @@ -59,9 +59,10 @@ int ListWidget::Item::userValue() const DENG2_PIMPL_NOREF(ListWidget) { Items items; - int selection = 0; ///< Selected item (-1 if none). - int first = 0; ///< First visible item. - int numvis = 0; + int selection = 0; ///< Selected item (-1 if none). + int first = 0; ///< First visible item. + int numvis = 0; + bool reorderEnabled = false; ~Impl() { qDeleteAll(items); } }; @@ -124,13 +125,19 @@ void ListWidget::draw() const Vector4f const &textColor = mnRendState->textColors[color()]; float t = flashSelection? 1 : 0; - if(flashSelection && cfg.common.menuTextFlashSpeed > 0) + Vector4f flashColor = textColor; + + if (flashSelection) /* && cfg.common.menuTextFlashSpeed > 0) { float const speed = cfg.common.menuTextFlashSpeed / 2.f; t = (1 + sin(page().timer() / (float)TICSPERSEC * speed * DD_PI)) / 2; + }*/ + { + flashColor = selectionFlashColor(flashColor); } - Vector4f const flashColor = de::lerp(textColor, Vector4f(Vector3f(cfg.common.menuTextFlashColor), textColor.w), t); + +// Vector4f const flashColor = de::lerp(textColor, Vector4f(Vector3f(cfg.common.menuTextFlashColor), textColor.w), t); Vector4f const dimColor = Vector4f(Vector3f(textColor) * MNDATA_LIST_NONSELECTION_LIGHT, textColor.w); if(d->first < d->items.count() && d->numvis > 0) @@ -142,13 +149,21 @@ void ListWidget::draw() const int itemIdx = d->first; do { - Item const *item = d->items[itemIdx]; - Vector4f const &color = d->selection == itemIdx? (flashSelection? flashColor : textColor) : dimColor; + const Item *item = d->items[itemIdx]; + + const Vector4f &color = + d->selection == itemIdx ? (flashSelection ? flashColor : textColor) : dimColor; - FR_SetColorAndAlpha(color.x, color.y, color.z, color.w); + const int itemHeight = + FR_TextHeight(item->text().toUtf8().constData()) * (1 + MNDATA_LIST_LEADING); + + FR_SetColorAndAlpha(color.x, + color.y, + color.z, + color.w * scrollingFadeout(origin.y, origin.y + itemHeight)); FR_DrawTextXY3(item->text().toUtf8().constData(), origin.x, origin.y, ALIGN_TOPLEFT, Hu_MenuMergeEffectWithDrawTextFlags(0)); - origin.y += FR_TextHeight(item->text().toUtf8().constData()) * (1 + MNDATA_LIST_LEADING); - } while(++itemIdx < d->items.count() && itemIdx < d->first + d->numvis); + origin.y += itemHeight; + } while (++itemIdx < d->items.count() && itemIdx < d->first + d->numvis); DGL_Disable(DGL_TEXTURE_2D); } @@ -156,11 +171,11 @@ void ListWidget::draw() const int ListWidget::handleCommand(menucommand_e cmd) { - switch(cmd) + switch (cmd) { case MCMD_NAV_DOWN: case MCMD_NAV_UP: - if(isActive()) + if (isActive()) { int oldSelection = d->selection; if(MCMD_NAV_DOWN == cmd) @@ -184,7 +199,7 @@ int ListWidget::handleCommand(menucommand_e cmd) return false; // Not eaten. case MCMD_NAV_OUT: - if(isActive()) + if (isActive()) { S_LocalSound(SFX_MENU_CANCEL, NULL); setFlags(Active, UnsetFlags); @@ -194,7 +209,7 @@ int ListWidget::handleCommand(menucommand_e cmd) return false; // Not eaten. case MCMD_SELECT: - if(!isActive()) + if (!isActive()) { S_LocalSound(SFX_MENU_ACCEPT, NULL); setFlags(Active); @@ -208,6 +223,18 @@ int ListWidget::handleCommand(menucommand_e cmd) } return true; + case MCMD_NAV_LEFT: + case MCMD_NAV_RIGHT: + if (d->reorderEnabled && isActive()) + { + if (reorder(selection(), cmd == MCMD_NAV_LEFT ? -1 : +1)) + { + S_LocalSound(SFX_MENU_SLIDER_MOVE, NULL); + execAction(Modified); + } + } + return true; + default: return false; // Not eaten. } } @@ -241,7 +268,7 @@ void ListWidget::updateVisibleSelection() int ListWidget::itemData(int index) const { - if(index >= 0 && index < itemCount()) + if (index >= 0 && index < itemCount()) { return d->items[index]->userValue(); } @@ -283,5 +310,38 @@ bool ListWidget::selectItemByValue(int userValue, int flags) return selectItem(findItem(userValue), flags); } +bool ListWidget::reorder(int itemIndex, int indexOffset) +{ + if (itemIndex + indexOffset < 0 || itemIndex + indexOffset >= d->items.size()) + { + return false; // Would go out of bounds. + } + + if (d->selection == itemIndex) + { + d->selection += indexOffset; + } + + while (indexOffset < 0) + { + std::swap(d->items[itemIndex - 1], d->items[itemIndex]); + --itemIndex; + ++indexOffset; + } + while (indexOffset > 0) + { + std::swap(d->items[itemIndex + 1], d->items[itemIndex]); + ++itemIndex; + --indexOffset; + } + return true; +} + +ListWidget &ListWidget::setReorderingEnabled(bool reorderEnabled) +{ + d->reorderEnabled = reorderEnabled; + return *this; +} + } // namespace menu } // namespace common diff --git a/doomsday/apps/plugins/common/src/menu/widgets/sliderwidget.cpp b/doomsday/apps/plugins/common/src/menu/widgets/sliderwidget.cpp index 6e8d995f03..825efa511f 100644 --- a/doomsday/apps/plugins/common/src/menu/widgets/sliderwidget.cpp +++ b/doomsday/apps/plugins/common/src/menu/widgets/sliderwidget.cpp @@ -164,7 +164,9 @@ void SliderWidget::draw() const M_DrawGlowBar(from, to, HEIGHT * 1.1f, true, true, true, 0, 0, 0, mnRendState->pageAlpha * mnRendState->textShadow); } - DGL_Color4f(1, 1, 1, mnRendState->pageAlpha); + const float fadeout = scrollingFadeout(); + + DGL_Color4f(1, 1, 1, mnRendState->pageAlpha * fadeout); GL_DrawPatch(pSliderLeft, Vector2i(0, 0), ALIGN_TOPRIGHT, DPF_NO_OFFSETX); GL_DrawPatch(pSliderRight, Vector2i(MNDATA_SLIDER_SLOTS * WIDTH, 0)); @@ -172,7 +174,7 @@ void SliderWidget::draw() const DGL_SetPatch(pSliderMiddle, DGL_REPEAT, DGL_REPEAT); DGL_DrawRectf2Tiled(0, middleInfo.geometry.origin.y, MNDATA_SLIDER_SLOTS * WIDTH, HEIGHT, middleInfo.geometry.size.width, middleInfo.geometry.size.height); - DGL_Color4f(1, 1, 1, mnRendState->pageAlpha); + DGL_Color4f(1, 1, 1, mnRendState->pageAlpha * fadeout); GL_DrawPatch(pSliderHandle, Vector2i(d->thumbPos(), 1), ALIGN_TOP, DPF_NO_OFFSET); DGL_Disable(DGL_TEXTURE_2D); diff --git a/doomsday/apps/plugins/common/src/menu/widgets/widget.cpp b/doomsday/apps/plugins/common/src/menu/widgets/widget.cpp index bec22dd956..6af3a44d80 100644 --- a/doomsday/apps/plugins/common/src/menu/widgets/widget.cpp +++ b/doomsday/apps/plugins/common/src/menu/widgets/widget.cpp @@ -21,6 +21,7 @@ #include #include "common.h" #include "menu/widgets/widget.h" +#include "menu/page.h" #include "hu_menu.h" // menu sounds @@ -255,13 +256,11 @@ int Widget::handleCommand(menucommand_e cmd) bool Widget::hasAction(Action id) const { - DENG2_ASSERT(id >= Modified && id <= FocusGained); return d->actions.contains(id); } Widget &Widget::setAction(Action id, ActionCallback callback) { - DENG2_ASSERT(id >= Modified && id <= FocusGained); if(callback) { d->actions.insert(id, callback); @@ -303,5 +302,43 @@ QVariant const &Widget::userValue2() const return d->userValue2; } +float Widget::scrollingFadeout() const +{ + const auto geom = geometry(); + return scrollingFadeout(geom.topLeft.y, geom.bottomRight.y); +} + +float Widget::scrollingFadeout(int yTop, int yBottom) const +{ + if (page().flags() & Page::NoScroll) + { + return 1.f; + } + + const float FADEOUT_LEN = 20; + const auto viewRegion = page().viewRegion(); + + if (yBottom < viewRegion.topLeft.y) + { + return de::max(0.f, 1.f - (viewRegion.topLeft.y - yBottom) / FADEOUT_LEN); + } + if (yTop > viewRegion.bottomRight.y) + { + return de::max(0.f, 1.f - (yTop - viewRegion.bottomRight.y) / FADEOUT_LEN); + } + return 1.f; +} + +Vector4f Widget::selectionFlashColor(const Vector4f &noFlashColor) const +{ + if (isFocused() && cfg.common.menuTextFlashSpeed > 0) + { + const float speed = cfg.common.menuTextFlashSpeed / 2.f; + const float t = (1 + sin(page().timer() / (float)TICSPERSEC * speed * DD_PI)) / 2; + return lerp(noFlashColor, Vector4f(Vector3f(cfg.common.menuTextFlashColor), 1.f), t); + } + return noFlashColor; +} + } // namespace menu } // namespace common diff --git a/doomsday/apps/plugins/doom/src/d_main.cpp b/doomsday/apps/plugins/doom/src/d_main.cpp index 8fdc606bd1..40e80654a9 100644 --- a/doomsday/apps/plugins/doom/src/d_main.cpp +++ b/doomsday/apps/plugins/doom/src/d_main.cpp @@ -243,7 +243,7 @@ void D_PreInit() sizeof(cfg.common.hudColor))); cfg.common.hudColor[CA] = 1; - cfg.common.hudFog = 1; + cfg.common.hudFog = 5; cfg.common.hudIconAlpha = 1; cfg.common.xhairAngle = 0; cfg.common.xhairSize = .5f; diff --git a/doomsday/apps/plugins/doom64/src/d_main.cpp b/doomsday/apps/plugins/doom64/src/d_main.cpp index 117dbc098a..8f164626a0 100644 --- a/doomsday/apps/plugins/doom64/src/d_main.cpp +++ b/doomsday/apps/plugins/doom64/src/d_main.cpp @@ -167,7 +167,7 @@ void D_PreInit() cfg.common.hudColor[0] = 1; cfg.common.hudColor[1] = cfg.common.hudColor[2] = 0; cfg.common.hudColor[3] = 0.75f; - cfg.common.hudFog = 1; + cfg.common.hudFog = 5; cfg.common.hudIconAlpha = 0.5f; cfg.common.xhairAngle = 0; cfg.common.xhairSize = .5f;