1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-25 15:35:23 +00:00

Merge branch 'master' of https://github.com/OpenMW/openmw into unix-console

This commit is contained in:
Evil Eye 2019-07-03 21:58:06 +02:00
commit 405c556ce9
76 changed files with 459 additions and 181 deletions

View File

@ -2,17 +2,20 @@
------
Bug #1515: Opening console masks dialogue, inventory menu
Bug #2395: Duplicated plugins in the launcher when multiple data directories provide the same plugin
Bug #2969: Scripted items can stack
Bug #2987: Editor: some chance and AI data fields can overflow
Bug #3006: 'else if' operator breaks script compilation
Bug #3109: SetPos/Position handles actors differently
Bug #3282: Unintended behaviour when assigning F3 and Windows keys
Bug #3550: Companion from mod attacks the air after combat has ended
Bug #3623: Display scaling breaks mouse recognition
Bug #3725: Using script function in a non-conditional expression breaks script compilation
Bug #3733: Normal maps are inverted on mirrored UVs
Bug #3765: DisableTeleporting makes Mark/Recall/Intervention effects undetectable
Bug #3778: [Mod] Improved Thrown Weapon Projectiles - weapons have wrong transformation during throw animation
Bug #3812: Wrong multiline tooltips width when word-wrapping is enabled
Bug #4202: Open .omwaddon files without needing toopen openmw-cs first
Bug #4240: Ash storm origin coordinates and hand shielding animation behavior are incorrect
Bug #4329: Removed birthsign abilities are restored after reloading the save
Bug #4341: Error message about missing GDB is too vague
@ -20,6 +23,7 @@
Bug #4384: Resist Normal Weapons only checks ammunition for ranged weapons
Bug #4411: Reloading a saved game while falling prevents damage in some cases
Bug #4540: Rain delay when exiting water
Bug #4639: Black screen after completing first mages guild mission + training
Bug #4701: PrisonMarker record is not hardcoded like other markers
Bug #4703: Editor: it's possible to preview levelled list records
Bug #4705: Editor: unable to open exterior cell views from Instances table
@ -99,6 +103,13 @@
Bug #5038: Enchanting success chance calculations are blatantly wrong
Bug #5047: # in cell names sets color
Bug #5050: Invalid spell effects are not handled gracefully
Bug #5056: Calling Cast function on player doesn't equip the spell but casts it
Bug #5060: Magic effect visuals stop when death animation begins instead of when it ends
Bug #5063: Shape named "Tri Shadow" in creature mesh is visible if it isn't hidden
Bug #5069: Blocking creatures' attacks doesn't degrade shields
Bug #5074: Paralyzed actors greet the player
Bug #5075: Enchanting cast style can be changed if there's no object
Bug #5082: Scrolling with controller in GUI mode is broken
Feature #1774: Handle AvoidNode
Feature #2229: Improve pathfinding AI
Feature #3025: Analogue gamepad movement controls
@ -126,14 +137,17 @@
Feature #4968: Scalable UI widget skins
Feature #4994: Persistent pinnable windows hiding
Feature #5000: Compressed BSA format support
Feature #5005: Editor: Instance window via Scene window
Feature #5010: Native graphics herbalism support
Feature #5031: Make GetWeaponType function return different values for tools
Feature #5033: Magic armor mitigation for creatures
Feature #5034: Make enchanting window stay open after a failed attempt
Feature #5036: Allow scripted faction leaving
Feature #5046: Gamepad thumbstick cursor speed
Feature #5051: Provide a separate textures for scrollbars
Task #4686: Upgrade media decoder to a more current FFmpeg API
Task #4695: Optimize Distant Terrain memory consumption
Task #4789: Optimize cell transitions
Task #4721: Add NMake support to the Windows prebuild script
0.45.0

View File

@ -109,15 +109,14 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName)
{
QStringList paths = mGameSettings.getDataDirs();
foreach(const QString &path, paths)
mSelector->addFiles(path);
mDataLocal = mGameSettings.getDataLocal();
if (!mDataLocal.isEmpty())
mSelector->addFiles(mDataLocal);
paths.insert(0, mDataLocal);
foreach(const QString &path, paths)
mSelector->addFiles(path);
paths.insert(0, mDataLocal);
PathIterator pathIterator(paths);
mSelector->setProfileContent(filesInProfile(contentModelName, pathIterator));

View File

@ -27,8 +27,11 @@ CS::Editor::Editor (int argc, char **argv)
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig();
mViewManager = new CSVDoc::ViewManager(mDocumentManager);
setupDataFiles (config.first);
if (argc > 1)
{
mFileToLoad = argv[1];
mDataDirs = config.first;
}
NifOsg::Loader::setShowMarkers(true);
@ -79,15 +82,6 @@ CS::Editor::~Editor ()
remove(mPid.string().c_str())); // ignore any error
}
void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs)
{
for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter)
{
QString path = QString::fromUtf8 (iter->string().c_str());
mFileDialog.addFiles(path);
}
}
std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfig(bool quiet)
{
boost::program_options::variables_map variables;
@ -114,9 +108,9 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
Fallback::Map::init(variables["fallback"].as<FallbackMap>().mMap);
const std::string encoding = variables["encoding"].as<Files::EscapeHashString>().toStdString();
mDocumentManager.setEncoding (ToUTF8::calculateEncoding (encoding));
mFileDialog.setEncoding (QString::fromUtf8(encoding.c_str()));
mEncodingName = variables["encoding"].as<Files::EscapeHashString>().toStdString();
mDocumentManager.setEncoding(ToUTF8::calculateEncoding(mEncodingName));
mFileDialog.setEncoding (QString::fromUtf8(mEncodingName.c_str()));
mDocumentManager.setResourceDir (mResources = variables["resources"].as<Files::EscapeHashString>().toStdString());
@ -160,7 +154,7 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end());
//iterate the data directories and add them to the file dialog for loading
for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter)
for (Files::PathContainer::const_reverse_iterator iter = dataDirs.rbegin(); iter != dataDirs.rend(); ++iter)
{
QString path = QString::fromUtf8 (iter->string().c_str());
mFileDialog.addFiles(path);
@ -199,8 +193,7 @@ void CS::Editor::createAddon()
mStartup.hide();
mFileDialog.clearFiles();
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig(/*quiet*/true);
setupDataFiles (config.first);
readConfig(/*quiet*/true);
mFileDialog.showDialog (CSVDoc::ContentAction_New);
}
@ -224,18 +217,24 @@ void CS::Editor::loadDocument()
mStartup.hide();
mFileDialog.clearFiles();
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig(/*quiet*/true);
setupDataFiles (config.first);
readConfig(/*quiet*/true);
mFileDialog.showDialog (CSVDoc::ContentAction_Edit);
}
void CS::Editor::openFiles (const boost::filesystem::path &savePath)
void CS::Editor::openFiles (const boost::filesystem::path &savePath, const std::vector<boost::filesystem::path> &discoveredFiles)
{
std::vector<boost::filesystem::path> files;
foreach (const QString &path, mFileDialog.selectedFilePaths())
files.push_back(path.toUtf8().constData());
if(discoveredFiles.empty())
{
foreach(const QString &path, mFileDialog.selectedFilePaths())
files.push_back(path.toUtf8().constData());
}
else
{
files = discoveredFiles;
}
mDocumentManager.addDocument (files, savePath, false);
@ -361,9 +360,53 @@ int CS::Editor::run()
Misc::Rng::init();
mStartup.show();
QApplication::setQuitOnLastWindowClosed(true);
QApplication::setQuitOnLastWindowClosed (true);
if (mFileToLoad.empty())
{
mStartup.show();
}
else
{
ESM::ESMReader fileReader;
ToUTF8::Utf8Encoder encoder = ToUTF8::calculateEncoding(mEncodingName);
fileReader.setEncoder(&encoder);
fileReader.open(mFileToLoad.string());
std::vector<boost::filesystem::path> discoveredFiles;
for (std::vector<ESM::Header::MasterData>::const_iterator itemIter = fileReader.getGameFiles().begin();
itemIter != fileReader.getGameFiles().end(); ++itemIter)
{
for (Files::PathContainer::const_iterator pathIter = mDataDirs.begin();
pathIter != mDataDirs.end(); ++pathIter)
{
const boost::filesystem::path masterPath = *pathIter / itemIter->name;
if (boost::filesystem::exists(masterPath))
{
discoveredFiles.push_back(masterPath);
break;
}
}
}
discoveredFiles.push_back(mFileToLoad);
QString extension = QString::fromStdString(mFileToLoad.extension().string()).toLower();
if (extension == ".esm")
{
mFileToLoad.replace_extension(".omwgame");
mDocumentManager.addDocument(discoveredFiles, mFileToLoad, false);
}
else if (extension == ".esp")
{
mFileToLoad.replace_extension(".omwaddon");
mDocumentManager.addDocument(discoveredFiles, mFileToLoad, false);
}
else
{
openFiles(mFileToLoad, discoveredFiles);
}
}
return QApplication::exec();
}

