1 /* 2 * Copyright 2015 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SampleCode.h" 9 #include "SkAnimTimer.h" 10 #include "SkDrawable.h" 11 #include "SkView.h" 12 #include "SkCanvas.h" 13 #include "SkDrawable.h" 14 #include "SkPath.h" 15 #include "SkRandom.h" 16 #include "SkRSXform.h" 17 #include "SkSurface.h" 18 #include "SkGradientShader.h" 19 20 const struct { 21 SkXfermode::Mode fMode; 22 const char* fName; 23 } gModes[] = { 24 { SkXfermode::kSrcOver_Mode, "src-over" }, 25 { SkXfermode::kSrc_Mode, "src" }, 26 { SkXfermode::kSrcIn_Mode, "src-in" }, 27 { SkXfermode::kSrcOut_Mode, "src-out" }, 28 { SkXfermode::kSrcATop_Mode, "src-atop" }, 29 { SkXfermode::kDstOver_Mode, "dst-over" }, 30 { SkXfermode::kDstIn_Mode, "dst-in" }, 31 { SkXfermode::kDstOut_Mode, "dst-out" }, 32 { SkXfermode::kDstATop_Mode, "dst-atop" }, 33 }; 34 const int N_Modes = SK_ARRAY_COUNT(gModes); 35 36 class HasEventWig : public SkView { 37 public: postWidgetEvent()38 void postWidgetEvent() { 39 SkEvent evt; 40 this->onPrepareWidEvent(&evt); 41 this->postToListeners(evt, 0); 42 } 43 44 protected: onPrepareWidEvent(SkEvent *)45 virtual void onPrepareWidEvent(SkEvent*) {} 46 }; 47 48 static SkRandom gRand; 49 50 class PushButtonWig : public HasEventWig { 51 SkString fLabel; 52 SkColor fColor; 53 uint32_t fFast32; 54 55 public: PushButtonWig(const char label[],uint32_t fast)56 PushButtonWig(const char label[], uint32_t fast) : fLabel(label) { 57 fColor = (gRand.nextU() & 0x7F7F7F7F) | SkColorSetARGB(0xFF, 0, 0, 0x80); 58 fFast32 = fast; 59 } 60 61 protected: onPrepareWidEvent(SkEvent * evt)62 void onPrepareWidEvent(SkEvent* evt) override { 63 evt->setType("push-button"); 64 evt->setFast32(fFast32); 65 evt->setString("label", fLabel.c_str()); 66 } 67 68 // bool onEvent(const SkEvent&) override; onDraw(SkCanvas * canvas)69 void onDraw(SkCanvas* canvas) override { 70 SkRect r; 71 this->getLocalBounds(&r); 72 SkPaint paint; 73 paint.setAntiAlias(true); 74 paint.setColor(fColor); 75 canvas->drawRoundRect(r, 8, 8, paint); 76 77 paint.setColor(0xFFFFFFFF); 78 paint.setTextSize(16); 79 paint.setTextAlign(SkPaint::kCenter_Align); 80 paint.setLCDRenderText(true); 81 canvas->drawText(fLabel.c_str(), fLabel.size(), r.centerX(), r.fTop + 0.68f * r.height(), paint); 82 } 83 onFindClickHandler(SkScalar x,SkScalar y,unsigned modi)84 Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override { 85 return new Click(this); 86 } 87 onClick(Click * click)88 bool onClick(Click* click) override { 89 SkRect target = SkRect::MakeXYWH(click->fCurr.x() - 1, click->fCurr.y() - 1, 3, 3); 90 SkRect r; 91 this->getLocalBounds(&r); 92 if (r.intersects(target)) { 93 fColor = SkColorSetA(fColor, 0x99); 94 } else { 95 fColor = SkColorSetA(fColor, 0xFF); 96 } 97 this->inval(nullptr); 98 99 if (click->fState == SkView::Click::kUp_State) { 100 this->postWidgetEvent(); 101 } 102 return true; 103 } 104 105 private: 106 typedef HasEventWig INHERITED; 107 }; 108 109 110 class ModeDrawable : public SkDrawable { 111 public: ModeDrawable()112 ModeDrawable() : fMode(SkXfermode::kSrcOver_Mode), fLoc(SkPoint::Make(0, 0)) {} 113 114 SkXfermode::Mode fMode; 115 SkPoint fLoc; 116 hitTest(SkScalar x,SkScalar y)117 bool hitTest(SkScalar x, SkScalar y) { 118 SkRect target = SkRect::MakeXYWH(x - fLoc.x() - 1, y - fLoc.y() - 1, 3, 3); 119 return this->getBounds().intersects(target); 120 } 121 }; 122 123 class CircDrawable : public ModeDrawable { 124 SkPaint fPaint; 125 SkRect fBounds; 126 127 public: CircDrawable(SkScalar size,SkColor c)128 CircDrawable(SkScalar size, SkColor c) { 129 const SkColor colors[] = { 0, c }; 130 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateRadial(SkPoint::Make(size/2, size/2), size/2, 131 colors, nullptr, 2, 132 SkShader::kClamp_TileMode)); 133 fPaint.setShader(shader); 134 fBounds = SkRect::MakeWH(size, size); 135 } 136 137 protected: onGetBounds()138 SkRect onGetBounds() override { 139 return fBounds; 140 } 141 onDraw(SkCanvas * canvas)142 void onDraw(SkCanvas* canvas) override { 143 fPaint.setXfermodeMode(fMode); 144 canvas->save(); 145 canvas->translate(fLoc.x(), fLoc.y()); 146 canvas->drawOval(fBounds, fPaint); 147 canvas->restore(); 148 } 149 }; 150 151 class XferDemo : public SampleView { 152 enum { 153 N = 4 154 }; 155 156 SkRect fModeRect[N_Modes]; 157 SkAutoTUnref<CircDrawable> fDrs[N]; 158 CircDrawable* fSelected; 159 addButtons()160 void addButtons() { 161 SkScalar x = 10; 162 SkScalar y = 10; 163 for (int i = 0; i < N_Modes; ++i) { 164 SkAutoTUnref<SkView> v(new PushButtonWig(gModes[i].fName, gModes[i].fMode)); 165 v->setSize(70, 25); 166 v->setLoc(x, y); 167 v->setVisibleP(true); 168 v->setEnabledP(true); 169 v->addListenerID(this->getSinkID()); 170 this->attachChildToFront(v); 171 fModeRect[i] = SkRect::MakeXYWH(x, y + 28, 70, 2); 172 x += 80; 173 } 174 } 175 176 public: XferDemo()177 XferDemo() { 178 const SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorBLACK }; 179 for (int i = 0; i < N; ++i) { 180 fDrs[i].reset(new CircDrawable(200, colors[i])); 181 fDrs[i]->fLoc.set(100.f + i * 100, 100.f + i * 100); 182 fDrs[i]->fMode = SkXfermode::kSrcOver_Mode; 183 } 184 fSelected = nullptr; 185 186 this->addButtons(); 187 } 188 189 protected: onEvent(const SkEvent & evt)190 bool onEvent(const SkEvent& evt) override { 191 if (evt.isType("push-button")) { 192 if (fSelected) { 193 fSelected->fMode = (SkXfermode::Mode)evt.getFast32(); 194 this->inval(nullptr); 195 } 196 return true; 197 } 198 return this->INHERITED::onEvent(evt); 199 } 200 onQuery(SkEvent * evt)201 bool onQuery(SkEvent* evt) override { 202 if (SampleCode::TitleQ(*evt)) { 203 SampleCode::TitleR(evt, "XferDemo"); 204 return true; 205 } 206 return this->INHERITED::onQuery(evt); 207 } 208 onDrawContent(SkCanvas * canvas)209 void onDrawContent(SkCanvas* canvas) override { 210 SkPaint paint; 211 if (fSelected) { 212 for (int i = 0; i < N_Modes; ++i) { 213 if (fSelected->fMode == gModes[i].fMode) { 214 canvas->drawRect(fModeRect[i], paint); 215 break; 216 } 217 } 218 } 219 220 canvas->saveLayer(nullptr, nullptr); 221 for (int i = 0; i < N; ++i) { 222 fDrs[i]->draw(canvas); 223 } 224 canvas->restore(); 225 } 226 onFindClickHandler(SkScalar x,SkScalar y,unsigned)227 SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned) override { 228 fSelected = nullptr; 229 for (int i = N - 1; i >= 0; --i) { 230 if (fDrs[i]->hitTest(x, y)) { 231 fSelected = fDrs[i]; 232 break; 233 } 234 } 235 this->inval(nullptr); 236 return fSelected ? new Click(this) : nullptr; 237 } 238 onClick(Click * click)239 bool onClick(Click* click) override { 240 fSelected->fLoc.fX += click->fCurr.fX - click->fPrev.fX; 241 fSelected->fLoc.fY += click->fCurr.fY - click->fPrev.fY; 242 this->inval(nullptr); 243 return true; 244 } 245 246 private: 247 typedef SampleView INHERITED; 248 }; 249 250 ////////////////////////////////////////////////////////////////////////////// 251 252 DEF_SAMPLE( return new XferDemo; ) 253