1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-26 18:35:20 +00:00

Merge branch 'master' into ref

This commit is contained in:
Marc Zinnschlag 2013-07-06 17:54:19 +02:00
commit 4986b7d65d
260 changed files with 27906 additions and 2227 deletions

View File

@ -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 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 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 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 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 - sudo mkdir /usr/src/gtest/build
- cd /usr/src/gtest/build - cd /usr/src/gtest/build
- sudo cmake .. -DBUILD_SHARED_LIBS=1 - sudo cmake .. -DBUILD_SHARED_LIBS=1
@ -27,7 +26,7 @@ before_script:
- cd - - cd -
- mkdir build - mkdir build
- cd 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: script:
- make -j4 - make -j4
after_script: after_script:

View File

@ -4,6 +4,10 @@ if (APPLE)
set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app") set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app")
set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}") 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) endif (APPLE)
# Macros # Macros
@ -15,7 +19,7 @@ include (OpenMWMacros)
# Version # Version
set (OPENMW_VERSION_MAJOR 0) set (OPENMW_VERSION_MAJOR 0)
set (OPENMW_VERSION_MINOR 23) set (OPENMW_VERSION_MINOR 24)
set (OPENMW_VERSION_RELEASE 0) set (OPENMW_VERSION_RELEASE 0)
set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") 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(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(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(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 # Apps and tools
option(BUILD_BSATOOL "build BSA extractor" OFF) option(BUILD_BSATOOL "build BSA extractor" OFF)
@ -77,7 +82,13 @@ set(OENGINE_OGRE
${LIBDIR}/openengine/ogre/fader.cpp ${LIBDIR}/openengine/ogre/fader.cpp
${LIBDIR}/openengine/ogre/particles.cpp ${LIBDIR}/openengine/ogre/particles.cpp
${LIBDIR}/openengine/ogre/selectionbuffer.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 set(OENGINE_GUI
${LIBDIR}/openengine/gui/manager.cpp ${LIBDIR}/openengine/gui/manager.cpp
) )
@ -181,6 +192,12 @@ if (UNIX AND NOT APPLE)
find_package (Threads) find_package (Threads)
endif() 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) set(BOOST_COMPONENTS system filesystem program_options thread date_time wave)
@ -191,7 +208,7 @@ endif()
find_package(OGRE REQUIRED) find_package(OGRE REQUIRED)
find_package(MyGUI REQUIRED) find_package(MyGUI REQUIRED)
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
find_package(OIS REQUIRED) find_package(SDL2 REQUIRED)
find_package(OpenAL REQUIRED) find_package(OpenAL REQUIRED)
find_package(Bullet REQUIRED) find_package(Bullet REQUIRED)
IF(OGRE_STATIC) IF(OGRE_STATIC)
@ -205,7 +222,8 @@ ENDIF(OGRE_STATIC)
include_directories("." include_directories("."
${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_PLUGIN_INCLUDE_DIRS} ${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_PLUGIN_INCLUDE_DIRS}
${OGRE_Terrain_INCLUDE_DIR} ${OGRE_Terrain_INCLUDE_DIR}
${OIS_INCLUDE_DIRS} ${Boost_INCLUDE_DIR} ${SDL2_INCLUDE_DIR}
${Boost_INCLUDE_DIR}
${PLATFORM_INCLUDE_DIR} ${PLATFORM_INCLUDE_DIR}
${MYGUI_INCLUDE_DIRS} ${MYGUI_INCLUDE_DIRS}
${MYGUI_PLATFORM_INCLUDE_DIRS} ${MYGUI_PLATFORM_INCLUDE_DIRS}
@ -214,7 +232,7 @@ include_directories("."
${LIBDIR} ${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) if (APPLE)
# List used Ogre plugins # 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 configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local
"${OpenMW_BINARY_DIR}/openmw.cfg") "${OpenMW_BINARY_DIR}/openmw.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
"${OpenMW_BINARY_DIR}/openmw.cfg.install") "${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) if (NOT WIN32 AND NOT APPLE)
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop
@ -300,15 +321,15 @@ endif()
# Compiler settings # Compiler settings
if (CMAKE_COMPILER_IS_GNUCC) 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! # 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 execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
OUTPUT_VARIABLE GCC_VERSION) OUTPUT_VARIABLE GCC_VERSION)
if ("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) 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("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6)
endif (CMAKE_COMPILER_IS_GNUCC) 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}/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}/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}/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 resources
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "share/games/openmw/" FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT "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.") Data files from the original game is required to run it.")
SET(CPACK_DEBIAN_PACKAGE_NAME "openmw") SET(CPACK_DEBIAN_PACKAGE_NAME "openmw")
SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}") SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}")
SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW bsatool;Bsatool esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter") 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_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") SET(CPACK_DEBIAN_PACKAGE_SECTION "Games")
@ -437,6 +459,7 @@ endif(WIN32)
# Extern # Extern
add_subdirectory (extern/shiny) add_subdirectory (extern/shiny)
add_subdirectory (extern/oics) add_subdirectory (extern/oics)
add_subdirectory (extern/sdl4ogre)
# Components # Components
add_subdirectory (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}/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}/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}/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_GENERATOR "DragNDrop")
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION}) 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}/plugins.cfg" DESTINATION "${SYSCONFDIR}" )
INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.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}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" )
INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.cfg" DESTINATION "${SYSCONFDIR}" )
# Install resources # Install resources
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" ) INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" )

View File

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

View File

@ -108,11 +108,26 @@ bool parseOptions (int argc, char** argv, Arguments &info)
// there might be a better way to do this // there might be a better way to do this
bpo::options_description all; bpo::options_description all;
all.add(desc).add(hidden); 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::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); bpo::notify(variables);
if (variables.count ("help")) if (variables.count ("help"))

View File

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

View File

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

View File

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

View File

@ -1,11 +1,23 @@
#include <QApplication> #include <QApplication>
#include <QTextCodec> #include <QTextCodec>
#include <QDir> #include <QDir>
#include <QDebug>
#include <SDL.h>
#include "maindialog.hpp" #include "maindialog.hpp"
// SDL workaround
#include "graphicspage.hpp"
int main(int argc, char *argv[]) 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); QApplication app(argc, argv);
// Now we make sure the current dir is set to application path // 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 0;
} }
return app.exec(); int returnValue = app.exec();
SDL_Quit();
return returnValue;
} }

View File

