Merge branch 'master' into ref

actorid
Marc Zinnschlag 12 years ago
commit 4986b7d65d

@ -14,9 +14,8 @@ before_install:
- sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock libzzip-dev
- sudo apt-get install -qq libqt4-dev libxaw7-dev libxrandr-dev libfreeimage-dev libpng-dev
- sudo apt-get install -qq libopenal-dev libmpg123-dev libsndfile1-dev
- sudo apt-get install -qq libcg nvidia-cg-toolkit
- sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev
- sudo apt-get install -qq libois-dev libbullet-dev libogre-static-dev libmygui-static-dev
- sudo apt-get install -qq libbullet-dev libogre-static-dev libmygui-static-dev libsdl2-static-dev
- sudo mkdir /usr/src/gtest/build
- cd /usr/src/gtest/build
- sudo cmake .. -DBUILD_SHARED_LIBS=1
@ -27,7 +26,7 @@ before_script:
- cd -
- mkdir build
- cd build
- cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1
- cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 -DBOOST_STATIC=1 -DSDL2_STATIC=1 -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1
script:
- make -j4
after_script:

@ -4,6 +4,10 @@ if (APPLE)
set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app")
set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}")
set(CMAKE_EXE_LINKER_FLAGS "-F /Library/Frameworks")
set(CMAKE_SHARED_LINKER_FLAGS "-F /Library/Frameworks")
set(CMAKE_MODULE_LINKER_FLAGS "-F /Library/Frameworks")
endif (APPLE)
# Macros
@ -15,7 +19,7 @@ include (OpenMWMacros)
# Version
set (OPENMW_VERSION_MAJOR 0)
set (OPENMW_VERSION_MINOR 23)
set (OPENMW_VERSION_MINOR 24)
set (OPENMW_VERSION_RELEASE 0)
set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
@ -27,6 +31,7 @@ configure_file ("${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp.cmake" "${OpenMW_SOURCE_
option(MYGUI_STATIC "Link static build of Mygui into the binaries" FALSE)
option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries" FALSE)
option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE)
option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE)
# Apps and tools
option(BUILD_BSATOOL "build BSA extractor" OFF)
@ -77,7 +82,13 @@ set(OENGINE_OGRE
${LIBDIR}/openengine/ogre/fader.cpp
${LIBDIR}/openengine/ogre/particles.cpp
${LIBDIR}/openengine/ogre/selectionbuffer.cpp
${LIBDIR}/openengine/ogre/imagerotate.cpp
)
if (APPLE)
set(OENGINE_OGRE ${OENGINE_OGRE} ${LIBDIR}/openengine/ogre/osx_utils.mm)
endif ()
set(OENGINE_GUI
${LIBDIR}/openengine/gui/manager.cpp
)
@ -181,6 +192,12 @@ if (UNIX AND NOT APPLE)
find_package (Threads)
endif()
include (CheckIncludeFileCXX)
check_include_file_cxx(unordered_map HAVE_UNORDERED_MAP)
if (HAVE_UNORDERED_MAP)
add_definitions(-DHAVE_UNORDERED_MAP)
endif ()
set(BOOST_COMPONENTS system filesystem program_options thread date_time wave)
@ -191,7 +208,7 @@ endif()
find_package(OGRE REQUIRED)
find_package(MyGUI REQUIRED)
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
find_package(OIS REQUIRED)
find_package(SDL2 REQUIRED)
find_package(OpenAL REQUIRED)
find_package(Bullet REQUIRED)
IF(OGRE_STATIC)
@ -205,7 +222,8 @@ ENDIF(OGRE_STATIC)
include_directories("."
${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_PLUGIN_INCLUDE_DIRS}
${OGRE_Terrain_INCLUDE_DIR}
${OIS_INCLUDE_DIRS} ${Boost_INCLUDE_DIR}
${SDL2_INCLUDE_DIR}
${Boost_INCLUDE_DIR}
${PLATFORM_INCLUDE_DIR}
${MYGUI_INCLUDE_DIRS}
${MYGUI_PLATFORM_INCLUDE_DIRS}
@ -214,7 +232,7 @@ include_directories("."
${LIBDIR}
)
link_directories(${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR})
link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR})
if (APPLE)
# List used Ogre plugins
@ -287,9 +305,12 @@ configure_file(${OpenMW_SOURCE_DIR}/files/transparency-overrides.cfg
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local
"${OpenMW_BINARY_DIR}/openmw.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
"${OpenMW_BINARY_DIR}/openmw.cfg.install")
configure_file(${OpenMW_SOURCE_DIR}/files/opencs.cfg
"${OpenMW_BINARY_DIR}/opencs.cfg")
if (NOT WIN32 AND NOT APPLE)
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop
@ -300,15 +321,15 @@ endif()
# Compiler settings
if (CMAKE_COMPILER_IS_GNUCC)
add_definitions (-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long)
SET(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}")
# Silence warnings in OGRE headers. Remove once OGRE got fixed!
add_definitions (-Wno-ignored-qualifiers)
SET(CMAKE_CXX_FLAGS "-Wno-ignored-qualifiers ${CMAKE_CXX_FLAGS}")
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
OUTPUT_VARIABLE GCC_VERSION)
if ("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6)
add_definitions (-Wno-unused-but-set-parameter)
SET(CMAKE_CXX_FLAGS "-Wno-unused-but-set-parameter ${CMAKE_CXX_FLAGS}")
endif("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6)
endif (CMAKE_COMPILER_IS_GNUCC)
@ -334,6 +355,7 @@ if(DPKG_PROGRAM)
INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "../etc/openmw/" RENAME "openmw.cfg" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
#Install resources
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "share/games/openmw/" FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT "Resources")
@ -349,8 +371,8 @@ if(DPKG_PROGRAM)
Data files from the original game is required to run it.")
SET(CPACK_DEBIAN_PACKAGE_NAME "openmw")
SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}")
SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW bsatool;Bsatool esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter")
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libois-1.3.0 (>= 1.3.0), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2), libqtgui4 (>= 4.7.0)")
SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW bsatool;Bsatool esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter")
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2), libqtgui4 (>= 4.7.0)")
SET(CPACK_DEBIAN_PACKAGE_SECTION "Games")
@ -437,6 +459,7 @@ endif(WIN32)
# Extern
add_subdirectory (extern/shiny)
add_subdirectory (extern/oics)
add_subdirectory (extern/sdl4ogre)
# Components
add_subdirectory (components)
@ -572,6 +595,7 @@ if (APPLE)
install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/opencs.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
set(CPACK_GENERATOR "DragNDrop")
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
@ -687,6 +711,7 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE)
#INSTALL(FILES "${OpenMW_BINARY_DIR}/plugins.cfg" DESTINATION "${SYSCONFDIR}" )
INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" )
INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" )
INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.cfg" DESTINATION "${SYSCONFDIR}" )
# Install resources
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" )

@ -17,11 +17,6 @@ target_link_libraries(esmtool
components
)
#if (APPLE)
# find_library(CARBON_FRAMEWORK Carbon)
# target_link_libraries(openmw ${CARBON_FRAMEWORK})
#endif (APPLE)
if (BUILD_WITH_CODE_COVERAGE)
add_definitions (--coverage)
target_link_libraries(esmtool gcov)

@ -108,11 +108,26 @@ bool parseOptions (int argc, char** argv, Arguments &info)
// there might be a better way to do this
bpo::options_description all;
all.add(desc).add(hidden);
bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv)
.options(all).positional(p).run();
bpo::variables_map variables;
bpo::store(valid_opts, variables);
try
{
bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv)
.options(all).positional(p).run();
bpo::store(valid_opts, variables);
}
catch(boost::program_options::unknown_option & x)
{
std::cerr << "ERROR: " << x.what() << std::endl;
return false;
}
catch(boost::program_options::invalid_command_line_syntax & x)
{
std::cerr << "ERROR: " << x.what() << std::endl;
return false;
}
bpo::notify(variables);
if (variables.count ("help"))

@ -90,6 +90,7 @@ target_link_libraries(omwlauncher
${Boost_LIBRARIES}
${OGRE_LIBRARIES}
${OGRE_STATIC_PLUGINS}
${SDL2_LIBRARY}
${QT_LIBRARIES}
components
)

@ -3,6 +3,7 @@
#include <QDesktopWidget>
#include <QMessageBox>
#include <QDir>
#include <SDL.h>
#include <cstdlib>
@ -35,13 +36,14 @@ GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &g
setupUi(this);
// Set the maximum res we can set in windowed mode
QRect res = QApplication::desktop()->screenGeometry();
QRect res = getMaximumResolution();
customWidthSpinBox->setMaximum(res.width());
customHeightSpinBox->setMaximum(res.height());
connect(rendererComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(rendererChanged(const QString&)));
connect(fullScreenCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotFullScreenChanged(int)));
connect(standardRadioButton, SIGNAL(toggled(bool)), this, SLOT(slotStandardToggled(bool)));
connect(screenComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(screenChanged(int)));
}
@ -144,17 +146,41 @@ bool GraphicsPage::setupOgre()
}
antiAliasingComboBox->clear();
resolutionComboBox->clear();
antiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem));
resolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem));
// Load the rest of the values
loadSettings();
return true;
}
void GraphicsPage::loadSettings()
bool GraphicsPage::setupSDL()
{
int displays = SDL_GetNumVideoDisplays();
if (displays < 0)
{
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error receiving number of screens"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>SDL_GetNumDisplayModes failed:</b><br><br>") + QString::fromStdString(SDL_GetError()) + "<br>");
msgBox.exec();
return false;
}
for (int i = 0; i < displays; i++)
{
screenComboBox->addItem(QString(tr("Screen ")) + QString::number(i + 1));
}
return true;
}
bool GraphicsPage::loadSettings()
{
if (!setupSDL())
return false;
if (!setupOgre())
return false;
if (mGraphicsSettings.value(QString("Video/vsync")) == QLatin1String("true"))
vSyncCheckBox->setCheckState(Qt::Checked);
@ -168,6 +194,9 @@ void GraphicsPage::loadSettings()
QString width = mGraphicsSettings.value(QString("Video/resolution x"));
QString height = mGraphicsSettings.value(QString("Video/resolution y"));
QString resolution = width + QString(" x ") + height;
QString screen = mGraphicsSettings.value(QString("Video/screen"));
screenComboBox->setCurrentIndex(screen.toInt());
int resIndex = resolutionComboBox->findText(resolution, Qt::MatchStartsWith);
@ -180,6 +209,8 @@ void GraphicsPage::loadSettings()
customHeightSpinBox->setValue(height.toInt());
}
return true;
}
void GraphicsPage::saveSettings()
@ -205,6 +236,8 @@ void GraphicsPage::saveSettings()
mGraphicsSettings.setValue(QString("Video/resolution x"), QString::number(customWidthSpinBox->value()));
mGraphicsSettings.setValue(QString("Video/resolution y"), QString::number(customHeightSpinBox->value()));
}
mGraphicsSettings.setValue(QString("Video/screen"), QString::number(screenComboBox->currentIndex()));
}
QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer)
@ -240,64 +273,83 @@ QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSy
return result;
}
QStringList GraphicsPage::getAvailableResolutions(Ogre::RenderSystem *renderer)
QStringList GraphicsPage::getAvailableResolutions(int screen)
{
QString key("Video Mode");
QStringList result;
SDL_DisplayMode mode;
int modeIndex, modes = SDL_GetNumDisplayModes(screen);
uint row = 0;
Ogre::ConfigOptionMap options = renderer->getConfigOptions();
for (Ogre::ConfigOptionMap::iterator i = options.begin (); i != options.end (); i++, row++)
if (modes < 0)
{
if (key.toStdString() != i->first)
continue;
Ogre::StringVector::iterator opt_it;
uint idx = 0;
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error receiving resolutions"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>SDL_GetNumDisplayModes failed:</b><br><br>") + QString::fromStdString(SDL_GetError()) + "<br>");
msgBox.exec();
return result;
}
for (opt_it = i->second.possibleValues.begin ();
opt_it != i->second.possibleValues.end (); opt_it++, idx++)
for (modeIndex = 0; modeIndex < modes; modeIndex++)
{
if (SDL_GetDisplayMode(screen, modeIndex, &mode) < 0)
{
QRegExp resolutionRe(QString("(\\d+) x (\\d+).*"));
QString resolution = QString::fromStdString(*opt_it).simplified();
if (resolutionRe.exactMatch(resolution)) {
int width = resolutionRe.cap(1).toInt();
int height = resolutionRe.cap(2).toInt();
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error receiving resolutions"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>SDL_GetDisplayMode failed:</b><br><br>") + QString::fromStdString(SDL_GetError()) + "<br>");
msgBox.exec();
return result;
}
QString aspect = getAspect(width, height);
QString cleanRes = resolutionRe.cap(1) + QString(" x ") + resolutionRe.cap(2);
QString aspect = getAspect(mode.w, mode.h);
QString resolution = QString::number(mode.w) + QString(" x ") + QString::number(mode.h);
if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10")) {
cleanRes.append(tr("\t(Wide ") + aspect + ")");
if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10")) {
resolution.append(tr("\t(Wide ") + aspect + ")");
} else if (aspect == QLatin1String("4:3")) {
cleanRes.append(tr("\t(Standard 4:3)"));
}
// do not add duplicate resolutions
if (!result.contains(cleanRes))
result.append(cleanRes);
}
} else if (aspect == QLatin1String("4:3")) {
resolution.append(tr("\t(Standard 4:3)"));
}
}
// Sort the resolutions in descending order
qSort(result.begin(), result.end(), naturalSortGreaterThanCI);
result.append(resolution);
}
result.removeDuplicates();
return result;
}
QRect GraphicsPage::getMaximumResolution()
{
QRect max;
int screens = QApplication::desktop()->screenCount();
for (int i = 0; i < screens; ++i)
{
QRect res = QApplication::desktop()->screenGeometry(i);
if (res.width() > max.width())
max.setWidth(res.width());
if (res.height() > max.height())
max.setHeight(res.height());
}
return max;
}
void GraphicsPage::rendererChanged(const QString &renderer)
{
mSelectedRenderSystem = mOgre->getRenderSystemByName(renderer.toStdString());
antiAliasingComboBox->clear();
resolutionComboBox->clear();
antiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem));
resolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem));
}
void GraphicsPage::screenChanged(int screen)
{
if (screen >= 0) {
resolutionComboBox->clear();
resolutionComboBox->addItems(getAvailableResolutions(screen));
}
}
void GraphicsPage::slotFullScreenChanged(int state)

@ -30,10 +30,11 @@ public:
GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSettings, QWidget *parent = 0);
void saveSettings();
bool setupOgre();
bool loadSettings();
public slots:
void rendererChanged(const QString &renderer);
void screenChanged(int screen);
private slots:
void slotFullScreenChanged(int state);
@ -55,10 +56,11 @@ private:
GraphicsSettings &mGraphicsSettings;
QStringList getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer);
QStringList getAvailableResolutions(Ogre::RenderSystem *renderer);
void loadSettings();
QStringList getAvailableResolutions(int screen);
QRect getMaximumResolution();
bool setupOgre();
bool setupSDL();
};
#endif

@ -1,11 +1,23 @@
#include <QApplication>
#include <QTextCodec>
#include <QDir>
#include <QDebug>
#include <SDL.h>
#include "maindialog.hpp"
// SDL workaround
#include "graphicspage.hpp"
int main(int argc, char *argv[])
{
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
qDebug() << "SDL_Init failed: " << QString::fromStdString(SDL_GetError());
return 0;
}
QApplication app(argc, argv);
// Now we make sure the current dir is set to application path
@ -41,6 +53,8 @@ int main(int argc, char *argv[])
return 0;
}
return app.exec();
int returnValue = app.exec();
SDL_Quit();
return returnValue;
}

