diff --git a/CMakeLists.txt b/CMakeLists.txt index 577b6f6b2..cfd1c7dd3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -391,11 +391,11 @@ if(WIN32) INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".") SET(CPACK_GENERATOR "NSIS") - SET(CPACK_PACKAGE_NAME "OpenMW") + SET(CPACK_PACKAGE_NAME "OpenMW ${OPENMW_VERSION}") SET(CPACK_PACKAGE_VENDOR "OpenMW.org") SET(CPACK_PACKAGE_VERSION ${OPENMW_VERSION}) SET(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR}) - SET(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINO}) + SET(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINOR}) SET(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE}) SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW;omwlauncher;OpenMW Launcher") SET(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '\$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Readme.lnk' '\$INSTDIR\\\\readme.txt'") diff --git a/apps/esmtool/labels.cpp b/apps/esmtool/labels.cpp index 9fb233237..f08c31003 100644 --- a/apps/esmtool/labels.cpp +++ b/apps/esmtool/labels.cpp @@ -16,7 +16,7 @@ #include #include -std::string bodyPartLabel(char idx) +std::string bodyPartLabel(int idx) { const char *bodyPartLabels[] = { "Head", @@ -47,14 +47,14 @@ std::string bodyPartLabel(char idx) "Weapon", "Tail" }; - - if ((int)idx >= 0 && (int)(idx) <= 26) - return bodyPartLabels[(int)(idx)]; + + if (idx >= 0 && idx <= 26) + return bodyPartLabels[idx]; else return "Invalid"; } -std::string meshPartLabel(char idx) +std::string meshPartLabel(int idx) { const char *meshPartLabels[] = { "Head", @@ -73,25 +73,25 @@ std::string meshPartLabel(char idx) "Clavicle", "Tail" }; - - if ((int)(idx) >= 0 && (int)(idx) <= ESM::BodyPart::MP_Tail) - return meshPartLabels[(int)(idx)]; + + if (idx >= 0 && idx <= ESM::BodyPart::MP_Tail) + return meshPartLabels[idx]; else return "Invalid"; } -std::string meshTypeLabel(char idx) +std::string meshTypeLabel(int idx) { const char *meshTypeLabels[] = { "Skin", "Clothing", "Armor" }; - - if ((int)(idx) >= 0 && (int)(idx) <= ESM::BodyPart::MT_Armor) - return meshTypeLabels[(int)(idx)]; + + if (idx >= 0 && idx <= ESM::BodyPart::MT_Armor) + return meshTypeLabels[idx]; else - return "Invalid"; + return "Invalid"; } std::string clothingTypeLabel(int idx) @@ -108,7 +108,7 @@ std::string clothingTypeLabel(int idx) "Ring", "Amulet" }; - + if (idx >= 0 && idx <= 9) return clothingTypeLabels[idx]; else diff --git a/apps/esmtool/labels.hpp b/apps/esmtool/labels.hpp index 7f1ff7986..48d7b249b 100644 --- a/apps/esmtool/labels.hpp +++ b/apps/esmtool/labels.hpp @@ -3,9 +3,9 @@ #include -std::string bodyPartLabel(char idx); -std::string meshPartLabel(char idx); -std::string meshTypeLabel(char idx); +std::string bodyPartLabel(int idx); +std::string meshPartLabel(int idx); +std::string meshTypeLabel(int idx); std::string clothingTypeLabel(int idx); std::string armorTypeLabel(int idx); std::string dialogTypeLabel(int idx); diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 8cee3f0f4..d5d389a14 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -59,7 +59,7 @@ opencs_units (view/world ) opencs_units_noqt (view/world - dialoguesubview util subviews + dialoguesubview util subviews enumdelegate vartypedelegate ) @@ -75,7 +75,7 @@ opencs_units_noqt (view/tools set (OPENCS_US ) -set (OPENCS_RES +set (OPENCS_RES ../../files/opencs/resources.qrc ) source_group (opencs FILES ${OPENCS_SRC} ${OPENCS_HDR}) @@ -104,4 +104,4 @@ target_link_libraries(opencs ${Boost_LIBRARIES} ${QT_LIBRARIES} components -) \ No newline at end of file +) diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index 4b1a688c2..aa315804b 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -5,6 +5,7 @@ #include #include +#include class Application : public QApplication { @@ -31,9 +32,12 @@ class Application : public QApplication int main(int argc, char *argv[]) { + Q_INIT_RESOURCE (resources); Application mApplication (argc, argv); + mApplication.setWindowIcon (QIcon (":./opencs.png")); + CS::Editor editor; return editor.run(); -} \ No newline at end of file +} diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 796135c3f..da29f6c68 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -18,6 +18,136 @@ void CSMDoc::Document::load (const std::vector::const_i if (lastAsModified) getData().loadFile (*end2, false); + + addOptionalGmsts(); +} + +void CSMDoc::Document::addOptionalGmsts() +{ + static const char *sFloats[] = + { + "fCombatDistanceWerewolfMod", + "fFleeDistance", + "fWereWolfAcrobatics", + "fWereWolfAgility", + "fWereWolfAlchemy", + "fWereWolfAlteration", + "fWereWolfArmorer", + "fWereWolfAthletics", + "fWereWolfAxe", + "fWereWolfBlock", + "fWereWolfBluntWeapon", + "fWereWolfConjuration", + "fWereWolfDestruction", + "fWereWolfEnchant", + "fWereWolfEndurance", + "fWereWolfFatigue", + "fWereWolfHandtoHand", + "fWereWolfHealth", + "fWereWolfHeavyArmor", + "fWereWolfIllusion", + "fWereWolfIntellegence", + "fWereWolfLightArmor", + "fWereWolfLongBlade", + "fWereWolfLuck", + "fWereWolfMagicka", + "fWereWolfMarksman", + "fWereWolfMediumArmor", + "fWereWolfMerchantile", + "fWereWolfMysticism", + "fWereWolfPersonality", + "fWereWolfRestoration", + "fWereWolfRunMult", + "fWereWolfSecurity", + "fWereWolfShortBlade", + "fWereWolfSilverWeaponDamageMult", + "fWereWolfSneak", + "fWereWolfSpear", + "fWereWolfSpeechcraft", + "fWereWolfSpeed", + "fWereWolfStrength", + "fWereWolfUnarmored", + "fWereWolfWillPower", + 0 + }; + + static const char *sIntegers[] = + { + "iWereWolfBounty", + "iWereWolfFightMod", + "iWereWolfFleeMod", + "iWereWolfLevelToAttack", + 0 + }; + + static const char *sStrings[] = + { + "sCompanionShare", + "sCompanionWarningButtonOne", + "sCompanionWarningButtonTwo", + "sCompanionWarningMessage", + "sDeleteNote", + "sEditNote", + "sEffectSummonCreature01", + "sEffectSummonCreature02", + "sEffectSummonCreature03", + "sEffectSummonCreature04", + "sEffectSummonCreature05", + "sEffectSummonFabricant", + "sLevitateDisabled", + "sMagicCreature01ID", + "sMagicCreature02ID", + "sMagicCreature03ID", + "sMagicCreature04ID", + "sMagicCreature05ID", + "sMagicFabricantID", + "sMaxSale", + "sProfitValue", + "sTeleportDisabled", + "sWerewolfAlarmMessage", + "sWerewolfPopup", + "sWerewolfRefusal", + "sWerewolfRestMessage", + 0 + }; + + for (int i=0; sFloats[i]; ++i) + { + ESM::GameSetting gmst; + gmst.mId = sFloats[i]; + gmst.mF = 0; + gmst.mType = ESM::VT_Float; + addOptionalGmst (gmst); + } + + for (int i=0; sIntegers[i]; ++i) + { + ESM::GameSetting gmst; + gmst.mId = sIntegers[i]; + gmst.mI = 0; + gmst.mType = ESM::VT_Long; + addOptionalGmst (gmst); + } + + for (int i=0; sStrings[i]; ++i) + { + ESM::GameSetting gmst; + gmst.mId = sStrings[i]; + gmst.mStr = ""; + gmst.mType = ESM::VT_String; + addOptionalGmst (gmst); + } +} + +void CSMDoc::Document::addOptionalGmst (const ESM::GameSetting& gmst) +{ + if (getData().getGmsts().searchId (gmst.mId)==-1) + { + CSMWorld::Record record; + record.mBase = gmst; + record.mState = CSMWorld::RecordBase::State_BaseOnly; + getData().getGmsts().appendRecord (record); + } } void CSMDoc::Document::createBase() diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 0162681bc..413e840d3 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -17,6 +17,11 @@ class QAbstractItemModel; +namespace ESM +{ + struct GameSetting; +} + namespace CSMDoc { class Document : public QObject @@ -46,6 +51,10 @@ namespace CSMDoc void createBase(); + void addOptionalGmsts(); + + void addOptionalGmst (const ESM::GameSetting& gmst); + public: Document (const std::vector& files, bool new_); diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index f1871a6a9..40581972e 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -29,7 +29,8 @@ namespace CSMWorld Display_String, Display_Integer, Display_Float, - Display_Var + Display_Var, + Display_VarType }; std::string mTitle; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index cfbd804a5..2d81a24e9 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -79,7 +79,7 @@ namespace CSMWorld int mType; FixedRecordTypeColumn (int type) - : Column ("Type", ColumnBase::Display_Integer, 0), mType (type) {} + : Column ("Record Type", ColumnBase::Display_Integer, 0), mType (type) {} virtual QVariant get (const Record& record) const { @@ -92,10 +92,11 @@ namespace CSMWorld } }; + /// \attention A var type column must be immediately followed by a suitable value column. template struct VarTypeColumn : public Column { - VarTypeColumn() : Column ("Type", ColumnBase::Display_Integer) {} + VarTypeColumn() : Column ("Type", ColumnBase::Display_VarType) {} virtual QVariant get (const Record& record) const { diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index f120c75f1..c59763f51 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -54,6 +54,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getGlobals() return mGlobals; } +const CSMWorld::IdCollection& CSMWorld::Data::getGmsts() const +{ + return mGmsts; +} + +CSMWorld::IdCollection& CSMWorld::Data::getGmsts() +{ + return mGmsts; +} + QAbstractTableModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -72,7 +82,11 @@ void CSMWorld::Data::merge() void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) { ESM::ESMReader reader; - /// \todo set encoder + + /// \todo set encoding properly, once config implementation has been fixed. + ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding ("win1252")); + reader.setEncoder (&encoder); + reader.open (path.string()); // Note: We do not need to send update signals here, because at this point the model is not connected diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 519817a3b..374534651 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -40,6 +40,10 @@ namespace CSMWorld IdCollection& getGlobals(); + const IdCollection& getGmsts() const; + + IdCollection& getGmsts(); + QAbstractTableModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/record.cpp b/apps/opencs/model/world/record.cpp index 229985a8a..14f63c155 100644 --- a/apps/opencs/model/world/record.cpp +++ b/apps/opencs/model/world/record.cpp @@ -3,19 +3,19 @@ CSMWorld::RecordBase::~RecordBase() {} -bool CSMWorld::RecordBase::RecordBase::isDeleted() const +bool CSMWorld::RecordBase::isDeleted() const { return mState==State_Deleted || mState==State_Erased; } -bool CSMWorld::RecordBase::RecordBase::isErased() const +bool CSMWorld::RecordBase::isErased() const { return mState==State_Erased; } -bool CSMWorld::RecordBase::RecordBase::isModified() const +bool CSMWorld::RecordBase::isModified() const { return mState==State_Modified || mState==State_ModifiedOnly; } \ No newline at end of file diff --git a/apps/opencs/view/doc/opendialog.cpp b/apps/opencs/view/doc/opendialog.cpp index 9a5feb23a..7b62aafa3 100644 --- a/apps/opencs/view/doc/opendialog.cpp +++ b/apps/opencs/view/doc/opendialog.cpp @@ -10,48 +10,48 @@ OpenDialog::OpenDialog(QWidget * parent) : QDialog(parent) QVBoxLayout *layout = new QVBoxLayout(this); mFileSelector = new DataFilesList(mCfgMgr, this); layout->addWidget(mFileSelector); - - //FIXME - same as DataFilesPage::setupDataFiles + + /// \todo move config to Editor class and add command line options. // We use the Configuration Manager to retrieve the configuration values boost::program_options::variables_map variables; boost::program_options::options_description desc; - + desc.add_options() ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()) ("data-local", boost::program_options::value()->default_value("")) ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) ("encoding", boost::program_options::value()->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()); } - + std::string local = variables["data-local"].as(); 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()); - + Files::PathContainer dataDirs; dataDirs.insert(dataDirs.end(), mDataDirs.begin(), mDataDirs.end()); dataDirs.insert(dataDirs.end(), mDataLocal.begin(), mDataLocal.end()); mFileSelector->setupDataFiles(dataDirs, encoding); - + buttonBox = new QDialogButtonBox(QDialogButtonBox::Open | QDialogButtonBox::Cancel, Qt::Horizontal, this); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); layout->addWidget(buttonBox); - + setLayout(layout); setWindowTitle(tr("Open")); } diff --git a/apps/opencs/view/doc/operation.cpp b/apps/opencs/view/doc/operation.cpp index 3f415da03..c301195bc 100644 --- a/apps/opencs/view/doc/operation.cpp +++ b/apps/opencs/view/doc/operation.cpp @@ -35,7 +35,7 @@ void CSVDoc::Operation::updateLabel (int threads) CSVDoc::Operation::Operation (int type) : mType (type), mStalling (false) { /// \todo Add a cancel button or a pop up menu with a cancel item - + setBarColor( type); updateLabel(); /// \todo assign different progress bar colours to allow the user to distinguish easily between operation types @@ -51,4 +51,70 @@ void CSVDoc::Operation::setProgress (int current, int max, int threads) int CSVDoc::Operation::getType() const { return mType; -} \ No newline at end of file +} + +void CSVDoc::Operation::setBarColor (int type) +{ + QString style ="QProgressBar {" + "text-align: center;" + "}" + "QProgressBar::chunk {" + "background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 %1, stop:.50 %2 stop: .51 %3 stop:1 %4);" + "text-align: center;" + "margin: 2px 1px 1p 2px;" + "}"; + + // "QProgressBar::chunk {background-color: %1;}"; + + QString topColor = "#F2F6F8"; + QString bottomColor = "#E0EFF9"; + QString midTopColor = "#D8E1E7"; + QString midBottomColor = "#B5C6D0"; // default gray gloss + + // colors inspired by samples from: + // http://www.colorzilla.com/gradient-editor/ + + switch (type) + { + case CSMDoc::State_Saving: + + topColor = "#FECCB1"; + midTopColor = "#F17432"; + midBottomColor = "#EA5507"; + bottomColor = "#FB955E"; // red gloss #2 + //break; + + case CSMDoc::State_Searching: + + topColor = "#EBF1F6"; + midTopColor = "#ABD3EE"; + midBottomColor = "#89C3EB"; + bottomColor = "#D5EBFB"; //blue gloss #4 + //break; + + case CSMDoc::State_Verifying: + + topColor = "#BFD255"; + midTopColor = "#8EB92A"; + midBottomColor = "#72AA00"; + bottomColor = "#9ECB2D"; //green gloss + //break; + + case CSMDoc::State_Compiling: + + topColor = "#F3E2C7"; + midTopColor = "#C19E67"; + midBottomColor = "#B68D4C"; + bottomColor = "#E9D4B3"; //l Brown 3D + //break; + + default: + + topColor = "#F2F6F8"; + bottomColor = "#E0EFF9"; + midTopColor = "#D8E1E7"; + midBottomColor = "#B5C6D0"; // gray gloss for undefined ops + } + + setStyleSheet(style.arg(topColor).arg(midTopColor).arg(midBottomColor).arg(bottomColor)); +} diff --git a/apps/opencs/view/doc/operation.hpp b/apps/opencs/view/doc/operation.hpp index 362725b6f..a5abf73b7 100644 --- a/apps/opencs/view/doc/operation.hpp +++ b/apps/opencs/view/doc/operation.hpp @@ -25,7 +25,11 @@ namespace CSVDoc void setProgress (int current, int max, int threads); int getType() const; + + private: + + void setBarColor (int type); }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index b01b9ce34..473049999 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -6,6 +6,10 @@ #include "../../model/doc/documentmanager.hpp" #include "../../model/doc/document.hpp" +#include "../world/util.hpp" +#include "../world/enumdelegate.hpp" +#include "../world/vartypedelegate.hpp" + #include "view.hpp" void CSVDoc::ViewManager::updateIndices() @@ -29,11 +33,16 @@ void CSVDoc::ViewManager::updateIndices() CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) : mDocumentManager (documentManager) { + mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; + mDelegateFactories->add (CSMWorld::ColumnBase::Display_VarType, + new CSVWorld::VarTypeDelegateFactory (ESM::VT_None, ESM::VT_String, ESM::VT_Int, ESM::VT_Float)); } CSVDoc::ViewManager::~ViewManager() { + delete mDelegateFactories; + for (std::vector::iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) delete *iter; } diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index 91a80d496..72e7a3e1a 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -11,6 +11,11 @@ namespace CSMDoc class DocumentManager; } +namespace CSVWorld +{ + class CommandDelegateFactoryCollection; +} + namespace CSVDoc { class View; @@ -21,6 +26,7 @@ namespace CSVDoc CSMDoc::DocumentManager& mDocumentManager; std::vector mViews; + CSVWorld::CommandDelegateFactoryCollection *mDelegateFactories; // not implemented ViewManager (const ViewManager&); diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp new file mode 100644 index 000000000..7a8b45373 --- /dev/null +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -0,0 +1,101 @@ + +#include "enumdelegate.hpp" + +#include + +#include +#include +#include + +#include "../../model/world/commands.hpp" + +void CSVWorld::EnumDelegate::setModelDataImp (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const +{ + if (QComboBox *comboBox = dynamic_cast (editor)) + { + QString value = comboBox->currentText(); + + for (std::vector >::const_iterator iter (mValues.begin()); + iter!=mValues.end(); ++iter) + if (iter->second==value) + { + addCommands (model, index, iter->first); + break; + } + } +} + +void CSVWorld::EnumDelegate::addCommands (QAbstractItemModel *model, + const QModelIndex& index, int type) const +{ + getUndoStack().push (new CSMWorld::ModifyCommand (*model, index, type)); +} + + +CSVWorld::EnumDelegate::EnumDelegate (const std::vector >& values, + QUndoStack& undoStack, QObject *parent) +: CommandDelegate (undoStack, parent), mValues (values) +{ + +} + +QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + QComboBox *comboBox = new QComboBox (parent); + + for (std::vector >::const_iterator iter (mValues.begin()); + iter!=mValues.end(); ++iter) + comboBox->addItem (iter->second); + + return comboBox; +} + +void CSVWorld::EnumDelegate::setEditorData (QWidget *editor, const QModelIndex& index) const +{ + if (QComboBox *comboBox = dynamic_cast (editor)) + { + int value = index.data (Qt::EditRole).toInt(); + + std::size_t size = mValues.size(); + + for (std::size_t i=0; isetCurrentIndex (i); + break; + } + } +} + +void CSVWorld::EnumDelegate::paint (QPainter *painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + QStyleOptionViewItemV4 option2 (option); + + int value = index.data().toInt(); + + for (std::vector >::const_iterator iter (mValues.begin()); + iter!=mValues.end(); ++iter) + if (iter->first==value) + { + option2.text = iter->second; + + QApplication::style()->drawControl (QStyle::CE_ItemViewItem, &option2, painter); + + break; + } +} + + +CSVWorld::CommandDelegate *CSVWorld::EnumDelegateFactory::makeDelegate (QUndoStack& undoStack, + QObject *parent) const +{ + return new EnumDelegate (mValues, undoStack, parent); +} + +void CSVWorld::EnumDelegateFactory::add (int value, const QString& name) +{ + mValues.push_back (std::make_pair (value, name)); +} diff --git a/apps/opencs/view/world/enumdelegate.hpp b/apps/opencs/view/world/enumdelegate.hpp new file mode 100644 index 000000000..f11252371 --- /dev/null +++ b/apps/opencs/view/world/enumdelegate.hpp @@ -0,0 +1,57 @@ +#ifndef CSV_WORLD_ENUMDELEGATE_H +#define CSV_WORLD_ENUMDELEGATE_H + +#include + +#include + +#include + +#include "util.hpp" + +namespace CSVWorld +{ + /// \brief Integer value that represents an enum and is interacted with via a combobox + class EnumDelegate : public CommandDelegate + { + std::vector > mValues; + + private: + + virtual void setModelDataImp (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const; + + virtual void addCommands (QAbstractItemModel *model, + const QModelIndex& index, int type) const; + + public: + + EnumDelegate (const std::vector >& values, + QUndoStack& undoStack, QObject *parent); + + virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem& option, + const QModelIndex& index) const; + + virtual void setEditorData (QWidget *editor, const QModelIndex& index) const; + + virtual void paint (QPainter *painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const; + + }; + + class EnumDelegateFactory : public CommandDelegateFactory + { + std::vector > mValues; + + public: + + virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; + ///< The ownership of the returned CommandDelegate is transferred to the caller. + + void add (int value, const QString& name); + }; + + +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 0721ead2c..f9167d259 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -102,7 +102,12 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q if (flags & CSMWorld::ColumnBase::Flag_Table) { - CommandDelegate *delegate = new CommandDelegate (undoStack, this); + CSMWorld::ColumnBase::Display display = static_cast ( + mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); + + CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate (display, + undoStack, this); + mDelegates.push_back (delegate); setItemDelegateForColumn (i, delegate); } diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 7181dd4d1..5ada1d84f 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -1,6 +1,8 @@ #include "util.hpp" +#include + #include #include "../../model/world/commands.hpp" @@ -35,6 +37,70 @@ QVariant CSVWorld::NastyTableModelHack::getData() const return mData; } + +CSVWorld::CommandDelegateFactory::~CommandDelegateFactory() {} + + +CSVWorld::CommandDelegateFactoryCollection *CSVWorld::CommandDelegateFactoryCollection::sThis = 0; + +CSVWorld::CommandDelegateFactoryCollection::CommandDelegateFactoryCollection() +{ + if (sThis) + throw std::logic_error ("multiple instances of CSVWorld::CommandDelegateFactoryCollection"); + + sThis = this; +} + +CSVWorld::CommandDelegateFactoryCollection::~CommandDelegateFactoryCollection() +{ + sThis = 0; + + for (std::map::iterator iter ( + mFactories.begin()); + iter!=mFactories.end(); ++iter) + delete iter->second; +} + +void CSVWorld::CommandDelegateFactoryCollection::add (CSMWorld::ColumnBase::Display display, + CommandDelegateFactory *factory) +{ + mFactories.insert (std::make_pair (display, factory)); +} + +CSVWorld::CommandDelegate *CSVWorld::CommandDelegateFactoryCollection::makeDelegate ( + CSMWorld::ColumnBase::Display display, QUndoStack& undoStack, QObject *parent) const +{ + std::map::const_iterator iter = + mFactories.find (display); + + if (iter!=mFactories.end()) + return iter->second->makeDelegate (undoStack, parent); + + return new CommandDelegate (undoStack, parent); +} + +const CSVWorld::CommandDelegateFactoryCollection& CSVWorld::CommandDelegateFactoryCollection::get() +{ + if (!sThis) + throw std::logic_error ("no instance of CSVWorld::CommandDelegateFactoryCollection"); + + return *sThis; +} + + +QUndoStack& CSVWorld::CommandDelegate::getUndoStack() const +{ + return mUndoStack; +} + +void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const +{ + NastyTableModelHack hack (*model); + QStyledItemDelegate::setModelData (editor, &hack, index); + mUndoStack.push (new CSMWorld::ModifyCommand (*model, index, hack.getData())); +} + CSVWorld::CommandDelegate::CommandDelegate (QUndoStack& undoStack, QObject *parent) : QStyledItemDelegate (parent), mUndoStack (undoStack), mEditLock (false) {} @@ -44,14 +110,18 @@ void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemMode { if (!mEditLock) { - NastyTableModelHack hack (*model); - QStyledItemDelegate::setModelData (editor, &hack, index); - mUndoStack.push (new CSMWorld::ModifyCommand (*model, index, hack.getData())); + setModelDataImp (editor, model, index); } + ///< \todo provide some kind of feedback to the user, indicating that editing is currently not possible. } -void CSVWorld::CommandDelegate::setEditLock (bool locked) +void CSVWorld::CommandDelegate::setEditLock (bool locked) { mEditLock = locked; +} + +bool CSVWorld::CommandDelegate::isEditLocked() const +{ + return mEditLock; } \ No newline at end of file diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp index 136583118..5334abf9c 100644 --- a/apps/opencs/view/world/util.hpp +++ b/apps/opencs/view/world/util.hpp @@ -1,9 +1,13 @@ #ifndef CSV_WORLD_UTIL_H #define CSV_WORLD_UTIL_H +#include + #include #include +#include "../../model/world/columnbase.hpp" + class QUndoStack; namespace CSVWorld @@ -31,19 +35,73 @@ namespace CSVWorld QVariant getData() const; }; + class CommandDelegate; + + class CommandDelegateFactory + { + public: + + virtual ~CommandDelegateFactory(); + + virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const = 0; + ///< The ownership of the returned CommandDelegate is transferred to the caller. + }; + + class CommandDelegateFactoryCollection + { + static CommandDelegateFactoryCollection *sThis; + std::map mFactories; + + private: + + // not implemented + CommandDelegateFactoryCollection (const CommandDelegateFactoryCollection&); + CommandDelegateFactoryCollection& operator= (const CommandDelegateFactoryCollection&); + + public: + + CommandDelegateFactoryCollection(); + + ~CommandDelegateFactoryCollection(); + + void add (CSMWorld::ColumnBase::Display display, CommandDelegateFactory *factory); + ///< The ownership of \æ factory is transferred to *this. + /// + /// This function must not be called more than once per value of \æ display. + + CommandDelegate *makeDelegate (CSMWorld::ColumnBase::Display display, QUndoStack& undoStack, + QObject *parent) const; + ///< The ownership of the returned CommandDelegate is transferred to the caller. + /// + /// If no factory is registered for \a display, a CommandDelegate will be returned. + + static const CommandDelegateFactoryCollection& get(); + + }; + ///< \brief Use commands instead of manipulating the model directly class CommandDelegate : public QStyledItemDelegate { QUndoStack& mUndoStack; bool mEditLock; + protected: + + QUndoStack& getUndoStack() const; + + virtual void setModelDataImp (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const; + public: CommandDelegate (QUndoStack& undoStack, QObject *parent); - void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const; + virtual void setModelData (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const; void setEditLock (bool locked); + + bool isEditLocked() const; }; } diff --git a/apps/opencs/view/world/vartypedelegate.cpp b/apps/opencs/view/world/vartypedelegate.cpp new file mode 100644 index 000000000..3ee759ef2 --- /dev/null +++ b/apps/opencs/view/world/vartypedelegate.cpp @@ -0,0 +1,103 @@ + +#include "vartypedelegate.hpp" + +#include + +#include "../../model/world/commands.hpp" + +void CSVWorld::VarTypeDelegate::addCommands (QAbstractItemModel *model, const QModelIndex& index, int type) + const +{ + QModelIndex next = model->index (index.row(), index.column()+1); + + QVariant old = model->data (next); + + QVariant value; + + switch (type) + { + case ESM::VT_Short: + case ESM::VT_Int: + case ESM::VT_Long: + + value = old.toInt(); + break; + + case ESM::VT_Float: + + value = old.toFloat(); + break; + + case ESM::VT_String: + + value = old.toString(); + break; + + default: break; // ignore the rest + } + + getUndoStack().beginMacro ( + "Modify " + model->headerData (index.column(), Qt::Horizontal, Qt::DisplayRole).toString()); + + getUndoStack().push (new CSMWorld::ModifyCommand (*model, index, type)); + getUndoStack().push (new CSMWorld::ModifyCommand (*model, next, value)); + + getUndoStack().endMacro(); +} + +CSVWorld::VarTypeDelegate::VarTypeDelegate (const std::vector >& values, + QUndoStack& undoStack, QObject *parent) +: EnumDelegate (values, undoStack, parent) +{} + + +CSVWorld::VarTypeDelegateFactory::VarTypeDelegateFactory (ESM::VarType type0, + ESM::VarType type1, ESM::VarType type2, ESM::VarType type3) +{ + if (type0!=ESM::VT_Unknown) + add (type0); + + if (type1!=ESM::VT_Unknown) + add (type1); + + if (type2!=ESM::VT_Unknown) + add (type2); + + if (type3!=ESM::VT_Unknown) + add (type3); +} + +CSVWorld::CommandDelegate *CSVWorld::VarTypeDelegateFactory::makeDelegate (QUndoStack& undoStack, + QObject *parent) const +{ + return new VarTypeDelegate (mValues, undoStack, parent); +} + +void CSVWorld::VarTypeDelegateFactory::add (ESM::VarType type) +{ + struct Name + { + ESM::VarType mType; + const char *mName; + }; + + static const Name sNames[] = + { + { ESM::VT_None, "empty" }, + { ESM::VT_Short, "short" }, + { ESM::VT_Int, "long" }, + { ESM::VT_Long, "long" }, + { ESM::VT_Float, "float" }, + { ESM::VT_String, "string" }, + { ESM::VT_Unknown, 0 } // end marker + }; + + for (int i=0; sNames[i].mName; ++i) + if (sNames[i].mType==type) + { + mValues.push_back (std::make_pair (type, sNames[i].mName)); + return; + } + + throw std::logic_error ("Unsupported variable type"); +} diff --git a/apps/opencs/view/world/vartypedelegate.hpp b/apps/opencs/view/world/vartypedelegate.hpp new file mode 100644 index 000000000..621dd316b --- /dev/null +++ b/apps/opencs/view/world/vartypedelegate.hpp @@ -0,0 +1,38 @@ +#ifndef CSV_WORLD_VARTYPEDELEGATE_H +#define CSV_WORLD_VARTYPEDELEGATE_H + +#include "enumdelegate.hpp" + +namespace CSVWorld +{ + class VarTypeDelegate : public EnumDelegate + { + private: + + virtual void addCommands (QAbstractItemModel *model, + const QModelIndex& index, int type) const; + + public: + + VarTypeDelegate (const std::vector >& values, + QUndoStack& undoStack, QObject *parent); + }; + + class VarTypeDelegateFactory : public CommandDelegateFactory + { + std::vector > mValues; + + public: + + VarTypeDelegateFactory (ESM::VarType type0 = ESM::VT_Unknown, + ESM::VarType type1 = ESM::VT_Unknown, ESM::VarType type2 = ESM::VT_Unknown, + ESM::VarType type3 = ESM::VT_Unknown); + + virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; + ///< The ownership of the returned CommandDelegate is transferred to the caller. + + void add (ESM::VarType type); + }; +} + +#endif diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index f1c7c53ac..53fa15692 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -125,6 +125,12 @@ if(APPLE) find_library(COCOA_FRAMEWORK Cocoa) find_library(IOKIT_FRAMEWORK IOKit) target_link_libraries(openmw ${CARBON_FRAMEWORK} ${COCOA_FRAMEWORK} ${IOKIT_FRAMEWORK}) + + if (FFMPEG_FOUND) + find_library(COREVIDEO_FRAMEWORK CoreVideo) + find_library(VDA_FRAMEWORK VideoDecodeAcceleration) + target_link_libraries(openmw ${COREVIDEO_FRAMEWORK} ${VDA_FRAMEWORK}) + endif() endif(APPLE) if(DPKG_PROGRAM) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 30bfced06..4f7435fad 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -199,6 +199,7 @@ namespace MWBase ///< Hides dialog and schedules dialog to be deleted. virtual void messageBox (const std::string& message, const std::vector& buttons) = 0; + virtual void enterPressed () = 0; virtual int readPressedButton() = 0; ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 06467bb21..2c561eb85 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -12,6 +12,7 @@ #include "../mwworld/actionalchemy.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" @@ -61,6 +62,9 @@ namespace MWClass boost::shared_ptr Apparatus::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action( new MWWorld::ActionTake (ptr)); diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 704173b1c..654cb87fd 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -15,6 +15,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" @@ -64,6 +65,9 @@ namespace MWClass boost::shared_ptr Armor::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index c411bb193..892ac091c 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -13,6 +13,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -62,6 +63,9 @@ namespace MWClass boost::shared_ptr Clothing::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index bbe005955..a2d75131e 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -9,6 +9,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/failedaction.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/customdata.hpp" #include "../mwworld/cellstore.hpp" @@ -85,6 +86,9 @@ namespace MWClass boost::shared_ptr Container::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + const std::string lockedSound = "LockedChest"; const std::string trapActivationSound = "Disarm Trap Fail"; diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 7ad8f1b47..bbba45df5 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -13,6 +13,7 @@ #include "../mwworld/physicssystem.hpp" #include "../mwworld/actioneat.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwmechanics/npcstats.hpp" @@ -72,6 +73,9 @@ namespace MWClass boost::shared_ptr Ingredient::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index b94b0d395..235e57d37 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -88,6 +88,9 @@ namespace MWClass boost::shared_ptr Light::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index a667fefb2..7e909437c 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -13,6 +13,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -62,6 +63,9 @@ namespace MWClass boost::shared_ptr Lockpick::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 94d40bcb7..d43a44359 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -14,6 +14,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/manualref.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -65,6 +66,9 @@ namespace MWClass boost::shared_ptr Miscellaneous::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); @@ -210,6 +214,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = newRef.getPtr().get(); newPtr = MWWorld::Ptr(&cell.mMiscItems.insert(*ref), &cell); + newPtr.getRefData ().setCount(goldAmount); } else { MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 09d152de7..c3a6df211 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -13,6 +13,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -62,6 +63,9 @@ namespace MWClass boost::shared_ptr Potion::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action( new MWWorld::ActionTake (ptr)); diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 0d8653aa8..a28be17e7 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -13,6 +13,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -61,6 +62,9 @@ namespace MWClass boost::shared_ptr Probe::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index edb28d16c..39a7f65e0 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -11,6 +11,7 @@ #include "../mwworld/actiontake.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -60,6 +61,9 @@ namespace MWClass boost::shared_ptr Repair::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index c8fe0d276..d8c11558c 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -13,6 +13,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -62,6 +63,9 @@ namespace MWClass boost::shared_ptr Weapon::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 4837821e0..c53a68cf4 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -48,7 +48,6 @@ BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager) getWidget(okButton, "OKButton"); okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); - okButton->setEnabled(false); updateBirths(); updateSpells(); @@ -85,7 +84,6 @@ void BirthDialog::setBirthId(const std::string &birthId) mBirthList->setIndexSelected(i); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - okButton->setEnabled(true); break; } } @@ -114,7 +112,6 @@ void BirthDialog::onSelectBirth(MyGUI::ListBox* _sender, size_t _index) MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - okButton->setEnabled(true); const std::string *birthId = mBirthList->getItemDataAt(_index); if (boost::iequals(mCurrentBirthId, *birthId)) @@ -133,8 +130,6 @@ void BirthDialog::updateBirths() const MWWorld::Store &signs = MWBase::Environment::get().getWorld()->getStore().get(); - int index = 0; - // sort by name std::vector < std::pair > birthSigns; @@ -145,12 +140,20 @@ void BirthDialog::updateBirths() } std::sort(birthSigns.begin(), birthSigns.end(), sortBirthSigns); - for (std::vector < std::pair >::const_iterator it2 = birthSigns.begin(); it2 != birthSigns.end(); ++it2) + int index = 0; + for (std::vector >::const_iterator it2 = birthSigns.begin(); + it2 != birthSigns.end(); ++it2, ++index) { mBirthList->addItem(it2->second->mName, it2->first); - if (boost::iequals(it2->first, mCurrentBirthId)) + if (mCurrentBirthId.empty()) + { mBirthList->setIndexSelected(index); - ++index; + mCurrentBirthId = it2->first; + } + else if (boost::iequals(it2->first, mCurrentBirthId)) + { + mBirthList->setIndexSelected(index); + } } } diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 659795e18..777751069 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -14,8 +14,10 @@ using namespace MWGui; -BookWindow::BookWindow (MWBase::WindowManager& parWindowManager) : - WindowBase("openmw_book.layout", parWindowManager) +BookWindow::BookWindow (MWBase::WindowManager& parWindowManager) + : WindowBase("openmw_book.layout", parWindowManager) + , mTakeButtonShow(true) + , mTakeButtonAllowed(true) { getWidget(mCloseButton, "CloseButton"); mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onCloseButtonClicked); @@ -85,7 +87,14 @@ void BookWindow::open (MWWorld::Ptr book) void BookWindow::setTakeButtonShow(bool show) { - mTakeButton->setVisible(show); + mTakeButtonShow = show; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); +} + +void BookWindow::setInventoryAllowed(bool allowed) +{ + mTakeButtonAllowed = allowed; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); } void BookWindow::onCloseButtonClicked (MyGUI::Widget* sender) diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index 5887975ea..a509f131f 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -17,6 +17,8 @@ namespace MWGui void open(MWWorld::Ptr book); void setTakeButtonShow(bool show); + void setInventoryAllowed(bool allowed); + protected: void onNextPageButtonClicked (MyGUI::Widget* sender); void onPrevPageButtonClicked (MyGUI::Widget* sender); @@ -40,6 +42,9 @@ namespace MWGui std::vector mPages; MWWorld::Ptr mBook; + + bool mTakeButtonShow; + bool mTakeButtonAllowed; }; } diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index c14c7f74b..2eed21a52 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -104,7 +104,6 @@ PickClassDialog::PickClassDialog(MWBase::WindowManager& parWindowManager) MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onOkClicked); - okButton->setEnabled(false); updateClasses(); updateStats(); @@ -140,7 +139,6 @@ void PickClassDialog::setClassId(const std::string &classId) mClassList->setIndexSelected(i); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - okButton->setEnabled(true); break; } } @@ -169,7 +167,6 @@ void PickClassDialog::onSelectClass(MyGUI::ListBox* _sender, size_t _index) MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - okButton->setEnabled(true); const std::string *classId = mClassList->getItemDataAt(_index); if (boost::iequals(mCurrentClassId, *classId)) @@ -197,8 +194,15 @@ void PickClassDialog::updateClasses() const std::string &id = it->mId; mClassList->addItem(it->mName, id); - if (boost::iequals(id, mCurrentClassId)) + if (mCurrentClassId.empty()) + { + mCurrentClassId = id; mClassList->setIndexSelected(index); + } + else if (boost::iequals(id, mCurrentClassId)) + { + mClassList->setIndexSelected(index); + } ++index; } } diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 4090b592d..7f28e9e17 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -6,7 +6,9 @@ #include "../mwworld/ptr.hpp" #include +#include #include +#include using namespace MWGui; @@ -67,118 +69,135 @@ namespace return value; } + + Ogre::UTFString::unicode_char unicodeCharFromChar(char ch) + { + std::string s; + s += ch; + Ogre::UTFString string(s); + return string.getChar(0); + } } -std::vector BookTextParser::split(std::string text, const int width, const int height) +std::vector BookTextParser::split(std::string utf8Text, const int width, const int height) { + using Ogre::UTFString; std::vector result; MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor - text = Interpreter::fixDefinesBook(text, interpreterContext); + utf8Text = Interpreter::fixDefinesBook(utf8Text, interpreterContext); - boost::algorithm::replace_all(text, "
", "\n"); - boost::algorithm::replace_all(text, "

