Replaced combo boxes with list box dialogues to help navigate certain elements better in VR.

pull/615/head
madsbuvi 4 years ago
parent 00d6dc3a86
commit a0a7e6b5aa

@ -249,7 +249,7 @@ if(BUILD_OPENMW_VR)
add_openmw_dir (mwvr
openxraction openxractionset openxrdebug openxrinput openxrmanager openxrmanagerimpl openxrplatform openxrswapchain openxrswapchainimage openxrswapchainimpl
realisticcombat
vranimation vrcamera vrenvironment vrframebuffer vrgui vrinputmanager vrinput vrmetamenu vrsession vrshadow vrtypes vrview vrviewer vrvirtualkeyboard
vranimation vrcamera vrenvironment vrframebuffer vrgui vrinputmanager vrinput vrlistbox vrmetamenu vrsession vrshadow vrtypes vrview vrviewer vrvirtualkeyboard
)
openmw_add_executable(openmw_vr

@ -27,6 +27,10 @@
#include "itemwidget.hpp"
#include "widgets.hpp"
#ifdef USE_OPENXR
#include "../mwvr/vrlistbox.hpp"
#endif
namespace MWGui
{
AlchemyWindow::AlchemyWindow()
@ -34,6 +38,9 @@ namespace MWGui
, mCurrentFilter(FilterType::ByName)
, mModel(nullptr)
, mSortModel(nullptr)
, mFilterCombo(nullptr)
, mFilterEdit(nullptr)
, mFilterButton(nullptr)
, mAlchemy(new MWMechanics::Alchemy())
, mApparatus (4)
, mIngredients (4)
@ -54,8 +61,31 @@ namespace MWGui
getWidget(mDecreaseButton, "DecreaseButton");
getWidget(mNameEdit, "NameEdit");
getWidget(mItemView, "ItemView");
getWidget(mFilterValue, "FilterValue");
getWidget(mFilterCombo, "FilterValue");
getWidget(mFilterType, "FilterType");
getWidget(mFilterEdit, "FilterEdit");
getWidget(mFilterButton, "FilterButton");
if (MWBase::Environment::get().getVrMode())
{
#ifdef USE_OPENXR
mFilterListBox = new MWVR::VrListBox();
#endif
mFilterCombo->setVisible(false);
mFilterCombo->setUserString("Hidden", "true");
}
else
{
mFilterButton->setVisible(false);
mFilterButton->setUserString("Hidden", "true");
mFilterEdit->setVisible(false);
mFilterEdit->setUserString("Hidden", "true");
}
mFilterButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onFilterButtonClicked);
mFilterEdit->eventEditTextChange += MyGUI::newDelegate(this, &AlchemyWindow::onFilterEdited);
mFilterCombo->eventComboChangePosition += MyGUI::newDelegate(this, &AlchemyWindow::onFilterChanged);
mFilterCombo->eventEditTextChange += MyGUI::newDelegate(this, &AlchemyWindow::onFilterEdited);
mBrewCountEdit->eventValueChanged += MyGUI::newDelegate(this, &AlchemyWindow::onCountValueChanged);
mBrewCountEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &AlchemyWindow::onAccept);
@ -78,8 +108,7 @@ namespace MWGui
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCancelButtonClicked);
mNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &AlchemyWindow::onAccept);
mFilterValue->eventComboChangePosition += MyGUI::newDelegate(this, &AlchemyWindow::onFilterChanged);
mFilterValue->eventEditTextChange += MyGUI::newDelegate(this, &AlchemyWindow::onFilterEdited);
mFilterType->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::switchFilterType);
center();
@ -160,7 +189,8 @@ namespace MWGui
else
mCurrentFilter = FilterType::ByEffect;
updateFilters();
mFilterValue->clearIndexSelected();
mFilterCombo->clearIndexSelected();
mFilterEdit->setCaption("");
updateFilters();
}
@ -183,39 +213,44 @@ namespace MWGui
}
mSortModel->setNameFilter({});
mSortModel->setEffectFilter({});
mFilterValue->clearIndexSelected();
mFilterCombo->clearIndexSelected();
mFilterEdit->setCaption("");
updateFilters();
mItemView->update();
}
void AlchemyWindow::updateFilters()
{
std::set<std::string> itemNames, itemEffects;
mItemEffects.clear();
mItemNames.clear();
for (size_t i = 0; i < mModel->getItemCount(); ++i)
{
MWWorld::Ptr item = mModel->getItem(i).mBase;
if (item.getTypeName() != typeid(ESM::Ingredient).name())
continue;
itemNames.insert(item.getClass().getName(item));
mItemNames.insert(item.getClass().getName(item));
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
auto const alchemySkill = player.getClass().getSkill(player, ESM::Skill::Alchemy);
auto const effects = MWMechanics::Alchemy::effectsDescription(item, alchemySkill);
itemEffects.insert(effects.begin(), effects.end());
mItemEffects.insert(effects.begin(), effects.end());
}
mFilterValue->removeAllItems();
auto const addItems = [&](auto const& container)
mFilterCombo->removeAllItems();
for (auto const& item : items())
{
for (auto const& item : container)
mFilterValue->addItem(item);
};
mFilterCombo->addItem(item);
}
}
const std::set<std::string>& AlchemyWindow::items()
{
switch (mCurrentFilter)
{
case FilterType::ByName: addItems(itemNames); break;
case FilterType::ByEffect: addItems(itemEffects); break;
case FilterType::ByName: return mItemNames; break;
case FilterType::ByEffect: return mItemEffects; break;
}
}
@ -242,6 +277,20 @@ namespace MWGui
applyFilter(_sender->getCaption());
}
void AlchemyWindow::onFilterButtonClicked(MyGUI::Widget* _sender)
{
#ifdef USE_OPENXR
mFilterListBox->open(mFilterCombo, [this](std::size_t index) {
if (index != MyGUI::ITEM_NONE)
{
auto filter = mFilterCombo->getItemNameAt(index);
mFilterEdit->setCaption(filter);
applyFilter(filter);
}
});
#endif
}
void AlchemyWindow::onOpen()
{
mAlchemy->clear();

@ -6,6 +6,7 @@
#include <MyGUI_ControllerItem.h>
#include <MyGUI_ComboBox.h>
#include <MyGUI_ListBox.h>
#include <components/widgets/box.hpp>
#include <components/widgets/numericeditbox.hpp>
@ -17,6 +18,11 @@ namespace MWMechanics
class Alchemy;
}
namespace MWVR
{
class VrListBox;
}
namespace MWGui
{
class ItemView;
@ -54,10 +60,16 @@ namespace MWGui
MyGUI::Button* mIncreaseButton;
MyGUI::Button* mDecreaseButton;
Gui::AutoSizedButton* mFilterType;
MyGUI::ComboBox* mFilterValue;
MyGUI::ComboBox* mFilterCombo;
MyGUI::EditBox* mFilterEdit;
MyGUI::Button* mFilterButton;
MWVR::VrListBox* mFilterListBox;
MyGUI::EditBox* mNameEdit;
Gui::NumericEditBox* mBrewCountEdit;
std::set<std::string> mItemNames;
std::set<std::string> mItemEffects;
void onCancelButtonClicked(MyGUI::Widget* _sender);
void onCreateButtonClicked(MyGUI::Widget* _sender);
void onIngredientSelected(MyGUI::Widget* _sender);
@ -72,8 +84,10 @@ namespace MWGui
void initFilter();
void onFilterChanged(MyGUI::ComboBox* _sender, size_t _index);
void onFilterEdited(MyGUI::EditBox* _sender);
void onFilterButtonClicked(MyGUI::Widget* _sender);
void switchFilterType(MyGUI::Widget* _sender);
void updateFilters();
const std::set<std::string>& items();
void addRepeatController(MyGUI::Widget* widget);

@ -30,6 +30,10 @@
#include "../mwstate/character.hpp"
#ifdef USE_OPENXR
#include "../mwvr/vrlistbox.hpp"
#endif
#include "confirmationdialog.hpp"
namespace MWGui
@ -41,7 +45,6 @@ namespace MWGui
, mCurrentSlot(nullptr)
{
getWidget(mScreenshot, "Screenshot");
getWidget(mCharacterSelection, "SelectCharacter");
getWidget(mInfoText, "InfoText");
getWidget(mOkButton, "OkButton");
getWidget(mCancelButton, "CancelButton");
@ -49,11 +52,28 @@ namespace MWGui
getWidget(mSaveList, "SaveList");
getWidget(mSaveNameEdit, "SaveNameEdit");
getWidget(mSpacer, "Spacer");
getWidget(mCharacterSelection, "SelectCharacter");
getWidget(mCharacterSelectionButton, "SelectCharacterButton");
if (MWBase::Environment::get().getVrMode())
{
#ifdef USE_OPENXR
mCharacterSelectionListBox = new MWVR::VrListBox();
#endif
mCharacterSelection->setVisible(false);
mCharacterSelection->setUserString("Hidden", "true");
}
else
{
mCharacterSelectionButton->setVisible(false);
mCharacterSelectionButton->setUserString("Hidden", "true");
}
mCharacterSelectionButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterSelectionButtonClicked);
mCharacterSelection->eventComboChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterSelected);
mCharacterSelection->eventComboAccept += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterAccept);
mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onOkButtonClicked);
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onCancelButtonClicked);
mDeleteButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteButtonClicked);
mCharacterSelection->eventComboChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterSelected);
mCharacterSelection->eventComboAccept += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterAccept);
mSaveList->eventListChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onSlotSelected);
mSaveList->eventListMouseItemActivate += MyGUI::newDelegate(this, &SaveGameDialog::onSlotMouseClick);
mSaveList->eventListSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onSlotActivated);
@ -147,11 +167,15 @@ namespace MWGui
if (mSaving)
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveNameEdit);
else
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList);
if (MWBase::Environment::get().getVrMode())
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCharacterSelectionButton);
else
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList);
center();
mCharacterSelection->setCaption("");
mCharacterSelectionButton->setCaption("");
mCharacterSelection->removeAllItems();
mCurrentCharacter = nullptr;
mCurrentSlot = nullptr;
@ -209,6 +233,8 @@ namespace MWGui
mCharacterSelection->setIndexSelected(selectedIndex);
if (selectedIndex == MyGUI::ITEM_NONE)
mCharacterSelection->setCaption("Select Character ...");
else
mCharacterSelectionButton->setCaption(mCharacterSelection->getCaption());
fillSaveList();
@ -218,8 +244,17 @@ namespace MWGui
{
mSaving = !load;
mSaveNameEdit->setVisible(!load);
mCharacterSelection->setUserString("Hidden", load ? "false" : "true");
mCharacterSelection->setVisible(load);
if (MWBase::Environment::get().getVrMode())
{
mCharacterSelectionButton->setUserString("Hidden", load ? "false" : "true");
mCharacterSelectionButton->setVisible(load);
}
else
{
mCharacterSelection->setUserString("Hidden", load ? "false" : "true");
mCharacterSelection->setVisible(load);
}
mSpacer->setUserString("Hidden", load ? "false" : "true");
mDeleteButton->setUserString("Hidden", load ? "false" : "true");
@ -244,6 +279,21 @@ namespace MWGui
confirmDeleteSave();
}
void SaveGameDialog::onCharacterSelectionButtonClicked(MyGUI::Widget* sender)
{
#ifdef USE_OPENXR
mCharacterSelectionListBox->open(mCharacterSelection, [this](std::size_t index) {
if (index != MyGUI::ITEM_NONE)
{
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList);
auto caption = mCharacterSelection->getItemNameAt(index);
mCharacterSelectionButton->setCaption(caption);
onCharacterSelected(mCharacterSelection, index);
}
});
#endif
}
void SaveGameDialog::onConfirmationGiven()
{
accept(true);

@ -11,6 +11,11 @@ namespace MWState
struct Slot;
}
namespace MWVR
{
class VrListBox;
}
namespace MWGui
{
@ -31,6 +36,7 @@ namespace MWGui
void onCancelButtonClicked (MyGUI::Widget* sender);
void onOkButtonClicked (MyGUI::Widget* sender);
void onDeleteButtonClicked (MyGUI::Widget* sender);
void onCharacterSelectionButtonClicked(MyGUI::Widget* sender);
void onCharacterSelected (MyGUI::ComboBox* sender, size_t pos);
void onCharacterAccept(MyGUI::ComboBox* sender, size_t pos);
// Slot selected (mouse click or arrow keys)
@ -57,6 +63,8 @@ namespace MWGui
bool mSaving;
MyGUI::ComboBox* mCharacterSelection;
MWVR::VrListBox* mCharacterSelectionListBox;
MyGUI::Button* mCharacterSelectionButton;
MyGUI::EditBox* mInfoText;
MyGUI::Button* mOkButton;
MyGUI::Button* mCancelButton;

@ -548,6 +548,7 @@ namespace MWVR
LayerConfig videoPlayerConfig = createDefaultConfig(4, true, SizingMode::Fixed);
LayerConfig messageBoxConfig = createDefaultConfig(6, false, SizingMode::Auto);;
LayerConfig notificationConfig = createDefaultConfig(7, false, SizingMode::Fixed);
LayerConfig listBoxConfig = createDefaultConfig(10, true);
LayerConfig statsWindowConfig = createSideBySideConfig(0);
LayerConfig inventoryWindowConfig = createSideBySideConfig(1);
@ -624,6 +625,7 @@ namespace MWVR
{"DialogueWindow", dialogueWindowConfig},
{"MessageBox", messageBoxConfig},
{"Windows", defaultWindowsConfig},
{"ListBox", listBoxConfig},
{"MainMenu", mainMenuConfig},
{"Notification", notificationConfig},
{"InputBlocker", videoPlayerConfig},

@ -534,8 +534,7 @@ namespace MWVR
vrGuiManager->updateTracking();
break;
case A_MenuSelect:
if (!wm->injectKeyPress(MyGUI::KeyCode::Return, 0, false))
executeAction(MWInput::A_Activate);
wm->injectKeyPress(MyGUI::KeyCode::Return, 0, false);
break;
case A_MenuBack:
if (MyGUI::InputManager::getInstance().isModalAny())
@ -559,6 +558,9 @@ namespace MWVR
mBindingsManager->ics().getChannel(MWInput::A_Use)->setValue(0.f);
pointActivation(false);
break;
case A_MenuSelect:
wm->injectKeyRelease(MyGUI::KeyCode::Return);
break;
default:
break;
}