@ -292,8 +292,8 @@ bool MainDialog::setup()
// Now create the pages as they need the settings
createPages();
// Call this so we can exit on Ogre errors before mainwindow is shown
if (!mGraphicsPage->setupOgre())
// Call this so we can exit on Ogre/SDL errors before mainwindow is shown
if (!mGraphicsPage->loadSettings())
return false;
loadSettings();
@ -310,6 +310,8 @@ void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous)
bool MainDialog::setupLauncherSettings()
{
mLauncherSettings.setMultiValueEnabled(true);
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
QStringList paths;
@ -427,6 +429,8 @@ bool MainDialog::setupGameSettings()
bool MainDialog::setupGraphicsSettings()
{
mGraphicsSettings.setMultiValueEnabled(false);
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string());
@ -608,8 +612,21 @@ void MainDialog::closeEvent(QCloseEvent *event)
void MainDialog::play()
{
if (!writeSettings())
if (!writeSettings()) {
qApp->quit();
return;
}
if(!mGameSettings.hasMaster()) {
QMessageBox msgBox;
msgBox.setWindowTitle(tr("No master file selected"));
msgBox.setIcon(QMessageBox::Warning);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>You do not have any master files selected.</b><br><br> \
OpenMW will not start without a master file selected.<br>"));
msgBox.exec();
return;
}
// Launch the game detached
startProgram(QString("openmw"), true);

@ -6,8 +6,6 @@
#include <QRegExp>
#include <QMap>
#include <QDebug>
#include <components/files/configurationmanager.hpp>
#include <boost/version.hpp>
@ -103,8 +101,8 @@ bool GameSettings::readFile(QTextStream &stream)
if (keyRe.indexIn(line) != -1) {
QString key = keyRe.cap(1);
QString value = keyRe.cap(2);
QString key = keyRe.cap(1).trimmed();
QString value = keyRe.cap(2).trimmed();
// Don't remove existing data entries
if (key != QLatin1String("data"))

@ -43,6 +43,7 @@ public:
inline QStringList getDataDirs() { return mDataDirs; }
inline void addDataDir(const QString &dir) { if(!dir.isEmpty()) mDataDirs.append(dir); }
inline QString getDataLocal() {return mDataLocal; }
inline bool hasMaster() { return mSettings.count(QString("master")) > 0; }
QStringList values(const QString &key, const QStringList &defaultValues = QStringList());
bool readFile(QTextStream &stream);

@ -7,14 +7,12 @@
#include <QRegExp>
#include <QMap>
#include <QDebug>
template <class Map>
class SettingsBase
{
public:
SettingsBase() {}
SettingsBase() { mMultiValue = false; }
~SettingsBase() {}
inline QString value(const QString &key, const QString &defaultValue = QString())
@ -36,6 +34,11 @@ public:
mSettings.insertMulti(key, value);
}
inline void setMultiValueEnabled(bool enable)
{
mMultiValue = enable;
}
inline void remove(const QString &key)
{
mSettings.remove(key);
@ -66,8 +69,8 @@ public:
if (keyRe.indexIn(line) != -1) {
QString key = keyRe.cap(1);
QString value = keyRe.cap(2);
QString key = keyRe.cap(1).trimmed();
QString value = keyRe.cap(2).trimmed();
if (!sectionPrefix.isEmpty())
key.prepend(sectionPrefix);
@ -75,8 +78,13 @@ public:
mSettings.remove(key);
QStringList values = mCache.values(key);
if (!values.contains(value)) {
mCache.insertMulti(key, value);
if (mMultiValue) {
mCache.insertMulti(key, value);
} else {
mCache.insert(key, value);
}
}
}
}
@ -94,6 +102,8 @@ public:
private:
Map mSettings;
Map mCache;
bool mMultiValue;
};
#endif // SETTINGSBASE_HPP

@ -645,7 +645,7 @@ std::string MwIniImporter::numberToString(int n) {
return str.str();
}
MwIniImporter::multistrmap MwIniImporter::loadIniFile(std::string filename) {
MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filename) const {
std::cout << "load ini file: " << filename << std::endl;
std::string section("");
@ -701,7 +701,7 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(std::string filename) {
return map;
}
MwIniImporter::multistrmap MwIniImporter::loadCfgFile(std::string filename) {
MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const std::string& filename) {
std::cout << "load cfg file: " << filename << std::endl;
MwIniImporter::multistrmap map;
@ -738,12 +738,11 @@ MwIniImporter::multistrmap MwIniImporter::loadCfgFile(std::string filename) {
return map;
}
void MwIniImporter::merge(multistrmap &cfg, multistrmap &ini) {
multistrmap::iterator cfgIt;
multistrmap::iterator iniIt;
for(strmap::iterator it=mMergeMap.begin(); it!=mMergeMap.end(); ++it) {
void MwIniImporter::merge(multistrmap &cfg, const multistrmap &ini) const {
multistrmap::const_iterator iniIt;
for(strmap::const_iterator it=mMergeMap.begin(); it!=mMergeMap.end(); ++it) {
if((iniIt = ini.find(it->second)) != ini.end()) {
for(std::vector<std::string>::iterator vc = iniIt->second.begin(); vc != iniIt->second.end(); ++vc) {
for(std::vector<std::string>::const_iterator vc = iniIt->second.begin(); vc != iniIt->second.end(); ++vc) {
cfg.erase(it->first);
insertMultistrmap(cfg, it->first, *vc);
}
@ -751,14 +750,13 @@ void MwIniImporter::merge(multistrmap &cfg, multistrmap &ini) {
}
}
void MwIniImporter::mergeFallback(multistrmap &cfg, multistrmap &ini) {
void MwIniImporter::mergeFallback(multistrmap &cfg, const multistrmap &ini) const {
cfg.erase("fallback");
multistrmap::iterator cfgIt;
multistrmap::iterator iniIt;
for(std::vector<std::string>::iterator it=mMergeFallback.begin(); it!=mMergeFallback.end(); ++it) {
multistrmap::const_iterator iniIt;
for(std::vector<std::string>::const_iterator it=mMergeFallback.begin(); it!=mMergeFallback.end(); ++it) {
if((iniIt = ini.find(*it)) != ini.end()) {
for(std::vector<std::string>::iterator vc = iniIt->second.begin(); vc != iniIt->second.end(); ++vc) {
for(std::vector<std::string>::const_iterator vc = iniIt->second.begin(); vc != iniIt->second.end(); ++vc) {
std::string value(*it);
std::replace( value.begin(), value.end(), ' ', '_' );
std::replace( value.begin(), value.end(), ':', '_' );
@ -769,21 +767,21 @@ void MwIniImporter::mergeFallback(multistrmap &cfg, multistrmap &ini) {
}
}
void MwIniImporter::insertMultistrmap(multistrmap &cfg, std::string key, std::string value) {
multistrmap::iterator it = cfg.find(key);
void MwIniImporter::insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value) {
const multistrmap::const_iterator it = cfg.find(key);
if(it == cfg.end()) {
cfg.insert(std::make_pair (key, std::vector<std::string>() ));
}
cfg[key].push_back(value);
}
void MwIniImporter::importArchives(multistrmap &cfg, multistrmap &ini) {
void MwIniImporter::importArchives(multistrmap &cfg, const multistrmap &ini) const {
std::vector<std::string> archives;
std::string baseArchive("Archives:Archive ");
std::string archive;
// Search archives listed in ini file
multistrmap::iterator it = ini.begin();
multistrmap::const_iterator it = ini.begin();
for(int i=0; it != ini.end(); i++) {
archive = baseArchive;
archive.append(this->numberToString(i));
@ -793,7 +791,7 @@ void MwIniImporter::importArchives(multistrmap &cfg, multistrmap &ini) {
break;
}
for(std::vector<std::string>::iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) {
for(std::vector<std::string>::const_iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) {
archives.push_back(*entry);
}
}
@ -805,18 +803,18 @@ void MwIniImporter::importArchives(multistrmap &cfg, multistrmap &ini) {
// does not appears in the ini file
cfg["fallback-archive"].push_back("Morrowind.bsa");
for(std::vector<std::string>::iterator it=archives.begin(); it!=archives.end(); ++it) {
for(std::vector<std::string>::const_iterator it=archives.begin(); it!=archives.end(); ++it) {
cfg["fallback-archive"].push_back(*it);
}
}
void MwIniImporter::importGameFiles(multistrmap &cfg, multistrmap &ini) {
void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) const {
std::vector<std::string> esmFiles;
std::vector<std::string> espFiles;
std::string baseGameFile("Game Files:GameFile");
std::string gameFile("");
multistrmap::iterator it = ini.begin();
multistrmap::const_iterator it = ini.begin();
for(int i=0; it != ini.end(); i++) {
gameFile = baseGameFile;
gameFile.append(this->numberToString(i));
@ -826,7 +824,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, multistrmap &ini) {
break;
}
for(std::vector<std::string>::iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) {
for(std::vector<std::string>::const_iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) {
std::string filetype(entry->substr(entry->length()-3));
Misc::StringUtils::toLower(filetype);
@ -844,22 +842,22 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, multistrmap &ini) {
cfg.erase("master");
cfg.insert( std::make_pair<std::string, std::vector<std::string> > ("master", std::vector<std::string>() ) );
for(std::vector<std::string>::iterator it=esmFiles.begin(); it!=esmFiles.end(); ++it) {
for(std::vector<std::string>::const_iterator it=esmFiles.begin(); it!=esmFiles.end(); ++it) {
cfg["master"].push_back(*it);
}
cfg.erase("plugin");
cfg.insert( std::make_pair<std::string, std::vector<std::string> > ("plugin", std::vector<std::string>() ) );
for(std::vector<std::string>::iterator it=espFiles.begin(); it!=espFiles.end(); ++it) {
for(std::vector<std::string>::const_iterator it=espFiles.begin(); it!=espFiles.end(); ++it) {
cfg["plugin"].push_back(*it);
}
}
void MwIniImporter::writeToFile(boost::iostreams::stream<boost::iostreams::file_sink> &out, multistrmap &cfg) {
void MwIniImporter::writeToFile(boost::iostreams::stream<boost::iostreams::file_sink> &out, const multistrmap &cfg) {
for(multistrmap::iterator it=cfg.begin(); it != cfg.end(); ++it) {
for(std::vector<std::string>::iterator entry=it->second.begin(); entry != it->second.end(); ++entry) {
for(multistrmap::const_iterator it=cfg.begin(); it != cfg.end(); ++it) {
for(std::vector<std::string>::const_iterator entry=it->second.begin(); entry != it->second.end(); ++entry) {
out << (it->first) << "=" << (*entry) << std::endl;
}
}

@ -18,18 +18,17 @@ class MwIniImporter {
MwIniImporter();
void setInputEncoding(const ToUTF8::FromType& encoding);
void setVerbose(bool verbose);
multistrmap loadIniFile(std::string filename);
multistrmap loadCfgFile(std::string filename);
void merge(multistrmap &cfg, multistrmap &ini);
void mergeFallback(multistrmap &cfg, multistrmap &ini);
void importGameFiles(multistrmap &cfg, multistrmap &ini);
void importArchives(multistrmap &cfg, multistrmap &ini);
void writeToFile(boost::iostreams::stream<boost::iostreams::file_sink> &out, multistrmap &cfg);
multistrmap loadIniFile(const std::string& filename) const;
static multistrmap loadCfgFile(const std::string& filename);
void merge(multistrmap &cfg, const multistrmap &ini) const;
void mergeFallback(multistrmap &cfg, const multistrmap &ini) const;
void importGameFiles(multistrmap &cfg, const multistrmap &ini) const;
void importArchives(multistrmap &cfg, const multistrmap &ini) const;
static void writeToFile(boost::iostreams::stream<boost::iostreams::file_sink> &out, const multistrmap &cfg);
private:
void insertMultistrmap(multistrmap &cfg, std::string key, std::string value);
std::string numberToString(int n);
std::string toUTF8(const std::string &str);
static void insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value);
static std::string numberToString(int n);
bool mVerbose;
strmap mMergeMap;
std::vector<std::string> mMergeFallback;

@ -28,12 +28,26 @@ int main(int argc, char *argv[]) {
p_desc.add("ini", 1).add("cfg", 1);
bpo::variables_map vm;
bpo::parsed_options parsed = bpo::command_line_parser(argc, argv)
.options(desc)
.positional(p_desc)
.run();
bpo::store(parsed, vm);
try
{
bpo::parsed_options parsed = bpo::command_line_parser(argc, argv)
.options(desc)
.positional(p_desc)
.run();
bpo::store(parsed, vm);
}
catch(boost::program_options::unknown_option & x)
{
std::cerr << "ERROR: " << x.what() << std::endl;
return false;
}
catch(boost::program_options::invalid_command_line_syntax & x)
{
std::cerr << "ERROR: " << x.what() << std::endl;
return false;
}
if(vm.count("help") || !vm.count("ini") || !vm.count("cfg")) {
std::cout << desc;
@ -55,10 +69,8 @@ int main(int argc, char *argv[]) {
std::cerr << "ini file does not exist" << std::endl;
return -3;
}
if(!boost::filesystem::exists(cfgFile)) {
if(!boost::filesystem::exists(cfgFile))
std::cerr << "cfg file does not exist" << std::endl;
return -4;
}
MwIniImporter importer;
importer.setVerbose(vm.count("verbose"));

@ -57,11 +57,11 @@ opencs_hdrs_noqt (view/doc
opencs_units (view/world
table tablesubview scriptsubview
table tablesubview scriptsubview util
)
opencs_units_noqt (view/world
dialoguesubview util subviews enumdelegate vartypedelegate scripthighlighter
dialoguesubview subviews enumdelegate vartypedelegate scripthighlighter recordstatusdelegate
)
@ -79,6 +79,7 @@ opencs_units (view/settings
abstractwidget
usersettingsdialog
editorpage
windowpage
)
opencs_units_noqt (view/settings

@ -61,6 +61,11 @@ void CS::Editor::setupDataFiles()
QString path = QString::fromStdString(iter->string());
mFileDialog.addFiles(path);
}
//load the settings into the userSettings instance.
const QString settingFileName = "opencs.cfg";
CSMSettings::UserSettings::instance().loadSettings(settingFileName);
}
void CS::Editor::createDocument()

@ -10,6 +10,7 @@
#include "view/doc/viewmanager.hpp"
#include "view/doc/startup.hpp"
#include "view/doc/filedialog.hpp"
#include "model/settings/usersettings.hpp"
namespace CS
{
@ -17,6 +18,7 @@ namespace CS
{
Q_OBJECT
CSMSettings::UserSettings mUserSettings;
CSMDoc::DocumentManager mDocumentManager;
CSVDoc::ViewManager mViewManager;
CSVDoc::StartupDialogue mStartup;

File diff suppressed because it is too large Load Diff

@ -52,6 +52,8 @@ namespace CSMDoc
void createBase();
void addGmsts();
void addOptionalGmsts();
void addOptionalGlobals();

@ -15,21 +15,31 @@ namespace CSMSettings
QStringList *mValues;
public:
explicit SettingContainer (QObject *parent = 0);
explicit SettingContainer (const QString &value, QObject *parent = 0);
virtual QString getName() const {return "";}
/// add a value to the container
/// multiple values supported
void insert (const QString &value);
/// update an existing value
/// index specifies multiple values
void update (const QString &value, int index = 0);
/// return value at specified index
QString getValue (int index = -1) const;
/// retrieve list of all values
inline QStringList *getValues() const { return mValues; }
/// return size of list
int count() const;
//test for empty container
//useful for default-constructed containers returned by QMap when invalid key is passed
/// test for empty container
/// useful for default-constructed containers returned by QMap when invalid key is passed
inline bool isEmpty() const { return (!mValue && !mValues); }
inline bool isMultiValue() const { return (mValues); }
};
}

@ -1,5 +1,7 @@
#include "settingsitem.hpp"
#include <QStringList>
bool CSMSettings::SettingsItem::updateItem (const QStringList *values)
{
QStringList::ConstIterator it = values->begin();
@ -66,21 +68,21 @@ bool CSMSettings::SettingsItem::updateItem(int valueListIndex)
bool CSMSettings::SettingsItem::validate (const QString &value)
{
bool isValid = true;
//if there is no value list or value pair, there is no validation to do
bool isValid = !(!mValueList->isEmpty() || mValuePair);
//validation required only if a value list or min/max value pair has been provided
if (mValueList->size()>0)
if (!isValid && !mValueList->isEmpty())
{
for (QStringList::ConstIterator it = mValueList->begin(); it !=mValueList->end(); ++it)
for (QStringList::Iterator it = mValueList->begin(); it != mValueList->end(); ++it)
// foreach (QString listItem, *mValueList)
{
isValid = ( value == *it);
isValid = (value == *it);
if (isValid)
break;
}
}
else if (mValuePair)
else if (!isValid && mValuePair)
{
int numVal = value.toInt();

@ -7,12 +7,13 @@
namespace CSMSettings
{
/// Represents a setting including metadata
/// (valid values, ranges, defaults, and multivalue status
class SettingsItem : public SettingContainer
{
QStringPair *mValuePair;
QStringList *mValueList;
bool mIsMultiValue;
QString mName;
QString mDefaultValue;
public:
@ -20,26 +21,41 @@ namespace CSMSettings
const QString& defaultValue, QObject *parent = 0)
: SettingContainer(defaultValue, parent),
mIsMultiValue (isMultiValue), mValueList (0),
mName (name), mValuePair (0), mDefaultValue (defaultValue)
{}
mValuePair (0), mDefaultValue (defaultValue)
{
QObject::setObjectName(name);
}
/// updateItem overloads for updating setting value
/// provided a list of values (multi-valued),
/// a specific value
/// or an index value corresponding to the mValueList
bool updateItem (const QStringList *values);
bool updateItem (const QString &value);
bool updateItem (int valueListIndex);
/// retroeve list of valid values for setting
inline QStringList *getValueList() { return mValueList; }
/// write list of valid values for setting
inline void setValueList (QStringList *valueList) { mValueList = valueList; }
/// valuePair used for spin boxes (max / min)
inline QStringPair *getValuePair() { return mValuePair; }
/// set value range (spinbox / integer use)
inline void setValuePair (QStringPair valuePair) { mValuePair = new QStringPair(valuePair); }
inline QString getName () const { return mName; }
inline bool isMultivalue () { return mIsMultiValue; }
void setDefaultValue (const QString &value);
QString getDefaultValue () const;
private:
/// Verifies that the supplied value is one of the following:
/// 1. Within the limits of the value pair (min / max)
/// 2. One of the values indicated in the value list
bool validate (const QString &value);
};
}

@ -8,11 +8,13 @@
#include <QMessageBox>
#include <QTextCodec>
#include <components/files/configurationmanager.hpp>
#include <QFile>
#include <QDebug>
#include <components/files/configurationmanager.hpp>
#include "settingcontainer.hpp"
#include <boost/version.hpp>
/**
* Workaround for problems with whitespaces in paths in older versions of Boost library
*/
@ -29,109 +31,236 @@ namespace boost
} /* namespace boost */
#endif /* (BOOST_VERSION <= 104600) */
CSMSettings::UserSettings *CSMSettings::UserSettings::mUserSettingsInstance = 0;
CSMSettings::UserSettings::UserSettings()
{
assert(!mUserSettingsInstance);
mUserSettingsInstance = this;
mReadWriteMessage = QObject::tr("<br><b>Could not open or create file for writing</b><br><br> \
Please make sure you have the right permissions and try again.<br>");
mReadOnlyMessage = QObject::tr("<br><b>Could not open file for reading</b><br><br> \
Please make sure you have the right permissions and try again.<br>");
}
CSMSettings::UserSettings::~UserSettings()
{
mUserSettingsInstance = 0;
}
QFile *CSMSettings::UserSettings::openFile (const QString &filename)
QTextStream *CSMSettings::UserSettings::openFileStream (const QString &filePath, bool isReadOnly) const
{
QFile *file = new QFile(filename);
QIODevice::OpenMode openFlags = QIODevice::Text;
if (isReadOnly)
openFlags = QIODevice::ReadOnly | openFlags;
else
openFlags = QIODevice::ReadWrite | QIODevice::Truncate | openFlags;
bool success = (file->open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) ;
QFile *file = new QFile(filePath);
QTextStream *stream = 0;
if (!success)
if (file->open(openFlags))
{
// File cannot be opened or created
QMessageBox msgBox;
msgBox.setWindowTitle(QObject::tr("Error writing OpenMW configuration file"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(QObject::tr("<br><b>Could not open or create %0 for writing</b><br><br> \
Please make sure you have the right permissions \
and try again.<br>").arg(file->fileName()));
msgBox.exec();
delete file;
file = 0;
stream = new QTextStream(file);
stream->setCodec(QTextCodec::codecForName("UTF-8"));
}
return file;
return stream;
}
bool CSMSettings::UserSettings::writeFile(QFile *file, QMap<QString, CSMSettings::SettingList *> &settings)
bool CSMSettings::UserSettings::writeSettings(QMap<QString, CSMSettings::SettingList *> &settings)
{
if (!file)
return false;
QTextStream *stream = openFileStream(mUserFilePath);
QTextStream stream(file);
stream.setCodec(QTextCodec::codecForName("UTF-8"));
bool success = (stream);
QList<QString> keyList = settings.keys();
foreach (QString key, keyList)
if (success)
{
SettingList *sectionSettings = settings[key];
QList<QString> keyList = settings.keys();
foreach (QString key, keyList)
{
SettingList *sectionSettings = settings[key];
stream << "[" << key << "]" << '\n';
*stream << "[" << key << "]" << '\n';
foreach (SettingContainer *item, *sectionSettings)
stream << item->getName() << " = " << item->getValue() << '\n';
}
foreach (SettingContainer *item, *sectionSettings)
*stream << item->objectName() << " = " << item->getValue() << '\n';
}
file->close();
stream->device()->close();
delete stream;
stream = 0;
}
else
{
displayFileErrorMessage(mReadWriteMessage, false);
}
return true;
return (success);
}
void CSMSettings::UserSettings::getSettings(QTextStream &stream, SectionMap &sections)
const CSMSettings::SectionMap &CSMSettings::UserSettings::getSettings() const
{
//looks for a square bracket, "'\\["
//that has one or more "not nothing" in it, "([^]]+)"
//and is closed with a square bracket, "\\]"
return mSectionSettings;
}
QRegExp sectionRe("^\\[([^]]+)\\]");
bool CSMSettings::UserSettings::loadFromFile(const QString &filePath)
{
if (filePath.isEmpty())
return false;
//Find any character(s) that is/are not equal sign(s), "[^=]+"
//followed by an optional whitespace, an equal sign, and another optional whirespace, "\\s*=\\s*"
//and one or more periods, "(.+)"
mSectionSettings.clear();
QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$");
QTextStream *stream = openFileStream (filePath, true);
CSMSettings::SettingMap *settings = 0;
QString section = "none";
bool success = (stream);
while (!stream.atEnd())
if (success)
{
QString line = stream.readLine().simplified();
//looks for a square bracket, "'\\["
//that has one or more "not nothing" in it, "([^]]+)"
//and is closed with a square bracket, "\\]"
QRegExp sectionRe("^\\[([^]]+)\\]");
if (line.isEmpty() || line.startsWith("#"))
continue;
//Find any character(s) that is/are not equal sign(s), "[^=]+"
//followed by an optional whitespace, an equal sign, and another optional whitespace, "\\s*=\\s*"
//and one or more periods, "(.+)"
//if a section is found, push it onto a new QStringList
//and push the QStringList onto
if (sectionRe.exactMatch(line))
QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$");
CSMSettings::SettingMap *settings = 0;
QString section = "none";
while (!stream->atEnd())
{
//add the previous section's settings to the member map
if (settings)
sections.insert(section, settings);
//save new section and create a new list
section = sectionRe.cap(1);
settings = new SettingMap;
continue;
QString line = stream->readLine().simplified();
if (line.isEmpty() || line.startsWith("#"))
continue;
//if a section is found, push it onto a new QStringList
//and push the QStringList onto
if (sectionRe.exactMatch(line))
{
//add the previous section's settings to the member map
if (settings)
mSectionSettings.insert(section, settings);
//save new section and create a new list
section = sectionRe.cap(1);
settings = new SettingMap;
continue;
}
if (keyRe.indexIn(line) != -1)
{
SettingContainer *sc = new SettingContainer (keyRe.cap(2).simplified());
sc->setObjectName(keyRe.cap(1).simplified());
(*settings)[keyRe.cap(1).simplified()] = sc;
}
}
if (keyRe.indexIn(line) != -1)
mSectionSettings.insert(section, settings);
stream->device()->close();
delete stream;
stream = 0;
}
return success;
}
void CSMSettings::UserSettings::loadSettings (const QString &fileName)
{
//global
QString globalFilePath = QString::fromStdString(mCfgMgr.getGlobalPath().string()) + fileName;
bool globalOk = loadFromFile(globalFilePath);
//local
QString localFilePath = QString::fromStdString(mCfgMgr.getLocalPath().string()) + fileName;
bool localOk = loadFromFile(localFilePath);
//user
mUserFilePath = QString::fromStdString(mCfgMgr.getUserPath().string()) + fileName;
loadFromFile(mUserFilePath);
if (!(localOk || globalOk))
{
QString message = QObject::tr("<br><b>Could not open user settings files for reading</b><br><br> \
Global and local settings files could not be read.\
You may have incorrect file permissions or the OpenCS installation may be corrupted.<br>");
message += QObject::tr("<br>Global filepath: ") + globalFilePath;
message += QObject::tr("<br>Local filepath: ") + localFilePath;
displayFileErrorMessage ( message, true);
}
}
void CSMSettings::UserSettings::updateSettings (const QString &sectionName, const QString &settingName)
{
if (mSectionSettings.find(sectionName) == mSectionSettings.end())
return;
SettingMap *settings = mSectionSettings.value(sectionName);
if (settingName.isEmpty())
{
foreach (const SettingContainer *setting, *settings)
emit signalUpdateEditorSetting (setting->objectName(), setting->getValue());
}
else
{
if (settings->find(settingName) != settings->end())
{
SettingContainer *sc = new SettingContainer (keyRe.cap(2).simplified());
(*settings)[keyRe.cap(1).simplified()] = sc;
const SettingContainer *setting = settings->value(settingName);
emit signalUpdateEditorSetting (setting->objectName(), setting->getValue());
}
}
}
QString CSMSettings::UserSettings::getSetting (const QString &section, const QString &setting) const
{
QString retVal = "";
if (mSectionSettings.find(section) != mSectionSettings.end())
{
CSMSettings::SettingMap *settings = mSectionSettings.value(section);
if (settings->find(setting) != settings->end())
retVal = settings->value(setting)->getValue();
}
sections.insert(section, settings);
return retVal;
}
CSMSettings::UserSettings& CSMSettings::UserSettings::instance()
{
assert(mUserSettingsInstance);
return *mUserSettingsInstance;
}
void CSMSettings::UserSettings::displayFileErrorMessage(const QString &message, bool isReadOnly)
{
// File cannot be opened or created
QMessageBox msgBox;
msgBox.setWindowTitle(QObject::tr("OpenCS configuration file I/O error"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
if (!isReadOnly)
msgBox.setText (mReadWriteMessage + message);
else
msgBox.setText (message);
msgBox.exec();
}

@ -10,6 +10,10 @@
#include "support.hpp"
#ifndef Q_MOC_RUN
#include <components/files/configurationmanager.hpp>
#endif
namespace Files { typedef std::vector<boost::filesystem::path> PathContainer;
struct ConfigurationManager;}
@ -22,29 +26,56 @@ namespace CSMSettings {
Q_OBJECT
public:
static UserSettings &instance()
{
static UserSettings instance;
SectionMap mSectionSettings;
static UserSettings *mUserSettingsInstance;
QString mUserFilePath;
Files::ConfigurationManager mCfgMgr;
QString mReadOnlyMessage;
QString mReadWriteMessage;
return instance;
}
QFile *openFile (const QString &);
bool writeFile(QFile *file, QMap<QString, SettingList *> &sections);
void getSettings (QTextStream &stream, SectionMap &settings);
public:
private:
/// Singleton implementation
static UserSettings& instance();
UserSettings *mUserSettingsInstance;
UserSettings();
~UserSettings();
UserSettings (UserSettings const &); //not implemented
void operator= (UserSettings const &); //not implemented
/// Writes settings to the last loaded settings file
bool writeSettings(QMap<QString, SettingList *> &sections);
/// Called from editor to trigger signal to update the specified setting.
/// If no setting name is specified, all settings found in the specified section are updated.
void updateSettings (const QString &sectionName, const QString &settingName = "");
/// Retrieves the settings file at all three levels (global, local and user).
/// \todo Multi-valued settings are not fully implemented. Setting values
/// \todo loaded in later files will always overwrite previously loaded values.
void loadSettings (const QString &fileName);
/// Returns the entire map of settings across all sections
const SectionMap &getSettings () const;
/// Retrieves the value as a QString of the specified setting in the specified section
QString getSetting(const QString &section, const QString &setting) const;
private:
/// Opens a QTextStream from the provided path as read-only or read-write.
QTextStream *openFileStream (const QString &filePath, bool isReadOnly = false) const;
/// Parses a setting file specified in filePath from the provided text stream.
bool loadFromFile (const QString &filePath = "");
void displayFileErrorMessage(const QString &message, bool isReadOnly);
signals:
void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue);
};

@ -41,7 +41,8 @@ namespace CSMWorld
Display_ArmorType,
Display_ClothingType,
Display_CreatureType,
Display_WeaponType
Display_WeaponType,
Display_RecordState
};
std::string mTitle;

@ -53,7 +53,7 @@ namespace CSMWorld
template<typename ESXRecordT>
struct RecordStateColumn : public Column<ESXRecordT>
{
RecordStateColumn() : Column<ESXRecordT> ("*", ColumnBase::Display_Integer) {}
RecordStateColumn() : Column<ESXRecordT> ("*", ColumnBase::Display_RecordState) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
@ -1148,4 +1148,4 @@ namespace CSMWorld
};
}
#endif
#endif

@ -41,7 +41,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
mColumns.push_back (RefIdColumn ("ID", ColumnBase::Display_String,
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false));
baseColumns.mId = &mColumns.back();
mColumns.push_back (RefIdColumn ("*", ColumnBase::Display_Integer,
mColumns.push_back (RefIdColumn ("*", ColumnBase::Display_RecordState,
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false));
baseColumns.mModified = &mColumns.back();
mColumns.push_back (RefIdColumn ("Type", ColumnBase::Display_Integer,
@ -539,4 +539,4 @@ void CSMWorld::RefIdCollection::load (ESM::ESMReader& reader, bool base, Univers
int CSMWorld::RefIdCollection::getAppendIndex (UniversalId::Type type) const
{
return mData.getAppendIndex (type);
}
}

@ -1,5 +1,6 @@
#include "subview.hpp"
CSVDoc::SubView::SubView (const CSMWorld::UniversalId& id) : mUniversalId (id)
{
/// \todo add a button to the title bar that clones this sub view
@ -15,3 +16,7 @@ CSMWorld::UniversalId CSVDoc::SubView::getUniversalId() const
{
return mUniversalId;
}
void CSVDoc::SubView::updateEditorSetting (const QString &settingName, const QString &settingValue)
{
}

@ -35,6 +35,7 @@ namespace CSVDoc
CSMWorld::UniversalId getUniversalId() const;
virtual void setEditLock (bool locked) = 0;
virtual void updateEditorSetting (const QString &, const QString &);
signals:
@ -42,4 +43,4 @@ namespace CSVDoc
};
}
#endif
#endif

@ -182,7 +182,13 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to
: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1),
mViewTotal (totalViews)
{
resize (300, 300); /// \todo get default size from settings and set reasonable minimal size
QString width = CSMSettings::UserSettings::instance().getSetting(QString("Window Size"), QString("Width"));
QString height = CSMSettings::UserSettings::instance().getSetting(QString("Window Size"), QString("Height"));
if(width==QString() || height==QString())
resize(800, 600);
else
resize (width.toInt(), height.toInt());
mSubViewWindow.setDockOptions (QMainWindow::AllowNestedDocks);
@ -261,11 +267,14 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id)
/// \todo add an user setting to reuse sub views (on a per document basis or on a per top level view basis)
SubView *view = mSubViewFactory.makeSubView (id, *mDocument);
view->setObjectName ("subview");
mSubViewWindow.addDockWidget (Qt::TopDockWidgetArea, view);
connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&)), this,
SLOT (addSubView (const CSMWorld::UniversalId&)));
CSMSettings::UserSettings::instance().updateSettings("Editor", "Record Status Display");
view->show();
}
@ -374,20 +383,34 @@ void CSVDoc::View::showUserSettings()
{
CSVSettings::UserSettingsDialog *settingsDialog = new CSVSettings::UserSettingsDialog(this);
connect (&(CSMSettings::UserSettings::instance()), SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)),
this, SLOT (slotUpdateEditorSetting (const QString &, const QString &)) );
settingsDialog->show();
}
void CSVDoc::View::slotUpdateEditorSetting(const QString &settingName, const QString &settingValue)
void CSVDoc::View::resizeViewWidth (int width)
{
static QString lastValue = "";
if (width >= 0)
resize (width, geometry().height());
}
if (lastValue != settingValue)
{
//evaluate settingName against tokens to determine which function to call to update Editor application.
void CSVDoc::View::resizeViewHeight (int height)
{
if (height >= 0)
resize (geometry().width(), height);
}
lastValue = settingValue;
void CSVDoc::View::updateEditorSetting (const QString &settingName, const QString &settingValue)
{
if (settingName == "Record Status Display")
{
foreach (QObject *view, mSubViewWindow.children())
{
if (view->objectName() == "subview")
dynamic_cast<CSVDoc::SubView *>(view)->updateEditorSetting (settingName, settingValue);
}
}
else if (settingName == "Width")
resizeViewWidth (settingValue.toInt());
else if (settingName == "Height")
resizeViewHeight (settingValue.toInt());
}

@ -68,6 +68,14 @@ namespace CSVDoc
void exitApplication();
void loadUserSettings();
/// User preference function
void resizeViewWidth (int width);
/// User preference function
void resizeViewHeight (int height);
public:
View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews);
@ -88,6 +96,9 @@ namespace CSVDoc
Operations *getOperations() const;
/// Function called by view manager when user preferences are updated
void updateEditorSetting (const QString &, const QString &);
signals:
void newDocumentRequest();
@ -102,8 +113,6 @@ namespace CSVDoc
void abortOperation (int type);
void slotUpdateEditorSetting (const QString &settingName, const QString &settingValue);
private slots:
void newView();

@ -12,13 +12,14 @@
#include "../world/util.hpp"
#include "../world/enumdelegate.hpp"
#include "../world/vartypedelegate.hpp"
#include "../world/recordstatusdelegate.hpp"
#include "../settings/usersettingsdialog.hpp"
#include "view.hpp"
#include <QMessageBox>
#include <QPushButton>
#include <QtGui/QApplication>
#include <QDebug>
void CSVDoc::ViewManager::updateIndices()
{
@ -117,6 +118,12 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
mDelegateFactories->add (CSMWorld::ColumnBase::Display_WeaponType,
new CSVWorld::EnumDelegateFactory (sWeaponTypes));
mDelegateFactories->add (CSMWorld::ColumnBase::Display_RecordState,
new CSVWorld::RecordStatusDelegateFactory() );
connect (&CSMSettings::UserSettings::instance(), SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)),
this, SLOT (slotUpdateEditorSetting (const QString &, const QString &)));
}
CSVDoc::ViewManager::~ViewManager()
@ -343,3 +350,13 @@ void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view)
if (notifySaveOnClose (view))
QApplication::instance()->exit();
}
void CSVDoc::ViewManager::slotUpdateEditorSetting (const QString &settingName, const QString &settingValue)
{
if (settingName == "Record Status Display" ||
settingName == "Width" || settingName == "Height")
{
foreach (CSVDoc::View *view, mViews)
view->updateEditorSetting (settingName, settingValue);
}
}

@ -72,6 +72,9 @@ namespace CSVDoc
void progress (int current, int max, int type, int threads, CSMDoc::Document *document);
void onExitWarningHandler(int state, CSMDoc::Document* document);
/// connected to update signal in UserSettings
void slotUpdateEditorSetting (const QString &, const QString &);
};
}

@ -38,27 +38,27 @@ CSVSettings::AbstractWidget *CSVSettings::AbstractBlock::buildWidget (const QStr
{
case Widget_RadioButton:
widg = createSettingWidget<QRadioButton> (def, layout);
widg = new SettingWidget<QRadioButton> (def, layout, mBox);
break;
case Widget_SpinBox:
widg = createSettingWidget<QSpinBox> (def, layout);
widg = new SettingWidget<QSpinBox> (def, layout, mBox);
break;
case Widget_CheckBox:
widg = createSettingWidget<QCheckBox> (def, layout);
widg = new SettingWidget<QCheckBox> (def, layout, mBox);
break;
case Widget_LineEdit:
widg = createSettingWidget<QLineEdit> (def, layout);
widg = new SettingWidget<QLineEdit> (def, layout, mBox);
break;
case Widget_ListBox:
widg = createSettingWidget<QListWidget> (def, layout);
widg = new SettingWidget<QListWidget> (def, layout, mBox);
break;
case Widget_ComboBox:
widg = createSettingWidget<QComboBox> (def, layout);
widg = new SettingWidget<QComboBox> (def, layout, mBox);
break;
default:

@ -11,6 +11,7 @@
namespace CSVSettings
{
/// Abstract base class for all blocks
class AbstractBlock : public QObject
{
Q_OBJECT
@ -31,40 +32,50 @@ namespace CSVSettings
bool isVisible() const;
virtual CSMSettings::SettingList *getSettings() = 0;
/// update settings found in the passed map and are encapsulated by the block
virtual bool updateSettings (const CSMSettings::SettingMap &settings) = 0;
/// update callback function called from update slot
/// used for updating application-level settings in the editor
virtual bool updateBySignal (const QString &name, const QString &value, bool &doEmit)
{ return false; }
protected:
/// Creates the layout which for the blocks QGroupBox
QLayout *createLayout (Orientation direction, bool isZeroMargin, QWidget* parent = 0);
/// Creates widgets that exist as direct children of the block
AbstractWidget *buildWidget (const QString &widgetName, WidgetDef &wDef,
QLayout *layout = 0, bool isConnected = true) const;
template <typename T>
AbstractWidget *createSettingWidget (WidgetDef &wDef, QLayout *layout) const
{
return new SettingWidget<T> (wDef, layout, mBox);
}
QWidget *getParent() const;
public slots:
/// enables / disables block-level widgets based on signals from other widgets
/// used in ToggleBlock
void slotSetEnabled (bool value);
/// receives updates to applicaion-level settings in the Editor
void slotUpdateSetting (const QString &settingName, const QString &settingValue);
private slots:
/// receives updates to a setting in the block pushed from the application level
void slotUpdate (const QString &value);
signals:
//signal to functions outside the settings tab widget
/// signal to UserSettings instance
void signalUpdateSetting (const QString &propertyName, const QString &propertyValue);
/// signal to widget for updating widget value
void signalUpdateWidget (const QString & value);
//propertyName and propertyValue are for properties for which the updated setting acts as a proxy
/// ProxyBlock use only.
/// Name and value correspond to settings for which the block is a proxy.
void signalUpdateProxySetting (const QString &propertyName, const QString &propertyValue);
};
}

@ -13,12 +13,17 @@
CSVSettings::AbstractPage::AbstractPage(QWidget *parent):
QWidget(parent)
{
QGridLayout *pageLayout = new QGridLayout(this);
setLayout (pageLayout);
}
CSVSettings::AbstractPage::AbstractPage(const QString &pageName, QWidget *parent):
QWidget(parent)
{
QWidget::setObjectName (pageName);
QGridLayout *pageLayout = new QGridLayout(this);
setLayout (pageLayout);
}
CSVSettings::AbstractPage::~AbstractPage()

@ -14,6 +14,11 @@ namespace CSVSettings {
typedef QList<AbstractBlock *> AbstractBlockList;
/// Abstract base class for all setting pages in the dialog
/// \todo Scripted implementation of settings should eliminate the need
/// \todo derive page classes.
/// \todo AbstractPage should be replaced with a general page construction class.
class AbstractPage: public QWidget
{
@ -28,18 +33,24 @@ namespace CSVSettings {
~AbstractPage();
virtual void setupUi()=0;
virtual void setupUi() = 0;
/// triggers widgiet initialization at the page level. All widgets updated to
/// current setting values
virtual void initializeWidgets (const CSMSettings::SettingMap &settings) = 0;
/// retrieve the list of settings local to the page.
CSMSettings::SettingList *getSettings();
void setObjectName();
protected:
/// Create a block for the page.
/// Block is constructed using passed definition struct
/// Page level-layout is created and assigned
template <typename S, typename T>
AbstractBlock *buildBlock (T &def)
AbstractBlock *buildBlock (T *def)
{
S *block = new S (this);
int ret = block->build (def);
@ -47,12 +58,12 @@ namespace CSVSettings {
if (ret < 0)
return 0;
QWidget::layout()->addWidget (block->getGroupBox());
QGroupBox *box = block->getGroupBox();
QWidget::layout()->addWidget (box);
return block;
}
};
}

@ -8,6 +8,7 @@ class QLayout;
namespace CSVSettings
{
/// Abstract base class for widgets which are used in user preferences dialog
class AbstractWidget : public QObject
{
Q_OBJECT
@ -16,45 +17,49 @@ namespace CSVSettings
public:
/// Passed layout is assigned the constructed widget.
/// if no layout is passed, one is created.
explicit AbstractWidget (QLayout *layout = 0, QWidget* parent = 0)
: QObject (parent), mLayout (layout)
{}
//retrieve layout for insertion into itemblock
/// retrieve layout for insertion into itemblock
QLayout *getLayout();
//create the derived widget instance
/// create the derived widget instance
void build (QWidget* widget, WidgetDef &def, bool noLabel = false);
//reference to the derived widget instance
/// reference to the derived widget instance
virtual QWidget *widget() = 0;
protected:
//called by inbound signal for type-specific widget udpates
/// Callback called by receiving slot for widget udpates
virtual void updateWidget (const QString &value) = 0;
//converts user-defined enum to Qt equivalents
/// Converts user-defined enum to Qt equivalents
QFlags<Qt::AlignmentFlag> getAlignment (Alignment flag);
private:
//widget initialization utilities
/// Creates layout and assigns label and widget as appropriate
void createLayout (Orientation direction, bool isZeroMargin);
/// Creates label and widget according to passed definition
void buildLabelAndWidget (QWidget *widget, WidgetDef &def, bool noLabel);
signals:
//outbound update
/// outbound update signal
void signalUpdateItem (const QString &value);
public slots:
//inbound updates
/// receives inbound updates
void slotUpdateWidget (const QString &value);
//Outbound updates from derived widget signal
/// Overloads for outbound updates from derived widget signal
void slotUpdateItem (const QString &value);
void slotUpdateItem (bool value);
void slotUpdateItem (int value);

@ -20,16 +20,11 @@
CSVSettings::BlankPage::BlankPage(QWidget *parent):
AbstractPage("Blank", parent)
{
initPage();
}
CSVSettings::BlankPage::BlankPage(const QString &title, QWidget *parent):
AbstractPage(title, parent)
{
initPage();
}
void CSVSettings::BlankPage::initPage()
{
// Hacks to get the stylesheet look properly
#ifdef Q_OS_MAC
@ -43,10 +38,7 @@ void CSVSettings::BlankPage::initPage()
void CSVSettings::BlankPage::setupUi()
{
QGroupBox *pageBox = new QGroupBox(this);
QLayout* pageLayout = new QVBoxLayout();
setLayout(pageLayout);
pageLayout->addWidget(pageBox);
layout()->addWidget(pageBox);
}
void CSVSettings::BlankPage::initializeWidgets (const CSMSettings::SettingMap &settings)

@ -10,6 +10,8 @@ namespace CSVSettings {
class UserSettings;
class AbstractBlock;
/// Derived page with no widgets
/// Reference use only.
class BlankPage : public AbstractPage
{
@ -20,9 +22,6 @@ namespace CSVSettings {
void setupUi();
void initializeWidgets (const CSMSettings::SettingMap &settings);
private:
void initPage();
};
}

@ -23,7 +23,7 @@ int CSVSettings::CustomBlock::build(GroupBlockDefList &defList, GroupBlockDefLis
for (; listIt != defList.end(); ++listIt)
{
if (!(*listIt)->isProxy)
retVal = buildGroupBlock (*(*listIt));
retVal = buildGroupBlock (*listIt);
else
{
mGroupList << proxyBlock;
@ -32,7 +32,7 @@ int CSVSettings::CustomBlock::build(GroupBlockDefList &defList, GroupBlockDefLis
}
if (proxyIt != defaultIt)
retVal = buildProxyBlock (*(*proxyIt), proxyBlock);
retVal = buildProxyBlock (*proxyIt, proxyBlock);
return retVal;
}
@ -40,12 +40,12 @@ int CSVSettings::CustomBlock::build(GroupBlockDefList &defList, GroupBlockDefLis
CSVSettings::GroupBox *CSVSettings::CustomBlock::buildGroupBox (Orientation orientation)
{
GroupBox *box = new GroupBox (false, mBox);
QLayout *layout = createLayout (orientation, true, box);
createLayout (orientation, true, box);
return box;
}
int CSVSettings::CustomBlock::buildGroupBlock(GroupBlockDef &def)
int CSVSettings::CustomBlock::buildGroupBlock(GroupBlockDef *def)
{
GroupBlock *block = new GroupBlock (getParent());
@ -57,9 +57,9 @@ int CSVSettings::CustomBlock::buildGroupBlock(GroupBlockDef &def)
return block->build(def);
}
int CSVSettings::CustomBlock::buildProxyBlock(GroupBlockDef& def, ProxyBlock *block)
int CSVSettings::CustomBlock::buildProxyBlock(GroupBlockDef *def, ProxyBlock *block)
{
if (def.properties.size() != 1)
if (def->settingItems.size() != 1)
return -1;
int retVal = block->build(def);
@ -67,7 +67,8 @@ int CSVSettings::CustomBlock::buildProxyBlock(GroupBlockDef& def, ProxyBlock *bl
if (retVal != 0)
return retVal;
foreach (QStringList *list, *(def.properties.at(0)->proxyList))
// The first settingItem is the proxy setting, containing the list of settings bound to it.
foreach (QStringList *list, *(def->settingItems.at(0)->proxyList))
{
QString proxiedBlockName = list->at(0);

@ -8,6 +8,8 @@ namespace CSVSettings
class ProxyBlock;
/// Base class for customized user preference setting blocks
/// Special block classes should be derived from CustomBlock
class CustomBlock : public AbstractBlock
{
@ -19,18 +21,27 @@ namespace CSVSettings
explicit CustomBlock (QWidget *parent = 0);
/// Update settings local to the block
bool updateSettings (const CSMSettings::SettingMap &settings);
/// Retrieve settings local to the block
CSMSettings::SettingList *getSettings();
/// construct the block using the passed definition
int build (GroupBlockDefList &defList, GroupBlockDefList::Iterator *it = 0);
protected:
/// construct the block groupbox
GroupBox *buildGroupBox (Orientation orientation);
private:
int buildGroupBlock(GroupBlockDef &def);
int buildProxyBlock(GroupBlockDef &def, ProxyBlock *block);
/// Construction function for creating a standard GroupBlock child
int buildGroupBlock(GroupBlockDef *def);
/// Construction function for creating a standard ProxyBlock child
int buildProxyBlock(GroupBlockDef *def, ProxyBlock *block);
};
}
#endif // CUSTOMBLOCK_HPP

@ -1,156 +1,46 @@
#include "editorpage.hpp"
#include <QList>
#include <QListView>
#include <QGroupBox>
#include <QRadioButton>
#include <QDockWidget>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QStyle>
#ifdef Q_OS_MAC
#include <QPlastiqueStyle>
#endif
#include "../../model/settings/usersettings.hpp"
#include "groupblock.hpp"
#include "toggleblock.hpp"
#include "../../model/settings/usersettings.hpp"
CSVSettings::EditorPage::EditorPage(QWidget *parent):
AbstractPage("Editor", parent)
CSVSettings::EditorPage::EditorPage(QWidget* parent) :
AbstractPage("Display Format", parent)
{
// Hacks to get the stylesheet look properly
#ifdef Q_OS_MAC
QPlastiqueStyle *style = new QPlastiqueStyle;
//profilesComboBox->setStyle(style);
#endif
setupUi();
}
void CSVSettings::EditorPage::setupUi()
CSVSettings::GroupBlockDef *CSVSettings::EditorPage::setupRecordStatusDisplay()
{
GroupBlockDef undoStack (QString("Undo Stack Size"));
GroupBlockDef topLevelWindowCount (QString("Maximum Top-Level Window Count"));
GroupBlockDef reuseSubwindow (QString("Reuse Subwindows"));
GroupBlockDef customWindowSize (QString ("Custom Window Size"));
GroupBlockDef definedWindowSize (QString ("Pre-Defined Window Size"));
GroupBlockDef windowSizeToggle (QString ("Window Size"));
CustomBlockDef windowSize (QString ("Window Size"));
////////////////////////////
//undo stack size property
///////////////////////////
SettingsItemDef *undoStackItem = new SettingsItemDef (undoStack.title, "32");
undoStack.properties << undoStackItem;
undoStackItem->minMax.left = "0";
undoStackItem->minMax.right = "64";
WidgetDef stackWidget (Widget_SpinBox);
stackWidget.minMax = &(undoStackItem->minMax);
stackWidget.widgetWidth = 50;
undoStackItem->widget = stackWidget;
//////////////////////////////////////
//number of top level windows property
/////////////////////////////////////
SettingsItemDef *topLevelItem = new SettingsItemDef (topLevelWindowCount.title, "100");
topLevelWindowCount.properties << topLevelItem;
topLevelItem->minMax.left = "1";
topLevelItem->minMax.right = "256";
WidgetDef topLvlWinWidget (Widget_SpinBox);
topLvlWinWidget.minMax = &(topLevelItem->minMax);
topLvlWinWidget.widgetWidth = 50;
topLevelItem->widget = topLvlWinWidget;
///////////////////////////
//reuse subwindows property
////////////////////////////
SettingsItemDef *reuseSubItem = new SettingsItemDef (reuseSubwindow.title, "Reuse Subwindows");
*(reuseSubItem->valueList) << "None" << "Top-Level" << "Document-Level";
WidgetDef reuseSubWidget (Widget_RadioButton);
reuseSubWidget.valueList = (reuseSubItem->valueList);
reuseSubWidget.widgetAlignment = Align_Left;
GroupBlockDef *statusBlock = new GroupBlockDef(QString("Record Status Display"));
reuseSubwindow.properties << reuseSubItem;
reuseSubItem->widget = reuseSubWidget;
SettingsItemDef *statusItem = new SettingsItemDef (statusBlock->title, "Icon and Text");
*(statusItem->valueList) << QString("Icon and Text") << QString("Icon Only") << QString("Text Only");
///////////////////////////////
//custom window size properties
///////////////////////////////
WidgetDef statusWidget (Widget_RadioButton);
statusWidget.valueList = statusItem->valueList;
//custom width
SettingsItemDef *widthItem = new SettingsItemDef ("Window Width", "640");
widthItem->widget = WidgetDef (Widget_LineEdit);
widthItem->widget.widgetWidth = 45;
statusItem->widget = statusWidget;
//custom height
SettingsItemDef *heightItem = new SettingsItemDef ("Window Height", "480");
heightItem->widget = WidgetDef (Widget_LineEdit);
heightItem->widget.widgetWidth = 45;
heightItem->widget.caption = "x";
statusBlock->settingItems << statusItem;
customWindowSize.properties << widthItem << heightItem;
customWindowSize.widgetOrientation = Orient_Horizontal;
customWindowSize.isVisible = false;
//pre-defined
SettingsItemDef *widthByHeightItem = new SettingsItemDef ("Window Size", "640x480");
WidgetDef widthByHeightWidget = WidgetDef (Widget_ComboBox);
widthByHeightWidget.widgetWidth = 90;
*(widthByHeightItem->valueList) << "640x480" << "800x600" << "1024x768";
QStringList *widthProxy = new QStringList;
QStringList *heightProxy = new QStringList;
(*widthProxy) << "Window Width" << "640" << "800" << "1024";
(*heightProxy) << "Window Height" << "480" << "600" << "768";
*(widthByHeightItem->proxyList) << widthProxy << heightProxy;
widthByHeightItem->widget = widthByHeightWidget;
definedWindowSize.properties << widthByHeightItem;
definedWindowSize.isProxy = true;
definedWindowSize.isVisible = false;
// window size toggle
windowSizeToggle.captions << "Pre-Defined" << "Custom";
windowSizeToggle.widgetOrientation = Orient_Vertical;
windowSizeToggle.isVisible = false;
//define a widget for each group in the toggle
for (int i = 0; i < 2; i++)
windowSizeToggle.widgets << new WidgetDef (Widget_RadioButton);
windowSizeToggle.widgets.at(0)->isDefault = false;
windowSize.blockDefList << &windowSizeToggle << &definedWindowSize << &customWindowSize;
windowSize.defaultValue = "Custom";
QGridLayout *pageLayout = new QGridLayout(this);
return statusBlock;
}
setLayout (pageLayout);
void CSVSettings::EditorPage::setupUi()
{
mAbstractBlocks << buildBlock<GroupBlock> (topLevelWindowCount)
<< buildBlock<GroupBlock> (reuseSubwindow)
<< buildBlock<ToggleBlock> (windowSize)
<< buildBlock<GroupBlock> (undoStack);
mAbstractBlocks << buildBlock<GroupBlock>(setupRecordStatusDisplay());
foreach (AbstractBlock *block, mAbstractBlocks)
{
connect (block, SIGNAL (signalUpdateSetting (const QString &, const QString &)),
this, SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)) );
}
connect ( this,
SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)),
&(CSMSettings::UserSettings::instance()),
SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)));
}
void CSVSettings::EditorPage::initializeWidgets (const CSMSettings::SettingMap &settings)

@ -1,28 +1,33 @@
#ifndef EDITORPAGE_H
#define EDITORPAGE_H
#ifndef EDITORPAGE_HPP
#define EDITORPAGE_HPP
#include "support.hpp"
#include "abstractpage.hpp"
class QGroupBox;
namespace CSVSettings {
class UserSettings;
class AbstractBlock;
namespace CSVSettings
{
class EditorPage : public AbstractPage
{
Q_OBJECT
public:
explicit EditorPage(QWidget *parent = 0);
EditorPage(QWidget *parent = 0);
void setupUi();
void initializeWidgets (const CSMSettings::SettingMap &settings);
void setupUi();
private:
/// User preference view of the record status delegate's icon / text setting
GroupBlockDef *setupRecordStatusDisplay();
signals:
/// Signals up for changes to editor application-level settings
void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue);
public slots:
};
}
#endif //EDITORPAGE_H
#endif // EDITORPAGE_HPP

@ -9,22 +9,22 @@ CSVSettings::GroupBlock::GroupBlock (bool isVisible, QWidget *parent)
: AbstractBlock (isVisible, parent)
{}
int CSVSettings::GroupBlock::build (GroupBlockDef &def)
int CSVSettings::GroupBlock::build (GroupBlockDef *def)
{
if (def.properties.size() == 0)
if (def->settingItems.size() == 0)
return -1;
int retVal = 0;
setVisible (def.isVisible);
setVisible (def->isVisible);
mBox->setLayout(createLayout (def.widgetOrientation, true));
mBox->setLayout(createLayout (def->widgetOrientation, true));
setObjectName (def.title);
mBox->setTitle (def.title);
setObjectName (def->title);
mBox->setTitle (def->title);
foreach (SettingsItemDef *itemDef, def.properties)
foreach (SettingsItemDef *itemDef, def->settingItems)
{
ItemBlock *block = new ItemBlock (mBox);

@ -8,6 +8,8 @@ namespace CSVSettings
{
class ItemBlock;
/// Base class for group blocks.
/// Derived block classes should use CustomBlock
class GroupBlock : public AbstractBlock
{
ItemBlockList mItemBlockList;
@ -16,15 +18,24 @@ namespace CSVSettings
GroupBlock (QWidget* parent = 0);
GroupBlock (bool isVisible, QWidget *parent = 0);
int build (GroupBlockDef &def);
/// build the gorup block based on passed definition
int build (GroupBlockDef *def);
/// update settings local to the group block
bool updateSettings (const CSMSettings::SettingMap &settings);
/// retrieve setting list local to the group block
CSMSettings::SettingList *getSettings();
/// retrieve item block by name from the passed list or local list
ItemBlock *getItemBlock (const QString &name, ItemBlockList *blockList = 0);
/// retrieve the item block by index from the local list
ItemBlock *getItemBlock (int index);
protected:
/// create block layout based on passed definition
int buildLayout (GroupBlockDef &def);
};

@ -5,6 +5,7 @@
namespace CSVSettings
{
/// Custom implementation of QGroupBox to be used with block classes
class GroupBox : public QGroupBox
{
static const QString INVISIBLE_BOX_STYLE;

@ -15,22 +15,32 @@ namespace CSVSettings
ItemBlock (QWidget* parent = 0);
/// pure virtual function not implemneted
bool updateSettings (const CSMSettings::SettingMap &settings) { return false; }
CSMSettings::SettingList *getSettings ();
QString getValue () const;
/// item blocks encapsulate only one setting
int getSettingCount();
/// update setting value and corresponding widget
bool update (const QString &value);
/// virtual construction function
int build(SettingsItemDef &iDef);
private:
/// custom construction function
void buildItemBlock (SettingsItemDef& iDef);
void buildItemBlockWidgets (SettingsItemDef& iDef);
/// update the setting value
bool updateItem (const QString &);
/// callback function triggered when update to application level is signalled
bool updateBySignal (const QString &name, const QString &value, bool &doEmit);
};
}

@ -5,10 +5,10 @@ CSVSettings::ProxyBlock::ProxyBlock (QWidget *parent)
: GroupBlock (parent)
{
}
int CSVSettings::ProxyBlock::build (GroupBlockDef &proxyDef)
int CSVSettings::ProxyBlock::build (GroupBlockDef *proxyDef)
{
//get the list of pre-defined values for the proxy
mValueList = proxyDef.properties.at(0)->valueList;
mValueList = proxyDef->settingItems.at(0)->valueList;
bool success = GroupBlock::build(proxyDef);
@ -53,6 +53,8 @@ bool CSVSettings::ProxyBlock::updateProxiedSettings()
bool success = false;
int i = 0;
//find the value index of the selected value in the proxy setting
for (; i < mValueList->size(); ++i)
{
success = (value == mValueList->at(i));
@ -64,6 +66,7 @@ bool CSVSettings::ProxyBlock::updateProxiedSettings()
if (!success)
return false;
// update the containing the proxied item's name
foreach (QStringList *list, mProxyList)
{
if ( list->at(0) == block->objectName())

@ -9,8 +9,7 @@ namespace CSVSettings
{
Q_OBJECT
//NOTE: mProxyItemBlockList and mProxyList
//should be combined into a value pair and stored in one list.
/// TODO: Combine mProxyItemBlockList and mProxyList.
ItemBlockList mProxiedItemBlockList;
ProxyList mProxyList;
QStringList *mValueList;
@ -20,17 +19,28 @@ namespace CSVSettings
explicit ProxyBlock (QWidget *parent = 0);
explicit ProxyBlock (ItemBlock *proxyItemBlock, QWidget *parent = 0);
/// Add a block that contains a proxied setting to the proxy block.
void addSetting (ItemBlock* settingBlock, QStringList *proxyList);
int build (GroupBlockDef &def);
int build (GroupBlockDef *def);
CSMSettings::SettingList *getSettings() { return 0; }
/// Update settings local to the proxy block pushed from application level
bool updateSettings (const CSMSettings::SettingMap &settings);
/// callback function triggered when update to the application level is signaled.
bool updateBySignal (const QString &name, const QString &value, bool &doEmit);
private:
/// return the item block of a proxied setting
ItemBlock *getProxiedItemBlock (const QString &name);
/// update the proxy setting with data from the proxied settings
bool updateByProxiedSettings(const CSMSettings::SettingMap *settings = 0);
/// update proxied settings with data from the proxy setting
bool updateProxiedSettings();
private slots:

@ -16,7 +16,8 @@
namespace CSVSettings
{
//VALID FOR RADIOBUTTON / CHECKBOX (or other toggle widget with it's own label)
/// Generic template for radiobuttons / checkboxes
template <typename T1>
class SettingWidget : public AbstractWidget
{
@ -47,6 +48,7 @@ namespace CSVSettings
}
};
/// spin box template
template <>
class SettingWidget <QSpinBox>: public AbstractWidget
{
@ -90,6 +92,7 @@ namespace CSVSettings
};
/// combo box template
template <>
class SettingWidget <QComboBox>: public CSVSettings::AbstractWidget
{
@ -142,6 +145,7 @@ namespace CSVSettings
};
/// line edit template
template <>
class SettingWidget <QLineEdit>: public CSVSettings::AbstractWidget
{
@ -175,6 +179,8 @@ namespace CSVSettings
}
};
/// list widget template
/// \todo Not fully implemented. Only widget supporting multi-valued settings
template <>
class SettingWidget <QListWidget>: public CSVSettings::AbstractWidget
{

@ -44,21 +44,44 @@ namespace CSVSettings
Align_Right = Qt::AlignRight
};
//template for defining the widget of a property.
/// definition struct for widgets
struct WidgetDef
{
WidgetType type; //type of widget providing input
int labelWidth; //width of caption label
int widgetWidth; //width of input widget
Orientation orientation; //label / widget orientation (horizontal / vertical)
QString inputMask; //input mask (line edit)
QString caption; //label caption. Leave empty for multiple items. See BlockDef::captionList
QString value; //widget value. Leave empty for multiple items. See BlockDef::valueList
CSMSettings::QStringPair *minMax; //Min/Max QString value pair. If empty, assigned to property item value pair.
QStringList *valueList; //value list for list widgets. If left empty, is assigned to property item value list during block build().
bool isDefault; //isDefault - determined at runtime.
Alignment valueAlignment; //left / center / right-justify text in widget
Alignment widgetAlignment; //left / center / right-justify widget in group box
/// type of widget providing input
WidgetType type;
/// width of caption label
int labelWidth;
/// width of input widget
int widgetWidth;
/// label / widget orientation (horizontal / vertical)
Orientation orientation;
/// input mask (line edit only)
QString inputMask;
/// label caption. Leave empty for multiple items. See BlockDef::captionList
QString caption;
/// widget value. Leave empty for multiple items. See BlockDef::valueList
QString value;
/// Min/Max QString value pair. If empty, assigned to property item value pair.
CSMSettings::QStringPair *minMax;
/// value list for list widgets. If left empty, is assigned to property item value list during block build().
QStringList *valueList;
/// determined at runtime
bool isDefault;
/// left / center / right-justify text in widget
Alignment valueAlignment;
/// left / center / right-justify widget in group box
Alignment widgetAlignment;
WidgetDef() : labelWidth (-1), widgetWidth (-1),
@ -79,20 +102,34 @@ namespace CSVSettings
};
//Defines the attributes of the property as it is represented in the config file
//as well as the UI elements (group box and widget) that serve it.
//Only one widget may serve as the input widget for the property.
/// Defines the attributes of the setting as it is represented in the config file
/// as well as the UI elements (group box and widget) that serve it.
/// Only one widget may serve as the input widget for the setting.
struct SettingsItemDef
{
QString name; //property name
QStringList *valueList; //list of valid values for the property.
//Used to populate option widget captions or list widget item lists (see WidgetDef::caption / value)
/// setting name
QString name;
/// list of valid values for the setting
QStringList *valueList;
/// Used to populate option widget captions or list widget item lists (see WidgetDef::caption / value)
QString defaultValue;
/// flag indicating multi-valued setting
bool hasMultipleValues;
CSMSettings::QStringPair minMax; //minimum / maximum value pair
WidgetDef widget; //definition of the input widget for this setting
Orientation orientation; //general orientation of the widget / label for this property
ProxyList *proxyList; //list of property and corresponding default values for proxy widget
/// minimum / maximum value pair
CSMSettings::QStringPair minMax;
/// definition of the input widget for this setting
WidgetDef widget;
/// general orientation of the widget / label for this setting
Orientation orientation;
/// list of settings and corresponding default values for proxy widget
ProxyList *proxyList;
SettingsItemDef() : name (""), defaultValue (""), orientation (Orient_Vertical), hasMultipleValues (false)
{}
@ -104,18 +141,32 @@ namespace CSVSettings
};
//Hierarchically, this is a "sub-section" of properties within a section, solely for UI organization.
//Does not correlate to config file structure.
/// Generic container block
struct GroupBlockDef
{
QString title; //title of the block containing the property or properties of this sub-section
QStringList captions; //list of captions for widgets at the block level (not associated with any particular property)
WidgetList widgets; //list of widgets at the block level (not associated with any particular property)
QList<SettingsItemDef *> properties; //list of the property(ies) which are subordinate to the property block.
Orientation widgetOrientation; //general orientation of widgets in group block
bool isVisible; //determines whether or not box border/title are visible
bool isProxy; //indicates whether or not this block defines a proxy block
QString defaultValue; //generic default value attribute
/// block title
QString title;
/// list of captions for widgets at the block level (not associated with any particular setting)
QStringList captions;
/// list of widgets at the block level (not associated with any particular setting)
WidgetList widgets;
/// list of the settings which are subordinate to the setting block.
QList<SettingsItemDef *> settingItems;
/// general orientation of widgets in group block
Orientation widgetOrientation;
/// determines whether or not box border/title are visible
bool isVisible;
/// indicates whether or not this block defines a proxy block
bool isProxy;
/// generic default value attribute
QString defaultValue;
GroupBlockDef (): title(""), widgetOrientation (Orient_Vertical), isVisible (true), isProxy (false), defaultValue ("")
{}
@ -125,11 +176,19 @@ namespace CSVSettings
{}
};
/// used to create unique, complex blocks
struct CustomBlockDef
{
/// block title
QString title;
QString defaultValue; //default value for widgets unique to the custom block
GroupBlockDefList blockDefList; //list of settings groups that comprise the settings within the custom block
/// default value for widgets unique to the custom block
QString defaultValue;
/// list of settings groups that comprise the settings within the custom block
GroupBlockDefList blockDefList;
/// orientation of the widgets within the block
Orientation blockOrientation;
CustomBlockDef (): title (""), defaultValue (""), blockOrientation (Orient_Horizontal)

@ -7,24 +7,24 @@ CSVSettings::ToggleBlock::ToggleBlock(QWidget *parent) :
CustomBlock(parent)
{}
int CSVSettings::ToggleBlock::build(CustomBlockDef &def)
int CSVSettings::ToggleBlock::build(CustomBlockDef *def)
{
if (def.blockDefList.size()==0)
if (def->blockDefList.size()==0)
return -1;
QList<GroupBlockDef *>::Iterator it = def.blockDefList.begin();
QList<GroupBlockDef *>::Iterator it = def->blockDefList.begin();
//first def in the list is the def for the toggle block
GroupBlockDef *toggleDef = *it++;
if (toggleDef->captions.size() != def.blockDefList.size()-1 )
if (toggleDef->captions.size() != def->blockDefList.size()-1 )
return -2;
if (toggleDef->widgets.size() == 0)
return -3;
//create the toogle block UI structure
QLayout *blockLayout = createLayout (def.blockOrientation, true);
QLayout *blockLayout = createLayout (def->blockOrientation, true);
GroupBox *propertyBox = buildGroupBox (toggleDef->widgetOrientation);
mBox->setLayout(blockLayout);
@ -34,13 +34,13 @@ int CSVSettings::ToggleBlock::build(CustomBlockDef &def)
//this manages proxy block construction.
//Any settings managed by the proxy setting
//must be included in the blocks defined in the list.
CustomBlock::build (def.blockDefList, &it);
CustomBlock::build (def->blockDefList, &it);
for (GroupBlockList::iterator it = mGroupList.begin(); it != mGroupList.end(); ++it)
propertyBox->layout()->addWidget ((*it)->getGroupBox());
//build togle widgets, linking them to the settings
GroupBox *toggleBox = buildToggleWidgets (*toggleDef, def.defaultValue);
GroupBox *toggleBox = buildToggleWidgets (toggleDef, def->defaultValue);
blockLayout->addWidget(toggleBox);
blockLayout->addWidget(propertyBox);
@ -49,16 +49,16 @@ int CSVSettings::ToggleBlock::build(CustomBlockDef &def)
return 0;
}
CSVSettings::GroupBox *CSVSettings::ToggleBlock::buildToggleWidgets (GroupBlockDef &def, QString &defaultToggle)
CSVSettings::GroupBox *CSVSettings::ToggleBlock::buildToggleWidgets (GroupBlockDef *def, QString &defaultToggle)
{
GroupBox *box = new GroupBox (false, getParent());
QLayout *layout = createLayout (def.widgetOrientation, true, static_cast<QWidget *>(box));
QLayout *layout = createLayout (def->widgetOrientation, true, static_cast<QWidget *>(box));
for (int i = 0; i < def.widgets.size(); ++i)
for (int i = 0; i < def->widgets.size(); ++i)
{
QString caption = def.captions.at(i);
WidgetDef *wDef = def.widgets.at(i);
QString caption = def->captions.at(i);
WidgetDef *wDef = def->widgets.at(i);
wDef->caption = caption;
wDef->widgetAlignment = Align_Left;

@ -18,10 +18,12 @@ namespace CSVSettings
public:
explicit ToggleBlock(QWidget *parent = 0);
int build (CustomBlockDef &def);
int build (CustomBlockDef *def);
private:
GroupBox *buildToggleWidgets (GroupBlockDef &def, QString &defaultToggle);
/// Constructor for toggle widgets that are specific to toggle block
/// Widgets are not a part of the user preference settings
GroupBox *buildToggleWidgets (GroupBlockDef *def, QString &defaultToggle);
};
}
#endif // TOGGLEBLOCK_HPP

@ -10,25 +10,26 @@
#include <QPushButton>
#include <QDockWidget>
#include "blankpage.hpp"
#include <QGridLayout>
#include "editorpage.hpp"
#include "../../model/settings/support.hpp"
#include "windowpage.hpp"
#include "../../model/settings/support.hpp"
#include <boost/filesystem/path.hpp>
#include "settingwidget.hpp"
#include <QDebug>
CSVSettings::UserSettingsDialog::UserSettingsDialog(QMainWindow *parent) :
QMainWindow (parent), mStackedWidget (0)
{
setWindowTitle(QString::fromUtf8 ("User Settings"));
buildPages();
setWidgetStates (loadSettings());
positionWindow ();
setWidgetStates ();
connect (mListWidget,
SIGNAL (currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
this,
SLOT (slotChangePage (QListWidgetItem*, QListWidgetItem*)));
SLOT (slotChangePage (QListWidgetItem*, QListWidgetItem*)));
}
CSVSettings::UserSettingsDialog::~UserSettingsDialog()
@ -40,17 +41,21 @@ void CSVSettings::UserSettingsDialog::closeEvent (QCloseEvent *event)
writeSettings();
}
void CSVSettings::UserSettingsDialog::setWidgetStates (CSMSettings::SectionMap settingsMap)
void CSVSettings::UserSettingsDialog::setWidgetStates ()
{
CSMSettings::UserSettings::instance().loadSettings("opencs.cfg");
const CSMSettings::SectionMap &sectionSettings = CSMSettings::UserSettings::instance().getSettings();
//iterate the tabWidget's pages (sections)
for (int i = 0; i < mStackedWidget->count(); i++)
{
//get the settings defined for the entire section
CSMSettings::SettingMap *settings = settingsMap [mStackedWidget->widget(i)->objectName()];
//and update widget
QString pageName = mStackedWidget->widget(i)->objectName();
//if found, initialize the page's widgets
if (settings)
if (sectionSettings.find(pageName) != sectionSettings.end())
{
CSMSettings::SettingMap *settings = sectionSettings.value(pageName);
AbstractPage *page = getAbstractPage (i);
page->initializeWidgets(*settings);
}
@ -65,85 +70,26 @@ void CSVSettings::UserSettingsDialog::buildPages()
mListWidget = new QListWidget (centralWidget);
mStackedWidget = new QStackedWidget (centralWidget);
QLayout* dialogLayout = new QHBoxLayout();
QGridLayout* dialogLayout = new QGridLayout();
dialogLayout->addWidget (mListWidget);
dialogLayout->addWidget (mStackedWidget);
mListWidget->setMinimumWidth(0);
mListWidget->setSizePolicy (QSizePolicy::Preferred, QSizePolicy::Expanding);
mStackedWidget->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed);
dialogLayout->addWidget (mListWidget,0,0);
dialogLayout->addWidget (mStackedWidget,0,1, Qt::AlignTop);
centralWidget->setLayout (dialogLayout);
setCentralWidget (centralWidget);
setDockOptions (QMainWindow::AllowNestedDocks);
//uncomment to test with sample editor page.
//createSamplePage();
createPage<BlankPage>("Page1");
createPage<BlankPage>("Page2");
createPage<BlankPage>("Page3");
}
void CSVSettings::UserSettingsDialog::createSamplePage()
{
//add pages to stackedwidget and items to listwidget
CSVSettings::AbstractPage *page
= new CSVSettings::EditorPage(this);
mStackedWidget->addWidget (page);
new QListWidgetItem (page->objectName(), mListWidget);
connect ( page, SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)),
&(CSMSettings::UserSettings::instance()), SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)));
}
void CSVSettings::UserSettingsDialog::positionWindow ()
{
QRect scr = QApplication::desktop()->screenGeometry();
move(scr.center().x() - (width() / 2), scr.center().y() - (height() / 2));
createPage<WindowPage>();
createPage<EditorPage>();
}
CSMSettings::SectionMap CSVSettings::UserSettingsDialog::loadSettings ()
{
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
mPaths.append(QString("opencs.cfg"));
mPaths.append(userPath + QString("opencs.cfg"));
CSMSettings::SectionMap settingsMap;
foreach (const QString &path, mPaths)
{
qDebug() << "Loading config file:" << qPrintable(path);
QFile file(path);
if (file.exists())
{
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error opening OpenCS configuration file"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(QObject::tr("<br><b>Could not open %0 for reading</b><br><br> \
Please make sure you have the right permissions \
and try again.<br>").arg(file.fileName()));
msgBox.exec();
return settingsMap;
}
QTextStream stream(&file);
stream.setCodec(QTextCodec::codecForName("UTF-8"));
CSMSettings::UserSettings::instance().getSettings(stream, settingsMap);
}
file.close();
}
return settingsMap;
}
void CSVSettings::UserSettingsDialog::writeSettings()
{
QMap<QString, CSMSettings::SettingList *> settings;
@ -153,9 +99,7 @@ void CSVSettings::UserSettingsDialog::writeSettings()
AbstractPage *page = getAbstractPage (i);
settings [page->objectName()] = page->getSettings();
}
CSMSettings::UserSettings::instance().writeFile(CSMSettings::UserSettings::instance().openFile(mPaths.back()), settings);
CSMSettings::UserSettings::instance().writeSettings(settings);
}
CSVSettings::AbstractPage *CSVSettings::UserSettingsDialog::getAbstractPage (int index)

@ -4,14 +4,13 @@
#include <QMainWindow>
#include <QStackedWidget>
#include <QListWidgetItem>
#ifndef Q_MOC_RUN
#include <components/files/configurationmanager.hpp>
#endif
#include <QApplication>
#include "../../model/settings/usersettings.hpp"
#include "../../model/settings/support.hpp"
#include "editorpage.hpp"
class QHBoxLayout;
class AbstractWidget;
class QStackedWidget;
@ -25,10 +24,8 @@ namespace CSVSettings {
{
Q_OBJECT
QStringList mPaths;
QListWidget *mListWidget;
QStackedWidget *mStackedWidget;
Files::ConfigurationManager mCfgMgr;
public:
UserSettingsDialog(QMainWindow *parent = 0);
@ -36,35 +33,39 @@ namespace CSVSettings {
private:
/// Settings are written on close
void closeEvent (QCloseEvent *event);
/// return the setting page by name
/// performs dynamic cast to AbstractPage *
AbstractPage *getAbstractPage (int index);
void setWidgetStates (CSMSettings::SectionMap settingsMap);
void setWidgetStates ();
void buildPages();
void positionWindow ();
CSMSettings::SectionMap loadSettings();
void writeSettings();
void createSamplePage();
/// Templated function to create a custom user preference page
template <typename T>
void createPage (const QString &title)
void createPage ()
{
T *page = new T(title, this);
T *page = new T(mStackedWidget);
mStackedWidget->addWidget (dynamic_cast<QWidget *>(page));
new QListWidgetItem (page->objectName(), mListWidget);
//finishing touches
if (mStackedWidget->sizeHint().width() < 640)
mStackedWidget->sizeHint().setWidth(640);
QFontMetrics fm (QApplication::font());
int textWidth = fm.width(page->objectName());
if (mStackedWidget->sizeHint().height() < 480)
mStackedWidget->sizeHint().setHeight(480);
if ((textWidth + 50) > mListWidget->minimumWidth())
mListWidget->setMinimumWidth(textWidth + 50);
resize (mStackedWidget->sizeHint());
}
public slots:
/// Called when a different page is selected in the left-hand list widget
void slotChangePage (QListWidgetItem*, QListWidgetItem*);
};

@ -0,0 +1,144 @@
#include "windowpage.hpp"
#include <QList>
#include <QListView>
#include <QGroupBox>
#include <QRadioButton>
#include <QDockWidget>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QStyle>
#ifdef Q_OS_MAC
#include <QPlastiqueStyle>
#endif
#include "../../model/settings/usersettings.hpp"
#include "groupblock.hpp"
#include "toggleblock.hpp"
#include "../../view/settings/abstractblock.hpp"
CSVSettings::WindowPage::WindowPage(QWidget *parent):
AbstractPage("Window", parent)
{
// Hacks to get the stylesheet look properly
#ifdef Q_OS_MAC
QPlastiqueStyle *style = new QPlastiqueStyle;
//profilesComboBox->setStyle(style);
#endif
setupUi();
}
CSVSettings::GroupBlockDef * CSVSettings::WindowPage::buildDefinedWindowSize()
{
GroupBlockDef *block = new GroupBlockDef ( "Defined Size");
SettingsItemDef *widthByHeightItem = new SettingsItemDef ("Window Size", "640x480");
WidgetDef widthByHeightWidget = WidgetDef (Widget_ComboBox);
widthByHeightWidget.widgetWidth = 90;
*(widthByHeightItem->valueList) << "640x480" << "800x600" << "1024x768" << "1440x900";
QStringList *widthProxy = new QStringList;
QStringList *heightProxy = new QStringList;
(*widthProxy) << "Width" << "640" << "800" << "1024" << "1440";
(*heightProxy) << "Height" << "480" << "600" << "768" << "900";
*(widthByHeightItem->proxyList) << widthProxy << heightProxy;
widthByHeightItem->widget = widthByHeightWidget;
block->settingItems << widthByHeightItem;
block->isProxy = true;
block->isVisible = false;
return block;
}
CSVSettings::GroupBlockDef *CSVSettings::WindowPage::buildCustomWindowSize()
{
GroupBlockDef *block = new GroupBlockDef ("Custom Size");
//custom width
SettingsItemDef *widthItem = new SettingsItemDef ("Width", "640");
widthItem->widget = WidgetDef (Widget_LineEdit);
widthItem->widget.widgetWidth = 45;
widthItem->widget.inputMask = "9999";
//custom height
SettingsItemDef *heightItem = new SettingsItemDef ("Height", "480");
heightItem->widget = WidgetDef (Widget_LineEdit);
heightItem->widget.widgetWidth = 45;
heightItem->widget.caption = "x";
heightItem->widget.inputMask = "9999";
block->settingItems << widthItem << heightItem;
block->widgetOrientation = Orient_Horizontal;
block->isVisible = false;
return block;
}
CSVSettings::GroupBlockDef *CSVSettings::WindowPage::buildWindowSizeToggle()
{
GroupBlockDef *block = new GroupBlockDef ("Window Size");
// window size toggle
block->captions << "Pre-Defined" << "Custom";
block->widgetOrientation = Orient_Vertical;
block->isVisible = false;
//define a widget for each group in the toggle
for (int i = 0; i < 2; i++)
block->widgets << new WidgetDef (Widget_RadioButton);
block->widgets.at(0)->isDefault = false;
return block;
}
CSVSettings::CustomBlockDef *CSVSettings::WindowPage::buildWindowSize(GroupBlockDef *toggle_def,
GroupBlockDef *defined_def,
GroupBlockDef *custom_def)
{
CustomBlockDef *block = new CustomBlockDef(QString ("Window Size"));
block->blockDefList << toggle_def << defined_def << custom_def;
block->defaultValue = "Custom";
return block;
}
void CSVSettings::WindowPage::setupUi()
{
CustomBlockDef *windowSize = buildWindowSize(buildWindowSizeToggle(),
buildDefinedWindowSize(),
buildCustomWindowSize()
);
mAbstractBlocks << buildBlock<ToggleBlock> (windowSize);
foreach (AbstractBlock *block, mAbstractBlocks)
{
connect (block, SIGNAL (signalUpdateSetting (const QString &, const QString &)),
this, SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)) );
}
connect ( this,
SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)),
&(CSMSettings::UserSettings::instance()),
SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)));
}
void CSVSettings::WindowPage::initializeWidgets (const CSMSettings::SettingMap &settings)
{
//iterate each item in each blocks in this section
//validate the corresponding setting against the defined valuelist if any.
for (AbstractBlockList::Iterator it_block = mAbstractBlocks.begin();
it_block != mAbstractBlocks.end(); ++it_block)
(*it_block)->updateSettings (settings);
}

@ -0,0 +1,34 @@
#ifndef WINDOWPAGE_H
#define WINDOWPAGE_H
#include "abstractpage.hpp"
class QGroupBox;
namespace CSVSettings {
class UserSettings;
class AbstractBlock;
class WindowPage : public AbstractPage
{
Q_OBJECT
public:
WindowPage(QWidget *parent = 0);
void setupUi();
void initializeWidgets (const CSMSettings::SettingMap &settings);
///
GroupBlockDef *buildCustomWindowSize();
GroupBlockDef *buildDefinedWindowSize();
GroupBlockDef *buildWindowSizeToggle();
CustomBlockDef *buildWindowSize (GroupBlockDef *, GroupBlockDef *, GroupBlockDef *);
signals:
void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue);
};
}
#endif //WINDOWPAGE_H

@ -0,0 +1,122 @@
#include "recordstatusdelegate.hpp"
#include <QPainter>
#include <QApplication>
#include <QUndoStack>
#include "../../model/settings/usersettings.hpp"
CSVWorld::RecordStatusDelegate::RecordStatusDelegate(QUndoStack &undoStack, QObject *parent)
: CommandDelegate (undoStack, parent)
{
mModifiedIcon = new QIcon (":./modified.png");
mAddedIcon = new QIcon (":./added.png");
mDeletedIcon = new QIcon (":./removed.png");
mBaseIcon = new QIcon (":./base.png");
mIconSize = 16;
//Offset values are most likely device-dependent.
//Need to replace with device-independent references.
mTextLeftOffset = 3;
mIconTopOffset = -3;
mStatusDisplay = 0; //icons and text by default. Remove when implemented as a user preference
mFont = QApplication::font();
mFont.setPointSize(10);
mFontMetrics = new QFontMetrics(mFont);
mTextAlignment.setAlignment (Qt::AlignLeft | Qt::AlignVCenter );
}
void CSVWorld::RecordStatusDelegate::paint (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
painter->save();
QString text = "";
QIcon *icon = 0;
switch (index.data().toInt())
{
case 0: // State_BaseOnly
text = "Base";
icon = mBaseIcon;
break;
case 1: // State_Modified
text = "Modified";
icon = mModifiedIcon;
break;
case 2: // State_Modified_Only
text = "Added";
icon = mAddedIcon;
break;
case 3: // State_Deleted
case 4: // State_Erased
text = "Deleted";
icon = mDeletedIcon;
break;
default:
break;
}
QRect textRect = option.rect;
QRect iconRect = option.rect;
//for icon-only (1), default option.rect centers icon left-to-right
//otherwise, size option.rect to fit the icon, forcing left-alignment with text
iconRect.setTop (iconRect.top() + mIconTopOffset);
iconRect.setBottom (iconRect.top() + mIconSize);
if (mStatusDisplay == 0 && (icon) )
{
iconRect.setRight (iconRect.left()+ mIconSize*2);
textRect.setLeft (iconRect.right() + mTextLeftOffset *1.25);
}
else
textRect.setLeft (textRect.left() + mTextLeftOffset );
if ( (mStatusDisplay == 0 || mStatusDisplay == 1) && (icon) )
painter->drawPixmap(iconRect.center().x()-10,iconRect.center().y()+2, icon->pixmap(mIconSize, mIconSize));
// icon + text or text only, or force text if no icon exists for status
if (mStatusDisplay == 0 || mStatusDisplay == 2 || !(icon) )
{
painter->setFont(mFont);
painter->drawText(textRect, text, mTextAlignment);
}
painter->restore();
}
QSize CSVWorld::RecordStatusDelegate::sizeHint (const QStyleOptionViewItem &option, const QModelIndex &index) const
{
return QSize();
}
CSVWorld::CommandDelegate *CSVWorld::RecordStatusDelegateFactory::makeDelegate (QUndoStack& undoStack,
QObject *parent) const
{
return new RecordStatusDelegate (undoStack, parent);
}
void CSVWorld::RecordStatusDelegate::updateEditorSetting (const QString &settingName, const QString &settingValue)
{
if (settingName == "Record Status Display")
{
if (settingValue == "Icon and Text")
mStatusDisplay = 0;
else if (settingValue == "Icon Only")
mStatusDisplay = 1;
else if (settingValue == "Text Only")
mStatusDisplay = 2;
else
mStatusDisplay = 0;
}
}

@ -0,0 +1,53 @@
#ifndef RECORDSTATUSDELEGATE_H
#define RECORDSTATUSDELEGATE_H
#include "util.hpp"
#include <QTextOption>
#include <QFont>
class QIcon;
class QFont;
class QFontMetrics;
namespace CSVWorld
{
class RecordStatusDelegate : public CommandDelegate
{
QFont mFont;
QFontMetrics *mFontMetrics;
QTextOption mTextAlignment;
QIcon *mModifiedIcon;
QIcon *mAddedIcon;
QIcon *mDeletedIcon;
QIcon *mBaseIcon;
int mStatusDisplay;
int mIconSize;
int mIconTopOffset;
int mTextLeftOffset;
public:
explicit RecordStatusDelegate(QUndoStack& undoStack, QObject *parent = 0);
void paint (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
QSize sizeHint (const QStyleOptionViewItem &option, const QModelIndex &index) const;
void updateEditorSetting (const QString &settingName, const QString &settingValue);
};
class RecordStatusDelegateFactory : public CommandDelegateFactory
{
public:
virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const;
///< The ownership of the returned CommandDelegate is transferred to the caller.
};
}
#endif // RECORDSTATUSDELEGATE_H

@ -12,6 +12,7 @@
#include "../../model/world/idtableproxymodel.hpp"
#include "../../model/world/idtable.hpp"
#include "../../model/world/record.hpp"
#include "recordstatusdelegate.hpp"
#include "util.hpp"
@ -80,7 +81,7 @@ std::vector<std::string> CSVWorld::Table::listDeletableSelectedIds() const
CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack,
bool createAndDelete)
: mUndoStack (undoStack), mCreateAction (0), mEditLock (false)
: mUndoStack (undoStack), mCreateAction (0), mEditLock (false), mRecordStatusDisplay (0)
{
mModel = &dynamic_cast<CSMWorld::IdTable&> (*data.getTableModel (id));
@ -161,6 +162,7 @@ void CSVWorld::Table::createRecord()
mUndoStack.push (new CSMWorld::CreateCommand (*mProxyModel, stream.str()));
}
}
void CSVWorld::Table::revertRecord()
@ -201,4 +203,13 @@ void CSVWorld::Table::deleteRecord()
mUndoStack.endMacro();
}
}
}
}
void CSVWorld::Table::updateEditorSetting (const QString &settingName, const QString &settingValue)
{
if (settingName == "Record Status Display")
{
dynamic_cast<CSVWorld::RecordStatusDelegate *>(this->itemDelegateForColumn(1))->updateEditorSetting (settingName, settingValue);
emit dataChanged(mModel->index(0,1), mModel->index(mModel->rowCount()-1, 1));
}
}

@ -34,6 +34,7 @@ namespace CSVWorld
CSMWorld::IdTableProxyModel *mProxyModel;
CSMWorld::IdTable *mModel;
bool mEditLock;
int mRecordStatusDisplay;
private:
@ -52,6 +53,8 @@ namespace CSVWorld
CSMWorld::UniversalId getUniversalId (int row) const;
void updateEditorSetting (const QString &settingName, const QString &settingValue);
private slots:
void createRecord();

@ -22,4 +22,11 @@ void CSVWorld::TableSubView::setEditLock (bool locked)
void CSVWorld::TableSubView::rowActivated (const QModelIndex& index)
{
focusId (mTable->getUniversalId (index.row()));
}
}
void CSVWorld::TableSubView::updateEditorSetting(const QString &settingName, const QString &settingValue)
{
if (settingName == "Record Status Display")
mTable->updateEditorSetting(settingName, settingValue);
}

@ -23,8 +23,8 @@ namespace CSVWorld
public:
TableSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, bool createAndDelete);
virtual void setEditLock (bool locked);
void updateEditorSetting (const QString &, const QString &);
private slots:
@ -32,4 +32,4 @@ namespace CSVWorld
};
}
#endif
#endif

@ -82,6 +82,8 @@ namespace CSVWorld
///< \brief Use commands instead of manipulating the model directly
class CommandDelegate : public QStyledItemDelegate
{
Q_OBJECT
QUndoStack& mUndoStack;
bool mEditLock;
@ -105,6 +107,10 @@ namespace CSVWorld
void setEditLock (bool locked);
bool isEditLocked() const;
private slots:
virtual void slotUpdateEditorSetting (const QString &settingName, const QString &settingValue) {}
};
}

@ -33,7 +33,7 @@ add_openmw_dir (mwgui
enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor spellicons
merchantrepair repair soulgemdialog companionwindow bookpage journalviewmodel journalbooks
keywordsearch itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview
tradeitemmodel companionitemmodel pickpocketitemmodel
tradeitemmodel companionitemmodel pickpocketitemmodel fontloader controllers
)
add_openmw_dir (mwdialogue
@ -106,19 +106,23 @@ target_link_libraries(openmw
${OGRE_LIBRARIES}
${OGRE_Terrain_LIBRARY}
${OGRE_STATIC_PLUGINS}
${OIS_LIBRARIES}
${Boost_LIBRARIES}
${OPENAL_LIBRARY}
${SOUND_INPUT_LIBRARY}
${BULLET_LIBRARIES}
${MYGUI_LIBRARIES}
${SDL2_LIBRARY}
${MYGUI_PLATFORM_LIBRARIES}
"shiny"
"shiny.OgrePlatform"
${SHINY_LIBRARIES}
"oics"
"sdl4ogre"
components
)
if (NOT UNIX)
target_link_libraries(openmw ${SDL2MAIN_LIBRARY})
endif()
# Fix for not visible pthreads functions for linker with glibc 2.15
if (UNIX AND NOT APPLE)
target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT})
@ -131,10 +135,9 @@ endif()
if(APPLE)
find_library(CARBON_FRAMEWORK Carbon)
find_library(COCOA_FRAMEWORK Cocoa)
find_library(IOKIT_FRAMEWORK IOKit)
target_link_libraries(openmw ${CARBON_FRAMEWORK} ${COCOA_FRAMEWORK} ${IOKIT_FRAMEWORK})
target_link_libraries(openmw ${COCOA_FRAMEWORK} ${IOKIT_FRAMEWORK})
if (FFMPEG_FOUND)
find_library(COREVIDEO_FRAMEWORK CoreVideo)

@ -1,4 +1,5 @@
#include "engine.hpp"
#include "components/esm/loadcell.hpp"
#include <OgreRoot.h>
@ -37,6 +38,8 @@
#include "mwmechanics/mechanicsmanagerimp.hpp"
#include <SDL.h>
void OMW::Engine::executeLocalScripts()
{
MWWorld::LocalScripts& localScripts = MWBase::Environment::get().getWorld()->getLocalScripts();
@ -75,7 +78,8 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
try
{
float frametime = std::min(evt.timeSinceLastFrame, 0.2f);
mEnvironment.setFrameDuration(frametime);
mEnvironment.setFrameDuration (frametime);
// update input
MWBase::Environment::get().getInputManager()->update(frametime, false);
@ -129,7 +133,6 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
: mOgre (0)
, mFpsLevel(0)
, mDebug (false)
, mVerboseScripts (false)
, mNewGame (false)
, mUseSound (true)
@ -141,6 +144,18 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
{
std::srand ( std::time(NULL) );
MWClass::registerClasses();
Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE;
if(SDL_WasInit(flags) == 0)
{
//kindly ask SDL not to trash our OGL context
//might this be related to http://bugzilla.libsdl.org/show_bug.cgi?id=748 ?
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
if(SDL_Init(flags) != 0)
{
throw std::runtime_error("Could not initialize SDL! " + std::string(SDL_GetError()));
}
}
}
OMW::Engine::~Engine()
@ -148,6 +163,7 @@ OMW::Engine::~Engine()
mEnvironment.cleanup();
delete mScriptContext;
delete mOgre;
SDL_Quit();
}
// Load BSA files
@ -268,11 +284,6 @@ void OMW::Engine::addPlugin (const std::string& plugin)
}
}
void OMW::Engine::setDebugMode(bool debugMode)
{
mDebug = debugMode;
}
void OMW::Engine::setScriptsVerbosity(bool scriptsVerbosity)
{
mVerboseScripts = scriptsVerbosity;
@ -315,6 +326,8 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings)
else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg"))
nifOverrides.loadTransparencyOverrides(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg");
settings.setBool("hardware cursors", "GUI", true);
return settingspath;
}
@ -352,14 +365,16 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
addResourcesDirectory(mResDir / "shadows");
addZipResource(mResDir / "mygui" / "Obliviontt.zip");
// Create the window
OEngine::Render::WindowSettings windowSettings;
windowSettings.fullscreen = settings.getBool("fullscreen", "Video");
windowSettings.window_x = settings.getInt("resolution x", "Video");
windowSettings.window_y = settings.getInt("resolution y", "Video");
windowSettings.screen = settings.getInt("screen", "Video");
windowSettings.vsync = settings.getBool("vsync", "Video");
windowSettings.icon = "openmw.png";
std::string aa = settings.getString("antialiasing", "Video");
windowSettings.fsaa = (aa.substr(0, 4) == "MSAA") ? aa.substr(5, aa.size()-5) : "0";
mOgre->createWindow("OpenMW", windowSettings);
loadBSA();
@ -380,7 +395,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
mEnvironment.setWindowManager (new MWGui::WindowManager(
mExtensions, mFpsLevel, mOgre, mCfgMgr.getLogPath().string() + std::string("/"),
mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage));
mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding));
if (mNewGame)
mEnvironment.getWindowManager()->setNewGame(true);
@ -409,7 +424,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
mEnvironment.setInputManager (new MWInput::InputManager (*mOgre,
MWBase::Environment::get().getWorld()->getPlayer(),
*MWBase::Environment::get().getWindowManager(), mDebug, *this, keybinderUser, keybinderUserExists));
*MWBase::Environment::get().getWindowManager(), *this, keybinderUser, keybinderUserExists));
mEnvironment.getWorld()->renderPlayer();

@ -71,7 +71,6 @@ namespace OMW
std::vector<std::string> mMaster;
std::vector<std::string> mPlugins;
int mFpsLevel;
bool mDebug;
bool mVerboseScripts;
bool mNewGame;
bool mUseSound;
@ -147,10 +146,6 @@ namespace OMW
/// Enable fps counter
void showFPS(int level);
/// Enable debug mode:
/// - non-exclusive input
void setDebugMode(bool debugMode);
/// Enable or disable verbose script output
void setScriptsVerbosity(bool scriptsVerbosity);

@ -2,6 +2,7 @@
#include <components/files/configurationmanager.hpp>
#include <SDL_main.h>
#include "engine.hpp"
#if defined(_WIN32) && !defined(_CONSOLE)
@ -118,9 +119,6 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
("anim-verbose", bpo::value<bool>()->implicit_value(true)
->default_value(false), "output animation indices files")
("debug", bpo::value<bool>()->implicit_value(true)
->default_value(false), "debug mode")
("nosound", bpo::value<bool>()->implicit_value(true)
->default_value(false), "disable all sounds")
@ -217,8 +215,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
StringsVector master = variables["master"].as<StringsVector>();
if (master.empty())
{
std::cout << "No master file given. Assuming Morrowind.esm" << std::endl;
master.push_back("Morrowind");
std::cout << "No master file given. Aborting...\n";
return false;
}
StringsVector plugin = variables["plugin"].as<StringsVector>();
@ -243,7 +241,6 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
engine.setNewGame(variables["new-game"].as<bool>());
// other settings
engine.setDebugMode(variables["debug"].as<bool>());
engine.setSoundUsage(!variables["nosound"].as<bool>());
engine.setScriptsVerbosity(variables["script-verbose"].as<bool>());
engine.setCompileAll(variables["script-all"].as<bool>());

@ -112,6 +112,8 @@ namespace MWBase
virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0;
///< Skip the animation for the given MW-reference for one frame. Calls to this function for
/// references that are currently not in the scene should be ignored.
virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) = 0;
};
}

@ -55,6 +55,11 @@ namespace MWGui
class DialogueWindow;
}
namespace SFO
{
class CursorManager;
}
namespace MWBase
{
/// \brief Interface for widnow manager (implemented in MWGui)
@ -92,6 +97,7 @@ namespace MWBase
virtual void updatePlayer() = 0;
virtual MWGui::GuiMode getMode() const = 0;
virtual bool containsMode(MWGui::GuiMode) const = 0;
virtual bool isGuiMode() const = 0;
@ -159,7 +165,7 @@ namespace MWBase
virtual void setFocusObject(const MWWorld::Ptr& focus) = 0;
virtual void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) = 0;
virtual void setMouseVisible(bool visible) = 0;
virtual void setCursorVisible(bool visible) = 0;
virtual void getMousePosition(int &x, int &y) = 0;
virtual void getMousePosition(float &x, float &y) = 0;
virtual void setDragDrop(bool dragDrop) = 0;
@ -258,6 +264,8 @@ namespace MWBase
virtual void changePointer (const std::string& name) = 0;
virtual const Translation::Storage& getTranslationDataStorage() const = 0;
virtual void setKeyFocusWidget (MyGUI::Widget* widget) = 0;
};
}

