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