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