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_time_picker.h"
17#include <cstdio>
18#include <ctime>
19#include "draw/draw_rect.h"
20#include "gfx_utils/graphic_log.h"
21#include "securec.h"
22#include "themes/theme_manager.h"
23
24namespace OHOS {
25UITimePicker::UITimePicker()
26    : selectedValue_{0},
27      selectedHour_{0},
28      selectedMinute_{0},
29      selectedSecond_{0},
30      secVisible_(false),
31      loopState_{false},
32      pickerWidth_(0),
33      itemsHeight_(0),
34      xPos_(0),
35      backgroundFontSize_(0),
36      highlightFontSize_(0),
37      backgroundFontName_(nullptr),
38      highlightFontName_(nullptr),
39      pickerListener_(this),
40      timePickerListener_(nullptr)
41{
42    Theme* theme = ThemeManager::GetInstance().GetCurrent();
43    if (theme != nullptr) {
44        style_ = &(theme->GetPickerBackgroundStyle());
45    } else {
46        style_ = &(StyleDefault::GetPickerBackgroundStyle());
47    }
48    backgroundFontId_ = style_->font_;
49    backgroundColor_ = style_->textColor_;
50    if (theme != nullptr) {
51        style_ = &(theme->GetPickerHighlightStyle());
52    } else {
53        style_ = &(StyleDefault::GetPickerHighlightStyle());
54    }
55#if ENABLE_FOCUS_MANAGER
56    focusable_ = true;
57#endif
58    highlightFontId_ = style_->font_;
59    highlightColor_ = style_->textColor_;
60
61    hourPicker_ = nullptr;
62    minutePicker_ = nullptr;
63    secondPicker_ = nullptr;
64}
65
66UITimePicker::~UITimePicker()
67{
68    DeInitTimePicker();
69    if (backgroundFontName_ != nullptr) {
70        UIFree(backgroundFontName_);
71        backgroundFontName_ = nullptr;
72    }
73
74    if (highlightFontName_ != nullptr) {
75        UIFree(highlightFontName_);
76        highlightFontName_ = nullptr;
77    }
78}
79
80void UITimePicker::InitTimePicker()
81{
82    xPos_ = 0;
83    if (secVisible_) {
84        pickerWidth_ = GetWidth() / SEC_VISIBLE_COUNT;
85        InitPicker(hourPicker_, TIME_START, HOUR_END);
86        xPos_ = pickerWidth_;
87        InitPicker(minutePicker_, TIME_START, MIN_END);
88        xPos_ *= (SEC_VISIBLE_COUNT - 1);
89        InitPicker(secondPicker_, TIME_START, SEC_END);
90        if (secondPicker_ != nullptr) {
91            secondPicker_->SetLoopState(loopState_[PICKER_SEC]);
92        }
93    } else {
94        pickerWidth_ = GetWidth() / SEC_INVISIBLE_COUNT;
95        InitPicker(hourPicker_, TIME_START, HOUR_END);
96        xPos_ = pickerWidth_;
97        InitPicker(minutePicker_, TIME_START, MIN_END);
98    }
99    if (hourPicker_ != nullptr) {
100        hourPicker_->SetLoopState(loopState_[PICKER_HOUR]);
101    }
102    if (minutePicker_ != nullptr) {
103        minutePicker_->SetLoopState(loopState_[PICKER_MIN]);
104    }
105
106    RefreshSelected(selectedValue_);
107}
108
109void UITimePicker::DeInitTimePicker()
110{
111    DeInitPicker(secondPicker_);
112    DeInitPicker(minutePicker_);
113    DeInitPicker(hourPicker_);
114}
115
116void UITimePicker::RefreshTimePicker()
117{
118    DeInitTimePicker();
119    InitTimePicker();
120}
121
122void UITimePicker::InitPicker(UIPicker*& picker, int16_t start, int16_t end)
123{
124    picker = new UIPicker();
125    if (picker == nullptr) {
126        GRAPHIC_LOGE("new UIPicker fail");
127        return;
128    }
129    picker->SetPosition(xPos_, 0, pickerWidth_, GetHeight());
130    picker->SetItemHeight(itemsHeight_);
131    picker->SetFontId(backgroundFontId_, highlightFontId_);
132    if ((backgroundFontName_ == nullptr) || (highlightFontName_ == nullptr)) {
133        picker->SetFontId(backgroundFontId_, highlightFontId_);
134    } else {
135        picker->SetBackgroundFont(backgroundFontName_, backgroundFontSize_);
136        picker->SetHighlightFont(highlightFontName_, highlightFontSize_);
137    }
138    picker->SetTextColor(backgroundColor_, highlightColor_);
139    picker->SetValues(start, end);
140    picker->RegisterSelectedListener(&pickerListener_);
141    Add(picker);
142
143#if ENABLE_ROTATE_INPUT
144    if (end == HOUR_END) {
145        picker->GetChildrenHead()->SetViewId(HOUR_LIST_NAME);
146    } else if (end == MIN_END && secondPicker_ == nullptr) {
147        picker->GetChildrenHead()->SetViewId(MIN_LIST_NAME);
148    } else if (end == SEC_END) {
149        picker->GetChildrenHead()->SetViewId(SEC_LIST_NAME);
150    }
151#endif
152}
153
154void UITimePicker::DeInitPicker(UIPicker*& picker)
155{
156    if (picker != nullptr) {
157        Remove(picker);
158        picker->ClearValues();
159        delete picker;
160        picker = nullptr;
161    }
162}
163
164void UITimePicker::TimeSelectedCallback()
165{
166    uint16_t hourSelect = hourPicker_->GetSelected();
167    uint16_t minSelect = minutePicker_->GetSelected();
168    GetValueByIndex(selectedHour_, BUF_SIZE, hourSelect, TIME_START, HOUR_END);
169    GetValueByIndex(selectedMinute_, BUF_SIZE, minSelect, TIME_START, MIN_END);
170
171    if (memset_s(selectedValue_, SELECTED_VALUE_SIZE, 0, SELECTED_VALUE_SIZE) != EOK) {
172        return;
173    }
174
175    if (secVisible_) {
176        uint16_t secSelect = secondPicker_->GetSelected();
177        GetValueByIndex(selectedSecond_, BUF_SIZE, secSelect, TIME_START, SEC_END);
178        if (sprintf_s(selectedValue_, SELECTED_VALUE_SIZE, "%s:%s:%s",
179            selectedHour_, selectedMinute_, selectedSecond_) < 0) {
180            return;
181        }
182    } else {
183        if (sprintf_s(selectedValue_, SELECTED_VALUE_SIZE, "%s:%s", selectedHour_, selectedMinute_) < 0) {
184            return;
185        }
186    }
187
188    if (timePickerListener_ != nullptr) {
189        timePickerListener_->OnTimePickerStoped(*this);
190    }
191}
192
193void UITimePicker::GetValueByIndex(char* value, uint8_t len, uint16_t index, int16_t start, int16_t end)
194{
195    if ((value != nullptr) && (index < end - start + 1)) {
196        if (sprintf_s(value, len, "%02u", index) < 0) {
197            return;
198        }
199    }
200}
201
202bool UITimePicker::SetSelected(const char* value)
203{
204    if (value == nullptr) {
205        return false;
206    }
207
208    if (memset_s(selectedValue_, SELECTED_VALUE_SIZE, 0, SELECTED_VALUE_SIZE) != EOK) {
209        return false;
210    }
211
212    if (strcpy_s(selectedValue_, SELECTED_VALUE_SIZE, value) != EOK) {
213        return false;
214    }
215    if (secVisible_) {
216        if (sscanf_s(value, "%[^:]%*c%[^:]%*c%[^\n]", selectedHour_, BUF_SIZE,
217                     selectedMinute_, BUF_SIZE, selectedSecond_, BUF_SIZE) < 3) { // 3: three variables
218            return false;
219        }
220    } else {
221        if (sscanf_s(value, "%[^:]%*c%[^\n]", selectedHour_, BUF_SIZE,
222                     selectedMinute_, BUF_SIZE) < 2) { // 2: two variables
223            return false;
224        }
225    }
226    return RefreshSelected(selectedValue_);
227}
228
229bool UITimePicker::RefreshSelected(const char* value)
230{
231    uint32_t hourSelect;
232    uint32_t minSelect;
233
234    if (value == nullptr) {
235        return false;
236    }
237
238    if (secVisible_) {
239        uint32_t secSelect;
240        // 3: three variables
241        if (sscanf_s(value, "%u:%u:%u", &hourSelect, &minSelect, &secSelect) < 3) {
242            return false;
243        }
244        secondPicker_->SetSelected(secSelect);
245    } else {
246        if (sscanf_s(value, "%u:%u", &hourSelect, &minSelect) < 2) { // 2: two variables
247            return false;
248        }
249    }
250
251    hourPicker_->SetSelected(hourSelect);
252    minutePicker_->SetSelected(minSelect);
253    return true;
254}
255
256bool UITimePicker::OnPressEvent(const PressEvent& event)
257{
258    if (event.GetCurrentPos().x < (GetX() + hourPicker_->GetX() + hourPicker_->GetWidth())) {
259        hourPicker_->RequestFocus();
260    } else if (event.GetCurrentPos().x < (GetX() + minutePicker_->GetX() + minutePicker_->GetWidth())) {
261        minutePicker_->RequestFocus();
262    } else if (event.GetCurrentPos().x < (GetX() + secondPicker_->GetX() + secondPicker_->GetWidth())) {
263        secondPicker_->RequestFocus();
264    }
265    return UIView::OnPressEvent(event);
266}
267
268void UITimePicker::SetItemHeight(int16_t height)
269{
270    itemsHeight_ = height;
271    RefreshTimePicker();
272}
273
274void UITimePicker::EnableSecond(bool state)
275{
276    secVisible_ = state;
277    RefreshTimePicker();
278}
279
280void UITimePicker::SetTextStyle(uint16_t backgroundFontId,
281                                uint16_t highlightFontId,
282                                ColorType backgroundColor,
283                                ColorType highlightColor)
284{
285    highlightFontId_ = highlightFontId;
286    if (highlightFontName_ != nullptr) {
287        UIFree(highlightFontName_);
288        highlightFontName_ = nullptr;
289    }
290
291    backgroundFontId_ = backgroundFontId;
292    if (backgroundFontName_ != nullptr) {
293        UIFree(backgroundFontName_);
294        backgroundFontName_ = nullptr;
295    }
296
297    highlightColor_ = highlightColor;
298    backgroundColor_ = backgroundColor;
299    RefreshTimePicker();
300}
301
302void UITimePicker::SetTextColor(ColorType backgroundColor, ColorType highlightColor)
303{
304    backgroundColor_ = backgroundColor;
305    highlightColor_ = highlightColor;
306    RefreshTimePicker();
307}
308
309void UITimePicker::SetBackgroundFont(const char* name, uint8_t size)
310{
311    Text::SetFont(name, size, backgroundFontName_, backgroundFontSize_);
312    RefreshTimePicker();
313}
314
315void UITimePicker::SetHighlightFont(const char* name, uint8_t size)
316{
317    Text::SetFont(name, size, highlightFontName_, highlightFontSize_);
318    RefreshTimePicker();
319}
320
321void UITimePicker::SetWidth(int16_t width)
322{
323    UIView::SetWidth(width);
324    RefreshTimePicker();
325}
326
327void UITimePicker::SetHeight(int16_t height)
328{
329    UIView::SetHeight(height);
330    RefreshTimePicker();
331}
332
333void UITimePicker::SetLoopState(const uint8_t pickerType, bool state)
334{
335    switch (pickerType) {
336        case PICKER_HOUR:
337            loopState_[PICKER_HOUR] = state;
338            break;
339        case PICKER_MIN:
340            loopState_[PICKER_MIN] = state;
341            break;
342        case PICKER_SEC:
343            loopState_[PICKER_SEC] = state;
344            break;
345        default:
346            return;
347    }
348    RefreshTimePicker();
349}
350}
351