@ -0,0 +1,89 @@
#include "vrlistbox.hpp"
#include <MyGUI_InputManager.h>
#include <MyGUI_LayerManager.h>
#include <MyGUI_ComboBox.h>
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/statemanager.hpp"
namespace MWVR
{
VrListBox::VrListBox()
: WindowModal("openmw_vr_listbox.layout")
, mOK(nullptr)
, mCancel(nullptr)
, mListBox(nullptr)
, mIndex(MyGUI::ITEM_NONE)
, mCallback()
{
getWidget(mOK, "OkButton");
getWidget(mCancel, "CancelButton");
getWidget(mListBox, "ListBox");
mOK->eventMouseButtonClick += MyGUI::newDelegate(this, &VrListBox::onOKButtonClicked);
mCancel->eventMouseButtonClick += MyGUI::newDelegate(this, &VrListBox::onCancelButtonClicked);
mListBox->eventListChangePosition += MyGUI::newDelegate(this, &VrListBox::onItemChanged);
mListBox->eventListSelectAccept += MyGUI::newDelegate(this, &VrListBox::onListAccept);
}
VrListBox::~VrListBox()
{
}
void VrListBox::open(MyGUI::ComboBox* comboBox, Callback callback)
{
mCallback = callback;
mIndex = MyGUI::ITEM_NONE;
mListBox->removeAllItems();
mListBox->setIndexSelected(MyGUI::ITEM_NONE);
for (unsigned i = 0; i < comboBox->getItemCount(); i++)
mListBox->addItem(comboBox->getItemNameAt(i));
mListBox->setItemSelect(comboBox->getIndexSelected());
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mListBox);
center();
setVisible(true);
}
void VrListBox::close()
{
setVisible(false);
}
void VrListBox::onItemChanged(MyGUI::ListBox* _sender, size_t _index)
{
mIndex = _index;
}
void VrListBox::onCancelButtonClicked(MyGUI::Widget* sender)
{
close();
if (mCallback)
mCallback(MyGUI::ITEM_NONE);
}
void VrListBox::onOKButtonClicked(MyGUI::Widget* sender)
{
accept(mIndex);
}
void VrListBox::onListAccept(MyGUI::ListBox* sender, size_t pos)
{
accept(pos);
}
void VrListBox::accept(size_t index)
{
close();
if (mCallback)
mCallback(index);
}
}