@ -342,6 +342,10 @@ namespace MWBase
virtual void getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out) = 0;
///< get all containers in active cells owned by this Npc
virtual void getItemsOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out) = 0;
///< get all items in active cells owned by this Npc
virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable) = 0;
virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0;

@ -5,6 +5,7 @@
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/magiceffects.hpp"
#include "../mwmechanics/movement.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp"
@ -29,6 +30,7 @@ namespace
{
MWMechanics::CreatureStats mCreatureStats;
MWWorld::ContainerStore mContainerStore;
MWMechanics::Movement mMovement;
virtual MWWorld::CustomData *clone() const;
};
@ -47,6 +49,18 @@ namespace MWClass
{
std::auto_ptr<CustomData> data (new CustomData);
static bool inited = false;
if(!inited)
{
const MWBase::World *world = MWBase::Environment::get().getWorld();
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
fMinWalkSpeedCreature = gmst.find("fMinWalkSpeedCreature");
fMaxWalkSpeedCreature = gmst.find("fMaxWalkSpeedCreature");
inited = true;
}
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
// creature stats
@ -181,6 +195,42 @@ namespace MWClass
return true;
}
float Creature::getSpeed(const MWWorld::Ptr &ptr) const
{
MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
float walkSpeed = fMinWalkSpeedCreature->getFloat() + 0.01 * stats.getAttribute(ESM::Attribute::Speed).getModified()
* (fMaxWalkSpeedCreature->getFloat() - fMinWalkSpeedCreature->getFloat());
/// \todo what about the rest?
return walkSpeed;
}
MWMechanics::Movement& Creature::getMovementSettings (const MWWorld::Ptr& ptr) const
{
ensureCustomData (ptr);
return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mMovement;
}
Ogre::Vector3 Creature::getMovementVector (const MWWorld::Ptr& ptr) const
{
MWMechanics::Movement &movement = getMovementSettings(ptr);
Ogre::Vector3 vec(movement.mPosition);
movement.mPosition[0] = 0.0f;
movement.mPosition[1] = 0.0f;
movement.mPosition[2] = 0.0f;
return vec;
}
Ogre::Vector3 Creature::getRotationVector (const MWWorld::Ptr& ptr) const
{
MWMechanics::Movement &movement = getMovementSettings(ptr);
Ogre::Vector3 vec(movement.mRotation);
movement.mRotation[0] = 0.0f;
movement.mRotation[1] = 0.0f;
movement.mRotation[2] = 0.0f;
return vec;
}
MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::Ptr& ptr) const
{
MWWorld::LiveCellRef<ESM::Creature> *ref =
@ -249,4 +299,7 @@ namespace MWClass
return MWWorld::Ptr(&cell.mCreatures.insert(*ref), &cell);
}
const ESM::GameSetting* Creature::fMinWalkSpeedCreature;
const ESM::GameSetting* Creature::fMaxWalkSpeedCreature;
}

