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 
24 namespace OHOS {
UITimePicker()25 UITimePicker::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 
~UITimePicker()66 UITimePicker::~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 
InitTimePicker()80 void 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 
DeInitTimePicker()109 void UITimePicker::DeInitTimePicker()
110 {
111     DeInitPicker(secondPicker_);
112     DeInitPicker(minutePicker_);
113     DeInitPicker(hourPicker_);
114 }
115 
RefreshTimePicker()116 void UITimePicker::RefreshTimePicker()
117 {
118     DeInitTimePicker();
119     InitTimePicker();
120 }
121 
InitPicker(UIPicker * & picker,int16_t start,int16_t end)122 void 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 
DeInitPicker(UIPicker * & picker)154 void UITimePicker::DeInitPicker(UIPicker*& picker)
155 {
156     if (picker != nullptr) {
157         Remove(picker);
158         picker->ClearValues();
159         delete picker;
160         picker = nullptr;
161     }
162 }
163 
TimeSelectedCallback()164 void 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 
GetValueByIndex(char * value,uint8_t len,uint16_t index,int16_t start,int16_t end)193 void 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 
SetSelected(const char * value)202 bool 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 
RefreshSelected(const char * value)229 bool 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 
OnPressEvent(const PressEvent & event)256 bool 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 
SetItemHeight(int16_t height)268 void UITimePicker::SetItemHeight(int16_t height)
269 {
270     itemsHeight_ = height;
271     RefreshTimePicker();
272 }
273 
EnableSecond(bool state)274 void UITimePicker::EnableSecond(bool state)
275 {
276     secVisible_ = state;
277     RefreshTimePicker();
278 }
279 
SetTextStyle(uint16_t backgroundFontId,uint16_t highlightFontId,ColorType backgroundColor,ColorType highlightColor)280 void 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 
SetTextColor(ColorType backgroundColor,ColorType highlightColor)302 void UITimePicker::SetTextColor(ColorType backgroundColor, ColorType highlightColor)
303 {
304     backgroundColor_ = backgroundColor;
305     highlightColor_ = highlightColor;
306     RefreshTimePicker();
307 }
308 
SetBackgroundFont(const char * name,uint8_t size)309 void UITimePicker::SetBackgroundFont(const char* name, uint8_t size)
310 {
311     Text::SetFont(name, size, backgroundFontName_, backgroundFontSize_);
312     RefreshTimePicker();
313 }
314 
SetHighlightFont(const char * name,uint8_t size)315 void UITimePicker::SetHighlightFont(const char* name, uint8_t size)
316 {
317     Text::SetFont(name, size, highlightFontName_, highlightFontSize_);
318     RefreshTimePicker();
319 }
320 
SetWidth(int16_t width)321 void UITimePicker::SetWidth(int16_t width)
322 {
323     UIView::SetWidth(width);
324     RefreshTimePicker();
325 }
326 
SetHeight(int16_t height)327 void UITimePicker::SetHeight(int16_t height)
328 {
329     UIView::SetHeight(height);
330     RefreshTimePicker();
331 }
332 
SetLoopState(const uint8_t pickerType,bool state)333 void 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