View File

@ -54,8 +54,9 @@ namespace CS
bool mFsStrict;
CSVTools::Merge mMerge;
CSVDoc::ViewManager* mViewManager;
void setupDataFiles (const Files::PathContainer& dataDirs);
boost::filesystem::path mFileToLoad;
Files::PathContainer mDataDirs;
std::string mEncodingName;
std::pair<Files::PathContainer, std::vector<std::string> > readConfig(bool quiet=false);
///< \return data paths
@ -83,7 +84,7 @@ namespace CS
void cancelFileDialog();
void loadDocument();
void openFiles (const boost::filesystem::path &path);
void openFiles (const boost::filesystem::path &path, const std::vector<boost::filesystem::path> &discoveredFiles = std::vector<boost::filesystem::path>());
void createNewFile (const boost::filesystem::path& path);
void createNewGame (const boost::filesystem::path& file);

View File

@ -247,6 +247,9 @@ void CSMPrefs::State::declare()
addValues (landeditOutsideVisibleCell);
declareInt ("texturebrush-maximumsize", "Maximum texture brush size", 50).
setMin (1);
declareBool ("open-list-view", "Open displays list view", false).
setTooltip ("When opening a reference from the scene view, it will open the"
" instance list view instead of the individual instance record view.");
declareCategory ("Key Bindings");
@ -331,6 +334,7 @@ void CSMPrefs::State::declare()
declareShortcut ("scene-navi-primary", "Camera Rotation From Mouse Movement", QKeySequence(Qt::LeftButton));
declareShortcut ("scene-navi-secondary", "Camera Translation From Mouse Movement",
QKeySequence(Qt::ControlModifier | (int)Qt::LeftButton));
declareShortcut ("scene-open-primary", "Primary Open", QKeySequence(Qt::ShiftModifier | (int)Qt::LeftButton));
declareShortcut ("scene-edit-primary", "Primary Edit", QKeySequence(Qt::RightButton));
declareShortcut ("scene-edit-secondary", "Secondary Edit",
QKeySequence(Qt::ControlModifier | (int)Qt::RightButton));

View File

@ -22,6 +22,7 @@
#include "../../model/world/idtable.hpp"
#include "../world/subviews.hpp"
#include "../world/scenesubview.hpp"
#include "../world/tablesubview.hpp"
#include "../tools/subviews.hpp"
@ -626,6 +627,20 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin
connect (view, SIGNAL (updateSubViewIndices (SubView *)),
this, SLOT (updateSubViewIndices (SubView *)));
CSVWorld::TableSubView* tableView = dynamic_cast<CSVWorld::TableSubView*>(view);
if (tableView)
{
connect (this, SIGNAL (requestFocus (const std::string&)),
tableView, SLOT (requestFocus (const std::string&)));
}
CSVWorld::SceneSubView* sceneView = dynamic_cast<CSVWorld::SceneSubView*>(view);
if (sceneView)
{
connect(sceneView, SIGNAL(requestFocus(const std::string&)),
this, SLOT(onRequestFocus(const std::string&)));
}
view->show();
if (!hint.empty())
@ -1065,3 +1080,16 @@ void CSVDoc::View::createScrollArea()
mScroll->setWidget(&mSubViewWindow);
setCentralWidget(mScroll);
}
void CSVDoc::View::onRequestFocus (const std::string& id)
{
if(CSMPrefs::get()["3D Scene Editing"]["open-list-view"].isTrue())
{
addReferencesSubView();
emit requestFocus(id);
}
else
{
addSubView(CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Reference, id));
}
}

View File

@ -140,6 +140,8 @@ namespace CSVDoc
void mergeDocument (CSMDoc::Document *document);
void requestFocus (const std::string& id);
public slots:
void addSubView (const CSMWorld::UniversalId& id, const std::string& hint = "");
@ -262,6 +264,8 @@ namespace CSVDoc
void moveScrollBarToEnd(int min, int max);
void merge();
void onRequestFocus (const std::string& id);
};
}

View File

@ -29,6 +29,8 @@ void CSVRender::EditMode::setEditLock (bool locked)
}
void CSVRender::EditMode::primaryOpenPressed (const WorldspaceHitResult& hit) {}
void CSVRender::EditMode::primaryEditPressed (const WorldspaceHitResult& hit) {}
void CSVRender::EditMode::secondaryEditPressed (const WorldspaceHitResult& hit) {}

View File

@ -39,6 +39,9 @@ namespace CSVRender
/// Default-implementation: Ignored.
virtual void setEditLock (bool locked);
/// Default-implementation: Ignored.
virtual void primaryOpenPressed (const WorldspaceHitResult& hit);
/// Default-implementation: Ignored.
virtual void primaryEditPressed (const WorldspaceHitResult& hit);

View File

@ -94,6 +94,8 @@ CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidg
parent), mSubMode (0), mSubModeId ("move"), mSelectionMode (0), mDragMode (DragMode_None),
mDragAxis (-1), mLocked (false), mUnitScaleDist(1)
{
connect(this, SIGNAL(requestFocus(const std::string&)),
worldspaceWidget, SIGNAL(requestFocus(const std::string&)));
}
void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar)
@ -174,6 +176,18 @@ void CSVRender::InstanceMode::primaryEditPressed (const WorldspaceHitResult& hit
primarySelectPressed (hit);
}
void CSVRender::InstanceMode::primaryOpenPressed (const WorldspaceHitResult& hit)
{
if(hit.tag)
{
if (CSVRender::ObjectTag *objectTag = dynamic_cast<CSVRender::ObjectTag *> (hit.tag.get()))
{
const std::string refId = objectTag->mObject->getReferenceId();
emit requestFocus(refId);
}
}
}
void CSVRender::InstanceMode::secondaryEditPressed (const WorldspaceHitResult& hit)
{
if (CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue())

View File

@ -55,6 +55,8 @@ namespace CSVRender
virtual void setEditLock (bool locked);
virtual void primaryOpenPressed (const WorldspaceHitResult& hit);
virtual void primaryEditPressed (const WorldspaceHitResult& hit);
virtual void secondaryEditPressed (const WorldspaceHitResult& hit);
@ -83,6 +85,10 @@ namespace CSVRender
virtual int getSubMode() const;
signals:
void requestFocus (const std::string& id);
private slots:
void subModeChanged (const std::string& id);

View File

@ -63,6 +63,10 @@ namespace CSVRender
}
}
void PathgridMode::primaryOpenPressed(const WorldspaceHitResult& hitResult)
{
}
void PathgridMode::primaryEditPressed(const WorldspaceHitResult& hitResult)
{
if (CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue() &&

View File

@ -21,6 +21,8 @@ namespace CSVRender
virtual void deactivate(CSVWidget::SceneToolbar* toolbar);
virtual void primaryOpenPressed(const WorldspaceHitResult& hit);
virtual void primaryEditPressed(const WorldspaceHitResult& hit);
virtual void secondaryEditPressed(const WorldspaceHitResult& hit);

View File

@ -77,6 +77,10 @@ void CSVRender::TerrainTextureMode::deactivate(CSVWidget::SceneToolbar* toolbar)
EditMode::deactivate(toolbar);
}
void CSVRender::TerrainTextureMode::primaryOpenPressed(const WorldspaceHitResult& hit) // Apply changes here
{
}
void CSVRender::TerrainTextureMode::primaryEditPressed(const WorldspaceHitResult& hit) // Apply changes here
{
CSMDoc::Document& document = getWorldspaceWidget().getDocument();

View File

@ -35,6 +35,8 @@ namespace CSVRender
/// \brief Editmode for terrain texture grid
TerrainTextureMode(WorldspaceWidget*, QWidget* parent = nullptr);
void primaryOpenPressed (const WorldspaceHitResult& hit);
/// \brief Create single command for one-click texture editing
void primaryEditPressed (const WorldspaceHitResult& hit);

View File

@ -101,6 +101,9 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg
// Shortcuts
CSMPrefs::Shortcut* primaryEditShortcut = new CSMPrefs::Shortcut("scene-edit-primary", "scene-speed-modifier",
CSMPrefs::Shortcut::SM_Detach, this);
CSMPrefs::Shortcut* primaryOpenShortcut = new CSMPrefs::Shortcut("scene-open-primary", this);
connect(primaryOpenShortcut, SIGNAL(activated(bool)), this, SLOT(primaryOpen(bool)));
connect(primaryEditShortcut, SIGNAL(activated(bool)), this, SLOT(primaryEdit(bool)));
connect(primaryEditShortcut, SIGNAL(secondary(bool)), this, SLOT(speedMode(bool)));
@ -696,6 +699,8 @@ void CSVRender::WorldspaceWidget::handleInteractionPress (const WorldspaceHitRes
editMode.primarySelectPressed (hit);
else if (type == InteractionType_SecondarySelect)
editMode.secondarySelectPressed (hit);
else if (type == InteractionType_PrimaryOpen)
editMode.primaryOpenPressed (hit);
}
CSVRender::EditMode *CSVRender::WorldspaceWidget::getEditMode()
@ -703,6 +708,11 @@ CSVRender::EditMode *CSVRender::WorldspaceWidget::getEditMode()
return dynamic_cast<CSVRender::EditMode *> (mEditMode->getCurrent());
}
void CSVRender::WorldspaceWidget::primaryOpen(bool activate)
{
handleInteraction(InteractionType_PrimaryOpen, activate);
}
void CSVRender::WorldspaceWidget::primaryEdit(bool activate)
{
handleInteraction(InteractionType_PrimaryEdit, activate);

View File

@ -91,6 +91,7 @@ namespace CSVRender
InteractionType_PrimarySelect,
InteractionType_SecondaryEdit,
InteractionType_SecondarySelect,
InteractionType_PrimaryOpen,
InteractionType_None
};
@ -263,6 +264,8 @@ namespace CSVRender
void showToolTip();
void primaryOpen(bool activate);
void primaryEdit(bool activate);
void secondaryEdit(bool activate);
@ -283,6 +286,8 @@ namespace CSVRender
void dataDropped(const std::vector<CSMWorld::UniversalId>& data);
void requestFocus (const std::string& id);
friend class MouseState;
};
}

