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 "SkString.h" 18 #include "SkSurface.h" 19 #include "SkGradientShader.h" 20 21 const SkBlendMode gModes[] = { 22 SkBlendMode::kSrcOver, 23 SkBlendMode::kSrc, 24 SkBlendMode::kSrcIn, 25 SkBlendMode::kSrcOut, 26 SkBlendMode::kSrcATop, 27 SkBlendMode::kDstOver, 28 SkBlendMode::kDstIn, 29 SkBlendMode::kDstOut, 30 SkBlendMode::kDstATop, 31 }; 32 const int N_Modes = SK_ARRAY_COUNT(gModes); 33 34 static SkRandom gRand; 35 36 struct ModeButton { 37 SkString fLabel; 38 SkColor fColor; 39 SkRect fRect; 40 41 public: 42 void init(const char label[], const SkRect& rect) { 43 fLabel = label; 44 fRect = rect; 45 fColor = (gRand.nextU() & 0x7F7F7F7F) | SkColorSetARGB(0xFF, 0, 0, 0x80); 46 } 47 48 void draw(SkCanvas* canvas) { 49 SkPaint paint; 50 paint.setAntiAlias(true); 51 paint.setColor(fColor); 52 canvas->drawRoundRect(fRect, 8, 8, paint); 53 54 paint.setColor(0xFFFFFFFF); 55 paint.setTextSize(16); 56 paint.setTextAlign(SkPaint::kCenter_Align); 57 paint.setLCDRenderText(true); 58 canvas->drawString(fLabel, fRect.centerX(), fRect.fTop + 0.68f * fRect.height(), paint); 59 } 60 61 bool hitTest(SkScalar x, SkScalar y) { 62 return fRect.intersects(x - 1, y - 1, x + 1, y + 1); 63 } 64 }; 65 66 class ModeDrawable : public SkDrawable { 67 public: 68 ModeDrawable() : fMode(SkBlendMode::kSrcOver), fLoc(SkPoint::Make(0, 0)) {} 69 70 SkBlendMode fMode; 71 SkPoint fLoc; 72 73 bool hitTest(SkScalar x, SkScalar y) { 74 SkRect target = SkRect::MakeXYWH(x - fLoc.x() - 1, y - fLoc.y() - 1, 3, 3); 75 return this->getBounds().intersects(target); 76 } 77 }; 78 79 class CircDrawable : public ModeDrawable { 80 SkPaint fPaint; 81 SkRect fBounds; 82 83 public: 84 CircDrawable(SkScalar size, SkColor c) { 85 const SkColor colors[] = { 0, c }; 86 fPaint.setShader(SkGradientShader::MakeRadial(SkPoint::Make(size/2, size/2), size/2, 87 colors, nullptr, 2, 88 SkShader::kClamp_TileMode)); 89 fBounds = SkRect::MakeWH(size, size); 90 } 91 92 protected: 93 SkRect onGetBounds() override { 94 return fBounds; 95 } 96 97 void onDraw(SkCanvas* canvas) override { 98 fPaint.setBlendMode(fMode); 99 canvas->save(); 100 canvas->translate(fLoc.x(), fLoc.y()); 101 canvas->drawOval(fBounds, fPaint); 102 canvas->restore(); 103 } 104 }; 105 106 class XferDemo : public SampleView { 107 enum { 108 N = 4 109 }; 110 111 SkRect fModeRect[N_Modes]; 112 ModeButton fModeButtons[N_Modes]; 113 sk_sp<CircDrawable> fDrs[N]; 114 CircDrawable* fSelected; 115 116 void addButtons() { 117 SkScalar x = 10; 118 SkScalar y = 10; 119 for (int i = 0; i < N_Modes; ++i) { 120 fModeButtons[i].init(SkBlendMode_Name(gModes[i]), SkRect::MakeXYWH(x, y, 70, 25)); 121 fModeRect[i] = SkRect::MakeXYWH(x, y + 28, 70, 2); 122 x += 80; 123 } 124 } 125 126 public: 127 XferDemo() { 128 const SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorBLACK }; 129 for (int i = 0; i < N; ++i) { 130 fDrs[i].reset(new CircDrawable(200, colors[i])); 131 fDrs[i]->fLoc.set(100.f + i * 100, 100.f + i * 100); 132 fDrs[i]->fMode = SkBlendMode::kSrcOver; 133 } 134 fSelected = nullptr; 135 136 this->addButtons(); 137 } 138 139 protected: 140 bool onQuery(SkEvent* evt) override { 141 if (SampleCode::TitleQ(*evt)) { 142 SampleCode::TitleR(evt, "XferDemo"); 143 return true; 144 } 145 return this->INHERITED::onQuery(evt); 146 } 147 148 void onDrawContent(SkCanvas* canvas) override { 149 for (int i = 0; i < N_Modes; ++i) { 150 fModeButtons[i].draw(canvas); 151 } 152 153 SkPaint paint; 154 if (fSelected) { 155 for (int i = 0; i < N_Modes; ++i) { 156 if (fSelected->fMode == gModes[i]) { 157 canvas->drawRect(fModeRect[i], paint); 158 break; 159 } 160 } 161 } 162 163 canvas->saveLayer(nullptr, nullptr); 164 for (int i = 0; i < N; ++i) { 165 fDrs[i]->draw(canvas); 166 } 167 canvas->restore(); 168 } 169 170 SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned) override { 171 // Check mode buttons first 172 for (int i = 0; i < N_Modes; ++i) { 173 if (fModeButtons[i].hitTest(x, y)) { 174 Click* click = new Click(this); 175 click->fMeta.setS32("mode", i); 176 return click; 177 } 178 } 179 fSelected = nullptr; 180 for (int i = N - 1; i >= 0; --i) { 181 if (fDrs[i]->hitTest(x, y)) { 182 fSelected = fDrs[i].get(); 183 break; 184 } 185 } 186 return fSelected ? new Click(this) : nullptr; 187 } 188 189 bool onClick(Click* click) override { 190 int32_t mode; 191 if (click->fMeta.findS32("mode", &mode)) { 192 if (fSelected && Click::kUp_State == click->fState) { 193 fSelected->fMode = gModes[mode]; 194 } 195 } else { 196 fSelected->fLoc.fX += click->fCurr.fX - click->fPrev.fX; 197 fSelected->fLoc.fY += click->fCurr.fY - click->fPrev.fY; 198 } 199 return true; 200 } 201 202 private: 203 typedef SampleView INHERITED; 204 }; 205 206 ////////////////////////////////////////////////////////////////////////////// 207 208 DEF_SAMPLE( return new XferDemo; ) 209