1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-02 22:45:35 +00:00
This commit is contained in:
gus 2013-03-14 18:24:32 +00:00
commit 61e0d6b364
347 changed files with 9998 additions and 7559 deletions

View file

@ -29,6 +29,7 @@ option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binarie
option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE) option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE)
# Apps and tools # Apps and tools
option(BUILD_BSATOOL "build BSA extractor" OFF)
option(BUILD_ESMTOOL "build ESM inspector" ON) option(BUILD_ESMTOOL "build ESM inspector" ON)
option(BUILD_LAUNCHER "build Launcher" ON) option(BUILD_LAUNCHER "build Launcher" ON)
option(BUILD_MWINIIMPORTER "build MWiniImporter" ON) option(BUILD_MWINIIMPORTER "build MWiniImporter" ON)
@ -74,7 +75,6 @@ set(LIBDIR ${CMAKE_SOURCE_DIR}/libs)
set(OENGINE_OGRE set(OENGINE_OGRE
${LIBDIR}/openengine/ogre/renderer.cpp ${LIBDIR}/openengine/ogre/renderer.cpp
${LIBDIR}/openengine/ogre/fader.cpp ${LIBDIR}/openengine/ogre/fader.cpp
${LIBDIR}/openengine/ogre/imagerotate.cpp
${LIBDIR}/openengine/ogre/selectionbuffer.cpp ${LIBDIR}/openengine/ogre/selectionbuffer.cpp
) )
set(OENGINE_GUI set(OENGINE_GUI
@ -183,7 +183,7 @@ endif()
# find boost without components so we can use Boost_VERSION # find boost without components so we can use Boost_VERSION
find_package(Boost REQUIRED) find_package(Boost REQUIRED)
set(BOOST_COMPONENTS system filesystem program_options thread) set(BOOST_COMPONENTS system filesystem program_options thread date_time)
if (Boost_VERSION LESS 104900) if (Boost_VERSION LESS 104900)
set(SHINY_USE_WAVE_SYSTEM_INSTALL "TRUE") set(SHINY_USE_WAVE_SYSTEM_INSTALL "TRUE")
@ -300,6 +300,8 @@ configure_file(${OpenMW_SOURCE_DIR}/files/openmw.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
"${OpenMW_BINARY_DIR}/openmw.desktop") "${OpenMW_BINARY_DIR}/openmw.desktop")
configure_file(${OpenMW_SOURCE_DIR}/files/opencs.desktop
"${OpenMW_BINARY_DIR}/opencs.desktop")
endif() endif()
# Compiler settings # Compiler settings
@ -353,7 +355,7 @@ 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 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), 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_SECTION "Games") SET(CPACK_DEBIAN_PACKAGE_SECTION "Games")
@ -380,7 +382,6 @@ if(WIN32)
"${OpenMW_SOURCE_DIR}/OFL.txt" "${OpenMW_SOURCE_DIR}/OFL.txt"
"${OpenMW_SOURCE_DIR}/DejaVu Font License.txt" "${OpenMW_SOURCE_DIR}/DejaVu Font License.txt"
"${OpenMW_SOURCE_DIR}/Daedric Font License.txt" "${OpenMW_SOURCE_DIR}/Daedric Font License.txt"
"${OpenMW_BINARY_DIR}/launcher.qss"
"${OpenMW_BINARY_DIR}/settings-default.cfg" "${OpenMW_BINARY_DIR}/settings-default.cfg"
"${OpenMW_BINARY_DIR}/transparency-overrides.cfg" "${OpenMW_BINARY_DIR}/transparency-overrides.cfg"
"${OpenMW_BINARY_DIR}/Release/omwlauncher.exe" "${OpenMW_BINARY_DIR}/Release/omwlauncher.exe"
@ -448,6 +449,10 @@ add_subdirectory (components)
# Apps and tools # Apps and tools
add_subdirectory( apps/openmw ) add_subdirectory( apps/openmw )
if (BUILD_BSATOOL)
add_subdirectory( apps/bsatool )
endif()
if (BUILD_ESMTOOL) if (BUILD_ESMTOOL)
add_subdirectory( apps/esmtool ) add_subdirectory( apps/esmtool )
endif() endif()
@ -534,6 +539,9 @@ if (WIN32)
set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS}) set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS})
endif (BUILD_LAUNCHER) endif (BUILD_LAUNCHER)
set_target_properties(openmw PROPERTIES COMPILE_FLAGS ${WARNINGS}) set_target_properties(openmw PROPERTIES COMPILE_FLAGS ${WARNINGS})
if (BUILD_BSATOOL)
set_target_properties(bsatool PROPERTIES COMPILE_FLAGS ${WARNINGS})
endif (BUILD_BSATOOL)
if (BUILD_ESMTOOL) if (BUILD_ESMTOOL)
set_target_properties(esmtool PROPERTIES COMPILE_FLAGS ${WARNINGS}) set_target_properties(esmtool PROPERTIES COMPILE_FLAGS ${WARNINGS})
endif (BUILD_ESMTOOL) endif (BUILD_ESMTOOL)
@ -567,8 +575,6 @@ if (APPLE)
install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(DIRECTORY "${OpenMW_BINARY_DIR}/resources" 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}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/launcher.qss" 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)
@ -660,6 +666,9 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE)
IF(BUILD_LAUNCHER) IF(BUILD_LAUNCHER)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" ) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" )
ENDIF(BUILD_LAUNCHER) ENDIF(BUILD_LAUNCHER)
IF(BUILD_BSATOOL)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/bsatool" DESTINATION "${BINDIR}" )
ENDIF(BUILD_BSATOOL)
IF(BUILD_ESMTOOL) IF(BUILD_ESMTOOL)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" ) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" )
ENDIF(BUILD_ESMTOOL) ENDIF(BUILD_ESMTOOL)
@ -682,7 +691,4 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE)
# Install resources # Install resources
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" ) INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" )
IF(BUILD_LAUNCHER)
INSTALL(FILES "${OpenMW_BINARY_DIR}/launcher.qss" DESTINATION "${DATADIR}/resources" )
ENDIF(BUILD_LAUNCHER)
endif(NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) endif(NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE)

View file

@ -0,0 +1,19 @@
set(BSATOOL
bsatool.cpp
)
source_group(apps\\bsatool FILES ${BSATOOL})
# Main executable
add_executable(bsatool
${BSATOOL}
)
target_link_libraries(bsatool
${Boost_LIBRARIES}
components
)
if (BUILD_WITH_CODE_COVERAGE)
add_definitions (--coverage)
target_link_libraries(bsatool gcov)
endif()

288
apps/bsatool/bsatool.cpp Normal file
View file

@ -0,0 +1,288 @@
#include <iostream>
#include <vector>
#include <exception>
#include <boost/program_options.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <components/bsa/bsa_file.hpp>
#define BSATOOL_VERSION 1.1
// Create local aliases for brevity
namespace bpo = boost::program_options;
namespace bfs = boost::filesystem;
struct Arguments
{
std::string mode;
std::string filename;
std::string extractfile;
std::string outdir;
bool longformat;
bool fullpath;
};
void replaceAll(std::string& str, const std::string& needle, const std::string& substitute)
{
int pos = str.find(needle);
while(pos != -1)
{
str.replace(pos, needle.size(), substitute);
pos = str.find(needle);
}
}
bool parseOptions (int argc, char** argv, Arguments &info)
{
bpo::options_description desc("Inspect and extract files from Bethesda BSA archives\n\n"
"Usages:\n"
" bsatool list [-l] archivefile\n"
" List the files presents in the input archive.\n\n"
" bsatool extract [-f] archivefile [file_to_extract] [output_directory]\n"
" Extract a file from the input archive.\n\n"
" bsatool extractall archivefile [output_directory]\n"
" Extract all files from the input archive.\n\n"
"Allowed options");
desc.add_options()
("help,h", "print help message.")
("version,v", "print version information and quit.")
("long,l", "Include extra information in archive listing.")
("full-path,f", "Create diretory hierarchy on file extraction "
"(always true for extractall).")
;
// input-file is hidden and used as a positional argument
bpo::options_description hidden("Hidden Options");
hidden.add_options()
( "mode,m", bpo::value<std::string>(), "bsatool mode")
( "input-file,i", bpo::value< std::vector<std::string> >(), "input file")
;
bpo::positional_options_description p;
p.add("mode", 1).add("input-file", 3);
// there might be a better way to do this
bpo::options_description all;
all.add(desc).add(hidden);
bpo::variables_map variables;
try
{
bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv)
.options(all).positional(p).run();
bpo::store(valid_opts, variables);
}
catch(std::exception &e)
{
std::cout << "ERROR parsing arguments: " << e.what() << "\n\n"
<< desc << std::endl;
return false;
}
bpo::notify(variables);
if (variables.count ("help"))
{
std::cout << desc << std::endl;
return false;
}
if (variables.count ("version"))
{
std::cout << "BSATool version " << BSATOOL_VERSION << std::endl;
return false;
}
if (!variables.count("mode"))
{
std::cout << "ERROR: no mode specified!\n\n"
<< desc << std::endl;
return false;
}
info.mode = variables["mode"].as<std::string>();
if (!(info.mode == "list" || info.mode == "extract" || info.mode == "extractall"))
{
std::cout << std::endl << "ERROR: invalid mode \"" << info.mode << "\"\n\n"
<< desc << std::endl;
return false;
}
if (!variables.count("input-file"))
{
std::cout << "\nERROR: missing BSA archive\n\n"
<< desc << std::endl;
return false;
}
info.filename = variables["input-file"].as< std::vector<std::string> >()[0];
// Default output to the working directory
info.outdir = ".";
if (info.mode == "extract")
{
if (variables["input-file"].as< std::vector<std::string> >().size() < 2)
{
std::cout << "\nERROR: file to extract unspecified\n\n"
<< desc << std::endl;
return false;
}
if (variables["input-file"].as< std::vector<std::string> >().size() > 1)
info.extractfile = variables["input-file"].as< std::vector<std::string> >()[1];
if (variables["input-file"].as< std::vector<std::string> >().size() > 2)
info.outdir = variables["input-file"].as< std::vector<std::string> >()[2];
}
else if (variables["input-file"].as< std::vector<std::string> >().size() > 1)
info.outdir = variables["input-file"].as< std::vector<std::string> >()[1];
info.longformat = variables.count("long");
info.fullpath = variables.count("full-path");
return true;
}
int list(Bsa::BSAFile& bsa, Arguments& info);
int extract(Bsa::BSAFile& bsa, Arguments& info);
int extractAll(Bsa::BSAFile& bsa, Arguments& info);
int main(int argc, char** argv)
{
Arguments info;
if(!parseOptions (argc, argv, info))
return 1;
// Open file
Bsa::BSAFile bsa;
try
{
bsa.open(info.filename);
}
catch(std::exception &e)
{
std::cout << "ERROR reading BSA archive '" << info.filename
<< "'\nDetails:\n" << e.what() << std::endl;
return 2;
}
if (info.mode == "list")
return list(bsa, info);
else if (info.mode == "extract")
return extract(bsa, info);
else if (info.mode == "extractall")
return extractAll(bsa, info);
else
{
std::cout << "Unsupported mode. That is not supposed to happen." << std::endl;
return 1;
}
}
int list(Bsa::BSAFile& bsa, Arguments& info)
{
// List all files
const Bsa::BSAFile::FileList &files = bsa.getList();
for(int i=0; i<files.size(); i++)
{
if(info.longformat)
{
// Long format
std::cout << std::setw(50) << std::left << files[i].name;
std::cout << std::setw(8) << std::left << std::dec << files[i].fileSize;
std::cout << "@ 0x" << std::hex << files[i].offset << std::endl;
}
else
std::cout << files[i].name << std::endl;
}
return 0;
}
int extract(Bsa::BSAFile& bsa, Arguments& info)
{
std::string archivePath = info.extractfile;
replaceAll(archivePath, "/", "\\");
std::string extractPath = info.extractfile;
replaceAll(extractPath, "\\", "/");
if (!bsa.exists(archivePath.c_str()))
{
std::cout << "ERROR: file '" << archivePath << "' not found\n";
std::cout << "In archive: " << info.filename << std::endl;
return 3;
}
// Get the target path (the path the file will be extracted to)
bfs::path relPath (extractPath);
bfs::path outdir (info.outdir);
bfs::path target;
if (info.fullpath)
target = outdir / relPath;
else
target = outdir / relPath.filename();
// Create the directory hierarchy
bfs::create_directories(target.parent_path());
bfs::file_status s = bfs::status(target.parent_path());
if (!bfs::is_directory(s))
{
std::cout << "ERROR: " << target.parent_path() << " is not a directory." << std::endl;
return 3;
}
// Get a stream for the file to extract
Ogre::DataStreamPtr data = bsa.getFile(archivePath.c_str());
bfs::ofstream out(target, std::ios::binary);
// Write the file to disk
std::cout << "Extracting " << info.extractfile << " to " << target << std::endl;
out.write(data->getAsString().c_str(), data->size());
out.close();
return 0;
}
int extractAll(Bsa::BSAFile& bsa, Arguments& info)
{
// Get the list of files present in the archive
Bsa::BSAFile::FileList list = bsa.getList();
// Iter on the list
for(Bsa::BSAFile::FileList::iterator it = list.begin(); it != list.end(); ++it) {
const char* archivePath = it->name;
std::string extractPath (archivePath);
replaceAll(extractPath, "\\", "/");
// Get the target path (the path the file will be extracted to)
bfs::path target (info.outdir);
target /= extractPath;
// Create the directory hierarchy
bfs::create_directories(target.parent_path());
bfs::file_status s = bfs::status(target.parent_path());
if (!bfs::is_directory(s))
{
std::cout << "ERROR: " << target.parent_path() << " is not a directory." << std::endl;
return 3;
}
// Get a stream for the file to extract
// (inefficient because getFile iter on the list again)
Ogre::DataStreamPtr data = bsa.getFile(archivePath);
bfs::ofstream out(target, std::ios::binary);
// Write the file to disk
std::cout << "Extracting " << target << std::endl;
out.write(data->getAsString().c_str(), data->size());
out.close();
}
return 0;
}

View file

@ -23,8 +23,7 @@ struct ESMData
std::string author; std::string author;
std::string description; std::string description;
int version; int version;
int type; std::vector<ESM::Header::MasterData> masters;
ESM::ESMReader::MasterList masters;
std::deque<EsmTool::RecordBase *> mRecords; std::deque<EsmTool::RecordBase *> mRecords;
std::map<ESM::Cell *, std::deque<ESM::CellRef> > mCellRefs; std::map<ESM::Cell *, std::deque<ESM::CellRef> > mCellRefs;
@ -284,16 +283,13 @@ int load(Arguments& info)
info.data.author = esm.getAuthor(); info.data.author = esm.getAuthor();
info.data.description = esm.getDesc(); info.data.description = esm.getDesc();
info.data.masters = esm.getMasters(); info.data.masters = esm.getMasters();
info.data.version = esm.getVer();
info.data.type = esm.getType();
if (!quiet) if (!quiet)
{ {
std::cout << "Author: " << esm.getAuthor() << std::endl std::cout << "Author: " << esm.getAuthor() << std::endl
<< "Description: " << esm.getDesc() << std::endl << "Description: " << esm.getDesc() << std::endl
<< "File format version: " << esm.getFVer() << std::endl << "File format version: " << esm.getFVer() << std::endl;
<< "Special flag: " << esm.getSpecial() << std::endl; std::vector<ESM::Header::MasterData> m = esm.getMasters();
ESM::ESMReader::MasterList m = esm.getMasters();
if (!m.empty()) if (!m.empty())
{ {
std::cout << "Masters:" << std::endl; std::cout << "Masters:" << std::endl;
@ -430,9 +426,9 @@ int clone(Arguments& info)
esm.setAuthor(info.data.author); esm.setAuthor(info.data.author);
esm.setDescription(info.data.description); esm.setDescription(info.data.description);
esm.setVersion(info.data.version); esm.setVersion(info.data.version);
esm.setType(info.data.type); esm.setRecordCount (recordCount);
for (ESM::ESMReader::MasterList::iterator it = info.data.masters.begin(); it != info.data.masters.end(); ++it) for (std::vector<ESM::Header::MasterData>::iterator it = info.data.masters.begin(); it != info.data.masters.end(); ++it)
esm.addMaster(it->name, it->size); esm.addMaster(it->name, it->size);
std::fstream save(info.outname.c_str(), std::fstream::out | std::fstream::binary); std::fstream save(info.outname.c_str(), std::fstream::out | std::fstream::binary);

View file

@ -112,14 +112,11 @@ std::string ruleString(ESM::DialInfo::SelectStruct ss)
case '5': oper_str = ">="; break; case '5': oper_str = ">="; break;
} }
std::string value_str = "??"; std::ostringstream stream;
if (ss.mType == ESM::VT_Int) stream << ss.mValue;
value_str = str(boost::format("%d") % ss.mI);
else if (ss.mType == ESM::VT_Float)
value_str = str(boost::format("%f") % ss.mF);
std::string result = str(boost::format("%-12s %-32s %2s %s") std::string result = str(boost::format("%-12s %-32s %2s %s")
% type_str % func_str % oper_str % value_str); % type_str % func_str % oper_str % stream.str());
return result; return result;
} }
@ -713,31 +710,13 @@ void Record<ESM::Faction>::print()
template<> template<>
void Record<ESM::Global>::print() void Record<ESM::Global>::print()
{ {
// nothing to print (well, nothing that's correct anyway) std::cout << " " << mData.mValue << std::endl;
std::cout << " Type: " << mData.mType << std::endl;
std::cout << " Value: " << mData.mValue << std::endl;
} }
template<> template<>
void Record<ESM::GameSetting>::print() void Record<ESM::GameSetting>::print()
{ {
std::cout << " Value: "; std::cout << " " << mData.mValue << std::endl;
switch (mData.mType) {
case ESM::VT_String:
std::cout << "'" << mData.mStr << "' (std::string)";
break;
case ESM::VT_Float:
std::cout << mData.mF << " (float)";
break;
case ESM::VT_Int:
std::cout << mData.mI << " (int)";
break;
default:
std::cout << "unknown type";
}
} }
template<> template<>

View file