@ -12,6 +12,9 @@ namespace MWClass
virtual MWWorld::Ptr
copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const;
static const ESM::GameSetting *fMinWalkSpeedCreature;
static const ESM::GameSetting *fMaxWalkSpeedCreature;
public:
virtual std::string getId (const MWWorld::Ptr& ptr) const;
@ -66,6 +69,18 @@ namespace MWClass
virtual bool isPersistent (const MWWorld::Ptr& ptr) const;
virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const;
///< Return desired movement.
virtual Ogre::Vector3 getMovementVector (const MWWorld::Ptr& ptr) const;
///< Return desired movement vector (determined based on movement settings,
/// stance and stats).
virtual Ogre::Vector3 getRotationVector (const MWWorld::Ptr& ptr) const;
///< Return desired rotations, as euler angles.
float getSpeed (const MWWorld::Ptr& ptr) const;
static void registerSelf();
virtual std::string getModel(const MWWorld::Ptr &ptr) const;

@ -223,6 +223,9 @@ struct TypesetBookImpl::Typesetter : BookTypesetter
Style * createStyle (char const * fontName, Colour fontColour)
{
if (strcmp(fontName, "") == 0)
return createStyle(MyGUI::FontManager::getInstance().getDefaultFont().c_str(), fontColour);
for (Styles::iterator i = mBook->mStyles.begin (); i != mBook->mStyles.end (); ++i)
if (i->match (fontName, fontColour, fontColour, fontColour, 0))
return &*i;
@ -405,7 +408,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter
while (!stream.eof () && !ucsLineBreak (stream.peek ()) && ucsBreakingSpace (stream.peek ()))
{
MyGUI::GlyphInfo* gi = style->mFont->getGlyphInfo (stream.peek ());
space_width += gi->advance;
if (gi)
space_width += gi->advance + gi->bearingX;
stream.consume ();
}
@ -414,7 +418,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter
while (!stream.eof () && !ucsLineBreak (stream.peek ()) && !ucsBreakingSpace (stream.peek ()))
{
MyGUI::GlyphInfo* gi = style->mFont->getGlyphInfo (stream.peek ());
word_width += gi->advance + gi->bearingX;
if (gi)
word_width += gi->advance + gi->bearingX;
word_height = line_height;
++character_count;
stream.consume ();
@ -628,6 +633,9 @@ namespace
{
MyGUI::GlyphInfo* gi = mFont->getGlyphInfo (ch);
if (!gi)
return;
MyGUI::FloatRect vr;
vr.left = mCursor.left + gi->bearingX;
@ -647,7 +655,8 @@ namespace
{
MyGUI::GlyphInfo* gi = mFont->getGlyphInfo (ch);
mCursor.left += gi->bearingX + gi->advance;
if (gi)
mCursor.left += gi->bearingX + gi->advance;
}
private:

@ -130,26 +130,12 @@ namespace MWGui
void BookWindow::onNextPageButtonClicked (MyGUI::Widget* sender)
{
if ((mCurrentPage+1)*2 < mPages.size())
{
MWBase::Environment::get().getSoundManager()->playSound ("book page2", 1.0, 1.0);
++mCurrentPage;
updatePages();
}
nextPage();
}
void BookWindow::onPrevPageButtonClicked (MyGUI::Widget* sender)
{
if (mCurrentPage > 0)
{
MWBase::Environment::get().getSoundManager()->playSound ("book page", 1.0, 1.0);
--mCurrentPage;
updatePages();
}
prevPage();
}
void BookWindow::updatePages()
@ -194,5 +180,28 @@ namespace MWGui
if (button->getAlign().isRight())
button->setPosition(button->getPosition() + MyGUI::IntPoint(diff.width,0));
}
void BookWindow::nextPage()
{
if ((mCurrentPage+1)*2 < mPages.size())
{
MWBase::Environment::get().getSoundManager()->playSound ("book page2", 1.0, 1.0);
++mCurrentPage;
updatePages();
}
}
void BookWindow::prevPage()
{
if (mCurrentPage > 0)
{
MWBase::Environment::get().getSoundManager()->playSound ("book page", 1.0, 1.0);
--mCurrentPage;
updatePages();
}
}
}

@ -16,7 +16,8 @@ namespace MWGui
void open(MWWorld::Ptr book);
void setTakeButtonShow(bool show);
void nextPage();
void prevPage();
void setInventoryAllowed(bool allowed);
protected:

@ -238,6 +238,12 @@ namespace MWGui
}
}
void CharacterCreation::doRenderUpdate()
{
if (mRaceDialog)
mRaceDialog->doRenderUpdate();
}
void CharacterCreation::setPlayerHealth (const MWMechanics::DynamicStat<float>& value)
{
mPlayerHealth = value;

@ -41,6 +41,7 @@ namespace MWGui
void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value);
void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat<float>& value);
void configureSkills (const SkillList& major, const SkillList& minor);
void doRenderUpdate();
private:
//Dialogs

