Merged files

openmw-30
Jeffrey Haines 11 years ago
commit a65e8393bb

@ -86,8 +86,6 @@ option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest ang GMock fram
# Sound source selection
option(USE_FFMPEG "use ffmpeg for sound" ON)
option(USE_AUDIERE "use audiere for sound" ON)
option(USE_MPG123 "use mpg123 + libsndfile for sound" ON)
# OS X deployment
option(OPENMW_OSX_DEPLOYMENT OFF)
@ -171,27 +169,6 @@ if (USE_FFMPEG)
endif (FFMPEG_FOUND)
endif (USE_FFMPEG)
if (USE_AUDIERE AND NOT GOT_SOUND_INPUT)
find_package(Audiere)
if (AUDIERE_FOUND)
set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${AUDIERE_INCLUDE_DIR})
set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${AUDIERE_LIBRARY})
set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_AUDIERE)
set(GOT_SOUND_INPUT 1)
endif (AUDIERE_FOUND)
endif (USE_AUDIERE AND NOT GOT_SOUND_INPUT)
if (USE_MPG123 AND NOT GOT_SOUND_INPUT)
find_package(MPG123 REQUIRED)
find_package(SNDFILE REQUIRED)
if (MPG123_FOUND AND SNDFILE_FOUND)
set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${MPG123_INCLUDE_DIR} ${SNDFILE_INCLUDE_DIR})
set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${MPG123_LIBRARY} ${SNDFILE_LIBRARY})
set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_MPG123)
set(GOT_SOUND_INPUT 1)
endif (MPG123_FOUND AND SNDFILE_FOUND)
endif (USE_MPG123 AND NOT GOT_SOUND_INPUT)
if (NOT GOT_SOUND_INPUT)
message(WARNING "--------------------")
message(WARNING "Failed to find any sound input packages")
@ -434,7 +411,6 @@ IF(NOT WIN32 AND NOT APPLE)
# Install licenses
INSTALL(FILES "DejaVu Font License.txt" DESTINATION "${LICDIR}" )
INSTALL(FILES "OFL.txt" DESTINATION "${LICDIR}" )
INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" )
ENDIF (DPKG_PROGRAM)

@ -333,7 +333,7 @@ int load(Arguments& info)
// Is the user interested in this record type?
bool interested = true;
if (info.types.size() > 0)
if (!info.types.empty())
{
std::vector<std::string>::iterator match;
match = std::find(info.types.begin(), info.types.end(),

@ -124,7 +124,7 @@ void printEffectList(ESM::EffectList effects)
{
int i = 0;
std::vector<ESM::ENAMstruct>::iterator eit;
for (eit = effects.mList.begin(); eit != effects.mList.end(); eit++)
for (eit = effects.mList.begin(); eit != effects.mList.end(); ++eit)
{
std::cout << " Effect[" << i << "]: " << magicEffectLabel(eit->mEffectID)
<< " (" << eit->mEffectID << ")" << std::endl;

@ -214,13 +214,13 @@ QStringList Launcher::GraphicsPage::getAvailableOptions(const QString &key, Ogre
uint row = 0;
Ogre::ConfigOptionMap options = renderer->getConfigOptions();
for (Ogre::ConfigOptionMap::iterator i = options.begin (); i != options.end (); i++, row++)
for (Ogre::ConfigOptionMap::iterator i = options.begin (); i != options.end (); ++i, ++row)
{
Ogre::StringVector::iterator opt_it;
uint idx = 0;
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)
{
if (strcmp (key.toStdString().c_str(), i->first.c_str()) == 0) {
result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromStdString((*opt_it).c_str()).simplified();

@ -60,7 +60,7 @@ opencs_hdrs_noqt (view/doc
opencs_units (view/world
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
cellcreator referenceablecreator referencecreator scenesubview scenetoolbar scenetool
scenetoolmode infocreator scriptedit dialoguesubview previewsubview regionmap
scenetoolmode infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable
)
opencs_units (view/render
@ -95,7 +95,9 @@ opencs_units (view/settings
booleanview
textview
listview
rangeview
resizeablestackedwidget
spinbox
)
opencs_units_noqt (view/settings

@ -121,7 +121,7 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
//iterate the data directories and add them to the file dialog for loading
for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter)
{
QString path = QString::fromStdString(iter->string());
QString path = QString::fromUtf8 (iter->string().c_str());
mFileDialog.addFiles(path);
}
/*

@ -1,29 +1,22 @@
#include "setting.hpp"
#include "support.hpp"
CSMSettings::Setting::Setting()
{
buildDefaultSetting();
}
CSMSettings::Setting::Setting(SettingType typ, const QString &settingName,
const QString &pageName, const QStringList &values)
const QString &pageName)
: mIsEditorSetting (false)
{
buildDefaultSetting();
int vType = static_cast <int> (typ);
int settingType = static_cast <int> (typ);
if ((vType % 2) == 0)
setProperty (Property_IsMultiValue,
QVariant(true).toString());
else
vType--;
//even-numbered setting types are multi-valued
if ((settingType % 2) == 0)
setProperty (Property_IsMultiValue, QVariant(true).toString());
setProperty (Property_ViewType, QVariant (vType / 2).toString());
//view type is related to setting type by an order of magnitude
setProperty (Property_SettingType, QVariant (settingType).toString());
setProperty (Property_Page, pageName);
setProperty (Property_Name, settingName);
setProperty (Property_DeclaredValues, values);
}
void CSMSettings::Setting::buildDefaultSetting()
@ -74,6 +67,11 @@ int CSMSettings::Setting::columnSpan() const
return property (Property_ColumnSpan).at(0).toInt();
}
void CSMSettings::Setting::setDeclaredValues (QStringList list)
{
setProperty (Property_DeclaredValues, list);
}
QStringList CSMSettings::Setting::declaredValues() const
{
return property (Property_DeclaredValues);
@ -97,6 +95,16 @@ QStringList CSMSettings::Setting::property (SettingProperty prop) const
return mProperties.at(prop);
}
void CSMSettings::Setting::setDefaultValue (int value)
{
setDefaultValues (QStringList() << QVariant (value).toString());
}
void CSMSettings::Setting::setDefaultValue (double value)
{
setDefaultValues (QStringList() << QVariant (value).toString());
}
void CSMSettings::Setting::setDefaultValue (const QString &value)
{
setDefaultValues (QStringList() << value);
@ -166,6 +174,16 @@ bool CSMSettings::Setting::serializable() const
return (property (Property_Serializable).at(0) == "true");
}
void CSMSettings::Setting::setSpecialValueText(const QString &text)
{
setProperty (Property_SpecialValueText, text);
}
QString CSMSettings::Setting::specialValueText() const
{
return property (Property_SpecialValueText).at(0);
}
void CSMSettings::Setting::setName (const QString &value)
{
setProperty (Property_Name, value);
@ -186,6 +204,16 @@ QString CSMSettings::Setting::page() const
return property (Property_Page).at(0);
}
void CSMSettings::Setting::setPrefix (const QString &value)
{
setProperty (Property_Prefix, value);
}
QString CSMSettings::Setting::prefix() const
{
return property (Property_Prefix).at(0);
}
void CSMSettings::Setting::setRowSpan (const int value)
{
setProperty (Property_RowSpan, value);
@ -196,15 +224,106 @@ int CSMSettings::Setting::rowSpan () const
return property (Property_RowSpan).at(0).toInt();
}
void CSMSettings::Setting::setViewType (int vType)
void CSMSettings::Setting::setSingleStep (int value)
{
setProperty (Property_SingleStep, value);
}
void CSMSettings::Setting::setSingleStep (double value)
{
setProperty (Property_SingleStep, value);
}
QString CSMSettings::Setting::singleStep() const
{
return property (Property_SingleStep).at(0);
}
void CSMSettings::Setting::setSuffix (const QString &value)
{
setProperty (Property_Suffix, value);
}
QString CSMSettings::Setting::suffix() const
{
return property (Property_Suffix).at(0);
}
void CSMSettings::Setting::setTickInterval (int value)
{
setProperty (Property_TickInterval, value);
}
int CSMSettings::Setting::tickInterval () const
{
return property (Property_TickInterval).at(0).toInt();
}
void CSMSettings::Setting::setTicksAbove (bool state)
{
setProperty (Property_TicksAbove, state);
}
bool CSMSettings::Setting::ticksAbove() const
{
setProperty (Property_ViewType, vType);
return (property (Property_TicksAbove).at(0) == "true");
}
void CSMSettings::Setting::setTicksBelow (bool state)
{
setProperty (Property_TicksBelow, state);
}
bool CSMSettings::Setting::ticksBelow() const
{
return (property (Property_TicksBelow).at(0) == "true");
}
void CSMSettings::Setting::setType (int settingType)
{
setProperty (Property_SettingType, settingType);
}
CSMSettings::SettingType CSMSettings::Setting::type() const
{
return static_cast <CSMSettings::SettingType> ( property (
Property_SettingType).at(0).toInt());
}
void CSMSettings::Setting::setMaximum (int value)
{
setProperty (Property_Maximum, value);
}
void CSMSettings::Setting::setMaximum (double value)
{
setProperty (Property_Maximum, value);
}
QString CSMSettings::Setting::maximum() const
{
return property (Property_Maximum).at(0);
}
void CSMSettings::Setting::setMinimum (int value)
{
setProperty (Property_Minimum, value);
}
void CSMSettings::Setting::setMinimum (double value)
{
setProperty (Property_Minimum, value);
}
QString CSMSettings::Setting::minimum() const
{
return property (Property_Minimum).at(0);
}
CSVSettings::ViewType CSMSettings::Setting::viewType() const
{
return static_cast <CSVSettings::ViewType>
(property(Property_ViewType).at(0).toInt());
return static_cast <CSVSettings::ViewType> ( property (
Property_SettingType).at(0).toInt() / 10);
}
void CSMSettings::Setting::setViewColumn (int value)
@ -242,6 +361,17 @@ int CSMSettings::Setting::widgetWidth() const
{
return property (Property_WidgetWidth).at(0).toInt();
}
void CSMSettings::Setting::setWrapping (bool state)
{
setProperty (Property_Wrapping, state);
}
bool CSMSettings::Setting::wrapping() const
{
return (property (Property_Wrapping).at(0) == "true");
}
void CSMSettings::Setting::setProperty (SettingProperty prop, bool value)
{
setProperty (prop, QStringList() << QVariant (value).toString());
@ -252,6 +382,11 @@ void CSMSettings::Setting::setProperty (SettingProperty prop, int value)
setProperty (prop, QStringList() << QVariant (value).toString());
}
void CSMSettings::Setting::setProperty (SettingProperty prop, double value)
{
setProperty (prop, QStringList() << QVariant (value).toString());
}
void CSMSettings::Setting::setProperty (SettingProperty prop,
const QString &value)
{
@ -264,18 +399,3 @@ void CSMSettings::Setting::setProperty (SettingProperty prop,
if (prop < mProperties.size())
mProperties.replace (prop, value);
}
QDataStream &operator <<(QDataStream &stream, const CSMSettings::Setting& setting)
{
stream << setting.properties();
stream << setting.proxies();
return stream;
}
QDataStream &operator >>(QDataStream& stream, CSMSettings::Setting& setting)
{
// stream >> setting.properties();
// stream >> setting.proxies();
return stream;
}

@ -27,12 +27,8 @@ namespace CSMSettings
public:
explicit Setting();
explicit Setting(SettingType typ, const QString &settingName,
const QString &pageName,
const QStringList &values = QStringList());
const QString &pageName);
void addProxy (const Setting *setting, const QStringList &vals);
void addProxy (const Setting *setting, const QList <QStringList> &list);
@ -49,6 +45,8 @@ namespace CSMSettings
void setDefinedValues (QStringList list);
QStringList definedValues() const;
void setDefaultValue (int value);
void setDefaultValue (double value);
void setDefaultValue (const QString &value);
void setDefaultValues (const QStringList &values);
@ -66,12 +64,26 @@ namespace CSMSettings
void setIsMultiValue (bool state);
bool isMultiValue() const;
void setMask (const QString &value);
QString mask() const;
void setMaximum (int value);
void setMaximum (double value);
QString maximum() const;
void setMinimum (int value);
void setMinimum (double value);
QString minimum() const;
void setName (const QString &value);
QString name() const;
void setPage (const QString &value);
QString page() const;
void setPrefix (const QString &value);
QString prefix() const;
void setRowSpan (const int value);
int rowSpan() const;
@ -80,6 +92,25 @@ namespace CSMSettings
void setSerializable (bool state);
bool serializable() const;
void setSpecialValueText (const QString &text);
QString specialValueText() const;
void setSingleStep (int value);
void setSingleStep (double value);
QString singleStep() const;
void setSuffix (const QString &value);
QString suffix() const;
void setTickInterval (int value);
int tickInterval() const;
void setTicksAbove (bool state);
bool ticksAbove() const;
void setTicksBelow (bool state);
bool ticksBelow() const;
void setViewColumn (int value);
int viewColumn() const;
@ -88,9 +119,14 @@ namespace CSMSettings
void setViewRow (int value);
int viewRow() const;
void setViewType (int vType);
void setType (int settingType);
CSMSettings::SettingType type() const;
CSVSettings::ViewType viewType() const;
void setWrapping (bool state);
bool wrapping() const;
void setWidgetWidth (int value);
int widgetWidth() const;
@ -100,6 +136,7 @@ namespace CSMSettings
///boilerplate code to convert setting values of common types
void setProperty (SettingProperty prop, bool value);
void setProperty (SettingProperty prop, int value);
void setProperty (SettingProperty prop, double value);
void setProperty (SettingProperty prop, const QString &value);
void setProperty (SettingProperty prop, const QStringList &value);
@ -111,9 +148,4 @@ namespace CSMSettings
};
}
Q_DECLARE_METATYPE(CSMSettings::Setting)
QDataStream &operator <<(QDataStream &stream, const CSMSettings::Setting& setting);
QDataStream &operator >>(QDataStream &stream, CSMSettings::Setting& setting);
#endif // CSMSETTINGS_SETTING_HPP

@ -30,8 +30,7 @@ void CSMSettings::SettingManager::dumpModel()
}
CSMSettings::Setting *CSMSettings::SettingManager::createSetting
(CSMSettings::SettingType typ, const QString &page, const QString &name,
const QStringList &values)
(CSMSettings::SettingType typ, const QString &page, const QString &name)
{
//get list of all settings for the current setting name
if (findSetting (page, name))
@ -41,7 +40,8 @@ CSMSettings::Setting *CSMSettings::SettingManager::createSetting
return 0;
}
Setting *setting = new Setting (typ, name, page, values);
Setting *setting = new Setting (typ, name, page);
//add declaration to the model
mSettings.append (setting);

@ -46,8 +46,7 @@ namespace CSMSettings
///add a new setting to the model and return it
Setting *createSetting (CSMSettings::SettingType typ,
const QString &page, const QString &name,
const QStringList &values = QStringList());
const QString &page, const QString &name);
///add definitions to the settings specified in the page map
void addDefinitions (DefinitionPageMap &pageMap);

@ -27,7 +27,7 @@ namespace CSMSettings
{
Property_Name = 0,
Property_Page = 1,
Property_ViewType = 2,
Property_SettingType = 2,
Property_IsMultiValue = 3,
Property_IsMultiLine = 4,
Property_WidgetWidth = 5,
@ -37,24 +37,49 @@ namespace CSMSettings
Property_Serializable = 9,
Property_ColumnSpan = 10,
Property_RowSpan = 11,
Property_Minimum = 12,
Property_Maximum = 13,
Property_SpecialValueText = 14,
Property_Prefix = 15,
Property_Suffix = 16,
Property_SingleStep = 17,
Property_Wrapping = 18,
Property_TickInterval = 19,
Property_TicksAbove = 20,
Property_TicksBelow = 21,
//Stringlists should always be the last items
Property_DefaultValues = 12,
Property_DeclaredValues = 13,
Property_DefinedValues = 14,
Property_Proxies = 15
Property_DefaultValues = 22,
Property_DeclaredValues = 23,
Property_DefinedValues = 24,
Property_Proxies = 25
};
enum SettingType
{
Type_MultiBool = 0,
Type_SingleBool = 1,
Type_MultiList = 2,
Type_SingleList = 3,
Type_MultiRange = 4,
Type_SingleRange = 5,
Type_MultiText = 6,
Type_SingleText = 7
/*
* 0 - 9 - Boolean widgets
* 10-19 - List widgets
* 21-29 - Range widgets
* 31-39 - Text widgets
*
* Each range corresponds to a View_Type enum by a factor of 10.
*
* Even-numbered values are single-value widgets
* Odd-numbered values are multi-valued widgets
*/
Type_CheckBox = 0,
Type_RadioButton = 1,
Type_ListView = 10,
Type_ComboBox = 11,
Type_SpinBox = 21,
Type_DoubleSpinBox = 23,
Type_Slider = 25,
Type_Dial = 27,
Type_TextArea = 30,
Type_LineEdit = 31,
Type_Undefined = 40
};
enum MergeMethod
@ -84,7 +109,7 @@ namespace CSVSettings
};
}
//
namespace CSMSettings
{
struct PropertyDefaultValues
@ -96,9 +121,11 @@ namespace CSMSettings
const QString sPropertyNames[] =
{
"name", "page", "view_type", "is_multi_value",
"name", "page", "setting_type", "is_multi_value",
"is_multi_line", "widget_width", "view_row", "view_column", "delimiter",
"is_serializable","column_span", "row_span",
"is_serializable","column_span", "row_span", "minimum", "maximum",
"special_value_text", "prefix", "suffix", "single_step", "wrapping",
"tick_interval", "ticks_above", "ticks_below",
"defaults", "declarations", "definitions", "proxies"
};
@ -106,16 +133,26 @@ namespace CSMSettings
{
"", //name
"", //page
"0", //view type
"40", //setting type
"false", //multivalue
"false", //multiline
"0", //widget width
"7", //widget width
"-1", //view row
"-1", //view column
",", //delimiter
"true", //serialized
"1", //column span
"1", //row span
"0", //value range
"0", //value minimum
"0", //value maximum
"", //special text
"", //prefix
"", //suffix
"false", //wrapping
"1", //tick interval
"false", //ticks above
"true", //ticks below
"", //default values
"", //declared values
"", //defined values

@ -47,11 +47,11 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
{
QString section = "Window Size";
{
Setting *width = createSetting (Type_SingleText, section, "Width");
Setting *height = createSetting (Type_SingleText, section, "Height");
Setting *width = createSetting (Type_LineEdit, section, "Width");
Setting *height = createSetting (Type_LineEdit, section, "Height");
width->setWidgetWidth (5);
height->setWidgetWidth (5);
height->setWidgetWidth (8);
width->setDefaultValues (QStringList() << "1024");
height->setDefaultValues (QStringList() << "768");
@ -65,14 +65,11 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
/*
*Create the proxy setting for predefined values
*/
Setting *preDefined = createSetting (Type_SingleList, section,
"Pre-Defined",
QStringList()
<< "640 x 480"
<< "800 x 600"
<< "1024 x 768"
<< "1440 x 900"
);
Setting *preDefined = createSetting (Type_ComboBox, section,
"Pre-Defined");
preDefined->setDeclaredValues (QStringList() << "640 x 480"
<< "800 x 600" << "1024 x 768" << "1440 x 900");
preDefined->setViewLocation (1, 1);
preDefined->setWidgetWidth (10);
@ -94,13 +91,14 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
QStringList values = QStringList()
<< defaultValue << "Icon Only" << "Text Only";
Setting *rsd = createSetting (Type_SingleBool,
section, "Record Status Display",
values);
Setting *rsd = createSetting (Type_RadioButton,
section, "Record Status Display");
Setting *ritd = createSetting (Type_RadioButton,
section, "Referenceable ID Type Display");
Setting *ritd = createSetting (Type_SingleBool,
section, "Referenceable ID Type Display",
values);
rsd->setDeclaredValues (values);
ritd->setDeclaredValues (values);
rsd->setEditorSetting (true);
ritd->setEditorSetting (true);
@ -108,44 +106,67 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
section = "Proxy Selection Test";
{
//create three setting objects, specifying the basic widget type,
//the setting view name, the page name, and the default value
Setting *masterBoolean = createSetting (Type_SingleBool, section,
"Master Proxy",
QStringList()
<< "Profile One" << "Profile Two"
<< "Profile Three" << "Profile Four"
);
Setting *slaveBoolean = createSetting (Type_MultiBool, section,
"Proxy Checkboxes",
QStringList() << "One" << "Two"
<< "Three" << "Four" << "Five"
);
Setting *slaveSingleText = createSetting (Type_SingleText, section,
"Proxy TextBox 1"
);
Setting *slaveMultiText = createSetting (Type_SingleText, section,
"ProxyTextBox 2"
);
// There are three types of values:
//
// Declared values - Pre-determined values, typically for
// combobox drop downs and boolean (radiobutton / checkbox) labels.
// These values represent the total possible list of values that may
// define a setting. No other values are allowed.
//
// Defined values - Values which represent the atual, current value of
// a setting. For settings with declared values, this must be one or
// several declared values, as appropriate.
//
// Proxy values - values the proxy master updates the proxy slave when
// it's own definition is set / changed. These are definitions for
// proxy slave settings, but must match any declared values the proxy
// slave has, if any.
/******************************************************************
* There are three types of values:
*
* Declared values
*
* Pre-determined values, typically for
* combobox drop downs and boolean (radiobutton / checkbox) labels.
* These values represent the total possible list of values that
* may define a setting. No other values are allowed.
*
* Defined values
*
* Values which represent the actual, current value of
* a setting. For settings with declared values, this must be one or
* several declared values, as appropriate.
*
* Proxy values - values the proxy master updates the proxy slave when
* it's own definition is set / changed. These are definitions for
* proxy slave settings, but must match any declared values the proxy
* slave has, if any.
*******************************************************************/
//create setting objects, specifying the basic widget type,
//the page name, and the view name
/*
Setting *masterBoolean = createSetting (Type_RadioButton, section,
"Master Proxy");
Setting *slaveBoolean = createSetting (Type_CheckBox, section,
"Proxy Checkboxes");
Setting *slaveSingleText = createSetting (Type_LineEdit, section,
"Proxy TextBox 1");
Setting *slaveMultiText = createSetting (Type_LineEdit, section,
"ProxyTextBox 2");
Setting *slaveAlphaSpinbox = createSetting (Type_SpinBox, section,
"Alpha Spinbox");
Setting *slaveIntegerSpinbox = createSetting (Type_SpinBox, section,
"Int Spinbox");
Setting *slaveDoubleSpinbox = createSetting (Type_DoubleSpinBox,
section, "Double Spinbox");
Setting *slaveSlider = createSetting (Type_Slider, section, "Slider");
Setting *slaveDial = createSetting (Type_Dial, section, "Dial");
//set declared values for selected views
masterBoolean->setDeclaredValues (QStringList()
<< "Profile One" << "Profile Two"
<< "Profile Three" << "Profile Four");
slaveBoolean->setDeclaredValues (QStringList()
<< "One" << "Two" << "Three" << "Four" << "Five");
slaveAlphaSpinbox->setDeclaredValues (QStringList()
<< "One" << "Two" << "Three" << "Four");
masterBoolean->addProxy (slaveBoolean, QList <QStringList>()
<< (QStringList() << "One" << "Three")
@ -168,11 +189,47 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
<< (QStringList() << "Two" << "Four")
);
masterBoolean->addProxy (slaveAlphaSpinbox, QList <QStringList>()
<< (QStringList() << "Four")
<< (QStringList() << "Three")
<< (QStringList() << "Two")
<< (QStringList() << "One"));
masterBoolean->addProxy (slaveIntegerSpinbox, QList <QStringList> ()
<< (QStringList() << "0")
<< (QStringList() << "7")
<< (QStringList() << "14")
<< (QStringList() << "21"));
masterBoolean->addProxy (slaveDoubleSpinbox, QList <QStringList> ()
<< (QStringList() << "0.17")
<< (QStringList() << "0.34")
<< (QStringList() << "0.51")
<< (QStringList() << "0.68"));
masterBoolean->addProxy (slaveSlider, QList <QStringList> ()
<< (QStringList() << "25")
<< (QStringList() << "50")
<< (QStringList() << "75")
<< (QStringList() << "100")
);
masterBoolean->addProxy (slaveDial, QList <QStringList> ()
<< (QStringList() << "25")
<< (QStringList() << "50")
<< (QStringList() << "75")
<< (QStringList() << "100")
);
//settings with proxies are not serialized by default
//other settings non-serialized for demo purposes
slaveBoolean->setSerializable (false);
slaveSingleText->setSerializable (false);
slaveMultiText->setSerializable (false);
slaveAlphaSpinbox->setSerializable (false);
slaveIntegerSpinbox->setSerializable (false);
slaveDoubleSpinbox->setSerializable (false);
slaveSlider->setSerializable (false);
slaveBoolean->setDefaultValues (QStringList()
<< "One" << "Three" << "Five");
@ -184,7 +241,39 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
slaveSingleText->setWidgetWidth (24);
slaveMultiText->setWidgetWidth (24);
}
slaveAlphaSpinbox->setDefaultValue ("Two");
slaveAlphaSpinbox->setWidgetWidth (20);
//slaveAlphaSpinbox->setPrefix ("No. ");
//slaveAlphaSpinbox->setSuffix ("!");
slaveAlphaSpinbox->setWrapping (true);
slaveIntegerSpinbox->setDefaultValue (14);
slaveIntegerSpinbox->setMinimum (0);
slaveIntegerSpinbox->setMaximum (58);
slaveIntegerSpinbox->setPrefix ("$");
slaveIntegerSpinbox->setSuffix (".00");
slaveIntegerSpinbox->setWidgetWidth (10);
slaveIntegerSpinbox->setSpecialValueText ("Nothing!");
slaveDoubleSpinbox->setDefaultValue (0.51);
slaveDoubleSpinbox->setSingleStep(0.17);
slaveDoubleSpinbox->setMaximum(4.0);
slaveSlider->setMinimum (0);
slaveSlider->setMaximum (100);
slaveSlider->setDefaultValue (75);
slaveSlider->setWidgetWidth (100);
slaveSlider->setTicksAbove (true);
slaveSlider->setTickInterval (25);
slaveDial->setMinimum (0);
slaveDial->setMaximum (100);
slaveDial->setSingleStep (5);
slaveDial->setDefaultValue (75);
slaveDial->setTickInterval (25);
*/
}
}
CSMSettings::UserSettings::~UserSettings()
@ -195,13 +284,13 @@ CSMSettings::UserSettings::~UserSettings()
void CSMSettings::UserSettings::loadSettings (const QString &fileName)
{
mUserFilePath = QString::fromUtf8
(mCfgMgr.getUserConfigPath().c_str()) + fileName.toUtf8();
(mCfgMgr.getUserConfigPath().string().c_str()) + fileName.toUtf8();
QString global = QString::fromUtf8
(mCfgMgr.getGlobalPath().c_str()) + fileName.toUtf8();
(mCfgMgr.getGlobalPath().string().c_str()) + fileName.toUtf8();
QString local = QString::fromUtf8
(mCfgMgr.getLocalPath().c_str()) + fileName.toUtf8();
(mCfgMgr.getLocalPath().string().c_str()) + fileName.toUtf8();
//open user and global streams
QTextStream *userStream = openFilestream (mUserFilePath, true);

@ -453,7 +453,7 @@ CSMWorld::IdCollection<CSMFilter::Filter>& CSMWorld::Data::getFilters()
return mFilters;
}
QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id)
QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& id)
{
std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType());

@ -1,6 +1,9 @@
#include "tablemimedata.hpp"
#include <string>
#include <QDebug>
#include "universalid.hpp"
#include "columnbase.hpp"
@ -11,7 +14,7 @@ mDocument(document)
mObjectsFormats << QString::fromUtf8 (("tabledata/" + id.getTypeName()).c_str());
}
CSMWorld::TableMimeData::TableMimeData (std::vector< CSMWorld::UniversalId >& id, const CSMDoc::Document& document) :
CSMWorld::TableMimeData::TableMimeData (const std::vector< CSMWorld::UniversalId >& id, const CSMDoc::Document& document) :
mUniversalId (id), mDocument(document)
{
for (std::vector<UniversalId>::iterator it (mUniversalId.begin()); it != mUniversalId.end(); ++it)
@ -33,7 +36,8 @@ std::string CSMWorld::TableMimeData::getIcon() const
{
if (mUniversalId.empty())
{
throw ("TableMimeData holds no UniversalId");
qDebug()<<"TableMimeData object does not hold any records!"; //because throwing in the event loop tends to be problematic
throw("TableMimeData object does not hold any records!");
}
std::string tmpIcon;
@ -50,7 +54,7 @@ std::string CSMWorld::TableMimeData::getIcon() const
if (tmpIcon != mUniversalId[i].getIcon())
{
return ":/multitype.png"; //icon stolen from gnome
return ":/multitype.png"; //icon stolen from gnome TODO: get new icon
}
tmpIcon = mUniversalId[i].getIcon();
@ -531,4 +535,4 @@ CSMWorld::ColumnBase::Display CSMWorld::TableMimeData::convertEnums (CSMWorld::U
const CSMDoc::Document* CSMWorld::TableMimeData::getDocumentPtr() const
{
return &mDocument;
}
}

@ -33,7 +33,7 @@ namespace CSMWorld
public:
TableMimeData(UniversalId id, const CSMDoc::Document& document);
TableMimeData(std::vector<UniversalId>& id, const CSMDoc::Document& document);
TableMimeData(const std::vector<UniversalId>& id, const CSMDoc::Document& document);
~TableMimeData();
@ -56,6 +56,7 @@ namespace CSMWorld
UniversalId returnMatching(CSMWorld::ColumnBase::Display type) const;
static CSMWorld::UniversalId::Type convertEnums(CSMWorld::ColumnBase::Display type);
static CSMWorld::ColumnBase::Display convertEnums(CSMWorld::UniversalId::Type type);
private:

@ -64,6 +64,7 @@ namespace
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_TopicInfo, "TopicInfo", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_JournalInfo, "JournalInfo", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell", ":./cell.png" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell_Missing, "Cell", ":./cell.png" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Referenceable, "Referenceables", 0 },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Activator, "Activator", ":./activator.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Potion, "Potion", ":./potion.png" },

@ -60,6 +60,7 @@ namespace CSMWorld
Type_Spell,
Type_Cells,
Type_Cell,
Type_Cell_Missing, //For cells that does not exist yet.
Type_Referenceables,
Type_Referenceable,
Type_Activator,

@ -3,8 +3,12 @@
#include <sstream>
CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget *parent)
: WorldspaceWidget (parent)
#include <QtGui/qevent.h>
#include <apps/opencs/model/world/tablemimedata.hpp>
CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document)
: WorldspaceWidget (document, parent)
{}
void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint)
@ -44,4 +48,45 @@ void CSVRender::PagedWorldspaceWidget::setCellSelection (const CSMWorld::CellSel
{
mSelection = selection;
emit cellSelectionChanged (mSelection);
}
std::pair< int, int > CSVRender::PagedWorldspaceWidget::getCoordinatesFromId (const std::string& record) const
{
std::istringstream stream (record.c_str());
char ignore;
int x, y;
stream >> ignore >> x >> y;
return std::make_pair(x, y);
}
void CSVRender::PagedWorldspaceWidget::handleDrop (const std::vector< CSMWorld::UniversalId >& data)
{
bool selectionChanged = false;
for (unsigned i = 0; i < data.size(); ++i)
{
std::pair<int, int> coordinates(getCoordinatesFromId(data[i].getId()));
if (mSelection.add(CSMWorld::CellCoordinates(coordinates.first, coordinates.second)))
{
selectionChanged = true;
}
}
if (selectionChanged)
{
emit cellSelectionChanged(mSelection);
}
}
CSVRender::WorldspaceWidget::dropRequirments CSVRender::PagedWorldspaceWidget::getDropRequirements (CSVRender::WorldspaceWidget::dropType type) const
{
switch (type)
{
case cellsExterior:
return canHandle;
case cellsInterior:
return needUnpaged;
default:
return ignored;
}
}

@ -13,17 +13,25 @@ namespace CSVRender
CSMWorld::CellSelection mSelection;
private:
std::pair<int, int> getCoordinatesFromId(const std::string& record) const;
public:
PagedWorldspaceWidget (QWidget *parent);
PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document);
///< \note Sets the cell area selection to an invalid value to indicate that currently
/// no cells are displayed. The cells to be displayed will be specified later through
/// hint system.
virtual void useViewHint (const std::string& hint);
void useViewHint (const std::string& hint);
void setCellSelection (const CSMWorld::CellSelection& selection);
virtual void handleDrop(const std::vector<CSMWorld::UniversalId>& data);
virtual dropRequirments getDropRequirements(dropType type) const;
signals:
void cellSelectionChanged (const CSMWorld::CellSelection& selection);

@ -320,7 +320,7 @@ namespace CSVRender
}
if (mUpdate)
if (mUpdate && mWindow)
{
mUpdate = false;
mWindow->update();

@ -36,7 +36,7 @@ namespace CSVRender
SceneWidget(QWidget *parent);
virtual ~SceneWidget();
QPaintEngine* paintEngine() const;
QPaintEngine* paintEngine() const;
CSVWorld::SceneToolMode *makeLightingSelector (CSVWorld::SceneToolbar *parent);
///< \attention The created tool is not added to the toolbar (via addTool). Doing that

@ -3,10 +3,13 @@
#include <OgreColourValue.h>
#include <QtGui/qevent.h>
#include "../../model/doc/document.hpp"
#include "../../model/world/data.hpp"
#include "../../model/world/idtable.hpp"
#include "../../model/world/tablemimedata.hpp"
void CSVRender::UnpagedWorldspaceWidget::update()
{
@ -20,9 +23,8 @@ void CSVRender::UnpagedWorldspaceWidget::update()
/// \todo deal with mSunlight and mFog/mForDensity
}
CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& cellId,
CSMDoc::Document& document, QWidget *parent)
: WorldspaceWidget (parent), mCellId (cellId)
CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document, QWidget* parent)
: WorldspaceWidget (document, parent), mCellId (cellId)
{
mCellsModel = &dynamic_cast<CSMWorld::IdTable&> (
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells));
@ -63,4 +65,26 @@ void CSVRender::UnpagedWorldspaceWidget::cellRowsAboutToBeRemoved (const QModelI
if (cellIndex.row()>=start && cellIndex.row()<=end)
emit closeRequest();
}
}
void CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vector< CSMWorld::UniversalId >& data)
{
mCellId = data.begin()->getId();
update();
emit cellChanged(*data.begin());
}
CSVRender::WorldspaceWidget::dropRequirments CSVRender::UnpagedWorldspaceWidget::getDropRequirements (CSVRender::WorldspaceWidget::dropType type) const
{
switch(type)
{
case cellsInterior:
return canHandle;
case cellsExterior:
return needPaged;
default:
return ignored;
}
}