@ -0,0 +1,47 @@
#ifndef OPENMW_GAME_MWVR_LISTBOX_H
#define OPENMW_GAME_MWVR_LISTBOX_H
#include "../mwgui/windowbase.hpp"
#include <MyGUI_Button.h>
#include <MyGUI_ListBox.h>
#include "components/widgets/virtualkeyboardmanager.hpp"
#include <set>
#include <memory>
namespace Gui
{
class VirtualKeyboardManager;
}
namespace MWVR
{
//! A simple dialogue that presents a list of choices. Used as an alternative to combo boxes in VR.
class VrListBox : public MWGui::WindowModal
{
public:
using Callback = std::function<void(std::size_t)>;
VrListBox();
~VrListBox();
void open(MyGUI::ComboBox* comboBox, Callback callback);
void close();
private:
void onItemChanged(MyGUI::ListBox* _sender, size_t _index);
void onCancelButtonClicked(MyGUI::Widget* sender);
void onOKButtonClicked(MyGUI::Widget* sender);
void onListAccept(MyGUI::ListBox* sender, size_t pos);
void accept(size_t index);
MyGUI::Widget* mCancel;
MyGUI::Widget* mOK;
MyGUI::ListBox* mListBox;
std::size_t mIndex;
Callback mCallback;
};
}
#endif

