• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_analog_clock.h"
17 
18 #include "components/ui_image_view.h"
19 #include "draw/draw_image.h"
20 #include "engines/gfx/gfx_engine_manager.h"
21 #include "gfx_utils/graphic_log.h"
22 #include "gfx_utils/style.h"
23 #include "imgdecode/cache_manager.h"
24 #include "themes/theme.h"
25 
26 namespace OHOS {
UIAnalogClock()27 UIAnalogClock::UIAnalogClock()
28 {
29     touchable_ = true;
30 }
31 
SetHandImage(HandType type,const UIImageView & img,Point position,Point center)32 void UIAnalogClock::SetHandImage(HandType type, const UIImageView& img, Point position, Point center)
33 {
34     Hand* hand = nullptr;
35     if (type == HandType::HOUR_HAND) {
36         hand = &hourHand_;
37     } else if (type == HandType::MINUTE_HAND) {
38         hand = &minuteHand_;
39     } else {
40         hand = &secondHand_;
41     }
42 
43     hand->center_ = center;
44     hand->position_ = position;
45     hand->initAngle_ = 0;
46     hand->preAngle_ = 0;
47     hand->nextAngle_ = 0;
48     hand->drawtype_ = DrawType::DRAW_IMAGE;
49 
50     if (img.GetSrcType() == IMG_SRC_FILE) {
51         CacheEntry entry;
52         RetCode ret = CacheManager::GetInstance().Open(img.GetPath(), *style_, entry);
53         if (ret != RetCode::OK) {
54             return;
55         }
56         hand->imageInfo_ = entry.GetImageInfo();
57     } else {
58         hand->imageInfo_ = *(img.GetImageInfo());
59     }
60 }
61 
SetHandLine(HandType type,Point position,Point center,ColorType color,uint16_t width,uint16_t height,OpacityType opacity)62 void UIAnalogClock::SetHandLine(HandType type,
63                                 Point position,
64                                 Point center,
65                                 ColorType color,
66                                 uint16_t width,
67                                 uint16_t height,
68                                 OpacityType opacity)
69 {
70     Hand* hand = nullptr;
71     if (type == HandType::HOUR_HAND) {
72         hand = &hourHand_;
73     } else if (type == HandType::MINUTE_HAND) {
74         hand = &minuteHand_;
75     } else {
76         hand = &secondHand_;
77     }
78 
79     hand->color_ = color;
80     hand->height_ = height;
81     hand->width_ = width;
82     hand->position_ = position;
83     hand->center_ = center;
84     hand->opacity_ = opacity;
85     hand->initAngle_ = 0;
86     hand->preAngle_ = 0;
87     hand->nextAngle_ = 0;
88     hand->drawtype_ = DrawType::DRAW_LINE;
89 }
90 
GetHandRotateCenter(HandType type) const91 Point UIAnalogClock::GetHandRotateCenter(HandType type) const
92 {
93     if (type == HandType::HOUR_HAND) {
94         return hourHand_.center_;
95     } else if (type == HandType::MINUTE_HAND) {
96         return minuteHand_.center_;
97     } else {
98         return secondHand_.center_;
99     }
100 }
101 
GetHandPosition(HandType type) const102 Point UIAnalogClock::GetHandPosition(HandType type) const
103 {
104     if (type == HandType::HOUR_HAND) {
105         return hourHand_.position_;
106     } else if (type == HandType::MINUTE_HAND) {
107         return minuteHand_.position_;
108     } else {
109         return secondHand_.position_;
110     }
111 }
112 
GetHandInitAngle(HandType type) const113 uint16_t UIAnalogClock::GetHandInitAngle(HandType type) const
114 {
115     if (type == HandType::HOUR_HAND) {
116         return hourHand_.initAngle_;
117     } else if (type == HandType::MINUTE_HAND) {
118         return minuteHand_.initAngle_;
119     } else {
120         return secondHand_.initAngle_;
121     }
122 }
123 
GetHandCurrentAngle(HandType type) const124 uint16_t UIAnalogClock::GetHandCurrentAngle(HandType type) const
125 {
126     if (type == HandType::HOUR_HAND) {
127         return hourHand_.nextAngle_;
128     } else if (type == HandType::MINUTE_HAND) {
129         return minuteHand_.nextAngle_;
130     } else {
131         return secondHand_.nextAngle_;
132     }
133 }
134 
SetInitTime24Hour(uint8_t hour,uint8_t minute,uint8_t second)135 void UIAnalogClock::SetInitTime24Hour(uint8_t hour, uint8_t minute, uint8_t second)
136 {
137     currentHour_ = hour % ONE_DAY_IN_HOUR;
138     currentMinute_ = minute % ONE_HOUR_IN_MINUTE;
139     currentSecond_ = second % ONE_MINUTE_IN_SECOND;
140 
141     hourHand_.initAngle_ = ConvertHandValueToAngle(currentHour_, HALF_DAY_IN_HOUR, currentMinute_, ONE_HOUR_IN_MINUTE);
142     hourHand_.preAngle_ = hourHand_.initAngle_;
143     hourHand_.nextAngle_ = hourHand_.initAngle_;
144 
145     minuteHand_.initAngle_ =
146         ConvertHandValueToAngle(currentMinute_, ONE_HOUR_IN_MINUTE, currentSecond_, ONE_MINUTE_IN_SECOND);
147     minuteHand_.preAngle_ = minuteHand_.initAngle_;
148     minuteHand_.nextAngle_ = minuteHand_.initAngle_;
149 
150     secondHand_.initAngle_ = ConvertHandValueToAngle(currentSecond_, ONE_MINUTE_IN_SECOND);
151     secondHand_.preAngle_ = secondHand_.initAngle_;
152     secondHand_.nextAngle_ = secondHand_.initAngle_;
153 
154     UpdateClock(true);
155     Invalidate();
156 }
157 
SetInitTime12Hour(uint8_t hour,uint8_t minute,uint8_t second,bool am)158 void UIAnalogClock::SetInitTime12Hour(uint8_t hour, uint8_t minute, uint8_t second, bool am)
159 {
160     SetInitTime24Hour((hour % HALF_DAY_IN_HOUR) + (am ? 0 : HALF_DAY_IN_HOUR), minute, second);
161 }
162 
ConvertHandValueToAngle(uint8_t handValue,uint8_t range,uint8_t secondHandValue,uint8_t ratio) const163 uint16_t UIAnalogClock::ConvertHandValueToAngle(uint8_t handValue,
164                                                 uint8_t range,
165                                                 uint8_t secondHandValue,
166                                                 uint8_t ratio) const
167 {
168     if ((range == 0) || (ratio == 0)) {
169         GRAPHIC_LOGW("UIAnalogClock::ConvertHandValueToAngle Invalid range or ratio\n");
170         return 0;
171     }
172     /*
173      * Example: calculate the angle of hour hand
174      * Assume that the time is 5: 30, then range is 12, radio is 60
175      * angle is [(5 * 60  + 30) / (12 * 60)] * 360
176      */
177     uint32_t degree = (static_cast<uint16_t>(handValue) * ratio + secondHandValue);
178     degree = static_cast<uint32_t>(CIRCLE_IN_DEGREE * degree / (static_cast<uint16_t>(range) * ratio));
179 
180     return static_cast<uint16_t>(degree % CIRCLE_IN_DEGREE);
181 }
182 
ConvertHandValueToAngle(uint8_t handValue,uint8_t range) const183 uint16_t UIAnalogClock::ConvertHandValueToAngle(uint8_t handValue, uint8_t range) const
184 {
185     if (range == 0) {
186         GRAPHIC_LOGW("UIAnalogClock::ConvertHandValueToAngle Invalid range or ratio\n");
187         return 0;
188     }
189     /*
190      * Example: calculate the angle of second hand without millisecond handle
191      * Assume that the time is 5:30:30, then range is 60
192      * angle is (30 / 60) * 360
193      */
194     return (static_cast<uint16_t>(handValue) * CIRCLE_IN_DEGREE / range);
195 }
196 
UpdateClock(bool clockInit)197 void UIAnalogClock::UpdateClock(bool clockInit)
198 {
199     hourHand_.nextAngle_ = ConvertHandValueToAngle(currentHour_, HALF_DAY_IN_HOUR, currentMinute_, ONE_HOUR_IN_MINUTE);
200     minuteHand_.nextAngle_ =
201         ConvertHandValueToAngle(currentMinute_, ONE_HOUR_IN_MINUTE, currentSecond_, ONE_MINUTE_IN_SECOND);
202     secondHand_.nextAngle_ = ConvertHandValueToAngle(currentSecond_, ONE_MINUTE_IN_SECOND);
203 
204     Rect rect = GetRect();
205     CalculateRedrawArea(rect, hourHand_, clockInit);
206     CalculateRedrawArea(rect, minuteHand_, clockInit);
207     if (GetWorkMode() == WorkMode::NORMAL) {
208         CalculateRedrawArea(rect, secondHand_, clockInit);
209     }
210 }
211 
OnDraw(BufferInfo & gfxDstBuffer,const Rect & invalidatedArea)212 void UIAnalogClock::OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea)
213 {
214     BaseGfxEngine::GetInstance()->DrawRect(gfxDstBuffer, GetRect(), invalidatedArea, *style_, opaScale_);
215 }
216 
OnPostDraw(BufferInfo & gfxDstBuffer,const Rect & invalidatedArea)217 void UIAnalogClock::OnPostDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea)
218 {
219     UpdateClock(true);
220     Rect current = GetOrigRect();
221     DrawHand(gfxDstBuffer, current, invalidatedArea, hourHand_);
222     DrawHand(gfxDstBuffer, current, invalidatedArea, minuteHand_);
223     if (GetWorkMode() == WorkMode::NORMAL) {
224         DrawHand(gfxDstBuffer, current, invalidatedArea, secondHand_);
225     }
226     UIView::OnPostDraw(gfxDstBuffer, invalidatedArea);
227 }
228 
CalculateRedrawArea(const Rect & current,Hand & hand,bool clockInit)229 void UIAnalogClock::CalculateRedrawArea(const Rect& current, Hand& hand, bool clockInit)
230 {
231     /*
232      * Use the current image as an independent rectangular area
233      * to calculate the coordinate conversion coefficient.
234      */
235     int16_t imgWidth = hand.imageInfo_.header.width;
236     int16_t imgHeight = hand.imageInfo_.header.height;
237 
238     int16_t left = hand.position_.x + current.GetLeft();
239     int16_t right = left + imgWidth - 1;
240     int16_t top = hand.position_.y + current.GetTop();
241     int16_t bottom = top + imgHeight - 1;
242     Rect imgRect(left, top, right, bottom);
243     TransformMap backwardMap(imgRect);
244     Vector2<float> pivot;
245     pivot.x_ = hand.center_.x;
246     pivot.y_ = hand.center_.y;
247 
248     /* Rotate the specified angle,  */
249     backwardMap.Rotate(hand.nextAngle_ - hand.initAngle_, pivot);
250     Rect redraw = hand.target_;
251     hand.target_ = backwardMap.GetBoxRect();
252     hand.trans_ = backwardMap;
253     hand.preAngle_ = hand.nextAngle_;
254     if (!clockInit) {
255         /* Prevent old images from being residued */
256         redraw.Join(redraw, hand.target_);
257         InvalidateRect(redraw);
258     }
259 }
260 
DrawHand(BufferInfo & gfxDstBuffer,const Rect & current,const Rect & invalidatedArea,Hand & hand)261 void UIAnalogClock::DrawHand(BufferInfo& gfxDstBuffer, const Rect& current, const Rect& invalidatedArea, Hand& hand)
262 {
263     if (hand.drawtype_ == DrawType::DRAW_IMAGE) {
264         DrawHandImage(gfxDstBuffer, current, invalidatedArea, hand);
265     } else {
266         DrawHandLine(gfxDstBuffer, invalidatedArea, hand);
267     }
268 }
269 
DrawHandImage(BufferInfo & gfxDstBuffer,const Rect & current,const Rect & invalidatedArea,Hand & hand)270 void UIAnalogClock::DrawHandImage(BufferInfo& gfxDstBuffer,
271                                   const Rect& current,
272                                   const Rect& invalidatedArea,
273                                   Hand& hand)
274 {
275     if (hand.imageInfo_.data == nullptr) {
276         return;
277     }
278     uint8_t pxSize = DrawUtils::GetPxSizeByColorMode(hand.imageInfo_.header.colorMode);
279     TransformDataInfo imageTranDataInfo = {hand.imageInfo_.header, hand.imageInfo_.data, pxSize, BlurLevel::LEVEL0,
280                                            TransformAlgorithm::BILINEAR};
281     BaseGfxEngine::GetInstance()->DrawTransform(gfxDstBuffer, invalidatedArea, {0, 0}, Color::Black(), opaScale_,
282                                                 hand.trans_, imageTranDataInfo);
283 }
284 
DrawHandLine(BufferInfo & gfxDstBuffer,const Rect & invalidatedArea,Hand & hand)285 void UIAnalogClock::DrawHandLine(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea, Hand& hand)
286 {
287     float sinma = Sin(hand.nextAngle_);
288     float cosma = Sin(hand.nextAngle_ + THREE_QUARTER_IN_DEGREE);
289     int32_t handLength = hand.height_;
290     Rect rect = GetRect();
291     Point start;
292     Point end;
293     Point curCenter;
294     curCenter.x = hand.position_.x + hand.center_.x + rect.GetLeft();
295     curCenter.y = hand.position_.y + hand.center_.y + rect.GetTop();
296 
297     int32_t startToCenterLength = hand.center_.y;
298 
299     int32_t xPointLength = static_cast<int32_t>(startToCenterLength * sinma);
300     int32_t yPointLength = static_cast<int32_t>(startToCenterLength * cosma);
301 
302     start.x = xPointLength + curCenter.x;
303     start.y = yPointLength + curCenter.y;
304 
305     /*
306      * @ startToCenterLength: means the length between StartPoint and CenterPoint.
307      * @ handlength: means the hand height.
308      * @ xlength: means X-axis length relative to the center point
309      * @ ylength: means Y-axis length relative to the center point
310      */
311     int32_t xlength = static_cast<int32_t>((startToCenterLength - handLength) * sinma);
312     int32_t ylength = static_cast<int32_t>((startToCenterLength - handLength) * cosma);
313     end.x = xlength + curCenter.x;
314     end.y = ylength + curCenter.y;
315 
316     BaseGfxEngine::GetInstance()->DrawLine(gfxDstBuffer, start, end, invalidatedArea, hand.width_, hand.color_,
317                                            hand.opacity_);
318 }
319 
SetWorkMode(WorkMode newMode)320 void UIAnalogClock::SetWorkMode(WorkMode newMode)
321 {
322     WorkMode oldMode = mode_;
323 
324     if (oldMode != newMode) {
325         /*
326          * After entering the alwayson mode, all child controls are no longer drawn,
327          * making the simplest analog clock.
328          */
329         isViewGroup_ = (newMode == ALWAYS_ON) ? false : true;
330         mode_ = newMode;
331         Invalidate();
332     }
333 }
334 } // namespace OHOS
335