lottie/example: enhanced lottieviewer example 38/187938/5
authorJaeun Choi <jaeun12.choi@samsung.com>
Wed, 29 Aug 2018 14:24:45 +0000 (23:24 +0900)
committerYoungbok Shin <youngb.shin@samsung.com>
Fri, 31 Aug 2018 08:02:23 +0000 (17:02 +0900)
Change-Id: I0eb2a8c528376397190c75b084e9510c3698c034

example/lottieview.cpp
example/lottieview.h
example/lottieviewer.cpp
example/resource/layout.edc
example/resource/layout.edj

index 79ce8fb..82eba73 100644 (file)
@@ -6,8 +6,12 @@ static Eina_Bool
 animator(void *data , double pos)
 {
     LottieView *view = static_cast<LottieView *>(data);
-    view->seek(pos);
-    if (pos == 1.0) {
+    float nextPos = pos + view->mStartPos;
+    if (nextPos > 1.0) nextPos = 1.0;
+
+    view->seek(nextPos);
+    if (nextPos == 1.0) {
+      view->mAnimator = NULL;
       view->finished();
       return EINA_FALSE;
     }
@@ -81,6 +85,38 @@ void LottieView::update(const std::vector<LOTNode *> &renderList)
     evas_object_vg_root_node_set(mVg, root);
 }
 
+static void mImageDelCb(void *data, Evas *evas, Evas_Object *obj, void *)
+{
+    LottieView *lottie = (LottieView *)data;
+
+    if (lottie->mImage != obj) return;
+
+    lottie->mImage = NULL;
+    lottie->stop();
+}
+
+static void mVgDelCb(void *data, Evas *evas, Evas_Object *obj, void *)
+{
+    LottieView *lottie = (LottieView *)data;
+    if (lottie->mVg != obj) return;
+
+    lottie->mVg = NULL;
+    lottie->stop();
+}
+
+void LottieView::initializeBufferObject(Evas *evas)
+{
+    if (mRenderMode) {
+        mImage = evas_object_image_filled_add(evas);
+        evas_object_image_colorspace_set(mImage, EVAS_COLORSPACE_ARGB8888);
+        evas_object_image_alpha_set(mImage, EINA_TRUE);
+        evas_object_event_callback_add(mImage, EVAS_CALLBACK_DEL, mImageDelCb, this);
+    } else {
+        mVg = evas_object_vg_add(evas);
+        evas_object_event_callback_add(mVg, EVAS_CALLBACK_DEL, mVgDelCb, this);
+    }
+}
+
 LottieView::LottieView(Evas *evas, bool renderMode, bool asyncRender):mVg(nullptr), mImage(nullptr)
 {
     mPalying = false;
@@ -95,13 +131,7 @@ LottieView::LottieView(Evas *evas, bool renderMode, bool asyncRender):mVg(nullpt
     mRenderMode = renderMode;
     mAsyncRender = asyncRender;
 
-    if (mRenderMode) {
-        mImage = evas_object_image_filled_add(evas);
-        evas_object_image_colorspace_set(mImage, EVAS_COLORSPACE_ARGB8888);
-        evas_object_image_alpha_set(mImage, EINA_TRUE);
-    } else {
-        mVg = evas_object_vg_add(evas);
-    }
+    initializeBufferObject(evas);
 }
 
 LottieView::~LottieView()
@@ -115,6 +145,14 @@ LottieView::~LottieView()
     delete mPlayer;
 }
 
+Evas_Object *LottieView::getImage() {
+    if (mRenderMode) {
+        return mImage;
+    } else {
+        return mVg;
+    }
+}
+
 void LottieView::show()
 {
     if (mRenderMode) {
@@ -139,16 +177,17 @@ void LottieView::seek(float pos)
     if (mPalying && mReverse)
         pos = 1.0 - pos;
 
+    mPos = pos;
+
     if (mRenderMode) {
         LOTBuffer buf;
         evas_object_image_size_get(mImage, &buf.width, &buf.height);
         if (mAsyncRender) {
             if (mRenderTask.valid()) return;
             mDirty = true;
-            mPendingPos = pos;
             buf.buffer = (uint32_t *)evas_object_image_data_get(mImage, EINA_TRUE);
             buf.bytesPerLine =  evas_object_image_stride_get(mImage);
-            mRenderTask = mPlayer->render(mPendingPos, buf);
+            mRenderTask = mPlayer->render(mPos, buf);
             mBuffer = buf;
             // to force a redraw
             evas_object_image_data_update_add(mImage, 0 , 0, buf.width, buf.height);
@@ -168,6 +207,11 @@ void LottieView::seek(float pos)
     }
 }
 
+float LottieView::getPos()
+{
+   return mPos;
+}
+
 void LottieView::render()
 {
     if (!mDirty) return;
@@ -186,7 +230,7 @@ void LottieView::render()
         }
         mBuffer.buffer = nullptr;
     } else {
-        const std::vector<LOTNode *> &renderList = mPlayer->renderList(mPendingPos);
+        const std::vector<LOTNode *> &renderList = mPlayer->renderList(mPos);
         update(renderList);
     }
 }
@@ -239,6 +283,8 @@ void LottieView::setRepeatMode(LottieView::RepeatMode mode)
 
 void LottieView::play()
 {
+    mStartPos = mPos;
+    if (mAnimator) ecore_animator_del(mAnimator);
     mAnimator = ecore_animator_timeline_add(mPlayer->playTime()/mSpeed, animator, this);
     mReverse = false;
     mCurCount = mRepeatCount;
@@ -253,6 +299,10 @@ void LottieView::pause()
 void LottieView::stop()
 {
     mPalying = false;
+    if (mAnimator) {
+        ecore_animator_del(mAnimator);
+        mAnimator = NULL;
+    }
 }
 
 void LottieView::restart()
@@ -263,6 +313,9 @@ void LottieView::restart()
             mReverse = !mReverse;
         else
             mReverse = false;
+
+        mStartPos = 0;
+        if (mAnimator) ecore_animator_del(mAnimator);
         mAnimator = ecore_animator_timeline_add(mPlayer->playTime()/mSpeed, animator, this);
     }
 }
