1 /*
2  * Copyright (c) 2021 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_INDEXER_RENDER_INDEXER_CIRCLE_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_INDEXER_RENDER_INDEXER_CIRCLE_H
18 
19 #include "core/animation/animator.h"
20 #include "core/animation/keyframe_animation.h"
21 #include "core/components/arc/render_arc.h"
22 #include "core/components/indexer/render_indexer.h"
23 
24 namespace OHOS::Ace {
25 
26 constexpr double INDEXER_HOT_RGN_RADIUS = 23.0;
27 constexpr int32_t CHANGE_FROM_CLICK = -1;
28 constexpr int32_t CHANGE_FROM_LIST = 0;
29 constexpr int32_t INDEXER_ANIMATION_DURATION = 300;
30 
31 enum class IndexerItemStatus { EXPAND, COLLAPSE, ANIMATION };
32 
33 class RenderIndexerCircle : public RenderIndexer {
34     DECLARE_ACE_TYPE(RenderIndexerCircle, RenderIndexer);
35 
36 public:
37     RenderIndexerCircle() = default;
38     ~RenderIndexerCircle() override = default;
39     static RefPtr<RenderNode> Create();
40     void Update(const RefPtr<Component>& component) override;
41     void PerformLayout() override;
42     bool TouchTest(const Point& globalPoint, const Point& parentLocalPoint, const TouchRestrict& touchRestrict,
43         TouchTestResult& result) override;
44     void HandleTouchDown(const TouchEventInfo& info) override;
45     void HandleTouchUp(const TouchEventInfo& info) override;
46     void HandleTouchMove(const TouchEventInfo& info) override;
47     int32_t GetTouchedItemIndex(const Offset& touchPosition) override;
48     void InitIndexTable() override;
49     void HandleListMoveItems(int32_t curHeadIndex) override;
50     void UpdateCurrentSectionItem(int32_t curSection) override;
51     void BeginFocusAnimation(int32_t originIndex, int32_t targetIndex) override;
52     bool RotationTest(const RotationEvent& event) override;
53     bool NeedProcess(const RefPtr<RenderNode>& item) const override;
54     bool NeedRotation() const override;
55 
56     bool IsValidArc();
57     bool IsValidIndicatorBox();
58     bool IsValidBubbleBox() override;
IsItemColorEnabled()59     bool IsItemColorEnabled() const
60     {
61         return itemColorEnabled_;
62     }
63 
GetIndexerStatus()64     IndexerItemStatus GetIndexerStatus()
65     {
66         return curStatus_;
67     }
68 
69 protected:
70     bool NeedChangeIndexer(int32_t index);
71     bool ChangeLanguage(int32_t index);
72     void HandleRotation(double value);
73     void CollapseItems();
74     void ExpandItems();
75 
76     // marker item focused
77     void SetItemsFocused(int32_t index, bool force = false, bool smooth = true);
78 
79     // calculate index in items by position index in circle
80     int32_t GetActualItemIndex(int32_t positionIndex);
81 
82     // calculate position index in circle by index in items
83     int32_t GetPositionItemIndex(int32_t index);
84 
85     // identify indexer status
86     IndexerItemStatus nextStatus_ = IndexerItemStatus::EXPAND;
87     IndexerItemStatus curStatus_ = IndexerItemStatus::EXPAND;
88 
89     RefPtr<Animator> collapseController_;       // control expand or collapse animation
90     RefPtr<Animator> focusController_;          // control click to change focus animation
91     RefPtr<Animator> collapseScrollController_; // control focus change when scroll
92 
93     int32_t curItemType_ = 0;
94     int32_t itemMaxCount_ = INDEXER_ITEM_MAX_COUNT; // the max count of the items while in expand mode
95     int32_t currentCount_ = INDEXER_ITEM_MAX_COUNT; // current shown item nums exclude collapse item
96     double arcHeadOffset_ = 0.0;    // the offset of the arc, item # to the original position, in radians
97     double arcMaxLen_ = M_PI * 2.0; // the max length of the arc, in radians
98 
99 private:
100     void InitBubbleBox(const Size& size);
101     void InitIndicatorBox();
102     void ResetItemsPosition();
103     void BuildArcAnimation();
104     void BeginArcAnimation(bool collapse);
105     void BeginCollapseScrollAnimation(double originOffset, double targetOffset);
106     void HandleCollapseScrollAnimationStop();
107     void HandleArcAnimationStart();
108     void HandleArcAnimationStop();
109     void InitFocusInterpolator(double origin, double target, int32_t originIndex, int32_t targetIndex);
110     void InitCollapseScrollInterpolator(double origin, double target);
111     void SetIndexerItemStatus(bool inAnimation, int32_t originIndex, int32_t targetIndex);
112     void UpdateItemBackground(double value, int32_t originIndex, int32_t targetIndex);
113     void UpdateItemBackground(double value, int32_t index);
114     void UpdateArcTail(double value);
115     int32_t GetNearestItem(const Offset& position, bool move);
116     int32_t GetNearestItem(double position);
117     double GetPositionAngle(const Offset& position);
118     bool CollapseItemHitTest(const Offset& position);
119     void FireIndexerChangeEvent() const;
120 
121     // update all item visible status with range from head to tail
122     void SetItemsVisible(double arcHead, double arcTail);
123 
124     // update specific item's position
125     void SetItemPosition(const RefPtr<RenderNode>& item, int32_t positionIndex);
126     void SetItemPosition(const RefPtr<RenderNode>& item, double angle);
127 
128     // update all items's position by arc offset
129     void UpdateItemsPosition(double arcOffset);
130 
131     // update collapse item position
132     void SetCollapseItemPosition(double position);
133 
134     // handle touch down event when arc is collapsed
135     void TouchOnCollapseArc(const Offset& position);
136 
137     // rotate items for animation
138     void RotateItems(double arcOffset);
139 
140     std::function<void(const std::string&)> indexerChangeEvent_;
141 
142     double outerRadius_ = 0.0;                   // the outer radius of the arc, the same as half of the layout width
143     RefPtr<RenderArc> arc_;                      // reference of the arc render node
144     RefPtr<RenderBox> indicatorBox_;             // reference of the indicator box render node
145     double arcHeadPosition_ = INDEXER_ARC_BEGIN; // the begin position of the arc, in radians
146     double arcTailPosition_ = 2 * M_PI;          // the tail position of the arc, in radians
147     int32_t collapseItemCount_ = INDEXER_COLLAPSE_ITEM_COUNT; // the max count of the items while in collapse mode
148     double collapseItemPosition_ = INDEXER_ARC_BEGIN;         // position of the collapse item, in radians
149     double hotRgnSize_ = INDEXER_HOT_RGN_RADIUS;              // radius for item clicking
150     double rotationStepValue_ = 0.0;
151     double perItemExtent_ = 2.0 * M_PI / itemMaxCount_;
152 
153     bool touching_ = false; // whether the item is in touching
154     bool itemColorEnabled_ = true;
155     bool hasCollapseItem_ = false;
156 };
157 
158 } // namespace OHOS::Ace
159 
160 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_INDEXER_RENDER_INDEXER_CIRCLE_H
161