OLD | NEW |
| (Empty) |
1 | |
2 /* | |
3 * Copyright 2011 Google Inc. | |
4 * | |
5 * Use of this source code is governed by a BSD-style license that can be | |
6 * found in the LICENSE file. | |
7 */ | |
8 #include "SkWidget.h" | |
9 #include "SkCanvas.h" | |
10 #include "SkKey.h" | |
11 #include "SkParsePaint.h" | |
12 #include "SkSystemEventTypes.h" | |
13 #include "SkTextBox.h" | |
14 | |
15 #if 0 | |
16 | |
17 #ifdef SK_DEBUG | |
18 static void assert_no_attr(const SkDOM& dom, const SkDOM::Node* node, const
char attr[]) | |
19 { | |
20 const char* value = dom.findAttr(node, attr); | |
21 if (value) | |
22 SkDebugf("unknown attribute %s=\"%s\"\n", attr, value); | |
23 } | |
24 #else | |
25 #define assert_no_attr(dom, node, attr) | |
26 #endif | |
27 | |
28 #include "SkAnimator.h" | |
29 #include "SkTime.h" | |
30 | |
31 /////////////////////////////////////////////////////////////////////////////// | |
32 | |
33 enum SkinType { | |
34 kPushButton_SkinType, | |
35 kStaticText_SkinType, | |
36 | |
37 kSkinTypeCount | |
38 }; | |
39 | |
40 struct SkinSuite { | |
41 SkinSuite(); | |
42 ~SkinSuite() | |
43 { | |
44 for (int i = 0; i < kSkinTypeCount; i++) | |
45 delete fAnimators[i]; | |
46 } | |
47 | |
48 SkAnimator* get(SkinType); | |
49 | |
50 private: | |
51 SkAnimator* fAnimators[kSkinTypeCount]; | |
52 }; | |
53 | |
54 SkinSuite::SkinSuite() | |
55 { | |
56 static const char kSkinPath[] = "skins/"; | |
57 | |
58 static const char* gSkinNames[] = { | |
59 "pushbutton_skin.xml", | |
60 "statictext_skin.xml" | |
61 }; | |
62 | |
63 for (unsigned i = 0; i < SK_ARRAY_COUNT(gSkinNames); i++) | |
64 { | |
65 size_t len = strlen(gSkinNames[i]); | |
66 SkString path(sizeof(kSkinPath) - 1 + len); | |
67 | |
68 memcpy(path.writable_str(), kSkinPath, sizeof(kSkinPath) - 1); | |
69 memcpy(path.writable_str() + sizeof(kSkinPath) - 1, gSkinNames[i], len); | |
70 | |
71 fAnimators[i] = new SkAnimator; | |
72 if (!fAnimators[i]->decodeURI(path.c_str())) | |
73 { | |
74 delete fAnimators[i]; | |
75 fAnimators[i] = nullptr; | |
76 } | |
77 } | |
78 } | |
79 | |
80 SkAnimator* SkinSuite::get(SkinType st) | |
81 { | |
82 SkASSERT((unsigned)st < kSkinTypeCount); | |
83 return fAnimators[st]; | |
84 } | |
85 | |
86 static SkinSuite* gSkinSuite; | |
87 | |
88 static SkAnimator* get_skin_animator(SkinType st) | |
89 { | |
90 #if 0 | |
91 if (gSkinSuite == nullptr) | |
92 gSkinSuite = new SkinSuite; | |
93 return gSkinSuite->get(st); | |
94 #else | |
95 return nullptr; | |
96 #endif | |
97 } | |
98 | |
99 /////////////////////////////////////////////////////////////////////////////// | |
100 | |
101 void SkWidget::Init() | |
102 { | |
103 } | |
104 | |
105 void SkWidget::Term() | |
106 { | |
107 delete gSkinSuite; | |
108 } | |
109 | |
110 void SkWidget::onEnabledChange() | |
111 { | |
112 this->inval(nullptr); | |
113 } | |
114 | |
115 void SkWidget::postWidgetEvent() | |
116 { | |
117 if (!fEvent.isType("") && this->hasListeners()) | |
118 { | |
119 this->prepareWidgetEvent(&fEvent); | |
120 this->postToListeners(fEvent); | |
121 } | |
122 } | |
123 | |
124 void SkWidget::prepareWidgetEvent(SkEvent*) | |
125 { | |
126 // override in subclass to add any additional fields before posting | |
127 } | |
128 | |
129 void SkWidget::onInflate(const SkDOM& dom, const SkDOM::Node* node) | |
130 { | |
131 this->INHERITED::onInflate(dom, node); | |
132 | |
133 if ((node = dom.getFirstChild(node, "event")) != nullptr) | |
134 fEvent.inflate(dom, node); | |
135 } | |
136 | |
137 /////////////////////////////////////////////////////////////////////////////// | |
138 | |
139 size_t SkHasLabelWidget::getLabel(SkString* str) const | |
140 { | |
141 if (str) | |
142 *str = fLabel; | |
143 return fLabel.size(); | |
144 } | |
145 | |
146 size_t SkHasLabelWidget::getLabel(char buffer[]) const | |
147 { | |
148 if (buffer) | |
149 memcpy(buffer, fLabel.c_str(), fLabel.size()); | |
150 return fLabel.size(); | |
151 } | |
152 | |
153 void SkHasLabelWidget::setLabel(const SkString& str) | |
154 { | |
155 this->setLabel(str.c_str(), str.size()); | |
156 } | |
157 | |
158 void SkHasLabelWidget::setLabel(const char label[]) | |
159 { | |
160 this->setLabel(label, strlen(label)); | |
161 } | |
162 | |
163 void SkHasLabelWidget::setLabel(const char label[], size_t len) | |
164 { | |
165 if (!fLabel.equals(label, len)) | |
166 { | |
167 fLabel.set(label, len); | |
168 this->onLabelChange(); | |
169 } | |
170 } | |
171 | |
172 void SkHasLabelWidget::onLabelChange() | |
173 { | |
174 // override in subclass | |
175 } | |
176 | |
177 void SkHasLabelWidget::onInflate(const SkDOM& dom, const SkDOM::Node* node) | |
178 { | |
179 this->INHERITED::onInflate(dom, node); | |
180 | |
181 const char* text = dom.findAttr(node, "label"); | |
182 if (text) | |
183 this->setLabel(text); | |
184 } | |
185 | |
186 ////////////////////////////////////////////////////////////////////////////////
///// | |
187 | |
188 void SkButtonWidget::setButtonState(State state) | |
189 { | |
190 if (fState != state) | |
191 { | |
192 fState = state; | |
193 this->onButtonStateChange(); | |
194 } | |
195 } | |
196 | |
197 void SkButtonWidget::onButtonStateChange() | |
198 { | |
199 this->inval(nullptr); | |
200 } | |
201 | |
202 void SkButtonWidget::onInflate(const SkDOM& dom, const SkDOM::Node* node) | |
203 { | |
204 this->INHERITED::onInflate(dom, node); | |
205 | |
206 int index; | |
207 if ((index = dom.findList(node, "buttonState", "off,on,unknown")) >= 0) | |
208 this->setButtonState((State)index); | |
209 } | |
210 | |
211 ////////////////////////////////////////////////////////////////////////////////
///// | |
212 | |
213 bool SkPushButtonWidget::onEvent(const SkEvent& evt) | |
214 { | |
215 if (evt.isType(SK_EventType_Key) && evt.getFast32() == kOK_SkKey) | |
216 { | |
217 this->postWidgetEvent(); | |
218 return true; | |
219 } | |
220 return this->INHERITED::onEvent(evt); | |
221 } | |
222 | |
223 static const char* computeAnimatorState(int enabled, int focused, SkButtonWidget
::State state) | |
224 { | |
225 if (!enabled) | |
226 return "disabled"; | |
227 if (state == SkButtonWidget::kOn_State) | |
228 { | |
229 SkASSERT(focused); | |
230 return "enabled-pressed"; | |
231 } | |
232 if (focused) | |
233 return "enabled-focused"; | |
234 return "enabled"; | |
235 } | |
236 | |
237 #include "SkBlurMask.h" | |
238 #include "SkBlurMaskFilter.h" | |
239 #include "SkEmbossMaskFilter.h" | |
240 | |
241 static void create_emboss(SkPaint* paint, SkScalar radius, bool focus, bool pres
sed) | |
242 { | |
243 SkEmbossMaskFilter::Light light; | |
244 | |
245 light.fDirection[0] = SK_Scalar1/2; | |
246 light.fDirection[1] = SK_Scalar1/2; | |
247 light.fDirection[2] = SK_Scalar1/3; | |
248 light.fAmbient = 0x48; | |
249 light.fSpecular = 0x80; | |
250 | |
251 if (pressed) | |
252 { | |
253 light.fDirection[0] = -light.fDirection[0]; | |
254 light.fDirection[1] = -light.fDirection[1]; | |
255 } | |
256 if (focus) | |
257 light.fDirection[2] += SK_Scalar1/4; | |
258 | |
259 SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(radius); | |
260 paint->setMaskFilter(new SkEmbossMaskFilter(sigma, light))->unref(); | |
261 } | |
262 | |
263 void SkPushButtonWidget::onDraw(SkCanvas* canvas) | |
264 { | |
265 this->INHERITED::onDraw(canvas); | |
266 | |
267 SkString label; | |
268 this->getLabel(&label); | |
269 | |
270 SkAnimator* anim = get_skin_animator(kPushButton_SkinType); | |
271 | |
272 if (anim) | |
273 { | |
274 SkEvent evt("user"); | |
275 | |
276 evt.setString("id", "prime"); | |
277 evt.setScalar("prime-width", this->width()); | |
278 evt.setScalar("prime-height", this->height()); | |
279 evt.setString("prime-text", label); | |
280 evt.setString("prime-state", computeAnimatorState(this->isEnabled(), thi
s->hasFocus(), this->getButtonState())); | |
281 | |
282 (void)anim->doUserEvent(evt); | |
283 SkPaint paint; | |
284 anim->draw(canvas, &paint, SkTime::GetMSecs()); | |
285 } | |
286 else | |
287 { | |
288 SkRect r; | |
289 SkPaint p; | |
290 | |
291 r.set(0, 0, this->width(), this->height()); | |
292 p.setAntiAliasOn(true); | |
293 p.setColor(SK_ColorBLUE); | |
294 create_emboss(&p, SkIntToScalar(12)/5, this->hasFocus(), this->getButton
State() == kOn_State); | |
295 canvas->drawRoundRect(r, SkScalarHalf(this->height()), SkScalarHalf(this
->height()), p); | |
296 p.setMaskFilter(nullptr); | |
297 | |
298 p.setTextAlign(SkPaint::kCenter_Align); | |
299 | |
300 SkTextBox box; | |
301 box.setMode(SkTextBox::kOneLine_Mode); | |
302 box.setSpacingAlign(SkTextBox::kCenter_SpacingAlign); | |
303 box.setBox(0, 0, this->width(), this->height()); | |
304 | |
305 // if (this->getButtonState() == kOn_State) | |
306 // p.setColor(SK_ColorRED); | |
307 // else | |
308 p.setColor(SK_ColorWHITE); | |
309 | |
310 box.draw(canvas, label.c_str(), label.size(), p); | |
311 } | |
312 } | |
313 | |
314 SkView::Click* SkPushButtonWidget::onFindClickHandler(SkScalar x, SkScalar y, un
signed modi) | |
315 { | |
316 this->acceptFocus(); | |
317 return new Click(this); | |
318 } | |
319 | |
320 bool SkPushButtonWidget::onClick(Click* click) | |
321 { | |
322 SkRect r; | |
323 State state = kOff_State; | |
324 | |
325 this->getLocalBounds(&r); | |
326 if (r.contains(click->fCurr)) | |
327 { | |
328 if (click->fState == Click::kUp_State) | |
329 this->postWidgetEvent(); | |
330 else | |
331 state = kOn_State; | |
332 } | |
333 this->setButtonState(state); | |
334 return true; | |
335 } | |
336 | |
337 ////////////////////////////////////////////////////////////////////////////////
////////// | |
338 | |
339 SkStaticTextView::SkStaticTextView(U32 flags) : SkView(flags) | |
340 { | |
341 fMargin.set(0, 0); | |
342 fMode = kFixedSize_Mode; | |
343 fSpacingAlign = SkTextBox::kStart_SpacingAlign; | |
344 } | |
345 | |
346 SkStaticTextView::~SkStaticTextView() | |
347 { | |
348 } | |
349 | |
350 void SkStaticTextView::computeSize() | |
351 { | |
352 if (fMode == kAutoWidth_Mode) | |
353 { | |
354 SkScalar width = fPaint.measureText(fText.c_str(), fText.size(), nullptr
, nullptr); | |
355 this->setWidth(width + fMargin.fX * 2); | |
356 } | |
357 else if (fMode == kAutoHeight_Mode) | |
358 { | |
359 SkScalar width = this->width() - fMargin.fX * 2; | |
360 int lines = width > 0 ? SkTextLineBreaker::CountLines(fText.c_str(), fTe
xt.size(), fPaint, width) : 0; | |
361 | |
362 SkScalar before, after; | |
363 (void)fPaint.measureText(0, nullptr, &before, &after); | |
364 | |
365 this->setHeight(lines * (after - before) + fMargin.fY * 2); | |
366 } | |
367 } | |
368 | |
369 void SkStaticTextView::setMode(Mode mode) | |
370 { | |
371 SkASSERT((unsigned)mode < kModeCount); | |
372 | |
373 if (fMode != mode) | |
374 { | |
375 fMode = SkToU8(mode); | |
376 this->computeSize(); | |
377 } | |
378 } | |
379 | |
380 void SkStaticTextView::setSpacingAlign(SkTextBox::SpacingAlign align) | |
381 { | |
382 fSpacingAlign = SkToU8(align); | |
383 this->inval(nullptr); | |
384 } | |
385 | |
386 void SkStaticTextView::getMargin(SkPoint* margin) const | |
387 { | |
388 if (margin) | |
389 *margin = fMargin; | |
390 } | |
391 | |
392 void SkStaticTextView::setMargin(SkScalar dx, SkScalar dy) | |
393 { | |
394 if (fMargin.fX != dx || fMargin.fY != dy) | |
395 { | |
396 fMargin.set(dx, dy); | |
397 this->computeSize(); | |
398 this->inval(nullptr); | |
399 } | |
400 } | |
401 | |
402 size_t SkStaticTextView::getText(SkString* text) const | |
403 { | |
404 if (text) | |
405 *text = fText; | |
406 return fText.size(); | |
407 } | |
408 | |
409 size_t SkStaticTextView::getText(char text[]) const | |
410 { | |
411 if (text) | |
412 memcpy(text, fText.c_str(), fText.size()); | |
413 return fText.size(); | |
414 } | |
415 | |
416 void SkStaticTextView::setText(const SkString& text) | |
417 { | |
418 this->setText(text.c_str(), text.size()); | |
419 } | |
420 | |
421 void SkStaticTextView::setText(const char text[]) | |
422 { | |
423 this->setText(text, strlen(text)); | |
424 } | |
425 | |
426 void SkStaticTextView::setText(const char text[], size_t len) | |
427 { | |
428 if (!fText.equals(text, len)) | |
429 { | |
430 fText.set(text, len); | |
431 this->computeSize(); | |
432 this->inval(nullptr); | |
433 } | |
434 } | |
435 | |
436 void SkStaticTextView::getPaint(SkPaint* paint) const | |
437 { | |
438 if (paint) | |
439 *paint = fPaint; | |
440 } | |
441 | |
442 void SkStaticTextView::setPaint(const SkPaint& paint) | |
443 { | |
444 if (fPaint != paint) | |
445 { | |
446 fPaint = paint; | |
447 this->computeSize(); | |
448 this->inval(nullptr); | |
449 } | |
450 } | |
451 | |
452 void SkStaticTextView::onDraw(SkCanvas* canvas) | |
453 { | |
454 this->INHERITED::onDraw(canvas); | |
455 | |
456 if (fText.isEmpty()) | |
457 return; | |
458 | |
459 SkTextBox box; | |
460 | |
461 box.setMode(fMode == kAutoWidth_Mode ? SkTextBox::kOneLine_Mode : SkTextBox:
:kLineBreak_Mode); | |
462 box.setSpacingAlign(this->getSpacingAlign()); | |
463 box.setBox(fMargin.fX, fMargin.fY, this->width() - fMargin.fX, this->height(
) - fMargin.fY); | |
464 box.draw(canvas, fText.c_str(), fText.size(), fPaint); | |
465 } | |
466 | |
467 void SkStaticTextView::onInflate(const SkDOM& dom, const SkDOM::Node* node) | |
468 { | |
469 this->INHERITED::onInflate(dom, node); | |
470 | |
471 int index; | |
472 if ((index = dom.findList(node, "mode", "fixed,auto-width,auto-height")) >=
0) | |
473 this->setMode((Mode)index); | |
474 else | |
475 assert_no_attr(dom, node, "mode"); | |
476 | |
477 if ((index = dom.findList(node, "spacing-align", "start,center,end")) >= 0) | |
478 this->setSpacingAlign((SkTextBox::SpacingAlign)index); | |
479 else | |
480 assert_no_attr(dom, node, "mode"); | |
481 | |
482 SkScalar s[2]; | |
483 if (dom.findScalars(node, "margin", s, 2)) | |
484 this->setMargin(s[0], s[1]); | |
485 else | |
486 assert_no_attr(dom, node, "margin"); | |
487 | |
488 const char* text = dom.findAttr(node, "text"); | |
489 if (text) | |
490 this->setText(text); | |
491 | |
492 if ((node = dom.getFirstChild(node, "paint")) != nullptr) | |
493 SkPaint_Inflate(&fPaint, dom, node); | |
494 } | |
495 | |
496 ////////////////////////////////////////////////////////////////////////////////
///////////////////// | |
497 | |
498 #include "SkImageDecoder.h" | |
499 | |
500 SkBitmapView::SkBitmapView(U32 flags) : SkView(flags) | |
501 { | |
502 } | |
503 | |
504 SkBitmapView::~SkBitmapView() | |
505 { | |
506 } | |
507 | |
508 bool SkBitmapView::getBitmap(SkBitmap* bitmap) const | |
509 { | |
510 if (bitmap) | |
511 *bitmap = fBitmap; | |
512 return fBitmap.colorType() != kUnknown_SkColorType; | |
513 } | |
514 | |
515 void SkBitmapView::setBitmap(const SkBitmap* bitmap, bool viewOwnsPixels) | |
516 { | |
517 if (bitmap) | |
518 { | |
519 fBitmap = *bitmap; | |
520 fBitmap.setOwnsPixels(viewOwnsPixels); | |
521 } | |
522 } | |
523 | |
524 bool SkBitmapView::loadBitmapFromFile(const char path[]) | |
525 { | |
526 SkBitmap bitmap; | |
527 | |
528 if (SkImageDecoder::DecodeFile(path, &bitmap)) | |
529 { | |
530 this->setBitmap(&bitmap, true); | |
531 bitmap.setOwnsPixels(false); | |
532 return true; | |
533 } | |
534 return false; | |
535 } | |
536 | |
537 void SkBitmapView::onDraw(SkCanvas* canvas) | |
538 { | |
539 if (fBitmap.colorType() != kUnknown_SkColorType && | |
540 fBitmap.width() && fBitmap.height()) | |
541 { | |
542 SkAutoCanvasRestore restore(canvas, true); | |
543 SkPaint p; | |
544 | |
545 p.setFilterType(SkPaint::kBilinear_FilterType); | |
546 canvas->scale( this->width() / fBitmap.width(), | |
547 this->height() / fBitmap.height(), | |
548 0, 0); | |
549 canvas->drawBitmap(fBitmap, 0, 0, p); | |
550 } | |
551 } | |
552 | |
553 void SkBitmapView::onInflate(const SkDOM& dom, const SkDOM::Node* node) | |
554 { | |
555 this->INHERITED::onInflate(dom, node); | |
556 | |
557 const char* src = dom.findAttr(node, "src"); | |
558 if (src) | |
559 (void)this->loadBitmapFromFile(src); | |
560 } | |
561 | |
562 #endif | |
OLD | NEW |