@ -407,7 +407,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");
@ -866,7 +866,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()

@ -5,6 +5,7 @@
#include "../mwscript/extensions.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
namespace MWGui
{
@ -131,16 +132,12 @@ namespace MWGui
// Give keyboard focus to the combo box whenever the console is
// turned on
MyGUI::InputManager::getInstance().setKeyFocusWidget(command);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(command);
}
void Console::disable()
{
setVisible(false);
setSelectedObject(MWWorld::Ptr());
// Remove keyboard focus from the console input whenever the
// console is turned off
MyGUI::InputManager::getInstance().setKeyFocusWidget(NULL);
}
void Console::setFont(const std::string &fntName)
@ -415,7 +412,7 @@ namespace MWGui
setTitle("#{sConsoleTitle}");
mPtr = MWWorld::Ptr();
}
MyGUI::InputManager::getInstance().setKeyFocusWidget(command);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(command);
}
void Console::onReferenceUnavailable()

@ -3,11 +3,39 @@
#include "../mwworld/containerstore.hpp"
#include "../mwworld/class.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
namespace
{
bool stacks (const MWWorld::Ptr& left, const MWWorld::Ptr& right)
{
if (left == right)
return true;
// If one of the items is in an inventory and currently equipped, we need to check stacking both ways to be sure
if (left.getContainerStore() && right.getContainerStore())
return left.getContainerStore()->stacks(left, right)
&& right.getContainerStore()->stacks(left, right);
if (left.getContainerStore())
return left.getContainerStore()->stacks(left, right);
if (right.getContainerStore())
return right.getContainerStore()->stacks(left, right);
MWWorld::ContainerStore store;
return store.stacks(left, right);
}
}
namespace MWGui
{
ContainerItemModel::ContainerItemModel(const std::vector<MWWorld::Ptr>& itemSources)
ContainerItemModel::ContainerItemModel(const std::vector<MWWorld::Ptr>& itemSources, const std::vector<MWWorld::Ptr>& worldItems)
: mItemSources(itemSources)
, mWorldItems(worldItems)
{
assert (mItemSources.size());
}
@ -65,8 +93,7 @@ void ContainerItemModel::removeItem (const ItemStack& item, size_t count)
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{
// If one of the items is in an inventory and currently equipped, we need to check stacking both ways to be sure
if (*it == item.mBase || (store.stacks(*it, item.mBase) && item.mBase.getContainerStore()->stacks(*it, item.mBase)))
if (stacks(*it, item.mBase))
{
int refCount = it->getRefData().getCount();
it->getRefData().setCount(std::max(0, refCount - toRemove));
@ -76,6 +103,21 @@ void ContainerItemModel::removeItem (const ItemStack& item, size_t count)
}
}
}
for (std::vector<MWWorld::Ptr>::iterator source = mWorldItems.begin(); source != mWorldItems.end(); ++source)
{
if (stacks(*source, item.mBase))
{
int refCount = source->getRefData().getCount();
if (refCount - toRemove <= 0)
MWBase::Environment::get().getWorld()->deleteObject(*source);
else
source->getRefData().setCount(std::max(0, refCount - toRemove));
toRemove -= refCount;
if (toRemove <= 0)
return;
}
}
throw std::runtime_error("Not enough items to remove could be found");
}
@ -91,8 +133,7 @@ void ContainerItemModel::update()
std::vector<ItemStack>::iterator itemStack = mItems.begin();
for (; itemStack != mItems.end(); ++itemStack)
{
// If one of the items is in an inventory and currently equipped, we need to check stacking both ways to be sure
if (store.stacks(itemStack->mBase, *it) && it->getContainerStore()->stacks(itemStack->mBase, *it))
if (stacks(*it, itemStack->mBase))
{
// we already have an item stack of this kind, add to it
itemStack->mCount += it->getRefData().getCount();
@ -108,6 +149,26 @@ void ContainerItemModel::update()
}
}
}
for (std::vector<MWWorld::Ptr>::iterator source = mWorldItems.begin(); source != mWorldItems.end(); ++source)
{
std::vector<ItemStack>::iterator itemStack = mItems.begin();
for (; itemStack != mItems.end(); ++itemStack)
{
if (stacks(*source, itemStack->mBase))
{
// we already have an item stack of this kind, add to it
itemStack->mCount += source->getRefData().getCount();
break;
}
}
if (itemStack == mItems.end())
{
// no stack yet, create one
ItemStack newItem (*source, this, source->getRefData().getCount());
mItems.push_back(newItem);
}
}
}
}

