Chromium Code Reviews| Index: samplecode/SampleBevel.cpp |
| diff --git a/samplecode/SampleBevel.cpp b/samplecode/SampleBevel.cpp |
| index 868ce35244288fa99b9c76c4ff0c75705650c173..a59362a7873101bd60f8220a7e60ca4e0bf0fada 100644 |
| --- a/samplecode/SampleBevel.cpp |
| +++ b/samplecode/SampleBevel.cpp |
| @@ -11,57 +11,654 @@ |
| #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: |
|
robertphillips
2016/08/19 17:50:20
one line ?
dvonbeck
2016/08/19 18:25:17
Done.
|
| + Control(SkString name) |
| + : fName(name), fParent(nullptr), fRelativeY(0) {} |
| + |
| + // Use this to propagate a click's position down to a control. Gets modulated by the component's |
| + // relative position |
|
robertphillips
2016/08/19 17:50:19
const & ?
dvonbeck
2016/08/19 18:25:16
Done.
|
| + bool click(SkPoint clickPos) { |
| + SkPoint relativeClickPos = SkPoint::Make(clickPos.fX, clickPos.fY - fRelativeY); |
| + 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(0, fRelativeY); |
| + this->onDrawContent(canvas); |
| + canvas->restore(); |
| + } |
| + |
|
robertphillips
2016/08/19 17:50:19
argumend ?
dvonbeck
2016/08/19 18:25:17
Done.
|
| + // Returns true when click position argumend lands over a control region in this control. Click |
| + // position gets modulated by the component's relative position. |
|
robertphillips
2016/08/19 17:50:19
const& ?
dvonbeck
2016/08/19 18:25:18
Done.
|
| + bool isInCtrlRegion(SkPoint click) { |
| + SkPoint relativeClickPos = SkPoint::Make(click.fX, click.fY - fRelativeY); |
| + 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, SkScalar relativeY) { |
| + SkASSERT(parent); |
| + SkASSERT(!fParent); // No chidren transfer since relativeY would get invalid for younger kid |
| + |
| + fParent = parent; |
| + fRelativeY = relativeY; |
| + 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. |
|
robertphillips
2016/08/19 17:50:19
& on string ?
dvonbeck
2016/08/19 18:25:18
Done.
|
| + 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(SkPoint clickPos) { return false; }; |
|
egdaniel
2016/08/19 17:56:35
const &
dvonbeck
2016/08/19 18:25:18
Done.
|
| + |
| + // Overriden by sub-classes with controls. Should return true if clickPos lands inside a control |
| + // region, to enable mouse caputre. |
|
robertphillips
2016/08/19 17:50:19
const SkPoint& ?
dvonbeck
2016/08/19 18:25:17
Done.
|
| + virtual bool onIsInCtrlRegion(SkPoint clickPos) const { return false; }; |
| + |
|
robertphillips
2016/08/19 17:50:19
Why not a relativeX too ? An SkPoint ?
|
| + // The y-coordinate of the control relative to it's parent |
| + SkScalar fRelativeY; |
| +}; |
| + |
| +class ParentControl : public Control { // Interface for all controls that have children |
| +public: |
|
robertphillips
2016/08/19 17:50:20
const SkString& ?
use INHERITED ?
dvonbeck
2016/08/19 18:25:17
Done.
|
| + ParentControl(SkString name) : Control(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; |
|
robertphillips
2016/08/19 17:50:19
private:
INHERITED
?
dvonbeck
2016/08/19 18:25:17
Done.
|
| +}; |
| + |
| +class ControlPanel : public ParentControl { |
| +public: |
| + |
| + ControlPanel(SkScalar width) |
|
robertphillips
2016/08/19 17:50:19
tabbed too far over
dvonbeck
2016/08/19 18:25:18
Done.
|
| + : 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, 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; |
| + } |
| + |
|
robertphillips
2016/08/19 17:50:20
overlength
dvonbeck
2016/08/19 18:25:17
Done.
|
| + void onClickRelease() override { // Propagate click release to selected control, deselect control |
|
robertphillips
2016/08/19 17:50:19
add newlines and brackets
dvonbeck
2016/08/19 18:25:17
Done.
|
| + 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 |
|
robertphillips
2016/08/19 17:50:19
const & ?
dvonbeck
2016/08/19 18:25:16
Done.
|
| + bool onClick(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(SkPoint clickPos) const override { |
|
egdaniel
2016/08/19 17:56:35
const &
dvonbeck
2016/08/19 18:25:17
Done.
|
| + for (int i = 0; i < fControls.count(); i++) { |
|
robertphillips
2016/08/19 17:50:20
\ns and brackets
dvonbeck
2016/08/19 18:25:16
Done.
|
| + 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: |
|
robertphillips
2016/08/19 17:50:19
ovveride ?
dvonbeck
2016/08/19 18:25:17
Done.
|
| + SkScalar height() const { //ovverride} |
| + return 2.0f * kLabelHeight; |
| + } |
| + |
| + // Set width-dependant variables when new parent is set |
| + void onSetParent() override { |
|
robertphillips
2016/08/19 17:50:19
one line ?
dvonbeck
2016/08/19 18:25:17
Done.
|
| + 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.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(SkPoint clickPos) override { |
|
egdaniel
2016/08/19 17:56:35
const &
dvonbeck
2016/08/19 18:25:17
Done.
|
| + 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; |
| + } |
| + |
|
robertphillips
2016/08/19 17:50:19
const & ?
dvonbeck
2016/08/19 18:25:17
Done.
|
| + bool onIsInCtrlRegion(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) |
|
robertphillips
2016/08/19 17:50:20
use INHERITED here ?
dvonbeck
2016/08/19 18:25:18
Done.
|
| + : Control(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; |
|
robertphillips
2016/08/19 17:50:19
private:
INHERITED
?
dvonbeck
2016/08/19 18:25:17
Done.
|
| +}; |
| + |
| +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, 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, 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. |
| + */ |
|
robertphillips
2016/08/19 17:50:19
const & ?
dvonbeck
2016/08/19 18:25:17
Done.
|
| + static sk_sp<ParentControl> Make(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 |
|
robertphillips
2016/08/19 17:50:19
const & ?
dvonbeck
2016/08/19 18:25:17
Done.
|
| + bool onClick(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(SkPoint clickPos) const override { |
| + if (fControlSelector->isInCtrlRegion(clickPos)) return true; |
|
robertphillips
2016/08/19 17:50:19
\ns and brackets
dvonbeck
2016/08/19 18:25:18
Done.
|
| + if (fControls[fSelectedControl]->isInCtrlRegion(clickPos)) return true; |
| + |
| + return false; |
| + } |
| + |
| +private: |
|
robertphillips
2016/08/19 17:50:19
one line ?
const SkString& ?
use INHERITED here ?
dvonbeck
2016/08/19 18:25:17
Doesn't fit in one line, rest are done
|
| + ControlSwitcher(SkString name) |
| + : ParentControl(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; |
| +}; |
| + |
| +class ContinuousSliderControl : public Control { |
| +public: |
| + SkScalar height() const override { |
| + return 2.0f * kLabelHeight; |
| + } |
| + |
| + void onSetParent() { |
| + 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(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(SkPoint clickPos) override { |
| + SkASSERT(fParent); |
| + SkScalar x = SkScalarPin(clickPos.fX, 0.0f, fSliderRange); |
| + *fOutput = (x/fSliderRange) * (fMax - fMin) + fMin; |
| + return true; |
| + } |
| + |
| + bool onIsInCtrlRegion(SkPoint clickPos) const override { |
| + SkASSERT(fParent); |
| + return fCtrlRegion.contains(SkRect::MakeXYWH(clickPos.fX, clickPos.fY, 1, 1)); |
| + } |
| + |
| +private: |
| + ContinuousSliderControl(SkString name, SkScalar* output, SkScalar min, SkScalar max) |
| + : Control(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; |
| +}; |
| + |
| +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(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(SkPoint clickPos) override { |
| + SkASSERT(fParent); |
| + fOutput->fX = clickPos.fX - fCtrlRegion.centerX(); |
| + fOutput->fY = clickPos.fY - fCtrlRegion.centerY(); |
| + fOutput->normalize(); |
| + |
| + return true; |
| + } |
| + |
| + bool onIsInCtrlRegion(SkPoint clickPos) const override { |
| + SkASSERT(fParent); |
| + return fCtrlRegion.contains(SkRect::MakeXYWH(clickPos.fX, clickPos.fY, |
| + 1, 1)); |
| + } |
| + |
| +private: |
| + RadialDirectionControl(SkString name, SkVector* output) |
| + : Control(name) |
| + , fOutput(output) { |
| + fCtrlRegion = SkRect::MakeXYWH(0.0f, kLabelHeight, kRegionRadius * 2.0f, kRegionRadius * 2.0f); |
|
egdaniel
2016/08/19 17:56:35
100 chars.
dvonbeck
2016/08/19 18:25:17
Done.
|
| + } |
| + |
| + SkVector* fOutput; |
| + SkRect fCtrlRegion; |
| + |
| + static constexpr SkScalar kRegionRadius = 50.0f; |
| + static constexpr SkScalar kStrokeWidth = 6.0f; |
| + static constexpr SkScalar kCapRadius = kStrokeWidth / 2.0f; |
| +}; |
| + |
| +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(SkString name, SkColor3f* input) |
| + : Control(name) |
| + , fInput(input) {} |
| + |
| + SkColor3f* fInput; |
| + SkRect fDisplayRect; |
| + |
| + static constexpr SkScalar kHeight = 24.0f; |
| + static constexpr SkScalar kPadding = 4.0f; |
| +}; |
| 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 = SkNormalSource::BevelType::kLinear; |
| + |
| + 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)); |
|
robertphillips
2016/08/19 17:50:19
That's and exciting cast there. I propose you actu
dvonbeck
2016/08/19 18:25:16
Done.
|
| + fControlPanel.add(DiscreteSliderControl::Make(SkString("BevelType"), (int*)&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()); |
| @@ -112,58 +709,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(); |
|
egdaniel
2016/08/19 17:56:35
Does this correctly destroy the old lights in fLig
dvonbeck
2016/08/19 18:25:17
Yes, SkLights is backed by SkTArray of lights. Des
|
| // Draw shapes |
| SkScalar xPos = kCtrlRange + 25.0f; |
| @@ -183,107 +741,32 @@ 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; |
| @@ -291,8 +774,22 @@ private: |
| 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; |