rlottie: Added dynamic property change feature
authorsubhransu mohanty <sub.mohanty@samsung.com>
Tue, 23 Apr 2019 05:59:50 +0000 (14:59 +0900)
committerHermet Park <hermetpark@gmail.com>
Thu, 25 Apr 2019 04:14:33 +0000 (13:14 +0900)
The keypath can handle globe(**) and wildchar(*) reg ex.
Currently only support fillcolor , fill opacity , stroke color , stroke opacity and stroke width property.

14 files changed:
example/demo.cpp
example/lottieview.h
example/resource/dynamic_property.json [new file with mode: 0755]
inc/rlottie.h
src/lottie/CMakeLists.txt
src/lottie/lottieanimation.cpp
src/lottie/lottieitem.cpp
src/lottie/lottieitem.h
src/lottie/lottiekeypath.cpp [new file with mode: 0644]
src/lottie/lottiekeypath.h [new file with mode: 0644]
src/lottie/lottiemodel.h
src/lottie/lottieparser.cpp
src/lottie/lottieproxymodel.h
src/lottie/meson.build

index 368e29f..48625c6 100644 (file)
@@ -45,10 +45,13 @@ main(void)
    app->setup();
 
    std::string filePath = DEMO_DIR;
-   filePath +="3d.json";
+   filePath +="circuit.json";
 
    LottieView *view = new LottieView(app->evas());
    view->setFilePath(filePath.c_str());
+   if (view->player()) {
+       view->player()->setValue<rlottie::Property::FillColor>("**", rlottie::Color(0, 1, 0));
+   }
    view->setPos(0, 0);
    view->setSize(800, 800);
    view->show();
index a042523..0874e97 100644 (file)
@@ -43,6 +43,7 @@ public:
         evas_object_del(renderObject());
     }
     RenderStrategy(Evas_Object *obj):_renderObject(obj){}
+    virtual rlottie::Animation *player() {return nullptr;}
     virtual void loadFromFile(const char *filePath) = 0;
     virtual void loadFromData(const std::string &jsonData, const std::string &key, const std::string &resourcePath) = 0;
     virtual size_t totalFrame() = 0;