@ -292,8 +292,8 @@ bool MainDialog::setup()
// Now create the pages as they need the settings // Now create the pages as they need the settings
createPages(); createPages();
// Call this so we can exit on Ogre errors before mainwindow is shown // Call this so we can exit on Ogre/SDL errors before mainwindow is shown
if (!mGraphicsPage->setupOgre()) if (!mGraphicsPage->loadSettings())
return false; return false;
loadSettings(); loadSettings();
@ -310,6 +310,8 @@ void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous)
bool MainDialog::setupLauncherSettings() bool MainDialog::setupLauncherSettings()
{ {
mLauncherSettings.setMultiValueEnabled(true);
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
QStringList paths; QStringList paths;
@ -427,6 +429,8 @@ bool MainDialog::setupGameSettings()
bool MainDialog::setupGraphicsSettings() bool MainDialog::setupGraphicsSettings()
{ {
mGraphicsSettings.setMultiValueEnabled(false);
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string()); QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string());
@ -608,8 +612,21 @@ void MainDialog::closeEvent(QCloseEvent *event)
void MainDialog::play() void MainDialog::play()
{ {
if (!writeSettings()) if (!writeSettings()) {
qApp->quit(); 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 // Launch the game detached
startProgram(QString("openmw"), true); startProgram(QString("openmw"), true);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -28,12 +28,26 @@ int main(int argc, char *argv[]) {
p_desc.add("ini", 1).add("cfg", 1); p_desc.add("ini", 1).add("cfg", 1);
bpo::variables_map vm; 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")) { if(vm.count("help") || !vm.count("ini") || !vm.count("cfg")) {
std::cout << desc; std::cout << desc;
@ -55,10 +69,8 @@ int main(int argc, char *argv[]) {
std::cerr << "ini file does not exist" << std::endl; std::cerr << "ini file does not exist" << std::endl;
return -3; return -3;
} }
if(!boost::filesystem::exists(cfgFile)) { if(!boost::filesystem::exists(cfgFile))
std::cerr << "cfg file does not exist" << std::endl; std::cerr << "cfg file does not exist" << std::endl;
return -4;
}
MwIniImporter importer; MwIniImporter importer;
importer.setVerbose(vm.count("verbose")); importer.setVerbose(vm.count("verbose"));

View File

@ -57,11 +57,11 @@ opencs_hdrs_noqt (view/doc
opencs_units (view/world opencs_units (view/world
table tablesubview scriptsubview table tablesubview scriptsubview util
) )
opencs_units_noqt (view/world 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 abstractwidget
usersettingsdialog usersettingsdialog
editorpage editorpage
windowpage
) )
opencs_units_noqt (view/settings opencs_units_noqt (view/settings

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -1,5 +1,7 @@
#include "settingsitem.hpp" #include "settingsitem.hpp"
#include <QStringList>
bool CSMSettings::SettingsItem::updateItem (const QStringList *values) bool CSMSettings::SettingsItem::updateItem (const QStringList *values)
{ {
QStringList::ConstIterator it = values->begin(); QStringList::ConstIterator it = values->begin();
@ -66,21 +68,21 @@ bool CSMSettings::SettingsItem::updateItem(int valueListIndex)
bool CSMSettings::SettingsItem::validate (const QString &value) 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 (!isValid && !mValueList->isEmpty())
if (mValueList->size()>0)
{ {
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) if (isValid)
break; break;
} }
} }
else if (!isValid && mValuePair)
else if (mValuePair)
{ {
int numVal = value.toInt(); int numVal = value.toInt();

View File

@ -7,12 +7,13 @@
namespace CSMSettings namespace CSMSettings
{ {
/// Represents a setting including metadata
/// (valid values, ranges, defaults, and multivalue status
class SettingsItem : public SettingContainer class SettingsItem : public SettingContainer
{ {
QStringPair *mValuePair; QStringPair *mValuePair;
QStringList *mValueList; QStringList *mValueList;
bool mIsMultiValue; bool mIsMultiValue;
QString mName;
QString mDefaultValue; QString mDefaultValue;
public: public:
@ -20,26 +21,41 @@ namespace CSMSettings
const QString& defaultValue, QObject *parent = 0) const QString& defaultValue, QObject *parent = 0)
: SettingContainer(defaultValue, parent), : SettingContainer(defaultValue, parent),
mIsMultiValue (isMultiValue), mValueList (0), 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 QStringList *values);
bool updateItem (const QString &value); bool updateItem (const QString &value);
bool updateItem (int valueListIndex); bool updateItem (int valueListIndex);
/// retroeve list of valid values for setting
inline QStringList *getValueList() { return mValueList; } inline QStringList *getValueList() { return mValueList; }
/// write list of valid values for setting
inline void setValueList (QStringList *valueList) { mValueList = valueList; } inline void setValueList (QStringList *valueList) { mValueList = valueList; }
/// valuePair used for spin boxes (max / min)
inline QStringPair *getValuePair() { return mValuePair; } inline QStringPair *getValuePair() { return mValuePair; }
/// set value range (spinbox / integer use)
inline void setValuePair (QStringPair valuePair) { mValuePair = new QStringPair(valuePair); } inline void setValuePair (QStringPair valuePair) { mValuePair = new QStringPair(valuePair); }
inline QString getName () const { return mName; }
inline bool isMultivalue () { return mIsMultiValue; } inline bool isMultivalue () { return mIsMultiValue; }
void setDefaultValue (const QString &value); void setDefaultValue (const QString &value);
QString getDefaultValue () const; QString getDefaultValue () const;
private: 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); bool validate (const QString &value);
}; };
} }

View File

@ -8,11 +8,13 @@
#include <QMessageBox> #include <QMessageBox>
#include <QTextCodec> #include <QTextCodec>
#include <QFile>
#include <QDebug>
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#include "settingcontainer.hpp" #include "settingcontainer.hpp"
#include <boost/version.hpp> #include <boost/version.hpp>
/** /**
* Workaround for problems with whitespaces in paths in older versions of Boost library * Workaround for problems with whitespaces in paths in older versions of Boost library
*/ */
@ -29,109 +31,236 @@ namespace boost
} /* namespace boost */ } /* namespace boost */
#endif /* (BOOST_VERSION <= 104600) */ #endif /* (BOOST_VERSION <= 104600) */
CSMSettings::UserSettings *CSMSettings::UserSettings::mUserSettingsInstance = 0;
CSMSettings::UserSettings::UserSettings() CSMSettings::UserSettings::UserSettings()
{ {
assert(!mUserSettingsInstance);
mUserSettingsInstance = this; 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() 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;
bool success = (file->open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) ; if (isReadOnly)
openFlags = QIODevice::ReadOnly | openFlags;
else
openFlags = QIODevice::ReadWrite | QIODevice::Truncate | openFlags;
if (!success) QFile *file = new QFile(filePath);
QTextStream *stream = 0;
if (file->open(openFlags))
{ {
// File cannot be opened or created stream = new QTextStream(file);
QMessageBox msgBox; stream->setCodec(QTextCodec::codecForName("UTF-8"));
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;
} }
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) QTextStream *stream = openFileStream(mUserFilePath);
bool success = (stream);
if (success)
{
QList<QString> keyList = settings.keys();
foreach (QString key, keyList)
{
SettingList *sectionSettings = settings[key];
*stream << "[" << key << "]" << '\n';
foreach (SettingContainer *item, *sectionSettings)
*stream << item->objectName() << " = " << item->getValue() << '\n';
}
stream->device()->close();
delete stream;
stream = 0;
}
else
{
displayFileErrorMessage(mReadWriteMessage, false);
}
return (success);
}
const CSMSettings::SectionMap &CSMSettings::UserSettings::getSettings() const
{
return mSectionSettings;
}
bool CSMSettings::UserSettings::loadFromFile(const QString &filePath)
{
if (filePath.isEmpty())
return false; return false;
QTextStream stream(file); mSectionSettings.clear();
stream.setCodec(QTextCodec::codecForName("UTF-8"));
QList<QString> keyList = settings.keys(); QTextStream *stream = openFileStream (filePath, true);
foreach (QString key, keyList) bool success = (stream);
if (success)
{ {
SettingList *sectionSettings = settings[key]; //looks for a square bracket, "'\\["
//that has one or more "not nothing" in it, "([^]]+)"
//and is closed with a square bracket, "\\]"
stream << "[" << key << "]" << '\n'; QRegExp sectionRe("^\\[([^]]+)\\]");
foreach (SettingContainer *item, *sectionSettings) //Find any character(s) that is/are not equal sign(s), "[^=]+"
stream << item->getName() << " = " << item->getValue() << '\n'; //followed by an optional whitespace, an equal sign, and another optional whitespace, "\\s*=\\s*"
//and one or more periods, "(.+)"
QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$");
CSMSettings::SettingMap *settings = 0;
QString section = "none";
while (!stream->atEnd())
{
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;
}
}
mSectionSettings.insert(section, settings);
stream->device()->close();
delete stream;
stream = 0;
} }
file->close(); return success;
return true;
} }
void CSMSettings::UserSettings::getSettings(QTextStream &stream, SectionMap &sections) void CSMSettings::UserSettings::loadSettings (const QString &fileName)
{ {
//looks for a square bracket, "'\\[" //global
//that has one or more "not nothing" in it, "([^]]+)" QString globalFilePath = QString::fromStdString(mCfgMgr.getGlobalPath().string()) + fileName;
//and is closed with a square bracket, "\\]" bool globalOk = loadFromFile(globalFilePath);
QRegExp sectionRe("^\\[([^]]+)\\]");
//Find any character(s) that is/are not equal sign(s), "[^=]+" //local
//followed by an optional whitespace, an equal sign, and another optional whirespace, "\\s*=\\s*" QString localFilePath = QString::fromStdString(mCfgMgr.getLocalPath().string()) + fileName;
//and one or more periods, "(.+)" bool localOk = loadFromFile(localFilePath);
QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$"); //user
mUserFilePath = QString::fromStdString(mCfgMgr.getUserPath().string()) + fileName;
loadFromFile(mUserFilePath);
CSMSettings::SettingMap *settings = 0; if (!(localOk || globalOk))
QString section = "none";
while (!stream.atEnd())
{ {
QString line = stream.readLine().simplified(); 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>");
if (line.isEmpty() || line.startsWith("#")) message += QObject::tr("<br>Global filepath: ") + globalFilePath;
continue; message += QObject::tr("<br>Local filepath: ") + localFilePath;
//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)
sections.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());
(*settings)[keyRe.cap(1).simplified()] = sc;
}
displayFileErrorMessage ( message, true);
} }
sections.insert(section, settings); }
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())
{
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();
}
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();
} }

