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_slider.h"
17
18 #include "common/image.h"
19 #include "dock/focus_manager.h"
20 #include "dock/vibrator_manager.h"
21 #include "draw/draw_image.h"
22 #include "engines/gfx/gfx_engine_manager.h"
23 #include "gfx_utils/graphic_log.h"
24 #include "imgdecode/cache_manager.h"
25 #include "themes/theme_manager.h"
26
27 namespace OHOS {
UISlider()28 UISlider::UISlider() : knobWidth_(0), knobStyleAllocFlag_(false), knobImage_(nullptr), listener_(nullptr)
29 {
30 touchable_ = true;
31 draggable_ = true;
32 dragParentInstead_ = false;
33 #if ENABLE_FOCUS_MANAGER
34 focusable_ = true;
35 #endif
36 #if ENABLE_ROTATE_INPUT
37 rotateFactor_ = DEFAULT_SLIDER_ROTATE_FACTOR;
38 cachedRotation_ = 0;
39 #endif
40
41 Theme* theme = ThemeManager::GetInstance().GetCurrent();
42 if (theme != nullptr) {
43 knobStyle_ = &(theme->GetSliderKnobStyle());
44 } else {
45 knobStyle_ = &(StyleDefault::GetSliderKnobStyle());
46 }
47 }
48
~UISlider()49 UISlider::~UISlider()
50 {
51 if (knobImage_ != nullptr) {
52 delete knobImage_;
53 knobImage_ = nullptr;
54 }
55
56 if (knobStyleAllocFlag_) {
57 delete knobStyle_;
58 knobStyle_ = nullptr;
59 knobStyleAllocFlag_ = false;
60 }
61 }
62
SetKnobStyle(const Style & style)63 void UISlider::SetKnobStyle(const Style& style)
64 {
65 if (!knobStyleAllocFlag_) {
66 knobStyle_ = new Style;
67 if (knobStyle_ == nullptr) {
68 GRAPHIC_LOGE("new Style fail");
69 return;
70 }
71 knobStyleAllocFlag_ = true;
72 }
73 *knobStyle_ = style;
74 }
75
SetKnobStyle(uint8_t key,int64_t value)76 void UISlider::SetKnobStyle(uint8_t key, int64_t value)
77 {
78 if (!knobStyleAllocFlag_) {
79 knobStyle_ = new Style(*knobStyle_);
80 if (knobStyle_ == nullptr) {
81 GRAPHIC_LOGE("new Style fail");
82 return;
83 }
84 knobStyleAllocFlag_ = true;
85 }
86 knobStyle_->SetStyle(key, value);
87 }
88
GetKnobStyle() const89 const Style& UISlider::GetKnobStyle() const
90 {
91 return *knobStyle_;
92 }
93
GetKnobStyle(uint8_t key) const94 int64_t UISlider::GetKnobStyle(uint8_t key) const
95 {
96 return knobStyle_->GetStyle(key);
97 }
98
SetKnobImage(const ImageInfo * knobImage)99 void UISlider::SetKnobImage(const ImageInfo* knobImage)
100 {
101 if (!InitImage()) {
102 return;
103 }
104 knobImage_->SetSrc(knobImage);
105 }
106
SetKnobImage(const char * knobImage)107 void UISlider::SetKnobImage(const char* knobImage)
108 {
109 if (!InitImage()) {
110 return;
111 }
112 knobImage_->SetSrc(knobImage);
113 }
114
DrawKnob(BufferInfo & gfxDstBuffer,const Rect & invalidatedArea,const Rect & foregroundRect)115 void UISlider::DrawKnob(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea, const Rect& foregroundRect)
116 {
117 int16_t halfKnobWidth = GetKnobWidth() / 2; // 2: half
118 int16_t offset;
119 Rect knobBar;
120 switch (direction_) {
121 case Direction::DIR_LEFT_TO_RIGHT: {
122 offset = (knobWidth_ - progressHeight_) / 2; // 2: half
123 knobBar.SetRect(foregroundRect.GetRight() - halfKnobWidth, foregroundRect.GetTop() - offset,
124 foregroundRect.GetRight() + halfKnobWidth, foregroundRect.GetBottom() + offset);
125 break;
126 }
127 case Direction::DIR_RIGHT_TO_LEFT: {
128 offset = (knobWidth_ - progressHeight_) / 2; // 2: half
129 knobBar.SetRect(foregroundRect.GetLeft() - halfKnobWidth, foregroundRect.GetTop() - offset,
130 foregroundRect.GetLeft() + halfKnobWidth, foregroundRect.GetBottom() + offset);
131 break;
132 }
133 case Direction::DIR_BOTTOM_TO_TOP: {
134 offset = (knobWidth_ - progressWidth_) / 2; // 2: half
135 knobBar.SetRect(foregroundRect.GetLeft() - offset, foregroundRect.GetTop() - halfKnobWidth,
136 foregroundRect.GetRight() + offset, foregroundRect.GetTop() + halfKnobWidth);
137 break;
138 }
139 case Direction::DIR_TOP_TO_BOTTOM: {
140 offset = (knobWidth_ - progressWidth_) / 2; // 2: half
141 knobBar.SetRect(foregroundRect.GetLeft() - offset, foregroundRect.GetBottom() - halfKnobWidth,
142 foregroundRect.GetRight() + offset, foregroundRect.GetBottom() + halfKnobWidth);
143 break;
144 }
145 default: {
146 GRAPHIC_LOGW("UISlider::DrawKnob Direction error!\n");
147 }
148 }
149 DrawValidRect(gfxDstBuffer, knobImage_, knobBar, invalidatedArea, *knobStyle_, 0);
150 }
151
InitImage()152 bool UISlider::InitImage()
153 {
154 if (!UIAbstractProgress::InitImage()) {
155 return false;
156 }
157 if (knobImage_ == nullptr) {
158 knobImage_ = new Image();
159 if (knobImage_ == nullptr) {
160 GRAPHIC_LOGE("new Image fail");
161 return false;
162 }
163 }
164 return true;
165 }
166
SetImage(const ImageInfo * backgroundImage,const ImageInfo * foregroundImage)167 void UISlider::SetImage(const ImageInfo* backgroundImage, const ImageInfo* foregroundImage)
168 {
169 if (!InitImage()) {
170 return;
171 }
172 backgroundImage_->SetSrc(backgroundImage);
173 foregroundImage_->SetSrc(foregroundImage);
174 }
175
SetImage(const char * backgroundImage,const char * foregroundImage)176 void UISlider::SetImage(const char* backgroundImage, const char* foregroundImage)
177 {
178 if (!InitImage()) {
179 return;
180 }
181 backgroundImage_->SetSrc(backgroundImage);
182 foregroundImage_->SetSrc(foregroundImage);
183 }
184
DrawForeground(BufferInfo & gfxDstBuffer,const Rect & invalidatedArea,Rect & coords)185 void UISlider::DrawForeground(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea, Rect& coords)
186 {
187 Point startPoint;
188 int16_t progressWidth;
189 int16_t progressHeight;
190 uint16_t radius;
191 GetBackgroundParam(startPoint, progressWidth, progressHeight, radius, *foregroundStyle_);
192
193 int16_t left;
194 int16_t right;
195 int16_t top;
196 int16_t bottom;
197 int16_t length;
198 Rect foregroundRect;
199
200 switch (direction_) {
201 case Direction::DIR_LEFT_TO_RIGHT: {
202 length = GetCurrentPos(progressWidth_ + 1);
203 foregroundRect.SetRect(startPoint.x, startPoint.y, startPoint.x + progressWidth - 1,
204 startPoint.y + progressHeight_ - 1);
205
206 left = startPoint.x - radius - 1;
207 right = left + length;
208 coords.SetRect(left, startPoint.y, right, startPoint.y + progressHeight_ - 1);
209 break;
210 }
211 case Direction::DIR_RIGHT_TO_LEFT: {
212 length = GetCurrentPos(progressWidth_ + 1);
213 foregroundRect.SetRect(startPoint.x, startPoint.y, startPoint.x + progressWidth - 1,
214 startPoint.y + progressHeight_ - 1);
215
216 right = startPoint.x + progressWidth + radius + 1;
217 left = right - length;
218 coords.SetRect(left, startPoint.y, right, startPoint.y + progressHeight_ - 1);
219 break;
220 }
221 case Direction::DIR_TOP_TO_BOTTOM: {
222 length = GetCurrentPos(progressHeight_ + 1);
223 foregroundRect.SetRect(startPoint.x, startPoint.y, startPoint.x + progressWidth_ - 1,
224 startPoint.y + progressHeight - 1);
225
226 top = startPoint.y - radius - 1;
227 bottom = top + length;
228 coords.SetRect(startPoint.x, top, startPoint.x + progressWidth_ - 1, bottom);
229 break;
230 }
231 case Direction::DIR_BOTTOM_TO_TOP: {
232 length = GetCurrentPos(progressHeight_ + 1);
233 foregroundRect.SetRect(startPoint.x, startPoint.y, startPoint.x + progressWidth_ - 1,
234 startPoint.y + progressHeight - 1);
235
236 bottom = startPoint.y + progressHeight + radius + 1;
237 top = bottom - length;
238 coords.SetRect(startPoint.x, top, startPoint.x + progressWidth_ - 1, bottom);
239 break;
240 }
241 default: {
242 GRAPHIC_LOGE("UISlider: DrawForeground direction Err!\n");
243 return;
244 }
245 }
246 if (coords.Intersect(coords, invalidatedArea)) {
247 DrawValidRect(gfxDstBuffer, foregroundImage_, foregroundRect, coords, *foregroundStyle_, radius);
248 }
249 }
250
OnDraw(BufferInfo & gfxDstBuffer,const Rect & invalidatedArea)251 void UISlider::OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea)
252 {
253 BaseGfxEngine::GetInstance()->DrawRect(gfxDstBuffer, GetOrigRect(), invalidatedArea, *style_, opaScale_);
254
255 Rect trunc(invalidatedArea);
256 if (trunc.Intersect(trunc, GetOrigRect())) {
257 DrawBackground(gfxDstBuffer, trunc);
258 Rect foregroundRect;
259 DrawForeground(gfxDstBuffer, trunc, foregroundRect);
260 DrawKnob(gfxDstBuffer, trunc, foregroundRect);
261 }
262 }
263
CalculateCurrentValue(int16_t length,int16_t totalLength)264 int32_t UISlider::CalculateCurrentValue(int16_t length, int16_t totalLength)
265 {
266 if (totalLength != 0) {
267 return static_cast<int32_t>(rangeMin_ + (static_cast<int64_t>(rangeMax_) - rangeMin_) * length / totalLength);
268 }
269 return 0;
270 }
271
UpdateCurrentValue(const Point & knobPosition)272 int32_t UISlider::UpdateCurrentValue(const Point& knobPosition)
273 {
274 Point startPoint;
275 Rect rect = GetOrigRect();
276 // 2: Half of the gap
277 startPoint.x = rect.GetLeft() + style_->borderWidth_ + style_->paddingLeft_ + (GetWidth() - progressWidth_) / 2;
278 // 2: Half of the gap
279 startPoint.y = rect.GetTop() + style_->borderWidth_ + style_->paddingTop_ + (GetHeight() - progressHeight_) / 2;
280
281 int32_t value = curValue_;
282 switch (direction_) {
283 case Direction::DIR_LEFT_TO_RIGHT:
284 if (knobPosition.x <= startPoint.x) {
285 value = rangeMin_;
286 } else if (knobPosition.x >= startPoint.x + progressWidth_) {
287 value = rangeMax_;
288 } else {
289 value = CalculateCurrentValue(knobPosition.x - startPoint.x, progressWidth_);
290 }
291 break;
292 case Direction::DIR_RIGHT_TO_LEFT:
293 if (knobPosition.x <= startPoint.x) {
294 value = rangeMax_;
295 } else if (knobPosition.x >= startPoint.x + progressWidth_) {
296 value = rangeMin_;
297 } else {
298 value = CalculateCurrentValue(startPoint.x + progressWidth_ - knobPosition.x, progressWidth_);
299 }
300 break;
301 case Direction::DIR_BOTTOM_TO_TOP:
302 if (knobPosition.y <= startPoint.y) {
303 value = rangeMax_;
304 } else if (knobPosition.y >= startPoint.y + progressHeight_) {
305 value = rangeMin_;
306 } else {
307 value = CalculateCurrentValue(startPoint.y + progressHeight_ - knobPosition.y, progressHeight_);
308 }
309 break;
310 case Direction::DIR_TOP_TO_BOTTOM:
311 if (knobPosition.y <= startPoint.y) {
312 value = rangeMin_;
313 } else if (knobPosition.y >= startPoint.y + progressHeight_) {
314 value = rangeMax_;
315 } else {
316 value = CalculateCurrentValue(knobPosition.y - startPoint.y, progressHeight_);
317 }
318 break;
319 default:
320 GRAPHIC_LOGW("UISlider::UpdateCurrentValue Direction error!\n");
321 }
322 SetValue(value);
323 return value;
324 }
325
OnClickEvent(const ClickEvent & event)326 bool UISlider::OnClickEvent(const ClickEvent& event)
327 {
328 Point knobPosition = event.GetCurrentPos();
329 int32_t value = UpdateCurrentValue(knobPosition);
330 if (listener_ != nullptr) {
331 listener_->OnChange(value);
332 }
333 bool ret = UIView::OnClickEvent(event);
334 Invalidate();
335 return ret;
336 }
337
OnDragEvent(const DragEvent & event)338 bool UISlider::OnDragEvent(const DragEvent& event)
339 {
340 Point knobPosition = event.GetCurrentPos();
341 int32_t value = UpdateCurrentValue(knobPosition);
342 if (listener_ != nullptr) {
343 listener_->OnChange(value);
344 }
345 Invalidate();
346 return UIView::OnDragEvent(event);
347 }
348
OnDragEndEvent(const DragEvent & event)349 bool UISlider::OnDragEndEvent(const DragEvent& event)
350 {
351 Point knobPosition = event.GetCurrentPos();
352 int32_t value = UpdateCurrentValue(knobPosition);
353 if (listener_ != nullptr) {
354 listener_->OnChange(value);
355 listener_->OnRelease(value);
356 }
357 Invalidate();
358 return UIView::OnDragEndEvent(event);
359 }
360
361 #if ENABLE_ROTATE_INPUT
OnRotateEvent(const RotateEvent & event)362 bool UISlider::OnRotateEvent(const RotateEvent& event)
363 {
364 int32_t realRotation = 0;
365 cachedRotation_ += event.GetRotate() * rotateFactor_;
366 realRotation = static_cast<int32_t>(cachedRotation_);
367 if (realRotation == 0) {
368 return UIView::OnRotateEvent(event);
369 }
370 cachedRotation_ = 0;
371 #if ENABLE_VIBRATOR
372 int32_t lastValue = curValue_;
373 #endif
374 SetValue(curValue_ + realRotation);
375 if (listener_ != nullptr) {
376 listener_->OnChange(curValue_);
377 }
378 #if ENABLE_VIBRATOR
379 VibratorFunc vibratorFunc = VibratorManager::GetInstance()->GetVibratorFunc();
380 if (vibratorFunc != nullptr && lastValue != curValue_) {
381 if (curValue_ == rangeMin_ || curValue_ == rangeMax_) {
382 GRAPHIC_LOGI("UISlider::OnRotateEvent calls TYPE_THREE vibrator");
383 vibratorFunc(VibratorType::VIBRATOR_TYPE_THREE);
384 } else {
385 int32_t changedValue = MATH_ABS(curValue_ - lastValue);
386 for (int32_t i = 0; i < changedValue; i++) {
387 GRAPHIC_LOGI("UISlider::OnRotateEvent calls TYPE_TWO vibrator");
388 vibratorFunc(VibratorType::VIBRATOR_TYPE_TWO);
389 }
390 }
391 }
392 #endif
393 return UIView::OnRotateEvent(event);
394 }
395
OnRotateEndEvent(const RotateEvent & event)396 bool UISlider::OnRotateEndEvent(const RotateEvent& event)
397 {
398 cachedRotation_ = 0;
399 return UIView::OnRotateEndEvent(event);
400 }
401 #endif
402 } // namespace OHOS
403