View File

@ -83,6 +83,9 @@ void CSVWorld::SceneSubView::makeConnections (CSVRender::UnpagedWorldspaceWidget
connect(widget, SIGNAL(cellChanged(const CSMWorld::UniversalId&)),
this, SLOT(cellSelectionChanged(const CSMWorld::UniversalId&)));
connect(widget, SIGNAL(requestFocus (const std::string&)),
this, SIGNAL(requestFocus (const std::string&)));
}
void CSVWorld::SceneSubView::makeConnections (CSVRender::PagedWorldspaceWidget* widget)
@ -94,6 +97,9 @@ void CSVWorld::SceneSubView::makeConnections (CSVRender::PagedWorldspaceWidget*
connect (widget, SIGNAL (cellSelectionChanged (const CSMWorld::CellSelection&)),
this, SLOT (cellSelectionChanged (const CSMWorld::CellSelection&)));
connect(widget, SIGNAL(requestFocus (const std::string&)),
this, SIGNAL(requestFocus (const std::string&)));
}
CSVWidget::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::WorldspaceWidget* widget, widgetType type)

View File

@ -82,6 +82,10 @@ namespace CSVWorld
void cellSelectionChanged (const CSMWorld::UniversalId& id);
void handleDrop(const std::vector<CSMWorld::UniversalId>& data);
signals:
void requestFocus (const std::string& id);
};
}

View File

@ -737,7 +737,12 @@ void CSVWorld::Table::requestFocus (const std::string& id)
QModelIndex index = mProxyModel->getModelIndex (id, 0);
if (index.isValid())
scrollTo (index, QAbstractItemView::PositionAtTop);
{
// This will scroll to the row.
selectRow (index.row());
// This will actually select it.
selectionModel()->select (index, QItemSelectionModel::Select | QItemSelectionModel::Rows);
}
}
void CSVWorld::Table::recordFilterChanged (std::shared_ptr<CSMFilter::Node> filter)

View File

@ -165,3 +165,8 @@ bool CSVWorld::TableSubView::eventFilter (QObject* object, QEvent* event)
}
return false;
}
void CSVWorld::TableSubView::requestFocus (const std::string& id)
{
mTable->requestFocus(id);
}

View File

@ -60,6 +60,10 @@ namespace CSVWorld
void cloneRequest (const CSMWorld::UniversalId& toClone);
void createFilterRequest(std::vector< CSMWorld::UniversalId >& types,
Qt::DropAction action);
public slots:
void requestFocus (const std::string& id);
};
}

View File

@ -289,6 +289,9 @@ namespace MWBase
virtual const Translation::Storage& getTranslationDataStorage() const = 0;
/// Warning: do not use MyGUI::InputManager::setKeyFocusWidget directly. Instead use this.
virtual void setKeyFocusWidget (MyGUI::Widget* widget) = 0;
virtual void loadUserFonts() = 0;
virtual Loading::Listener* getLoadingScreen() = 0;

View File

@ -5,7 +5,6 @@
#include <MyGUI_EditBox.h>
#include <MyGUI_ControllerManager.h>
#include <MyGUI_ControllerRepeatClick.h>
#include <MyGUI_InputManager.h>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -169,7 +168,7 @@ namespace MWGui
update();
MyGUI::InputManager::getInstance().setKeyFocusWidget(mNameEdit);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNameEdit);
}
void AlchemyWindow::onIngredientSelected(MyGUI::Widget* _sender)

View File

@ -4,7 +4,6 @@
#include <MyGUI_ImageBox.h>
#include <MyGUI_Gui.h>
#include <MyGUI_ScrollView.h>
#include <MyGUI_InputManager.h>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -72,7 +71,7 @@ namespace MWGui
WindowModal::onOpen();
updateBirths();
updateSpells();
MyGUI::InputManager::getInstance().setKeyFocusWidget(mBirthList);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mBirthList);
// Show the current birthsign by default
const std::string &signId =

View File

@ -101,7 +101,7 @@ namespace MWGui
setTakeButtonShow(showTakeButton);
MyGUI::InputManager::getInstance().setKeyFocusWidget(mCloseButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton);
}
void BookWindow::setTakeButtonShow(bool show)
@ -161,9 +161,9 @@ namespace MWGui
mPrevPageButton->setVisible(prevPageVisible);
if (focus == mNextPageButton && !nextPageVisible && prevPageVisible)
MyGUI::InputManager::getInstance().setKeyFocusWidget(mPrevPageButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mPrevPageButton);
else if (focus == mPrevPageButton && !prevPageVisible && nextPageVisible)
MyGUI::InputManager::getInstance().setKeyFocusWidget(mNextPageButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNextPageButton);
if (mPages.empty())
return;

View File

@ -3,7 +3,6 @@
#include <MyGUI_ImageBox.h>
#include <MyGUI_ListBox.h>
#include <MyGUI_Gui.h>
#include <MyGUI_InputManager.h>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -136,7 +135,7 @@ namespace MWGui
WindowModal::onOpen ();
updateClasses();
updateStats();
MyGUI::InputManager::getInstance().setKeyFocusWidget(mClassList);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mClassList);
// Show the current class by default
MWWorld::Ptr player = MWMechanics::getPlayer();
@ -437,7 +436,7 @@ namespace MWGui
getWidget(mEditName, "EditName");
// Make sure the edit box has focus
MyGUI::InputManager::getInstance().setKeyFocusWidget(mEditName);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mEditName);
MyGUI::Button* descriptionButton;
getWidget(descriptionButton, "DescriptionButton");
@ -903,7 +902,7 @@ namespace MWGui
okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sInputMenu1", ""));
// Make sure the edit box has focus
MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit);
}
DescriptionDialog::~DescriptionDialog()

View File

@ -2,7 +2,6 @@
#include <MyGUI_Button.h>
#include <MyGUI_EditBox.h>
#include <MyGUI_InputManager.h>
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
@ -34,7 +33,7 @@ namespace MWGui
mMessage->setSize(mMessage->getWidth(), mMessage->getTextSize().height + 24);
MyGUI::InputManager::getInstance().setKeyFocusWidget(mOkButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mOkButton);
center();
}

View File

