blob: 9d3c936523ef4d4b63575a1dd1ac440bf7e4613f [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
27const char* get_skin_enum_path(SkinEnum se)
28{
robertphillips@google.coma22e2112012-08-16 14:58:06 +000029 SkASSERT((unsigned)se < kSkinEnumCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +000030
robertphillips@google.coma22e2112012-08-16 14:58:06 +000031 static const char* gSkinPaths[] = {
reed@android.com8a1c16f2008-12-17 15:59:43 +000032 "common/default/default/skins/border3.xml",
33 "common/default/default/skins/button.xml",
34 "common/default/default/skins/progressBar.xml",
35 "common/default/default/skins/scrollBar.xml",
36 "common/default/default/skins/statictextpaint.xml"
robertphillips@google.coma22e2112012-08-16 14:58:06 +000037 };
reed@android.com8a1c16f2008-12-17 15:59:43 +000038
robertphillips@google.coma22e2112012-08-16 14:58:06 +000039 return gSkinPaths[se];
reed@android.com8a1c16f2008-12-17 15:59:43 +000040}
41
mike@reedtribe.orgf3811622013-03-19 02:18:33 +000042void init_skin_anim(const char path[], SkAnimator* anim) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +000043 SkASSERT(path && anim);
reed@android.com8a1c16f2008-12-17 15:59:43 +000044
scroggoa1193e42015-01-21 12:09:53 -080045 SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(path));
mike@reedtribe.orgf3811622013-03-19 02:18:33 +000046 if (!stream.get()) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +000047 SkDEBUGF(("init_skin_anim: loading skin failed <%s>\n", path));
48 sk_throw();
49 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000050
mike@reedtribe.orgf3811622013-03-19 02:18:33 +000051 if (!anim->decodeStream(stream)) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +000052 SkDEBUGF(("init_skin_anim: decoding skin failed <%s>\n", path));
53 sk_throw();
54 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000055}
56
57void init_skin_anim(SkinEnum se, SkAnimator* anim)
58{
robertphillips@google.coma22e2112012-08-16 14:58:06 +000059 init_skin_anim(get_skin_enum_path(se), anim);
reed@android.com8a1c16f2008-12-17 15:59:43 +000060}
61
62void init_skin_paint(SkinEnum se, SkPaint* paint)
63{
robertphillips@google.coma22e2112012-08-16 14:58:06 +000064 SkASSERT(paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +000065
rmistry@google.comd6176b02012-08-23 18:14:13 +000066 SkAnimator anim;
67 SkCanvas canvas;
68
robertphillips@google.coma22e2112012-08-16 14:58:06 +000069 init_skin_anim(se, &anim);
70 anim.draw(&canvas, paint, 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +000071}
72
73void inflate_paint(const SkDOM& dom, const SkDOM::Node* node, SkPaint* paint)
74{
robertphillips@google.coma22e2112012-08-16 14:58:06 +000075 SkASSERT(paint);
reed@android.com8a1c16f2008-12-17 15:59:43 +000076
rmistry@google.comd6176b02012-08-23 18:14:13 +000077 SkAnimator anim;
78 SkCanvas canvas;
79
robertphillips@google.coma22e2112012-08-16 14:58:06 +000080 if (!anim.decodeDOM(dom, node))
81 {
82 SkDEBUGF(("inflate_paint: decoding dom failed\n"));
83 SkDEBUGCODE(dom.dump(node);)
84 sk_throw();
rmistry@google.comd6176b02012-08-23 18:14:13 +000085 }
robertphillips@google.coma22e2112012-08-16 14:58:06 +000086 anim.draw(&canvas, paint, 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +000087}
88
89////////////////////////////////////////////////////////////////////////////////////////
90
91SkWidgetView::SkWidgetView() : SkView(SkView::kFocusable_Mask | SkView::kEnabled_Mask)
92{
93}
94
95const char* SkWidgetView::getLabel() const
96{
robertphillips@google.coma22e2112012-08-16 14:58:06 +000097 return fLabel.c_str();
reed@android.com8a1c16f2008-12-17 15:59:43 +000098}
rmistry@google.comd6176b02012-08-23 18:14:13 +000099
reed@android.com8a1c16f2008-12-17 15:59:43 +0000100void SkWidgetView::getLabel(SkString* label) const
101{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000102 if (label)
103 *label = fLabel;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000104}
105
106void SkWidgetView::setLabel(const char label[])
107{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000108 this->setLabel(label, label ? strlen(label) : 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000109}
110
111void SkWidgetView::setLabel(const char label[], size_t len)
112{
halcanary96fcdcc2015-08-27 07:41:13 -0700113 if ((label == nullptr && fLabel.size() != 0) || !fLabel.equals(label, len))
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000114 {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000115 SkString tmp(label, len);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000116
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000117 this->onLabelChange(fLabel.c_str(), tmp.c_str());
118 fLabel.swap(tmp);
119 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000120}
121
122void SkWidgetView::setLabel(const SkString& label)
123{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000124 if (fLabel != label)
125 {
126 this->onLabelChange(fLabel.c_str(), label.c_str());
127 fLabel = label;
128 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129}
130
131bool SkWidgetView::postWidgetEvent()
132{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000133 if (!fEvent.isType(""))
134 {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000135 SkEvent evt(fEvent); // make a copy since onPrepareWidgetEvent may edit the event
reed@android.com8a1c16f2008-12-17 15:59:43 +0000136
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000137 if (this->onPrepareWidgetEvent(&evt))
138 {
139 SkDEBUGCODE(evt.dump("SkWidgetView::postWidgetEvent");)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000140
rmistry@google.comd6176b02012-08-23 18:14:13 +0000141 this->postToListeners(evt); // wonder if this should return true if there are > 0 listeners...
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000142 return true;
143 }
144 }
145 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146}
147
148/*virtual*/ void SkWidgetView::onInflate(const SkDOM& dom, const SkDOM::Node* node)
149{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000150 this->INHERITED::onInflate(dom, node);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000151
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000152 const char* label = dom.findAttr(node, "label");
153 if (label)
154 this->setLabel(label);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000155
halcanary96fcdcc2015-08-27 07:41:13 -0700156 if ((node = dom.getFirstChild(node, "event")) != nullptr)
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000157 fEvent.inflate(dom, node);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000158}
159
160/*virtual*/ void SkWidgetView::onLabelChange(const char oldLabel[], const char newLabel[])
161{
halcanary96fcdcc2015-08-27 07:41:13 -0700162 this->inval(nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000163}
164
165static const char gWidgetEventSinkIDSlotName[] = "sk-widget-sinkid-slot";
166
167/*virtual*/ bool SkWidgetView::onPrepareWidgetEvent(SkEvent* evt)
168{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000169 evt->setS32(gWidgetEventSinkIDSlotName, this->getSinkID());
170 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000171}
172
173SkEventSinkID SkWidgetView::GetWidgetEventSinkID(const SkEvent& evt)
174{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000175 int32_t sinkID;
176
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000177 return evt.findS32(gWidgetEventSinkIDSlotName, &sinkID) ? (SkEventSinkID)sinkID : 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178}
179
180///////////////////////////////////////////////////////////////////////////////////////////////////
181
182/*virtual*/ bool SkButtonView::onEvent(const SkEvent& evt)
183{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000184 if (evt.isType(SK_EventType_Key) && evt.getFast32() == kOK_SkKey)
185 {
186 this->postWidgetEvent();
187 return true;
188 }
189 return this->INHERITED::onEvent(evt);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000190}
191
192///////////////////////////////////////////////////////////////////////////////////////////////////
193
194SkCheckButtonView::SkCheckButtonView() : fCheckState(kOff_CheckState)
195{
196}
197
198void SkCheckButtonView::setCheckState(CheckState state)
199{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000200 SkASSERT((unsigned)state <= kUnknown_CheckState);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000201
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000202 if (fCheckState != state)
203 {
204 this->onCheckStateChange(this->getCheckState(), state);
205 fCheckState = SkToU8(state);
206 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000207}
rmistry@google.comd6176b02012-08-23 18:14:13 +0000208
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209/*virtual*/ void SkCheckButtonView::onCheckStateChange(CheckState oldState, CheckState newState)
210{
halcanary96fcdcc2015-08-27 07:41:13 -0700211 this->inval(nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212}
213
214/*virtual*/ void SkCheckButtonView::onInflate(const SkDOM& dom, const SkDOM::Node* node)
215{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000216 this->INHERITED::onInflate(dom, node);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000217
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000218 int index = dom.findList(node, "check-state", "off,on,unknown");
219 if (index >= 0)
220 this->setCheckState((CheckState)index);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000221}
222
223static const char gCheckStateSlotName[] = "sk-checkbutton-check-slot";
224
225/*virtual*/ bool SkCheckButtonView::onPrepareWidgetEvent(SkEvent* evt)
226{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000227 // could check if we're "disabled", and return false...
reed@android.com8a1c16f2008-12-17 15:59:43 +0000228
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000229 evt->setS32(gCheckStateSlotName, this->getCheckState());
230 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231}
232
233bool SkCheckButtonView::GetWidgetEventCheckState(const SkEvent& evt, CheckState* state)
234{
rmistry@google.comd6176b02012-08-23 18:14:13 +0000235 int32_t state32;
236
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000237 if (evt.findS32(gCheckStateSlotName, &state32))
238 {
239 if (state)
240 *state = (CheckState)state32;
241 return true;
242 }
243 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244}
245
246///////////////////////////////////////////////////////////////////////////////////////////////////
247///////////////////////////////////////////////////////////////////////////////////////////////////
248///////////////////////////////////////////////////////////////////////////////////////////////////
249
250#include "SkTime.h"
251#include <stdio.h>
252
253class SkAnimButtonView : public SkButtonView {
254public:
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000255 SkAnimButtonView()
256 {
257 fAnim.setHostEventSink(this);
258 init_skin_anim(kButton_SkinEnum, &fAnim);
259 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000260
261protected:
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000262 virtual void onLabelChange(const char oldLabel[], const char newLabel[])
263 {
264 this->INHERITED::onLabelChange(oldLabel, newLabel);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000265
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000266 SkEvent evt("user");
267 evt.setString("id", "setLabel");
268 evt.setString("LABEL", newLabel);
269 fAnim.doUserEvent(evt);
270 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000271
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000272 virtual void onFocusChange(bool gainFocus)
273 {
274 this->INHERITED::onFocusChange(gainFocus);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000276 SkEvent evt("user");
277 evt.setString("id", "setFocus");
278 evt.setS32("FOCUS", gainFocus);
279 fAnim.doUserEvent(evt);
280 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000281
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000282 virtual void onSizeChange()
283 {
284 this->INHERITED::onSizeChange();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000286 SkEvent evt("user");
287 evt.setString("id", "setDim");
288 evt.setScalar("dimX", this->width());
289 evt.setScalar("dimY", this->height());
290 fAnim.doUserEvent(evt);
291 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000293 virtual void onDraw(SkCanvas* canvas)
294 {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000295 SkPaint paint;
296 SkAnimator::DifferenceType diff = fAnim.draw(canvas, &paint, SkTime::GetMSecs());
297
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000298 if (diff == SkAnimator::kDifferent)
halcanary96fcdcc2015-08-27 07:41:13 -0700299 this->inval(nullptr);
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000300 else if (diff == SkAnimator::kPartiallyDifferent)
301 {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000302 SkRect bounds;
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000303 fAnim.getInvalBounds(&bounds);
304 this->inval(&bounds);
305 }
306 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000307
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000308 virtual bool onEvent(const SkEvent& evt)
309 {
310 if (evt.isType(SK_EventType_Inval))
311 {
halcanary96fcdcc2015-08-27 07:41:13 -0700312 this->inval(nullptr);
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000313 return true;
314 }
315 if (evt.isType("recommendDim"))
316 {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000317 SkScalar height;
318
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000319 if (evt.findScalar("y", &height))
320 this->setHeight(height);
321 return true;
322 }
323 return this->INHERITED::onEvent(evt);
324 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000325
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000326 virtual bool onPrepareWidgetEvent(SkEvent* evt)
327 {
328 if (this->INHERITED::onPrepareWidgetEvent(evt))
329 {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000330 SkEvent e("user");
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000331 e.setString("id", "handlePress");
332 (void)fAnim.doUserEvent(e);
333 return true;
334 }
335 return false;
336 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000337
338private:
rmistry@google.comd6176b02012-08-23 18:14:13 +0000339 SkAnimator fAnim;
340
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000341 typedef SkButtonView INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342};
343
344////////////////////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000345////////////////////////////////////////////////////////////////////////////////////////////
346
347SkView* SkWidgetFactory(const char name[])
348{
halcanary96fcdcc2015-08-27 07:41:13 -0700349 if (name == nullptr)
350 return nullptr;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000351
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000352 // must be in the same order as the SkSkinWidgetEnum is declared
353 static const char* gNames[] = {
354 "sk-border",
355 "sk-button",
356 "sk-image",
357 "sk-list",
358 "sk-progress",
359 "sk-scroll",
360 "sk-text"
rmistry@google.comd6176b02012-08-23 18:14:13 +0000361
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000362 };
reed@android.com8a1c16f2008-12-17 15:59:43 +0000363
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000364 for (size_t i = 0; i < SK_ARRAY_COUNT(gNames); i++)
365 if (!strcmp(gNames[i], name))
366 return SkWidgetFactory((SkWidgetEnum)i);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000367
halcanary96fcdcc2015-08-27 07:41:13 -0700368 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369}
370
371#include "SkImageView.h"
372#include "SkProgressBarView.h"
373#include "SkScrollBarView.h"
374#include "SkBorderView.h"
375
376SkView* SkWidgetFactory(SkWidgetEnum sw)
377{
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000378 switch (sw) {
379 case kBorder_WidgetEnum:
380 return new SkBorderView;
381 case kButton_WidgetEnum:
382 return new SkAnimButtonView;
383 case kImage_WidgetEnum:
384 return new SkImageView;
385 case kList_WidgetEnum:
386 return new SkListView;
387 case kProgress_WidgetEnum:
388 return new SkProgressBarView;
389 case kScroll_WidgetEnum:
390 return new SkScrollBarView;
391 case kText_WidgetEnum:
392 return new SkStaticTextView;
393 default:
394 SkDEBUGFAIL("unknown enum passed to SkWidgetFactory");
395 break;
396 }
halcanary96fcdcc2015-08-27 07:41:13 -0700397 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000398}