@@ -63,7 +64,7 @@ private:
 class CppApiBase : public RenderStrategy {
 public:
     CppApiBase(Evas_Object *renderObject): RenderStrategy(renderObject) {}
-
+    rlottie::Animation *player() {return mPlayer.get();}
     void loadFromFile(const char *filePath)
     {
         mPlayer = rlottie::Animation::loadFromFile(filePath);
@@ -283,6 +284,7 @@ public:
     };
     LottieView(Evas *evas, Strategy s = Strategy::renderCppAsync);
     ~LottieView();
+    rlottie::Animation *player(){return mRenderDelegate->player();}
     Evas_Object *getImage();
     void setSize(int w, int h);
     void setPos(int x, int y);
diff --git a/example/resource/dynamic_property.json b/example/resource/dynamic_property.json
new file mode 100755 (executable)
index 0000000..ef04bd0
--- /dev/null
@@ -0,0 +1 @@
+{"v":"5.4.3","fr":60,"ip":0,"op":30,"w":800,"h":800,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"ABCDEFG Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[395,397,0],"ix":2},"a":{"a":0,"k":[86,-17,0],"ix":1},"s":{"a":0,"k":[343,343,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-0.516],[0.334,-0.269],[0.949,-0.047],[0,0],[0,0],[0,0],[0.545,0.475],[0.668,1.594],[0,0],[0,0],[0,0],[0.598,-0.563],[0.996,-0.176],[0,0],[0,0],[0,0],[0.346,0.275],[0,0.363],[-0.399,0.926],[0,0],[0,0]],"o":[[0.469,1.113],[0,0.387],[-0.334,0.27],[0,0],[0,0],[0,0],[-0.973,-0.059],[-0.545,-0.475],[0,0],[0,0],[0,0],[-0.727,1.723],[-0.293,0.281],[0,0],[0,0],[0,0],[-1.149,-0.082],[-0.346,-0.275],[0,-0.457],[0,0],[0,0],[0,0]],"v":[[17.912,-4.553],[18.615,-2.109],[18.114,-1.125],[16.189,-0.65],[16.189,0],[25.594,0],[25.594,-0.65],[23.317,-1.45],[21.498,-4.553],[13.201,-24.381],[12.586,-24.381],[4.201,-4.764],[2.215,-1.336],[0.281,-0.65],[0.281,0],[7.787,0],[7.787,-0.65],[5.546,-1.187],[5.027,-2.145],[5.625,-4.219],[7.242,-7.98],[16.471,-7.98]],"c":true},"ix":2},"nm":"A","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[7.787,-9.281],[11.936,-18.914],[15.979,-9.281]],"c":true},"ix":2},"nm":"A","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.921568986481,0.921568986481,0.921568986481,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"A","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.727,0.943],[0,1.195],[0.926,1.072],[1.758,0.422],[1.922,0],[0,0],[0,0],[0,0],[-0.457,-0.516],[0,-1.477],[0,0],[0.269,-0.41],[0.996,0],[0,0],[0,0],[0,0],[-1.307,0.498],[-0.75,1.084],[0,1.184],[1.137,1.078],[1.652,0.352]],"o":[[0.726,-0.943],[0,-1.394],[-0.926,-1.072],[-1.16,-0.281],[0,0],[0,0],[0,0],[0.902,0],[0.34,0.387],[0,0],[0,1.336],[-0.434,0.633],[0,0],[0,0],[0,0],[2.683,0],[1.307,-0.498],[0.75,-1.084],[0,-1.558],[-0.82,-0.773],[1.418,-0.457]],"v":[[45.844,-14.265],[46.934,-17.473],[45.545,-21.173],[41.52,-23.414],[36.896,-23.836],[26.596,-23.836],[26.596,-23.186],[27.492,-23.186],[29.531,-22.412],[30.041,-19.617],[30.041,-4.219],[29.637,-1.6],[27.492,-0.65],[26.596,-0.65],[26.596,0],[37.846,0],[43.831,-0.747],[46.916,-3.12],[48.041,-6.521],[46.336,-10.477],[42.627,-12.164]],"c":true},"ix":2},"nm":"B","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[-1.172,0],[-1.137,-0.984],[0,-1.394],[0.457,-0.762],[0.861,-0.369],[1.711,0],[0.556,0.041],[0.433,0.082]],"o":[[0.937,-0.258],[2.18,0],[1.137,0.984],[0,0.903],[-0.457,0.762],[-0.861,0.369],[-0.668,0],[-0.557,-0.041],[0,0]],"v":[[33.416,-22.271],[36.58,-22.658],[41.555,-21.182],[43.26,-17.613],[42.574,-15.117],[40.597,-13.421],[36.738,-12.867],[34.901,-12.929],[33.416,-13.113]],"c":true},"ix":2},"nm":"B","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[-0.516,0.024],[-0.727,0],[-1.137,-0.492],[-0.504,-0.855],[0,-0.926],[1.113,-0.955],[2.121,0],[1.359,0.316]],"o":[[0.316,-0.059],[0.516,-0.023],[1.676,0],[1.137,0.492],[0.504,0.856],[0,1.406],[-1.113,0.955],[-1.324,0],[0,0]],"v":[[33.416,-11.496],[34.664,-11.619],[36.527,-11.654],[40.746,-10.916],[43.207,-8.895],[43.963,-6.223],[42.293,-2.681],[37.441,-1.248],[33.416,-1.723]],"c":true},"ix":2},"nm":"B","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.921568986481,0.921568986481,0.921568986481,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"B","np":6,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.305,-0.316],[0.316,0],[0.492,0.258],[1.723,0],[1.869,-1.096],[1.066,-1.992],[0,-2.379],[-1.617,-2.18],[-3.949,0],[-1.594,0.984],[-1.195,2.121],[0,0],[1.184,-0.662],[1.547,0],[1.389,0.844],[0.691,1.582],[0,2.156],[-0.733,1.758],[-1.277,0.803],[-1.582,0],[-1.348,-1.066],[-0.727,-2.426],[0,0],[0,0]],"o":[[-0.129,0.563],[-0.235,0.223],[-0.211,0],[-1.676,-0.844],[-2.215,0],[-1.869,1.096],[-1.066,1.992],[0,2.953],[2.168,2.93],[2.191,0],[1.594,-0.984],[0,0],[-1.418,1.969],[-1.184,0.662],[-1.781,0],[-1.389,-0.844],[-0.692,-1.582],[0,-2.613],[0.732,-1.758],[1.277,-0.803],[1.887,0],[1.347,1.066],[0,0],[0,0],[0,0]],"v":[[71.068,-24.381],[70.418,-23.063],[69.592,-22.729],[68.537,-23.115],[63.439,-24.381],[57.313,-22.737],[52.91,-18.105],[51.311,-11.549],[53.736,-3.85],[62.912,0.545],[68.59,-0.932],[72.773,-5.59],[72.229,-5.941],[68.326,-1.995],[64.23,-1.002],[59.476,-2.268],[56.355,-5.906],[55.318,-11.514],[56.417,-18.07],[59.432,-21.911],[63.721,-23.115],[68.572,-21.516],[71.684,-16.277],[72.229,-16.277],[71.684,-24.381]],"c":true},"ix":2},"nm":"C","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.921568986481,0.921568986481,0.921568986481,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"C","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-2.262,2.485],[0,3.316],[1.131,1.887],[1.857,0.809],[3.562,0],[0,0],[0,0],[0,0],[-0.457,-0.516],[0,-1.488],[0,0],[0.258,-0.387],[1.008,0],[0,0],[0,0]],"o":[[4.629,0],[2.015,-2.226],[0,-2.472],[-1.131,-1.887],[-1.858,-0.809],[0,0],[0,0],[0,0],[0.902,0],[0.328,0.375],[0,0],[0,1.348],[-0.422,0.645],[0,0],[0,0],[0,0]],"v":[[85.289,0],[95.625,-3.727],[98.648,-12.041],[96.952,-18.58],[92.47,-22.623],[84.34,-23.836],[74.637,-23.836],[74.637,-23.186],[75.533,-23.186],[77.572,-22.412],[78.064,-19.617],[78.064,-4.219],[77.678,-1.617],[75.533,-0.65],[74.637,-0.65],[74.637,0]],"c":true},"ix":2},"nm":"D","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[-1.055,0],[-1.793,-1.898],[0,-3.293],[1.793,-1.91],[2.719,0],[1.488,0.328]],"o":[[1.347,-0.34],[2.813,0],[1.793,1.898],[0,3.27],[-1.793,1.91],[-1.008,0],[0,0]],"v":[[81.439,-21.99],[85.043,-22.5],[91.951,-19.652],[94.641,-11.865],[91.951,-4.096],[85.184,-1.23],[81.439,-1.723]],"c":true},"ix":2},"nm":"D","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.921568986481,0.921568986481,0.921568986481,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"D","np":5,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-0.469,-0.176],[-0.299,-0.469],[-0.246,-1.254],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.422,-0.469],[0,-1.512],[0,0],[0.135,-0.375],[0.375,-0.187],[0.563,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.726,-0.726],[0.609,-0.187],[1.347,0],[0,0],[0.234,0.135],[0.094,0.229],[0,1.055],[0,0],[0,0],[-0.481,-0.234],[-0.211,-0.41],[-0.164,-1.16],[0,0],[0,0],[0,0],[0.609,-0.539],[1.359,0],[0,0],[0,0]],"o":[[1.184,0],[0.586,0.246],[0.299,0.469],[0,0],[0,0],[0,0],[0,0],[0,0],[0.984,0],[0.305,0.352],[0,0],[0,1.16],[-0.135,0.375],[-0.504,0.27],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.762,1.465],[-0.563,0.551],[-0.609,0.188],[0,0],[-0.656,0],[-0.235,-0.135],[-0.094,-0.229],[0,0],[0,0],[0.996,0],[0.48,0.235],[0.164,0.328],[0,0],[0,0],[0,0],[-0.07,1.36],[-0.457,0.41],[0,0],[0,0],[0,0]],"v":[[114.082,-22.535],[116.561,-22.271],[117.888,-21.199],[118.705,-18.615],[119.391,-18.615],[119.127,-23.836],[100.758,-23.836],[100.758,-23.186],[101.602,-23.186],[103.711,-22.482],[104.168,-19.688],[104.168,-4.201],[103.966,-1.898],[103.201,-1.055],[101.602,-0.65],[100.758,-0.65],[100.758,0],[119.127,0],[121.184,-5.977],[120.48,-5.977],[118.248,-2.689],[116.49,-1.582],[113.555,-1.301],[109.512,-1.301],[108.176,-1.503],[107.684,-2.048],[107.543,-3.973],[107.543,-11.83],[112.781,-11.83],[114.996,-11.479],[116.033,-10.512],[116.525,-8.279],[117.176,-8.279],[117.176,-16.576],[116.525,-16.576],[115.506,-13.729],[112.781,-13.113],[107.543,-13.113],[107.543,-22.535]],"c":true},"ix":2},"nm":"E","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.921568986481,0.921568986481,0.921568986481,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"E","np":3,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-0.592,-0.234],[-0.404,-0.521],[-0.305,-1.113],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.504,-0.281],[-0.117,-0.293],[0,-1.207],[0,0],[0.281,-0.375],[0.984,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.516,0.281],[0.117,0.293],[0,1.207],[0,0],[0,0],[-0.404,-0.217],[-0.229,-0.433],[-0.012,-0.926],[0,0],[0,0],[0,0],[0.463,-0.439],[0.996,0],[0,0],[0,0]],"o":[[1.242,0],[0.592,0.235],[0.404,0.522],[0,0],[0,0],[0,0],[0,0],[0,0],[0.574,0],[0.363,0.211],[0.152,0.387],[0,0],[0,1.43],[-0.445,0.574],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.563,0],[-0.375,-0.211],[-0.152,-0.387],[0,0],[0,0],[0.797,0],[0.404,0.217],[0.229,0.434],[0,0],[0,0],[0,0],[-0.152,1.301],[-0.463,0.439],[0,0],[0,0],[0,0]],"v":[[134.631,-22.535],[137.382,-22.184],[138.876,-21.05],[139.939,-18.598],[140.555,-18.598],[140.326,-23.836],[122.59,-23.836],[122.59,-23.186],[123.434,-23.186],[125.051,-22.764],[125.771,-22.008],[126,-19.617],[126,-4.219],[125.578,-1.512],[123.434,-0.65],[122.59,-0.65],[122.59,0],[132.82,0],[132.82,-0.65],[131.959,-0.65],[130.342,-1.072],[129.604,-1.828],[129.375,-4.219],[129.375,-11.707],[133.717,-11.707],[135.519,-11.382],[136.468,-10.406],[136.828,-8.367],[137.479,-8.367],[137.479,-16.436],[136.828,-16.436],[135.905,-13.825],[133.717,-13.166],[129.375,-13.166],[129.375,-22.535]],"c":true},"ix":2},"nm":"F","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.921568986481,0.921568986481,0.921568986481,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"F","np":3,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.158,-0.205],[0.222,0],[0.656,0.246],[0.709,0.141],[0.867,0],[1.746,-1.02],[1.195,-2.285],[0,-2.098],[-1.793,-2.215],[-4.605,0],[-1.313,0.34],[-1.348,0.727],[0,0],[-0.235,0.434],[-0.914,0],[0,0],[0,0],[0,0],[0,0],[-0.381,-0.193],[-0.182,-0.369],[0,-1.195],[0,0],[0.82,-0.222],[0.879,0],[1.424,0.873],[0.879,1.875],[0,2.274],[-1.324,2.028],[-3.035,0],[-1.418,-1.371],[-0.621,-1.875],[0,0],[0,0]],"o":[[-0.035,0.598],[-0.158,0.205],[-0.223,0],[-1.301,-0.48],[-0.709,-0.141],[-2.379,0],[-2.086,1.23],[-1.008,1.922],[0,2.895],[2.391,2.953],[1.605,0],[1.312,-0.34],[0,0],[0,-1.277],[0.34,-0.609],[0,0],[0,0],[0,0],[0,0],[0.961,0],[0.381,0.193],[0.182,0.369],[0,0],[-0.762,0.434],[-0.82,0.223],[-1.5,0],[-1.424,-0.873],[-0.879,-1.875],[0,-2.801],[1.582,-2.402],[2.226,0],[0.984,0.949],[0,0],[0,0],[0,0]],"v":[[163.477,-24.381],[163.187,-23.177],[162.615,-22.869],[161.297,-23.238],[158.282,-24.17],[155.918,-24.381],[149.73,-22.852],[144.809,-17.578],[143.297,-11.549],[145.986,-3.885],[156.48,0.545],[160.857,0.035],[164.848,-1.564],[164.848,-8.859],[165.199,-11.426],[167.08,-12.34],[167.52,-12.34],[167.52,-13.008],[158.291,-13.008],[158.291,-12.34],[160.304,-12.05],[161.147,-11.206],[161.42,-8.859],[161.42,-1.969],[159.047,-0.984],[156.498,-0.65],[152.112,-1.96],[148.658,-6.082],[147.34,-12.305],[149.326,-19.547],[156.252,-23.15],[161.719,-21.094],[164.127,-16.857],[164.742,-16.857],[164.127,-24.381]],"c":true},"ix":2},"nm":"G","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.921568986481,0.921568986481,0.921568986481,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"G","np":3,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
index 3d6c967..11e1e7c 100644 (file)
@@ -51,6 +51,38 @@ struct LOTLayerNode;
 
 namespace rlottie {
 
+struct Color {
+    Color(){}
+    Color(float r, float g , float b):mr(r), mg(g), mb(b){}
+public:
+    float mr{0}, mg{0}, mb{0};
+};
+
+struct Size {
+    Size(float w, float h):mw(w), mh(h){}
+private:
+    float mw{0} , mh{0};
+};
+
+struct Point {
+    Point(float x, float y):mx(x), my(y){}
+private:
+    float mx{0} , my{0};
+};
+
+enum class Property {
+    FillColor,     /*!< Color property of Fill object , value type is rlottie::Color */
+    FillOpacity,   /*!< Opacity property of Fill object , value type is float [ 0 .. 100] */
+    StrokeColor,   /*!< Color property of Stroke object , value type is rlottie::Color */
+    StrokeOpacity, /*!< Opacity property of Stroke object , value type is float [ 0 .. 100] */
+    StrokeWidth,   /*!< stroke with property of Stroke object , value type is float */
+    TrAnchor,      /*!< Transform Anchor property of Layer and Group object , value type is rlottie::Point */
+    TrPosition,    /*!< Transform Position property of Layer and Group object , value type is rlottie::Point */
+    TrScale,       /*!< Transform Scale property of Layer and Group object , value type is rlottie::Size. range[0 ..100] */
+    TrRotation,    /*!< Transform Scale property of Layer and Group object , value type is float. range[0 .. 360] in degrees*/
+    TrOpacity      /*!< Transform Opacity property of Layer and Group object , value type is float [ 0 .. 100] */
+};
+
 class LOT_EXPORT Surface {
 public:
     /**
@@ -337,6 +369,29 @@ public:
     const LayerInfoList& layers() const;
 
     /**
+     *  @brief Sets property value for the specified {@link KeyPath}. This {@link KeyPath} can resolve
+     *  to multiple contents. In that case, the callback's value will apply to all of them.
+     *
+     *  Keypath should conatin object names separated by (.) and can handle globe(**) or wildchar(*).
+     *
+     *  @usage
+     *  To change fillcolor property of fill1 object in the layer1->group1->fill1 hirarchy to RED color
+     *
+     *     player->setValue<rlottie::Property::FillColor>("layer1.group1.fill1", rlottie::Color(1, 0, 0);
+     *
+     *  if all the color property inside group1 needs to be changed to GREEN color
+     *
+     *     player->setValue<rlottie::Property::FillColor>("**.group1.**", rlottie::Color(0, 1, 0);
+     *
+     *  @internal
+     */
+    template<Property prop, typename AnyValue>
+    void setValue(const std::string &keypath, AnyValue value)
+    {
+        setValue(std::integral_constant<ValueType, mapType(prop)>{}, prop, keypath, value);
+    }
+
+    /**
      *  @brief default destructor
      *
      *  @internal
@@ -344,6 +399,34 @@ public:
     ~Animation();
 
 private:
+    enum class ValueType {Color,Point,Size,Float};
+    static constexpr ValueType mapType(Property prop) {
+        switch (prop) {
+        case Property::FillColor:
+        case Property::StrokeColor:
+            return ValueType::Color;
+        case Property::FillOpacity:
+        case Property::StrokeOpacity:
+        case Property::StrokeWidth:
+        case Property::TrOpacity:
+        case Property::TrRotation:
+            return ValueType::Float;
+        case Property::TrAnchor:
+        case Property::TrPosition:
+            return ValueType::Point;
+        case Property::TrScale:
+            return ValueType::Size;
+        }
+    }
+
+    void setValue(std::integral_constant<ValueType, ValueType::Color>,
+                  Property, const std::string &, Color);
+    void setValue(std::integral_constant<ValueType, ValueType::Float>,
+                  Property, const std::string &, float);
+    void setValue(std::integral_constant<ValueType, ValueType::Size>,
+                  Property, const std::string &, Size);
+    void setValue(std::integral_constant<ValueType, ValueType::Point>,
+                  Property, const std::string &, Point);
     /**
      *  @brief default constructor
      *
@@ -354,6 +437,7 @@ private:
     std::unique_ptr<AnimationImpl> d;
 };
 
+
 }  // namespace lotplayer
 
 #endif  // _RLOTTIE_H_
index a81356b..89a2b68 100644 (file)
@@ -7,6 +7,7 @@ target_sources(rlottie
         "${CMAKE_CURRENT_LIST_DIR}/lottieproxymodel.cpp"
         "${CMAKE_CURRENT_LIST_DIR}/lottieparser.cpp"
         "${CMAKE_CURRENT_LIST_DIR}/lottieanimation.cpp"
+        "${CMAKE_CURRENT_LIST_DIR}/lottiekeypath.cpp"
     )
 
 target_include_directories(rlottie
index b8e0674..d5376ea 100644 (file)
@@ -51,6 +51,8 @@ public:
                  renderTree(size_t frameNo, const VSize &size);
 
     const LayerInfoList& layerInfoList() const { return mModel->layerInfoList();}
+    void setValue(const std::string &keypath, LOTVariant &&value);
+    void removeFilter(const std::string &keypath, Property prop);
 private:
     std::string                  mFilePath;
     std::shared_ptr<LOTModel>    mModel;
@@ -59,6 +61,12 @@ private:
     std::atomic<bool>            mRenderInProgress;
 };
 
+void AnimationImpl::setValue(const std::string &keypath, LOTVariant &&value)
+{
+    if (keypath.empty()) return;
+    mCompItem->setValue(keypath, value);
+}
+
 const LOTLayerNode *AnimationImpl::renderTree(size_t frameNo, const VSize &size)
 {
     if (update(frameNo, size)) {
@@ -306,6 +314,34 @@ const LayerInfoList& Animation::layers() const
     return d->layerInfoList();
 }
 
+void Animation::setValue(std::integral_constant<ValueType, ValueType::Color>,Property prop,
+                         const std::string &keypath,
+                         Color value)
+{
+    d->setValue(keypath, LOTVariant(prop, value));
+}
+
+void Animation::setValue(std::integral_constant<ValueType, ValueType::Float>, Property prop,
+                         const std::string &keypath,
+                         float value)
+{
+    d->setValue(keypath, LOTVariant(prop, value));
+}
+
+void Animation::setValue(std::integral_constant<ValueType, ValueType::Size>,Property prop,
+                         const std::string &keypath,
+                         Size value)
+{
+    d->setValue(keypath, LOTVariant(prop, value));
+}
+
+void Animation::setValue(std::integral_constant<ValueType, ValueType::Point>, Property prop,
+                         const std::string &keypath,
+                         Point value)
+{
+    d->setValue(keypath, LOTVariant(prop, value));
+}
+
 Animation::Animation(): d(std::make_unique<AnimationImpl>()) {}
 
 /*
index 2da6981..dd5a113 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/* 
  * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved.
  * 
  * This library is free software; you can redistribute it and/or
@@ -24,6 +24,7 @@
 #include "vdasher.h"
 #include "vpainter.h"
 #include "vraster.h"
+#include "lottiekeypath.h"
 
 /* Lottie Layer Rules
  * 1. time stretch is pre calculated and applied to all the properties of the
  * AE. which means (start frame > endFrame) 3.
  */
 
+static
+bool transformProp(rlottie::Property prop)
+{
+    switch (prop) {
+        case rlottie::Property::TrAnchor:
+        case rlottie::Property::TrScale:
+        case rlottie::Property::TrOpacity:
+        case rlottie::Property::TrPosition:
+        case rlottie::Property::TrRotation:
+            return true;
+        default:
+            return false;
+    }
+}
+static
+bool fillProp(rlottie::Property prop)
+{
+    switch (prop) {
+        case rlottie::Property::FillColor:
+        case rlottie::Property::FillOpacity:
+            return true;
+        default:
+            return false;
+    }
+}
+
+static
+bool strokeProp(rlottie::Property prop)
+{
+    switch (prop) {
+        case rlottie::Property::StrokeColor:
+        case rlottie::Property::StrokeOpacity:
+        case rlottie::Property::StrokeWidth:
+            return true;
+        default:
+            return false;
+    }
+}
+
 LOTCompItem::LOTCompItem(LOTModel *model)
     : mRootModel(model), mUpdateViewBox(false), mCurFrameNo(-1)
 {
@@ -41,6 +81,12 @@ LOTCompItem::LOTCompItem(LOTModel *model)
     mViewSize = mCompData->size();
 }
 
+void LOTCompItem::setValue(const std::string &keypath, LOTVariant &value)
+{
+    LOTKeyPath key(keypath);
+    mRootLayer->resolveKeyPath(key, 0, value);
+}
+
 std::unique_ptr<LOTLayerItem>
 LOTCompItem::createLayerItem(LOTLayerData *layerData)
 {
@@ -369,6 +415,50 @@ LOTLayerItem::LOTLayerItem(LOTLayerData *layerData): mLayerData(layerData)
         mLayerMask = std::make_unique<LOTLayerMaskItem>(mLayerData);
 }
 
+bool LOTLayerItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth,
+                                  LOTVariant &value)
+{
+    if (!keyPath.matches(name(), depth)) {
+      return false;
+    }
+
+    if (!keyPath.skip(name())) {
+      if (keyPath.fullyResolvesTo(name(), depth) &&
+          transformProp(value.property())) {
+          //@TODO handle propery update.
+      }
+    }
+    return true;
+}
+
+bool LOTShapeLayerItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth,
+                                       LOTVariant &value)
+{
+    if (LOTLayerItem::resolveKeyPath(keyPath, depth, value)){
+        if (keyPath.propagate(name(), depth)) {
+            uint newDepth = keyPath.nextDepth(name(), depth);
+            mRoot->resolveKeyPath(keyPath, newDepth, value);
+        }
+        return true;
+    }
+    return false;
+}
+
+bool LOTCompLayerItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth,
+                                      LOTVariant &value)
+{
+    if (LOTLayerItem::resolveKeyPath(keyPath, depth, value)) {
+        if (keyPath.propagate(name(), depth)) {
+            uint newDepth = keyPath.nextDepth(name(), depth);
+            for (const auto &layer : mLayers) {
+                layer->resolveKeyPath( keyPath, newDepth, value);
+            }
+        }
+        return true;
+    }
+    return false;
+}
+
 void LOTLayerItem::updateStaticProperty()
 {
     if (mParentLayer) mParentLayer->updateStaticProperty();
@@ -862,6 +952,56 @@ void LOTShapeLayerItem::renderList(std::vector<VDrawable *> &list)
     mRoot->renderList(list);
 }
 