index e3e02d5..c94247c 100644 (file)
@@ -25,7 +25,7 @@ public:
     };
     LottieView(Evas *evas, bool renderMode = true, bool asyncRender = true);
     ~LottieView();
-    Evas_Object * getImage() { return mRenderMode ? mImage : mVg; }
+    Evas_Object *getImage();
     void setSize(int w, int h);
     void setPos(int x, int y);
     void setFilePath(const char *filePath);
@@ -39,11 +39,13 @@ public:
     long getTotalFrame() const { return mTotalFrame; }
 public:
     void seek(float pos);
+    float getPos();
     void finished();
     void play();
     void pause();
     void stop();
     void render();
+    void initializeBufferObject(Evas *evas);
 private:
     void createVgNode(LOTNode *node, Efl_VG *parent);
     void update(const std::vector<LOTNode *> &);
@@ -67,7 +69,8 @@ public:
     bool                     mRenderMode;
     bool                     mAsyncRender;
     bool                     mDirty;
-    float                    mPendingPos;
+    float                    mStartPos;
+    float                    mPos;
     float                    mFrameRate;
     long                     mTotalFrame;
     std::future<bool>        mRenderTask;
index 9e80c55..1d0b2e3 100644 (file)
@@ -2,6 +2,10 @@
 #include "lottieview.h"
 #include<iostream>
 #include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <error.h>
 
 using namespace std;
 
@@ -9,13 +13,74 @@ typedef struct _AppInfo AppInfo;
 struct _AppInfo {
    LottieView *view;
    Evas_Object *layout;
+   Evas_Object *slider;
+   Evas_Object *button;
+   Ecore_Evas *ee;
+   Eina_Bool autoPlaying;
 };
 
+typedef struct _ItemData ItemData;
+struct _ItemData {
+   int index;
+};
+
+Eina_List *jsonFiles;
+bool renderMode = true;
+
+static void
+_layout_del_cb(void *data, Evas *, Evas_Object *, void *)
+{
+   AppInfo *info = (AppInfo *)data;
+   if (info->view) delete info->view;
+   info->view = NULL;
+
+   ecore_evas_data_set(info->ee, "AppInfo", NULL);
+
+   free(info);
+}
+
+static void
+_update_frame_info(AppInfo *info, double pos)
+{
+   int frameNo = pos * info->view->getTotalFrame();
+   char buf[64];
+
+   sprintf(buf, "%d / %ld", frameNo, info->view->getTotalFrame());
+   elm_object_part_text_set(info->layout, "text", buf);
+}
+
+static void
+_toggle_start_button(AppInfo *info)
+{
+   if (!info->autoPlaying)
+     {
+        info->autoPlaying = EINA_TRUE;
+        info->view->play();
+        elm_object_text_set(info->button, "Stop");
+     }
+   else
+     {
+        info->autoPlaying = EINA_FALSE;
+        info->view->stop();
+        elm_object_text_set(info->button, "Start");
+     }
+}
+
 static void