@ -1,7 +1,6 @@
#include "console.hpp"
#include <MyGUI_EditBox.h>
#include <MyGUI_InputManager.h>
#include <MyGUI_LayerManager.h>
#include <boost/filesystem.hpp>
@ -153,7 +152,7 @@ namespace MWGui
{
// Give keyboard focus to the combo box whenever the console is
// turned on and place it over other widgets
MyGUI::InputManager::getInstance().setKeyFocusWidget(mCommandLine);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCommandLine);
MyGUI::LayerManager::getInstance().upLayerItem(mMainWidget);
}
@ -507,7 +506,7 @@ namespace MWGui
mPtr = object;
}
// User clicked on an object. Restore focus to the console command line.
MyGUI::InputManager::getInstance().setKeyFocusWidget(mCommandLine);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCommandLine);
}
else
{

View File

@ -141,7 +141,7 @@ namespace MWGui
mItemView->setModel (mSortModel);
mItemView->resetScrollBars();
MyGUI::InputManager::getInstance().setKeyFocusWidget(mCloseButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton);
setTitle(container.getClass().getName(container));
}
@ -175,7 +175,7 @@ namespace MWGui
if(mDragAndDrop != nullptr && mDragAndDrop->mIsOnDragAndDrop)
return;
MyGUI::InputManager::getInstance().setKeyFocusWidget(mCloseButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton);
// transfer everything into the player's inventory
ItemModel* playerModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getModel();
@ -222,7 +222,7 @@ namespace MWGui
{
if(mDragAndDrop == nullptr || !mDragAndDrop->mIsOnDragAndDrop)
{
MyGUI::InputManager::getInstance().setKeyFocusWidget(mCloseButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton);
onTakeAllButtonClicked(mTakeButton);

View File

@ -3,7 +3,6 @@
#include <MyGUI_Button.h>
#include <MyGUI_ScrollBar.h>
#include <MyGUI_RenderManager.h>
#include <MyGUI_InputManager.h>
#include <components/widgets/numericeditbox.hpp>
@ -48,7 +47,7 @@ namespace MWGui
mMainWidget->getHeight());
// by default, the text edit field has the focus of the keyboard
MyGUI::InputManager::getInstance().setKeyFocusWidget(mItemEdit);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mItemEdit);
mSlider->setScrollPosition(maxCount-1);

View File

@ -5,7 +5,6 @@
#include <MyGUI_ProgressBar.h>
#include <MyGUI_ScrollBar.h>
#include <MyGUI_Button.h>
#include <MyGUI_InputManager.h>
#include <components/debug/debuglog.hpp>
#include <components/widgets/list.hpp>
@ -381,7 +380,7 @@ namespace MWGui
{
onTopicActivated(topic);
if (mGoodbyeButton->getEnabled())
MyGUI::InputManager::getInstance().setKeyFocusWidget(mGoodbyeButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton);
}
else if (topic == sPersuasion)
mPersuasionDialog.setVisible(true);
@ -444,7 +443,7 @@ namespace MWGui
return;
}
MyGUI::InputManager::getInstance().setKeyFocusWidget(mGoodbyeButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton);
setTitle(mPtr.getClass().getName(mPtr));
@ -623,7 +622,7 @@ namespace MWGui
bool goodbyeWasEnabled = mGoodbyeButton->getEnabled();
mGoodbyeButton->setEnabled(goodbyeEnabled);
if (goodbyeEnabled && !goodbyeWasEnabled)
MyGUI::InputManager::getInstance().setKeyFocusWidget(mGoodbyeButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton);
bool topicsEnabled = !MWBase::Environment::get().getDialogueManager()->isInChoice() && !mGoodbye;
mTopicsList->setEnabled(topicsEnabled);

View File

@ -5,7 +5,6 @@
#include <MyGUI_Button.h>
#include <MyGUI_ScrollView.h>
#include <MyGUI_EditBox.h>
#include <MyGUI_InputManager.h>
#include <components/widgets/list.hpp>
#include <components/settings/settings.hpp>
@ -68,7 +67,7 @@ namespace MWGui
void EnchantingDialog::onOpen()
{
center();
MyGUI::InputManager::getInstance().setKeyFocusWidget(mName);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mName);
}
void EnchantingDialog::setSoulGem(const MWWorld::Ptr &gem)

View File

@ -254,7 +254,7 @@ namespace
}
updateShowingPages();
MyGUI::InputManager::getInstance().setKeyFocusWidget(getWidget<MyGUI::Widget>(CloseBTN));
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(getWidget<MyGUI::Widget>(CloseBTN));
}
void onClose()
@ -377,9 +377,9 @@ namespace
prevPageBtn->setVisible(prevPageVisible);
if (focus == nextPageBtn && !nextPageVisible && prevPageVisible)
MyGUI::InputManager::getInstance().setKeyFocusWidget(prevPageBtn);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(prevPageBtn);
else if (focus == prevPageBtn && !prevPageVisible && nextPageVisible)
MyGUI::InputManager::getInstance().setKeyFocusWidget(nextPageBtn);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(nextPageBtn);
setVisible (PageOneNum, relPages > 0);
setVisible (PageTwoNum, relPages > 1);

View File

@ -83,7 +83,7 @@ void KeyboardNavigation::restoreFocus(int mode)
{
MyGUI::Widget* w = found->second;
if (w && w->getVisible() && w->getEnabled())
MyGUI::InputManager::getInstance().setKeyFocusWidget(found->second);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(found->second);
}
}
@ -130,7 +130,7 @@ void KeyboardNavigation::onFrame()
// workaround incorrect key focus resets (fix in MyGUI TBD)
if (!shouldAcceptKeyFocus(focus) && shouldAcceptKeyFocus(mCurrentFocus) && (!mModalWindow || isRootParent(mCurrentFocus, mModalWindow)))
{
MyGUI::InputManager::getInstance().setKeyFocusWidget(mCurrentFocus);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCurrentFocus);
focus = mCurrentFocus;
}
@ -154,12 +154,12 @@ void KeyboardNavigation::setDefaultFocus(MyGUI::Widget *window, MyGUI::Widget *d
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
if (!focus || !shouldAcceptKeyFocus(focus))
{
MyGUI::InputManager::getInstance().setKeyFocusWidget(defaultFocus);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(defaultFocus);
}
else
{
if (!isRootParent(focus, window))
MyGUI::InputManager::getInstance().setKeyFocusWidget(defaultFocus);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(defaultFocus);
}
}
@ -276,7 +276,7 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap)
else if (direction == D_Up && (vertdiff >= 0 || !isVertical))
return false;
MyGUI::InputManager::getInstance().setKeyFocusWidget(keyFocusList[index]);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[index]);
return true;
}
@ -291,7 +291,7 @@ bool KeyboardNavigation::selectFirstWidget()
if (!keyFocusList.empty())
{
MyGUI::InputManager::getInstance().setKeyFocusWidget(keyFocusList[0]);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(keyFocusList[0]);
return true;
}
return false;

View File

@ -3,7 +3,6 @@
#include <MyGUI_TextBox.h>
#include <MyGUI_Gui.h>
#include <MyGUI_RenderManager.h>
#include <MyGUI_InputManager.h>
#include <components/widgets/imagebutton.hpp>
#include <components/settings/settings.hpp>
@ -68,12 +67,12 @@ namespace MWGui
if (isMainMenu)
{
if (mButtons["loadgame"]->getVisible())
MyGUI::InputManager::getInstance().setKeyFocusWidget(mButtons["loadgame"]);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mButtons["loadgame"]);
else
MyGUI::InputManager::getInstance().setKeyFocusWidget(mButtons["newgame"]);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mButtons["newgame"]);
}
else
MyGUI::InputManager::getInstance().setKeyFocusWidget(mButtons["return"]);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mButtons["return"]);
}
Layout::setVisible (visible);

View File

@ -1123,7 +1123,7 @@ namespace MWGui
{
WindowModal::onOpen();
center();
MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit);
}
void EditNoteDialog::onCancelButtonClicked(MyGUI::Widget *sender)

View File

@ -3,7 +3,6 @@
#include <MyGUI_ListBox.h>
#include <MyGUI_ImageBox.h>
#include <MyGUI_Gui.h>
#include <MyGUI_InputManager.h>
#include <osg/Texture2D>
@ -166,7 +165,7 @@ namespace MWGui
mHeadRotate->setScrollPosition(initialPos);
onHeadRotate(mHeadRotate, initialPos);
MyGUI::InputManager::getInstance().setKeyFocusWidget(mRaceList);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mRaceList);
}
void RaceDialog::setRaceId(const std::string &raceId)

View File