View File

@ -10,6 +10,10 @@
#include "support.hpp" #include "support.hpp"
#ifndef Q_MOC_RUN
#include <components/files/configurationmanager.hpp>
#endif
namespace Files { typedef std::vector<boost::filesystem::path> PathContainer; namespace Files { typedef std::vector<boost::filesystem::path> PathContainer;
struct ConfigurationManager;} struct ConfigurationManager;}
@ -22,29 +26,56 @@ namespace CSMSettings {
Q_OBJECT Q_OBJECT
SectionMap mSectionSettings;
static UserSettings *mUserSettingsInstance;
QString mUserFilePath;
Files::ConfigurationManager mCfgMgr;
QString mReadOnlyMessage;
QString mReadWriteMessage;
public: public:
static UserSettings &instance() /// Singleton implementation
{ static UserSettings& instance();
static UserSettings instance;
return instance;
}
QFile *openFile (const QString &);
bool writeFile(QFile *file, QMap<QString, SettingList *> &sections);
void getSettings (QTextStream &stream, SectionMap &settings);
private:
UserSettings *mUserSettingsInstance;
UserSettings(); UserSettings();
~UserSettings(); ~UserSettings();
UserSettings (UserSettings const &); //not implemented UserSettings (UserSettings const &); //not implemented
void operator= (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: signals:
void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue); void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue);
}; };

View File

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

View File

@ -53,7 +53,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct RecordStateColumn : public Column<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 virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -1148,4 +1148,4 @@ namespace CSMWorld
}; };
} }
#endif #endif

View File

@ -41,7 +41,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
mColumns.push_back (RefIdColumn ("ID", ColumnBase::Display_String, mColumns.push_back (RefIdColumn ("ID", ColumnBase::Display_String,
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false)); ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false));
baseColumns.mId = &mColumns.back(); 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)); ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false));
baseColumns.mModified = &mColumns.back(); baseColumns.mModified = &mColumns.back();
mColumns.push_back (RefIdColumn ("Type", ColumnBase::Display_Integer, 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 int CSMWorld::RefIdCollection::getAppendIndex (UniversalId::Type type) const
{ {
return mData.getAppendIndex (type); return mData.getAppendIndex (type);
} }

View File

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

View File

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

View File

@ -182,7 +182,13 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to
: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1),
mViewTotal (totalViews) 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); 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) /// \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); SubView *view = mSubViewFactory.makeSubView (id, *mDocument);
view->setObjectName ("subview");
mSubViewWindow.addDockWidget (Qt::TopDockWidgetArea, view); mSubViewWindow.addDockWidget (Qt::TopDockWidgetArea, view);
connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&)), this, connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&)), this,
SLOT (addSubView (const CSMWorld::UniversalId&))); SLOT (addSubView (const CSMWorld::UniversalId&)));
CSMSettings::UserSettings::instance().updateSettings("Editor", "Record Status Display");
view->show(); view->show();
} }
@ -374,20 +383,34 @@ void CSVDoc::View::showUserSettings()
{ {
CSVSettings::UserSettingsDialog *settingsDialog = new CSVSettings::UserSettingsDialog(this); 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(); 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)
{
lastValue = settingValue; if (height >= 0)
} resize (geometry().width(), height);
}
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());
} }

View File

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

View File

@ -12,13 +12,14 @@
#include "../world/util.hpp" #include "../world/util.hpp"
#include "../world/enumdelegate.hpp" #include "../world/enumdelegate.hpp"
#include "../world/vartypedelegate.hpp" #include "../world/vartypedelegate.hpp"
#include "../world/recordstatusdelegate.hpp"
#include "../settings/usersettingsdialog.hpp"
#include "view.hpp" #include "view.hpp"
#include <QMessageBox> #include <QMessageBox>
#include <QPushButton> #include <QPushButton>
#include <QtGui/QApplication> #include <QtGui/QApplication>
#include <QDebug>
void CSVDoc::ViewManager::updateIndices() void CSVDoc::ViewManager::updateIndices()
{ {
@ -117,6 +118,12 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
mDelegateFactories->add (CSMWorld::ColumnBase::Display_WeaponType, mDelegateFactories->add (CSMWorld::ColumnBase::Display_WeaponType,
new CSVWorld::EnumDelegateFactory (sWeaponTypes)); 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() CSVDoc::ViewManager::~ViewManager()
@ -343,3 +350,13 @@ void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view)
if (notifySaveOnClose (view)) if (notifySaveOnClose (view))
QApplication::instance()->exit(); 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);
}
}

