/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SampleCode.h"
#include "SkAnimTimer.h"
#include "SkDrawable.h"
#include "SkView.h"
#include "SkCanvas.h"
#include "SkDrawable.h"
#include "SkPath.h"
#include "SkRandom.h"
#include "SkRSXform.h"
#include "SkSurface.h"
#include "SkGradientShader.h"
const struct {
SkXfermode::Mode fMode;
const char* fName;
} gModes[] = {
{ SkXfermode::kSrcOver_Mode, "src-over" },
{ SkXfermode::kSrc_Mode, "src" },
{ SkXfermode::kSrcIn_Mode, "src-in" },
{ SkXfermode::kSrcOut_Mode, "src-out" },
{ SkXfermode::kSrcATop_Mode, "src-atop" },
{ SkXfermode::kDstOver_Mode, "dst-over" },
{ SkXfermode::kDstIn_Mode, "dst-in" },
{ SkXfermode::kDstOut_Mode, "dst-out" },
{ SkXfermode::kDstATop_Mode, "dst-atop" },
};
const int N_Modes = SK_ARRAY_COUNT(gModes);
class HasEventWig : public SkView {
public:
void postWidgetEvent() {
SkEvent evt;
this->onPrepareWidEvent(&evt);
this->postToListeners(evt, 0);
}
protected:
virtual void onPrepareWidEvent(SkEvent*) {}
};
static SkRandom gRand;
class PushButtonWig : public HasEventWig {
SkString fLabel;
SkColor fColor;
uint32_t fFast32;
public:
PushButtonWig(const char label[], uint32_t fast) : fLabel(label) {
fColor = (gRand.nextU() & 0x7F7F7F7F) | SkColorSetARGB(0xFF, 0, 0, 0x80);
fFast32 = fast;
}
protected:
void onPrepareWidEvent(SkEvent* evt) override {
evt->setType("push-button");
evt->setFast32(fFast32);
evt->setString("label", fLabel.c_str());
}
// bool onEvent(const SkEvent&) override;
void onDraw(SkCanvas* canvas) override {
SkRect r;
this->getLocalBounds(&r);
SkPaint paint;
paint.setAntiAlias(true);
paint.setColor(fColor);
canvas->drawRoundRect(r, 8, 8, paint);
paint.setColor(0xFFFFFFFF);
paint.setTextSize(16);
paint.setTextAlign(SkPaint::kCenter_Align);
paint.setLCDRenderText(true);
canvas->drawText(fLabel.c_str(), fLabel.size(), r.centerX(), r.fTop + 0.68f * r.height(), paint);
}
Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
return new Click(this);
}
bool onClick(Click* click) override {
SkRect target = SkRect::MakeXYWH(click->fCurr.x() - 1, click->fCurr.y() - 1, 3, 3);
SkRect r;
this->getLocalBounds(&r);
if (r.intersects(target)) {
fColor = SkColorSetA(fColor, 0x99);
} else {
fColor = SkColorSetA(fColor, 0xFF);
}
this->inval(nullptr);
if (click->fState == SkView::Click::kUp_State) {
this->postWidgetEvent();
}
return true;
}
private:
typedef HasEventWig INHERITED;
};
class ModeDrawable : public SkDrawable {
public:
ModeDrawable() : fMode(SkXfermode::kSrcOver_Mode), fLoc(SkPoint::Make(0, 0)) {}
SkXfermode::Mode fMode;
SkPoint fLoc;
bool hitTest(SkScalar x, SkScalar y) {
SkRect target = SkRect::MakeXYWH(x - fLoc.x() - 1, y - fLoc.y() - 1, 3, 3);
return this->getBounds().intersects(target);
}
};
class CircDrawable : public ModeDrawable {
SkPaint fPaint;
SkRect fBounds;
public:
CircDrawable(SkScalar size, SkColor c) {
const SkColor colors[] = { 0, c };
SkAutoTUnref<SkShader> shader(SkGradientShader::CreateRadial(SkPoint::Make(size/2, size/2), size/2,
colors, nullptr, 2,
SkShader::kClamp_TileMode));
fPaint.setShader(shader);
fBounds = SkRect::MakeWH(size, size);
}
protected:
SkRect onGetBounds() override {
return fBounds;
}
void onDraw(SkCanvas* canvas) override {
fPaint.setXfermodeMode(fMode);
canvas->save();
canvas->translate(fLoc.x(), fLoc.y());
canvas->drawOval(fBounds, fPaint);
canvas->restore();
}
};
class XferDemo : public SampleView {
enum {
N = 4
};
SkRect fModeRect[N_Modes];
SkAutoTUnref<CircDrawable> fDrs[N];
CircDrawable* fSelected;
void addButtons() {
SkScalar x = 10;
SkScalar y = 10;
for (int i = 0; i < N_Modes; ++i) {
SkAutoTUnref<SkView> v(new PushButtonWig(gModes[i].fName, gModes[i].fMode));
v->setSize(70, 25);
v->setLoc(x, y);
v->setVisibleP(true);
v->setEnabledP(true);
v->addListenerID(this->getSinkID());
this->attachChildToFront(v);
fModeRect[i] = SkRect::MakeXYWH(x, y + 28, 70, 2);
x += 80;
}
}
public:
XferDemo() {
const SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorBLACK };
for (int i = 0; i < N; ++i) {
fDrs[i].reset(new CircDrawable(200, colors[i]));
fDrs[i]->fLoc.set(100.f + i * 100, 100.f + i * 100);
fDrs[i]->fMode = SkXfermode::kSrcOver_Mode;
}
fSelected = nullptr;
this->addButtons();
}
protected:
bool onEvent(const SkEvent& evt) override {
if (evt.isType("push-button")) {
if (fSelected) {
fSelected->fMode = (SkXfermode::Mode)evt.getFast32();
this->inval(nullptr);
}
return true;
}
return this->INHERITED::onEvent(evt);
}
bool onQuery(SkEvent* evt) override {
if (SampleCode::TitleQ(*evt)) {
SampleCode::TitleR(evt, "XferDemo");
return true;
}
return this->INHERITED::onQuery(evt);
}
void onDrawContent(SkCanvas* canvas) override {
SkPaint paint;
if (fSelected) {
for (int i = 0; i < N_Modes; ++i) {
if (fSelected->fMode == gModes[i].fMode) {
canvas->drawRect(fModeRect[i], paint);
break;
}
}
}
canvas->saveLayer(nullptr, nullptr);
for (int i = 0; i < N; ++i) {
fDrs[i]->draw(canvas);
}
canvas->restore();
}
SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned) override {
fSelected = nullptr;
for (int i = N - 1; i >= 0; --i) {
if (fDrs[i]->hitTest(x, y)) {
fSelected = fDrs[i];
break;
}
}
this->inval(nullptr);
return fSelected ? new Click(this) : nullptr;
}
bool onClick(Click* click) override {
fSelected->fLoc.fX += click->fCurr.fX - click->fPrev.fX;
fSelected->fLoc.fY += click->fCurr.fY - click->fPrev.fY;
this->inval(nullptr);
return true;
}
private:
typedef SampleView INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
DEF_SAMPLE( return new XferDemo; )