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_digital_clock.h"
17#include <cstdio>
18#include "components/ui_view_group.h"
19#include "font/ui_font.h"
20#include "gfx_utils/graphic_log.h"
21#include "securec.h"
22
23namespace OHOS {
24UIDigitalClock::UIDigitalClock()
25    : timeLabels_{0},
26      displayMode_(DISPLAY_24_HOUR),
27      leadingZero_(true),
28      color_(Color::White()),
29      prevHour_(0),
30      prevMinute_(0),
31      prevSecond_(0),
32      verticalShow_(false)
33{
34    style_ = &(StyleDefault::GetBackgroundTransparentStyle());
35}
36
37void UIDigitalClock::InitTimeLabels()
38{
39    for (uint8_t i = 0; i < TIME_ELEMENT_COUNT; i++) {
40        if (timeLabels_[i] == nullptr) {
41            timeLabels_[i] = new UILabel;
42            if (timeLabels_[i] == nullptr) {
43                GRAPHIC_LOGE("new UILabel fail");
44                return;
45            }
46            timeLabels_[i]->SetLineBreakMode(UILabel::LINE_BREAK_ADAPT);
47            timeLabels_[i]->SetStyle(STYLE_BACKGROUND_OPA, OPA_TRANSPARENT);
48            Add(timeLabels_[i]);
49        }
50    }
51}
52
53void UIDigitalClock::DisplayLeadingZero(bool displayLeadingZero)
54{
55    leadingZero_ = displayLeadingZero;
56    UpdateClock(false);
57}
58
59void UIDigitalClock::SetOpacity(uint8_t opacity)
60{
61    opaScale_ = opacity;
62    InitTimeLabels();
63    for (uint8_t i = 0; i < TIME_ELEMENT_COUNT; i++) {
64        timeLabels_[i]->SetStyle(STYLE_TEXT_OPA, opacity);
65    }
66    RefreshTime();
67}
68
69uint8_t UIDigitalClock::GetOpacity() const
70{
71    return opaScale_;
72}
73
74void UIDigitalClock::SetFontId(uint16_t fontId)
75{
76    SetStyle(STYLE_TEXT_FONT, fontId);
77    InitTimeLabels();
78    for (uint8_t i = 0; i < TIME_ELEMENT_COUNT; i++) {
79        timeLabels_[i]->SetFontId(fontId);
80    }
81    UpdateClock(false);
82}
83
84void UIDigitalClock::SetFont(const char* name, uint8_t size)
85{
86    InitTimeLabels();
87    for (uint8_t i = 0; i < TIME_ELEMENT_COUNT; i++) {
88        timeLabels_[i]->SetFont(name, size);
89    }
90    UpdateClock(false);
91}
92
93void UIDigitalClock::SetColor(ColorType color)
94{
95    color_ = color;
96    InitTimeLabels();
97    for (uint8_t i = 0; i < TIME_ELEMENT_COUNT; i++) {
98        timeLabels_[i]->SetStyle(STYLE_TEXT_COLOR, color.full);
99    }
100    RefreshTime();
101}
102
103void UIDigitalClock::TimeElementRefresh()
104{
105    InitTimeLabels();
106    if (currentHour_ != prevHour_) {
107        prevHour_ = currentHour_;
108        timeLabels_[HOUR_ELEMENT]->Invalidate();
109    }
110
111    if (currentMinute_ != prevMinute_) {
112        prevMinute_ = currentMinute_;
113        timeLabels_[MINUTE_ELEMENT]->Invalidate();
114    }
115
116    if (currentSecond_ != prevSecond_) {
117        prevSecond_ = currentSecond_;
118        timeLabels_[SECOND_ELEMENT]->Invalidate();
119    }
120}
121
122void UIDigitalClock::RefreshTime()
123{
124    InitTimeLabels();
125    for (uint8_t i = 0; i < TIME_ELEMENT_COUNT; i++) {
126        timeLabels_[i]->Invalidate();
127    }
128}
129
130void UIDigitalClock::UpdateClock(bool clockInit)
131{
132    char buf[TIME_ELEMENT_COUNT][BUFFER_SIZE] = {{0}};
133    const char* formatWithColon = leadingZero_ ? "%02d:" : "%d:";
134    const char* formatWithoutColon = leadingZero_ ? "%02d" : "%d";
135    const char* format = verticalShow_ ? formatWithoutColon : formatWithColon;
136    const char* formatForMinute = verticalShow_ ? "%02d" : "%02d:";
137    switch (displayMode_) {
138        case DISPLAY_24_HOUR_NO_SECONDS: {
139            if (sprintf_s(buf[HOUR_ELEMENT], BUFFER_SIZE, format, currentHour_) < 0) {
140                return;
141            }
142            if (sprintf_s(buf[MINUTE_ELEMENT], BUFFER_SIZE, "%02d", currentMinute_) < 0) {
143                return;
144            }
145            break;
146        }
147        case DISPLAY_12_HOUR_NO_SECONDS: {
148            if (sprintf_s(buf[HOUR_ELEMENT], BUFFER_SIZE, format, currentHour_ % HALF_DAY_IN_HOUR) < 0) {
149                return;
150            }
151            if (sprintf_s(buf[MINUTE_ELEMENT], BUFFER_SIZE, "%02d", currentMinute_) < 0) {
152                return;
153            }
154            break;
155        }
156        case DISPLAY_12_HOUR: {
157            if (sprintf_s(buf[HOUR_ELEMENT], BUFFER_SIZE, format, currentHour_ % HALF_DAY_IN_HOUR) < 0) {
158                return;
159            }
160            if (sprintf_s(buf[MINUTE_ELEMENT], BUFFER_SIZE, formatForMinute, currentMinute_) < 0) {
161                return;
162            }
163            if (sprintf_s(buf[SECOND_ELEMENT], BUFFER_SIZE, "%02d", currentSecond_) < 0) {
164                return;
165            }
166            break;
167        }
168        case DISPLAY_24_HOUR: {
169            if (sprintf_s(buf[HOUR_ELEMENT], BUFFER_SIZE, format, currentHour_) < 0) {
170                return;
171            }
172            if (sprintf_s(buf[MINUTE_ELEMENT], BUFFER_SIZE, formatForMinute, currentMinute_) < 0) {
173                return;
174            }
175            if (sprintf_s(buf[SECOND_ELEMENT], BUFFER_SIZE, "%02d", currentSecond_) < 0) {
176                return;
177            }
178            break;
179        }
180        default: {
181            break;
182        }
183    }
184    SetTimeLabels(buf);
185}
186
187void UIDigitalClock::SetTimeLabels(const char buf[TIME_ELEMENT_COUNT][BUFFER_SIZE])
188{
189    InitTimeLabels();
190    for (uint8_t i = 0; i < TIME_ELEMENT_COUNT; i++) {
191        timeLabels_[i]->SetText(buf[i]);
192    }
193
194    SetTimeLabelsPosition();
195    TimeElementRefresh();
196}
197
198void UIDigitalClock::SetHorizontal()
199{
200    InitTimeLabels();
201    uint16_t totalWidth = timeLabels_[HOUR_ELEMENT]->GetWidth() + timeLabels_[MINUTE_ELEMENT]->GetWidth() +
202                          timeLabels_[SECOND_ELEMENT]->GetWidth();
203    UITextLanguageAlignment align = timeLabels_[HOUR_ELEMENT]->GetHorAlign();
204    int16_t x = 0;
205    Rect rect = GetContentRect();
206    if (align == TEXT_ALIGNMENT_CENTER) {
207        x = (rect.GetWidth() >> 1) - (totalWidth >> 1);
208    } else if (align == TEXT_ALIGNMENT_RIGHT) {
209        x = rect.GetRight() - totalWidth;
210    }
211    timeLabels_[HOUR_ELEMENT]->SetPosition(x, 0);
212    int16_t width = timeLabels_[HOUR_ELEMENT]->GetWidth();
213    for (uint8_t i = 1; i < TIME_ELEMENT_COUNT; i++) {
214        timeLabels_[i]->SetPosition(x + width, 0);
215        width += timeLabels_[i]->GetWidth();
216    }
217}
218
219void UIDigitalClock::SetTimeLabelsPosition()
220{
221    if (verticalShow_) {
222        SetVertical();
223    } else {
224        SetHorizontal();
225    }
226}
227
228void UIDigitalClock::SetVertical()
229{
230    InitTimeLabels();
231    int16_t fontHeight = timeLabels_[HOUR_ELEMENT]->GetHeight();
232    timeLabels_[HOUR_ELEMENT]->SetPosition(0, 0);
233    int16_t y = fontHeight;
234    for (uint8_t i = 1; i < TIME_ELEMENT_COUNT; i++) {
235        timeLabels_[i]->SetPosition(0, y);
236        y += fontHeight;
237    }
238}
239
240UIDigitalClock::~UIDigitalClock()
241{
242    for (uint8_t i = 0; i < TIME_ELEMENT_COUNT; i++) {
243        if (timeLabels_[i] != nullptr) {
244            Remove(timeLabels_[i]);
245            delete timeLabels_[i];
246            timeLabels_[i] = nullptr;
247        }
248    }
249}
250} // namespace OHOS
251