Sample not RefCnted; ClickHandling moved out of viewer

Change-Id: I23456144b267192928a1253692daf846329f2ab5
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/227067
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Hal Canary <halcanary@google.com>
diff --git a/samplecode/PerlinPatch.cpp b/samplecode/PerlinPatch.cpp
index eb40048..5736e9e 100644
--- a/samplecode/PerlinPatch.cpp
+++ b/samplecode/PerlinPatch.cpp
@@ -160,7 +160,7 @@
     class PtClick : public Click {
     public:
         int fIndex;
-        PtClick(Sample* view, int index) : Click(view), fIndex(index) {}
+        PtClick(int index) : fIndex(index) {}
     };
 
     static bool hittest(const SkPoint& pt, SkScalar x, SkScalar y) {
@@ -169,19 +169,19 @@
 
     Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, ModifierKey modi) override {
         if (ModifierKey::kShift == modi) {
-            return new PtClick(this, -1);
+            return new PtClick(-1);
         }
         if (ModifierKey::kControl == modi) {
-            return new PtClick(this, -2);
+            return new PtClick(-2);
         }
         SkPoint clickPoint = {x, y};
         fInvMatrix.mapPoints(&clickPoint, 1);
         for (size_t i = 0; i < SK_ARRAY_COUNT(fPts); i++) {
             if (hittest(fPts[i], clickPoint.fX, clickPoint.fY)) {
-                return new PtClick(this, (int)i);
+                return new PtClick((int)i);
             }
         }
-        return this->INHERITED::onFindClickHandler(x, y, modi);
+        return nullptr;
     }
 
     bool onClick(Click* click) override {
diff --git a/samplecode/Sample.cpp b/samplecode/Sample.cpp
index 67d9da0..69eb677 100644
--- a/samplecode/Sample.cpp
+++ b/samplecode/Sample.cpp
@@ -61,76 +61,45 @@
 
 ////////////////////////////////////////////////////////////////////////////
 
-Sample::Click::Click(Sample* target) {
-    SkASSERT(target);
-    fTarget = sk_ref_sp(target);
-}
-
-Sample::Click::~Click() {}
-
-Sample::Click* Sample::findClickHandler(SkScalar x, SkScalar y, ModifierKey modi) {
-    if (x < 0 || y < 0 || x >= fWidth || y >= fHeight) {
-        return nullptr;
+bool Sample::mouse(SkPoint point, InputState clickState, ModifierKey modifierKeys) {
+    switch (clickState) {
+        case InputState::kDown:
+            fClick = nullptr;
+            if (point.x() < 0 || point.y() < 0 || point.x() >= fWidth || point.y() >= fHeight) {
+                return false;
+            }
+            fClick.reset(this->onFindClickHandler(point.x(), point.y(), modifierKeys));
+            if (!fClick) {
+                return false;
+            }
+            fClick->fPrev = fClick->fCurr = fClick->fOrig = point;
+            fClick->fState = InputState::kDown;
+            fClick->fModifierKeys = modifierKeys;
+            this->onClick(fClick.get());
+            return true;
+        case InputState::kMove:
+            if (fClick) {
+                fClick->fPrev = fClick->fCurr;
+                fClick->fCurr = point;
+                fClick->fState = InputState::kMove;
+                fClick->fModifierKeys = modifierKeys;
+                return this->onClick(fClick.get());
+            }
+            return false;
+        case InputState::kUp:
+            if (fClick) {
+                fClick->fPrev = fClick->fCurr;
+                fClick->fCurr = point;
+                fClick->fState = InputState::kUp;
+                fClick->fModifierKeys = modifierKeys;
+                bool result = this->onClick(fClick.get());
+                fClick = nullptr;
+                return result;
+            }
+            break;
     }
-
-    return this->onFindClickHandler(x, y, modi);
-}
-
-void Sample::DoClickDown(Click* click, int x, int y, ModifierKey modi) {
-    SkASSERT(click);
-
-    Sample* target = click->fTarget.get();
-    if (nullptr == target) {
-        return;
-    }
-
-    click->fIOrig.set(x, y);
-    click->fICurr = click->fIPrev = click->fIOrig;
-
-    click->fOrig.iset(x, y);
-    click->fPrev = click->fCurr = click->fOrig;
-
-    click->fState = Click::kDown_State;
-    click->fModifierKeys = modi;
-    target->onClick(click);
-}
-
-void Sample::DoClickMoved(Click* click, int x, int y, ModifierKey modi) {
-    SkASSERT(click);
-
-    Sample* target = click->fTarget.get();
-    if (nullptr == target) {
-        return;
-    }
-
-    click->fIPrev = click->fICurr;
-    click->fICurr.set(x, y);
-
-    click->fPrev = click->fCurr;
-    click->fCurr.iset(x, y);
-
-    click->fState = Click::kMoved_State;
-    click->fModifierKeys = modi;
-    target->onClick(click);
-}
-
-void Sample::DoClickUp(Click* click, int x, int y, ModifierKey modi) {
-    SkASSERT(click);
-
-    Sample* target = click->fTarget.get();
-    if (nullptr == target) {
-        return;
-    }
-
-    click->fIPrev = click->fICurr;
-    click->fICurr.set(x, y);
-
-    click->fPrev = click->fCurr;
-    click->fCurr.iset(x, y);
-
-    click->fState = Click::kUp_State;
-    click->fModifierKeys = modi;
-    target->onClick(click);
+    SkASSERT(false);
+    return false;
 }
 
 //////////////////////////////////////////////////////////////////////
diff --git a/samplecode/Sample.h b/samplecode/Sample.h
index a7c0a39..390ac4c 100644
--- a/samplecode/Sample.h
+++ b/samplecode/Sample.h
@@ -29,7 +29,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-class Sample : public SkRefCnt {
+class Sample {
 public:
     Sample()
         : fBGColor(SK_ColorWHITE)
@@ -37,6 +37,8 @@
         , fHaveCalledOnceBeforeDraw(false)
     {}
 
+    virtual ~Sample() = default;
+
     SkScalar    width() const { return fWidth; }
     SkScalar    height() const { return fHeight; }
     void        setSize(SkScalar width, SkScalar height);
@@ -49,32 +51,20 @@
 
     virtual bool onChar(SkUnichar) { return false; }
 
-    //  Click handling
+    // Click handling
+    // TODO: unify Sample::InputState and sk_app::Window::InputState
+    enum class InputState { kDown, kUp, kMove };
     class Click {
     public:
-        Click(Sample* target);
-        virtual ~Click();
-
-        enum State {
-            kDown_State,
-            kMoved_State,
-            kUp_State
-        };
-        SkPoint     fOrig, fPrev, fCurr;
-        SkIPoint    fIOrig, fIPrev, fICurr;
-        State       fState;
+        virtual ~Click() = default;
+        SkPoint     fOrig = {0, 0};
+        SkPoint     fPrev = {0, 0};
+        SkPoint     fCurr = {0, 0};
+        InputState  fState = InputState::kDown;
         ModifierKey fModifierKeys = ModifierKey::kNone;
-
         SkMetaData  fMeta;
-    private:
-        sk_sp<Sample> fTarget;
-
-        friend class Sample;
     };
-    Click* findClickHandler(SkScalar x, SkScalar y, ModifierKey modifierKeys);
-    static void DoClickDown(Click*, int x, int y, ModifierKey modi);
-    static void DoClickMoved(Click*, int x, int y, ModifierKey modi);
-    static void DoClickUp(Click*, int x, int y, ModifierKey modi);
+    bool mouse(SkPoint point, InputState clickState, ModifierKey modifierKeys);
 
     void setBGColor(SkColor color) { fBGColor = color; }
     bool animate(double nanos) { return this->onAnimate(nanos); }
@@ -97,9 +87,13 @@
     virtual void onOnceBeforeDraw() {}
 
 private:
+    std::unique_ptr<Click> fClick;
     SkColor fBGColor;
     SkScalar fWidth, fHeight;
     bool fHaveCalledOnceBeforeDraw;
+
+    Sample(const Sample&) = delete;
+    Sample& operator=(const Sample&) = delete;
 };
 
 #endif
diff --git a/samplecode/SampleAAGeometry.cpp b/samplecode/SampleAAGeometry.cpp
index 14a2c60..5086f97 100644
--- a/samplecode/SampleAAGeometry.cpp
+++ b/samplecode/SampleAAGeometry.cpp
@@ -683,25 +683,22 @@
     SkPath::Verb fVerb;
     SkScalar fWeight;
 
-    MyClick(Sample* target, ClickType type, ControlType control)
-        : Click(target)
-        , fType(type)
+    MyClick(ClickType type, ControlType control)
+        : fType(type)
         , fControl(control)
         , fVerb((SkPath::Verb) -1)
         , fWeight(1) {
     }
 
-    MyClick(Sample* target, ClickType type, int index)
-        : Click(target)
-        , fType(type)
+    MyClick(ClickType type, int index)
+        : fType(type)
         , fControl((ControlType) index)
         , fVerb((SkPath::Verb) -1)
         , fWeight(1) {
     }
 
-    MyClick(Sample* target, ClickType type, int index, SkPath::Verb verb, SkScalar weight)
-        : Click(target)
-        , fType(type)
+    MyClick(ClickType type, int index, SkPath::Verb verb, SkScalar weight)
+        : fType(type)
         , fControl((ControlType) index)
         , fVerb(verb)
         , fWeight(weight) {
@@ -892,8 +889,8 @@
         return true;
     }
 
-    void savePath(Click::State state) {
-        if (state != Click::kDown_State) {
+    void savePath(InputState state) {
+        if (state != InputState::kDown) {
             return;
         }
         if (fUndo && fUndo->fPath == fPath) {
@@ -1611,25 +1608,25 @@
         SkPoint pt = {x, y};
         int ptHit = hittest_pt(pt);
         if (ptHit >= 0) {
-            return new MyClick(this, MyClick::kPtType, ptHit);
+            return new MyClick(MyClick::kPtType, ptHit);
         }
         SkPath::Verb verb;
         SkScalar weight;
         int verbHit = hittest_verb(pt, &verb, &weight);
         if (verbHit >= 0) {
-            return new MyClick(this, MyClick::kVerbType, verbHit, verb, weight);
+            return new MyClick(MyClick::kVerbType, verbHit, verb, weight);
         }
         if (!fHideAll) {
             const SkRect& rectPt = SkRect::MakeXYWH(x, y, 1, 1);
             for (int index = 0; index < kControlCount; ++index) {
                 if (kControlList[index].fControl->contains(rectPt)) {
-                    return new MyClick(this, MyClick::kControlType,
+                    return new MyClick(MyClick::kControlType,
                             kControlList[index].fControlType);
                 }
             }
             for (int index = 0; index < kButtonCount; ++index) {
                 if (kButtonList[index].fButton->contains(rectPt)) {
-                    return new MyClick(this, MyClick::kControlType, kButtonList[index].fButtonType);
+                    return new MyClick(MyClick::kControlType, kButtonList[index].fButtonType);
                 }
             }
         }
@@ -1639,9 +1636,9 @@
         fActiveVerb = -1;
         fActivePt = -1;
         if (fHandlePathMove) {
-            return new MyClick(this, MyClick::kPathType, MyClick::kPathMove);
+            return new MyClick(MyClick::kPathType, MyClick::kPathMove);
         }
-        return this->INHERITED::onFindClickHandler(x, y, modi);
+        return nullptr;
     }
 
     static SkScalar MapScreenYtoValue(int y, const UniControl& control) {
@@ -1657,16 +1654,16 @@
                 savePath(click->fState);
                 fActivePt = myClick->ptHit();
                 SkPoint pt = fPath.getPoint((int) myClick->fControl);
-                pt.offset(SkIntToScalar(click->fICurr.fX - click->fIPrev.fX),
-                        SkIntToScalar(click->fICurr.fY - click->fIPrev.fY));
+                pt.offset(SkIntToScalar(click->fCurr.fX - click->fPrev.fX),
+                        SkIntToScalar(click->fCurr.fY - click->fPrev.fY));
                 set_path_pt(fActivePt, pt, &fPath);
                 validatePath();
                 return true;
                 }
             case MyClick::kPathType:
                 savePath(click->fState);
-                fPath.offset(SkIntToScalar(click->fICurr.fX - click->fIPrev.fX),
-                        SkIntToScalar(click->fICurr.fY - click->fIPrev.fY));
+                fPath.offset(SkIntToScalar(click->fCurr.fX - click->fPrev.fX),
+                        SkIntToScalar(click->fCurr.fY - click->fPrev.fY));
                 validatePath();
                 return true;
             case MyClick::kVerbType: {
@@ -1682,12 +1679,12 @@
                 fWeightControl.fVisible = myClick->fVerb == SkPath::kConic_Verb;
                 } break;
             case MyClick::kControlType: {
-                if (click->fState != Click::kDown_State && myClick->isButton()) {
+                if (click->fState != InputState::kDown && myClick->isButton()) {
                     return true;
                 }
                 switch (myClick->fControl) {
                     case MyClick::kFilterControl: {
-                        SkScalar val = MapScreenYtoValue(click->fICurr.fY, fFilterControl);
+                        SkScalar val = MapScreenYtoValue(click->fCurr.fY, fFilterControl);
                         if (val - fFilterControl.fValLo < fFilterControl.fValHi - val) {
                             fFilterControl.fValLo = SkTMax(0.f, val);
                         } else {
@@ -1695,17 +1692,17 @@
                         }
                         } break;
                     case MyClick::kResControl:
-                        fResControl.fValLo = MapScreenYtoValue(click->fICurr.fY, fResControl);
+                        fResControl.fValLo = MapScreenYtoValue(click->fCurr.fY, fResControl);
                         break;
                     case MyClick::kWeightControl: {
                         savePath(click->fState);
-                        SkScalar w = MapScreenYtoValue(click->fICurr.fY, fWeightControl);
+                        SkScalar w = MapScreenYtoValue(click->fCurr.fY, fWeightControl);
                         set_path_weight(fActiveVerb, w, &fPath);
                         validatePath();
                         fWeightControl.fValLo = w;
                         } break;
                     case MyClick::kWidthControl:
-                        fWidthControl.fValLo = MapScreenYtoValue(click->fICurr.fY, fWidthControl);
+                        fWidthControl.fValLo = MapScreenYtoValue(click->fCurr.fY, fWidthControl);
                         break;
                     case MyClick::kLineButton:
                         savePath(click->fState);
@@ -1821,8 +1818,8 @@
         for (int index = 0; index < kButtonCount; ++index) {
             Button* button = kButtonList[index].fButton;
             if (button->fVisible && uni == button->fLabel) {
-                MyClick click(this, MyClick::kControlType, kButtonList[index].fButtonType);
-                click.fState = Click::kDown_State;
+                MyClick click(MyClick::kControlType, kButtonList[index].fButtonType);
+                click.fState = InputState::kDown;
                 (void) this->onClick(&click);
                 return true;
             }
@@ -1837,8 +1834,8 @@
             for (int index = 0; index < kButtonCount; ++index) {
                 Button* button = kButtonList[index].fButton;
                 if (button->fVisible && (uni & ~0x20) == (button->fLabel & ~0x20)) {
-                    MyClick click(this, MyClick::kControlType, kButtonList[index].fButtonType);
-                    click.fState = Click::kDown_State;
+                    MyClick click(MyClick::kControlType, kButtonList[index].fButtonType);
+                    click.fState = InputState::kDown;
                     (void) this->onClick(&click);
                     return true;
                 }
diff --git a/samplecode/SampleCCPRGeometry.cpp b/samplecode/SampleCCPRGeometry.cpp
index 6908e98..3145865 100644
--- a/samplecode/SampleCCPRGeometry.cpp
+++ b/samplecode/SampleCCPRGeometry.cpp
@@ -401,24 +401,19 @@
 
 class CCPRGeometryView::Click : public Sample::Click {
 public:
-    Click(Sample* target, int ptIdx) : Sample::Click(target), fPtIdx(ptIdx) {}
+    Click(int ptIdx) : fPtIdx(ptIdx) {}
 
     void doClick(SkPoint points[]) {
         if (fPtIdx >= 0) {
-            this->dragPoint(points, fPtIdx);
+            points[fPtIdx] += fCurr - fPrev;
         } else {
             for (int i = 0; i < 4; ++i) {
-                this->dragPoint(points, i);
+                points[i] += fCurr - fPrev;
             }
         }
     }
 
 private:
-    void dragPoint(SkPoint points[], int idx) {
-        SkIPoint delta = fICurr - fIPrev;
-        points[idx] += SkPoint::Make(delta.x(), delta.y());
-    }
-
     int fPtIdx;
 };
 
@@ -428,10 +423,10 @@
             continue;
         }
         if (fabs(x - fPoints[i].x()) < 20 && fabsf(y - fPoints[i].y()) < 20) {
-            return new Click(this, i);
+            return new Click(i);
         }
     }
-    return new Click(this, -1);
+    return new Click(-1);
 }
 
 bool CCPRGeometryView::onClick(Sample::Click* click) {
diff --git a/samplecode/SampleDegenerateQuads.cpp b/samplecode/SampleDegenerateQuads.cpp
index 5303594..cadc600 100644
--- a/samplecode/SampleDegenerateQuads.cpp
+++ b/samplecode/SampleDegenerateQuads.cpp
@@ -452,9 +452,8 @@
 
 class DegenerateQuadSample::Click : public Sample::Click {
 public:
-    Click(Sample* target, const SkRect& clamp, int index)
-            : Sample::Click(target)
-            , fOuterRect(clamp)
+    Click(const SkRect& clamp, int index)
+            : fOuterRect(clamp)
             , fIndex(index) {}
 
     void doClick(SkPoint points[4]) {
@@ -472,7 +471,7 @@
     int fIndex;
 
     void drag(SkPoint* point) {
-        SkIPoint delta = fICurr - fIPrev;
+        SkPoint delta = fCurr - fPrev;
         *point += SkPoint::Make(delta.x() / kViewScale, delta.y() / kViewScale);
         point->fX = SkMinScalar(fOuterRect.fRight, SkMaxScalar(point->fX, fOuterRect.fLeft));
         point->fY = SkMinScalar(fOuterRect.fBottom, SkMaxScalar(point->fY, fOuterRect.fTop));
@@ -483,10 +482,10 @@
     SkPoint inCTM = SkPoint::Make((x - kViewOffset) / kViewScale, (y - kViewOffset) / kViewScale);
     for (int i = 0; i < 4; ++i) {
         if ((fCorners[i] - inCTM).length() < 10.f / kViewScale) {
-            return new Click(this, fOuterRect, i);
+            return new Click(fOuterRect, i);
         }
     }
-    return new Click(this, fOuterRect, -1);
+    return new Click(fOuterRect, -1);
 }
 
 bool DegenerateQuadSample::onClick(Sample::Click* click) {
diff --git a/samplecode/SampleFatBits.cpp b/samplecode/SampleFatBits.cpp
index d661aaa..796fdd5 100644
--- a/samplecode/SampleFatBits.cpp
+++ b/samplecode/SampleFatBits.cpp
@@ -364,7 +364,7 @@
 class IndexClick : public Sample::Click {
     int fIndex;
 public:
-    IndexClick(Sample* v, int index) : Sample::Click(v), fIndex(index) {}
+    IndexClick(int index) : fIndex(index) {}
 
     static int GetIndex(Sample::Click* click) {
         return ((IndexClick*)click)->fIndex;
@@ -480,7 +480,7 @@
                 break;
             }
         }
-        return new IndexClick(this, index);
+        return new IndexClick(index);
     }
 
     bool onClick(Click* click) override {
diff --git a/samplecode/SampleLayers.cpp b/samplecode/SampleLayers.cpp
index 037530c..526ea69 100644
--- a/samplecode/SampleLayers.cpp
+++ b/samplecode/SampleLayers.cpp
@@ -224,12 +224,12 @@
     }
 
     Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, ModifierKey modi) override {
-        return new Click(this);
+        return new Click();
     }
 
     bool onClick(Click* click) override {
         fCenter = click->fCurr;
-        return this->INHERITED::onClick(click);
+        return true;
     }
 
 private:
diff --git a/samplecode/SampleLua.cpp b/samplecode/SampleLua.cpp
index 9416248..99d486c 100644
--- a/samplecode/SampleLua.cpp
+++ b/samplecode/SampleLua.cpp
@@ -120,7 +120,7 @@
                 SkDebugf("lua err: %s\n", lua_tostring(L, -1));
             } else {
                 if (lua_isboolean(L, -1) && lua_toboolean(L, -1)) {
-                    return new Click(this);
+                    return new Click();
                 }
             }
         }
@@ -130,10 +130,10 @@
     bool onClick(Click* click) override {
         const char* state = nullptr;
         switch (click->fState) {
-            case Click::kMoved_State:
+            case InputState::kMove:
                 state = "moved";
                 break;
-            case Click::kUp_State:
+            case InputState::kUp:
                 state = "up";
                 break;
             default:
diff --git a/samplecode/SampleMixer.cpp b/samplecode/SampleMixer.cpp
index 1def7db..5998d21 100644
--- a/samplecode/SampleMixer.cpp
+++ b/samplecode/SampleMixer.cpp
@@ -73,12 +73,12 @@
 
     virtual Click* onFindClickHandler(SkScalar x, SkScalar y, ModifierKey) override {
         return fRect.contains(SkScalarRoundToInt(x),
-                              SkScalarRoundToInt(y)) ? new Click(this) : nullptr;
+                              SkScalarRoundToInt(y)) ? new Click() : nullptr;
     }
 
     bool onClick(Click* click) override {
-        fRect.offset(click->fICurr.fX - click->fIPrev.fX,
-                     click->fICurr.fY - click->fIPrev.fY);
+        fRect.offset(click->fCurr.fX - click->fPrev.fX,
+                     click->fCurr.fY - click->fPrev.fY);
         return true;
     }
 
@@ -157,7 +157,7 @@
     virtual Click* onFindClickHandler(SkScalar x, SkScalar y, ModifierKey) override {
         fMode = (fMode == SkBlendMode::kSrcOver) ? SkBlendMode::kClear : SkBlendMode::kSrcOver;
         return fRect.contains(SkScalarRoundToInt(x),
-                              SkScalarRoundToInt(y)) ? new Click(this) : nullptr;
+                              SkScalarRoundToInt(y)) ? new Click() : nullptr;
     }
 
     bool onClick(Click* click) override {
diff --git a/samplecode/SamplePatch.cpp b/samplecode/SamplePatch.cpp
index 1ec5a5c..eba334a 100644
--- a/samplecode/SamplePatch.cpp
+++ b/samplecode/SamplePatch.cpp
@@ -290,7 +290,7 @@
     class PtClick : public Click {
     public:
         int fIndex;
-        PtClick(Sample* view, int index) : Click(view), fIndex(index) {}
+        PtClick(int index) : fIndex(index) {}
     };
 
     static bool hittest(const SkPoint& pt, SkScalar x, SkScalar y) {
@@ -302,10 +302,10 @@
         y -= DY;
         for (size_t i = 0; i < SK_ARRAY_COUNT(fPts); i++) {
             if (hittest(fPts[i], x, y)) {
-                return new PtClick(this, (int)i);
+                return new PtClick((int)i);
             }
         }
-        return this->INHERITED::onFindClickHandler(x, y, modi);
+        return nullptr;
     }
 
     bool onClick(Click* click) override {
@@ -397,7 +397,7 @@
     }
 
     Click* onFindClickHandler(SkScalar x, SkScalar y, ModifierKey modi) override {
-        Click* click = new Click(this);
+        Click* click = new Click();
         fPath.reset();
         fPath.moveTo(x, y);
         return click;
@@ -405,7 +405,7 @@
 
     bool onClick(Click* click) override {
         switch (click->fState) {
-            case Click::kMoved_State:
+            case InputState::kMove:
                 fPath.lineTo(click->fCurr);
                 fDirty = true;
                 break;
@@ -485,7 +485,7 @@
     }
 
     Click* onFindClickHandler(SkScalar x, SkScalar y, ModifierKey modi) override {
-        Click* click = new Click(this);
+        Click* click = new Click();
         fPath.reset();
         fPath.moveTo(x, y);
         return click;
@@ -493,7 +493,7 @@
 
     bool onClick(Click* click) override {
         switch (click->fState) {
-            case Click::kMoved_State:
+            case InputState::kMove:
                 fPath.lineTo(click->fCurr);
                 break;
             default:
diff --git a/samplecode/SamplePath.cpp b/samplecode/SamplePath.cpp
index f698613..0ca52e9 100644
--- a/samplecode/SamplePath.cpp
+++ b/samplecode/SamplePath.cpp
@@ -191,7 +191,7 @@
 
     Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, ModifierKey modi) override {
         fShowHairline = !fShowHairline;
-        return this->INHERITED::onFindClickHandler(x, y, modi);
+        return nullptr;
     }
 
 private:
@@ -294,12 +294,12 @@
         const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2);
         for (int i = 0; i < N; ++i) {
             if (r.intersects(SkRect::MakeXYWH(fPts[i].fX, fPts[i].fY, 1, 1))) {
-                Click* click = new Click(this);
+                Click* click = new Click();
                 click->fMeta.setS32("index", i);
                 return click;
             }
         }
-        return this->INHERITED::onFindClickHandler(x, y, modi);
+        return nullptr;
     }
 
 private:
@@ -422,12 +422,12 @@
         const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2);
         for (int i = 0; i < N; ++i) {
             if (r.intersects(SkRect::MakeXYWH(fPts[i].fX, fPts[i].fY, 1, 1))) {
-                Click* click = new Click(this);
+                Click* click = new Click();
                 click->fMeta.setS32("index", i);
                 return click;
             }
         }
-        return this->INHERITED::onFindClickHandler(x, y, modi);
+        return nullptr;
     }
 
 private:
@@ -539,7 +539,7 @@
         const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2);
         for (int i = 0; i < N; ++i) {
             if (r.intersects(SkRect::MakeXYWH(fPts[i].fX, fPts[i].fY, 1, 1))) {
-                Click* click = new Click(this);
+                Click* click = new Click();
                 click->fMeta.setS32("index", i);
                 return click;
             }
@@ -735,7 +735,7 @@
         const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2);
         for (int i = 0; i < N; ++i) {
             if (r.intersects(SkRect::MakeXYWH(fPts[i].fX, fPts[i].fY, 1, 1))) {
-                Click* click = new Click(this);
+                Click* click = new Click();
                 click->fMeta.setS32("index", i);
                 return click;
             }
diff --git a/samplecode/SamplePathClip.cpp b/samplecode/SamplePathClip.cpp
index 5760d68..36c6268 100644
--- a/samplecode/SamplePathClip.cpp
+++ b/samplecode/SamplePathClip.cpp
@@ -53,7 +53,7 @@
     }
 
     Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, ModifierKey) override {
-        return new Click(this);
+        return new Click();
     }
 
     bool onClick(Click* click) override {
@@ -227,21 +227,21 @@
 
     class MyClick : public Click {
     public:
-        MyClick(Sample* view) : Click(view) {}
+        MyClick() {}
         virtual void handleMove() = 0;
     };
 
     class VertClick : public MyClick {
         SkPoint* fPt;
     public:
-        VertClick(Sample* view, SkPoint* pt) : MyClick(view), fPt(pt) {}
+        VertClick(SkPoint* pt) : fPt(pt) {}
         void handleMove() override { *fPt = snap(fCurr); }
     };
 
     class DragRectClick : public MyClick {
         SkRect* fRect;
     public:
-        DragRectClick(Sample* view, SkRect* rect) : MyClick(view), fRect(rect) {}
+        DragRectClick(SkRect* rect) : fRect(rect) {}
         void handleMove() override { fRect->offset(fCurr.x() - fPrev.x(), fCurr.y() - fPrev.y()); }
     };
 
@@ -250,8 +250,7 @@
         SkPoint* fPoly;
         int fCount;
     public:
-        DragPolyClick(Sample* view, SkPoint poly[], int count)
-            : MyClick(view), fPoly(poly), fCount(count)
+        DragPolyClick(SkPoint poly[], int count) : fPoly(poly), fCount(count)
         {
             SkASSERT((size_t)count <= SK_ARRAY_COUNT(fSrc));
             memcpy(fSrc, poly, count * sizeof(SkPoint));
@@ -267,7 +266,7 @@
 
     class DoNothingClick : public MyClick {
     public:
-        DoNothingClick(Sample* view) : MyClick(view) {}
+        DoNothingClick() {}
         void handleMove() override {}
     };
 
@@ -281,20 +280,20 @@
     Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, ModifierKey) override {
         for (int i = 0; i < N; ++i) {
             if (hit_test(fPoly[i], x, y)) {
-                return new VertClick(this, &fPoly[i]);
+                return new VertClick(&fPoly[i]);
             }
         }
 
         SkPath path;
         path.addPoly(fPoly, N, true);
         if (path.contains(x, y)) {
-            return new DragPolyClick(this, fPoly, N);
+            return new DragPolyClick(fPoly, N);
         }
 
         if (fClip.intersects(SkRect::MakeLTRB(x - 1, y - 1, x + 1, y + 1))) {
-            return new DragRectClick(this, &fClip);
+            return new DragRectClick(&fClip);
         }
-        return new DoNothingClick(this);
+        return new DoNothingClick();
     }
 
     bool onClick(Click* click) override {
diff --git a/samplecode/SampleQuadStroker.cpp b/samplecode/SampleQuadStroker.cpp
index 13cd306..20f5ff7 100644
--- a/samplecode/SampleQuadStroker.cpp
+++ b/samplecode/SampleQuadStroker.cpp
@@ -718,88 +718,88 @@
     class MyClick : public Click {
     public:
         int fIndex;
-        MyClick(Sample* target, int index) : Click(target), fIndex(index) {}
+        MyClick(int index) : fIndex(index) {}
     };
 
     virtual Sample::Click* onFindClickHandler(SkScalar x, SkScalar y,
                                               ModifierKey modi) override {
         for (size_t i = 0; i < SK_ARRAY_COUNT(fPts); ++i) {
             if (hittest(fPts[i], x, y)) {
-                return new MyClick(this, (int)i);
+                return new MyClick((int)i);
             }
         }
         const SkRect& rectPt = SkRect::MakeXYWH(x, y, 1, 1);
         if (fWeightControl.contains(rectPt)) {
-            return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 1);
+            return new MyClick((int) SK_ARRAY_COUNT(fPts) + 1);
         }
         if (fRadiusControl.contains(rectPt)) {
-            return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 2);
+            return new MyClick((int) SK_ARRAY_COUNT(fPts) + 2);
         }
 #ifdef SK_DEBUG
         if (fErrorControl.contains(rectPt)) {
-            return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 3);
+            return new MyClick((int) SK_ARRAY_COUNT(fPts) + 3);
         }
 #endif
         if (fWidthControl.contains(rectPt)) {
-            return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 4);
+            return new MyClick((int) SK_ARRAY_COUNT(fPts) + 4);
         }
         if (fCubicButton.fBounds.contains(rectPt)) {
             fCubicButton.fEnabled ^= true;
-            return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 5);
+            return new MyClick((int) SK_ARRAY_COUNT(fPts) + 5);
         }
         if (fConicButton.fBounds.contains(rectPt)) {
             fConicButton.fEnabled ^= true;
-            return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 6);
+            return new MyClick((int) SK_ARRAY_COUNT(fPts) + 6);
         }
         if (fQuadButton.fBounds.contains(rectPt)) {
             fQuadButton.fEnabled ^= true;
-            return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 7);
+            return new MyClick((int) SK_ARRAY_COUNT(fPts) + 7);
         }
         if (fArcButton.fBounds.contains(rectPt)) {
             fArcButton.fEnabled ^= true;
-            return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 8);
+            return new MyClick((int) SK_ARRAY_COUNT(fPts) + 8);
         }
         if (fRRectButton.fBounds.contains(rectPt)) {
             fRRectButton.fEnabled ^= true;
-            return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 9);
+            return new MyClick((int) SK_ARRAY_COUNT(fPts) + 9);
         }
         if (fCircleButton.fBounds.contains(rectPt)) {
             bool wasEnabled = fCircleButton.fEnabled;
             fCircleButton.fEnabled = !fCircleButton.fFill;
             fCircleButton.fFill = wasEnabled && !fCircleButton.fFill;
-            return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 10);
+            return new MyClick((int) SK_ARRAY_COUNT(fPts) + 10);
         }
         if (fTextButton.fBounds.contains(rectPt)) {
             fTextButton.fEnabled ^= true;
-            return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 11);
+            return new MyClick((int) SK_ARRAY_COUNT(fPts) + 11);
         }
-        return this->INHERITED::onFindClickHandler(x, y, modi);
+        return nullptr;
     }
 
