1 /*
2  * Copyright (c) 2020-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 #include "components/ui_picker.h"
17 #include "dock/vibrator_manager.h"
18 #include "draw/draw_line.h"
19 #include "draw/draw_rect.h"
20 #include "themes/theme_manager.h"
21 
22 namespace OHOS {
PickerListScrollListener(UIPicker * picker,UIList * list)23 PickerListScrollListener::PickerListScrollListener(UIPicker* picker, UIList* list)
24     : listView_(list),
25       pickerView_(picker),
26       selectView_(nullptr),
27       lastSelectView_(nullptr),
28       selectIndex_(0),
29       isInitted_(false) {}
30 
OnItemSelected(int16_t index,UIView * view)31 void PickerListScrollListener::OnItemSelected(int16_t index, UIView* view)
32 {
33     if (!isInitted_) {
34         return;
35     }
36 
37     if ((lastSelectView_ != nullptr) && (listView_ != nullptr) && (pickerView_ != nullptr) && (view != nullptr)) {
38         lastSelectView_->SetStyle(STYLE_TEXT_COLOR, pickerView_->GetBackgroundTextColor().full);
39         if (pickerView_->backgroundFontName_ == nullptr) {
40             static_cast<UILabel*>(lastSelectView_)->SetFontId(pickerView_->backgroundFontId_);
41         } else {
42             static_cast<UILabel*>(lastSelectView_)
43                 ->SetFont(pickerView_->backgroundFontName_, pickerView_->backgroundFontSize_);
44         }
45         view->SetStyle(STYLE_TEXT_COLOR, pickerView_->GetHighlightTextColor().full);
46         if (pickerView_->highlightFontName_ == nullptr) {
47             static_cast<UILabel*>(view)->SetFontId(pickerView_->highlightFontId_);
48         } else {
49             static_cast<UILabel*>(view)->SetFont(pickerView_->highlightFontName_, pickerView_->highlightFontSize_);
50         }
51         lastSelectView_ = view;
52         selectIndex_ = index;
53         listView_->Invalidate();
54         if (pickerView_->pickerListener_) {
55             pickerView_->pickerListener_->OnPickerChanged(*pickerView_);
56         }
57     }
58 }
59 
OnScrollEnd(int16_t index,UIView * view)60 void PickerListScrollListener::OnScrollEnd(int16_t index, UIView* view)
61 {
62     if ((view == nullptr) || (listView_ == nullptr) || (pickerView_ == nullptr)) {
63         return;
64     }
65 
66     if (lastSelectView_ != nullptr) {
67         lastSelectView_->SetStyle(STYLE_TEXT_COLOR, pickerView_->GetBackgroundTextColor().full);
68         if (pickerView_->backgroundFontName_ == nullptr) {
69             static_cast<UILabel*>(lastSelectView_)->SetFontId(pickerView_->backgroundFontId_);
70         } else {
71             static_cast<UILabel*>(lastSelectView_)
72                 ->SetFont(pickerView_->backgroundFontName_, pickerView_->backgroundFontSize_);
73         }
74         lastSelectView_ = view;
75     }
76 
77     view->SetStyle(STYLE_TEXT_COLOR, pickerView_->GetHighlightTextColor().full);
78     if (pickerView_->highlightFontName_ == nullptr) {
79         static_cast<UILabel*>(view)->SetFontId(pickerView_->highlightFontId_);
80     } else {
81         static_cast<UILabel*>(view)->SetFont(pickerView_->highlightFontName_, pickerView_->highlightFontSize_);
82     }
83 
84     listView_->Invalidate();
85     selectView_ = view;
86     selectIndex_ = index;
87 
88     if (pickerView_->pickerListener_) {
89         pickerView_->pickerListener_->OnPickerStoped(*pickerView_);
90     }
91 }
92 
UIPicker()93 UIPicker::UIPicker()
94     : isWidthSet_(false),
95       isHeightSet_(false),
96       textAdapter_(nullptr),
97       maxCount_(0),
98       isScrollBlankSizeSet_(false),
99       scrollBlankSize_(0),
100       backgroundFontSize_(0),
101       highlightFontSize_(0),
102       backgroundFontName_(nullptr),
103       highlightFontName_(nullptr),
104       itemsWidth_(0),
105       itemsHeight_(0),
106       rangeValue_(nullptr),
107       rangeValueCount_(0),
108       startValue_(0),
109       endValue_(0),
110       isSetAdaptered_(false),
111       pickerListener_(nullptr)
112 {
113     Theme* theme = ThemeManager::GetInstance().GetCurrent();
114     if (theme != nullptr) {
115         style_ = &(theme->GetPickerBackgroundStyle());
116     } else {
117         style_ = &(StyleDefault::GetPickerBackgroundStyle());
118     }
119     backgroundFontId_ = style_->font_;
120     backgroundColor_ = style_->textColor_;
121     direct_ = UITextLanguageDirect::TEXT_DIRECT_LTR;
122 
123     if (theme != nullptr) {
124         style_ = &(theme->GetPickerHighlightStyle());
125     } else {
126         style_ = &(StyleDefault::GetPickerHighlightStyle());
127     }
128     highlightFontId_ = style_->font_;
129     highlightColor_ = style_->textColor_;
130 
131     list_.SetThrowDrag(true);
132     list_.SetStyle(StyleDefault::GetBackgroundTransparentStyle());
133 #if ENABLE_ROTATE_INPUT
134     list_.rotateFactor_ = DEFAULT_PICKER_ROTATE_FACTOR;
135     list_.rotateThrowthreshold_ = PICKERVIEW_ROTATE_THROW_THRESHOLD;
136     list_.rotateAccCoefficient_ = PICKERVIEW_ROTATE_DISTANCE_COEFF;
137 #endif
138 #if ENABLE_FOCUS_MANAGER
139     focusable_ = true;
140 #endif
141     list_.SetLoopState(false);
142     list_.EnableAutoAlign(true);
143     listListener_ = new PickerListScrollListener(this, &list_);
144     list_.SetScrollStateListener(listListener_);
145     Add(&list_);
146 }
147 
~UIPicker()148 UIPicker::~UIPicker()
149 {
150     ClearValues();
151     Remove(&list_);
152     if (listListener_ != nullptr) {
153         delete listListener_;
154         listListener_ = nullptr;
155     }
156 
157     if (backgroundFontName_ != nullptr) {
158         UIFree(backgroundFontName_);
159         backgroundFontName_ = nullptr;
160     }
161 
162     if (highlightFontName_ != nullptr) {
163         UIFree(highlightFontName_);
164         highlightFontName_ = nullptr;
165     }
166 
167     if (textAdapter_ != nullptr) {
168         delete textAdapter_;
169         textAdapter_ = nullptr;
170     }
171 }
172 
SetValues(int16_t start,int16_t end)173 bool UIPicker::SetValues(int16_t start, int16_t end)
174 {
175     if (start > end) {
176         return false;
177     }
178 
179     startValue_ = start;
180     endValue_ = end;
181     return RefreshValues(start, end);
182 }
183 
SetValues(const char * value[],uint16_t count)184 bool UIPicker::SetValues(const char* value[], uint16_t count)
185 {
186     if (value == nullptr) {
187         return false;
188     }
189 
190     rangeValue_ = value;
191     rangeValueCount_ = count;
192     return RefreshValues(value, count);
193 }
194 
Refresh()195 void UIPicker::Refresh()
196 {
197     if (rangeValue_) {
198         RefreshValues(rangeValue_, rangeValueCount_);
199     } else if ((startValue_ != 0) || (endValue_ != 0)) {
200         RefreshValues(startValue_, endValue_);
201     }
202 }
203 
RefreshValues(int16_t start,int16_t end)204 bool UIPicker::RefreshValues(int16_t start, int16_t end)
205 {
206     if ((start == 0) && (end == 0)) {
207         return false;
208     }
209     maxCount_ = end - start + 1;
210     if (!isWidthSet_ || !isHeightSet_ || !itemsHeight_) {
211         return false;
212     }
213     uint16_t userSelectIndex = listListener_->GetSelectIndex();
214     ClearList();
215     InitTextAdapter();
216     textAdapter_->SetData(start, end);
217     RefreshList();
218     RefreshSelected(userSelectIndex);
219     return true;
220 }
221 
RefreshValues(const char * value[],uint16_t count)222 bool UIPicker::RefreshValues(const char* value[], uint16_t count)
223 {
224     if (value == nullptr) {
225         return false;
226     }
227     maxCount_ = count;
228     if (!isWidthSet_ || !isHeightSet_ || !itemsHeight_) {
229         return false;
230     }
231     uint16_t userSelectIndex = listListener_->GetSelectIndex();
232     ClearList();
233     for (uint16_t i = 0; i < count; i++) {
234         dataList_.PushBack(value[i]);
235     }
236     InitTextAdapter();
237     textAdapter_->SetData(&dataList_);
238     RefreshList();
239     RefreshSelected(userSelectIndex);
240 
241     return true;
242 }
243 
RefreshList()244 void UIPicker::RefreshList()
245 {
246     int16_t height = GetHeight();
247     itemsWidth_ = GetWidth();
248     textAdapter_->SetWidth(itemsWidth_);
249     textAdapter_->SetHeight(itemsHeight_);
250     textAdapter_->SetLineBreakMode(UILabel::LINE_BREAK_CLIP);
251     if (backgroundFontName_ == nullptr) {
252         textAdapter_->SetFontId(backgroundFontId_);
253     } else {
254         textAdapter_->SetFont(backgroundFontName_, backgroundFontSize_);
255     }
256     textAdapter_->GetStyle().textColor_ = backgroundColor_;
257     textAdapter_->SetDirect(direct_);
258     list_.SetHeight(height);
259     list_.SetWidth(itemsWidth_);
260     list_.LayoutCenterOfParent();
261     list_.SetSelectPosition(height / 2);                   // 2: half
262     if (isScrollBlankSizeSet_) {
263         list_.SetScrollBlankSize(scrollBlankSize_);
264     } else {
265         list_.SetScrollBlankSize((height - itemsHeight_) / 2); // 2: half
266     }
267     if (!isSetAdaptered_) {
268         list_.SetAdapter(textAdapter_);
269         isSetAdaptered_ = true;
270     }
271 
272     list_.RefreshList();
273     RefreshSelected(0);
274 }
275 
ClearValues()276 void UIPicker::ClearValues()
277 {
278     rangeValue_ = nullptr;
279     rangeValueCount_ = 0;
280     maxCount_ = 0;
281     ClearList();
282     ClearTextAdapter();
283 }
284 
ClearList()285 void UIPicker::ClearList()
286 {
287     itemsWidth_ = 0;
288     if (listListener_) {
289         listListener_->SetSelectView(nullptr);
290         listListener_->SetSelectIndex(0);
291         listListener_->SetInitStatus(false);
292     }
293     dataList_.Clear();
294 }
295 
ClearTextAdapter()296 void UIPicker::ClearTextAdapter()
297 {
298     if (textAdapter_ != nullptr) {
299         delete textAdapter_;
300         textAdapter_ = nullptr;
301     }
302     list_.SetAdapter(textAdapter_);
303     list_.RefreshList();
304     isSetAdaptered_ = false;
305 }
306 
SetSelected(uint16_t index)307 bool UIPicker::SetSelected(uint16_t index)
308 {
309     return RefreshSelected(index);
310 }
311 
RefreshSelected(uint16_t index)312 bool UIPicker::RefreshSelected(uint16_t index)
313 {
314     if (maxCount_ <= index) {
315         GRAPHIC_LOGW("Failed to refresh selected since index is beyond range!");
316         return false;
317     }
318     if (itemsHeight_ && (list_.GetChildrenHead() != nullptr) && isWidthSet_ && isHeightSet_) {
319         listListener_->SetInitStatus(false);
320         // 2: half
321         int16_t yOffset = (list_.GetHeight() - itemsHeight_) / 2 -
322                           itemsHeight_ * (index - list_.GetChildrenHead()->GetViewIndex());
323         list_.SetScrollStateListener(nullptr);
324         list_.ScrollBy(yOffset - list_.GetChildrenHead()->GetY());
325         list_.SetScrollStateListener(listListener_);
326         listListener_->SetScrollState(ListScrollListener::SCROLL_STATE_STOP);
327         UIView* childView = static_cast<UIView*>(list_.GetChildrenHead());
328         uint16_t lastSelectIndex = listListener_->GetSelectIndex();
329 
330         while (childView != nullptr) {
331             int16_t viewIndex = childView->GetViewIndex();
332             if (viewIndex == lastSelectIndex) {
333                 childView->SetStyle(STYLE_TEXT_COLOR, GetBackgroundTextColor().full);
334                 if (backgroundFontName_ == nullptr) {
335                     static_cast<UILabel*>(childView)->SetFontId(backgroundFontId_);
336                 } else {
337                     static_cast<UILabel*>(childView)->SetFont(backgroundFontName_, backgroundFontSize_);
338                 }
339             }
340             if (viewIndex == index) {
341                 childView->SetStyle(STYLE_TEXT_COLOR, GetHighlightTextColor().full);
342                 if (highlightFontName_ == nullptr) {
343                     static_cast<UILabel*>(childView)->SetFontId(highlightFontId_);
344                 } else {
345                     static_cast<UILabel*>(childView)->SetFont(highlightFontName_, highlightFontSize_);
346                 }
347                 listListener_->SetSelectView(childView);
348                 listListener_->SetInitStatus(true);
349             }
350             childView = childView->GetNextSibling();
351         }
352         listListener_->SetSelectIndex(index);
353         list_.Invalidate();
354         return true;
355     }
356     listListener_->SetSelectIndex(index);
357     return false;
358 }
359 
GetSelected() const360 uint16_t UIPicker::GetSelected() const
361 {
362     return listListener_->GetSelectIndex();
363 }
364 
SetFontId(uint16_t backgroundFontId,uint16_t highlightFontId)365 void UIPicker::SetFontId(uint16_t backgroundFontId, uint16_t highlightFontId)
366 {
367     if ((backgroundFontId == backgroundFontId_) && (highlightFontId == highlightFontId_)) {
368         return;
369     }
370     backgroundFontId_ = backgroundFontId;
371     if (backgroundFontName_ != nullptr) {
372         UIFree(backgroundFontName_);
373         backgroundFontName_ = nullptr;
374     }
375 
376     highlightFontId_ = highlightFontId;
377     if (highlightFontName_ != nullptr) {
378         UIFree(highlightFontName_);
379         highlightFontName_ = nullptr;
380     }
381 
382     Refresh();
383 }
384 
SetBackgroundFont(const char * name,uint8_t size)385 void UIPicker::SetBackgroundFont(const char* name, uint8_t size)
386 {
387     if ((name != nullptr) && (backgroundFontName_ != nullptr)) {
388         if (strcmp(name, backgroundFontName_) == 0 && size == backgroundFontSize_) {
389             return;
390         }
391     }
392     Text::SetFont(name, size, backgroundFontName_, backgroundFontSize_);
393     Refresh();
394 }
395 
SetHighlightFont(const char * name,uint8_t size)396 void UIPicker::SetHighlightFont(const char* name, uint8_t size)
397 {
398     if ((name != nullptr) && (highlightFontName_ != nullptr)) {
399         if (strcmp(name, highlightFontName_) == 0 && size == highlightFontSize_) {
400             return;
401         }
402     }
403     Text::SetFont(name, size, highlightFontName_, highlightFontSize_);
404     Refresh();
405 }
406 
SetTextColor(ColorType backgroundColor,ColorType highlightColor)407 void UIPicker::SetTextColor(ColorType backgroundColor, ColorType highlightColor)
408 {
409     if ((backgroundColor.full == backgroundColor_.full) && (highlightColor.full == highlightColor_.full)) {
410         return;
411     }
412     backgroundColor_ = backgroundColor;
413     highlightColor_ = highlightColor;
414     Refresh();
415 }
416 
SetItemHeight(int16_t height)417 void UIPicker::SetItemHeight(int16_t height)
418 {
419     if (height == itemsHeight_) {
420         return;
421     }
422     if (height > 0) {
423         itemsHeight_ = height;
424         Refresh();
425     }
426 }
427 
SetWidth(int16_t width)428 void UIPicker::SetWidth(int16_t width)
429 {
430     if (width == UIView::GetWidth()) {
431         return;
432     }
433     if (width > 0) {
434         UIView::SetWidth(width);
435         isWidthSet_ = true;
436         Refresh();
437     }
438 }
439 
SetHeight(int16_t height)440 void UIPicker::SetHeight(int16_t height)
441 {
442     if (height == UIView::GetHeight()) {
443         return;
444     }
445     if (height > 0) {
446         UIView::SetHeight(height);
447         isHeightSet_ = true;
448         Refresh();
449     }
450 }
451 
SetLoopState(bool state)452 void UIPicker::SetLoopState(bool state)
453 {
454     if (state == list_.GetLoopState()) {
455         return;
456     }
457     list_.SetLoopState(state);
458     Refresh();
459 }
460 
SetDirect(UITextLanguageDirect direct)461 void UIPicker::SetDirect(UITextLanguageDirect direct)
462 {
463     if (direct == direct_) {
464         return;
465     }
466     direct_ = direct;
467     Refresh();
468 }
469 
SetTextFormatter(TextFormatter * formatter)470 void UIPicker::SetTextFormatter(TextFormatter* formatter)
471 {
472     InitTextAdapter();
473     textAdapter_->SetTextFormatter(formatter);
474     Refresh();
475 }
476 } // namespace OHOS
477