+bool LOTContentGroupItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value)
+{
+    if (!keyPath.matches(name(), depth)) {
+      return false;
+    }
+
+    if (!keyPath.skip(name())) {
+      if (keyPath.fullyResolvesTo(name(), depth) &&
+          transformProp(value.property())) {
+          //@TODO handle property update
+      }
+    }
+
+    if (keyPath.propagate(name(), depth)) {
+        uint newDepth = keyPath.nextDepth(name(), depth);
+        for (auto &child : mContents) {
+            child->resolveKeyPath( keyPath, newDepth, value);
+        }
+    }
+    return true;
+}
+
+bool LOTFillItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value)
+{
+    if (!keyPath.matches(mModel.name(), depth)) {
+      return false;
+    }
+
+    if (keyPath.fullyResolvesTo(mModel.name(), depth) &&
+        fillProp(value.property())) {
+        mModel.filter().addValue(value);
+        return true;
+    }
+    return false;
+}
+
+bool LOTStrokeItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value)
+{
+    if (!keyPath.matches(mModel.name(), depth)) {
+      return false;
+    }
+
+    if (keyPath.fullyResolvesTo(mModel.name(), depth) &&
+        strokeProp(value.property())) {
+        mModel.filter().addValue(value);
+        return true;
+    }
+    return false;
+}
+
 LOTContentGroupItem::LOTContentGroupItem(LOTGroupData *data) : mData(data)
 {
     addChildren(mData);
index 365bbd0..49276de 100644 (file)
@@ -31,6 +31,7 @@
 #include"rlottie.h"
 #include"vpainter.h"
 #include"vdrawable.h"
+#include"lottiekeypath.h"
 
 V_USE_NAMESPACE
 
@@ -46,7 +47,6 @@ class LOTLayerItem;
 class LOTMaskItem;
 class VDrawable;
 
-
 class LOTCompItem
 {
 public:
@@ -58,6 +58,7 @@ public:
    void buildRenderTree();
    const LOTLayerNode * renderTree()const;
    bool render(const rlottie::Surface &surface);
+   void setValue(const std::string &keypath, LOTVariant &value);
 private:
    VMatrix                                    mScaleMatrix;
    VSize                                      mViewSize;
@@ -86,11 +87,12 @@ public:
 };
 
 typedef vFlag<DirtyFlagBit> DirtyFlag;
+
 class LOTLayerItem
 {
 public:
+   virtual ~LOTLayerItem() = default;
    LOTLayerItem(LOTLayerData *layerData);
-   virtual ~LOTLayerItem()= default;
    int id() const {return mLayerData->id();}
    int parentId() const {return mLayerData->parentId();}
    void setParentLayer(LOTLayerItem *parent){mParentLayer = parent;}
@@ -105,6 +107,8 @@ public:
    bool visible() const;
    virtual void buildLayerNode();
    LOTLayerNode * layerNode() const {return mLayerCNode.get();}
+   const std::string & name() const {return mLayerData->name();}
+   virtual bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value);
 protected:
    virtual void updateContent() = 0;
    inline VMatrix combinedMatrix() const {return mCombinedMatrix;}
@@ -136,6 +140,7 @@ public:
    void updateStaticProperty() final;
    void render(VPainter *painter, const VRle &mask, const VRle &matteRle) final;
    void buildLayerNode() final;
+   bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value) override;
 protected:
    void updateContent() final;
 private:
@@ -169,6 +174,7 @@ public:
    static std::unique_ptr<LOTContentItem> createContentItem(LOTData *contentData);
    void renderList(std::vector<VDrawable *> &list)final;
    void buildLayerNode() final;
+   bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value) override;
 protected:
    void updateContent() final;
    std::vector<LOTNode *>               mCNodeList;
@@ -250,11 +256,12 @@ class LOTTrimItem;
 class LOTContentItem
 {
 public:
-   virtual ~LOTContentItem()= default;
+   virtual ~LOTContentItem() = default;
    virtual void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag) = 0;
    virtual void renderList(std::vector<VDrawable *> &){}
    void setParent(LOTContentItem *parent) {mParent = parent;}
    LOTContentItem *parent() const {return mParent;}
+   virtual bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value) {return false;}
 private:
    LOTContentItem *mParent{nullptr};
 };
@@ -265,12 +272,18 @@ public:
     LOTContentGroupItem(){}
    LOTContentGroupItem(LOTGroupData *data);
    void addChildren(LOTGroupData *data);
-   void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag);
+   void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag) override;
    void applyTrim();
    void processTrimItems(std::vector<LOTPathDataItem *> &list);
    void processPaintItems(std::vector<LOTPathDataItem *> &list);
-   void renderList(std::vector<VDrawable *> &list);
+   void renderList(std::vector<VDrawable *> &list) override;
    const VMatrix & matrix() const { return mMatrix;}