View File

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

View File

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

View File

@ -11,6 +11,7 @@
namespace CSVSettings namespace CSVSettings
{ {
/// Abstract base class for all blocks
class AbstractBlock : public QObject class AbstractBlock : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -31,40 +32,50 @@ namespace CSVSettings
bool isVisible() const; bool isVisible() const;
virtual CSMSettings::SettingList *getSettings() = 0; 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; 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) virtual bool updateBySignal (const QString &name, const QString &value, bool &doEmit)
{ return false; } { return false; }
protected: protected:
/// Creates the layout which for the blocks QGroupBox
QLayout *createLayout (Orientation direction, bool isZeroMargin, QWidget* parent = 0); 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, AbstractWidget *buildWidget (const QString &widgetName, WidgetDef &wDef,
QLayout *layout = 0, bool isConnected = true) const; 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; QWidget *getParent() const;
public slots: public slots:
/// enables / disables block-level widgets based on signals from other widgets
/// used in ToggleBlock
void slotSetEnabled (bool value); void slotSetEnabled (bool value);
/// receives updates to applicaion-level settings in the Editor
void slotUpdateSetting (const QString &settingName, const QString &settingValue); void slotUpdateSetting (const QString &settingName, const QString &settingValue);
private slots: private slots:
/// receives updates to a setting in the block pushed from the application level
void slotUpdate (const QString &value); void slotUpdate (const QString &value);
signals: signals:
//signal to functions outside the settings tab widget /// signal to UserSettings instance
void signalUpdateSetting (const QString &propertyName, const QString &propertyValue); void signalUpdateSetting (const QString &propertyName, const QString &propertyValue);
/// signal to widget for updating widget value
void signalUpdateWidget (const QString & 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); void signalUpdateProxySetting (const QString &propertyName, const QString &propertyValue);
}; };
} }

View File

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

View File