@ -11,7 +11,7 @@ namespace MWGui
class ContainerItemModel : public ItemModel
{
public:
ContainerItemModel (const std::vector<MWWorld::Ptr>& itemSources);
ContainerItemModel (const std::vector<MWWorld::Ptr>& itemSources, const std::vector<MWWorld::Ptr>& worldItems);
///< @note The order of elements \a itemSources matters here. The first element has the highest priority for removal,
/// while the last element will be used to add new items to.
@ -28,6 +28,7 @@ namespace MWGui
private:
std::vector<MWWorld::Ptr> mItemSources;
std::vector<MWWorld::Ptr> mWorldItems;
std::vector<ItemStack> mItems;
};

@ -0,0 +1,54 @@
#include "controllers.hpp"
namespace MWGui
{
namespace Controllers
{
ControllerRepeatClick::ControllerRepeatClick() :
mInit(0.5),
mStep(0.1),
mEnabled(true),
mTimeLeft(0)
{
}
ControllerRepeatClick::~ControllerRepeatClick()
{
}
bool ControllerRepeatClick::addTime(MyGUI::Widget* _widget, float _time)
{
if(mTimeLeft == 0)
mTimeLeft = mInit;
mTimeLeft -= _time;
while (mTimeLeft <= 0)
{
mTimeLeft += mStep;
eventRepeatClick(_widget, this);
}
return true;
}
void ControllerRepeatClick::setRepeat(float init, float step)
{
mInit = init;
mStep = step;
}
void ControllerRepeatClick::setEnabled(bool enable)
{
mEnabled = enable;
}
void ControllerRepeatClick::setProperty(const std::string& _key, const std::string& _value)
{
}
void ControllerRepeatClick::prepareItem(MyGUI::Widget* _widget)
{
}
}
}