@ -1,35 +1,55 @@
set(LAUNCHER set(LAUNCHER
datafilespage.cpp
graphicspage.cpp graphicspage.cpp
main.cpp main.cpp
maindialog.cpp maindialog.cpp
playpage.cpp playpage.cpp
datafilespage.cpp
utils/profilescombobox.cpp settings/gamesettings.cpp
settings/graphicssettings.cpp
settings/launchersettings.cpp
utils/checkablemessagebox.cpp
utils/textinputdialog.cpp utils/textinputdialog.cpp
launcher.rc launcher.rc
) )
set(LAUNCHER_HEADER set(LAUNCHER_HEADER
datafilespage.hpp
graphicspage.hpp graphicspage.hpp
maindialog.hpp maindialog.hpp
playpage.hpp playpage.hpp
datafilespage.hpp
utils/profilescombobox.hpp settings/gamesettings.hpp
settings/graphicssettings.hpp
settings/launchersettings.hpp
settings/settingsbase.hpp
utils/checkablemessagebox.hpp
utils/textinputdialog.hpp utils/textinputdialog.hpp
) )
# Headers that must be pre-processed # Headers that must be pre-processed
set(LAUNCHER_HEADER_MOC set(LAUNCHER_HEADER_MOC
datafilespage.hpp
graphicspage.hpp graphicspage.hpp
maindialog.hpp maindialog.hpp
playpage.hpp playpage.hpp
datafilespage.hpp
utils/profilescombobox.hpp utils/checkablemessagebox.hpp
utils/textinputdialog.hpp utils/textinputdialog.hpp
) )
source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER} ${LAUNCHER_HEADER_MOC}) set(LAUNCHER_UI
../../files/ui/datafilespage.ui
../../files/ui/graphicspage.ui
../../files/ui/mainwindow.ui
../../files/ui/playpage.ui
)
source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER})
find_package(Qt4 REQUIRED) find_package(Qt4 REQUIRED)
set(QT_USE_QTGUI 1) set(QT_USE_QTGUI 1)
@ -40,10 +60,12 @@ if(WIN32)
set(QT_USE_QTMAIN TRUE) set(QT_USE_QTMAIN TRUE)
endif(WIN32) endif(WIN32)
QT4_ADD_RESOURCES(RCC_SRCS resources.qrc) QT4_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/launcher/launcher.qrc)
QT4_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC}) QT4_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC})
QT4_WRAP_UI(UI_HDRS ${LAUNCHER_UI})
include(${QT_USE_FILE}) include(${QT_USE_FILE})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
# Main executable # Main executable
IF(OGRE_STATIC) IF(OGRE_STATIC)
@ -58,8 +80,10 @@ ENDIF(OGRE_STATIC)
add_executable(omwlauncher add_executable(omwlauncher
${GUI_TYPE} ${GUI_TYPE}
${LAUNCHER} ${LAUNCHER}
${LAUNCHER_HEADER}
${RCC_SRCS} ${RCC_SRCS}
${MOC_SRCS} ${MOC_SRCS}
${UI_HDRS}
) )
target_link_libraries(omwlauncher target_link_libraries(omwlauncher
@ -74,18 +98,6 @@ if(DPKG_PROGRAM)
INSTALL(TARGETS omwlauncher RUNTIME DESTINATION games COMPONENT omwlauncher) INSTALL(TARGETS omwlauncher RUNTIME DESTINATION games COMPONENT omwlauncher)
endif() endif()
if (APPLE)
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss
"${APP_BUNDLE_DIR}/../launcher.qss")
else()
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/resources/launcher.qss")
# Fallback in case getGlobalDataPath does not point to resources
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/launcher.qss")
endif()
if (BUILD_WITH_CODE_COVERAGE) if (BUILD_WITH_CODE_COVERAGE)
add_definitions (--coverage) add_definitions (--coverage)
target_link_libraries(omwlauncher gcov) target_link_libraries(omwlauncher gcov)

View file

@ -1,445 +1,308 @@
#include <QtGui>
#include <components/esm/esmreader.hpp>
#include <components/files/configurationmanager.hpp>
#include <components/fileorderlist/datafileslist.hpp>
#include <components/fileorderlist/utils/lineedit.hpp>
#include <components/fileorderlist/utils/naturalsort.hpp>
#include <components/fileorderlist/utils/filedialog.hpp>
////#include "model/datafilesmodel.hpp"
////#include "model/esm/esmfile.hpp"
#include "utils/profilescombobox.hpp"
////#include "utils/filedialog.hpp"
////#include "utils/naturalsort.hpp"
#include "utils/textinputdialog.hpp"
#include "datafilespage.hpp" #include "datafilespage.hpp"
#include <boost/version.hpp> #include <QtGui>
/**
* Workaround for problems with whitespaces in paths in older versions of Boost library #include <components/files/configurationmanager.hpp>
*/
#if (BOOST_VERSION <= 104600) #include <components/fileorderlist/model/datafilesmodel.hpp>
namespace boost #include <components/fileorderlist/model/pluginsproxymodel.hpp>
#include <components/fileorderlist/model/esm/esmfile.hpp>
#include <components/fileorderlist/utils/lineedit.hpp>
#include <components/fileorderlist/utils/naturalsort.hpp>
#include <components/fileorderlist/utils/profilescombobox.hpp>
#include "settings/gamesettings.hpp"
#include "settings/launchersettings.hpp"
#include "utils/textinputdialog.hpp"
DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, LauncherSettings &launcherSettings, QWidget *parent)
: mCfgMgr(cfg)
, mGameSettings(gameSettings)
, mLauncherSettings(launcherSettings)
, QWidget(parent)
{ {
setupUi(this);
template<> // Models
inline boost::filesystem::path lexical_cast<boost::filesystem::path, std::string>(const std::string& arg) mDataFilesModel = new DataFilesModel(this);
{
return boost::filesystem::path(arg);
}
} /* namespace boost */ mMastersProxyModel = new QSortFilterProxyModel();
#endif /* (BOOST_VERSION <= 104600) */ mMastersProxyModel->setFilterRegExp(QString("^.*\\.esm"));
mMastersProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
mMastersProxyModel->setSourceModel(mDataFilesModel);
using namespace ESM; mPluginsProxyModel = new PluginsProxyModel();
using namespace std; mPluginsProxyModel->setFilterRegExp(QString("^.*\\.esp"));
mPluginsProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
mPluginsProxyModel->setSourceModel(mDataFilesModel);
DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, QWidget *parent) mFilterProxyModel = new QSortFilterProxyModel();
: QWidget(parent) mFilterProxyModel->setDynamicSortFilter(true);
, mCfgMgr(cfg) mFilterProxyModel->setSourceModel(mPluginsProxyModel);
{
mDataFilesList = new DataFilesList(mCfgMgr, this);
// Bottom part with profile options QCheckBox checkBox;
QLabel *profileLabel = new QLabel(tr("Current Profile: "), this); unsigned int height = checkBox.sizeHint().height() + 4;
mProfilesComboBox = new ProfilesComboBox(this); mastersTable->setModel(mMastersProxyModel);
mProfilesComboBox->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); mastersTable->setObjectName("MastersTable");
mProfilesComboBox->setInsertPolicy(QComboBox::NoInsert); mastersTable->setContextMenuPolicy(Qt::CustomContextMenu);
mProfilesComboBox->setDuplicatesEnabled(false); mastersTable->setSortingEnabled(false);
mProfilesComboBox->setEditEnabled(false); mastersTable->setSelectionBehavior(QAbstractItemView::SelectRows);
mastersTable->setSelectionMode(QAbstractItemView::ExtendedSelection);
mastersTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
mastersTable->setAlternatingRowColors(true);
mastersTable->horizontalHeader()->setStretchLastSection(true);
mastersTable->horizontalHeader()->hide();
mProfileToolBar = new QToolBar(this); // Set the row height to the size of the checkboxes
mProfileToolBar->setMovable(false); mastersTable->verticalHeader()->setDefaultSectionSize(height);
mProfileToolBar->setIconSize(QSize(16, 16)); mastersTable->verticalHeader()->setResizeMode(QHeaderView::Fixed);
mastersTable->verticalHeader()->hide();
mProfileToolBar->addWidget(profileLabel); pluginsTable->setModel(mFilterProxyModel);
mProfileToolBar->addWidget(mProfilesComboBox); pluginsTable->setObjectName("PluginsTable");
pluginsTable->setContextMenuPolicy(Qt::CustomContextMenu);
pluginsTable->setSortingEnabled(false);
pluginsTable->setSelectionBehavior(QAbstractItemView::SelectRows);
pluginsTable->setSelectionMode(QAbstractItemView::ExtendedSelection);
pluginsTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
pluginsTable->setAlternatingRowColors(true);
pluginsTable->setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
pluginsTable->horizontalHeader()->setStretchLastSection(true);
pluginsTable->horizontalHeader()->hide();
QVBoxLayout *pageLayout = new QVBoxLayout(this); pluginsTable->verticalHeader()->setDefaultSectionSize(height);
pluginsTable->verticalHeader()->setResizeMode(QHeaderView::Fixed);
pageLayout->addWidget(mDataFilesList); // Adjust the tableview widths inside the splitter
pageLayout->addWidget(mProfileToolBar); QList<int> sizeList;
sizeList << mLauncherSettings.value(QString("General/MastersTable/width"), QString("200")).toInt();
sizeList << mLauncherSettings.value(QString("General/PluginTable/width"), QString("340")).toInt();
splitter->setSizes(sizeList);
// Create a dialog for the new profile name input // Create a dialog for the new profile name input
mNewProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this); mNewProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this);
connect(profilesComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentIndexChanged(int)));
connect(mNewProfileDialog->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(updateOkButton(QString))); connect(mNewProfileDialog->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(updateOkButton(QString)));
connect(pluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex)));
connect(mastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex)));
connect(pluginsTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint)));
connect(mastersTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint)));
connect(mDataFilesModel, SIGNAL(layoutChanged()), this, SLOT(updateViews()));
connect(mProfilesComboBox, SIGNAL(profileRenamed(QString,QString)), this, SLOT(profileRenamed(QString,QString))); connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString)));
connect(mProfilesComboBox, SIGNAL(profileChanged(QString,QString)), this, SLOT(profileChanged(QString,QString)));
connect(splitter, SIGNAL(splitterMoved(int,int)), this, SLOT(updateSplitter()));
createActions(); createActions();
setupConfig(); setupDataFiles();
} }
void DataFilesPage::createActions() void DataFilesPage::createActions()
{ {
// Refresh the plugins
QAction *refreshAction = new QAction(tr("Refresh"), this);
refreshAction->setShortcut(QKeySequence(tr("F5")));
connect(refreshAction, SIGNAL(triggered()), this, SLOT(refresh()));
// Profile actions // Add the actions to the toolbuttons
mNewProfileAction = new QAction(QIcon::fromTheme("document-new"), tr("&New Profile"), this); newProfileButton->setDefaultAction(newProfileAction);
mNewProfileAction->setToolTip(tr("New Profile")); deleteProfileButton->setDefaultAction(deleteProfileAction);
mNewProfileAction->setShortcut(QKeySequence(tr("Ctrl+N")));
connect(mNewProfileAction, SIGNAL(triggered()), this, SLOT(newProfile()));
mDeleteProfileAction = new QAction(QIcon::fromTheme("edit-delete"), tr("Delete Profile"), this); // Context menu actions
mDeleteProfileAction->setToolTip(tr("Delete Profile")); mContextMenu = new QMenu(this);
mDeleteProfileAction->setShortcut(QKeySequence(tr("Delete"))); mContextMenu->addAction(checkAction);
connect(mDeleteProfileAction, SIGNAL(triggered()), this, SLOT(deleteProfile())); mContextMenu->addAction(uncheckAction);
// Add the newly created actions to the toolbar
mProfileToolBar->addSeparator();
mProfileToolBar->addAction(mNewProfileAction);
mProfileToolBar->addAction(mDeleteProfileAction);
} }
void DataFilesPage::setupConfig() void DataFilesPage::setupDataFiles()
{ {
// Open our config file // Set the encoding to the one found in openmw.cfg or the default
QString config = QString::fromStdString((mCfgMgr.getUserPath() / "launcher.cfg").string()); mDataFilesModel->setEncoding(mGameSettings.value(QString("encoding"), QString("win1252")));
mLauncherConfig = new QSettings(config, QSettings::IniFormat);
// Make sure we have no groups open QStringList paths = mGameSettings.getDataDirs();
while (!mLauncherConfig->group().isEmpty()) {
mLauncherConfig->endGroup(); foreach (const QString &path, paths) {
mDataFilesModel->addFiles(path);
} }
mLauncherConfig->beginGroup("Profiles"); QString dataLocal = mGameSettings.getDataLocal();
QStringList profiles = mLauncherConfig->childGroups(); if (!dataLocal.isEmpty())
mDataFilesModel->addFiles(dataLocal);
// Add the profiles to the combobox // Sort by date accessed for now
foreach (const QString &profile, profiles) { mDataFilesModel->sort(3);
if (profile.contains(QRegExp("[^a-zA-Z0-9_]"))) QStringList profiles = mLauncherSettings.subKeys(QString("Profiles/"));
continue; // Profile name contains garbage QString profile = mLauncherSettings.value(QString("Profiles/currentprofile"));
if (!profiles.isEmpty())
profilesComboBox->addItems(profiles);
qDebug() << "adding " << profile; // Add the current profile if empty
mProfilesComboBox->addItem(profile); if (profilesComboBox->findText(profile) == -1)
} profilesComboBox->addItem(profile);
// Add a default profile if (profilesComboBox->findText(QString("Default")) == -1)
if (mProfilesComboBox->findText(QString("Default")) == -1) { profilesComboBox->addItem(QString("Default"));
mProfilesComboBox->addItem(QString("Default"));
}
QString currentProfile = mLauncherConfig->value("CurrentProfile").toString();
if (currentProfile.isEmpty()) {
// No current profile selected
currentProfile = "Default";
}
const int currentIndex = mProfilesComboBox->findText(currentProfile);
if (currentIndex != -1) {
// Profile is found
mProfilesComboBox->setCurrentIndex(currentIndex);
}
mLauncherConfig->endGroup();
}
void DataFilesPage::readConfig()
{
QString profile = mProfilesComboBox->currentText();
// Make sure we have no groups open
while (!mLauncherConfig->group().isEmpty()) {
mLauncherConfig->endGroup();
}
mLauncherConfig->beginGroup("Profiles");
mLauncherConfig->beginGroup(profile);
QStringList childKeys = mLauncherConfig->childKeys();
QStringList plugins;
// Sort the child keys numerical instead of alphabetically
// i.e. Plugin1, Plugin2 instead of Plugin1, Plugin10
qSort(childKeys.begin(), childKeys.end(), naturalSortLessThanCI);
foreach (const QString &key, childKeys) {
const QString keyValue = mLauncherConfig->value(key).toString();
mDataFilesList->setCheckState(keyValue, Qt::Checked);
}
qDebug() << plugins;
}
bool DataFilesPage::showDataFilesWarning()
{
QMessageBox msgBox;
msgBox.setWindowTitle("Error detecting Morrowind installation");
msgBox.setIcon(QMessageBox::Warning);
msgBox.setStandardButtons(QMessageBox::Cancel);
msgBox.setText(tr("<br><b>Could not find the Data Files location</b><br><br> \
The directory containing the data files was not found.<br><br> \
Press \"Browse...\" to specify the location manually.<br>"));
QAbstractButton *dirSelectButton =
msgBox.addButton(tr("B&rowse..."), QMessageBox::ActionRole);
msgBox.exec();
if (msgBox.clickedButton() == dirSelectButton) {
// Show a custom dir selection dialog which only accepts valid dirs
QString selectedDir = FileDialog::getExistingDirectory(
this, tr("Select Data Files Directory"),
QDir::currentPath(),
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
// Add the user selected data directory
if (!selectedDir.isEmpty()) {
mDataDirs.push_back(Files::PathContainer::value_type(selectedDir.toStdString()));
mCfgMgr.processPaths(mDataDirs);
} else {
// Cancel from within the dir selection dialog
return false;
}
if (profile.isEmpty() || profile == QLatin1String("Default")) {
deleteProfileAction->setEnabled(false);
profilesComboBox->setEditEnabled(false);
profilesComboBox->setCurrentIndex(profilesComboBox->findText(QString("Default")));
} else { } else {
// Cancel profilesComboBox->setEditEnabled(true);
return false; profilesComboBox->setCurrentIndex(profilesComboBox->findText(profile));
} }
return true; // We do this here to prevent deletion of profiles when initializing the combobox
connect(profilesComboBox, SIGNAL(profileRenamed(QString,QString)), this, SLOT(profileRenamed(QString,QString)));
connect(profilesComboBox, SIGNAL(profileChanged(QString,QString)), this, SLOT(profileChanged(QString,QString)));
loadSettings();
} }
bool DataFilesPage::setupDataFiles() void DataFilesPage::loadSettings()
{ {
// We use the Configuration Manager to retrieve the configuration values QString profile = mLauncherSettings.value(QString("Profiles/currentprofile"));
boost::program_options::variables_map variables;
boost::program_options::options_description desc;
desc.add_options()
("data", boost::program_options::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")->multitoken())
("data-local", boost::program_options::value<std::string>()->default_value(""))
("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false))
("encoding", boost::program_options::value<std::string>()->default_value("win1252"));
boost::program_options::notify(variables);
mCfgMgr.readConfiguration(variables, desc);
if (variables["data"].empty()) {
if (!showDataFilesWarning())
return false;
} else {
mDataDirs = Files::PathContainer(variables["data"].as<Files::PathContainer>());
}
std::string local = variables["data-local"].as<std::string>();
if (!local.empty()) {
mDataLocal.push_back(Files::PathContainer::value_type(local));
}
mCfgMgr.processPaths(mDataDirs);
mCfgMgr.processPaths(mDataLocal);
// Second chance to display the warning, the data= entries are invalid
while (mDataDirs.empty()) {
if (!showDataFilesWarning())
return false;
}
// Set the charset for reading the esm/esp files
QString encoding = QString::fromStdString(variables["encoding"].as<std::string>());
Files::PathContainer paths;
paths.insert(paths.end(), mDataDirs.begin(), mDataDirs.end());
paths.insert(paths.end(), mDataLocal.begin(), mDataLocal.end());
mDataFilesList->setupDataFiles(paths, encoding);
readConfig();
return true;
}
void DataFilesPage::writeConfig(QString profile)
{
QString pathStr = QString::fromStdString(mCfgMgr.getUserPath().string());
QDir userPath(pathStr);
if (!userPath.exists()) {
if (!userPath.mkpath(pathStr)) {
QMessageBox msgBox;
msgBox.setWindowTitle("Error creating OpenMW configuration directory");
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Could not create %0</b><br><br> \
Please make sure you have the right permissions and try again.<br>").arg(pathStr));
msgBox.exec();
qApp->quit();
return;
}
}
// Open the OpenMW config as a QFile
QFile file(pathStr.append("openmw.cfg"));
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
// File cannot be opened or created
QMessageBox msgBox;
msgBox.setWindowTitle("Error writing OpenMW configuration file");
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Could not open or create %0</b><br><br> \
Please make sure you have the right permissions and try again.<br>").arg(file.fileName()));
msgBox.exec();
qApp->quit();
return;
}
QTextStream in(&file);
QByteArray buffer;
// Remove all previous entries from config
while (!in.atEnd()) {
QString line = in.readLine();
if (!line.startsWith("master") &&
!line.startsWith("plugin") &&
!line.startsWith("data") &&
!line.startsWith("data-local"))
{
buffer += line += "\n";
}
}
file.close();
// Now we write back the other config entries
if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
QMessageBox msgBox;
msgBox.setWindowTitle("Error writing OpenMW configuration file");
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Could not write to %0</b><br><br> \
Please make sure you have the right permissions and try again.<br>").arg(file.fileName()));
msgBox.exec();
qApp->quit();
return;
}
if (!buffer.isEmpty()) {
file.write(buffer);
}
QTextStream gameConfig(&file);
// First write the list of data dirs
mCfgMgr.processPaths(mDataDirs);
mCfgMgr.processPaths(mDataLocal);
QString path;
// data= directories
for (Files::PathContainer::iterator it = mDataDirs.begin(); it != mDataDirs.end(); ++it) {
path = QString::fromStdString(it->string());
path.remove(QChar('\"'));
// Make sure the string is quoted when it contains spaces
if (path.contains(" ")) {
gameConfig << "data=\"" << path << "\"" << endl;
} else {
gameConfig << "data=" << path << endl;
}
}
// data-local directory
if (!mDataLocal.empty()) {
path = QString::fromStdString(mDataLocal.front().string());
path.remove(QChar('\"'));
if (path.contains(" ")) {
gameConfig << "data-local=\"" << path << "\"" << endl;
} else {
gameConfig << "data-local=" << path << endl;
}
}
if (profile.isEmpty())
profile = mProfilesComboBox->currentText();
if (profile.isEmpty()) if (profile.isEmpty())
return; return;
// Make sure we have no groups open mDataFilesModel->uncheckAll();
while (!mLauncherConfig->group().isEmpty()) {
mLauncherConfig->endGroup(); QStringList masters = mLauncherSettings.values(QString("Profiles/") + profile + QString("/master"), Qt::MatchExactly);
QStringList plugins = mLauncherSettings.values(QString("Profiles/") + profile + QString("/plugin"), Qt::MatchExactly);
foreach (const QString &master, masters) {
QModelIndex index = mDataFilesModel->indexFromItem(mDataFilesModel->findItem(master));
if (index.isValid())
mDataFilesModel->setCheckState(index, Qt::Checked);
} }
mLauncherConfig->beginGroup("Profiles"); foreach (const QString &plugin, plugins) {
mLauncherConfig->setValue("CurrentProfile", profile); QModelIndex index = mDataFilesModel->indexFromItem(mDataFilesModel->findItem(plugin));
if (index.isValid())
// Open the profile-name subgroup mDataFilesModel->setCheckState(index, Qt::Checked);
mLauncherConfig->beginGroup(profile);
mLauncherConfig->remove(""); // Clear the subgroup
// Now write the masters to the configs
const QStringList checkedFiles = mDataFilesList->checkedFiles();
for(int i=0; i < checkedFiles.size(); i++)
{
if (checkedFiles.at(i).lastIndexOf("esm") != -1)
{
mLauncherConfig->setValue(QString("Master%0").arg(i), checkedFiles.at(i));
gameConfig << "master=" << checkedFiles.at(i) << endl;
}
else
{
mLauncherConfig->setValue(QString("Plugin%1").arg(i), checkedFiles.at(i));
gameConfig << "plugin=" << checkedFiles.at(i) << endl;
}
} }
file.close();
mLauncherConfig->endGroup();
mLauncherConfig->endGroup();
mLauncherConfig->sync();
} }
void DataFilesPage::saveSettings()
void DataFilesPage::newProfile()
{ {
if (mNewProfileDialog->exec() == QDialog::Accepted) { if (mDataFilesModel->rowCount() < 1)
return;
const QString text = mNewProfileDialog->lineEdit()->text(); QString profile = mLauncherSettings.value(QString("Profiles/currentprofile"));
mProfilesComboBox->addItem(text);
// Copy the currently checked items to cfg if (profile.isEmpty()) {
writeConfig(text); profile = profilesComboBox->currentText();
mLauncherConfig->sync(); mLauncherSettings.setValue(QString("Profiles/currentprofile"), profile);
mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(text));
} }
mLauncherSettings.remove(QString("Profiles/") + profile + QString("/master"));
mLauncherSettings.remove(QString("Profiles/") + profile + QString("/plugin"));
mGameSettings.remove(QString("master"));
mGameSettings.remove(QString("plugin"));
QStringList items = mDataFilesModel->checkedItems();
foreach(const QString &item, items) {
if (item.endsWith(QString(".esm"), Qt::CaseInsensitive)) {
mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/master"), item);
mGameSettings.setMultiValue(QString("master"), item);
} else if (item.endsWith(QString(".esp"), Qt::CaseInsensitive)) {
mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/plugin"), item);
mGameSettings.setMultiValue(QString("plugin"), item);
}
}
} }
void DataFilesPage::updateOkButton(const QString &text) void DataFilesPage::updateOkButton(const QString &text)
{ {
// We do this here because we need the profiles combobox text
if (text.isEmpty()) { if (text.isEmpty()) {
mNewProfileDialog->setOkButtonEnabled(false); mNewProfileDialog->setOkButtonEnabled(false);
return; return;
} }
(mProfilesComboBox->findText(text) == -1) (profilesComboBox->findText(text) == -1)
? mNewProfileDialog->setOkButtonEnabled(true) ? mNewProfileDialog->setOkButtonEnabled(true)
: mNewProfileDialog->setOkButtonEnabled(false); : mNewProfileDialog->setOkButtonEnabled(false);
} }
void DataFilesPage::deleteProfile() void DataFilesPage::updateSplitter()
{ {
QString profile = mProfilesComboBox->currentText(); // Sigh, update the saved splitter size in settings only when moved
// Since getting mSplitter->sizes() if page is hidden returns invalid values
QList<int> sizes = splitter->sizes();
mLauncherSettings.setValue(QString("General/MastersTable/width"), QString::number(sizes.at(0)));
mLauncherSettings.setValue(QString("General/PluginsTable/width"), QString::number(sizes.at(1)));
}
void DataFilesPage::updateViews()
{
// Ensure the columns are hidden because sort() re-enables them
mastersTable->setColumnHidden(1, true);
mastersTable->setColumnHidden(2, true);
mastersTable->setColumnHidden(3, true);
mastersTable->setColumnHidden(4, true);
mastersTable->setColumnHidden(5, true);
mastersTable->setColumnHidden(6, true);
mastersTable->setColumnHidden(7, true);
mastersTable->setColumnHidden(8, true);
pluginsTable->setColumnHidden(1, true);
pluginsTable->setColumnHidden(2, true);
pluginsTable->setColumnHidden(3, true);
pluginsTable->setColumnHidden(4, true);
pluginsTable->setColumnHidden(5, true);
pluginsTable->setColumnHidden(6, true);
pluginsTable->setColumnHidden(7, true);
pluginsTable->setColumnHidden(8, true);
}
void DataFilesPage::setProfilesComboBoxIndex(int index)
{
profilesComboBox->setCurrentIndex(index);
}
void DataFilesPage::slotCurrentIndexChanged(int index)
{
emit profileChanged(index);
}
QAbstractItemModel* DataFilesPage::profilesComboBoxModel()
{
return profilesComboBox->model();
}
int DataFilesPage::profilesComboBoxIndex()
{
return profilesComboBox->currentIndex();
}
void DataFilesPage::on_newProfileAction_triggered()
{
if (mNewProfileDialog->exec() == QDialog::Accepted) {
QString profile = mNewProfileDialog->lineEdit()->text();
profilesComboBox->addItem(profile);
profilesComboBox->setCurrentIndex(profilesComboBox->findText(profile));
}
}
void DataFilesPage::on_deleteProfileAction_triggered()
{
QString profile = profilesComboBox->currentText();
if (profile.isEmpty()) if (profile.isEmpty())
return; return;
@ -456,49 +319,143 @@ void DataFilesPage::deleteProfile()
msgBox.exec(); msgBox.exec();
if (msgBox.clickedButton() == deleteButton) { if (msgBox.clickedButton() == deleteButton) {
// Make sure we have no groups open mLauncherSettings.remove(QString("Profiles/") + profile + QString("/master"));
while (!mLauncherConfig->group().isEmpty()) { mLauncherSettings.remove(QString("Profiles/") + profile + QString("/plugin"));
mLauncherConfig->endGroup();
}
mLauncherConfig->beginGroup("Profiles");
// Open the profile-name subgroup
mLauncherConfig->beginGroup(profile);
mLauncherConfig->remove(""); // Clear the subgroup
mLauncherConfig->endGroup();
mLauncherConfig->endGroup();
// Remove the profile from the combobox // Remove the profile from the combobox
mProfilesComboBox->removeItem(mProfilesComboBox->findText(profile)); profilesComboBox->removeItem(profilesComboBox->findText(profile));
} }
} }
void DataFilesPage::on_checkAction_triggered()
{
if (pluginsTable->hasFocus())
setPluginsCheckstates(Qt::Checked);
if (mastersTable->hasFocus())
setMastersCheckstates(Qt::Checked);
}
void DataFilesPage::on_uncheckAction_triggered()
{
if (pluginsTable->hasFocus())
setPluginsCheckstates(Qt::Unchecked);
if (mastersTable->hasFocus())
setMastersCheckstates(Qt::Unchecked);
}
void DataFilesPage::setMastersCheckstates(Qt::CheckState state)
{
if (!mastersTable->selectionModel()->hasSelection()) {
return;
}
QModelIndexList indexes = mastersTable->selectionModel()->selectedIndexes();
foreach (const QModelIndex &index, indexes)
{
if (!index.isValid())
return;
QModelIndex sourceIndex = mMastersProxyModel->mapToSource(index);
if (!sourceIndex.isValid())
return;
mDataFilesModel->setCheckState(sourceIndex, state);
}
}
void DataFilesPage::setPluginsCheckstates(Qt::CheckState state)
{
if (!pluginsTable->selectionModel()->hasSelection()) {
return;
}
QModelIndexList indexes = pluginsTable->selectionModel()->selectedIndexes();
foreach (const QModelIndex &index, indexes)
{
if (!index.isValid())
return;
QModelIndex sourceIndex = mPluginsProxyModel->mapToSource(
mFilterProxyModel->mapToSource(index));
if (!sourceIndex.isValid())
return;
mDataFilesModel->setCheckState(sourceIndex, state);
}
}
void DataFilesPage::setCheckState(QModelIndex index)
{
if (!index.isValid())
return;
QObject *object = QObject::sender();
// Not a signal-slot call
if (!object)
return;
if (object->objectName() == QLatin1String("PluginsTable")) {
QModelIndex sourceIndex = mPluginsProxyModel->mapToSource(
mFilterProxyModel->mapToSource(index));
if (sourceIndex.isValid()) {
(mDataFilesModel->checkState(sourceIndex) == Qt::Checked)
? mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked)
: mDataFilesModel->setCheckState(sourceIndex, Qt::Checked);
}
}
if (object->objectName() == QLatin1String("MastersTable")) {
QModelIndex sourceIndex = mMastersProxyModel->mapToSource(index);
if (sourceIndex.isValid()) {
(mDataFilesModel->checkState(sourceIndex) == Qt::Checked)
? mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked)
: mDataFilesModel->setCheckState(sourceIndex, Qt::Checked);
}
}
return;
}
void DataFilesPage::filterChanged(const QString filter)
{
QRegExp regExp(filter, Qt::CaseInsensitive, QRegExp::FixedString);
mFilterProxyModel->setFilterRegExp(regExp);
}
void DataFilesPage::profileChanged(const QString &previous, const QString &current) void DataFilesPage::profileChanged(const QString &previous, const QString &current)
{ {
qDebug() << "Profile is changed from: " << previous << " to " << current;
// Prevent the deletion of the default profile // Prevent the deletion of the default profile
if (current == QLatin1String("Default")) { if (current == QLatin1String("Default")) {
mDeleteProfileAction->setEnabled(false); deleteProfileAction->setEnabled(false);
mProfilesComboBox->setEditEnabled(false); profilesComboBox->setEditEnabled(false);
} else { } else {
mDeleteProfileAction->setEnabled(true); deleteProfileAction->setEnabled(true);
mProfilesComboBox->setEditEnabled(true); profilesComboBox->setEditEnabled(true);
} }
if (!previous.isEmpty()) { if (previous.isEmpty())
writeConfig(previous);
mLauncherConfig->sync();
if (mProfilesComboBox->currentIndex() == -1)
return;
} else {
return; return;
}
mDataFilesList->uncheckAll(); if (profilesComboBox->findText(previous) == -1)
readConfig(); return; // Profile was deleted
// Store the previous profile
mLauncherSettings.setValue(QString("Profiles/currentprofile"), previous);
saveSettings();
mLauncherSettings.setValue(QString("Profiles/currentprofile"), current);
loadSettings();
} }
void DataFilesPage::profileRenamed(const QString &previous, const QString &current) void DataFilesPage::profileRenamed(const QString &previous, const QString &current)
@ -507,27 +464,85 @@ void DataFilesPage::profileRenamed(const QString &previous, const QString &curre
return; return;
// Save the new profile name // Save the new profile name
writeConfig(current); mLauncherSettings.setValue(QString("Profiles/currentprofile"), current);
saveSettings();
// Make sure we have no groups open // Remove the old one
while (!mLauncherConfig->group().isEmpty()) { mLauncherSettings.remove(QString("Profiles/") + previous + QString("/master"));
mLauncherConfig->endGroup(); mLauncherSettings.remove(QString("Profiles/") + previous + QString("/plugin"));
}
mLauncherConfig->beginGroup("Profiles"); // Remove the profile from the combobox
profilesComboBox->removeItem(profilesComboBox->findText(previous));
// Open the profile-name subgroup loadSettings();
mLauncherConfig->beginGroup(previous);
mLauncherConfig->remove(""); // Clear the subgroup
mLauncherConfig->endGroup();
mLauncherConfig->endGroup();
mLauncherConfig->sync();
// Remove the profile from the combobox }
mProfilesComboBox->removeItem(mProfilesComboBox->findText(previous));
void DataFilesPage::showContextMenu(const QPoint &point)
mDataFilesList->uncheckAll(); {
////mMastersModel->uncheckAll(); QObject *object = QObject::sender();
////mPluginsModel->uncheckAll();
readConfig(); // Not a signal-slot call
if (!object)
return;
if (object->objectName() == QLatin1String("PluginsTable")) {
if (!pluginsTable->selectionModel()->hasSelection())
return;
QPoint globalPos = pluginsTable->mapToGlobal(point);
QModelIndexList indexes = pluginsTable->selectionModel()->selectedIndexes();
// Show the check/uncheck actions depending on the state of the selected items
uncheckAction->setEnabled(false);
checkAction->setEnabled(false);
foreach (const QModelIndex &index, indexes)
{
if (!index.isValid())
return;
QModelIndex sourceIndex = mPluginsProxyModel->mapToSource(
mFilterProxyModel->mapToSource(index));
if (!sourceIndex.isValid())
return;
(mDataFilesModel->checkState(sourceIndex) == Qt::Checked)
? uncheckAction->setEnabled(true)
: checkAction->setEnabled(true);
}
// Show menu
mContextMenu->exec(globalPos);
}
if (object->objectName() == QLatin1String("MastersTable")) {
if (!mastersTable->selectionModel()->hasSelection())
return;
QPoint globalPos = mastersTable->mapToGlobal(point);
QModelIndexList indexes = mastersTable->selectionModel()->selectedIndexes();
// Show the check/uncheck actions depending on the state of the selected items
uncheckAction->setEnabled(false);
checkAction->setEnabled(false);
foreach (const QModelIndex &index, indexes)
{
if (!index.isValid())
return;
QModelIndex sourceIndex = mMastersProxyModel->mapToSource(index);
if (!sourceIndex.isValid())
return;
(mDataFilesModel->checkState(sourceIndex) == Qt::Checked)
? uncheckAction->setEnabled(true)
: checkAction->setEnabled(true);
}
mContextMenu->exec(globalPos);
}
} }

View file

@ -3,78 +3,86 @@
#include <QWidget> #include <QWidget>
#include <QModelIndex> #include <QModelIndex>
#include "utils/profilescombobox.hpp"
#include <components/files/collections.hpp>
#include "ui_datafilespage.h"
class QTableView;
class QSortFilterProxyModel; class QSortFilterProxyModel;
class QSettings; class QAbstractItemModel;
class QAction; class QAction;
class QToolBar;
class QMenu; class QMenu;
class ProfilesComboBox;
class DataFilesModel;
class DataFilesModel;
class TextInputDialog; class TextInputDialog;
class DataFilesList; class GameSettings;
class LauncherSettings;
class PluginsProxyModel;
namespace Files { struct ConfigurationManager; } namespace Files { struct ConfigurationManager; }
class DataFilesPage : public QWidget class DataFilesPage : public QWidget, private Ui::DataFilesPage
{ {
Q_OBJECT Q_OBJECT
public: public:
DataFilesPage(Files::ConfigurationManager& cfg, QWidget *parent = 0); DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, LauncherSettings &launcherSettings, QWidget *parent = 0);
ProfilesComboBox *mProfilesComboBox; QAbstractItemModel* profilesComboBoxModel();
int profilesComboBoxIndex();
void writeConfig(QString profile = QString()); void writeConfig(QString profile = QString());
bool showDataFilesWarning(); void saveSettings();
bool setupDataFiles();
signals:
void profileChanged(int index);
public slots: public slots:
void setCheckState(QModelIndex index);
void setProfilesComboBoxIndex(int index);
void filterChanged(const QString filter);
void showContextMenu(const QPoint &point);
void profileChanged(const QString &previous, const QString &current); void profileChanged(const QString &previous, const QString &current);
void profileRenamed(const QString &previous, const QString &current); void profileRenamed(const QString &previous, const QString &current);
void updateOkButton(const QString &text); void updateOkButton(const QString &text);
void updateSplitter();
void updateViews();
// Action slots // Action slots
void newProfile(); void on_newProfileAction_triggered();
void deleteProfile(); void on_deleteProfileAction_triggered();
// void moveUp(); void on_checkAction_triggered();
// void moveDown(); void on_uncheckAction_triggered();
// void moveTop();
// void moveBottom(); private slots:
void slotCurrentIndexChanged(int index);
private: private:
DataFilesList *mDataFilesList; DataFilesModel *mDataFilesModel;
QToolBar *mProfileToolBar; PluginsProxyModel *mPluginsProxyModel;
QSortFilterProxyModel *mMastersProxyModel;
QAction *mNewProfileAction; QSortFilterProxyModel *mFilterProxyModel;
QAction *mDeleteProfileAction;
// QAction *mMoveUpAction; QMenu *mContextMenu;
// QAction *mMoveDownAction;
// QAction *mMoveTopAction;
// QAction *mMoveBottomAction;
Files::ConfigurationManager &mCfgMgr; Files::ConfigurationManager &mCfgMgr;
Files::PathContainer mDataDirs;
Files::PathContainer mDataLocal;
QSettings *mLauncherConfig; GameSettings &mGameSettings;
LauncherSettings &mLauncherSettings;
TextInputDialog *mNewProfileDialog; TextInputDialog *mNewProfileDialog;
// const QStringList checkedPlugins(); void setMastersCheckstates(Qt::CheckState state);
// const QStringList selectedMasters(); void setPluginsCheckstates(Qt::CheckState state);
void createActions(); void createActions();
void setupDataFiles();
void setupConfig(); void setupConfig();
void readConfig(); void readConfig();
void loadSettings();
}; };
#endif #endif

View file

@ -1,16 +1,17 @@
#include "graphicspage.hpp"
#include <QtGui> #include <QtGui>
#include <cstdlib> #include <cstdlib>
#include <boost/math/common_factor.hpp> #include <boost/math/common_factor.hpp>
#include <boost/filesystem.hpp>
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#include <components/files/ogreplugin.hpp> #include <components/files/ogreplugin.hpp>
#include <components/settings/settings.hpp>
#include <components/fileorderlist/utils/naturalsort.hpp> #include <components/fileorderlist/utils/naturalsort.hpp>
#include "graphicspage.hpp" #include "settings/graphicssettings.hpp"
QString getAspect(int x, int y) QString getAspect(int x, int y)
{ {
@ -24,52 +25,22 @@ QString getAspect(int x, int y)
return QString(QString::number(xaspect) + ":" + QString::number(yaspect)); return QString(QString::number(xaspect) + ":" + QString::number(yaspect));
} }
GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, QWidget *parent) GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSetting, QWidget *parent)
: QWidget(parent) : mCfgMgr(cfg)
, mCfgMgr(cfg) , mGraphicsSettings(graphicsSetting)
, QWidget(parent)
{ {
QGroupBox *rendererGroup = new QGroupBox(tr("Renderer"), this); setupUi(this);
QLabel *rendererLabel = new QLabel(tr("Rendering Subsystem:"), rendererGroup); // Set the maximum res we can set in windowed mode
mRendererComboBox = new QComboBox(rendererGroup); QRect res = QApplication::desktop()->screenGeometry();
customWidthSpinBox->setMaximum(res.width());
customHeightSpinBox->setMaximum(res.height());
// Layout for the combobox and label connect(rendererComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(rendererChanged(const QString&)));
QGridLayout *renderSystemLayout = new QGridLayout(); connect(fullScreenCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotFullScreenChanged(int)));
renderSystemLayout->addWidget(rendererLabel, 0, 0, 1, 1); connect(standardRadioButton, SIGNAL(toggled(bool)), this, SLOT(slotStandardToggled(bool)));
renderSystemLayout->addWidget(mRendererComboBox, 0, 1, 1, 1);
// Display
QGroupBox *displayGroup = new QGroupBox(tr("Display"), this);
mVSyncCheckBox = new QCheckBox(tr("Vertical Sync"), displayGroup);
mFullScreenCheckBox = new QCheckBox(tr("Full Screen"), displayGroup);
QLabel *antiAliasingLabel = new QLabel(tr("Antialiasing:"), displayGroup);
QLabel *resolutionLabel = new QLabel(tr("Resolution:"), displayGroup);
mResolutionComboBox = new QComboBox(displayGroup);
mAntiAliasingComboBox = new QComboBox(displayGroup);
QVBoxLayout *rendererGroupLayout = new QVBoxLayout(rendererGroup);
rendererGroupLayout->addLayout(renderSystemLayout);
QGridLayout *displayGroupLayout = new QGridLayout(displayGroup);
displayGroupLayout->addWidget(mVSyncCheckBox, 0, 0, 1, 1);
displayGroupLayout->addWidget(mFullScreenCheckBox, 1, 0, 1, 1);
displayGroupLayout->addWidget(antiAliasingLabel, 2, 0, 1, 1);
displayGroupLayout->addWidget(mAntiAliasingComboBox, 2, 1, 1, 1);
displayGroupLayout->addWidget(resolutionLabel, 3, 0, 1, 1);
displayGroupLayout->addWidget(mResolutionComboBox, 3, 1, 1, 1);
// Layout for the whole page
QVBoxLayout *pageLayout = new QVBoxLayout(this);
QSpacerItem *vSpacer1 = new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Expanding);
pageLayout->addWidget(rendererGroup);
pageLayout->addWidget(displayGroup);
pageLayout->addItem(vSpacer1);
connect(mRendererComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(rendererChanged(const QString&)));
} }
bool GraphicsPage::setupOgre() bool GraphicsPage::setupOgre()
@ -116,11 +87,11 @@ bool GraphicsPage::setupOgre()
#endif #endif
} }
boost::filesystem::path absPluginPath = boost::filesystem::absolute(boost::filesystem::path(pluginDir)); QDir dir(QString::fromStdString(pluginDir));
pluginDir = dir.absolutePath().toStdString();
pluginDir = absPluginPath.string();
Files::loadOgrePlugin(pluginDir, "RenderSystem_GL", *mOgre); Files::loadOgrePlugin(pluginDir, "RenderSystem_GL", *mOgre);
Files::loadOgrePlugin(pluginDir, "RenderSystem_GL3Plus", *mOgre);
Files::loadOgrePlugin(pluginDir, "RenderSystem_Direct3D9", *mOgre); Files::loadOgrePlugin(pluginDir, "RenderSystem_Direct3D9", *mOgre);
#ifdef ENABLE_PLUGIN_GL #ifdef ENABLE_PLUGIN_GL
@ -137,7 +108,7 @@ bool GraphicsPage::setupOgre()
for (Ogre::RenderSystemList::const_iterator r = renderers.begin(); r != renderers.end(); ++r) { for (Ogre::RenderSystemList::const_iterator r = renderers.begin(); r != renderers.end(); ++r) {
mSelectedRenderSystem = *r; mSelectedRenderSystem = *r;
mRendererComboBox->addItem((*r)->getName().c_str()); rendererComboBox->addItem((*r)->getName().c_str());
} }
QString openGLName = QString("OpenGL Rendering Subsystem"); QString openGLName = QString("OpenGL Rendering Subsystem");
@ -153,71 +124,85 @@ bool GraphicsPage::setupOgre()
msgBox.setIcon(QMessageBox::Critical); msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Could not select a valid render system</b><br><br> \ msgBox.setText(tr("<br><b>Could not select a valid render system</b><br><br> \
Please make sure the plugins.cfg file exists and contains a valid rendering plugin.<br>")); Please make sure the plugins.cfg file exists and contains a valid rendering plugin.<br>"));
msgBox.exec(); msgBox.exec();
return false; return false;
} }
// Now fill the GUI elements // Now fill the GUI elements
int index = mRendererComboBox->findText(QString::fromStdString(Settings::Manager::getString("render system", "Video"))); int index = rendererComboBox->findText(mGraphicsSettings.value(QString("Video/render system")));
if ( index != -1) { if ( index != -1) {
mRendererComboBox->setCurrentIndex(index); rendererComboBox->setCurrentIndex(index);
} } else {
else
{
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
mRendererComboBox->setCurrentIndex(mRendererComboBox->findText(direct3DName)); rendererComboBox->setCurrentIndex(rendererComboBox->findText(direct3DName));
#else #else
mRendererComboBox->setCurrentIndex(mRendererComboBox->findText(openGLName)); rendererComboBox->setCurrentIndex(rendererComboBox->findText(openGLName));
#endif #endif
} }
mAntiAliasingComboBox->clear(); antiAliasingComboBox->clear();
mResolutionComboBox->clear(); resolutionComboBox->clear();
mAntiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); antiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem));
mResolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem)); resolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem));
readConfig(); // Load the rest of the values
loadSettings();
return true; return true;
} }
void GraphicsPage::readConfig() void GraphicsPage::loadSettings()
{ {
if (Settings::Manager::getBool("vsync", "Video")) if (mGraphicsSettings.value(QString("Video/vsync")) == QLatin1String("true"))
mVSyncCheckBox->setCheckState(Qt::Checked); vSyncCheckBox->setCheckState(Qt::Checked);
if (Settings::Manager::getBool("fullscreen", "Video")) if (mGraphicsSettings.value(QString("Video/fullscreen")) == QLatin1String("true"))
mFullScreenCheckBox->setCheckState(Qt::Checked); fullScreenCheckBox->setCheckState(Qt::Checked);
int aaIndex = mAntiAliasingComboBox->findText(QString::fromStdString(Settings::Manager::getString("antialiasing", "Video"))); int aaIndex = antiAliasingComboBox->findText(mGraphicsSettings.value(QString("Video/antialiasing")));
if (aaIndex != -1) if (aaIndex != -1)
mAntiAliasingComboBox->setCurrentIndex(aaIndex); antiAliasingComboBox->setCurrentIndex(aaIndex);
QString resolution = QString::number(Settings::Manager::getInt("resolution x", "Video")); QString width = mGraphicsSettings.value(QString("Video/resolution x"));
resolution.append(" x " + QString::number(Settings::Manager::getInt("resolution y", "Video"))); QString height = mGraphicsSettings.value(QString("Video/resolution y"));
QString resolution = width + QString(" x ") + height;
int resIndex = mResolutionComboBox->findText(resolution, Qt::MatchStartsWith); int resIndex = resolutionComboBox->findText(resolution, Qt::MatchStartsWith);
if (resIndex != -1)
mResolutionComboBox->setCurrentIndex(resIndex); if (resIndex != -1) {
standardRadioButton->toggle();
resolutionComboBox->setCurrentIndex(resIndex);
} else {
customRadioButton->toggle();
customWidthSpinBox->setValue(width.toInt());
customHeightSpinBox->setValue(height.toInt());
}
} }
void GraphicsPage::writeConfig() void GraphicsPage::saveSettings()
{ {
Settings::Manager::setBool("vsync", "Video", mVSyncCheckBox->checkState()); vSyncCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/vsync"), QString("true"))
Settings::Manager::setBool("fullscreen", "Video", mFullScreenCheckBox->checkState()); : mGraphicsSettings.setValue(QString("Video/vsync"), QString("false"));
Settings::Manager::setString("antialiasing", "Video", mAntiAliasingComboBox->currentText().toStdString());
Settings::Manager::setString("render system", "Video", mRendererComboBox->currentText().toStdString());
// Get the current resolution, but with the tabs replaced with a single space fullScreenCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("true"))
QString resolution = mResolutionComboBox->currentText().simplified(); : mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("false"));
QStringList tokens = resolution.split(" ", QString::SkipEmptyParts);
int resX = tokens.at(0).toInt(); mGraphicsSettings.setValue(QString("Video/antialiasing"), antiAliasingComboBox->currentText());
int resY = tokens.at(2).toInt(); mGraphicsSettings.setValue(QString("Video/render system"), rendererComboBox->currentText());
Settings::Manager::setInt("resolution x", "Video", resX);
Settings::Manager::setInt("resolution y", "Video", resY);
if (standardRadioButton->isChecked()) {
QRegExp resolutionRe(QString("(\\d+) x (\\d+).*"));
if (resolutionRe.exactMatch(resolutionComboBox->currentText().simplified())) {
mGraphicsSettings.setValue(QString("Video/resolution x"), resolutionRe.cap(1));
mGraphicsSettings.setValue(QString("Video/resolution y"), resolutionRe.cap(2));
}
} else {
mGraphicsSettings.setValue(QString("Video/resolution x"), QString::number(customWidthSpinBox->value()));
mGraphicsSettings.setValue(QString("Video/resolution y"), QString::number(customHeightSpinBox->value()));
}
} }
QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer) QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer)
@ -231,16 +216,14 @@ QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSy
{ {
Ogre::StringVector::iterator opt_it; Ogre::StringVector::iterator opt_it;
uint idx = 0; uint idx = 0;
for (opt_it = i->second.possibleValues.begin ();
opt_it != i->second.possibleValues.end (); opt_it++, idx++)
{
if (strcmp (key.toStdString().c_str(), i->first.c_str()) == 0) for (opt_it = i->second.possibleValues.begin();
{ opt_it != i->second.possibleValues.end(); opt_it++, idx++)
{
if (strcmp (key.toStdString().c_str(), i->first.c_str()) == 0) {
result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromStdString((*opt_it).c_str()).simplified(); result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromStdString((*opt_it).c_str()).simplified();
} }
} }
} }
// Sort ascending // Sort ascending
@ -257,7 +240,7 @@ QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSy
QStringList GraphicsPage::getAvailableResolutions(Ogre::RenderSystem *renderer) QStringList GraphicsPage::getAvailableResolutions(Ogre::RenderSystem *renderer)
{ {
QString key ("Video Mode"); QString key("Video Mode");
QStringList result; QStringList result;
uint row = 0; uint row = 0;
@ -274,24 +257,26 @@ QStringList GraphicsPage::getAvailableResolutions(Ogre::RenderSystem *renderer)
for (opt_it = i->second.possibleValues.begin (); for (opt_it = i->second.possibleValues.begin ();
opt_it != i->second.possibleValues.end (); opt_it++, idx++) opt_it != i->second.possibleValues.end (); opt_it++, idx++)
{ {
QString qval = QString::fromStdString(*opt_it).simplified(); QRegExp resolutionRe(QString("(\\d+) x (\\d+)"));
// remove extra tokens after the resolution (for example bpp, can be there or not depending on rendersystem) QString resolution = QString::fromStdString(*opt_it).simplified();
QStringList tokens = qval.split(" ", QString::SkipEmptyParts);
assert (tokens.size() >= 3);
QString resolutionStr = tokens.at(0) + QString(" x ") + tokens.at(2);
QString aspect = getAspect(tokens.at(0).toInt(),tokens.at(2).toInt()); if (resolutionRe.exactMatch(resolution)) {
if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10")) { int width = resolutionRe.cap(1).toInt();
resolutionStr.append(tr("\t(Widescreen ") + aspect + ")"); int height = resolutionRe.cap(2).toInt();
} else if (aspect == QLatin1String("4:3")) { QString aspect = getAspect(width, height);
resolutionStr.append(tr("\t(Standard 4:3)"));
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)"));
}
// do not add duplicate resolutions
if (!result.contains(resolution))
result.append(resolution);
} }
// do not add duplicate resolutions
if (!result.contains(resolutionStr))
result << resolutionStr;
} }
} }
@ -305,9 +290,36 @@ void GraphicsPage::rendererChanged(const QString &renderer)
{ {
mSelectedRenderSystem = mOgre->getRenderSystemByName(renderer.toStdString()); mSelectedRenderSystem = mOgre->getRenderSystemByName(renderer.toStdString());
mAntiAliasingComboBox->clear(); antiAliasingComboBox->clear();
mResolutionComboBox->clear(); resolutionComboBox->clear();
mAntiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); antiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem));
mResolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem)); resolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem));
}
void GraphicsPage::slotFullScreenChanged(int state)
{
if (state == Qt::Checked) {
standardRadioButton->toggle();
customRadioButton->setEnabled(false);
customWidthSpinBox->setEnabled(false);
customHeightSpinBox->setEnabled(false);
} else {
customRadioButton->setEnabled(true);
customWidthSpinBox->setEnabled(true);
customHeightSpinBox->setEnabled(true);
}
}
void GraphicsPage::slotStandardToggled(bool checked)
{
if (checked) {
resolutionComboBox->setEnabled(true);
customWidthSpinBox->setEnabled(false);
customHeightSpinBox->setEnabled(false);
} else {
resolutionComboBox->setEnabled(false);
customWidthSpinBox->setEnabled(true);
customHeightSpinBox->setEnabled(true);
}
} }

