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_SELECT_SELECT_PATTERN_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SELECT_SELECT_PATTERN_H
18 
19 #include <cstdint>
20 #include <optional>
21 
22 #include "base/memory/referenced.h"
23 #include "base/utils/utils.h"
24 #include "core/components/common/properties/color.h"
25 #include "core/components/select/select_theme.h"
26 #include "core/components/theme/icon_theme.h"
27 #include "core/components_ng/base/frame_node.h"
28 #include "core/components_ng/event/event_hub.h"
29 #include "core/components_ng/pattern/option/option_paint_method.h"
30 #include "core/components_ng/pattern/option/option_paint_property.h"
31 #include "core/components_ng/pattern/pattern.h"
32 #include "core/components_ng/pattern/select/select_accessibility_property.h"
33 #include "core/components_ng/pattern/select/select_event_hub.h"
34 #include "core/components_ng/pattern/select/select_layout_algorithm.h"
35 #include "core/components_ng/pattern/select/select_model.h"
36 #include "core/components_ng/pattern/text/text_layout_property.h"
37 #include "core/components_ng/pattern/select/select_model_ng.h"
38 
39 namespace OHOS::Ace::NG {
40 class InspectorFilter;
41 
42 class SelectPattern : public Pattern {
43     DECLARE_ACE_TYPE(SelectPattern, Pattern);
44 
45 public:
46     SelectPattern() = default;
47     ~SelectPattern() override = default;
48 
IsAtomicNode()49     bool IsAtomicNode() const override
50     {
51         return false;
52     }
53 
CreateAccessibilityProperty()54     RefPtr<AccessibilityProperty> CreateAccessibilityProperty() override
55     {
56         return MakeRefPtr<SelectAccessibilityProperty>();
57     }
58 
CreateLayoutAlgorithm()59     RefPtr<LayoutAlgorithm> CreateLayoutAlgorithm() override
60     {
61         return MakeRefPtr<SelectLayoutAlgorithm>();
62     }
63 
CreateEventHub()64     RefPtr<EventHub> CreateEventHub() override
65     {
66         return MakeRefPtr<SelectEventHub>();
67     }
68 
69     void BuildChild();
70 
SetMenuNode(const RefPtr<FrameNode> & menuWrapper)71     void SetMenuNode(const RefPtr<FrameNode>& menuWrapper)
72     {
73         menuWrapper_ = menuWrapper;
74     }
75 
GetMenuWrapper()76     const RefPtr<FrameNode>& GetMenuWrapper() const
77     {
78         return menuWrapper_;
79     }
80 
GetMenuNode()81     RefPtr<FrameNode> GetMenuNode() const
82     {
83         CHECK_NULL_RETURN(menuWrapper_, nullptr);
84         return DynamicCast<FrameNode>(menuWrapper_->GetChildAtIndex(0));
85     }
86 
SetSelectSize(const SizeF & selectSize)87     void SetSelectSize(const SizeF& selectSize)
88     {
89         selectSize_ = selectSize;
90     }
GetSelectSize()91     SizeF GetSelectSize() const
92     {
93         return selectSize_;
94     }
95 
96     void AddOptionNode(const RefPtr<FrameNode>& option);
97 
ClearOptions()98     void ClearOptions()
99     {
100         options_.clear();
101     }
102 
InitSelected()103     void InitSelected()
104     {
105         selected_ = -1;
106     }
107 
GetSelected()108     int32_t GetSelected() const
109     {
110         return selected_;
111     }
112 
113     void SetSelected(int32_t index);
114 
115     // set properties of text node
116     void SetValue(const std::string& value);
117     void SetFontSize(const Dimension& value);
118     void SetItalicFontStyle(const Ace::FontStyle& value);
119     void SetFontWeight(const FontWeight& value);
120     void SetFontFamily(const std::vector<std::string>& value);
121     void SetFontColor(const Color& color);
122 
123     // set props of option nodes
124     void SetOptionBgColor(const Color& color);
125     void SetOptionFontSize(const Dimension& value);
126     void SetOptionItalicFontStyle(const Ace::FontStyle& value);
127     void SetOptionFontWeight(const FontWeight& value);
128     void SetOptionFontFamily(const std::vector<std::string>& value);
129     void SetOptionFontColor(const Color& color);
130 
131     // set props of option node when selected
132     void SetSelectedOptionBgColor(const Color& color);
133     void SetSelectedOptionFontSize(const Dimension& value);
134     void SetSelectedOptionItalicFontStyle(const Ace::FontStyle& value);
135     void SetSelectedOptionFontWeight(const FontWeight& value);
136     void SetSelectedOptionFontFamily(const std::vector<std::string>& value);
137     void SetSelectedOptionFontColor(const Color& color);
138 
139     // set props of menu background
140     void SetMenuBackgroundColor(const Color& color);
141     void SetMenuBackgroundBlurStyle(const BlurStyleOption& blurStyle);
142 
143     // Get functions for unit tests
144     const std::vector<RefPtr<FrameNode>>& GetOptions();
145 
GetFocusPattern()146     FocusPattern GetFocusPattern() const override
147     {
148         return { FocusType::NODE, true, FocusStyleType::INNER_BORDER };
149     }
150 
151     // update selected option props
152     void UpdateSelectedProps(int32_t index);
153 
154     void UpdateLastSelectedProps(int32_t index);
155 
156     // reset options props when selected index is -1
157     void ResetOptionProps();
158 
SetBgBlendColor(const Color & color)159     void SetBgBlendColor(const Color& color)
160     {
161         bgBlendColor_ = color;
162     }
163 
GetBgBlendColor()164     Color GetBgBlendColor() const
165     {
166         return bgBlendColor_;
167     }
168 
SetIsHover(bool isHover)169     void SetIsHover(bool isHover)
170     {
171         isHover_ = isHover;
172     }
173 
IsHover()174     bool IsHover() const
175     {
176         return isHover_;
177     }
178 
179     void SetItemSelected(int index, const std::string& value);
180     void PlayBgColorAnimation(bool isHoverChange = true);
181     void SetSpace(const Dimension& value);
182     void SetArrowPosition(const ArrowPosition value);
183     void SetMenuAlign(const MenuAlign& menuAlign);
184 
185     std::string GetValue();
186     std::string ProvideRestoreInfo() override;
187     void OnRestoreInfo(const std::string& restoreInfo) override;
188     void OnColorConfigurationUpdate() override;
189     void OnLanguageConfigurationUpdate() override;
190 
191     Dimension GetFontSize();
192     void SetSelectDefaultTheme();
193     void SetOptionWidth(const Dimension& value);
194     void SetOptionHeight(const Dimension& value);
195     void SetOptionWidthFitTrigger(bool isFitTrigger);
196     void ShowSelectMenu();
197     void SetHasOptionWidth(bool hasOptionWidth);
198     void SetControlSize(const ControlSize& controlSize);
199     void SetDivider(const SelectDivider& divider);
200     ControlSize GetControlSize();
201     void SetLayoutDirection(TextDirection value);
202 
203 private:
204     void OnAttachToFrameNode() override;
205     void OnModifyDone() override;
206     void OnAfterModifyDone() override;
207     bool OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config) override;
208 
HasRowNode()209     bool HasRowNode() const
210     {
211         return rowId_.has_value();
212     }
213 
HasTextNode()214     bool HasTextNode() const
215     {
216         return textId_.has_value();
217     }
218 
HasSpinnerNode()219     bool HasSpinnerNode() const
220     {
221         return spinnerId_.has_value();
222     }
223 
GetRowId()224     int32_t GetRowId()
225     {
226         if (!rowId_.has_value()) {
227             rowId_ = ElementRegister::GetInstance()->MakeUniqueId();
228         }
229         return rowId_.value();
230     }
231 
GetTextId()232     int32_t GetTextId()
233     {
234         if (!textId_.has_value()) {
235             textId_ = ElementRegister::GetInstance()->MakeUniqueId();
236         }
237         return textId_.value();
238     }
239 
GetSpinnerId()240     int32_t GetSpinnerId()
241     {
242         if (!spinnerId_.has_value()) {
243             spinnerId_ = ElementRegister::GetInstance()->MakeUniqueId();
244         }
245         return spinnerId_.value();
246     }
247 
248     // change background color when pressed
249     void RegisterOnPress();
250     // change background color when hovered
251     void RegisterOnHover();
252     // add click event to show menu
253     void RegisterOnClick();
254 
255     void RegisterOnKeyEvent();
256     bool OnKeyEvent(const KeyEvent& event);
257 
258     // callback when an option is selected
259     void CreateSelectedCallback();
260     // change text and spinner color if disabled
261     void SetDisabledStyle();
262 
263     // update text to selected option's text
264     void UpdateText(int32_t index);
265 
266     void InitTextProps(const RefPtr<TextLayoutProperty>& textProps, const RefPtr<SelectTheme>& theme);
267     void InitSpinner(
268         const RefPtr<FrameNode>& spinner, const RefPtr<IconTheme>& iconTheme, const RefPtr<SelectTheme>& selectTheme);
269     void InitSpinner(const RefPtr<FrameNode>& spinner, const RefPtr<SelectTheme>& selectTheme);
270     void UpdateOptionsWidth(float selectWidth);
271     void ResetParams();
272 
273     std::vector<RefPtr<FrameNode>> options_;
274     RefPtr<FrameNode> menuWrapper_ = nullptr;
275     RefPtr<FrameNode> text_ = nullptr;
276     RefPtr<FrameNode> spinner_ = nullptr;
277     SizeF selectSize_;
278 
279     // index of selected option
280     int32_t selected_ = -1;
281     // props when selected
282     struct OptionFont {
283         // text style when selected
284         std::optional<Dimension> FontSize;
285         std::optional<Ace::FontStyle> FontStyle;
286         std::optional<FontWeight> FontWeight;
287         std::optional<std::vector<std::string>> FontFamily;
288         std::optional<Color> FontColor;
289     };
290     OptionFont selectedFont_;
291     std::optional<Color> selectedBgColor_;
292     OptionFont optionFont_;
293     std::optional<Color> optionBgColor_;
294 
295     void ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const override;
296     void ToJsonArrowAndText(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const;
297     void ToJsonOptionAlign(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const;
298     void ToJsonMenuBackgroundStyle(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const;
299     void ToJsonDivider(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const;
300     // XTS inspector helper functions
301     std::string InspectorGetOptions() const;
302     std::string InspectorGetSelectedFont() const;
303 
304     std::optional<int32_t> rowId_;
305     std::optional<int32_t> textId_;
306     std::optional<int32_t> spinnerId_;
307 
308     Color bgBlendColor_ = Color::TRANSPARENT;
309     bool isHover_ = false;
310     bool isSelected_ = false;
311     MenuAlign menuAlign_;
312     std::string selectValue_;
313     bool isFitTrigger_ = false;
314     Color selectDefaultBgColor_ = Color::TRANSPARENT;
315     ControlSize controlSize_ = ControlSize::NORMAL;
316     ACE_DISALLOW_COPY_AND_MOVE(SelectPattern);
317 };
318 
319 } // namespace OHOS::Ace::NG
320 
321 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SELECT_SELECT_PATTERN_H
322