From 647e185e524da3739caa9179de23a7f3a34b3eb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Tue, 8 Sep 2015 23:52:34 +0200 Subject: [PATCH] Added IntNode, IntPropertyBind, PanelPictureChoice and /water/model property --- src/definition/IntDiff.cpp | 7 ++ src/definition/IntDiff.h | 30 +++++ src/definition/IntNode.cpp | 83 +++++++++++++ src/definition/IntNode.h | 43 +++++++ src/definition/WaterDefinition.cpp | 103 +++++++++------- src/definition/WaterDefinition.h | 8 +- src/definition/definition.pro | 8 +- src/definition/definition_global.h | 2 + .../modeler/quickapp/FloatPropertyBind.cpp | 1 - .../modeler/quickapp/IntPropertyBind.cpp | 37 ++++++ .../modeler/quickapp/IntPropertyBind.h | 36 ++++++ .../modeler/quickapp/WaterModeler.cpp | 11 +- src/interface/modeler/quickapp/WaterModeler.h | 5 +- .../modeler/quickapp/modeler_global.h | 1 + .../quickapp/qml/PanelPictureChoice.qml | 48 ++++++++ .../quickapp/qml/PictureChoiceItem.qml | 7 ++ .../modeler/quickapp/qml/ToolbarButton.qml | 2 + .../modeler/quickapp/qml/WaterSection.qml | 32 ++++- src/interface/modeler/quickapp/qml/app.qrc | 5 + .../quickapp/qml/images/icon_preset.png | Bin 0 -> 1219 bytes .../quickapp/qml/images/preset_water_lake.jpg | Bin 0 -> 17594 bytes .../quickapp/qml/images/preset_water_sea.jpg | Bin 0 -> 17266 bytes src/interface/modeler/quickapp/quickapp.pro | 6 +- src/tests/IntNode_Test.cpp | 113 ++++++++++++++++++ src/tests/tests.pro | 3 +- 25 files changed, 534 insertions(+), 57 deletions(-) create mode 100644 src/definition/IntDiff.cpp create mode 100644 src/definition/IntDiff.h create mode 100644 src/definition/IntNode.cpp create mode 100644 src/definition/IntNode.h create mode 100644 src/interface/modeler/quickapp/IntPropertyBind.cpp create mode 100644 src/interface/modeler/quickapp/IntPropertyBind.h create mode 100644 src/interface/modeler/quickapp/qml/PanelPictureChoice.qml create mode 100644 src/interface/modeler/quickapp/qml/PictureChoiceItem.qml create mode 100644 src/interface/modeler/quickapp/qml/images/icon_preset.png create mode 100644 src/interface/modeler/quickapp/qml/images/preset_water_lake.jpg create mode 100644 src/interface/modeler/quickapp/qml/images/preset_water_sea.jpg create mode 100644 src/tests/IntNode_Test.cpp diff --git a/src/definition/IntDiff.cpp b/src/definition/IntDiff.cpp new file mode 100644 index 0000000..792acf8 --- /dev/null +++ b/src/definition/IntDiff.cpp @@ -0,0 +1,7 @@ +#include "IntDiff.h" + +IntDiff::IntDiff(const DefinitionNode *node, int oldvalue, int newvalue): + DefinitionDiff(node), oldvalue(oldvalue), newvalue(newvalue) +{ +} + diff --git a/src/definition/IntDiff.h b/src/definition/IntDiff.h new file mode 100644 index 0000000..c337124 --- /dev/null +++ b/src/definition/IntDiff.h @@ -0,0 +1,30 @@ +#ifndef INTDIFF_H +#define INTDIFF_H + +#include "definition_global.h" + +#include "DefinitionDiff.h" + +namespace paysages { +namespace definition { + +/** + * Diff for an IntNode. + */ +class DEFINITIONSHARED_EXPORT IntDiff: public DefinitionDiff +{ +public: + IntDiff(const DefinitionNode *node, int oldvalue, int newvalue); + + inline int getOldValue() const {return oldvalue;} + inline int getNewValue() const {return newvalue;} + +private: + int oldvalue; + int newvalue; +}; + +} +} + +#endif // INTDIFF_H diff --git a/src/definition/IntNode.cpp b/src/definition/IntNode.cpp new file mode 100644 index 0000000..cd16c49 --- /dev/null +++ b/src/definition/IntNode.cpp @@ -0,0 +1,83 @@ +#include "IntNode.h" + +#include "PackStream.h" +#include "IntDiff.h" +#include "Logs.h" +#include +#include + +IntNode::IntNode(DefinitionNode* parent, const std::string &name, int value): + DefinitionNode(parent, name, "int"), value(value) +{ +} + +std::string IntNode::toString(int indent) const +{ + std::ostringstream stream; + + stream << DefinitionNode::toString(indent) << " " << value; + + return stream.str(); +} + +void IntNode::save(PackStream *stream) const +{ + stream->write(&value); +} + +void IntNode::load(PackStream *stream) +{ + stream->read(&value); +} + +void IntNode::copy(DefinitionNode *destination) const +{ + if (destination->getTypeName() == getTypeName()) + { + ((IntNode *)destination)->value = value; + } + else + { + Logs::error() << "Can't copy from " << getTypeName() << " to " << destination->getTypeName() << std::endl; + } +} + +void IntNode::setValue(int new_value) +{ + addDiff(produceDiff(new_value)); +} + +const IntDiff *IntNode::produceDiff(int new_value) const +{ + return new IntDiff(this, value, new_value); +} + +void IntNode::generateInitDiffs(std::vector *diffs) const +{ + diffs->push_back(produceDiff(value)); +} + +bool IntNode::applyDiff(const DefinitionDiff *diff, bool backward) +{ + if (!DefinitionNode::applyDiff(diff, backward)) + { + return false; + } + + assert(diff->getTypeName() == "int"); + const IntDiff *int_diff = (const IntDiff *)diff; + + double previous = backward ? int_diff->getNewValue() : int_diff->getOldValue(); + double next = backward ? int_diff->getOldValue() : int_diff->getNewValue(); + + if (value == previous) + { + value = next; + return true; + } + else + { + Logs::error() << "Can't apply int diff " << previous << " => " << next << " to " << getName() << std::endl; + return false; + } +} diff --git a/src/definition/IntNode.h b/src/definition/IntNode.h new file mode 100644 index 0000000..bf9ccf6 --- /dev/null +++ b/src/definition/IntNode.h @@ -0,0 +1,43 @@ +#ifndef INTNODE_H +#define INTNODE_H + +#include "definition_global.h" + +#include "DefinitionNode.h" + +namespace paysages { +namespace definition { + +/** + * Node with a single integer value, for the definition tree. + */ +class DEFINITIONSHARED_EXPORT IntNode: public DefinitionNode +{ +public: + IntNode(DefinitionNode* parent, const std::string &name, int value = 0); + + inline int getValue() const {return value;} + + virtual std::string toString(int indent) const override; + virtual void save(PackStream* stream) const override; + virtual void load(PackStream* stream) override; + virtual void copy(DefinitionNode* destination) const override; + + /** + * Change the int value stored. + * + * The DiffManager is used as intermediary, so that the change may not happen immediately. + */ + void setValue(int new_value); + const IntDiff *produceDiff(int new_value) const; + void generateInitDiffs(std::vector *diffs) const; + virtual bool applyDiff(const DefinitionDiff *diff, bool backward=false) override; + +private: + int value; +}; + +} +} + +#endif // INTNODE_H diff --git a/src/definition/WaterDefinition.cpp b/src/definition/WaterDefinition.cpp index e6bd72a..d739af7 100644 --- a/src/definition/WaterDefinition.cpp +++ b/src/definition/WaterDefinition.cpp @@ -4,11 +4,13 @@ #include "NoiseState.h" #include "Color.h" #include "SurfaceMaterial.h" +#include "IntNode.h" #include "FloatNode.h" WaterDefinition::WaterDefinition(DefinitionNode* parent): DefinitionNode(parent, "water", "water") { + model = new IntNode(this, "model", -1); reflection = new FloatNode(this, "reflection"); material = new SurfaceMaterial; @@ -24,6 +26,8 @@ WaterDefinition::WaterDefinition(DefinitionNode* parent): detail_height = 0.0; turbulence = 0.0; foam_coverage = 0.0; + + model->addWatcher(this, true); } WaterDefinition::~WaterDefinition() @@ -101,47 +105,6 @@ void WaterDefinition::validate() { DefinitionNode::validate(); - material->validate(); - foam_material->validate(); -} - -void WaterDefinition::applyPreset(WaterPreset preset) -{ - noise_state->randomizeOffsets(); - - if (preset == WATER_PRESET_LAKE) - { - transparency = 0.5; - reflection->setValue(0.2); - transparency_depth = 4.0; - material->setColor(0.08, 0.15, 0.2, 1.0); - depth_color->r = 0.0; - depth_color->g = 0.1; - depth_color->b = 0.1; - lighting_depth = 6.0; - scaling = 1.0; - waves_height = 0.8; - detail_height = 0.05; - turbulence = 0.1; - foam_coverage = 0.15; - } - else if (preset == WATER_PRESET_SEA) - { - transparency = 0.3; - reflection->setValue(0.07); - transparency_depth = 3.0; - material->setColor(0.05, 0.18, 0.2, 1.0); - depth_color->r = 0.0; - depth_color->g = 0.18; - depth_color->b = 0.15; - lighting_depth = 4.0; - scaling = 1.5; - waves_height = 1.0; - detail_height = 0.06; - turbulence = 0.3; - foam_coverage = 0.4; - } - depth_color->a = 1.0; material->base->a = 1.0; material->reflection = 1.0; @@ -152,5 +115,61 @@ void WaterDefinition::applyPreset(WaterPreset preset) foam_material->shininess = 1.5; foam_material->hardness = 0.2; - validate(); + material->validate(); + foam_material->validate(); +} + +void WaterDefinition::nodeChanged(const DefinitionNode *node, const DefinitionDiff *) +{ + if (node == model) + { + noise_state->randomizeOffsets(); + + switch (model->getValue()) + { + case 1: + transparency = 0.3; + reflection->setValue(0.07); + transparency_depth = 3.0; + material->setColor(0.05, 0.18, 0.2, 1.0); + depth_color->r = 0.0; + depth_color->g = 0.18; + depth_color->b = 0.15; + lighting_depth = 4.0; + scaling = 1.5; + waves_height = 1.0; + detail_height = 0.06; + turbulence = 0.3; + foam_coverage = 0.4; + break; + case 0: + default: + transparency = 0.5; + reflection->setValue(0.2); + transparency_depth = 4.0; + material->setColor(0.08, 0.15, 0.2, 1.0); + depth_color->r = 0.0; + depth_color->g = 0.1; + depth_color->b = 0.1; + lighting_depth = 6.0; + scaling = 1.0; + waves_height = 0.8; + detail_height = 0.05; + turbulence = 0.1; + foam_coverage = 0.15; + break; + } + } +} + +void WaterDefinition::applyPreset(WaterPreset preset) +{ + if (preset == WATER_PRESET_LAKE) + { + model->setValue(0); + } + else if (preset == WATER_PRESET_SEA) + { + model->setValue(1); + } } diff --git a/src/definition/WaterDefinition.h b/src/definition/WaterDefinition.h index c55f999..69eddfa 100644 --- a/src/definition/WaterDefinition.h +++ b/src/definition/WaterDefinition.h @@ -4,11 +4,12 @@ #include "definition_global.h" #include "DefinitionNode.h" +#include "DefinitionWatcher.h" namespace paysages { namespace definition { -class DEFINITIONSHARED_EXPORT WaterDefinition: public DefinitionNode +class DEFINITIONSHARED_EXPORT WaterDefinition: public DefinitionNode, public DefinitionWatcher { public: WaterDefinition(DefinitionNode* parent); @@ -20,9 +21,11 @@ public: virtual void copy(DefinitionNode* destination) const override; virtual void validate() override; + inline IntNode *propModel() const {return model;} inline FloatNode *propReflection() const {return reflection;} -public: + virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff); + typedef enum { WATER_PRESET_LAKE, @@ -48,6 +51,7 @@ public: NoiseState* noise_state; private: + IntNode *model; FloatNode *reflection; }; diff --git a/src/definition/definition.pro b/src/definition/definition.pro index 8714bfa..7105ccf 100644 --- a/src/definition/definition.pro +++ b/src/definition/definition.pro @@ -35,7 +35,9 @@ SOURCES += \ DefinitionDiff.cpp \ FloatDiff.cpp \ DiffManager.cpp \ - DefinitionWatcher.cpp + DefinitionWatcher.cpp \ + IntNode.cpp \ + IntDiff.cpp HEADERS +=\ definition_global.h \ @@ -60,7 +62,9 @@ HEADERS +=\ DefinitionDiff.h \ FloatDiff.h \ DiffManager.h \ - DefinitionWatcher.h + DefinitionWatcher.h \ + IntNode.h \ + IntDiff.h unix:!symbian { maemo5 { diff --git a/src/definition/definition_global.h b/src/definition/definition_global.h index 1909942..9f2d446 100644 --- a/src/definition/definition_global.h +++ b/src/definition/definition_global.h @@ -17,6 +17,8 @@ namespace definition { class DefinitionDiff; class FloatNode; class FloatDiff; + class IntNode; + class IntDiff; class DiffManager; class DefinitionWatcher; class Scenery; diff --git a/src/interface/modeler/quickapp/FloatPropertyBind.cpp b/src/interface/modeler/quickapp/FloatPropertyBind.cpp index bc7d572..7c40386 100644 --- a/src/interface/modeler/quickapp/FloatPropertyBind.cpp +++ b/src/interface/modeler/quickapp/FloatPropertyBind.cpp @@ -4,7 +4,6 @@ #include "FloatNode.h" #include "Logs.h" -#include #include FloatPropertyBind::FloatPropertyBind(MainModelerWindow *window, const QString &object_name, const QString &property_name, FloatNode *node): diff --git a/src/interface/modeler/quickapp/IntPropertyBind.cpp b/src/interface/modeler/quickapp/IntPropertyBind.cpp new file mode 100644 index 0000000..61a11e7 --- /dev/null +++ b/src/interface/modeler/quickapp/IntPropertyBind.cpp @@ -0,0 +1,37 @@ +#include "IntPropertyBind.h" + +#include "MainModelerWindow.h" +#include "IntNode.h" +#include "Logs.h" + +IntPropertyBind::IntPropertyBind(MainModelerWindow *window, const QString &object_name, const QString &property_name, IntNode *node): + QObject(window), node(node), property(property_name) +{ + item = window->findQmlObject(object_name); + if (item) + { + node->addWatcher(this, true); + connect(item, SIGNAL(changed(int)), this, SLOT(propertyChanged(int))); + } + else + { + item = NULL; + Logs::error() << "Can't find object :" << object_name.toStdString() << std::endl; + } +} + +void IntPropertyBind::nodeChanged(const DefinitionNode *, const DefinitionDiff *) +{ + if (item) + { + item->setProperty(property.toLocal8Bit(), node->getValue()); + } +} + +void IntPropertyBind::propertyChanged(int value) +{ + if (value != node->getValue()) + { + node->setValue(value); + } +} diff --git a/src/interface/modeler/quickapp/IntPropertyBind.h b/src/interface/modeler/quickapp/IntPropertyBind.h new file mode 100644 index 0000000..f8bbfdf --- /dev/null +++ b/src/interface/modeler/quickapp/IntPropertyBind.h @@ -0,0 +1,36 @@ +#ifndef INTPROPERTYBIND_H +#define INTPROPERTYBIND_H + +#include "modeler_global.h" + +#include +#include "DefinitionWatcher.h" + +namespace paysages { +namespace modeler { + +/** + * Bind an int Qml property to an IntNode. + * + * The IntNode must exist through this object lifetime. + */ +class IntPropertyBind : public QObject, public DefinitionWatcher +{ + Q_OBJECT +public: + IntPropertyBind(MainModelerWindow *window, const QString &object_name, const QString &property_name, IntNode *node); + + virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) override; + +private slots: + void propertyChanged(int value); + +private: + IntNode *node; + QString property; + QObject *item; +}; + +} +} +#endif // INTPROPERTYBIND_H diff --git a/src/interface/modeler/quickapp/WaterModeler.cpp b/src/interface/modeler/quickapp/WaterModeler.cpp index 4f4fe73..d44af33 100644 --- a/src/interface/modeler/quickapp/WaterModeler.cpp +++ b/src/interface/modeler/quickapp/WaterModeler.cpp @@ -5,6 +5,7 @@ #include "TerrainDefinition.h" #include "WaterDefinition.h" #include "FloatPropertyBind.h" +#include "IntPropertyBind.h" #include "OpenGLRenderer.h" #include "OpenGLWater.h" @@ -17,14 +18,16 @@ WaterModeler::WaterModeler(MainModelerWindow *ui): connect(toggle_water, SIGNAL(toggled(bool)), this, SLOT(enableRendering(bool))); } - prop_water_height = new FloatPropertyBind(ui, "water_height", "value", ui->getScenery()->getTerrain()->propWaterHeight()); - prop_water_reflexion = new FloatPropertyBind(ui, "water_reflection", "value", ui->getScenery()->getWater()->propReflection()); + prop_model = new IntPropertyBind(ui, "water_model", "value", ui->getScenery()->getWater()->propModel()); + prop_height = new FloatPropertyBind(ui, "water_height", "value", ui->getScenery()->getTerrain()->propWaterHeight()); + prop_reflexion = new FloatPropertyBind(ui, "water_reflection", "value", ui->getScenery()->getWater()->propReflection()); } WaterModeler::~WaterModeler() { - delete prop_water_height; - delete prop_water_reflexion; + delete prop_model; + delete prop_height; + delete prop_reflexion; } void WaterModeler::enableRendering(bool enable) diff --git a/src/interface/modeler/quickapp/WaterModeler.h b/src/interface/modeler/quickapp/WaterModeler.h index a50a9a1..1ecd487 100644 --- a/src/interface/modeler/quickapp/WaterModeler.h +++ b/src/interface/modeler/quickapp/WaterModeler.h @@ -20,8 +20,9 @@ public slots: private: MainModelerWindow *ui; - FloatPropertyBind *prop_water_height; - FloatPropertyBind *prop_water_reflexion; + IntPropertyBind *prop_model; + FloatPropertyBind *prop_height; + FloatPropertyBind *prop_reflexion; }; } diff --git a/src/interface/modeler/quickapp/modeler_global.h b/src/interface/modeler/quickapp/modeler_global.h index 717e7c5..77b8895 100644 --- a/src/interface/modeler/quickapp/modeler_global.h +++ b/src/interface/modeler/quickapp/modeler_global.h @@ -19,6 +19,7 @@ namespace modeler { class ModelerCameras; class FloatPropertyBind; + class IntPropertyBind; } } diff --git a/src/interface/modeler/quickapp/qml/PanelPictureChoice.qml b/src/interface/modeler/quickapp/qml/PanelPictureChoice.qml new file mode 100644 index 0000000..d347a0a --- /dev/null +++ b/src/interface/modeler/quickapp/qml/PanelPictureChoice.qml @@ -0,0 +1,48 @@ +import QtQuick 2.0 +import QtQuick.Controls 1.2 + +// Panel with a selection of pictures to choose from +// Mainly used for presets or models +BasePanel { + id: panel + property alias items: container.children + property int value: -1 + width: items[0].width + 10 + signal changed(int value) + + ExclusiveGroup { + id: exclusive_item + + onCurrentChanged: { + if (current) { + panel.value = current.position; + } else { + panel.value = -1; + } + } + } + + onValueChanged: { + if (!exclusive_item.current || exclusive_item.current.position !== panel.value) { + if (panel.value >= 0) { + exclusive_item.current = items[panel.value]; + } else { + exclusive_item.current = null; + } + } + changed(value); + } + + onItemsChanged: { + for (var i = 0; i < items.length; i++) { + items[i].exclusiveGroup = exclusive_item; + items[i].position = i; + } + } + + Column { + id: container + anchors.centerIn: panel + } +} + diff --git a/src/interface/modeler/quickapp/qml/PictureChoiceItem.qml b/src/interface/modeler/quickapp/qml/PictureChoiceItem.qml new file mode 100644 index 0000000..f295498 --- /dev/null +++ b/src/interface/modeler/quickapp/qml/PictureChoiceItem.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 + +ToolbarButton { + property int position: -1 + image_width: 128 + image_height: 128 +} diff --git a/src/interface/modeler/quickapp/qml/ToolbarButton.qml b/src/interface/modeler/quickapp/qml/ToolbarButton.qml index def0465..48fdba6 100644 --- a/src/interface/modeler/quickapp/qml/ToolbarButton.qml +++ b/src/interface/modeler/quickapp/qml/ToolbarButton.qml @@ -13,6 +13,8 @@ Item { property string helptext property string hovertext property string shortcut + property alias image_width: image.width + property alias image_height: image.height signal clicked signal toggled(bool value) diff --git a/src/interface/modeler/quickapp/qml/WaterSection.qml b/src/interface/modeler/quickapp/qml/WaterSection.qml index d77d6ce..2989504 100644 --- a/src/interface/modeler/quickapp/qml/WaterSection.qml +++ b/src/interface/modeler/quickapp/qml/WaterSection.qml @@ -7,6 +7,12 @@ BaseSection { BaseToolbar { id: toolbar + ToolbarButton { + id: tool_water_preset + picture: "images/icon_preset.png" + hovertext: qsTr("Choose a water model") + } + ToolbarButton { id: tool_water_level checked: true @@ -16,12 +22,28 @@ BaseSection { ToolbarButton { id: tool_water_reflection - checked: false picture: "images/icon_water_reflection.png" hovertext: qsTr("Reflection of the water surface") } } + PanelPictureChoice { + id: panel_water_preset + enabled: false + anchors.left: toolbar.right + objectName: "water_model" + items: [ + PictureChoiceItem { + picture: "images/preset_water_lake.jpg" + hovertext: "Water model : Lake" + }, + PictureChoiceItem { + picture: "images/preset_water_sea.jpg" + hovertext: "Water model : Sea" + } + ] + } + PanelSimpleFloat { id: panel_water_level enabled: false @@ -39,6 +61,14 @@ BaseSection { } states: [ + State { + name: "WaterPreset" + when: tool_water_preset.checked + PropertyChanges { + target: panel_water_preset + enabled: true + } + }, State { name: "WaterHeight" when: tool_water_level.checked diff --git a/src/interface/modeler/quickapp/qml/app.qrc b/src/interface/modeler/quickapp/qml/app.qrc index 73d2d65..4f4a4b5 100644 --- a/src/interface/modeler/quickapp/qml/app.qrc +++ b/src/interface/modeler/quickapp/qml/app.qrc @@ -44,5 +44,10 @@ AtmosphereSection.qml PanelSimpleFloat.qml images/icon_water_reflection.png + PanelPictureChoice.qml + PictureChoiceItem.qml + images/preset_water_lake.jpg + images/preset_water_sea.jpg + images/icon_preset.png diff --git a/src/interface/modeler/quickapp/qml/images/icon_preset.png b/src/interface/modeler/quickapp/qml/images/icon_preset.png new file mode 100644 index 0000000000000000000000000000000000000000..34bd0bbef585a0a960b87e397370f4b1b0da059d GIT binary patch literal 1219 zcmV;!1U&nRP)NS)`VamYQPX5jK(J;3C8#W&xj-{B1lj~g<=DxAB5Dz7+*j{0;sio7ZXCn zU?PSPNsJ&LiI@@$;X`PH-XPz5A_!6F6l3eW_c2kvP(O#)8?JAiAz=fJcgoA_AZQy>ML1|HOMJQ4T+7!c>_ zwkwYiMgxt&!$56>mH8yl;~U!v8Mn1P3Va!ucp)G(ivLSM2k<;FJp+s?U=i>~U|c@} z6Kn_Z5U?|3@)z<5Apu+t^!Gc^0=x*!kuBK_+|DqzW3~XQf!2`8Uj$wP+T`!ud4SLv z(*LzA6Hm9pz<3+_3qzdu11sd(8ep6Je~)Y#Eo%xHL#}qf2EbV0Y>4x&fb&}4ueDDZ z!k>l!4gup#JAEpP(?Q@1iOfN(m0*t_MiGYp_NMogFi{H-{7f9o(UPTunc zx0zY4n;>Oqw$6`4TnVS-*wvc!&%kP6w$u-po(}K(GOg)>&!+(AA`JXs4hUUR$Jw|N`cud9oqa_-^8pP62O}w!1rfK)$?X;Im*%~Ev}xB z1XgA7^_F~IP-|C!urnrvdf9%#)c4t;5+vIdl9sp-<^g{NM35Onsmg8z{wpAaGT?Pz zJor##`yn-r!1#5Hz&K7s+X3L^V$tWD6|%TJG1BI_z%pee%39G~uaL>@S5%e?Zb@LR z0)%c$Jz+?#D&)M5D{wjsp&EEc0m4z2A^1fVo7Ou5!A@Q)3J5EeR>BllA&eGfMk6LT z3!&1dEDhV!A&GaVX}}V~4=zI}7iGz|c5pgl1lS_Ae4%QGqO>*zJz-Zd6+|Z1p`w3nxP65LAE<>mU z)+j(Y;Bo;~jd$bJ7QzviA&gOy*N(Xip+*Tpuj>$oy|PrTq%1kT9jef|`En?oF_t?9 zpdatCnFR0*hHr`i58%E0aoW|DP=R+tw%>3CT*7-l!f7iLWy$3EgdV(iBuc{KmeQB; zUb-qN>x?L>+yXXGqP8suggd}?O58fLY==G(ToMceYx5~f_kf>(rD4ZOso8SiUp$fY hJl+FX=NPff_CHiQXdb_%#y0=}002ovPDHLkV1h**A?g4C literal 0 HcmV?d00001 diff --git a/src/interface/modeler/quickapp/qml/images/preset_water_lake.jpg b/src/interface/modeler/quickapp/qml/images/preset_water_lake.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e15953b87d76f47e9f3682ab2fccd05e36e065a0 GIT binary patch literal 17594 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%0AQ9bC0*SVkh1!lCIBOp9PAd|N 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 + EXPECT_DOUBLE_EQ(8, diff->getOldValue()); + EXPECT_DOUBLE_EQ(-4, diff->getNewValue()); + + bool result = node.applyDiff(diff); + + EXPECT_TRUE(result); + EXPECT_DOUBLE_EQ(-4, node.getValue()); + + delete diff; +} + +TEST(IntNode, applyDiff) +{ + IntNode node(NULL, "test", 1); + IntDiff diff(&node, 1, 2); + DefinitionNode onode(NULL, "test", "badtype"); + DefinitionDiff odiff(&onode); + bool result; + + EXPECT_DOUBLE_EQ(1, node.getValue()); + + // apply + result = node.applyDiff(&diff); + + EXPECT_TRUE(result); + EXPECT_DOUBLE_EQ(2, node.getValue()); + + // can't apply twice + result = node.applyDiff(&diff); + + EXPECT_FALSE(result); + EXPECT_DOUBLE_EQ(2, node.getValue()); + + // reverse + result = node.applyDiff(&diff, true); + + EXPECT_TRUE(result); + EXPECT_DOUBLE_EQ(1, node.getValue()); + + // can't reverse twice + result = node.applyDiff(&diff, true); + + EXPECT_FALSE(result); + EXPECT_DOUBLE_EQ(1, node.getValue()); + + // bad type + result = node.applyDiff(&odiff); + + EXPECT_FALSE(result); + EXPECT_DOUBLE_EQ(1, node.getValue()); + + // apply again + result = node.applyDiff(&diff); + + EXPECT_TRUE(result); + EXPECT_DOUBLE_EQ(2, node.getValue()); +} + diff --git a/src/tests/tests.pro b/src/tests/tests.pro index ce4b6a1..0431165 100644 --- a/src/tests/tests.pro +++ b/src/tests/tests.pro @@ -27,7 +27,8 @@ SOURCES += main.cpp \ FloatNode_Test.cpp \ DiffManager_Test.cpp \ ColorHSL_Test.cpp \ - RenderProgress_Test.cpp + RenderProgress_Test.cpp \ + IntNode_Test.cpp HEADERS += \ BaseTestCase.h