View file

@ -5,8 +5,8 @@
#include <OgreRoot.h> #include <OgreRoot.h>
#include <OgreRenderSystem.h> #include <OgreRenderSystem.h>
#include <OgreConfigFile.h> //#include <OgreConfigFile.h>
#include <OgreConfigDialog.h> //#include <OgreConfigDialog.h>
// Static plugin headers // Static plugin headers
#ifdef ENABLE_PLUGIN_GL #ifdef ENABLE_PLUGIN_GL
@ -16,26 +16,29 @@
# include "OgreD3D9Plugin.h" # include "OgreD3D9Plugin.h"
#endif #endif
class QComboBox; #include "ui_graphicspage.h"
class QCheckBox;
class QStackedWidget; class GraphicsSettings;
class QSettings;
namespace Files { struct ConfigurationManager; } namespace Files { struct ConfigurationManager; }
class GraphicsPage : public QWidget class GraphicsPage : public QWidget, private Ui::GraphicsPage
{ {
Q_OBJECT Q_OBJECT
public: public:
GraphicsPage(Files::ConfigurationManager &cfg, QWidget *parent = 0); GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSettings, QWidget *parent = 0);
void saveSettings();
bool setupOgre(); bool setupOgre();
void writeConfig();
public slots: public slots:
void rendererChanged(const QString &renderer); void rendererChanged(const QString &renderer);
private slots:
void slotFullScreenChanged(int state);
void slotStandardToggled(bool checked);
private: private:
Ogre::Root *mOgre; Ogre::Root *mOgre;
Ogre::RenderSystem *mSelectedRenderSystem; Ogre::RenderSystem *mSelectedRenderSystem;
@ -48,22 +51,14 @@ private:
Ogre::D3D9Plugin* mD3D9Plugin; Ogre::D3D9Plugin* mD3D9Plugin;
#endif #endif
QComboBox *mRendererComboBox;
QStackedWidget *mDisplayStackedWidget;
QComboBox *mAntiAliasingComboBox;
QComboBox *mResolutionComboBox;
QCheckBox *mVSyncCheckBox;
QCheckBox *mFullScreenCheckBox;
Files::ConfigurationManager &mCfgMgr; Files::ConfigurationManager &mCfgMgr;
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(Ogre::RenderSystem *renderer);
void createPages(); void loadSettings();
void readConfig();
}; };
#endif #endif

View file

@ -1,6 +1,6 @@
#include <QApplication> #include <QApplication>
#include <QTextCodec>
#include <QDir> #include <QDir>
#include <QFile>
#include "maindialog.hpp" #include "maindialog.hpp"
@ -30,14 +30,17 @@ int main(int argc, char *argv[])
QDir::setCurrent(dir.absolutePath()); QDir::setCurrent(dir.absolutePath());
// Support non-latin characters
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
MainDialog mainWin; MainDialog mainWin;
if (mainWin.setup()) { if (mainWin.setup()) {
mainWin.show(); mainWin.show();
return app.exec(); } else {
return 0;
} }
return 0; return app.exec();
} }

View file

@ -1,52 +1,16 @@
#include "maindialog.hpp"
#include <QtGui> #include <QtGui>
#include "maindialog.hpp" #include "utils/checkablemessagebox.hpp"
#include "playpage.hpp" #include "playpage.hpp"
#include "graphicspage.hpp" #include "graphicspage.hpp"
#include "datafilespage.hpp" #include "datafilespage.hpp"
MainDialog::MainDialog() MainDialog::MainDialog()
: mGameSettings(mCfgMgr)
{ {
QWidget *centralWidget = new QWidget(this);
setCentralWidget(centralWidget);
mIconWidget = new QListWidget(centralWidget);
mIconWidget->setObjectName("IconWidget");
mIconWidget->setViewMode(QListView::IconMode);
mIconWidget->setWrapping(false);
mIconWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Just to be sure
mIconWidget->setIconSize(QSize(48, 48));
mIconWidget->setMovement(QListView::Static);
mIconWidget->setMinimumWidth(400);
mIconWidget->setFixedHeight(80);
mIconWidget->setSpacing(4);
mIconWidget->setCurrentRow(0);
mIconWidget->setFlow(QListView::LeftToRight);
QGroupBox *groupBox = new QGroupBox(centralWidget);
QVBoxLayout *groupLayout = new QVBoxLayout(groupBox);
mPagesWidget = new QStackedWidget(groupBox);
groupLayout->addWidget(mPagesWidget);
QPushButton *playButton = new QPushButton(tr("Play"));
QDialogButtonBox *buttonBox = new QDialogButtonBox(centralWidget);
buttonBox->setStandardButtons(QDialogButtonBox::Close);
buttonBox->addButton(playButton, QDialogButtonBox::AcceptRole);
QVBoxLayout *dialogLayout = new QVBoxLayout(centralWidget);
dialogLayout->addWidget(mIconWidget);
dialogLayout->addWidget(groupBox);
dialogLayout->addWidget(buttonBox);
setWindowTitle(tr("OpenMW Launcher"));
setWindowIcon(QIcon(":/images/openmw.png"));
// Remove what's this? button
setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
setMinimumSize(QSize(575, 575));
// Install the stylesheet font // Install the stylesheet font
QFile file; QFile file;
QFontDatabase fontDatabase; QFontDatabase fontDatabase;
@ -56,64 +20,67 @@ MainDialog::MainDialog()
// Check if the font is installed // Check if the font is installed
if (!fonts.contains("EB Garamond")) { if (!fonts.contains("EB Garamond")) {
QString font = QString::fromStdString((mCfgMgr.getGlobalDataPath() / "resources/mygui/EBGaramond-Regular.ttf").string()); QString font = QString::fromStdString(mCfgMgr.getGlobalDataPath().string()) + QString("resources/mygui/EBGaramond-Regular.ttf");
file.setFileName(font); file.setFileName(font);
if (!file.exists()) { if (!file.exists()) {
font = QString::fromStdString((mCfgMgr.getLocalPath() / "resources/mygui/EBGaramond-Regular.ttf").string()); font = QString::fromStdString(mCfgMgr.getLocalPath().string()) + QString("resources/mygui/EBGaramond-Regular.ttf");
} }
fontDatabase.addApplicationFont(font); fontDatabase.addApplicationFont(font);
} }
// Load the stylesheet setupUi(this);
QString config = QString::fromStdString((mCfgMgr.getGlobalDataPath() / "resources/launcher.qss").string());
file.setFileName(config);
if (!file.exists()) { iconWidget->setViewMode(QListView::IconMode);
file.setFileName(QString::fromStdString((mCfgMgr.getLocalPath() / "launcher.qss").string())); iconWidget->setWrapping(false);
} iconWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Just to be sure
iconWidget->setIconSize(QSize(48, 48));
iconWidget->setMovement(QListView::Static);
file.open(QFile::ReadOnly); iconWidget->setSpacing(4);
QString styleSheet = QLatin1String(file.readAll()); iconWidget->setCurrentRow(0);
qApp->setStyleSheet(styleSheet); iconWidget->setFlow(QListView::LeftToRight);
file.close();
QPushButton *playButton = new QPushButton(tr("Play"));
buttonBox->addButton(playButton, QDialogButtonBox::AcceptRole);
connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(close()));
connect(buttonBox, SIGNAL(accepted()), this, SLOT(play())); connect(buttonBox, SIGNAL(accepted()), this, SLOT(play()));
// Remove what's this? button
setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
createIcons(); createIcons();
createPages();
} }
void MainDialog::createIcons() void MainDialog::createIcons()
{ {
if (!QIcon::hasThemeIcon("document-new")) { if (!QIcon::hasThemeIcon("document-new"))
QIcon::setThemeName("tango"); QIcon::setThemeName("tango");
}
// We create a fallback icon because the default fallback doesn't work // We create a fallback icon because the default fallback doesn't work
QIcon graphicsIcon = QIcon(":/icons/tango/video-display.png"); QIcon graphicsIcon = QIcon(":/icons/tango/video-display.png");
QListWidgetItem *playButton = new QListWidgetItem(mIconWidget); QListWidgetItem *playButton = new QListWidgetItem(iconWidget);
playButton->setIcon(QIcon(":/images/openmw.png")); playButton->setIcon(QIcon(":/images/openmw.png"));
playButton->setText(tr("Play")); playButton->setText(tr("Play"));
playButton->setTextAlignment(Qt::AlignCenter); playButton->setTextAlignment(Qt::AlignCenter);
playButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); playButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
QListWidgetItem *graphicsButton = new QListWidgetItem(mIconWidget); QListWidgetItem *graphicsButton = new QListWidgetItem(iconWidget);
graphicsButton->setIcon(QIcon::fromTheme("video-display", graphicsIcon)); graphicsButton->setIcon(QIcon::fromTheme("video-display", graphicsIcon));
graphicsButton->setText(tr("Graphics")); graphicsButton->setText(tr("Graphics"));
graphicsButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom | Qt::AlignAbsolute); graphicsButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom | Qt::AlignAbsolute);
graphicsButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); graphicsButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
QListWidgetItem *dataFilesButton = new QListWidgetItem(mIconWidget); QListWidgetItem *dataFilesButton = new QListWidgetItem(iconWidget);
dataFilesButton->setIcon(QIcon(":/images/openmw-plugin.png")); dataFilesButton->setIcon(QIcon(":/images/openmw-plugin.png"));
dataFilesButton->setText(tr("Data Files")); dataFilesButton->setText(tr("Data Files"));
dataFilesButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom); dataFilesButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom);
dataFilesButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); dataFilesButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
connect(mIconWidget, connect(iconWidget,
SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
this, SLOT(changePage(QListWidgetItem*,QListWidgetItem*))); this, SLOT(changePage(QListWidgetItem*,QListWidgetItem*)));
@ -122,77 +89,183 @@ void MainDialog::createIcons()
void MainDialog::createPages() void MainDialog::createPages()
{ {
mPlayPage = new PlayPage(this); mPlayPage = new PlayPage(this);
mGraphicsPage = new GraphicsPage(mCfgMgr, this); mGraphicsPage = new GraphicsPage(mCfgMgr, mGraphicsSettings, this);
mDataFilesPage = new DataFilesPage(mCfgMgr, this); mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, mLauncherSettings, this);
// Set the combobox of the play page to imitate the combobox on the datafilespage // Set the combobox of the play page to imitate the combobox on the datafilespage
mPlayPage->mProfilesComboBox->setModel(mDataFilesPage->mProfilesComboBox->model()); mPlayPage->setProfilesComboBoxModel(mDataFilesPage->profilesComboBoxModel());
mPlayPage->mProfilesComboBox->setCurrentIndex(mDataFilesPage->mProfilesComboBox->currentIndex()); mPlayPage->setProfilesComboBoxIndex(mDataFilesPage->profilesComboBoxIndex());
// Add the pages to the stacked widget // Add the pages to the stacked widget
mPagesWidget->addWidget(mPlayPage); pagesWidget->addWidget(mPlayPage);
mPagesWidget->addWidget(mGraphicsPage); pagesWidget->addWidget(mGraphicsPage);
mPagesWidget->addWidget(mDataFilesPage); pagesWidget->addWidget(mDataFilesPage);
// Select the first page // Select the first page
mIconWidget->setCurrentItem(mIconWidget->item(0), QItemSelectionModel::Select); iconWidget->setCurrentItem(iconWidget->item(0), QItemSelectionModel::Select);
connect(mPlayPage->mPlayButton, SIGNAL(clicked()), this, SLOT(play())); connect(mPlayPage, SIGNAL(playButtonClicked()), this, SLOT(play()));
connect(mPlayPage->mProfilesComboBox, connect(mPlayPage, SIGNAL(profileChanged(int)), mDataFilesPage, SLOT(setProfilesComboBoxIndex(int)));
SIGNAL(currentIndexChanged(int)), connect(mDataFilesPage, SIGNAL(profileChanged(int)), mPlayPage, SLOT(setProfilesComboBoxIndex(int)));
mDataFilesPage->mProfilesComboBox, SLOT(setCurrentIndex(int)));
connect(mDataFilesPage->mProfilesComboBox,
SIGNAL(currentIndexChanged(int)),
mPlayPage->mProfilesComboBox, SLOT(setCurrentIndex(int)));
} }
bool MainDialog::showFirstRunDialog()
{
CheckableMessageBox msgBox(this);
msgBox.setWindowTitle(tr("Morrowind installation detected"));
QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxQuestion);
int size = QApplication::style()->pixelMetric(QStyle::PM_MessageBoxIconSize);
msgBox.setIconPixmap(icon.pixmap(size, size));
QAbstractButton *importerButton =
msgBox.addButton(tr("Import"), QDialogButtonBox::AcceptRole); // ActionRole doesn't work?!
QAbstractButton *skipButton =
msgBox.addButton(tr("Skip"), QDialogButtonBox::RejectRole);
Q_UNUSED(skipButton); // Surpress compiler unused warning
msgBox.setStandardButtons(QDialogButtonBox::NoButton);
msgBox.setText(tr("<br><b>An existing Morrowind installation was detected</b><br><br> \
Would you like to import settings from Morrowind.ini?<br>"));
msgBox.setCheckBoxText(tr("Include selected masters and plugins (creates a new profile)"));
msgBox.exec();
if (msgBox.clickedButton() == importerButton) {
QStringList iniPaths;
foreach (const QString &path, mGameSettings.getDataDirs()) {
QDir dir(path);
dir.setPath(dir.canonicalPath()); // Resolve symlinks
if (!dir.cdUp())
continue; // Cannot move from Data Files
if (dir.exists(QString("Morrowind.ini")))
iniPaths.append(dir.absoluteFilePath(QString("Morrowind.ini")));
}
if (iniPaths.isEmpty()) {
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error reading Morrowind configuration file"));
msgBox.setIcon(QMessageBox::Warning);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(QObject::tr("<br><b>Could not find Morrowind.ini</b><br><br> \
The problem may be due to an incomplete installation of Morrowind.<br> \
Reinstalling Morrowind may resolve the problem."));
msgBox.exec();
return false;
}
if (iniPaths.count() > 1) {
// Multiple Morrowind.ini files found
bool ok;
QString path = QInputDialog::getItem(this, tr("Multiple configurations found"),
tr("<br><b>There are multiple Morrowind.ini files found.</b><br><br> \
Please select the one you wish to import from:"), iniPaths, 0, false, &ok);
if (ok && !path.isEmpty()) {
iniPaths.clear();
iniPaths.append(path);
} else {
// Cancel was clicked TODO: should we abort here?
return false;
}
}
// Create the file if it doesn't already exist, else the importer will fail
QString path = QString::fromStdString(mCfgMgr.getUserPath().string()) + QString("openmw.cfg");
QFile file(path);
if (!file.exists()) {
if (!file.open(QIODevice::ReadWrite)) {
// File cannot be created
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error writing OpenMW configuration file"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(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();
return false;
}
file.close();
}
// Construct the arguments to run the importer
QStringList arguments;
if (msgBox.isChecked())
arguments.append(QString("-g"));
arguments.append(iniPaths.first());
arguments.append(path);
if (!startProgram(QString("mwiniimport"), arguments, false))
return false;
// Re-read the game settings
if (!setupGameSettings())
return false;
// Add a new profile
if (msgBox.isChecked()) {
mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), QString("Imported"));
mLauncherSettings.remove(QString("Profiles/Imported/master"));
mLauncherSettings.remove(QString("Profiles/Imported/plugin"));
QStringList masters = mGameSettings.values(QString("master"));
QStringList plugins = mGameSettings.values(QString("plugin"));
foreach (const QString &master, masters) {
mLauncherSettings.setMultiValue(QString("Profiles/Imported/master"), master);
}
foreach (const QString &plugin, plugins) {
mLauncherSettings.setMultiValue(QString("Profiles/Imported/plugin"), plugin);
}
}
}
return true;
}
bool MainDialog::setup() bool MainDialog::setup()
{ {
// Create the settings manager and load default settings file if (!setupLauncherSettings())
const std::string localdefault = (mCfgMgr.getLocalPath() / "settings-default.cfg").string();
const std::string globaldefault = (mCfgMgr.getGlobalPath() / "settings-default.cfg").string();
// prefer local
if (boost::filesystem::exists(localdefault)) {
mSettings.loadDefault(localdefault);
} else if (boost::filesystem::exists(globaldefault)) {
mSettings.loadDefault(globaldefault);
} else {
QMessageBox msgBox;
msgBox.setWindowTitle("Error reading OpenMW configuration file");
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Could not find %0</b><br><br> \
The problem may be due to an incomplete installation of OpenMW.<br> \
Reinstalling OpenMW may resolve the problem.").arg(QString::fromStdString(globaldefault)));
msgBox.exec();
return false; return false;
if (!setupGameSettings())
return false;
if (!setupGraphicsSettings())
return false;
// Check if we need to show the importer
if (mLauncherSettings.value(QString("General/firstrun"), QString("true")) == QLatin1String("true"))
{
if (!showFirstRunDialog())
return false;
} }
// load user settings if they exist, otherwise just load the default settings as user settings // Now create the pages as they need the settings
const std::string settingspath = (mCfgMgr.getUserPath() / "settings.cfg").string(); createPages();
if (boost::filesystem::exists(settingspath)) // Call this so we can exit on Ogre errors before mainwindow is shown
mSettings.loadUser(settingspath); if (!mGraphicsPage->setupOgre())
else if (boost::filesystem::exists(localdefault))
mSettings.loadUser(localdefault);
else if (boost::filesystem::exists(globaldefault))
mSettings.loadUser(globaldefault);
// Setup the Graphics page
if (!mGraphicsPage->setupOgre()) {
return false; return false;
}
// Setup the Data Files page
if (!mDataFilesPage->setupDataFiles()) {
return false;
}
loadSettings();
return true; return true;
} }
@ -201,89 +274,410 @@ void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous)
if (!current) if (!current)
current = previous; current = previous;
mPagesWidget->setCurrentIndex(mIconWidget->row(current)); pagesWidget->setCurrentIndex(iconWidget->row(current));
}
bool MainDialog::setupLauncherSettings()
{
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
QStringList paths;
paths.append(QString("launcher.cfg"));
paths.append(userPath + QString("launcher.cfg"));
foreach (const QString &path, paths) {
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 OpenMW 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 false;
}
QTextStream stream(&file);
stream.setCodec(QTextCodec::codecForName("UTF-8"));
mLauncherSettings.readFile(stream);
}
file.close();
}
return true;
}
bool MainDialog::setupGameSettings()
{
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string());
QStringList paths;
paths.append(userPath + QString("openmw.cfg"));
paths.append(QString("openmw.cfg"));
paths.append(globalPath + QString("openmw.cfg"));
foreach (const QString &path, paths) {
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 OpenMW 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 false;
}
QTextStream stream(&file);
stream.setCodec(QTextCodec::codecForName("UTF-8"));
mGameSettings.readFile(stream);
}
file.close();
}
QStringList dataDirs;
// Check if the paths actually contain data files
foreach (const QString path, mGameSettings.getDataDirs()) {
QDir dir(path);
QStringList filters;
filters << "*.esp" << "*.esm";
if (!dir.entryList(filters).isEmpty())
dataDirs.append(path);
}
if (dataDirs.isEmpty())
{
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error detecting Morrowind installation"));
msgBox.setIcon(QMessageBox::Warning);
msgBox.setStandardButtons(QMessageBox::Cancel);
msgBox.setText(QObject::tr("<br><b>Could not find the Data Files location</b><br><br> \
The directory containing the data files was not found.<br><br> \
Press \"Browse...\" to specify the location manually.<br>"));
QAbstractButton *dirSelectButton =
msgBox.addButton(QObject::tr("B&rowse..."), QMessageBox::ActionRole);
msgBox.exec();
QString selectedFile;
if (msgBox.clickedButton() == dirSelectButton) {
selectedFile = QFileDialog::getOpenFileName(
NULL,
QObject::tr("Select master file"),
QDir::currentPath(),
QString(tr("Morrowind master file (*.esm)")));
}
if (selectedFile.isEmpty())
return false; // Cancel was clicked;
QFileInfo info(selectedFile);
// Add the new dir to the settings file and to the data dir container
mGameSettings.setMultiValue(QString("data"), info.absolutePath());
mGameSettings.addDataDir(info.absolutePath());
}
return true;
}
bool MainDialog::setupGraphicsSettings()
{
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string());
QFile localDefault(QString("settings-default.cfg"));
QFile globalDefault(globalPath + QString("settings-default.cfg"));
if (!localDefault.exists() && !globalDefault.exists()) {
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error reading OpenMW configuration file"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(QObject::tr("<br><b>Could not find settings-default.cfg</b><br><br> \
The problem may be due to an incomplete installation of OpenMW.<br> \
Reinstalling OpenMW may resolve the problem."));
msgBox.exec();
return false;
}
QStringList paths;
paths.append(globalPath + QString("settings-default.cfg"));
paths.append(QString("settings-default.cfg"));
paths.append(userPath + QString("settings.cfg"));
foreach (const QString &path, paths) {
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 OpenMW 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 false;
}
QTextStream stream(&file);
stream.setCodec(QTextCodec::codecForName("UTF-8"));
mGraphicsSettings.readFile(stream);
}
file.close();
}
return true;
}
void MainDialog::loadSettings()
{
int width = mLauncherSettings.value(QString("General/MainWindow/width")).toInt();
int height = mLauncherSettings.value(QString("General/MainWindow/height")).toInt();
int posX = mLauncherSettings.value(QString("General/MainWindow/posx")).toInt();
int posY = mLauncherSettings.value(QString("General/MainWindow/posy")).toInt();
resize(width, height);
move(posX, posY);
}
void MainDialog::saveSettings()
{
QString width = QString::number(this->width());
QString height = QString::number(this->height());
mLauncherSettings.setValue(QString("General/MainWindow/width"), width);
mLauncherSettings.setValue(QString("General/MainWindow/height"), height);
QString posX = QString::number(this->pos().x());
QString posY = QString::number(this->pos().y());
mLauncherSettings.setValue(QString("General/MainWindow/posx"), posX);
mLauncherSettings.setValue(QString("General/MainWindow/posy"), posY);
mLauncherSettings.setValue(QString("General/firstrun"), QString("false"));
}
bool MainDialog::writeSettings()
{
// Now write all config files
saveSettings();
mGraphicsPage->saveSettings();
mDataFilesPage->saveSettings();
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
QDir dir(userPath);
if (!dir.exists()) {
if (!dir.mkpath(userPath)) {
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error creating OpenMW configuration directory"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Could not create %0</b><br><br> \
Please make sure you have the right permissions \
and try again.<br>").arg(userPath));
msgBox.exec();
return false;
}
}
// Game settings
QFile file(userPath + QString("openmw.cfg"));
if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) {
// File cannot be opened or created
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error writing OpenMW configuration file"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(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();
return false;
}
QTextStream stream(&file);
stream.setCodec(QTextCodec::codecForName("UTF-8"));
mGameSettings.writeFile(stream);
file.close();
// Graphics settings
file.setFileName(userPath + QString("settings.cfg"));
if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) {
// File cannot be opened or created
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error writing OpenMW configuration file"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(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();
return false;
}
stream.setDevice(&file);
stream.setCodec(QTextCodec::codecForName("UTF-8"));
mGraphicsSettings.writeFile(stream);
file.close();
// Launcher settings
file.setFileName(userPath + QString("launcher.cfg"));
if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) {
// File cannot be opened or created
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error writing Launcher configuration file"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(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();
return false;
}
stream.setDevice(&file);
stream.setCodec(QTextCodec::codecForName("UTF-8"));
mLauncherSettings.writeFile(stream);
file.close();
return true;
} }
void MainDialog::closeEvent(QCloseEvent *event) void MainDialog::closeEvent(QCloseEvent *event)
{ {
// Now write all config files writeSettings();
mDataFilesPage->writeConfig();
mGraphicsPage->writeConfig();
// Save user settings
const std::string settingspath = (mCfgMgr.getUserPath() / "settings.cfg").string();
mSettings.saveUser(settingspath);
event->accept(); event->accept();
} }
void MainDialog::play() void MainDialog::play()
{ {
// First do a write of all the configs, just to be sure if (!writeSettings())
mDataFilesPage->writeConfig(); qApp->quit();
mGraphicsPage->writeConfig();
// Save user settings // Launch the game detached
const std::string settingspath = (mCfgMgr.getUserPath() / "settings.cfg").string(); startProgram(QString("openmw"), true);
mSettings.saveUser(settingspath); qApp->quit();
}
bool MainDialog::startProgram(const QString &name, const QStringList &arguments, bool detached)
{
QString path = name;
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
QString game = "./openmw.exe"; path.append(QString(".exe"));
QFile file(game);
#elif defined(Q_OS_MAC) #elif defined(Q_OS_MAC)
QDir dir(QCoreApplication::applicationDirPath()); QDir dir(QCoreApplication::applicationDirPath());
QString game = dir.absoluteFilePath("openmw"); path = dir.absoluteFilePath(name);
QFile file(game);
game = "\"" + game + "\"";
#else #else
QString game = "./openmw"; path.prepend(QString("./"));
QFile file(game);
#endif #endif
QFile file(path);
QProcess process; QProcess process;
QFileInfo info(file); QFileInfo info(file);
if (!file.exists()) { if (!file.exists()) {
QMessageBox msgBox; QMessageBox msgBox;
msgBox.setWindowTitle("Error starting OpenMW"); msgBox.setWindowTitle(tr("Error starting executable"));
msgBox.setIcon(QMessageBox::Warning); msgBox.setIcon(QMessageBox::Warning);
msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Could not find OpenMW</b><br><br> \ msgBox.setText(tr("<br><b>Could not find %1</b><br><br> \
The OpenMW application is not found.<br> \ The application is not found.<br> \
Please make sure OpenMW is installed correctly and try again.<br>")); Please make sure OpenMW is installed correctly and try again.<br>").arg(info.fileName()));
msgBox.exec(); msgBox.exec();
return; return false;
} }
if (!info.isExecutable()) { if (!info.isExecutable()) {
QMessageBox msgBox; QMessageBox msgBox;
msgBox.setWindowTitle("Error starting OpenMW"); msgBox.setWindowTitle(tr("Error starting executable"));
msgBox.setIcon(QMessageBox::Warning); msgBox.setIcon(QMessageBox::Warning);
msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Could not start OpenMW</b><br><br> \ msgBox.setText(tr("<br><b>Could not start %1</b><br><br> \
The OpenMW application is not executable.<br> \ The application is not executable.<br> \
Please make sure you have the right permissions and try again.<br>")); Please make sure you have the right permissions and try again.<br>").arg(info.fileName()));
msgBox.exec(); msgBox.exec();
return; return false;
} }
// Start the game // Start the executable
if (!process.startDetached(game)) { if (detached) {
QMessageBox msgBox; if (!process.startDetached(path, arguments)) {
msgBox.setWindowTitle("Error starting OpenMW"); QMessageBox msgBox;
msgBox.setIcon(QMessageBox::Critical); msgBox.setWindowTitle(tr("Error starting executable"));
msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setIcon(QMessageBox::Critical);
msgBox.setText(tr("<br><b>Could not start OpenMW</b><br><br> \ msgBox.setStandardButtons(QMessageBox::Ok);
An error occurred while starting OpenMW.<br><br> \ msgBox.setText(tr("<br><b>Could not start %1</b><br><br> \
Press \"Show Details...\" for more information.<br>")); An error occurred while starting %1.<br><br> \
msgBox.setDetailedText(process.errorString()); Press \"Show Details...\" for more information.<br>").arg(info.fileName()));
msgBox.exec(); msgBox.setDetailedText(process.errorString());
msgBox.exec();
return; return false;
}
} else { } else {
qApp->quit(); process.start(path, arguments);
} if (!process.waitForFinished()) {
} QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error starting executable"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Could not start %1</b><br><br> \
An error occurred while starting %1.<br><br> \
Press \"Show Details...\" for more information.<br>").arg(info.fileName()));
msgBox.setDetailedText(process.errorString());
msgBox.exec();
return false;
}
if (process.exitCode() != 0) {
QString error(process.readAllStandardError());
error.append(tr("\nArguments:\n"));
error.append(arguments.join(" "));
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error running executable"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Executable %1 returned an error</b><br><br> \
An error occurred while running %1.<br><br> \
Press \"Show Details...\" for more information.<br>").arg(info.fileName()));
msgBox.setDetailedText(error);
msgBox.exec();
return false;
}
}
return true;
}

View file

@ -4,7 +4,12 @@
#include <QMainWindow> #include <QMainWindow>
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#include <components/settings/settings.hpp>
#include "settings/gamesettings.hpp"
#include "settings/graphicssettings.hpp"
#include "settings/launchersettings.hpp"
#include "ui_mainwindow.h"
class QListWidget; class QListWidget;
class QListWidgetItem; class QListWidgetItem;
@ -17,32 +22,46 @@ class PlayPage;
class GraphicsPage; class GraphicsPage;
class DataFilesPage; class DataFilesPage;
class MainDialog : public QMainWindow class MainDialog : public QMainWindow, private Ui::MainWindow
{ {
Q_OBJECT Q_OBJECT
public: public:
MainDialog(); MainDialog();
bool setup();
bool showFirstRunDialog();
public slots: public slots:
void changePage(QListWidgetItem *current, QListWidgetItem *previous); void changePage(QListWidgetItem *current, QListWidgetItem *previous);
void play(); void play();
bool setup();
private: private:
void createIcons(); void createIcons();
void createPages(); void createPages();
void closeEvent(QCloseEvent *event);
QListWidget *mIconWidget; bool setupLauncherSettings();
QStackedWidget *mPagesWidget; bool setupGameSettings();
bool setupGraphicsSettings();
void loadSettings();
void saveSettings();
bool writeSettings();
inline bool startProgram(const QString &name, bool detached = false) { return startProgram(name, QStringList(), detached); }
bool startProgram(const QString &name, const QStringList &arguments, bool detached = false);
void closeEvent(QCloseEvent *event);
PlayPage *mPlayPage; PlayPage *mPlayPage;
GraphicsPage *mGraphicsPage; GraphicsPage *mGraphicsPage;
DataFilesPage *mDataFilesPage; DataFilesPage *mDataFilesPage;
Files::ConfigurationManager mCfgMgr; Files::ConfigurationManager mCfgMgr;
Settings::Manager mSettings;
GameSettings mGameSettings;
GraphicsSettings mGraphicsSettings;
LauncherSettings mLauncherSettings;
}; };
#endif #endif

View file

@ -1,43 +1,39 @@
#include <QtGui>
#include "playpage.hpp" #include "playpage.hpp"
#include <QtGui>
PlayPage::PlayPage(QWidget *parent) : QWidget(parent) PlayPage::PlayPage(QWidget *parent) : QWidget(parent)
{ {
QWidget *playWidget = new QWidget(this); setupUi(this);
playWidget->setObjectName("PlayGroup");
playWidget->setFixedSize(QSize(425, 375));
mPlayButton = new QPushButton(tr("Play"), playWidget);
mPlayButton->setObjectName("PlayButton");
mPlayButton->setMinimumSize(QSize(200, 50));
QLabel *profileLabel = new QLabel(tr("Current Profile:"), playWidget);
profileLabel->setObjectName("ProfileLabel");
// Hacks to get the stylesheet look properly
#ifdef Q_OS_MAC
QPlastiqueStyle *style = new QPlastiqueStyle; QPlastiqueStyle *style = new QPlastiqueStyle;
mProfilesComboBox = new QComboBox(playWidget); profilesComboBox->setStyle(style);
mProfilesComboBox->setObjectName("ProfilesComboBox"); #endif
mProfilesComboBox->setStyle(style); profilesComboBox->setView(new QListView());
QGridLayout *playLayout = new QGridLayout(playWidget); connect(profilesComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentIndexChanged(int)));
connect(playButton, SIGNAL(clicked()), this, SLOT(slotPlayClicked()));
QSpacerItem *hSpacer1 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); }
QSpacerItem *hSpacer2 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
QSpacerItem *vSpacer1 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); void PlayPage::setProfilesComboBoxModel(QAbstractItemModel *model)
QSpacerItem *vSpacer2 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); {
profilesComboBox->setModel(model);
}
playLayout->addWidget(mPlayButton, 1, 1, 1, 1); void PlayPage::setProfilesComboBoxIndex(int index)
playLayout->addWidget(profileLabel, 2, 1, 1, 1); {
playLayout->addWidget(mProfilesComboBox, 3, 1, 1, 1); profilesComboBox->setCurrentIndex(index);
playLayout->addItem(hSpacer1, 2, 0, 1, 1); }
playLayout->addItem(hSpacer2, 2, 2, 1, 1);
playLayout->addItem(vSpacer1, 0, 1, 1, 1);
playLayout->addItem(vSpacer2, 4, 1, 1, 1);
QHBoxLayout *pageLayout = new QHBoxLayout(this); void PlayPage::slotCurrentIndexChanged(int index)
{
emit profileChanged(index);
}
pageLayout->addWidget(playWidget); void PlayPage::slotPlayClicked()
{
} emit playButtonClicked();
}

