blob: bc6b91164277350294d5472c99e98cc3c949d268 [file] [log] [blame]
reed1a9caff2015-09-02 19:05:10 -07001/*
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
Ben Wagnerb2c4ea62018-08-08 11:36:17 -04008#include "Sample.h"
reed1a9caff2015-09-02 19:05:10 -07009#include "SkAnimTimer.h"
10#include "SkDrawable.h"
reed1a9caff2015-09-02 19:05:10 -070011#include "SkCanvas.h"
12#include "SkDrawable.h"
13#include "SkPath.h"
14#include "SkRandom.h"
15#include "SkRSXform.h"
Brian Osman8ceee432017-12-01 10:52:28 -050016#include "SkString.h"
reed1a9caff2015-09-02 19:05:10 -070017#include "SkSurface.h"
Mike Reeda697df92018-10-26 07:28:30 -040018#include "SkTextUtils.h"
reed1a9caff2015-09-02 19:05:10 -070019#include "SkGradientShader.h"
20
Brian Osmand1e67e72017-03-15 12:19:37 -040021const 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,
reed1a9caff2015-09-02 19:05:10 -070031};
32const int N_Modes = SK_ARRAY_COUNT(gModes);
33
reed1a9caff2015-09-02 19:05:10 -070034static SkRandom gRand;
35
Brian Osmanede860e2017-11-22 16:36:07 -050036struct ModeButton {
reed1a9caff2015-09-02 19:05:10 -070037 SkString fLabel;
38 SkColor fColor;
Brian Osmanede860e2017-11-22 16:36:07 -050039 SkRect fRect;
reed1a9caff2015-09-02 19:05:10 -070040
41public:
Brian Osmanede860e2017-11-22 16:36:07 -050042 void init(const char label[], const SkRect& rect) {
43 fLabel = label;
44 fRect = rect;
reed1a9caff2015-09-02 19:05:10 -070045 fColor = (gRand.nextU() & 0x7F7F7F7F) | SkColorSetARGB(0xFF, 0, 0, 0x80);
reed1a9caff2015-09-02 19:05:10 -070046 }
halcanary9d524f22016-03-29 09:03:52 -070047
Brian Osmanede860e2017-11-22 16:36:07 -050048 void draw(SkCanvas* canvas) {
reed1a9caff2015-09-02 19:05:10 -070049 SkPaint paint;
50 paint.setAntiAlias(true);
51 paint.setColor(fColor);
Brian Osmanede860e2017-11-22 16:36:07 -050052 canvas->drawRoundRect(fRect, 8, 8, paint);
reed1a9caff2015-09-02 19:05:10 -070053
54 paint.setColor(0xFFFFFFFF);
Mike Reedb579f072019-01-03 15:45:53 -050055 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);
reed1a9caff2015-09-02 19:05:10 -070060 }
61
Brian Osmanede860e2017-11-22 16:36:07 -050062 bool hitTest(SkScalar x, SkScalar y) {
63 return fRect.intersects(x - 1, y - 1, x + 1, y + 1);
reed1a9caff2015-09-02 19:05:10 -070064 }
reed1a9caff2015-09-02 19:05:10 -070065};
66
reed1a9caff2015-09-02 19:05:10 -070067class ModeDrawable : public SkDrawable {
68public:
reed374772b2016-10-05 17:33:02 -070069 ModeDrawable() : fMode(SkBlendMode::kSrcOver), fLoc(SkPoint::Make(0, 0)) {}
reed1a9caff2015-09-02 19:05:10 -070070
reed374772b2016-10-05 17:33:02 -070071 SkBlendMode fMode;
72 SkPoint fLoc;
reed1a9caff2015-09-02 19:05:10 -070073
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
80class CircDrawable : public ModeDrawable {
81 SkPaint fPaint;
82 SkRect fBounds;
83
84public:
85 CircDrawable(SkScalar size, SkColor c) {
86 const SkColor colors[] = { 0, c };
reed8a21c9f2016-03-08 18:50:00 -080087 fPaint.setShader(SkGradientShader::MakeRadial(SkPoint::Make(size/2, size/2), size/2,
reed1a9caff2015-09-02 19:05:10 -070088 colors, nullptr, 2,
89 SkShader::kClamp_TileMode));
reed1a9caff2015-09-02 19:05:10 -070090 fBounds = SkRect::MakeWH(size, size);
91 }
92
93protected:
94 SkRect onGetBounds() override {
95 return fBounds;
96 }
97
98 void onDraw(SkCanvas* canvas) override {
reed374772b2016-10-05 17:33:02 -070099 fPaint.setBlendMode(fMode);
reed1a9caff2015-09-02 19:05:10 -0700100 canvas->save();
101 canvas->translate(fLoc.x(), fLoc.y());
102 canvas->drawOval(fBounds, fPaint);
103 canvas->restore();
104 }
105};
106
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400107class XferDemo : public Sample {
reed1a9caff2015-09-02 19:05:10 -0700108 enum {
109 N = 4
110 };
halcanary9d524f22016-03-29 09:03:52 -0700111
reed1a9caff2015-09-02 19:05:10 -0700112 SkRect fModeRect[N_Modes];
Brian Osmanede860e2017-11-22 16:36:07 -0500113 ModeButton fModeButtons[N_Modes];
Hal Canary2db83612016-11-04 13:02:54 -0400114 sk_sp<CircDrawable> fDrs[N];
reed1a9caff2015-09-02 19:05:10 -0700115 CircDrawable* fSelected;
116
117 void addButtons() {
118 SkScalar x = 10;
119 SkScalar y = 10;
120 for (int i = 0; i < N_Modes; ++i) {
Brian Osmanede860e2017-11-22 16:36:07 -0500121 fModeButtons[i].init(SkBlendMode_Name(gModes[i]), SkRect::MakeXYWH(x, y, 70, 25));
reed1a9caff2015-09-02 19:05:10 -0700122 fModeRect[i] = SkRect::MakeXYWH(x, y + 28, 70, 2);
123 x += 80;
124 }
125 }
126
127public:
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);
reed374772b2016-10-05 17:33:02 -0700133 fDrs[i]->fMode = SkBlendMode::kSrcOver;
reed1a9caff2015-09-02 19:05:10 -0700134 }
135 fSelected = nullptr;
136
137 this->addButtons();
138 }
139
140protected:
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400141 bool onQuery(Sample::Event* evt) override {
142 if (Sample::TitleQ(*evt)) {
143 Sample::TitleR(evt, "XferDemo");
reed1a9caff2015-09-02 19:05:10 -0700144 return true;
145 }
146 return this->INHERITED::onQuery(evt);
147 }
148
149 void onDrawContent(SkCanvas* canvas) override {
Brian Osmanede860e2017-11-22 16:36:07 -0500150 for (int i = 0; i < N_Modes; ++i) {
151 fModeButtons[i].draw(canvas);
152 }
153
reed1a9caff2015-09-02 19:05:10 -0700154 SkPaint paint;
155 if (fSelected) {
156 for (int i = 0; i < N_Modes; ++i) {
Brian Osmand1e67e72017-03-15 12:19:37 -0400157 if (fSelected->fMode == gModes[i]) {
reed1a9caff2015-09-02 19:05:10 -0700158 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
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400171 Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned) override {
Brian Osmanede860e2017-11-22 16:36:07 -0500172 // 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 }
reed1a9caff2015-09-02 19:05:10 -0700180 fSelected = nullptr;
181 for (int i = N - 1; i >= 0; --i) {
182 if (fDrs[i]->hitTest(x, y)) {
Hal Canary2db83612016-11-04 13:02:54 -0400183 fSelected = fDrs[i].get();
reed1a9caff2015-09-02 19:05:10 -0700184 break;
185 }
186 }
reed1a9caff2015-09-02 19:05:10 -0700187 return fSelected ? new Click(this) : nullptr;
188 }
halcanary9d524f22016-03-29 09:03:52 -0700189
reed1a9caff2015-09-02 19:05:10 -0700190 bool onClick(Click* click) override {
Brian Osmanede860e2017-11-22 16:36:07 -0500191 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 }
reed1a9caff2015-09-02 19:05:10 -0700200 return true;
201 }
202
203private:
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400204 typedef Sample INHERITED;
reed1a9caff2015-09-02 19:05:10 -0700205};
206
207//////////////////////////////////////////////////////////////////////////////
208
209DEF_SAMPLE( return new XferDemo; )