", "\n\n"); + boost::algorithm::replace_all(utf8Text, "\n", ""); + boost::algorithm::replace_all(utf8Text, "
", "\n"); + boost::algorithm::replace_all(utf8Text, "

", "\n\n"); + UTFString text(utf8Text); const int spacing = 48; - while (text.size() > 0) + const UTFString::unicode_char LEFT_ANGLE = unicodeCharFromChar('<'); + const UTFString::unicode_char NEWLINE = unicodeCharFromChar('\n'); + const UTFString::unicode_char SPACE = unicodeCharFromChar(' '); + + while (!text.empty()) { // read in characters until we have exceeded the size, or run out of text int currentWidth = 0; int currentHeight = 0; - std::string currentText; - std::string currentWord; - unsigned int i=0; - while (currentHeight <= height-spacing && i', i) == std::string::npos) + const size_t tagStart = index + 1; + const size_t tagEnd = text.find('>', tagStart); + if (tagEnd == UTFString::npos) throw std::runtime_error("BookTextParser Error: Tag is not terminated"); + const std::string tag = text.substr(tagStart, tagEnd - tagStart).asUTF8(); - if (text.size() > i+4 && text.substr(i, 4) == "', i)-i), false); - currentHeight += (mHeight-h); + const int h = mHeight; + parseImage(tag, false); + currentHeight += (mHeight - h); currentWidth = 0; } - else if (text.size() > i+5 && text.substr(i, 5) == "', i)-i)); - currentHeight += 18; // keep this in sync with the font size + parseFont(tag); + if (currentWidth != 0) { + currentHeight += currentFontHeight(); + currentWidth = 0; + } currentWidth = 0; } - else if (text.size() > i+4 && text.substr(i, 4) == "', i)-i)); - currentHeight += 18; // keep this in sync with the font size - currentWidth = 0; + parseDiv(tag); + if (currentWidth != 0) { + currentHeight += currentFontHeight(); + currentWidth = 0; + } } - - currentText += text.substr(i, text.find('>', i)-i+1); - i = text.find('>', i); + index = tagEnd; } - else if (text[i] == '\n') + else if (ch == NEWLINE) { - currentHeight += 18; // keep this in sync with the font size + currentHeight += currentFontHeight(); currentWidth = 0; - currentWord = ""; - currentText += text[i]; + currentWordStart = index; } - else if (text[i] == ' ') + else if (ch == SPACE) { currentWidth += 3; // keep this in sync with the font's SpaceWidth property - currentWord = ""; - currentText += text[i]; + currentWordStart = index; } else { - currentWidth += - MyGUI::FontManager::getInstance().getByName (mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont) - ->getGlyphInfo(static_cast(text[i]))->width; - currentWord += text[i]; - currentText += text[i]; + currentWidth += widthForCharGlyph(ch); } if (currentWidth > width) { - currentHeight += 18; // keep this in sync with the font size + currentHeight += currentFontHeight(); currentWidth = 0; - // add size of the current word - unsigned int j=0; - while (jgetGlyphInfo(static_cast(currentWord[j]))->width; - ++j; - } + UTFString word = text.substr(currentWordStart, index - currentWordStart); + for (UTFString::const_iterator it = word.begin(), end = word.end(); it != end; ++it) + currentWidth += widthForCharGlyph(it.getCharacter()); } - - ++i; - } - if (currentHeight > height-spacing) - { - // remove the last word - currentText.erase(currentText.size()-currentWord.size(), currentText.size()); + index += UTFString::_utf16_char_length(ch); } + const size_t pageEnd = (currentHeight > height - spacing && currentWordStart != 0) + ? currentWordStart : index; - result.push_back(currentText); - text.erase(0, currentText.size()); + result.push_back(text.substr(0, pageEnd).asUTF8()); + text.erase(0, pageEnd); } return result; } +float BookTextParser::widthForCharGlyph(unsigned unicodeChar) const +{ + std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont); + return MyGUI::FontManager::getInstance().getByName(fontName) + ->getGlyphInfo(unicodeChar)->width; +} + +float BookTextParser::currentFontHeight() const +{ + std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont); + return MyGUI::FontManager::getInstance().getByName(fontName)->getDefaultHeight(); +} + MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, const int width) { MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor text = Interpreter::fixDefinesBook(text, interpreterContext); - mParent = parent; mWidth = width; mHeight = 0; @@ -189,12 +208,13 @@ MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, co MyGUI::Gui::getInstance().destroyWidget(mParent->getChildAt(0)); } + boost::algorithm::replace_all(text, "\n", ""); boost::algorithm::replace_all(text, "
", "\n"); boost::algorithm::replace_all(text, "