@ -14,6 +14,11 @@ namespace CSVSettings {
typedef QList<AbstractBlock *> AbstractBlockList; 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 class AbstractPage: public QWidget
{ {
@ -28,18 +33,24 @@ namespace CSVSettings {
~AbstractPage(); ~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; virtual void initializeWidgets (const CSMSettings::SettingMap &settings) = 0;
/// retrieve the list of settings local to the page.
CSMSettings::SettingList *getSettings(); CSMSettings::SettingList *getSettings();
void setObjectName(); void setObjectName();
protected: 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> template <typename S, typename T>
AbstractBlock *buildBlock (T &def) AbstractBlock *buildBlock (T *def)
{ {
S *block = new S (this); S *block = new S (this);
int ret = block->build (def); int ret = block->build (def);
@ -47,12 +58,12 @@ namespace CSVSettings {
if (ret < 0) if (ret < 0)
return 0; return 0;
QWidget::layout()->addWidget (block->getGroupBox()); QGroupBox *box = block->getGroupBox();
QWidget::layout()->addWidget (box);
return block; return block;
} }
}; };
} }

View File

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

View File

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

View File

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

View File

@ -23,7 +23,7 @@ int CSVSettings::CustomBlock::build(GroupBlockDefList &defList, GroupBlockDefLis
for (; listIt != defList.end(); ++listIt) for (; listIt != defList.end(); ++listIt)
{ {
if (!(*listIt)->isProxy) if (!(*listIt)->isProxy)
retVal = buildGroupBlock (*(*listIt)); retVal = buildGroupBlock (*listIt);
else else
{ {
mGroupList << proxyBlock; mGroupList << proxyBlock;
@ -32,7 +32,7 @@ int CSVSettings::CustomBlock::build(GroupBlockDefList &defList, GroupBlockDefLis
} }
if (proxyIt != defaultIt) if (proxyIt != defaultIt)
retVal = buildProxyBlock (*(*proxyIt), proxyBlock); retVal = buildProxyBlock (*proxyIt, proxyBlock);
return retVal; return retVal;
} }
@ -40,12 +40,12 @@ int CSVSettings::CustomBlock::build(GroupBlockDefList &defList, GroupBlockDefLis
CSVSettings::GroupBox *CSVSettings::CustomBlock::buildGroupBox (Orientation orientation) CSVSettings::GroupBox *CSVSettings::CustomBlock::buildGroupBox (Orientation orientation)
{ {
GroupBox *box = new GroupBox (false, mBox); GroupBox *box = new GroupBox (false, mBox);
QLayout *layout = createLayout (orientation, true, box); createLayout (orientation, true, box);
return box; return box;
} }
int CSVSettings::CustomBlock::buildGroupBlock(GroupBlockDef &def) int CSVSettings::CustomBlock::buildGroupBlock(GroupBlockDef *def)
{ {
GroupBlock *block = new GroupBlock (getParent()); GroupBlock *block = new GroupBlock (getParent());
@ -57,9 +57,9 @@ int CSVSettings::CustomBlock::buildGroupBlock(GroupBlockDef &def)
return block->build(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; return -1;
int retVal = block->build(def); int retVal = block->build(def);
@ -67,7 +67,8 @@ int CSVSettings::CustomBlock::buildProxyBlock(GroupBlockDef& def, ProxyBlock *bl
if (retVal != 0) if (retVal != 0)
return retVal; 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); QString proxiedBlockName = list->at(0);

View File

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

View File

@ -1,156 +1,46 @@
#include "editorpage.hpp" #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 "groupblock.hpp"
#include "toggleblock.hpp" #include "../../model/settings/usersettings.hpp"
CSVSettings::EditorPage::EditorPage(QWidget *parent): CSVSettings::EditorPage::EditorPage(QWidget* parent) :
AbstractPage("Editor", 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(); setupUi();
} }
CSVSettings::GroupBlockDef *CSVSettings::EditorPage::setupRecordStatusDisplay()
{
GroupBlockDef *statusBlock = new GroupBlockDef(QString("Record Status Display"));
SettingsItemDef *statusItem = new SettingsItemDef (statusBlock->title, "Icon and Text");
*(statusItem->valueList) << QString("Icon and Text") << QString("Icon Only") << QString("Text Only");
WidgetDef statusWidget (Widget_RadioButton);
statusWidget.valueList = statusItem->valueList;
statusItem->widget = statusWidget;
statusBlock->settingItems << statusItem;
return statusBlock;
}
void CSVSettings::EditorPage::setupUi() void CSVSettings::EditorPage::setupUi()
{ {
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"));
//////////////////////////// mAbstractBlocks << buildBlock<GroupBlock>(setupRecordStatusDisplay());
//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;
reuseSubwindow.properties << reuseSubItem;
reuseSubItem->widget = reuseSubWidget;
///////////////////////////////
//custom window size properties
///////////////////////////////
//custom width
SettingsItemDef *widthItem = new SettingsItemDef ("Window Width", "640");
widthItem->widget = WidgetDef (Widget_LineEdit);
widthItem->widget.widgetWidth = 45;
//custom height
SettingsItemDef *heightItem = new SettingsItemDef ("Window Height", "480");
heightItem->widget = WidgetDef (Widget_LineEdit);
heightItem->widget.widgetWidth = 45;
heightItem->widget.caption = "x";
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);
setLayout (pageLayout);
mAbstractBlocks << buildBlock<GroupBlock> (topLevelWindowCount)
<< buildBlock<GroupBlock> (reuseSubwindow)
<< buildBlock<ToggleBlock> (windowSize)
<< buildBlock<GroupBlock> (undoStack);
foreach (AbstractBlock *block, mAbstractBlocks) foreach (AbstractBlock *block, mAbstractBlocks)
{ {
connect (block, SIGNAL (signalUpdateSetting (const QString &, const QString &)), connect (block, SIGNAL (signalUpdateSetting (const QString &, const QString &)),
this, SIGNAL (signalUpdateEditorSetting (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) void CSVSettings::EditorPage::initializeWidgets (const CSMSettings::SettingMap &settings)

View File

@ -1,28 +1,33 @@
#ifndef EDITORPAGE_H #ifndef EDITORPAGE_HPP
#define EDITORPAGE_H #define EDITORPAGE_HPP
#include "support.hpp"
#include "abstractpage.hpp" #include "abstractpage.hpp"
class QGroupBox; namespace CSVSettings
{
namespace CSVSettings {
class UserSettings;
class AbstractBlock;
class EditorPage : public AbstractPage class EditorPage : public AbstractPage
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit EditorPage(QWidget *parent = 0);
EditorPage(QWidget *parent = 0);
void setupUi();
void initializeWidgets (const CSMSettings::SettingMap &settings); 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:
/// Signals up for changes to editor application-level settings
void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue); void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue);
public slots:
}; };
} }
#endif //EDITORPAGE_H
#endif // EDITORPAGE_HPP

View File

@ -9,22 +9,22 @@ CSVSettings::GroupBlock::GroupBlock (bool isVisible, QWidget *parent)
: AbstractBlock (isVisible, 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; return -1;
int retVal = 0; int retVal = 0;
setVisible (def.isVisible); setVisible (def->isVisible);
mBox->setLayout(createLayout (def.widgetOrientation, true)); mBox->setLayout(createLayout (def->widgetOrientation, true));
setObjectName (def.title); setObjectName (def->title);
mBox->setTitle (def.title); mBox->setTitle (def->title);
foreach (SettingsItemDef *itemDef, def.properties) foreach (SettingsItemDef *itemDef, def->settingItems)
{ {
ItemBlock *block = new ItemBlock (mBox); ItemBlock *block = new ItemBlock (mBox);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,7 +16,8 @@
namespace CSVSettings namespace CSVSettings
{ {
//VALID FOR RADIOBUTTON / CHECKBOX (or other toggle widget with it's own label)
/// Generic template for radiobuttons / checkboxes
template <typename T1> template <typename T1>
class SettingWidget : public AbstractWidget class SettingWidget : public AbstractWidget
{ {
@ -47,6 +48,7 @@ namespace CSVSettings
} }
}; };
/// spin box template
template <> template <>
class SettingWidget <QSpinBox>: public AbstractWidget class SettingWidget <QSpinBox>: public AbstractWidget
{ {
@ -90,6 +92,7 @@ namespace CSVSettings
}; };
/// combo box template
template <> template <>
class SettingWidget <QComboBox>: public CSVSettings::AbstractWidget class SettingWidget <QComboBox>: public CSVSettings::AbstractWidget
{ {
@ -142,6 +145,7 @@ namespace CSVSettings
}; };
/// line edit template
template <> template <>
class SettingWidget <QLineEdit>: public CSVSettings::AbstractWidget 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 <> template <>
class SettingWidget <QListWidget>: public CSVSettings::AbstractWidget class SettingWidget <QListWidget>: public CSVSettings::AbstractWidget
{ {

View File

@ -44,21 +44,44 @@ namespace CSVSettings
Align_Right = Qt::AlignRight Align_Right = Qt::AlignRight
}; };
//template for defining the widget of a property. /// definition struct for widgets
struct WidgetDef struct WidgetDef
{ {
WidgetType type; //type of widget providing input /// type of widget providing input
int labelWidth; //width of caption label WidgetType type;
int widgetWidth; //width of input widget
Orientation orientation; //label / widget orientation (horizontal / vertical) /// width of caption label
QString inputMask; //input mask (line edit) int labelWidth;
QString caption; //label caption. Leave empty for multiple items. See BlockDef::captionList
QString value; //widget value. Leave empty for multiple items. See BlockDef::valueList /// width of input widget
CSMSettings::QStringPair *minMax; //Min/Max QString value pair. If empty, assigned to property item value pair. int widgetWidth;
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. /// label / widget orientation (horizontal / vertical)
Alignment valueAlignment; //left / center / right-justify text in widget Orientation orientation;
Alignment widgetAlignment; //left / center / right-justify widget in group box
/// 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), 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 /// 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. /// 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. /// Only one widget may serve as the input widget for the setting.
struct SettingsItemDef struct SettingsItemDef
{ {
QString name; //property name /// setting name
QStringList *valueList; //list of valid values for the property. QString name;
//Used to populate option widget captions or list widget item lists (see WidgetDef::caption / value)
/// 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; QString defaultValue;
/// flag indicating multi-valued setting
bool hasMultipleValues; bool hasMultipleValues;
CSMSettings::QStringPair minMax; //minimum / maximum value pair
WidgetDef widget; //definition of the input widget for this setting /// minimum / maximum value pair
Orientation orientation; //general orientation of the widget / label for this property CSMSettings::QStringPair minMax;
ProxyList *proxyList; //list of property and corresponding default values for proxy widget
/// 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) 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. /// Generic container block
//Does not correlate to config file structure.
struct GroupBlockDef struct GroupBlockDef
{ {
QString title; //title of the block containing the property or properties of this sub-section /// block title
QStringList captions; //list of captions for widgets at the block level (not associated with any particular property) QString title;
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. /// list of captions for widgets at the block level (not associated with any particular setting)
Orientation widgetOrientation; //general orientation of widgets in group block QStringList captions;
bool isVisible; //determines whether or not box border/title are visible
bool isProxy; //indicates whether or not this block defines a proxy block /// list of widgets at the block level (not associated with any particular setting)
QString defaultValue; //generic default value attribute 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 ("") GroupBlockDef (): title(""), widgetOrientation (Orient_Vertical), isVisible (true), isProxy (false), defaultValue ("")
{} {}
@ -125,11 +176,19 @@ namespace CSVSettings
{} {}
}; };
/// used to create unique, complex blocks
struct CustomBlockDef struct CustomBlockDef
{ {
/// block title
QString 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; Orientation blockOrientation;
CustomBlockDef (): title (""), defaultValue (""), blockOrientation (Orient_Horizontal) CustomBlockDef (): title (""), defaultValue (""), blockOrientation (Orient_Horizontal)

View File

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

View File

@ -18,10 +18,12 @@ namespace CSVSettings
public: public:
explicit ToggleBlock(QWidget *parent = 0); explicit ToggleBlock(QWidget *parent = 0);
int build (CustomBlockDef &def); int build (CustomBlockDef *def);
private: 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 #endif // TOGGLEBLOCK_HPP

View File

@ -10,25 +10,26 @@
#include <QPushButton> #include <QPushButton>
#include <QDockWidget> #include <QDockWidget>
#include "blankpage.hpp" #include <QGridLayout>
#include "editorpage.hpp"
#include "../../model/settings/support.hpp"
#include "editorpage.hpp"
#include "windowpage.hpp"
#include "../../model/settings/support.hpp"
#include <boost/filesystem/path.hpp>
#include "settingwidget.hpp" #include "settingwidget.hpp"
#include <QDebug>
CSVSettings::UserSettingsDialog::UserSettingsDialog(QMainWindow *parent) : CSVSettings::UserSettingsDialog::UserSettingsDialog(QMainWindow *parent) :
QMainWindow (parent), mStackedWidget (0) QMainWindow (parent), mStackedWidget (0)
{ {
setWindowTitle(QString::fromUtf8 ("User Settings")); setWindowTitle(QString::fromUtf8 ("User Settings"));
buildPages(); buildPages();
setWidgetStates (loadSettings()); setWidgetStates ();
positionWindow ();
connect (mListWidget, connect (mListWidget,
SIGNAL (currentItemChanged(QListWidgetItem*, QListWidgetItem*)), SIGNAL (currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
this, this,
SLOT (slotChangePage (QListWidgetItem*, QListWidgetItem*))); SLOT (slotChangePage (QListWidgetItem*, QListWidgetItem*)));
} }
CSVSettings::UserSettingsDialog::~UserSettingsDialog() CSVSettings::UserSettingsDialog::~UserSettingsDialog()
@ -40,17 +41,21 @@ void CSVSettings::UserSettingsDialog::closeEvent (QCloseEvent *event)
writeSettings(); 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) //iterate the tabWidget's pages (sections)
for (int i = 0; i < mStackedWidget->count(); i++) for (int i = 0; i < mStackedWidget->count(); i++)
{ {
//get the settings defined for the entire section //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 (sectionSettings.find(pageName) != sectionSettings.end())
if (settings)
{ {
CSMSettings::SettingMap *settings = sectionSettings.value(pageName);
AbstractPage *page = getAbstractPage (i); AbstractPage *page = getAbstractPage (i);
page->initializeWidgets(*settings); page->initializeWidgets(*settings);
} }
@ -65,83 +70,24 @@ void CSVSettings::UserSettingsDialog::buildPages()
mListWidget = new QListWidget (centralWidget); mListWidget = new QListWidget (centralWidget);
mStackedWidget = new QStackedWidget (centralWidget); mStackedWidget = new QStackedWidget (centralWidget);
QLayout* dialogLayout = new QHBoxLayout(); QGridLayout* dialogLayout = new QGridLayout();
dialogLayout->addWidget (mListWidget); mListWidget->setMinimumWidth(0);
dialogLayout->addWidget (mStackedWidget); 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); centralWidget->setLayout (dialogLayout);
setCentralWidget (centralWidget); setCentralWidget (centralWidget);
setDockOptions (QMainWindow::AllowNestedDocks); setDockOptions (QMainWindow::AllowNestedDocks);
//uncomment to test with sample editor page.
//createSamplePage();
createPage<BlankPage>("Page1");
createPage<BlankPage>("Page2");
createPage<BlankPage>("Page3");
}
void CSVSettings::UserSettingsDialog::createSamplePage() createPage<WindowPage>();
{ createPage<EditorPage>();
//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));
}
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() void CSVSettings::UserSettingsDialog::writeSettings()
@ -153,9 +99,7 @@ void CSVSettings::UserSettingsDialog::writeSettings()
AbstractPage *page = getAbstractPage (i); AbstractPage *page = getAbstractPage (i);
settings [page->objectName()] = page->getSettings(); settings [page->objectName()] = page->getSettings();
} }
CSMSettings::UserSettings::instance().writeSettings(settings);
CSMSettings::UserSettings::instance().writeFile(CSMSettings::UserSettings::instance().openFile(mPaths.back()), settings);
} }
CSVSettings::AbstractPage *CSVSettings::UserSettingsDialog::getAbstractPage (int index) CSVSettings::AbstractPage *CSVSettings::UserSettingsDialog::getAbstractPage (int index)

View File

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

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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

View File

@ -12,6 +12,7 @@
#include "../../model/world/idtableproxymodel.hpp" #include "../../model/world/idtableproxymodel.hpp"
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
#include "../../model/world/record.hpp" #include "../../model/world/record.hpp"
#include "recordstatusdelegate.hpp"
#include "util.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, CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack,
bool createAndDelete) bool createAndDelete)
: mUndoStack (undoStack), mCreateAction (0), mEditLock (false) : mUndoStack (undoStack), mCreateAction (0), mEditLock (false), mRecordStatusDisplay (0)
{ {
mModel = &dynamic_cast<CSMWorld::IdTable&> (*data.getTableModel (id)); mModel = &dynamic_cast<CSMWorld::IdTable&> (*data.getTableModel (id));
@ -161,6 +162,7 @@ void CSVWorld::Table::createRecord()
mUndoStack.push (new CSMWorld::CreateCommand (*mProxyModel, stream.str())); mUndoStack.push (new CSMWorld::CreateCommand (*mProxyModel, stream.str()));
} }
} }
void CSVWorld::Table::revertRecord() void CSVWorld::Table::revertRecord()
@ -201,4 +203,13 @@ void CSVWorld::Table::deleteRecord()
mUndoStack.endMacro(); 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));
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,5 @@
#include "engine.hpp" #include "engine.hpp"
#include "components/esm/loadcell.hpp" #include "components/esm/loadcell.hpp"
#include <OgreRoot.h> #include <OgreRoot.h>
@ -37,6 +38,8 @@
#include "mwmechanics/mechanicsmanagerimp.hpp" #include "mwmechanics/mechanicsmanagerimp.hpp"
#include <SDL.h>
void OMW::Engine::executeLocalScripts() void OMW::Engine::executeLocalScripts()
{ {
MWWorld::LocalScripts& localScripts = MWBase::Environment::get().getWorld()->getLocalScripts(); MWWorld::LocalScripts& localScripts = MWBase::Environment::get().getWorld()->getLocalScripts();
@ -75,7 +78,8 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
try try
{ {
float frametime = std::min(evt.timeSinceLastFrame, 0.2f); float frametime = std::min(evt.timeSinceLastFrame, 0.2f);
mEnvironment.setFrameDuration(frametime);
mEnvironment.setFrameDuration (frametime);
// update input // update input
MWBase::Environment::get().getInputManager()->update(frametime, false); 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) OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
: mOgre (0) : mOgre (0)
, mFpsLevel(0) , mFpsLevel(0)
, mDebug (false)
, mVerboseScripts (false) , mVerboseScripts (false)
, mNewGame (false) , mNewGame (false)
, mUseSound (true) , mUseSound (true)
@ -141,6 +144,18 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
{ {
std::srand ( std::time(NULL) ); std::srand ( std::time(NULL) );
MWClass::registerClasses(); 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() OMW::Engine::~Engine()
@ -148,6 +163,7 @@ OMW::Engine::~Engine()
mEnvironment.cleanup(); mEnvironment.cleanup();
delete mScriptContext; delete mScriptContext;
delete mOgre; delete mOgre;
SDL_Quit();
} }
// Load BSA files // 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) void OMW::Engine::setScriptsVerbosity(bool scriptsVerbosity)
{ {
mVerboseScripts = 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")) else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg"))
nifOverrides.loadTransparencyOverrides(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg"); nifOverrides.loadTransparencyOverrides(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg");
settings.setBool("hardware cursors", "GUI", true);
return settingspath; return settingspath;
} }
@ -352,14 +365,16 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
addResourcesDirectory(mResDir / "shadows"); addResourcesDirectory(mResDir / "shadows");
addZipResource(mResDir / "mygui" / "Obliviontt.zip"); addZipResource(mResDir / "mygui" / "Obliviontt.zip");
// Create the window
OEngine::Render::WindowSettings windowSettings; OEngine::Render::WindowSettings windowSettings;
windowSettings.fullscreen = settings.getBool("fullscreen", "Video"); windowSettings.fullscreen = settings.getBool("fullscreen", "Video");
windowSettings.window_x = settings.getInt("resolution x", "Video"); windowSettings.window_x = settings.getInt("resolution x", "Video");
windowSettings.window_y = settings.getInt("resolution y", "Video"); windowSettings.window_y = settings.getInt("resolution y", "Video");
windowSettings.screen = settings.getInt("screen", "Video");
windowSettings.vsync = settings.getBool("vsync", "Video"); windowSettings.vsync = settings.getBool("vsync", "Video");
windowSettings.icon = "openmw.png";
std::string aa = settings.getString("antialiasing", "Video"); std::string aa = settings.getString("antialiasing", "Video");
windowSettings.fsaa = (aa.substr(0, 4) == "MSAA") ? aa.substr(5, aa.size()-5) : "0"; windowSettings.fsaa = (aa.substr(0, 4) == "MSAA") ? aa.substr(5, aa.size()-5) : "0";
mOgre->createWindow("OpenMW", windowSettings); mOgre->createWindow("OpenMW", windowSettings);
loadBSA(); loadBSA();
@ -380,7 +395,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
mEnvironment.setWindowManager (new MWGui::WindowManager( mEnvironment.setWindowManager (new MWGui::WindowManager(
mExtensions, mFpsLevel, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), mExtensions, mFpsLevel, mOgre, mCfgMgr.getLogPath().string() + std::string("/"),
mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage)); mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding));
if (mNewGame) if (mNewGame)
mEnvironment.getWindowManager()->setNewGame(true); mEnvironment.getWindowManager()->setNewGame(true);
@ -409,7 +424,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
mEnvironment.setInputManager (new MWInput::InputManager (*mOgre, mEnvironment.setInputManager (new MWInput::InputManager (*mOgre,
MWBase::Environment::get().getWorld()->getPlayer(), MWBase::Environment::get().getWorld()->getPlayer(),
*MWBase::Environment::get().getWindowManager(), mDebug, *this, keybinderUser, keybinderUserExists)); *MWBase::Environment::get().getWindowManager(), *this, keybinderUser, keybinderUserExists));
mEnvironment.getWorld()->renderPlayer(); mEnvironment.getWorld()->renderPlayer();

View File

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

View File

@ -2,6 +2,7 @@
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#include <SDL_main.h>
#include "engine.hpp" #include "engine.hpp"
#if defined(_WIN32) && !defined(_CONSOLE) #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) ("anim-verbose", bpo::value<bool>()->implicit_value(true)
->default_value(false), "output animation indices files") ->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) ("nosound", bpo::value<bool>()->implicit_value(true)
->default_value(false), "disable all sounds") ->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>(); StringsVector master = variables["master"].as<StringsVector>();
if (master.empty()) if (master.empty())
{ {
std::cout << "No master file given. Assuming Morrowind.esm" << std::endl; std::cout << "No master file given. Aborting...\n";
master.push_back("Morrowind"); return false;
} }
StringsVector plugin = variables["plugin"].as<StringsVector>(); 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>()); engine.setNewGame(variables["new-game"].as<bool>());
// other settings // other settings
engine.setDebugMode(variables["debug"].as<bool>());
engine.setSoundUsage(!variables["nosound"].as<bool>()); engine.setSoundUsage(!variables["nosound"].as<bool>());
engine.setScriptsVerbosity(variables["script-verbose"].as<bool>()); engine.setScriptsVerbosity(variables["script-verbose"].as<bool>());
engine.setCompileAll(variables["script-all"].as<bool>()); engine.setCompileAll(variables["script-all"].as<bool>());

View File

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

View File

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

View File

@ -342,6 +342,10 @@ namespace MWBase
virtual void getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out) = 0; virtual void getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out) = 0;
///< get all containers in active cells owned by this Npc ///< 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; virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0;

View File

@ -5,6 +5,7 @@
#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/magiceffects.hpp" #include "../mwmechanics/magiceffects.hpp"
#include "../mwmechanics/movement.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
@ -29,6 +30,7 @@ namespace
{ {
MWMechanics::CreatureStats mCreatureStats; MWMechanics::CreatureStats mCreatureStats;
MWWorld::ContainerStore mContainerStore; MWWorld::ContainerStore mContainerStore;
MWMechanics::Movement mMovement;
virtual MWWorld::CustomData *clone() const; virtual MWWorld::CustomData *clone() const;
}; };
@ -47,6 +49,18 @@ namespace MWClass
{ {
std::auto_ptr<CustomData> data (new CustomData); 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>(); MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
// creature stats // creature stats
@ -181,6 +195,42 @@ namespace MWClass
return true; 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 MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::Ptr& ptr) const
{ {
MWWorld::LiveCellRef<ESM::Creature> *ref = MWWorld::LiveCellRef<ESM::Creature> *ref =
@ -249,4 +299,7 @@ namespace MWClass
return MWWorld::Ptr(&cell.mCreatures.insert(*ref), &cell); return MWWorld::Ptr(&cell.mCreatures.insert(*ref), &cell);
} }
const ESM::GameSetting* Creature::fMinWalkSpeedCreature;
const ESM::GameSetting* Creature::fMaxWalkSpeedCreature;
} }

View File

@ -12,6 +12,9 @@ namespace MWClass
virtual MWWorld::Ptr virtual MWWorld::Ptr
copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const;
static const ESM::GameSetting *fMinWalkSpeedCreature;
static const ESM::GameSetting *fMaxWalkSpeedCreature;
public: public:
virtual std::string getId (const MWWorld::Ptr& ptr) const; virtual std::string getId (const MWWorld::Ptr& ptr) const;
@ -66,6 +69,18 @@ namespace MWClass
virtual bool isPersistent (const MWWorld::Ptr& ptr) const; 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(); static void registerSelf();
virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual std::string getModel(const MWWorld::Ptr &ptr) const;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -407,7 +407,7 @@ namespace MWGui
getWidget(mEditName, "EditName"); getWidget(mEditName, "EditName");
// Make sure the edit box has focus // Make sure the edit box has focus
MyGUI::InputManager::getInstance().setKeyFocusWidget(mEditName); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mEditName);
MyGUI::Button* descriptionButton; MyGUI::Button* descriptionButton;
getWidget(descriptionButton, "DescriptionButton"); getWidget(descriptionButton, "DescriptionButton");
@ -866,7 +866,7 @@ namespace MWGui
okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sInputMenu1", "")); okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sInputMenu1", ""));
// Make sure the edit box has focus // Make sure the edit box has focus
MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit);
} }
DescriptionDialog::~DescriptionDialog() DescriptionDialog::~DescriptionDialog()