+   const std::string & name() const
+   {
+       static const std::string TAG = "__";
+       return mData ? mData->name() : TAG;
+   }
+   bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value) override;
 protected:
    LOTGroupData                                  *mData{nullptr};
    std::vector<std::unique_ptr<LOTContentItem>>   mContents;
@@ -398,6 +411,7 @@ public:
 protected:
    void updateContent(int frameNo) final;
    void updateRenderNode() final;
+   bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value) final;
 private:
    LOTProxyModel<LOTFillData> mModel;
    VColor                     mColor;
@@ -424,6 +438,7 @@ public:
 protected:
    void updateContent(int frameNo) final;
    void updateRenderNode() final;
+   bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value) final;
 private:
    LOTProxyModel<LOTStrokeData> mModel;
    LOTStrokeData               *mData;
diff --git a/src/lottie/lottiekeypath.cpp b/src/lottie/lottiekeypath.cpp
new file mode 100644 (file)
index 0000000..9507660
--- /dev/null
@@ -0,0 +1,81 @@
+#include "lottiekeypath.h"
+
+#include <sstream>
+
+LOTKeyPath::LOTKeyPath(const std::string &keyPath)
+{
+    std::stringstream ss (keyPath);
+    std::string item;
+
+    while (getline (ss, item, '.')) {
+        mKeys.push_back (item);
+    }
+}
+
+bool LOTKeyPath::matches(const std::string &key, uint depth)
+{
+  if (skip(key)) {
+    // This is an object we programatically create.
+    return true;
+  }
+  if (depth > size()) {
+    return false;
+  }
+  if ((mKeys[depth] == key) ||
+      (mKeys[depth] == "*") ||
+      (mKeys[depth] == "**")) {
+    return true;
+  }
+  return false;
+}
+
+uint LOTKeyPath::nextDepth(const std::string key, uint depth) {
+  if (skip(key)) {
+    // If it's a container then we added programatically and it isn't a part of the keypath.
+    return depth;
+  }
+  if ( mKeys[depth] != "**") {
+    // If it's not a globstar then it is part of the keypath.
+    return depth + 1;
+  }
+  if (depth == size()) {
+    // The last key is a globstar.
+    return depth;
+  }
+  if (mKeys[depth + 1] == key) {
+    // We are a globstar and the next key is our current key so consume both.
+    return depth + 2;
+  }
+  return depth;
+}
+
+bool LOTKeyPath::fullyResolvesTo(const std::string key, uint depth) {
+    if (depth > mKeys.size()) {
+      return false;
+    }
+
+    bool isLastDepth = (depth == size());
+
+    if (!isGlobstar(depth)) {
+      bool matches = (mKeys[depth] == key) || isGlob(depth);
+      return (isLastDepth || (depth == size() - 1 && endsWithGlobstar())) && matches;
+    }
+
+    bool isGlobstarButNextKeyMatches = !isLastDepth && mKeys[depth + 1] == key;
+    if (isGlobstarButNextKeyMatches) {
+      return depth == size() - 1 ||
+          (depth == size() - 2 && endsWithGlobstar());
+    }
+
+    if (isLastDepth) {
+      return true;
+    }
+
+    if (depth + 1 < size()) {
+      // We are a globstar but there is more than 1 key after the globstar we we can't fully match.
+      return false;
+    }
+    // Return whether the next key (which we now know is the last one) is the same as the current
+    // key.
+    return mKeys[depth + 1] == key;
+  }
diff --git a/src/lottie/lottiekeypath.h b/src/lottie/lottiekeypath.h
new file mode 100644 (file)
index 0000000..68ddde0
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef LOTTIEKEYPATH_H
+#define LOTTIEKEYPATH_H
+
+#include <string>
+#include <vector>
+
+class LOTKeyPath{
+public:
+    LOTKeyPath(const std::string &keyPath);
+    bool matches(const std::string &key, uint depth);
+    uint nextDepth(const std::string key, uint depth);
+    bool fullyResolvesTo(const std::string key, uint depth);
+
+    bool propagate(const std::string key, uint depth) {
+        return skip(key) ? true : (depth < size()) || (mKeys[depth] == "**");
+    }
+    bool skip(const std::string &key) const { return key == "__";}
+private:
+    bool isGlobstar(uint depth) const {return mKeys[depth] == "**";}
+    bool isGlob(uint depth) const {return mKeys[depth] == "*";}
+    bool endsWithGlobstar() const { return mKeys.back() == "**"; }
+    uint size() const {return mKeys.size() - 1;}
+private:
+    std::vector<std::string> mKeys;
+};
+
+#endif //LOTTIEKEYPATH_H
index 8f4cd93..d26aab9 100644 (file)
@@ -295,7 +295,7 @@ class LOTDataVisitor;
 class LOTData
 {
 public:
-    enum class Type {
+    enum class Type :short {
         Composition = 1,
         Layer,
         ShapeGroup,
@@ -316,10 +316,12 @@ public:
     bool isStatic() const{return mStatic;}
     void setStatic(bool value) {mStatic = value;}
     bool hidden() const {return mHidden;}
+    const std::string& name() const{ return mName;}
 public:
-    bool                mStatic{true};
-    bool                mHidden{false};
-    LOTData::Type       mType;
+    std::string               mName;
+    bool                      mStatic{true};
+    bool                      mHidden{false};
+    LOTData::Type             mType;
 };
 
 class LOTGroupData: public LOTData
index 9afdc2d..10ecd28 100644 (file)
@@ -748,6 +748,7 @@ void LottieParserImpl::parseLayers(LOTCompositionData *comp)
     comp->mRootLayer->mRoot = true;
     comp->mRootLayer->mLayerType = LayerType::Precomp;
     comp->mRootLayer->mTransform = std::make_shared<LOTTransformData>();
+    comp->mRootLayer->mName = std::string("__");
     bool staticFlag = true;
     RAPIDJSON_ASSERT(PeekType() == kArrayType);
     EnterArray();
@@ -857,7 +858,7 @@ std::shared_ptr<LOTData> LottieParserImpl::parseLayer(bool record)
             layer->mLayerType = getLayerType();
         } else if (0 == strcmp(key, "nm")) { /*Layer name*/
             RAPIDJSON_ASSERT(PeekType() == kStringType);
-            layerName = GetString();
+            layer->mName = GetString();
         } else if (0 == strcmp(key, "ind")) { /*Layer index in AE. Used for
                                                  parenting and expressions.*/
             RAPIDJSON_ASSERT(PeekType() == kNumberType);
@@ -939,7 +940,7 @@ std::shared_ptr<LOTData> LottieParserImpl::parseLayer(bool record)
     layer->mCompRef = compRef;
 
     if (record) {
-        mLayerInfoList.push_back(LayerInfo(layerName, layer->mInFrame, layer->mOutFrame));
+        mLayerInfoList.push_back(LayerInfo(layer->mName, layer->mInFrame, layer->mOutFrame));
     }
     return sharedLayer;
 }
@@ -1070,7 +1071,9 @@ std::shared_ptr<LOTData> LottieParserImpl::parseGroupObject()
 
     LOTShapeGroupData *group = sharedGroup.get();
     while (const char *key = NextObjectKey()) {
-        if (0 == strcmp(key, "it")) {
+        if (0 == strcmp(key, "nm")) {
+            group->mName = GetString();
+        } else if (0 == strcmp(key, "it")) {
             RAPIDJSON_ASSERT(PeekType() == kArrayType);
             EnterArray();
             while (NextArrayValue()) {
@@ -1105,7 +1108,9 @@ std::shared_ptr<LOTData> LottieParserImpl::parseRectObject()
     LOTRectData *                obj = sharedRect.get();
 
     while (const char *key = NextObjectKey()) {
-        if (0 == strcmp(key, "p")) {
+        if (0 == strcmp(key, "nm")) {
+            obj->mName = GetString();
+        } else if (0 == strcmp(key, "p")) {
             parseProperty(obj->mPos);
         } else if (0 == strcmp(key, "s")) {
             parseProperty(obj->mSize);
@@ -1134,7 +1139,9 @@ std::shared_ptr<LOTData> LottieParserImpl::parseEllipseObject()
     LOTEllipseData *obj = sharedEllipse.get();
 
     while (const char *key = NextObjectKey()) {
-        if (0 == strcmp(key, "p")) {
+        if (0 == strcmp(key, "nm")) {
+            obj->mName = GetString();
+        } else if (0 == strcmp(key, "p")) {
             parseProperty(obj->mPos);
         } else if (0 == strcmp(key, "s")) {
             parseProperty(obj->mSize);
@@ -1160,7 +1167,9 @@ std::shared_ptr<LOTData> LottieParserImpl::parseShapeObject()
     LOTShapeData *obj = sharedShape.get();
 
     while (const char *key = NextObjectKey()) {
-        if (0 == strcmp(key, "ks")) {
+        if (0 == strcmp(key, "nm")) {
+            obj->mName = GetString();
+        } else if (0 == strcmp(key, "ks")) {
             parseShapeProperty(obj->mShape);
         } else if (0 == strcmp(key, "d")) {
             obj->mDirection = GetInt();
@@ -1188,7 +1197,9 @@ std::shared_ptr<LOTData> LottieParserImpl::parsePolystarObject()
     LOTPolystarData *obj = sharedPolystar.get();
 
     while (const char *key = NextObjectKey()) {
-        if (0 == strcmp(key, "p")) {
+        if (0 == strcmp(key, "nm")) {
+            obj->mName = GetString();
+        } else if (0 == strcmp(key, "p")) {
             parseProperty(obj->mPos);
         } else if (0 == strcmp(key, "pt")) {
             parseProperty(obj->mPointCount);
@@ -1251,7 +1262,9 @@ std::shared_ptr<LOTData> LottieParserImpl::parseTrimObject()
     LOTTrimData *                obj = sharedTrim.get();
 
     while (const char *key = NextObjectKey()) {
-        if (0 == strcmp(key, "s")) {
+        if (0 == strcmp(key, "nm")) {
+            obj->mName = GetString();
+        } else if (0 == strcmp(key, "s")) {
             parseProperty(obj->mStart);
         } else if (0 == strcmp(key, "e")) {
             parseProperty(obj->mEnd);
@@ -1280,7 +1293,9 @@ std::shared_ptr<LOTData> LottieParserImpl::parseReapeaterObject()
     LOTRepeaterData *obj = sharedRepeater.get();
 
     while (const char *key = NextObjectKey()) {
-        if (0 == strcmp(key, "c")) {
+        if (0 == strcmp(key, "nm")) {
+            obj->mName = GetString();
+        } else if (0 == strcmp(key, "c")) {
             parseProperty(obj->mCopies);
             float maxCopy= 0.0;
             if (!obj->mCopies.isStatic()) {
@@ -1326,7 +1341,9 @@ std::shared_ptr<LOTTransformData> LottieParserImpl::parseTransformObject(bool dd
     if (ddd) obj->m3D = std::make_unique<LOT3DData>();
 
     while (const char *key = NextObjectKey()) {
-        if (0 == strcmp(key, "a")) {
+        if (0 == strcmp(key, "nm")) {
+            obj->mName = GetString();
+        } else if (0 == strcmp(key, "a")) {
             parseProperty(obj->mAnchor);
         } else if (0 == strcmp(key, "p")) {
             EnterObject();
@@ -1394,7 +1411,9 @@ std::shared_ptr<LOTData> LottieParserImpl::parseFillObject()
     LOTFillData *                obj = sharedFill.get();
 
     while (const char *key = NextObjectKey()) {
-        if (0 == strcmp(key, "c")) {
+        if (0 == strcmp(key, "nm")) {
+            obj->mName = GetString();
+        } else if (0 == strcmp(key, "c")) {
             parseProperty(obj->mColor);
         } else if (0 == strcmp(key, "o")) {
             parseProperty(obj->mOpacity);
@@ -1480,7 +1499,9 @@ std::shared_ptr<LOTData> LottieParserImpl::parseStrokeObject()
     LOTStrokeData *obj = sharedStroke.get();
 
     while (const char *key = NextObjectKey()) {
-        if (0 == strcmp(key, "c")) {
+        if (0 == strcmp(key, "nm")) {
+            obj->mName = GetString();
+        } else if (0 == strcmp(key, "c")) {
             parseProperty(obj->mColor);
         } else if (0 == strcmp(key, "o")) {
             parseProperty(obj->mOpacity);
@@ -1561,7 +1582,9 @@ std::shared_ptr<LOTData> LottieParserImpl::parseGFillObject()
     LOTGFillData *obj = sharedGFill.get();
 
     while (const char *key = NextObjectKey()) {
-        if (0 == strcmp(key, "r")) {
+        if (0 == strcmp(key, "nm")) {
+            obj->mName = GetString();
+        } else if (0 == strcmp(key, "r")) {
             obj->mFillRule = getFillRule();
         } else {
             parseGradientProperty(obj, key);
@@ -1607,7 +1630,9 @@ std::shared_ptr<LOTData> LottieParserImpl::parseGStrokeObject()
     LOTGStrokeData *obj = sharedGStroke.get();
 
     while (const char *key = NextObjectKey()) {
-        if (0 == strcmp(key, "w")) {
+        if (0 == strcmp(key, "nm")) {
+            obj->mName = GetString();
+        } else if (0 == strcmp(key, "w")) {
             parseProperty(obj->mWidth);
         } else if (0 == strcmp(key, "lc")) {
             obj->mCapStyle = getLineCap();
@@ -2077,6 +2102,7 @@ public:
         vDebug << level
                << "{ "
                << layerType(obj->mLayerType)
+               << ", name: "<< obj->name()
                << ", id:" << obj->mId << " Pid:" << obj->mParentId
                << ", a:" << !obj->isStatic()
                << ", "<<matteType(obj->mMatteType)
@@ -2120,7 +2146,7 @@ public:
         switch (obj->mType) {
         case LOTData::Type::Repeater: {
             auto r = static_cast<LOTRepeaterData *>(obj);
-            vDebug << level << "{ Repeater: a:" << !obj->isStatic()
+            vDebug << level << "{ Repeater: name: "<<obj->name()<<" , a:" << !obj->isStatic()
                    << ", copies:" << r->maxCopies()
                    << ", offset:" << r->offset(0);
             visitChildren(static_cast<LOTGroupData *>(obj), level);
@@ -2128,7 +2154,7 @@ public:
             break;
         }
         case LOTData::Type::ShapeGroup: {
-            vDebug << level << "{ ShapeGroup: a:" << !obj->isStatic();
+            vDebug << level << "{ ShapeGroup: name: "<<obj->name()<<" , a:" << !obj->isStatic();
             visitChildren(static_cast<LOTGroupData *>(obj), level);
             vDebug << level << "} ShapeGroup";
             break;
@@ -2138,44 +2164,44 @@ public:
             break;
         }
         case LOTData::Type::Trim:{
-            vDebug << level << "{ Trim: a:" << !obj->isStatic() << " }";
+            vDebug << level << "{ Trim: name: "<<obj->name()<<" , a:" << !obj->isStatic() << " }";
             break;
         }
         case LOTData::Type::Rect:{
-            vDebug << level << "{ Rect: a:" << !obj->isStatic() << " }";
+            vDebug << level << "{ Rect: name: "<<obj->name()<<" , a:" << !obj->isStatic() << " }";
             break;
         }
         case LOTData::Type::Ellipse:{
-            vDebug << level << "{ Ellipse: a:" << !obj->isStatic() << " }";
+            vDebug << level << "{ Ellipse: name: "<<obj->name()<<" , a:" << !obj->isStatic() << " }";
             break;
         }
         case LOTData::Type::Shape:{
-            vDebug << level << "{ Shape: a:" << !obj->isStatic() << " }";
+            vDebug << level << "{ Shape: name: "<<obj->name()<<" , a:" << !obj->isStatic() << " }";
             break;
         }
         case LOTData::Type::Polystar:{
-            vDebug << level << "{ Polystar: a:" << !obj->isStatic() << " }";
+            vDebug << level << "{ Polystar: name: "<<obj->name()<<" , a:" << !obj->isStatic() << " }";
             break;
         }
         case LOTData::Type::Transform:{
-            vDebug << level << "{ Transform: a: " << !obj->isStatic() << " }";
+            vDebug << level << "{ Transform: name: "<<obj->name()<<" , a: " << !obj->isStatic() << " }";
             break;
         }
         case LOTData::Type::Stroke:{
-            vDebug << level << "{ Stroke: a:" << !obj->isStatic() << " }";
+            vDebug << level << "{ Stroke: name: "<<obj->name()<<" , a:" << !obj->isStatic() << " }";
             break;
         }
         case LOTData::Type::GStroke:{
-            vDebug << level << "{ GStroke: a:" << !obj->isStatic() << " }";
+            vDebug << level << "{ GStroke: name: "<<obj->name()<<" , a:" << !obj->isStatic() << " }";
             break;
         }
         case LOTData::Type::Fill:{
-            vDebug << level << "{ Fill: a:" << !obj->isStatic() << " }";
+            vDebug << level << "{ Fill: name: "<<obj->name()<<" , a:" << !obj->isStatic() << " }";
             break;
         }
         case LOTData::Type::GFill:{
             auto f = static_cast<LOTGFillData *>(obj);
-            vDebug << level << "{ GFill: a:" << !f->isStatic()
+            vDebug << level << "{ GFill: name: "<<obj->name()<<" , a:" << !f->isStatic()
                    << ", ty:" << f->mGradientType << ", s:" << f->mStartPoint.value(0)
                    << ", e:" << f->mEndPoint.value(0) << " }";
             break;
index b62292a..54a7d52 100644 (file)
 #ifndef LOTTIEPROXYMODEL_H
 #define LOTTIEPROXYMODEL_H
 
+#include<bitset>
 #include "lottiemodel.h"
+#include "rlottie.h"
+
+// Naive way to implement std::variant
+// refactor it when we move to c++17
+// users should make sure proper combination
+// of id and value are passed while creating the object.
+class LOTVariant
+{
+public:
+    enum Type {Color, Point, Size, Float};
+    LOTVariant(rlottie::Property prop, float  v):property_(prop),valueType_(Type::Float),value_(v){}
+    LOTVariant(rlottie::Property prop, rlottie::Color  col):property_(prop),valueType_(Type::Color),color_(col){}
+    LOTVariant(rlottie::Property prop, rlottie::Point  pt):property_(prop),valueType_(Type::Point),pos_(pt){}
+    LOTVariant(rlottie::Property prop, rlottie::Size  sz):property_(prop),valueType_(Type::Size),size_(sz){}
+    Type type() const {return valueType_;}
+    rlottie::Property property() const {return property_;}
+    float value() const {return value_;}
+    rlottie::Color color() const {return color_;}
+    rlottie::Point pos() const {return pos_;}
+    rlottie::Size  size() const {return size_;}
+public:
+    rlottie::Property property_;
+    Type  valueType_;
+    union {
+      float           value_;
+      rlottie::Color  color_;
+      rlottie::Point  pos_;
+      rlottie::Size   size_;
+    };
+};
+
+class LOTFilter
+{
+public:
+    void addValue(LOTVariant &value)
+    {
+        uint index = static_cast<uint>(value.property());
+        if (mBitset.test(index)) {
+            for (uint i=0; i < mFilters.size(); i++ ) {
+                if (mFilters[i].property() == value.property()) {
+                    mFilters[i] = value;
+                    break;
+                }
+            }
+        } else {
+            mBitset.set(index);
+            mFilters.push_back(value);
+        }
+    }
+
+    void removeValue(LOTVariant &value)
+    {
+        uint index = static_cast<uint>(value.property());
+        if (mBitset.test(index)) {
+            mBitset.reset(index);
+            for (uint i=0; i < mFilters.size(); i++ ) {
+                if (mFilters[i].property() == value.property()) {
+                    mFilters.erase(mFilters.begin() + i);
+                    break;
+                }
+            }
+        }
+    }
+    bool hasFilter(rlottie::Property prop) const
+    {
+        return mBitset.test(static_cast<uint>(prop));
+    }
+    LottieColor color(rlottie::Property prop) const
+    {
+        rlottie::Color col = data(prop).color();
+        return LottieColor(col.mr, col.mg, col.mb);
+    }
+    float opacity(rlottie::Property prop) const
+    {
+        float val = data(prop).value();
+        return val/100;
+    }
+    float value(rlottie::Property prop) const
+    {
+        return data(prop).value();
+    }
+private:
+    LOTVariant data(rlottie::Property prop) const
+    {
+        for (uint i=0; i < mFilters.size(); i++ ) {
+            if (mFilters[i].property() == prop) {
+                return mFilters[i];
+            }
+        }
+        return LOTVariant(prop, 0);
+    }
+    std::vector<LOTVariant>    mFilters;
+    std::bitset<32>            mBitset{0};
+};
 
 template <typename T>
 class LOTProxyModel
 {
 public:
     LOTProxyModel(T *model): _modelData(model) {}
-    void addValueProvider() {/* Impement*/}
-    void removeValueProvider() {/* Impement*/}
-    bool hasValueProvider() {return false;}
-    LottieColor color(int frame) const { return _modelData->color(frame);}
-    float opacity(int frame) const { return _modelData->opacity(frame);}
-    FillRule fillRule() const {return _modelData->fillRule();}
-
-    float strokeWidth(int frame) const {return _modelData->strokeWidth(frame);}
+    LOTFilter& filter() {return mFilter;}
+    const std::string & name() const {return _modelData->name();}
+    LottieColor color(int frame) const
+    {
+        if (mFilter.hasFilter(rlottie::Property::StrokeColor)) {
+            return mFilter.color(rlottie::Property::StrokeColor);
+        }
+        return _modelData->color(frame);
+    }
+    float opacity(int frame) const
+    {
+        if (mFilter.hasFilter(rlottie::Property::StrokeOpacity)) {
+            return mFilter.opacity(rlottie::Property::StrokeOpacity);
+        }
+        return _modelData->opacity(frame);
+    }
+    float strokeWidth(int frame) const
+    {
+        if (mFilter.hasFilter(rlottie::Property::StrokeWidth)) {
+            return mFilter.value(rlottie::Property::StrokeWidth);
+        }
+        return _modelData->strokeWidth(frame);
+    }
     float meterLimit() const {return _modelData->meterLimit();}
     CapStyle capStyle() const {return _modelData->capStyle();}
     JoinStyle joinStyle() const {return _modelData->joinStyle();}
@@ -41,7 +151,35 @@ public:
     int getDashInfo(int frameNo, float *array) const {return _modelData->getDashInfo(frameNo, array);}
 
 private:
-    T *_modelData;
+    T                         *_modelData;
+    LOTFilter                  mFilter;
+};
+
+template <>
+class LOTProxyModel<LOTFillData>
+{
+public:
+    LOTProxyModel(LOTFillData *model): _modelData(model) {}
+    LOTFilter& filter() {return mFilter;}
+    const std::string & name() const {return _modelData->name();}
+    LottieColor color(int frame) const
+    {
+        if (mFilter.hasFilter(rlottie::Property::FillColor)) {
+            return mFilter.color(rlottie::Property::FillColor);
+        }
+        return _modelData->color(frame);
+    }
+    float opacity(int frame) const
+    {
+        if (mFilter.hasFilter(rlottie::Property::FillOpacity)) {
+            return mFilter.opacity(rlottie::Property::FillOpacity);
+        }
+        return _modelData->opacity(frame);
+    }
+    FillRule fillRule() const {return _modelData->fillRule();}
+private:
+    LOTFillData               *_modelData;
+    LOTFilter                  mFilter;
 };
 
 #endif // LOTTIEITEM_H
index b49bbb2..a6d1856 100644 (file)
@@ -5,6 +5,7 @@ source_file += files('lottiemodel.cpp')
 source_file += files('lottieproxymodel.cpp')
 source_file += files('lottieanimation.cpp')
 source_file += files('lottieitem.cpp')
+source_file += files('lottiekeypath.cpp')
 
 
 lottie_dep = declare_dependency(