Index: samplecode/SampleBevel.cpp |
diff --git a/samplecode/SampleBevel.cpp b/samplecode/SampleBevel.cpp |
index 868ce35244288fa99b9c76c4ff0c75705650c173..e592cf191aa38e11e9cf0f0aa559bb8685475a96 100644 |
--- a/samplecode/SampleBevel.cpp |
+++ b/samplecode/SampleBevel.cpp |
@@ -11,57 +11,682 @@ |
#include "SkNormalSource.h" |
#include "sk_tool_utils.h" |
+class ParentControl; |
+ |
+// Abstract base class for all components that a control panel must have |
+class Control : public SkRefCnt { |
+public: |
+ Control(SkString name) |
+ : fName(name) |
+ , fParent(nullptr) |
+ , fRelativePos(SkPoint::Make(0.0f, 0.0f)) {} |
+ |
+ // Use this to propagate a click's position down to a control. Gets modulated by the component's |
+ // relative position |
+ bool click(const SkPoint& clickPos) { |
+ SkPoint relativeClickPos = SkPoint::Make(clickPos.fX - fRelativePos.fX, |
+ clickPos.fY - fRelativePos.fY); |
+ return this->onClick(relativeClickPos); |
+ } |
+ |
+ // Use this to draw the control and its appropriate children. Gets modulated by the component's |
+ // relative position. |
+ void drawContent(SkCanvas *canvas) { |
+ canvas->save(); |
+ canvas->translate(fRelativePos.fX, fRelativePos.fY); |
+ this->onDrawContent(canvas); |
+ canvas->restore(); |
+ } |
+ |
+ /* Returns true when click position argumend lands over a control region in this control. Click |
+ * position gets modulated by the component's relative position. |
+ * |
+ * @param click The position of the click in the coordinate space relative to the parent |
+ */ |
+ bool isInCtrlRegion(const SkPoint& click) { |
+ SkPoint relativeClickPos = SkPoint::Make(click.fX - fRelativePos.fX, |
+ click.fY - fRelativePos.fY); |
+ return this->onIsInCtrlRegion(relativeClickPos); |
+ } |
+ |
+ // Returns height of content drawn |
+ virtual SkScalar height() const = 0; |
+ |
+ // Sets the parent of this component. May only be used once. Height must remain constant after |
+ // parent is set. |
+ void setParent(ParentControl *parent, const SkPoint& relativePos) { |
+ SkASSERT(parent); |
+ SkASSERT(!fParent); // No chidren transfer since relativeY would get invalid for younger kid |
+ |
+ fParent = parent; |
+ fRelativePos = relativePos; |
+ this->onSetParent(); |
+ } |
+ |
+ // Overriden by sub-classes that need to recompute fields after parent is set. Called after |
+ // setting fParent. |
+ virtual void onSetParent() {} |
+ |
+ // Overriden by sub-classes that need to know when a click is released. |
+ virtual void onClickRelease() {} |
+ |
+protected: |
+ |
+ // Draws a label for the component, using its name and a passed value. Does NOT modulate by |
+ // relative height, expects CTM to have been adjusted in advance. |
+ void drawLabel(SkCanvas *canvas, const SkString& valueStr) const { |
+ // TODO Cache this |
+ sk_sp<SkTypeface> fLabelTypeface = |
+ sk_tool_utils::create_portable_typeface("sans-serif", SkFontStyle()); |
+ |
+ SkString label; |
+ label.append(fName); |
+ label.append(": "); |
+ label.append(valueStr); |
+ |
+ SkPaint labelPaint; |
+ labelPaint.setTypeface(fLabelTypeface); |
+ labelPaint.setAntiAlias(true); |
+ labelPaint.setColor(0xFFFFFFFF); |
+ labelPaint.setTextSize(12.0f); |
+ |
+ canvas->drawText(label.c_str(), label.size(), 0, kLabelHeight - 6.0f, labelPaint); |
+ } |
+ |
+ SkString fName; |
+ ParentControl* fParent; |
+ |
+ static constexpr SkScalar kLabelHeight = 20.0f; |
+ |
+private: |
+ // Overriden by sub-class to draw component. Do not call directly, drawContent() modulates by |
+ // relative position. |
+ virtual void onDrawContent(SkCanvas *canvas) = 0; |
+ |
+ // Overriden by sub-class to handle clicks. Do not call directly, click() modulates by relative |
+ // position. Return true if holding mouse capture |
+ virtual bool onClick(const SkPoint& clickPos) { return false; }; |
+ |
+ // Overriden by sub-classes with controls. Should return true if clickPos lands inside a control |
+ // region, to enable mouse caputre. |
+ virtual bool onIsInCtrlRegion(const SkPoint& clickPos) const { return false; }; |
+ |
+ // The position of the control relative to it's parent |
+ SkPoint fRelativePos; |
+}; |
+ |
+class ParentControl : public Control { // Interface for all controls that have children |
+public: |
+ ParentControl(const SkString& name) : INHERITED(name) {} |
+ |
+ // Adds a child |
+ virtual void add(sk_sp<Control> control) = 0; |
+ |
+ // Returns the control's width. Used to propagate width down to components that don't specify it |
+ virtual SkScalar width() const = 0; |
+ |
+private: |
+ typedef Control INHERITED; |
+}; |
+ |
+class ControlPanel : public ParentControl { |
+public: |
+ |
+ ControlPanel(SkScalar width) |
+ : ParentControl(SkString("ControlPanel")) |
+ , fWidth(width) |
+ , fHeight(0.0f) |
+ , fSelectedControl(-1) {} |
+ |
+ // Width unspecified, expectation is inheritance from parent |
+ ControlPanel() : ControlPanel(-1.0f) {} |
+ |
+ // Use this for introducing clicks on a ControlPanel from outside of the framework. It |
+ // propagates click release or position down the chain. Returns false when click capture is |
+ // being released. |
+ bool inClick(SkView::Click *inClick) { |
+ if (SkView::Click::State::kUp_State == inClick->fState) { |
+ this->onClickRelease(); |
+ return false; |
+ } |
+ return this->click(inClick->fCurr); |
+ } |
+ |
+ // Add children |
+ void add(sk_sp<Control> control) override { |
+ SkASSERT(!fParent); // Validity of parent's relativeY and fHeight depends on immutability |
+ fControls.push_back(control); |
+ control->setParent(this, SkPoint::Make(0.0f, fHeight)); |
+ fHeight += control->height(); |
+ } |
+ |
+ SkScalar width() const override { |
+ return fParent ? fParent->width() : fWidth; // Width inherited from parent if there is one |
+ } |
+ |
+ SkScalar height() const override { |
+ return fHeight; |
+ } |
+ |
+ // Propagate click release to selected control, deselect control |
+ void onClickRelease() override { |
+ if (fSelectedControl >= 0) { |
+ fControls[fSelectedControl]->onClickRelease(); |
+ } |
+ fSelectedControl = -1; |
+ } |
+ |
+ // Propagate onSetParent() down to children, some might need fParent->width() refresh |
+ void onSetParent() override { |
+ for (int i = 0; i < fControls.count(); i++) { |
+ fControls[i]->onSetParent(); |
+ } |
+ } |
+ |
+ // Holds a vertical shelf of controls. Can't be hierarchy root if not given a width value. |
+ static sk_sp<ParentControl> Make() { |
+ return sk_sp<ParentControl>(new ControlPanel()); |
+ } |
+ |
+ // Holds a vertical shelf of controls. Only control that can be hooked from outside the |
+ // framework. |
+ static sk_sp<ParentControl> Make(SkScalar width) { |
+ return sk_sp<ParentControl>(new ControlPanel(width)); |
+ } |
+ |
+protected: |
+ // Returns true if control panel has mouse captured, false when it is ready to release |
+ // capture |
+ bool onClick(const SkPoint& click) override { |
+ |
+ if (fSelectedControl == -1) { // If no child control selected, check every child |
+ for (int i = 0; i < fControls.count(); i++) { |
+ if (fControls[i]->isInCtrlRegion(click)) { |
+ fSelectedControl = i; |
+ break; |
+ } |
+ } |
+ } |
+ |
+ if (fSelectedControl >= 0) { // If child control selected, propagate click |
+ bool keepSelection = fControls[fSelectedControl]->click(click); |
+ if (!keepSelection) { |
+ fSelectedControl = -1; |
+ } |
+ return keepSelection; |
+ } |
+ |
+ return false; |
+ } |
+ |
+ // Draw all children |
+ void onDrawContent(SkCanvas* canvas) override { |
+ canvas->save(); |
+ for (int i = 0; i < fControls.count(); i++) { |
+ fControls[i]->drawContent(canvas); |
+ } |
+ canvas->restore(); |
+ } |
+ |
+ // Check all children's control regions |
+ bool onIsInCtrlRegion(const SkPoint& clickPos) const override { |
+ for (int i = 0; i < fControls.count(); i++) { |
+ if (fControls[i]->isInCtrlRegion(clickPos)) { |
+ return true; |
+ } |
+ } |
+ |
+ return false; |
+ } |
+ |
+private: |
+ SkScalar fWidth; |
+ SkScalar fHeight; |
+ |
+ SkTArray<sk_sp<Control>> fControls; |
+ int fSelectedControl; |
+}; |
+ |
+class DiscreteSliderControl : public Control { |
+public: |
+ SkScalar height() const override { |
+ return 2.0f * kLabelHeight; |
+ } |
+ |
+ // Set width-dependant variables when new parent is set |
+ void onSetParent() override { |
+ fCtrlRegion = SkRect::MakeXYWH(0.0f, kLabelHeight, fParent->width(), kSliderHeight); |
+ fSliderRange = fParent->width() - kSliderWidth; |
+ } |
+ |
+ /* Make a slider for an integer value. Snaps to discrete positions. |
+ * |
+ * @params name The name of the control, displayed in the label |
+ * @params output Pointer to the integer that will be set by the slider |
+ * @params min Min value for output. |
+ * @params max Max value for output. |
+ */ |
+ static sk_sp<Control> Make(SkString name, int* output, int min, int max) { |
+ return sk_sp<Control>(new DiscreteSliderControl(name, output, min, max)); |
+ } |
+ |
+protected: |
+ void onDrawContent(SkCanvas* canvas) override { |
+ SkASSERT(fParent); |
+ int numChoices = fMax - fMin + 1; |
+ fSlider.offsetTo(fSliderRange * ( (*fOutput)/SkIntToScalar(numChoices) |
+ + 1.0f/(2.0f * numChoices) ), |
+ fSlider.fTop); |
+ |
+ SkString valueStr; |
+ valueStr.appendS32(*fOutput); |
+ this->drawLabel(canvas, valueStr); |
+ |
+ SkPaint sliderPaint; |
+ sliderPaint.setColor(0xFFF3F3F3); |
+ canvas->drawRect(fSlider, sliderPaint); |
+ |
+ SkPaint ctrlRegionPaint; |
+ ctrlRegionPaint.setColor(0xFFFFFFFF); |
+ ctrlRegionPaint.setStyle(SkPaint::kStroke_Style); |
+ ctrlRegionPaint.setStrokeWidth(2.0f); |
+ canvas->drawRect(fCtrlRegion, ctrlRegionPaint); |
+ } |
+ |
+ bool onClick(const SkPoint& clickPos) override { |
+ SkASSERT(fParent); |
+ SkScalar x = SkScalarPin(clickPos.fX, 0.0f, fSliderRange); |
+ int numChoices = fMax - fMin + 1; |
+ *fOutput = SkTMin(SkScalarFloorToInt(numChoices * x / fSliderRange) + fMin, fMax); |
+ |
+ return true; |
+ } |
+ |
+ bool onIsInCtrlRegion(const SkPoint& clickPos) const override { |
+ SkASSERT(fParent); |
+ return fCtrlRegion.contains(SkRect::MakeXYWH(clickPos.fX, clickPos.fY, 1, 1)); |
+ } |
+ |
+private: |
+ DiscreteSliderControl(SkString name, int* output, int min, int max) |
+ : INHERITED(name) |
+ , fOutput(output) |
+ , fMin(min) |
+ , fMax(max) { |
+ fSlider = SkRect::MakeXYWH(0, kLabelHeight, kSliderWidth, kSliderHeight); |
+ } |
+ |
+ int* fOutput; |
+ int fMin; |
+ int fMax; |
+ SkRect fSlider; // The rectangle that slides |
+ // The region in which the rectangle slides. Also the region in which mouse is caputred |
+ SkRect fCtrlRegion; |
+ SkScalar fSliderRange; // The width in pixels over which the slider can slide |
+ |
+ static constexpr SkScalar kSliderHeight = 20.0f; |
+ static constexpr SkScalar kSliderWidth = 10.0f; |
+ |
+ typedef Control INHERITED; |
+}; |
+ |
+class ControlSwitcher : public ParentControl { |
+public: |
+ // Add children |
+ void add(sk_sp<Control> control) override { |
+ SkASSERT(!fParent); // Validity of parent's relativeY and fHeight depends on immutability |
+ fControls.push_back(control); |
+ control->setParent(this, SkPoint::Make(0.0f, kSelectorHeight)); |
+ fHeight = SkMaxScalar(fHeight, control->height()); // Setting height to max child height. |
+ } |
+ |
+ SkScalar width() const override { return fParent ? (fParent->width()) : 0; } |
+ |
+ SkScalar height() const override { |
+ return fHeight; |
+ } |
+ |
+ // Propagate onClickRelease to control that currently captures mouse |
+ void onClickRelease() override { |
+ if (fCtrlOnClick) { |
+ fCtrlOnClick->onClickRelease(); |
+ } |
+ fCtrlOnClick = nullptr; |
+ } |
+ |
+ void onSetParent() override { |
+ for (int i = 0; i < fControls.count(); i++) { |
+ fControls[i]->onSetParent(); // Propagate to children |
+ } |
+ |
+ // Finalize control selector |
+ // TODO can be moved to constructor if list-initialized |
+ if (!finalizedChildren) { |
+ fControlSelector = DiscreteSliderControl::Make( |
+ SkString(fName), &fSelectedControl, 0, fControls.count()-1); |
+ fControlSelector->setParent(this, SkPoint::Make(0.0f, 0.0f)); |
+ fHeight += kSelectorHeight; |
+ |
+ SkASSERT(fControlSelector->height() <= kSelectorHeight); |
+ } |
+ } |
+ |
+ /* A set of a selector and a list of controls. Displays the control from the list of controls |
+ * with the index set by the aforementioned selector. |
+ * |
+ * @param name The name of the switcher. Will be displayed in the selector's label. |
+ */ |
+ static sk_sp<ParentControl> Make(const SkString& name) { |
+ return sk_sp<ParentControl>(new ControlSwitcher(name)); |
+ } |
+ |
+protected: |
+ // Draw selector and currently selected control |
+ void onDrawContent(SkCanvas* canvas) override { |
+ fControlSelector->drawContent(canvas); |
+ fControls[fSelectedControl]->drawContent(canvas); |
+ } |
+ |
+ // Returns true if control panel has mouse captured, false when it is ready to release |
+ // capture |
+ bool onClick(const SkPoint& click) override { |
+ if (!fCtrlOnClick) { |
+ if (fControlSelector->isInCtrlRegion(click)) { |
+ fCtrlOnClick = fControlSelector.get(); |
+ } else if (fControls[fSelectedControl]->isInCtrlRegion(click)) { |
+ fCtrlOnClick = fControls[fSelectedControl].get(); |
+ } |
+ } |
+ if (fCtrlOnClick) { |
+ return fCtrlOnClick->click(click); |
+ } |
+ |
+ return false; |
+ } |
+ |
+ // Is in control region of selector or currently selected control |
+ bool onIsInCtrlRegion(const SkPoint& clickPos) const override { |
+ if (fControlSelector->isInCtrlRegion(clickPos)) { |
+ return true; |
+ } |
+ if (fControls[fSelectedControl]->isInCtrlRegion(clickPos)) { |
+ return true; |
+ } |
+ |
+ return false; |
+ } |
+ |
+private: |
+ ControlSwitcher(const SkString& name) |
+ : INHERITED(name) |
+ , fHeight(0.0) |
+ , fSelectedControl(0) |
+ , fCtrlOnClick(nullptr){} |
+ |
+ bool finalizedChildren = false; |
+ |
+ sk_sp<Control> fControlSelector; |
+ SkScalar fHeight; |
+ SkTArray<sk_sp<Control>> fControls; |
+ int fSelectedControl; |
+ |
+ Control* fCtrlOnClick; |
+ |
+ static constexpr SkScalar kSelectorHeight = 40.0f; |
+ |
+ typedef ParentControl INHERITED; |
+}; |
+ |
+class ContinuousSliderControl : public Control { |
+public: |
+ SkScalar height() const override { |
+ return 2.0f * kLabelHeight; |
+ } |
+ |
+ void onSetParent() override { |
+ fSlider = SkRect::MakeXYWH(0, kLabelHeight, kSliderWidth, kSliderHeight); |
+ fCtrlRegion = SkRect::MakeXYWH(0.0f, kLabelHeight, fParent->width(), kSliderHeight); |
+ fSliderRange = fParent->width() - kSliderWidth; |
+ } |
+ |
+ /* Make a slider for an SkScalar. |
+ * |
+ * @params name The name of the control, displayed in the label |
+ * @params output Pointer to the SkScalar that will be set by the slider |
+ * @params min Min value for output |
+ * @params max Max value for output |
+ */ |
+ static sk_sp<Control> Make(const SkString& name, SkScalar* output, SkScalar min, SkScalar max) { |
+ return sk_sp<Control>(new ContinuousSliderControl(name, output, min, max)); |
+ } |
+ |
+protected: |
+ void onDrawContent(SkCanvas* canvas) override { |
+ SkASSERT(fParent); |
+ SkScalar x = fSliderRange * (*fOutput - fMin) / (fMax - fMin); |
+ fSlider.offsetTo(SkScalarPin(x, 0.0f, fSliderRange), fSlider.fTop); |
+ |
+ SkString valueStr; |
+ valueStr.appendScalar(*fOutput); |
+ this->drawLabel(canvas, valueStr); |
+ |
+ SkPaint sliderPaint; |
+ sliderPaint.setColor(0xFFF3F3F3); |
+ canvas->drawRect(fSlider, sliderPaint); |
+ |
+ SkPaint ctrlRegionPaint; |
+ ctrlRegionPaint.setColor(0xFFFFFFFF); |
+ ctrlRegionPaint.setStyle(SkPaint::kStroke_Style); |
+ ctrlRegionPaint.setStrokeWidth(2.0f); |
+ canvas->drawRect(fCtrlRegion, ctrlRegionPaint); |
+ } |
+ |
+ bool onClick(const SkPoint& clickPos) override { |
+ SkASSERT(fParent); |
+ SkScalar x = SkScalarPin(clickPos.fX, 0.0f, fSliderRange); |
+ *fOutput = (x/fSliderRange) * (fMax - fMin) + fMin; |
+ return true; |
+ } |
+ |
+ bool onIsInCtrlRegion(const SkPoint& clickPos) const override { |
+ SkASSERT(fParent); |
+ return fCtrlRegion.contains(SkRect::MakeXYWH(clickPos.fX, clickPos.fY, 1, 1)); |
+ } |
+ |
+private: |
+ ContinuousSliderControl(const SkString& name, SkScalar* output, SkScalar min, SkScalar max) |
+ : INHERITED(name) |
+ , fOutput(output) |
+ , fMin(min) |
+ , fMax(max) {} |
+ |
+ SkScalar* fOutput; |
+ SkScalar fMin; |
+ SkScalar fMax; |
+ SkRect fSlider; |
+ SkRect fCtrlRegion; |
+ SkScalar fSliderRange; |
+ |
+ static constexpr SkScalar kSliderHeight = 20.0f; |
+ static constexpr SkScalar kSliderWidth = 10.0f; |
+ |
+ typedef Control INHERITED; |
+}; |
+ |
+class RadialDirectionControl : public Control { |
+public: |
+ SkScalar height() const override { |
+ return kLabelHeight + 2.0f * kRegionRadius; |
+ } |
+ |
+ /* Make a direction selector. |
+ * |
+ * @params name The name of the control, displayed in the label |
+ * @params output Pointer to the SkVector that will be set by the slider |
+ */ |
+ static sk_sp<Control> Make(const SkString& name, SkVector* output) { |
+ return sk_sp<Control>(new RadialDirectionControl(name, output)); |
+ } |
+ |
+protected: |
+ void onDrawContent(SkCanvas* canvas) override { |
+ SkASSERT(fParent); |
+ |
+ SkString valueStr; |
+ valueStr.appendf("%.2f, %.2f", fOutput->fX, fOutput->fY); |
+ this->drawLabel(canvas, valueStr); |
+ |
+ SkPoint lineEnd = SkPoint::Make(fCtrlRegion.centerX(), fCtrlRegion.centerY()) |
+ + (*fOutput * (kRegionRadius - kCapRadius)); |
+ SkPaint linePaint; |
+ linePaint.setColor(0xFFF3F3F3); |
+ linePaint.setStrokeWidth(kStrokeWidth); |
+ linePaint.setAntiAlias(true); |
+ linePaint.setStrokeCap(SkPaint::kRound_Cap); |
+ canvas->drawLine(fCtrlRegion.centerX(), fCtrlRegion.centerY(), |
+ lineEnd.fX, lineEnd.fY, linePaint); |
+ |
+ SkPaint ctrlRegionPaint; |
+ ctrlRegionPaint.setColor(0xFFFFFFFF); |
+ ctrlRegionPaint.setStyle(SkPaint::kStroke_Style); |
+ ctrlRegionPaint.setStrokeWidth(2.0f); |
+ ctrlRegionPaint.setAntiAlias(true); |
+ canvas->drawCircle(fCtrlRegion.centerX(), fCtrlRegion.centerY(), kRegionRadius, |
+ ctrlRegionPaint); |
+ } |
+ |
+ bool onClick(const SkPoint& clickPos) override { |
+ SkASSERT(fParent); |
+ fOutput->fX = clickPos.fX - fCtrlRegion.centerX(); |
+ fOutput->fY = clickPos.fY - fCtrlRegion.centerY(); |
+ fOutput->normalize(); |
+ |
+ return true; |
+ } |
+ |
+ bool onIsInCtrlRegion(const SkPoint& clickPos) const override { |
+ SkASSERT(fParent); |
+ return fCtrlRegion.contains(SkRect::MakeXYWH(clickPos.fX, clickPos.fY, |
+ 1, 1)); |
+ } |
+ |
+private: |
+ RadialDirectionControl(const SkString& name, SkVector* output) |
+ : INHERITED(name) |
+ , fOutput(output) { |
+ fCtrlRegion = SkRect::MakeXYWH(0.0f, kLabelHeight, |
+ kRegionRadius * 2.0f, kRegionRadius * 2.0f); |
+ } |
+ |
+ SkVector* fOutput; |
+ SkRect fCtrlRegion; |
+ |
+ static constexpr SkScalar kRegionRadius = 50.0f; |
+ static constexpr SkScalar kStrokeWidth = 6.0f; |
+ static constexpr SkScalar kCapRadius = kStrokeWidth / 2.0f; |
+ |
+ typedef Control INHERITED; |
+}; |
+ |
+class ColorDisplay: public Control { |
+public: |
+ SkScalar height() const override { |
+ return kHeight; |
+ } |
+ |
+ void onSetParent() override { |
+ fDisplayRect = SkRect::MakeXYWH(0.0f, kPadding, fParent->width(), kHeight - kPadding); |
+ } |
+ |
+ /* Make a display that shows an SkColor3f. |
+ * |
+ * @params output Pointer to the SkColor3f that will be displayed |
+ */ |
+ static sk_sp<Control> Make(SkColor3f* input) { |
+ return sk_sp<Control>(new ColorDisplay(SkString("ColorDisplay"), input)); |
+ } |
+ |
+protected: |
+ void onDrawContent(SkCanvas* canvas) override { |
+ SkASSERT(fParent); |
+ |
+ SkPaint displayPaint; |
+ displayPaint.setColor(SkColor4f::FromColor3f(*fInput, 1.0f).toSkColor()); |
+ canvas->drawRect(fDisplayRect, displayPaint); |
+ } |
+ |
+private: |
+ ColorDisplay(const SkString& name, SkColor3f* input) |
+ : INHERITED(name) |
+ , fInput(input) {} |
+ |
+ SkColor3f* fInput; |
+ SkRect fDisplayRect; |
+ |
+ static constexpr SkScalar kHeight = 24.0f; |
+ static constexpr SkScalar kPadding = 4.0f; |
+ |
+ typedef Control INHERITED; |
+}; |
class BevelView : public SampleView { |
public: |
BevelView() |
: fShapeBounds(SkRect::MakeWH(kShapeBoundsSize, kShapeBoundsSize)) |
- , fRedLight(SkLights::Light::MakeDirectional(SkColor3f::Make(0.6f, 0.45f, 0.3f), |
- SkVector3::Make(0.0f, -5.0f, 1.0f))) |
- , fBlueLight(SkLights::Light::MakeDirectional(SkColor3f::Make(0.3f, 0.45f, 0.6f), |
- SkVector3::Make(0.0f, 5.0f, 1.0f))) { |
+ , fControlPanel(kCtrlRange) { |
this->setBGColor(0xFF666868); // Slightly colorized gray for contrast |
- // Lights |
- SkLights::Builder builder; |
- builder.add(fRedLight); |
- builder.add(fBlueLight); |
- builder.add(SkLights::Light::MakeAmbient(SkColor3f::Make(0.4f, 0.4f, 0.4f))); |
- fLights = builder.finish(); |
- |
// Controls |
+ fBevelWidth = 25.0f; |
+ fBevelHeight = 25.0f; |
+ fBevelType = 0; |
+ |
+ int currLight = 0; |
+ fLightDefs[currLight++] = |
+ {SkVector::Make(0.0f, 1.0f), 1.0f, SkColor3f::Make(0.6f, 0.45f, 0.3f)}; |
+ fLightDefs[currLight++] = |
+ {SkVector::Make(0.0f, -1.0f), 1.0f, SkColor3f::Make(0.3f, 0.45f, 0.6f)}; |
+ fLightDefs[currLight++] = |
+ {SkVector::Make(1.0f, 0.0f), 1.0f, SkColor3f::Make(0.0f, 0.0f, 0.0f)}; |
+ // Making sure we initialized all lights |
+ SkASSERT(currLight == kNumLights); |
+ |
+ fControlPanel.add(ContinuousSliderControl::Make(SkString("BevelWidth"), &fBevelWidth, |
+ 1.0f, kShapeBoundsSize)); |
+ fControlPanel.add(ContinuousSliderControl::Make(SkString("BevelHeight"), &fBevelHeight, |
+ -50.0f, 50.0f)); |
+ fControlPanel.add(DiscreteSliderControl::Make(SkString("BevelType"), &fBevelType, |
+ 0, 2)); |
+ sk_sp<ParentControl> lightCtrlSelector = ControlSwitcher::Make(SkString("SelectedLight")); |
+ for (int i = 0; i < kNumLights; i++) { |
+ SkString name("Light"); |
+ name.appendS32(i); |
+ sk_sp<ParentControl> currLightPanel = ControlPanel::Make(); |
+ SkString dirName(name); |
+ dirName.append("Dir"); |
+ currLightPanel->add(RadialDirectionControl::Make(dirName, &(fLightDefs[i].fDirXY))); |
+ SkString heightName(name); |
+ heightName.append("Height"); |
+ currLightPanel->add(ContinuousSliderControl::Make(heightName, &(fLightDefs[i].fDirZ), |
+ 0.0f, 2.0f)); |
+ SkString redName(name); |
+ redName.append("Red"); |
+ currLightPanel->add(ContinuousSliderControl::Make(redName, &(fLightDefs[i].fColor.fX), |
+ 0.0f, 1.0f)); |
+ SkString greenName(name); |
+ greenName.append("Green"); |
+ currLightPanel->add(ContinuousSliderControl::Make(greenName, &(fLightDefs[i].fColor.fY), |
+ 0.0f, 1.0f)); |
+ SkString blueName(name); |
+ blueName.append("Blue"); |
+ currLightPanel->add(ContinuousSliderControl::Make(blueName, &(fLightDefs[i].fColor.fZ), |
+ 0.0f, 1.0f)); |
+ currLightPanel->add(ColorDisplay::Make(&(fLightDefs[i].fColor))); |
+ lightCtrlSelector->add(currLightPanel); |
+ } |
+ fControlPanel.add(lightCtrlSelector); |
- SkScalar currY = kSliderHeight; |
- |
- const SkScalar kWidthCtrlInitialPos = 0.2f; |
- fCtrlRangeRects[0] = SkRect::MakeXYWH(0.0f, currY, |
- kCtrlRange + kSliderWidth, |
- kSliderHeight); |
- fWidthCtrlRect = SkRect::MakeXYWH(kWidthCtrlInitialPos * kCtrlRange, currY, |
- kSliderWidth, kSliderHeight); |
- fBevelWidth = kBevelWidthMax * kWidthCtrlInitialPos; |
- currY += 2 * kSliderHeight; |
- |
- const SkScalar kHeightCtrlInitialPos = 0.75f; |
- fCtrlRangeRects[1] = SkRect::MakeXYWH(0.0f, currY, |
- kCtrlRange + kSliderWidth, |
- kSliderHeight); |
- fHeightCtrlRect = SkRect::MakeXYWH(kHeightCtrlInitialPos * kCtrlRange, currY, |
- kSliderWidth, kSliderHeight); |
- // Mapping from (0, 1) to (-1, 1) |
- fBevelHeight = kBevelHeightMax * (kHeightCtrlInitialPos * 2.0f - 1.0f); |
- currY += 2 * kSliderHeight; |
- |
- const SkScalar kTypeCtrlInitialPos = 1.0f / (2.0f * kBevelTypeCount); |
- fCtrlRangeRects[2] = SkRect::MakeXYWH(0.0f, currY, |
- kCtrlRange + kSliderWidth, |
- kSliderHeight); |
- fTypeCtrlRect = SkRect::MakeXYWH(kTypeCtrlInitialPos * kCtrlRange, currY, |
- kSliderWidth, kSliderHeight); |
- fBevelType = (SkNormalSource::BevelType) SkScalarFloorToInt(kTypeCtrlInitialPos); |
- currY += 2 * kSliderHeight; |
- |
- fSelectedCtrlRect = nullptr; |
+ fControlPanelSelected = false; |
fDirtyNormalSource = true; |
fLabelTypeface = sk_tool_utils::create_portable_typeface("sans-serif", SkFontStyle()); |
@@ -87,7 +712,8 @@ protected: |
SkPaint paint; |
if (fDirtyNormalSource) { |
- fNormalSource = SkNormalSource::MakeBevel(fBevelType, fBevelWidth, fBevelHeight); |
+ fNormalSource = SkNormalSource::MakeBevel((SkNormalSource::BevelType)fBevelType, |
+ fBevelWidth, fBevelHeight); |
fDirtyNormalSource = false; |
} |
@@ -112,58 +738,19 @@ protected: |
void onDrawContent(SkCanvas *canvas) override { |
canvas->save(); |
- canvas->resetMatrix(); // Force static controls and labels |
- |
- // Draw controls |
- |
- SkPaint ctrlRectPaint; |
- ctrlRectPaint.setColor(0xFFF3F3F3); |
- canvas->drawRect(fWidthCtrlRect, ctrlRectPaint); |
- canvas->drawRect(fHeightCtrlRect, ctrlRectPaint); |
- canvas->drawRect(fTypeCtrlRect, ctrlRectPaint); |
- |
- SkPaint ctrlRectRangePaint; |
- ctrlRectRangePaint.setColor(0xFFFFFFFF); |
- ctrlRectRangePaint.setStyle(SkPaint::kStroke_Style); |
- ctrlRectRangePaint.setStrokeWidth(2.0f); |
- |
- for (size_t i = 0; i < kNumControls; i++) { |
- canvas->drawRect(fCtrlRangeRects[i], ctrlRectRangePaint); |
- } |
- |
- // Draw labels |
- constexpr SkScalar kTextSize = 12.0f; |
- SkString widthLabel, heightLabel, typeLabel; |
- SkPaint labelPaint; |
- labelPaint.setTypeface(fLabelTypeface); |
- labelPaint.setAntiAlias(true); |
- labelPaint.setColor(0xFFFFFFFF); |
- labelPaint.setTextSize(kTextSize); |
- |
- widthLabel.appendf("BevelWidth: %f", fBevelWidth); |
- heightLabel.appendf("BevelHeight: %f", fBevelHeight); |
- typeLabel.append("BevelType: "); |
+ canvas->resetMatrix(); // Force static control panel position |
+ fControlPanel.drawContent(canvas); |
+ canvas->restore(); |
- switch (fBevelType) { |
- case SkNormalSource::BevelType::kLinear: |
- typeLabel.append("Linear"); |
- break; |
- case SkNormalSource::BevelType::kRoundedIn: |
- typeLabel.append("RoundedIn"); |
- break; |
- case SkNormalSource::BevelType::kRoundedOut: |
- typeLabel.append("RoundedOut"); |
- break; |
+ SkLights::Builder builder; |
+ for (int i = 0; i < kNumLights; i++) { |
+ builder.add(SkLights::Light::MakeDirectional(fLightDefs[i].fColor, |
+ SkPoint3::Make(fLightDefs[i].fDirXY.fX, |
+ fLightDefs[i].fDirXY.fY, |
+ fLightDefs[i].fDirZ))); |
} |
- |
- canvas->drawText(widthLabel.c_str(), widthLabel.size(), 0, |
- fWidthCtrlRect.fTop - kTextSize/2.0f, labelPaint); |
- canvas->drawText(heightLabel.c_str(), heightLabel.size(), 0, |
- fHeightCtrlRect.fTop - kTextSize/2.0f, labelPaint); |
- canvas->drawText(typeLabel.c_str(), typeLabel.size(), 0, |
- fTypeCtrlRect.fTop - kTextSize/2.0f, labelPaint); |
- |
- canvas->restore(); // Return to modified matrix when drawing shapes |
+ builder.add(SkLights::Light::MakeAmbient(SkColor3f::Make(0.4f, 0.4f, 0.4f))); |
+ fLights = builder.finish(); |
// Draw shapes |
SkScalar xPos = kCtrlRange + 25.0f; |
@@ -183,116 +770,56 @@ protected: |
} |
bool onClick(Click *click) override { |
- SkScalar x = click->fCurr.fX; |
- SkScalar y = click->fCurr.fY; |
- |
- SkScalar dx = x - click->fPrev.fX; |
- SkScalar dy = y - click->fPrev.fY; |
- |
- // Control deselection |
- if (Click::State::kUp_State == click->fState) { |
- fSelectedCtrlRect = nullptr; |
- return true; |
- } |
- |
- // Control selection |
- if (nullptr == fSelectedCtrlRect && Click::State::kDown_State == click->fState) { |
- if (fWidthCtrlRect.contains(SkRect::MakeXYWH(x, y, 1, 1))) { |
- fSelectedCtrlRect = &fWidthCtrlRect; |
- } else if (fHeightCtrlRect.contains(SkRect::MakeXYWH(x, y, 1, 1))) { |
- fSelectedCtrlRect = &fHeightCtrlRect; |
- } else if (fTypeCtrlRect.contains(SkRect::MakeXYWH(x, y, 1, 1))) { |
- fSelectedCtrlRect = &fTypeCtrlRect; |
- } |
- } |
- |
- if (nullptr != fSelectedCtrlRect) { // Control modification |
- fSelectedCtrlRect->offsetTo(SkScalarPin(x, 0.0f, kCtrlRange), fSelectedCtrlRect->fTop); |
- |
- fBevelHeight = (fHeightCtrlRect.fLeft / kCtrlRange) * kBevelHeightMax * 2.0f |
- - kBevelHeightMax; |
- fBevelWidth = (fWidthCtrlRect.fLeft / kCtrlRange) * kBevelWidthMax; |
- fBevelType = (SkNormalSource::BevelType)SkTMin( |
- SkScalarFloorToInt(kBevelTypeCount * fTypeCtrlRect.fLeft / kCtrlRange), |
- kBevelTypeCount - 1); |
- |
- // Snap type controls to 3 positions |
- fTypeCtrlRect.offsetTo(kCtrlRange * ( ((int)fBevelType)/SkIntToScalar(kBevelTypeCount) |
- + 1.0f/(2.0f * kBevelTypeCount) ), |
- fTypeCtrlRect.fTop); |
- |
- // Ensuring width is non-zero |
- fBevelWidth = SkMaxScalar(1.0f, fBevelWidth); |
+ // Control panel mouse handling |
+ fControlPanelSelected = fControlPanel.inClick(click); |
+ if (fControlPanelSelected) { // Control modification |
fDirtyNormalSource = true; |
this->inval(nullptr); |
return true; |
- } else { // Moving light |
- if (dx != 0 || dy != 0) { |
- float recipX = 1.0f / kAppWidth; |
- float recipY = 1.0f / kAppHeight; |
- |
- if (0 == click->fModifierKeys) { // No modifier |
- fBlueLight = SkLights::Light::MakeDirectional(fBlueLight.color(), |
- SkVector3::Make((kAppWidth/2.0f - x) * recipX * -3.0f, |
- (kAppHeight/2.0f - y) * recipY * -3.0f, |
- 1.0f)); |
- } else if (1 == click->fModifierKeys) { // Shift key |
- fRedLight = SkLights::Light::MakeDirectional(fRedLight.color(), |
- SkVector3::Make((kAppWidth/2.0f - x) * recipX * -3.0f, |
- (kAppHeight/2.0f - y) * recipY * -3.0f, |
- 1.0f)); |
- } |
- |
- SkLights::Builder builder; |
- builder.add(fRedLight); |
- builder.add(fBlueLight); |
- builder.add(SkLights::Light::MakeAmbient( |
- SkColor3f::Make(0.4f, 0.4f, 0.4f))); |
- fLights = builder.finish(); |
- |
- this->inval(nullptr); |
- } |
- return true; |
} |
+ // TODO move shapes |
+ this->inval(nullptr); |
return true; |
} |
private: |
static constexpr int kNumTestRects = 3; |
- static constexpr SkScalar kAppWidth = 400.0f; |
- static constexpr SkScalar kAppHeight = 400.0f; |
static constexpr SkScalar kShapeBoundsSize = 120.0f; |
static constexpr SkScalar kCtrlRange = 150.0f; |
- static constexpr SkScalar kBevelWidthMax = kShapeBoundsSize; |
- static constexpr SkScalar kBevelHeightMax = 50.0f; |
- static constexpr int kBevelTypeCount = 3; |
- static constexpr SkScalar kSliderHeight = 20.0f; |
- static constexpr SkScalar kSliderWidth = 10.0f; |
+ static constexpr int kNumLights = 3; |
const SkRect fShapeBounds; |
- static constexpr int kNumControls = 3; |
- SkRect fCtrlRangeRects[kNumControls]; |
- SkRect* fSelectedCtrlRect; |
- SkRect fWidthCtrlRect; |
- SkRect fHeightCtrlRect; |
- SkRect fTypeCtrlRect; |
- |
SkScalar fBevelWidth; |
SkScalar fBevelHeight; |
- SkNormalSource::BevelType fBevelType; |
+ int fBevelType; |
+ |
sk_sp<SkNormalSource> fNormalSource; |
bool fDirtyNormalSource; |
sk_sp<SkLights> fLights; |
- SkLights::Light fRedLight; |
- SkLights::Light fBlueLight; |
+ |
+ struct LightDef { |
+ SkVector fDirXY; |
+ SkScalar fDirZ; |
+ SkColor3f fColor; |
+ |
+ LightDef() {} |
+ LightDef(SkVector dirXY, SkScalar dirZ, SkColor3f color) |
+ : fDirXY(dirXY) |
+ , fDirZ(dirZ) |
+ , fColor(color) {} |
+ }; |
+ LightDef fLightDefs[kNumLights]; |
+ |
+ ControlPanel fControlPanel; |
+ bool fControlPanelSelected; |
sk_sp<SkTypeface> fLabelTypeface; |