@ -94,7 +94,7 @@ namespace MWGui
MWBase::Environment::get().getStateManager()->deleteGame (mCurrentCharacter, mCurrentSlot);
mSaveList->removeItemAt(mSaveList->getIndexSelected());
onSlotSelected(mSaveList, mSaveList->getIndexSelected());
MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveList);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList);
if (mSaveList->getItemCount() == 0)
{
@ -114,7 +114,7 @@ namespace MWGui
void SaveGameDialog::onDeleteSlotCancel()
{
MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveList);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList);
}
void SaveGameDialog::onSaveNameChanged(MyGUI::EditBox *sender)
@ -138,9 +138,9 @@ namespace MWGui
mSaveNameEdit->setCaption ("");
if (mSaving)
MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveNameEdit);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveNameEdit);
else
MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveList);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList);
center();
@ -244,7 +244,7 @@ namespace MWGui
void SaveGameDialog::onConfirmationCancel()
{
MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveList);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList);
}
void SaveGameDialog::accept(bool reallySure)
@ -331,7 +331,7 @@ namespace MWGui
void SaveGameDialog::onCharacterAccept(MyGUI::ComboBox* sender, size_t pos)
{
// Give key focus to save list so we can confirm the selection with Enter
MyGUI::InputManager::getInstance().setKeyFocusWidget(mSaveList);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mSaveList);
}
void SaveGameDialog::fillSaveList()

View File

@ -38,12 +38,20 @@ namespace MWGui
if (!mRunning)
return;
if (mRemainingTime <= 0 || mStartAlpha == mTargetAlpha)
if (mStartAlpha == mTargetAlpha)
{
finish();
return;
}
if (mRemainingTime <= 0)
{
// Make sure the target alpha is applied
mFader->notifyAlphaChanged(mTargetAlpha);
finish();
return;
}
if (mRemainingTime > mTargetTime)
{
mRemainingTime -= dt;
@ -162,7 +170,7 @@ namespace MWGui
if (time < 0.f)
return;
if (time == 0.f)
if (time == 0.f && delay == 0.f)
{
mCurrentAlpha = targetAlpha;
applyAlpha();

View File

@ -1,7 +1,6 @@
#include "scrollwindow.hpp"
#include <MyGUI_ScrollView.h>
#include <MyGUI_InputManager.h>
#include <components/esm/loadbook.hpp>
#include <components/widgets/imagebutton.hpp>
@ -67,7 +66,7 @@ namespace MWGui
setTakeButtonShow(showTakeButton);
MyGUI::InputManager::getInstance().setKeyFocusWidget(mCloseButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCloseButton);
}
void ScrollWindow::onKeyButtonPressed(MyGUI::Widget *sender, MyGUI::KeyCode key, MyGUI::Char character)

View File

@ -6,7 +6,6 @@
#include <MyGUI_ScrollView.h>
#include <MyGUI_Gui.h>
#include <MyGUI_TabControl.h>
#include <MyGUI_InputManager.h>
#include <boost/algorithm/string.hpp>
@ -616,7 +615,7 @@ namespace MWGui
highlightCurrentResolution();
updateControlsBox();
resetScrollbars();
MyGUI::InputManager::getInstance().setKeyFocusWidget(mOkButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mOkButton);
}
void SettingsWindow::onWindowResize(MyGUI::Window *_sender)

View File

@ -2,7 +2,6 @@
#include <MyGUI_ImageBox.h>
#include <MyGUI_Gui.h>
#include <MyGUI_InputManager.h>
#include <components/esm/records.hpp>
#include <components/widgets/list.hpp>
@ -432,7 +431,7 @@ namespace MWGui
void SpellCreationDialog::onOpen()
{
center();
MyGUI::InputManager::getInstance().setKeyFocusWidget(mNameEdit);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mNameEdit);
}
void SpellCreationDialog::onReferenceUnavailable ()

View File

@ -83,7 +83,7 @@ namespace MWGui
// Reset the filter focus when opening the window
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
if (focus == mFilterEdit)
MyGUI::InputManager::getInstance().resetKeyFocusWidget();
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(nullptr);
updateSpells();
}

View File

@ -5,7 +5,6 @@
#include <MyGUI_EditBox.h>
#include <MyGUI_Button.h>
#include <MyGUI_InputManager.h>
namespace MWGui
{
@ -24,7 +23,7 @@ namespace MWGui
okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TextInputDialog::onOkClicked);
// Make sure the edit box has focus
MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit);
}
void TextInputDialog::setNextButtonShow(bool shown)
@ -47,7 +46,7 @@ namespace MWGui
{
WindowModal::onOpen();
// Make sure the edit box has focus
MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit);
}
// widget controls
@ -57,7 +56,7 @@ namespace MWGui
if (mTextEdit->getCaption() == "")
{
MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}");
MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget (mTextEdit);
}
else
eventDone(this);

View File

@ -136,7 +136,7 @@ namespace MWGui
onFilterChanged(mFilterAll);
MyGUI::InputManager::getInstance().setKeyFocusWidget(mTotalBalance);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTotalBalance);
}
void TradeWindow::onFrame(float dt)

View File

@ -93,9 +93,9 @@ namespace MWGui
}
if (mUntilHealedButton->getVisible())
MyGUI::InputManager::getInstance().setKeyFocusWidget(mUntilHealedButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mUntilHealedButton);
else
MyGUI::InputManager::getInstance().setKeyFocusWidget(mWaitButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mWaitButton);
}
bool WaitDialog::exit()
@ -222,7 +222,7 @@ namespace MWGui
{
mHourText->setCaptionWithReplacing (MyGUI::utility::toString(position+1) + " #{sRestMenu2}");
mManualHours = position+1;
MyGUI::InputManager::getInstance().setKeyFocusWidget(mWaitButton);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mWaitButton);
}
void WaitDialog::onKeyButtonPressed(MyGUI::Widget *sender, MyGUI::KeyCode key, MyGUI::Char character)

View File

