blob: 2803d93efce244b8e8658c1e362c6dba596b0f05 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
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 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#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{
senorblanco@chromium.org64cc5792011-05-19 19:58:58 +0000127 if ((label == NULL && fLabel.size() != 0) || !fLabel.equals(label, len))
reed@android.com8a1c16f2008-12-17 15:59:43 +0000128 {
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
deanm@chromium.org1599a432009-06-04 15:37:11 +0000170 if ((node = dom.getFirstChild(node, "event")) != NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000171 fEvent.inflate(dom, node);
172}
173
174/*virtual*/ void SkWidgetView::onLabelChange(const char oldLabel[], const char newLabel[])
175{
deanm@chromium.org1599a432009-06-04 15:37:11 +0000176 this->inval(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177}
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{
deanm@chromium.org1599a432009-06-04 15:37:11 +0000225 this->inval(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226}
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)
deanm@chromium.org1599a432009-06-04 15:37:11 +0000313 this->inval(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000314 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 {
deanm@chromium.org1599a432009-06-04 15:37:11 +0000326 this->inval(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000327 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////////////////////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000359////////////////////////////////////////////////////////////////////////////////////////////
360
361SkView* SkWidgetFactory(const char name[])
362{
deanm@chromium.org1599a432009-06-04 15:37:11 +0000363 if (name == NULL)
364 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000365
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
senorblanco@chromium.org64cc5792011-05-19 19:58:58 +0000378 for (size_t i = 0; i < SK_ARRAY_COUNT(gNames); i++)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000379 if (!strcmp(gNames[i], name))
380 return SkWidgetFactory((SkWidgetEnum)i);
381
deanm@chromium.org1599a432009-06-04 15:37:11 +0000382 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000383}
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:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000408 SkDEBUGFAIL("unknown enum passed to SkWidgetFactory");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000409 break;
410 }
deanm@chromium.org1599a432009-06-04 15:37:11 +0000411 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000412}