View file

@ -3,19 +3,33 @@
#include <QWidget> #include <QWidget>
#include "ui_playpage.h"
class QComboBox; class QComboBox;
class QPushButton; class QPushButton;
class QAbstractItemModel;
class PlayPage : public QWidget class PlayPage : public QWidget, private Ui::PlayPage
{ {
Q_OBJECT Q_OBJECT
public: public:
PlayPage(QWidget *parent = 0); PlayPage(QWidget *parent = 0);
void setProfilesComboBoxModel(QAbstractItemModel *model);
signals:
void profileChanged(int index);
void playButtonClicked();
public slots:
void setProfilesComboBoxIndex(int index);
private slots:
void slotCurrentIndexChanged(int index);
void slotPlayClicked();
QComboBox *mProfilesComboBox;
QPushButton *mPlayButton;
}; };
#endif #endif

View file

@ -1,21 +0,0 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/images">
<file alias="clear.png">resources/images/clear.png</file>
<file alias="down.png">resources/images/down.png</file>
<file alias="openmw.png">resources/images/openmw.png</file>
<file alias="openmw-plugin.png">resources/images/openmw-plugin.png</file>
<file alias="openmw-header.png">resources/images/openmw-header.png</file>
<file alias="playpage-background.png">resources/images/playpage-background.png</file>
</qresource>
<qresource prefix="icons/tango">
<file alias="index.theme">resources/icons/tango/index.theme</file>
<file alias="video-display.png">resources/icons/tango/video-display.png</file>
<file alias="16x16/document-new.png">resources/icons/tango/document-new.png</file>
<file alias="16x16/edit-copy.png">resources/icons/tango/edit-copy.png</file>
<file alias="16x16/edit-delete.png">resources/icons/tango/edit-delete.png</file>
<file alias="16x16/go-bottom.png">resources/icons/tango/go-bottom.png</file>
<file alias="16x16/go-down.png">resources/icons/tango/go-down.png</file>
<file alias="16x16/go-top.png">resources/icons/tango/go-top.png</file>
<file alias="16x16/go-up.png">resources/icons/tango/go-up.png</file>
</qresource>
</RCC>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 644 B

View file

@ -0,0 +1,177 @@
#include "gamesettings.hpp"
#include <QTextStream>
#include <QDir>
#include <QString>
#include <QRegExp>
#include <QMap>
#include <QDebug>
#include <components/files/configurationmanager.hpp>
#include <boost/version.hpp>
/**
* Workaround for problems with whitespaces in paths in older versions of Boost library
*/
#if (BOOST_VERSION <= 104600)
namespace boost
{
template<>
inline boost::filesystem::path lexical_cast<boost::filesystem::path, std::string>(const std::string& arg)
{
return boost::filesystem::path(arg);
}
} /* namespace boost */
#endif /* (BOOST_VERSION <= 104600) */
GameSettings::GameSettings(Files::ConfigurationManager &cfg)
: mCfgMgr(cfg)
{
}
GameSettings::~GameSettings()
{
}
void GameSettings::validatePaths()
{
if (mSettings.isEmpty() || !mDataDirs.isEmpty())
return; // Don't re-validate paths if they are already parsed
QStringList paths = mSettings.values(QString("data"));
Files::PathContainer dataDirs;
foreach (const QString &path, paths) {
dataDirs.push_back(Files::PathContainer::value_type(path.toStdString()));
}
// Parse the data dirs to convert the tokenized paths
mCfgMgr.processPaths(dataDirs);
mDataDirs.clear();
for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) {
QString path = QString::fromStdString(it->string());
path.remove(QChar('\"'));
QDir dir(path);
if (dir.exists())
mDataDirs.append(path);
}
// Do the same for data-local
QString local = mSettings.value(QString("data-local"));
if (local.isEmpty())
return;
dataDirs.clear();
dataDirs.push_back(Files::PathContainer::value_type(local.toStdString()));
mCfgMgr.processPaths(dataDirs);
if (!dataDirs.empty()) {
QString path = QString::fromStdString(dataDirs.front().string());
path.remove(QChar('\"'));
QDir dir(path);
if (dir.exists())
mDataLocal = path;
}
}
QStringList GameSettings::values(const QString &key, const QStringList &defaultValues)
{
if (!mSettings.values(key).isEmpty())
return mSettings.values(key);
return defaultValues;
}
bool GameSettings::readFile(QTextStream &stream)
{
QMap<QString, QString> cache;
QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$");
while (!stream.atEnd()) {
QString line = stream.readLine().simplified();
if (line.isEmpty() || line.startsWith("#"))
continue;
if (keyRe.indexIn(line) != -1) {
QString key = keyRe.cap(1).simplified();
QString value = keyRe.cap(2).simplified();
// Don't remove existing data entries
if (key != QLatin1String("data"))
mSettings.remove(key);
QStringList values = cache.values(key);
values.append(mSettings.values(key));
if (!values.contains(value)) {
cache.insertMulti(key, value);
}
}
}
if (mSettings.isEmpty()) {
mSettings = cache; // This is the first time we read a file
validatePaths();
return true;
}
// Merge the changed keys with those which didn't
mSettings.unite(cache);
validatePaths();
return true;
}
bool GameSettings::writeFile(QTextStream &stream)
{
// Iterate in reverse order to preserve insertion order
QMapIterator<QString, QString> i(mSettings);
i.toBack();
while (i.hasPrevious()) {
i.previous();
if (i.key() == QLatin1String("master") || i.key() == QLatin1String("plugin"))
continue;
// Quote paths with spaces
if (i.key() == QLatin1String("data")
|| i.key() == QLatin1String("data-local")
|| i.key() == QLatin1String("resources"))
{
if (i.value().contains(QChar(' ')))
{
QString stripped = i.value();
stripped.remove(QChar('\"')); // Remove quotes
stream << i.key() << "=\"" << stripped << "\"\n";
continue;
}
}
stream << i.key() << "=" << i.value() << "\n";
}
QStringList masters = mSettings.values(QString("master"));
for (int i = masters.count(); i--;) {
stream << "master=" << masters.at(i) << "\n";
}
QStringList plugins = mSettings.values(QString("plugin"));
for (int i = plugins.count(); i--;) {
stream << "plugin=" << plugins.at(i) << "\n";
}
return true;
}

View file

@ -0,0 +1,61 @@
#ifndef GAMESETTINGS_HPP
#define GAMESETTINGS_HPP
#include <QTextStream>
#include <QStringList>
#include <QString>
#include <QMap>
#include <boost/filesystem/path.hpp>
namespace Files { typedef std::vector<boost::filesystem::path> PathContainer;
struct ConfigurationManager;}
class GameSettings
{
public:
GameSettings(Files::ConfigurationManager &cfg);
~GameSettings();
inline QString value(const QString &key, const QString &defaultValue = QString())
{
return mSettings.value(key).isEmpty() ? defaultValue : mSettings.value(key);
}
inline void setValue(const QString &key, const QString &value)
{
mSettings.insert(key, value);
}
inline void setMultiValue(const QString &key, const QString &value)
{
QStringList values = mSettings.values(key);
if (!values.contains(value))
mSettings.insertMulti(key, value);
}
inline void remove(const QString &key)
{
mSettings.remove(key);
}
inline QStringList getDataDirs() { return mDataDirs; }
inline void addDataDir(const QString &dir) { if(!dir.isEmpty()) mDataDirs.append(dir); }
inline QString getDataLocal() {return mDataLocal; }
QStringList values(const QString &key, const QStringList &defaultValues = QStringList());
bool readFile(QTextStream &stream);
bool writeFile(QTextStream &stream);
private:
Files::ConfigurationManager &mCfgMgr;
void validatePaths();
QMap<QString, QString> mSettings;
QStringList mDataDirs;
QString mDataLocal;
};
#endif // GAMESETTINGS_HPP

View file

@ -0,0 +1,44 @@
#include "graphicssettings.hpp"
#include <QTextStream>
#include <QString>
#include <QRegExp>
#include <QMap>
GraphicsSettings::GraphicsSettings()
{
}
GraphicsSettings::~GraphicsSettings()
{
}
bool GraphicsSettings::writeFile(QTextStream &stream)
{
QString sectionPrefix;
QRegExp sectionRe("([^/]+)/(.+)$");
QMap<QString, QString> settings = SettingsBase::getSettings();
QMapIterator<QString, QString> i(settings);
while (i.hasNext()) {
i.next();
QString prefix;
QString key;
if (sectionRe.exactMatch(i.key())) {
prefix = sectionRe.cap(1);
key = sectionRe.cap(2);
}
if (sectionPrefix != prefix) {
sectionPrefix = prefix;
stream << "\n[" << prefix << "]\n";
}
stream << key << " = " << i.value() << "\n";
}
return true;
}

View file

@ -0,0 +1,16 @@
#ifndef GRAPHICSSETTINGS_HPP
#define GRAPHICSSETTINGS_HPP
#include "settingsbase.hpp"
class GraphicsSettings : public SettingsBase<QMap<QString, QString> >
{
public:
GraphicsSettings();
~GraphicsSettings();
bool writeFile(QTextStream &stream);
};
#endif // GRAPHICSSETTINGS_HPP

View file

@ -0,0 +1,101 @@
#include "launchersettings.hpp"
#include <QTextStream>
#include <QString>
#include <QRegExp>
#include <QMap>
LauncherSettings::LauncherSettings()
{
}
LauncherSettings::~LauncherSettings()
{
}
QStringList LauncherSettings::values(const QString &key, Qt::MatchFlags flags)
{
QMap<QString, QString> settings = SettingsBase::getSettings();
if (flags == Qt::MatchExactly)
return settings.values(key);
QStringList result;
if (flags == Qt::MatchStartsWith) {
QStringList keys = settings.keys();
foreach (const QString &currentKey, keys) {
if (currentKey.startsWith(key))
result.append(settings.value(currentKey));
}
}
return result;
}
QStringList LauncherSettings::subKeys(const QString &key)
{
QMap<QString, QString> settings = SettingsBase::getSettings();
QStringList keys = settings.uniqueKeys();
QRegExp keyRe("(.+)/");
QStringList result;
foreach (const QString &currentKey, keys) {
if (keyRe.indexIn(currentKey) != -1) {
QString prefixedKey = keyRe.cap(1);
if(prefixedKey.startsWith(key)) {
QString subKey = prefixedKey.remove(key);
if (!subKey.isEmpty())
result.append(subKey);
}
}
}
result.removeDuplicates();
return result;
}
bool LauncherSettings::writeFile(QTextStream &stream)
{
QString sectionPrefix;
QRegExp sectionRe("([^/]+)/(.+)$");
QMap<QString, QString> settings = SettingsBase::getSettings();
QMapIterator<QString, QString> i(settings);
i.toBack();
while (i.hasPrevious()) {
i.previous();
QString prefix;
QString key;
if (sectionRe.exactMatch(i.key())) {
prefix = sectionRe.cap(1);
key = sectionRe.cap(2);
}
// Get rid of legacy settings
if (key.contains(QChar('\\')))
continue;
if (key == QLatin1String("CurrentProfile"))
continue;
if (sectionPrefix != prefix) {
sectionPrefix = prefix;
stream << "\n[" << prefix << "]\n";
}
stream << key << "=" << i.value() << "\n";
}
return true;
}

View file

@ -0,0 +1,19 @@
#ifndef LAUNCHERSETTINGS_HPP
#define LAUNCHERSETTINGS_HPP
#include "settingsbase.hpp"
class LauncherSettings : public SettingsBase<QMap<QString, QString> >
{
public:
LauncherSettings();
~LauncherSettings();
QStringList subKeys(const QString &key);
QStringList values(const QString &key, Qt::MatchFlags flags = Qt::MatchExactly);
bool writeFile(QTextStream &stream);
};
#endif // LAUNCHERSETTINGS_HPP

View file

@ -0,0 +1,98 @@
#ifndef SETTINGSBASE_HPP
#define SETTINGSBASE_HPP
#include <QTextStream>
#include <QStringList>
#include <QString>
#include <QRegExp>
#include <QMap>
#include <QDebug>
template <class Map>
class SettingsBase
{
public:
SettingsBase() {}
~SettingsBase() {}
inline QString value(const QString &key, const QString &defaultValue = QString())
{
return mSettings.value(key).isEmpty() ? defaultValue : mSettings.value(key);
}
inline void setValue(const QString &key, const QString &value)
{
QStringList values = mSettings.values(key);
if (!values.contains(value))
mSettings.insert(key, value);
}
inline void setMultiValue(const QString &key, const QString &value)
{
QStringList values = mSettings.values(key);
if (!values.contains(value))
mSettings.insertMulti(key, value);
}
inline void remove(const QString &key)
{
mSettings.remove(key);
}
Map getSettings() {return mSettings;}
bool readFile(QTextStream &stream)
{
mCache.clear();
QString sectionPrefix;
QRegExp sectionRe("^\\[([^]]+)\\]");
QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$");
while (!stream.atEnd()) {
QString line = stream.readLine().simplified();
if (line.isEmpty() || line.startsWith("#"))
continue;
if (sectionRe.exactMatch(line)) {
sectionPrefix = sectionRe.cap(1);
sectionPrefix.append("/");
continue;
}
if (keyRe.indexIn(line) != -1) {
QString key = keyRe.cap(1).simplified();
QString value = keyRe.cap(2).simplified();
if (!sectionPrefix.isEmpty())
key.prepend(sectionPrefix);
mSettings.remove(key);
QStringList values = mCache.values(key);
if (!values.contains(value)) {
mCache.insertMulti(key, value);
}
}
}
if (mSettings.isEmpty()) {
mSettings = mCache; // This is the first time we read a file
return true;
}
// Merge the changed keys with those which didn't
mSettings.unite(mCache);
return true;
}
private:
Map mSettings;
Map mCache;
};
#endif // SETTINGSBASE_HPP

View file

@ -0,0 +1,269 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "checkablemessagebox.hpp"
#include <QVariant>
#include <QPushButton>
#include <QAction>
#include <QApplication>
#include <QButtonGroup>
#include <QCheckBox>
#include <QDialog>
#include <QDialogButtonBox>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QLabel>
#include <QSpacerItem>
#include <QVBoxLayout>
/*!
\class Utils::CheckableMessageBox
\brief A messagebox suitable for questions with a
"Do not ask me again" checkbox.
Emulates the QMessageBox API with
static conveniences. The message label can open external URLs.
*/
class CheckableMessageBoxPrivate
{
public:
CheckableMessageBoxPrivate(QDialog *q)
: clickedButton(0)
{
QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
pixmapLabel = new QLabel(q);
sizePolicy.setHorizontalStretch(0);
sizePolicy.setVerticalStretch(0);
sizePolicy.setHeightForWidth(pixmapLabel->sizePolicy().hasHeightForWidth());
pixmapLabel->setSizePolicy(sizePolicy);
pixmapLabel->setVisible(false);
QSpacerItem *pixmapSpacer =
new QSpacerItem(0, 5, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding);
messageLabel = new QLabel(q);
messageLabel->setMinimumSize(QSize(300, 0));
messageLabel->setWordWrap(true);
messageLabel->setOpenExternalLinks(true);
messageLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse);
QSpacerItem *checkBoxRightSpacer =
new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum);
QSpacerItem *buttonSpacer =
new QSpacerItem(0, 1, QSizePolicy::Minimum, QSizePolicy::Minimum);
checkBox = new QCheckBox(q);
checkBox->setText(CheckableMessageBox::tr("Do not ask again"));
buttonBox = new QDialogButtonBox(q);
buttonBox->setOrientation(Qt::Horizontal);
buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
QVBoxLayout *verticalLayout = new QVBoxLayout();
verticalLayout->addWidget(pixmapLabel);
verticalLayout->addItem(pixmapSpacer);
QHBoxLayout *horizontalLayout_2 = new QHBoxLayout();
horizontalLayout_2->addLayout(verticalLayout);
horizontalLayout_2->addWidget(messageLabel);
QHBoxLayout *horizontalLayout = new QHBoxLayout();
horizontalLayout->addWidget(checkBox);
horizontalLayout->addItem(checkBoxRightSpacer);
QVBoxLayout *verticalLayout_2 = new QVBoxLayout(q);
verticalLayout_2->addLayout(horizontalLayout_2);
verticalLayout_2->addLayout(horizontalLayout);
verticalLayout_2->addItem(buttonSpacer);
verticalLayout_2->addWidget(buttonBox);
}
QLabel *pixmapLabel;
QLabel *messageLabel;
QCheckBox *checkBox;
QDialogButtonBox *buttonBox;
QAbstractButton *clickedButton;
};
CheckableMessageBox::CheckableMessageBox(QWidget *parent) :
QDialog(parent),
d(new CheckableMessageBoxPrivate(this))
{
setModal(true);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
connect(d->buttonBox, SIGNAL(accepted()), SLOT(accept()));
connect(d->buttonBox, SIGNAL(rejected()), SLOT(reject()));
connect(d->buttonBox, SIGNAL(clicked(QAbstractButton*)),
SLOT(slotClicked(QAbstractButton*)));
}
CheckableMessageBox::~CheckableMessageBox()
{
delete d;
}
void CheckableMessageBox::slotClicked(QAbstractButton *b)
{
d->clickedButton = b;
}
QAbstractButton *CheckableMessageBox::clickedButton() const
{
return d->clickedButton;
}
QDialogButtonBox::StandardButton CheckableMessageBox::clickedStandardButton() const
{
if (d->clickedButton)
return d->buttonBox->standardButton(d->clickedButton);
return QDialogButtonBox::NoButton;
}
QString CheckableMessageBox::text() const
{
return d->messageLabel->text();
}
void CheckableMessageBox::setText(const QString &t)
{
d->messageLabel->setText(t);
}
QPixmap CheckableMessageBox::iconPixmap() const
{
if (const QPixmap *p = d->pixmapLabel->pixmap())
return QPixmap(*p);
return QPixmap();
}
void CheckableMessageBox::setIconPixmap(const QPixmap &p)
{
d->pixmapLabel->setPixmap(p);
d->pixmapLabel->setVisible(!p.isNull());
}
bool CheckableMessageBox::isChecked() const
{
return d->checkBox->isChecked();
}
void CheckableMessageBox::setChecked(bool s)
{
d->checkBox->setChecked(s);
}
QString CheckableMessageBox::checkBoxText() const
{
return d->checkBox->text();
}
void CheckableMessageBox::setCheckBoxText(const QString &t)
{
d->checkBox->setText(t);
}
bool CheckableMessageBox::isCheckBoxVisible() const
{
return d->checkBox->isVisible();
}
void CheckableMessageBox::setCheckBoxVisible(bool v)
{
d->checkBox->setVisible(v);
}
QDialogButtonBox::StandardButtons CheckableMessageBox::standardButtons() const
{
return d->buttonBox->standardButtons();
}
void CheckableMessageBox::setStandardButtons(QDialogButtonBox::StandardButtons s)
{
d->buttonBox->setStandardButtons(s);
}
QPushButton *CheckableMessageBox::button(QDialogButtonBox::StandardButton b) const
{
return d->buttonBox->button(b);
}
QPushButton *CheckableMessageBox::addButton(const QString &text, QDialogButtonBox::ButtonRole role)
{
return d->buttonBox->addButton(text, role);
}
QDialogButtonBox::StandardButton CheckableMessageBox::defaultButton() const
{
foreach (QAbstractButton *b, d->buttonBox->buttons())
if (QPushButton *pb = qobject_cast<QPushButton *>(b))
if (pb->isDefault())
return d->buttonBox->standardButton(pb);
return QDialogButtonBox::NoButton;
}
void CheckableMessageBox::setDefaultButton(QDialogButtonBox::StandardButton s)
{
if (QPushButton *b = d->buttonBox->button(s)) {
b->setDefault(true);
b->setFocus();
}
}
QDialogButtonBox::StandardButton
CheckableMessageBox::question(QWidget *parent,
const QString &title,
const QString &question,
const QString &checkBoxText,
bool *checkBoxSetting,
QDialogButtonBox::StandardButtons buttons,
QDialogButtonBox::StandardButton defaultButton)
{
CheckableMessageBox mb(parent);
mb.setWindowTitle(title);
mb.setIconPixmap(QMessageBox::standardIcon(QMessageBox::Question));
mb.setText(question);
mb.setCheckBoxText(checkBoxText);
mb.setChecked(*checkBoxSetting);
mb.setStandardButtons(buttons);
mb.setDefaultButton(defaultButton);
mb.exec();
*checkBoxSetting = mb.isChecked();
return mb.clickedStandardButton();
}
QMessageBox::StandardButton CheckableMessageBox::dialogButtonBoxToMessageBoxButton(QDialogButtonBox::StandardButton db)
{
return static_cast<QMessageBox::StandardButton>(int(db));
}

View file

@ -0,0 +1,100 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CHECKABLEMESSAGEBOX_HPP
#define CHECKABLEMESSAGEBOX_HPP
#include <QDialogButtonBox>
#include <QMessageBox>
#include <QDialog>
class CheckableMessageBoxPrivate;
class CheckableMessageBox : public QDialog
{
Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText)
Q_PROPERTY(QPixmap iconPixmap READ iconPixmap WRITE setIconPixmap)
Q_PROPERTY(bool isChecked READ isChecked WRITE setChecked)
Q_PROPERTY(QString checkBoxText READ checkBoxText WRITE setCheckBoxText)
Q_PROPERTY(QDialogButtonBox::StandardButtons buttons READ standardButtons WRITE setStandardButtons)
Q_PROPERTY(QDialogButtonBox::StandardButton defaultButton READ defaultButton WRITE setDefaultButton)
public:
explicit CheckableMessageBox(QWidget *parent);
virtual ~CheckableMessageBox();
static QDialogButtonBox::StandardButton
question(QWidget *parent,
const QString &title,
const QString &question,
const QString &checkBoxText,
bool *checkBoxSetting,
QDialogButtonBox::StandardButtons buttons = QDialogButtonBox::Yes|QDialogButtonBox::No,
QDialogButtonBox::StandardButton defaultButton = QDialogButtonBox::No);
QString text() const;
void setText(const QString &);
bool isChecked() const;
void setChecked(bool s);
QString checkBoxText() const;
void setCheckBoxText(const QString &);
bool isCheckBoxVisible() const;
void setCheckBoxVisible(bool);
QDialogButtonBox::StandardButtons standardButtons() const;
void setStandardButtons(QDialogButtonBox::StandardButtons s);
QPushButton *button(QDialogButtonBox::StandardButton b) const;
QPushButton *addButton(const QString &text, QDialogButtonBox::ButtonRole role);
QDialogButtonBox::StandardButton defaultButton() const;
void setDefaultButton(QDialogButtonBox::StandardButton s);
// See static QMessageBox::standardPixmap()
QPixmap iconPixmap() const;
void setIconPixmap (const QPixmap &p);
// Query the result
QAbstractButton *clickedButton() const;
QDialogButtonBox::StandardButton clickedStandardButton() const;
// Conversion convenience
static QMessageBox::StandardButton dialogButtonBoxToMessageBoxButton(QDialogButtonBox::StandardButton);
private slots:
void slotClicked(QAbstractButton *b);
private:
CheckableMessageBoxPrivate *d;
};
#endif // CHECKABLEMESSAGEBOX_HPP

View file

@ -1,52 +0,0 @@
#include <QRegExpValidator>
#include <QLineEdit>
#include <QString>
#include "profilescombobox.hpp"
ProfilesComboBox::ProfilesComboBox(QWidget *parent) :
QComboBox(parent)
{
mValidator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore
setEditable(true);
setValidator(mValidator);
setCompleter(0);
connect(this, SIGNAL(currentIndexChanged(int)), this,
SLOT(slotIndexChanged(int)));
connect(lineEdit(), SIGNAL(returnPressed()), this,
SLOT(slotReturnPressed()));
}
void ProfilesComboBox::setEditEnabled(bool editable)
{
if (!editable)
return setEditable(false);
// Reset the completer and validator
setEditable(true);
setValidator(mValidator);
setCompleter(0);
}
void ProfilesComboBox::slotReturnPressed()
{
QString current = currentText();
QString previous = itemText(currentIndex());
if (findText(current) != -1)
return;
setItemText(currentIndex(), current);
emit(profileRenamed(previous, current));
}
void ProfilesComboBox::slotIndexChanged(int index)
{
if (index == -1)
return;
emit(profileChanged(mOldProfile, currentText()));
mOldProfile = itemText(index);
}

View file

@ -1,14 +1,14 @@
#include "textinputdialog.hpp"
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QApplication>
#include <QPushButton> #include <QPushButton>
#include <QDebug>
#include <QLabel>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QValidator> #include <QValidator>
#include <QLabel>
#include <components/fileorderlist/utils/lineedit.hpp> #include <components/fileorderlist/utils/lineedit.hpp>
#include "textinputdialog.hpp"
TextInputDialog::TextInputDialog(const QString& title, const QString &text, QWidget *parent) : TextInputDialog::TextInputDialog(const QString& title, const QString &text, QWidget *parent) :
QDialog(parent) QDialog(parent)
{ {
@ -17,9 +17,19 @@ TextInputDialog::TextInputDialog(const QString& title, const QString &text, QWid
mButtonBox->addButton(QDialogButtonBox::Ok); mButtonBox->addButton(QDialogButtonBox::Ok);
mButtonBox->addButton(QDialogButtonBox::Cancel); mButtonBox->addButton(QDialogButtonBox::Cancel);
setMaximumHeight(height()); // Line edit
setOkButtonEnabled(false); QValidator *validator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore
setModal(true); mLineEdit = new LineEdit(this);
mLineEdit->setValidator(validator);
mLineEdit->setCompleter(0);
QLabel *label = new QLabel(this);
label->setText(text);
QVBoxLayout *dialogLayout = new QVBoxLayout(this);
dialogLayout->addWidget(label);
dialogLayout->addWidget(mLineEdit);
dialogLayout->addWidget(mButtonBox);
// Messageboxes on mac have no title // Messageboxes on mac have no title
#ifndef Q_OS_MAC #ifndef Q_OS_MAC
@ -28,22 +38,12 @@ TextInputDialog::TextInputDialog(const QString& title, const QString &text, QWid
Q_UNUSED(title); Q_UNUSED(title);
#endif #endif
QLabel *label = new QLabel(this); setOkButtonEnabled(false);
label->setText(text); setModal(true);
// Line edit
QValidator *validator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore
mLineEdit = new LineEdit(this);
mLineEdit->setValidator(validator);
mLineEdit->setCompleter(0);
QVBoxLayout *dialogLayout = new QVBoxLayout(this);
dialogLayout->addWidget(label);
dialogLayout->addWidget(mLineEdit);
dialogLayout->addWidget(mButtonBox);
connect(mButtonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(mButtonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(mButtonBox, SIGNAL(rejected()), this, SLOT(reject())); connect(mButtonBox, SIGNAL(rejected()), this, SLOT(reject()));
} }
int TextInputDialog::exec() int TextInputDialog::exec()
@ -55,7 +55,17 @@ int TextInputDialog::exec()
void TextInputDialog::setOkButtonEnabled(bool enabled) void TextInputDialog::setOkButtonEnabled(bool enabled)
{ {
QPushButton *okButton = mButtonBox->button(QDialogButtonBox::Ok); QPushButton *okButton = mButtonBox->button(QDialogButtonBox::Ok);
okButton->setEnabled(enabled); okButton->setEnabled(enabled);
QPalette *palette = new QPalette();
palette->setColor(QPalette::Text,Qt::red);
if (enabled) {
mLineEdit->setPalette(QApplication::palette());
} else {
// Existing profile name, make the text red
mLineEdit->setPalette(*palette);
}
} }

View file

@ -1,4 +1,3 @@
set (OPENCS_SRC main.cpp) set (OPENCS_SRC main.cpp)
opencs_units (. editor) opencs_units (. editor)
@ -41,7 +40,7 @@ opencs_units_noqt (model/tools
opencs_units (view/doc opencs_units (view/doc
viewmanager view operations operation subview startup opendialog viewmanager view operations operation subview startup filedialog
) )
@ -76,6 +75,10 @@ set (OPENCS_US
) )
set (OPENCS_RES ../../files/opencs/resources.qrc set (OPENCS_RES ../../files/opencs/resources.qrc
../../files/launcher/launcher.qrc
)
set (OPENCS_UI ../../files/ui/datafilespage.ui
) )
source_group (opencs FILES ${OPENCS_SRC} ${OPENCS_HDR}) source_group (opencs FILES ${OPENCS_SRC} ${OPENCS_HDR})

View file

@ -1,14 +1,12 @@
#include "editor.hpp" #include "editor.hpp"
#include <sstream>
#include <QtGui/QApplication> #include <QtGui/QApplication>
#include "model/doc/document.hpp" #include "model/doc/document.hpp"
#include "model/world/data.hpp" #include "model/world/data.hpp"
CS::Editor::Editor() : mViewManager (mDocumentManager), mNewDocumentIndex (0) CS::Editor::Editor() : mViewManager (mDocumentManager)
{ {
connect (&mViewManager, SIGNAL (newDocumentRequest ()), this, SLOT (createDocument ())); connect (&mViewManager, SIGNAL (newDocumentRequest ()), this, SLOT (createDocument ()));
connect (&mViewManager, SIGNAL (loadDocumentRequest ()), this, SLOT (loadDocument ())); connect (&mViewManager, SIGNAL (loadDocumentRequest ()), this, SLOT (loadDocument ()));
@ -16,47 +14,106 @@ CS::Editor::Editor() : mViewManager (mDocumentManager), mNewDocumentIndex (0)
connect (&mStartup, SIGNAL (createDocument()), this, SLOT (createDocument ())); connect (&mStartup, SIGNAL (createDocument()), this, SLOT (createDocument ()));
connect (&mStartup, SIGNAL (loadDocument()), this, SLOT (loadDocument ())); connect (&mStartup, SIGNAL (loadDocument()), this, SLOT (loadDocument ()));
connect (&mOpenDialog, SIGNAL(accepted()), this, SLOT(openFiles())); connect (&mFileDialog, SIGNAL(openFiles()), this, SLOT(openFiles()));
connect (&mFileDialog, SIGNAL(createNewFile()), this, SLOT(createNewFile()));
setupDataFiles();
}
void CS::Editor::setupDataFiles()
{
boost::program_options::variables_map variables;
boost::program_options::options_description desc;
desc.add_options()
("data", boost::program_options::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")->multitoken())
("data-local", boost::program_options::value<std::string>()->default_value(""))
("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false))
("encoding", boost::program_options::value<std::string>()->default_value("win1252"));
boost::program_options::notify(variables);
mCfgMgr.readConfiguration(variables, desc);
Files::PathContainer mDataDirs, mDataLocal;
if (!variables["data"].empty()) {
mDataDirs = Files::PathContainer(variables["data"].as<Files::PathContainer>());
}
std::string local = variables["data-local"].as<std::string>();
if (!local.empty()) {
mDataLocal.push_back(Files::PathContainer::value_type(local));
}
mCfgMgr.processPaths(mDataDirs);
mCfgMgr.processPaths(mDataLocal);
// Set the charset for reading the esm/esp files
QString encoding = QString::fromStdString(variables["encoding"].as<std::string>());
mFileDialog.setEncoding(encoding);
Files::PathContainer dataDirs;
dataDirs.insert(dataDirs.end(), mDataDirs.begin(), mDataDirs.end());
dataDirs.insert(dataDirs.end(), mDataLocal.begin(), mDataLocal.end());
for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter)
{
QString path = QString::fromStdString(iter->string());
mFileDialog.addFiles(path);
}
} }
void CS::Editor::createDocument() void CS::Editor::createDocument()
{ {
mStartup.hide(); mStartup.hide();
/// \todo open the ESX picker instead mFileDialog.newFile();
std::ostringstream stream;
stream << "NewDocument" << (++mNewDocumentIndex);
std::vector<boost::filesystem::path> files;
files.push_back (stream.str());
CSMDoc::Document *document = mDocumentManager.addDocument (files, true);
mViewManager.addView (document);
} }
void CS::Editor::loadDocument() void CS::Editor::loadDocument()
{ {
mStartup.hide(); mStartup.hide();
mOpenDialog.show();
mOpenDialog.raise(); mFileDialog.openFile();
mOpenDialog.activateWindow();
} }
void CS::Editor::openFiles() void CS::Editor::openFiles()
{ {
std::vector<boost::filesystem::path> paths; std::vector<boost::filesystem::path> files;
mOpenDialog.getFileList(paths); QStringList paths = mFileDialog.checkedItemsPaths();
CSMDoc::Document *document = mDocumentManager.addDocument(paths, false);
foreach (const QString &path, paths) {
files.push_back(path.toStdString());
}
CSMDoc::Document *document = mDocumentManager.addDocument(files, false);
mViewManager.addView (document); mViewManager.addView (document);
mFileDialog.hide();
}
void CS::Editor::createNewFile()
{
std::vector<boost::filesystem::path> files;
QStringList paths = mFileDialog.checkedItemsPaths();
foreach (const QString &path, paths) {
files.push_back(path.toStdString());
}
files.push_back(mFileDialog.fileName().toStdString());
CSMDoc::Document *document = mDocumentManager.addDocument (files, true);
mViewManager.addView (document);
mFileDialog.hide();
} }
int CS::Editor::run() int CS::Editor::run()
{ {
mStartup.show(); mStartup.show();
QApplication::setQuitOnLastWindowClosed (true);
return QApplication::exec(); return QApplication::exec();
} }

View file

@ -3,11 +3,13 @@
#include <QObject> #include <QObject>
#include <components/files/configurationmanager.hpp>
#include "model/doc/documentmanager.hpp" #include "model/doc/documentmanager.hpp"
#include "view/doc/viewmanager.hpp" #include "view/doc/viewmanager.hpp"
#include "view/doc/startup.hpp" #include "view/doc/startup.hpp"
#include "view/doc/opendialog.hpp" #include "view/doc/filedialog.hpp"
namespace CS namespace CS
{ {
@ -15,12 +17,14 @@ namespace CS
{ {
Q_OBJECT Q_OBJECT
int mNewDocumentIndex; ///< \todo remove when the proper new document dialogue is implemented.
CSMDoc::DocumentManager mDocumentManager; CSMDoc::DocumentManager mDocumentManager;
CSVDoc::ViewManager mViewManager; CSVDoc::ViewManager mViewManager;
CSVDoc::StartupDialogue mStartup; CSVDoc::StartupDialogue mStartup;
OpenDialog mOpenDialog; FileDialog mFileDialog;
Files::ConfigurationManager mCfgMgr;
void setupDataFiles();
// not implemented // not implemented
Editor (const Editor&); Editor (const Editor&);
@ -39,7 +43,8 @@ namespace CS
void loadDocument(); void loadDocument();
void openFiles(); void openFiles();
void createNewFile();
}; };
} }
#endif #endif

View file

@ -2,7 +2,7 @@
#include "document.hpp" #include "document.hpp"
#include <cassert> #include <cassert>
#include <QDebug>
void CSMDoc::Document::load (const std::vector<boost::filesystem::path>::const_iterator& begin, void CSMDoc::Document::load (const std::vector<boost::filesystem::path>::const_iterator& begin,
const std::vector<boost::filesystem::path>::const_iterator& end, bool lastAsModified) const std::vector<boost::filesystem::path>::const_iterator& end, bool lastAsModified)
{ {
@ -18,9 +18,6 @@ void CSMDoc::Document::load (const std::vector<boost::filesystem::path>::const_i
if (lastAsModified) if (lastAsModified)
getData().loadFile (*end2, false); getData().loadFile (*end2, false);
addOptionalGmsts();
addOptionalGlobals();
} }
void CSMDoc::Document::addOptionalGmsts() void CSMDoc::Document::addOptionalGmsts()
@ -116,8 +113,7 @@ void CSMDoc::Document::addOptionalGmsts()
{ {
ESM::GameSetting gmst; ESM::GameSetting gmst;
gmst.mId = sFloats[i]; gmst.mId = sFloats[i];
gmst.mF = 0; gmst.mValue.setType (ESM::VT_Float);
gmst.mType = ESM::VT_Float;
addOptionalGmst (gmst); addOptionalGmst (gmst);
} }
@ -125,8 +121,7 @@ void CSMDoc::Document::addOptionalGmsts()
{ {
ESM::GameSetting gmst; ESM::GameSetting gmst;
gmst.mId = sIntegers[i]; gmst.mId = sIntegers[i];
gmst.mI = 0; gmst.mValue.setType (ESM::VT_Int);
gmst.mType = ESM::VT_Long;
addOptionalGmst (gmst); addOptionalGmst (gmst);
} }
@ -134,8 +129,8 @@ void CSMDoc::Document::addOptionalGmsts()
{ {
ESM::GameSetting gmst; ESM::GameSetting gmst;
gmst.mId = sStrings[i]; gmst.mId = sStrings[i];
gmst.mStr = "<no text>"; gmst.mValue.setType (ESM::VT_String);
gmst.mType = ESM::VT_String; gmst.mValue.setString ("<no text>");
addOptionalGmst (gmst); addOptionalGmst (gmst);
} }
} }
@ -154,8 +149,7 @@ void CSMDoc::Document::addOptionalGlobals()
{ {
ESM::Global global; ESM::Global global;
global.mId = sGlobals[i]; global.mId = sGlobals[i];
global.mType = ESM::VT_Int; global.mValue.setType (ESM::VT_Long);
global.mValue = 0;
addOptionalGlobal (global); addOptionalGlobal (global);
} }
} }
@ -192,11 +186,18 @@ void CSMDoc::Document::createBase()
for (int i=0; sGlobals[i]; ++i) for (int i=0; sGlobals[i]; ++i)
{ {
ESM::Global record; ESM::Global record;
record.mId = sGlobals[i]; record.mId = sGlobals[i];
record.mValue = i==0 ? 1 : 0;
record.mType = ESM::VT_Float; record.mValue.setType (i==2 ? ESM::VT_Float : ESM::VT_Int);
if (i==0)
record.mValue.setInteger (1);
getData().getGlobals().add (record); getData().getGlobals().add (record);
} }
/// \todo add GMSTs
} }
CSMDoc::Document::Document (const std::vector<boost::filesystem::path>& files, bool new_) CSMDoc::Document::Document (const std::vector<boost::filesystem::path>& files, bool new_)
@ -211,7 +212,9 @@ CSMDoc::Document::Document (const std::vector<boost::filesystem::path>& files, b
mName = files.back().filename().string(); mName = files.back().filename().string();
if (files.size()>1 || !new_) if (new_ && files.size()==1)
createBase();
else if (files.size()>1)
{ {
std::vector<boost::filesystem::path>::const_iterator end = files.end(); std::vector<boost::filesystem::path>::const_iterator end = files.end();
@ -221,8 +224,8 @@ CSMDoc::Document::Document (const std::vector<boost::filesystem::path>& files, b
load (files.begin(), end, !new_); load (files.begin(), end, !new_);
} }
if (new_ && files.size()==1) addOptionalGmsts();
createBase(); addOptionalGlobals();
connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool))); connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool)));
@ -234,6 +237,9 @@ CSMDoc::Document::Document (const std::vector<boost::filesystem::path>& files, b
connect (&mSaveTimer, SIGNAL(timeout()), this, SLOT (saving())); connect (&mSaveTimer, SIGNAL(timeout()), this, SLOT (saving()));
} }
CSMDoc::Document::~Document()
{}
QUndoStack& CSMDoc::Document::getUndoStack() QUndoStack& CSMDoc::Document::getUndoStack()
{ {
return mUndoStack; return mUndoStack;
@ -287,11 +293,13 @@ void CSMDoc::Document::abortOperation (int type)
} }
} }
void CSMDoc::Document::modificationStateChanged (bool clean) void CSMDoc::Document::modificationStateChanged (bool clean)
{ {
emit stateChanged (getState(), this); emit stateChanged (getState(), this);
} }
void CSMDoc::Document::operationDone (int type) void CSMDoc::Document::operationDone (int type)
{ {
emit stateChanged (getState(), this); emit stateChanged (getState(), this);
@ -305,9 +313,12 @@ void CSMDoc::Document::saving()
if (mSaveCount>15) if (mSaveCount>15)
{ {
//clear the stack before resetting the save state
//to avoid emitting incorrect states
mUndoStack.setClean();
mSaveCount = 0; mSaveCount = 0;
mSaveTimer.stop(); mSaveTimer.stop();
mUndoStack.setClean();
emit stateChanged (getState(), this); emit stateChanged (getState(), this);
} }
} }