View File

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

View File

@ -3,11 +3,39 @@
#include "../mwworld/containerstore.hpp" #include "../mwworld/containerstore.hpp"
#include "../mwworld/class.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 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) : mItemSources(itemSources)
, mWorldItems(worldItems)
{ {
assert (mItemSources.size()); 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) 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 (stacks(*it, item.mBase))
if (*it == item.mBase || (store.stacks(*it, item.mBase) && item.mBase.getContainerStore()->stacks(*it, item.mBase)))
{ {
int refCount = it->getRefData().getCount(); int refCount = it->getRefData().getCount();
it->getRefData().setCount(std::max(0, refCount - toRemove)); 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"); 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(); std::vector<ItemStack>::iterator itemStack = mItems.begin();
for (; itemStack != mItems.end(); ++itemStack) 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 (stacks(*it, itemStack->mBase))
if (store.stacks(itemStack->mBase, *it) && it->getContainerStore()->stacks(itemStack->mBase, *it))
{ {
// we already have an item stack of this kind, add to it // we already have an item stack of this kind, add to it
itemStack->mCount += it->getRefData().getCount(); 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);
}
}
} }
} }

View File

@ -11,7 +11,7 @@ namespace MWGui
class ContainerItemModel : public ItemModel class ContainerItemModel : public ItemModel
{ {
public: 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, ///< @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. /// while the last element will be used to add new items to.
@ -28,6 +28,7 @@ namespace MWGui
private: private:
std::vector<MWWorld::Ptr> mItemSources; std::vector<MWWorld::Ptr> mItemSources;
std::vector<MWWorld::Ptr> mWorldItems;
std::vector<ItemStack> mItems; std::vector<ItemStack> mItems;
}; };

