|
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] = NULL; |
|
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 == NULL) |
|
92 gSkinSuite = new SkinSuite; |
|
93 return gSkinSuite->get(st); |
|
94 #else |
|
95 return NULL; |
|
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(NULL); |
|
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")) != NULL) |
|
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(NULL); |
|
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 pressed) |
|
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(), this->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->getButtonState() == kOn_State); |
|
295 canvas->drawRoundRect(r, SkScalarHalf(this->height()), SkScalarHalf(this->height()), p); |
|
296 p.setMaskFilter(NULL); |
|
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, unsigned 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(), NULL, NULL); |
|
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(), fText.size(), fPaint, width) : 0; |
|
361 |
|
362 SkScalar before, after; |
|
363 (void)fPaint.measureText(0, NULL, &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(NULL); |
|
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(NULL); |
|
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(NULL); |
|
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(NULL); |
|
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")) != NULL) |
|
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 |