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