[dali_2.3.37] Merge branch 'devel/master'
[platform/core/uifw/dali-demo.git] / examples / image-view-encoded-image-buffer / image-view-encoded-image-buffer-example.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include <dali-toolkit/dali-toolkit.h>
19 #include <dali-toolkit/devel-api/controls/control-devel.h>
20 #include <dali-toolkit/devel-api/visuals/animated-vector-image-visual-actions-devel.h>
21 #include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
22 #include <dali-toolkit/public-api/image-loader/image-url.h>
23 #include <dali-toolkit/public-api/image-loader/image.h>
24 #include <dali/dali.h>
25 #include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
26 #include <string>
27
28 #include "shared/view.h"
29
30 using namespace Dali;
31 using namespace Dali::Toolkit;
32
33 namespace
34 {
35 const char* BACKGROUND_IMAGE(DEMO_IMAGE_DIR "background-gradient.jpg");
36 const char* TOOLBAR_IMAGE(DEMO_IMAGE_DIR "top-bar.png");
37 const char* APPLICATION_TITLE("Image view with encoded image buffer");
38
39 const char* IMAGE_PATH[] = {
40   DEMO_IMAGE_DIR "gallery-small-23.jpg",
41   DEMO_IMAGE_DIR "woodEffect.jpg",
42   DEMO_IMAGE_DIR "wood.png", // 32bits image
43   // DEMO_IMAGE_DIR "heartsframe.9.png", ///< Not implemented yet.
44   DEMO_IMAGE_DIR "dog-anim.webp",
45   DEMO_IMAGE_DIR "World.svg",        // svg image
46   DEMO_IMAGE_DIR "insta_camera.json" // lottie image
47 };
48
49 const unsigned int NUMBER_OF_RESOURCES = sizeof(IMAGE_PATH) / sizeof(char*);
50
51 const unsigned int VECTOR_IMAGE_INDEX          = NUMBER_OF_RESOURCES - 2u;
52 const unsigned int ANIMATED_VECTOR_IMAGE_INDEX = NUMBER_OF_RESOURCES - 1u;
53
54 const unsigned int NUMBER_OF_IMAGES_ROW    = 3;
55 const unsigned int NUMBER_OF_IMAGES_COLUMN = 2;
56 const unsigned int NUMBER_OF_IMAGES        = NUMBER_OF_IMAGES_ROW * NUMBER_OF_IMAGES_COLUMN;
57
58 constexpr Vector2 IMAGE_VIEW_SIZE(200.0f, 200.0f);
59
60 const unsigned int TIMER_INTERVAL = 1000; // ms
61
62 EncodedImageBuffer ConvertFileToEncodedImageBuffer(const char* url)
63 {
64   EncodedImageBuffer buffer;
65   FILE*              fp;
66   fp = fopen(url, "rb");
67   if(fp != NULL)
68   {
69     fseek(fp, 0, SEEK_END);
70     size_t                size = ftell(fp);
71     Dali::Vector<uint8_t> data;
72     data.Resize(size);
73     fseek(fp, 0, SEEK_SET);
74     size_t realSize = fread(data.Begin(), sizeof(uint8_t), size, fp);
75     fclose(fp);
76     data.Resize(realSize);
77     buffer = EncodedImageBuffer::New(data);
78   }
79   return buffer;
80 }
81
82 } // namespace
83
84 class ImageViewEncodedImageBufferApp : public ConnectionTracker
85 {
86 public:
87   ImageViewEncodedImageBufferApp(Application& application)
88   : mApplication(application)
89   {
90     // Connect to the Application's Init signal
91     mApplication.InitSignal().Connect(this, &ImageViewEncodedImageBufferApp::Create);
92   }
93
94   ~ImageViewEncodedImageBufferApp()
95   {
96     // Nothing to do here
97   }
98
99   void Create(Application& application)
100   {
101     // The Init signal is received once (only) during the Application lifetime
102
103     ImageUrl backgroundImageUrl = Image::GenerateUrl(ConvertFileToEncodedImageBuffer(BACKGROUND_IMAGE));
104     ImageUrl toolbarImageUrl    = Image::GenerateUrl(ConvertFileToEncodedImageBuffer(TOOLBAR_IMAGE));
105
106     // Creates a default view with a default tool bar.
107     // The view is added to the window.
108     mContentLayer = DemoHelper::CreateView(application,
109                                            mView,
110                                            mToolBar,
111                                            backgroundImageUrl.GetUrl(),
112                                            toolbarImageUrl.GetUrl(),
113                                            APPLICATION_TITLE);
114
115     // Initialize
116     mState      = 0;
117     mImageIndex = 0;
118     UpdateImageUrl();
119     UpdateImageViews();
120
121     // Create automatic unparent and create ticker.
122     mTimer = Timer::New(TIMER_INTERVAL);
123     mTimer.TickSignal().Connect(this, &ImageViewEncodedImageBufferApp::OnTick);
124     mTimer.Start();
125
126     application.GetWindow().GetRootLayer().TouchedSignal().Connect(this, &ImageViewEncodedImageBufferApp::OnTouch);
127
128     application.GetWindow().KeyEventSignal().Connect(this, &ImageViewEncodedImageBufferApp::OnKeyEvent);
129   }
130
131 private:
132   void UpdateImageUrl()
133   {
134     if(mImageIndex < NUMBER_OF_RESOURCES)
135     {
136       mImageBuffer = ConvertFileToEncodedImageBuffer(IMAGE_PATH[mImageIndex]);
137     }
138
139     if(mImageIndex == VECTOR_IMAGE_INDEX)
140     {
141       mImageBuffer.SetImageType(EncodedImageBuffer::ImageType::VECTOR_IMAGE);
142     }
143     else if(mImageIndex == ANIMATED_VECTOR_IMAGE_INDEX)
144     {
145       mImageBuffer.SetImageType(EncodedImageBuffer::ImageType::ANIMATED_VECTOR_IMAGE);
146     }
147
148     mImageUrl = Image::GenerateUrl(mImageBuffer);
149   }
150
151   void UpdateImageViews()
152   {
153     for(int i = 0; i < static_cast<int>(NUMBER_OF_IMAGES_ROW); i++)
154     {
155       for(int j = 0; j < static_cast<int>(NUMBER_OF_IMAGES_COLUMN); j++)
156       {
157         int viewId = i * NUMBER_OF_IMAGES_COLUMN + j;
158         // Remove old image and set null
159         if(mImageViews[viewId])
160         {
161           mImageViews[viewId].Unparent();
162           mImageViews[viewId] = ImageView(); // Set null image view
163         }
164
165         bool needToCreate = true;
166
167         // If current state don't wanna create current view, just skip
168         unsigned int currentViewState = 1u << ((i + j) & 1);
169         if(mState & currentViewState)
170         {
171           needToCreate = false;
172         }
173
174         if(needToCreate)
175         {
176           mImageViews[viewId] = CreateImageView(i, j);
177           mContentLayer.Add(mImageViews[viewId]);
178         }
179       }
180     }
181   }
182   ImageView CreateImageView(int offset_y, int offset_x)
183   {
184     ImageView view = ImageView::New();
185     view.SetProperty(Actor::Property::SIZE, IMAGE_VIEW_SIZE);
186     view.SetProperty(Actor::Property::POSITION, Vector2(IMAGE_VIEW_SIZE.x * offset_x, IMAGE_VIEW_SIZE.y * offset_y + mToolBar.GetNaturalSize().y));
187     view.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
188
189     Property::Map imagePropertyMap;
190     imagePropertyMap.Insert(Visual::Property::TYPE, Visual::IMAGE);
191     imagePropertyMap.Insert(ImageVisual::Property::URL, mImageUrl.GetUrl());
192
193     view.SetProperty(ImageView::Property::IMAGE, imagePropertyMap);
194
195     if(mImageIndex == ANIMATED_VECTOR_IMAGE_INDEX)
196     {
197       DevelControl::DoAction(view, ImageView::Property::IMAGE, DevelAnimatedVectorImageVisual::Action::PLAY, Property::Value());
198     }
199
200     return view;
201   }
202
203   bool OnTick()
204   {
205     mState = (mState + 1) % 4;
206     UpdateImageViews();
207     return true; // Keep tick always
208   }
209
210   bool OnTouch(Actor actor, const TouchEvent& touch)
211   {
212     if(touch.GetState(0) == PointState::UP)
213     {
214       // Change resource
215       mImageIndex = (mImageIndex + 1) % NUMBER_OF_RESOURCES;
216       // Change resource's url
217       UpdateImageUrl();
218       // Update image views
219       UpdateImageViews();
220     }
221     return true;
222   }
223
224   /**
225    * Main key event handler
226    */
227   void OnKeyEvent(const KeyEvent& event)
228   {
229     if(event.GetState() == KeyEvent::DOWN)
230     {
231       if(IsKey(event, DALI_KEY_ESCAPE) || IsKey(event, DALI_KEY_BACK))
232       {
233         if(mTimer.IsRunning())
234         {
235           mTimer.Stop();
236           mTimer.TickSignal().Disconnect(this, &ImageViewEncodedImageBufferApp::OnTick);
237         }
238         mApplication.Quit();
239       }
240     }
241   }
242
243 private:
244   Application& mApplication;
245
246   Toolkit::Control mView;         ///< The View instance.
247   Toolkit::ToolBar mToolBar;      ///< The View's Toolbar.
248   Layer            mContentLayer; ///< Content layer
249
250   Toolkit::ImageView mImageViews[NUMBER_OF_IMAGES];
251
252   unsigned int       mImageIndex{0u};
253   EncodedImageBuffer mImageBuffer;
254   ImageUrl           mImageUrl;
255
256   // Automatic unparent and create ticker.
257   Timer        mTimer;
258   unsigned int mState{0u}; ///< 0 : draw all images, 1 : draw half, 2 : draw another half, 3 : don't draw images.
259 };
260
261 int DALI_EXPORT_API main(int argc, char** argv)
262 {
263   Application                    application = Application::New(&argc, &argv, DEMO_THEME_PATH);
264   ImageViewEncodedImageBufferApp test(application);
265   application.MainLoop();
266   return 0;
267 }