@ -85,7 +85,8 @@ namespace MWVR
void VrVirtualKeyboard::delegateOnSetFocus(MyGUI::Widget* _sender, MyGUI::Widget* _old)
{
open(static_cast<MyGUI::EditBox*>(_sender));
if (_sender->getUserString("VirtualKeyboard") != "false")
open(static_cast<MyGUI::EditBox*>(_sender));
}
void VrVirtualKeyboard::delegateOnLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new)

@ -488,11 +488,10 @@ namespace Gui
}
EditBox::EditBox(bool shouldSupportVirtualKeyboard)
EditBox::EditBox()
: mVirtualKeyboardRegistered(false)
{
if (shouldSupportVirtualKeyboard)
registerVirtualKeyboard();
registerVirtualKeyboard();
}
EditBox::~EditBox()
{
@ -500,14 +499,11 @@ namespace Gui
}
void EditBox::registerVirtualKeyboard()
{
if (!mVirtualKeyboardRegistered)
auto* vkm = Gui::VirtualKeyboardManager::getInstancePtr();
if (vkm)
{
auto* vkm = Gui::VirtualKeyboardManager::getInstancePtr();
if (vkm)
{
vkm->registerEditBox(this);
mVirtualKeyboardRegistered = true;
}
vkm->registerEditBox(this);
mVirtualKeyboardRegistered = true;
}
}
void EditBox::unregisterVirtualKeyboard()