@ -31,13 +31,21 @@ namespace CSVRender
public:
UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document,
QWidget *parent);
QWidget *parent);
virtual dropRequirments getDropRequirements(dropType type) const;
virtual void handleDrop(const std::vector<CSMWorld::UniversalId>& data);
private slots:
void cellDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
void cellRowsAboutToBeRemoved (const QModelIndex& parent, int start, int end);
signals:
void cellChanged(const CSMWorld::UniversalId& id);
};
}

@ -5,15 +5,20 @@
#include <OgreSceneManager.h>
#include <OgreEntity.h>
#include <QtGui/qevent.h>
#include "../world/scenetoolmode.hpp"
#include <apps/opencs/model/world/universalid.hpp>
CSVRender::WorldspaceWidget::WorldspaceWidget (QWidget *parent)
: SceneWidget (parent)
CSVRender::WorldspaceWidget::WorldspaceWidget (const CSMDoc::Document& document, QWidget* parent)
: SceneWidget (parent), mDocument(document)
{
Ogre::Entity* ent = getSceneManager()->createEntity("cube", Ogre::SceneManager::PT_CUBE);
ent->setMaterialName("BaseWhite");
getSceneManager()->getRootSceneNode()->attachObject(ent);
setAcceptDrops(true);
}
void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode)
@ -46,4 +51,78 @@ CSVWorld::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector (
this, SLOT (selectNavigationMode (const std::string&)));
return tool;
}
CSVRender::WorldspaceWidget::dropType CSVRender::WorldspaceWidget::getDropType (
const std::vector< CSMWorld::UniversalId >& data)
{
dropType output = notCells;
bool firstIteration = true;
for (unsigned i = 0; i < data.size(); ++i)
{
if (data[i].getType() == CSMWorld::UniversalId::Type_Cell ||
data[i].getType() == CSMWorld::UniversalId::Type_Cell_Missing)
{
if (*(data[i].getId().begin()) == '#') //exterior
{
if (firstIteration)
{
output = cellsExterior;
firstIteration = false;
continue;
}
if (output == cellsInterior)
{
output = cellsMixed;
break;
} else {
output = cellsInterior;
}
} else //interior
{
if (firstIteration)
{
output = cellsInterior;
firstIteration = false;
continue;
}
if (output == cellsExterior)
{
output = cellsMixed;
break;
} else {
output = cellsInterior;
}
}
} else {
output = notCells;
break;
}
}
return output;
}
void CSVRender::WorldspaceWidget::dragEnterEvent (QDragEnterEvent* event)
{
event->accept();
}
void CSVRender::WorldspaceWidget::dragMoveEvent(QDragMoveEvent *event)
{
event->accept();
}
void CSVRender::WorldspaceWidget::dropEvent (QDropEvent* event)
{
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
if (mime->fromDocument (mDocument))
{
emit dataDropped(mime->getData());
} //not handling drops from different documents at the moment
}

@ -6,7 +6,13 @@
#include "navigation1st.hpp"
#include "navigationfree.hpp"
#include "navigationorbit.hpp"
#include <apps/opencs/model/doc/document.hpp>
#include <apps/opencs/model/world/tablemimedata.hpp>
namespace CSMWorld
{
class UniversalId;
}
namespace CSVWorld
{
class SceneToolMode;
@ -25,7 +31,23 @@ namespace CSVRender
public:
WorldspaceWidget (QWidget *parent = 0);
enum dropType
{
cellsMixed,
cellsInterior,
cellsExterior,
notCells
};
enum dropRequirments
{
canHandle,
needPaged,
needUnpaged,
ignored //either mixed cells, or not cells
};
WorldspaceWidget (const CSMDoc::Document& document, QWidget *parent = 0);
CSVWorld::SceneToolMode *makeNavigationSelector (CSVWorld::SceneToolbar *parent);
///< \attention The created tool is not added to the toolbar (via addTool). Doing that
@ -33,9 +55,26 @@ namespace CSVRender
void selectDefaultNavigationMode();
static dropType getDropType(const std::vector<CSMWorld::UniversalId>& data);
virtual dropRequirments getDropRequirements(dropType type) const = 0;
virtual void useViewHint (const std::string& hint);
///< Default-implementation: ignored.
virtual void handleDrop(const std::vector<CSMWorld::UniversalId>& data) = 0;
protected:
const CSMDoc::Document& mDocument; //for checking if drop comes from same document
private:
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent* event);
void dragMoveEvent(QDragMoveEvent *event);
private slots:
void selectNavigationMode (const std::string& mode);
@ -43,6 +82,7 @@ namespace CSVRender
signals:
void closeRequest();
void dataDropped(const std::vector<CSMWorld::UniversalId>& data);
};
}