@ -697,7 +697,7 @@ namespace MWGui
setCursorVisible(!gameMode);
if (gameMode)
MyGUI::InputManager::getInstance().resetKeyFocusWidget();
setKeyFocusWidget (nullptr);
// Icons of forced hidden windows are displayed
setMinimapVisibility((mAllowed & GW_Map) && (!mMap->pinned() || (mForceHidden & GW_Map)));
@ -1675,6 +1675,13 @@ namespace MWGui
}
}
// Remove this wrapper once onKeyFocusChanged call is rendered unnecessary
void WindowManager::setKeyFocusWidget(MyGUI::Widget *widget)
{
MyGUI::InputManager::getInstance().setKeyFocusWidget(widget);
onKeyFocusChanged(widget);
}
void WindowManager::onKeyFocusChanged(MyGUI::Widget *widget)
{
if (widget && widget->castType<MyGUI::EditBox>(false))
@ -1868,7 +1875,7 @@ namespace MWGui
sizeVideo(screenSize.width, screenSize.height);
MyGUI::Widget* oldKeyFocus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
MyGUI::InputManager::getInstance().setKeyFocusWidget(mVideoWidget);
setKeyFocusWidget(mVideoWidget);
mVideoBackground->setVisible(true);
@ -1906,7 +1913,7 @@ namespace MWGui
MWBase::Environment::get().getSoundManager()->resumeSounds();
MyGUI::InputManager::getInstance().setKeyFocusWidget(oldKeyFocus);
setKeyFocusWidget(oldKeyFocus);
setCursorVisible(cursorWasVisible);

View File

@ -147,6 +147,9 @@ namespace MWGui
/// (and will continually update the window while doing so)
virtual void playVideo(const std::string& name, bool allowSkipping);
/// Warning: do not use MyGUI::InputManager::setKeyFocusWidget directly. Instead use this.
virtual void setKeyFocusWidget (MyGUI::Widget* widget);
virtual void setNewGame(bool newgame);
virtual void pushGuiMode(GuiMode mode, const MWWorld::Ptr& arg);

View File

@ -77,6 +77,7 @@ namespace MWInput
, mSneaking(false)
, mAttemptJump(false)
, mInvUiScalingFactor(1.f)
, mGamepadCursorSpeed(Settings::Manager::getFloat("gamepad cursor speed", "Input"))
, mFakeDeviceID(1)
{
mInputManager = new SDLUtil::InputWrapper(window, viewer, grab);
@ -558,9 +559,9 @@ namespace MWInput
// We keep track of our own mouse position, so that moving the mouse while in
// game mode does not move the position of the GUI cursor
float xmove = xAxis * dt * 1500.0f * mInvUiScalingFactor;
float ymove = yAxis * dt * 1500.0f * mInvUiScalingFactor;
if (xmove != 0|| ymove != 0)
float xmove = xAxis * dt * 1500.0f * mInvUiScalingFactor * mGamepadCursorSpeed;
float ymove = yAxis * dt * 1500.0f * mInvUiScalingFactor * mGamepadCursorSpeed;
if (xmove != 0|| ymove != 0 || zAxis != 0)
{
mGuiCursorX += xmove;
mGuiCursorY += ymove;
@ -623,11 +624,7 @@ namespace MWInput
mPlayer->setAutoMove (false);
mPlayer->setForwardBackward((yAxis - 0.5f) * 2 * -1);
}
else if(mPlayer->getAutoMove())
{
triedToMove = true;
mPlayer->setForwardBackward (1);
}
if (triedToMove)
mJoystickLastUsed = true;
@ -649,7 +646,8 @@ namespace MWInput
mPlayer->setAutoMove (false);
mPlayer->setForwardBackward (actionIsActive(A_MoveForward) ? 1 : -1);
}
else if(mPlayer->getAutoMove())
if (mPlayer->getAutoMove())
{
alwaysRunAllowed = true;
triedToMove = true;

View File

@ -209,6 +209,7 @@ namespace MWInput
std::map<std::string, bool> mControlSwitch;
float mInvUiScalingFactor;
float mGamepadCursorSpeed;
private:
void convertMousePosForMyGUI(int& x, int& y);

View File

@ -551,7 +551,7 @@ namespace MWMechanics
void Actors::adjustMagicEffects (const MWWorld::Ptr& creature)
{
CreatureStats& creatureStats = creature.getClass().getCreatureStats (creature);
if (creatureStats.isDead())
if (creatureStats.isDeathAnimationFinished())
return;
MagicEffects now = creatureStats.getSpells().getMagicEffects();
@ -1665,10 +1665,6 @@ namespace MWMechanics
stats.getActiveSpells().visitEffectSources(soulTrap);
}
// Reset magic effects and recalculate derived effects
// One case where we need this is to make sure bound items are removed upon death
stats.modifyMagicEffects(MWMechanics::MagicEffects());
stats.getActiveSpells().clear();
calculateCreatureStatModifiers(iter->first, 0);
if (cls.isEssential(iter->first))
@ -1680,6 +1676,10 @@ namespace MWMechanics
++mDeathCount[Misc::StringUtils::lowerCase(iter->first.getCellRef().getRefId())];
// Reset magic effects and recalculate derived effects
// One case where we need this is to make sure bound items are removed upon death
stats.modifyMagicEffects(MWMechanics::MagicEffects());
stats.getActiveSpells().clear();
// Make sure spell effects are removed
purgeSpellEffects(stats.getActorId());

View File

@ -116,6 +116,9 @@ namespace MWMechanics
|| target.getClass().getCreatureStats(target).isDead())
return true;
if (actor == target) // This should never happen.
return true;
if (!storage.isFleeing())
{
if (storage.mCurrentAction.get()) // need to wait to init action with its attack range

View File

@ -527,7 +527,8 @@ namespace MWMechanics
if (greetingState == AiWanderStorage::Greet_None)
{
if ((playerPos - actorPos).length2() <= helloDistance*helloDistance &&
!player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getWorld()->getLOS(player, actor)
!player.getClass().getCreatureStats(player).isDead() && !actor.getClass().getCreatureStats(actor).isParalyzed()
&& MWBase::Environment::get().getWorld()->getLOS(player, actor)
&& MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, actor))
greetingTimer++;

View File

@ -1135,8 +1135,8 @@ void CharacterController::updateIdleStormState(bool inwater)
{
if (!mAnimation->isPlaying("idlestorm"))
{
mAnimation->play("idlestorm", Priority_Storm, MWRender::Animation::BlendMask_RightArm, true,
1.0f, "start", "stop", 0.0f, ~0ul);
int mask = MWRender::Animation::BlendMask_Torso | MWRender::Animation::BlendMask_RightArm;
mAnimation->play("idlestorm", Priority_Storm, mask, true, 1.0f, "start", "stop", 0.0f, ~0ul);
}
else
{
@ -2648,7 +2648,7 @@ void CharacterController::updateContinuousVfx()
for (std::vector<int>::iterator it = effects.begin(); it != effects.end(); ++it)
{
if (mPtr.getClass().getCreatureStats(mPtr).isDead()
if (mPtr.getClass().getCreatureStats(mPtr).isDeathAnimationFinished()
|| mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(MWMechanics::EffectKey(*it)).getMagnitude() <= 0)
mAnimation->removeEffect(*it);
}
@ -2675,14 +2675,14 @@ void CharacterController::setVisibility(float visibility)
if (mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Invisibility).getModifier()) // Ignore base magnitude (see bug #3555).
{
if (mPtr == getPlayer())
alpha = 0.4f;
alpha = 0.25f;
else
alpha = 0.f;
alpha = 0.05f;
}
float chameleon = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude();
if (chameleon)
{
alpha *= std::max(0.2f, (100.f - chameleon)/100.f);
alpha *= std::min(0.75f, std::max(0.25f, (100.f - chameleon)/100.f));
}
visibility = std::min(visibility, alpha);

View File

@ -115,16 +115,13 @@ namespace MWMechanics
if (Misc::Rng::roll0to99() < x)
{
if (!(weapon.isEmpty() && !attacker.getClass().isNpc())) // Unarmed creature attacks don't affect armor condition
{
// Reduce shield durability by incoming damage
int shieldhealth = shield->getClass().getItemHealth(*shield);
// Reduce shield durability by incoming damage
int shieldhealth = shield->getClass().getItemHealth(*shield);
shieldhealth -= std::min(shieldhealth, int(damage));
shield->getCellRef().setCharge(shieldhealth);
if (shieldhealth == 0)
inv.unequipItem(*shield, blocker);
}
shieldhealth -= std::min(shieldhealth, int(damage));
shield->getCellRef().setCharge(shieldhealth);
if (shieldhealth == 0)
inv.unequipItem(*shield, blocker);
// Reduce blocker fatigue
const float fFatigueBlockBase = gmst.find("fFatigueBlockBase")->mValue.getFloat();
const float fFatigueBlockMult = gmst.find("fFatigueBlockMult")->mValue.getFloat();

View File

@ -102,10 +102,7 @@ namespace MWMechanics
void Enchanting::nextCastStyle()
{
if (itemEmpty())
{
mCastStyle = ESM::Enchantment::WhenUsed;
return;
}
const bool powerfulSoul = getGemCharge() >= \
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("iSoulAmountForConstantEffect")->mValue.getInteger();
@ -267,6 +264,8 @@ namespace MWMechanics
void Enchanting::setEnchanter(const MWWorld::Ptr& enchanter)
{
mEnchanter = enchanter;
// Reset cast style
mCastStyle = ESM::Enchantment::CastOnce;
}
int Enchanting::getEnchantChance() const

View File

@ -1647,18 +1647,28 @@ namespace MWMechanics
void MechanicsManager::startCombat(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target)
{
MWMechanics::AiSequence& aiSequence = ptr.getClass().getCreatureStats(ptr).getAiSequence();
CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
if (aiSequence.isInCombat(target))
// Don't add duplicate packages nor add packages to dead actors.
if (stats.isDead() || stats.getAiSequence().isInCombat(target))
return;
aiSequence.stack(MWMechanics::AiCombat(target), ptr);
// The target is somehow the same as the actor. Early-out.
if (ptr == target)
{
// We don't care about dialogue filters since the target is invalid.
// We still want to play the combat taunt.
MWBase::Environment::get().getDialogueManager()->say(ptr, "attack");
return;
}
stats.getAiSequence().stack(MWMechanics::AiCombat(target), ptr);
if (target == getPlayer())
{
// if guard starts combat with player, guards pursuing player should do the same
if (ptr.getClass().isClass(ptr, "Guard"))
{
ptr.getClass().getCreatureStats(ptr).setHitAttemptActorId(target.getClass().getCreatureStats(target).getActorId()); // Stops guard from ending combat if player is unreachable
stats.setHitAttemptActorId(target.getClass().getCreatureStats(target).getActorId()); // Stops guard from ending combat if player is unreachable
for (Actors::PtrActorMap::const_iterator iter = mActors.begin(); iter != mActors.end(); ++iter)
{
if (iter->first.getClass().isClass(iter->first, "Guard"))
@ -1676,8 +1686,7 @@ namespace MWMechanics
}
// Must be done after the target is set up, so that CreatureTargetted dialogue filter works properly
if (ptr.getClass().isNpc() && !ptr.getClass().getCreatureStats(ptr).isDead())
MWBase::Environment::get().getDialogueManager()->say(ptr, "attack");
MWBase::Environment::get().getDialogueManager()->say(ptr, "attack");
}
void MechanicsManager::getObjectsInRange(const osg::Vec3f &position, float radius, std::vector<MWWorld::Ptr> &objects)

View File

@ -1096,21 +1096,29 @@ namespace MWScript
std::string targetId = ::Misc::StringUtils::lowerCase(runtime.getStringLiteral (runtime[0].mInteger));
runtime.pop();
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find (spellId);
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search(spellId);
if (!spell)
{
runtime.getContext().report("spellcasting failed: can not find spell \""+spellId+"\"");
runtime.getContext().report("spellcasting failed: cannot find spell \""+spellId+"\"");
return;
}
if (spell->mData.mType != ESM::Spell::ST_Spell && spell->mData.mType != ESM::Spell::ST_Power)
{
runtime.getContext().report("spellcasting failed: you can cast only spells and powers.");
runtime.getContext().report("spellcasting failed: you can only cast spells and powers.");
return;
}
// Obviously we can not use casting animation for player here
if (ptr.getClass().isActor() && ptr != MWMechanics::getPlayer())
if (ptr == MWMechanics::getPlayer())
{
MWWorld::InventoryStore& store = ptr.getClass().getInventoryStore(ptr);
store.setSelectedEnchantItem(store.end());
MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, ptr)));
MWBase::Environment::get().getWindowManager()->updateSpellWindow();
return;
}
if (ptr.getClass().isActor())
{
MWMechanics::AiCast castPackage(targetId, spellId, true);
ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(castPackage, ptr);

View File

@ -169,8 +169,8 @@ void ESMStore::validate()
if (!fact)
{
Log(Debug::Verbose) << "NPC '" << npc.mId << "' (" << npc.mName << ") has nonexistent faction '" << npc.mFaction << "', ignoring it.";
npc.mFaction = "";
npc.mNpdt.mRank = -1;
npc.mFaction.clear();
npc.mNpdt.mRank = 0;
changed = true;
}
}

View File

@ -2808,6 +2808,7 @@ namespace MWWorld
/// \note Using _any_ door pointed to the interior,
/// not the one pointed to current door.
pos = destDoor.mRef.getDoorDest();
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
return true;
}
}
@ -2818,6 +2819,7 @@ namespace MWWorld
if (!statics.empty())
{
pos = statics.begin()->mRef.getPosition();
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
return true;
}

View File

@ -33,7 +33,7 @@ namespace Compiler
{
extensions.registerInstruction ("aiactivate", "c/l", opcodeAIActivate,
opcodeAIActivateExplicit);
extensions.registerInstruction ("aitravel", "fff/lx", opcodeAiTravel,
extensions.registerInstruction ("aitravel", "fff/zx", opcodeAiTravel,
opcodeAiTravelExplicit);
extensions.registerInstruction ("aiescort", "cffff/l", opcodeAiEscort,
opcodeAiEscortExplicit);

View File

@ -428,7 +428,7 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path)
{
QFileInfo info(dir.absoluteFilePath(path2));
if (item(info.absoluteFilePath()) != 0)
if (item(info.fileName()))
continue;
try {

View File

@ -16,7 +16,7 @@ struct CustomMarker
std::string mNote;
bool operator == (const CustomMarker& other)
bool operator == (const CustomMarker& other) const
{
return mNote == other.mNote && mCell == other.mCell && mWorldX == other.mWorldX && mWorldY == other.mWorldY;
}

View File

@ -40,7 +40,7 @@ struct Clothing
int mType;
float mWeight;
unsigned short mValue;
short mEnchant;
unsigned short mEnchant;
};
CTDTstruct mData;

View File

@ -59,7 +59,7 @@ struct Weapon
short mType;
unsigned short mHealth;
float mSpeed, mReach;
short mEnchant; // Enchantment points. The real value is mEnchant/10.f
unsigned short mEnchant; // Enchantment points. The real value is mEnchant/10.f
unsigned char mChop[2], mSlash[2], mThrust[2]; // Min and max
int mFlags;
}; // 32 bytes

View File

@ -4,8 +4,10 @@
#include <pwd.h>
#include <unistd.h>
#include <linux/limits.h>
#include <boost/filesystem/fstream.hpp>
#include <components/debug/debuglog.hpp>
#include <components/misc/stringops.hpp>
@ -50,6 +52,9 @@ namespace Files
LinuxPath::LinuxPath(const std::string& application_name)
: mName(application_name)
{
boost::filesystem::path localPath = getLocalPath();
if (chdir(localPath.string().c_str()) != 0)
Log(Debug::Warning) << "Error " << errno << " when changing current directory";
}
boost::filesystem::path LinuxPath::getUserConfigPath() const
@ -75,7 +80,21 @@ boost::filesystem::path LinuxPath::getGlobalConfigPath() const
boost::filesystem::path LinuxPath::getLocalPath() const
{
return boost::filesystem::path("./");
boost::filesystem::path localPath("./");
char binPath[PATH_MAX];
memset(binPath, 0, sizeof(binPath));
const char *statusPaths[] = {"/proc/self/exe", "/proc/self/file", "/proc/curproc/exe", "/proc/curproc/file"};
for(const char *path : statusPaths)
{
if (readlink(path, binPath, sizeof(binPath)) != -1)
{
localPath = boost::filesystem::path(binPath).parent_path();
break;
}
}
return localPath;
}
boost::filesystem::path LinuxPath::getGlobalDataPath() const

View File

@ -9,11 +9,31 @@ namespace Files
struct MemBuf : std::streambuf
{
MemBuf(char const* buffer, size_t size)
{
// a streambuf isn't specific to istreams, so we need a non-const pointer :/
char* nonconstBuffer = (const_cast<char*>(buffer));
this->setg(nonconstBuffer, nonconstBuffer, nonconstBuffer + size);
: bufferStart(const_cast<char*>(buffer))
, bufferEnd(bufferStart + size)
{
this->setg(bufferStart, bufferStart, bufferEnd);
}
pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode which) override
{
if (dir == std::ios_base::cur)
gbump(off);
else
setg(bufferStart, (dir == std::ios_base::beg ? bufferStart : bufferEnd) + off, bufferEnd);
return gptr() - bufferStart;
}
pos_type seekpos(pos_type pos, std::ios_base::openmode which) override
{
return seekoff(pos, std::ios_base::beg, which);
}
protected:
char* bufferStart;
char* bufferEnd;
};
/// @brief A variant of std::istream that reads from a constant in-memory buffer.

View File

@ -11,6 +11,8 @@
#include <boost/locale.hpp>
namespace bconv = boost::locale::conv;
#include <components/debug/debuglog.hpp>
/**
* FIXME: Someone with Windows system should check this and correct if necessary
* FIXME: MAX_PATH is irrelevant for extended-length paths, i.e. \\?\...
@ -33,6 +35,10 @@ WindowsPath::WindowsPath(const std::string& application_name)
See boost::filesystem and boost::locale reference for details.
*/
boost::filesystem::path::imbue(boost::locale::generator().generate(""));
boost::filesystem::path localPath = getLocalPath();
if (!SetCurrentDirectoryA(localPath.string().c_str()))
Log(Debug::Warning) << "Error " << GetLastError() << " when changing current directory";
}
boost::filesystem::path WindowsPath::getUserConfigPath() const
@ -73,7 +79,17 @@ boost::filesystem::path WindowsPath::getGlobalConfigPath() const
boost::filesystem::path WindowsPath::getLocalPath() const
{
return boost::filesystem::path("./");
boost::filesystem::path localPath("./");
WCHAR path[MAX_PATH + 1];
memset(path, 0, sizeof(path));
if (GetModuleFileNameW(nullptr, path, MAX_PATH + 1) > 0)
{
localPath = boost::filesystem::path(bconv::utf_to_utf<char>(path)).parent_path();
}
// lookup exe path
return localPath;
}
boost::filesystem::path WindowsPath::getGlobalDataPath() const

View File

@ -238,10 +238,12 @@ struct NiRotatingParticles : Node
// A node used as the base to switch between child nodes, such as for LOD levels.
struct NiSwitchNode : public NiNode
{
unsigned int initialIndex;
void read(NIFStream *nif)
{
NiNode::read(nif);
nif->getInt(); // unknown
initialIndex = nif->getUInt();
}
};

View File

@ -400,7 +400,10 @@ namespace NifOsg
return;
}
osg::ref_ptr<osg::Texture2D> texture2d (new osg::Texture2D(handleSourceTexture(textureEffect->texture.getPtr(), imageManager)));
osg::ref_ptr<osg::Image> image (handleSourceTexture(textureEffect->texture.getPtr(), imageManager));
osg::ref_ptr<osg::Texture2D> texture2d (new osg::Texture2D(image));
if (image)
texture2d->setTextureSize(image->s(), image->t());
texture2d->setName("envMap");
unsigned int clamp = static_cast<unsigned int>(textureEffect->clamp);
int wrapT = (clamp) & 0x1;
@ -585,8 +588,11 @@ namespace NifOsg
{
const Nif::NiTriShape* triShape = static_cast<const Nif::NiTriShape*>(nifNode);
const std::string nodeName = Misc::StringUtils::lowerCase(triShape->name);
static const std::string pattern = "tri editormarker";
if (!hasMarkers || nodeName.compare(0, pattern.size(), pattern) != 0)
static const std::string markerName = "tri editormarker";
static const std::string shadowName = "shadow";
static const std::string shadowName2 = "tri shadow";
const bool isMarker = hasMarkers && !nodeName.compare(0, markerName.size(), markerName);
if (!isMarker && nodeName.compare(0, shadowName.size(), shadowName) && nodeName.compare(0, shadowName2.size(), shadowName2))
{
if (triShape->skin.empty())
handleTriShape(triShape, node, composite, boundTextures, animflags);
@ -629,10 +635,8 @@ namespace NifOsg
if (nifNode->recType == Nif::RC_NiSwitchNode)
{
// show only first child by default
node->asSwitch()->setSingleChildOn(0);
const Nif::NiSwitchNode* niSwitchNode = static_cast<const Nif::NiSwitchNode*>(nifNode);
node->asSwitch()->setSingleChildOn(niSwitchNode->initialIndex);
if (niSwitchNode->name == Constants::NightDayLabel && !SceneUtil::hasUserDescription(rootNode, Constants::NightDayLabel))
rootNode->getOrCreateUserDataContainer()->addDescription(Constants::NightDayLabel);
else if (niSwitchNode->name == Constants::HerbalismLabel && !SceneUtil::hasUserDescription(rootNode, Constants::HerbalismLabel))
@ -770,7 +774,10 @@ namespace NifOsg
wrapT = inherit->getWrap(osg::Texture2D::WRAP_T);
}
osg::ref_ptr<osg::Texture2D> texture (new osg::Texture2D(handleSourceTexture(st.getPtr(), imageManager)));
osg::ref_ptr<osg::Image> image (handleSourceTexture(st.getPtr(), imageManager));
osg::ref_ptr<osg::Texture2D> texture (new osg::Texture2D(image));
if (image)
texture->setTextureSize(image->s(), image->t());
texture->setWrap(osg::Texture::WRAP_S, wrapS);
texture->setWrap(osg::Texture::WRAP_T, wrapT);
textures.push_back(texture);
@ -1337,6 +1344,8 @@ namespace NifOsg
const Nif::NiSourceTexture *st = tex.texture.getPtr();
osg::ref_ptr<osg::Image> image = handleSourceTexture(st, imageManager);
texture2d = new osg::Texture2D(image);
if (image)
texture2d->setTextureSize(image->s(), image->t());
}
else
texture2d = new osg::Texture2D;

View File

@ -1802,12 +1802,11 @@ bool Optimizer::MergeGeometryVisitor::mergePrimitive(osg::DrawElementsUInt& lhs,
bool Optimizer::MergeGroupsVisitor::isOperationPermissible(osg::Group& node)
{
return !node.asSwitch() &&
!node.asTransform() &&
!node.getCullCallback() &&
return !node.getCullCallback() &&
!node.getEventCallback() &&
!node.getUpdateCallback() &&
isOperationPermissibleForObject(&node);
isOperationPermissibleForObject(&node) &&
typeid(node)==typeid(osg::Group);
}
void Optimizer::MergeGroupsVisitor::apply(osg::LOD &lod)

View File

@ -163,6 +163,7 @@ namespace Shader
if (image)
{
osg::ref_ptr<osg::Texture2D> normalMapTex (new osg::Texture2D(image));
normalMapTex->setTextureSize(image->s(), image->t());
normalMapTex->setWrap(osg::Texture::WRAP_S, diffuseMap->getWrap(osg::Texture::WRAP_S));
normalMapTex->setWrap(osg::Texture::WRAP_T, diffuseMap->getWrap(osg::Texture::WRAP_T));
normalMapTex->setFilter(osg::Texture::MIN_FILTER, diffuseMap->getFilter(osg::Texture::MIN_FILTER));
@ -186,7 +187,9 @@ namespace Shader
boost::replace_last(specularMapFileName, ".", mSpecularMapPattern + ".");
if (mImageManager.getVFS()->exists(specularMapFileName))
{
osg::ref_ptr<osg::Texture2D> specularMapTex (new osg::Texture2D(mImageManager.getImage(specularMapFileName)));
osg::ref_ptr<osg::Image> image (mImageManager.getImage(specularMapFileName));
osg::ref_ptr<osg::Texture2D> specularMapTex (new osg::Texture2D(image));
specularMapTex->setTextureSize(image->s(), image->t());
specularMapTex->setWrap(osg::Texture::WRAP_S, diffuseMap->getWrap(osg::Texture::WRAP_S));
specularMapTex->setWrap(osg::Texture::WRAP_T, diffuseMap->getWrap(osg::Texture::WRAP_T));
specularMapTex->setFilter(osg::Texture::MIN_FILTER, diffuseMap->getFilter(osg::Texture::MIN_FILTER));

View File

@ -133,3 +133,16 @@ which are always sent if a controller is present and detected.
Disabling this setting can be useful for working around controller-related issues or for setting up split-screen gameplay configurations.
This setting can be toggled in game with the Enable Joystick button in the Controls panel of the Options menu.
gamepad cursor speed
--------------------
:Type: float
:Range: >0
:Default: 1.0
This setting controls the speed of the cursor within GUI mode when using the joystick.
This setting has no effect on the camera rotation speed, which is controlled by the
camera sensitivity setting.
This setting can only be configured by editing the settings configuration file.

View File

@ -19,6 +19,11 @@
<Child type="Button" skin="MW_Box" offset="18 0 54 14" align="Stretch" name="Background"/>
<!-- These are only provided to get mouse input, they should have no skin and be transparent -->
<Child type="Button" skin="MW_ScrollEmptyPart" offset="14 0 24 14" align="Top HStretch" name="FirstPart"/>
<Child type="Button" skin="MW_ScrollEmptyPart" offset="52 0 24 14" align="Top HStretch" name="SecondPart"/>
<!-- Arrows -->
<Child type="Widget" skin="MW_Box" offset="0 0 15 14" align="Left VStretch"/>
@ -27,11 +32,6 @@
<Child type="Widget" skin="MW_Box" offset="75 0 15 14" align="Right VStretch"/>
<Child type="Button" skin="MW_ArrowRight" offset="77 2 10 10" align="Right VStretch" name="End"/>
<!-- These are only provided to get mouse input, they should have no skin and be transparent -->
<Child type="Button" skin="MW_ScrollEmptyPart" offset="14 0 24 14" align="Top HStretch" name="FirstPart"/>
<Child type="Button" skin="MW_ScrollEmptyPart" offset="52 0 24 14" align="Top HStretch" name="SecondPart"/>
<Child type="Button" skin="MW_ScrollTrackH" offset="38 2 30 9" align="Left VStretch" name="Track"/>
</Resource>
@ -61,6 +61,11 @@
<Child type="Button" skin="MW_Box" offset="0 18 14 55" align="Stretch" name="Background"/>
<!-- These are only provided to get mouse input, they should have no skin and be transparent -->
<Child type="Button" skin="MW_ScrollEmptyPart" offset="0 14 24 14" align="Left VStretch" name="FirstPart"/>
<Child type="Button" skin="MW_ScrollEmptyPart" offset="0 52 24 14" align="Left VStretch" name="SecondPart"/>
<!-- Arrows -->
<Child type="Widget" skin="MW_Box" offset="0 0 14 15" align="Top HStretch"/>
@ -69,11 +74,6 @@
<Child type="Widget" skin="MW_Box" offset="0 76 14 15" align="Bottom HStretch"/>
<Child type="Button" skin="MW_ArrowDown" offset="2 78 10 10" align="Bottom HStretch" name="End"/>
<!-- These are only provided to get mouse input, they should have no skin and be transparent -->
<Child type="Button" skin="MW_ScrollEmptyPart" offset="0 14 24 14" align="Left VStretch" name="FirstPart"/>
<Child type="Button" skin="MW_ScrollEmptyPart" offset="0 52 24 14" align="Left VStretch" name="SecondPart"/>
<!-- Tracker must be last to be on top and receive mouse events -->
<Child type="Button" skin="MW_ScrollTrackV" offset="2 40 9 30" align="Top HStretch" name="Track"/>

View File

@ -364,6 +364,9 @@ invert y axis = false
# Enable controller support.
enable controller = true
# Emulated gamepad cursor sensitivity.
gamepad cursor speed = 1.0
[Saves]
# Name of last character played, and default for loading save files.