@ -26,7 +26,7 @@ namespace Gui
MYGUI_RTTI_DERIVED( EditBox )
/// @param supportsVirtualKeyboard If true, VR mode will spawn a virtual keyboard whenever this widget is focused.
EditBox(bool shouldSupportVirtualKeyboard = true);
EditBox();
~EditBox();
private:

@ -99,6 +99,7 @@ set(MYGUI_FILES
openmw_trade_window_vr.layout
openmw_trainingwindow.layout
openmw_travel_window.layout
openmw_vr_listbox.layout
openmw_vr_virtual_keyboard.layout
openmw_wait_dialog.layout
openmw_wait_dialog_progressbar.layout

@ -83,6 +83,12 @@
<UserString key="HStretch" value="true"/>
<Property key="ModeDrop" value="false"/>
</Widget>
<Widget type="EditBox" skin="MW_TextEdit" position="0 2 0 24" name="FilterEdit">
<UserString key="HStretch" value="true"/>
</Widget>
<Widget type="AutoSizedButton" skin="MW_Button" position="10 2 1 1" name="FilterButton">
<Property key="Caption" value="List"/> <!-- default value, can be either sIngredients or sMagicEffects -->
</Widget>
</Widget>

@ -18,6 +18,7 @@
<Property key="Size" value="600 520"/>
</Layer>
<Layer name="Windows" overlapped="true" pick="true"/>
<Layer name="ListBox" overlapped="true" pick="true"/>
<Layer name="Debug" overlapped="true" pick="true"/>
<Layer name="Notification" overlapped="false" pick="false"/>
<Layer name="Tooltip" overlapped="true" pick="true"/>

@ -21,6 +21,11 @@
<UserString key="HStretch" value="true"/>
</Widget>
<Widget type="AutoSizedButton" skin="MW_Button" position="0 0 200 24" name="SelectCharacterButton">
<Property key="Caption" value="Select Character"/>
<UserString key="HStretch" value="true"/>
</Widget>
<Widget type="ListBox" skin="MW_List" position="0 0 200 200" name="SaveList">
<UserString key="HStretch" value="true"/>

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<Widget type="VBox" skin="MW_DialogNoTransp" layer="ListBox" position="0 0 500 300" name="_Main" align="Center">
<Property key="Spacing" value="8"/>
<Property key="Padding" value="8"/>
<Widget type="ListBox" skin="MW_List" position="0 0 200 400" name="ListBox">
<UserString key="HStretch" value="true"/>
<UserString key="VStretch" value="true"/>
</Widget>
<Widget type="HBox" skin="">
<Property key="Padding" value="8"/>
<UserString key="HStretch" value="true"/>
<UserString key="VStretch" value="true"/>
<Widget type="AutoSizedButton" skin="MW_Button" name="OkButton">
<Property key="Caption" value="#{sOk}"/>
</Widget>
<Widget type="AutoSizedButton" skin="MW_Button" name="CancelButton">
<Property key="Caption" value="#{sCancel}"/>
</Widget>
</Widget>
</Widget>
</MyGUI>
Loading…
Cancel
Save