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
22namespace OHOS {
23PickerListScrollListener::PickerListScrollListener(UIPicker* picker, UIList* list)
24    : listView_(list),
25      pickerView_(picker),
26      selectView_(nullptr),
27      lastSelectView_(nullptr),
28      selectIndex_(0),
29      isInitted_(false) {}
30
31void 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
60void 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
93UIPicker::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
148UIPicker::~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
173bool 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
184bool 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
195void UIPicker::Refresh()
196{
197    if (rangeValue_) {
198        RefreshValues(rangeValue_, rangeValueCount_);
199    } else if ((startValue_ != 0) || (endValue_ != 0)) {
200        RefreshValues(startValue_, endValue_);
201    }
202}
203
204bool 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
222bool 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
244void 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
276void UIPicker::ClearValues()
277{
278    rangeValue_ = nullptr;
279    rangeValueCount_ = 0;
280    maxCount_ = 0;
281    ClearList();
282    ClearTextAdapter();
283}
284
285void 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
296void 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
307bool UIPicker::SetSelected(uint16_t index)
308{
309    return RefreshSelected(index);
310}
311
312bool 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
360uint16_t UIPicker::GetSelected() const
361{
362    return listListener_->GetSelectIndex();
363}
364
365void 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
385void 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
396void 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
407void 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
417void 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
428void 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
440void 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
452void UIPicker::SetLoopState(bool state)
453{
454    if (state == list_.GetLoopState()) {
455        return;
456    }
457    list_.SetLoopState(state);
458    Refresh();
459}
460
461void UIPicker::SetDirect(UITextLanguageDirect direct)
462{
463    if (direct == direct_) {
464        return;
465    }
466    direct_ = direct;
467    Refresh();
468}
469
470void UIPicker::SetTextFormatter(TextFormatter* formatter)
471{
472    InitTextAdapter();
473    textAdapter_->SetTextFormatter(formatter);
474    Refresh();
475}
476} // namespace OHOS
477