1 /*
2  * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_TEXT_PICKER_TEXT_PICKER_COLUMN_PATTERN_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_TEXT_PICKER_TEXT_PICKER_COLUMN_PATTERN_H
18 
19 #include <optional>
20 
21 #include "core/components/common/properties/color.h"
22 #include "core/components/picker/picker_theme.h"
23 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
24 #include "core/components_ng/pattern/picker/picker_type_define.h"
25 #include "core/components_ng/pattern/text/text_layout_property.h"
26 #include "core/components_ng/pattern/text_picker/textpicker_accessibility_property.h"
27 #include "core/components_ng/pattern/text_picker/textpicker_event_hub.h"
28 #include "core/components_ng/pattern/text_picker/textpicker_layout_algorithm.h"
29 #include "core/components_ng/pattern/text_picker/textpicker_layout_property.h"
30 #include "core/components_ng/pattern/text_picker/textpicker_overscroll.h"
31 #include "core/components_ng/pattern/text_picker/textpicker_paint_method.h"
32 #include "core/components_ng/pattern/text_picker/toss_animation_controller.h"
33 
34 namespace OHOS::Ace::NG {
35 using EventCallback = std::function<void(bool)>;
36 using ColumnChangeCallback = std::function<void(const RefPtr<FrameNode>&, bool, uint32_t, bool)>;
37 
38 struct TextProperties {
39     Dimension upFontSize;
40     Dimension fontSize;
41     Dimension downFontSize;
42     Color upColor;
43     Color currentColor;
44     Color downColor;
45     FontWeight upFontWeight;
46     FontWeight fontWeight;
47     FontWeight downFontWeight;
48 };
49 
50 struct TextPickerOptionProperty {
51     float height = 0.0f;
52     float fontheight = 0.0f;
53     float prevDistance = 0.0f; // between the prev item and itself when scroll up
54     float nextDistance = 0.0f; // between the next item and itself when scroll down
55 };
56 
57 class EventParam : public virtual AceType {
58     DECLARE_ACE_TYPE(EventParam, AceType)
59 
60 public:
61     WeakPtr<FrameNode> instance;
62     int32_t itemIndex = 0;
63     int32_t itemTotalCounts = 0;
64 };
65 
66 enum class ScrollDirection {
67     UP = 0,
68     DOWN,
69 };
70 
71 enum class OptionIndex {
72     COLUMN_INDEX_0 = 0,
73     COLUMN_INDEX_1,
74     COLUMN_INDEX_2,
75     COLUMN_INDEX_3,
76     COLUMN_INDEX_4,
77     COLUMN_INDEX_5,
78     COLUMN_INDEX_6
79 };
80 
81 class TextPickerColumnPattern : public LinearLayoutPattern {
82     DECLARE_ACE_TYPE(TextPickerColumnPattern, LinearLayoutPattern);
83 
84 public:
TextPickerColumnPattern()85     TextPickerColumnPattern() : LinearLayoutPattern(true) {};
86 
87     ~TextPickerColumnPattern() override = default;
88 
IsAtomicNode()89     bool IsAtomicNode() const override
90     {
91         return true;
92     }
93 
CreateLayoutAlgorithm()94     RefPtr<LayoutAlgorithm> CreateLayoutAlgorithm() override
95     {
96         auto layoutAlgorithm = MakeRefPtr<TextPickerLayoutAlgorithm>();
97         if (algorithmOffset_.size() == 0) {
98             ResetAlgorithmOffset();
99         }
100         layoutAlgorithm->SetCurrentOffset(algorithmOffset_);
101         layoutAlgorithm->SetDefaultPickerItemHeight(defaultPickerItemHeight_);
102         return layoutAlgorithm;
103     }
104 
CreateLayoutProperty()105     RefPtr<LayoutProperty> CreateLayoutProperty() override
106     {
107         return MakeRefPtr<LinearLayoutProperty>(true);
108     }
109 
110     void FlushCurrentOptions(bool isDown = false, bool isUpateTextContentOnly = false, bool isDirectlyClear = false,
111         bool isUpdateAnimationProperties = false);
112 
113     void InitilaScorllEvent();
114 
115     void UpdateCurrentOffset(float offset);
116 
117     void UpdateColumnChildPosition(double offsetY);
118 
GetOverscroller()119     TextPickerOverscroller& GetOverscroller()
120     {
121         return overscroller_;
122     }
123 
124     bool CanMove(bool isDown) const;
125 
126     bool NotLoopOptions() const;
127 
128     bool InnerHandleScroll(bool isDown, bool isUpatePropertiesOnly = false, bool isUpdateAnimationProperties = false);
129 
SetDefaultPickerItemHeight(double defaultPickerItemHeight)130     void SetDefaultPickerItemHeight(double defaultPickerItemHeight)
131     {
132         defaultPickerItemHeight_ = defaultPickerItemHeight;
133     }
134 
135     uint32_t GetShowOptionCount() const;
136 
137     std::string GetSelectedObject(bool isColumnChange, int32_t status = 0) const;
138 
SetSelected(uint32_t value)139     void SetSelected(uint32_t value)
140     {
141         selectedIndex_ = value;
142     }
GetSelected()143     uint32_t GetSelected() const
144     {
145         return selectedIndex_;
146     }
147 
SetRange(const std::vector<std::string> & value)148     void SetRange(const std::vector<std::string>& value)
149     {
150         if (value.empty()) {
151             return;
152         }
153         range_ = value;
154     }
155 
GetRange()156     const std::vector<std::string>& GetRange() const
157     {
158         return range_;
159     }
160 
GetCurrentText()161     std::string GetCurrentText() const
162     {
163         return GetOption(GetCurrentIndex());
164     }
165 
GetCurrentIndex()166     uint32_t GetCurrentIndex() const
167     {
168         return currentIndex_;
169     }
SetCurrentIndex(uint32_t value)170     void SetCurrentIndex(uint32_t value)
171     {
172         if (value != currentIndex_) {
173             isIndexChanged_ = true;
174             currentIndex_ = value;
175         }
176     }
177 
GetOptionCount()178     uint32_t GetOptionCount() const
179     {
180         return options_.size();
181     }
182 
GetOption(uint32_t index)183     std::string GetOption(uint32_t index) const
184     {
185         if (index >= GetOptionCount()) {
186             return "";
187         }
188         return options_[index].text_;
189     }
190 
SetOptions(std::vector<NG::RangeContent> & value)191     void SetOptions(std::vector<NG::RangeContent>& value)
192     {
193         options_.clear();
194         for (auto& content : value) {
195             options_.emplace_back(content);
196         }
197     }
198 
ClearOptions()199     void ClearOptions()
200     {
201         options_.clear();
202     }
203 
SetColumnKind(int32_t kind)204     void SetColumnKind(int32_t kind)
205     {
206         columnkind_ = kind;
207     }
208 
GetCurrentOffset()209     float GetCurrentOffset() const
210     {
211         return deltaSize_;
212     }
213 
SetCurrentOffset(float deltaSize)214     void SetCurrentOffset(float deltaSize)
215     {
216         deltaSize_ = deltaSize;
217     }
218 
GetToss()219     const RefPtr<TextPickerTossAnimationController>& GetToss() const
220     {
221         return tossAnimationController_;
222     }
223 
HandleEventCallback(bool refresh)224     void HandleEventCallback(bool refresh)
225     {
226         if (EventCallback_) {
227             EventCallback_(refresh);
228         }
229     }
230 
GetEventCallback()231     const EventCallback& GetEventCallback() const
232     {
233         return EventCallback_;
234     }
235 
SetEventCallback(EventCallback && value)236     void SetEventCallback(EventCallback&& value)
237     {
238         EventCallback_ = value;
239     }
240 
HandleScrollStopEventCallback(bool refresh)241     void HandleScrollStopEventCallback(bool refresh)
242     {
243         if (scrollStopEventCallback_) {
244             scrollStopEventCallback_(refresh);
245         }
246     }
247 
GetScrollStopEventCallback()248     const EventCallback& GetScrollStopEventCallback() const
249     {
250         return scrollStopEventCallback_;
251     }
252 
SetScrollStopEventCallback(EventCallback && value)253     void SetScrollStopEventCallback(EventCallback&& value)
254     {
255         scrollStopEventCallback_ = value;
256     }
257 
SetLocalDownDistance(float value)258     void SetLocalDownDistance(float value)
259     {
260         localDownDistance_ = value;
261     }
262 
GetLocalDownDistance()263     float GetLocalDownDistance() const
264     {
265         return localDownDistance_;
266     }
267 
268     void UpdateToss(double offsetY);
269 
270     void TossStoped();
271 
272     void UpdateScrollDelta(double delta);
273 
CreateAccessibilityProperty()274     RefPtr<AccessibilityProperty> CreateAccessibilityProperty() override
275     {
276         return MakeRefPtr<TextPickerAccessibilityProperty>();
277     }
278 
SetChangeCallback(ColumnChangeCallback && value)279     void SetChangeCallback(ColumnChangeCallback&& value)
280     {
281         changeCallback_ = value;
282     }
283 
HandleChangeCallback(bool isAdd,bool needNotify)284     void HandleChangeCallback(bool isAdd, bool needNotify)
285     {
286         if (changeCallback_) {
287             changeCallback_(GetHost(), isAdd, GetCurrentIndex(), needNotify);
288         }
289     }
290 
GetHalfDisplayCounts()291     int32_t GetHalfDisplayCounts() const
292     {
293         return halfDisplayCounts_;
294     }
295 
GetOffset()296     double GetOffset() const
297     {
298         return offsetCurSet_;
299     }
300 
SetYLast(double value)301     void SetYLast(double value)
302     {
303         yLast_ = value;
304     }
305 
306     void TossAnimationStoped();
307 
308     void PlayResetAnimation();
309 
GetMidShiftDistance()310     std::vector<TextPickerOptionProperty> GetMidShiftDistance() const
311     {
312         return optionProperties_;
313     }
314 
SetMainVelocity(double mainVelocity)315     void SetMainVelocity(double mainVelocity)
316     {
317         mainVelocity_ = mainVelocity;
318     }
319 
GetMainVelocity()320     double GetMainVelocity() const
321     {
322         return mainVelocity_;
323     }
324 
SetTossStatus(bool status)325     void SetTossStatus(bool status)
326     {
327         isTossStatus_ = status;
328         if (!status && NotLoopOptions() && !pressed_ && !isReboundInProgress_ && overscroller_.IsOverScroll()) {
329             // Start rebound animation when toss stoped
330             CreateReboundAnimation(overscroller_.GetOverScroll(), 0.0);
331             HandleScrollStopEventCallback(true);
332         }
333     }
334 
GetTossStatus()335     bool GetTossStatus() const
336     {
337         return isTossStatus_;
338     }
339 
SetYOffset(double value)340     void SetYOffset(double value)
341     {
342         yOffset_ = value;
343     }
344 
GetTouchBreakStatus()345     bool GetTouchBreakStatus() const
346     {
347         return touchBreak_;
348     }
349 
NeedResetOptionPropertyHeight(bool needOptionPropertyHeightReset)350     void NeedResetOptionPropertyHeight(bool needOptionPropertyHeightReset)
351     {
352         needOptionPropertyHeightReset_ = needOptionPropertyHeightReset;
353     }
354 
isHover()355     bool isHover() const
356     {
357         return isHover_;
358     }
359 
360     int32_t GetOverScrollDeltaIndex() const;
361     void SetCanLoop(bool isLoop);
362 
SetScrollDirection(bool isDown)363     void SetScrollDirection(bool isDown)
364     {
365         isDownScroll_ = isDown;
366     }
367 
IsDownScroll()368     bool IsDownScroll()
369     {
370         return isDownScroll_;
371     }
372     void ResetOptionPropertyHeight();
373     void ResetTotalDelta();
374 
375 private:
376     void OnModifyDone() override;
377     void OnAttachToFrameNode() override;
378     bool OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config) override;
379 
380     bool OnKeyEvent(const KeyEvent& event);
381     bool HandleDirectionKey(KeyCode code);
382 
383     void InitPanEvent(const RefPtr<GestureEventHub>& gestureHub);
384     void HandleDragStart(const GestureEvent& event);
385     void HandleDragMove(const GestureEvent& event);
386     void HandleDragEnd();
387     void CreateAnimation();
388     void CreateAnimation(double from, double to);
389     void CreateReboundAnimation(double from, double to);
390     void ScrollOption(double delta);
391     std::vector<TextPickerOptionProperty> optionProperties_;
392     std::vector<int32_t> algorithmOffset_;
393     void ResetAlgorithmOffset();
394     void CalcAlgorithmOffset(double distancePercent);
395     void SetOptionShiftDistance();
396     double GetShiftDistanceForLandscape(int32_t index, ScrollDirection dir);
397     double GetShiftDistance(int32_t index, ScrollDirection dir);
398     double GetSelectedDistance(int32_t index, int32_t nextIndex, ScrollDirection dir);
399     double GetUpCandidateDistance(int32_t index, int32_t nextIndex, ScrollDirection dir);
400     double GetDownCandidateDistance(int32_t index, int32_t nextIndex, ScrollDirection dir);
401     void OnTouchDown();
402     void OnTouchUp();
403     void ParseTouchListener();
404     void ParseMouseEvent();
405     void InitMouseAndPressEvent();
406     void HandleMouseEvent(bool isHover);
407     void SetButtonBackgroundColor(const Color& pressColor);
408     void PlayPressAnimation(const Color& pressColor);
409     void FlushCurrentTextOptions(const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty,
410         bool isUpateTextContentOnly, bool isDirectlyClear);
411     void FlushCurrentImageOptions();
412     void FlushCurrentMixtureOptions(
413         const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty, bool isUpateTextContentOnly);
414     void UpdatePickerTextProperties(const RefPtr<TextLayoutProperty>& textLayoutProperty,
415         const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty, uint32_t currentIndex, uint32_t middleIndex,
416         uint32_t showCount);
417     void UpdateSelectedTextProperties(const RefPtr<PickerTheme>& pickerTheme,
418         const RefPtr<TextLayoutProperty>& textLayoutProperty,
419         const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty);
420     void UpdateCandidateTextProperties(const RefPtr<PickerTheme>& pickerTheme,
421         const RefPtr<TextLayoutProperty>& textLayoutProperty,
422         const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty);
423     void UpdateDisappearTextProperties(const RefPtr<PickerTheme>& pickerTheme,
424         const RefPtr<TextLayoutProperty>& textLayoutProperty,
425         const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty);
426     void AddAnimationTextProperties(uint32_t currentIndex, const RefPtr<TextLayoutProperty>& textLayoutProperty);
427     void UpdateTextPropertiesLinear(bool isDown, double scale);
428     void TextPropertiesLinearAnimation(const RefPtr<TextLayoutProperty>& textLayoutProperty, uint32_t index,
429         uint32_t showCount, bool isDown, double scale);
430     void FlushAnimationTextProperties(bool isDown);
431     Dimension LinearFontSize(const Dimension& startFontSize, const Dimension& endFontSize, double percent);
432     void ClearCurrentTextOptions(const RefPtr<TextPickerLayoutProperty>& textPickerLayoutProperty,
433         bool isUpateTextContentOnly, bool isDirectlyClear);
434 
435     RefPtr<TextPickerLayoutProperty> GetParentLayout() const;
436     RefPtr<TouchEventImpl> CreateItemTouchEventListener();
437     void OnAroundButtonClick(RefPtr<EventParam> param);
438     void OnMiddleButtonTouchDown();
439     void OnMiddleButtonTouchMove();
440     void OnMiddleButtonTouchUp();
441     int32_t GetMiddleButtonIndex();
442 
443     bool touchEventInit_ = false;
444     RefPtr<InputEvent> CreateMouseHoverEventListener(RefPtr<EventParam> param);
445     RefPtr<ClickEvent> CreateItemClickEventListener(RefPtr<EventParam> param);
446     void SetAccessibilityAction();
447 
448     void InitTextFontFamily();
449     bool SpringCurveTailMoveProcess(bool useRebound, double& dragDelta);
450     void SpringCurveTailEndProcess(bool useRebound, bool stopMove);
451     void UpdateTextAccessibilityProperty(RefPtr<FrameNode>& textNode, int32_t virtualIndex,
452         std::list<RefPtr<UINode>>::iterator& iter, bool virtualIndexValidate);
453 
454     float localDownDistance_ = 0.0f;
455     Color pressColor_;
456     Color hoverColor_;
457     EventCallback EventCallback_;
458     EventCallback scrollStopEventCallback_;
459     RefPtr<ClickEvent> clickEventListener_;
460     bool enabled_ = true;
461     int32_t focusKeyID_ = 0;
462     RefPtr<TouchEventImpl> touchListener_;
463     bool isPress_ = false;
464     bool isHover_ = false;
465     RefPtr<InputEvent> mouseEvent_;
466     double defaultPickerItemHeight_ = 0.0;
467     uint32_t selectedIndex_ = 0;
468     std::string selectedValue_;
469     std::vector<std::string> range_ { "" };
470     uint32_t currentIndex_ = 0;
471     std::vector<NG::RangeContent> options_;
472     int32_t columnkind_ = 0;
473     int32_t currentChildIndex_ = 0;
474     float deltaSize_ = 0.0f;
475     double totalDragDelta_ = 0.0;
476     double yLast_ = 0.0;
477     double yOffset_ = 0.0;
478     double jumpInterval_ = 0.0;
479     Size optionSize_;
480     Dimension fixHeight_;
481     bool isIndexChanged_ = false;
482 
483     RefPtr<PanEvent> panEvent_;
484     bool pressed_ = false;
485     double scrollDelta_ = 0.0;
486     bool animationCreated_ = false;
487     RefPtr<TextPickerTossAnimationController> tossAnimationController_ =
488         AceType::MakeRefPtr<TextPickerTossAnimationController>();
489     RefPtr<NodeAnimatablePropertyFloat> scrollProperty_;
490     RefPtr<NodeAnimatablePropertyFloat> aroundClickProperty_;
491     std::shared_ptr<AnimationUtils::Animation> animation_;
492     std::shared_ptr<AnimationUtils::Animation> reboundAnimation_;
493     std::vector<TextProperties> animationProperties_;
494     float dividerSpacing_ = 0.0f;
495     float gradientHeight_ = 0.0f;
496     bool isReboundInProgress_ = false;
497     TextPickerOverscroller overscroller_;
498     ColumnChangeCallback changeCallback_;
499 
500     int32_t halfDisplayCounts_ = 0;
501 
502     double mainVelocity_ = 0.0;
503     float offsetCurSet_ = 0.0f;
504     float distancePercent_ = 0.0f;
505     bool isTossStatus_ = false;
506     bool clickBreak_ = false;
507     bool touchBreak_ = false;
508     bool animationBreak_ = false;
509     bool needOptionPropertyHeightReset_ = false;
510     bool isLoop_ = true;
511     bool isDownScroll_ = false;
512 
513     bool hasAppCustomFont_ = false;
514     bool hasUserDefinedDisappearFontFamily_ = false;
515     bool hasUserDefinedNormalFontFamily_ = false;
516     bool hasUserDefinedSelectedFontFamily_ = false;
517 
518     ACE_DISALLOW_COPY_AND_MOVE(TextPickerColumnPattern);
519 };
520 } // namespace OHOS::Ace::NG
521 
522 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_TEXT_PICKER_TEXT_PICKER_COLUMN_PATTERN_H
523