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 "SkWidgetViews.h"
9#include "SkAnimator.h"
10#include "SkCanvas.h"
11#include "SkPaint.h"
12#include "SkStream.h"
13#include "SkSystemEventTypes.h"
14
15#ifdef SK_DEBUG
16	static void assert_no_attr(const SkDOM& dom, const SkDOM::Node* node, const char attr[])
17	{
18		const char* value = dom.findAttr(node, attr);
19		if (value)
20			SkDebugf("unknown attribute %s=\"%s\"\n", attr, value);
21	}
22#else
23	#define assert_no_attr(dom, node, attr)
24#endif
25/*
26I have moved this to SkWidgetViews.h
27enum SkinEnum {
28	kButton_SkinEnum,
29	kProgress_SkinEnum,
30	kScroll_SkinEnum,
31	kStaticText_SkinEnum,
32
33	kSkinEnumCount
34};
35*/
36
37const char* get_skin_enum_path(SkinEnum se)
38{
39	SkASSERT((unsigned)se < kSkinEnumCount);
40
41	static const char* gSkinPaths[] = {
42            "common/default/default/skins/border3.xml",
43            "common/default/default/skins/button.xml",
44            "common/default/default/skins/progressBar.xml",
45            "common/default/default/skins/scrollBar.xml",
46            "common/default/default/skins/statictextpaint.xml"
47	};
48
49	return gSkinPaths[se];
50}
51
52void init_skin_anim(const char path[], SkAnimator* anim)
53{
54	SkASSERT(path && anim);
55
56	SkFILEStream	stream(path);
57
58	if (!stream.isValid())
59	{
60		SkDEBUGF(("init_skin_anim: loading skin failed <%s>\n", path));
61		sk_throw();
62	}
63
64	if (!anim->decodeStream(&stream))
65	{
66		SkDEBUGF(("init_skin_anim: decoding skin failed <%s>\n", path));
67		sk_throw();
68	}
69}
70
71void init_skin_anim(SkinEnum se, SkAnimator* anim)
72{
73	init_skin_anim(get_skin_enum_path(se), anim);
74}
75
76void init_skin_paint(SkinEnum se, SkPaint* paint)
77{
78	SkASSERT(paint);
79
80	SkAnimator	anim;
81	SkCanvas	canvas;
82
83	init_skin_anim(se, &anim);
84	anim.draw(&canvas, paint, 0);
85}
86
87void inflate_paint(const SkDOM& dom, const SkDOM::Node* node, SkPaint* paint)
88{
89	SkASSERT(paint);
90
91	SkAnimator	anim;
92	SkCanvas	canvas;
93
94	if (!anim.decodeDOM(dom, node))
95	{
96		SkDEBUGF(("inflate_paint: decoding dom failed\n"));
97		SkDEBUGCODE(dom.dump(node);)
98		sk_throw();
99	}
100	anim.draw(&canvas, paint, 0);
101}
102
103////////////////////////////////////////////////////////////////////////////////////////
104
105SkWidgetView::SkWidgetView() : SkView(SkView::kFocusable_Mask | SkView::kEnabled_Mask)
106{
107}
108
109const char* SkWidgetView::getLabel() const
110{
111	return fLabel.c_str();
112}
113
114void SkWidgetView::getLabel(SkString* label) const
115{
116	if (label)
117		*label = fLabel;
118}
119
120void SkWidgetView::setLabel(const char label[])
121{
122	this->setLabel(label, label ? strlen(label) : 0);
123}
124
125void SkWidgetView::setLabel(const char label[], size_t len)
126{
127	if ((label == NULL && fLabel.size() != 0) || !fLabel.equals(label, len))
128	{
129		SkString	tmp(label, len);
130
131		this->onLabelChange(fLabel.c_str(), tmp.c_str());
132		fLabel.swap(tmp);
133	}
134}
135
136void SkWidgetView::setLabel(const SkString& label)
137{
138	if (fLabel != label)
139	{
140		this->onLabelChange(fLabel.c_str(), label.c_str());
141		fLabel = label;
142	}
143}
144
145bool SkWidgetView::postWidgetEvent()
146{
147	if (!fEvent.isType(""))
148	{
149		SkEvent	evt(fEvent);	// make a copy since onPrepareWidgetEvent may edit the event
150
151		if (this->onPrepareWidgetEvent(&evt))
152		{
153			SkDEBUGCODE(evt.dump("SkWidgetView::postWidgetEvent");)
154
155			this->postToListeners(evt);	// wonder if this should return true if there are > 0 listeners...
156			return true;
157		}
158	}
159	return false;
160}
161
162/*virtual*/ void SkWidgetView::onInflate(const SkDOM& dom, const SkDOM::Node* node)
163{
164	this->INHERITED::onInflate(dom, node);
165
166	const char* label = dom.findAttr(node, "label");
167	if (label)
168		this->setLabel(label);
169
170	if ((node = dom.getFirstChild(node, "event")) != NULL)
171		fEvent.inflate(dom, node);
172}
173
174/*virtual*/ void SkWidgetView::onLabelChange(const char oldLabel[], const char newLabel[])
175{
176	this->inval(NULL);
177}
178
179static const char gWidgetEventSinkIDSlotName[] = "sk-widget-sinkid-slot";
180
181/*virtual*/ bool SkWidgetView::onPrepareWidgetEvent(SkEvent* evt)
182{
183	evt->setS32(gWidgetEventSinkIDSlotName, this->getSinkID());
184	return true;
185}
186
187SkEventSinkID SkWidgetView::GetWidgetEventSinkID(const SkEvent& evt)
188{
189	int32_t	sinkID;
190
191	return evt.findS32(gWidgetEventSinkIDSlotName, &sinkID) ? (SkEventSinkID)sinkID : 0;
192}
193
194///////////////////////////////////////////////////////////////////////////////////////////////////
195
196/*virtual*/ bool SkButtonView::onEvent(const SkEvent& evt)
197{
198	if (evt.isType(SK_EventType_Key) && evt.getFast32() == kOK_SkKey)
199	{
200		this->postWidgetEvent();
201		return true;
202	}
203	return this->INHERITED::onEvent(evt);
204}
205
206///////////////////////////////////////////////////////////////////////////////////////////////////
207
208SkCheckButtonView::SkCheckButtonView() : fCheckState(kOff_CheckState)
209{
210}
211
212void SkCheckButtonView::setCheckState(CheckState state)
213{
214	SkASSERT((unsigned)state <= kUnknown_CheckState);
215
216	if (fCheckState != state)
217	{
218		this->onCheckStateChange(this->getCheckState(), state);
219		fCheckState = SkToU8(state);
220	}
221}
222
223/*virtual*/ void SkCheckButtonView::onCheckStateChange(CheckState oldState, CheckState newState)
224{
225	this->inval(NULL);
226}
227
228/*virtual*/ void SkCheckButtonView::onInflate(const SkDOM& dom, const SkDOM::Node* node)
229{
230	this->INHERITED::onInflate(dom, node);
231
232	int index = dom.findList(node, "check-state", "off,on,unknown");
233	if (index >= 0)
234		this->setCheckState((CheckState)index);
235}
236
237static const char gCheckStateSlotName[] = "sk-checkbutton-check-slot";
238
239/*virtual*/ bool SkCheckButtonView::onPrepareWidgetEvent(SkEvent* evt)
240{
241	// could check if we're "disabled", and return false...
242
243	evt->setS32(gCheckStateSlotName, this->getCheckState());
244	return true;
245}
246
247bool SkCheckButtonView::GetWidgetEventCheckState(const SkEvent& evt, CheckState* state)
248{
249	int32_t	state32;
250
251	if (evt.findS32(gCheckStateSlotName, &state32))
252	{
253		if (state)
254			*state = (CheckState)state32;
255		return true;
256	}
257	return false;
258}
259
260///////////////////////////////////////////////////////////////////////////////////////////////////
261///////////////////////////////////////////////////////////////////////////////////////////////////
262///////////////////////////////////////////////////////////////////////////////////////////////////
263
264#include "SkTime.h"
265#include <stdio.h>
266
267class SkAnimButtonView : public SkButtonView {
268public:
269	SkAnimButtonView()
270	{
271		fAnim.setHostEventSink(this);
272		init_skin_anim(kButton_SkinEnum, &fAnim);
273	}
274
275protected:
276	virtual void onLabelChange(const char oldLabel[], const char newLabel[])
277	{
278		this->INHERITED::onLabelChange(oldLabel, newLabel);
279
280		SkEvent evt("user");
281		evt.setString("id", "setLabel");
282		evt.setString("LABEL", newLabel);
283		fAnim.doUserEvent(evt);
284	}
285
286	virtual void onFocusChange(bool gainFocus)
287	{
288		this->INHERITED::onFocusChange(gainFocus);
289
290		SkEvent evt("user");
291		evt.setString("id", "setFocus");
292		evt.setS32("FOCUS", gainFocus);
293		fAnim.doUserEvent(evt);
294	}
295
296	virtual void onSizeChange()
297	{
298		this->INHERITED::onSizeChange();
299
300		SkEvent evt("user");
301		evt.setString("id", "setDim");
302		evt.setScalar("dimX", this->width());
303		evt.setScalar("dimY", this->height());
304		fAnim.doUserEvent(evt);
305	}
306
307	virtual void onDraw(SkCanvas* canvas)
308	{
309		SkPaint						paint;
310		SkAnimator::DifferenceType	diff = fAnim.draw(canvas, &paint, SkTime::GetMSecs());
311
312		if (diff == SkAnimator::kDifferent)
313			this->inval(NULL);
314		else if (diff == SkAnimator::kPartiallyDifferent)
315		{
316			SkRect	bounds;
317			fAnim.getInvalBounds(&bounds);
318			this->inval(&bounds);
319		}
320	}
321
322	virtual bool onEvent(const SkEvent& evt)
323	{
324		if (evt.isType(SK_EventType_Inval))
325		{
326			this->inval(NULL);
327			return true;
328		}
329		if (evt.isType("recommendDim"))
330		{
331			SkScalar	height;
332
333			if (evt.findScalar("y", &height))
334				this->setHeight(height);
335			return true;
336		}
337		return this->INHERITED::onEvent(evt);
338	}
339
340	virtual bool onPrepareWidgetEvent(SkEvent* evt)
341	{
342		if (this->INHERITED::onPrepareWidgetEvent(evt))
343		{
344			SkEvent	e("user");
345			e.setString("id", "handlePress");
346			(void)fAnim.doUserEvent(e);
347			return true;
348		}
349		return false;
350	}
351
352private:
353	SkAnimator	fAnim;
354
355	typedef SkButtonView INHERITED;
356};
357
358////////////////////////////////////////////////////////////////////////////////////////////
359////////////////////////////////////////////////////////////////////////////////////////////
360
361SkView* SkWidgetFactory(const char name[])
362{
363	if (name == NULL)
364		return NULL;
365
366	// must be in the same order as the SkSkinWidgetEnum is declared
367	static const char* gNames[] = {
368		"sk-border",
369		"sk-button",
370		"sk-image",
371		"sk-list",
372		"sk-progress",
373		"sk-scroll",
374		"sk-text"
375
376	};
377
378	for (size_t i = 0; i < SK_ARRAY_COUNT(gNames); i++)
379		if (!strcmp(gNames[i], name))
380			return SkWidgetFactory((SkWidgetEnum)i);
381
382	return NULL;
383}
384
385#include "SkImageView.h"
386#include "SkProgressBarView.h"
387#include "SkScrollBarView.h"
388#include "SkBorderView.h"
389
390SkView* SkWidgetFactory(SkWidgetEnum sw)
391{
392	switch (sw) {
393	case kBorder_WidgetEnum:
394		return new SkBorderView;
395	case kButton_WidgetEnum:
396		return new SkAnimButtonView;
397	case kImage_WidgetEnum:
398		return new SkImageView;
399	case kList_WidgetEnum:
400		return new SkListView;
401	case kProgress_WidgetEnum:
402		return new SkProgressBarView;
403	case kScroll_WidgetEnum:
404		return new SkScrollBarView;
405	case kText_WidgetEnum:
406		return new SkStaticTextView;
407	default:
408		SkDEBUGFAIL("unknown enum passed to SkWidgetFactory");
409		break;
410	}
411	return NULL;
412}
413