View File

@ -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)
{
}
}
}

View File

@ -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

View File

@ -2,6 +2,9 @@
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
namespace MWGui namespace MWGui
{ {
CountDialog::CountDialog() : CountDialog::CountDialog() :
@ -40,7 +43,7 @@ namespace MWGui
mMainWidget->getHeight()); mMainWidget->getHeight());
// by default, the text edit field has the focus of the keyboard // 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); mSlider->setScrollPosition(maxCount-1);
mItemEdit->setCaption(boost::lexical_cast<std::string>(maxCount)); mItemEdit->setCaption(boost::lexical_cast<std::string>(maxCount));

View File

@ -7,6 +7,7 @@
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/soundmanager.hpp"
#include "../mwmechanics/npcstats.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 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); typesetter->sectionBreak(9);
if (mTitle != "") if (mTitle != "")
typesetter->write(title, to_utf8_span(mTitle.c_str())); typesetter->write(title, to_utf8_span(mTitle.c_str()));
@ -159,7 +160,7 @@ namespace MWGui
if (hyperLinks.size() && MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation()) 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 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) 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 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 linkHot (143/255.f, 155/255.f, 218/255.f);
const MyGUI::Colour linkNormal (112/255.f, 126/255.f, 207/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 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->sectionBreak(9);
typesetter->write(title, to_utf8_span(mText.c_str())); typesetter->write(title, to_utf8_span(mText.c_str()));
} }
@ -224,16 +225,22 @@ namespace MWGui
void Choice::activated() void Choice::activated()
{ {
MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.0, 1.0);
MWBase::Environment::get().getDialogueManager()->questionAnswered(mChoiceId); MWBase::Environment::get().getDialogueManager()->questionAnswered(mChoiceId);
} }
void Topic::activated() void Topic::activated()
{ {
MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f);
MWBase::Environment::get().getDialogueManager()->keywordSelected(Misc::StringUtils::lowerCase(mTopicId)); MWBase::Environment::get().getDialogueManager()->keywordSelected(Misc::StringUtils::lowerCase(mTopicId));
} }
void Goodbye::activated() void Goodbye::activated()
{ {
MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f);
MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); MWBase::Environment::get().getDialogueManager()->goodbyeSelected();
} }
@ -465,13 +472,14 @@ namespace MWGui
(*it)->write(typesetter, &mKeywordSearch, mTopicLinks); (*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 // choices
const MyGUI::Colour linkHot (223/255.f, 201/255.f, 159/255.f); 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 linkNormal (150/255.f, 50/255.f, 30/255.f);
const MyGUI::Colour linkActive (243/255.f, 237/255.f, 221/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); Choice* link = new Choice(it->second);
mLinks.push_back(link); mLinks.push_back(link);

View File

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

View File

@ -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);
}
}

