blob: 45e9868856f4b2cf348bdeeb46522a290ec6a409 [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
mike@reedtribe.orgf3811622013-03-19 02:18:33 +000044void init_skin_anim(const char path[], SkAnimator* anim) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +000045 SkASSERT(path && anim);
reed@android.com8a1c16f2008-12-17 15:59:43 +000046
mike@reedtribe.orgf3811622013-03-19 02:18:33 +000047 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path));
48 if (!stream.get()) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +000049 SkDEBUGF(("init_skin_anim: loading skin failed <%s>\n", path));
50 sk_throw();
51 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000052
mike@reedtribe.orgf3811622013-03-19 02:18:33 +000053 if (!anim->decodeStream(stream)) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +000054 SkDEBUGF(("init_skin_anim: decoding skin failed <%s>\n", path));
55 sk_throw();
56 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000057}
58
59void init_skin_anim(SkinEnum se, SkAnimator* anim)
60{
robertphillips@google.coma22e2112012-08-16 14:58:06 +000061 init_skin_anim(get_skin_enum_path(se), anim);
reed@android.com8a1c16f2008-12-17 15:59:43 +000062}
63
64void init_skin_paint(SkinEnum se, SkPaint* paint)
65{
robertphillips@google.coma22e2112012-08-16 14:58:06 +000066 SkASSERT(paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +000067
rmistry@google.comd6176b02012-08-23 18:14:13 +000068 SkAnimator anim;
69 SkCanvas canvas;
70
robertphillips@google.coma22e2112012-08-16 14:58:06 +000071 init_skin_anim(se, &anim);
72 anim.draw(&canvas, paint, 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +000073}
74
75void inflate_paint(const SkDOM& dom, const SkDOM::Node* node, SkPaint* paint)
76{
robertphillips@google.coma22e2112012-08-16 14:58:06 +000077 SkASSERT(paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +000078
rmistry@google.comd6176b02012-08-23 18:14:13 +000079 SkAnimator anim;
80 SkCanvas canvas;
81
robertphillips@google.coma22e2112012-08-16 14:58:06 +000082 if (!anim.decodeDOM(dom, node))
83 {
84 SkDEBUGF(("inflate_paint: decoding dom failed\n"));
85 SkDEBUGCODE(dom.dump(node);)
86 sk_throw();
rmistry@google.comd6176b02012-08-23 18:14:13 +000087 }
robertphillips@google.coma22e2112012-08-16 14:58:06 +000088 anim.draw(&canvas, paint, 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +000089}
90
91////////////////////////////////////////////////////////////////////////////////////////
92
93SkWidgetView::SkWidgetView() : SkView(SkView::kFocusable_Mask | SkView::kEnabled_Mask)
94{
95}
96
97const char* SkWidgetView::getLabel() const
98{
robertphillips@google.coma22e2112012-08-16 14:58:06 +000099 return fLabel.c_str();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000100}
rmistry@google.comd6176b02012-08-23 18:14:13 +0000101
reed@android.com8a1c16f2008-12-17 15:59:43 +0000102void SkWidgetView::getLabel(SkString* label) const
103{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000104 if (label)
105 *label = fLabel;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000106}
107
108void SkWidgetView::setLabel(const char label[])
109{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000110 this->setLabel(label, label ? strlen(label) : 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000111}
112
113void SkWidgetView::setLabel(const char label[], size_t len)
114{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000115 if ((label == NULL && fLabel.size() != 0) || !fLabel.equals(label, len))
116 {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000117 SkString tmp(label, len);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000118
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000119 this->onLabelChange(fLabel.c_str(), tmp.c_str());
120 fLabel.swap(tmp);
121 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000122}
123
124void SkWidgetView::setLabel(const SkString& label)
125{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000126 if (fLabel != label)
127 {
128 this->onLabelChange(fLabel.c_str(), label.c_str());
129 fLabel = label;
130 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000131}
132
133bool SkWidgetView::postWidgetEvent()
134{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000135 if (!fEvent.isType(""))
136 {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000137 SkEvent evt(fEvent); // make a copy since onPrepareWidgetEvent may edit the event
reed@android.com8a1c16f2008-12-17 15:59:43 +0000138
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000139 if (this->onPrepareWidgetEvent(&evt))
140 {
141 SkDEBUGCODE(evt.dump("SkWidgetView::postWidgetEvent");)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142
rmistry@google.comd6176b02012-08-23 18:14:13 +0000143 this->postToListeners(evt); // wonder if this should return true if there are > 0 listeners...
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000144 return true;
145 }
146 }
147 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000148}
149
150/*virtual*/ void SkWidgetView::onInflate(const SkDOM& dom, const SkDOM::Node* node)
151{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000152 this->INHERITED::onInflate(dom, node);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000154 const char* label = dom.findAttr(node, "label");
155 if (label)
156 this->setLabel(label);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000157
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000158 if ((node = dom.getFirstChild(node, "event")) != NULL)
159 fEvent.inflate(dom, node);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000160}
161
162/*virtual*/ void SkWidgetView::onLabelChange(const char oldLabel[], const char newLabel[])
163{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000164 this->inval(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165}
166
167static const char gWidgetEventSinkIDSlotName[] = "sk-widget-sinkid-slot";
168
169/*virtual*/ bool SkWidgetView::onPrepareWidgetEvent(SkEvent* evt)
170{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000171 evt->setS32(gWidgetEventSinkIDSlotName, this->getSinkID());
172 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000173}
174
175SkEventSinkID SkWidgetView::GetWidgetEventSinkID(const SkEvent& evt)
176{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000177 int32_t sinkID;
178
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000179 return evt.findS32(gWidgetEventSinkIDSlotName, &sinkID) ? (SkEventSinkID)sinkID : 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180}
181
182///////////////////////////////////////////////////////////////////////////////////////////////////
183
184/*virtual*/ bool SkButtonView::onEvent(const SkEvent& evt)
185{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000186 if (evt.isType(SK_EventType_Key) && evt.getFast32() == kOK_SkKey)
187 {
188 this->postWidgetEvent();
189 return true;
190 }
191 return this->INHERITED::onEvent(evt);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192}
193
194///////////////////////////////////////////////////////////////////////////////////////////////////
195
196SkCheckButtonView::SkCheckButtonView() : fCheckState(kOff_CheckState)
197{
198}
199
200void SkCheckButtonView::setCheckState(CheckState state)
201{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000202 SkASSERT((unsigned)state <= kUnknown_CheckState);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000203
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000204 if (fCheckState != state)
205 {
206 this->onCheckStateChange(this->getCheckState(), state);
207 fCheckState = SkToU8(state);
208 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209}
rmistry@google.comd6176b02012-08-23 18:14:13 +0000210
reed@android.com8a1c16f2008-12-17 15:59:43 +0000211/*virtual*/ void SkCheckButtonView::onCheckStateChange(CheckState oldState, CheckState newState)
212{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000213 this->inval(NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000214}
215
216/*virtual*/ void SkCheckButtonView::onInflate(const SkDOM& dom, const SkDOM::Node* node)
217{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000218 this->INHERITED::onInflate(dom, node);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000219
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000220 int index = dom.findList(node, "check-state", "off,on,unknown");
221 if (index >= 0)
222 this->setCheckState((CheckState)index);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223}
224
225static const char gCheckStateSlotName[] = "sk-checkbutton-check-slot";
226
227/*virtual*/ bool SkCheckButtonView::onPrepareWidgetEvent(SkEvent* evt)
228{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000229 // could check if we're "disabled", and return false...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000230
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000231 evt->setS32(gCheckStateSlotName, this->getCheckState());
232 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233}
234
235bool SkCheckButtonView::GetWidgetEventCheckState(const SkEvent& evt, CheckState* state)
236{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000237 int32_t state32;
238
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000239 if (evt.findS32(gCheckStateSlotName, &state32))
240 {
241 if (state)
242 *state = (CheckState)state32;
243 return true;
244 }
245 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246}
247
248///////////////////////////////////////////////////////////////////////////////////////////////////
249///////////////////////////////////////////////////////////////////////////////////////////////////
250///////////////////////////////////////////////////////////////////////////////////////////////////
251
252#include "SkTime.h"
253#include <stdio.h>
254
255class SkAnimButtonView : public SkButtonView {
256public:
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000257 SkAnimButtonView()
258 {
259 fAnim.setHostEventSink(this);
260 init_skin_anim(kButton_SkinEnum, &fAnim);
261 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000262
263protected:
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000264 virtual void onLabelChange(const char oldLabel[], const char newLabel[])
265 {
266 this->INHERITED::onLabelChange(oldLabel, newLabel);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000267
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000268 SkEvent evt("user");
269 evt.setString("id", "setLabel");
270 evt.setString("LABEL", newLabel);
271 fAnim.doUserEvent(evt);
272 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000273
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000274 virtual void onFocusChange(bool gainFocus)
275 {
276 this->INHERITED::onFocusChange(gainFocus);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000277
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000278 SkEvent evt("user");
279 evt.setString("id", "setFocus");
280 evt.setS32("FOCUS", gainFocus);
281 fAnim.doUserEvent(evt);
282 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000283
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000284 virtual void onSizeChange()
285 {
286 this->INHERITED::onSizeChange();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000287
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000288 SkEvent evt("user");
289 evt.setString("id", "setDim");
290 evt.setScalar("dimX", this->width());
291 evt.setScalar("dimY", this->height());
292 fAnim.doUserEvent(evt);
293 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000294
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000295 virtual void onDraw(SkCanvas* canvas)
296 {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000297 SkPaint paint;
298 SkAnimator::DifferenceType diff = fAnim.draw(canvas, &paint, SkTime::GetMSecs());
299
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000300 if (diff == SkAnimator::kDifferent)
301 this->inval(NULL);
302 else if (diff == SkAnimator::kPartiallyDifferent)
303 {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000304 SkRect bounds;
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000305 fAnim.getInvalBounds(&bounds);
306 this->inval(&bounds);
307 }
308 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000309
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000310 virtual bool onEvent(const SkEvent& evt)
311 {
312 if (evt.isType(SK_EventType_Inval))
313 {
314 this->inval(NULL);
315 return true;
316 }
317 if (evt.isType("recommendDim"))
318 {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000319 SkScalar height;
320
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000321 if (evt.findScalar("y", &height))
322 this->setHeight(height);
323 return true;
324 }
325 return this->INHERITED::onEvent(evt);
326 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000327
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000328 virtual bool onPrepareWidgetEvent(SkEvent* evt)
329 {
330 if (this->INHERITED::onPrepareWidgetEvent(evt))
331 {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000332 SkEvent e("user");
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000333 e.setString("id", "handlePress");
334 (void)fAnim.doUserEvent(e);
335 return true;
336 }
337 return false;
338 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000339
340private:
rmistry@google.comd6176b02012-08-23 18:14:13 +0000341 SkAnimator fAnim;
342
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000343 typedef SkButtonView INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344};
345
346////////////////////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000347////////////////////////////////////////////////////////////////////////////////////////////
348
349SkView* SkWidgetFactory(const char name[])
350{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000351 if (name == NULL)
352 return NULL;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000353
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000354 // must be in the same order as the SkSkinWidgetEnum is declared
355 static const char* gNames[] = {
356 "sk-border",
357 "sk-button",
358 "sk-image",
359 "sk-list",
360 "sk-progress",
361 "sk-scroll",
362 "sk-text"
rmistry@google.comd6176b02012-08-23 18:14:13 +0000363
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000364 };
reed@android.com8a1c16f2008-12-17 15:59:43 +0000365
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000366 for (size_t i = 0; i < SK_ARRAY_COUNT(gNames); i++)
367 if (!strcmp(gNames[i], name))
368 return SkWidgetFactory((SkWidgetEnum)i);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000370 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000371}
372
373#include "SkImageView.h"
374#include "SkProgressBarView.h"
375#include "SkScrollBarView.h"
376#include "SkBorderView.h"
377
378SkView* SkWidgetFactory(SkWidgetEnum sw)
379{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000380 switch (sw) {
381 case kBorder_WidgetEnum:
382 return new SkBorderView;
383 case kButton_WidgetEnum:
384 return new SkAnimButtonView;
385 case kImage_WidgetEnum:
386 return new SkImageView;
387 case kList_WidgetEnum:
388 return new SkListView;
389 case kProgress_WidgetEnum:
390 return new SkProgressBarView;
391 case kScroll_WidgetEnum:
392 return new SkScrollBarView;
393 case kText_WidgetEnum:
394 return new SkStaticTextView;
395 default:
396 SkDEBUGFAIL("unknown enum passed to SkWidgetFactory");
397 break;
398 }
399 return NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000400}