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 "Sample.h" 9 #include "SkAnimTimer.h" 10 #include "SkDrawable.h" 11 #include "SkCanvas.h" 12 #include "SkDrawable.h" 13 #include "SkPath.h" 14 #include "SkRandom.h" 15 #include "SkRSXform.h" 16 #include "SkString.h" 17 #include "SkSurface.h" 18 #include "SkTextUtils.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: initModeButton42 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 drawModeButton48 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 SkFont font; 56 font.setSize(16); 57 font.setEdging(SkFont::Edging::kSubpixelAntiAlias); 58 SkTextUtils::DrawString(canvas, fLabel.c_str(), fRect.centerX(), fRect.fTop + 0.68f * fRect.height(), 59 font, paint, SkTextUtils::kCenter_Align); 60 } 61 hitTestModeButton62 bool hitTest(SkScalar x, SkScalar y) { 63 return fRect.intersects(x - 1, y - 1, x + 1, y + 1); 64 } 65 }; 66 67 class ModeDrawable : public SkDrawable { 68 public: ModeDrawable()69 ModeDrawable() : fMode(SkBlendMode::kSrcOver), fLoc(SkPoint::Make(0, 0)) {} 70 71 SkBlendMode fMode; 72 SkPoint fLoc; 73 hitTest(SkScalar x,SkScalar y)74 bool hitTest(SkScalar x, SkScalar y) { 75 SkRect target = SkRect::MakeXYWH(x - fLoc.x() - 1, y - fLoc.y() - 1, 3, 3); 76 return this->getBounds().intersects(target); 77 } 78 }; 79 80 class CircDrawable : public ModeDrawable { 81 SkPaint fPaint; 82 SkRect fBounds; 83 84 public: CircDrawable(SkScalar size,SkColor c)85 CircDrawable(SkScalar size, SkColor c) { 86 const SkColor colors[] = { 0, c }; 87 fPaint.setShader(SkGradientShader::MakeRadial(SkPoint::Make(size/2, size/2), size/2, 88 colors, nullptr, 2, 89 SkShader::kClamp_TileMode)); 90 fBounds = SkRect::MakeWH(size, size); 91 } 92 93 protected: onGetBounds()94 SkRect onGetBounds() override { 95 return fBounds; 96 } 97 onDraw(SkCanvas * canvas)98 void onDraw(SkCanvas* canvas) override { 99 fPaint.setBlendMode(fMode); 100 canvas->save(); 101 canvas->translate(fLoc.x(), fLoc.y()); 102 canvas->drawOval(fBounds, fPaint); 103 canvas->restore(); 104 } 105 }; 106 107 class XferDemo : public Sample { 108 enum { 109 N = 4 110 }; 111 112 SkRect fModeRect[N_Modes]; 113 ModeButton fModeButtons[N_Modes]; 114 sk_sp<CircDrawable> fDrs[N]; 115 CircDrawable* fSelected; 116 addButtons()117 void addButtons() { 118 SkScalar x = 10; 119 SkScalar y = 10; 120 for (int i = 0; i < N_Modes; ++i) { 121 fModeButtons[i].init(SkBlendMode_Name(gModes[i]), SkRect::MakeXYWH(x, y, 70, 25)); 122 fModeRect[i] = SkRect::MakeXYWH(x, y + 28, 70, 2); 123 x += 80; 124 } 125 } 126 127 public: XferDemo()128 XferDemo() { 129 const SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorBLACK }; 130 for (int i = 0; i < N; ++i) { 131 fDrs[i].reset(new CircDrawable(200, colors[i])); 132 fDrs[i]->fLoc.set(100.f + i * 100, 100.f + i * 100); 133 fDrs[i]->fMode = SkBlendMode::kSrcOver; 134 } 135 fSelected = nullptr; 136 137 this->addButtons(); 138 } 139 140 protected: onQuery(Sample::Event * evt)141 bool onQuery(Sample::Event* evt) override { 142 if (Sample::TitleQ(*evt)) { 143 Sample::TitleR(evt, "XferDemo"); 144 return true; 145 } 146 return this->INHERITED::onQuery(evt); 147 } 148 onDrawContent(SkCanvas * canvas)149 void onDrawContent(SkCanvas* canvas) override { 150 for (int i = 0; i < N_Modes; ++i) { 151 fModeButtons[i].draw(canvas); 152 } 153 154 SkPaint paint; 155 if (fSelected) { 156 for (int i = 0; i < N_Modes; ++i) { 157 if (fSelected->fMode == gModes[i]) { 158 canvas->drawRect(fModeRect[i], paint); 159 break; 160 } 161 } 162 } 163 164 canvas->saveLayer(nullptr, nullptr); 165 for (int i = 0; i < N; ++i) { 166 fDrs[i]->draw(canvas); 167 } 168 canvas->restore(); 169 } 170 onFindClickHandler(SkScalar x,SkScalar y,unsigned)171 Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned) override { 172 // Check mode buttons first 173 for (int i = 0; i < N_Modes; ++i) { 174 if (fModeButtons[i].hitTest(x, y)) { 175 Click* click = new Click(this); 176 click->fMeta.setS32("mode", i); 177 return click; 178 } 179 } 180 fSelected = nullptr; 181 for (int i = N - 1; i >= 0; --i) { 182 if (fDrs[i]->hitTest(x, y)) { 183 fSelected = fDrs[i].get(); 184 break; 185 } 186 } 187 return fSelected ? new Click(this) : nullptr; 188 } 189 onClick(Click * click)190 bool onClick(Click* click) override { 191 int32_t mode; 192 if (click->fMeta.findS32("mode", &mode)) { 193 if (fSelected && Click::kUp_State == click->fState) { 194 fSelected->fMode = gModes[mode]; 195 } 196 } else { 197 fSelected->fLoc.fX += click->fCurr.fX - click->fPrev.fX; 198 fSelected->fLoc.fY += click->fCurr.fY - click->fPrev.fY; 199 } 200 return true; 201 } 202 203 private: 204 typedef Sample INHERITED; 205 }; 206 207 ////////////////////////////////////////////////////////////////////////////// 208 209 DEF_SAMPLE( return new XferDemo; ) 210