@ -18,10 +18,19 @@ CSVSettings::BooleanView::BooleanView (CSMSettings::Setting *setting,
{
QAbstractButton *button = 0;
if (isMultiValue())
switch (setting->type())
{
case CSMSettings::Type_CheckBox:
button = new QCheckBox (value, this);
else
break;
case CSMSettings::Type_RadioButton:
button = new QRadioButton (value, this);
break;
default:
break;
}
connect (button, SIGNAL (clicked (bool)),
this, SLOT (slotToggled (bool)));

@ -1,5 +1,5 @@
#ifndef CSVSETTINGS_BOOLEANVIEW_HPP
#define CSVSETTINGS_BOOELANVIEW_HPP
#define CSVSETTINGS_BOOLEANVIEW_HPP
#include <QWidget>
#include <QAbstractButton>

@ -123,10 +123,8 @@ void CSVSettings::Dialog::show()
{
if (pages().isEmpty())
buildPages();
QPoint screenCenter = QApplication::desktop()->screenGeometry().center();
move (screenCenter - geometry().center());
QWidget::show();
}

@ -60,8 +60,10 @@ void CSVSettings::Frame::showWidgets()
QWidget *widg = static_cast <QWidget *> (obj);
if (widg->property("sizePolicy").isValid())
{
widg->setSizePolicy
(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
}
}
layout()->activate();
setFixedSize(minimumSizeHint());

@ -3,9 +3,12 @@
#include "booleanview.hpp"
#include "textview.hpp"
#include "listview.hpp"
#include "rangeview.hpp"
#include "../../model/settings/usersettings.hpp"
#include "../../model/settings/connector.hpp"
#include "../../model/settings/support.hpp"
#include "settingwindow.hpp"
QMap <CSVSettings::ViewType, CSVSettings::IViewFactory *>
@ -85,4 +88,5 @@ void CSVSettings::Page::buildFactories()
mViewFactories[ViewType_Boolean] = new BooleanViewFactory (this);
mViewFactories[ViewType_Text] = new TextViewFactory (this);
mViewFactories[ViewType_List] = new ListViewFactory (this);
mViewFactories[ViewType_Range] = new RangeViewFactory (this);
}

@ -0,0 +1,204 @@
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGroupBox>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include <QAbstractSpinBox>
#include <QAbstractSlider>
#include <QDial>
#include <QSlider>
#include "rangeview.hpp"
#include "spinbox.hpp"
#include "../../model/settings/setting.hpp"
#include "../../model/settings/support.hpp"
CSVSettings::RangeView::RangeView (CSMSettings::Setting *setting,
Page *parent)
: mRangeWidget (0), mRangeType (setting->type()), View (setting, parent)
{
mRangeWidget = 0;
if (isMultiValue())
return;
switch (mRangeType)
{
case CSMSettings::Type_SpinBox:
case CSMSettings::Type_DoubleSpinBox:
buildSpinBox (setting);
break;
case CSMSettings::Type_Dial:
case CSMSettings::Type_Slider:
buildSlider (setting);
break;
default:
break;
}
mRangeWidget->setFixedWidth (widgetWidth (setting->widgetWidth()));
mRangeWidget->setObjectName (setting->name());
addWidget (mRangeWidget);
}
void CSVSettings::RangeView::buildSlider (CSMSettings::Setting *setting)
{
switch (setting->type())
{
case CSMSettings::Type_Slider:
mRangeWidget = new QSlider (Qt::Horizontal, this);
mRangeWidget->setProperty ("tickInterval", setting->tickInterval());
if (setting->ticksAbove())
{
if (setting->ticksBelow())
mRangeWidget->setProperty ("tickPosition", QSlider::TicksBothSides);
else
mRangeWidget->setProperty ("tickPosition", QSlider::TicksAbove);
}
else if (setting->ticksBelow())
mRangeWidget->setProperty ("tickPosition", QSlider::TicksBelow);
else
mRangeWidget->setProperty ("tickPosition", QSlider::NoTicks);
break;
case CSMSettings::Type_Dial:
mRangeWidget = new QDial (this);
mRangeWidget->setProperty ("wrapping", setting->wrapping());
mRangeWidget->setProperty ("notchesVisible",
(setting->ticksAbove() || setting->ticksBelow()));
break;
default:
break;
}
mRangeWidget->setProperty ("minimum", setting->minimum());
mRangeWidget->setProperty ("maximum", setting->maximum());
mRangeWidget->setProperty ("tracking", false);
mRangeWidget->setProperty ("singleStep", setting->singleStep());
connect (mRangeWidget, SIGNAL (valueChanged (int)),
this, SLOT (slotUpdateView (int)));
}
void CSVSettings::RangeView::buildSpinBox (CSMSettings::Setting *setting)
{
SpinBox *sb = 0;
switch (setting->type())
{
case CSMSettings::Type_SpinBox:
sb = new SpinBox (this);
if (!setting->declaredValues().isEmpty())
sb->setValueList (setting->declaredValues());
mRangeWidget = sb;
connect (mRangeWidget, SIGNAL (valueChanged (int)),
this, SLOT (slotUpdateView (int)));
break;
case CSMSettings::Type_DoubleSpinBox:
mRangeWidget = new QDoubleSpinBox (this);
connect (mRangeWidget, SIGNAL (valueChanged (double)),
this, SLOT (slotUpdateView (double)));
break;
default:
break;
}
//min / max values are set automatically in AlphaSpinBox
if (setting->declaredValues().isEmpty())
{
mRangeWidget->setProperty ("minimum", setting->minimum());
mRangeWidget->setProperty ("maximum", setting->maximum());
mRangeWidget->setProperty ("singleStep", setting->singleStep());
mRangeWidget->setProperty ("specialValueText",
setting->specialValueText());
}
mRangeWidget->setProperty ("prefix", setting->prefix());
mRangeWidget->setProperty ("suffix", setting->suffix());
mRangeWidget->setProperty ("wrapping", setting->wrapping());
}
void CSVSettings::RangeView::slotUpdateView (int value)
{
QString textValue = "";
QStringList list;
switch (mRangeType)
{
case CSMSettings::Type_SpinBox:
list = static_cast <SpinBox *> (mRangeWidget)->valueList();
if (!list.isEmpty())
textValue = list.at(value);
break;
default:
break;
}
if (textValue.isEmpty())
textValue = QVariant (value).toString();
setSelectedValue (textValue, false);
View::updateView();
}
void CSVSettings::RangeView::slotUpdateView (double value)
{
setSelectedValue (QVariant(value).toString(), false);
View::updateView();
}
void CSVSettings::RangeView::updateView (bool signalUpdate) const
{
QString value;
if (!selectedValues().isEmpty())
value = selectedValues().at(0);
switch (mRangeType)
{
case CSMSettings::Type_SpinBox:
static_cast <SpinBox *> (mRangeWidget)->setValue (value);
break;
case CSMSettings::Type_DoubleSpinBox:
static_cast <QDoubleSpinBox *> (mRangeWidget)->setValue (value.toDouble());
break;
case CSMSettings::Type_Slider:
case CSMSettings::Type_Dial:
mRangeWidget->setProperty ("value", value.toInt());
mRangeWidget->setProperty ("sliderPosition", value.toInt());
break;
default:
break;
}
View::updateView (signalUpdate);
}
CSVSettings::RangeView *CSVSettings::RangeViewFactory::createView
(CSMSettings::Setting *setting,
Page *parent)
{
return new RangeView (setting, parent);
}

@ -0,0 +1,49 @@
#ifndef CSVSETTINGS_RANGEVIEW_HPP
#define CSVSETTINGS_RANGEVIEW_HPP
#include "view.hpp"
#include "../../model/settings/support.hpp"
class QStringListModel;
class QAbstractSpinBox;
namespace CSVSettings
{
class RangeView : public View
{
Q_OBJECT
QWidget *mRangeWidget;
CSMSettings::SettingType mRangeType;
public:
explicit RangeView (CSMSettings::Setting *setting,
Page *parent);
protected:
void updateView (bool signalUpdate = true) const;
void buildSlider (CSMSettings::Setting *setting);
void buildSpinBox (CSMSettings::Setting *setting);
private slots:
void slotUpdateView (int value);
void slotUpdateView (double value);
};
class RangeViewFactory : public QObject, public IViewFactory
{
Q_OBJECT
public:
explicit RangeViewFactory (QWidget *parent = 0)
: QObject (parent)
{}
RangeView *createView (CSMSettings::Setting *setting,
Page *parent);
};
}
#endif // CSVSETTINGS_RANGEVIEW_HPP

@ -19,7 +19,7 @@ void CSVSettings::SettingWindow::createPages()
QList <CSMSettings::Setting *> connectedSettings;
foreach (const QString &pageName, pageMap.keys())
{
{
QList <CSMSettings::Setting *> pageSettings = pageMap.value (pageName);
mPages.append (new Page (pageName, pageSettings, this));

@ -0,0 +1,51 @@
#include "spinbox.hpp"
#include <QSpinBox>
#include <QLineEdit>
CSVSettings::SpinBox::SpinBox(QWidget *parent)
: mValueList(QStringList()), QSpinBox(parent)
{
setRange (0, 0);
}
QString CSVSettings::SpinBox::textFromValue(int val) const
{
if (mValueList.isEmpty())
return QVariant (val).toString();
QString value = "";
if (val < mValueList.size())
value = mValueList.at (val);
return value;
}
int CSVSettings::SpinBox::valueFromText(const QString &text) const
{
if (mValueList.isEmpty())
return -1;
if (mValueList.contains (text))
return mValueList.indexOf(text);
return -1;
}
void CSVSettings::SpinBox::setValue (const QString &value)
{
if (!mValueList.isEmpty())
{
lineEdit()->setText (value);
QSpinBox::setValue(valueFromText(value));
}
else
QSpinBox::setValue (value.toInt());
}
void CSVSettings::SpinBox::setValueList (const QStringList &list)
{
mValueList = list;
setMaximum (list.size() - 1);
}

@ -0,0 +1,31 @@
#ifndef CSVSETTINGS_SPINBOX_HPP
#define CSVSETTINGS_SPINBOX_HPP
#include <QObject>
#include <QStringList>
#include <QSpinBox>
namespace CSVSettings
{
class SpinBox : public QSpinBox
{
Q_OBJECT
QStringList mValueList;
public:
explicit SpinBox(QWidget *parent = 0);
void setObjectName (const QString &name);
void setValue (const QString &value);
void setValueList (const QStringList &list);
const QStringList &valueList() const { return mValueList; }
protected:
QString textFromValue (int val) const;
int valueFromText (const QString &text) const;
};
}
#endif // CSVSETTINGS_SPINBOX_HPP

@ -28,11 +28,6 @@ bool CSVSettings::TextView::isEquivalent
return (lhs.trimmed() == rhs.trimmed());
}
void CSVSettings::TextView::setWidgetText (const QString &value) const
{
mTextWidget->setProperty ("text", value);
}
void CSVSettings::TextView::slotTextEdited (QString value)
{
QStringList values = value.split (mDelimiter, QString::SkipEmptyParts);
@ -51,19 +46,14 @@ void CSVSettings::TextView::updateView(bool signalUpdate) const
{
QString values = selectedValues().join (mDelimiter);
if (isEquivalent (widgetText(), values))
if (isEquivalent (mTextWidget->property("text").toString(), values))
return;
setWidgetText (values);
mTextWidget->setProperty("text", values);
View::updateView (signalUpdate);
}
QString CSVSettings::TextView::widgetText() const
{
return mTextWidget->property("text").toString();
}
CSVSettings::TextView *CSVSettings::TextViewFactory::createView
(CSMSettings::Setting *setting,
Page *parent)

@ -32,12 +32,6 @@ namespace CSVSettings
///Comparison function that returns true if the trimmed() strings
///are equal
bool isEquivalent (const QString &lhs, const QString &rhs) const;
///Convenience function to return the text of the widget
QString widgetText() const;
///Convenience function to set the text of the widget
void setWidgetText (const QString &value) const;
};
class TextViewFactory : public QObject, public IViewFactory

@ -192,6 +192,7 @@ bool CSVSettings::View::stringListsMatch (
QList <QStandardItem *> CSVSettings::View::toStandardItemList
(const QStringList &list) const
{
QList <QStandardItem *> itemList;
foreach (const QString &value, list)

@ -101,7 +101,7 @@ namespace CSVSettings
void showEvent ( QShowEvent * event );
///Virtual for updating a specific View subclass
///bool indicates whether a signal is emitted that the view was updated
///bool indicates whether viewUpdated() signal is emitted
virtual void updateView (bool signalUpdate = true) const;
///Returns the pixel width corresponding to the specified number of

@ -25,7 +25,7 @@ CSVWorld::DataDisplayDelegate::DataDisplayDelegate(const ValueList &values,
void CSVWorld::DataDisplayDelegate::buildPixmaps ()
{
if (mPixmaps.size() > 0)
if (!mPixmaps.empty())
mPixmaps.clear();
IconList::iterator it = mIcons.begin();
@ -33,7 +33,7 @@ void CSVWorld::DataDisplayDelegate::buildPixmaps ()
while (it != mIcons.end())
{
mPixmaps.push_back (std::make_pair (it->first, it->second.pixmap (mIconSize) ) );
it++;
++it;
}
}

@ -183,7 +183,7 @@ CSVWorld::CommandDelegate* CSVWorld::DialogueDelegateDispatcher::makeDelegate(CS
{
delegate = CommandDelegateFactoryCollection::get().makeDelegate (
display, mUndoStack, mParent);
mDelegates.insert(std::make_pair<int, CommandDelegate*>(display, delegate));
mDelegates.insert(std::make_pair(display, delegate));
} else
{
delegate = delegateIt->second;

@ -0,0 +1,38 @@
#include <QDrag>
#include "../../model/world/tablemimedata.hpp"
#include "dragrecordtable.hpp"
void CSVWorld::DragRecordTable::startDrag (const CSVWorld::DragRecordTable& table)
{
CSMWorld::TableMimeData* mime = new CSMWorld::TableMimeData (table.getDraggedRecords(), mDocument);
if (mime)
{
QDrag* drag = new QDrag (this);
drag->setMimeData (mime);
drag->setPixmap (QString::fromUtf8 (mime->getIcon().c_str()));
drag->exec (Qt::CopyAction);
}
}
CSVWorld::DragRecordTable::DragRecordTable (CSMDoc::Document& document, QWidget* parent) :
mDocument(document),
QTableView(parent),
mEditLock(false)
{}
void CSVWorld::DragRecordTable::setEditLock (bool locked)
{
mEditLock = locked;
}
void CSVWorld::DragRecordTable::dragEnterEvent(QDragEnterEvent *event)
{
event->acceptProposedAction();
}
void CSVWorld::DragRecordTable::dragMoveEvent(QDragMoveEvent *event)
{
event->accept();
}

@ -0,0 +1,45 @@
#ifndef CSV_WORLD_DRAGRECORDTABLE_H
#define CSV_WORLD_DRAGRECORDTABLE_H
#include <QTableView>
#include <QtGui/qevent.h>
class QWidget;
class QAction;
namespace CSMDoc
{
class Document;
}
namespace CSMWorld
{
class UniversalId;
}
namespace CSVWorld
{
class DragRecordTable : public QTableView
{
protected:
CSMDoc::Document& mDocument;
bool mEditLock;
public:
DragRecordTable(CSMDoc::Document& document, QWidget* parent = NULL);
virtual std::vector<CSMWorld::UniversalId> getDraggedRecords() const = 0;
void setEditLock(bool locked);
protected:
void startDrag(const DragRecordTable& table);
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
};
}
#endif

@ -17,6 +17,7 @@
#include "../../model/world/idtable.hpp"
#include "../../model/world/commands.hpp"
#include "../../model/world/columns.hpp"
#include "../../model/world/tablemimedata.hpp"
void CSVWorld::RegionMap::contextMenuEvent (QContextMenuEvent *event)
{
@ -180,7 +181,7 @@ void CSVWorld::RegionMap::setRegion (const std::string& regionId)
CSVWorld::RegionMap::RegionMap (const CSMWorld::UniversalId& universalId,
CSMDoc::Document& document, QWidget *parent)
: QTableView (parent), mEditLock (false), mDocument (document)
: DragRecordTable(document, parent)
{
verticalHeader()->hide();
horizontalHeader()->hide();
@ -223,11 +224,8 @@ CSVWorld::RegionMap::RegionMap (const CSMWorld::UniversalId& universalId,
mViewInTableAction = new QAction (tr ("View Cells in Table"), this);
connect (mViewInTableAction, SIGNAL (triggered()), this, SLOT (viewInTable()));
addAction (mViewInTableAction);
}
void CSVWorld::RegionMap::setEditLock (bool locked)
{
mEditLock = locked;
setAcceptDrops(true);
}
void CSVWorld::RegionMap::selectAll()
@ -343,4 +341,65 @@ void CSVWorld::RegionMap::viewInTable()
hint << ")";
emit editRequest (CSMWorld::UniversalId::Type_Cells, hint.str());
}
void CSVWorld::RegionMap::mouseMoveEvent (QMouseEvent* event)
{
startDrag(*this);
}
std::vector< CSMWorld::UniversalId > CSVWorld::RegionMap::getDraggedRecords() const
{
QModelIndexList selected(getSelectedCells(true, false));
std::vector<CSMWorld::UniversalId> ids;
foreach (QModelIndex it, selected)
{
ids.push_back(
CSMWorld::UniversalId(
CSMWorld::UniversalId::Type_Cell,
model()->data(it, CSMWorld::RegionMap::Role_CellId).toString().toUtf8().constData()));
}
selected = getSelectedCells(false, true);
foreach (QModelIndex it, selected)
{
ids.push_back(
CSMWorld::UniversalId(
CSMWorld::UniversalId::Type_Cell_Missing,
model()->data(it, CSMWorld::RegionMap::Role_CellId).toString().toUtf8().constData()));
}
return ids;
}
void CSVWorld::RegionMap::dropEvent (QDropEvent* event)
{
QModelIndex index = indexAt (event->pos());
bool exists = QTableView::model()->data(index, Qt::BackgroundRole)!=QBrush (Qt::DiagCrossPattern);
if (!index.isValid() || !exists)
{
return;
}
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
if (mime->fromDocument(mDocument) && mime->holdsType(CSMWorld::UniversalId::Type_Region))
{
CSMWorld::UniversalId record (mime->returnMatching (CSMWorld::UniversalId::Type_Region));
QAbstractItemModel *regionModel = model();
CSMWorld::IdTable *cellsModel = &dynamic_cast<CSMWorld::IdTable&> (*
mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_Cells));
std::string cellId(regionModel->data (index, CSMWorld::RegionMap::Role_CellId).
toString().toUtf8().constData());
QModelIndex index2(cellsModel->getModelIndex (cellId,
cellsModel->findColumnIndex (CSMWorld::Columns::ColumnId_Region)));
mDocument.getUndoStack().push(new CSMWorld::ModifyCommand
(*cellsModel, index2, QString::fromUtf8(record.getId().c_str())));
mRegionId = record.getId();
}
}

@ -1,8 +1,14 @@
#ifndef CSV_WORLD_REGIONMAP_H
#define CSV_WORLD_REGIONMAP_H
#include <cstddef>
#include <vector>
#include <QObject>
#include <QTableView>
#include "./dragrecordtable.hpp"
class QAction;
namespace CSMDoc
@ -17,7 +23,7 @@ namespace CSMWorld
namespace CSVWorld
{
class RegionMap : public QTableView
class RegionMap : public DragRecordTable
{
Q_OBJECT
@ -29,8 +35,6 @@ namespace CSVWorld
QAction *mUnsetRegionAction;
QAction *mViewAction;
QAction *mViewInTableAction;
bool mEditLock;
CSMDoc::Document& mDocument;
std::string mRegionId;
private:
@ -50,12 +54,16 @@ namespace CSVWorld
void setRegion (const std::string& regionId);
///< Set region Id of selected cells.
void mouseMoveEvent(QMouseEvent *event);
void dropEvent(QDropEvent* event);
public:
RegionMap (const CSMWorld::UniversalId& universalId, CSMDoc::Document& document,
QWidget *parent = 0);
void setEditLock (bool locked);
virtual std::vector<CSMWorld::UniversalId> getDraggedRecords() const;
signals:

@ -6,6 +6,7 @@
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <cassert>
#include "../../model/doc/document.hpp"
@ -18,11 +19,10 @@
#include "tablebottombox.hpp"
#include "creator.hpp"
#include "scenetoolbar.hpp"
#include "scenetoolmode.hpp"
CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document)
: SubView (id)
: SubView (id), mLayout(new QHBoxLayout), mDocument(document), mScene(NULL), mToolbar(NULL)
{
QVBoxLayout *layout = new QVBoxLayout;
@ -32,33 +32,35 @@ CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::D
new TableBottomBox (NullCreatorFactory(), document.getData(), document.getUndoStack(), id,
this), 0);
QHBoxLayout *layout2 = new QHBoxLayout;
mLayout->setContentsMargins (QMargins (0, 0, 0, 0));
layout2->setContentsMargins (QMargins (0, 0, 0, 0));
SceneToolbar *toolbar = new SceneToolbar (48+6, this);
CSVRender::WorldspaceWidget* wordspaceWidget = NULL;
widgetType whatWidget;
if (id.getId()=="sys::default")
{
CSVRender::PagedWorldspaceWidget *widget = new CSVRender::PagedWorldspaceWidget (this);
mScene = widget;
connect (widget, SIGNAL (cellSelectionChanged (const CSMWorld::CellSelection&)),
this, SLOT (cellSelectionChanged (const CSMWorld::CellSelection&)));
whatWidget = widget_Paged;
CSVRender::PagedWorldspaceWidget *newWidget = new CSVRender::PagedWorldspaceWidget (this, document);
wordspaceWidget = newWidget;
makeConnections(newWidget);
}
else
mScene = new CSVRender::UnpagedWorldspaceWidget (id.getId(), document, this);
{
whatWidget = widget_Unpaged;
SceneToolMode *navigationTool = mScene->makeNavigationSelector (toolbar);
toolbar->addTool (navigationTool);
CSVRender::UnpagedWorldspaceWidget *newWidget = new CSVRender::UnpagedWorldspaceWidget (id.getId(), document, this);
SceneToolMode *lightingTool = mScene->makeLightingSelector (toolbar);
toolbar->addTool (lightingTool);
wordspaceWidget = newWidget;
layout2->addWidget (toolbar, 0);
makeConnections(newWidget);
}
layout2->addWidget (mScene, 1);
replaceToolbarAndWorldspace(wordspaceWidget, makeToolbar(wordspaceWidget, whatWidget));
layout->insertLayout (0, layout2, 1);
layout->insertLayout (0, mLayout, 1);
CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this);
@ -69,10 +71,53 @@ CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::D
widget->setLayout (layout);
setWidget (widget);
}
mScene->selectDefaultNavigationMode();
void CSVWorld::SceneSubView::makeConnections (CSVRender::UnpagedWorldspaceWidget* widget)
{
connect (widget, SIGNAL (closeRequest()), this, SLOT (closeRequest()));
connect(widget, SIGNAL(dataDropped(const std::vector<CSMWorld::UniversalId>&)),
this, SLOT(handleDrop(const std::vector<CSMWorld::UniversalId>&)));
connect(widget, SIGNAL(cellChanged(const CSMWorld::UniversalId&)),
this, SLOT(cellSelectionChanged(const CSMWorld::UniversalId&)));
}
void CSVWorld::SceneSubView::makeConnections (CSVRender::PagedWorldspaceWidget* widget)
{
connect (widget, SIGNAL (closeRequest()), this, SLOT (closeRequest()));
connect(widget, SIGNAL(dataDropped(const std::vector<CSMWorld::UniversalId>&)),
this, SLOT(handleDrop(const std::vector<CSMWorld::UniversalId>&)));
connect (widget, SIGNAL (cellSelectionChanged (const CSMWorld::CellSelection&)),
this, SLOT (cellSelectionChanged (const CSMWorld::CellSelection&)));
}
CSVWorld::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::WorldspaceWidget* widget, widgetType type)
{
CSVWorld::SceneToolbar* toolbar = new SceneToolbar (48+6, this);
SceneToolMode *navigationTool = widget->makeNavigationSelector (toolbar);
toolbar->addTool (navigationTool);
SceneToolMode *lightingTool = widget->makeLightingSelector (toolbar);
toolbar->addTool (lightingTool);
/* Add buttons specific to the type. For now no need for it.
*
switch (type)
{
case widget_Paged:
break;
case widget_Unpaged:
break;
connect (mScene, SIGNAL (closeRequest()), this, SLOT (closeRequest()));
}
*/
return toolbar;
}
void CSVWorld::SceneSubView::setEditLock (bool locked)
@ -102,8 +147,19 @@ void CSVWorld::SceneSubView::closeRequest()
deleteLater();
}
void CSVWorld::SceneSubView::cellSelectionChanged (const CSMWorld::UniversalId& id)
{
setUniversalId(id);
std::ostringstream stream;
stream << "Scene: " << getUniversalId().getId();
setWindowTitle (QString::fromUtf8 (stream.str().c_str()));
}
void CSVWorld::SceneSubView::cellSelectionChanged (const CSMWorld::CellSelection& selection)
{
setUniversalId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Scene, "sys::default"));
int size = selection.getSize();
std::ostringstream stream;
@ -126,4 +182,62 @@ void CSVWorld::SceneSubView::cellSelectionChanged (const CSMWorld::CellSelection
}
setWindowTitle (QString::fromUtf8 (stream.str().c_str()));
}
void CSVWorld::SceneSubView::handleDrop (const std::vector< CSMWorld::UniversalId >& data)
{
CSVRender::PagedWorldspaceWidget* pagedNewWidget = NULL;
CSVRender::UnpagedWorldspaceWidget* unPagedNewWidget = NULL;
SceneToolbar* toolbar = NULL;
switch (mScene->getDropRequirements(CSVRender::WorldspaceWidget::getDropType(data)))
{
case CSVRender::WorldspaceWidget::canHandle:
mScene->handleDrop(data);
break;
case CSVRender::WorldspaceWidget::needPaged:
pagedNewWidget = new CSVRender::PagedWorldspaceWidget(this, mDocument);
toolbar = makeToolbar(pagedNewWidget, widget_Paged);
makeConnections(pagedNewWidget);
replaceToolbarAndWorldspace(pagedNewWidget, toolbar);
mScene->handleDrop(data);
break;
case CSVRender::WorldspaceWidget::needUnpaged:
unPagedNewWidget = new CSVRender::UnpagedWorldspaceWidget(data.begin()->getId(), mDocument, this);
toolbar = makeToolbar(unPagedNewWidget, widget_Unpaged);
makeConnections(unPagedNewWidget);
replaceToolbarAndWorldspace(unPagedNewWidget, toolbar);
cellSelectionChanged(*(data.begin()));
break;
case CSVRender::WorldspaceWidget::ignored:
return;
}
}
void CSVWorld::SceneSubView::replaceToolbarAndWorldspace (CSVRender::WorldspaceWidget* widget, CSVWorld::SceneToolbar* toolbar)
{
assert(mLayout);
if (mScene)
{
mLayout->removeWidget(mScene);
mScene->deleteLater();
}
if (mToolbar)
{
mLayout->removeWidget(mToolbar);
mToolbar->deleteLater();
}
mScene = widget;
mToolbar = toolbar;
mLayout->addWidget (mToolbar, 0);
mLayout->addWidget (mScene, 1);
mScene->selectDefaultNavigationMode();
}

@ -1,7 +1,10 @@
#ifndef CSV_WORLD_SCENESUBVIEW_H
#define CSV_WORLD_SCENESUBVIEW_H
#include <QHBoxLayout>
#include "../doc/subview.hpp"
#include "scenetoolbar.hpp"
class QModelIndex;
@ -18,6 +21,8 @@ namespace CSMDoc
namespace CSVRender
{
class WorldspaceWidget;
class PagedWorldspaceWidget;
class UnpagedWorldspaceWidget;
}
namespace CSVWorld
@ -32,6 +37,9 @@ namespace CSVWorld
TableBottomBox *mBottom;
CSVRender::WorldspaceWidget *mScene;
QHBoxLayout* mLayout;
CSMDoc::Document& mDocument;
SceneToolbar* mToolbar;
public:
@ -45,11 +53,30 @@ namespace CSVWorld
virtual void useHint (const std::string& hint);
private:
void makeConnections(CSVRender::PagedWorldspaceWidget* widget);
void makeConnections(CSVRender::UnpagedWorldspaceWidget* widget);
void replaceToolbarAndWorldspace(CSVRender::WorldspaceWidget* widget, SceneToolbar* toolbar);
enum widgetType
{
widget_Paged,
widget_Unpaged
};
SceneToolbar* makeToolbar(CSVRender::WorldspaceWidget* widget, widgetType type);
private slots:
void closeRequest();
void cellSelectionChanged (const CSMWorld::CellSelection& selection);
void cellSelectionChanged (const CSMWorld::UniversalId& id);
void handleDrop(const std::vector<CSMWorld::UniversalId>& data);
};
}

