blob: 9c1cae7fb21b36c94455d915de66be6310332e70 [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
reed@android.com8a1c16f2008-12-17 15:59:43 +000015/*
16I have moved this to SkWidgetViews.h
17enum SkinEnum {
robertphillips@google.coma22e2112012-08-16 14:58:06 +000018 kButton_SkinEnum,
19 kProgress_SkinEnum,
20 kScroll_SkinEnum,
21 kStaticText_SkinEnum,
rmistry@google.comd6176b02012-08-23 18:14:13 +000022
robertphillips@google.coma22e2112012-08-16 14:58:06 +000023 kSkinEnumCount
reed@android.com8a1c16f2008-12-17 15:59:43 +000024};
25*/
26
robertphillips@google.coma22e2112012-08-16 14:58:06 +000027SK_DEFINE_INST_COUNT(SkListSource)
28
reed@android.com8a1c16f2008-12-17 15:59:43 +000029const char* get_skin_enum_path(SkinEnum se)
30{
robertphillips@google.coma22e2112012-08-16 14:58:06 +000031 SkASSERT((unsigned)se < kSkinEnumCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +000032
robertphillips@google.coma22e2112012-08-16 14:58:06 +000033 static const char* gSkinPaths[] = {
reed@android.com8a1c16f2008-12-17 15:59:43 +000034 "common/default/default/skins/border3.xml",
35 "common/default/default/skins/button.xml",
36 "common/default/default/skins/progressBar.xml",
37 "common/default/default/skins/scrollBar.xml",
38 "common/default/default/skins/statictextpaint.xml"
robertphillips@google.coma22e2112012-08-16 14:58:06 +000039 };
reed@android.com8a1c16f2008-12-17 15:59:43 +000040
robertphillips@google.coma22e2112012-08-16 14:58:06 +000041 return gSkinPaths[se];
reed@android.com8a1c16f2008-12-17 15:59:43 +000042}
43
44void init_skin_anim(const char path[], SkAnimator* anim)
45{
robertphillips@google.coma22e2112012-08-16 14:58:06 +000046 SkASSERT(path && anim);
reed@android.com8a1c16f2008-12-17 15:59:43 +000047
rmistry@google.comd6176b02012-08-23 18:14:13 +000048 SkFILEStream stream(path);
reed@android.com8a1c16f2008-12-17 15:59:43 +000049
robertphillips@google.coma22e2112012-08-16 14:58:06 +000050 if (!stream.isValid())
51 {
52 SkDEBUGF(("init_skin_anim: loading skin failed <%s>\n", path));
53 sk_throw();
54 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000055
robertphillips@google.coma22e2112012-08-16 14:58:06 +000056 if (!anim->decodeStream(&stream))
57 {
58 SkDEBUGF(("init_skin_anim: decoding skin failed <%s>\n", path));
59 sk_throw();
60 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000061}
62
63void init_skin_anim(SkinEnum se, SkAnimator* anim)
64{
robertphillips@google.coma22e2112012-08-16 14:58:06 +000065 init_skin_anim(get_skin_enum_path(se), anim);
reed@android.com8a1c16f2008-12-17 15:59:43 +000066}
67
68void init_skin_paint(SkinEnum se, SkPaint* paint)
69{
robertphillips@google.coma22e2112012-08-16 14:58:06 +000070 SkASSERT(paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +000071
rmistry@google.comd6176b02012-08-23 18:14:13 +000072 SkAnimator anim;
73 SkCanvas canvas;
74
robertphillips@google.coma22e2112012-08-16 14:58:06 +000075 init_skin_anim(se, &anim);
76 anim.draw(&canvas, paint, 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +000077}
78
79void inflate_paint(const SkDOM& dom, const SkDOM::Node* node, SkPaint* paint)
80{
robertphillips@google.coma22e2112012-08-16 14:58:06 +000081 SkASSERT(paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +000082
rmistry@google.comd6176b02012-08-23 18:14:13 +000083 SkAnimator anim;
84 SkCanvas canvas;
85
robertphillips@google.coma22e2112012-08-16 14:58:06 +000086 if (!anim.decodeDOM(dom, node))
87 {
88 SkDEBUGF(("inflate_paint: decoding dom failed\n"));
89 SkDEBUGCODE(dom.dump(node);)
90 sk_throw();
rmistry@google.comd6176b02012-08-23 18:14:13 +000091 }
robertphillips@google.coma22e2112012-08-16 14:58:06 +000092 anim.draw(&canvas, paint, 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +000093}
94
95////////////////////////////////////////////////////////////////////////////////////////
96
97SkWidgetView::SkWidgetView() : SkView(SkView::kFocusable_Mask | SkView::kEnabled_Mask)
98{
99}
100
101const char* SkWidgetView::getLabel() const
102{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000103 return fLabel.c_str();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000104}
rmistry@google.comd6176b02012-08-23 18:14:13 +0000105
reed@android.com8a1c16f2008-12-17 15:59:43 +0000106void SkWidgetView::getLabel(SkString* label) const
107{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000108 if (label)
109 *label = fLabel;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000110}
111
112void SkWidgetView::setLabel(const char label[])
113{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000114 this->setLabel(label, label ? strlen(label) : 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000115}
116
117void SkWidgetView::setLabel(const char label[], size_t len)
118{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000119 if ((label == NULL && fLabel.size() != 0) || !fLabel.equals(label, len))
120 {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000121 SkString tmp(label, len);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000122
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000123 this->onLabelChange(fLabel.c_str(), tmp.c_str());
124 fLabel.swap(tmp);
125 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126}
127
128void SkWidgetView::setLabel(const SkString& label)
129{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000130 if (fLabel != label)
131 {
132 this->onLabelChange(fLabel.c_str(), label.c_str());
133 fLabel = label;
134 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000135}
136
137bool SkWidgetView::postWidgetEvent()
138{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000139 if (!fEvent.isType(""))
140 {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000141 SkEvent evt(fEvent); // make a copy since onPrepareWidgetEvent may edit the event
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000143 if (this->onPrepareWidgetEvent(&evt))
144 {
145 SkDEBUGCODE(evt.dump("SkWidgetView::postWidgetEvent");)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146
rmistry@google.comd6176b02012-08-23 18:14:13 +0000147 this->postToListeners(evt); // wonder if this should return true if there are > 0 listeners...
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000148 return true;
149 }
150 }
151 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152}
153
154/*virtual*/ void SkWidgetView::onInflate(const SkDOM& dom, const SkDOM::Node* node)
155{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000156 this->INHERITED::onInflate(dom, node);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000158 const char* label = dom.findAttr(node, "label");
159 if (label)
160 this->setLabel(label);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000161
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000162 if ((node = dom.getFirstChild(node, "event")) != NULL)
163 fEvent.inflate(dom, node);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000164}
165
166/*virtual*/ void SkWidgetView::onLabelChange(const char oldLabel[], const char newLabel[])
167{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000168 this->inval(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169}
170
171static const char gWidgetEventSinkIDSlotName[] = "sk-widget-sinkid-slot";
172
173/*virtual*/ bool SkWidgetView::onPrepareWidgetEvent(SkEvent* evt)
174{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000175 evt->setS32(gWidgetEventSinkIDSlotName, this->getSinkID());
176 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177}
178
179SkEventSinkID SkWidgetView::GetWidgetEventSinkID(const SkEvent& evt)
180{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000181 int32_t sinkID;
182
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000183 return evt.findS32(gWidgetEventSinkIDSlotName, &sinkID) ? (SkEventSinkID)sinkID : 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184}
185
186///////////////////////////////////////////////////////////////////////////////////////////////////
187
188/*virtual*/ bool SkButtonView::onEvent(const SkEvent& evt)
189{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000190 if (evt.isType(SK_EventType_Key) && evt.getFast32() == kOK_SkKey)
191 {
192 this->postWidgetEvent();
193 return true;
194 }
195 return this->INHERITED::onEvent(evt);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000196}
197
198///////////////////////////////////////////////////////////////////////////////////////////////////
199
200SkCheckButtonView::SkCheckButtonView() : fCheckState(kOff_CheckState)
201{
202}
203
204void SkCheckButtonView::setCheckState(CheckState state)
205{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000206 SkASSERT((unsigned)state <= kUnknown_CheckState);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000207
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000208 if (fCheckState != state)
209 {
210 this->onCheckStateChange(this->getCheckState(), state);
211 fCheckState = SkToU8(state);
212 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213}
rmistry@google.comd6176b02012-08-23 18:14:13 +0000214
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215/*virtual*/ void SkCheckButtonView::onCheckStateChange(CheckState oldState, CheckState newState)
216{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000217 this->inval(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218}
219
220/*virtual*/ void SkCheckButtonView::onInflate(const SkDOM& dom, const SkDOM::Node* node)
221{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000222 this->INHERITED::onInflate(dom, node);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000223
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000224 int index = dom.findList(node, "check-state", "off,on,unknown");
225 if (index >= 0)
226 this->setCheckState((CheckState)index);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000227}
228
229static const char gCheckStateSlotName[] = "sk-checkbutton-check-slot";
230
231/*virtual*/ bool SkCheckButtonView::onPrepareWidgetEvent(SkEvent* evt)
232{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000233 // could check if we're "disabled", and return false...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000235 evt->setS32(gCheckStateSlotName, this->getCheckState());
236 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237}
238
239bool SkCheckButtonView::GetWidgetEventCheckState(const SkEvent& evt, CheckState* state)
240{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000241 int32_t state32;
242
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000243 if (evt.findS32(gCheckStateSlotName, &state32))
244 {
245 if (state)
246 *state = (CheckState)state32;
247 return true;
248 }
249 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000250}
251
252///////////////////////////////////////////////////////////////////////////////////////////////////
253///////////////////////////////////////////////////////////////////////////////////////////////////
254///////////////////////////////////////////////////////////////////////////////////////////////////
255
256#include "SkTime.h"
257#include <stdio.h>
258
259class SkAnimButtonView : public SkButtonView {
260public:
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000261 SkAnimButtonView()
262 {
263 fAnim.setHostEventSink(this);
264 init_skin_anim(kButton_SkinEnum, &fAnim);
265 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266
267protected:
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000268 virtual void onLabelChange(const char oldLabel[], const char newLabel[])
269 {
270 this->INHERITED::onLabelChange(oldLabel, newLabel);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000272 SkEvent evt("user");
273 evt.setString("id", "setLabel");
274 evt.setString("LABEL", newLabel);
275 fAnim.doUserEvent(evt);
276 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000277
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000278 virtual void onFocusChange(bool gainFocus)
279 {
280 this->INHERITED::onFocusChange(gainFocus);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000281
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000282 SkEvent evt("user");
283 evt.setString("id", "setFocus");
284 evt.setS32("FOCUS", gainFocus);
285 fAnim.doUserEvent(evt);
286 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000287
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000288 virtual void onSizeChange()
289 {
290 this->INHERITED::onSizeChange();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000291
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000292 SkEvent evt("user");
293 evt.setString("id", "setDim");
294 evt.setScalar("dimX", this->width());
295 evt.setScalar("dimY", this->height());
296 fAnim.doUserEvent(evt);
297 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000298
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000299 virtual void onDraw(SkCanvas* canvas)
300 {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000301 SkPaint paint;
302 SkAnimator::DifferenceType diff = fAnim.draw(canvas, &paint, SkTime::GetMSecs());
303
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000304 if (diff == SkAnimator::kDifferent)
305 this->inval(NULL);
306 else if (diff == SkAnimator::kPartiallyDifferent)
307 {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000308 SkRect bounds;
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000309 fAnim.getInvalBounds(&bounds);
310 this->inval(&bounds);
311 }
312 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000313
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000314 virtual bool onEvent(const SkEvent& evt)
315 {
316 if (evt.isType(SK_EventType_Inval))
317 {
318 this->inval(NULL);
319 return true;
320 }
321 if (evt.isType("recommendDim"))
322 {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000323 SkScalar height;
324
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000325 if (evt.findScalar("y", &height))
326 this->setHeight(height);
327 return true;
328 }
329 return this->INHERITED::onEvent(evt);
330 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000331
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000332 virtual bool onPrepareWidgetEvent(SkEvent* evt)
333 {
334 if (this->INHERITED::onPrepareWidgetEvent(evt))
335 {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000336 SkEvent e("user");
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000337 e.setString("id", "handlePress");
338 (void)fAnim.doUserEvent(e);
339 return true;
340 }
341 return false;
342 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000343
344private:
rmistry@google.comd6176b02012-08-23 18:14:13 +0000345 SkAnimator fAnim;
346
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000347 typedef SkButtonView INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000348};
349
350////////////////////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351////////////////////////////////////////////////////////////////////////////////////////////
352
353SkView* SkWidgetFactory(const char name[])
354{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000355 if (name == NULL)
356 return NULL;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000357
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000358 // must be in the same order as the SkSkinWidgetEnum is declared
359 static const char* gNames[] = {
360 "sk-border",
361 "sk-button",
362 "sk-image",
363 "sk-list",
364 "sk-progress",
365 "sk-scroll",
366 "sk-text"
rmistry@google.comd6176b02012-08-23 18:14:13 +0000367
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000368 };
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000370 for (size_t i = 0; i < SK_ARRAY_COUNT(gNames); i++)
371 if (!strcmp(gNames[i], name))
372 return SkWidgetFactory((SkWidgetEnum)i);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000373
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000374 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000375}
376
377#include "SkImageView.h"
378#include "SkProgressBarView.h"
379#include "SkScrollBarView.h"
380#include "SkBorderView.h"
381
382SkView* SkWidgetFactory(SkWidgetEnum sw)
383{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000384 switch (sw) {
385 case kBorder_WidgetEnum:
386 return new SkBorderView;
387 case kButton_WidgetEnum:
388 return new SkAnimButtonView;
389 case kImage_WidgetEnum:
390 return new SkImageView;
391 case kList_WidgetEnum:
392 return new SkListView;
393 case kProgress_WidgetEnum:
394 return new SkProgressBarView;
395 case kScroll_WidgetEnum:
396 return new SkScrollBarView;
397 case kText_WidgetEnum:
398 return new SkStaticTextView;
399 default:
400 SkDEBUGFAIL("unknown enum passed to SkWidgetFactory");
401 break;
402 }
403 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000404}