View File

@ -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

View File

@ -202,14 +202,14 @@ namespace MWGui
float BookTextParser::widthForCharGlyph(unsigned unicodeChar) const 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) return MyGUI::FontManager::getInstance().getByName(fontName)
->getGlyphInfo(unicodeChar)->width; ->getGlyphInfo(unicodeChar)->width;
} }
float BookTextParser::currentFontHeight() const 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(); return MyGUI::FontManager::getInstance().getByName(fontName)->getDefaultHeight();
} }
@ -251,10 +251,8 @@ namespace MWGui
MyGUI::Gui::getInstance().destroyWidget(mParent->getChildAt(0)); MyGUI::Gui::getInstance().destroyWidget(mParent->getChildAt(0));
} }
boost::algorithm::replace_all(text, "\n", "\n"); boost::algorithm::replace_all(text, "<BR>", "\n");
boost::algorithm::replace_all(text, "\r", "\r"); boost::algorithm::replace_all(text, "<P>", "\n\n");
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::trim_left(text); boost::algorithm::trim_left(text);
// remove trailing " // remove trailing "

View File

@ -13,8 +13,6 @@ namespace MWGui
, mType(Type_Normal) , mType(Type_Normal)
, mBase(base) , mBase(base)
{ {
assert(base.getContainerStore());
if (MWWorld::Class::get(base).getEnchantment(base) != "") if (MWWorld::Class::get(base).getEnchantment(base) != "")
mFlags |= Flag_Enchanted; mFlags |= Flag_Enchanted;
} }
@ -31,18 +29,42 @@ namespace MWGui
{ {
if(mBase == other.mBase) if(mBase == other.mBase)
return true; 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) bool operator == (const ItemStack& left, const ItemStack& right)
{ {
if (left.mType != right.mType) if (left.mType != right.mType)
return false; return false;
if(left.mBase == right.mBase) if(left.mBase == right.mBase)
return true; 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() ItemModel::ItemModel()

View File

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

View File

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

View File

@ -10,6 +10,7 @@
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/inputmanager.hpp"
namespace MWGui 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 // 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) // (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)); Ogre::CompositorChain* chain = Ogre::CompositorManager::getSingleton().getCompositorChain(mWindow->getViewport(0));

View File

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

View File

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

View File

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

View File

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

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