SkWidgetViews.cpp revision f8cacf6b11e35785df8efb613b0c3592d535f603
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