@ -188,8 +188,8 @@ std::vector<std::string> CSVWorld::Table::listDeletableSelectedIds() const
CSVWorld::Table::Table (const CSMWorld::UniversalId& id,
bool createAndDelete, bool sorting, CSMDoc::Document& document)
: mCreateAction (0), mCloneAction(0), mEditLock (false), mRecordStatusDisplay (0),
mDocument (document)
: mCreateAction (0), mCloneAction(0), mRecordStatusDisplay (0),
DragRecordTable(document)
{
mModel = &dynamic_cast<CSMWorld::IdTable&> (*mDocument.getData().getTableModel (id));
@ -282,7 +282,7 @@ void CSVWorld::Table::setEditLock (bool locked)
for (std::vector<CommandDelegate *>::iterator iter (mDelegates.begin()); iter!=mDelegates.end(); ++iter)
(*iter)->setEditLock (locked);
mEditLock = locked;
DragRecordTable::setEditLock(locked);
}
CSMWorld::UniversalId CSVWorld::Table::getUniversalId (int row) const
@ -298,7 +298,7 @@ void CSVWorld::Table::revertRecord()
{
std::vector<std::string> revertableIds = listRevertableSelectedIds();
if (revertableIds.size()>0)
if (!revertableIds.empty())
{
if (revertableIds.size()>1)
mDocument.getUndoStack().beginMacro (tr ("Revert multiple records"));
@ -318,7 +318,7 @@ void CSVWorld::Table::deleteRecord()
{
std::vector<std::string> deletableIds = listDeletableSelectedIds();
if (deletableIds.size()>0)
if (!deletableIds.empty())
{
if (deletableIds.size()>1)
mDocument.getUndoStack().beginMacro (tr ("Delete multiple records"));
@ -518,42 +518,8 @@ void CSVWorld::Table::mouseMoveEvent (QMouseEvent* event)
{
if (event->buttons() & Qt::LeftButton)
{
QModelIndexList selectedRows = selectionModel()->selectedRows();
if (selectedRows.size() == 0)
{
return;
}
QDrag* drag = new QDrag (this);
CSMWorld::TableMimeData* mime = NULL;
if (selectedRows.size() == 1)
{
mime = new CSMWorld::TableMimeData (getUniversalId (selectedRows.begin()->row()), mDocument);
}
else
{
std::vector<CSMWorld::UniversalId> idToDrag;
foreach (QModelIndex it, selectedRows) //I had a dream. Dream where you could use C++11 in OpenMW.
{
idToDrag.push_back (getUniversalId (it.row()));
}
mime = new CSMWorld::TableMimeData (idToDrag, mDocument);
}
drag->setMimeData (mime);
drag->setPixmap (QString::fromUtf8 (mime->getIcon().c_str()));
drag->exec(Qt::CopyAction);
startDrag(*this);
}
}
void CSVWorld::Table::dragEnterEvent(QDragEnterEvent *event)
{
event->acceptProposedAction();
}
void CSVWorld::Table::dropEvent(QDropEvent *event)
@ -583,11 +549,6 @@ void CSVWorld::Table::dropEvent(QDropEvent *event)
} //TODO handle drops from different document
}
void CSVWorld::Table::dragMoveEvent(QDragMoveEvent *event)
{
event->accept();
}
std::vector<std::string> CSVWorld::Table::getColumnsWithDisplay(CSMWorld::ColumnBase::Display display) const
{
const int count = mModel->columnCount();
@ -605,3 +566,18 @@ std::vector<std::string> CSVWorld::Table::getColumnsWithDisplay(CSMWorld::Column
}
return titles;
}
std::vector< CSMWorld::UniversalId > CSVWorld::Table::getDraggedRecords() const
{
QModelIndexList selectedRows = selectionModel()->selectedRows();
std::vector<CSMWorld::UniversalId> idToDrag;
foreach (QModelIndex it, selectedRows) //I had a dream. Dream where you could use C++11 in OpenMW.
{
idToDrag.push_back (getUniversalId (it.row()));
}
return idToDrag;
}

@ -4,11 +4,11 @@
#include <vector>
#include <string>
#include <QTableView>
#include <QtGui/qevent.h>
#include "../../model/filter/node.hpp"
#include "../../model/world/columnbase.hpp"
#include "dragrecordtable.hpp"
class QUndoStack;
class QAction;
@ -31,7 +31,7 @@ namespace CSVWorld
class CommandDelegate;
///< Table widget
class Table : public QTableView
class Table : public DragRecordTable
{
Q_OBJECT
@ -47,9 +47,7 @@ namespace CSVWorld
QAction *mPreviewAction;
CSMWorld::IdTableProxyModel *mProxyModel;
CSMWorld::IdTable *mModel;
bool mEditLock;
int mRecordStatusDisplay;
CSMDoc::Document& mDocument;
private:
@ -61,10 +59,6 @@ namespace CSVWorld
void mouseMoveEvent(QMouseEvent *event);
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
public:
@ -74,12 +68,14 @@ namespace CSVWorld
///< \param createAndDelete Allow creation and deletion of records.
/// \param sorting Allow changing order of rows in the view via column headers.
void setEditLock (bool locked);
virtual void setEditLock (bool locked);
CSMWorld::UniversalId getUniversalId (int row) const;
std::vector<std::string> getColumnsWithDisplay(CSMWorld::ColumnBase::Display display) const;
virtual std::vector<CSMWorld::UniversalId> getDraggedRecords() const;
signals:
void editRequest (const CSMWorld::UniversalId& id, const std::string& hint);
@ -92,6 +88,7 @@ namespace CSVWorld
/// \param modified Number of added and modified records
void createRequest();
void cloneRequest(const CSMWorld::UniversalId&);
private slots:

@ -48,7 +48,7 @@ add_openmw_dir (mwscript
)
add_openmw_dir (mwsound
soundmanagerimp openal_output audiere_decoder mpgsnd_decoder ffmpeg_decoder
soundmanagerimp openal_output ffmpeg_decoder
)
add_openmw_dir (mwworld
@ -67,7 +67,7 @@ add_openmw_dir (mwclass
add_openmw_dir (mwmechanics
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
drawstate spells activespells npcstats aipackage aisequence aipersue alchemy aiwander aitravel aifollow
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow
aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting
disease pickpocket levelledlist combat steering obstacle
)

@ -5,6 +5,11 @@
#include <stdint.h>
namespace Loading
{
class Listener;
}
namespace ESM
{
class ESMReader;
@ -45,9 +50,6 @@ namespace MWBase
virtual void goodbye() = 0;
virtual MWWorld::Ptr getActor() const = 0;
///< Return the actor the player is currently talking to.
virtual void say(const MWWorld::Ptr &actor, const std::string &topic) const = 0;
//calbacks for the GUI
@ -63,7 +65,7 @@ namespace MWBase
virtual int countSavedGameRecords() const = 0;
virtual void write (ESM::ESMWriter& writer) const = 0;
virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const = 0;
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
};

@ -11,6 +11,11 @@
#include "../mwdialogue/topic.hpp"
#include "../mwdialogue/quest.hpp"
namespace Loading
{
class Listener;
}
namespace ESM
{
class ESMReader;
@ -80,7 +85,7 @@ namespace MWBase
virtual int countSavedGameRecords() const = 0;
virtual void write (ESM::ESMWriter& writer) const = 0;
virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const = 0;
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
};

@ -55,6 +55,8 @@ namespace MWBase
virtual void endGame() = 0;
virtual void deleteGame (const MWState::Character *character, const MWState::Slot *slot) = 0;
virtual void saveGame (const std::string& description, const MWState::Slot *slot = 0) = 0;
///< Write a saved game to \a slot or create a new slot if \a slot == 0.
///

@ -156,8 +156,9 @@ namespace MWBase
virtual void setValue (const std::string& id, int value) = 0;
/// Set time left for the player to start drowning (update the drowning bar)
/// @param time value from [0,20]
virtual void setDrowningTimeLeft (float time) =0;
/// @param time time left to start drowning
/// @param maxTime how long we can be underwater (in total) until drowning starts
virtual void setDrowningTimeLeft (float time, float maxTime) = 0;
virtual void setPlayerClass (const ESM::Class &class_) = 0;
///< set current class of player
@ -302,8 +303,12 @@ namespace MWBase
/// Clear all savegame-specific data
virtual void clear() = 0;
virtual void write (ESM::ESMWriter& writer) = 0;
virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) = 0;
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
virtual int countSavedGameRecords() const = 0;
/// Does the current stack of GUI-windows permit saving?
virtual bool isSavingAllowed() const = 0;
};
}

@ -108,7 +108,7 @@ namespace MWBase
virtual int countSavedGameRecords() const = 0;
virtual void write (ESM::ESMWriter& writer) const = 0;
virtual void write (ESM::ESMWriter& writer, Loading::Listener& listener) const = 0;
virtual void readRecord (ESM::ESMReader& reader, int32_t type,
const std::map<int, int>& contentFileMap) = 0;
@ -407,6 +407,8 @@ namespace MWBase
virtual bool getLOS(const MWWorld::Ptr& npc,const MWWorld::Ptr& targetNpc) = 0;
///< get Line of Sight (morrowind stupid implementation)
virtual float getDistToNearestRayHit(const Ogre::Vector3& from, const Ogre::Vector3& dir, float maxDist) = 0;
virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable) = 0;
virtual int canRest() = 0;

@ -624,6 +624,8 @@ namespace MWClass
if (!attacker.isEmpty() && ptr.getClass().isNpc() && ptr.getClass().getCreatureStats(ptr).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() <= 30)
MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault);
getCreatureStats(ptr).setAttacked(true);
if(!successful)
{
// TODO: Handle HitAttemptOnMe script function
@ -659,7 +661,6 @@ namespace MWClass
{
MWBase::Environment::get().getDialogueManager()->say(ptr, "hit");
}
getCreatureStats(ptr).setAttacked(true);
// Check for knockdown
float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * fKnockDownMult->getFloat();

@ -170,6 +170,14 @@ namespace MWClass
virtual int getBaseGold(const MWWorld::Ptr& ptr) const;
virtual bool isClass(const MWWorld::Ptr& ptr, const std::string &className) const;
virtual bool canSwim (const MWWorld::Ptr &ptr) const {
return true;
}
virtual bool canWalk (const MWWorld::Ptr &ptr) const {
return true;
}
};
}

