[dali_2.3.41] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-scroller.cpp
1 /*
2  * Copyright (c) 2024 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 // CLASS HEADER
19 #include <dali-toolkit/internal/text/text-scroller.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23
24 // INTERNAL INCLUDES
25 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
26 #include <dali-toolkit/internal/text/text-scroller-interface.h>
27
28 namespace Dali
29 {
30 namespace Toolkit
31 {
32 namespace
33 {
34 #if defined(DEBUG_ENABLED)
35 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_SCROLLING");
36 #endif
37
38 const int MINIMUM_SCROLL_SPEED = 1; // Speed should be set by Property system.
39
40 /**
41  * @brief How the text should be aligned horizontally when scrolling the text.
42  *
43  * -0.5f aligns the text to the left, 0.0f aligns the text to the center, 0.5f aligns the text to the right.
44  * The final alignment depends on two factors:
45  *   1) The alignment value of the text label (Use Text::HorizontalAlignment enumerations).
46  *   2) The text direction, i.e. whether it's LTR or RTL (0 = LTR, 1 = RTL).
47  */
48 const float HORIZONTAL_ALIGNMENT_TABLE[Text::HorizontalAlignment::END + 1][2] =
49   {
50     // HorizontalAlignment::BEGIN
51     {
52       -0.5f, // LTR
53       0.5f   // RTL
54     },
55
56     // HorizontalAlignment::CENTER
57     {
58       0.0f, // LTR
59       0.0f  // RTL
60     },
61
62     // HorizontalAlignment::END
63     {
64       0.5f, // LTR
65       -0.5f // RTL
66     }};
67
68 /**
69  * @brief How the text should be aligned vertically when scrolling the text.
70  *
71  * -0.5f aligns the text to the top, 0.0f aligns the text to the center, 0.5f aligns the text to the bottom.
72  * The alignment depends on the alignment value of the text label (Use Text::VerticalAlignment enumerations).
73  */
74 const float VERTICAL_ALIGNMENT_TABLE[Text::VerticalAlignment::BOTTOM + 1] =
75   {
76     -0.5f, // VerticalAlignment::TOP
77     0.0f,  // VerticalAlignment::CENTER
78     0.5f   // VerticalAlignment::BOTTOM
79 };
80
81 } // namespace
82
83 namespace Text
84 {
85 TextScrollerPtr TextScroller::New(ScrollerInterface& scrollerInterface)
86 {
87   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextScroller::New\n");
88
89   TextScrollerPtr textScroller(new TextScroller(scrollerInterface));
90   return textScroller;
91 }
92
93 void TextScroller::SetGap(int gap)
94 {
95   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextScroller::SetGap gap[%d]\n", gap);
96   mWrapGap = static_cast<float>(gap);
97 }
98
99 int TextScroller::GetGap() const
100 {
101   return static_cast<int>(mWrapGap);
102 }
103
104 void TextScroller::SetSpeed(int scrollSpeed)
105 {
106   mScrollSpeed = std::max(MINIMUM_SCROLL_SPEED, scrollSpeed);
107 }
108
109 int TextScroller::GetSpeed() const
110 {
111   return mScrollSpeed;
112 }
113
114 void TextScroller::SetLoopCount(int loopCount)
115 {
116   if(loopCount >= 0)
117   {
118     mLoopCount = loopCount;
119   }
120
121   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextScroller::SetLoopCount [%d] Status[%s]\n", mLoopCount, (loopCount) ? "looping" : "stop");
122 }
123
124 int TextScroller::GetLoopCount() const
125 {
126   return mLoopCount;
127 }
128
129 void TextScroller::SetLoopDelay(float delay)
130 {
131   mLoopDelay = delay;
132 }
133
134 float TextScroller::GetLoopDelay() const
135 {
136   return mLoopDelay;
137 }
138
139 void TextScroller::SetStopMode(TextLabel::AutoScrollStopMode::Type stopMode)
140 {
141   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextScroller::SetAutoScrollStopMode [%s]\n", (stopMode == TextLabel::AutoScrollStopMode::IMMEDIATE) ? "IMMEDIATE" : "FINISH_LOOP");
142   mStopMode = stopMode;
143 }
144
145 void TextScroller::StopScrolling()
146 {
147   if(IsScrolling())
148   {
149     switch(mStopMode)
150     {
151       case TextLabel::AutoScrollStopMode::IMMEDIATE:
152       {
153         mIsStop = false;
154         mScrollAnimation.Stop();
155         mScrollerInterface.ScrollingFinished();
156         break;
157       }
158       case TextLabel::AutoScrollStopMode::FINISH_LOOP:
159       {
160         mIsStop = true;
161         mScrollAnimation.SetLoopCount(1); // As animation already playing this allows the current animation to finish instead of trying to stop mid-way
162         break;
163       }
164       default:
165       {
166         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Undifined AutoScrollStopMode\n");
167       }
168     }
169   }
170   else
171   {
172     mScrollerInterface.ScrollingFinished();
173   }
174 }
175
176 bool TextScroller::IsStop()
177 {
178   return mIsStop;
179 }
180
181 bool TextScroller::IsScrolling()
182 {
183   return (mScrollAnimation && mScrollAnimation.GetState() == Animation::PLAYING);
184 }
185
186 TextLabel::AutoScrollStopMode::Type TextScroller::GetStopMode() const
187 {
188   return mStopMode;
189 }
190
191 TextScroller::TextScroller(ScrollerInterface& scrollerInterface)
192 : mScrollerInterface(scrollerInterface),
193   mScrollDeltaIndex(Property::INVALID_INDEX),
194   mScrollSpeed(MINIMUM_SCROLL_SPEED),
195   mLoopCount(1),
196   mLoopDelay(0.0f),
197   mWrapGap(0.0f),
198   mStopMode(TextLabel::AutoScrollStopMode::FINISH_LOOP),
199   mIsStop(false)
200 {
201   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextScroller Default Constructor\n");
202 }
203
204 TextScroller::~TextScroller()
205 {
206 }
207
208 void TextScroller::SetParameters(Actor scrollingTextActor, Renderer renderer, TextureSet textureSet, const Size& controlSize, const Size& textureSize, const float wrapGap, CharacterDirection direction, HorizontalAlignment::Type horizontalAlignment, VerticalAlignment::Type verticalAlignment)
209 {
210   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextScroller::SetParameters controlSize[%f,%f] textureSize[%f,%f] direction[%d]\n", controlSize.x, controlSize.y, textureSize.x, textureSize.y, direction);
211   mRenderer = renderer;
212
213   float animationProgress = 0.0f;
214   int   remainedLoop      = mLoopCount;
215   if(mScrollAnimation)
216   {
217     if(mScrollAnimation.GetState() == Animation::PLAYING)
218     {
219       animationProgress = mScrollAnimation.GetCurrentProgress();
220
221       if(mLoopCount > 0) // If not a ininity loop, then calculate remained loop
222       {
223         remainedLoop = mLoopCount - (mScrollAnimation.GetCurrentLoop());
224         remainedLoop = mIsStop ? 1 : (remainedLoop <= 0 ? 1 : remainedLoop);
225       }
226     }
227     mScrollAnimation.Clear();
228
229     // Reset to the original shader and texture before scrolling
230     mRenderer.SetShader(mShader);
231     if(mTextureSet)
232     {
233       mRenderer.SetTextures(mTextureSet);
234     }
235   }
236
237   mShader     = mRenderer.GetShader();
238   mTextureSet = mRenderer.GetTextures();
239
240   // Set the shader and texture for scrolling
241   Shader shader = Shader::New(SHADER_TEXT_SCROLLER_SHADER_VERT, SHADER_TEXT_SCROLLER_SHADER_FRAG, Shader::Hint::NONE, "TEXT_SCROLLER");
242   mRenderer.SetShader(shader);
243   mRenderer.SetTextures(textureSet);
244
245   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextScroller::SetParameters wrapGap[%f]\n", wrapGap);
246
247   float horizontalAlign;
248
249   if(textureSize.x > controlSize.x)
250   {
251     // if Text is elided, scroll should start at the begin of text.
252     horizontalAlign = HORIZONTAL_ALIGNMENT_TABLE[HorizontalAlignment::BEGIN][direction];
253   }
254   else
255   {
256     horizontalAlign = HORIZONTAL_ALIGNMENT_TABLE[horizontalAlignment][direction];
257   }
258
259   const float verticalAlign = VERTICAL_ALIGNMENT_TABLE[verticalAlignment];
260
261   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextScroller::SetParameters horizontalAlign[%f], verticalAlign[%f]\n", horizontalAlign, verticalAlign);
262
263   shader.RegisterProperty("uTextureSize", textureSize);
264   shader.RegisterProperty("uHorizontalAlign", horizontalAlign);
265   shader.RegisterProperty("uVerticalAlign", verticalAlign);
266   shader.RegisterProperty("uGap", wrapGap);
267   mScrollDeltaIndex = shader.RegisterProperty("uDelta", 0.0f);
268
269   float scrollAmount   = std::max(textureSize.width, controlSize.width);
270   float scrollDuration = scrollAmount / mScrollSpeed;
271
272   if(direction)
273   {
274     scrollAmount = -scrollAmount; // reverse direction of scrolling
275   }
276
277   StartScrolling(scrollingTextActor, scrollAmount, scrollDuration, remainedLoop);
278   mScrollAnimation.SetCurrentProgress(animationProgress);
279 }
280
281 void TextScroller::AutoScrollAnimationFinished(Dali::Animation& animation)
282 {
283   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextScroller::AutoScrollAnimationFinished\n");
284   mIsStop = false;
285   if(mStopMode == TextLabel::AutoScrollStopMode::FINISH_LOOP)
286   {
287     mScrollerInterface.ScrollingFinished();
288   }
289 }
290
291 void TextScroller::StartScrolling(Actor scrollingTextActor, float scrollAmount, float scrollDuration, int loopCount)
292 {
293   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextScroller::StartScrolling scrollAmount[%f] scrollDuration[%f], loop[%d] speed[%d]\n", scrollAmount, scrollDuration, loopCount, mScrollSpeed);
294   Shader shader    = mRenderer.GetShader();
295   mScrollAnimation = Animation::New(scrollDuration);
296   mScrollAnimation.AnimateTo(Property(shader, mScrollDeltaIndex), scrollAmount, TimePeriod(mLoopDelay, scrollDuration));
297   mScrollAnimation.SetEndAction(Animation::DISCARD);
298   mScrollAnimation.SetLoopCount(loopCount);
299   mScrollAnimation.FinishedSignal().Connect(this, &TextScroller::AutoScrollAnimationFinished);
300   mScrollAnimation.Play();
301
302   mIsStop = false;
303 }
304
305 } // namespace Text
306
307 } // namespace Toolkit
308
309 } // namespace Dali