-    static SkScalar MapScreenYtoValue(int y, const SkRect& control, SkScalar min,
+    static SkScalar MapScreenYtoValue(SkScalar y, const SkRect& control, SkScalar min,
             SkScalar max) {
-        return (SkIntToScalar(y) - control.fTop) / control.height() * (max - min) + min;
+        return (y - control.fTop) / control.height() * (max - min) + min;
     }
 
     bool onClick(Click* click) override {
         int index = ((MyClick*)click)->fIndex;
         if (index < (int) SK_ARRAY_COUNT(fPts)) {
-            fPts[index].offset(SkIntToScalar(click->fICurr.fX - click->fIPrev.fX),
-                               SkIntToScalar(click->fICurr.fY - click->fIPrev.fY));
+            fPts[index].offset(click->fCurr.fX - click->fPrev.fX,
+                               click->fCurr.fY - click->fPrev.fY);
         } else if (index == (int) SK_ARRAY_COUNT(fPts) + 1) {
-            fWeight = MapScreenYtoValue(click->fICurr.fY, fWeightControl, 0, 5);
+            fWeight = MapScreenYtoValue(click->fCurr.fY, fWeightControl, 0, 5);
         } else if (index == (int) SK_ARRAY_COUNT(fPts) + 2) {
-            fRadius = MapScreenYtoValue(click->fICurr.fY, fRadiusControl, 0, 500);
+            fRadius = MapScreenYtoValue(click->fCurr.fY, fRadiusControl, 0, 500);
         }
 #ifdef SK_DEBUG
         else if (index == (int) SK_ARRAY_COUNT(fPts) + 3) {
-            gDebugStrokerError = SkTMax(FLT_EPSILON, MapScreenYtoValue(click->fICurr.fY,
+            gDebugStrokerError = SkTMax(FLT_EPSILON, MapScreenYtoValue(click->fCurr.fY,
                     fErrorControl, kStrokerErrorMin, kStrokerErrorMax));
             gDebugStrokerErrorSet = true;
         }
 #endif
         else if (index == (int) SK_ARRAY_COUNT(fPts) + 4) {
-            fWidth = SkTMax(FLT_EPSILON, MapScreenYtoValue(click->fICurr.fY, fWidthControl,
+            fWidth = SkTMax(FLT_EPSILON, MapScreenYtoValue(click->fCurr.fY, fWidthControl,
                     kWidthMin, kWidthMax));
             fAnimate = fWidth <= kWidthMin;
         }
diff --git a/samplecode/SampleRegion.cpp b/samplecode/SampleRegion.cpp
index cff677f..21b2da7 100644
--- a/samplecode/SampleRegion.cpp
+++ b/samplecode/SampleRegion.cpp
@@ -328,12 +328,12 @@
     virtual Sample::Click* onFindClickHandler(SkScalar x, SkScalar y,
                                               ModifierKey modi) override {
         return fRect.contains(SkScalarRoundToInt(x),
-                              SkScalarRoundToInt(y)) ? new Click(this) : nullptr;
+                              SkScalarRoundToInt(y)) ? new Click() : nullptr;
     }
 
     bool onClick(Click* click) override {
-        fRect.offset(click->fICurr.fX - click->fIPrev.fX,
-                     click->fICurr.fY - click->fIPrev.fY);
+        fRect.offset(click->fCurr.fX - click->fPrev.fX,
+                     click->fCurr.fY - click->fPrev.fY);
         return true;
     }
 
diff --git a/samplecode/SampleSG.cpp b/samplecode/SampleSG.cpp
index e129de1..2dbc7c5 100644
--- a/samplecode/SampleSG.cpp
+++ b/samplecode/SampleSG.cpp
@@ -74,11 +74,11 @@
 
     Click* onFindClickHandler(SkScalar x, SkScalar y, ModifierKey modi) override {
         if (auto node = fScene->nodeAt({x, y})) {
-            Click* click = new Click(this);
+            Click* click = new Click();
             click->fMeta.setPtr("node", (void*)node);
             return click;
         }
-        return this->INHERITED::onFindClickHandler(x, y, modi);
+        return nullptr;
     }
 
     bool onClick(Click* click) override {
diff --git a/samplecode/SampleVertices.cpp b/samplecode/SampleVertices.cpp
index 1db11c1..4563703 100644
--- a/samplecode/SampleVertices.cpp
+++ b/samplecode/SampleVertices.cpp
@@ -100,7 +100,7 @@
     }
 
     Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, ModifierKey) override {
-        return new Click(this);
+        return new Click();
     }
 
     bool onClick(Click* click) override {
diff --git a/samplecode/SampleXfer.cpp b/samplecode/SampleXfer.cpp
index 1a3854b..dfea45d 100644
--- a/samplecode/SampleXfer.cpp
+++ b/samplecode/SampleXfer.cpp
@@ -164,7 +164,7 @@
         // Check mode buttons first
         for (int i = 0; i < N_Modes; ++i) {
             if (fModeButtons[i].hitTest(x, y)) {
-                Click* click = new Click(this);
+                Click* click = new Click();
                 click->fMeta.setS32("mode", i);
                 return click;
             }
@@ -176,13 +176,13 @@
                 break;
             }
         }
-        return fSelected ? new Click(this) : nullptr;
+        return fSelected ? new Click() : nullptr;
     }
 
     bool onClick(Click* click) override {
         int32_t mode;
         if (click->fMeta.findS32("mode", &mode)) {
-            if (fSelected && Click::kUp_State == click->fState) {
+            if (fSelected && InputState::kUp == click->fState) {
                 fSelected->fMode = gModes[mode];
             }
         } else {
diff --git a/tools/viewer/SampleSlide.cpp b/tools/viewer/SampleSlide.cpp
index 5bdb487..1710915 100644
--- a/tools/viewer/SampleSlide.cpp
+++ b/tools/viewer/SampleSlide.cpp
@@ -13,15 +13,12 @@
 
 using namespace sk_app;
 
-SampleSlide::SampleSlide(const SampleFactory factory)
-    : fSampleFactory(factory)
-    , fClick(nullptr)
-{
-    sk_sp<Sample> sample(factory());
+SampleSlide::SampleSlide(const SampleFactory factory) : fSampleFactory(factory) {
+    std::unique_ptr<Sample> sample(factory());
     fName = sample->name();
 }
 
-SampleSlide::~SampleSlide() { delete fClick; }
+SampleSlide::~SampleSlide() {}
 
 SkISize SampleSlide::getDimensions() const  {
     return SkISize::Make(SkScalarCeilToInt(fSample->width()), SkScalarCeilToInt(fSample->height()));
@@ -49,34 +46,8 @@
 
 bool SampleSlide::onMouse(SkScalar x, SkScalar y, Window::InputState state,
                           ModifierKey modifierKeys) {
-    bool handled = false;
-    switch (state) {
-        case Window::kDown_InputState: {
-            delete fClick;
-            fClick = fSample->findClickHandler(SkIntToScalar(x), SkIntToScalar(y), modifierKeys);
-            if (fClick) {
-                Sample::DoClickDown(fClick, x, y, modifierKeys);
-                handled = true;
-            }
-            break;
-        }
-        case Window::kMove_InputState: {
-            if (fClick) {
-                Sample::DoClickMoved(fClick, x, y, modifierKeys);
-                handled = true;
-            }
-            break;
-        }
-        case Window::kUp_InputState: {
-            if (fClick) {
-                Sample::DoClickUp(fClick, x, y, modifierKeys);
-                delete fClick;
-                fClick = nullptr;
-                handled = true;
-            }
-            break;
-        }
-    }
-
-    return handled;
+    static_assert((Sample::InputState)Window::kDown_InputState == Sample::InputState::kDown, "");
+    static_assert((Sample::InputState)Window::kUp_InputState   == Sample::InputState::kUp,   "");
+    static_assert((Sample::InputState)Window::kMove_InputState == Sample::InputState::kMove, "");
+    return fSample && fSample->mouse({x, y}, (Sample::InputState)state, modifierKeys);
 }
diff --git a/tools/viewer/SampleSlide.h b/tools/viewer/SampleSlide.h
index f8872b9..700b07e 100644
--- a/tools/viewer/SampleSlide.h
+++ b/tools/viewer/SampleSlide.h
@@ -32,8 +32,7 @@
 
 private:
     const SampleFactory fSampleFactory;
-    sk_sp<Sample> fSample;
-    Sample::Click* fClick;
+    std::unique_ptr<Sample> fSample;
 };
 
 #endif