@ -468,11 +468,6 @@ namespace MWDialogue
mIsInChoice = true;
}
MWWorld::Ptr DialogueManager::getActor() const
{
return mActor;
}
void DialogueManager::goodbye()
{
mIsInChoice = true;
@ -614,7 +609,7 @@ namespace MWDialogue
return 1; // known topics
}
void DialogueManager::write (ESM::ESMWriter& writer) const
void DialogueManager::write (ESM::ESMWriter& writer, Loading::Listener& progress) const
{
ESM::DialogueState state;
@ -626,6 +621,7 @@ namespace MWDialogue
writer.startRecord (ESM::REC_DIAS);
state.save (writer);
writer.endRecord (ESM::REC_DIAS);
progress.increaseProgress();
}
void DialogueManager::readRecord (ESM::ESMReader& reader, int32_t type)

@ -68,9 +68,6 @@ namespace MWDialogue
virtual void goodbye();
virtual MWWorld::Ptr getActor() const;
///< Return the actor the player is currently talking to.
virtual bool checkServiceRefused ();
virtual void say(const MWWorld::Ptr &actor, const std::string &topic) const;
@ -86,7 +83,7 @@ namespace MWDialogue
virtual int countSavedGameRecords() const;
virtual void write (ESM::ESMWriter& writer) const;
virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const;
virtual void readRecord (ESM::ESMReader& reader, int32_t type);
};

@ -111,8 +111,14 @@ bool MWDialogue::Filter::testPlayer (const ESM::DialInfo& info) const
// check cell
if (!info.mCell.empty())
if (!Misc::StringUtils::ciEqual(player.getCell()->getCell()->mName, info.mCell))
{
// supports partial matches, just like getPcCell
const std::string& playerCell = player.getCell()->getCell()->mName;
bool match = playerCell.length()>=info.mCell.length() &&
Misc::StringUtils::ciEqual(playerCell.substr (0, info.mCell.length()), info.mCell);
if (!match)
return false;
}
return true;
}

@ -167,7 +167,7 @@ namespace MWDialogue
return count;
}
void Journal::write (ESM::ESMWriter& writer) const
void Journal::write (ESM::ESMWriter& writer, Loading::Listener& progress) const
{
for (TQuestIter iter (mQuests.begin()); iter!=mQuests.end(); ++iter)
{
@ -178,6 +178,7 @@ namespace MWDialogue
writer.startRecord (ESM::REC_QUES);
state.save (writer);
writer.endRecord (ESM::REC_QUES);
progress.increaseProgress();
for (Topic::TEntryIter iter (quest.begin()); iter!=quest.end(); ++iter)
{
@ -188,6 +189,7 @@ namespace MWDialogue
writer.startRecord (ESM::REC_JOUR);
entry.save (writer);
writer.endRecord (ESM::REC_JOUR);
progress.increaseProgress();
}
}
@ -199,6 +201,7 @@ namespace MWDialogue
writer.startRecord (ESM::REC_JOUR);
entry.save (writer);
writer.endRecord (ESM::REC_JOUR);
progress.increaseProgress();
}
for (TTopicIter iter (mTopics.begin()); iter!=mTopics.end(); ++iter)
@ -214,6 +217,7 @@ namespace MWDialogue
writer.startRecord (ESM::REC_JOUR);
entry.save (writer);
writer.endRecord (ESM::REC_JOUR);
progress.increaseProgress();
}
}
}

@ -64,7 +64,7 @@ namespace MWDialogue
virtual int countSavedGameRecords() const;
virtual void write (ESM::ESMWriter& writer) const;
virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const;
virtual void readRecord (ESM::ESMReader& reader, int32_t type);
};

@ -188,12 +188,13 @@ namespace MWGui
break;
case GM_ClassCreate:
MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog);
mCreateClassDialog = 0;
mCreateClassDialog = new CreateClassDialog();
if (!mCreateClassDialog)
{
mCreateClassDialog = new CreateClassDialog();
mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone);
mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack);
}
mCreateClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen);
mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone);
mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack);
mCreateClassDialog->setVisible(true);
if (mCreationStage < CSE_RaceChosen)
mCreationStage = CSE_RaceChosen;
@ -531,8 +532,8 @@ namespace MWGui
mPlayerClass = klass;
MWBase::Environment::get().getWindowManager()->setPlayerClass(klass);
MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog);
mCreateClassDialog = 0;
// Do not delete dialog, so that choices are rembered in case we want to go back and adjust them later
mCreateClassDialog->setVisible(false);
}
updatePlayerHealth();
@ -554,8 +555,8 @@ namespace MWGui
void CharacterCreation::onCreateClassDialogBack()
{
MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog);
mCreateClassDialog = 0;
// Do not delete dialog, so that choices are rembered in case we want to go back and adjust them later
mCreateClassDialog->setVisible(false);
MWBase::Environment::get().getWindowManager()->popGuiMode();
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class);

@ -10,7 +10,7 @@ namespace MWGui
{
}
void CompanionItemModel::copyItem (const ItemStack& item, size_t count)
void CompanionItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner=false)
{
if (mActor.getClass().isNpc())
{
@ -18,7 +18,7 @@ namespace MWGui
stats.modifyProfit(MWWorld::Class::get(item.mBase).getValue(item.mBase) * count);
}
InventoryItemModel::copyItem(item, count);
InventoryItemModel::copyItem(item, count, setNewOwner);
}
void CompanionItemModel::removeItem (const ItemStack& item, size_t count)

@ -13,7 +13,7 @@ namespace MWGui
public:
CompanionItemModel (const MWWorld::Ptr& actor);
virtual void copyItem (const ItemStack& item, size_t count);
virtual void copyItem (const ItemStack& item, size_t count, bool setNewOwner);
virtual void removeItem (const ItemStack& item, size_t count);
};

@ -215,16 +215,22 @@ namespace MWGui
{
std::vector<std::string> matches;
listNames();
mCommandLine->setCaption(complete( mCommandLine->getOnlyText(), matches ));
#if 0
int i = 0;
for(std::vector<std::string>::iterator it=matches.begin(); it < matches.end(); ++it,++i )
std::string oldCaption = mCommandLine->getCaption();
std::string newCaption = complete( mCommandLine->getOnlyText(), matches );
mCommandLine->setCaption(newCaption);
// List candidates if repeatedly pressing tab
if (oldCaption == newCaption && matches.size())
{
printOK( *it );
if( i == 50 )
break;
int i = 0;
printOK("");
for(std::vector<std::string>::iterator it=matches.begin(); it < matches.end(); ++it,++i )
{
printOK( *it );
if( i == 50 )
break;
}
}
#endif
}
if(mCommandHistory.empty()) return;

@ -13,6 +13,7 @@
#include "../mwworld/containerstore.hpp"
#include "../mwmechanics/pickpocket.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "countdialog.hpp"
#include "tradewindow.hpp"
@ -84,8 +85,7 @@ namespace MWGui
// otherwise, do the transfer
if (targetModel != mSourceModel)
{
targetModel->copyItem(mItem, mDraggedCount);
mSourceModel->removeItem(mItem, mDraggedCount);
mSourceModel->moveItem(mItem, mDraggedCount, targetModel);
}
mSourceModel->update();
@ -292,8 +292,7 @@ namespace MWGui
if (!onTakeItem(item, item.mCount))
break;
playerModel->copyItem(item, item.mCount);
mModel->removeItem(item, item.mCount);
mModel->moveItem(item, item.mCount, playerModel);
}
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container);
@ -341,7 +340,11 @@ namespace MWGui
}
else
{
MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item.mBase, count);
// Looting a dead corpse is considered OK
if (mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead())
return true;
else
MWBase::Environment::get().getMechanicsManager()->itemTaken(player, item.mBase, count);
}
return true;
}

@ -71,7 +71,7 @@ ItemModel::ModelIndex ContainerItemModel::getIndex (ItemStack item)
return -1;
}
void ContainerItemModel::copyItem (const ItemStack& item, size_t count)
void ContainerItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner)
{
const MWWorld::Ptr& source = mItemSources[mItemSources.size()-1];
if (item.mBase.getContainerStore() == &source.getClass().getContainerStore(source))

@ -21,7 +21,7 @@ namespace MWGui
virtual ModelIndex getIndex (ItemStack item);
virtual size_t getItemCount();
virtual void copyItem (const ItemStack& item, size_t count);
virtual void copyItem (const ItemStack& item, size_t count, bool setNewOwner=false);
virtual void removeItem (const ItemStack& item, size_t count);
virtual void update();

@ -196,6 +196,16 @@ namespace MWGui
bitmapFile->read(&textureData[0], width*height*4);
bitmapFile->close();
std::string resourceName;
if (name.size() >= 5 && Misc::StringUtils::ciEqual(name.substr(0, 5), "magic"))
resourceName = "Magic Cards";
else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "century"))
resourceName = "Century Gothic";
else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "daedric"))
resourceName = "Daedric";
else
return; // no point in loading it, since there is no way of using additional fonts
std::string textureName = name;
Ogre::Image image;
image.loadDynamicImage(&textureData[0], width, height, Ogre::PF_BYTE_RGBA);
@ -208,18 +218,11 @@ namespace MWGui
// Register the font with MyGUI
MyGUI::ResourceManualFont* font = static_cast<MyGUI::ResourceManualFont*>(
MyGUI::FactoryManager::getInstance().createObject("Resource", "ResourceManualFont"));
// We need to emulate loading from XML because the data members are private as of mygui 3.2.0
MyGUI::xml::Document xmlDocument;
MyGUI::xml::ElementPtr root = xmlDocument.createRoot("ResourceManualFont");
if (name.size() >= 5 && Misc::StringUtils::ciEqual(name.substr(0, 5), "magic"))
root->addAttribute("name", "Magic Cards");
else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "century"))
root->addAttribute("name", "Century Gothic");
else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "daedric"))
root->addAttribute("name", "Daedric");
else
return; // no point in loading it, since there is no way of using additional fonts
root->addAttribute("name", resourceName);
MyGUI::xml::ElementPtr defaultHeight = root->createChild("Property");
defaultHeight->addAttribute("key", "DefaultHeight");
@ -285,6 +288,7 @@ namespace MWGui
font->deserialization(root, MyGUI::Version(3,2,0));
MyGUI::ResourceManager::getInstance().removeByName(font->getResourceName());
MyGUI::ResourceManager::getInstance().addResource(font);
}

@ -52,7 +52,7 @@ namespace MWGui
, mWeaponVisible(true)
, mSpellVisible(true)
, mWorldMouseOver(false)
, mEnemyHealthTimer(0)
, mEnemyHealthTimer(-1)
, mIsDrowning(false)
, mWeaponSpellTimer(0.f)
, mDrowningFlashTheta(0.f)
@ -203,9 +203,9 @@ namespace MWGui
}
}
void HUD::setDrowningTimeLeft(float time)
void HUD::setDrowningTimeLeft(float time, float maxTime)
{
size_t progress = time/20.0*200.0;
size_t progress = time/maxTime*200.0;
mDrowning->setProgressPosition(progress);
bool isDrowning = (progress == 0);
@ -625,7 +625,7 @@ namespace MWGui
if (mIsDrowning)
{
float intensity = (cos(mDrowningFlashTheta) + 1.0f) / 2.0f;
mDrowningFlash->setColour(MyGUI::Colour(intensity, intensity, intensity));
mDrowningFlash->setColour(MyGUI::Colour(intensity, 0, 0));
}
}
@ -639,4 +639,10 @@ namespace MWGui
updateEnemyHealthBar();
}
void HUD::resetEnemy()
{
mEnemy = MWWorld::Ptr();
mEnemyHealthTimer = -1;
}
}

@ -22,8 +22,9 @@ namespace MWGui
void setBatchCount(unsigned int count);
/// Set time left for the player to start drowning
/// @param time value from [0,20]
void setDrowningTimeLeft(float time);
/// @param time time left to start drowning
/// @param maxTime how long we can be underwater (in total) until drowning starts
void setDrowningTimeLeft(float time, float maxTime);
void setDrowningBarVisible(bool visible);
void setHmsVisible(bool visible);
@ -56,6 +57,7 @@ namespace MWGui
void update();
void setEnemy(const MWWorld::Ptr& enemy);
void resetEnemy();
private:
MyGUI::ProgressBar *mHealth, *mMagicka, *mStamina, *mEnemyHealth, *mDrowning;

@ -4,6 +4,8 @@
#include "../mwworld/class.hpp"
#include "../mwworld/inventorystore.hpp"
#include "../mwmechanics/creaturestats.hpp"
namespace MWGui
{
@ -38,11 +40,11 @@ ItemModel::ModelIndex InventoryItemModel::getIndex (ItemStack item)
return -1;
}
void InventoryItemModel::copyItem (const ItemStack& item, size_t count)
void InventoryItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner)
{
if (item.mBase.getContainerStore() == &mActor.getClass().getContainerStore(mActor))
throw std::runtime_error("Item to copy needs to be from a different container!");
mActor.getClass().getContainerStore(mActor).add(item.mBase, count, mActor);
mActor.getClass().getContainerStore(mActor).add(item.mBase, count, mActor, setNewOwner);
}
@ -57,6 +59,18 @@ void InventoryItemModel::removeItem (const ItemStack& item, size_t count)
throw std::runtime_error("Not enough items in the stack to remove");
}
void InventoryItemModel::moveItem(const ItemStack &item, size_t count, ItemModel *otherModel)
{
bool setNewOwner = false;
// Are you dead? Then you wont need that anymore
if (mActor.getClass().isActor() && mActor.getClass().getCreatureStats(mActor).isDead())
setNewOwner = true;
otherModel->copyItem(item, count, setNewOwner);
removeItem(item, count);
}
void InventoryItemModel::update()
{
MWWorld::ContainerStore& store = MWWorld::Class::get(mActor).getContainerStore(mActor);

@ -15,9 +15,12 @@ namespace MWGui
virtual ModelIndex getIndex (ItemStack item);
virtual size_t getItemCount();
virtual void copyItem (const ItemStack& item, size_t count);
virtual void copyItem (const ItemStack& item, size_t count, bool setNewOwner=false);
virtual void removeItem (const ItemStack& item, size_t count);
/// Move items from this model to \a otherModel.
virtual void moveItem (const ItemStack& item, size_t count, ItemModel* otherModel);
virtual void update();
protected:

@ -35,7 +35,7 @@ namespace MWGui
, mTrading(false)
, mLastXSize(0)
, mLastYSize(0)
, mPreview(MWBase::Environment::get().getWorld ()->getPlayerPtr())
, mPreview(new MWRender::InventoryPreview(MWBase::Environment::get().getWorld ()->getPlayerPtr()))
, mPreviewDirty(true)
, mDragAndDrop(dragAndDrop)
, mSelectedItem(-1)
@ -91,8 +91,8 @@ namespace MWGui
mTradeModel = new TradeItemModel(new InventoryItemModel(mPtr), MWWorld::Ptr());
mSortModel = new SortFilterItemModel(mTradeModel);
mItemView->setModel(mSortModel);
mPreview = MWRender::InventoryPreview(mPtr);
mPreview.setup();
mPreview.reset(new MWRender::InventoryPreview(mPtr));
mPreview->setup();
}
void InventoryWindow::setGuiMode(GuiMode mode)
@ -444,7 +444,7 @@ namespace MWGui
MWWorld::Ptr InventoryWindow::getAvatarSelectedItem(int x, int y)
{
int slot = mPreview.getSlotSelected (x, y);
int slot = mPreview->getSlotSelected (x, y);
if (slot == -1)
return MWWorld::Ptr();
@ -493,7 +493,7 @@ namespace MWGui
mPreviewDirty = false;
MyGUI::IntSize size = mAvatarImage->getSize();
mPreview.update (size.width, size.height);
mPreview->update (size.width, size.height);
mAvatarImage->setImageTexture("CharacterPreview");
mAvatarImage->setImageCoord(MyGUI::IntCoord(0, 0, std::min(512, size.width), std::min(1024, size.height)));

@ -34,7 +34,7 @@ namespace MWGui
MWWorld::Ptr getAvatarSelectedItem(int x, int y);
void rebuildAvatar() {
mPreview.rebuild();
mPreview->rebuild();
}
TradeItemModel* getTradeModel();
@ -81,7 +81,7 @@ namespace MWGui
int mLastXSize;
int mLastYSize;
MWRender::InventoryPreview mPreview;
std::auto_ptr<MWRender::InventoryPreview> mPreview;
bool mTrading;

@ -71,16 +71,22 @@ namespace MWGui
{
}
void ItemModel::moveItem(const ItemStack &item, size_t count, ItemModel *otherModel)
{
otherModel->copyItem(item, count);
removeItem(item, count);
}
ProxyItemModel::~ProxyItemModel()
{
delete mSourceModel;
}
void ProxyItemModel::copyItem (const ItemStack& item, size_t count)
void ProxyItemModel::copyItem (const ItemStack& item, size_t count, bool setNewOwner)
{
// no need to use mapToSource since itemIndex refers to an index in the sourceModel
mSourceModel->copyItem (item, count);
mSourceModel->copyItem (item, count, setNewOwner);
}
void ProxyItemModel::removeItem (const ItemStack& item, size_t count)

@ -55,7 +55,11 @@ namespace MWGui
virtual void update() = 0;
virtual void copyItem (const ItemStack& item, size_t count) = 0;
/// Move items from this model to \a otherModel.
virtual void moveItem (const ItemStack& item, size_t count, ItemModel* otherModel);
/// @param setNewOwner Set the copied item's owner to the actor we are copying to, or keep the original owner?
virtual void copyItem (const ItemStack& item, size_t count, bool setNewOwner=false) = 0;
virtual void removeItem (const ItemStack& item, size_t count) = 0;
private:
@ -69,7 +73,7 @@ namespace MWGui
{
public:
virtual ~ProxyItemModel();
virtual void copyItem (const ItemStack& item, size_t count);
virtual void copyItem (const ItemStack& item, size_t count, bool setNewOwner=false);
virtual void removeItem (const ItemStack& item, size_t count);
virtual ModelIndex getIndex (ItemStack item);

@ -48,7 +48,7 @@ namespace MWGui
void MWList::redraw(bool scrollbarShown)
{
const int _scrollBarWidth = 24; // fetch this from skin?
const int _scrollBarWidth = 20; // fetch this from skin?
const int scrollBarWidth = scrollbarShown ? _scrollBarWidth : 0;
const int spacing = 3;
size_t scrollbarPosition = mScrollView->getScrollPosition();
@ -83,7 +83,7 @@ namespace MWGui
else
{
MyGUI::ImageBox* separator = mScrollView->createWidget<MyGUI::ImageBox>("MW_HLine",
MyGUI::IntCoord(2, mItemHeight, mScrollView->getWidth()-4, 18),
MyGUI::IntCoord(2, mItemHeight, mScrollView->getWidth() - scrollBarWidth - 4, 18),
MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch);
separator->setNeedMouseFocus(false);
@ -91,7 +91,7 @@ namespace MWGui
}
++i;
}
mScrollView->setCanvasSize(mClient->getSize().width + (_scrollBarWidth-scrollBarWidth), std::max(mItemHeight, mClient->getSize().height));
mScrollView->setCanvasSize(mClient->getSize().width, std::max(mItemHeight, mClient->getSize().height));
if (!scrollbarShown && mItemHeight > mClient->getSize().height)
redraw(true);

@ -160,7 +160,6 @@ namespace MWGui
void LoadingScreen::setProgress (size_t value)
{
assert(value < mProgressBar->getScrollRange());
if (value - mProgress < mProgressBar->getScrollRange()/100.f)
return;
mProgress = value;
@ -174,7 +173,6 @@ namespace MWGui
mProgressBar->setScrollPosition(0);
size_t value = mProgress + increase;
mProgress = value;
assert(mProgress < mProgressBar->getScrollRange());
mProgressBar->setTrackSize(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize());
draw();
}

@ -25,7 +25,7 @@ namespace MWGui
virtual void setProgressRange (size_t range);
virtual void setProgress (size_t value);
virtual void increaseProgress (size_t increase);
virtual void increaseProgress (size_t increase=1);
virtual void setVisible(bool visible);

@ -28,7 +28,7 @@ namespace MWGui
{
getWidget(mVersionText, "VersionText");
std::stringstream sstream;
sstream << "OpenMW version: " << OPENMW_VERSION;
sstream << "OpenMW Version: " << OPENMW_VERSION;
// adding info about git hash if available
std::string rev = OPENMW_VERSION_COMMITHASH;
@ -36,7 +36,7 @@ namespace MWGui
if (!rev.empty() && !tag.empty())
{
rev = rev.substr(0,10);
sstream << "\nrevision: " << rev;
sstream << "\nRevision: " << rev;
}
std::string output = sstream.str();
@ -170,7 +170,8 @@ namespace MWGui
buttons.push_back("loadgame");
if (state==MWBase::StateManager::State_Running &&
MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1)
MWBase::Environment::get().getWorld()->getGlobalInt ("chargenstate")==-1 &&
MWBase::Environment::get().getWindowManager()->isSavingAllowed())
buttons.push_back("savegame");
buttons.push_back("options");

@ -14,6 +14,8 @@
#include "../mwrender/globalmap.hpp"
#include "../components/esm/globalmap.hpp"
#include "widgets.hpp"
namespace MWGui
@ -436,7 +438,6 @@ namespace MWGui
worldY * mGlobalMapRender->getHeight()+6,
12, 12);
static int _counter=0;
MyGUI::Button* markerWidget = mGlobalMapOverlay->createWidget<MyGUI::Button>("ButtonImage",
widgetCoord, MyGUI::Align::Default, "Door" + boost::lexical_cast<std::string>(_counter));
@ -452,6 +453,11 @@ namespace MWGui
markerWidget->setUserString("ToolTipType", "Layout");
markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine");
markerWidget->setUserString("Caption_TextOneLine", name);
CellId cell;
cell.first = x;
cell.second = y;
mMarkers.push_back(cell);
}
void MapWindow::cellExplored(int x, int y)
@ -580,6 +586,7 @@ namespace MWGui
void MapWindow::clear()
{
mMarkers.clear();
mGlobalMapRender->clear();
while (mEventBoxGlobal->getChildCount())
@ -588,21 +595,34 @@ namespace MWGui
MyGUI::Gui::getInstance().destroyWidget(mGlobalMapOverlay->getChildAt(0));
}
void MapWindow::write(ESM::ESMWriter &writer)
void MapWindow::write(ESM::ESMWriter &writer, Loading::Listener& progress)
{
mGlobalMapRender->write(writer);
ESM::GlobalMap map;
mGlobalMapRender->write(map);
map.mMarkers = mMarkers;
writer.startRecord(ESM::REC_GMAP);
map.save(writer);
writer.endRecord(ESM::REC_GMAP);
progress.increaseProgress();
}
void MapWindow::readRecord(ESM::ESMReader &reader, int32_t type)
{
std::vector<std::pair<int, int> > exploredCells;
mGlobalMapRender->readRecord(reader, type, exploredCells);
for (std::vector<std::pair<int, int> >::iterator it = exploredCells.begin(); it != exploredCells.end(); ++it)
if (type == ESM::REC_GMAP)
{
const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Cell>().search(it->first, it->second);
if (cell && !cell->mName.empty())
addVisitedLocation(cell->mName, it->first, it->second);
ESM::GlobalMap map;
map.load(reader);
mGlobalMapRender->read(map);
for (std::vector<ESM::GlobalMap::CellId>::iterator it = map.mMarkers.begin(); it != map.mMarkers.end(); ++it)
{
const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Cell>().search(it->first, it->second);
if (cell && !cell->mName.empty())
addVisitedLocation(cell->mName, it->first, it->second);
}
}
}
}