View file

@ -63,6 +63,7 @@ namespace CSMDoc
public: public:
Document (const std::vector<boost::filesystem::path>& files, bool new_); Document (const std::vector<boost::filesystem::path>& files, bool new_);
~Document();
QUndoStack& getUndoStack(); QUndoStack& getUndoStack();
@ -105,4 +106,4 @@ namespace CSMDoc
}; };
} }
#endif #endif

View file

@ -30,7 +30,8 @@ namespace CSMWorld
Display_Integer, Display_Integer,
Display_Float, Display_Float,
Display_Var, Display_Var,
Display_VarType Display_GmstVarType,
Display_GlobalVarType
}; };
std::string mTitle; std::string mTitle;

View file

@ -12,13 +12,13 @@ namespace CSMWorld
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
return record.get().mValue; return record.get().mValue.getFloat();
} }
virtual void set (Record<ESXRecordT>& record, const QVariant& data) virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{ {
ESXRecordT record2 = record.get(); ESXRecordT record2 = record.get();
record2.mValue = data.toFloat(); record2.mValue.setFloat (data.toFloat());
record.setModified (record2); record.setModified (record2);
} }
@ -96,17 +96,17 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct VarTypeColumn : public Column<ESXRecordT> struct VarTypeColumn : public Column<ESXRecordT>
{ {
VarTypeColumn() : Column<ESXRecordT> ("Type", ColumnBase::Display_VarType) {} VarTypeColumn (ColumnBase::Display display) : Column<ESXRecordT> ("Type", display) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
return static_cast<int> (record.get().mType); return static_cast<int> (record.get().mValue.getType());
} }
virtual void set (Record<ESXRecordT>& record, const QVariant& data) virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{ {
ESXRecordT record2 = record.get(); ESXRecordT record2 = record.get();
record2.mType = static_cast<ESM::VarType> (data.toInt()); record2.mValue.setType (static_cast<ESM::VarType> (data.toInt()));
record.setModified (record2); record.setModified (record2);
} }
@ -123,11 +123,21 @@ namespace CSMWorld
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
switch (record.get().mType) switch (record.get().mValue.getType())
{ {
case ESM::VT_String: return record.get().mStr.c_str(); break; case ESM::VT_String:
case ESM::VT_Int: return record.get().mI; break;
case ESM::VT_Float: return record.get().mF; break; return record.get().mValue.getString().c_str(); break;
case ESM::VT_Int:
case ESM::VT_Short:
case ESM::VT_Long:
return record.get().mValue.getInteger(); break;
case ESM::VT_Float:
return record.get().mValue.getFloat(); break;
default: return QVariant(); default: return QVariant();
} }
@ -137,11 +147,24 @@ namespace CSMWorld
{ {
ESXRecordT record2 = record.get(); ESXRecordT record2 = record.get();
switch (record2.mType) switch (record2.mValue.getType())
{ {
case ESM::VT_String: record2.mStr = data.toString().toUtf8().constData(); break; case ESM::VT_String:
case ESM::VT_Int: record2.mI = data.toInt(); break;
case ESM::VT_Float: record2.mF = data.toFloat(); break; record2.mValue.setString (data.toString().toUtf8().constData());
break;
case ESM::VT_Int:
case ESM::VT_Short:
case ESM::VT_Long:
record2.mValue.setInteger (data.toInt());
break;
case ESM::VT_Float:
record2.mValue.setFloat (data.toFloat());
break;
default: break; default: break;
} }

View file

@ -6,6 +6,7 @@
#include <QAbstractTableModel> #include <QAbstractTableModel>
#include <components/esm/esmreader.hpp> #include <components/esm/esmreader.hpp>
#include <components/esm/defs.hpp>
#include <components/esm/loadglob.hpp> #include <components/esm/loadglob.hpp>
#include "idtable.hpp" #include "idtable.hpp"
@ -26,12 +27,13 @@ CSMWorld::Data::Data()
mGlobals.addColumn (new StringIdColumn<ESM::Global>); mGlobals.addColumn (new StringIdColumn<ESM::Global>);
mGlobals.addColumn (new RecordStateColumn<ESM::Global>); mGlobals.addColumn (new RecordStateColumn<ESM::Global>);
mGlobals.addColumn (new FixedRecordTypeColumn<ESM::Global> (UniversalId::Type_Global)); mGlobals.addColumn (new FixedRecordTypeColumn<ESM::Global> (UniversalId::Type_Global));
mGlobals.addColumn (new FloatValueColumn<ESM::Global>); mGlobals.addColumn (new VarTypeColumn<ESM::Global> (ColumnBase::Display_GlobalVarType));
mGlobals.addColumn (new VarValueColumn<ESM::Global>);
mGmsts.addColumn (new StringIdColumn<ESM::GameSetting>); mGmsts.addColumn (new StringIdColumn<ESM::GameSetting>);
mGmsts.addColumn (new RecordStateColumn<ESM::GameSetting>); mGmsts.addColumn (new RecordStateColumn<ESM::GameSetting>);
mGmsts.addColumn (new FixedRecordTypeColumn<ESM::GameSetting> (UniversalId::Type_Gmst)); mGmsts.addColumn (new FixedRecordTypeColumn<ESM::GameSetting> (UniversalId::Type_Gmst));
mGmsts.addColumn (new VarTypeColumn<ESM::GameSetting>); mGmsts.addColumn (new VarTypeColumn<ESM::GameSetting> (ColumnBase::Display_GmstVarType));
mGmsts.addColumn (new VarValueColumn<ESM::GameSetting>); mGmsts.addColumn (new VarValueColumn<ESM::GameSetting>);
addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global);

View file

@ -0,0 +1,272 @@
#include "filedialog.hpp"
#include <QCheckBox>
#include <QPushButton>
#include <QDialogButtonBox>
#include <QSortFilterProxyModel>
#include <QRegExpValidator>
#include <QRegExp>
#include <QSpacerItem>
#include <QPushButton>
#include <QLabel>
#include <components/fileorderlist/model/datafilesmodel.hpp>
#include <components/fileorderlist/model/pluginsproxymodel.hpp>
#include <components/fileorderlist/model/esm/esmfile.hpp>
#include <components/fileorderlist/utils/lineedit.hpp>
FileDialog::FileDialog(QWidget *parent) :
QDialog(parent)
{
setupUi(this);
// Models
mDataFilesModel = new DataFilesModel(this);
mMastersProxyModel = new QSortFilterProxyModel();
mMastersProxyModel->setFilterRegExp(QString("^.*\\.esm"));
mMastersProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
mMastersProxyModel->setSourceModel(mDataFilesModel);
mPluginsProxyModel = new PluginsProxyModel();
mPluginsProxyModel->setFilterRegExp(QString("^.*\\.esp"));
mPluginsProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
mPluginsProxyModel->setSourceModel(mDataFilesModel);
mFilterProxyModel = new QSortFilterProxyModel();
mFilterProxyModel->setDynamicSortFilter(true);
mFilterProxyModel->setSourceModel(mPluginsProxyModel);
QCheckBox checkBox;
unsigned int height = checkBox.sizeHint().height() + 4;
mastersTable->setModel(mMastersProxyModel);
mastersTable->setObjectName("MastersTable");
mastersTable->setContextMenuPolicy(Qt::CustomContextMenu);
mastersTable->setSortingEnabled(false);
mastersTable->setSelectionBehavior(QAbstractItemView::SelectRows);
mastersTable->setSelectionMode(QAbstractItemView::ExtendedSelection);
mastersTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
mastersTable->setAlternatingRowColors(true);
mastersTable->horizontalHeader()->setStretchLastSection(true);
// Set the row height to the size of the checkboxes
mastersTable->verticalHeader()->setDefaultSectionSize(height);
mastersTable->verticalHeader()->setResizeMode(QHeaderView::Fixed);
mastersTable->verticalHeader()->hide();
pluginsTable->setModel(mFilterProxyModel);
pluginsTable->setObjectName("PluginsTable");
pluginsTable->setContextMenuPolicy(Qt::CustomContextMenu);
pluginsTable->setSortingEnabled(false);
pluginsTable->setSelectionBehavior(QAbstractItemView::SelectRows);
pluginsTable->setSelectionMode(QAbstractItemView::ExtendedSelection);
pluginsTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
pluginsTable->setAlternatingRowColors(true);
pluginsTable->setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
pluginsTable->horizontalHeader()->setStretchLastSection(true);
pluginsTable->verticalHeader()->setDefaultSectionSize(height);
pluginsTable->verticalHeader()->setResizeMode(QHeaderView::Fixed);
// Hide the profile elements
profileLabel->hide();
profilesComboBox->hide();
newProfileButton->hide();
deleteProfileButton->hide();
// Add some extra widgets
QHBoxLayout *nameLayout = new QHBoxLayout();
QSpacerItem *spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
mNameLabel = new QLabel(tr("File Name:"), this);
QRegExpValidator *validator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9\\s]*$"));
mNameLineEdit = new LineEdit(this);
mNameLineEdit->setValidator(validator);
nameLayout->addSpacerItem(spacer);
nameLayout->addWidget(mNameLabel);
nameLayout->addWidget(mNameLineEdit);
mButtonBox = new QDialogButtonBox(this);
mCreateButton = new QPushButton(tr("Create"), this);
mCreateButton->setEnabled(false);
verticalLayout->addLayout(nameLayout);
verticalLayout->addWidget(mButtonBox);
// Set sizes
QList<int> sizeList;
sizeList << 175;
sizeList << 200;
splitter->setSizes(sizeList);
resize(600, 400);
connect(mDataFilesModel, SIGNAL(layoutChanged()), this, SLOT(updateViews()));
connect(mDataFilesModel, SIGNAL(checkedItemsChanged(QStringList)), this, SLOT(updateOpenButton(QStringList)));
connect(mNameLineEdit, SIGNAL(textChanged(QString)), this, SLOT(updateCreateButton(QString)));
connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString)));
connect(pluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex)));
connect(mastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex)));
connect(mCreateButton, SIGNAL(clicked()), this, SLOT(createButtonClicked()));
connect(mButtonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(mButtonBox, SIGNAL(rejected()), this, SLOT(reject()));
}
void FileDialog::updateViews()
{
// Ensure the columns are hidden because sort() re-enables them
mastersTable->setColumnHidden(1, true);
mastersTable->setColumnHidden(3, true);
mastersTable->setColumnHidden(4, true);
mastersTable->setColumnHidden(5, true);
mastersTable->setColumnHidden(6, true);
mastersTable->setColumnHidden(7, true);
mastersTable->setColumnHidden(8, true);
mastersTable->resizeColumnsToContents();
pluginsTable->setColumnHidden(1, true);
pluginsTable->setColumnHidden(3, true);
pluginsTable->setColumnHidden(4, true);
pluginsTable->setColumnHidden(5, true);
pluginsTable->setColumnHidden(6, true);
pluginsTable->setColumnHidden(7, true);
pluginsTable->setColumnHidden(8, true);
pluginsTable->resizeColumnsToContents();
}
void FileDialog::updateOpenButton(const QStringList &items)
{
QPushButton *openButton = mButtonBox->button(QDialogButtonBox::Open);
if (!openButton)
return;
openButton->setEnabled(!items.isEmpty());
}
void FileDialog::updateCreateButton(const QString &name)
{
if (!mCreateButton->isVisible())
return;
mCreateButton->setEnabled(!name.isEmpty());
}
void FileDialog::filterChanged(const QString &filter)
{
QRegExp filterRe(filter, Qt::CaseInsensitive, QRegExp::FixedString);
mFilterProxyModel->setFilterRegExp(filterRe);
}
void FileDialog::addFiles(const QString &path)
{
mDataFilesModel->addFiles(path);
mDataFilesModel->sort(3); // Sort by date accessed
}
void FileDialog::setEncoding(const QString &encoding)
{
mDataFilesModel->setEncoding(encoding);
}
void FileDialog::setCheckState(QModelIndex index)
{
if (!index.isValid())
return;
QObject *object = QObject::sender();
// Not a signal-slot call
if (!object)
return;
if (object->objectName() == QLatin1String("PluginsTable")) {
QModelIndex sourceIndex = mPluginsProxyModel->mapToSource(
mFilterProxyModel->mapToSource(index));
if (sourceIndex.isValid()) {
(mDataFilesModel->checkState(sourceIndex) == Qt::Checked)
? mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked)
: mDataFilesModel->setCheckState(sourceIndex, Qt::Checked);
}
}
if (object->objectName() == QLatin1String("MastersTable")) {
QModelIndex sourceIndex = mMastersProxyModel->mapToSource(index);
if (sourceIndex.isValid()) {
(mDataFilesModel->checkState(sourceIndex) == Qt::Checked)
? mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked)
: mDataFilesModel->setCheckState(sourceIndex, Qt::Checked);
}
}
return;
}
QStringList FileDialog::checkedItemsPaths()
{
return mDataFilesModel->checkedItemsPaths();
}
QString FileDialog::fileName()
{
return mNameLineEdit->text();
}
void FileDialog::openFile()
{
setWindowTitle(tr("Open"));
mNameLabel->hide();
mNameLineEdit->hide();
mCreateButton->hide();
mButtonBox->removeButton(mCreateButton);
mButtonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Open);
QPushButton *openButton = mButtonBox->button(QDialogButtonBox::Open);
openButton->setEnabled(false);
show();
raise();
activateWindow();
}
void FileDialog::newFile()
{
setWindowTitle(tr("New"));
mNameLabel->show();
mNameLineEdit->clear();
mNameLineEdit->show();
mCreateButton->show();
mButtonBox->setStandardButtons(QDialogButtonBox::Cancel);
mButtonBox->addButton(mCreateButton, QDialogButtonBox::ActionRole);
show();
raise();
activateWindow();
}
void FileDialog::accept()
{
emit openFiles();
}
void FileDialog::createButtonClicked()
{
emit createNewFile();
}

View file

@ -0,0 +1,66 @@
#ifndef FILEDIALOG_HPP
#define FILEDIALOG_HPP
#include <QDialog>
#include <QModelIndex>
#include "ui_datafilespage.h"
class QDialogButtonBox;
class QSortFilterProxyModel;
class QAbstractItemModel;
class QPushButton;
class QStringList;
class QString;
class QMenu;
class DataFilesModel;
class PluginsProxyModel;
class FileDialog : public QDialog, private Ui::DataFilesPage
{
Q_OBJECT
public:
explicit FileDialog(QWidget *parent = 0);
void addFiles(const QString &path);
void setEncoding(const QString &encoding);
void openFile();
void newFile();
void accepted();
QStringList checkedItemsPaths();
QString fileName();
signals:
void openFiles();
void createNewFile();
public slots:
void accept();
private slots:
void updateViews();
void updateOpenButton(const QStringList &items);
void updateCreateButton(const QString &name);
void setCheckState(QModelIndex index);
void filterChanged(const QString &filter);
void createButtonClicked();
private:
QLabel *mNameLabel;
LineEdit *mNameLineEdit;
QPushButton *mCreateButton;
QDialogButtonBox *mButtonBox;
DataFilesModel *mDataFilesModel;
PluginsProxyModel *mPluginsProxyModel;
QSortFilterProxyModel *mMastersProxyModel;
QSortFilterProxyModel *mFilterProxyModel;
};
#endif // FILEDIALOG_HPP

View file

@ -56,7 +56,7 @@ void CSVDoc::Operations::quitOperation (int type)
mLayout->removeItem ((*iter)->getLayout()); mLayout->removeItem ((*iter)->getLayout());
delete *iter; (*iter)->deleteLater();
mOperations.erase (iter); mOperations.erase (iter);
if (oldCount > 1) if (oldCount > 1)

View file

@ -7,6 +7,7 @@
#include <QMenuBar> #include <QMenuBar>
#include <QMdiArea> #include <QMdiArea>
#include <QDockWidget> #include <QDockWidget>
#include <QtGui/QApplication>
#include "../../model/doc/document.hpp" #include "../../model/doc/document.hpp"
@ -39,6 +40,16 @@ void CSVDoc::View::setupFileMenu()
mSave = new QAction (tr ("&Save"), this); mSave = new QAction (tr ("&Save"), this);
connect (mSave, SIGNAL (triggered()), this, SLOT (save())); connect (mSave, SIGNAL (triggered()), this, SLOT (save()));
file->addAction (mSave); file->addAction (mSave);
QAction *close = new QAction (tr ("&Close"), this);
connect (close, SIGNAL (triggered()), this, SLOT (close()));
file->addAction(close);
QAction *exit = new QAction (tr ("&Exit"), this);
connect (exit, SIGNAL (triggered()), this, SLOT (exit()));
connect (this, SIGNAL(exitApplicationRequest(CSVDoc::View *)), &mViewManager, SLOT(exitApplication(CSVDoc::View *)));
file->addAction(exit);
} }
void CSVDoc::View::setupEditMenu() void CSVDoc::View::setupEditMenu()
@ -117,15 +128,15 @@ void CSVDoc::View::updateActions()
mVerify->setEnabled (!(mDocument->getState() & CSMDoc::State_Verifying)); mVerify->setEnabled (!(mDocument->getState() & CSMDoc::State_Verifying));
} }
CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews, QMainWindow *viewParent) CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews)
: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews), QMainWindow (viewParent) : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1),
mViewTotal (totalViews)
{ {
setDockOptions (QMainWindow::AllowNestedDocks);
resize (300, 300); /// \todo get default size from settings and set reasonable minimal size resize (300, 300); /// \todo get default size from settings and set reasonable minimal size
mSubViewWindow = new QMainWindow(); mSubViewWindow.setDockOptions (QMainWindow::AllowNestedDocks);
setCentralWidget (mSubViewWindow);
setCentralWidget (&mSubViewWindow);
mOperations = new Operations; mOperations = new Operations;
addDockWidget (Qt::BottomDockWidgetArea, mOperations); addDockWidget (Qt::BottomDockWidgetArea, mOperations);
@ -200,7 +211,7 @@ 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);
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&)));
@ -239,7 +250,12 @@ void CSVDoc::View::abortOperation (int type)
updateActions(); updateActions();
} }
QDockWidget *CSVDoc::View::getOperations() const CSVDoc::Operations *CSVDoc::View::getOperations() const
{ {
return mOperations; return mOperations;
} }
void CSVDoc::View::exit()
{
emit exitApplicationRequest (this);
}

View file

@ -41,7 +41,8 @@ namespace CSVDoc
std::vector<QAction *> mEditingActions; std::vector<QAction *> mEditingActions;
Operations *mOperations; Operations *mOperations;
SubViewFactoryManager mSubViewFactory; SubViewFactoryManager mSubViewFactory;
QMainWindow* mSubViewWindow; QMainWindow mSubViewWindow;
// not implemented // not implemented
View (const View&); View (const View&);
@ -65,9 +66,12 @@ namespace CSVDoc
void updateActions(); void updateActions();
void exitApplication();
public: public:
View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews, QMainWindow *viewParent); View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews);
///< The ownership of \a document is not transferred to *this. ///< The ownership of \a document is not transferred to *this.
virtual ~View(); virtual ~View();
@ -82,7 +86,7 @@ namespace CSVDoc
void updateProgress (int current, int max, int type, int threads); void updateProgress (int current, int max, int type, int threads);
QDockWidget *getOperations() const; Operations *getOperations() const;
signals: signals:
@ -90,23 +94,28 @@ namespace CSVDoc
void loadDocumentRequest(); void loadDocumentRequest();
void exitApplicationRequest (CSVDoc::View *view);
public slots: public slots:
void addSubView (const CSMWorld::UniversalId& id); void addSubView (const CSMWorld::UniversalId& id);
void abortOperation (int type);
private slots: private slots:
void newView(); void newView();
void save(); void save();
void exit();
void verify(); void verify();
void addGlobalsSubView(); void addGlobalsSubView();
void addGmstsSubView(); void addGmstsSubView();
void abortOperation (int type);
}; };
} }

View file

@ -12,6 +12,11 @@
#include "view.hpp" #include "view.hpp"
#include <QMessageBox>
#include <QPushButton>
#include <QtGui/QApplication>
#include <QDebug>
void CSVDoc::ViewManager::updateIndices() void CSVDoc::ViewManager::updateIndices()
{ {
std::map<CSMDoc::Document *, std::pair<int, int> > documents; std::map<CSMDoc::Document *, std::pair<int, int> > documents;
@ -31,12 +36,15 @@ void CSVDoc::ViewManager::updateIndices()
} }
CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
: mDocumentManager (documentManager) : mDocumentManager (documentManager), mExitOnSaveStateChange(false), mUserWarned(false)
{ {
mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection;
mDelegateFactories->add (CSMWorld::ColumnBase::Display_VarType, mDelegateFactories->add (CSMWorld::ColumnBase::Display_GmstVarType,
new CSVWorld::VarTypeDelegateFactory (ESM::VT_None, ESM::VT_String, ESM::VT_Int, ESM::VT_Float)); new CSVWorld::VarTypeDelegateFactory (ESM::VT_None, ESM::VT_String, ESM::VT_Int, ESM::VT_Float));
mDelegateFactories->add (CSMWorld::ColumnBase::Display_GlobalVarType,
new CSVWorld::VarTypeDelegateFactory (ESM::VT_Short, ESM::VT_Long, ESM::VT_Float));
} }
CSVDoc::ViewManager::~ViewManager() CSVDoc::ViewManager::~ViewManager()
@ -59,9 +67,8 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document)
this, SLOT (progress (int, int, int, int, CSMDoc::Document *))); this, SLOT (progress (int, int, int, int, CSMDoc::Document *)));
} }
QMainWindow *mainWindow = new QMainWindow; View *view = new View (*this, document, countViews (document)+1);
View *view = new View (*this, document, countViews (document)+1, mainWindow);
mViews.push_back (view); mViews.push_back (view);
@ -90,23 +97,143 @@ bool CSVDoc::ViewManager::closeRequest (View *view)
{ {
std::vector<View *>::iterator iter = std::find (mViews.begin(), mViews.end(), view); std::vector<View *>::iterator iter = std::find (mViews.begin(), mViews.end(), view);
bool continueWithClose = true;
if (iter!=mViews.end()) if (iter!=mViews.end())
{ {
bool last = countViews (view->getDocument())<=1; bool last = countViews (view->getDocument())<=1;
/// \todo check if save is in progress -> warn user about possible data loss
/// \todo check if document has not been saved -> return false and start close dialogue
mViews.erase (iter);
view->deleteLater();
if (last) if (last)
mDocumentManager.removeDocument (view->getDocument()); continueWithClose = notifySaveOnClose (view);
else else
{
(*iter)->deleteLater();
mViews.erase (iter);
updateIndices(); updateIndices();
}
} }
return true; return continueWithClose;
}
bool CSVDoc::ViewManager::notifySaveOnClose (CSVDoc::View *view)
{
bool result = true;
CSMDoc::Document *document = view->getDocument();
//notify user of saving in progress
if ( (document->getState() & CSMDoc::State_Saving) )
result = showSaveInProgressMessageBox (view);
//notify user of unsaved changes and process response
else if ( document->getState() & CSMDoc::State_Modified)
result = showModifiedDocumentMessageBox (view);
return result;
}
bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (CSVDoc::View *view)
{
QMessageBox messageBox;
CSMDoc::Document *document = view->getDocument();
messageBox.setText ("The document has been modified.");
messageBox.setInformativeText ("Do you want to save your changes?");
messageBox.setStandardButtons (QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
messageBox.setDefaultButton (QMessageBox::Save);
bool retVal = true;
connect (this, SIGNAL (closeMessageBox()), &messageBox, SLOT (close()));
connect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *)));
mUserWarned = true;
int response = messageBox.exec();
mUserWarned = false;
switch (response)
{
case QMessageBox::Save:
document->save();
mExitOnSaveStateChange = true;
retVal = false;
break;
case QMessageBox::Discard:
disconnect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *)));
break;
case QMessageBox::Cancel:
//disconnect to prevent unintended view closures
disconnect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *)));
retVal = false;
break;
default:
break;
}
return retVal;
}
bool CSVDoc::ViewManager::showSaveInProgressMessageBox (CSVDoc::View *view)
{
QMessageBox messageBox;
CSMDoc::Document *document = view->getDocument();
messageBox.setText ("The document is currently being saved.");
messageBox.setInformativeText("Do you want to close now and abort saving, or wait until saving has completed?");
QPushButton* waitButton = messageBox.addButton (tr("Wait"), QMessageBox::YesRole);
QPushButton* closeButton = messageBox.addButton (tr("Close Now"), QMessageBox::RejectRole);
QPushButton* cancelButton = messageBox.addButton (tr("Cancel"), QMessageBox::NoRole);
messageBox.setDefaultButton (waitButton);
bool retVal = true;
//Connections shut down message box if operation ends before user makes a decision.
connect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *)));
connect (this, SIGNAL (closeMessageBox()), &messageBox, SLOT (close()));
//set / clear the user warned flag to indicate whether or not the message box is currently active.
mUserWarned = true;
messageBox.exec();
mUserWarned = false;
//if closed by the warning handler, defaults to the RejectRole button (closeButton)
if (messageBox.clickedButton() == waitButton)
{
//save the View iterator for shutdown after the save operation ends
mExitOnSaveStateChange = true;
retVal = false;
}
else if (messageBox.clickedButton() == closeButton)
{
//disconnect to avoid segmentation fault
disconnect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *)));
view->abortOperation(CSMDoc::State_Saving);
mExitOnSaveStateChange = true;
}
else if (messageBox.clickedButton() == cancelButton)
{
//abort shutdown, allow save to complete
//disconnection to prevent unintended view closures
mExitOnSaveStateChange = false;
disconnect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *)));
retVal = false;
}
return retVal;
} }
void CSVDoc::ViewManager::documentStateChanged (int state, CSMDoc::Document *document) void CSVDoc::ViewManager::documentStateChanged (int state, CSMDoc::Document *document)
@ -122,3 +249,25 @@ void CSVDoc::ViewManager::progress (int current, int max, int type, int threads,
if ((*iter)->getDocument()==document) if ((*iter)->getDocument()==document)
(*iter)->updateProgress (current, max, type, threads); (*iter)->updateProgress (current, max, type, threads);
} }
void CSVDoc::ViewManager::onExitWarningHandler (int state, CSMDoc::Document *document)
{
if ( !(state & CSMDoc::State_Saving) )
{
//if the user is being warned (message box is active), shut down the message box,
//as there is no save operation currently running
if ( mUserWarned )
emit closeMessageBox();
//otherwise, the user has closed the message box before the save operation ended.
//exit the application
else if (mExitOnSaveStateChange)
QApplication::instance()->exit();
}
}
void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view)
{
if (notifySaveOnClose (view))
QApplication::instance()->exit();
}

View file

@ -27,12 +27,17 @@ namespace CSVDoc
CSMDoc::DocumentManager& mDocumentManager; CSMDoc::DocumentManager& mDocumentManager;
std::vector<View *> mViews; std::vector<View *> mViews;
CSVWorld::CommandDelegateFactoryCollection *mDelegateFactories; CSVWorld::CommandDelegateFactoryCollection *mDelegateFactories;
bool mExitOnSaveStateChange;
bool mUserWarned;
// not implemented // not implemented
ViewManager (const ViewManager&); ViewManager (const ViewManager&);
ViewManager& operator= (const ViewManager&); ViewManager& operator= (const ViewManager&);
void updateIndices(); void updateIndices();
bool notifySaveOnClose (View *view = 0);
bool showModifiedDocumentMessageBox (View *view);
bool showSaveInProgressMessageBox (View *view);
public: public:
@ -54,13 +59,21 @@ namespace CSVDoc
void loadDocumentRequest(); void loadDocumentRequest();
void closeMessageBox();
public slots:
void exitApplication (CSVDoc::View *view);
private slots: private slots:
void documentStateChanged (int state, CSMDoc::Document *document); void documentStateChanged (int state, CSMDoc::Document *document);
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);
}; };
} }
#endif #endif

