Merge "dali-toolkit: update text selection UI handles with selection properties"...
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller-input-font-handler.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 // CLASS HEADER
19 #include <dali-toolkit/internal/text/text-controller-input-font-handler.h>
20
21 // EXTERNAL INCLUDES
22 #include <memory.h>
23
24 // INTERNAL INCLUDES
25 #include <dali-toolkit/internal/text/text-controller-impl.h>
26
27 namespace Dali
28 {
29
30 namespace Toolkit
31 {
32
33 namespace Text
34 {
35
36 namespace
37 {
38
39 /**
40  * @brief Adds a new font description run for the selected text.
41  *
42  * The new font parameters are added after the call to this method.
43  *
44  * @param[in] eventData The event data pointer.
45  * @param[in] logicalModel The logical model where to add the new font description run.
46  * @param[out] startOfSelectedText Index to the first selected character.
47  * @param[out] lengthOfSelectedText Number of selected characters.
48  */
49 FontDescriptionRun& UpdateSelectionFontStyleRun( EventData* eventData,
50                                                  LogicalModelPtr logicalModel,
51                                                  CharacterIndex& startOfSelectedText,
52                                                  Length& lengthOfSelectedText )
53 {
54   const bool handlesCrossed = eventData->mLeftSelectionPosition > eventData->mRightSelectionPosition;
55
56   // Get start and end position of selection
57   startOfSelectedText = handlesCrossed ? eventData->mRightSelectionPosition : eventData->mLeftSelectionPosition;
58   lengthOfSelectedText = ( handlesCrossed ? eventData->mLeftSelectionPosition : eventData->mRightSelectionPosition ) - startOfSelectedText;
59
60   // Add the font run.
61   const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count();
62   logicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
63
64   FontDescriptionRun& fontDescriptionRun = *( logicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
65
66   fontDescriptionRun.characterRun.characterIndex = startOfSelectedText;
67   fontDescriptionRun.characterRun.numberOfCharacters = lengthOfSelectedText;
68
69   // Recalculate the selection highlight as the metrics may have changed.
70   eventData->mUpdateLeftSelectionPosition = true;
71   eventData->mUpdateRightSelectionPosition = true;
72   eventData->mUpdateHighlightBox = true;
73
74   return fontDescriptionRun;
75 }
76
77 } // unnamed namespace
78
79 void Controller::InputFontHandler::SetInputFontFamily(Controller& controller, const std::string& fontFamily)
80 {
81   if( NULL != controller.mImpl->mEventData )
82   {
83     controller.mImpl->mEventData->mInputStyle.familyName = fontFamily;
84     controller.mImpl->mEventData->mInputStyle.isFamilyDefined = true;
85
86     if( EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState )
87     {
88       CharacterIndex startOfSelectedText = 0u;
89       Length lengthOfSelectedText = 0u;
90
91       if( EventData::SELECTING == controller.mImpl->mEventData->mState )
92       {
93         // Update a font description run for the selecting state.
94         FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( controller.mImpl->mEventData,
95                                                                               controller.mImpl->mModel->mLogicalModel,
96                                                                               startOfSelectedText,
97                                                                               lengthOfSelectedText );
98
99         fontDescriptionRun.familyLength = fontFamily.size();
100         fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
101         memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength );
102         fontDescriptionRun.familyDefined = true;
103
104         // The memory allocated for the font family name is freed when the font description is removed from the logical model.
105
106         controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
107         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
108         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
109       }
110       else
111       {
112         controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0;
113         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
114         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count();
115       }
116
117       // Request to relayout.
118       controller.mImpl->mOperationsPending = static_cast<OperationsMask>( controller.mImpl->mOperationsPending |
119                                                                VALIDATE_FONTS            |
120                                                                SHAPE_TEXT                |
121                                                                GET_GLYPH_METRICS         |
122                                                                LAYOUT                    |
123                                                                UPDATE_LAYOUT_SIZE        |
124                                                                REORDER                   |
125                                                                ALIGN );
126       controller.mImpl->mRecalculateNaturalSize = true;
127       controller.mImpl->RequestRelayout();
128
129       // As the font changes, recalculate the handle positions is needed.
130       controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true;
131       controller.mImpl->mEventData->mUpdateRightSelectionPosition = true;
132       controller.mImpl->mEventData->mUpdateHighlightBox = true;
133       controller.mImpl->mEventData->mScrollAfterUpdatePosition = true;
134     }
135   }
136 }
137
138 const std::string& Controller::InputFontHandler::GetInputFontFamily(const Controller& controller)
139 {
140   if( NULL != controller.mImpl->mEventData )
141   {
142     return controller.mImpl->mEventData->mInputStyle.familyName;
143   }
144
145   // Return the default font's family if there is no EventData.
146   return controller.GetDefaultFontFamily();
147 }
148
149 void Controller::InputFontHandler::SetInputFontWeight(const Controller& controller, FontWeight weight)
150 {
151   if( NULL != controller.mImpl->mEventData )
152   {
153     controller.mImpl->mEventData->mInputStyle.weight = weight;
154     controller.mImpl->mEventData->mInputStyle.isWeightDefined = true;
155
156     if( EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState )
157     {
158       CharacterIndex startOfSelectedText = 0u;
159       Length lengthOfSelectedText = 0u;
160
161       if( EventData::SELECTING == controller.mImpl->mEventData->mState )
162       {
163         // Update a font description run for the selecting state.
164         FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( controller.mImpl->mEventData,
165                                                                               controller.mImpl->mModel->mLogicalModel,
166                                                                               startOfSelectedText,
167                                                                               lengthOfSelectedText );
168
169         fontDescriptionRun.weight = weight;
170         fontDescriptionRun.weightDefined = true;
171
172         controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
173         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
174         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
175       }
176       else
177       {
178         controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0;
179         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
180         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count();
181       }
182
183       // Request to relayout.
184       controller.mImpl->mOperationsPending = static_cast<OperationsMask>( controller.mImpl->mOperationsPending |
185                                                                VALIDATE_FONTS            |
186                                                                SHAPE_TEXT                |
187                                                                GET_GLYPH_METRICS         |
188                                                                LAYOUT                    |
189                                                                UPDATE_LAYOUT_SIZE        |
190                                                                REORDER                   |
191                                                                ALIGN );
192       controller.mImpl->mRecalculateNaturalSize = true;
193       controller.mImpl->RequestRelayout();
194
195       // As the font might change, recalculate the handle positions is needed.
196       controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true;
197       controller.mImpl->mEventData->mUpdateRightSelectionPosition = true;
198       controller.mImpl->mEventData->mUpdateHighlightBox = true;
199       controller.mImpl->mEventData->mScrollAfterUpdatePosition = true;
200     }
201   }
202 }
203
204 bool Controller::InputFontHandler::IsInputFontWeightDefined(const Controller& controller)
205 {
206   bool defined = false;
207
208   if( NULL != controller.mImpl->mEventData )
209   {
210     defined = controller.mImpl->mEventData->mInputStyle.isWeightDefined;
211   }
212
213   return defined;
214 }
215
216 FontWeight Controller::InputFontHandler::GetInputFontWeight(const Controller& controller)
217 {
218   if( NULL != controller.mImpl->mEventData )
219   {
220     return controller.mImpl->mEventData->mInputStyle.weight;
221   }
222
223   return controller.GetDefaultFontWeight();
224 }
225
226 void Controller::InputFontHandler::SetInputFontWidth(Controller& controller, FontWidth width)
227 {
228   if( NULL != controller.mImpl->mEventData )
229   {
230     controller.mImpl->mEventData->mInputStyle.width = width;
231     controller.mImpl->mEventData->mInputStyle.isWidthDefined = true;
232
233     if( EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState )
234     {
235       CharacterIndex startOfSelectedText = 0u;
236       Length lengthOfSelectedText = 0u;
237
238       if( EventData::SELECTING == controller.mImpl->mEventData->mState )
239       {
240         // Update a font description run for the selecting state.
241         FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( controller.mImpl->mEventData,
242                                                                               controller.mImpl->mModel->mLogicalModel,
243                                                                               startOfSelectedText,
244                                                                               lengthOfSelectedText );
245
246         fontDescriptionRun.width = width;
247         fontDescriptionRun.widthDefined = true;
248
249         controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
250         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
251         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
252       }
253       else
254       {
255         controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0;
256         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
257         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count();
258       }
259
260       // Request to relayout.
261       controller.mImpl->mOperationsPending = static_cast<OperationsMask>( controller.mImpl->mOperationsPending |
262                                                                VALIDATE_FONTS            |
263                                                                SHAPE_TEXT                |
264                                                                GET_GLYPH_METRICS         |
265                                                                LAYOUT                    |
266                                                                UPDATE_LAYOUT_SIZE        |
267                                                                REORDER                   |
268                                                                ALIGN );
269       controller.mImpl->mRecalculateNaturalSize = true;
270       controller.mImpl->RequestRelayout();
271
272       // As the font might change, recalculate the handle positions is needed.
273       controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true;
274       controller.mImpl->mEventData->mUpdateRightSelectionPosition = true;
275       controller.mImpl->mEventData->mUpdateHighlightBox = true;
276       controller.mImpl->mEventData->mScrollAfterUpdatePosition = true;
277     }
278   }
279 }
280
281 bool Controller::InputFontHandler::IsInputFontWidthDefined(const Controller& controller)
282 {
283   bool defined = false;
284
285   if( NULL != controller.mImpl->mEventData )
286   {
287     defined = controller.mImpl->mEventData->mInputStyle.isWidthDefined;
288   }
289
290   return defined;
291 }
292
293 FontWidth Controller::InputFontHandler::GetInputFontWidth(const Controller& controller)
294 {
295   if( NULL != controller.mImpl->mEventData )
296   {
297     return controller.mImpl->mEventData->mInputStyle.width;
298   }
299
300   return controller.GetDefaultFontWidth();
301 }
302
303 void Controller::InputFontHandler::SetInputFontSlant(Controller& controller, FontSlant slant)
304 {
305   if( NULL != controller.mImpl->mEventData )
306   {
307     controller.mImpl->mEventData->mInputStyle.slant = slant;
308     controller.mImpl->mEventData->mInputStyle.isSlantDefined = true;
309
310     if( EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState )
311     {
312       CharacterIndex startOfSelectedText = 0u;
313       Length lengthOfSelectedText = 0u;
314
315       if( EventData::SELECTING == controller.mImpl->mEventData->mState )
316       {
317         // Update a font description run for the selecting state.
318         FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( controller.mImpl->mEventData,
319                                                                               controller.mImpl->mModel->mLogicalModel,
320                                                                               startOfSelectedText,
321                                                                               lengthOfSelectedText );
322
323         fontDescriptionRun.slant = slant;
324         fontDescriptionRun.slantDefined = true;
325
326         controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
327         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
328         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
329       }
330       else
331       {
332         controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0;
333         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
334         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count();
335       }
336
337       // Request to relayout.
338       controller.mImpl->mOperationsPending = static_cast<OperationsMask>( controller.mImpl->mOperationsPending |
339                                                                VALIDATE_FONTS            |
340                                                                SHAPE_TEXT                |
341                                                                GET_GLYPH_METRICS         |
342                                                                LAYOUT                    |
343                                                                UPDATE_LAYOUT_SIZE        |
344                                                                REORDER                   |
345                                                                ALIGN );
346       controller.mImpl->mRecalculateNaturalSize = true;
347       controller.mImpl->RequestRelayout();
348
349       // As the font might change, recalculate the handle positions is needed.
350       controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true;
351       controller.mImpl->mEventData->mUpdateRightSelectionPosition = true;
352       controller.mImpl->mEventData->mUpdateHighlightBox = true;
353       controller.mImpl->mEventData->mScrollAfterUpdatePosition = true;
354     }
355   }
356 }
357
358 bool Controller::InputFontHandler::IsInputFontSlantDefined(const Controller& controller)
359 {
360   bool defined = false;
361
362   if( NULL != controller.mImpl->mEventData )
363   {
364     defined = controller.mImpl->mEventData->mInputStyle.isSlantDefined;
365   }
366
367   return defined;
368 }
369
370 FontSlant Controller::InputFontHandler::GetInputFontSlant(const Controller& controller)
371 {
372   if( NULL != controller.mImpl->mEventData )
373   {
374     return controller.mImpl->mEventData->mInputStyle.slant;
375   }
376
377   return controller.GetDefaultFontSlant();
378 }
379
380 void Controller::InputFontHandler::SetInputFontPointSize(Controller& controller, float size)
381 {
382   if( NULL != controller.mImpl->mEventData )
383   {
384     controller.mImpl->mEventData->mInputStyle.size = size;
385     controller.mImpl->mEventData->mInputStyle.isSizeDefined = true;
386
387     if( EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState )
388     {
389       CharacterIndex startOfSelectedText = 0u;
390       Length lengthOfSelectedText = 0u;
391
392       if( EventData::SELECTING == controller.mImpl->mEventData->mState )
393       {
394         // Update a font description run for the selecting state.
395         FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( controller.mImpl->mEventData,
396                                                                               controller.mImpl->mModel->mLogicalModel,
397                                                                               startOfSelectedText,
398                                                                               lengthOfSelectedText );
399
400         fontDescriptionRun.size = static_cast<PointSize26Dot6>( size * 64.f );
401         fontDescriptionRun.sizeDefined = true;
402
403         controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
404         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
405         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
406       }
407       else
408       {
409         controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0;
410         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
411         controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count();
412       }
413
414       // Request to relayout.
415       controller.mImpl->mOperationsPending = static_cast<OperationsMask>( controller.mImpl->mOperationsPending |
416                                                                VALIDATE_FONTS            |
417                                                                SHAPE_TEXT                |
418                                                                GET_GLYPH_METRICS         |
419                                                                LAYOUT                    |
420                                                                UPDATE_LAYOUT_SIZE        |
421                                                                REORDER                   |
422                                                                ALIGN );
423       controller.mImpl->mRecalculateNaturalSize = true;
424       controller.mImpl->RequestRelayout();
425
426       // As the font might change, recalculate the handle positions is needed.
427       controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true;
428       controller.mImpl->mEventData->mUpdateRightSelectionPosition = true;
429       controller.mImpl->mEventData->mUpdateHighlightBox = true;
430       controller.mImpl->mEventData->mScrollAfterUpdatePosition = true;
431     }
432   }
433 }
434
435 float Controller::InputFontHandler::GetInputFontPointSize(const Controller& controller)
436 {
437   if( NULL != controller.mImpl->mEventData )
438   {
439     return controller.mImpl->mEventData->mInputStyle.size;
440   }
441
442   // Return the default font's point size if there is no EventData.
443   return controller.GetDefaultFontSize( Text::Controller::POINT_SIZE );
444 }
445 } // namespace Text
446
447 } // namespace Toolkit
448
449 } // namespace Dali