c9c0017c8696ac0edbd2ea0fae02171236f22296
[platform/core/uifw/dali-demo.git] / examples / simple-text-renderer / simple-text-renderer-example.cpp
1 /*
2  * Copyright (c) 2020 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 /**
19  * @file simple-text-renderer-example.cpp
20  * @brief Basic usage of Text Renderer utility.
21  */
22
23 // EXTERNAL INCLUDES
24 #include <dali-toolkit/dali-toolkit.h>
25 #include <dali-toolkit/devel-api/text/text-utils-devel.h>
26 #include <dali/devel-api/adaptor-framework/image-loading.h>
27 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
28
29 // INTERNAL INCLUDES
30 #include "generated/simple-text-renderer-vert.h"
31 #include "generated/simple-text-renderer-frag.h"
32
33 using namespace std;
34 using namespace Dali;
35 using namespace Dali::Toolkit;
36
37 namespace
38 {
39 const std::string IMAGE1 = DEMO_IMAGE_DIR "application-icon-1.png";
40 const std::string IMAGE2 = DEMO_IMAGE_DIR "application-icon-6.png";
41
42 Renderer CreateRenderer()
43 {
44   // Create the geometry.
45   struct Vertex
46   {
47     Dali::Vector2 position;
48     Dali::Vector2 texCoord;
49   };
50
51   static const Vertex vertices[] = {{Dali::Vector2(-0.5f, -0.5f), Dali::Vector2(0.0f, 0.0f)},
52                                     {Dali::Vector2(0.5f, -0.5f), Dali::Vector2(1.0f, 0.0f)},
53                                     {Dali::Vector2(-0.5f, 0.5f), Dali::Vector2(0.0f, 1.0f)},
54                                     {Dali::Vector2(0.5f, 0.5f), Dali::Vector2(1.0f, 1.0f)}};
55
56   Property::Map property;
57   property.Add("aPosition", Property::VECTOR2).Add("aTexCoord", Property::VECTOR2);
58
59   VertexBuffer vertexBuffer = VertexBuffer::New(property);
60
61   vertexBuffer.SetData(vertices, sizeof(vertices) / sizeof(Vertex));
62
63   Geometry geometry = Geometry::New();
64   geometry.AddVertexBuffer(vertexBuffer);
65
66   geometry.SetType(Geometry::TRIANGLE_STRIP);
67
68   // Create the shader
69   Shader shader = Shader::New(SHADER_SIMPLE_TEXT_RENDERER_VERT, SHADER_SIMPLE_TEXT_RENDERER_FRAG);
70
71   // Create the renderer
72
73   Renderer renderer = Renderer::New(geometry, shader);
74
75   return renderer;
76 }
77
78 TextureSet CreateTextureSet(const Dali::Toolkit::DevelText::RendererParameters& textParameters, const std::vector<std::string>& embeddedItems)
79 {
80   Dali::Vector<Dali::Toolkit::DevelText::EmbeddedItemInfo> embeddedItemLayout;
81
82   Devel::PixelBuffer pixelBuffer = Toolkit::DevelText::Render(textParameters, embeddedItemLayout);
83
84   const int dstWidth  = static_cast<int>(pixelBuffer.GetWidth());
85   const int dstHeight = static_cast<int>(pixelBuffer.GetHeight());
86
87   unsigned int index = 0u;
88   for(const auto& itemLayout : embeddedItemLayout)
89   {
90     int width  = static_cast<int>(itemLayout.size.width);
91     int height = static_cast<int>(itemLayout.size.height);
92     int x      = static_cast<int>(itemLayout.position.x);
93     int y      = static_cast<int>(itemLayout.position.y);
94
95     Dali::Devel::PixelBuffer itemPixelBuffer = Dali::LoadImageFromFile(embeddedItems[index++]);
96     itemPixelBuffer.Resize(width, height);
97     itemPixelBuffer.Rotate(itemLayout.angle);
98
99     width  = static_cast<int>(itemPixelBuffer.GetWidth());
100     height = static_cast<int>(itemPixelBuffer.GetHeight());
101
102     Dali::Pixel::Format itemPixelFormat = itemPixelBuffer.GetPixelFormat();
103
104     // Check if the item is out of the buffer.
105
106     if((x + width < 0) ||
107        (x > dstWidth) ||
108        (y < 0) ||
109        (y - height > dstHeight))
110     {
111       // The embedded item is completely out of the buffer.
112       continue;
113     }
114
115     // Crop if it exceeds the boundaries of the destination buffer.
116     int layoutX   = 0;
117     int layoutY   = 0;
118     int cropX     = 0;
119     int cropY     = 0;
120     int newWidth  = width;
121     int newHeight = height;
122
123     bool crop = false;
124
125     if(0 > x)
126     {
127       newWidth += x;
128       cropX = std::abs(x);
129       crop  = true;
130     }
131     else
132     {
133       layoutX = x;
134     }
135
136     if(cropX + newWidth > dstWidth)
137     {
138       crop = true;
139       newWidth -= ((cropX + newWidth) - dstWidth);
140     }
141
142     layoutY = y;
143     if(0.f > layoutY)
144     {
145       newHeight += layoutY;
146       cropY = std::abs(layoutY);
147       crop  = true;
148     }
149
150     if(cropY + newHeight > dstHeight)
151     {
152       crop = true;
153       newHeight -= ((cropY + newHeight) - dstHeight);
154     }
155
156     uint16_t uiCropX     = static_cast<uint16_t>(cropX);
157     uint16_t uiCropY     = static_cast<uint16_t>(cropY);
158     uint16_t uiNewWidth  = static_cast<uint16_t>(newWidth);
159     uint16_t uiNewHeight = static_cast<uint16_t>(newHeight);
160
161     if(crop)
162     {
163       itemPixelBuffer.Crop(uiCropX, uiCropY, uiNewWidth, uiNewHeight);
164     }
165
166     // Blend the item pixel buffer with the text's color according its blending mode.
167     if(Dali::TextAbstraction::ColorBlendingMode::MULTIPLY == itemLayout.colorBlendingMode)
168     {
169       Dali::Devel::PixelBuffer buffer = Dali::Devel::PixelBuffer::New(uiNewWidth,
170                                                                       uiNewHeight,
171                                                                       itemPixelFormat);
172
173       unsigned char*       bufferPtr     = buffer.GetBuffer();
174       const unsigned char* itemBufferPtr = itemPixelBuffer.GetBuffer();
175       const unsigned int   bytesPerPixel = Dali::Pixel::GetBytesPerPixel(itemPixelFormat);
176       const unsigned int   size          = uiNewWidth * uiNewHeight * bytesPerPixel;
177
178       for(unsigned int i = 0u; i < size; i += bytesPerPixel)
179       {
180         *(bufferPtr + 0u) = static_cast<unsigned char>(static_cast<float>(*(itemBufferPtr + 0u)) * textParameters.textColor.r);
181         *(bufferPtr + 1u) = static_cast<unsigned char>(static_cast<float>(*(itemBufferPtr + 1u)) * textParameters.textColor.g);
182         *(bufferPtr + 2u) = static_cast<unsigned char>(static_cast<float>(*(itemBufferPtr + 2u)) * textParameters.textColor.b);
183         *(bufferPtr + 3u) = static_cast<unsigned char>(static_cast<float>(*(itemBufferPtr + 3u)) * textParameters.textColor.a);
184
185         itemBufferPtr += bytesPerPixel;
186         bufferPtr += bytesPerPixel;
187       }
188
189       itemPixelBuffer = buffer;
190     }
191
192     Dali::Toolkit::DevelText::UpdateBuffer(itemPixelBuffer, pixelBuffer, layoutX, layoutY, true);
193   }
194
195   PixelData pixelData = Devel::PixelBuffer::Convert(pixelBuffer);
196
197   Texture texture = Texture::New(TextureType::TEXTURE_2D,
198                                  pixelData.GetPixelFormat(),
199                                  pixelData.GetWidth(),
200                                  pixelData.GetHeight());
201   texture.Upload(pixelData);
202
203   TextureSet textureSet = TextureSet::New();
204   textureSet.SetTexture(0u, texture);
205
206   return textureSet;
207 }
208
209 } // namespace
210
211 /**
212  * @brief The main class of the demo.
213  */
214 class SimpleTextRendererExample : public ConnectionTracker
215 {
216 public:
217   SimpleTextRendererExample(Application& application)
218   : mApplication(application)
219   {
220     // Connect to the Application's Init signal
221     mApplication.InitSignal().Connect(this, &SimpleTextRendererExample::Create);
222   }
223
224   ~SimpleTextRendererExample()
225   {
226     // Nothing to do here.
227   }
228
229   /**
230    * One-time setup in response to Application InitSignal.
231    */
232   void Create(Application& application)
233   {
234     Window window = application.GetWindow();
235     window.SetBackgroundColor(Color::WHITE);
236     window.SetBackgroundColor(Vector4(0.04f, 0.345f, 0.392f, 1.0f));
237
238     window.KeyEventSignal().Connect(this, &SimpleTextRendererExample::OnKeyEvent);
239
240     const std::string image1 = "<item 'width'=26 'height'=26 'url'='" + IMAGE1 + "'/>";
241     const std::string image2 = "<item 'width'=26 'height'=26/>";
242
243     Dali::Toolkit::DevelText::RendererParameters textParameters;
244     textParameters.text                = "Hello " + image1 + " world " + image2 + " this " + image1 + " is " + image2 + " a " + image1 + " demo " + image2 + " of " + image1 + " circular " + image2 + " text " + image1 + " width " + image2 + " icons.";
245     textParameters.horizontalAlignment = "center";
246     textParameters.verticalAlignment   = "center";
247     textParameters.circularAlignment   = "center";
248     textParameters.fontFamily          = "SamsungUI";
249     textParameters.fontWeight          = "";
250     textParameters.fontWidth           = "";
251     textParameters.fontSlant           = "";
252     textParameters.layout              = "circular";
253     textParameters.textColor           = Color::BLACK;
254     textParameters.fontSize            = 25.f;
255     textParameters.textWidth           = 360u;
256     textParameters.textHeight          = 360u;
257     textParameters.radius              = 180u;
258     textParameters.beginAngle          = 15.f;
259     textParameters.incrementAngle      = 360.f;
260     textParameters.ellipsisEnabled     = true;
261     textParameters.markupEnabled       = true;
262
263     std::vector<std::string> embeddedItems = {IMAGE2, IMAGE2, IMAGE2, IMAGE2, IMAGE2};
264
265     TextureSet textureSet = CreateTextureSet(textParameters, embeddedItems);
266
267     Renderer renderer = CreateRenderer();
268     renderer.SetTextures(textureSet);
269
270     Actor actor = Actor::New();
271     actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
272     actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
273     actor.SetProperty(Actor::Property::POSITION, Vector2(0.f, 0.f));
274     actor.SetProperty(Actor::Property::SIZE, Vector2(360.f, 360.f));
275     actor.SetProperty(Actor::Property::COLOR, Color::WHITE);
276
277     actor.AddRenderer(renderer);
278
279     window.Add(actor);
280   }
281
282   /**
283    * Main key event handler
284    */
285   void OnKeyEvent(const KeyEvent& event)
286   {
287     if(event.GetState() == KeyEvent::DOWN)
288     {
289       if(IsKey(event, DALI_KEY_ESCAPE) || IsKey(event, DALI_KEY_BACK))
290       {
291         mApplication.Quit();
292       }
293     }
294   }
295
296 private:
297   Application& mApplication;
298 };
299
300 /** Entry point for Linux & Tizen applications */
301 int DALI_EXPORT_API main(int argc, char** argv)
302 {
303   Application application = Application::New(&argc, &argv);
304
305   SimpleTextRendererExample test(application);
306
307   application.MainLoop();
308
309   return 0;
310 }