@ -0,0 +1,46 @@
#ifndef MWGUI_CONTROLLERS_H
#define MWGUI_CONTROLLERS_H
#include <MyGUI_Widget.h>
#include <MyGUI_ControllerItem.h>
namespace MWGui
{
namespace Controllers
{
class ControllerRepeatClick :
public MyGUI::ControllerItem
{
MYGUI_RTTI_DERIVED( ControllerRepeatClick )
public:
ControllerRepeatClick();
virtual ~ControllerRepeatClick();
void setRepeat(float init, float step);
void setEnabled(bool enable);
virtual void setProperty(const std::string& _key, const std::string& _value);
// Events
typedef MyGUI::delegates::CMultiDelegate2<MyGUI::Widget*, MyGUI::ControllerItem*> EventHandle_RepeatClickVoid;
/** Event : Repeat Click.\n
signature : void method(MyGUI::Widget* _sender, MyGUI::ControllerItem *_controller)\n
*/
EventHandle_RepeatClickVoid eventRepeatClick;
private:
bool addTime(MyGUI::Widget* _widget, float _time);
void prepareItem(MyGUI::Widget* _widget);
private:
float mInit;
float mStep;
bool mEnabled;
float mTimeLeft;
};
}
}
#endif

@ -2,6 +2,9 @@
#include <boost/lexical_cast.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
namespace MWGui
{
CountDialog::CountDialog() :
@ -40,7 +43,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);
mItemEdit->setCaption(boost::lexical_cast<std::string>(maxCount));