@ -55,6 +55,9 @@ namespace MWGui
bool mChanged;
bool mFogOfWar;
typedef std::pair<int, int> CellId;
std::vector<CellId> mMarkers;
std::vector<MyGUI::ImageBox*> mMapWidgets;
std::vector<MyGUI::ImageBox*> mFogWidgets;
@ -105,7 +108,7 @@ namespace MWGui
/// Clear all savegame-specific data
void clear();
void write (ESM::ESMWriter& writer);
void write (ESM::ESMWriter& writer, Loading::Listener& progress);
void readRecord (ESM::ESMReader& reader, int32_t type);
private:

@ -2,6 +2,8 @@
#include <boost/lexical_cast.hpp>
#include <components/esm/quickkeys.hpp>
#include "../mwworld/inventorystore.hpp"
#include "../mwworld/class.hpp"
@ -55,6 +57,14 @@ namespace MWGui
}
}
void QuickKeysMenu::clear()
{
for (int i=0; i<10; ++i)
{
unassign(mQuickKeyButtons[i], i);
}
}
QuickKeysMenu::~QuickKeysMenu()
{
delete mAssignDialog;
@ -154,8 +164,6 @@ namespace MWGui
frame->setUserString ("ToolTipType", "ItemPtr");
frame->setUserData(item);
frame->eventMouseButtonClick += MyGUI::newDelegate(this, &QuickKeysMenu::onQuickKeyButtonClicked);
MyGUI::ImageBox* image = frame->createWidget<MyGUI::ImageBox>("ImageBox", MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default);
std::string path = std::string("icons\\");
path += MWWorld::Class::get(item).getInventoryIcon(item);
@ -165,7 +173,8 @@ namespace MWGui
image->setImageTexture (path);
image->setNeedMouseFocus (false);
mItemSelectionDialog->setVisible(false);
if (mItemSelectionDialog)
mItemSelectionDialog->setVisible(false);
}
void QuickKeysMenu::onAssignItemCancel()
@ -198,7 +207,8 @@ namespace MWGui
image->setImageTexture (path);
image->setNeedMouseFocus (false);
mMagicSelectionDialog->setVisible(false);
if (mMagicSelectionDialog)
mMagicSelectionDialog->setVisible(false);
}
void QuickKeysMenu::onAssignMagic (const std::string& spellId)
@ -239,7 +249,8 @@ namespace MWGui
image->setImageTexture (path);
image->setNeedMouseFocus (false);
mMagicSelectionDialog->setVisible(false);
if (mMagicSelectionDialog)
mMagicSelectionDialog->setVisible(false);
}
void QuickKeysMenu::onAssignMagicCancel ()
@ -325,7 +336,6 @@ namespace MWGui
}
store.setSelectedEnchantItem(it);
MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item);
}
}
@ -375,6 +385,110 @@ namespace MWGui
center();
}
void QuickKeysMenu::write(ESM::ESMWriter &writer)
{
writer.startRecord(ESM::REC_KEYS);
ESM::QuickKeys keys;
for (int i=0; i<10; ++i)
{
MyGUI::Button* button = mQuickKeyButtons[i];
int type = *button->getUserData<QuickKeyType>();
ESM::QuickKeys::QuickKey key;
key.mType = type;
switch (type)
{
case Type_Unassigned:
break;
case Type_Item:
case Type_MagicItem:
{
MWWorld::Ptr item = *button->getChildAt(0)->getUserData<MWWorld::Ptr>();
key.mId = item.getCellRef().mRefID;
break;
}
case Type_Magic:
std::string spellId = button->getChildAt(0)->getUserString("Spell");
key.mId = spellId;
break;
}
keys.mKeys.push_back(key);
}
keys.save(writer);
writer.endRecord(ESM::REC_KEYS);
}
void QuickKeysMenu::readRecord(ESM::ESMReader &reader, int32_t type)
{
if (type != ESM::REC_KEYS)
return;
ESM::QuickKeys keys;
keys.load(reader);
int i=0;
for (std::vector<ESM::QuickKeys::QuickKey>::const_iterator it = keys.mKeys.begin(); it != keys.mKeys.end(); ++it)
{
if (i >= 10)
return;
mSelectedIndex = i;
int keyType = it->mType;
std::string id = it->mId;
MyGUI::Button* button = mQuickKeyButtons[i];
switch (keyType)
{
case Type_Magic:
onAssignMagic(id);
break;
case Type_Item:
case Type_MagicItem:
{
// Find the item by id
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player);
MWWorld::Ptr item;
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{
if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, id))
{
if (item.isEmpty() ||
// Prefer the stack with the lowest remaining uses
(it->getCellRef().mCharge != -1 && (item.getCellRef().mCharge == -1 || it->getCellRef().mCharge < item.getCellRef().mCharge) ))
{
item = *it;
}
}
}
if (item.isEmpty())
unassign(button, i);
else
{
if (keyType == Type_Item)
onAssignItem(item);
else if (keyType == Type_MagicItem)
onAssignMagicItem(item);
}
break;
}
case Type_Unassigned:
unassign(button, i);
break;
}
++i;
}
}
// ---------------------------------------------------------------------------------------------------------

@ -41,6 +41,11 @@ namespace MWGui
};
void write (ESM::ESMWriter& writer);
void readRecord (ESM::ESMReader& reader, int32_t type);
void clear();
private:
MyGUI::EditBox* mInstructionLabel;
MyGUI::Button* mOkButton;

@ -17,6 +17,8 @@ namespace MWGui
void checkReferenceAvailable(); ///< closes the window, if the MW-reference has become unavailable
void resetReference() { mPtr = MWWorld::Ptr(); mCurrentPlayerCell = NULL; }
protected:
virtual void onReferenceUnavailable() = 0; ///< called when reference has become unavailable

@ -23,6 +23,7 @@ namespace MWGui
: WindowModal("openmw_savegame_dialog.layout")
, mSaving(true)
, mCurrentCharacter(NULL)
, mCurrentSlot(NULL)
{
getWidget(mScreenshot, "Screenshot");
getWidget(mCharacterSelection, "SelectCharacter");
@ -36,6 +37,7 @@ namespace MWGui
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SaveGameDialog::onCancelButtonClicked);
mCharacterSelection->eventComboChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onCharacterSelected);
mSaveList->eventListChangePosition += MyGUI::newDelegate(this, &SaveGameDialog::onSlotSelected);
mSaveList->eventListMouseItemActivate += MyGUI::newDelegate(this, &SaveGameDialog::onSlotMouseClick);
mSaveList->eventListSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onSlotActivated);
mSaveNameEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &SaveGameDialog::onEditSelectAccept);
mSaveNameEdit->eventEditTextChange += MyGUI::newDelegate(this, &SaveGameDialog::onSaveNameChanged);
@ -47,6 +49,37 @@ namespace MWGui
accept();
}
void SaveGameDialog::onSlotMouseClick(MyGUI::ListBox* sender, size_t pos)
{
onSlotSelected(sender, pos);
if (pos != MyGUI::ITEM_NONE && MyGUI::InputManager::getInstance().isShiftPressed())
{
ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog();
dialog->open("#{sMessage3}");
dialog->eventOkClicked.clear();
dialog->eventOkClicked += MyGUI::newDelegate(this, &SaveGameDialog::onDeleteSlotConfirmed);
dialog->eventCancelClicked.clear();
}
}
void SaveGameDialog::onDeleteSlotConfirmed()
{
MWBase::Environment::get().getStateManager()->deleteGame (mCurrentCharacter, mCurrentSlot);
mSaveList->removeItemAt(mSaveList->getIndexSelected());
onSlotSelected(mSaveList, MyGUI::ITEM_NONE);
// The character might be deleted now
size_t previousIndex = mCharacterSelection->getIndexSelected();
open();
if (mCharacterSelection->getItemCount())
{
size_t nextCharacter = std::min(previousIndex, mCharacterSelection->getItemCount()-1);
mCharacterSelection->setIndexSelected(nextCharacter);
onCharacterSelected(mCharacterSelection, nextCharacter);
}
}
void SaveGameDialog::onSaveNameChanged(MyGUI::EditBox *sender)
{
// This might have previously been a save slot from the list. If so, that is no longer the case
@ -69,6 +102,12 @@ namespace MWGui
center();
mCharacterSelection->setCaption("");
mCharacterSelection->removeAllItems();
mCurrentCharacter = NULL;
mCurrentSlot = NULL;
mSaveList->removeAllItems();
MWBase::StateManager* mgr = MWBase::Environment::get().getStateManager();
if (mgr->characterBegin() == mgr->characterEnd())
return;
@ -78,8 +117,6 @@ namespace MWGui
std::string directory =
Misc::StringUtils::lowerCase (Settings::Manager::getString ("character", "Saves"));
mCharacterSelection->removeAllItems();
int selectedIndex = MyGUI::ITEM_NONE;
for (MWBase::StateManager::CharacterIterator it = mgr->characterBegin(); it != mgr->characterEnd(); ++it)
@ -152,23 +189,10 @@ namespace MWGui
{
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(NULL);
// Get the selected slot, if any
unsigned int i=0;
const MWState::Slot* slot = NULL;
if (mCurrentCharacter)
{
for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it,++i)
{
if (i == mSaveList->getIndexSelected())
slot = &*it;
}
}
if (mSaving)
{
// If overwriting an existing slot, ask for confirmation first
if (slot != NULL && !reallySure)
if (mCurrentSlot != NULL && !reallySure)
{
ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog();
dialog->open("#{sMessage4}");
@ -182,19 +206,23 @@ namespace MWGui
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage65}");
return;
}
MWBase::Environment::get().getStateManager()->saveGame (mSaveNameEdit->getCaption(), slot);
}
setVisible(false);
MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_MainMenu);
if (mSaving)
{
MWBase::Environment::get().getStateManager()->saveGame (mSaveNameEdit->getCaption(), mCurrentSlot);
}
else
{
if (mCurrentCharacter && slot)
if (mCurrentCharacter && mCurrentSlot)
{
MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, slot);
MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_MainMenu);
MWBase::Environment::get().getStateManager()->loadGame (mCurrentCharacter, mCurrentSlot);
}
}
setVisible(false);
if (MWBase::Environment::get().getStateManager()->getState()==
MWBase::StateManager::State_NoGame)
{
@ -221,6 +249,7 @@ namespace MWGui
assert(character && "Can't find selected character");
mCurrentCharacter = character;
mCurrentSlot = NULL;
fillSaveList();
}
@ -240,6 +269,7 @@ namespace MWGui
{
if (pos == MyGUI::ITEM_NONE)
{
mCurrentSlot = NULL;
mInfoText->setCaption("");
mScreenshot->setImageTexture("");
return;
@ -248,17 +278,17 @@ namespace MWGui
if (mSaving)
mSaveNameEdit->setCaption(sender->getItemNameAt(pos));
const MWState::Slot* slot = NULL;
mCurrentSlot = NULL;
unsigned int i=0;
for (MWState::Character::SlotIterator it = mCurrentCharacter->begin(); it != mCurrentCharacter->end(); ++it, ++i)
{
if (i == pos)
slot = &*it;
mCurrentSlot = &*it;
}
assert(slot && "Can't find selected slot");
assert(mCurrentSlot && "Can't find selected slot");
std::stringstream text;
time_t time = slot->mTimeStamp;
time_t time = mCurrentSlot->mTimeStamp;
struct tm* timeinfo;
timeinfo = localtime(&time);
@ -269,24 +299,24 @@ namespace MWGui
char buffer[size];
if (std::strftime(buffer, size, "%x %X", timeinfo) > 0)
text << buffer << "\n";
text << "Level " << slot->mProfile.mPlayerLevel << "\n";
text << slot->mProfile.mPlayerCell << "\n";
text << "Level " << mCurrentSlot->mProfile.mPlayerLevel << "\n";
text << mCurrentSlot->mProfile.mPlayerCell << "\n";
// text << "Time played: " << slot->mProfile.mTimePlayed << "\n";
int hour = int(slot->mProfile.mInGameTime.mGameHour);
int hour = int(mCurrentSlot->mProfile.mInGameTime.mGameHour);
bool pm = hour >= 12;
if (hour >= 13) hour -= 12;
if (hour == 0) hour = 12;
text
<< slot->mProfile.mInGameTime.mDay << " "
<< MWBase::Environment::get().getWorld()->getMonthName(slot->mProfile.mInGameTime.mMonth)
<< mCurrentSlot->mProfile.mInGameTime.mDay << " "
<< MWBase::Environment::get().getWorld()->getMonthName(mCurrentSlot->mProfile.mInGameTime.mMonth)
<< " " << hour << " " << (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}");
mInfoText->setCaptionWithReplacing(text.str());
// Decode screenshot
std::vector<char> data = slot->mProfile.mScreenshot; // MemoryDataStream doesn't work with const data :(
std::vector<char> data = mCurrentSlot->mProfile.mScreenshot; // MemoryDataStream doesn't work with const data :(
Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&data[0], data.size()));
Ogre::Image image;
image.load(stream, "jpg");

@ -6,6 +6,7 @@
namespace MWState
{
class Character;
class Slot;
}
namespace MWGui
@ -24,8 +25,15 @@ namespace MWGui
void onCancelButtonClicked (MyGUI::Widget* sender);
void onOkButtonClicked (MyGUI::Widget* sender);
void onCharacterSelected (MyGUI::ComboBox* sender, size_t pos);
// Slot selected (mouse click or arrow keys)
void onSlotSelected (MyGUI::ListBox* sender, size_t pos);
// Slot activated (double click or enter key)
void onSlotActivated (MyGUI::ListBox* sender, size_t pos);
// Slot clicked with mouse
void onSlotMouseClick(MyGUI::ListBox* sender, size_t pos);
void onDeleteSlotConfirmed();
void onEditSelectAccept (MyGUI::EditBox* sender);
void onSaveNameChanged (MyGUI::EditBox* sender);
void onConfirmationGiven();
@ -46,6 +54,7 @@ namespace MWGui
MyGUI::Widget* mSpacer;
const MWState::Character* mCurrentCharacter;
const MWState::Slot* mCurrentSlot;
};

@ -322,7 +322,6 @@ namespace MWGui
}
store.setSelectedEnchantItem(it);
MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item);
updateSpells();
}

@ -475,7 +475,7 @@ namespace MWGui
text += std::string("#DDC79E") + faction->mName;
if (expelled.find(it->first) != expelled.end())
text += "\n#{sExpelled}";
text += "\n#BF9959#{sExpelled}";
else
{
text += std::string("\n#BF9959") + faction->mRanks[it->second];

@ -120,14 +120,11 @@ namespace MWGui
if (i == sourceModel->getItemCount())
throw std::runtime_error("The borrowed item disappeared");
// reset owner before copying
// reset owner while copying, but only for items bought by the player
bool setNewOwner = (mMerchant.isEmpty());
const ItemStack& item = sourceModel->getItem(i);
std::string owner = item.mBase.getCellRef().mOwner;
if (mMerchant.isEmpty()) // only for items bought by player
item.mBase.getCellRef().mOwner = "";
// copy the borrowed items to our model
copyItem(item, it->mCount);
item.mBase.getCellRef().mOwner = owner;
copyItem(item, it->mCount, setNewOwner);
// then remove them from the source model
sourceModel->removeItem(item, it->mCount);
}

