blob: e7eb77257772a9806a28f4db203129722d43267f [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001#include "SkWidgetViews.h"
2#include "SkAnimator.h"
3#include "SkCanvas.h"
4#include "SkPaint.h"
5#include "SkStream.h"
6#include "SkSystemEventTypes.h"
7
8#ifdef SK_DEBUG
9 static void assert_no_attr(const SkDOM& dom, const SkDOM::Node* node, const char attr[])
10 {
11 const char* value = dom.findAttr(node, attr);
12 if (value)
13 SkDebugf("unknown attribute %s=\"%s\"\n", attr, value);
14 }
15#else
16 #define assert_no_attr(dom, node, attr)
17#endif
18/*
19I have moved this to SkWidgetViews.h
20enum SkinEnum {
21 kButton_SkinEnum,
22 kProgress_SkinEnum,
23 kScroll_SkinEnum,
24 kStaticText_SkinEnum,
25
26 kSkinEnumCount
27};
28*/
29
30const char* get_skin_enum_path(SkinEnum se)
31{
32 SkASSERT((unsigned)se < kSkinEnumCount);
33
34 static const char* gSkinPaths[] = {
35 "common/default/default/skins/border3.xml",
36 "common/default/default/skins/button.xml",
37 "common/default/default/skins/progressBar.xml",
38 "common/default/default/skins/scrollBar.xml",
39 "common/default/default/skins/statictextpaint.xml"
40 };
41
42 return gSkinPaths[se];
43}
44
45void init_skin_anim(const char path[], SkAnimator* anim)
46{
47 SkASSERT(path && anim);
48
49 SkFILEStream stream(path);
50
51 if (!stream.isValid())
52 {
53 SkDEBUGF(("init_skin_anim: loading skin failed <%s>\n", path));
54 sk_throw();
55 }
56
57 if (!anim->decodeStream(&stream))
58 {
59 SkDEBUGF(("init_skin_anim: decoding skin failed <%s>\n", path));
60 sk_throw();
61 }
62}
63
64void init_skin_anim(SkinEnum se, SkAnimator* anim)
65{
66 init_skin_anim(get_skin_enum_path(se), anim);
67}
68
69void init_skin_paint(SkinEnum se, SkPaint* paint)
70{
71 SkASSERT(paint);
72
73 SkAnimator anim;
74 SkCanvas canvas;
75
76 init_skin_anim(se, &anim);
77 anim.draw(&canvas, paint, 0);
78}
79
80void inflate_paint(const SkDOM& dom, const SkDOM::Node* node, SkPaint* paint)
81{
82 SkASSERT(paint);
83
84 SkAnimator anim;
85 SkCanvas canvas;
86
87 if (!anim.decodeDOM(dom, node))
88 {
89 SkDEBUGF(("inflate_paint: decoding dom failed\n"));
90 SkDEBUGCODE(dom.dump(node);)
91 sk_throw();
92 }
93 anim.draw(&canvas, paint, 0);
94}
95
96////////////////////////////////////////////////////////////////////////////////////////
97
98SkWidgetView::SkWidgetView() : SkView(SkView::kFocusable_Mask | SkView::kEnabled_Mask)
99{
100}
101
102const char* SkWidgetView::getLabel() const
103{
104 return fLabel.c_str();
105}
106
107void SkWidgetView::getLabel(SkString* label) const
108{
109 if (label)
110 *label = fLabel;
111}
112
113void SkWidgetView::setLabel(const char label[])
114{
115 this->setLabel(label, label ? strlen(label) : 0);
116}
117
118void SkWidgetView::setLabel(const char label[], size_t len)
119{
120 if (label == nil && fLabel.size() != 0 || !fLabel.equals(label, len))
121 {
122 SkString tmp(label, len);
123
124 this->onLabelChange(fLabel.c_str(), tmp.c_str());
125 fLabel.swap(tmp);
126 }
127}
128
129void SkWidgetView::setLabel(const SkString& label)
130{
131 if (fLabel != label)
132 {
133 this->onLabelChange(fLabel.c_str(), label.c_str());
134 fLabel = label;
135 }
136}
137
138bool SkWidgetView::postWidgetEvent()
139{
140 if (!fEvent.isType(""))
141 {
142 SkEvent evt(fEvent); // make a copy since onPrepareWidgetEvent may edit the event
143
144 if (this->onPrepareWidgetEvent(&evt))
145 {
146 SkDEBUGCODE(evt.dump("SkWidgetView::postWidgetEvent");)
147
148 this->postToListeners(evt); // wonder if this should return true if there are > 0 listeners...
149 return true;
150 }
151 }
152 return false;
153}
154
155/*virtual*/ void SkWidgetView::onInflate(const SkDOM& dom, const SkDOM::Node* node)
156{
157 this->INHERITED::onInflate(dom, node);
158
159 const char* label = dom.findAttr(node, "label");
160 if (label)
161 this->setLabel(label);
162
163 if ((node = dom.getFirstChild(node, "event")) != nil)
164 fEvent.inflate(dom, node);
165}
166
167/*virtual*/ void SkWidgetView::onLabelChange(const char oldLabel[], const char newLabel[])
168{
169 this->inval(nil);
170}
171
172static const char gWidgetEventSinkIDSlotName[] = "sk-widget-sinkid-slot";
173
174/*virtual*/ bool SkWidgetView::onPrepareWidgetEvent(SkEvent* evt)
175{
176 evt->setS32(gWidgetEventSinkIDSlotName, this->getSinkID());
177 return true;
178}
179
180SkEventSinkID SkWidgetView::GetWidgetEventSinkID(const SkEvent& evt)
181{
182 int32_t sinkID;
183
184 return evt.findS32(gWidgetEventSinkIDSlotName, &sinkID) ? (SkEventSinkID)sinkID : 0;
185}
186
187///////////////////////////////////////////////////////////////////////////////////////////////////
188
189/*virtual*/ bool SkButtonView::onEvent(const SkEvent& evt)
190{
191 if (evt.isType(SK_EventType_Key) && evt.getFast32() == kOK_SkKey)
192 {
193 this->postWidgetEvent();
194 return true;
195 }
196 return this->INHERITED::onEvent(evt);
197}
198
199///////////////////////////////////////////////////////////////////////////////////////////////////
200
201SkCheckButtonView::SkCheckButtonView() : fCheckState(kOff_CheckState)
202{
203}
204
205void SkCheckButtonView::setCheckState(CheckState state)
206{
207 SkASSERT((unsigned)state <= kUnknown_CheckState);
208
209 if (fCheckState != state)
210 {
211 this->onCheckStateChange(this->getCheckState(), state);
212 fCheckState = SkToU8(state);
213 }
214}
215
216/*virtual*/ void SkCheckButtonView::onCheckStateChange(CheckState oldState, CheckState newState)
217{
218 this->inval(nil);
219}
220
221/*virtual*/ void SkCheckButtonView::onInflate(const SkDOM& dom, const SkDOM::Node* node)
222{
223 this->INHERITED::onInflate(dom, node);
224
225 int index = dom.findList(node, "check-state", "off,on,unknown");
226 if (index >= 0)
227 this->setCheckState((CheckState)index);
228}
229
230static const char gCheckStateSlotName[] = "sk-checkbutton-check-slot";
231
232/*virtual*/ bool SkCheckButtonView::onPrepareWidgetEvent(SkEvent* evt)
233{
234 // could check if we're "disabled", and return false...
235
236 evt->setS32(gCheckStateSlotName, this->getCheckState());
237 return true;
238}
239
240bool SkCheckButtonView::GetWidgetEventCheckState(const SkEvent& evt, CheckState* state)
241{
242 int32_t state32;
243
244 if (evt.findS32(gCheckStateSlotName, &state32))
245 {
246 if (state)
247 *state = (CheckState)state32;
248 return true;
249 }
250 return false;
251}
252
253///////////////////////////////////////////////////////////////////////////////////////////////////
254///////////////////////////////////////////////////////////////////////////////////////////////////
255///////////////////////////////////////////////////////////////////////////////////////////////////
256
257#include "SkTime.h"
258#include <stdio.h>
259
260class SkAnimButtonView : public SkButtonView {
261public:
262 SkAnimButtonView()
263 {
264 fAnim.setHostEventSink(this);
265 init_skin_anim(kButton_SkinEnum, &fAnim);
266 }
267
268protected:
269 virtual void onLabelChange(const char oldLabel[], const char newLabel[])
270 {
271 this->INHERITED::onLabelChange(oldLabel, newLabel);
272
273 SkEvent evt("user");
274 evt.setString("id", "setLabel");
275 evt.setString("LABEL", newLabel);
276 fAnim.doUserEvent(evt);
277 }
278
279 virtual void onFocusChange(bool gainFocus)
280 {
281 this->INHERITED::onFocusChange(gainFocus);
282
283 SkEvent evt("user");
284 evt.setString("id", "setFocus");
285 evt.setS32("FOCUS", gainFocus);
286 fAnim.doUserEvent(evt);
287 }
288
289 virtual void onSizeChange()
290 {
291 this->INHERITED::onSizeChange();
292
293 SkEvent evt("user");
294 evt.setString("id", "setDim");
295 evt.setScalar("dimX", this->width());
296 evt.setScalar("dimY", this->height());
297 fAnim.doUserEvent(evt);
298 }
299
300 virtual void onDraw(SkCanvas* canvas)
301 {
302 SkPaint paint;
303 SkAnimator::DifferenceType diff = fAnim.draw(canvas, &paint, SkTime::GetMSecs());
304
305 if (diff == SkAnimator::kDifferent)
306 this->inval(nil);
307 else if (diff == SkAnimator::kPartiallyDifferent)
308 {
309 SkRect bounds;
310 fAnim.getInvalBounds(&bounds);
311 this->inval(&bounds);
312 }
313 }
314
315 virtual bool onEvent(const SkEvent& evt)
316 {
317 if (evt.isType(SK_EventType_Inval))
318 {
319 this->inval(nil);
320 return true;
321 }
322 if (evt.isType("recommendDim"))
323 {
324 SkScalar height;
325
326 if (evt.findScalar("y", &height))
327 this->setHeight(height);
328 return true;
329 }
330 return this->INHERITED::onEvent(evt);
331 }
332
333 virtual bool onPrepareWidgetEvent(SkEvent* evt)
334 {
335 if (this->INHERITED::onPrepareWidgetEvent(evt))
336 {
337 SkEvent e("user");
338 e.setString("id", "handlePress");
339 (void)fAnim.doUserEvent(e);
340 return true;
341 }
342 return false;
343 }
344
345private:
346 SkAnimator fAnim;
347
348 typedef SkButtonView INHERITED;
349};
350
351////////////////////////////////////////////////////////////////////////////////////////////
352
353#include "SkTextBox.h"
354
355SkStaticTextView::SkStaticTextView()
356{
357 fMargin.set(0, 0);
358 fMode = kFixedSize_Mode;
359 fSpacingAlign = SkTextBox::kStart_SpacingAlign;
360
361 init_skin_paint(kStaticText_SkinEnum, &fPaint);
362}
363
364SkStaticTextView::~SkStaticTextView()
365{
366}
367
368void SkStaticTextView::computeSize()
369{
370 if (fMode == kAutoWidth_Mode)
371 {
372 SkScalar width = fPaint.measureText(fText.c_str(), fText.size());
373 this->setWidth(width + fMargin.fX * 2);
374 }
375 else if (fMode == kAutoHeight_Mode)
376 {
377 SkScalar width = this->width() - fMargin.fX * 2;
378 int lines = width > 0 ? SkTextLineBreaker::CountLines(fText.c_str(), fText.size(), fPaint, width) : 0;
379
380 this->setHeight(lines * fPaint.getFontSpacing() + fMargin.fY * 2);
381 }
382}
383
384void SkStaticTextView::setMode(Mode mode)
385{
386 SkASSERT((unsigned)mode < kModeCount);
387
388 if (fMode != mode)
389 {
390 fMode = SkToU8(mode);
391 this->computeSize();
392 }
393}
394
395void SkStaticTextView::setSpacingAlign(SkTextBox::SpacingAlign align)
396{
397 fSpacingAlign = SkToU8(align);
398 this->inval(nil);
399}
400
401void SkStaticTextView::getMargin(SkPoint* margin) const
402{
403 if (margin)
404 *margin = fMargin;
405}
406
407void SkStaticTextView::setMargin(SkScalar dx, SkScalar dy)
408{
409 if (fMargin.fX != dx || fMargin.fY != dy)
410 {
411 fMargin.set(dx, dy);
412 this->computeSize();
413 this->inval(nil);
414 }
415}
416
417size_t SkStaticTextView::getText(SkString* text) const
418{
419 if (text)
420 *text = fText;
421 return fText.size();
422}
423
424size_t SkStaticTextView::getText(char text[]) const
425{
426 if (text)
427 memcpy(text, fText.c_str(), fText.size());
428 return fText.size();
429}
430
431void SkStaticTextView::setText(const SkString& text)
432{
433 this->setText(text.c_str(), text.size());
434}
435
436void SkStaticTextView::setText(const char text[])
437{
438 if (text == nil)
439 text = "";
440 this->setText(text, strlen(text));
441}
442
443void SkStaticTextView::setText(const char text[], size_t len)
444{
445 if (!fText.equals(text, len))
446 {
447 fText.set(text, len);
448 this->computeSize();
449 this->inval(nil);
450 }
451}
452
453void SkStaticTextView::getPaint(SkPaint* paint) const
454{
455 if (paint)
456 *paint = fPaint;
457}
458
459void SkStaticTextView::setPaint(const SkPaint& paint)
460{
461 if (fPaint != paint)
462 {
463 fPaint = paint;
464 this->computeSize();
465 this->inval(nil);
466 }
467}
468
469void SkStaticTextView::onDraw(SkCanvas* canvas)
470{
471 this->INHERITED::onDraw(canvas);
472
473 if (fText.isEmpty())
474 return;
475
476 SkTextBox box;
477
478 box.setMode(fMode == kAutoWidth_Mode ? SkTextBox::kOneLine_Mode : SkTextBox::kLineBreak_Mode);
479 box.setSpacingAlign(this->getSpacingAlign());
480 box.setBox(fMargin.fX, fMargin.fY, this->width() - fMargin.fX, this->height() - fMargin.fY);
481 box.draw(canvas, fText.c_str(), fText.size(), fPaint);
482}
483
484void SkStaticTextView::onInflate(const SkDOM& dom, const SkDOM::Node* node)
485{
486 this->INHERITED::onInflate(dom, node);
487
488 int index;
489 if ((index = dom.findList(node, "mode", "fixed,auto-width,auto-height")) >= 0)
490 this->setMode((Mode)index);
491 else
492 assert_no_attr(dom, node, "mode");
493
494 if ((index = dom.findList(node, "spacing-align", "start,center,end")) >= 0)
495 this->setSpacingAlign((SkTextBox::SpacingAlign)index);
496 else
497 assert_no_attr(dom, node, "spacing-align");
498
499 SkScalar s[2];
500 if (dom.findScalars(node, "margin", s, 2))
501 this->setMargin(s[0], s[1]);
502 else
503 assert_no_attr(dom, node, "margin");
504
505 const char* text = dom.findAttr(node, "text");
506 if (text)
507 this->setText(text);
508
509 if ((node = dom.getFirstChild(node, "paint")) != nil &&
510 (node = dom.getFirstChild(node, "screenplay")) != nil)
511 {
512 inflate_paint(dom, node, &fPaint);
513 }
514}
515
516////////////////////////////////////////////////////////////////////////////////////////////
517////////////////////////////////////////////////////////////////////////////////////////////
518
519SkView* SkWidgetFactory(const char name[])
520{
521 if (name == nil)
522 return nil;
523
524 // must be in the same order as the SkSkinWidgetEnum is declared
525 static const char* gNames[] = {
526 "sk-border",
527 "sk-button",
528 "sk-image",
529 "sk-list",
530 "sk-progress",
531 "sk-scroll",
532 "sk-text"
533
534 };
535
536 for (int i = 0; i < SK_ARRAY_COUNT(gNames); i++)
537 if (!strcmp(gNames[i], name))
538 return SkWidgetFactory((SkWidgetEnum)i);
539
540 return nil;
541}
542
543#include "SkImageView.h"
544#include "SkProgressBarView.h"
545#include "SkScrollBarView.h"
546#include "SkBorderView.h"
547
548SkView* SkWidgetFactory(SkWidgetEnum sw)
549{
550 switch (sw) {
551 case kBorder_WidgetEnum:
552 return new SkBorderView;
553 case kButton_WidgetEnum:
554 return new SkAnimButtonView;
555 case kImage_WidgetEnum:
556 return new SkImageView;
557 case kList_WidgetEnum:
558 return new SkListView;
559 case kProgress_WidgetEnum:
560 return new SkProgressBarView;
561 case kScroll_WidgetEnum:
562 return new SkScrollBarView;
563 case kText_WidgetEnum:
564 return new SkStaticTextView;
565 default:
566 SkASSERT(!"unknown enum passed to SkWidgetFactory");
567 break;
568 }
569 return nil;
570}