View file

@ -85,7 +85,7 @@ void CSVWorld::VarTypeDelegateFactory::add (ESM::VarType type)
{ {
{ ESM::VT_None, "empty" }, { ESM::VT_None, "empty" },
{ ESM::VT_Short, "short" }, { ESM::VT_Short, "short" },
{ ESM::VT_Int, "long" }, { ESM::VT_Int, "integer" },
{ ESM::VT_Long, "long" }, { ESM::VT_Long, "long" },
{ ESM::VT_Float, "float" }, { ESM::VT_Float, "float" },
{ ESM::VT_String, "string" }, { ESM::VT_String, "string" },

View file

@ -1,6 +1,8 @@
#ifndef CSV_WORLD_VARTYPEDELEGATE_H #ifndef CSV_WORLD_VARTYPEDELEGATE_H
#define CSV_WORLD_VARTYPEDELEGATE_H #define CSV_WORLD_VARTYPEDELEGATE_H
#include <components/esm/variant.hpp>
#include "enumdelegate.hpp" #include "enumdelegate.hpp"
namespace CSVWorld namespace CSVWorld

View file

@ -16,7 +16,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER})
add_openmw_dir (mwrender add_openmw_dir (mwrender
renderingmanager debugging sky player animation npcanimation creatureanimation activatoranimation renderingmanager debugging sky player animation npcanimation creatureanimation activatoranimation
actors objects renderinginterface localmap occlusionquery terrain terrainmaterial water shadows actors objects renderinginterface localmap occlusionquery terrain terrainmaterial water shadows
compositors characterpreview externalrendering globalmap videoplayer compositors characterpreview externalrendering globalmap videoplayer ripplesimulation refraction
) )
add_openmw_dir (mwinput add_openmw_dir (mwinput
@ -26,11 +26,11 @@ add_openmw_dir (mwinput
add_openmw_dir (mwgui add_openmw_dir (mwgui
text_input widgets race class birth review windowmanagerimp console dialogue text_input widgets race class birth review windowmanagerimp console dialogue
dialogue_history window_base stats_window messagebox journalwindow charactercreation dialogue_history window_base stats_window messagebox journalwindow charactercreation
map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow list map_window window_pinnable_base tooltips scrollwindow bookwindow list
formatting inventorywindow container hud countdialog tradewindow settingswindow formatting inventorywindow container hud countdialog tradewindow settingswindow
confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu
itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog
enchantingdialog trainingwindow travelwindow imagebutton exposedwindow enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor spellicons
) )
add_openmw_dir (mwdialogue add_openmw_dir (mwdialogue

View file

@ -9,16 +9,15 @@
#include <components/bsa/bsa_archive.hpp> #include <components/bsa/bsa_archive.hpp>
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#include <components/translation/translation.hpp> #include <components/translation/translation.hpp>
#include <components/nif/nif_file.hpp> #include <components/nif/niffile.hpp>
#include <components/nifoverrides/nifoverrides.hpp> #include <components/nifoverrides/nifoverrides.hpp>
#include <components/nifbullet/bullet_nif_loader.hpp> #include <components/nifbullet/bulletnifloader.hpp>
#include <components/nifogre/ogre_nif_loader.hpp> #include <components/nifogre/ogrenifloader.hpp>
#include "mwinput/inputmanagerimp.hpp" #include "mwinput/inputmanagerimp.hpp"
#include "mwgui/windowmanagerimp.hpp" #include "mwgui/windowmanagerimp.hpp"
#include "mwgui/cursorreplace.hpp"
#include "mwscript/scriptmanagerimp.hpp" #include "mwscript/scriptmanagerimp.hpp"
#include "mwscript/extensions.hpp" #include "mwscript/extensions.hpp"
@ -63,6 +62,13 @@ void OMW::Engine::setAnimationVerbose(bool animverbose)
{ {
} }
bool OMW::Engine::frameStarted (const Ogre::FrameEvent& evt)
{
if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
MWBase::Environment::get().getWorld()->frameStarted(evt.timeSinceLastFrame);
return true;
}
bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
{ {
try try
@ -143,16 +149,22 @@ OMW::Engine::~Engine()
delete mOgre; delete mOgre;
} }
// Load all BSA files in data directory. // Load BSA files
void OMW::Engine::loadBSA() void OMW::Engine::loadBSA()
{ {
const Files::MultiDirCollection& bsa = mFileCollections.getCollection (".bsa"); for (std::vector<std::string>::const_iterator archive = mArchives.begin(); archive != mArchives.end(); ++archive)
for (Files::MultiDirCollection::TIter iter(bsa.begin()); iter!=bsa.end(); ++iter)
{ {
std::cout << "Adding " << iter->second.string() << std::endl; if (mFileCollections.doesExist(*archive))
Bsa::addBSA(iter->second.string()); {
const std::string archivePath = mFileCollections.getPath(*archive).string();
std::cout << "Adding BSA archive " << archivePath << std::endl;
Bsa::addBSA(archivePath);
}
else
{
std::cout << "Archive " << *archive << " not found" << std::endl;
}
} }
const Files::PathContainer& dataDirs = mFileCollections.getPaths(); const Files::PathContainer& dataDirs = mFileCollections.getPaths();
@ -193,6 +205,11 @@ void OMW::Engine::setDataDirs (const Files::PathContainer& dataDirs)
mFileCollections = Files::Collections (dataDirs, !mFSStrict); mFileCollections = Files::Collections (dataDirs, !mFSStrict);
} }
// Add BSA archive
void OMW::Engine::addArchive (const std::string& archive) {
mArchives.push_back(archive);
}
// Set resource dir // Set resource dir
void OMW::Engine::setResourceDir (const boost::filesystem::path& parResDir) void OMW::Engine::setResourceDir (const boost::filesystem::path& parResDir)
{ {
@ -317,7 +334,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
addResourcesDirectory(mResDir / "mygui"); addResourcesDirectory(mResDir / "mygui");
addResourcesDirectory(mResDir / "water"); addResourcesDirectory(mResDir / "water");
addResourcesDirectory(mResDir / "gbuffer");
addResourcesDirectory(mResDir / "shadows"); addResourcesDirectory(mResDir / "shadows");
addZipResource(mResDir / "mygui" / "Obliviontt.zip"); addZipResource(mResDir / "mygui" / "Obliviontt.zip");
@ -333,9 +349,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
loadBSA(); loadBSA();
// cursor replacer (converts the cursor from the bsa so they can be used by mygui)
MWGui::CursorReplace replacer;
// Create the world // Create the world
mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins, mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins,
mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoder, mFallbackMap, mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoder, mFallbackMap,
@ -440,15 +453,13 @@ void OMW::Engine::go()
if (!mStartupScript.empty()) if (!mStartupScript.empty())
MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript); MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript);
std::cout << "\nPress Q/ESC or close window to exit.\n";
// Start the main rendering loop // Start the main rendering loop
mOgre->start(); mOgre->start();
// Save user settings // Save user settings
settings.saveUser(settingspath); settings.saveUser(settingspath);
std::cout << "Quitting peacefully.\n"; std::cout << "Quitting peacefully." << std::endl;
} }
void OMW::Engine::activate() void OMW::Engine::activate()

View file

@ -64,6 +64,7 @@ namespace OMW
ToUTF8::FromType mEncoding; ToUTF8::FromType mEncoding;
ToUTF8::Utf8Encoder* mEncoder; ToUTF8::Utf8Encoder* mEncoder;
Files::PathContainer mDataDirs; Files::PathContainer mDataDirs;
std::vector<std::string> mArchives;
boost::filesystem::path mResDir; boost::filesystem::path mResDir;
OEngine::Render::OgreRenderer *mOgre; OEngine::Render::OgreRenderer *mOgre;
std::string mCellName; std::string mCellName;
@ -99,12 +100,13 @@ namespace OMW
/// add a .zip resource /// add a .zip resource
void addZipResource (const boost::filesystem::path& path); void addZipResource (const boost::filesystem::path& path);
/// Load all BSA files in data directory. /// Load BSA files
void loadBSA(); void loadBSA();
void executeLocalScripts(); void executeLocalScripts();
virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt); virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt);
virtual bool frameStarted (const Ogre::FrameEvent& evt);
/// Load settings from various files, returns the path to the user settings file /// Load settings from various files, returns the path to the user settings file
std::string loadSettings (Settings::Manager & settings); std::string loadSettings (Settings::Manager & settings);
@ -125,6 +127,9 @@ namespace OMW
/// Set data dirs /// Set data dirs
void setDataDirs(const Files::PathContainer& dataDirs); void setDataDirs(const Files::PathContainer& dataDirs);
/// Add BSA archive
void addArchive(const std::string& archive);
/// Set resource dir /// Set resource dir
void setResourceDir(const boost::filesystem::path& parResDir); void setResourceDir(const boost::filesystem::path& parResDir);

View file

@ -100,6 +100,9 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
("data-local", bpo::value<std::string>()->default_value(""), ("data-local", bpo::value<std::string>()->default_value(""),
"set local data directory (highest priority)") "set local data directory (highest priority)")
("fallback-archive", bpo::value<StringsVector>()->default_value(StringsVector(), "fallback-archive")
->multitoken(), "set fallback BSA archives (later archives have higher priority)")
("resources", bpo::value<std::string>()->default_value("resources"), ("resources", bpo::value<std::string>()->default_value("resources"),
"set resources directory") "set resources directory")
@ -201,6 +204,13 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
engine.setDataDirs(dataDirs); engine.setDataDirs(dataDirs);
// fallback archives
StringsVector archives = variables["fallback-archive"].as<StringsVector>();
for (StringsVector::const_iterator it = archives.begin(); it != archives.end(); it++)
{
engine.addArchive(*it);
}
engine.setResourceDir(variables["resources"].as<std::string>()); engine.setResourceDir(variables["resources"].as<std::string>());
// master and plugin // master and plugin

View file

@ -237,6 +237,8 @@ namespace MWBase
virtual void startEnchanting(MWWorld::Ptr actor) = 0; virtual void startEnchanting(MWWorld::Ptr actor) = 0;
virtual void startTraining(MWWorld::Ptr actor) = 0; virtual void startTraining(MWWorld::Ptr actor) = 0;
virtual void changePointer (const std::string& name) = 0;
virtual const Translation::Storage& getTranslationDataStorage() const = 0; virtual const Translation::Storage& getTranslationDataStorage() const = 0;
}; };
} }

View file

@ -296,6 +296,7 @@ namespace MWBase
virtual bool toggleVanityMode(bool enable, bool force) = 0; virtual bool toggleVanityMode(bool enable, bool force) = 0;
virtual void allowVanityMode(bool allow) = 0; virtual void allowVanityMode(bool allow) = 0;
virtual void togglePlayerLooking(bool enable) = 0; virtual void togglePlayerLooking(bool enable) = 0;
virtual void changeVanityModeScale(float factor) = 0;
virtual void renderPlayer() = 0; virtual void renderPlayer() = 0;
@ -314,6 +315,7 @@ namespace MWBase
/// \todo this does not belong here /// \todo this does not belong here
virtual void playVideo(const std::string& name, bool allowSkipping) = 0; virtual void playVideo(const std::string& name, bool allowSkipping) = 0;
virtual void stopVideo() = 0; virtual void stopVideo() = 0;
virtual void frameStarted (float dt) = 0;
}; };
} }

View file

@ -35,7 +35,7 @@ namespace MWClass
{ {
const std::string model = getModel(ptr); const std::string model = getModel(ptr);
if(!model.empty()) if(!model.empty())
physics.addObject(ptr); physics.addObject(ptr,true);
} }
std::string Apparatus::getModel(const MWWorld::Ptr &ptr) const std::string Apparatus::getModel(const MWWorld::Ptr &ptr) const

View file

@ -38,7 +38,7 @@ namespace MWClass
{ {
const std::string model = getModel(ptr); const std::string model = getModel(ptr);
if(!model.empty()) if(!model.empty())
physics.addObject(ptr); physics.addObject(ptr,true);
} }
std::string Armor::getModel(const MWWorld::Ptr &ptr) const std::string Armor::getModel(const MWWorld::Ptr &ptr) const

View file

@ -33,7 +33,7 @@ namespace MWClass
{ {
const std::string model = getModel(ptr); const std::string model = getModel(ptr);
if(!model.empty()) if(!model.empty())
physics.addObject(ptr); physics.addObject(ptr,true);
} }
std::string Book::getModel(const MWWorld::Ptr &ptr) const std::string Book::getModel(const MWWorld::Ptr &ptr) const

View file

@ -36,7 +36,7 @@ namespace MWClass
{ {
const std::string model = getModel(ptr); const std::string model = getModel(ptr);
if(!model.empty()) if(!model.empty())
physics.addObject(ptr); physics.addObject(ptr,true);
} }
std::string Clothing::getModel(const MWWorld::Ptr &ptr) const std::string Clothing::getModel(const MWWorld::Ptr &ptr) const

View file

@ -132,7 +132,7 @@ namespace MWClass
const MWWorld::Ptr& actor) const const MWWorld::Ptr& actor) const
{ {
if (MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead()) if (MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead())
return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionOpen(ptr)); return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionOpen(ptr, true));
else else
return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionTalk (ptr)); return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionTalk (ptr));
} }

View file

@ -46,7 +46,7 @@ namespace MWClass
{ {
const std::string model = getModel(ptr); const std::string model = getModel(ptr);
if(!model.empty()) if(!model.empty())
physics.addObject(ptr); physics.addObject(ptr,true);
} }
std::string Ingredient::getModel(const MWWorld::Ptr &ptr) const std::string Ingredient::getModel(const MWWorld::Ptr &ptr) const

View file

@ -50,7 +50,7 @@ namespace MWClass
const std::string &model = ref->mBase->mModel; const std::string &model = ref->mBase->mModel;
if(!model.empty()) if(!model.empty())
physics.addObject(ptr); physics.addObject(ptr,ref->mBase->mData.mFlags & ESM::Light::Carry);
if (!ref->mBase->mSound.empty()) if (!ref->mBase->mSound.empty())
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->mBase->mSound, 1.0, 1.0, MWBase::SoundManager::Play_Loop); MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->mBase->mSound, 1.0, 1.0, MWBase::SoundManager::Play_Loop);

View file

@ -36,7 +36,7 @@ namespace MWClass
{ {
const std::string model = getModel(ptr); const std::string model = getModel(ptr);
if(!model.empty()) if(!model.empty())
physics.addObject(ptr); physics.addObject(ptr,true);
} }
std::string Lockpick::getModel(const MWWorld::Ptr &ptr) const std::string Lockpick::getModel(const MWWorld::Ptr &ptr) const

View file

@ -39,7 +39,7 @@ namespace MWClass
{ {
const std::string model = getModel(ptr); const std::string model = getModel(ptr);
if(!model.empty()) if(!model.empty())
physics.addObject(ptr); physics.addObject(ptr,true);
} }
std::string Miscellaneous::getModel(const MWWorld::Ptr &ptr) const std::string Miscellaneous::getModel(const MWWorld::Ptr &ptr) const

View file

@ -183,13 +183,10 @@ namespace MWClass
std::string bodyRaceID = headID.substr(0, end); std::string bodyRaceID = headID.substr(0, end);
std::string model = "meshes\\base_anim.nif"; std::string model = "meshes\\base_anim.nif";
if (bodyRaceID == "b_n_khajiit_m_" || const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(ref->mBase->mRace);
bodyRaceID == "b_n_khajiit_f_" || if(race->mData.mFlags & ESM::Race::Beast)
bodyRaceID == "b_n_argonian_m_" ||
bodyRaceID == "b_n_argonian_f_")
{
model = "meshes\\base_animkna.nif"; model = "meshes\\base_animkna.nif";
}
return model; return model;
} }
@ -220,7 +217,9 @@ namespace MWClass
const MWWorld::Ptr& actor) const const MWWorld::Ptr& actor) const
{ {
if (MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead()) if (MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead())
return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionOpen(ptr)); return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionOpen(ptr, true));
else if (MWWorld::Class::get(actor).getStance(actor, MWWorld::Class::Sneak))
return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionOpen(ptr)); // stealing
else else
return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionTalk (ptr)); return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionTalk (ptr));
} }
@ -365,11 +364,10 @@ namespace MWClass
fSwimRunAthleticsMult->getFloat(); fSwimRunAthleticsMult->getFloat();
moveSpeed = swimSpeed; moveSpeed = swimSpeed;
} }
else if(Npc::getStance(ptr, Run, false)) else if(Npc::getStance(ptr, Run, false) && !Npc::getStance(ptr, Sneak, false))
moveSpeed = runSpeed; moveSpeed = runSpeed;
else else
moveSpeed = walkSpeed; moveSpeed = walkSpeed;
if(getMovementSettings(ptr).mLeftRight != 0 && getMovementSettings(ptr).mForwardBackward == 0) if(getMovementSettings(ptr).mLeftRight != 0 && getMovementSettings(ptr).mForwardBackward == 0)
moveSpeed *= 0.75f; moveSpeed *= 0.75f;

View file

@ -20,6 +20,8 @@
#include "../mwrender/objects.hpp" #include "../mwrender/objects.hpp"
#include "../mwrender/renderinginterface.hpp" #include "../mwrender/renderinginterface.hpp"
#include "../mwmechanics/npcstats.hpp"
namespace MWClass namespace MWClass
{ {
void Potion::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const void Potion::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
@ -36,7 +38,7 @@ namespace MWClass
{ {
const std::string model = getModel(ptr); const std::string model = getModel(ptr);
if(!model.empty()) if(!model.empty())
physics.addObject(ptr); physics.addObject(ptr,true);
} }
std::string Potion::getModel(const MWWorld::Ptr &ptr) const std::string Potion::getModel(const MWWorld::Ptr &ptr) const
@ -138,6 +140,23 @@ namespace MWClass
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
info.effects = MWGui::Widgets::MWEffectList::effectListFromESM(&ref->mBase->mEffects); info.effects = MWGui::Widgets::MWEffectList::effectListFromESM(&ref->mBase->mEffects);
// hide effects the player doesnt know about
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer();
MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats (player);
int alchemySkill = npcStats.getSkill (ESM::Skill::Alchemy).getBase();
int i=0;
for (MWGui::Widgets::SpellEffectList::iterator it = info.effects.begin(); it != info.effects.end(); ++it)
{
/// \todo this code is duplicated from mwclass/ingredient, put it in a helper function
it->mKnown = ( (i == 0 && alchemySkill >= 15)
|| (i == 1 && alchemySkill >= 30)
|| (i == 2 && alchemySkill >= 45)
|| (i == 3 && alchemySkill >= 60));
++i;
}
info.isPotion = true; info.isPotion = true;
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {

View file

@ -36,7 +36,7 @@ namespace MWClass
{ {
const std::string model = getModel(ptr); const std::string model = getModel(ptr);
if(!model.empty()) if(!model.empty())
physics.addObject(ptr); physics.addObject(ptr,true);
} }
std::string Probe::getModel(const MWWorld::Ptr &ptr) const std::string Probe::getModel(const MWWorld::Ptr &ptr) const

View file

@ -34,7 +34,7 @@ namespace MWClass
{ {
const std::string model = getModel(ptr); const std::string model = getModel(ptr);
if(!model.empty()) if(!model.empty())
physics.addObject(ptr); physics.addObject(ptr,true);
} }
std::string Repair::getModel(const MWWorld::Ptr &ptr) const std::string Repair::getModel(const MWWorld::Ptr &ptr) const

View file

@ -36,7 +36,7 @@ namespace MWClass
{ {
const std::string model = getModel(ptr); const std::string model = getModel(ptr);
if(!model.empty()) if(!model.empty())
physics.addObject(ptr); physics.addObject(ptr,true);
} }
std::string Weapon::getModel(const MWWorld::Ptr &ptr) const std::string Weapon::getModel(const MWWorld::Ptr &ptr) const

View file

@ -2,6 +2,7 @@
#include "dialoguemanagerimp.hpp" #include "dialoguemanagerimp.hpp"
#include <cctype> #include <cctype>
#include <cstdlib>
#include <algorithm> #include <algorithm>
#include <iterator> #include <iterator>
@ -251,8 +252,12 @@ namespace MWDialogue
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
if (const ESM::DialInfo *info = filter.search (dialogue, true)) std::vector<const ESM::DialInfo *> infos = filter.list (dialogue, true, true);
if (!infos.empty())
{ {
const ESM::DialInfo* info = infos[std::rand() % infos.size()];
parseText (info->mResponse); parseText (info->mResponse);
if (dialogue.mType==ESM::Dialogue::Persuasion) if (dialogue.mType==ESM::Dialogue::Persuasion)

View file

@ -559,8 +559,21 @@ MWDialogue::Filter::Filter (const MWWorld::Ptr& actor, int choice, bool talkedTo
: mActor (actor), mChoice (choice), mTalkedToPlayer (talkedToPlayer) : mActor (actor), mChoice (choice), mTalkedToPlayer (talkedToPlayer)
{} {}
const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const const ESM::DialInfo* MWDialogue::Filter::search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const
{ {
std::vector<const ESM::DialInfo *> suitableInfos = list (dialogue, fallbackToInfoRefusal, false);
if (suitableInfos.empty())
return NULL;
else
return suitableInfos[0];
}
std::vector<const ESM::DialInfo *> MWDialogue::Filter::list (const ESM::Dialogue& dialogue,
bool fallbackToInfoRefusal, bool searchAll) const
{
std::vector<const ESM::DialInfo *> infos;
bool infoRefusal = false; bool infoRefusal = false;
// Iterate over topic responses to find a matching one // Iterate over topic responses to find a matching one
@ -569,14 +582,17 @@ const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue,
{ {
if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter)) if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter))
{ {
if (testDisposition (*iter)) if (testDisposition (*iter)) {
return &*iter; infos.push_back(&*iter);
if (!searchAll)
break;
}
else else
infoRefusal = true; infoRefusal = true;
} }
} }
if (infoRefusal && fallbackToInfoRefusal) if (infos.empty() && infoRefusal && fallbackToInfoRefusal)
{ {
// No response is valid because of low NPC disposition, // No response is valid because of low NPC disposition,
// search a response in the topic "Info Refusal" // search a response in the topic "Info Refusal"
@ -588,11 +604,14 @@ const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue,
for (std::vector<ESM::DialInfo>::const_iterator iter = infoRefusalDialogue.mInfo.begin(); for (std::vector<ESM::DialInfo>::const_iterator iter = infoRefusalDialogue.mInfo.begin();
iter!=infoRefusalDialogue.mInfo.end(); ++iter) iter!=infoRefusalDialogue.mInfo.end(); ++iter)
if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter)) if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter)) {
return &*iter; infos.push_back(&*iter);
if (!searchAll)
break;
}
} }
return 0; return infos;
} }
bool MWDialogue::Filter::responseAvailable (const ESM::Dialogue& dialogue) const bool MWDialogue::Filter::responseAvailable (const ESM::Dialogue& dialogue) const

View file

@ -1,6 +1,8 @@
#ifndef GAME_MWDIALOGUE_FILTER_H #ifndef GAME_MWDIALOGUE_FILTER_H
#define GAME_MWDIALOGUE_FILTER_H #define GAME_MWDIALOGUE_FILTER_H
#include <vector>
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
namespace ESM namespace ESM
@ -51,7 +53,10 @@ namespace MWDialogue
Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer); Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer);
const ESM::DialInfo *search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const; std::vector<const ESM::DialInfo *> list (const ESM::Dialogue& dialogue,
bool fallbackToInfoRefusal, bool searchAll) const;
const ESM::DialInfo* search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const;
///< Get a matching response for the requested dialogue. ///< Get a matching response for the requested dialogue.
/// Redirect to "Info Refusal" topic if a response fulfills all conditions but disposition. /// Redirect to "Info Refusal" topic if a response fulfills all conditions but disposition.

View file