@ -78,13 +78,13 @@ namespace MWGui
}
void TradeWindow::startTrade(const MWWorld::Ptr& actor)
{
{
mPtr = actor;
mCurrentBalance = 0;
mCurrentMerchantOffer = 0;
checkTradeTime();
checkTradeTime();
std::vector<MWWorld::Ptr> itemSources;
MWBase::Environment::get().getWorld()->getContainersOwnedBy(actor, itemSources);
@ -245,7 +245,7 @@ namespace MWGui
// were there any items traded at all?
std::vector<ItemStack> playerBought = playerItemModel->getItemsBorrowedToUs();
std::vector<ItemStack> merchantBought = mTradeModel->getItemsBorrowedToUs();
if (!playerBought.size() && !merchantBought.size())
if (playerBought.empty() && merchantBought.empty())
{
// user notification
MWBase::Environment::get().getWindowManager()->
@ -476,7 +476,7 @@ namespace MWGui
}
// Relates to NPC gold reset delay
void TradeWindow::checkTradeTime()
void TradeWindow::checkTradeTime()
{
MWMechanics::CreatureStats &sellerStats = mPtr.getClass().getCreatureStats(mPtr);
double delay = boost::lexical_cast<double>(MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fBarterGoldResetDelay")->getInt());
@ -488,14 +488,14 @@ namespace MWGui
}
}
void TradeWindow::updateTradeTime()
void TradeWindow::updateTradeTime()
{
MWWorld::ContainerStore store = mPtr.getClass().getContainerStore(mPtr);
MWMechanics::CreatureStats &sellerStats = mPtr.getClass().getCreatureStats(mPtr);
double delay = boost::lexical_cast<double>(MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fBarterGoldResetDelay")->getInt());
// If trade timestamp is within reset delay don't set
if ( ! (MWBase::Environment::get().getWorld()->getTimeStamp() >= sellerStats.getTradeTime() &&
if ( ! (MWBase::Environment::get().getWorld()->getTimeStamp() >= sellerStats.getTradeTime() &&
MWBase::Environment::get().getWorld()->getTimeStamp() < sellerStats.getTradeTime() + delay) )
{
sellerStats.setTradeTime(MWBase::Environment::get().getWorld()->getTimeStamp());

@ -187,7 +187,7 @@ namespace MWGui
MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged);
onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer());
SDL_ShowCursor(false);
//SDL_ShowCursor(false);
mCursorManager->setEnabled(true);
@ -289,6 +289,10 @@ namespace MWGui
void WindowManager::setNewGame(bool newgame)
{
// This method will always be called after loading a savegame or starting a new game
// Reset enemy, it could be a dangling pointer from a previous game
mHud->resetEnemy();
if (newgame)
{
disallowAll();
@ -621,9 +625,9 @@ namespace MWGui
mStatsWindow->setValue (id, value);
}
void WindowManager::setDrowningTimeLeft (float time)
void WindowManager::setDrowningTimeLeft (float time, float maxTime)
{
mHud->setDrowningTimeLeft(time);
mHud->setDrowningTimeLeft(time, maxTime);
}
void WindowManager::setPlayerClass (const ESM::Class &class_)
@ -1401,16 +1405,49 @@ namespace MWGui
void WindowManager::clear()
{
mMap->clear();
mQuickKeysMenu->clear();
mTrainingWindow->resetReference();
mDialogueWindow->resetReference();
mTradeWindow->resetReference();
mSpellBuyingWindow->resetReference();
mSpellCreationDialog->resetReference();
mEnchantingDialog->resetReference();
mContainerWindow->resetReference();
mCompanionWindow->resetReference();
mConsole->resetReference();
mGuiModes.clear();
updateVisible();
}
void WindowManager::write(ESM::ESMWriter &writer)
void WindowManager::write(ESM::ESMWriter &writer, Loading::Listener& progress)
{
mMap->write(writer);
mMap->write(writer, progress);
mQuickKeysMenu->write(writer);
progress.increaseProgress();
}
void WindowManager::readRecord(ESM::ESMReader &reader, int32_t type)
{
mMap->readRecord(reader, type);
if (type == ESM::REC_GMAP)
mMap->readRecord(reader, type);
else if (type == ESM::REC_KEYS)
mQuickKeysMenu->readRecord(reader, type);
}
int WindowManager::countSavedGameRecords() const
{
return 1 // Global map
+ 1; // QuickKeysMenu
}
bool WindowManager::isSavingAllowed() const
{
return !MyGUI::InputManager::getInstance().isModalAny()
// TODO: remove this, once we have properly serialized the state of open windows
&& (!isGuiMode() || (mGuiModes.size() == 1 && getMode() == GM_MainMenu));
}
void WindowManager::playVideo(const std::string &name, bool allowSkipping)

@ -166,8 +166,9 @@ namespace MWGui
virtual void setValue (const std::string& id, int value);
/// Set time left for the player to start drowning (update the drowning bar)
/// @param time value from [0,20]
virtual void setDrowningTimeLeft (float time);
/// @param time time left to start drowning
/// @param maxTime how long we can be underwater (in total) until drowning starts
virtual void setDrowningTimeLeft (float time, float maxTime);
virtual void setPlayerClass (const ESM::Class &class_); ///< set current class of player
virtual void configureSkills (const SkillList& major, const SkillList& minor); ///< configure skill groups, each set contains the skill ID for that group.
@ -290,8 +291,12 @@ namespace MWGui
/// Clear all savegame-specific data
virtual void clear();
virtual void write (ESM::ESMWriter& writer);
virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress);
virtual void readRecord (ESM::ESMReader& reader, int32_t type);
virtual int countSavedGameRecords() const;
/// Does the current stack of GUI-windows permit saving?
virtual bool isSavingAllowed() const;
private:
bool mConsoleOnlyScripts;

@ -114,6 +114,7 @@ namespace MWInput
, mTimeIdle(0.f)
, mOverencumberedMessageDelay(0.f)
, mAlwaysRunActive(false)
, mControlsDisabled(false)
{
Ogre::RenderWindow* window = ogre.getWindow ();
@ -265,19 +266,20 @@ namespace MWInput
void InputManager::update(float dt, bool disableControls, bool disableEvents)
{
mControlsDisabled = disableControls;
mInputManager->setMouseVisible(MWBase::Environment::get().getWindowManager()->getCursorVisible());
mInputManager->capture(disableEvents);
// inject some fake mouse movement to force updating MyGUI's widget states
MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel);
// update values of channels (as a result of pressed keys)
if (!disableControls)
mInputBinder->update(dt);
if (disableControls)
if (mControlsDisabled)
return;
// update values of channels (as a result of pressed keys)
mInputBinder->update(dt);
bool grab = !MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu)
&& MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Console;
@ -484,7 +486,7 @@ namespace MWInput
if (text)
{
edit->addText(MyGUI::UString(text));
edit->insertText(MyGUI::UString(text), edit->getTextCursor());
SDL_free(text);
}
}
@ -509,7 +511,8 @@ namespace MWInput
}
}
mInputBinder->keyPressed (arg);
if (!mControlsDisabled)
mInputBinder->keyPressed (arg);
OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym);

@ -68,7 +68,7 @@ namespace MWInput
/// Clear all savegame-specific data
virtual void clear();
virtual void update(float dt, bool disableControls, bool disableEvents=false);
virtual void update(float dt, bool disableControls=false, bool disableEvents=false);
void setPlayer (MWWorld::Player* player) { mPlayer = player; }
@ -145,6 +145,8 @@ namespace MWInput
bool mInvertY;
bool mControlsDisabled;
float mCameraSensitivity;
float mUISensitivity;
float mCameraYMultiplier;

@ -206,7 +206,7 @@ namespace MWMechanics
if (effectIt->mKey.mId == effectId)
effectIt = it->second.mEffects.erase(effectIt);
else
effectIt++;
++effectIt;
}
}
mSpellsChanged = true;
@ -224,7 +224,7 @@ namespace MWMechanics
&& it->second.mCasterHandle == actorHandle)
effectIt = it->second.mEffects.erase(effectIt);
else
effectIt++;
++effectIt;
}
}
mSpellsChanged = true;