", "\n\n"); // remove leading newlines - //while (text[0] == '\n') - // text.erase(0); +// while (text[0] == '\n') +// text.erase(0); // remove trailing " if (text[text.size()-1] == '\"') @@ -279,28 +299,30 @@ void BookTextParser::parseSubText(std::string text) { if (text[0] == '<') { - if (text.find('>') == std::string::npos) + const size_t tagStart = 1; + const size_t tagEnd = text.find('>', tagStart); + if (tagEnd == std::string::npos) throw std::runtime_error("BookTextParser Error: Tag is not terminated"); + const std::string tag = text.substr(tagStart, tagEnd - tagStart); - if (text.size() > 4 && text.substr(0, 4) == "'))); - else if (text.size() > 5 && text.substr(0, 5) == "'))); - else if (text.size() > 4 && text.substr(0, 4) == "'))); + if (boost::algorithm::starts_with(tag, "IMG")) + parseImage(tag); + if (boost::algorithm::starts_with(tag, "FONT")) + parseFont(tag); + if (boost::algorithm::starts_with(tag, "DOV")) + parseDiv(tag); - text.erase(0, text.find('>')+1); + text.erase(0, tagEnd + 1); } - bool tagFound = false; + size_t tagStart = std::string::npos; std::string realText; // real text, without tags - unsigned int i=0; - for (; isetSize(box->getSize().width, box->getTextSize().height); mHeight += box->getTextSize().height; - if (tagFound) + if (tagStart != std::string::npos) { - parseSubText(text.substr(i, text.size())); + parseSubText(text.substr(tagStart, text.size())); } } diff --git a/apps/openmw/mwgui/formatting.hpp b/apps/openmw/mwgui/formatting.hpp index a1e115491..ab1ee3af4 100644 --- a/apps/openmw/mwgui/formatting.hpp +++ b/apps/openmw/mwgui/formatting.hpp @@ -40,6 +40,8 @@ namespace MWGui std::vector split(std::string text, const int width, const int height); protected: + float widthForCharGlyph(unsigned unicodeChar) const; + float currentFontHeight() const; void parseSubText(std::string text); void parseImage(std::string tag, bool createWidget=true); diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index b660af7dd..896ab3bb5 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -1,3 +1,5 @@ +#include + #include "messagebox.hpp" using namespace MWGui; @@ -133,6 +135,10 @@ void MessageBoxManager::setMessageBoxSpeed (int speed) mMessageBoxSpeed = speed; } +void MessageBoxManager::enterPressed () +{ + mInterMessageBoxe->enterPressed(); +} int MessageBoxManager::readPressedButton () { @@ -359,7 +365,28 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan } } +void InteractiveMessageBox::enterPressed() +{ + + std::string ok = Misc::StringUtils::lowerCase(MyGUI::LanguageManager::getInstance().replaceTags("#{sOK}")); + std::vector::const_iterator button; + for(button = mButtons.begin(); button != mButtons.end(); ++button) + { + if(Misc::StringUtils::lowerCase((*button)->getCaption()) == ok) + { + buttonActivated(*button); + break; + } + } + +} + void InteractiveMessageBox::mousePressed (MyGUI::Widget* pressed) +{ + buttonActivated (pressed); +} + +void InteractiveMessageBox::buttonActivated (MyGUI::Widget* pressed) { mMarkedToDelete = true; int index = 0; diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 5e4c468d5..4be8bc5b7 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -34,7 +34,8 @@ namespace MWGui void removeMessageBox (float time, MessageBox *msgbox); bool removeMessageBox (MessageBox *msgbox); void setMessageBoxSpeed (int speed); - + + void enterPressed(); int readPressedButton (); MWBase::WindowManager *mWindowManager; @@ -70,12 +71,15 @@ namespace MWGui { public: InteractiveMessageBox (MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons); + void enterPressed (); void mousePressed (MyGUI::Widget* _widget); int readPressedButton (); bool mMarkedToDelete; private: + void buttonActivated (MyGUI::Widget* _widget); + MessageBoxManager& mMessageBoxManager; MyGUI::EditPtr mMessageWidget; MyGUI::WidgetPtr mButtonsWidget; diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index df6c99340..054cce7b8 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -81,7 +81,6 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) getWidget(okButton, "OKButton"); okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked); - okButton->setEnabled(false); updateRaces(); updateSkills(); @@ -135,7 +134,6 @@ void RaceDialog::setRaceId(const std::string &raceId) mRaceList->setIndexSelected(i); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - okButton->setEnabled(true); break; } } @@ -258,7 +256,6 @@ void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - okButton->setEnabled(true); const std::string *raceId = mRaceList->getItemDataAt(_index); if (boost::iequals(mCurrentRaceId, *raceId)) return; diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 8317025e0..3bd3a4743 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -12,8 +12,10 @@ using namespace MWGui; -ScrollWindow::ScrollWindow (MWBase::WindowManager& parWindowManager) : - WindowBase("openmw_scroll.layout", parWindowManager) +ScrollWindow::ScrollWindow (MWBase::WindowManager& parWindowManager) + : WindowBase("openmw_scroll.layout", parWindowManager) + , mTakeButtonShow(true) + , mTakeButtonAllowed(true) { getWidget(mTextView, "TextView"); @@ -50,7 +52,14 @@ void ScrollWindow::open (MWWorld::Ptr scroll) void ScrollWindow::setTakeButtonShow(bool show) { - mTakeButton->setVisible(show); + mTakeButtonShow = show; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); +} + +void ScrollWindow::setInventoryAllowed(bool allowed) +{ + mTakeButtonAllowed = allowed; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); } void ScrollWindow::onCloseButtonClicked (MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 7932a215b..42b6395a9 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -15,6 +15,7 @@ namespace MWGui void open (MWWorld::Ptr scroll); void setTakeButtonShow(bool show); + void setInventoryAllowed(bool allowed); protected: void onCloseButtonClicked (MyGUI::Widget* _sender); @@ -26,6 +27,10 @@ namespace MWGui MyGUI::ScrollView* mTextView; MWWorld::Ptr mScroll; + + bool mTakeButtonShow; + bool mTakeButtonAllowed; + }; } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 51eb3d87e..2cc8ff444 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -19,12 +19,17 @@ #include "inventorywindow.hpp" +static const float BALANCE_CHANGE_INITIAL_PAUSE = 0.5; // in seconds +static const float BALANCE_CHANGE_INTERVAL = 0.1; // in seconds + namespace MWGui { TradeWindow::TradeWindow(MWBase::WindowManager& parWindowManager) : WindowBase("openmw_trade_window.layout", parWindowManager) , ContainerBase(NULL) // no drag&drop , mCurrentBalance(0) + , mBalanceButtonsState(BBS_None) + , mBalanceChangePause(0.0) { MyGUI::ScrollView* itemView; MyGUI::Widget* containerWidget; @@ -59,8 +64,10 @@ namespace MWGui mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onCancelButtonClicked); mOfferButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onOfferButtonClicked); - mIncreaseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onIncreaseButtonClicked); - mDecreaseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onDecreaseButtonClicked); + mIncreaseButton->eventMouseButtonPressed += MyGUI::newDelegate(this, &TradeWindow::onIncreaseButtonPressed); + mIncreaseButton->eventMouseButtonReleased += MyGUI::newDelegate(this, &TradeWindow::onBalanceButtonReleased); + mDecreaseButton->eventMouseButtonPressed += MyGUI::newDelegate(this, &TradeWindow::onDecreaseButtonPressed); + mDecreaseButton->eventMouseButtonReleased += MyGUI::newDelegate(this, &TradeWindow::onBalanceButtonReleased); setCoord(400, 0, 400, 300); @@ -143,6 +150,21 @@ namespace MWGui } } + void TradeWindow::onFrame(float frameDuration) + { + if (!mMainWidget->getVisible() || mBalanceButtonsState == BBS_None) + return; + + mBalanceChangePause -= frameDuration; + if (mBalanceChangePause < 0.0) { + mBalanceChangePause += BALANCE_CHANGE_INTERVAL; + if (mBalanceButtonsState == BBS_Increase) + onIncreaseButtonTriggered(); + else if (mBalanceButtonsState == BBS_Decrease) + onDecreaseButtonTriggered(); + } + } + void TradeWindow::onOfferButtonClicked(MyGUI::Widget* _sender) { const MWWorld::Store &gmst = @@ -242,7 +264,7 @@ namespace MWGui //skill use! MWWorld::Class::get(playerPtr).skillUsageSucceeded(playerPtr, ESM::Skill::Mercantile, 0); - } + } int iBarterSuccessDisposition = gmst.find("iBarterSuccessDisposition")->getInt(); MWBase::Environment::get().getDialogueManager()->applyTemporaryDispositionChange(iBarterSuccessDisposition); @@ -271,14 +293,33 @@ namespace MWGui mWindowManager.removeGuiMode(GM_Barter); } - void TradeWindow::onIncreaseButtonClicked(MyGUI::Widget* _sender) + void TradeWindow::onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) + { + mBalanceButtonsState = BBS_Increase; + mBalanceChangePause = BALANCE_CHANGE_INITIAL_PAUSE; + onIncreaseButtonTriggered(); + } + + void TradeWindow::onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) + { + mBalanceButtonsState = BBS_Decrease; + mBalanceChangePause = BALANCE_CHANGE_INITIAL_PAUSE; + onDecreaseButtonTriggered(); + } + + void TradeWindow::onBalanceButtonReleased(MyGUI::Widget *_sender, int _left, int _top, MyGUI::MouseButton _id) + { + mBalanceButtonsState = BBS_None; + } + + void TradeWindow::onIncreaseButtonTriggered() { if(mCurrentBalance<=-1) mCurrentBalance -= 1; if(mCurrentBalance>=1) mCurrentBalance += 1; updateLabels(); } - void TradeWindow::onDecreaseButtonClicked(MyGUI::Widget* _sender) + void TradeWindow::onDecreaseButtonTriggered() { if(mCurrentBalance<-1) mCurrentBalance += 1; if(mCurrentBalance>1) mCurrentBalance -= 1; diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 219e44036..20d9b6069 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -34,6 +34,8 @@ namespace MWGui void addOrRemoveGold(int gold); + void onFrame(float frameDuration); + protected: MyGUI::Button* mFilterAll; MyGUI::Button* mFilterWeapon; @@ -57,12 +59,24 @@ namespace MWGui int mCurrentBalance; int mCurrentMerchantOffer; + enum BalanceButtonsState { + BBS_None, + BBS_Increase, + BBS_Decrease + } mBalanceButtonsState; + /// pause before next balance change will trigger while user holds +/- button pressed + float mBalanceChangePause; + void onWindowResize(MyGUI::Window* _sender); void onFilterChanged(MyGUI::Widget* _sender); void onOfferButtonClicked(MyGUI::Widget* _sender); void onCancelButtonClicked(MyGUI::Widget* _sender); - void onIncreaseButtonClicked(MyGUI::Widget* _sender); - void onDecreaseButtonClicked(MyGUI::Widget* _sender); + void onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + void onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + void onBalanceButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + + void onIncreaseButtonTriggered(); + void onDecreaseButtonTriggered(); // don't show items that the NPC has equipped in his trade-window. virtual bool ignoreEquippedItems() { return true; } diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 9615e95f7..465f588b8 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -132,6 +132,8 @@ namespace MWGui if (mWindowManager.getInventoryWindow()->getPlayerGold()addOrRemoveGold (-price); + MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(1); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); ESM::Position pos = *_sender->getUserData(); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 4f2c98c08..2c74dd2fd 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -1,5 +1,7 @@ #include "waitdialog.hpp" +#include + #include #include @@ -14,6 +16,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" +#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" #include "widgets.hpp" @@ -132,21 +135,62 @@ namespace MWGui void WaitDialog::onUntilHealedButtonClicked(MyGUI::Widget* sender) { - startWaiting(); + // we need to sleep for a specific time, and since that isn't calculated yet, we'll do it here + // I'm making the assumption here that the # of hours rested is calculated when rest is started + // TODO: the rougher logic here (calculating the hourly deltas) should really go into helper funcs elsewhere + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::CreatureStats stats = MWWorld::Class::get(player).getCreatureStats(player); + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + + float hourlyHealthDelta = stats.getAttribute(ESM::Attribute::Endurance).getModified() * 0.1; + + bool stunted = (stats.getMagicEffects().get(MWMechanics::EffectKey(136)).mMagnitude > 0); + float fRestMagicMult = store.get().find("fRestMagicMult")->getFloat(); + float hourlyMagickaDelta = fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified(); + + // this massive duplication is why it has to be put into helper functions instead + float fFatigueReturnBase = store.get().find("fFatigueReturnBase")->getFloat(); + float fFatigueReturnMult = store.get().find("fFatigueReturnMult")->getFloat(); + float fEndFatigueMult = store.get().find("fEndFatigueMult")->getFloat(); + float capacity = MWWorld::Class::get(player).getCapacity(player); + float encumbrance = MWWorld::Class::get(player).getEncumbrance(player); + float normalizedEncumbrance = (capacity == 0 ? 1 : encumbrance/capacity); + if (normalizedEncumbrance > 1) + normalizedEncumbrance = 1; + float hourlyFatigueDelta = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance); + hourlyFatigueDelta *= 3600 * fEndFatigueMult * stats.getAttribute(ESM::Attribute::Endurance).getModified(); + + float healthHours = hourlyHealthDelta >= 0.0 + ? (stats.getHealth().getBase() - stats.getHealth().getCurrent()) / hourlyHealthDelta + : 1.0f; + float magickaHours = stunted ? 0.0 : + hourlyMagickaDelta >= 0.0 + ? (stats.getMagicka().getBase() - stats.getMagicka().getCurrent()) / hourlyMagickaDelta + : 1.0f; + float fatigueHours = hourlyFatigueDelta >= 0.0 + ? (stats.getFatigue().getBase() - stats.getFatigue().getCurrent()) / hourlyFatigueDelta + : 1.0f; + + int autoHours = int(std::ceil( std::max(std::max(healthHours, magickaHours), std::max(fatigueHours, 1.0f)) )); // this should use a variadic max if possible + + startWaiting(autoHours); } void WaitDialog::onWaitButtonClicked(MyGUI::Widget* sender) { - startWaiting(); + startWaiting(mManualHours); } - void WaitDialog::startWaiting () + void WaitDialog::startWaiting(int hoursToWait) { MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0.2); setVisible(false); mProgressBar.setVisible (true); + mWaiting = true; mCurHour = 0; + mHours = hoursToWait; + mRemainingTime = 0.05; mProgressBar.setProgress (0, mHours); } @@ -159,7 +203,7 @@ namespace MWGui void WaitDialog::onHourSliderChangedPosition(MyGUI::ScrollBar* sender, size_t position) { mHourText->setCaptionWithReplacing (boost::lexical_cast(position+1) + " #{sRestMenu2}"); - mHours = position+1; + mManualHours = position+1; } void WaitDialog::setCanRest (bool canRest) @@ -181,9 +225,9 @@ namespace MWGui mRemainingTime -= dt; - if (mRemainingTime < 0) + while (mRemainingTime < 0) { - mRemainingTime = 0.05; + mRemainingTime += 0.05; ++mCurHour; mProgressBar.setProgress (mCurHour, mHours); @@ -197,6 +241,7 @@ namespace MWGui if (mCurHour > mHours) stopWaiting(); + } void WaitDialog::stopWaiting () diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 6af565c6e..c102d0fc6 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -47,6 +47,7 @@ namespace MWGui bool mSleeping; int mCurHour; int mHours; + int mManualHours; // stores the hours to rest selected via slider float mRemainingTime; WaitDialogProgressBar mProgressBar; @@ -58,7 +59,7 @@ namespace MWGui void setCanRest(bool canRest); - void startWaiting(); + void startWaiting(int hoursToWait); void stopWaiting(); }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 3ae0f37c5..fb4f3c5b3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -110,7 +110,6 @@ WindowManager::WindowManager( , mHudEnabled(true) , mTranslationDataStorage (translationDataStorage) { - // Set up the GUI system mGuiManager = new OEngine::GUI::MyGUIManager(mRendering->getWindow(), mRendering->getScene(), false, logpath); mGui = mGuiManager->getGui(); @@ -196,6 +195,9 @@ WindowManager::WindowManager( unsetSelectedSpell(); unsetSelectedWeapon(); + if (newGame) + disallowAll (); + // Set up visibility updateVisible(); } @@ -560,6 +562,11 @@ void WindowManager::messageBox (const std::string& message, const std::vectorenterPressed(); +} + int WindowManager::readPressedButton () { return mMessageBoxManager->readPressedButton(); @@ -608,6 +615,7 @@ void WindowManager::onFrame (float frameDuration) mHud->onFrame(frameDuration); mTrainingWindow->onFrame (frameDuration); + mTradeWindow->onFrame(frameDuration); mTrainingWindow->checkReferenceAvailable(); mDialogueWindow->checkReferenceAvailable(); @@ -945,12 +953,23 @@ bool WindowManager::isAllowed (GuiWindow wnd) const void WindowManager::allow (GuiWindow wnd) { mAllowed = (GuiWindow)(mAllowed | wnd); + + if (wnd & GW_Inventory) + { + mBookWindow->setInventoryAllowed (true); + mScrollWindow->setInventoryAllowed (true); + } + updateVisible(); } void WindowManager::disallowAll() { mAllowed = GW_None; + + mBookWindow->setInventoryAllowed (false); + mScrollWindow->setInventoryAllowed (false); + updateVisible(); } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index bae195669..864e875cb 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -189,6 +189,7 @@ namespace MWGui virtual void removeDialog(OEngine::GUI::Layout* dialog); ///< Hides dialog and schedules dialog to be deleted. virtual void messageBox (const std::string& message, const std::vector& buttons); + virtual void enterPressed (); virtual int readPressedButton (); ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) virtual void onFrame (float frameDuration); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 0934d8763..e5f024318 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -253,7 +253,7 @@ namespace MWInput // update values of channels (as a result of pressed keys) if (!loading) mInputCtrl->update(dt); - + // Update windows/gui as a result of input events // For instance this could mean opening a new window/dialog, // by doing this after the input events are handled we @@ -428,6 +428,14 @@ namespace MWInput bool InputManager::keyPressed( const OIS::KeyEvent &arg ) { + if(arg.key == OIS::KC_RETURN + && MWBase::Environment::get().getWindowManager()->isGuiMode() + && MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_InterMessageBox ) + { + // Pressing enter when a messagebox is prompting for "ok" will activate the ok button + MWBase::Environment::get().getWindowManager()->enterPressed(); + } + mInputCtrl->keyPressed (arg); unsigned int text = arg.text; #ifdef __APPLE__ // filter \016 symbol for F-keys on OS X @@ -581,10 +589,14 @@ namespace MWInput // Toggle between game mode and inventory mode if(gameMode) mWindows.pushGuiMode(MWGui::GM_Inventory); - else if(mWindows.getMode() == MWGui::GM_Inventory) - mWindows.popGuiMode(); + else + { + MWGui::GuiMode mode = mWindows.getMode(); + if(mode == MWGui::GM_Inventory || mode == MWGui::GM_Container) + mWindows.popGuiMode(); + } - // .. but don't touch any other mode. + // .. but don't touch any other mode, except container. } void InputManager::toggleConsole() @@ -625,11 +637,14 @@ namespace MWInput { if (!mWindows.isGuiMode ()) mWindows.pushGuiMode (MWGui::GM_QuickKeysMenu); + else if (mWindows.getMode () == MWGui::GM_QuickKeysMenu) + mWindows.removeGuiMode (MWGui::GM_QuickKeysMenu); } void InputManager::activate() { - mEngine.activate(); + if (mControlSwitch["playercontrols"]) + mEngine.activate(); } void InputManager::toggleAutoMove() diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index baec2f740..b71022504 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -17,6 +17,11 @@ #include "../mwsound/sound_decoder.hpp" #include "../mwsound/sound.hpp" +#ifdef _WIN32 +#include + +typedef SSIZE_T ssize_t; +#endif namespace MWRender { @@ -361,7 +366,11 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder } void open(const std::string&) +#ifdef _WIN32 + { fail(std::string("Invalid call to ")+__FUNCSIG__); } +#else { fail(std::string("Invalid call to ")+__PRETTY_FUNCTION__); } +#endif void close() { } diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 4cce19b86..81639b5be 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -21,6 +21,7 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwworld/player.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -47,6 +48,10 @@ namespace MWScript if (count<0) throw std::runtime_error ("second argument for AddItem must be non-negative"); + // no-op + if (count == 0) + return; + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), item); ref.getPtr().getRefData().setCount (count); @@ -60,6 +65,26 @@ namespace MWScript } MWWorld::Class::get (ptr).getContainerStore (ptr).add (ref.getPtr()); + + // Spawn a messagebox (only for items added to player's inventory) + if (ptr == MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer()) + { + // The two GMST entries below expand to strings informing the player of what, and how many of it has been added to their inventory + std::string msgBox; + std::string itemName = MWWorld::Class::get(ref.getPtr()).getName(ref.getPtr()); + if (count == 1) + { + msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage60}"); + msgBox = boost::str(boost::format(msgBox) % itemName); + } + else + { + msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage61}"); + msgBox = boost::str(boost::format(msgBox) % count % itemName); + } + + MWBase::Environment::get().getWindowManager()->messageBox(msgBox, std::vector()); + } } }; @@ -101,13 +126,19 @@ namespace MWScript Interpreter::Type_Integer count = runtime[0].mInteger; runtime.pop(); - + if (count<0) throw std::runtime_error ("second argument for RemoveItem must be non-negative"); + // no-op + if (count == 0) + return; + MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr); std::string itemName = ""; + + // originalCount holds the total number of items to remove, count holds the remaining number of items to remove Interpreter::Type_Integer originalCount = count; for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end() && count; @@ -130,28 +161,26 @@ namespace MWScript } } - /* The two GMST entries below expand to strings informing the player of what, and how many of it has been removed from their inventory */ - std::string msgBox; - if(originalCount - count > 1) + // Spawn a messagebox (only for items added to player's inventory) + if (ptr == MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer()) { - msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage63}"); - std::stringstream temp; - temp << boost::format(msgBox) % (originalCount - count) % itemName; - msgBox = temp.str(); - } - else - { - msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage62}"); - std::stringstream temp; - temp << boost::format(msgBox) % itemName; - msgBox = temp.str(); - } - - if(originalCount - count > 0) - MWBase::Environment::get().getWindowManager()->messageBox(msgBox, std::vector()); + // The two GMST entries below expand to strings informing the player of what, and how many of it has been removed from their inventory + std::string msgBox; + int numRemoved = (originalCount - count); + if(numRemoved > 1) + { + msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage63}"); + msgBox = boost::str (boost::format(msgBox) % numRemoved % itemName); + } + else + { + msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage62}"); + msgBox = boost::str (boost::format(msgBox) % itemName); + } - // To be fully compatible with original Morrowind, we would need to check if - // count is >= 0 here and throw an exception. But let's be tollerant instead. + if (numRemoved > 0) + MWBase::Environment::get().getWindowManager()->messageBox(msgBox, std::vector()); + } } }; diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 261a86ca6..00530a962 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -160,6 +160,7 @@ void FFmpeg_Decoder::open(const std::string &fname) { if(mFormatCtx->streams[j]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { + mFormatCtx->streams[j]->codec->request_sample_fmt = AV_SAMPLE_FMT_S16; mStream = &mFormatCtx->streams[j]; break; } diff --git a/apps/openmw/mwworld/actiontake.cpp b/apps/openmw/mwworld/actiontake.cpp index fd28dd52e..cdd19b46e 100644 --- a/apps/openmw/mwworld/actiontake.cpp +++ b/apps/openmw/mwworld/actiontake.cpp @@ -14,9 +14,6 @@ namespace MWWorld void ActionTake::executeImp (const Ptr& actor) { - if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) - return; - // insert into player's inventory MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPtr ("player", true); diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 1666ad823..257676076 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include namespace MWWorld { diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 27bdd77ce..de467666e 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -77,8 +77,8 @@ public: std::string mKey, mTrap; // Key and trap ID names, if any // No idea - occurs ONCE in Morrowind.esm, for an activator - char mUnam; - + signed char mUnam; + // Track deleted references. 0 - not deleted, 1 - deleted, but respawns, 2 - deleted and does not respawn. int mDeleted; @@ -164,14 +164,14 @@ struct Cell bool mWaterInt; int mMapColor; int mNAM0; - + // References "leased" from another cell (i.e. a different cell // introduced this ref, and it has been moved here by a plugin) CellRefTracker mLeasedRefs; MovedCellRefTracker mMovedRefs; - + void load(ESMReader &esm, MWWorld::ESMStore &store); - + // This method is left in for compatibility with esmtool. Parsing moved references currently requires // passing ESMStore, bit it does not know about this parameter, so we do it this way. void load(ESMReader &esm) {}; @@ -209,7 +209,7 @@ struct Cell reuse one memory location without blanking it between calls. */ static bool getNextRef(ESMReader &esm, CellRef &ref); - + /* This fetches an MVRF record, which is used to track moved references. * Since they are comparably rare, we use a separate method for this. */ diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index 078c78811..61f3f763d 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -30,7 +30,7 @@ struct Dialogue }; std::string mId; - char mType; + signed char mType; std::vector mInfo; void load(ESMReader &esm); diff --git a/components/to_utf8/tables_gen.hpp b/components/to_utf8/tables_gen.hpp index 9c32f0427..a1d4b6d80 100644 --- a/components/to_utf8/tables_gen.hpp +++ b/components/to_utf8/tables_gen.hpp @@ -8,7 +8,7 @@ namespace ToUTF8 /// Central European and Eastern European languages that use Latin script, /// such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, /// Serbian (Latin script), Romanian and Albanian. -static char windows_1250[] = +static signed char windows_1250[] = { 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, @@ -270,7 +270,7 @@ static char windows_1250[] = /// Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic /// and other languages -static char windows_1251[] = +static signed char windows_1251[] = { 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, @@ -531,7 +531,7 @@ static char windows_1251[] = }; /// Latin alphabet used by English and some other Western languages -static char windows_1252[] = +static signed char windows_1252[] = { 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index 275f5483f..e2a1b1220 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -216,7 +216,7 @@ void Utf8Encoder::copyFromArray(unsigned char ch, char* &out) return; } - const char *in = translationArray + ch*6; + const signed char *in = translationArray + ch*6; int len = *(in++); for (int i=0; i mOutput; - char* translationArray; + signed char* translationArray; }; } diff --git a/credits.txt b/credits.txt index 5d486c74e..936f3efd9 100644 --- a/credits.txt +++ b/credits.txt @@ -26,6 +26,7 @@ gugus / gus Jacob Essex (Yacoby) Jannik Heller (scrawl) Jason Hooks (jhooks) +Joel Graff (graffy) Karl-Felix Glatzer (k1ll) lazydev Leon Saunders (emoose) diff --git a/files/opencs/opencs.png b/files/opencs/opencs.png new file mode 100644 index 000000000..dddf220a3 Binary files /dev/null and b/files/opencs/opencs.png differ diff --git a/files/opencs/resources.qrc b/files/opencs/resources.qrc new file mode 100644 index 000000000..ecfab44a2 --- /dev/null +++ b/files/opencs/resources.qrc @@ -0,0 +1,5 @@ + + + opencs.png + +