@ -7,6 +7,7 @@
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/soundmanager.hpp"
#include "../mwmechanics/npcstats.hpp"
@ -115,7 +116,7 @@ namespace MWGui
void Response::write(BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map<std::string, Link*>& topicLinks) const
{
BookTypesetter::Style* title = typesetter->createStyle("EB Garamond", MyGUI::Colour(223/255.f, 201/255.f, 159/255.f));
BookTypesetter::Style* title = typesetter->createStyle("", MyGUI::Colour(223/255.f, 201/255.f, 159/255.f));
typesetter->sectionBreak(9);
if (mTitle != "")
typesetter->write(title, to_utf8_span(mTitle.c_str()));
@ -159,7 +160,7 @@ namespace MWGui
if (hyperLinks.size() && MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation())
{
BookTypesetter::Style* style = typesetter->createStyle("EB Garamond", MyGUI::Colour(202/255.f, 165/255.f, 96/255.f));
BookTypesetter::Style* style = typesetter->createStyle("", MyGUI::Colour(202/255.f, 165/255.f, 96/255.f));
size_t formatted = 0; // points to the first character that is not laid out yet
for (std::map<Range, intptr_t>::iterator it = hyperLinks.begin(); it != hyperLinks.end(); ++it)
{
@ -197,7 +198,7 @@ namespace MWGui
void Response::addTopicLink(BookTypesetter::Ptr typesetter, intptr_t topicId, size_t begin, size_t end) const
{
BookTypesetter::Style* style = typesetter->createStyle("EB Garamond", MyGUI::Colour(202/255.f, 165/255.f, 96/255.f));
BookTypesetter::Style* style = typesetter->createStyle("", MyGUI::Colour(202/255.f, 165/255.f, 96/255.f));
const MyGUI::Colour linkHot (143/255.f, 155/255.f, 218/255.f);
const MyGUI::Colour linkNormal (112/255.f, 126/255.f, 207/255.f);
@ -215,7 +216,7 @@ namespace MWGui
void Message::write(BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map<std::string, Link*>& topicLinks) const
{
BookTypesetter::Style* title = typesetter->createStyle("EB Garamond", MyGUI::Colour(223/255.f, 201/255.f, 159/255.f));
BookTypesetter::Style* title = typesetter->createStyle("", MyGUI::Colour(223/255.f, 201/255.f, 159/255.f));
typesetter->sectionBreak(9);
typesetter->write(title, to_utf8_span(mText.c_str()));
}
@ -224,16 +225,22 @@ namespace MWGui
void Choice::activated()
{
MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.0, 1.0);
MWBase::Environment::get().getDialogueManager()->questionAnswered(mChoiceId);
}
void Topic::activated()
{
MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f);
MWBase::Environment::get().getDialogueManager()->keywordSelected(Misc::StringUtils::lowerCase(mTopicId));
}
void Goodbye::activated()
{
MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f);
MWBase::Environment::get().getDialogueManager()->goodbyeSelected();
}
@ -465,13 +472,14 @@ namespace MWGui
(*it)->write(typesetter, &mKeywordSearch, mTopicLinks);
BookTypesetter::Style* body = typesetter->createStyle("EB Garamond", MyGUI::Colour::White);
BookTypesetter::Style* body = typesetter->createStyle("", MyGUI::Colour::White);
typesetter->sectionBreak(9);
// choices
const MyGUI::Colour linkHot (223/255.f, 201/255.f, 159/255.f);
const MyGUI::Colour linkNormal (150/255.f, 50/255.f, 30/255.f);
const MyGUI::Colour linkActive (243/255.f, 237/255.f, 221/255.f);
for (std::map<std::string, int>::iterator it = mChoices.begin(); it != mChoices.end(); ++it)
for (std::map<std::string, int>::reverse_iterator it = mChoices.rbegin(); it != mChoices.rend(); ++it)
{
Choice* link = new Choice(it->second);
mLinks.push_back(link);

@ -61,30 +61,32 @@ namespace MWGui
void EnchantingDialog::updateLabels()
{
std::stringstream enchantCost;
enchantCost << std::setprecision(1) << std::fixed << mEnchanting.getEnchantCost();
enchantCost << std::setprecision(1) << std::fixed << mEnchanting.getEnchantPoints();
mEnchantmentPoints->setCaption(enchantCost.str() + " / " + boost::lexical_cast<std::string>(mEnchanting.getMaxEnchantValue()));
mCharge->setCaption(boost::lexical_cast<std::string>(mEnchanting.getGemCharge()));
mCastCost->setCaption(boost::lexical_cast<std::string>(mEnchanting.getEnchantCost()));
std::stringstream castCost;
castCost << std::setprecision(1) << std::fixed << mEnchanting.getCastCost();
mCastCost->setCaption(boost::lexical_cast<std::string>(castCost.str()));
mPrice->setCaption(boost::lexical_cast<std::string>(mEnchanting.getEnchantPrice()));
switch(mEnchanting.getEnchantType())
switch(mEnchanting.getCastStyle())
{
case 0:
case ESM::Enchantment::CastOnce:
mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastOnce","Cast Once"));
mAddEffectDialog.constantEffect=false;
break;
case 1:
case ESM::Enchantment::WhenStrikes:
mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenStrikes", "When Strikes"));
mAddEffectDialog.constantEffect=false;
break;
case 2:
case ESM::Enchantment::WhenUsed:
mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenUsed", "When Used"));
mAddEffectDialog.constantEffect=false;
break;
case 3:
case ESM::Enchantment::ConstantEffect:
mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastConstant", "Cast Constant"));
mAddEffectDialog.constantEffect=true;
break;
@ -169,7 +171,7 @@ namespace MWGui
image->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onRemoveItem);
mEnchanting.setOldItem(item);
mEnchanting.nextEnchantType();
mEnchanting.nextCastStyle();
updateLabels();
}
@ -248,7 +250,7 @@ namespace MWGui
void EnchantingDialog::onTypeButtonClicked(MyGUI::Widget* sender)
{
mEnchanting.nextEnchantType();
mEnchanting.nextCastStyle();
updateLabels();
}
@ -278,7 +280,7 @@ namespace MWGui
return;
}
if (mEnchanting.getEnchantCost() > mEnchanting.getMaxEnchantValue())
if (mEnchanting.getEnchantPoints() > mEnchanting.getMaxEnchantValue())
{
MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage29}");
return;

@ -0,0 +1,238 @@
#include "fontloader.hpp"
#include <OgreResourceGroupManager.h>
#include <OgreTextureManager.h>
#include <MyGUI_ResourceManager.h>
#include <MyGUI_FontManager.h>
#include <MyGUI_ResourceManualFont.h>
#include <MyGUI_XmlDocument.h>
#include <MyGUI_FactoryManager.h>
#include <components/misc/stringops.hpp>
namespace
{
unsigned long utf8ToUnicode(const std::string& utf8)
{
size_t i = 0;
unsigned long unicode;
size_t todo;
unsigned char ch = utf8[i++];
if (ch <= 0x7F)
{
unicode = ch;
todo = 0;
}
else if (ch <= 0xBF)
{
throw std::logic_error("not a UTF-8 string");
}
else if (ch <= 0xDF)
{
unicode = ch&0x1F;
todo = 1;
}
else if (ch <= 0xEF)
{
unicode = ch&0x0F;
todo = 2;
}
else if (ch <= 0xF7)
{
unicode = ch&0x07;
todo = 3;
}
else
{
throw std::logic_error("not a UTF-8 string");
}
for (size_t j = 0; j < todo; ++j)
{
unsigned char ch = utf8[i++];
if (ch < 0x80 || ch > 0xBF)
throw std::logic_error("not a UTF-8 string");
unicode <<= 6;
unicode += ch & 0x3F;
}
if (unicode >= 0xD800 && unicode <= 0xDFFF)
throw std::logic_error("not a UTF-8 string");
if (unicode > 0x10FFFF)
throw std::logic_error("not a UTF-8 string");
return unicode;
}
}
namespace MWGui
{
FontLoader::FontLoader(ToUTF8::FromType encoding)
{
if (encoding == ToUTF8::WINDOWS_1252)
mEncoding = ToUTF8::CP437;
else
mEncoding = encoding;
}
void FontLoader::loadAllFonts()
{
Ogre::StringVector groups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups ();
for (Ogre::StringVector::iterator it = groups.begin(); it != groups.end(); ++it)
{
Ogre::StringVectorPtr resourcesInThisGroup = Ogre::ResourceGroupManager::getSingleton ().findResourceNames (*it, "*.fnt");
for (Ogre::StringVector::iterator resource = resourcesInThisGroup->begin(); resource != resourcesInThisGroup->end(); ++resource)
{
loadFont(*resource);
}
}
}
typedef struct
{
float x;
float y;
} Point;
typedef struct
{
float u1; // appears unused, always 0
Point top_left;
Point top_right;
Point bottom_left;
Point bottom_right;
float width;
float height;
float u2; // appears unused, always 0
float kerning;
float ascent;
} GlyphInfo;
void FontLoader::loadFont(const std::string &fileName)
{
Ogre::DataStreamPtr file = Ogre::ResourceGroupManager::getSingleton().openResource(fileName);
float fontSize;
int one;
file->read(&fontSize, sizeof(fontSize));
file->read(&one, sizeof(int));
assert(one == 1);
file->read(&one, sizeof(int));
assert(one == 1);
char name_[284];
file->read(name_, sizeof(name_));
std::string name(name_);
GlyphInfo data[256];
file->read(data, sizeof(data));
file->close();
// Create the font texture
std::string bitmapFilename = "Fonts/" + std::string(name) + ".tex";
Ogre::DataStreamPtr bitmapFile = Ogre::ResourceGroupManager::getSingleton().openResource(bitmapFilename);
int width, height;
bitmapFile->read(&width, sizeof(int));
bitmapFile->read(&height, sizeof(int));
std::vector<Ogre::uchar> textureData;
textureData.resize(width*height*4);
bitmapFile->read(&textureData[0], width*height*4);
bitmapFile->close();
std::string textureName = name;
Ogre::Image image;
image.loadDynamicImage(&textureData[0], width, height, Ogre::PF_BYTE_RGBA);
Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual(textureName,
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
Ogre::TEX_TYPE_2D,
width, height, 0, Ogre::PF_BYTE_RGBA);
texture->loadImage(image);
// Register the font with MyGUI
MyGUI::ResourceManualFont* font = static_cast<MyGUI::ResourceManualFont*>(
MyGUI::FactoryManager::getInstance().createObject("Resource", "ResourceManualFont"));
// We need to emulate loading from XML because the data members are private as of mygui 3.2.0
MyGUI::xml::Document xmlDocument;
MyGUI::xml::ElementPtr root = xmlDocument.createRoot("ResourceManualFont");
if (name.size() >= 5 && Misc::StringUtils::ciEqual(name.substr(0, 5), "magic"))
root->addAttribute("name", "Magic Cards");
else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "century"))
root->addAttribute("name", "Century Gothic");
else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "daedric"))
root->addAttribute("name", "Daedric");
else
return; // no point in loading it, since there is no way of using additional fonts
MyGUI::xml::ElementPtr defaultHeight = root->createChild("Property");
defaultHeight->addAttribute("key", "DefaultHeight");
defaultHeight->addAttribute("value", fontSize);
MyGUI::xml::ElementPtr source = root->createChild("Property");
source->addAttribute("key", "Source");
source->addAttribute("value", std::string(textureName));
MyGUI::xml::ElementPtr codes = root->createChild("Codes");
for(int i = 0; i < 256; i++)
{
int x1 = data[i].top_left.x*width;
int y1 = data[i].top_left.y*height;
int w = data[i].top_right.x*width - x1;
int h = data[i].bottom_left.y*height - y1;
ToUTF8::Utf8Encoder encoder(mEncoding);
unsigned long unicodeVal = utf8ToUnicode(encoder.getUtf8(std::string(1, (unsigned char)(i))));
MyGUI::xml::ElementPtr code = codes->createChild("Code");
code->addAttribute("index", unicodeVal);
code->addAttribute("coord", MyGUI::utility::toString(x1) + " "
+ MyGUI::utility::toString(y1) + " "
+ MyGUI::utility::toString(w) + " "
+ MyGUI::utility::toString(h));
code->addAttribute("advance", data[i].width);
code->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " "
+ MyGUI::utility::toString((fontSize-data[i].ascent)));
// ASCII vertical bar, use this as text input cursor
if (i == 124)
{
MyGUI::xml::ElementPtr cursorCode = codes->createChild("Code");
cursorCode->addAttribute("index", MyGUI::FontCodeType::Cursor);
cursorCode->addAttribute("coord", MyGUI::utility::toString(x1) + " "
+ MyGUI::utility::toString(y1) + " "
+ MyGUI::utility::toString(w) + " "
+ MyGUI::utility::toString(h));
cursorCode->addAttribute("advance", data[i].width);
cursorCode->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " "
+ MyGUI::utility::toString((fontSize-data[i].ascent)));
}
}
// These are required as well, but the fonts don't provide them
for (int i=0; i<3; ++i)
{
MyGUI::FontCodeType::Enum type;
if(i == 0)
type = MyGUI::FontCodeType::Selected;
else if (i == 1)
type = MyGUI::FontCodeType::SelectedBack;
else if (i == 2)
type = MyGUI::FontCodeType::NotDefined;
MyGUI::xml::ElementPtr cursorCode = codes->createChild("Code");
cursorCode->addAttribute("index", type);
cursorCode->addAttribute("coord", "0 0 0 0");
cursorCode->addAttribute("advance", "0");
cursorCode->addAttribute("bearing", "0 0");
}
font->deserialization(root, MyGUI::Version(3,2,0));
MyGUI::ResourceManager::getInstance().addResource(font);
}
}

@ -0,0 +1,25 @@
#ifndef MWGUI_FONTLOADER_H
#define MWGUI_FONTLOADER_H
#include <components/to_utf8/to_utf8.hpp>
namespace MWGui
{
/// @brief loads Morrowind's .fnt/.tex fonts for use with MyGUI and Ogre
class FontLoader
{
public:
FontLoader (ToUTF8::FromType encoding);
void loadAllFonts ();
private:
ToUTF8::FromType mEncoding;
void loadFont (const std::string& fileName);
};
}
#endif

@ -202,14 +202,14 @@ namespace MWGui
float BookTextParser::widthForCharGlyph(unsigned unicodeChar) const
{
std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont);
std::string fontName(mTextStyle.mFont == "Default" ? MyGUI::FontManager::getInstance().getDefaultFont() : mTextStyle.mFont);
return MyGUI::FontManager::getInstance().getByName(fontName)
->getGlyphInfo(unicodeChar)->width;
}
float BookTextParser::currentFontHeight() const
{
std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont);
std::string fontName(mTextStyle.mFont == "Default" ? MyGUI::FontManager::getInstance().getDefaultFont() : mTextStyle.mFont);
return MyGUI::FontManager::getInstance().getByName(fontName)->getDefaultHeight();
}
@ -251,10 +251,8 @@ namespace MWGui
MyGUI::Gui::getInstance().destroyWidget(mParent->getChildAt(0));
}
boost::algorithm::replace_all(text, "\n", "\n");
boost::algorithm::replace_all(text, "\r", "\r");
boost::algorithm::replace_all(text, "<BR>", "\n\n");
boost::algorithm::replace_all(text, "<P>", "\n\n"); // tweaking by adding another newline to see if that spaces out better
boost::algorithm::replace_all(text, "<BR>", "\n");
boost::algorithm::replace_all(text, "<P>", "\n\n");
boost::algorithm::trim_left(text);
// remove trailing "

@ -13,8 +13,6 @@ namespace MWGui
, mType(Type_Normal)
, mBase(base)
{
assert(base.getContainerStore());
if (MWWorld::Class::get(base).getEnchantment(base) != "")
mFlags |= Flag_Enchanted;
}
@ -31,18 +29,42 @@ namespace MWGui
{
if(mBase == other.mBase)
return true;
return mBase.getContainerStore()->stacks(mBase, other.mBase)
&& other.mBase.getContainerStore()->stacks(mBase, other.mBase);
// If one of the items is in an inventory and currently equipped, we need to check stacking both ways to be sure
if (mBase.getContainerStore() && other.mBase.getContainerStore())
return mBase.getContainerStore()->stacks(mBase, other.mBase)
&& other.mBase.getContainerStore()->stacks(mBase, other.mBase);
if (mBase.getContainerStore())
return mBase.getContainerStore()->stacks(mBase, other.mBase);
if (other.mBase.getContainerStore())
return other.mBase.getContainerStore()->stacks(mBase, other.mBase);
MWWorld::ContainerStore store;
return store.stacks(mBase, other.mBase);
}
bool operator == (const ItemStack& left, const ItemStack& right)
{
if (left.mType != right.mType)
return false;
if(left.mBase == right.mBase)
return true;
return left.mBase.getContainerStore()->stacks(left.mBase, right.mBase)
&& right.mBase.getContainerStore()->stacks(left.mBase, right.mBase);
// If one of the items is in an inventory and currently equipped, we need to check stacking both ways to be sure
if (left.mBase.getContainerStore() && right.mBase.getContainerStore())
return left.mBase.getContainerStore()->stacks(left.mBase, right.mBase)
&& right.mBase.getContainerStore()->stacks(left.mBase, right.mBase);
if (left.mBase.getContainerStore())
return left.mBase.getContainerStore()->stacks(left.mBase, right.mBase);
if (right.mBase.getContainerStore())
return right.mBase.getContainerStore()->stacks(left.mBase, right.mBase);
MWWorld::ContainerStore store;
return store.stacks(left.mBase, right.mBase);
}
ItemModel::ItemModel()

@ -189,14 +189,14 @@ book JournalBooks::createEmptyJournalBook ()
{
BookTypesetter::Ptr typesetter = createTypesetter ();
BookTypesetter::Style* header = typesetter->createStyle ("EB Garamond", MyGUI::Colour (0.60f, 0.00f, 0.00f));
BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black);
BookTypesetter::Style* header = typesetter->createStyle ("", MyGUI::Colour (0.60f, 0.00f, 0.00f));
BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black);
typesetter->write (header, to_utf8_span ("You have no journal entries!"));
typesetter->lineBreak ();
typesetter->write (body, to_utf8_span ("You should have gone though the starting quest and got an initial quest."));
BookTypesetter::Style* big = typesetter->createStyle ("EB Garamond 24", MyGUI::Colour::Black);
BookTypesetter::Style* big = typesetter->createStyle ("", MyGUI::Colour::Black);
BookTypesetter::Style* test = typesetter->createStyle ("MonoFont", MyGUI::Colour::Blue);
typesetter->sectionBreak (20);
@ -231,8 +231,8 @@ book JournalBooks::createJournalBook ()
{
BookTypesetter::Ptr typesetter = createTypesetter ();
BookTypesetter::Style* header = typesetter->createStyle ("EB Garamond", MyGUI::Colour (0.60f, 0.00f, 0.00f));
BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black);
BookTypesetter::Style* header = typesetter->createStyle ("", MyGUI::Colour (0.60f, 0.00f, 0.00f));
BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black);
mModel->visitJournalEntries (0, AddJournalEntry (typesetter, body, header, true));
@ -243,8 +243,8 @@ book JournalBooks::createTopicBook (uintptr_t topicId)
{
BookTypesetter::Ptr typesetter = createTypesetter ();
BookTypesetter::Style* header = typesetter->createStyle ("EB Garamond", MyGUI::Colour (0.60f, 0.00f, 0.00f));
BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black);
BookTypesetter::Style* header = typesetter->createStyle ("", MyGUI::Colour (0.60f, 0.00f, 0.00f));
BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black);
mModel->visitTopicName (topicId, AddTopicName (typesetter, header));
@ -259,8 +259,8 @@ book JournalBooks::createQuestBook (uintptr_t questId)
{
BookTypesetter::Ptr typesetter = createTypesetter ();
BookTypesetter::Style* header = typesetter->createStyle ("EB Garamond", MyGUI::Colour (0.60f, 0.00f, 0.00f));
BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black);
BookTypesetter::Style* header = typesetter->createStyle ("", MyGUI::Colour (0.60f, 0.00f, 0.00f));
BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black);
mModel->visitQuestName (questId, AddQuestName (typesetter, header));
@ -275,7 +275,7 @@ book JournalBooks::createTopicIndexBook ()
typesetter->setSectionAlignment (BookTypesetter::AlignCenter);
BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black);
BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black);
for (int i = 0; i < 26; ++i)
{
@ -300,7 +300,7 @@ book JournalBooks::createTopicIndexBook ()
book JournalBooks::createTopicIndexBook (char character)
{
BookTypesetter::Ptr typesetter = BookTypesetter::create (0x7FFFFFFF, 0x7FFFFFFF);
BookTypesetter::Style* style = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black);
BookTypesetter::Style* style = typesetter->createStyle ("", MyGUI::Colour::Black);
mModel->visitTopicNamesStartingWith (character, AddTopicLink (typesetter, style));
@ -310,7 +310,7 @@ book JournalBooks::createTopicIndexBook (char character)
book JournalBooks::createQuestIndexBook (bool activeOnly)
{
BookTypesetter::Ptr typesetter = BookTypesetter::create (0x7FFFFFFF, 0x7FFFFFFF);
BookTypesetter::Style* base = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black);
BookTypesetter::Style* base = typesetter->createStyle ("", MyGUI::Colour::Black);
mModel->visitQuestNames (activeOnly, AddQuestLink (typesetter, base));

@ -183,7 +183,7 @@ namespace
if (!MWBase::Environment::get().getWindowManager ()->getJournalAllowed ())
{
MWBase::Environment::get().getWindowManager()->popGuiMode ();
}
}
mModel->load ();
setBookMode ();
@ -433,7 +433,6 @@ namespace
void notifyClose(MyGUI::Widget* _sender)
{
MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0);
MWBase::Environment::get().getWindowManager ()->popGuiMode ();
}

@ -10,6 +10,7 @@
#include "../mwbase/world.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/inputmanager.hpp"
namespace MWGui
{
@ -126,7 +127,7 @@ namespace MWGui
// always update input before rendering something, otherwise mygui goes crazy when something was entered in the frame before
// (e.g. when using "coc" console command, it would enter an infinite loop and crash due to overflow)
//MWBase::Environment::get().getInputManager()->update(0, true);
MWBase::Environment::get().getInputManager()->update(0, true);
Ogre::CompositorChain* chain = Ogre::CompositorManager::getSingleton().getCompositorChain(mWindow->getViewport(0));

@ -34,6 +34,10 @@ namespace MWGui
{
}
LocalMapBase::~LocalMapBase()
{
}
void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop)
{
mLocalMap = widget;

@ -14,6 +14,7 @@ namespace MWGui
{
public:
LocalMapBase();
virtual ~LocalMapBase();
void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop=false);
void setCellPrefix(const std::string& prefix);

@ -32,6 +32,7 @@ namespace MWGui
, mFaceIndex(0)
, mHairIndex(0)
, mCurrentAngle(0)
, mPreviewDirty(true)
{
// Centre dialog
center();
@ -126,6 +127,8 @@ namespace MWGui
mHairIndex = boost::lexical_cast<int>(index) - 1;
mPreviewImage->setImageTexture ("CharacterHeadPreview");
mPreviewDirty = true;
}
@ -174,6 +177,7 @@ namespace MWGui
float angle = (float(_position) / 49.f - 0.5) * 3.14 * 2;
float diff = angle - mCurrentAngle;
mPreview->update (diff);
mPreviewDirty = true;
mCurrentAngle += diff;
}
@ -286,6 +290,16 @@ namespace MWGui
record.mHair = mAvailableHairs[mHairIndex];
mPreview->setPrototype(record);
mPreviewDirty = true;
}
void RaceDialog::doRenderUpdate()
{
if (mPreviewDirty)
{
mPreview->render();
mPreviewDirty = false;
}
}
void RaceDialog::updateRaces()

@ -52,6 +52,8 @@ namespace MWGui
*/
EventHandle_Void eventBack;
void doRenderUpdate();
protected:
void onHeadRotate(MyGUI::ScrollBar* _sender, size_t _position);
@ -98,6 +100,8 @@ namespace MWGui
float mCurrentAngle;
MWRender::RaceSelectionPreview* mPreview;
bool mPreviewDirty;
};
}
#endif

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save