-_win_del_cb(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
+_ee_pre_render_cb(Ecore_Evas *ee)
 {
-    LottieView *view = (LottieView *)data;
-    delete view;
+    AppInfo *info = (AppInfo *)ecore_evas_data_get(ee, "AppInfo");
+
+    if (info && info->autoPlaying && info->view)
+      {
+         float pos = info->view->getPos();
+         _update_frame_info(info, pos);
+         elm_slider_value_set(info->slider, (double)pos);
+         info->view->render();
+
+         if (pos >= 1.0)
+           _toggle_start_button(info);
+      }
 }
 
 static void
@@ -24,37 +89,34 @@ _slider_cb(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
    double val = elm_slider_value_get(obj);
    AppInfo *info = (AppInfo *)data;
 
-   int frameNo = val * info->view->getTotalFrame();
-   char buf[64];
+   _update_frame_info(info, val);
 
-   sprintf(buf, "%d / %ld", frameNo, info->view->getTotalFrame());
+   if (!info->autoPlaying)
+     {
+        info->view->seek(val);
+        info->view->render();
+     }
+}
 
-   elm_object_part_text_set(info->layout, "text", buf);
+static void
+_button_clicked_cb(void *data, Evas_Object *obj, void *event_info)
+{
+   AppInfo *info = (AppInfo *)data;
 
-   info->view->seek(val);
-   info->view->render();
+   _toggle_start_button(info);
 }
 
-EAPI_MAIN int
-elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
+Evas_Object *
+create_layout(Evas_Object *parent, char *file)
 {
-   Evas_Object *win, *layout, *slider, *image;
-   bool renderMode = true;
+   Evas_Object *layout, *slider, *image, *button;
+   Evas *e;
+   Ecore_Evas *ee;
    char buf[64];
-   AppInfo appInfo;
-
-   if (argc > 1) {
-      if (!strcmp(argv[1], "--disable-render"))
-         renderMode = false;
-   }
-
-   elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
-   win = elm_win_util_standard_add("lottie", "LottieViewer");
-   elm_win_autodel_set(win, EINA_TRUE);
-   evas_object_resize(win, 500, 700);
-   evas_object_show(win);
+   AppInfo *info = (AppInfo *)calloc(sizeof(AppInfo), 1);
 
-   layout = elm_layout_add(win);
+   //LAYOUT
+   layout = elm_layout_add(parent);
    evas_object_show(layout);
    evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
 
@@ -62,29 +124,42 @@ elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
    edjPath +="layout.edj";
 
    elm_layout_file_set(layout, edjPath.c_str(), "layout");
-   elm_win_resize_object_add(win, layout);
 
+   //LOTTIEVIEW
+   LottieView *view = new LottieView(evas_object_evas_get(layout), renderMode);
    std::string filePath = DEMO_DIR;
-   filePath +="insta_camera.json";
+   filePath +=file;
 
-   LottieView *view = new LottieView(evas_object_evas_get(win), renderMode);
    view->setFilePath(filePath.c_str());
    view->setSize(500, 500);
 
-   evas_object_smart_callback_add(win, "delete,request", _win_del_cb, (void *)view);
-
+   //IMAGE from LOTTIEVIEW
    image = view->getImage();
    evas_object_show(image);
    evas_object_size_hint_min_set(image, 500, 500);
    elm_object_part_content_set(layout, "lottie", image);
 
-   appInfo.view = view;
-   appInfo.layout = layout;
-
+   //SLIDER
    slider = elm_slider_add(layout);
-   evas_object_show(slider);
    elm_object_part_content_set(layout, "slider", slider);
-   evas_object_smart_callback_add(slider, "changed", _slider_cb, (void *)&appInfo);
+   evas_object_smart_callback_add(slider, "changed", _slider_cb, (void *)info);
+
+   button = elm_button_add(layout);
+   elm_object_text_set(button, "Start");
+   elm_object_part_content_set(layout, "button", button);
+   evas_object_smart_callback_add(button, "clicked", _button_clicked_cb, (void *)info);
+
+   e = evas_object_evas_get(layout);
+   ee = ecore_evas_ecore_evas_get(e);
+   ecore_evas_data_set(ee, "AppInfo", info);
+   ecore_evas_callback_pre_render_set(ee, _ee_pre_render_cb);
+
+   info->view = view;
+   info->layout = layout;
+   info->slider = slider;
+   info->button = button;
+   info->ee = ee;
+   evas_object_event_callback_add(layout, EVAS_CALLBACK_DEL, _layout_del_cb, (void *)info);
 
    sprintf(buf, "%d / %ld", 0, view->getTotalFrame());
    elm_object_part_text_set(layout, "text", buf);
@@ -92,6 +167,89 @@ elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
    view->seek(0.0);
    view->render();
 
+   return layout;
+}
+
+static void
+_gl_selected_cb(void *data, Evas_Object *obj, void *event_info)
+{
+   Evas_Object *nf = (Evas_Object *)data;
+   Elm_Object_Item *it = (Elm_Object_Item *)event_info;
+   elm_genlist_item_selected_set(it, EINA_FALSE);
+
+   Evas_Object *layout = create_layout(nf, (char *)eina_list_nth(jsonFiles, (elm_genlist_item_index_get(it) - 1)));
+   elm_naviframe_item_push(nf, NULL, NULL, NULL, layout, NULL);
+}
+
+static char *
+_gl_text_get(void *data, Evas_Object *obj, const char *part)
+{
+   ItemData *id = (ItemData *) data;
+   char *str = (char *)eina_list_nth(jsonFiles, id->index);
+   return strdup(str);
+}
+
+static void
+_gl_del(void *data, Evas_Object *obj)
+{
+}
+
+EAPI_MAIN int
+elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
+{
+   Evas_Object *win, *nf, *genlist;
+   Elm_Genlist_Item_Class *itc = elm_genlist_item_class_new();
+   ItemData *itemData;
+   DIR *dir;
+   struct dirent *ent;
+   int i, fileCount = 0;
+
+   if (argc > 1) {
+      if (!strcmp(argv[1], "--disable-render"))
+         renderMode = false;
+   }
+
+   //WIN       
+   elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
+   win = elm_win_util_standard_add("lottie", "LottieViewer");
+   elm_win_autodel_set(win, EINA_TRUE);
+   evas_object_resize(win, 500, 700);
+   evas_object_show(win);
+
+   //NAVIFRAME
+   nf = elm_naviframe_add(win);
+   evas_object_size_hint_weight_set(nf, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_win_resize_object_add(win, nf);
+   evas_object_show(nf);
+
+   //GENLIST
+   genlist = elm_genlist_add(nf);
+   elm_genlist_mode_set(genlist, ELM_LIST_COMPRESS);
+   evas_object_smart_callback_add(genlist, "selected", _gl_selected_cb, nf);
+
+   itc->item_style = "default";
+   itc->func.text_get = _gl_text_get;
+   itc->func.del = _gl_del;
+
+   std::string rscPath = DEMO_DIR;
+
+   dir = opendir(rscPath.c_str());
+   while ((ent = readdir(dir)) != NULL) {
+      if (!strncmp(ent->d_name + (strlen(ent->d_name) - 4), "json", 4)) {
+         jsonFiles = eina_list_append(jsonFiles, strdup(ent->d_name));
+         fileCount++;
+      }
+   }
+   closedir(dir);
+
+   for (i = 0; i < fileCount; i++) {
+      itemData = (ItemData *)calloc(sizeof(ItemData), 1);
+      itemData->index = i;
+      elm_genlist_item_append(genlist, itc, (void *)itemData, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
+   }
+
+   elm_naviframe_item_push(nf, "Lottie Viewer", NULL, NULL, genlist, NULL);
+
    elm_run();
 
    return 0;
index f13e870..9754416 100644 (file)
@@ -45,22 +45,51 @@ collections {
                align: 0.5 1.0;
                rel1.to_x: "left_pad";
                rel1.relative: 1.0 1.0;
-               rel2.to_x: "right_pad";
+               rel2.to_x: "button_left_pad";
                rel2.relative: 0.0 1.0;
+               fixed: 0 1;
             }
          }
          spacer { "left_pad";
             desc { state: "default" 0.0;
+               fixed: 1 0;
                min: 20 0;
+               align: 0.0 0.5;
                rel2.relative: 0.0 0.0;
             }
          }
          spacer { "right_pad";
             desc { state: "default" 0.0;
+               fixed: 1 0;
                min: 20 0;
+               align: 1.0 0.5;
                rel1.relative: 1.0 0.0;
             }
          }
+         swallow { "button";
+            desc { state: "default" 0.0;
+               fixed: 1 1;
+               min: 80 55;
+               align: 1.0 0.5;
+               rel1.to_x: "right_pad";
+               rel1.to_y: "slider";
+               rel1.relative: 0.0 0.5;
+               rel2.to_x: "right_pad";
+               rel2.to_y: "slider";
+               rel2.relative: 0.0 0.5;
+            }
+         }
+         spacer { "button_left_pad";
+            desc { state: "default" 0.0;
+               fixed: 1 0;
+               min: 20 0;
+               align: 1.0 0.5;
+               rel1.to_x: "button";
+               rel1.relative: 0.0 0.0;
+               rel2.to_x: "button";
+               rel2.relative: 0.0 1.0;
+            }
+         }
       }
    }
 }
index 38add6b..8a74b1a 100644 (file)
Binary files a/example/resource/layout.edj and b/example/resource/layout.edj differ