[dali_2.3.32] 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 = true;
154         mScrollAnimation.Stop();
155         break;
156       }
157       case TextLabel::AutoScrollStopMode::FINISH_LOOP:
158       {
159         mIsStop = true;
160         mScrollAnimation.SetLoopCount(1); // As animation already playing this allows the current animation to finish instead of trying to stop mid-way
161         break;
162       }
163       default:
164       {
165         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Undifined AutoScrollStopMode\n");
166       }
167     }
168   }
169   else
170   {
171     mScrollerInterface.ScrollingFinished();
172   }
173 }
174
175 bool TextScroller::IsStop()
176 {
177   return mIsStop;
178 }
179
180 bool TextScroller::IsScrolling()
181 {
182   return (mScrollAnimation && mScrollAnimation.GetState() == Animation::PLAYING);
183 }
184
185 TextLabel::AutoScrollStopMode::Type TextScroller::GetStopMode() const
186 {
187   return mStopMode;
188 }
189
190 TextScroller::TextScroller(ScrollerInterface& scrollerInterface)
191 : mScrollerInterface(scrollerInterface),
192   mScrollDeltaIndex(Property::INVALID_INDEX),
193   mScrollSpeed(MINIMUM_SCROLL_SPEED),
194   mLoopCount(1),
195   mLoopDelay(0.0f),
196   mWrapGap(0.0f),
197   mStopMode(TextLabel::AutoScrollStopMode::FINISH_LOOP),
198   mIsStop(false)
199 {
200   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextScroller Default Constructor\n");
201 }
202
203 TextScroller::~TextScroller()
204 {
205 }
206
207 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)
208 {
209   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);
210   mRenderer = renderer;
211
212   float animationProgress = 0.0f;
213   int   remainedLoop      = mLoopCount;
214   if(mScrollAnimation)
215   {
216     if(mScrollAnimation.GetState() == Animation::PLAYING)
217     {
218       animationProgress = mScrollAnimation.GetCurrentProgress();
219
220       if(mLoopCount > 0) // If not a ininity loop, then calculate remained loop
221       {
222         remainedLoop = mLoopCount - (mScrollAnimation.GetCurrentLoop());
223         remainedLoop = mIsStop ? 1 : (remainedLoop <= 0 ? 1 : remainedLoop);
224       }
225     }
226     mScrollAnimation.Clear();
227
228     // Reset to the original shader and texture before scrolling
229     mRenderer.SetShader(mShader);
230     if(mTextureSet)
231     {
232       mRenderer.SetTextures(mTextureSet);
233     }
234   }
235
236   mShader     = mRenderer.GetShader();
237   mTextureSet = mRenderer.GetTextures();
238
239   // Set the shader and texture for scrolling
240   Shader shader = Shader::New(SHADER_TEXT_SCROLLER_SHADER_VERT, SHADER_TEXT_SCROLLER_SHADER_FRAG, Shader::Hint::NONE, "TEXT_SCROLLER");
241   mRenderer.SetShader(shader);
242   mRenderer.SetTextures(textureSet);
243
244   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextScroller::SetParameters wrapGap[%f]\n", wrapGap);
245
246   float horizontalAlign;
247
248   if(textureSize.x > controlSize.x)
249   {
250     // if Text is elided, scroll should start at the begin of text.
251     horizontalAlign = HORIZONTAL_ALIGNMENT_TABLE[HorizontalAlignment::BEGIN][direction];
252   }
253   else
254   {
255     horizontalAlign = HORIZONTAL_ALIGNMENT_TABLE[horizontalAlignment][direction];
256   }
257
258   const float verticalAlign = VERTICAL_ALIGNMENT_TABLE[verticalAlignment];
259
260   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextScroller::SetParameters horizontalAlign[%f], verticalAlign[%f]\n", horizontalAlign, verticalAlign);
261
262   shader.RegisterProperty("uTextureSize", textureSize);
263   shader.RegisterProperty("uHorizontalAlign", horizontalAlign);
264   shader.RegisterProperty("uVerticalAlign", verticalAlign);
265   shader.RegisterProperty("uGap", wrapGap);
266   mScrollDeltaIndex = shader.RegisterProperty("uDelta", 0.0f);
267
268   float scrollAmount   = std::max(textureSize.width, controlSize.width);
269   float scrollDuration = scrollAmount / mScrollSpeed;
270
271   if(direction)
272   {
273     scrollAmount = -scrollAmount; // reverse direction of scrolling
274   }
275
276   StartScrolling(scrollingTextActor, scrollAmount, scrollDuration, remainedLoop);
277   mScrollAnimation.SetCurrentProgress(animationProgress);
278 }
279
280 void TextScroller::AutoScrollAnimationFinished(Dali::Animation& animation)
281 {
282   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextScroller::AutoScrollAnimationFinished\n");
283   mIsStop = false;
284   mScrollerInterface.ScrollingFinished();
285
286   // Revert to the original shader and texture after scrolling
287   mRenderer.SetShader(mShader);
288   if(mTextureSet)
289   {
290     mRenderer.SetTextures(mTextureSet);
291   }
292 }
293
294 void TextScroller::StartScrolling(Actor scrollingTextActor, float scrollAmount, float scrollDuration, int loopCount)
295 {
296   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "TextScroller::StartScrolling scrollAmount[%f] scrollDuration[%f], loop[%d] speed[%d]\n", scrollAmount, scrollDuration, loopCount, mScrollSpeed);
297   Shader shader    = mRenderer.GetShader();
298   mScrollAnimation = Animation::New(scrollDuration);
299   mScrollAnimation.AnimateTo(Property(shader, mScrollDeltaIndex), scrollAmount, TimePeriod(mLoopDelay, scrollDuration));
300   mScrollAnimation.SetEndAction(Animation::DISCARD);
301   mScrollAnimation.SetLoopCount(loopCount);
302   mScrollAnimation.FinishedSignal().Connect(this, &TextScroller::AutoScrollAnimationFinished);
303   mScrollAnimation.Play();
304
305   mIsStop = false;
306 }
307
308 } // namespace Text
309
310 } // namespace Toolkit
311
312 } // namespace Dali