1 /*
2  * Copyright (c) 2022 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 #include "bridge/declarative_frontend/jsview/models/search_model_impl.h"
17 
18 #include <utility>
19 
20 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
21 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
22 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
23 #include "bridge/declarative_frontend/view_stack_processor.h"
24 
25 namespace OHOS::Ace::Framework {
26 
27 namespace {
28 const TextInputAction INPUT_TEXTINPUTACTION_VALUE_DEFAULT = TextInputAction::UNSPECIFIED;
29 const std::vector<std::string> INPUT_FONT_FAMILY_VALUE = {
30     "sans-serif",
31 };
32 const std::vector<TextAlign> TEXT_ALIGNS = { TextAlign::START, TextAlign::CENTER, TextAlign::END };
33 Radius defaultRadius;
34 constexpr Dimension BOX_HOVER_RADIUS = 18.0_vp;
35 bool isPaddingChanged;
36 } // namespace
37 
Create(const std::optional<std::string> & value,const std::optional<std::string> & placeholder,const std::optional<std::string> & icon)38 RefPtr<TextFieldControllerBase> SearchModelImpl::Create(const std::optional<std::string>& value,
39     const std::optional<std::string>& placeholder, const std::optional<std::string>& icon)
40 {
41     auto searchComponent = AceType::MakeRefPtr<OHOS::Ace::SearchComponent>();
42     ViewStackProcessor::GetInstance()->ClaimElementId(searchComponent);
43     ViewStackProcessor::GetInstance()->Push(searchComponent);
44     auto textFieldComponent = AceType::MakeRefPtr<OHOS::Ace::TextFieldComponent>();
45     auto textFieldTheme = JSViewAbstract::GetTheme<TextFieldTheme>();
46     auto searchTheme = JSViewAbstract::GetTheme<SearchTheme>();
47     InitializeComponent(searchComponent, textFieldComponent, searchTheme, textFieldTheme);
48     PrepareSpecializedComponent(searchComponent, textFieldComponent);
49     if (value.has_value()) {
50         textFieldComponent->SetValue(value.value());
51     }
52     if (placeholder.has_value()) {
53         textFieldComponent->SetPlaceholder(placeholder.value());
54     }
55     if (icon.has_value()) {
56         textFieldComponent->SetIconImage(icon.value());
57     }
58     return textFieldComponent->GetTextFieldController();
59 }
60 
SetSearchButton(const std::string & text)61 void SearchModelImpl::SetSearchButton(const std::string& text)
62 {
63     auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
64     auto searchComponent = AceType::DynamicCast<SearchComponent>(component);
65     if (!searchComponent) {
66         LOGE("component error");
67         return;
68     }
69     searchComponent->SetSearchText(text);
70 }
71 
SetPlaceholderColor(const Color & color)72 void SearchModelImpl::SetPlaceholderColor(const Color& color)
73 {
74     auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
75     auto searchComponent = AceType::DynamicCast<SearchComponent>(component);
76     if (!searchComponent) {
77         LOGE("search component error");
78         return;
79     }
80     auto childComponent = searchComponent->GetChild();
81     if (!childComponent) {
82         LOGE("component error");
83         return;
84     }
85     auto textFieldComponent = AceType::DynamicCast<TextFieldComponent>(childComponent);
86     if (!textFieldComponent) {
87         LOGE("text component error");
88         return;
89     }
90     textFieldComponent->SetPlaceholderColor(color);
91     textFieldComponent->SetFocusPlaceholderColor(color);
92 }
93 
SetPlaceholderFont(const Font & font)94 void SearchModelImpl::SetPlaceholderFont(const Font& font)
95 {
96     auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
97     auto searchComponent = AceType::DynamicCast<SearchComponent>(component);
98     if (!searchComponent) {
99         LOGE("search component error");
100         return;
101     }
102     auto childComponent = searchComponent->GetChild();
103     if (!childComponent) {
104         LOGE("component error");
105         return;
106     }
107     auto textFieldComponent = AceType::DynamicCast<TextFieldComponent>(childComponent);
108     if (!textFieldComponent) {
109         LOGE("text component error");
110         return;
111     }
112     TextStyle textStyle = searchComponent->GetPlaceHoldStyle();
113     if (font.fontSize && font.fontSize->IsNonNegative()) {
114         textStyle.SetFontSize(font.fontSize.value());
115     }
116     if (font.fontWeight) {
117         textStyle.SetFontWeight(font.fontWeight.value());
118     }
119     if (font.fontStyle) {
120         textStyle.SetFontStyle(font.fontStyle.value());
121     }
122     if (!font.fontFamilies.empty()) {
123         textStyle.SetFontFamilies(font.fontFamilies);
124     }
125     textFieldComponent->SetPlaceHoldStyle(textStyle);
126 }
127 
SetTextFont(const Font & font)128 void SearchModelImpl::SetTextFont(const Font& font)
129 {
130     auto component = ViewStackProcessor::GetInstance()->GetMainComponent();
131     auto searchComponent = AceType::DynamicCast<SearchComponent>(component);
132     if (!searchComponent) {
133         LOGE("search component error");
134         return;
135     }
136     auto childComponent = searchComponent->GetChild();
137     if (!childComponent) {
138         LOGE("component error");
139         return;
140     }
141     auto textFieldComponent = AceType::DynamicCast<TextFieldComponent>(childComponent);
142     if (!textFieldComponent) {
143         LOGE("text component error");
144         return;
145     }
146     TextStyle textStyle = searchComponent->GetEditingStyle();
147     if (font.fontSize && font.fontSize->IsNonNegative()) {
148         textStyle.SetFontSize(font.fontSize.value());
149     }
150     if (font.fontWeight) {
151         textStyle.SetFontWeight(font.fontWeight.value());
152     }
153     if (font.fontStyle) {
154         textStyle.SetFontStyle(font.fontStyle.value());
155     }
156     if (!font.fontFamilies.empty()) {
157         textStyle.SetFontFamilies(font.fontFamilies);
158     }
159     textFieldComponent->SetEditingStyle(textStyle);
160 }
161 
SetTextAlign(const TextAlign & textAlign)162 void SearchModelImpl::SetTextAlign(const TextAlign& textAlign)
163 {
164     auto* stack = ViewStackProcessor::GetInstance();
165     auto component = AceType::DynamicCast<SearchComponent>(stack->GetMainComponent());
166     CHECK_NULL_VOID(component);
167     auto childComponent = component->GetChild();
168     CHECK_NULL_VOID(childComponent);
169     auto textFieldComponent = AceType::DynamicCast<TextFieldComponent>(childComponent);
170     CHECK_NULL_VOID(textFieldComponent);
171     textFieldComponent->SetTextAlign(textAlign);
172 }
173 
SetCopyOption(const CopyOptions & copyOptions)174 void SearchModelImpl::SetCopyOption(const CopyOptions& copyOptions)
175 {
176     JSViewSetProperty(&TextFieldComponent::SetCopyOption, copyOptions);
177 }
178 
SetFocusable(bool focusable)179 void SearchModelImpl::SetFocusable(bool focusable)
180 {
181     auto focusableComponent = ViewStackProcessor::GetInstance()->GetFocusableComponent();
182     CHECK_NULL_VOID(focusableComponent);
183     focusableComponent->SetFocusable(focusable);
184 }
185 
SetFocusNode(bool isFocusNode)186 void SearchModelImpl::SetFocusNode(bool isFocusNode)
187 {
188     auto focusableComponent = ViewStackProcessor::GetInstance()->GetFocusableComponent(false);
189     CHECK_NULL_VOID(focusableComponent);
190     focusableComponent->SetFocusNode(!isFocusNode);
191 }
192 
SetHeight(const Dimension & value)193 void SearchModelImpl::SetHeight(const Dimension& value)
194 {
195     auto stack = ViewStackProcessor::GetInstance();
196     auto searchComponent = AceType::DynamicCast<SearchComponent>(stack->GetMainComponent());
197     CHECK_NULL_VOID(searchComponent);
198     auto childComponent = searchComponent->GetChild();
199     CHECK_NULL_VOID(childComponent);
200     auto textFieldComponent = AceType::DynamicCast<TextFieldComponent>(childComponent);
201     CHECK_NULL_VOID(textFieldComponent);
202     textFieldComponent->SetHeight(value);
203 }
204 
SetBackBorder()205 void SearchModelImpl::SetBackBorder()
206 {
207     auto stack = ViewStackProcessor::GetInstance();
208     auto searchComponent = AceType::DynamicCast<SearchComponent>(stack->GetMainComponent());
209     CHECK_NULL_VOID(searchComponent);
210     auto childComponent = searchComponent->GetChild();
211     CHECK_NULL_VOID(childComponent);
212     auto textFieldComponent = AceType::DynamicCast<TextFieldComponent>(childComponent);
213     CHECK_NULL_VOID(textFieldComponent);
214     auto decoration = textFieldComponent->GetDecoration();
215     CHECK_NULL_VOID(decoration);
216     auto box = ViewStackProcessor::GetInstance()->GetBoxComponent();
217     auto boxDecoration = box->GetBackDecoration();
218     if (boxDecoration) {
219         decoration->SetBorder(boxDecoration->GetBorder());
220         Border border = {};
221         boxDecoration->SetBorder(border);
222     }
223     textFieldComponent->SetOriginBorder(decoration->GetBorder());
224 }
225 
SetOnSubmit(std::function<void (const std::string &)> && onSubmit)226 void SearchModelImpl::SetOnSubmit(std::function<void(const std::string&)>&& onSubmit)
227 {
228     auto* stack = ViewStackProcessor::GetInstance();
229     auto component = AceType::DynamicCast<SearchComponent>(stack->GetMainComponent());
230     CHECK_NULL_VOID(component);
231     component->SetOnSubmit(std::move(onSubmit));
232 }
233 
SetOnChange(std::function<void (const std::string &,PreviewText &)> && onChange)234 void SearchModelImpl::SetOnChange(std::function<void(const std::string&, PreviewText&)>&& onChange)
235 {
236     auto* stack = ViewStackProcessor::GetInstance();
237     auto component = AceType::DynamicCast<SearchComponent>(stack->GetMainComponent());
238     CHECK_NULL_VOID(component);
239     auto onChangeImpl = [onChange] (const std::string& value) {
240         if (!onChange) {
241             PreviewText previewText {};
242             onChange(value, previewText);
243         }
244     };
245     component->SetOnChange(std::move(onChangeImpl));
246 }
247 
SetOnCopy(std::function<void (const std::string &)> && func)248 void SearchModelImpl::SetOnCopy(std::function<void(const std::string&)>&& func)
249 {
250     auto* stack = ViewStackProcessor::GetInstance();
251     auto component = AceType::DynamicCast<SearchComponent>(stack->GetMainComponent());
252     CHECK_NULL_VOID(component);
253     auto childComponent = component->GetChild();
254     CHECK_NULL_VOID(childComponent);
255     auto textFieldComponent = AceType::DynamicCast<TextFieldComponent>(childComponent);
256     CHECK_NULL_VOID(textFieldComponent);
257     textFieldComponent->SetOnCopy(std::move(func));
258 }
259 
SetOnCut(std::function<void (const std::string &)> && func)260 void SearchModelImpl::SetOnCut(std::function<void(const std::string&)>&& func)
261 {
262     auto* stack = ViewStackProcessor::GetInstance();
263     auto component = AceType::DynamicCast<SearchComponent>(stack->GetMainComponent());
264     CHECK_NULL_VOID(component);
265     auto childComponent = component->GetChild();
266     CHECK_NULL_VOID(childComponent);
267     auto textFieldComponent = AceType::DynamicCast<TextFieldComponent>(childComponent);
268     CHECK_NULL_VOID(textFieldComponent);
269     textFieldComponent->SetOnCut(std::move(func));
270 }
271 
SetOnPaste(std::function<void (const std::string &)> && func)272 void SearchModelImpl::SetOnPaste(std::function<void(const std::string&)>&& func)
273 {
274     auto* stack = ViewStackProcessor::GetInstance();
275     auto component = AceType::DynamicCast<SearchComponent>(stack->GetMainComponent());
276     CHECK_NULL_VOID(component);
277     auto childComponent = component->GetChild();
278     CHECK_NULL_VOID(childComponent);
279     auto textFieldComponent = AceType::DynamicCast<TextFieldComponent>(childComponent);
280     CHECK_NULL_VOID(textFieldComponent);
281     textFieldComponent->SetOnPaste(std::move(func));
282 }
283 
InitializeDefaultValue(const RefPtr<BoxComponent> & boxComponent,const RefPtr<TextFieldComponent> & component,const RefPtr<TextFieldTheme> & theme)284 void SearchModelImpl::InitializeDefaultValue(const RefPtr<BoxComponent>& boxComponent,
285     const RefPtr<TextFieldComponent>& component, const RefPtr<TextFieldTheme>& theme)
286 {
287     component->SetAction(INPUT_TEXTINPUTACTION_VALUE_DEFAULT);
288     component->SetCursorColor(theme->GetCursorColor());
289     component->SetCursorRadius(theme->GetCursorRadius());
290     component->SetPlaceholderColor(theme->GetPlaceholderColor());
291 
292     component->SetFocusBgColor(theme->GetFocusBgColor());
293     component->SetFocusPlaceholderColor(theme->GetFocusPlaceholderColor());
294     component->SetFocusTextColor(theme->GetFocusTextColor());
295     component->SetBgColor(theme->GetBgColor());
296     component->SetTextColor(theme->GetTextColor());
297     component->SetSelectedColor(theme->GetSelectedColor());
298     component->SetHoverColor(theme->GetHoverColor());
299     component->SetPressColor(theme->GetPressColor());
300     component->SetNeedFade(theme->NeedFade());
301     component->SetShowEllipsis(theme->ShowEllipsis());
302 
303     TextStyle textStyle = component->GetTextStyle();
304     textStyle.SetTextColor(theme->GetTextColor());
305     textStyle.SetFontSize(theme->GetFontSize());
306     textStyle.SetFontWeight(theme->GetFontWeight());
307     textStyle.SetFontFamilies(INPUT_FONT_FAMILY_VALUE);
308     component->SetTextStyle(textStyle);
309 
310     component->SetCountTextStyle(theme->GetCountTextStyle());
311     component->SetOverCountStyle(theme->GetOverCountStyle());
312     component->SetCountTextStyleOuter(theme->GetCountTextStyleOuter());
313     component->SetOverCountStyleOuter(theme->GetOverCountStyleOuter());
314 
315     component->SetErrorTextStyle(theme->GetErrorTextStyle());
316     component->SetErrorSpacing(theme->GetErrorSpacing());
317     component->SetErrorIsInner(theme->GetErrorIsInner());
318     component->SetErrorBorderWidth(theme->GetErrorBorderWidth());
319     component->SetErrorBorderColor(theme->GetErrorBorderColor());
320 
321     RefPtr<Decoration> decoration = AceType::MakeRefPtr<Decoration>();
322     decoration->SetPadding(theme->GetPadding());
323     decoration->SetBackgroundColor(theme->GetBgColor());
324     decoration->SetBorderRadius(theme->GetBorderRadius());
325     defaultRadius = theme->GetBorderRadius();
326     const auto& boxDecoration = boxComponent->GetBackDecoration();
327     if (boxDecoration) {
328         decoration->SetImage(boxDecoration->GetImage());
329         decoration->SetGradient(boxDecoration->GetGradient());
330     }
331     component->SetDecoration(decoration);
332 
333     component->SetIconSize(theme->GetIconSize());
334     component->SetIconHotZoneSize(theme->GetIconHotZoneSize());
335 
336     boxComponent->SetPadding(theme->GetPadding());
337     component->SetHeight(theme->GetHeight());
338 }
339 
UpdateDecorationStyle(const RefPtr<BoxComponent> & boxComponent,const RefPtr<TextFieldComponent> & component,const Border & boxBorder,bool hasBoxRadius)340 void SearchModelImpl::UpdateDecorationStyle(const RefPtr<BoxComponent>& boxComponent,
341     const RefPtr<TextFieldComponent>& component, const Border& boxBorder, bool hasBoxRadius)
342 {
343     RefPtr<Decoration> decoration = component->GetDecoration();
344     if (!decoration) {
345         decoration = AceType::MakeRefPtr<Decoration>();
346     }
347     if (hasBoxRadius) {
348         decoration->SetBorder(boxBorder);
349     } else {
350         Border border = decoration->GetBorder();
351         border.SetLeftEdge(boxBorder.Left());
352         border.SetRightEdge(boxBorder.Right());
353         border.SetTopEdge(boxBorder.Top());
354         border.SetBottomEdge(boxBorder.Bottom());
355         border.SetBorderRadius(defaultRadius);
356         decoration->SetBorder(border);
357     }
358     component->SetOriginBorder(decoration->GetBorder());
359 
360     if (!boxComponent) {
361         return;
362     }
363     RefPtr<Decoration> boxDecoration = boxComponent->GetBackDecoration();
364     if (boxDecoration && (boxDecoration->GetImage() || boxDecoration->GetGradient().IsValid())) {
365         // clear box properties except background image and radius.
366         boxDecoration->SetBackgroundColor(Color::TRANSPARENT);
367         Border border;
368         if (!hasBoxRadius) {
369             border.SetBorderRadius(defaultRadius);
370         } else {
371             border.SetTopLeftRadius(boxBorder.TopLeftRadius());
372             border.SetTopRightRadius(boxBorder.TopRightRadius());
373             border.SetBottomLeftRadius(boxBorder.BottomLeftRadius());
374             border.SetBottomRightRadius(boxBorder.BottomRightRadius());
375         }
376         boxDecoration->SetBorder(border);
377     } else {
378         RefPtr<Decoration> backDecoration = AceType::MakeRefPtr<Decoration>();
379         backDecoration->SetBorderRadius(Radius(BOX_HOVER_RADIUS));
380         boxComponent->SetBackDecoration(backDecoration);
381     }
382     boxComponent->SetPadding(Edge());
383 }
384 
InitializeComponent(OHOS::Ace::RefPtr<OHOS::Ace::SearchComponent> & searchComponent,OHOS::Ace::RefPtr<OHOS::Ace::TextFieldComponent> & textFieldComponent,const OHOS::Ace::RefPtr<OHOS::Ace::SearchTheme> & searchTheme,const OHOS::Ace::RefPtr<OHOS::Ace::TextFieldTheme> & textFieldTheme)385 void SearchModelImpl::InitializeComponent(OHOS::Ace::RefPtr<OHOS::Ace::SearchComponent>& searchComponent,
386     OHOS::Ace::RefPtr<OHOS::Ace::TextFieldComponent>& textFieldComponent,
387     const OHOS::Ace::RefPtr<OHOS::Ace::SearchTheme>& searchTheme,
388     const OHOS::Ace::RefPtr<OHOS::Ace::TextFieldTheme>& textFieldTheme)
389 {
390     textFieldComponent->SetTextFieldController(AceType::MakeRefPtr<TextFieldController>());
391     textFieldComponent->SetTextEditController(AceType::MakeRefPtr<TextEditController>());
392     auto boxComponent = ViewStackProcessor::GetInstance()->GetBoxComponent();
393     InitializeDefaultValue(boxComponent, textFieldComponent, textFieldTheme);
394     boxComponent->SetBackDecoration(nullptr);
395     boxComponent->SetPadding(Edge());
396     textFieldComponent->SetIconSize(searchTheme->GetIconSize());
397     textFieldComponent->SetIconHotZoneSize(searchTheme->GetCloseIconHotZoneSize());
398     Edge decorationPadding;
399     Dimension leftPadding = searchTheme->GetLeftPadding();
400     Dimension rightPadding = searchTheme->GetRightPadding();
401     decorationPadding = Edge(rightPadding.Value(), 0.0, leftPadding.Value(), 0.0, leftPadding.Unit());
402     auto textFieldDecoration = textFieldComponent->GetDecoration();
403     if (textFieldDecoration) {
404         textFieldDecoration->SetPadding(decorationPadding);
405         textFieldDecoration->SetBorderRadius(searchTheme->GetBorderRadius());
406         textFieldComponent->SetOriginBorder(textFieldDecoration->GetBorder());
407     }
408     textFieldComponent->SetAction(TextInputAction::SEARCH);
409     textFieldComponent->SetWidthReserved(searchTheme->GetTextFieldWidthReserved());
410     textFieldComponent->SetTextColor(searchTheme->GetTextColor());
411     textFieldComponent->SetFocusTextColor(searchTheme->GetFocusTextColor());
412     textFieldComponent->SetPlaceholderColor(searchTheme->GetPlaceholderColor());
413     textFieldComponent->SetFocusPlaceholderColor(searchTheme->GetFocusPlaceholderColor());
414     textFieldComponent->SetBlockRightShade(searchTheme->GetBlockRightShade());
415 
416     auto textStyle = textFieldComponent->GetTextStyle();
417     searchComponent->SetPlaceHoldStyle(textStyle);
418     searchComponent->SetEditingStyle(textStyle);
419 
420     std::function<void(const std::string&)> submitEvent;
421     searchComponent->SetSubmitEvent(submitEvent);
422     searchComponent->SetChild(textFieldComponent);
423     searchComponent->SetTextEditController(textFieldComponent->GetTextEditController());
424     searchComponent->SetCloseIconSize(searchTheme->GetCloseIconSize());
425     searchComponent->SetCloseIconHotZoneHorizontal(searchTheme->GetCloseIconHotZoneSize());
426     searchComponent->SetHoverColor(textFieldTheme->GetHoverColor());
427     searchComponent->SetPressColor(textFieldTheme->GetPressColor());
428     isPaddingChanged = false;
429 }
430 
PrepareSpecializedComponent(OHOS::Ace::RefPtr<OHOS::Ace::SearchComponent> & searchComponent,OHOS::Ace::RefPtr<OHOS::Ace::TextFieldComponent> & textFieldComponent)431 void SearchModelImpl::PrepareSpecializedComponent(OHOS::Ace::RefPtr<OHOS::Ace::SearchComponent>& searchComponent,
432     OHOS::Ace::RefPtr<OHOS::Ace::TextFieldComponent>& textFieldComponent)
433 {
434     Border boxBorder;
435 
436     auto boxComponent = ViewStackProcessor::GetInstance()->GetBoxComponent();
437 
438     boxComponent->SetMouseAnimationType(HoverAnimationType::BOARD);
439     if (boxComponent->GetBackDecoration()) {
440         boxBorder = boxComponent->GetBackDecoration()->GetBorder();
441     }
442     UpdateDecorationStyle(boxComponent, textFieldComponent, boxBorder, false);
443     if (GreatOrEqual(boxComponent->GetHeightDimension().Value(), 0.0)) {
444         textFieldComponent->SetHeight(boxComponent->GetHeightDimension());
445     }
446     if (isPaddingChanged) {
447         auto padding = textFieldComponent->GetDecoration()->GetPadding();
448         if (searchComponent->GetTextDirection() == TextDirection::RTL) {
449             padding.SetLeft(padding.Left() + searchComponent->GetCloseIconHotZoneHorizontal());
450         } else {
451             padding.SetRight(padding.Right() + searchComponent->GetCloseIconHotZoneHorizontal());
452         }
453         textFieldComponent->GetDecoration()->SetPadding(padding);
454         searchComponent->SetDecoration(textFieldComponent->GetDecoration());
455         isPaddingChanged = false;
456     }
457 }
458 
459 } // namespace OHOS::Ace::Framework
460