@ -29,7 +29,7 @@
#include "aicombat.hpp"
#include "aifollow.hpp"
#include "aipersue.hpp"
#include "aipursue.hpp"
namespace
{
@ -194,21 +194,11 @@ namespace MWMechanics
+(actorpos.pos[1] - playerpos.pos[1])*(actorpos.pos[1] - playerpos.pos[1])
+(actorpos.pos[2] - playerpos.pos[2])*(actorpos.pos[2] - playerpos.pos[2]));
float fight = ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified();
float disp = 100; //creatures don't have disposition, so set it to 100 by default
if(ptr.getTypeName() == typeid(ESM::NPC).name())
{
disp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(ptr);
}
if( (fight == 100 )
|| (fight >= 95 && d <= 3000)
|| (fight >= 90 && d <= 2000)
|| (fight >= 80 && d <= 1000)
|| (fight >= 80 && disp <= 40)
|| (fight >= 70 && disp <= 35 && d <= 1000)
|| (fight >= 60 && disp <= 30 && d <= 1000)
|| (fight >= 50 && disp == 0)
|| (fight >= 40 && disp <= 10 && d <= 500)
)
{
bool LOS = MWBase::Environment::get().getWorld()->getLOS(ptr,player)
@ -216,7 +206,7 @@ namespace MWMechanics
if (LOS)
{
creatureStats.getAiSequence().stack(AiCombat(MWBase::Environment::get().getWorld()->getPlayerPtr()));
creatureStats.getAiSequence().stack(AiCombat(MWBase::Environment::get().getWorld()->getPlayerPtr()), ptr);
creatureStats.setHostile(true);
}
}
@ -548,7 +538,7 @@ namespace MWMechanics
// TODO: Add AI to follow player and fight for him
AiFollow package(ptr.getRefData().getHandle());
MWWorld::Class::get (ref.getPtr()).getCreatureStats (ref.getPtr()).getAiSequence().stack(package);
MWWorld::Class::get (ref.getPtr()).getCreatureStats (ref.getPtr()).getAiSequence().stack(package, ptr);
// TODO: VFX_SummonStart, VFX_SummonEnd
creatureStats.mSummonedCreatures.insert(std::make_pair(it->first,
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos).getRefData().getHandle()));
@ -751,34 +741,33 @@ namespace MWMechanics
CreatureStats& creatureStats = MWWorld::Class::get(ptr).getCreatureStats(ptr);
NpcStats& npcStats = MWWorld::Class::get(ptr).getNpcStats(ptr);
// If I'm a guard and I'm not hostile
if (ptr.getClass().isClass(ptr, "Guard") && !creatureStats.isHostile())
if (ptr.getClass().isClass(ptr, "Guard") && creatureStats.getAiSequence().getTypeId() != AiPackage::TypeIdPursue && !creatureStats.isHostile())
{
/// \todo Move me! I shouldn't be here...
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
float cutoff = float(esmStore.get<ESM::GameSetting>().find("iCrimeThreshold")->getInt()) *
float(esmStore.get<ESM::GameSetting>().find("iCrimeThresholdMultiplier")->getInt()) *
esmStore.get<ESM::GameSetting>().find("fCrimeGoldDiscountMult")->getFloat();
// Attack on sight if bounty is greater than the cutoff
float cutoff = float(esmStore.get<ESM::GameSetting>().find("iCrimeThreshold")->getInt());
// Force dialogue on sight if bounty is greater than the cutoff
// In vanilla morrowind, the greeting dialogue is scripted to either arrest the player (< 5000 bounty) or attack (>= 5000 bounty)
if ( player.getClass().getNpcStats(player).getBounty() >= cutoff
// TODO: do not run these two every frame. keep an Aware state for each actor and update it every 0.2 s or so?
&& MWBase::Environment::get().getWorld()->getLOS(ptr, player)
&& MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, ptr))
{
creatureStats.getAiSequence().stack(AiCombat(player));
creatureStats.setHostile(true);
npcStats.setCrimeId( MWBase::Environment::get().getWorld()->getPlayer().getCrimeId() );
creatureStats.getAiSequence().stack(AiPursue(player.getClass().getId(player)), ptr);
creatureStats.setAlarmed(true);
npcStats.setCrimeId(MWBase::Environment::get().getWorld()->getPlayer().getNewCrimeId());
}
}
// if I was a witness to a crime
if (npcStats.getCrimeId() != -1)
{
// if you've payed for your crimes and I havent noticed
// if you've paid for your crimes and I havent noticed
if( npcStats.getCrimeId() <= MWBase::Environment::get().getWorld()->getPlayer().getCrimeId() )
{
// Calm witness down
if (ptr.getClass().isClass(ptr, "Guard"))
creatureStats.getAiSequence().stopPersue();
creatureStats.getAiSequence().stopPursuit();
creatureStats.getAiSequence().stopCombat();
// Reset factors to attack
@ -793,17 +782,16 @@ namespace MWMechanics
else if (!creatureStats.isHostile())
{
if (ptr.getClass().isClass(ptr, "Guard"))
creatureStats.getAiSequence().stack(AiPersue(player.getClass().getId(player)));
creatureStats.getAiSequence().stack(AiPursue(player.getClass().getId(player)), ptr);
else
creatureStats.getAiSequence().stack(AiCombat(player));
creatureStats.getAiSequence().stack(AiCombat(player), ptr);
creatureStats.setHostile(true);
}
}
// if I didn't report a crime was I attacked?
else if (creatureStats.getAttacked() && !creatureStats.isHostile())
{
creatureStats.getAiSequence().stack(AiCombat(player));
creatureStats.getAiSequence().stack(AiCombat(player), ptr);
creatureStats.setHostile(true);
}
}
@ -911,12 +899,23 @@ namespace MWMechanics
iter->second->update(duration);
}
// Kill dead actors
// Kill dead actors, update some variables
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();iter++)
{
const MWWorld::Class &cls = MWWorld::Class::get(iter->first);
CreatureStats &stats = cls.getCreatureStats(iter->first);
//KnockedOutOneFrameLogic
//Used for "OnKnockedOut" command
//Put here to ensure that it's run for PRECISELY one frame.
if(stats.getKnockedDown() && !stats.getKnockedDownOneFrame() && !stats.getKnockedDownOverOneFrame()) { //Start it for one frame if nessesary
stats.setKnockedDownOneFrame(true);
}
else if (stats.getKnockedDownOneFrame() && !stats.getKnockedDownOverOneFrame()) { //Turn off KnockedOutOneframe
stats.setKnockedDownOneFrame(false);
stats.setKnockedDownOverOneFrame(true);
}
if(!stats.isDead())
{
if(iter->second->isDead())
@ -1050,8 +1049,7 @@ namespace MWMechanics
{
const MWWorld::Class &cls = MWWorld::Class::get(iter->first);
CreatureStats &stats = cls.getCreatureStats(iter->first);
if(stats.getAiSequence().getTypeId() == AiPackage::TypeIdFollow)
if(!stats.isDead() && stats.getAiSequence().getTypeId() == AiPackage::TypeIdFollow)
{
MWMechanics::AiFollow* package = static_cast<MWMechanics::AiFollow*>(stats.getAiSequence().getActivePackage());
if(package->getFollowedActor() == actor.getCellRef().mRefID)
@ -1072,8 +1070,7 @@ namespace MWMechanics
{
const MWWorld::Class &cls = MWWorld::Class::get(*iter);
CreatureStats &stats = cls.getCreatureStats(*iter);
if(stats.getAiSequence().getTypeId() == AiPackage::TypeIdCombat)
if(!stats.isDead() && stats.getAiSequence().getTypeId() == AiPackage::TypeIdCombat)
{
MWMechanics::AiCombat* package = static_cast<MWMechanics::AiCombat*>(stats.getAiSequence().getActivePackage());
if(package->getTargetId() == actor.getCellRef().mRefID)

@ -31,10 +31,52 @@ namespace
//chooses an attack depending on probability to avoid uniformity
void chooseBestAttack(const ESM::Weapon* weapon, MWMechanics::Movement &movement);
float getZAngleToDir(const Ogre::Vector3& dir, float dirLen = 0.0f)
{
float len = (dirLen > 0.0f)? dirLen : dir.length();
return Ogre::Radian( Ogre::Math::ACos(dir.y / len) * sgn(Ogre::Math::ASin(dir.x / len)) ).valueDegrees();
}
float getXAngleToDir(const Ogre::Vector3& dir, float dirLen = 0.0f)
{
float len = (dirLen > 0.0f)? dirLen : dir.length();
return Ogre::Radian(-Ogre::Math::ASin(dir.z / len)).valueDegrees();
}
const float PATHFIND_Z_REACH = 50.0f;
// distance at which actor pays more attention to decide whether to shortcut or stick to pathgrid
const float PATHFIND_CAUTION_DIST = 500.0f;
// distance after which actor (failed previously to shortcut) will try again
const float PATHFIND_SHORTCUT_RETRY_DIST = 300.0f;
// cast up-down ray with some offset from actor position to check for pits/obstacles on the way to target;
// magnitude of pits/obstacles is defined by PATHFIND_Z_REACH
bool checkWayIsClear(const Ogre::Vector3& from, const Ogre::Vector3& to, float offset)
{
if((to - from).length() >= PATHFIND_CAUTION_DIST || abs(from.z - to.z) <= PATHFIND_Z_REACH)
{
Ogre::Vector3 dir = to - from;
dir.z = 0;
dir.normalise();
float verticalOffset = 200; // instead of '200' here we want the height of the actor
Ogre::Vector3 _from = from + dir*offset + Ogre::Vector3::UNIT_Z * verticalOffset;
// cast up-down ray and find height in world space of hit
float h = _from.z - MWBase::Environment::get().getWorld()->getDistToNearestRayHit(_from, -Ogre::Vector3::UNIT_Z, verticalOffset + PATHFIND_Z_REACH + 1);
if(abs(from.z - h) <= PATHFIND_Z_REACH)
return true;
}
return false;
}
}
namespace MWMechanics
{
static const float MAX_ATTACK_DURATION = 0.35f;
static const float DOOR_CHECK_INTERVAL = 1.5f; // same as AiWander
// NOTE: MIN_DIST_TO_DOOR_SQUARED is defined in obstacle.hpp
@ -45,16 +87,16 @@ namespace MWMechanics
mTimerCombatMove(0),
mFollowTarget(false),
mReadyToAttack(false),
mStrike(false),
mAttack(false),
mCombatMove(false),
mBackOffDoor(false),
mRotate(false),
mMovement(),
mForceNoShortcut(false),
mShortcutFailPos(),
mBackOffDoor(false),
mCell(NULL),
mDoorIter(actor.getCell()->get<ESM::Door>().mList.end()),
mDoors(actor.getCell()->get<ESM::Door>()),
mDoorCheckDuration(0),
mTargetAngle(0)
mDoorCheckDuration(0)
{
}
@ -125,17 +167,23 @@ namespace MWMechanics
mCombatMove = false;
}
}
actor.getClass().getMovementSettings(actor) = mMovement;
actor.getClass().getMovementSettings(actor).mRotation[0] = 0;
actor.getClass().getMovementSettings(actor).mRotation[2] = 0;
if (mRotate)
if(mMovement.mRotation[2] != 0)
{
if(zTurn(actor, Ogre::Degree(mMovement.mRotation[2]))) mMovement.mRotation[2] = 0;
}
if(mMovement.mRotation[0] != 0)
{
if (zTurn(actor, Ogre::Degree(mTargetAngle)))
mRotate = false;
if(smoothTurn(actor, Ogre::Degree(mMovement.mRotation[0]), 0)) mMovement.mRotation[0] = 0;
}
mTimerAttack -= duration;
actor.getClass().getCreatureStats(actor).setAttackingOrSpell(mStrike);
actor.getClass().getCreatureStats(actor).setAttackingOrSpell(mAttack);
float tReaction = 0.25f;
if(mTimerReact < tReaction)
@ -145,7 +193,7 @@ namespace MWMechanics
}
//Update with period = tReaction
mTimerReact = 0;
bool cellChange = mCell && (actor.getCell() != mCell);
@ -156,16 +204,16 @@ namespace MWMechanics
//actual attacking logic
//TODO: Some skills affect period of strikes.For berserk-like style period ~ 0.25f
float attackPeriod = 1.0f;
float attacksPeriod = 1.0f;
if(mReadyToAttack)
{
if(mTimerAttack <= -attackPeriod)
if(mTimerAttack <= -attacksPeriod)
{
//TODO: should depend on time between 'start' to 'min attack'
//for better controlling of NPCs' attack strength.
//Also it seems that this time is different for slash/thrust/chop
mTimerAttack = 0.35f * static_cast<float>(rand())/RAND_MAX;
mStrike = true;
mTimerAttack = MAX_ATTACK_DURATION * static_cast<float>(rand())/RAND_MAX;
mAttack = true;
//say a provoking combat phrase
if (actor.getClass().isNpc())
@ -180,30 +228,31 @@ namespace MWMechanics
}
}
else if (mTimerAttack <= 0)
mStrike = false;
mAttack = false;
}
else
{
mTimerAttack = -attackPeriod;
mStrike = false;
mTimerAttack = -attacksPeriod;
mAttack = false;
}
const MWWorld::Class &cls = actor.getClass();
const MWWorld::Class &actorCls = actor.getClass();
const ESM::Weapon *weapon = NULL;
MWMechanics::WeaponType weaptype;
float weapRange, weapSpeed = 1.0f;
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
actorCls.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
if (actor.getClass().hasInventoryStore(actor))
// Get weapon characteristics
if (actorCls.hasInventoryStore(actor))
{
MWMechanics::DrawState_ state = actor.getClass().getCreatureStats(actor).getDrawState();
MWMechanics::DrawState_ state = actorCls.getCreatureStats(actor).getDrawState();
if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing)
actor.getClass().getCreatureStats(actor).setDrawState(MWMechanics::DrawState_Weapon);
actorCls.getCreatureStats(actor).setDrawState(MWMechanics::DrawState_Weapon);
//Get weapon speed and range
MWWorld::ContainerStoreIterator weaponSlot =
MWMechanics::getActiveWeapon(cls.getCreatureStats(actor), cls.getInventoryStore(actor), &weaptype);
MWMechanics::getActiveWeapon(actorCls.getCreatureStats(actor), actorCls.getInventoryStore(actor), &weaptype);
if (weaptype == WeapType_HandToHand)
{
@ -225,36 +274,27 @@ namespace MWMechanics
weapRange = 150; //TODO: use true attack range (the same problem in Creature::hit)
}
ESM::Position pos = actor.getRefData().getPosition();
/*
* Some notes on meanings of variables:
*
* rangeMelee:
* rangeAttack:
*
* - Distance where attack using the actor's weapon is possible
* - longer for ranged weapons (obviously?) vs. melee weapons
* - Distance where attack using the actor's weapon is possible:
* longer for ranged weapons (obviously?) vs. melee weapons
* - Determined by weapon's reach parameter; hardcoded value
* for ranged weapon and for creatures
* - Once within this distance mFollowTarget is triggered
* (TODO: check whether the follow logic still works for ranged
* weapons, since rangeCloseup is set to zero)
* - TODO: The variable name is confusing. It was ok when AiCombat only
* had melee weapons but now that ranged weapons are supported that is
* no longer the case. It should really be renamed to something
* like rangeStrike - alternatively, keep this name for melee
* weapons and use a different variable for tracking ranged weapon
* distance (rangeRanged maybe?)
*
* rangeCloseup:
* rangeFollow:
*
* - Applies to melee weapons or hand to hand only (or creatures without
* weapons)
* - Distance a little further away from the actor's weapon strike
* i.e. rangeCloseup > rangeMelee for melee weapons
* (the variable names make this simple concept counter-intuitive,
* something like rangeMelee > rangeStrike may be better)
* - Distance a little further away than the actor's weapon reach
* i.e. rangeFollow > rangeAttack for melee weapons
* - Hardcoded value (0 for ranged weapons)
* - Once the target gets beyond this distance mFollowTarget is cleared
* and a path to the target needs to be found
* - TODO: Possibly rename this variable to rangeMelee or even rangeFollow
*
* mFollowTarget:
*
@ -263,58 +303,72 @@ namespace MWMechanics
* available, since the default path without pathgrids is direct to
* target even if LOS is not achieved)
*/
float rangeMelee;
float rangeCloseUp;
float rangeAttack;
float rangeFollow;
bool distantCombat = false;
if (weaptype==WeapType_BowAndArrow || weaptype==WeapType_Crossbow || weaptype==WeapType_Thrown)
if (weaptype == WeapType_BowAndArrow || weaptype == WeapType_Crossbow || weaptype == WeapType_Thrown)
{
rangeMelee = 1000; // TODO: should depend on archer skill
rangeCloseUp = 0; //doesn't needed when attacking from distance
rangeAttack = 1000; // TODO: should depend on archer skill
rangeFollow = 0; // not needed in ranged combat
distantCombat = true;
}
else
{
rangeMelee = weapRange;
rangeCloseUp = 300;
rangeAttack = weapRange;
rangeFollow = 300;
}
ESM::Position pos = actor.getRefData().getPosition();
Ogre::Vector3 vActorPos(pos.pos);
Ogre::Vector3 vTargetPos(mTarget.getRefData().getPosition().pos);
Ogre::Vector3 vDirToTarget = vTargetPos - vActorPos;
bool isStuck = false;
float speed = 0.0f;
if(mMovement.mPosition[1] && (Ogre::Vector3(mLastPos.pos) - vActorPos).length() < (speed = actorCls.getSpeed(actor)) / 10.0f)
isStuck = true;
mLastPos = pos;
// check if actor can move along z-axis
bool canMoveByZ = (actorCls.canSwim(actor) && MWBase::Environment::get().getWorld()->isSwimming(actor))
|| MWBase::Environment::get().getWorld()->isFlying(actor);
Ogre::Vector3 vStart(pos.pos[0], pos.pos[1], pos.pos[2]);
ESM::Position targetPos = mTarget.getRefData().getPosition();
Ogre::Vector3 vDest(targetPos.pos[0], targetPos.pos[1], targetPos.pos[2]);
Ogre::Vector3 vDir = vDest - vStart;
float distBetween = vDir.length();
// determine vertical angle to target
// if actor can move along z-axis it will control movement dir
// if can't - it will control correct aiming
mMovement.mRotation[0] = getXAngleToDir(vDirToTarget);
vDirToTarget.z = 0;
float distToTarget = vDirToTarget.length();
// (within strike dist) || (not quite strike dist while following)
if(distBetween < rangeMelee || (distBetween <= rangeCloseUp && mFollowTarget) )
if(distToTarget < rangeAttack || (distToTarget <= rangeFollow && mFollowTarget && !isStuck) )
{
//Melee and Close-up combat
vDir.z = 0;
float dirLen = vDir.length();
mTargetAngle = Ogre::Radian( Ogre::Math::ACos(vDir.y / dirLen) * sgn(Ogre::Math::ASin(vDir.x / dirLen)) ).valueDegrees();
mRotate = true;
mMovement.mRotation[2] = getZAngleToDir(vDirToTarget, distToTarget);
//bool LOS = MWBase::Environment::get().getWorld()->getLOS(actor, mTarget);
// (not quite strike dist while following)
if (mFollowTarget && distBetween > rangeMelee)
if (mFollowTarget && distToTarget > rangeAttack)
{
//Close-up combat: just run up on target
mMovement.mPosition[1] = 1;
}
else // (within strike dist)
{
//Melee: stop running and attack
mMovement.mPosition[1] = 0;
// When attacking with a weapon, choose between slash, thrust or chop
if (actor.getClass().hasInventoryStore(actor))
chooseBestAttack(weapon, mMovement);
// set slash/thrust/chop attack
if (mAttack && !distantCombat) chooseBestAttack(weapon, mMovement);
if(mMovement.mPosition[0] || mMovement.mPosition[1])
{
mTimerCombatMove = 0.1f + 0.1f * static_cast<float>(rand())/RAND_MAX;
mCombatMove = true;
}
else if(actor.getClass().isNpc() && (!distantCombat || (distantCombat && rangeMelee/5)))
// only NPCs are smart enough to use dodge movements
else if(actorCls.isNpc() && (!distantCombat || (distantCombat && distToTarget < rangeAttack/2)))
{
//apply sideway movement (kind of dodging) with some probability
if(static_cast<float>(rand())/RAND_MAX < 0.25)
@ -325,7 +379,7 @@ namespace MWMechanics
}
}
if(distantCombat && distBetween < rangeMelee/4)
if(distantCombat && distToTarget < rangeAttack/4)
{
mMovement.mPosition[1] = -1;
}
@ -335,56 +389,105 @@ namespace MWMechanics
mFollowTarget = true;
}
}
else
else // remote pathfinding
{
//target is at far distance: build path to target
mFollowTarget = false;
buildNewPath(actor); //may fail to build a path, check before use
bool preferShortcut = false;
bool inLOS = MWBase::Environment::get().getWorld()->getLOS(actor, mTarget);
if(mReadyToAttack) isStuck = false;
// check if shortcut is available
if(!isStuck
&& (!mForceNoShortcut
|| (Ogre::Vector3(mShortcutFailPos.pos) - vActorPos).length() >= PATHFIND_SHORTCUT_RETRY_DIST)
&& inLOS)
{
if(speed == 0.0f) speed = actorCls.getSpeed(actor);
// maximum dist before pit/obstacle for actor to avoid them depending on his speed
float maxAvoidDist = tReaction * speed + speed / MAX_VEL_ANGULAR.valueRadians() * 2; // *2 - for reliability
preferShortcut = checkWayIsClear(vActorPos, vTargetPos, distToTarget > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2);
}
//delete visited path node
mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]);
// don't use pathgrid when actor can move in 3 dimensions
if(canMoveByZ) preferShortcut = true;
//if no new path leave mTargetAngle unchanged
if(!mPathFinder.getPath().empty())
if(preferShortcut)
{
//try shortcut
if(vDir.length() < mPathFinder.getDistToNext(pos.pos[0],pos.pos[1],pos.pos[2]) && MWBase::Environment::get().getWorld()->getLOS(actor, mTarget))
mTargetAngle = Ogre::Radian( Ogre::Math::ACos(vDir.y / vDir.length()) * sgn(Ogre::Math::ASin(vDir.x / vDir.length())) ).valueDegrees();
else
mTargetAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
mRotate = true;
mMovement.mRotation[2] = getZAngleToDir(vDirToTarget, distToTarget);
mForceNoShortcut = false;
mShortcutFailPos.pos[0] = mShortcutFailPos.pos[1] = mShortcutFailPos.pos[2] = 0;
mPathFinder.clearPath();
}
else // if shortcut failed stick to path grid
{
if(!isStuck && mShortcutFailPos.pos[0] == 0.0f && mShortcutFailPos.pos[1] == 0.0f && mShortcutFailPos.pos[2] == 0.0f)
{
mForceNoShortcut = true;
mShortcutFailPos = pos;
}
mFollowTarget = false;
buildNewPath(actor); //may fail to build a path, check before use
//delete visited path node
mPathFinder.checkWaypoint(pos.pos[0],pos.pos[1],pos.pos[2]);
// This works on the borders between the path grid and areas with no waypoints.
if(inLOS && mPathFinder.getPath().size() > 1)
{
// get point just before target
std::list<ESM::Pathgrid::Point>::const_iterator pntIter = --mPathFinder.getPath().end();
--pntIter;
Ogre::Vector3 vBeforeTarget = Ogre::Vector3(pntIter->mX, pntIter->mY, pntIter->mZ);
// if current actor pos is closer to target then last point of path (excluding target itself) then go straight on target
if(distToTarget <= (vTargetPos - vBeforeTarget).length())
{
mMovement.mRotation[2] = getZAngleToDir(vDirToTarget, distToTarget);
preferShortcut = true;
}
}
// if there is no new path, then go straight on target
if(!preferShortcut)
{
if(!mPathFinder.getPath().empty())
mMovement.mRotation[2] = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
else
mMovement.mRotation[2] = getZAngleToDir(vDirToTarget, distToTarget);
}
}
mMovement.mPosition[1] = 1;
mReadyToAttack = false;
}
if(distBetween > rangeMelee)
if(distToTarget > rangeAttack && !distantCombat)
{
//special run attack; it shouldn't affect melee combat tactics
if(actor.getClass().getMovementSettings(actor).mPosition[1] == 1)
if(actorCls.getMovementSettings(actor).mPosition[1] == 1)
{
//check if actor can overcome the distance = distToTarget - attackerWeapRange
//less than in time of playing weapon anim from 'start' to 'hit' tags (t_swing)
//then start attacking
float speed1 = cls.getSpeed(actor);
float speed1 = actorCls.getSpeed(actor);
float speed2 = mTarget.getClass().getSpeed(mTarget);
if(mTarget.getClass().getMovementSettings(mTarget).mPosition[0] == 0
&& mTarget.getClass().getMovementSettings(mTarget).mPosition[1] == 0)
speed2 = 0;
float s1 = distBetween - weapRange;
float s1 = distToTarget - weapRange;
float t = s1/speed1;
float s2 = speed2 * t;
float t_swing = 0.17f/weapSpeed;//instead of 0.17 should be the time of playing weapon anim from 'start' to 'hit' tags
float t_swing = (MAX_ATTACK_DURATION/2) / weapSpeed;//instead of 0.17 should be the time of playing weapon anim from 'start' to 'hit' tags
if (t + s2/speed1 <= t_swing)
{
mReadyToAttack = true;
if(mTimerAttack <= -attackPeriod)
if(mTimerAttack <= -attacksPeriod)
{
mTimerAttack = 0.3f*static_cast<float>(rand())/RAND_MAX;
mStrike = true;
mTimerAttack = MAX_ATTACK_DURATION * static_cast<float>(rand())/RAND_MAX;
mAttack = true;
}
}
}
@ -394,7 +497,7 @@ namespace MWMechanics
// coded at 250ms or 1/4 second
//
// TODO: Add a parameter to vary DURATION_SAME_SPOT?
if((distBetween > rangeMelee || mFollowTarget) &&
if((distToTarget > rangeAttack || mFollowTarget) &&
mObstacleCheck.check(actor, tReaction)) // check if evasive action needed
{
// first check if we're walking into a door
@ -406,12 +509,11 @@ namespace MWMechanics
// Check all the doors in this cell
mDoors = cell->get<ESM::Door>(); // update
mDoorIter = mDoors.mList.begin();
Ogre::Vector3 actorPos(actor.getRefData().getPosition().pos);
for (; mDoorIter != mDoors.mList.end(); ++mDoorIter)
{
MWWorld::LiveCellRef<ESM::Door>& ref = *mDoorIter;
float minSqr = 1.3*1.3*MIN_DIST_TO_DOOR_SQUARED; // for legibility
if(actorPos.squaredDistance(Ogre::Vector3(ref.mRef.mPos.pos)) < minSqr &&
if(vActorPos.squaredDistance(Ogre::Vector3(ref.mRef.mPos.pos)) < minSqr &&
ref.mData.getLocalRotation().rot[2] < 0.4f) // even small opening
{
//std::cout<<"closed door id \""<<ref.mRef.mRefID<<"\""<<std::endl;
@ -441,11 +543,10 @@ namespace MWMechanics
}
MWWorld::LiveCellRef<ESM::Door>& ref = *mDoorIter;
Ogre::Vector3 actorPos(actor.getRefData().getPosition().pos);
float minSqr = 1.6 * 1.6 * MIN_DIST_TO_DOOR_SQUARED; // for legibility
// TODO: add reaction to checking open doors
if(mBackOffDoor &&
actorPos.squaredDistance(Ogre::Vector3(ref.mRef.mPos.pos)) < minSqr)
vActorPos.squaredDistance(Ogre::Vector3(ref.mRef.mPos.pos)) < minSqr)
{
mMovement.mPosition[1] = -0.2; // back off, but slowly
}
@ -454,47 +555,38 @@ namespace MWMechanics
ref.mData.getLocalRotation().rot[2] >= 1)
{
mDoorIter = mDoors.mList.end();
mBackOffDoor = false;
mBackOffDoor = false;
//std::cout<<"open door id \""<<ref.mRef.mRefID<<"\""<<std::endl;
mMovement.mPosition[1] = 1;
}
else
{
mMovement.mPosition[1] = 1; // FIXME: oscillation?
}
actor.getClass().getMovementSettings(actor) = mMovement;
// these lines break ranged combat distance keeping
//else
//{
// mMovement.mPosition[1] = 1; // FIXME: oscillation?
//}
return false;
}
void AiCombat::buildNewPath(const MWWorld::Ptr& actor)
{
//Construct path to target
ESM::Pathgrid::Point dest;
dest.mX = mTarget.getRefData().getPosition().pos[0];
dest.mY = mTarget.getRefData().getPosition().pos[1];
dest.mZ = mTarget.getRefData().getPosition().pos[2];
Ogre::Vector3 newPathTarget = Ogre::Vector3(dest.mX, dest.mY, dest.mZ);
float dist = -1; //hack to indicate first time, to construct a new path
Ogre::Vector3 newPathTarget = Ogre::Vector3(mTarget.getRefData().getPosition().pos);
float dist;
if(!mPathFinder.getPath().empty())
{
ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back();
Ogre::Vector3 currPathTarget(lastPt.mX, lastPt.mY, lastPt.mZ);
dist = Ogre::Math::Abs((newPathTarget - currPathTarget).length());
dist = (newPathTarget - currPathTarget).length();
}
else dist = 1e+38F; // necessarily construct a new path
float targetPosThreshold;
bool isOutside = actor.getCell()->getCell()->isExterior();
if (isOutside)
targetPosThreshold = 300;
else
targetPosThreshold = 100;
float targetPosThreshold = (actor.getCell()->getCell()->isExterior())? 300 : 100;
if((dist < 0) || (dist > targetPosThreshold))
//construct new path only if target has moved away more than on [targetPosThreshold]
if(dist > targetPosThreshold)
{
//construct new path only if target has moved away more than on <targetPosThreshold>
ESM::Position pos = actor.getRefData().getPosition();
ESM::Pathgrid::Point start;
@ -502,17 +594,18 @@ namespace MWMechanics
start.mY = pos.pos[1];
start.mZ = pos.pos[2];
ESM::Pathgrid::Point dest;
dest.mX = newPathTarget.x;
dest.mY = newPathTarget.y;
dest.mZ = newPathTarget.z;
if(!mPathFinder.isPathConstructed())
mPathFinder.buildPath(start, dest, actor.getCell(), isOutside);
mPathFinder.buildPath(start, dest, actor.getCell(), false);
else
{
PathFinder newPathFinder;
newPathFinder.buildPath(start, dest, actor.getCell(), isOutside);
newPathFinder.buildPath(start, dest, actor.getCell(), false);
//TO EXPLORE:
//maybe here is a mistake (?): PathFinder::getPathSize() returns number of grid points in the path,
//not the actual path length. Here we should know if the new path is actually more effective.
//if(pathFinder2.getPathSize() < mPathFinder.getPathSize())
if(!mPathFinder.getPath().empty())
{
newPathFinder.syncStart(mPathFinder.getPath());

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

Loading…
Cancel
Save