@ -31,14 +31,13 @@ namespace
template<typename T> template<typename T>
bool selectCompareImp (const ESM::DialInfo::SelectStruct& select, T value1) bool selectCompareImp (const ESM::DialInfo::SelectStruct& select, T value1)
{ {
if (select.mType==ESM::VT_Short || select.mType==ESM::VT_Int || if (select.mValue.getType()==ESM::VT_Int)
select.mType==ESM::VT_Long)
{ {
return selectCompareImp (select.mSelectRule[4], value1, select.mI); return selectCompareImp (select.mSelectRule[4], value1, select.mValue.getInteger());
} }
else if (select.mType==ESM::VT_Float) else if (select.mValue.getType()==ESM::VT_Float)
{ {
return selectCompareImp (select.mSelectRule[4], value1, select.mF); return selectCompareImp (select.mSelectRule[4], value1, select.mValue.getFloat());
} }
else else
throw std::runtime_error ( throw std::runtime_error (

View file

@ -237,7 +237,7 @@ namespace MWGui
Widgets::SpellEffectList _list = Widgets::MWEffectList::effectListFromESM(&list); Widgets::SpellEffectList _list = Widgets::MWEffectList::effectListFromESM(&list);
effectsWidget->setEffectList(_list); effectsWidget->setEffectList(_list);
std::vector<MyGUI::WidgetPtr> effectItems; std::vector<MyGUI::Widget*> effectItems;
effectsWidget->createEffectWidgets(effectItems, mEffectsBox, coord, false, 0); effectsWidget->createEffectWidgets(effectItems, mEffectsBox, coord, false, 0);
effectsWidget->setCoord(coord); effectsWidget->setCoord(coord);
} }

View file

@ -40,11 +40,11 @@ BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager)
mBirthList->eventListMouseItemActivate += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); mBirthList->eventListMouseItemActivate += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth);
mBirthList->eventListChangePosition += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); mBirthList->eventListChangePosition += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth);
MyGUI::ButtonPtr backButton; MyGUI::Button* backButton;
getWidget(backButton, "BackButton"); getWidget(backButton, "BackButton");
backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onBackClicked); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onBackClicked);
MyGUI::ButtonPtr okButton; MyGUI::Button* okButton;
getWidget(okButton, "OKButton"); getWidget(okButton, "OKButton");
okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->setCaption(mWindowManager.getGameSettingString("sOK", ""));
okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked);
@ -55,7 +55,7 @@ BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager)
void BirthDialog::setNextButtonShow(bool shown) void BirthDialog::setNextButtonShow(bool shown)
{ {
MyGUI::ButtonPtr okButton; MyGUI::Button* okButton;
getWidget(okButton, "OKButton"); getWidget(okButton, "OKButton");
if (shown) if (shown)
@ -82,7 +82,7 @@ void BirthDialog::setBirthId(const std::string &birthId)
if (boost::iequals(*mBirthList->getItemDataAt<std::string>(i), birthId)) if (boost::iequals(*mBirthList->getItemDataAt<std::string>(i), birthId))
{ {
mBirthList->setIndexSelected(i); mBirthList->setIndexSelected(i);
MyGUI::ButtonPtr okButton; MyGUI::Button* okButton;
getWidget(okButton, "OKButton"); getWidget(okButton, "OKButton");
break; break;
} }
@ -110,7 +110,7 @@ void BirthDialog::onSelectBirth(MyGUI::ListBox* _sender, size_t _index)
if (_index == MyGUI::ITEM_NONE) if (_index == MyGUI::ITEM_NONE)
return; return;
MyGUI::ButtonPtr okButton; MyGUI::Button* okButton;
getWidget(okButton, "OKButton"); getWidget(okButton, "OKButton");
const std::string *birthId = mBirthList->getItemDataAt<std::string>(_index); const std::string *birthId = mBirthList->getItemDataAt<std::string>(_index);
@ -159,7 +159,7 @@ void BirthDialog::updateBirths()
void BirthDialog::updateSpells() void BirthDialog::updateSpells()
{ {
for (std::vector<MyGUI::WidgetPtr>::iterator it = mSpellItems.begin(); it != mSpellItems.end(); ++it) for (std::vector<MyGUI::Widget*>::iterator it = mSpellItems.begin(); it != mSpellItems.end(); ++it)
{ {
MyGUI::Gui::getInstance().destroyWidget(*it); MyGUI::Gui::getInstance().destroyWidget(*it);
} }

View file

@ -46,9 +46,9 @@ namespace MWGui
void updateSpells(); void updateSpells();
MyGUI::ListBox* mBirthList; MyGUI::ListBox* mBirthList;
MyGUI::WidgetPtr mSpellArea; MyGUI::Widget* mSpellArea;
MyGUI::ImageBox* mBirthImage; MyGUI::ImageBox* mBirthImage;
std::vector<MyGUI::WidgetPtr> mSpellItems; std::vector<MyGUI::Widget*> mSpellItems;
std::string mCurrentBirthId; std::string mCurrentBirthId;
}; };

View file

@ -8,7 +8,7 @@
#include "dialogue.hpp" #include "dialogue.hpp"
#include "mode.hpp" #include "mode.hpp"
#include "inventorywindow.hpp" #include "inventorywindow.hpp"
#include <boost/lexical_cast.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
@ -17,94 +17,24 @@ namespace
{ {
struct Step struct Step
{ {
const char* mText; const std::string mText;
const char* mButtons[3]; const std::string mButtons[3];
const char* mSound; const std::string mSound;
ESM::Class::Specialization mSpecializations[3]; // The specialization for each answer
}; };
static boost::array<Step, 10> sGenerateClassSteps = { { const ESM::Class::Specialization mSpecializations[3]={ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}; // The specialization for each answer
// Question 1
{"On a clear day you chance upon a strange animal, its legs trapped in a hunter's clawsnare. Judging from the bleeding, it will not survive long.", Step sGenerateClassSteps(int number) {
{"Draw your dagger, mercifully endings its life with a single thrust.", MWBase::World *world = MWBase::Environment::get().getWorld();
"Use herbs from your pack to put it to sleep.", number++;
"Do not interfere in the natural evolution of events, but rather take the opportunity to learn more about a strange animal that you have never seen before."}, Step step = {world->getFallback("Question_"+boost::lexical_cast<std::string>(number)+"_Question"),
"vo\\misc\\chargen qa1.wav", {world->getFallback("Question_"+boost::lexical_cast<std::string>(number)+"_AnswerOne"),
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} world->getFallback("Question_"+boost::lexical_cast<std::string>(number)+"_AnswerTwo"),
}, world->getFallback("Question_"+boost::lexical_cast<std::string>(number)+"_AnswerThree")},
// Question 2 "vo\\misc\\chargen qa"+boost::lexical_cast<std::string>(number)+".wav"
{"One Summer afternoon your father gives you a choice of chores.", };
{"Work in the forge with him casting iron for a new plow.", return step;
"Gather herbs for your mother who is preparing dinner.", }
"Go catch fish at the stream using a net and line."},
"vo\\misc\\chargen qa2.wav",
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
},
// Question 3
{"Your cousin has given you a very embarrassing nickname and, even worse, likes to call you it in front of your friends. You asked him to stop, but he finds it very amusing to watch you blush.",
{"Beat up your cousin, then tell him that if he ever calls you that nickname again, you will bloody him worse than this time.",
"Make up a story that makes your nickname a badge of honor instead of something humiliating.",
"Make up an even more embarrassing nickname for him and use it constantly until he learns his lesson."},
"vo\\misc\\chargen qa3.wav",
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
},
// Question 4
{"There is a lot of heated discussion at the local tavern over a grouped of people called 'Telepaths'. They have been hired by certain City-State kings. Rumor has it these Telepaths read a person's mind and tell their lord whether a follower is telling the truth or not.",
{"This is a terrible practice. A person's thoughts are his own and no one, not even a king, has the right to make such an invasion into another human's mind.",
"Loyal followers to the king have nothing to fear from a Telepath. It is important to have a method of finding assassins and spies before it is too late.",
"In these times, it is a necessary evil. Although you do not necessarily like the idea, a Telepath could have certain advantages during a time of war or in finding someone innocent of a crime."},
"vo\\misc\\chargen qa4.wav",
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
},
// Question 5
{"Your mother sends you to the market with a list of goods to buy. After you finish you find that by mistake a shopkeeper has given you too much money back in exchange for one of the items.",
{"Return to the store and give the shopkeeper his hard-earned money, explaining to him the mistake?",
"Decide to put the extra money to good use and purchase items that would help your family?",
"Pocket the extra money, knowing that shopkeepers in general tend to overcharge customers anyway?"},
"vo\\misc\\chargen qa5.wav",
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
},
// Question 6
{"While in the market place you witness a thief cut a purse from a noble. Even as he does so, the noble notices and calls for the city guards. In his haste to get away, the thief drops the purse near you. Surprisingly no one seems to notice the bag of coins at your feet.",
{"Pick up the bag and signal to the guard, knowing that the only honorable thing to do is return the money to its rightful owner.",
"Leave the bag there, knowing that it is better not to get involved.",
"Pick up the bag and pocket it, knowing that the extra windfall will help your family in times of trouble."},
"vo\\misc\\chargen qa6.wav",
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
},
// Question 7
{"Your father sends you on a task which you loathe, cleaning the stables. On the way there, pitchfork in hand, you run into your friend from the homestead near your own. He offers to do it for you, in return for a future favor of his choosing.",
{"Decline his offer, knowing that your father expects you to do the work, and it is better not to be in debt.",
"Ask him to help you, knowing that two people can do the job faster than one, and agree to help him with one task of his choosing in the future.",
"Accept his offer, reasoning that as long as the stables are cleaned, it matters not who does the cleaning."},
"vo\\misc\\chargen qa7.wav",
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
},
// Question 8
{"Your mother asks you to help fix the stove. While you are working, a very hot pipe slips its mooring and falls towards her.",
{"Position yourself between the pipe and your mother.",
"Grab the hot pipe and try to push it away.",
"Push your mother out of the way."},
"vo\\misc\\chargen qa8.wav",
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
},
// Question 9
{"While in town the baker gives you a sweetroll. Delighted, you take it into an alley to enjoy only to be intercepted by a gang of three other kids your age. The leader demands the sweetroll, or else he and his friends will beat you and take it.",
{"Drop the sweetroll and step on it, then get ready for the fight.",
"Give him the sweetroll now without argument, knowing that later this afternoon you will have all your friends with you and can come and take whatever he owes you.",
"Act like you're going to give him the sweetroll, but at the last minute throw it in the air, hoping that they'll pay attention to it long enough for you to get a shot in on the leader."},
"vo\\misc\\chargen qa9.wav",
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
},
// Question 10
{"Entering town you find that you are witness to a very well-dressed man running from a crowd. He screams to you for help. The crowd behind him seem very angry.",
{"Rush to the town's aid immediately, despite your lack of knowledge of the circumstances.",
"Stand aside and allow the man and the mob to pass, realizing it is probably best not to get involved.",
"Rush to the man's aid immediately, despite your lack of knowledge of the circumstances."},
"vo\\misc\\chargen qa10.wav",
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
}
} };
struct ClassPoint struct ClassPoint
{ {
@ -206,7 +136,9 @@ void CharacterCreation::spawnDialog(const char id)
mRaceDialog->setRaceId(mPlayerRaceId); mRaceDialog->setRaceId(mPlayerRaceId);
mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone); mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone);
mRaceDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogBack); mRaceDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogBack);
mRaceDialog->setVisible(true);; mRaceDialog->setVisible(true);
if (mCreationStage < CSE_NameChosen)
mCreationStage = CSE_NameChosen;
break; break;
case GM_Class: case GM_Class:
@ -215,6 +147,8 @@ void CharacterCreation::spawnDialog(const char id)
mClassChoiceDialog = new ClassChoiceDialog(*mWM); mClassChoiceDialog = new ClassChoiceDialog(*mWM);
mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice); mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice);
mClassChoiceDialog->setVisible(true); mClassChoiceDialog->setVisible(true);
if (mCreationStage < CSE_RaceChosen)
mCreationStage = CSE_RaceChosen;
break; break;
case GM_ClassPick: case GM_ClassPick:
@ -226,6 +160,8 @@ void CharacterCreation::spawnDialog(const char id)
mPickClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone); mPickClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone);
mPickClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogBack); mPickClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogBack);
mPickClassDialog->setVisible(true); mPickClassDialog->setVisible(true);
if (mCreationStage < CSE_RaceChosen)
mCreationStage = CSE_RaceChosen;
break; break;
case GM_Birth: case GM_Birth:
@ -237,6 +173,8 @@ void CharacterCreation::spawnDialog(const char id)
mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone); mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone);
mBirthSignDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack); mBirthSignDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack);
mBirthSignDialog->setVisible(true); mBirthSignDialog->setVisible(true);
if (mCreationStage < CSE_ClassChosen)
mCreationStage = CSE_ClassChosen;
break; break;
case GM_ClassCreate: case GM_ClassCreate:
@ -247,6 +185,8 @@ void CharacterCreation::spawnDialog(const char id)
mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone); mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone);
mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack); mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack);
mCreateClassDialog->setVisible(true); mCreateClassDialog->setVisible(true);
if (mCreationStage < CSE_RaceChosen)
mCreationStage = CSE_RaceChosen;
break; break;
case GM_ClassGenerate: case GM_ClassGenerate:
mGenerateClassStep = 0; mGenerateClassStep = 0;
@ -255,6 +195,8 @@ void CharacterCreation::spawnDialog(const char id)
mGenerateClassSpecializations[1] = 0; mGenerateClassSpecializations[1] = 0;
mGenerateClassSpecializations[2] = 0; mGenerateClassSpecializations[2] = 0;
showClassQuestionDialog(); showClassQuestionDialog();
if (mCreationStage < CSE_RaceChosen)
mCreationStage = CSE_RaceChosen;
break; break;
case GM_Review: case GM_Review:
mWM->removeDialog(mReviewDialog); mWM->removeDialog(mReviewDialog);
@ -292,6 +234,8 @@ void CharacterCreation::spawnDialog(const char id)
mReviewDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack); mReviewDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack);
mReviewDialog->eventActivateDialog += MyGUI::newDelegate(this, &CharacterCreation::onReviewActivateDialog); mReviewDialog->eventActivateDialog += MyGUI::newDelegate(this, &CharacterCreation::onReviewActivateDialog);
mReviewDialog->setVisible(true); mReviewDialog->setVisible(true);
if (mCreationStage < CSE_BirthSignChosen)
mCreationStage = CSE_BirthSignChosen;
break; break;
} }
} }
@ -624,7 +568,7 @@ void CharacterCreation::onClassQuestionChosen(int _index)
return; return;
} }
ESM::Class::Specialization specialization = sGenerateClassSteps[mGenerateClassStep].mSpecializations[_index]; ESM::Class::Specialization specialization = mSpecializations[_index];
if (specialization == ESM::Class::Stealth) if (specialization == ESM::Class::Stealth)
++mGenerateClassSpecializations[0]; ++mGenerateClassSpecializations[0];
else if (specialization == ESM::Class::Combat) else if (specialization == ESM::Class::Combat)
@ -637,7 +581,7 @@ void CharacterCreation::onClassQuestionChosen(int _index)
void CharacterCreation::showClassQuestionDialog() void CharacterCreation::showClassQuestionDialog()
{ {
if (mGenerateClassStep == sGenerateClassSteps.size()) if (mGenerateClassStep == 10)
{ {
static boost::array<ClassPoint, 23> classes = { { static boost::array<ClassPoint, 23> classes = { {
{"Acrobat", {6, 2, 2}}, {"Acrobat", {6, 2, 2}},
@ -704,7 +648,7 @@ void CharacterCreation::showClassQuestionDialog()
return; return;
} }
if (mGenerateClassStep > sGenerateClassSteps.size()) if (mGenerateClassStep > 10)
{ {
mWM->popGuiMode(); mWM->popGuiMode();
mWM->pushGuiMode(GM_Class); mWM->pushGuiMode(GM_Class);
@ -717,15 +661,15 @@ void CharacterCreation::showClassQuestionDialog()
mGenerateClassQuestionDialog = new InfoBoxDialog(*mWM); mGenerateClassQuestionDialog = new InfoBoxDialog(*mWM);
InfoBoxDialog::ButtonList buttons; InfoBoxDialog::ButtonList buttons;
mGenerateClassQuestionDialog->setText(sGenerateClassSteps[mGenerateClassStep].mText); mGenerateClassQuestionDialog->setText(sGenerateClassSteps(mGenerateClassStep).mText);
buttons.push_back(sGenerateClassSteps[mGenerateClassStep].mButtons[0]); buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[0]);
buttons.push_back(sGenerateClassSteps[mGenerateClassStep].mButtons[1]); buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[1]);
buttons.push_back(sGenerateClassSteps[mGenerateClassStep].mButtons[2]); buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[2]);
mGenerateClassQuestionDialog->setButtons(buttons); mGenerateClassQuestionDialog->setButtons(buttons);
mGenerateClassQuestionDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassQuestionChosen); mGenerateClassQuestionDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassQuestionChosen);
mGenerateClassQuestionDialog->setVisible(true); mGenerateClassQuestionDialog->setVisible(true);
MWBase::Environment::get().getSoundManager()->say(sGenerateClassSteps[mGenerateClassStep].mSound); MWBase::Environment::get().getSoundManager()->say(sGenerateClassSteps(mGenerateClassStep).mSound);
} }
void CharacterCreation::onGenerateClassBack() void CharacterCreation::onGenerateClassBack()

View file

@ -31,11 +31,11 @@ GenerateClassResultDialog::GenerateClassResultDialog(MWBase::WindowManager& parW
getWidget(mClassImage, "ClassImage"); getWidget(mClassImage, "ClassImage");
getWidget(mClassName, "ClassName"); getWidget(mClassName, "ClassName");
MyGUI::ButtonPtr backButton; MyGUI::Button* backButton;
getWidget(backButton, "BackButton"); getWidget(backButton, "BackButton");
backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked);
MyGUI::ButtonPtr okButton; MyGUI::Button* okButton;
getWidget(okButton, "OKButton"); getWidget(okButton, "OKButton");
okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->setCaption(mWindowManager.getGameSettingString("sOK", ""));
okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked);
@ -97,11 +97,11 @@ PickClassDialog::PickClassDialog(MWBase::WindowManager& parWindowManager)
getWidget(mClassImage, "ClassImage"); getWidget(mClassImage, "ClassImage");
MyGUI::ButtonPtr backButton; MyGUI::Button* backButton;
getWidget(backButton, "BackButton"); getWidget(backButton, "BackButton");
backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onBackClicked); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onBackClicked);
MyGUI::ButtonPtr okButton; MyGUI::Button* okButton;
getWidget(okButton, "OKButton"); getWidget(okButton, "OKButton");
okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onOkClicked); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onOkClicked);
@ -111,7 +111,7 @@ PickClassDialog::PickClassDialog(MWBase::WindowManager& parWindowManager)
void PickClassDialog::setNextButtonShow(bool shown) void PickClassDialog::setNextButtonShow(bool shown)
{ {
MyGUI::ButtonPtr okButton; MyGUI::Button* okButton;
getWidget(okButton, "OKButton"); getWidget(okButton, "OKButton");
if (shown) if (shown)
@ -138,7 +138,7 @@ void PickClassDialog::setClassId(const std::string &classId)
if (boost::iequals(*mClassList->getItemDataAt<std::string>(i), classId)) if (boost::iequals(*mClassList->getItemDataAt<std::string>(i), classId))
{ {
mClassList->setIndexSelected(i); mClassList->setIndexSelected(i);
MyGUI::ButtonPtr okButton; MyGUI::Button* okButton;
getWidget(okButton, "OKButton"); getWidget(okButton, "OKButton");
break; break;
} }
@ -166,7 +166,7 @@ void PickClassDialog::onSelectClass(MyGUI::ListBox* _sender, size_t _index)
if (_index == MyGUI::ITEM_NONE) if (_index == MyGUI::ITEM_NONE)
return; return;
MyGUI::ButtonPtr okButton; MyGUI::Button* okButton;
getWidget(okButton, "OKButton"); getWidget(okButton, "OKButton");
const std::string *classId = mClassList->getItemDataAt<std::string>(_index); const std::string *classId = mClassList->getItemDataAt<std::string>(_index);
@ -256,7 +256,7 @@ void InfoBoxDialog::fitToText(MyGUI::TextBox* widget)
widget->setSize(size); widget->setSize(size);
} }
void InfoBoxDialog::layoutVertically(MyGUI::WidgetPtr widget, int margin) void InfoBoxDialog::layoutVertically(MyGUI::Widget* widget, int margin)
{ {
size_t count = widget->getChildCount(); size_t count = widget->getChildCount();
int pos = 0; int pos = 0;
@ -264,7 +264,7 @@ void InfoBoxDialog::layoutVertically(MyGUI::WidgetPtr widget, int margin)
int width = 0; int width = 0;
for (unsigned i = 0; i < count; ++i) for (unsigned i = 0; i < count; ++i)
{ {
MyGUI::WidgetPtr child = widget->getChildAt(i); MyGUI::Widget* child = widget->getChildAt(i);
if (!child->getVisible()) if (!child->getVisible())
continue; continue;
@ -302,7 +302,7 @@ std::string InfoBoxDialog::getText() const
void InfoBoxDialog::setButtons(ButtonList &buttons) void InfoBoxDialog::setButtons(ButtonList &buttons)
{ {
for (std::vector<MyGUI::ButtonPtr>::iterator it = this->mButtons.begin(); it != this->mButtons.end(); ++it) for (std::vector<MyGUI::Button*>::iterator it = this->mButtons.begin(); it != this->mButtons.end(); ++it)
{ {
MyGUI::Gui::getInstance().destroyWidget(*it); MyGUI::Gui::getInstance().destroyWidget(*it);
} }
@ -310,7 +310,7 @@ void InfoBoxDialog::setButtons(ButtonList &buttons)
mCurrentButton = -1; mCurrentButton = -1;
// TODO: The buttons should be generated from a template in the layout file, ie. cloning an existing widget // TODO: The buttons should be generated from a template in the layout file, ie. cloning an existing widget
MyGUI::ButtonPtr button; MyGUI::Button* button;
MyGUI::IntCoord coord = MyGUI::IntCoord(0, 0, mButtonBar->getWidth(), 10); MyGUI::IntCoord coord = MyGUI::IntCoord(0, 0, mButtonBar->getWidth(), 10);
ButtonList::const_iterator end = buttons.end(); ButtonList::const_iterator end = buttons.end();
for (ButtonList::const_iterator it = buttons.begin(); it != end; ++it) for (ButtonList::const_iterator it = buttons.begin(); it != end; ++it)
@ -342,11 +342,11 @@ int InfoBoxDialog::getChosenButton() const
return mCurrentButton; return mCurrentButton;
} }
void InfoBoxDialog::onButtonClicked(MyGUI::WidgetPtr _sender) void InfoBoxDialog::onButtonClicked(MyGUI::Widget* _sender)
{ {
std::vector<MyGUI::ButtonPtr>::const_iterator end = mButtons.end(); std::vector<MyGUI::Button*>::const_iterator end = mButtons.end();
int i = 0; int i = 0;
for (std::vector<MyGUI::ButtonPtr>::const_iterator it = mButtons.begin(); it != end; ++it) for (std::vector<MyGUI::Button*>::const_iterator it = mButtons.begin(); it != end; ++it)
{ {
if (*it == _sender) if (*it == _sender)
{ {
@ -376,10 +376,10 @@ ClassChoiceDialog::ClassChoiceDialog(MWBase::WindowManager& parWindowManager)
CreateClassDialog::CreateClassDialog(MWBase::WindowManager& parWindowManager) CreateClassDialog::CreateClassDialog(MWBase::WindowManager& parWindowManager)
: WindowModal("openmw_chargen_create_class.layout", parWindowManager) : WindowModal("openmw_chargen_create_class.layout", parWindowManager)
, mSpecDialog(nullptr) , mSpecDialog(NULL)
, mAttribDialog(nullptr) , mAttribDialog(NULL)
, mSkillDialog(nullptr) , mSkillDialog(NULL)
, mDescDialog(nullptr) , mDescDialog(NULL)
{ {
// Centre dialog // Centre dialog
center(); center();
@ -420,15 +420,15 @@ CreateClassDialog::CreateClassDialog(MWBase::WindowManager& parWindowManager)
// Make sure the edit box has focus // Make sure the edit box has focus
MyGUI::InputManager::getInstance().setKeyFocusWidget(mEditName); MyGUI::InputManager::getInstance().setKeyFocusWidget(mEditName);
MyGUI::ButtonPtr descriptionButton; MyGUI::Button* descriptionButton;
getWidget(descriptionButton, "DescriptionButton"); getWidget(descriptionButton, "DescriptionButton");
descriptionButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionClicked); descriptionButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionClicked);
MyGUI::ButtonPtr backButton; MyGUI::Button* backButton;
getWidget(backButton, "BackButton"); getWidget(backButton, "BackButton");
backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onBackClicked); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onBackClicked);
MyGUI::ButtonPtr okButton; MyGUI::Button* okButton;
getWidget(okButton, "OKButton"); getWidget(okButton, "OKButton");
okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onOkClicked); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onOkClicked);
@ -518,7 +518,7 @@ std::vector<ESM::Skill::SkillEnum> CreateClassDialog::getMinorSkills() const
void CreateClassDialog::setNextButtonShow(bool shown) void CreateClassDialog::setNextButtonShow(bool shown)
{ {
MyGUI::ButtonPtr okButton; MyGUI::Button* okButton;
getWidget(okButton, "OKButton"); getWidget(okButton, "OKButton");
if (shown) if (shown)
@ -544,7 +544,7 @@ void CreateClassDialog::onDialogCancel()
mDescDialog = 0; mDescDialog = 0;
} }
void CreateClassDialog::onSpecializationClicked(MyGUI::WidgetPtr _sender) void CreateClassDialog::onSpecializationClicked(MyGUI::Widget* _sender)
{ {
delete mSpecDialog; delete mSpecDialog;
mSpecDialog = new SelectSpecializationDialog(mWindowManager); mSpecDialog = new SelectSpecializationDialog(mWindowManager);
@ -694,7 +694,7 @@ SelectSpecializationDialog::SelectSpecializationDialog(MWBase::WindowManager& pa
ToolTips::createSpecializationToolTip(mSpecialization1, magic, ESM::Class::Magic); ToolTips::createSpecializationToolTip(mSpecialization1, magic, ESM::Class::Magic);
ToolTips::createSpecializationToolTip(mSpecialization2, stealth, ESM::Class::Stealth); ToolTips::createSpecializationToolTip(mSpecialization2, stealth, ESM::Class::Stealth);
MyGUI::ButtonPtr cancelButton; MyGUI::Button* cancelButton;
getWidget(cancelButton, "CancelButton"); getWidget(cancelButton, "CancelButton");
cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", ""));
cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onCancelClicked); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onCancelClicked);
@ -706,7 +706,7 @@ SelectSpecializationDialog::~SelectSpecializationDialog()
// widget controls // widget controls
void SelectSpecializationDialog::onSpecializationClicked(MyGUI::WidgetPtr _sender) void SelectSpecializationDialog::onSpecializationClicked(MyGUI::Widget* _sender)
{ {
if (_sender == mSpecialization0) if (_sender == mSpecialization0)
mSpecializationId = ESM::Class::Combat; mSpecializationId = ESM::Class::Combat;
@ -747,7 +747,7 @@ SelectAttributeDialog::SelectAttributeDialog(MWBase::WindowManager& parWindowMan
ToolTips::createAttributeToolTip(attribute, attribute->getAttributeId()); ToolTips::createAttributeToolTip(attribute, attribute->getAttributeId());
} }
MyGUI::ButtonPtr cancelButton; MyGUI::Button* cancelButton;
getWidget(cancelButton, "CancelButton"); getWidget(cancelButton, "CancelButton");
cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", ""));
cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectAttributeDialog::onCancelClicked); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectAttributeDialog::onCancelClicked);
@ -840,7 +840,7 @@ SelectSkillDialog::SelectSkillDialog(MWBase::WindowManager& parWindowManager)
} }
} }
MyGUI::ButtonPtr cancelButton; MyGUI::Button* cancelButton;
getWidget(cancelButton, "CancelButton"); getWidget(cancelButton, "CancelButton");
cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", ""));
cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSkillDialog::onCancelClicked); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSkillDialog::onCancelClicked);
@ -873,7 +873,7 @@ DescriptionDialog::DescriptionDialog(MWBase::WindowManager& parWindowManager)
getWidget(mTextEdit, "TextEdit"); getWidget(mTextEdit, "TextEdit");
MyGUI::ButtonPtr okButton; MyGUI::Button* okButton;
getWidget(okButton, "OKButton"); getWidget(okButton, "OKButton");
okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DescriptionDialog::onOkClicked); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DescriptionDialog::onOkClicked);
okButton->setCaption(mWindowManager.getGameSettingString("sInputMenu1", "")); okButton->setCaption(mWindowManager.getGameSettingString("sInputMenu1", ""));

View file

@ -1,7 +1,7 @@
#ifndef MWGUI_CLASS_H #ifndef MWGUI_CLASS_H
#define MWGUI_CLASS_H #define MWGUI_CLASS_H
#include <MyGUI.h>
#include "widgets.hpp" #include "widgets.hpp"
#include "window_base.hpp" #include "window_base.hpp"
@ -35,17 +35,17 @@ namespace MWGui
EventHandle_Int eventButtonSelected; EventHandle_Int eventButtonSelected;
protected: protected:
void onButtonClicked(MyGUI::WidgetPtr _sender); void onButtonClicked(MyGUI::Widget* _sender);
private: private:
void fitToText(MyGUI::TextBox* widget); void fitToText(MyGUI::TextBox* widget);
void layoutVertically(MyGUI::WidgetPtr widget, int margin); void layoutVertically(MyGUI::Widget* widget, int margin);
int mCurrentButton; int mCurrentButton;
MyGUI::WidgetPtr mTextBox; MyGUI::Widget* mTextBox;
MyGUI::TextBox* mText; MyGUI::TextBox* mText;
MyGUI::WidgetPtr mButtonBar; MyGUI::Widget* mButtonBar;
std::vector<MyGUI::ButtonPtr> mButtons; std::vector<MyGUI::Button*> mButtons;
}; };
// Lets the player choose between 3 ways of creating a class // Lets the player choose between 3 ways of creating a class
@ -235,7 +235,7 @@ namespace MWGui
void onOkClicked(MyGUI::Widget* _sender); void onOkClicked(MyGUI::Widget* _sender);
private: private:
MyGUI::EditPtr mTextEdit; MyGUI::EditBox* mTextEdit;
}; };
class CreateClassDialog : public WindowModal class CreateClassDialog : public WindowModal
@ -265,7 +265,7 @@ namespace MWGui
void onOkClicked(MyGUI::Widget* _sender); void onOkClicked(MyGUI::Widget* _sender);
void onBackClicked(MyGUI::Widget* _sender); void onBackClicked(MyGUI::Widget* _sender);
void onSpecializationClicked(MyGUI::WidgetPtr _sender); void onSpecializationClicked(MyGUI::Widget* _sender);
void onSpecializationSelected(); void onSpecializationSelected();
void onAttributeClicked(Widgets::MWAttributePtr _sender); void onAttributeClicked(Widgets::MWAttributePtr _sender);
void onAttributeSelected(); void onAttributeSelected();
@ -280,7 +280,7 @@ namespace MWGui
void update(); void update();
private: private:
MyGUI::EditPtr mEditName; MyGUI::EditBox* mEditName;
MyGUI::TextBox* mSpecializationName; MyGUI::TextBox* mSpecializationName;
Widgets::MWAttributePtr mFavoriteAttribute0, mFavoriteAttribute1; Widgets::MWAttributePtr mFavoriteAttribute0, mFavoriteAttribute1;
Widgets::MWSkillPtr mMajorSkill[5]; Widgets::MWSkillPtr mMajorSkill[5];

View file

@ -216,7 +216,7 @@ namespace MWGui
} }
} }
void Console::keyPress(MyGUI::WidgetPtr _sender, void Console::keyPress(MyGUI::Widget* _sender,
MyGUI::KeyCode key, MyGUI::KeyCode key,
MyGUI::Char _char) MyGUI::Char _char)
{ {
@ -266,7 +266,7 @@ namespace MWGui
} }
} }
void Console::acceptCommand(MyGUI::EditPtr _sender) void Console::acceptCommand(MyGUI::EditBox* _sender)
{ {
const std::string &cm = command->getCaption(); const std::string &cm = command->getCaption();
if(cm.empty()) return; if(cm.empty()) return;

View file

@ -55,8 +55,8 @@ namespace MWGui
public: public:
MyGUI::EditPtr command; MyGUI::EditBox* command;
MyGUI::EditPtr history; MyGUI::EditBox* history;
typedef std::list<std::string> StringList; typedef std::list<std::string> StringList;
@ -95,11 +95,11 @@ namespace MWGui
private: private:
void keyPress(MyGUI::WidgetPtr _sender, void keyPress(MyGUI::Widget* _sender,
MyGUI::KeyCode key, MyGUI::KeyCode key,
MyGUI::Char _char); MyGUI::Char _char);
void acceptCommand(MyGUI::EditPtr _sender); void acceptCommand(MyGUI::EditBox* _sender);
std::string complete( std::string input, std::vector<std::string> &matches ); std::string complete( std::string input, std::vector<std::string> &matches );
}; };

View file

@ -15,6 +15,7 @@
#include "../mwworld/manualref.hpp" #include "../mwworld/manualref.hpp"
#include "../mwworld/containerstore.hpp" #include "../mwworld/containerstore.hpp"
#include "../mwworld/inventorystore.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/player.hpp" #include "../mwworld/player.hpp"
@ -70,9 +71,11 @@ namespace
} }
ContainerBase::ContainerBase(DragAndDrop* dragAndDrop) : ContainerBase::ContainerBase(DragAndDrop* dragAndDrop)
mDragAndDrop(dragAndDrop), : mDragAndDrop(dragAndDrop)
mFilter(ContainerBase::Filter_All) , mFilter(ContainerBase::Filter_All)
, mDisplayEquippedItems(true)
, mHighlightEquippedItems(true)
{ {
} }
@ -313,7 +316,6 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender)
{ {
object.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); object.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount);
} }
std::cout << "container weight " << curWeight << "/" << capacity << std::endl;
} }
else else
{ {
@ -430,7 +432,7 @@ void ContainerBase::drawItems()
equippedItems.erase(found); equippedItems.erase(found);
} }
// and add the items that are left (= have the correct category) // and add the items that are left (= have the correct category)
if (!ignoreEquippedItems()) if (mDisplayEquippedItems && mHighlightEquippedItems)
{ {
for (std::vector<MWWorld::Ptr>::const_iterator it=equippedItems.begin(); for (std::vector<MWWorld::Ptr>::const_iterator it=equippedItems.begin();
it != equippedItems.end(); ++it) it != equippedItems.end(); ++it)
@ -445,7 +447,8 @@ void ContainerBase::drawItems()
std::vector<MWWorld::Ptr> regularItems; std::vector<MWWorld::Ptr> regularItems;
for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter) for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter)
{ {
if (std::find(equippedItems.begin(), equippedItems.end(), *iter) == equippedItems.end() if ( (std::find(equippedItems.begin(), equippedItems.end(), *iter) == equippedItems.end()
|| (!mHighlightEquippedItems && mDisplayEquippedItems))
&& std::find(ignoreItems.begin(), ignoreItems.end(), *iter) == ignoreItems.end() && std::find(ignoreItems.begin(), ignoreItems.end(), *iter) == ignoreItems.end()
&& std::find(mBoughtItems.begin(), mBoughtItems.end(), *iter) == mBoughtItems.end()) && std::find(mBoughtItems.begin(), mBoughtItems.end(), *iter) == mBoughtItems.end())
regularItems.push_back(*iter); regularItems.push_back(*iter);
@ -587,6 +590,27 @@ void ContainerBase::returnBoughtItems(MWWorld::ContainerStore& store)
} }
} }
std::vector<MWWorld::Ptr> ContainerBase::getEquippedItems()
{
if (mPtr.getTypeName() != typeid(ESM::NPC).name())
return std::vector<MWWorld::Ptr>();
MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
std::vector<MWWorld::Ptr> items;
for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot)
{
MWWorld::ContainerStoreIterator it = invStore.getSlot(slot);
if (it != invStore.end())
{
items.push_back(*it);
}
}
return items;
}
MWWorld::ContainerStore& ContainerBase::getContainerStore() MWWorld::ContainerStore& ContainerBase::getContainerStore()
{ {
MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr); MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr);
@ -599,6 +623,7 @@ ContainerWindow::ContainerWindow(MWBase::WindowManager& parWindowManager,DragAnd
: ContainerBase(dragAndDrop) : ContainerBase(dragAndDrop)
, WindowBase("openmw_container_window.layout", parWindowManager) , WindowBase("openmw_container_window.layout", parWindowManager)
{ {
getWidget(mDisposeCorpseButton, "DisposeCorpseButton");
getWidget(mTakeButton, "TakeButton"); getWidget(mTakeButton, "TakeButton");
getWidget(mCloseButton, "CloseButton"); getWidget(mCloseButton, "CloseButton");
@ -608,6 +633,7 @@ ContainerWindow::ContainerWindow(MWBase::WindowManager& parWindowManager,DragAnd
getWidget(itemView, "ItemView"); getWidget(itemView, "ItemView");
setWidgets(containerWidget, itemView); setWidgets(containerWidget, itemView);
mDisposeCorpseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onDisposeCorpseButtonClicked);
mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked); mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked);
mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked); mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked);
@ -625,8 +651,18 @@ void ContainerWindow::onWindowResize(MyGUI::Window* window)
drawItems(); drawItems();
} }
void ContainerWindow::open(MWWorld::Ptr container) void ContainerWindow::open(MWWorld::Ptr container, bool loot)
{ {
mDisplayEquippedItems = true;
mHighlightEquippedItems = false;
if (container.getTypeName() == typeid(ESM::NPC).name() && !loot)
{
// we are stealing stuff
mDisplayEquippedItems = false;
}
mDisposeCorpseButton->setVisible(loot);
openContainer(container); openContainer(container);
setTitle(MWWorld::Class::get(container).getName(container)); setTitle(MWWorld::Class::get(container).getName(container));
drawItems(); drawItems();
@ -671,6 +707,22 @@ void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender)
} }
} }
void ContainerWindow::onDisposeCorpseButtonClicked(MyGUI::Widget *sender)
{
if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop)
{
onTakeAllButtonClicked(mTakeButton);
/// \todo I don't think this is the correct flag to check
if (MWWorld::Class::get(mPtr).isEssential(mPtr))
mWindowManager.messageBox("#{sDisposeCorpseFail}");
else
MWBase::Environment::get().getWorld()->deleteObject(mPtr);
mPtr = MWWorld::Ptr();
}
}
void ContainerWindow::onReferenceUnavailable() void ContainerWindow::onReferenceUnavailable()
{ {
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container);

View file

@ -82,6 +82,9 @@ namespace MWGui
void drawItems(); void drawItems();
protected: protected:
bool mDisplayEquippedItems;
bool mHighlightEquippedItems;
MyGUI::ScrollView* mItemView; MyGUI::ScrollView* mItemView;
MyGUI::Widget* mContainerWidget; MyGUI::Widget* mContainerWidget;
@ -111,14 +114,13 @@ namespace MWGui
virtual bool isTradeWindow() { return false; } virtual bool isTradeWindow() { return false; }
virtual bool isInventory() { return false; } virtual bool isInventory() { return false; }
virtual std::vector<MWWorld::Ptr> getEquippedItems() { return std::vector<MWWorld::Ptr>(); } virtual std::vector<MWWorld::Ptr> getEquippedItems();
virtual void _unequipItem(MWWorld::Ptr item) { ; } virtual void _unequipItem(MWWorld::Ptr item) { ; }
virtual bool isTrading() { return false; } virtual bool isTrading() { return false; }
virtual void onSelectedItemImpl(MWWorld::Ptr item) { ; } virtual void onSelectedItemImpl(MWWorld::Ptr item) { ; }
virtual bool ignoreEquippedItems() { return false; }
virtual std::vector<MWWorld::Ptr> itemsToIgnore() { return std::vector<MWWorld::Ptr>(); } virtual std::vector<MWWorld::Ptr> itemsToIgnore() { return std::vector<MWWorld::Ptr>(); }
virtual void notifyContentChanged() { ; } virtual void notifyContentChanged() { ; }
@ -131,15 +133,17 @@ namespace MWGui
virtual ~ContainerWindow(); virtual ~ContainerWindow();
void open(MWWorld::Ptr container); void open(MWWorld::Ptr container, bool loot=false);
protected: protected:
MyGUI::Button* mDisposeCorpseButton;
MyGUI::Button* mTakeButton; MyGUI::Button* mTakeButton;
MyGUI::Button* mCloseButton; MyGUI::Button* mCloseButton;
void onWindowResize(MyGUI::Window* window); void onWindowResize(MyGUI::Window* window);
void onCloseButtonClicked(MyGUI::Widget* _sender); void onCloseButtonClicked(MyGUI::Widget* _sender);
void onTakeAllButtonClicked(MyGUI::Widget* _sender); void onTakeAllButtonClicked(MyGUI::Widget* _sender);
void onDisposeCorpseButtonClicked(MyGUI::Widget* sender);
virtual void onReferenceUnavailable(); virtual void onReferenceUnavailable();
}; };

View file

@ -0,0 +1,131 @@
#include "cursor.hpp"
#include <MyGUI_PointerManager.h>
#include <MyGUI_InputManager.h>
#include <MyGUI_RenderManager.h>
#include <MyGUI_RotatingSkin.h>
#include <MyGUI_Gui.h>
#include <OgreMath.h>
namespace MWGui
{
ResourceImageSetPointerFix::ResourceImageSetPointerFix()
: mImageSet(NULL)
, mRotation(0)
{
}
ResourceImageSetPointerFix::~ResourceImageSetPointerFix()
{
}
void ResourceImageSetPointerFix::deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version)
{
Base::deserialization(_node, _version);
MyGUI::xml::ElementEnumerator info = _node->getElementEnumerator();
while (info.next("Property"))
{
const std::string& key = info->findAttribute("key");
const std::string& value = info->findAttribute("value");
if (key == "Point")
mPoint = MyGUI::IntPoint::parse(value);
else if (key == "Size")
mSize = MyGUI::IntSize::parse(value);
else if (key == "Rotation")
mRotation = MyGUI::utility::parseInt(value);
else if (key == "Resource")
mImageSet = MyGUI::ResourceManager::getInstance().getByName(value)->castType<MyGUI::ResourceImageSet>();
}
}
int ResourceImageSetPointerFix::getRotation()
{
return mRotation;
}
void ResourceImageSetPointerFix::setImage(MyGUI::ImageBox* _image)
{
if (mImageSet != NULL)
_image->setItemResourceInfo(mImageSet->getIndexInfo(0, 0));
}
void ResourceImageSetPointerFix::setPosition(MyGUI::ImageBox* _image, const MyGUI::IntPoint& _point)
{
_image->setCoord(_point.left - mPoint.left, _point.top - mPoint.top, mSize.width, mSize.height);
}
MyGUI::ResourceImageSetPtr ResourceImageSetPointerFix:: getImageSet()
{
return mImageSet;
}
MyGUI::IntPoint ResourceImageSetPointerFix::getHotSpot()
{
return mPoint;
}
MyGUI::IntSize ResourceImageSetPointerFix::getSize()
{
return mSize;
}
// ----------------------------------------------------------------------------------------
Cursor::Cursor()
{
// hide mygui's pointer since we're rendering it ourselves (because mygui's pointer doesn't support rotation)
MyGUI::PointerManager::getInstance().setVisible(false);
MyGUI::PointerManager::getInstance().eventChangeMousePointer += MyGUI::newDelegate(this, &Cursor::onCursorChange);
mWidget = MyGUI::Gui::getInstance().createWidget<MyGUI::ImageBox>("RotatingSkin",0,0,0,0,MyGUI::Align::Default,"Pointer","");
onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer());
}
Cursor::~Cursor()
{
}
void Cursor::onCursorChange(const std::string &name)
{
ResourceImageSetPointerFix* imgSetPtr = dynamic_cast<ResourceImageSetPointerFix*>(
MyGUI::PointerManager::getInstance().getByName(name));
assert(imgSetPtr != NULL);
MyGUI::ResourceImageSet* imgSet = imgSetPtr->getImageSet();
std::string texture = imgSet->getIndexInfo(0,0).texture;
mSize = imgSetPtr->getSize();
mHotSpot = imgSetPtr->getHotSpot();
int rotation = imgSetPtr->getRotation();
mWidget->setImageTexture(texture);
MyGUI::ISubWidget* main = mWidget->getSubWidgetMain();
MyGUI::RotatingSkin* rotatingSubskin = main->castType<MyGUI::RotatingSkin>();
rotatingSubskin->setCenter(MyGUI::IntPoint(mSize.width/2,mSize.height/2));
rotatingSubskin->setAngle(Ogre::Degree(rotation).valueRadians());
}
void Cursor::update()
{
MyGUI::IntPoint position = MyGUI::InputManager::getInstance().getMousePosition();
mWidget->setPosition(position - mHotSpot);
mWidget->setSize(mSize);
}
void Cursor::setVisible(bool visible)
{
mWidget->setVisible(visible);
}
}

View file

@ -0,0 +1,62 @@
#ifndef MWGUI_CURSOR_H
#define MWGUI_CURSOR_H
#include <MyGUI_IPointer.h>
#include <MyGUI_ResourceImageSet.h>
#include <MyGUI_RTTI.h>
namespace MWGui
{
/// \brief Allows us to get the members of
/// ResourceImageSetPointer that we need.
/// \example MyGUI::FactoryManager::getInstance().registerFactory<ResourceImageSetPointerFix>("Resource", "ResourceImageSetPointer");
/// MyGUI::ResourceManager::getInstance().load("core.xml");
class ResourceImageSetPointerFix :
public MyGUI::IPointer
{
MYGUI_RTTI_DERIVED( ResourceImageSetPointerFix )
public:
ResourceImageSetPointerFix();
virtual ~ResourceImageSetPointerFix();
virtual void deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version);
virtual void setImage(MyGUI::ImageBox* _image);
virtual void setPosition(MyGUI::ImageBox* _image, const MyGUI::IntPoint& _point);
//and now for the whole point of this class, allow us to get
//the hot spot, the image and the size of the cursor.
virtual MyGUI::ResourceImageSetPtr getImageSet();
virtual MyGUI::IntPoint getHotSpot();
virtual MyGUI::IntSize getSize();
virtual int getRotation();
private:
MyGUI::IntPoint mPoint;
MyGUI::IntSize mSize;
MyGUI::ResourceImageSetPtr mImageSet;
int mRotation; // rotation in degrees
};
class Cursor
{
public:
Cursor();
~Cursor();
void update ();
void setVisible (bool visible);
void onCursorChange (const std::string& name);
private:
MyGUI::ImageBox* mWidget;
MyGUI::IntSize mSize;
MyGUI::IntPoint mHotSpot;
};
}
#endif

View file

@ -1,16 +0,0 @@
#include "cursorreplace.hpp"
#include <boost/filesystem.hpp>
#include <openengine/ogre/imagerotate.hpp>
#include <OgreResourceGroupManager.h>
#include <OgreRoot.h>
using namespace MWGui;
CursorReplace::CursorReplace()
{
OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_vresize.png", 90);
OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_dresize1.png", -45);
OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_dresize2.png", 45);
}

View file

@ -1,16 +0,0 @@
#ifndef GAME_CURSORREPLACE_H
#define GAME_CURSORREPLACE_H
#include <string>
namespace MWGui
{
/// \brief MyGUI does not support rotating cursors, so we have to do it manually
class CursorReplace
{
public:
CursorReplace();
};
}
#endif

View file

@ -151,7 +151,7 @@ DialogueWindow::DialogueWindow(MWBase::WindowManager& parWindowManager)
getWidget(mTopicsList, "TopicsList"); getWidget(mTopicsList, "TopicsList");
mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic);
MyGUI::ButtonPtr byeButton; MyGUI::Button* byeButton;
getWidget(byeButton, "ByeButton"); getWidget(byeButton, "ByeButton");
byeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); byeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked);
@ -164,7 +164,7 @@ DialogueWindow::DialogueWindow(MWBase::WindowManager& parWindowManager)
void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender)
{ {
MyGUI::ISubWidgetText* t = mHistory->getClient()->getSubWidgetText(); MyGUI::ISubWidgetText* t = mHistory->getClient()->getSubWidgetText();
if(t == nullptr) if(t == NULL)
return; return;
const MyGUI::IntPoint& lastPressed = MyGUI::InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left); const MyGUI::IntPoint& lastPressed = MyGUI::InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left);
@ -223,50 +223,60 @@ void DialogueWindow::onByeClicked(MyGUI::Widget* _sender)
MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); MWBase::Environment::get().getDialogueManager()->goodbyeSelected();
} }
void DialogueWindow::onSelectTopic(std::string topic) void DialogueWindow::onSelectTopic(const std::string& topic, int id)
{ {
if (!mEnabled) return; if (!mEnabled) return;
const MWWorld::Store<ESM::GameSetting> &gmst = int separatorPos = mTopicsList->getItemCount();
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>(); for (unsigned int i=0; i<mTopicsList->getItemCount(); ++i)
{
if (mTopicsList->getItemNameAt(i) == "")
separatorPos = i;
}
if (topic == gmst.find("sBarter")->getString()) if (id > separatorPos)
{
/// \todo check if the player is allowed to trade with this actor (e.g. faction rank high enough)?
mWindowManager.pushGuiMode(GM_Barter);
mWindowManager.getTradeWindow()->startTrade(mPtr);
}
if (topic == gmst.find("sPersuasion")->getString())
{
mPersuasionDialog.setVisible(true);
}
else if (topic == gmst.find("sSpells")->getString())
{
mWindowManager.pushGuiMode(GM_SpellBuying);
mWindowManager.getSpellBuyingWindow()->startSpellBuying(mPtr);
}
else if (topic == gmst.find("sTravel")->getString())
{
mWindowManager.pushGuiMode(GM_Travel);
mWindowManager.getTravelWindow()->startTravel(mPtr);
}
else if (topic == gmst.find("sSpellMakingMenuTitle")->getString())
{
mWindowManager.pushGuiMode(GM_SpellCreation);
mWindowManager.startSpellMaking (mPtr);
}
else if (topic == gmst.find("sEnchanting")->getString())
{
mWindowManager.pushGuiMode(GM_Enchanting);
mWindowManager.startEnchanting (mPtr);
}
else if (topic == gmst.find("sServiceTrainingTitle")->getString())
{
mWindowManager.pushGuiMode(GM_Training);
mWindowManager.startTraining (mPtr);
}
else
MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic)); MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic));
else
{
const MWWorld::Store<ESM::GameSetting> &gmst =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
if (topic == gmst.find("sBarter")->getString())
{
/// \todo check if the player is allowed to trade with this actor (e.g. faction rank high enough)?
mWindowManager.pushGuiMode(GM_Barter);
mWindowManager.getTradeWindow()->startTrade(mPtr);
}
if (topic == gmst.find("sPersuasion")->getString())
{
mPersuasionDialog.setVisible(true);
}
else if (topic == gmst.find("sSpells")->getString())
{
mWindowManager.pushGuiMode(GM_SpellBuying);
mWindowManager.getSpellBuyingWindow()->startSpellBuying(mPtr);
}
else if (topic == gmst.find("sTravel")->getString())
{
mWindowManager.pushGuiMode(GM_Travel);
mWindowManager.getTravelWindow()->startTravel(mPtr);
}
else if (topic == gmst.find("sSpellMakingMenuTitle")->getString())
{
mWindowManager.pushGuiMode(GM_SpellCreation);
mWindowManager.startSpellMaking (mPtr);
}
else if (topic == gmst.find("sEnchanting")->getString())
{
mWindowManager.pushGuiMode(GM_Enchanting);
mWindowManager.startEnchanting (mPtr);
}
else if (topic == gmst.find("sServiceTrainingTitle")->getString())
{
mWindowManager.pushGuiMode(GM_Training);
mWindowManager.startTraining (mPtr);
}
}
} }
void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName)
@ -381,7 +391,7 @@ std::string DialogueWindow::parseText(const std::string& text)
std::vector<MWDialogue::HyperTextToken> hypertext = MWDialogue::ParseHyperText(text); std::vector<MWDialogue::HyperTextToken> hypertext = MWDialogue::ParseHyperText(text);
size_t historySize = 0; size_t historySize = 0;
if(mHistory->getClient()->getSubWidgetText() != nullptr) if(mHistory->getClient()->getSubWidgetText() != NULL)
{ {
historySize = mHistory->getOnlyText().size(); historySize = mHistory->getOnlyText().size();
} }

View file

@ -85,7 +85,7 @@ namespace MWGui
}; };
protected: protected:
void onSelectTopic(std::string topic); void onSelectTopic(const std::string& topic, int id);
void onByeClicked(MyGUI::Widget* _sender); void onByeClicked(MyGUI::Widget* _sender);
void onHistoryClicked(MyGUI::Widget* _sender); void onHistoryClicked(MyGUI::Widget* _sender);
void onMouseWheel(MyGUI::Widget* _sender, int _rel); void onMouseWheel(MyGUI::Widget* _sender, int _rel);
@ -113,7 +113,7 @@ namespace MWGui
DialogueHistory* mHistory; DialogueHistory* mHistory;
Widgets::MWList* mTopicsList; Widgets::MWList* mTopicsList;
MyGUI::ProgressPtr mDispositionBar; MyGUI::ProgressPtr mDispositionBar;
MyGUI::EditPtr mDispositionText; MyGUI::EditBox* mDispositionText;
PersuasionDialog mPersuasionDialog; PersuasionDialog mPersuasionDialog;

View file

@ -1,7 +1,5 @@
#include "exposedwindow.hpp" #include "exposedwindow.hpp"
#include "MyGUI_Window.h"
namespace MWGui namespace MWGui
{ {
MyGUI::VectorWidgetPtr ExposedWindow::getSkinWidgetsByName (const std::string &name) MyGUI::VectorWidgetPtr ExposedWindow::getSkinWidgetsByName (const std::string &name)
@ -16,7 +14,7 @@ namespace MWGui
if (widgets.empty()) if (widgets.empty())
{ {
MYGUI_ASSERT( ! _throw, "widget name '" << _name << "' not found in skin of layout '" << getName() << "'"); MYGUI_ASSERT( ! _throw, "widget name '" << _name << "' not found in skin of layout '" << getName() << "'");
return nullptr; return NULL;
} }
else else
{ {

View file

@ -1,7 +1,7 @@
#ifndef MWGUI_EXPOSEDWINDOW_H #ifndef MWGUI_EXPOSEDWINDOW_H
#define MWGUI_EXPOSEDWINDOW_H #define MWGUI_EXPOSEDWINDOW_H
#include "MyGUI_Window.h" #include <MyGUI_Window.h>
namespace MWGui namespace MWGui
{ {

View file

@ -2,7 +2,8 @@
#include <cmath> #include <cmath>
#include <MyGUI.h> #include <MyGUI_Widget.h>
#include <MyGUI_RenderManager.h>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
@ -19,6 +20,7 @@
#include "inventorywindow.hpp" #include "inventorywindow.hpp"
#include "container.hpp" #include "container.hpp"
#include "console.hpp" #include "console.hpp"
#include "spellicons.hpp"
using namespace MWGui; using namespace MWGui;
@ -32,7 +34,6 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop)
, mWeapStatus(NULL) , mWeapStatus(NULL)
, mSpellStatus(NULL) , mSpellStatus(NULL)
, mEffectBox(NULL) , mEffectBox(NULL)
, mEffect1(NULL)
, mMinimap(NULL) , mMinimap(NULL)
, mCompass(NULL) , mCompass(NULL)
, mCrosshair(NULL) , mCrosshair(NULL)
@ -86,9 +87,7 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop)
mSpellBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked); mSpellBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked);
getWidget(mEffectBox, "EffectBox"); getWidget(mEffectBox, "EffectBox");
getWidget(mEffect1, "Effect1");
mEffectBoxBaseRight = viewSize.width - mEffectBox->getRight(); mEffectBoxBaseRight = viewSize.width - mEffectBox->getRight();
mEffectBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked);
getWidget(mMinimapBox, "MiniMapBox"); getWidget(mMinimapBox, "MiniMapBox");
mMinimapBoxBaseRight = viewSize.width - mMinimapBox->getRight(); mMinimapBoxBaseRight = viewSize.width - mMinimapBox->getRight();
@ -107,13 +106,18 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop)
getWidget(mTriangleCounter, "TriangleCounter"); getWidget(mTriangleCounter, "TriangleCounter");
getWidget(mBatchCounter, "BatchCounter"); getWidget(mBatchCounter, "BatchCounter");
setEffect("icons\\s\\tx_s_chameleon.dds");
LocalMapBase::init(mMinimap, mCompass, this); LocalMapBase::init(mMinimap, mCompass, this);
mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked); mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked);
mMainWidget->eventMouseMove += MyGUI::newDelegate(this, &HUD::onWorldMouseOver); mMainWidget->eventMouseMove += MyGUI::newDelegate(this, &HUD::onWorldMouseOver);
mMainWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &HUD::onWorldMouseLostFocus); mMainWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &HUD::onWorldMouseLostFocus);
mSpellIcons = new SpellIcons();
}
HUD::~HUD()
{
delete mSpellIcons;
} }
void HUD::setFpsLevel(int level) void HUD::setFpsLevel(int level)
@ -156,11 +160,6 @@ void HUD::setBatchCount(unsigned int count)
mBatchCounter->setCaption(boost::lexical_cast<std::string>(count)); mBatchCounter->setCaption(boost::lexical_cast<std::string>(count));
} }
void HUD::setEffect(const char *img)
{
mEffect1->setImageTexture(img);
}
void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat<float>& value) void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat<float>& value)
{ {
static const char *ids[] = static const char *ids[] =
@ -222,7 +221,7 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender)
else else
world->dropObjectOnGround(world->getPlayer().getPlayer(), object); world->dropObjectOnGround(world->getPlayer().getPlayer(), object);
MyGUI::PointerManager::getInstance().setPointer("arrow"); MWBase::Environment::get().getWindowManager()->changePointer("arrow");
std::string sound = MWWorld::Class::get(object).getDownSoundId(object); std::string sound = MWWorld::Class::get(object).getDownSoundId(object);
MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0);
@ -273,21 +272,21 @@ void HUD::onWorldMouseOver(MyGUI::Widget* _sender, int x, int y)
bool canDrop = world->canPlaceObject(mouseX, mouseY); bool canDrop = world->canPlaceObject(mouseX, mouseY);
if (!canDrop) if (!canDrop)
MyGUI::PointerManager::getInstance().setPointer("drop_ground"); MWBase::Environment::get().getWindowManager()->changePointer("drop_ground");
else else
MyGUI::PointerManager::getInstance().setPointer("arrow"); MWBase::Environment::get().getWindowManager()->changePointer("arrow");
} }
else else
{ {
MyGUI::PointerManager::getInstance().setPointer("arrow"); MWBase::Environment::get().getWindowManager()->changePointer("arrow");
mWorldMouseOver = true; mWorldMouseOver = true;
} }
} }
void HUD::onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new) void HUD::onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new)
{ {
MyGUI::PointerManager::getInstance().setPointer("arrow"); MWBase::Environment::get().getWindowManager()->changePointer("arrow");
mWorldMouseOver = false; mWorldMouseOver = false;
} }
@ -542,3 +541,8 @@ void HUD::updatePositions()
mMapVisible = mMinimapBox->getVisible (); mMapVisible = mMinimapBox->getVisible ();
mEffectBox->setPosition((viewSize.width - mEffectBoxBaseRight) - mEffectBox->getWidth() + effectsDx, mEffectBox->getTop()); mEffectBox->setPosition((viewSize.width - mEffectBoxBaseRight) - mEffectBox->getWidth() + effectsDx, mEffectBox->getTop());
} }
void HUD::update()
{
mSpellIcons->updateWidgets(mEffectBox, true);
}

View file

@ -8,12 +8,13 @@
namespace MWGui namespace MWGui
{ {
class DragAndDrop; class DragAndDrop;
class SpellIcons;
class HUD : public OEngine::GUI::Layout, public LocalMapBase class HUD : public OEngine::GUI::Layout, public LocalMapBase
{ {
public: public:
HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop); HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop);
void setEffect(const char *img); virtual ~HUD();
void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value); void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value);
void setFPS(float fps); void setFPS(float fps);
void setTriangleCount(unsigned int count); void setTriangleCount(unsigned int count);
@ -43,6 +44,10 @@ namespace MWGui
bool getWorldMouseOver() { return mWorldMouseOver; } bool getWorldMouseOver() { return mWorldMouseOver; }
MyGUI::Widget* getEffectBox() { return mEffectBox; }
void update();
private: private:
MyGUI::ProgressPtr mHealth, mMagicka, mStamina; MyGUI::ProgressPtr mHealth, mMagicka, mStamina;
MyGUI::Widget* mHealthFrame; MyGUI::Widget* mHealthFrame;
@ -51,7 +56,6 @@ namespace MWGui
MyGUI::ProgressPtr mWeapStatus, mSpellStatus; MyGUI::ProgressPtr mWeapStatus, mSpellStatus;
MyGUI::Widget *mEffectBox, *mMinimapBox; MyGUI::Widget *mEffectBox, *mMinimapBox;
MyGUI::Button* mMinimapButton; MyGUI::Button* mMinimapButton;
MyGUI::ImageBox* mEffect1;
MyGUI::ScrollView* mMinimap; MyGUI::ScrollView* mMinimap;
MyGUI::ImageBox* mCompass; MyGUI::ImageBox* mCompass;
MyGUI::ImageBox* mCrosshair; MyGUI::ImageBox* mCrosshair;
@ -60,7 +64,7 @@ namespace MWGui
MyGUI::Widget* mDummy; MyGUI::Widget* mDummy;
MyGUI::WidgetPtr mFpsBox; MyGUI::Widget* mFpsBox;
MyGUI::TextBox* mFpsCounter; MyGUI::TextBox* mFpsCounter;
MyGUI::TextBox* mTriangleCounter; MyGUI::TextBox* mTriangleCounter;
MyGUI::TextBox* mBatchCounter; MyGUI::TextBox* mBatchCounter;
@ -85,6 +89,8 @@ namespace MWGui
bool mWorldMouseOver; bool mWorldMouseOver;
SpellIcons* mSpellIcons;
void onWorldClicked(MyGUI::Widget* _sender); void onWorldClicked(MyGUI::Widget* _sender);
void onWorldMouseOver(MyGUI::Widget* _sender, int x, int y); void onWorldMouseOver(MyGUI::Widget* _sender, int x, int y);
void onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new); void onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new);

View file

@ -1,7 +1,7 @@
#ifndef MWGUI_IMAGEBUTTON_H #ifndef MWGUI_IMAGEBUTTON_H
#define MWGUI_IMAGEBUTTON_H #define MWGUI_IMAGEBUTTON_H
#include "MyGUI_ImageBox.h" #include <MyGUI_ImageBox.h>
namespace MWGui namespace MWGui
{ {

View file

@ -160,11 +160,8 @@ namespace MWGui
// the "Take" button should not be visible. // the "Take" button should not be visible.
// NOTE: the take button is "reset" when the window opens, so we can safely do the following // NOTE: the take button is "reset" when the window opens, so we can safely do the following
// without screwing up future book windows // without screwing up future book windows
if (mDragAndDrop->mDraggedFrom == this) mWindowManager.getBookWindow()->setTakeButtonShow(false);
{ mWindowManager.getScrollWindow()->setTakeButtonShow(false);
mWindowManager.getBookWindow()->setTakeButtonShow(false);
mWindowManager.getScrollWindow()->setTakeButtonShow(false);
}
mDragAndDrop->mIsOnDragAndDrop = false; mDragAndDrop->mIsOnDragAndDrop = false;
MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget);
@ -214,24 +211,6 @@ namespace MWGui
return MWWorld::Ptr(); return MWWorld::Ptr();
} }
std::vector<MWWorld::Ptr> InventoryWindow::getEquippedItems()
{
MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
std::vector<MWWorld::Ptr> items;
for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot)
{
MWWorld::ContainerStoreIterator it = invStore.getSlot(slot);
if (it != invStore.end())
{
items.push_back(*it);
}
}
return items;
}
void InventoryWindow::_unequipItem(MWWorld::Ptr item) void InventoryWindow::_unequipItem(MWWorld::Ptr item)
{ {
MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);

View file

@ -64,7 +64,6 @@ namespace MWGui
virtual bool isTrading() { return mTrading; } virtual bool isTrading() { return mTrading; }
virtual bool isInventory() { return true; } virtual bool isInventory() { return true; }
virtual std::vector<MWWorld::Ptr> getEquippedItems();
virtual void _unequipItem(MWWorld::Ptr item); virtual void _unequipItem(MWWorld::Ptr item);
virtual void onReferenceUnavailable() { ; } virtual void onReferenceUnavailable() { ; }

View file

@ -29,8 +29,8 @@ namespace MWGui
void notifyNextPage(MyGUI::Widget* _sender); void notifyNextPage(MyGUI::Widget* _sender);
void notifyPrevPage(MyGUI::Widget* _sender); void notifyPrevPage(MyGUI::Widget* _sender);
MyGUI::EditPtr mLeftTextWidget; MyGUI::EditBox* mLeftTextWidget;
MyGUI::EditPtr mRightTextWidget; MyGUI::EditBox* mRightTextWidget;
MWGui::ImageButton* mPrevBtn; MWGui::ImageButton* mPrevBtn;
MWGui::ImageButton* mNextBtn; MWGui::ImageButton* mNextBtn;
std::vector<std::string> mLeftPages; std::vector<std::string> mLeftPages;

View file

@ -23,6 +23,8 @@ namespace MWGui
getWidget(mOkButton, "OkButton"); getWidget(mOkButton, "OkButton");
getWidget(mClassImage, "ClassImage"); getWidget(mClassImage, "ClassImage");
getWidget(mLevelText, "LevelText"); getWidget(mLevelText, "LevelText");
getWidget(mLevelDescription, "LevelDescription");
getWidget(mCoinBox, "Coins");
mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &LevelupDialog::onOkButtonClicked); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &LevelupDialog::onOkButtonClicked);
@ -80,11 +82,13 @@ namespace MWGui
void LevelupDialog::resetCoins () void LevelupDialog::resetCoins ()
{ {
int curX = mMainWidget->getWidth()/2 - (16 + 2) * 1.5; int curX = 0;
for (int i=0; i<3; ++i) for (int i=0; i<3; ++i)
{ {
MyGUI::ImageBox* image = mCoins[i]; MyGUI::ImageBox* image = mCoins[i];
image->setCoord(MyGUI::IntCoord(curX,250,16,16)); image->detachFromWidget();
image->attachToWidget(mCoinBox);
image->setCoord(MyGUI::IntCoord(curX,0,16,16));
curX += 24+2; curX += 24+2;
} }
} }
@ -95,6 +99,9 @@ namespace MWGui
for (unsigned int i=0; i<mSpentAttributes.size(); ++i) for (unsigned int i=0; i<mSpentAttributes.size(); ++i)
{ {
MyGUI::ImageBox* image = mCoins[i]; MyGUI::ImageBox* image = mCoins[i];
image->detachFromWidget();
image->attachToWidget(mMainWidget);
int attribute = mSpentAttributes[i]; int attribute = mSpentAttributes[i];
int xdiff = mAttributeMultipliers[attribute]->getCaption() == "" ? 0 : 30; int xdiff = mAttributeMultipliers[attribute]->getCaption() == "" ? 0 : 30;
@ -113,8 +120,6 @@ namespace MWGui
MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(player).getCreatureStats (player); MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(player).getCreatureStats (player);
MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player); MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player);
center();
mSpentAttributes.clear(); mSpentAttributes.clear();
resetCoins(); resetCoins();
@ -128,16 +133,25 @@ namespace MWGui
mClassImage->setImageTexture ("textures\\levelup\\" + cls->mId + ".dds"); mClassImage->setImageTexture ("textures\\levelup\\" + cls->mId + ".dds");
/// \todo replace this with INI-imported texts
int level = creatureStats.getLevel ()+1; int level = creatureStats.getLevel ()+1;
mLevelText->setCaptionWithReplacing("#{sLevelUpMenu1} " + boost::lexical_cast<std::string>(level)); mLevelText->setCaptionWithReplacing("#{sLevelUpMenu1} " + boost::lexical_cast<std::string>(level));
std::string levelupdescription;
if(level>20)
levelupdescription=world->getFallback("Level_Up_Default");
else
levelupdescription=world->getFallback("Level_Up_Level"+boost::lexical_cast<std::string>(level));
mLevelDescription->setCaption (levelupdescription);
for (int i=0; i<8; ++i) for (int i=0; i<8; ++i)
{ {
MyGUI::TextBox* text = mAttributeMultipliers[i]; MyGUI::TextBox* text = mAttributeMultipliers[i];
int mult = pcStats.getLevelupAttributeMultiplier (i); int mult = pcStats.getLevelupAttributeMultiplier (i);
text->setCaption(mult <= 1 ? "" : "x" + boost::lexical_cast<std::string>(mult)); text->setCaption(mult <= 1 ? "" : "x" + boost::lexical_cast<std::string>(mult));
} }
center();
} }
void LevelupDialog::onOkButtonClicked (MyGUI::Widget* sender) void LevelupDialog::onOkButtonClicked (MyGUI::Widget* sender)

View file

@ -17,6 +17,9 @@ namespace MWGui
MyGUI::Button* mOkButton; MyGUI::Button* mOkButton;
MyGUI::ImageBox* mClassImage; MyGUI::ImageBox* mClassImage;
MyGUI::TextBox* mLevelText; MyGUI::TextBox* mLevelText;
MyGUI::EditBox* mLevelDescription;
MyGUI::Widget* mCoinBox;
std::vector<MyGUI::Button*> mAttributes; std::vector<MyGUI::Button*> mAttributes;
std::vector<MyGUI::TextBox*> mAttributeValues; std::vector<MyGUI::TextBox*> mAttributeValues;

View file

@ -1,6 +1,9 @@
#include "list.hpp" #include "list.hpp"
#include <MyGUI.h> #include <MyGUI_Gui.h>
#include <MyGUI_Button.h>
#include <MyGUI_ImageBox.h>
#include <MyGUI_ScrollBar.h>
using namespace MWGui; using namespace MWGui;
using namespace MWGui::Widgets; using namespace MWGui::Widgets;
@ -20,7 +23,7 @@ void MWList::initialiseOverride()
if (mClient == 0) if (mClient == 0)
mClient = this; mClient = this;
mScrollView = mClient->createWidgetReal<MyGUI::ScrollView>( mScrollView = mClient->createWidgetReal<MWGui::Widgets::MWScrollView>(
"MW_ScrollView", MyGUI::FloatCoord(0.0, 0.0, 1.0, 1.0), "MW_ScrollView", MyGUI::FloatCoord(0.0, 0.0, 1.0, 1.0),
MyGUI::Align::Top | MyGUI::Align::Left | MyGUI::Align::Stretch, getName() + "_ScrollView"); MyGUI::Align::Top | MyGUI::Align::Left | MyGUI::Align::Stretch, getName() + "_ScrollView");
} }
@ -45,6 +48,7 @@ void MWList::redraw(bool scrollbarShown)
const int _scrollBarWidth = 24; // fetch this from skin? const int _scrollBarWidth = 24; // fetch this from skin?
const int scrollBarWidth = scrollbarShown ? _scrollBarWidth : 0; const int scrollBarWidth = scrollbarShown ? _scrollBarWidth : 0;
const int spacing = 3; const int spacing = 3;
size_t scrollbarPosition = mScrollView->getScrollPosition();
while (mScrollView->getChildCount()) while (mScrollView->getChildCount())
{ {
@ -52,6 +56,7 @@ void MWList::redraw(bool scrollbarShown)
} }
mItemHeight = 0; mItemHeight = 0;
int i=0;
for (std::vector<std::string>::const_iterator it=mItems.begin(); for (std::vector<std::string>::const_iterator it=mItems.begin();
it!=mItems.end(); ++it) it!=mItems.end(); ++it)
{ {
@ -68,6 +73,7 @@ void MWList::redraw(bool scrollbarShown)
int height = button->getTextSize().height; int height = button->getTextSize().height;
button->setSize(MyGUI::IntSize(button->getSize().width, height)); button->setSize(MyGUI::IntSize(button->getSize().width, height));
button->setUserData(i);
mItemHeight += height + spacing; mItemHeight += height + spacing;
} }
@ -80,11 +86,17 @@ void MWList::redraw(bool scrollbarShown)
mItemHeight += 18 + spacing; mItemHeight += 18 + spacing;
} }
++i;
} }
mScrollView->setCanvasSize(mClient->getSize().width + (_scrollBarWidth-scrollBarWidth), std::max(mItemHeight, mClient->getSize().height)); mScrollView->setCanvasSize(mClient->getSize().width + (_scrollBarWidth-scrollBarWidth), std::max(mItemHeight, mClient->getSize().height));
if (!scrollbarShown && mItemHeight > mClient->getSize().height) if (!scrollbarShown && mItemHeight > mClient->getSize().height)
redraw(true); redraw(true);
size_t scrollbarRange = mScrollView->getScrollRange();
if(scrollbarPosition > scrollbarRange)
scrollbarPosition = scrollbarRange;
mScrollView->setScrollPosition(scrollbarPosition);
} }
bool MWList::hasItem(const std::string& name) bool MWList::hasItem(const std::string& name)
@ -126,8 +138,8 @@ void MWList::onMouseWheel(MyGUI::Widget* _sender, int _rel)
void MWList::onItemSelected(MyGUI::Widget* _sender) void MWList::onItemSelected(MyGUI::Widget* _sender)
{ {
std::string name = static_cast<MyGUI::Button*>(_sender)->getCaption(); std::string name = static_cast<MyGUI::Button*>(_sender)->getCaption();
int id = *_sender->getUserData<int>();
eventItemSelected(name); eventItemSelected(name, id);
eventWidgetSelected(_sender); eventWidgetSelected(_sender);
} }
@ -135,3 +147,17 @@ MyGUI::Widget* MWList::getItemWidget(const std::string& name)
{ {
return mScrollView->findWidget (getName() + "_item_" + name); return mScrollView->findWidget (getName() + "_item_" + name);
} }
size_t MWScrollView::getScrollPosition()
{
return getVScroll()->getScrollPosition();
}
void MWScrollView::setScrollPosition(size_t position)
{
getVScroll()->setScrollPosition(position);
}
size_t MWScrollView::getScrollRange()
{
return getVScroll()->getScrollRange();
}

View file

@ -1,12 +1,25 @@
#ifndef MWGUI_LIST_HPP #ifndef MWGUI_LIST_HPP
#define MWGUI_LIST_HPP #define MWGUI_LIST_HPP
#include <MyGUI.h> #include <MyGUI_Widget.h>
#include <MyGUI_ScrollView.h>
namespace MWGui namespace MWGui
{ {
namespace Widgets namespace Widgets
{ {
/**
* \brief a custom ScrollView which has access to scrollbar properties
*/
class MWScrollView : public MyGUI::ScrollView
{
MYGUI_RTTI_DERIVED(MWScrollView)
public:
size_t getScrollPosition();
void setScrollPosition(size_t);
size_t getScrollRange();
};
/** /**
* \brief a very simple list widget that supports word-wrapping entries * \brief a very simple list widget that supports word-wrapping entries
* \note if the width or height of the list changes, you must call adjustSize() method * \note if the width or height of the list changes, you must call adjustSize() method
@ -17,14 +30,14 @@ namespace MWGui
public: public:
MWList(); MWList();
typedef MyGUI::delegates::CMultiDelegate1<std::string> EventHandle_String; typedef MyGUI::delegates::CMultiDelegate2<const std::string&, int> EventHandle_StringInt;
typedef MyGUI::delegates::CMultiDelegate1<MyGUI::Widget*> EventHandle_Widget; typedef MyGUI::delegates::CMultiDelegate1<MyGUI::Widget*> EventHandle_Widget;
/** /**
* Event: Item selected with the mouse. * Event: Item selected with the mouse.
* signature: void method(std::string itemName) * signature: void method(std::string itemName)
*/ */
EventHandle_String eventItemSelected; EventHandle_StringInt eventItemSelected;
/** /**
* Event: Item selected with the mouse. * Event: Item selected with the mouse.
@ -58,7 +71,7 @@ namespace MWGui
void onItemSelected(MyGUI::Widget* _sender); void onItemSelected(MyGUI::Widget* _sender);
private: private:
MyGUI::ScrollView* mScrollView; MWGui::Widgets::MWScrollView* mScrollView;
MyGUI::Widget* mClient; MyGUI::Widget* mClient;
std::vector<std::string> mItems; std::vector<std::string> mItems;

View file

@ -106,7 +106,7 @@ namespace MWGui
float progress = (float(mCurrentCellLoading)+refProgress) / float(mTotalCellsLoading); float progress = (float(mCurrentCellLoading)+refProgress) / float(mTotalCellsLoading);
assert(progress <= 1 && progress >= 0); assert(progress <= 1 && progress >= 0);
mLoadingText->setCaption(stage + "... "); mLoadingText->setCaption(stage);
mProgressBar->setProgressPosition (static_cast<size_t>(progress * 1000)); mProgressBar->setProgressPosition (static_cast<size_t>(progress * 1000));
static float loadingScreenFps = 30.f; static float loadingScreenFps = 30.f;

View file

@ -19,6 +19,8 @@ namespace MWGui
void onResChange(int w, int h); void onResChange(int w, int h);
void updateWindow(Ogre::RenderWindow* rw) { mWindow = rw; }
private: private:
bool mFirstLoad; bool mFirstLoad;

View file

@ -6,6 +6,8 @@
#include <OgreTextureManager.h> #include <OgreTextureManager.h>
#include <OgreSceneNode.h> #include <OgreSceneNode.h>
#include <MyGUI_Gui.h>
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
@ -13,6 +15,8 @@
#include "../mwrender/globalmap.hpp" #include "../mwrender/globalmap.hpp"
#include "widgets.hpp"
using namespace MWGui; using namespace MWGui;
LocalMapBase::LocalMapBase() LocalMapBase::LocalMapBase()
@ -96,6 +100,7 @@ void LocalMapBase::applyFogOfWar()
: ""); : "");
} }
} }
notifyMapChanged ();
} }
void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2) void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2)
@ -425,3 +430,17 @@ void MapWindow::notifyPlayerUpdate ()
{ {
globalMapUpdatePlayer (); globalMapUpdatePlayer ();
} }
void MapWindow::notifyMapChanged ()
{
// workaround to prevent the map from drawing on top of the button
MyGUI::IntCoord oldCoord = mButton->getCoord ();
MyGUI::Gui::getInstance().destroyWidget (mButton);
mButton = mMainWidget->createWidget<MWGui::Widgets::AutoSizedButton>("MW_Button",
oldCoord, MyGUI::Align::Bottom | MyGUI::Align::Right);
mButton->setProperty ("ExpandDirection", "Left");
mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked);
mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" :
"#{sWorld}");
}

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